blob: 74048023494931758e2ad79cc8320e80531d3fcb [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;
Meki Cherkaouiabb973b2012-05-09 14:25:57 -070024
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070025
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){
Meki Cherkaoui8f173612012-06-06 01:05:40 -070054 this.encodeUString(this.ostream, utf8Content, XML_UDATA);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070055};
56
57BinaryXMLEncoder.prototype.writeBlob = function(/*byte []*/ binaryContent
58 //, /*int*/ offset, /*int*/ length
59 ) {
Meki Cherkaouiabb973b2012-05-09 14:25:57 -070060
61 if(LOG >3) console.log(binaryContent);
62
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070063 this.encodeBlob(this.ostream, binaryContent, this.offset, binaryContent.length);
64};
65
66BinaryXMLEncoder.prototype.writeStartElement = function(/*String*/ tag, /*TreeMap<String,String>*/ attributes){
67
68 /*Long*/ dictionaryVal = tag;//stringToTag(tag);
69
70 if (null == dictionaryVal) {
71
72 this.encodeUString(this.ostream, tag, XML_TAG);
73
74 } else {
75 this.encodeTypeAndVal(XML_DTAG, dictionaryVal, this.ostream);
76 }
77
78 if (null != attributes) {
79 this.writeAttributes(attributes);
80 }
81};
82
83
84BinaryXMLEncoder.prototype.writeEndElement = function(){
85
86 this.ostream[this.offset] = XML_CLOSE;
87 this.offset+= 1;
88}
89
90BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
91
92 if (null == attributes) {
93 return;
94 }
95
96 // the keySet of a TreeMap is sorted.
97
98 for(var i=0; i<attributes.length;i++){
99 var strAttr = attributes[i].k;
100 var strValue = attributes[i].v;
101
102 var dictionaryAttr = stringToTag(strAttr);
103 if (null == dictionaryAttr) {
104 // not in dictionary, encode as attr
105 // compressed format wants length of tag represented as length-1
106 // to save that extra bit, as tag cannot be 0 length.
107 // encodeUString knows to do that.
108 this.encodeUString(this.ostream, strAttr, XML_ATTR);
109 } else {
110 this.encodeTypeAndVal(XML_DATTR, dictionaryAttr, this.ostream);
111 }
112 // Write value
113 this.encodeUString(this.ostream, strValue);
114
115 }
116
117
118}
119
120//returns a string
121stringToTag = function(/*long*/ tagVal) {
122 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
123 return CCNProtocolDTagsStrings[tagVal];
124 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
125 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
126 }
127 return null;
128};
129
130//returns a Long
131tagToString = function(/*String*/ tagName) {
132 // the slow way, but right now we don't care.... want a static lookup for the forward direction
133 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
134 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
135 return i;
136 }
137 }
138 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
139 return CCNProtocolDTags.CCNProtocolDataUnit;
140 }
141 return null;
142};
143
144
145BinaryXMLEncoder.prototype.writeElement = function(
146 //long
147 tag,
148 //byte[]
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700149 Content,
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700150 //TreeMap<String, String>
151 attributes) {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700152
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700153 this.writeStartElement(tag, attributes);
154 // Will omit if 0-length
155
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700156 if(typeof Content === 'number') {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700157 if(LOG>4) console.log('GOING TO WRITE THE NUMBER .charCodeAt(0) ' +Content.toString().charCodeAt(0) );
158 if(LOG>4) console.log('GOING TO WRITE THE NUMBER ' +Content.toString() );
159 if(LOG>4) console.log('type of number is ' +typeof Content.toString() );
160
161
162
163 this.writeUString(Content.toString());
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700164 //whatever
165
166 }
167
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700168 else if(typeof Content === 'string'){
169 if(LOG>4) console.log('GOING TO WRITE THE STRING ' +Content );
170 if(LOG>4) console.log('type of STRING is ' +typeof Content );
171
172 this.writeUString(Content);
173 }
174
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700175 else{
176 //else if(typeof Content === 'string'){
Meki Cherkaouib21911b2012-05-18 16:54:37 -0700177 //console.log('went here');
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700178 //this.writeBlob(Content);
179 //}
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700180 if(LOG>4) console.log('GOING TO WRITE A BLOB ' +Content );
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700181 //else if(typeof Content === 'object'){
182 this.writeBlob(Content);
183 //}
184 }
185
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700186 this.writeEndElement();
187}
188
189//TODO
190
191var TypeAndVal = function TypeAndVal(_type,_val) {
192 this.type = _type;
193 this.val = _val;
194
195};
196
197BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
198 //int
199 type,
200 //long
201 val,
202 //byte []
203 buf) {
204
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700205 if(LOG>4)console.log('Encoding type '+ type+ ' and value '+ val);
206
207 if(LOG>4) console.log('OFFSET IS ' + this.offset );
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700208
209 if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
Jeff Thompson34a2ec02012-09-29 21:47:05 -0700210 throw new Error("Tag and value must be positive, and tag valid.");
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700211 }
212
213 // Encode backwards. Calculate how many bytes we need:
214 var numEncodingBytes = this.numEncodingBytes(val);
215
216 if ((this.offset + numEncodingBytes) > buf.length) {
Jeff Thompson34a2ec02012-09-29 21:47:05 -0700217 throw new Error("Buffer space of " + (buf.length-this.offset) +
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700218 " bytes insufficient to hold " +
219 numEncodingBytes + " of encoded type and value.");
220 }
221
222 // Bottom 4 bits of val go in last byte with tag.
223 buf[this.offset + numEncodingBytes - 1] =
224 //(byte)
225 (BYTE_MASK &
226 (((XML_TT_MASK & type) |
227 ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
228 XML_TT_NO_MORE); // set top bit for last byte
229 val = val >>> XML_TT_VAL_BITS;;
230
231 // Rest of val goes into preceding bytes, 7 bits per byte, top bit
232 // is "more" flag.
233 var i = this.offset + numEncodingBytes - 2;
234 while ((0 != val) && (i >= this.offset)) {
235 buf[i] = //(byte)
236 (BYTE_MASK &
237 (val & XML_REG_VAL_MASK)); // leave top bit unset
238 val = val >>> XML_REG_VAL_BITS;
239 --i;
240 }
241 if (val != 0) {
Jeff Thompson34a2ec02012-09-29 21:47:05 -0700242 throw new Error( "This should not happen: miscalculated encoding");
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700243 //Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
244 }
245 this.offset+= numEncodingBytes;
246
247 return numEncodingBytes;
248};
249
250BinaryXMLEncoder.prototype.encodeUString = function(
251 //OutputStream
252 ostream,
253 //String
254 ustring,
255 //byte
256 type) {
257
258 if ((null == ustring) || (ustring.length == 0)) {
259 return;
260 }
261
262
263 //byte [] data utils
264 /*custom*/
265 //byte[]
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700266
267 if(LOG>3) console.log("The string to write is ");
268
269 if(LOG>3) console.log(ustring);
270
271 //COPY THE STRING TO AVOID PROBLEMS
272 strBytes = new Array(ustring.length);
273
274 var i = 0;
275
276 for( ; i<ustring.length; i++) //in InStr.ToCharArray())
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700277 {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700278 if(LOG>3)console.log("ustring[" + i + '] = ' + ustring[i]);
279 strBytes[i] = ustring.charCodeAt(i);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700280 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700281
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700282 //strBytes = DataUtils.getBytesFromUTF8String(ustring);
283
284 this.encodeTypeAndVal(type,
285 (((type == XML_TAG) || (type == XML_ATTR)) ?
286 (strBytes.length-1) :
287 strBytes.length), ostream);
288
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700289 if(LOG>3) console.log("THE string to write is ");
290
291 if(LOG>3) console.log(strBytes);
292
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700293 this.writeString(strBytes,this.offset);
294
295 this.offset+= strBytes.length;
296
297};
298
299
300
301BinaryXMLEncoder.prototype.encodeBlob = function(
302 //OutputStream
303 ostream,
304 //byte []
305 blob,
306 //int
307 offset,
308 //int
309 length) {
310
311
312 if ((null == blob) || (length == 0)) {
313
314 return;
315 }
316
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700317 if(LOG>4) console.log('LENGTH OF XML_BLOB IS '+length);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700318
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700319
320 blobCopy = new Array(blob.Length);
321 var i = 0;
322 for( ;i<blob.length;i++) //in InStr.ToCharArray())
323 {
324 blobCopy[i] = blob[i];
325 }
326
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700327 this.encodeTypeAndVal(XML_BLOB, length, ostream,offset);
328
329 if (null != blob) {
330
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700331 this.writeBlobArray(blobCopy,this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700332 this.offset += length;
333 }
334};
335
336var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
337var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
338var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
339
340BinaryXMLEncoder.prototype.numEncodingBytes = function(
341 //long
342 x) {
343 if (x <= ENCODING_LIMIT_1_BYTE) return (1);
344 if (x <= ENCODING_LIMIT_2_BYTES) return (2);
345 if (x <= ENCODING_LIMIT_3_BYTES) return (3);
346
347 var numbytes = 1;
348
349 // Last byte gives you XML_TT_VAL_BITS
350 // Remainder each give you XML_REG_VAL_BITS
351 x = x >>> XML_TT_VAL_BITS;
352 while (x != 0) {
353 numbytes++;
354 x = x >>> XML_REG_VAL_BITS;
355 }
356 return (numbytes);
357};
358
359BinaryXMLEncoder.prototype.writeDateTime = function(
360 //String
361 tag,
362 //CCNTime
363 dateTime) {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700364
365 if(LOG>4)console.log('ENCODING DATE with LONG VALUE');
366 if(LOG>4)console.log(dateTime.msec);
367
368 //var binarydate = DataUtils.unsignedLongToByteArray( Math.round((dateTime.msec/1000) * 4096) );
369
370
371 //parse to hex
372 var binarydate = Math.round((dateTime.msec/1000) * 4096).toString(16) ;
373
374 //HACK
375 var binarydate = DataUtils.toNumbers( '0'.concat(binarydate,'0')) ;
376
377
378 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE');
379 if(LOG>4)console.log(binarydate);
380
381 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE(HEX)');
382 if(LOG>4)console.log(DataUtils.toHex(binarydate));
383
384
385 this.writeElement(tag, binarydate);
386
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700387};
388
389BinaryXMLEncoder.prototype.writeString = function(
390 //String
391 input,
392 //CCNTime
393 offset) {
394
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700395 if(typeof input === 'string'){
396 //console.log('went here');
397 if(LOG>4) console.log('GOING TO WRITE A STRING');
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700398 if(LOG>4) console.log(input);
399
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700400 for (var i = 0; i < input.length; i++) {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700401 if(LOG>4) console.log('input.charCodeAt(i)=' + input.charCodeAt(i));
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700402 this.ostream[this.offset+i] = (input.charCodeAt(i));
403 }
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700404 }
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700405
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700406 else{
407
408 if(LOG>4) console.log('GOING TO WRITE A STRING IN BINARY FORM');
409 if(LOG>4) console.log(input);
410
411 this.writeBlobArray(input);
412
413 }
414 /*
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700415 else if(typeof input === 'object'){
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700416
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700417 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700418 */
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700419};
420
421BinaryXMLEncoder.prototype.writeBlobArray = function(
422 //String
423 Blob,
424 //CCNTime
425 offset) {
426
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700427 if(LOG>4) console.log('GOING TO WRITE A BLOB');
428
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700429 for (var i = 0; i < Blob.length; i++) {
430 this.ostream[this.offset+i] = Blob[i];
431 }
432
433};
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700434
435
436
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700437BinaryXMLEncoder.prototype.getReducedOstream = function() {
438
439 return this.ostream.slice(0,this.offset);
440
441};
442