blob: de03875e0eaffc14b239fe6c19028dae2ea47770 [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 Thompson96978b42012-12-29 21:59:54 -080044 this.ostream = new DynamicUint8Array(100);
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() {
Jeff Thompson96978b42012-12-29 21:59:54 -080087 this.ostream.ensureLength(this.offset + 1);
88 this.ostream.array[this.offset] = XML_CLOSE;
Jeff Thompsonc92706b2012-11-11 19:12:58 -080089 this.offset += 1;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070090}
91
Jeff Thompsonc92706b2012-11-11 19:12:58 -080092
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070093BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070094 if (null == attributes) {
95 return;
96 }
97
98 // the keySet of a TreeMap is sorted.
99
100 for(var i=0; i<attributes.length;i++){
101 var strAttr = attributes[i].k;
102 var strValue = attributes[i].v;
103
104 var dictionaryAttr = stringToTag(strAttr);
105 if (null == dictionaryAttr) {
106 // not in dictionary, encode as attr
107 // compressed format wants length of tag represented as length-1
108 // to save that extra bit, as tag cannot be 0 length.
109 // encodeUString knows to do that.
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800110 this.encodeUString(strAttr, XML_ATTR);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700111 } else {
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800112 this.encodeTypeAndVal(XML_DATTR, dictionaryAttr);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700113 }
114 // Write value
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800115 this.encodeUString(strValue);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700116
117 }
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700118}
119
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800120
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700121//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
Jeff Thompsond24dad32012-11-18 18:19:28 -0800145/*
146 * If Content is a string, then encode as utf8 and write UDATA.
147 */
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700148BinaryXMLEncoder.prototype.writeElement = function(
149 //long
150 tag,
151 //byte[]
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700152 Content,
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700153 //TreeMap<String, String>
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800154 attributes
155 ) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700156 this.writeStartElement(tag, attributes);
157 // Will omit if 0-length
158
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700159 if(typeof Content === 'number') {
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800160 if(LOG>4) console.log('GOING TO WRITE THE NUMBER .charCodeAt(0) ' + Content.toString().charCodeAt(0) );
161 if(LOG>4) console.log('GOING TO WRITE THE NUMBER ' + Content.toString() );
162 if(LOG>4) console.log('type of number is ' + typeof Content.toString() );
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700163
164 this.writeUString(Content.toString());
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700165 //whatever
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700166 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700167 else if(typeof Content === 'string'){
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800168 if(LOG>4) console.log('GOING TO WRITE THE STRING ' + Content );
169 if(LOG>4) console.log('type of STRING is ' + typeof Content );
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700170
171 this.writeUString(Content);
172 }
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700173 else{
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800174 if(LOG>4) console.log('GOING TO WRITE A BLOB ' + Content );
175
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700176 this.writeBlob(Content);
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700177 }
178
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700179 this.writeEndElement();
180}
181
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800182
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700183
184var TypeAndVal = function TypeAndVal(_type,_val) {
185 this.type = _type;
186 this.val = _val;
187
188};
189
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800190
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700191BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
192 //int
193 type,
194 //long
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800195 val
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800196 ) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700197
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800198 if(LOG>4) console.log('Encoding type '+ type+ ' and value '+ val);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700199
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800200 if(LOG>4) console.log('OFFSET IS ' + this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700201
202 if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
Jeff Thompson34a2ec02012-09-29 21:47:05 -0700203 throw new Error("Tag and value must be positive, and tag valid.");
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700204 }
205
206 // Encode backwards. Calculate how many bytes we need:
207 var numEncodingBytes = this.numEncodingBytes(val);
Jeff Thompson96978b42012-12-29 21:59:54 -0800208 this.ostream.ensureLength(this.offset + numEncodingBytes);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700209
210 // Bottom 4 bits of val go in last byte with tag.
Jeff Thompson96978b42012-12-29 21:59:54 -0800211 this.ostream.array[this.offset + numEncodingBytes - 1] =
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700212 //(byte)
213 (BYTE_MASK &
214 (((XML_TT_MASK & type) |
215 ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
216 XML_TT_NO_MORE); // set top bit for last byte
Jeff Thompson96978b42012-12-29 21:59:54 -0800217 val = val >>> XML_TT_VAL_BITS;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700218
219 // Rest of val goes into preceding bytes, 7 bits per byte, top bit
220 // is "more" flag.
221 var i = this.offset + numEncodingBytes - 2;
222 while ((0 != val) && (i >= this.offset)) {
Jeff Thompson96978b42012-12-29 21:59:54 -0800223 this.ostream.array[i] = //(byte)
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800224 (BYTE_MASK & (val & XML_REG_VAL_MASK)); // leave top bit unset
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700225 val = val >>> XML_REG_VAL_BITS;
226 --i;
227 }
228 if (val != 0) {
Jeff Thompson34a2ec02012-09-29 21:47:05 -0700229 throw new Error( "This should not happen: miscalculated encoding");
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700230 //Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
231 }
232 this.offset+= numEncodingBytes;
233
234 return numEncodingBytes;
235};
236
Jeff Thompsond24dad32012-11-18 18:19:28 -0800237/*
238 * Encode ustring as utf8.
239 */
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700240BinaryXMLEncoder.prototype.encodeUString = function(
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700241 //String
242 ustring,
243 //byte
244 type) {
245
Jeff Thompsond24dad32012-11-18 18:19:28 -0800246 if (null == ustring)
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700247 return;
Jeff Thompsond24dad32012-11-18 18:19:28 -0800248 if (type == XML_TAG || type == XML_ATTR && ustring.length == 0)
249 return;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700250
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700251 if(LOG>3) console.log("The string to write is ");
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700252 if(LOG>3) console.log(ustring);
253
Jeff Thompsond24dad32012-11-18 18:19:28 -0800254 var strBytes = DataUtils.stringToUtf8Array(ustring);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700255
256 this.encodeTypeAndVal(type,
257 (((type == XML_TAG) || (type == XML_ATTR)) ?
258 (strBytes.length-1) :
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800259 strBytes.length));
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700260
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700261 if(LOG>3) console.log("THE string to write is ");
262
263 if(LOG>3) console.log(strBytes);
264
Jeff Thompson96978b42012-12-29 21:59:54 -0800265 this.writeString(strBytes);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700266 this.offset+= strBytes.length;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700267};
268
269
270
271BinaryXMLEncoder.prototype.encodeBlob = function(
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800272 //Uint8Array
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700273 blob,
274 //int
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700275 length) {
276
277
Jeff Thompson84ca9502012-11-04 13:11:36 -0800278 if (null == blob)
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700279 return;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700280
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700281 if(LOG>4) console.log('LENGTH OF XML_BLOB IS '+length);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700282
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800283 /*blobCopy = new Array(blob.Length);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700284
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800285 for (i = 0; i < blob.length; i++) //in InStr.ToCharArray())
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700286 {
287 blobCopy[i] = blob[i];
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800288 }*/
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700289
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800290 this.encodeTypeAndVal(XML_BLOB, length);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700291
Jeff Thompson96978b42012-12-29 21:59:54 -0800292 this.writeBlobArray(blob);
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800293 this.offset += length;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700294};
295
296var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
297var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
298var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
299
300BinaryXMLEncoder.prototype.numEncodingBytes = function(
301 //long
302 x) {
303 if (x <= ENCODING_LIMIT_1_BYTE) return (1);
304 if (x <= ENCODING_LIMIT_2_BYTES) return (2);
305 if (x <= ENCODING_LIMIT_3_BYTES) return (3);
306
307 var numbytes = 1;
308
309 // Last byte gives you XML_TT_VAL_BITS
310 // Remainder each give you XML_REG_VAL_BITS
311 x = x >>> XML_TT_VAL_BITS;
312 while (x != 0) {
313 numbytes++;
314 x = x >>> XML_REG_VAL_BITS;
315 }
316 return (numbytes);
317};
318
319BinaryXMLEncoder.prototype.writeDateTime = function(
320 //String
321 tag,
322 //CCNTime
323 dateTime) {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700324
325 if(LOG>4)console.log('ENCODING DATE with LONG VALUE');
326 if(LOG>4)console.log(dateTime.msec);
327
328 //var binarydate = DataUtils.unsignedLongToByteArray( Math.round((dateTime.msec/1000) * 4096) );
329
330
331 //parse to hex
332 var binarydate = Math.round((dateTime.msec/1000) * 4096).toString(16) ;
333
334 //HACK
335 var binarydate = DataUtils.toNumbers( '0'.concat(binarydate,'0')) ;
336
337
338 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE');
339 if(LOG>4)console.log(binarydate);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700340 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE(HEX)');
341 if(LOG>4)console.log(DataUtils.toHex(binarydate));
342
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700343 this.writeElement(tag, binarydate);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700344};
345
Jeff Thompson96978b42012-12-29 21:59:54 -0800346// This does not update this.offset.
347BinaryXMLEncoder.prototype.writeString = function(input) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700348
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700349 if(typeof input === 'string'){
350 //console.log('went here');
351 if(LOG>4) console.log('GOING TO WRITE A STRING');
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700352 if(LOG>4) console.log(input);
353
Jeff Thompson96978b42012-12-29 21:59:54 -0800354 this.ostream.ensureLength(this.offset + input.length);
355 for (var i = 0; i < input.length; i++) {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700356 if(LOG>4) console.log('input.charCodeAt(i)=' + input.charCodeAt(i));
Jeff Thompson96978b42012-12-29 21:59:54 -0800357 this.ostream.array[this.offset + i] = (input.charCodeAt(i));
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700358 }
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700359 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700360 else{
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800361 if(LOG>4) console.log('GOING TO WRITE A STRING IN BINARY FORM');
362 if(LOG>4) console.log(input);
363
364 this.writeBlobArray(input);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700365 }
366 /*
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700367 else if(typeof input === 'object'){
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700368
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700369 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700370 */
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700371};
372
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800373
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700374BinaryXMLEncoder.prototype.writeBlobArray = function(
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800375 //Uint8Array
Jeff Thompson96978b42012-12-29 21:59:54 -0800376 blob) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700377
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700378 if(LOG>4) console.log('GOING TO WRITE A BLOB');
379
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800380 this.ostream.set(blob, this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700381};
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700382
383
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700384BinaryXMLEncoder.prototype.getReducedOstream = function() {
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800385 return this.ostream.subarray(0, this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700386};
387