| /** |
| * Copyright (C) 2013 Regents of the University of California. |
| * @author: Jeff Thompson <jefft0@remap.ucla.edu> |
| * Derived from BinaryXMLDecoder.js by Meki Cheraoui. |
| * See COPYING for copyright and distribution information. |
| */ |
| |
| #include "binary-xml.h" |
| #include "binary-xml-decoder.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 code, including if an element of value is not a decimal digit. |
| */ |
| static ndn_Error parseUnsignedDecimalInt(uint8_t *value, size_t valueLength, unsigned int *resultOut) |
| { |
| unsigned int result = 0; |
| |
| size_t i; |
| for (i = 0; i < valueLength; ++i) { |
| uint8_t digit = value[i]; |
| if (!(digit >= '0' && digit <= '9')) |
| return NDN_ERROR_element_of_value_is_not_a_decimal_digit; |
| |
| result *= 10; |
| result += (unsigned int)(digit - '0'); |
| } |
| |
| *resultOut = result; |
| return NDN_ERROR_success; |
| } |
| |
| ndn_Error 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_ERROR_read_past_the_end_of_the_input; |
| |
| unsigned int octet = unsafeReadOctet(self); |
| |
| if (!gotFirstOctet) { |
| if (octet == 0) |
| return NDN_ERROR_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 NDN_ERROR_success; |
| } |
| |
| ndn_Error ndn_BinaryXmlDecoder_readElementStartDTag(struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag) |
| { |
| if (self->offset == self->previouslyPeekedDTagStartOffset) { |
| // peekDTag already decoded this DTag. |
| if (self->previouslyPeekedDTag != expectedTag) |
| return NDN_ERROR_did_not_get_the_expected_DTAG; |
| |
| // Fast forward past the header. |
| self->offset = self->previouslyPeekedDTagEndOffset; |
| } |
| else { |
| ndn_Error error; |
| unsigned int type; |
| unsigned int value; |
| if ((error = ndn_BinaryXmlDecoder_decodeTypeAndValue(self, &type, &value))) |
| return error; |
| |
| if (type != ndn_BinaryXml_DTAG) |
| return NDN_ERROR_header_type_is_not_a_DTAG; |
| |
| if (value != expectedTag) |
| return NDN_ERROR_did_not_get_the_expected_DTAG; |
| } |
| |
| return NDN_ERROR_success; |
| } |
| |
| ndn_Error ndn_BinaryXmlDecoder_readElementClose(struct ndn_BinaryXmlDecoder *self) |
| { |
| if (self->offset >= self->inputLength) |
| return NDN_ERROR_read_past_the_end_of_the_input; |
| |
| if (unsafeReadOctet(self) != ndn_BinaryXml_CLOSE) |
| return NDN_ERROR_did_not_get_the_expected_element_close; |
| |
| return NDN_ERROR_success; |
| } |
| |
| ndn_Error ndn_BinaryXmlDecoder_peekDTag(struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, int *gotExpectedTag) |
| { |
| if (self->offset == self->previouslyPeekedDTagStartOffset) |
| // We already decoded this DTag. |
| *gotExpectedTag = (self->previouslyPeekedDTag == expectedTag ? 1 : 0); |
| else { |
| // 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_ERROR_read_past_the_end_of_the_input; |
| if (unsafeGetOctet(self) == ndn_BinaryXml_CLOSE) |
| return NDN_ERROR_success; |
| |
| unsigned int type; |
| unsigned int value; |
| size_t saveOffset = self->offset; |
| ndn_Error error = ndn_BinaryXmlDecoder_decodeTypeAndValue(self, &type, &value); |
| // readElementStartDTag will use this to fast forward. |
| self->previouslyPeekedDTagEndOffset = self->offset; |
| // Restore offset. |
| self->offset = saveOffset; |
| |
| if (error) |
| return error; |
| |
| if (type == ndn_BinaryXml_DTAG) { |
| self->previouslyPeekedDTagStartOffset = saveOffset; |
| self->previouslyPeekedDTag = value; |
| |
| if (value == expectedTag) |
| *gotExpectedTag = 1; |
| } |
| } |
| |
| return NDN_ERROR_success; |
| } |
| |
| ndn_Error ndn_BinaryXmlDecoder_readBinaryDTagElement |
| (struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, int allowNull, struct ndn_Blob *value) |
| { |
| ndn_Error error; |
| if ((error = ndn_BinaryXmlDecoder_readElementStartDTag(self, expectedTag))) |
| return error; |
| |
| if (allowNull) { |
| if (self->offset >= self->inputLength) |
| return NDN_ERROR_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->value = 0; |
| value->length = 0; |
| return NDN_ERROR_success; |
| } |
| } |
| |
| unsigned int itemType; |
| unsigned int uintValueLength; |
| if ((error = ndn_BinaryXmlDecoder_decodeTypeAndValue(self, &itemType, &uintValueLength))) |
| return error; |
| // Ignore itemType. |
| value->value = self->input + self->offset; |
| value->length = (size_t)uintValueLength; |
| self->offset += value->length; |
| |
| if ((error = ndn_BinaryXmlDecoder_readElementClose(self))) |
| return error; |
| |
| return NDN_ERROR_success; |
| } |
| |
| ndn_Error ndn_BinaryXmlDecoder_readOptionalBinaryDTagElement |
| (struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, int allowNull, struct ndn_Blob *value) |
| { |
| ndn_Error error; |
| int gotExpectedTag; |
| if ((error = ndn_BinaryXmlDecoder_peekDTag(self, expectedTag, &gotExpectedTag))) |
| return error; |
| if (gotExpectedTag) { |
| if ((error = ndn_BinaryXmlDecoder_readBinaryDTagElement(self, expectedTag, allowNull, value))) |
| return error; |
| } |
| else { |
| value->value = 0; |
| value->length = 0; |
| } |
| |
| return NDN_ERROR_success; |
| } |
| |
| ndn_Error ndn_BinaryXmlDecoder_readUDataDTagElement |
| (struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, struct ndn_Blob *value) |
| { |
| ndn_Error error; |
| if ((error = ndn_BinaryXmlDecoder_readElementStartDTag(self, expectedTag))) |
| return error; |
| |
| unsigned int itemType; |
| unsigned int uintValueLength; |
| if ((error = ndn_BinaryXmlDecoder_decodeTypeAndValue(self, &itemType, &uintValueLength))) |
| return error; |
| if (itemType != ndn_BinaryXml_UDATA) |
| return NDN_ERROR_item_is_not_UDATA; |
| value->value = self->input + self->offset; |
| value->length = uintValueLength; |
| self->offset += value->length; |
| |
| if ((error = ndn_BinaryXmlDecoder_readElementClose(self))) |
| return error; |
| |
| return NDN_ERROR_success; |
| } |
| |
| ndn_Error ndn_BinaryXmlDecoder_readOptionalUDataDTagElement |
| (struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, struct ndn_Blob *value) |
| { |
| ndn_Error error; |
| int gotExpectedTag; |
| if ((error = ndn_BinaryXmlDecoder_peekDTag(self, expectedTag, &gotExpectedTag))) |
| return error; |
| if (gotExpectedTag) { |
| if ((error = ndn_BinaryXmlDecoder_readUDataDTagElement(self, expectedTag, value))) |
| return error; |
| } |
| else { |
| value->value = 0; |
| value->length = 0; |
| } |
| |
| return NDN_ERROR_success; |
| } |
| |
| ndn_Error ndn_BinaryXmlDecoder_readUnsignedIntegerDTagElement |
| (struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, unsigned int *value) |
| { |
| struct ndn_Blob udataValue; |
| ndn_Error error; |
| if ((error = ndn_BinaryXmlDecoder_readUDataDTagElement(self, expectedTag, &udataValue))) |
| return error; |
| |
| if ((error = parseUnsignedDecimalInt(udataValue.value, udataValue.length, value))) |
| return error; |
| |
| return NDN_ERROR_success; |
| } |
| |
| ndn_Error ndn_BinaryXmlDecoder_readOptionalUnsignedIntegerDTagElement |
| (struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, int *value) |
| { |
| int gotExpectedTag; |
| ndn_Error error; |
| if ((error = ndn_BinaryXmlDecoder_peekDTag(self, expectedTag, &gotExpectedTag))) |
| return error; |
| |
| if (!gotExpectedTag) { |
| *value = -1; |
| return NDN_ERROR_success; |
| } |
| |
| unsigned int unsignedValue; |
| if ((error = ndn_BinaryXmlDecoder_readUnsignedIntegerDTagElement(self, expectedTag, &unsignedValue))) |
| return error; |
| |
| *value = (int)unsignedValue; |
| return NDN_ERROR_success; |
| } |
| |
| ndn_Error ndn_BinaryXmlDecoder_readTimeMillisecondsDTagElement |
| (struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, double *milliseconds) |
| { |
| ndn_Error error; |
| struct ndn_Blob bytes; |
| if ((error = ndn_BinaryXmlDecoder_readBinaryDTagElement(self, expectedTag, 0, &bytes))) |
| return error; |
| |
| *milliseconds = 1000.0 * ndn_BinaryXmlDecoder_unsignedBigEndianToDouble(bytes.value, bytes.length) / 4096.0; |
| return NDN_ERROR_success; |
| } |
| |
| ndn_Error ndn_BinaryXmlDecoder_readOptionalTimeMillisecondsDTagElement |
| (struct ndn_BinaryXmlDecoder *self, unsigned int expectedTag, double *milliseconds) |
| { |
| int gotExpectedTag; |
| ndn_Error error; |
| if ((error = ndn_BinaryXmlDecoder_peekDTag(self, expectedTag, &gotExpectedTag))) |
| return error; |
| |
| if (!gotExpectedTag) { |
| *milliseconds = -1.0; |
| return NDN_ERROR_success; |
| } |
| |
| if ((error = ndn_BinaryXmlDecoder_readTimeMillisecondsDTagElement(self, expectedTag, milliseconds))) |
| return error; |
| |
| return NDN_ERROR_success; |
| } |
| |
| double ndn_BinaryXmlDecoder_unsignedBigEndianToDouble(uint8_t *bytes, size_t bytesLength) |
| { |
| double result = 0.0; |
| size_t i; |
| for (i = 0; i < bytesLength; ++i) { |
| result *= 256.0; |
| result += (double)bytes[i]; |
| } |
| |
| return result; |
| } |