blob: 8f74cedd2fbe1a5208bce1b1f9b33cd8ca834b2c [file] [log] [blame]
Jeff Thompson76317aa2013-06-25 19:11:48 -07001/*
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 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 */
14static 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 */
23static inline unsigned int unsafeGetOctet(struct ndn_BinaryXMLDecoder *self)
24{
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.
34 * @return 0 for success, else an error string, including if an element of value is not a decimal digit.
35 */
36static 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 Thompsond6f13282013-06-27 17:31:50 -070054char *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
59 while (1) {
Jeff Thompsonf7316692013-06-26 21:31:42 -070060 if (self->offset >= self->inputLength)
Jeff Thompson04c0b6a2013-06-28 13:49:13 -070061 return "ndn_BinaryXMLDecoder_decodeTypeAndVal: read past the end of the input";
Jeff Thompson76317aa2013-06-25 19:11:48 -070062
Jeff Thompsonb4ee4002013-06-28 13:41:43 -070063 unsigned int octet = unsafeReadOctet(self);
Jeff Thompson76317aa2013-06-25 19:11:48 -070064
Jeff Thompson38cbd572013-06-28 14:01:10 -070065 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 Thompson76317aa2013-06-25 19:11:48 -070072 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 Thompsonb4ee4002013-06-28 13:41:43 -070083 return 0;
Jeff Thompson76317aa2013-06-25 19:11:48 -070084}
Jeff Thompson179d0502013-06-28 11:36:00 -070085
Jeff Thompson1156ed12013-07-01 16:13:56 -070086char *ndn_BinaryXMLDecoder_readElementStartDTag(struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag)
Jeff Thompson179d0502013-06-28 11:36:00 -070087{
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 Thompson1156ed12013-07-01 16:13:56 -070095 return "ndn_BinaryXMLDecoder_readElementStartDTag: 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 Thompson1156ed12013-07-01 16:13:56 -070098 return "ndn_BinaryXMLDecoder_readElementStartDTag: did not get the expected DTAG";
Jeff Thompson179d0502013-06-28 11:36:00 -070099
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700100 return 0;
Jeff Thompson74ab0812013-06-28 12:25:04 -0700101}
102
103char *ndn_BinaryXMLDecoder_readElementClose(struct ndn_BinaryXMLDecoder *self)
104{
105 if (self->offset >= self->inputLength)
Jeff Thompson04c0b6a2013-06-28 13:49:13 -0700106 return "ndn_BinaryXMLDecoder_readElementClose: read past the end of the input";
Jeff Thompson74ab0812013-06-28 12:25:04 -0700107
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700108 if (unsafeReadOctet(self) != ndn_BinaryXML_CLOSE)
Jeff Thompson1156ed12013-07-01 16:13:56 -0700109 return "ndn_BinaryXMLDecoder_readElementStartDTag: did not get the expected element close";
Jeff Thompson74ab0812013-06-28 12:25:04 -0700110
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700111 return 0;
Jeff Thompson74ab0812013-06-28 12:25:04 -0700112}
113
114char *ndn_BinaryXMLDecoder_peekDTag(struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag, int *gotExpectedTag)
115{
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)
121 return "ndn_BinaryXMLDecoder_readElementClose: read past the end of the input";
122 if (unsafeGetOctet(self) == 0)
123 return 0;
124
Jeff Thompson74ab0812013-06-28 12:25:04 -0700125 unsigned int type;
126 unsigned int value;
127 unsigned int saveOffset = self->offset;
128 char *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
135 if (type == ndn_BinaryXML_DTAG && value == expectedTag)
136 *gotExpectedTag = 1;
137
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700138 return 0;
139}
140
141char *ndn_BinaryXMLDecoder_readBinaryDTagElement
142 (struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag, int allowNull, unsigned char **value, unsigned int *valueLen)
143{
144 char *error;
Jeff Thompson1156ed12013-07-01 16:13:56 -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 Thompson04c0b6a2013-06-28 13:49:13 -0700150 return "ndn_BinaryXMLDecoder_readBinaryDTagElement: read past the end of the input";
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700151
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 Thompson167ca5a2013-07-07 20:45:43 -0700173
174char *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
195char *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
210char *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}