blob: 243835ac349b485a5fa1fd95fb1b2a1167057e76 [file] [log] [blame]
Jeff Thompson47eecfc2013-07-07 22:56:46 -07001/**
2 * @author: Jeff Thompson
Jeff Thompsone5b37a52013-07-08 15:39:01 -07003 * Derived from BinaryXMLDecoder.js by Meki Cheraoui.
Jeff Thompson47eecfc2013-07-07 22:56:46 -07004 * See COPYING for copyright and distribution information.
Jeff Thompson76317aa2013-06-25 19:11:48 -07005 */
6
Jeff Thompson53412192013-08-06 13:35:50 -07007#include "binary-xml.h"
8#include "binary-xml-decoder.h"
Jeff Thompson76317aa2013-06-25 19:11:48 -07009
Jeff Thompsonb4ee4002013-06-28 13:41:43 -070010/**
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 */
Jeff Thompsonf0fea002013-07-30 17:22:42 -070014static inline unsigned int unsafeReadOctet(struct ndn_BinaryXmlDecoder *self)
Jeff Thompsonb4ee4002013-06-28 13:41:43 -070015{
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 */
Jeff Thompsonf0fea002013-07-30 17:22:42 -070023static inline unsigned int unsafeGetOctet(struct ndn_BinaryXmlDecoder *self)
Jeff Thompsonb4ee4002013-06-28 13:41:43 -070024{
25 return (unsigned int)(self->input[self->offset] & 0xff);
26}
27
Jeff Thompson167ca5a2013-07-07 20:45:43 -070028/**
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.
Jeff Thompson8b666002013-07-08 01:16:26 -070034 * @return 0 for success, else an error code, including if an element of value is not a decimal digit.
Jeff Thompson167ca5a2013-07-07 20:45:43 -070035 */
Jeff Thompson8b666002013-07-08 01:16:26 -070036static ndn_Error parseUnsignedDecimalInt(unsigned char *value, unsigned int valueLength, unsigned int *resultOut)
Jeff Thompson167ca5a2013-07-07 20:45:43 -070037{
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'))
Jeff Thompson8b666002013-07-08 01:16:26 -070044 return NDN_ERROR_element_of_value_is_not_a_decimal_digit;
Jeff Thompson167ca5a2013-07-07 20:45:43 -070045
46 result *= 10;
47 result += (unsigned int)(digit - '0');
48 }
49
50 *resultOut = result;
Jeff Thompsonadaf9232013-08-08 14:30:29 -070051 return NDN_ERROR_success;
Jeff Thompson167ca5a2013-07-07 20:45:43 -070052}
53
Jeff Thompsonf0fea002013-07-30 17:22:42 -070054ndn_Error ndn_BinaryXmlDecoder_decodeTypeAndValue(struct ndn_BinaryXmlDecoder *self, unsigned int *type, unsigned int *valueOut)
Jeff Thompson82222e82013-06-26 19:32:59 -070055{
Jeff Thompson76317aa2013-06-25 19:11:48 -070056 unsigned int value = 0;
Jeff Thompson38cbd572013-06-28 14:01:10 -070057 int gotFirstOctet = 0;
Jeff Thompson76317aa2013-06-25 19:11:48 -070058
Jeff Thompsona0d18c92013-08-06 13:55:32 -070059 while (1) {
Jeff Thompsonf7316692013-06-26 21:31:42 -070060 if (self->offset >= self->inputLength)
Jeff Thompson8b666002013-07-08 01:16:26 -070061 return NDN_ERROR_read_past_the_end_of_the_input;
Jeff Thompson76317aa2013-06-25 19:11:48 -070062
Jeff Thompsona0d18c92013-08-06 13:55:32 -070063 unsigned int octet = unsafeReadOctet(self);
64
Jeff Thompson38cbd572013-06-28 14:01:10 -070065 if (!gotFirstOctet) {
66 if (octet == 0)
Jeff Thompson8b666002013-07-08 01:16:26 -070067 return NDN_ERROR_the_first_header_octet_may_not_be_zero;
Jeff Thompson38cbd572013-06-28 14:01:10 -070068
69 gotFirstOctet = 1;
70 }
71
Jeff Thompsona0d18c92013-08-06 13:55:32 -070072 if (octet & ndn_BinaryXml_TT_FINAL) {
Jeff Thompson76317aa2013-06-25 19:11:48 -070073 // Finished.
Jeff Thompsona0d18c92013-08-06 13:55:32 -070074 *type = octet & ndn_BinaryXml_TT_MASK;
75 value = (value << ndn_BinaryXml_TT_VALUE_BITS) | ((octet >> ndn_BinaryXml_TT_BITS) & ndn_BinaryXml_TT_VALUE_MASK);
Jeff Thompson76317aa2013-06-25 19:11:48 -070076 break;
Jeff Thompsona0d18c92013-08-06 13:55:32 -070077 }
78
79 value = (value << ndn_BinaryXml_REGULAR_VALUE_BITS) | (octet & ndn_BinaryXml_REGULAR_VALUE_MASK);
80 }
Jeff Thompson76317aa2013-06-25 19:11:48 -070081
Jeff Thompsona0d18c92013-08-06 13:55:32 -070082 *valueOut = value;
Jeff Thompsonadaf9232013-08-08 14:30:29 -070083 return NDN_ERROR_success;
Jeff Thompson76317aa2013-06-25 19:11:48 -070084}
Jeff Thompson179d0502013-06-28 11:36:00 -070085
Jeff Thompsonf0fea002013-07-30 17:22:42 -070086ndn_Error ndn_BinaryXmlDecoder_readElementStartDTag(struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag)
Jeff Thompson179d0502013-06-28 11:36:00 -070087{
Jeff Thompson8b666002013-07-08 01:16:26 -070088 ndn_Error error;
Jeff Thompson179d0502013-06-28 11:36:00 -070089 unsigned int type;
90 unsigned int value;
Jeff Thompson94ddc272013-08-08 14:17:38 -070091 if ((error = ndn_BinaryXmlDecoder_decodeTypeAndValue(self, &type, &value)))
Jeff Thompson179d0502013-06-28 11:36:00 -070092 return error;
93
Jeff Thompsonf0fea002013-07-30 17:22:42 -070094 if (type != ndn_BinaryXml_DTAG)
Jeff Thompson8b666002013-07-08 01:16:26 -070095 return NDN_ERROR_header_type_is_not_a_DTAG;
Jeff Thompson179d0502013-06-28 11:36:00 -070096
Jeff Thompson74ab0812013-06-28 12:25:04 -070097 if (value != expectedTag)
Jeff Thompson8b666002013-07-08 01:16:26 -070098 return NDN_ERROR_did_not_get_the_expected_DTAG;
Jeff Thompson179d0502013-06-28 11:36:00 -070099
Jeff Thompsonadaf9232013-08-08 14:30:29 -0700100 return NDN_ERROR_success;
Jeff Thompson74ab0812013-06-28 12:25:04 -0700101}
102
Jeff Thompsonf0fea002013-07-30 17:22:42 -0700103ndn_Error ndn_BinaryXmlDecoder_readElementClose(struct ndn_BinaryXmlDecoder *self)
Jeff Thompson74ab0812013-06-28 12:25:04 -0700104{
105 if (self->offset >= self->inputLength)
Jeff Thompson8b666002013-07-08 01:16:26 -0700106 return NDN_ERROR_read_past_the_end_of_the_input;
Jeff Thompson74ab0812013-06-28 12:25:04 -0700107
Jeff Thompsonf0fea002013-07-30 17:22:42 -0700108 if (unsafeReadOctet(self) != ndn_BinaryXml_CLOSE)
Jeff Thompson8b666002013-07-08 01:16:26 -0700109 return NDN_ERROR_did_not_get_the_expected_element_close;
Jeff Thompson74ab0812013-06-28 12:25:04 -0700110
Jeff Thompsonadaf9232013-08-08 14:30:29 -0700111 return NDN_ERROR_success;
Jeff Thompson74ab0812013-06-28 12:25:04 -0700112}
113
Jeff Thompsonf0fea002013-07-30 17:22:42 -0700114ndn_Error ndn_BinaryXmlDecoder_peekDTag(struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, int *gotExpectedTag)
Jeff Thompson74ab0812013-06-28 12:25:04 -0700115{
116 // Default to 0.
117 *gotExpectedTag = 0;
Jeff Thompson6d17b6e2013-06-28 14:04:01 -0700118
119 // First check if it is an element close (which cannot be the expected tag).
120 if (self->offset >= self->inputLength)
Jeff Thompson8b666002013-07-08 01:16:26 -0700121 return NDN_ERROR_read_past_the_end_of_the_input;
Jeff Thompson6d17b6e2013-06-28 14:04:01 -0700122 if (unsafeGetOctet(self) == 0)
Jeff Thompsonadaf9232013-08-08 14:30:29 -0700123 return NDN_ERROR_success;
Jeff Thompson6d17b6e2013-06-28 14:04:01 -0700124
Jeff Thompson74ab0812013-06-28 12:25:04 -0700125 unsigned int type;
126 unsigned int value;
127 unsigned int saveOffset = self->offset;
Jeff Thompsonf0fea002013-07-30 17:22:42 -0700128 ndn_Error error = ndn_BinaryXmlDecoder_decodeTypeAndValue(self, &type, &value);
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700129 // Restore offset.
Jeff Thompson74ab0812013-06-28 12:25:04 -0700130 self->offset = saveOffset;
131
132 if (error)
133 return error;
134
Jeff Thompsonf0fea002013-07-30 17:22:42 -0700135 if (type == ndn_BinaryXml_DTAG && value == expectedTag)
Jeff Thompson74ab0812013-06-28 12:25:04 -0700136 *gotExpectedTag = 1;
137
Jeff Thompsonadaf9232013-08-08 14:30:29 -0700138 return NDN_ERROR_success;
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700139}
140
Jeff Thompsonf0fea002013-07-30 17:22:42 -0700141ndn_Error ndn_BinaryXmlDecoder_readBinaryDTagElement
142 (struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, int allowNull, unsigned char **value, unsigned int *valueLength)
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700143{
Jeff Thompson8b666002013-07-08 01:16:26 -0700144 ndn_Error error;
Jeff Thompson94ddc272013-08-08 14:17:38 -0700145 if ((error = ndn_BinaryXmlDecoder_readElementStartDTag(self, expectedTag)))
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700146 return error;
147
148 if (allowNull) {
149 if (self->offset >= self->inputLength)
Jeff Thompson8b666002013-07-08 01:16:26 -0700150 return NDN_ERROR_read_past_the_end_of_the_input;
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700151
Jeff Thompsonf0fea002013-07-30 17:22:42 -0700152 if (unsafeGetOctet(self) == ndn_BinaryXml_CLOSE) {
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700153 // 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;
Jeff Thompson033d7fd2013-07-11 10:44:03 -0700156 *valueLength = 0;
Jeff Thompsonadaf9232013-08-08 14:30:29 -0700157 return NDN_ERROR_success;
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700158 }
159 }
160
161 unsigned int itemType;
Jeff Thompson94ddc272013-08-08 14:17:38 -0700162 if ((error = ndn_BinaryXmlDecoder_decodeTypeAndValue(self, &itemType, valueLength)))
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700163 return error;
164 // Ignore itemType.
165 *value = self->input + self->offset;
Jeff Thompson033d7fd2013-07-11 10:44:03 -0700166 self->offset += *valueLength;
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700167
Jeff Thompson94ddc272013-08-08 14:17:38 -0700168 if ((error = ndn_BinaryXmlDecoder_readElementClose(self)))
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700169 return error;
170
Jeff Thompsonadaf9232013-08-08 14:30:29 -0700171 return NDN_ERROR_success;
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700172}
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700173
Jeff Thompsonf0fea002013-07-30 17:22:42 -0700174ndn_Error ndn_BinaryXmlDecoder_readOptionalBinaryDTagElement
175 (struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, int allowNull, unsigned char **value, unsigned int *valueLength)
Jeff Thompson033d7fd2013-07-11 10:44:03 -0700176{
177 ndn_Error error;
178 int gotExpectedTag;
Jeff Thompson94ddc272013-08-08 14:17:38 -0700179 if ((error = ndn_BinaryXmlDecoder_peekDTag(self, expectedTag, &gotExpectedTag)))
Jeff Thompson033d7fd2013-07-11 10:44:03 -0700180 return error;
181 if (gotExpectedTag) {
Jeff Thompson94ddc272013-08-08 14:17:38 -0700182 if ((error = ndn_BinaryXmlDecoder_readBinaryDTagElement(self, expectedTag, allowNull, value, valueLength)))
Jeff Thompson033d7fd2013-07-11 10:44:03 -0700183 return error;
184 }
185 else {
186 *value = 0;
187 *valueLength = 0;
188 }
189
Jeff Thompsonadaf9232013-08-08 14:30:29 -0700190 return NDN_ERROR_success;
Jeff Thompson033d7fd2013-07-11 10:44:03 -0700191}
192
Jeff Thompsonf0fea002013-07-30 17:22:42 -0700193ndn_Error ndn_BinaryXmlDecoder_readUDataDTagElement
194 (struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, unsigned char **value, unsigned int *valueLength)
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700195{
Jeff Thompson8b666002013-07-08 01:16:26 -0700196 ndn_Error error;
Jeff Thompson94ddc272013-08-08 14:17:38 -0700197 if ((error = ndn_BinaryXmlDecoder_readElementStartDTag(self, expectedTag)))
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700198 return error;
199
200 unsigned int itemType;
Jeff Thompson94ddc272013-08-08 14:17:38 -0700201 if ((error = ndn_BinaryXmlDecoder_decodeTypeAndValue(self, &itemType, valueLength)))
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700202 return error;
Jeff Thompsonf0fea002013-07-30 17:22:42 -0700203 if (itemType != ndn_BinaryXml_UDATA)
Jeff Thompson8b666002013-07-08 01:16:26 -0700204 return NDN_ERROR_item_is_not_UDATA;
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700205 *value = self->input + self->offset;
Jeff Thompson033d7fd2013-07-11 10:44:03 -0700206 self->offset += *valueLength;
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700207
Jeff Thompson94ddc272013-08-08 14:17:38 -0700208 if ((error = ndn_BinaryXmlDecoder_readElementClose(self)))
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700209 return error;
210
Jeff Thompsonadaf9232013-08-08 14:30:29 -0700211 return NDN_ERROR_success;
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700212}
213
Jeff Thompson57be78e2013-08-27 13:40:23 -0700214ndn_Error ndn_BinaryXmlDecoder_readOptionalUDataDTagElement
215 (struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, unsigned char **value, unsigned int *valueLength)
216{
217 ndn_Error error;
218 int gotExpectedTag;
219 if ((error = ndn_BinaryXmlDecoder_peekDTag(self, expectedTag, &gotExpectedTag)))
220 return error;
221 if (gotExpectedTag) {
222 if ((error = ndn_BinaryXmlDecoder_readUDataDTagElement(self, expectedTag, value, valueLength)))
223 return error;
224 }
225 else {
226 *value = 0;
227 *valueLength = 0;
228 }
229
230 return NDN_ERROR_success;
231}
232
Jeff Thompsonf0fea002013-07-30 17:22:42 -0700233ndn_Error ndn_BinaryXmlDecoder_readUnsignedIntegerDTagElement
234 (struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, unsigned int *value)
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700235{
236 unsigned char *udataValue;
237 unsigned int udataValueLength;
Jeff Thompson8b666002013-07-08 01:16:26 -0700238 ndn_Error error;
Jeff Thompson94ddc272013-08-08 14:17:38 -0700239 if ((error = ndn_BinaryXmlDecoder_readUDataDTagElement(self, expectedTag, &udataValue, &udataValueLength)))
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700240 return error;
241
Jeff Thompson94ddc272013-08-08 14:17:38 -0700242 if ((error = parseUnsignedDecimalInt(udataValue, udataValueLength, value)))
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700243 return error;
244
Jeff Thompsonadaf9232013-08-08 14:30:29 -0700245 return NDN_ERROR_success;
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700246}
247
Jeff Thompsonf0fea002013-07-30 17:22:42 -0700248ndn_Error ndn_BinaryXmlDecoder_readOptionalUnsignedIntegerDTagElement
249 (struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, int *value)
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700250{
251 int gotExpectedTag;
Jeff Thompson8b666002013-07-08 01:16:26 -0700252 ndn_Error error;
Jeff Thompson94ddc272013-08-08 14:17:38 -0700253 if ((error = ndn_BinaryXmlDecoder_peekDTag(self, expectedTag, &gotExpectedTag)))
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700254 return error;
255
256 if (!gotExpectedTag) {
Jeff Thompson5abaaca2013-07-07 21:16:04 -0700257 *value = -1;
Jeff Thompsonadaf9232013-08-08 14:30:29 -0700258 return NDN_ERROR_success;
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700259 }
260
261 unsigned int unsignedValue;
Jeff Thompson94ddc272013-08-08 14:17:38 -0700262 if ((error = ndn_BinaryXmlDecoder_readUnsignedIntegerDTagElement(self, expectedTag, &unsignedValue)))
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700263 return error;
264
265 *value = (int)unsignedValue;
Jeff Thompsonadaf9232013-08-08 14:30:29 -0700266 return NDN_ERROR_success;
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700267}
Jeff Thompson5abaaca2013-07-07 21:16:04 -0700268
Jeff Thompsonf0fea002013-07-30 17:22:42 -0700269ndn_Error ndn_BinaryXmlDecoder_readTimeMillisecondsDTagElement
270 (struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, double *milliseconds)
Jeff Thompson9693d392013-07-11 14:58:53 -0700271{
272 ndn_Error error;
273 unsigned char *bytes;
274 unsigned int bytesLength;
Jeff Thompson94ddc272013-08-08 14:17:38 -0700275 if ((error = ndn_BinaryXmlDecoder_readBinaryDTagElement(self, expectedTag, 0, &bytes, &bytesLength)))
Jeff Thompson9693d392013-07-11 14:58:53 -0700276 return error;
277
Jeff Thompsonf0fea002013-07-30 17:22:42 -0700278 *milliseconds = 1000.0 * ndn_BinaryXmlDecoder_unsignedBigEndianToDouble(bytes, bytesLength) / 4096.0;
Jeff Thompsonadaf9232013-08-08 14:30:29 -0700279 return NDN_ERROR_success;
Jeff Thompson9693d392013-07-11 14:58:53 -0700280}
281
Jeff Thompsonf0fea002013-07-30 17:22:42 -0700282ndn_Error ndn_BinaryXmlDecoder_readOptionalTimeMillisecondsDTagElement
283 (struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, double *milliseconds)
Jeff Thompson9693d392013-07-11 14:58:53 -0700284{
285 int gotExpectedTag;
286 ndn_Error error;
Jeff Thompson94ddc272013-08-08 14:17:38 -0700287 if ((error = ndn_BinaryXmlDecoder_peekDTag(self, expectedTag, &gotExpectedTag)))
Jeff Thompson9693d392013-07-11 14:58:53 -0700288 return error;
289
290 if (!gotExpectedTag) {
Jeff Thompsone32dc5d2013-07-11 17:56:57 -0700291 *milliseconds = -1.0;
Jeff Thompsonadaf9232013-08-08 14:30:29 -0700292 return NDN_ERROR_success;
Jeff Thompson9693d392013-07-11 14:58:53 -0700293 }
294
Jeff Thompson94ddc272013-08-08 14:17:38 -0700295 if ((error = ndn_BinaryXmlDecoder_readTimeMillisecondsDTagElement(self, expectedTag, milliseconds)))
Jeff Thompson9693d392013-07-11 14:58:53 -0700296 return error;
297
Jeff Thompsonadaf9232013-08-08 14:30:29 -0700298 return NDN_ERROR_success;
Jeff Thompson9693d392013-07-11 14:58:53 -0700299}
300
Jeff Thompsonf0fea002013-07-30 17:22:42 -0700301double ndn_BinaryXmlDecoder_unsignedBigEndianToDouble(unsigned char *bytes, unsigned int bytesLength)
Jeff Thompson5abaaca2013-07-07 21:16:04 -0700302{
Jeff Thompson5553d992013-07-11 14:35:45 -0700303 double result = 0.0;
Jeff Thompson5abaaca2013-07-07 21:16:04 -0700304 unsigned int i;
305 for (i = 0; i < bytesLength; ++i) {
Jeff Thompson5553d992013-07-11 14:35:45 -0700306 result *= 256.0;
307 result += (double)bytes[i];
Jeff Thompson5abaaca2013-07-07 21:16:04 -0700308 }
309
310 return result;
311}