blob: cf357417063d65615f9dc24fa3a433c62c84bcff [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
22 * @return 0 for success, else an error string
23 */
24static char *writeArray(struct ndn_BinaryXMLEncoder *self, unsigned char *array, unsigned int arrayLength)
25{
26 char *error;
27 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
62char *ndn_BinaryXMLEncoder_encodeTypeAndValue(struct ndn_BinaryXMLEncoder *self, unsigned int type, unsigned int value)
63{
64 if (type > ndn_BinaryXML_UDATA)
65 return "ndn_BinaryXMLEncoder_encodeTypeAndValue: type is out of range";
66
67 // Encode backwards. Calculate how many bytes we need.
68 unsigned int nEncodingBytes = getNEncodingBytes(value);
69 char *error;
70 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.
89 return "ndn_BinaryXMLEncoder_encodeTypeAndValue: : miscalculated N encoding bytes";
90
91 self->offset+= nEncodingBytes;
92
93 return 0;
94}
Jeff Thompson5a984832013-07-01 19:28:27 -070095
96char *ndn_BinaryXMLEncoder_writeElementClose(struct ndn_BinaryXMLEncoder *self)
97{
98 char *error;
99 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
108char *ndn_BinaryXMLEncoder_writeBlob(struct ndn_BinaryXMLEncoder *self, unsigned char *value, unsigned int valueLength)
109{
110 char *error;
111 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
120char *ndn_BinaryXMLEncoder_writeBlobDTagElement(struct ndn_BinaryXMLEncoder *self, unsigned int tag, unsigned char *value, unsigned int valueLength)
121{
122 char *error;
123 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}