blob: f05a869f1b55fb675309eefc90a11bdcf9d80c01 [file] [log] [blame]
Meki Cherkaouif441d3a2012-04-22 15:17:52 -07001/*
2 * This class is used to encode and decode binary elements ( blog, type/value pairs)
3 *
4 * @author: ucla-cs
5 */
6
7var XML_EXT = 0x00;
8
9var XML_TAG = 0x01;
10
11var XML_DTAG = 0x02;
12
13var XML_ATTR = 0x03;
14
15var XML_DATTR = 0x04;
16
17var XML_BLOB = 0x05;
18
19var XML_UDATA = 0x06;
20
21var XML_CLOSE = 0x0;
22
23var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
24
25
26var XML_TT_BITS = 3;
27var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
28var XML_TT_VAL_BITS = XML_TT_BITS + 1;
29var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
30var XML_REG_VAL_BITS = 7;
31var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
32var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
33var BYTE_MASK = 0xFF;
34var LONG_BYTES = 8;
35var LONG_BITS = 64;
36
37var bits_11 = 0x0000007FF;
38var bits_18 = 0x00003FFFF;
39var bits_32 = 0x0FFFFFFFF;
40
41
42var BinaryXMLEncoder = function BinaryXMLEncoder(){
43
44 this.ostream = new Array(10000);
45
46
47 this.offset =0;
48
49 this.CODEC_NAME = "Binary";
50
51};
52
53BinaryXMLEncoder.prototype.writeUString = function(/*String*/ utf8Content){
54 this.encodeUString(this.ostream, utf8Content);
55};
56
57BinaryXMLEncoder.prototype.writeBlob = function(/*byte []*/ binaryContent
58 //, /*int*/ offset, /*int*/ length
59 ) {
60 console.log(binaryContent);
61 this.encodeBlob(this.ostream, binaryContent, this.offset, binaryContent.length);
62};
63
64BinaryXMLEncoder.prototype.writeStartElement = function(/*String*/ tag, /*TreeMap<String,String>*/ attributes){
65
66 /*Long*/ dictionaryVal = tag;//stringToTag(tag);
67
68 if (null == dictionaryVal) {
69
70 this.encodeUString(this.ostream, tag, XML_TAG);
71
72 } else {
73 this.encodeTypeAndVal(XML_DTAG, dictionaryVal, this.ostream);
74 }
75
76 if (null != attributes) {
77 this.writeAttributes(attributes);
78 }
79};
80
81
82BinaryXMLEncoder.prototype.writeEndElement = function(){
83
84 this.ostream[this.offset] = XML_CLOSE;
85 this.offset+= 1;
86}
87
88BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
89
90 if (null == attributes) {
91 return;
92 }
93
94 // the keySet of a TreeMap is sorted.
95
96 for(var i=0; i<attributes.length;i++){
97 var strAttr = attributes[i].k;
98 var strValue = attributes[i].v;
99
100 var dictionaryAttr = stringToTag(strAttr);
101 if (null == dictionaryAttr) {
102 // not in dictionary, encode as attr
103 // compressed format wants length of tag represented as length-1
104 // to save that extra bit, as tag cannot be 0 length.
105 // encodeUString knows to do that.
106 this.encodeUString(this.ostream, strAttr, XML_ATTR);
107 } else {
108 this.encodeTypeAndVal(XML_DATTR, dictionaryAttr, this.ostream);
109 }
110 // Write value
111 this.encodeUString(this.ostream, strValue);
112
113 }
114
115
116}
117
118//returns a string
119stringToTag = function(/*long*/ tagVal) {
120 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
121 return CCNProtocolDTagsStrings[tagVal];
122 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
123 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
124 }
125 return null;
126};
127
128//returns a Long
129tagToString = function(/*String*/ tagName) {
130 // the slow way, but right now we don't care.... want a static lookup for the forward direction
131 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
132 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
133 return i;
134 }
135 }
136 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
137 return CCNProtocolDTags.CCNProtocolDataUnit;
138 }
139 return null;
140};
141
142
143BinaryXMLEncoder.prototype.writeElement = function(
144 //long
145 tag,
146 //byte[]
147 binaryContent,
148 //TreeMap<String, String>
149 attributes) {
150 this.writeStartElement(tag, attributes);
151 // Will omit if 0-length
152
153 this.writeBlob(binaryContent);
154 this.writeEndElement();
155}
156
157//TODO
158
159var TypeAndVal = function TypeAndVal(_type,_val) {
160 this.type = _type;
161 this.val = _val;
162
163};
164
165BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
166 //int
167 type,
168 //long
169 val,
170 //byte []
171 buf) {
172
173 console.log('Encoding type '+ type+ ' and value '+ val);
174
175 if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
176 throw new Exception("Tag and value must be positive, and tag valid.");
177 }
178
179 // Encode backwards. Calculate how many bytes we need:
180 var numEncodingBytes = this.numEncodingBytes(val);
181
182 if ((this.offset + numEncodingBytes) > buf.length) {
183 throw new Exception("Buffer space of " + (buf.length-this.offset) +
184 " bytes insufficient to hold " +
185 numEncodingBytes + " of encoded type and value.");
186 }
187
188 // Bottom 4 bits of val go in last byte with tag.
189 buf[this.offset + numEncodingBytes - 1] =
190 //(byte)
191 (BYTE_MASK &
192 (((XML_TT_MASK & type) |
193 ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
194 XML_TT_NO_MORE); // set top bit for last byte
195 val = val >>> XML_TT_VAL_BITS;;
196
197 // Rest of val goes into preceding bytes, 7 bits per byte, top bit
198 // is "more" flag.
199 var i = this.offset + numEncodingBytes - 2;
200 while ((0 != val) && (i >= this.offset)) {
201 buf[i] = //(byte)
202 (BYTE_MASK &
203 (val & XML_REG_VAL_MASK)); // leave top bit unset
204 val = val >>> XML_REG_VAL_BITS;
205 --i;
206 }
207 if (val != 0) {
208 throw new Exception( "This should not happen: miscalculated encoding");
209 //Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
210 }
211 this.offset+= numEncodingBytes;
212
213 return numEncodingBytes;
214};
215
216BinaryXMLEncoder.prototype.encodeUString = function(
217 //OutputStream
218 ostream,
219 //String
220 ustring,
221 //byte
222 type) {
223
224 if ((null == ustring) || (ustring.length == 0)) {
225 return;
226 }
227
228
229 //byte [] data utils
230 /*custom*/
231 //byte[]
232 strBytes = new Array(ustring.Length);
233 var i = 0;
234 for( ;i<ustring.lengh;i++) //in InStr.ToCharArray())
235 {
236 strBytes[i] = ustring[i];
237 }
238 //strBytes = DataUtils.getBytesFromUTF8String(ustring);
239
240 this.encodeTypeAndVal(type,
241 (((type == XML_TAG) || (type == XML_ATTR)) ?
242 (strBytes.length-1) :
243 strBytes.length), ostream);
244
245
246 this.writeString(strBytes,this.offset);
247
248 this.offset+= strBytes.length;
249
250};
251
252
253
254BinaryXMLEncoder.prototype.encodeBlob = function(
255 //OutputStream
256 ostream,
257 //byte []
258 blob,
259 //int
260 offset,
261 //int
262 length) {
263
264
265 if ((null == blob) || (length == 0)) {
266
267 return;
268 }
269
270
271 this.encodeTypeAndVal(XML_BLOB, length, ostream,offset);
272
273 if (null != blob) {
274
275 this.writeString(blob,this.offset);
276 this.offset += length;
277 }
278};
279
280var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
281var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
282var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
283
284BinaryXMLEncoder.prototype.numEncodingBytes = function(
285 //long
286 x) {
287 if (x <= ENCODING_LIMIT_1_BYTE) return (1);
288 if (x <= ENCODING_LIMIT_2_BYTES) return (2);
289 if (x <= ENCODING_LIMIT_3_BYTES) return (3);
290
291 var numbytes = 1;
292
293 // Last byte gives you XML_TT_VAL_BITS
294 // Remainder each give you XML_REG_VAL_BITS
295 x = x >>> XML_TT_VAL_BITS;
296 while (x != 0) {
297 numbytes++;
298 x = x >>> XML_REG_VAL_BITS;
299 }
300 return (numbytes);
301};
302
303BinaryXMLEncoder.prototype.writeDateTime = function(
304 //String
305 tag,
306 //CCNTime
307 dateTime) {
308 this.writeElement(tag, dateTime.toBinaryTime());
309};
310
311BinaryXMLEncoder.prototype.writeString = function(
312 //String
313 input,
314 //CCNTime
315 offset) {
316
317
318 for (var i = 0; i < input.length; i++) {
319 this.ostream[this.offset+i] = (input.charCodeAt(i));
320 }
321
322};
323
324BinaryXMLEncoder.prototype.writeBlobArray = function(
325 //String
326 Blob,
327 //CCNTime
328 offset) {
329
330 for (var i = 0; i < Blob.length; i++) {
331 this.ostream[this.offset+i] = Blob[i];
332 }
333
334};
335BinaryXMLEncoder.prototype.getReducedOstream = function() {
336
337 return this.ostream.slice(0,this.offset);
338
339};
340