blob: c8a55f5db91943e9014151d541d80024be404f93 [file] [log] [blame]
Jeff Thompsonc8963652013-06-28 20:17:43 -07001/*
2 * Author: Jeff Thompson
3 *
4 * BSD license, See the LICENSE file for more information.
5 */
6
Jeff Thompson5a984832013-07-01 19:28:27 -07007#include "../util/ndn_memory.h"
Jeff Thompson590b8692013-06-28 22:07:41 -07008#include "BinaryXML.h"
Jeff Thompsonc8963652013-06-28 20:17:43 -07009#include "BinaryXMLEncoder.h"
Jeff Thompson590b8692013-06-28 22:07:41 -070010
11enum {
12 ENCODING_LIMIT_1_BYTE = ((1 << ndn_BinaryXML_TT_VALUE_BITS) - 1),
13 ENCODING_LIMIT_2_BYTES = ((1 << (ndn_BinaryXML_TT_VALUE_BITS + ndn_BinaryXML_REGULAR_VALUE_BITS)) - 1),
14 ENCODING_LIMIT_3_BYTES = ((1 << (ndn_BinaryXML_TT_VALUE_BITS + 2 * ndn_BinaryXML_REGULAR_VALUE_BITS)) - 1)
15};
16
17/**
Jeff Thompson5a984832013-07-01 19:28:27 -070018 * Call ndn_DynamicUCharArray_ensureLength to ensure that there is enough room in the output, and copy
19 * array to the output. This does not write a header.
20 * @param self pointer to the ndn_BinaryXMLEncoder struct
21 * @param array the array to copy
22 * @param arrayLength the length of the array
23 * @return 0 for success, else an error string
24 */
25static char *writeArray(struct ndn_BinaryXMLEncoder *self, unsigned char *array, unsigned int arrayLength)
26{
27 char *error;
28 if (error = ndn_DynamicUCharArray_ensureLength(&self->output, self->offset + arrayLength))
29 return error;
30
31 ndn_memcpy(self->output.array + self->offset, array, arrayLength);
32 self->offset += arrayLength;
33
34 return 0;
35}
36
37/**
Jeff Thompson590b8692013-06-28 22:07:41 -070038 * Return the number of bytes to encode a header of value x.
39 */
40static unsigned int getNEncodingBytes(unsigned int x)
41{
42 // Do a quick check for pre-compiled results.
43 if (x <= ENCODING_LIMIT_1_BYTE)
44 return 1;
45 if (x <= ENCODING_LIMIT_2_BYTES)
46 return 2;
47 if (x <= ENCODING_LIMIT_3_BYTES)
48 return 3;
49
50 unsigned int nBytes = 1;
51
52 // Last byte gives you TT_VALUE_BITS.
53 // Remainder each gives you REGULAR_VALUE_BITS.
54 x >>= ndn_BinaryXML_TT_VALUE_BITS;
55 while (x != 0) {
56 ++nBytes;
57 x >>= ndn_BinaryXML_REGULAR_VALUE_BITS;
58 }
59
60 return nBytes;
61}
Jeff Thompson433e6da2013-07-01 15:09:00 -070062
63char *ndn_BinaryXMLEncoder_encodeTypeAndValue(struct ndn_BinaryXMLEncoder *self, unsigned int type, unsigned int value)
64{
65 if (type > ndn_BinaryXML_UDATA)
66 return "ndn_BinaryXMLEncoder_encodeTypeAndValue: type is out of range";
67
68 // Encode backwards. Calculate how many bytes we need.
69 unsigned int nEncodingBytes = getNEncodingBytes(value);
70 char *error;
71 if (error = ndn_DynamicUCharArray_ensureLength(&self->output, self->offset + nEncodingBytes))
72 return error;
73
74 // Bottom 4 bits of value go in last byte with tag.
75 self->output.array[self->offset + nEncodingBytes - 1] =
76 (ndn_BinaryXML_TT_MASK & type |
77 ((ndn_BinaryXML_TT_VALUE_MASK & value) << ndn_BinaryXML_TT_BITS)) |
78 ndn_BinaryXML_TT_FINAL; // set top bit for last byte
79 value >>= ndn_BinaryXML_TT_VALUE_BITS;
80
81 // Rest of value goes into preceding bytes, 7 bits per byte. (Zero top bit is "more" flag.)
82 unsigned int i = self->offset + nEncodingBytes - 2;
83 while (value != 0 && i >= self->offset) {
84 self->output.array[i] = (value & ndn_BinaryXML_REGULAR_VALUE_MASK);
85 value >>= ndn_BinaryXML_REGULAR_VALUE_BITS;
86 --i;
87 }
88 if (value != 0)
89 // This should not happen if getNEncodingBytes is correct.
90 return "ndn_BinaryXMLEncoder_encodeTypeAndValue: : miscalculated N encoding bytes";
91
92 self->offset+= nEncodingBytes;
93
94 return 0;
95}
Jeff Thompson5a984832013-07-01 19:28:27 -070096
97char *ndn_BinaryXMLEncoder_writeElementClose(struct ndn_BinaryXMLEncoder *self)
98{
99 char *error;
100 if (error = ndn_DynamicUCharArray_ensureLength(&self->output, self->offset + 1))
101 return error;
102
103 self->output.array[self->offset] = ndn_BinaryXML_CLOSE;
104 self->offset += 1;
105
106 return 0;
107}
108
109char *ndn_BinaryXMLEncoder_writeBlob(struct ndn_BinaryXMLEncoder *self, unsigned char *value, unsigned int valueLength)
110{
111 char *error;
112 if (error = ndn_BinaryXMLEncoder_encodeTypeAndValue(self, ndn_BinaryXML_BLOB, valueLength))
113 return error;
114
115 if (error = writeArray(self, value, valueLength))
116 return error;
117
118 return 0;
119}
120
121char *ndn_BinaryXMLEncoder_writeBlobDTagElement(struct ndn_BinaryXMLEncoder *self, unsigned int tag, unsigned char *value, unsigned int valueLength)
122{
123 char *error;
124 if (error = ndn_BinaryXMLEncoder_writeElementStartDTag(self, tag))
125 return error;
126
127 if (error = ndn_BinaryXMLEncoder_writeBlob(self, value, valueLength))
128 return error;
129
130 if (error = ndn_BinaryXMLEncoder_writeElementClose(self))
131 return error;
132
133 return 0;
134}