| /** |
| * @author: Jeff Thompson |
| * See COPYING for copyright and distribution information. |
| */ |
| |
| #include "BinaryXML.h" |
| #include "BinaryXMLDecoder.h" |
| |
| /** |
| * Return the octet at self->offset, converting to unsigned int. Increment self->offset. |
| * This does not check for reading past the end of the input, so this is called "unsafe". |
| */ |
| static inline unsigned int unsafeReadOctet(struct ndn_BinaryXMLDecoder *self) |
| { |
| return (unsigned int)(self->input[self->offset++] & 0xff); |
| } |
| |
| /** |
| * Return the octet at self->offset, converting to unsigned int. Do not increment self->offset. |
| * This does not check for reading past the end of the input, so this is called "unsafe". |
| */ |
| static inline unsigned int unsafeGetOctet(struct ndn_BinaryXMLDecoder *self) |
| { |
| return (unsigned int)(self->input[self->offset] & 0xff); |
| } |
| |
| /** |
| * Parse the value as a decimal unsigned integer. This does not check for whitespace or + sign. |
| * If valueLength is 0, this succeeds with resultOut 0. |
| * @param value |
| * @param valueLength |
| * @param resultOut output the parsed integer. |
| * @return 0 for success, else an error string, including if an element of value is not a decimal digit. |
| */ |
| static char *parseUnsignedDecimalInt(unsigned char *value, unsigned int valueLength, unsigned int *resultOut) |
| { |
| unsigned int result = 0; |
| |
| unsigned int i; |
| for (i = 0; i < valueLength; ++i) { |
| unsigned char digit = value[i]; |
| if (!(digit >= '0' && digit <= '9')) |
| return "parseUnsignedDecimalInt: element of value is not a decimal digit"; |
| |
| result *= 10; |
| result += (unsigned int)(digit - '0'); |
| } |
| |
| *resultOut = result; |
| return 0; |
| } |
| |
| char *ndn_BinaryXMLDecoder_decodeTypeAndValue(struct ndn_BinaryXMLDecoder *self, unsigned int *type, unsigned int *valueOut) |
| { |
| unsigned int value = 0; |
| int gotFirstOctet = 0; |
| |
| while (1) { |
| if (self->offset >= self->inputLength) |
| return "ndn_BinaryXMLDecoder_decodeTypeAndVal: read past the end of the input"; |
| |
| unsigned int octet = unsafeReadOctet(self); |
| |
| if (!gotFirstOctet) { |
| if (octet == 0) |
| return "ndn_BinaryXMLDecoder_decodeTypeAndVal: the first header octet may not be zero"; |
| |
| gotFirstOctet = 1; |
| } |
| |
| if (octet & ndn_BinaryXML_TT_FINAL) { |
| // Finished. |
| *type = octet & ndn_BinaryXML_TT_MASK; |
| value = (value << ndn_BinaryXML_TT_VALUE_BITS) | ((octet >> ndn_BinaryXML_TT_BITS) & ndn_BinaryXML_TT_VALUE_MASK); |
| break; |
| } |
| |
| value = (value << ndn_BinaryXML_REGULAR_VALUE_BITS) | (octet & ndn_BinaryXML_REGULAR_VALUE_MASK); |
| } |
| |
| *valueOut = value; |
| return 0; |
| } |
| |
| char *ndn_BinaryXMLDecoder_readElementStartDTag(struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag) |
| { |
| char *error; |
| unsigned int type; |
| unsigned int value; |
| if (error = ndn_BinaryXMLDecoder_decodeTypeAndValue(self, &type, &value)) |
| return error; |
| |
| if (type != ndn_BinaryXML_DTAG) |
| return "ndn_BinaryXMLDecoder_readElementStartDTag: header type is not a DTAG"; |
| |
| if (value != expectedTag) |
| return "ndn_BinaryXMLDecoder_readElementStartDTag: did not get the expected DTAG"; |
| |
| return 0; |
| } |
| |
| char *ndn_BinaryXMLDecoder_readElementClose(struct ndn_BinaryXMLDecoder *self) |
| { |
| if (self->offset >= self->inputLength) |
| return "ndn_BinaryXMLDecoder_readElementClose: read past the end of the input"; |
| |
| if (unsafeReadOctet(self) != ndn_BinaryXML_CLOSE) |
| return "ndn_BinaryXMLDecoder_readElementStartDTag: did not get the expected element close"; |
| |
| return 0; |
| } |
| |
| char *ndn_BinaryXMLDecoder_peekDTag(struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag, int *gotExpectedTag) |
| { |
| // Default to 0. |
| *gotExpectedTag = 0; |
| |
| // First check if it is an element close (which cannot be the expected tag). |
| if (self->offset >= self->inputLength) |
| return "ndn_BinaryXMLDecoder_readElementClose: read past the end of the input"; |
| if (unsafeGetOctet(self) == 0) |
| return 0; |
| |
| unsigned int type; |
| unsigned int value; |
| unsigned int saveOffset = self->offset; |
| char *error = ndn_BinaryXMLDecoder_decodeTypeAndValue(self, &type, &value); |
| // Restore offset. |
| self->offset = saveOffset; |
| |
| if (error) |
| return error; |
| |
| if (type == ndn_BinaryXML_DTAG && value == expectedTag) |
| *gotExpectedTag = 1; |
| |
| return 0; |
| } |
| |
| char *ndn_BinaryXMLDecoder_readBinaryDTagElement |
| (struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag, int allowNull, unsigned char **value, unsigned int *valueLen) |
| { |
| char *error; |
| if (error = ndn_BinaryXMLDecoder_readElementStartDTag(self, expectedTag)) |
| return error; |
| |
| if (allowNull) { |
| if (self->offset >= self->inputLength) |
| return "ndn_BinaryXMLDecoder_readBinaryDTagElement: read past the end of the input"; |
| |
| if (unsafeGetOctet(self) == ndn_BinaryXML_CLOSE) { |
| // The binary item is missing, and this is allowed, so read the element close and return a null value. |
| ++self->offset; |
| *value = 0; |
| *valueLen = 0; |
| return 0; |
| } |
| } |
| |
| unsigned int itemType; |
| if (error = ndn_BinaryXMLDecoder_decodeTypeAndValue(self, &itemType, valueLen)) |
| return error; |
| // Ignore itemType. |
| *value = self->input + self->offset; |
| self->offset += *valueLen; |
| |
| if (error = ndn_BinaryXMLDecoder_readElementClose(self)) |
| return error; |
| |
| return 0; |
| } |
| |
| char *ndn_BinaryXMLDecoder_readUDataDTagElement |
| (struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag, unsigned char **value, unsigned int *valueLen) |
| { |
| char *error; |
| if (error = ndn_BinaryXMLDecoder_readElementStartDTag(self, expectedTag)) |
| return error; |
| |
| unsigned int itemType; |
| if (error = ndn_BinaryXMLDecoder_decodeTypeAndValue(self, &itemType, valueLen)) |
| return error; |
| if (itemType != ndn_BinaryXML_UDATA) |
| return "ndn_BinaryXMLDecoder_readUDataDTagElement: item is not UDATA"; |
| *value = self->input + self->offset; |
| self->offset += *valueLen; |
| |
| if (error = ndn_BinaryXMLDecoder_readElementClose(self)) |
| return error; |
| |
| return 0; |
| } |
| |
| char *ndn_BinaryXMLDecoder_readUnsignedIntegerDTagElement |
| (struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag, unsigned int *value) |
| { |
| unsigned char *udataValue; |
| unsigned int udataValueLength; |
| char *error; |
| if (error = ndn_BinaryXMLDecoder_readUDataDTagElement(self, expectedTag, &udataValue, &udataValueLength)) |
| return error; |
| |
| if (error = parseUnsignedDecimalInt(udataValue, udataValueLength, value)) |
| return error; |
| |
| return 0; |
| } |
| |
| char *ndn_BinaryXMLDecoder_readOptionalUnsignedIntegerDTagElement |
| (struct ndn_BinaryXMLDecoder *self, unsigned int expectedTag, int *value) |
| { |
| int gotExpectedTag; |
| char *error; |
| if (error = ndn_BinaryXMLDecoder_peekDTag(self, expectedTag, &gotExpectedTag)) |
| return error; |
| |
| if (!gotExpectedTag) { |
| *value = -1; |
| return 0; |
| } |
| |
| unsigned int unsignedValue; |
| if (error = ndn_BinaryXMLDecoder_readUnsignedIntegerDTagElement(self, expectedTag, &unsignedValue)) |
| return error; |
| |
| *value = (int)unsignedValue; |
| return 0; |
| } |
| |
| // TODO: This could be in a more central source file. |
| unsigned int ndn_BinaryXMLDecoder_bigEndianToUnsignedInt(unsigned char *bytes, unsigned int bytesLength) |
| { |
| unsigned int result = 0; |
| unsigned int i; |
| for (i = 0; i < bytesLength; ++i) { |
| result <<= 8; |
| result += (unsigned int)bytes[i]; |
| } |
| |
| return result; |
| } |