blob: 5f67fea19d9e73818812c621b6c486943201d837 [file] [log] [blame]
Meki Cherkaouif441d3a2012-04-22 15:17:52 -07001/*
Jeff Thompsone6923bf2012-10-14 09:47:42 -07002 * This class is used to encode ccnb binary elements (blob, type/value pairs).
Meki Cherkaouif441d3a2012-04-22 15:17:52 -07003 *
4 * @author: ucla-cs
Jeff Thompson745026e2012-10-13 12:49:20 -07005 * See COPYING for copyright and distribution information.
Meki Cherkaouif441d3a2012-04-22 15:17:52 -07006 */
7
8var XML_EXT = 0x00;
9
10var XML_TAG = 0x01;
11
12var XML_DTAG = 0x02;
13
14var XML_ATTR = 0x03;
15
16var XML_DATTR = 0x04;
17
18var XML_BLOB = 0x05;
19
20var XML_UDATA = 0x06;
21
22var XML_CLOSE = 0x0;
23
24var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
Meki Cherkaouiabb973b2012-05-09 14:25:57 -070025
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070026
27var XML_TT_BITS = 3;
28var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
29var XML_TT_VAL_BITS = XML_TT_BITS + 1;
30var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
31var XML_REG_VAL_BITS = 7;
32var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
33var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
34var BYTE_MASK = 0xFF;
35var LONG_BYTES = 8;
36var LONG_BITS = 64;
37
38var bits_11 = 0x0000007FF;
39var bits_18 = 0x00003FFFF;
40var bits_32 = 0x0FFFFFFFF;
41
42
43var BinaryXMLEncoder = function BinaryXMLEncoder(){
44
45 this.ostream = new Array(10000);
46
47
48 this.offset =0;
49
50 this.CODEC_NAME = "Binary";
51
52};
53
54BinaryXMLEncoder.prototype.writeUString = function(/*String*/ utf8Content){
Meki Cherkaoui8f173612012-06-06 01:05:40 -070055 this.encodeUString(this.ostream, utf8Content, XML_UDATA);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070056};
57
58BinaryXMLEncoder.prototype.writeBlob = function(/*byte []*/ binaryContent
59 //, /*int*/ offset, /*int*/ length
60 ) {
Meki Cherkaouiabb973b2012-05-09 14:25:57 -070061
62 if(LOG >3) console.log(binaryContent);
63
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070064 this.encodeBlob(this.ostream, binaryContent, this.offset, binaryContent.length);
65};
66
67BinaryXMLEncoder.prototype.writeStartElement = function(/*String*/ tag, /*TreeMap<String,String>*/ attributes){
68
69 /*Long*/ dictionaryVal = tag;//stringToTag(tag);
70
71 if (null == dictionaryVal) {
72
73 this.encodeUString(this.ostream, tag, XML_TAG);
74
75 } else {
76 this.encodeTypeAndVal(XML_DTAG, dictionaryVal, this.ostream);
77 }
78
79 if (null != attributes) {
80 this.writeAttributes(attributes);
81 }
82};
83
84
85BinaryXMLEncoder.prototype.writeEndElement = function(){
86
87 this.ostream[this.offset] = XML_CLOSE;
88 this.offset+= 1;
89}
90
91BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
92
93 if (null == attributes) {
94 return;
95 }
96
97 // the keySet of a TreeMap is sorted.
98
99 for(var i=0; i<attributes.length;i++){
100 var strAttr = attributes[i].k;
101 var strValue = attributes[i].v;
102
103 var dictionaryAttr = stringToTag(strAttr);
104 if (null == dictionaryAttr) {
105 // not in dictionary, encode as attr
106 // compressed format wants length of tag represented as length-1
107 // to save that extra bit, as tag cannot be 0 length.
108 // encodeUString knows to do that.
109 this.encodeUString(this.ostream, strAttr, XML_ATTR);
110 } else {
111 this.encodeTypeAndVal(XML_DATTR, dictionaryAttr, this.ostream);
112 }
113 // Write value
114 this.encodeUString(this.ostream, strValue);
115
116 }
117
118
119}
120
121//returns a string
122stringToTag = function(/*long*/ tagVal) {
123 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
124 return CCNProtocolDTagsStrings[tagVal];
125 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
126 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
127 }
128 return null;
129};
130
131//returns a Long
132tagToString = function(/*String*/ tagName) {
133 // the slow way, but right now we don't care.... want a static lookup for the forward direction
134 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
135 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
136 return i;
137 }
138 }
139 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
140 return CCNProtocolDTags.CCNProtocolDataUnit;
141 }
142 return null;
143};
144
145
146BinaryXMLEncoder.prototype.writeElement = function(
147 //long
148 tag,
149 //byte[]
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700150 Content,
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700151 //TreeMap<String, String>
152 attributes) {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700153
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700154 this.writeStartElement(tag, attributes);
155 // Will omit if 0-length
156
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700157 if(typeof Content === 'number') {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700158 if(LOG>4) console.log('GOING TO WRITE THE NUMBER .charCodeAt(0) ' +Content.toString().charCodeAt(0) );
159 if(LOG>4) console.log('GOING TO WRITE THE NUMBER ' +Content.toString() );
160 if(LOG>4) console.log('type of number is ' +typeof Content.toString() );
161
162
163
164 this.writeUString(Content.toString());
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700165 //whatever
166
167 }
168
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700169 else if(typeof Content === 'string'){
170 if(LOG>4) console.log('GOING TO WRITE THE STRING ' +Content );
171 if(LOG>4) console.log('type of STRING is ' +typeof Content );
172
173 this.writeUString(Content);
174 }
175
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700176 else{
177 //else if(typeof Content === 'string'){
Meki Cherkaouib21911b2012-05-18 16:54:37 -0700178 //console.log('went here');
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700179 //this.writeBlob(Content);
180 //}
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700181 if(LOG>4) console.log('GOING TO WRITE A BLOB ' +Content );
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700182 //else if(typeof Content === 'object'){
183 this.writeBlob(Content);
184 //}
185 }
186
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700187 this.writeEndElement();
188}
189
190//TODO
191
192var TypeAndVal = function TypeAndVal(_type,_val) {
193 this.type = _type;
194 this.val = _val;
195
196};
197
198BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
199 //int
200 type,
201 //long
202 val,
203 //byte []
204 buf) {
205
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700206 if(LOG>4)console.log('Encoding type '+ type+ ' and value '+ val);
207
208 if(LOG>4) console.log('OFFSET IS ' + this.offset );
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700209
210 if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
Jeff Thompson34a2ec02012-09-29 21:47:05 -0700211 throw new Error("Tag and value must be positive, and tag valid.");
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700212 }
213
214 // Encode backwards. Calculate how many bytes we need:
215 var numEncodingBytes = this.numEncodingBytes(val);
216
217 if ((this.offset + numEncodingBytes) > buf.length) {
Jeff Thompson34a2ec02012-09-29 21:47:05 -0700218 throw new Error("Buffer space of " + (buf.length-this.offset) +
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700219 " bytes insufficient to hold " +
220 numEncodingBytes + " of encoded type and value.");
221 }
222
223 // Bottom 4 bits of val go in last byte with tag.
224 buf[this.offset + numEncodingBytes - 1] =
225 //(byte)
226 (BYTE_MASK &
227 (((XML_TT_MASK & type) |
228 ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
229 XML_TT_NO_MORE); // set top bit for last byte
230 val = val >>> XML_TT_VAL_BITS;;
231
232 // Rest of val goes into preceding bytes, 7 bits per byte, top bit
233 // is "more" flag.
234 var i = this.offset + numEncodingBytes - 2;
235 while ((0 != val) && (i >= this.offset)) {
236 buf[i] = //(byte)
237 (BYTE_MASK &
238 (val & XML_REG_VAL_MASK)); // leave top bit unset
239 val = val >>> XML_REG_VAL_BITS;
240 --i;
241 }
242 if (val != 0) {
Jeff Thompson34a2ec02012-09-29 21:47:05 -0700243 throw new Error( "This should not happen: miscalculated encoding");
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700244 //Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
245 }
246 this.offset+= numEncodingBytes;
247
248 return numEncodingBytes;
249};
250
251BinaryXMLEncoder.prototype.encodeUString = function(
252 //OutputStream
253 ostream,
254 //String
255 ustring,
256 //byte
257 type) {
258
259 if ((null == ustring) || (ustring.length == 0)) {
260 return;
261 }
262
263
264 //byte [] data utils
265 /*custom*/
266 //byte[]
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700267
268 if(LOG>3) console.log("The string to write is ");
269
270 if(LOG>3) console.log(ustring);
271
272 //COPY THE STRING TO AVOID PROBLEMS
273 strBytes = new Array(ustring.length);
274
275 var i = 0;
276
277 for( ; i<ustring.length; i++) //in InStr.ToCharArray())
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700278 {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700279 if(LOG>3)console.log("ustring[" + i + '] = ' + ustring[i]);
280 strBytes[i] = ustring.charCodeAt(i);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700281 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700282
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700283 //strBytes = DataUtils.getBytesFromUTF8String(ustring);
284
285 this.encodeTypeAndVal(type,
286 (((type == XML_TAG) || (type == XML_ATTR)) ?
287 (strBytes.length-1) :
288 strBytes.length), ostream);
289
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700290 if(LOG>3) console.log("THE string to write is ");
291
292 if(LOG>3) console.log(strBytes);
293
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700294 this.writeString(strBytes,this.offset);
295
296 this.offset+= strBytes.length;
297
298};
299
300
301
302BinaryXMLEncoder.prototype.encodeBlob = function(
303 //OutputStream
304 ostream,
305 //byte []
306 blob,
307 //int
308 offset,
309 //int
310 length) {
311
312
313 if ((null == blob) || (length == 0)) {
314
315 return;
316 }
317
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700318 if(LOG>4) console.log('LENGTH OF XML_BLOB IS '+length);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700319
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700320
321 blobCopy = new Array(blob.Length);
322 var i = 0;
323 for( ;i<blob.length;i++) //in InStr.ToCharArray())
324 {
325 blobCopy[i] = blob[i];
326 }
327
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700328 this.encodeTypeAndVal(XML_BLOB, length, ostream,offset);
329
330 if (null != blob) {
331
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700332 this.writeBlobArray(blobCopy,this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700333 this.offset += length;
334 }
335};
336
337var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
338var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
339var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
340
341BinaryXMLEncoder.prototype.numEncodingBytes = function(
342 //long
343 x) {
344 if (x <= ENCODING_LIMIT_1_BYTE) return (1);
345 if (x <= ENCODING_LIMIT_2_BYTES) return (2);
346 if (x <= ENCODING_LIMIT_3_BYTES) return (3);
347
348 var numbytes = 1;
349
350 // Last byte gives you XML_TT_VAL_BITS
351 // Remainder each give you XML_REG_VAL_BITS
352 x = x >>> XML_TT_VAL_BITS;
353 while (x != 0) {
354 numbytes++;
355 x = x >>> XML_REG_VAL_BITS;
356 }
357 return (numbytes);
358};
359
360BinaryXMLEncoder.prototype.writeDateTime = function(
361 //String
362 tag,
363 //CCNTime
364 dateTime) {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700365
366 if(LOG>4)console.log('ENCODING DATE with LONG VALUE');
367 if(LOG>4)console.log(dateTime.msec);
368
369 //var binarydate = DataUtils.unsignedLongToByteArray( Math.round((dateTime.msec/1000) * 4096) );
370
371
372 //parse to hex
373 var binarydate = Math.round((dateTime.msec/1000) * 4096).toString(16) ;
374
375 //HACK
376 var binarydate = DataUtils.toNumbers( '0'.concat(binarydate,'0')) ;
377
378
379 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE');
380 if(LOG>4)console.log(binarydate);
381
382 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE(HEX)');
383 if(LOG>4)console.log(DataUtils.toHex(binarydate));
384
385
386 this.writeElement(tag, binarydate);
387
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700388};
389
390BinaryXMLEncoder.prototype.writeString = function(
391 //String
392 input,
393 //CCNTime
394 offset) {
395
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700396 if(typeof input === 'string'){
397 //console.log('went here');
398 if(LOG>4) console.log('GOING TO WRITE A STRING');
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700399 if(LOG>4) console.log(input);
400
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700401 for (var i = 0; i < input.length; i++) {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700402 if(LOG>4) console.log('input.charCodeAt(i)=' + input.charCodeAt(i));
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700403 this.ostream[this.offset+i] = (input.charCodeAt(i));
404 }
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700405 }
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700406
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700407 else{
408
409 if(LOG>4) console.log('GOING TO WRITE A STRING IN BINARY FORM');
410 if(LOG>4) console.log(input);
411
412 this.writeBlobArray(input);
413
414 }
415 /*
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700416 else if(typeof input === 'object'){
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700417
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700418 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700419 */
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700420};
421
422BinaryXMLEncoder.prototype.writeBlobArray = function(
423 //String
424 Blob,
425 //CCNTime
426 offset) {
427
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700428 if(LOG>4) console.log('GOING TO WRITE A BLOB');
429
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700430 for (var i = 0; i < Blob.length; i++) {
431 this.ostream[this.offset+i] = Blob[i];
432 }
433
434};
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700435
436
437
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700438BinaryXMLEncoder.prototype.getReducedOstream = function() {
439
440 return this.ostream.slice(0,this.offset);
441
442};
443