blob: 311b30a18173561c80ee44f2f088922566aac638 [file] [log] [blame]
Jeff Thompson47eecfc2013-07-07 22:56:46 -07001/**
2 * @author: Jeff Thompson
3 * See COPYING for copyright and distribution information.
Jeff Thompson76317aa2013-06-25 19:11:48 -07004 */
5
6#include "BinaryXML.h"
7#include "BinaryXMLDecoder.h"
8
Jeff Thompsonb4ee4002013-06-28 13:41:43 -07009/**
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 */
13static 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 */
22static inline unsigned int unsafeGetOctet(struct ndn_BinaryXMLDecoder *self)
23{
24 return (unsigned int)(self->input[self->offset] & 0xff);
25}
26
Jeff Thompson167ca5a2013-07-07 20:45:43 -070027/**
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 */
35static 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 Thompsond6f13282013-06-27 17:31:50 -070053char *ndn_BinaryXMLDecoder_decodeTypeAndValue(struct ndn_BinaryXMLDecoder *self, unsigned int *type, unsigned int *valueOut)
Jeff Thompson82222e82013-06-26 19:32:59 -070054{
Jeff Thompson76317aa2013-06-25 19:11:48 -070055 unsigned int value = 0;
Jeff Thompson38cbd572013-06-28 14:01:10 -070056 int gotFirstOctet = 0;
Jeff Thompson76317aa2013-06-25 19:11:48 -070057
58 while (1) {
Jeff Thompsonf7316692013-06-26 21:31:42 -070059 if (self->offset >= self->inputLength)
Jeff Thompson04c0b6a2013-06-28 13:49:13 -070060 return "ndn_BinaryXMLDecoder_decodeTypeAndVal: read past the end of the input";
Jeff Thompson76317aa2013-06-25 19:11:48 -070061
Jeff Thompsonb4ee4002013-06-28 13:41:43 -070062 unsigned int octet = unsafeReadOctet(self);
Jeff Thompson76317aa2013-06-25 19:11:48 -070063
Jeff Thompson38cbd572013-06-28 14:01:10 -070064 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 Thompson76317aa2013-06-25 19:11:48 -070071 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 Thompsonb4ee4002013-06-28 13:41:43 -070082 return 0;
Jeff Thompson76317aa2013-06-25 19:11:48 -070083}
Jeff Thompson179d0502013-06-28 11:36:00 -070084
Jeff Thompson1156ed12013-07-01 16:13:56 -070085char *ndn_BinaryXMLDecoder_readElementStartDTag(struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag)
Jeff Thompson179d0502013-06-28 11:36:00 -070086{
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 Thompson1156ed12013-07-01 16:13:56 -070094 return "ndn_BinaryXMLDecoder_readElementStartDTag: header type is not a DTAG";
Jeff Thompson179d0502013-06-28 11:36:00 -070095
Jeff Thompson74ab0812013-06-28 12:25:04 -070096 if (value != expectedTag)
Jeff Thompson1156ed12013-07-01 16:13:56 -070097 return "ndn_BinaryXMLDecoder_readElementStartDTag: did not get the expected DTAG";
Jeff Thompson179d0502013-06-28 11:36:00 -070098
Jeff Thompsonb4ee4002013-06-28 13:41:43 -070099 return 0;
Jeff Thompson74ab0812013-06-28 12:25:04 -0700100}
101
102char *ndn_BinaryXMLDecoder_readElementClose(struct ndn_BinaryXMLDecoder *self)
103{
104 if (self->offset >= self->inputLength)
Jeff Thompson04c0b6a2013-06-28 13:49:13 -0700105 return "ndn_BinaryXMLDecoder_readElementClose: read past the end of the input";
Jeff Thompson74ab0812013-06-28 12:25:04 -0700106
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700107 if (unsafeReadOctet(self) != ndn_BinaryXML_CLOSE)
Jeff Thompson1156ed12013-07-01 16:13:56 -0700108 return "ndn_BinaryXMLDecoder_readElementStartDTag: did not get the expected element close";
Jeff Thompson74ab0812013-06-28 12:25:04 -0700109
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700110 return 0;
Jeff Thompson74ab0812013-06-28 12:25:04 -0700111}
112
113char *ndn_BinaryXMLDecoder_peekDTag(struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag, int *gotExpectedTag)
114{
115 // Default to 0.
116 *gotExpectedTag = 0;
Jeff Thompson6d17b6e2013-06-28 14:04:01 -0700117
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 Thompson74ab0812013-06-28 12:25:04 -0700124 unsigned int type;
125 unsigned int value;
126 unsigned int saveOffset = self->offset;
127 char *error = ndn_BinaryXMLDecoder_decodeTypeAndValue(self, &type, &value);
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700128 // Restore offset.
Jeff Thompson74ab0812013-06-28 12:25:04 -0700129 self->offset = saveOffset;
130
131 if (error)
132 return error;
133
134 if (type == ndn_BinaryXML_DTAG && value == expectedTag)
135 *gotExpectedTag = 1;
136
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700137 return 0;
138}
139
140char *ndn_BinaryXMLDecoder_readBinaryDTagElement
141 (struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag, int allowNull, unsigned char **value, unsigned int *valueLen)
142{
143 char *error;
Jeff Thompson1156ed12013-07-01 16:13:56 -0700144 if (error = ndn_BinaryXMLDecoder_readElementStartDTag(self, expectedTag))
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700145 return error;
146
147 if (allowNull) {
148 if (self->offset >= self->inputLength)
Jeff Thompson04c0b6a2013-06-28 13:49:13 -0700149 return "ndn_BinaryXMLDecoder_readBinaryDTagElement: read past the end of the input";
Jeff Thompsonb4ee4002013-06-28 13:41:43 -0700150
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 Thompson167ca5a2013-07-07 20:45:43 -0700172
173char *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
194char *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
209char *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 Thompson5abaaca2013-07-07 21:16:04 -0700218 *value = -1;
Jeff Thompson167ca5a2013-07-07 20:45:43 -0700219 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 Thompson5abaaca2013-07-07 21:16:04 -0700229
230// TODO: This could be in a more central source file.
231unsigned 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}