blob: fba9ff604fa3045f1999a81bcdc46771787dc7c2 [file] [log] [blame]
Wentao Shangbd63e462012-12-03 16:19:33 -08001/**
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 *
Jeff Thompson146d7de2012-11-17 16:15:28 -08004 * @author: Meki Cheraoui
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(){
Jeff Thompsonc92706b2012-11-11 19:12:58 -080044 this.ostream = new Uint8Array(10000);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070045 this.offset =0;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070046 this.CODEC_NAME = "Binary";
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070047};
48
Jeff Thompsond24dad32012-11-18 18:19:28 -080049/*
50 * Encode utf8Content as utf8.
51 */
Jeff Thompsonc92706b2012-11-11 19:12:58 -080052BinaryXMLEncoder.prototype.writeUString = function(/*String*/ utf8Content) {
Jeff Thompsond15aa7b2012-11-17 15:17:24 -080053 this.encodeUString(utf8Content, XML_UDATA);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070054};
55
Jeff Thompsonc92706b2012-11-11 19:12:58 -080056
57BinaryXMLEncoder.prototype.writeBlob = function(
58 /*Uint8Array*/ binaryContent
Jeff Thompsonc92706b2012-11-11 19:12:58 -080059 ) {
Meki Cherkaouiabb973b2012-05-09 14:25:57 -070060
61 if(LOG >3) console.log(binaryContent);
62
Jeff Thompsond15aa7b2012-11-17 15:17:24 -080063 this.encodeBlob(binaryContent, binaryContent.length);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070064};
65
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070066
Jeff Thompsonc92706b2012-11-11 19:12:58 -080067BinaryXMLEncoder.prototype.writeStartElement = function(
68 /*String*/ tag,
69 /*TreeMap<String,String>*/ attributes
70 ) {
71
Jeff Thompsond15aa7b2012-11-17 15:17:24 -080072 /*Long*/ var dictionaryVal = tag; //stringToTag(tag);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070073
74 if (null == dictionaryVal) {
Jeff Thompsond15aa7b2012-11-17 15:17:24 -080075 this.encodeUString(tag, XML_TAG);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070076 } else {
Jeff Thompsond15aa7b2012-11-17 15:17:24 -080077 this.encodeTypeAndVal(XML_DTAG, dictionaryVal);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070078 }
79
80 if (null != attributes) {
81 this.writeAttributes(attributes);
82 }
83};
84
85
Jeff Thompsonc92706b2012-11-11 19:12:58 -080086BinaryXMLEncoder.prototype.writeEndElement = function() {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070087 this.ostream[this.offset] = XML_CLOSE;
Jeff Thompsonc92706b2012-11-11 19:12:58 -080088 this.offset += 1;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070089}
90
Jeff Thompsonc92706b2012-11-11 19:12:58 -080091
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070092BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070093 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.
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800109 this.encodeUString(strAttr, XML_ATTR);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700110 } else {
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800111 this.encodeTypeAndVal(XML_DATTR, dictionaryAttr);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700112 }
113 // Write value
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800114 this.encodeUString(strValue);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700115
116 }
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700117}
118
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800119
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700120//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
Jeff Thompsond24dad32012-11-18 18:19:28 -0800144/*
145 * If Content is a string, then encode as utf8 and write UDATA.
146 */
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700147BinaryXMLEncoder.prototype.writeElement = function(
148 //long
149 tag,
150 //byte[]
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700151 Content,
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700152 //TreeMap<String, String>
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800153 attributes
154 ) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700155 this.writeStartElement(tag, attributes);
156 // Will omit if 0-length
157
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700158 if(typeof Content === 'number') {
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800159 if(LOG>4) console.log('GOING TO WRITE THE NUMBER .charCodeAt(0) ' + Content.toString().charCodeAt(0) );
160 if(LOG>4) console.log('GOING TO WRITE THE NUMBER ' + Content.toString() );
161 if(LOG>4) console.log('type of number is ' + typeof Content.toString() );
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700162
163 this.writeUString(Content.toString());
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700164 //whatever
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700165 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700166 else if(typeof Content === 'string'){
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800167 if(LOG>4) console.log('GOING TO WRITE THE STRING ' + Content );
168 if(LOG>4) console.log('type of STRING is ' + typeof Content );
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700169
170 this.writeUString(Content);
171 }
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700172 else{
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800173 if(LOG>4) console.log('GOING TO WRITE A BLOB ' + Content );
174
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700175 this.writeBlob(Content);
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700176 }
177
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700178 this.writeEndElement();
179}
180
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800181
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700182
183var TypeAndVal = function TypeAndVal(_type,_val) {
184 this.type = _type;
185 this.val = _val;
186
187};
188
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800189
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700190BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
191 //int
192 type,
193 //long
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800194 val
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800195 ) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700196
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800197 if(LOG>4) console.log('Encoding type '+ type+ ' and value '+ val);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700198
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800199 if(LOG>4) console.log('OFFSET IS ' + this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700200
201 if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
Jeff Thompson34a2ec02012-09-29 21:47:05 -0700202 throw new Error("Tag and value must be positive, and tag valid.");
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700203 }
204
205 // Encode backwards. Calculate how many bytes we need:
206 var numEncodingBytes = this.numEncodingBytes(val);
207
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800208 if ((this.offset + numEncodingBytes) > this.ostream.length) {
209 throw new Error("Buffer space of " + (this.ostream.length - this.offset) +
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700210 " bytes insufficient to hold " +
211 numEncodingBytes + " of encoded type and value.");
212 }
213
214 // Bottom 4 bits of val go in last byte with tag.
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800215 this.ostream[this.offset + numEncodingBytes - 1] =
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700216 //(byte)
217 (BYTE_MASK &
218 (((XML_TT_MASK & type) |
219 ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
220 XML_TT_NO_MORE); // set top bit for last byte
221 val = val >>> XML_TT_VAL_BITS;;
222
223 // Rest of val goes into preceding bytes, 7 bits per byte, top bit
224 // is "more" flag.
225 var i = this.offset + numEncodingBytes - 2;
226 while ((0 != val) && (i >= this.offset)) {
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800227 this.ostream[i] = //(byte)
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800228 (BYTE_MASK & (val & XML_REG_VAL_MASK)); // leave top bit unset
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700229 val = val >>> XML_REG_VAL_BITS;
230 --i;
231 }
232 if (val != 0) {
Jeff Thompson34a2ec02012-09-29 21:47:05 -0700233 throw new Error( "This should not happen: miscalculated encoding");
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700234 //Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
235 }
236 this.offset+= numEncodingBytes;
237
238 return numEncodingBytes;
239};
240
Jeff Thompsond24dad32012-11-18 18:19:28 -0800241/*
242 * Encode ustring as utf8.
243 */
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700244BinaryXMLEncoder.prototype.encodeUString = function(
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700245 //String
246 ustring,
247 //byte
248 type) {
249
Jeff Thompsond24dad32012-11-18 18:19:28 -0800250 if (null == ustring)
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700251 return;
Jeff Thompsond24dad32012-11-18 18:19:28 -0800252 if (type == XML_TAG || type == XML_ATTR && ustring.length == 0)
253 return;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700254
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700255 if(LOG>3) console.log("The string to write is ");
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700256 if(LOG>3) console.log(ustring);
257
Jeff Thompsond24dad32012-11-18 18:19:28 -0800258 var strBytes = DataUtils.stringToUtf8Array(ustring);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700259
260 this.encodeTypeAndVal(type,
261 (((type == XML_TAG) || (type == XML_ATTR)) ?
262 (strBytes.length-1) :
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800263 strBytes.length));
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700264
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700265 if(LOG>3) console.log("THE string to write is ");
266
267 if(LOG>3) console.log(strBytes);
268
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700269 this.writeString(strBytes,this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700270 this.offset+= strBytes.length;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700271};
272
273
274
275BinaryXMLEncoder.prototype.encodeBlob = function(
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800276 //Uint8Array
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700277 blob,
278 //int
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700279 length) {
280
281
Jeff Thompson84ca9502012-11-04 13:11:36 -0800282 if (null == blob)
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700283 return;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700284
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700285 if(LOG>4) console.log('LENGTH OF XML_BLOB IS '+length);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700286
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800287 /*blobCopy = new Array(blob.Length);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700288
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800289 for (i = 0; i < blob.length; i++) //in InStr.ToCharArray())
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700290 {
291 blobCopy[i] = blob[i];
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800292 }*/
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700293
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800294 this.encodeTypeAndVal(XML_BLOB, length);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700295
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800296 this.writeBlobArray(blob, this.offset);
297 this.offset += length;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700298};
299
300var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
301var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
302var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
303
304BinaryXMLEncoder.prototype.numEncodingBytes = function(
305 //long
306 x) {
307 if (x <= ENCODING_LIMIT_1_BYTE) return (1);
308 if (x <= ENCODING_LIMIT_2_BYTES) return (2);
309 if (x <= ENCODING_LIMIT_3_BYTES) return (3);
310
311 var numbytes = 1;
312
313 // Last byte gives you XML_TT_VAL_BITS
314 // Remainder each give you XML_REG_VAL_BITS
315 x = x >>> XML_TT_VAL_BITS;
316 while (x != 0) {
317 numbytes++;
318 x = x >>> XML_REG_VAL_BITS;
319 }
320 return (numbytes);
321};
322
323BinaryXMLEncoder.prototype.writeDateTime = function(
324 //String
325 tag,
326 //CCNTime
327 dateTime) {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700328
329 if(LOG>4)console.log('ENCODING DATE with LONG VALUE');
330 if(LOG>4)console.log(dateTime.msec);
331
332 //var binarydate = DataUtils.unsignedLongToByteArray( Math.round((dateTime.msec/1000) * 4096) );
333
334
335 //parse to hex
336 var binarydate = Math.round((dateTime.msec/1000) * 4096).toString(16) ;
337
338 //HACK
339 var binarydate = DataUtils.toNumbers( '0'.concat(binarydate,'0')) ;
340
341
342 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE');
343 if(LOG>4)console.log(binarydate);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700344 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE(HEX)');
345 if(LOG>4)console.log(DataUtils.toHex(binarydate));
346
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700347 this.writeElement(tag, binarydate);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700348};
349
350BinaryXMLEncoder.prototype.writeString = function(
351 //String
352 input,
353 //CCNTime
354 offset) {
355
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700356 if(typeof input === 'string'){
357 //console.log('went here');
358 if(LOG>4) console.log('GOING TO WRITE A STRING');
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700359 if(LOG>4) console.log(input);
360
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800361 for (i = 0; i < input.length; i++) {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700362 if(LOG>4) console.log('input.charCodeAt(i)=' + input.charCodeAt(i));
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700363 this.ostream[this.offset+i] = (input.charCodeAt(i));
364 }
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700365 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700366 else{
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800367 if(LOG>4) console.log('GOING TO WRITE A STRING IN BINARY FORM');
368 if(LOG>4) console.log(input);
369
370 this.writeBlobArray(input);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700371 }
372 /*
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700373 else if(typeof input === 'object'){
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700374
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700375 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700376 */
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700377};
378
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800379
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700380BinaryXMLEncoder.prototype.writeBlobArray = function(
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800381 //Uint8Array
382 blob,
383 //int
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700384 offset) {
385
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700386 if(LOG>4) console.log('GOING TO WRITE A BLOB');
387
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800388 /*for (var i = 0; i < Blob.length; i++) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700389 this.ostream[this.offset+i] = Blob[i];
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800390 }*/
391 this.ostream.set(blob, this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700392};
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700393
394
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700395BinaryXMLEncoder.prototype.getReducedOstream = function() {
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800396 return this.ostream.subarray(0, this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700397};
398