blob: eacd1976d665f66e0ae59b3039a0a9a15cdb8ef1 [file] [log] [blame]
Jeff Thompson47eecfc2013-07-07 22:56:46 -07001/**
2 * @author: Jeff Thompson
3 * See COPYING for copyright and distribution information.
Jeff Thompsonc8963652013-06-28 20:17:43 -07004 */
5
Jeff Thompson5a984832013-07-01 19:28:27 -07006#include "../util/ndn_memory.h"
Jeff Thompson590b8692013-06-28 22:07:41 -07007#include "BinaryXML.h"
Jeff Thompsonc8963652013-06-28 20:17:43 -07008#include "BinaryXMLEncoder.h"
Jeff Thompson590b8692013-06-28 22:07:41 -07009
10enum {
11 ENCODING_LIMIT_1_BYTE = ((1 << ndn_BinaryXML_TT_VALUE_BITS) - 1),
12 ENCODING_LIMIT_2_BYTES = ((1 << (ndn_BinaryXML_TT_VALUE_BITS + ndn_BinaryXML_REGULAR_VALUE_BITS)) - 1),
13 ENCODING_LIMIT_3_BYTES = ((1 << (ndn_BinaryXML_TT_VALUE_BITS + 2 * ndn_BinaryXML_REGULAR_VALUE_BITS)) - 1)
14};
15
16/**
Jeff Thompson5a984832013-07-01 19:28:27 -070017 * Call ndn_DynamicUCharArray_ensureLength to ensure that there is enough room in the output, and copy
18 * array to the output. This does not write a header.
19 * @param self pointer to the ndn_BinaryXMLEncoder struct
20 * @param array the array to copy
21 * @param arrayLength the length of the array
Jeff Thompson8b666002013-07-08 01:16:26 -070022 * @return 0 for success, else an error code
Jeff Thompson5a984832013-07-01 19:28:27 -070023 */
Jeff Thompson8b666002013-07-08 01:16:26 -070024static ndn_Error writeArray(struct ndn_BinaryXMLEncoder *self, unsigned char *array, unsigned int arrayLength)
Jeff Thompson5a984832013-07-01 19:28:27 -070025{
Jeff Thompson8b666002013-07-08 01:16:26 -070026 ndn_Error error;
Jeff Thompson5a984832013-07-01 19:28:27 -070027 if (error = ndn_DynamicUCharArray_ensureLength(&self->output, self->offset + arrayLength))
28 return error;
29
30 ndn_memcpy(self->output.array + self->offset, array, arrayLength);
31 self->offset += arrayLength;
32
33 return 0;
34}
35
36/**
Jeff Thompson590b8692013-06-28 22:07:41 -070037 * Return the number of bytes to encode a header of value x.
38 */
39static unsigned int getNEncodingBytes(unsigned int x)
40{
41 // Do a quick check for pre-compiled results.
42 if (x <= ENCODING_LIMIT_1_BYTE)
43 return 1;
44 if (x <= ENCODING_LIMIT_2_BYTES)
45 return 2;
46 if (x <= ENCODING_LIMIT_3_BYTES)
47 return 3;
48
49 unsigned int nBytes = 1;
50
51 // Last byte gives you TT_VALUE_BITS.
52 // Remainder each gives you REGULAR_VALUE_BITS.
53 x >>= ndn_BinaryXML_TT_VALUE_BITS;
54 while (x != 0) {
55 ++nBytes;
56 x >>= ndn_BinaryXML_REGULAR_VALUE_BITS;
57 }
58
59 return nBytes;
60}
Jeff Thompson433e6da2013-07-01 15:09:00 -070061
Jeff Thompson8b666002013-07-08 01:16:26 -070062ndn_Error ndn_BinaryXMLEncoder_encodeTypeAndValue(struct ndn_BinaryXMLEncoder *self, unsigned int type, unsigned int value)
Jeff Thompson433e6da2013-07-01 15:09:00 -070063{
64 if (type > ndn_BinaryXML_UDATA)
Jeff Thompson8b666002013-07-08 01:16:26 -070065 return NDN_ERROR_header_type_is_out_of_range;
Jeff Thompson433e6da2013-07-01 15:09:00 -070066
67 // Encode backwards. Calculate how many bytes we need.
68 unsigned int nEncodingBytes = getNEncodingBytes(value);
Jeff Thompson8b666002013-07-08 01:16:26 -070069 ndn_Error error;
Jeff Thompson433e6da2013-07-01 15:09:00 -070070 if (error = ndn_DynamicUCharArray_ensureLength(&self->output, self->offset + nEncodingBytes))
71 return error;
72
73 // Bottom 4 bits of value go in last byte with tag.
74 self->output.array[self->offset + nEncodingBytes - 1] =
75 (ndn_BinaryXML_TT_MASK & type |
76 ((ndn_BinaryXML_TT_VALUE_MASK & value) << ndn_BinaryXML_TT_BITS)) |
77 ndn_BinaryXML_TT_FINAL; // set top bit for last byte
78 value >>= ndn_BinaryXML_TT_VALUE_BITS;
79
80 // Rest of value goes into preceding bytes, 7 bits per byte. (Zero top bit is "more" flag.)
81 unsigned int i = self->offset + nEncodingBytes - 2;
82 while (value != 0 && i >= self->offset) {
83 self->output.array[i] = (value & ndn_BinaryXML_REGULAR_VALUE_MASK);
84 value >>= ndn_BinaryXML_REGULAR_VALUE_BITS;
85 --i;
86 }
87 if (value != 0)
88 // This should not happen if getNEncodingBytes is correct.
Jeff Thompson8b666002013-07-08 01:16:26 -070089 return NDN_ERROR_encodeTypeAndValue_miscalculated_N_encoding_bytes;
Jeff Thompson433e6da2013-07-01 15:09:00 -070090
91 self->offset+= nEncodingBytes;
92
93 return 0;
94}
Jeff Thompson5a984832013-07-01 19:28:27 -070095
Jeff Thompson8b666002013-07-08 01:16:26 -070096ndn_Error ndn_BinaryXMLEncoder_writeElementClose(struct ndn_BinaryXMLEncoder *self)
Jeff Thompson5a984832013-07-01 19:28:27 -070097{
Jeff Thompson8b666002013-07-08 01:16:26 -070098 ndn_Error error;
Jeff Thompson5a984832013-07-01 19:28:27 -070099 if (error = ndn_DynamicUCharArray_ensureLength(&self->output, self->offset + 1))
100 return error;
101
102 self->output.array[self->offset] = ndn_BinaryXML_CLOSE;
103 self->offset += 1;
104
105 return 0;
106}
107
Jeff Thompson8b666002013-07-08 01:16:26 -0700108ndn_Error ndn_BinaryXMLEncoder_writeBlob(struct ndn_BinaryXMLEncoder *self, unsigned char *value, unsigned int valueLength)
Jeff Thompson5a984832013-07-01 19:28:27 -0700109{
Jeff Thompson8b666002013-07-08 01:16:26 -0700110 ndn_Error error;
Jeff Thompson5a984832013-07-01 19:28:27 -0700111 if (error = ndn_BinaryXMLEncoder_encodeTypeAndValue(self, ndn_BinaryXML_BLOB, valueLength))
112 return error;
113
114 if (error = writeArray(self, value, valueLength))
115 return error;
116
117 return 0;
118}
119
Jeff Thompson8b666002013-07-08 01:16:26 -0700120ndn_Error ndn_BinaryXMLEncoder_writeBlobDTagElement(struct ndn_BinaryXMLEncoder *self, unsigned int tag, unsigned char *value, unsigned int valueLength)
Jeff Thompson5a984832013-07-01 19:28:27 -0700121{
Jeff Thompson8b666002013-07-08 01:16:26 -0700122 ndn_Error error;
Jeff Thompson5a984832013-07-01 19:28:27 -0700123 if (error = ndn_BinaryXMLEncoder_writeElementStartDTag(self, tag))
124 return error;
125
126 if (error = ndn_BinaryXMLEncoder_writeBlob(self, value, valueLength))
127 return error;
128
129 if (error = ndn_BinaryXMLEncoder_writeElementClose(self))
130 return error;
131
132 return 0;
133}