Jeff Thompson | 76317aa | 2013-06-25 19:11:48 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Author: Jeff Thompson |
| 3 | * |
| 4 | * BSD license, See the LICENSE file for more information. |
| 5 | */ |
| 6 | |
| 7 | #include "BinaryXML.h" |
| 8 | #include "BinaryXMLDecoder.h" |
| 9 | |
Jeff Thompson | b4ee400 | 2013-06-28 13:41:43 -0700 | [diff] [blame] | 10 | /** |
| 11 | * Return the octet at self->offset, converting to unsigned int. Increment self->offset. |
| 12 | * This does not check for reading past the end of the input, so this is called "unsafe". |
| 13 | */ |
| 14 | static inline unsigned int unsafeReadOctet(struct ndn_BinaryXMLDecoder *self) |
| 15 | { |
| 16 | return (unsigned int)(self->input[self->offset++] & 0xff); |
| 17 | } |
| 18 | |
| 19 | /** |
| 20 | * Return the octet at self->offset, converting to unsigned int. Do not increment self->offset. |
| 21 | * This does not check for reading past the end of the input, so this is called "unsafe". |
| 22 | */ |
| 23 | static inline unsigned int unsafeGetOctet(struct ndn_BinaryXMLDecoder *self) |
| 24 | { |
| 25 | return (unsigned int)(self->input[self->offset] & 0xff); |
| 26 | } |
| 27 | |
Jeff Thompson | 167ca5a | 2013-07-07 20:45:43 -0700 | [diff] [blame^] | 28 | /** |
| 29 | * Parse the value as a decimal unsigned integer. This does not check for whitespace or + sign. |
| 30 | * If valueLength is 0, this succeeds with resultOut 0. |
| 31 | * @param value |
| 32 | * @param valueLength |
| 33 | * @param resultOut output the parsed integer. |
| 34 | * @return 0 for success, else an error string, including if an element of value is not a decimal digit. |
| 35 | */ |
| 36 | static char *parseUnsignedDecimalInt(unsigned char *value, unsigned int valueLength, unsigned int *resultOut) |
| 37 | { |
| 38 | unsigned int result = 0; |
| 39 | |
| 40 | unsigned int i; |
| 41 | for (i = 0; i < valueLength; ++i) { |
| 42 | unsigned char digit = value[i]; |
| 43 | if (!(digit >= '0' && digit <= '9')) |
| 44 | return "parseUnsignedDecimalInt: element of value is not a decimal digit"; |
| 45 | |
| 46 | result *= 10; |
| 47 | result += (unsigned int)(digit - '0'); |
| 48 | } |
| 49 | |
| 50 | *resultOut = result; |
| 51 | return 0; |
| 52 | } |
| 53 | |
Jeff Thompson | d6f1328 | 2013-06-27 17:31:50 -0700 | [diff] [blame] | 54 | char *ndn_BinaryXMLDecoder_decodeTypeAndValue(struct ndn_BinaryXMLDecoder *self, unsigned int *type, unsigned int *valueOut) |
Jeff Thompson | 82222e8 | 2013-06-26 19:32:59 -0700 | [diff] [blame] | 55 | { |
Jeff Thompson | 76317aa | 2013-06-25 19:11:48 -0700 | [diff] [blame] | 56 | unsigned int value = 0; |
Jeff Thompson | 38cbd57 | 2013-06-28 14:01:10 -0700 | [diff] [blame] | 57 | int gotFirstOctet = 0; |
Jeff Thompson | 76317aa | 2013-06-25 19:11:48 -0700 | [diff] [blame] | 58 | |
| 59 | while (1) { |
Jeff Thompson | f731669 | 2013-06-26 21:31:42 -0700 | [diff] [blame] | 60 | if (self->offset >= self->inputLength) |
Jeff Thompson | 04c0b6a | 2013-06-28 13:49:13 -0700 | [diff] [blame] | 61 | return "ndn_BinaryXMLDecoder_decodeTypeAndVal: read past the end of the input"; |
Jeff Thompson | 76317aa | 2013-06-25 19:11:48 -0700 | [diff] [blame] | 62 | |
Jeff Thompson | b4ee400 | 2013-06-28 13:41:43 -0700 | [diff] [blame] | 63 | unsigned int octet = unsafeReadOctet(self); |
Jeff Thompson | 76317aa | 2013-06-25 19:11:48 -0700 | [diff] [blame] | 64 | |
Jeff Thompson | 38cbd57 | 2013-06-28 14:01:10 -0700 | [diff] [blame] | 65 | if (!gotFirstOctet) { |
| 66 | if (octet == 0) |
| 67 | return "ndn_BinaryXMLDecoder_decodeTypeAndVal: the first header octet may not be zero"; |
| 68 | |
| 69 | gotFirstOctet = 1; |
| 70 | } |
| 71 | |
Jeff Thompson | 76317aa | 2013-06-25 19:11:48 -0700 | [diff] [blame] | 72 | if (octet & ndn_BinaryXML_TT_FINAL) { |
| 73 | // Finished. |
| 74 | *type = octet & ndn_BinaryXML_TT_MASK; |
| 75 | value = (value << ndn_BinaryXML_TT_VALUE_BITS) | ((octet >> ndn_BinaryXML_TT_BITS) & ndn_BinaryXML_TT_VALUE_MASK); |
| 76 | break; |
| 77 | } |
| 78 | |
| 79 | value = (value << ndn_BinaryXML_REGULAR_VALUE_BITS) | (octet & ndn_BinaryXML_REGULAR_VALUE_MASK); |
| 80 | } |
| 81 | |
| 82 | *valueOut = value; |
Jeff Thompson | b4ee400 | 2013-06-28 13:41:43 -0700 | [diff] [blame] | 83 | return 0; |
Jeff Thompson | 76317aa | 2013-06-25 19:11:48 -0700 | [diff] [blame] | 84 | } |
Jeff Thompson | 179d050 | 2013-06-28 11:36:00 -0700 | [diff] [blame] | 85 | |
Jeff Thompson | 1156ed1 | 2013-07-01 16:13:56 -0700 | [diff] [blame] | 86 | char *ndn_BinaryXMLDecoder_readElementStartDTag(struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag) |
Jeff Thompson | 179d050 | 2013-06-28 11:36:00 -0700 | [diff] [blame] | 87 | { |
| 88 | char *error; |
| 89 | unsigned int type; |
| 90 | unsigned int value; |
| 91 | if (error = ndn_BinaryXMLDecoder_decodeTypeAndValue(self, &type, &value)) |
| 92 | return error; |
| 93 | |
| 94 | if (type != ndn_BinaryXML_DTAG) |
Jeff Thompson | 1156ed1 | 2013-07-01 16:13:56 -0700 | [diff] [blame] | 95 | return "ndn_BinaryXMLDecoder_readElementStartDTag: header type is not a DTAG"; |
Jeff Thompson | 179d050 | 2013-06-28 11:36:00 -0700 | [diff] [blame] | 96 | |
Jeff Thompson | 74ab081 | 2013-06-28 12:25:04 -0700 | [diff] [blame] | 97 | if (value != expectedTag) |
Jeff Thompson | 1156ed1 | 2013-07-01 16:13:56 -0700 | [diff] [blame] | 98 | return "ndn_BinaryXMLDecoder_readElementStartDTag: did not get the expected DTAG"; |
Jeff Thompson | 179d050 | 2013-06-28 11:36:00 -0700 | [diff] [blame] | 99 | |
Jeff Thompson | b4ee400 | 2013-06-28 13:41:43 -0700 | [diff] [blame] | 100 | return 0; |
Jeff Thompson | 74ab081 | 2013-06-28 12:25:04 -0700 | [diff] [blame] | 101 | } |
| 102 | |
| 103 | char *ndn_BinaryXMLDecoder_readElementClose(struct ndn_BinaryXMLDecoder *self) |
| 104 | { |
| 105 | if (self->offset >= self->inputLength) |
Jeff Thompson | 04c0b6a | 2013-06-28 13:49:13 -0700 | [diff] [blame] | 106 | return "ndn_BinaryXMLDecoder_readElementClose: read past the end of the input"; |
Jeff Thompson | 74ab081 | 2013-06-28 12:25:04 -0700 | [diff] [blame] | 107 | |
Jeff Thompson | b4ee400 | 2013-06-28 13:41:43 -0700 | [diff] [blame] | 108 | if (unsafeReadOctet(self) != ndn_BinaryXML_CLOSE) |
Jeff Thompson | 1156ed1 | 2013-07-01 16:13:56 -0700 | [diff] [blame] | 109 | return "ndn_BinaryXMLDecoder_readElementStartDTag: did not get the expected element close"; |
Jeff Thompson | 74ab081 | 2013-06-28 12:25:04 -0700 | [diff] [blame] | 110 | |
Jeff Thompson | b4ee400 | 2013-06-28 13:41:43 -0700 | [diff] [blame] | 111 | return 0; |
Jeff Thompson | 74ab081 | 2013-06-28 12:25:04 -0700 | [diff] [blame] | 112 | } |
| 113 | |
| 114 | char *ndn_BinaryXMLDecoder_peekDTag(struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag, int *gotExpectedTag) |
| 115 | { |
| 116 | // Default to 0. |
| 117 | *gotExpectedTag = 0; |
Jeff Thompson | 6d17b6e | 2013-06-28 14:04:01 -0700 | [diff] [blame] | 118 | |
| 119 | // First check if it is an element close (which cannot be the expected tag). |
| 120 | if (self->offset >= self->inputLength) |
| 121 | return "ndn_BinaryXMLDecoder_readElementClose: read past the end of the input"; |
| 122 | if (unsafeGetOctet(self) == 0) |
| 123 | return 0; |
| 124 | |
Jeff Thompson | 74ab081 | 2013-06-28 12:25:04 -0700 | [diff] [blame] | 125 | unsigned int type; |
| 126 | unsigned int value; |
| 127 | unsigned int saveOffset = self->offset; |
| 128 | char *error = ndn_BinaryXMLDecoder_decodeTypeAndValue(self, &type, &value); |
Jeff Thompson | b4ee400 | 2013-06-28 13:41:43 -0700 | [diff] [blame] | 129 | // Restore offset. |
Jeff Thompson | 74ab081 | 2013-06-28 12:25:04 -0700 | [diff] [blame] | 130 | self->offset = saveOffset; |
| 131 | |
| 132 | if (error) |
| 133 | return error; |
| 134 | |
| 135 | if (type == ndn_BinaryXML_DTAG && value == expectedTag) |
| 136 | *gotExpectedTag = 1; |
| 137 | |
Jeff Thompson | b4ee400 | 2013-06-28 13:41:43 -0700 | [diff] [blame] | 138 | return 0; |
| 139 | } |
| 140 | |
| 141 | char *ndn_BinaryXMLDecoder_readBinaryDTagElement |
| 142 | (struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag, int allowNull, unsigned char **value, unsigned int *valueLen) |
| 143 | { |
| 144 | char *error; |
Jeff Thompson | 1156ed1 | 2013-07-01 16:13:56 -0700 | [diff] [blame] | 145 | if (error = ndn_BinaryXMLDecoder_readElementStartDTag(self, expectedTag)) |
Jeff Thompson | b4ee400 | 2013-06-28 13:41:43 -0700 | [diff] [blame] | 146 | return error; |
| 147 | |
| 148 | if (allowNull) { |
| 149 | if (self->offset >= self->inputLength) |
Jeff Thompson | 04c0b6a | 2013-06-28 13:49:13 -0700 | [diff] [blame] | 150 | return "ndn_BinaryXMLDecoder_readBinaryDTagElement: read past the end of the input"; |
Jeff Thompson | b4ee400 | 2013-06-28 13:41:43 -0700 | [diff] [blame] | 151 | |
| 152 | if (unsafeGetOctet(self) == ndn_BinaryXML_CLOSE) { |
| 153 | // The binary item is missing, and this is allowed, so read the element close and return a null value. |
| 154 | ++self->offset; |
| 155 | *value = 0; |
| 156 | *valueLen = 0; |
| 157 | return 0; |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | unsigned int itemType; |
| 162 | if (error = ndn_BinaryXMLDecoder_decodeTypeAndValue(self, &itemType, valueLen)) |
| 163 | return error; |
| 164 | // Ignore itemType. |
| 165 | *value = self->input + self->offset; |
| 166 | self->offset += *valueLen; |
| 167 | |
| 168 | if (error = ndn_BinaryXMLDecoder_readElementClose(self)) |
| 169 | return error; |
| 170 | |
| 171 | return 0; |
| 172 | } |
Jeff Thompson | 167ca5a | 2013-07-07 20:45:43 -0700 | [diff] [blame^] | 173 | |
| 174 | char *ndn_BinaryXMLDecoder_readUDataDTagElement |
| 175 | (struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag, unsigned char **value, unsigned int *valueLen) |
| 176 | { |
| 177 | char *error; |
| 178 | if (error = ndn_BinaryXMLDecoder_readElementStartDTag(self, expectedTag)) |
| 179 | return error; |
| 180 | |
| 181 | unsigned int itemType; |
| 182 | if (error = ndn_BinaryXMLDecoder_decodeTypeAndValue(self, &itemType, valueLen)) |
| 183 | return error; |
| 184 | if (itemType != ndn_BinaryXML_UDATA) |
| 185 | return "ndn_BinaryXMLDecoder_readUDataDTagElement: item is not UDATA"; |
| 186 | *value = self->input + self->offset; |
| 187 | self->offset += *valueLen; |
| 188 | |
| 189 | if (error = ndn_BinaryXMLDecoder_readElementClose(self)) |
| 190 | return error; |
| 191 | |
| 192 | return 0; |
| 193 | } |
| 194 | |
| 195 | char *ndn_BinaryXMLDecoder_readUnsignedIntegerDTagElement |
| 196 | (struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag, unsigned int *value) |
| 197 | { |
| 198 | unsigned char *udataValue; |
| 199 | unsigned int udataValueLength; |
| 200 | char *error; |
| 201 | if (error = ndn_BinaryXMLDecoder_readUDataDTagElement(self, expectedTag, &udataValue, &udataValueLength)) |
| 202 | return error; |
| 203 | |
| 204 | if (error = parseUnsignedDecimalInt(udataValue, udataValueLength, value)) |
| 205 | return error; |
| 206 | |
| 207 | return 0; |
| 208 | } |
| 209 | |
| 210 | char *ndn_BinaryXMLDecoder_readOptionalUnsignedIntegerDTagElement |
| 211 | (struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag, int *value) |
| 212 | { |
| 213 | int gotExpectedTag; |
| 214 | char *error; |
| 215 | if (error = ndn_BinaryXMLDecoder_peekDTag(self, expectedTag, &gotExpectedTag)) |
| 216 | return error; |
| 217 | |
| 218 | if (!gotExpectedTag) { |
| 219 | value = -1; |
| 220 | return 0; |
| 221 | } |
| 222 | |
| 223 | unsigned int unsignedValue; |
| 224 | if (error = ndn_BinaryXMLDecoder_readUnsignedIntegerDTagElement(self, expectedTag, &unsignedValue)) |
| 225 | return error; |
| 226 | |
| 227 | *value = (int)unsignedValue; |
| 228 | return 0; |
| 229 | } |