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