blob: 788362272f6b40593259d83f1001dd56c8b992c9 [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 *
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 Thompsonc92706b2012-11-11 19:12:58 -080049
50BinaryXMLEncoder.prototype.writeUString = function(/*String*/ utf8Content) {
Jeff Thompsond15aa7b2012-11-17 15:17:24 -080051 this.encodeUString(utf8Content, XML_UDATA);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070052};
53
Jeff Thompsonc92706b2012-11-11 19:12:58 -080054
55BinaryXMLEncoder.prototype.writeBlob = function(
56 /*Uint8Array*/ binaryContent
Jeff Thompsonc92706b2012-11-11 19:12:58 -080057 ) {
Meki Cherkaouiabb973b2012-05-09 14:25:57 -070058
59 if(LOG >3) console.log(binaryContent);
60
Jeff Thompsond15aa7b2012-11-17 15:17:24 -080061 this.encodeBlob(binaryContent, binaryContent.length);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070062};
63
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070064
Jeff Thompsonc92706b2012-11-11 19:12:58 -080065BinaryXMLEncoder.prototype.writeStartElement = function(
66 /*String*/ tag,
67 /*TreeMap<String,String>*/ attributes
68 ) {
69
Jeff Thompsond15aa7b2012-11-17 15:17:24 -080070 /*Long*/ var dictionaryVal = tag; //stringToTag(tag);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070071
72 if (null == dictionaryVal) {
Jeff Thompsond15aa7b2012-11-17 15:17:24 -080073 this.encodeUString(tag, XML_TAG);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070074 } else {
Jeff Thompsond15aa7b2012-11-17 15:17:24 -080075 this.encodeTypeAndVal(XML_DTAG, dictionaryVal);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070076 }
77
78 if (null != attributes) {
79 this.writeAttributes(attributes);
80 }
81};
82
83
Jeff Thompsonc92706b2012-11-11 19:12:58 -080084BinaryXMLEncoder.prototype.writeEndElement = function() {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070085 this.ostream[this.offset] = XML_CLOSE;
Jeff Thompsonc92706b2012-11-11 19:12:58 -080086 this.offset += 1;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070087}
88
Jeff Thompsonc92706b2012-11-11 19:12:58 -080089
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070090BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070091 if (null == attributes) {
92 return;
93 }
94
95 // the keySet of a TreeMap is sorted.
96
97 for(var i=0; i<attributes.length;i++){
98 var strAttr = attributes[i].k;
99 var strValue = attributes[i].v;
100
101 var dictionaryAttr = stringToTag(strAttr);
102 if (null == dictionaryAttr) {
103 // not in dictionary, encode as attr
104 // compressed format wants length of tag represented as length-1
105 // to save that extra bit, as tag cannot be 0 length.
106 // encodeUString knows to do that.
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800107 this.encodeUString(strAttr, XML_ATTR);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700108 } else {
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800109 this.encodeTypeAndVal(XML_DATTR, dictionaryAttr);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700110 }
111 // Write value
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800112 this.encodeUString(strValue);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700113
114 }
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700115}
116
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800117
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700118//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[]
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700147 Content,
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700148 //TreeMap<String, String>
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800149 attributes
150 ) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700151 this.writeStartElement(tag, attributes);
152 // Will omit if 0-length
153
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700154 if(typeof Content === 'number') {
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800155 if(LOG>4) console.log('GOING TO WRITE THE NUMBER .charCodeAt(0) ' + Content.toString().charCodeAt(0) );
156 if(LOG>4) console.log('GOING TO WRITE THE NUMBER ' + Content.toString() );
157 if(LOG>4) console.log('type of number is ' + typeof Content.toString() );
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700158
159 this.writeUString(Content.toString());
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700160 //whatever
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700161 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700162 else if(typeof Content === 'string'){
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800163 if(LOG>4) console.log('GOING TO WRITE THE STRING ' + Content );
164 if(LOG>4) console.log('type of STRING is ' + typeof Content );
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700165
166 this.writeUString(Content);
167 }
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700168 else{
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800169 if(LOG>4) console.log('GOING TO WRITE A BLOB ' + Content );
170
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700171 this.writeBlob(Content);
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700172 }
173
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700174 this.writeEndElement();
175}
176
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800177
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700178
179var TypeAndVal = function TypeAndVal(_type,_val) {
180 this.type = _type;
181 this.val = _val;
182
183};
184
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800185
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700186BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
187 //int
188 type,
189 //long
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800190 val
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800191 ) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700192
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800193 if(LOG>4) console.log('Encoding type '+ type+ ' and value '+ val);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700194
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800195 if(LOG>4) console.log('OFFSET IS ' + this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700196
197 if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
Jeff Thompson34a2ec02012-09-29 21:47:05 -0700198 throw new Error("Tag and value must be positive, and tag valid.");
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700199 }
200
201 // Encode backwards. Calculate how many bytes we need:
202 var numEncodingBytes = this.numEncodingBytes(val);
203
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800204 if ((this.offset + numEncodingBytes) > this.ostream.length) {
205 throw new Error("Buffer space of " + (this.ostream.length - this.offset) +
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700206 " bytes insufficient to hold " +
207 numEncodingBytes + " of encoded type and value.");
208 }
209
210 // Bottom 4 bits of val go in last byte with tag.
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800211 this.ostream[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
217 val = val >>> XML_TT_VAL_BITS;;
218
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 Thompsond15aa7b2012-11-17 15:17:24 -0800223 this.ostream[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 Thompsonc92706b2012-11-11 19:12:58 -0800237
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700238BinaryXMLEncoder.prototype.encodeUString = function(
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700239 //String
240 ustring,
241 //byte
242 type) {
243
244 if ((null == ustring) || (ustring.length == 0)) {
245 return;
246 }
247
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700248 if(LOG>3) console.log("The string to write is ");
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700249 if(LOG>3) console.log(ustring);
250
251 //COPY THE STRING TO AVOID PROBLEMS
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800252 var strBytes = new Array(ustring.length);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700253
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800254 for (i = 0; i < ustring.length; i++) //in InStr.ToCharArray())
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700255 {
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800256 if(LOG>3) console.log('ustring[' + i + '] = ' + ustring[i]);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700257 strBytes[i] = ustring.charCodeAt(i);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700258 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700259
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700260 //strBytes = DataUtils.getBytesFromUTF8String(ustring);
261
262 this.encodeTypeAndVal(type,
263 (((type == XML_TAG) || (type == XML_ATTR)) ?
264 (strBytes.length-1) :
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800265 strBytes.length));
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700266
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700267 if(LOG>3) console.log("THE string to write is ");
268
269 if(LOG>3) console.log(strBytes);
270
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700271 this.writeString(strBytes,this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700272 this.offset+= strBytes.length;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700273};
274
275
276
277BinaryXMLEncoder.prototype.encodeBlob = function(
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800278 //Uint8Array
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700279 blob,
280 //int
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700281 length) {
282
283
Jeff Thompson84ca9502012-11-04 13:11:36 -0800284 if (null == blob)
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700285 return;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700286
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700287 if(LOG>4) console.log('LENGTH OF XML_BLOB IS '+length);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700288
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800289 /*blobCopy = new Array(blob.Length);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700290
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800291 for (i = 0; i < blob.length; i++) //in InStr.ToCharArray())
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700292 {
293 blobCopy[i] = blob[i];
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800294 }*/
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700295
Jeff Thompsond15aa7b2012-11-17 15:17:24 -0800296 this.encodeTypeAndVal(XML_BLOB, length);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700297
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800298 this.writeBlobArray(blob, this.offset);
299 this.offset += length;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700300};
301
302var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
303var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
304var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
305
306BinaryXMLEncoder.prototype.numEncodingBytes = function(
307 //long
308 x) {
309 if (x <= ENCODING_LIMIT_1_BYTE) return (1);
310 if (x <= ENCODING_LIMIT_2_BYTES) return (2);
311 if (x <= ENCODING_LIMIT_3_BYTES) return (3);
312
313 var numbytes = 1;
314
315 // Last byte gives you XML_TT_VAL_BITS
316 // Remainder each give you XML_REG_VAL_BITS
317 x = x >>> XML_TT_VAL_BITS;
318 while (x != 0) {
319 numbytes++;
320 x = x >>> XML_REG_VAL_BITS;
321 }
322 return (numbytes);
323};
324
325BinaryXMLEncoder.prototype.writeDateTime = function(
326 //String
327 tag,
328 //CCNTime
329 dateTime) {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700330
331 if(LOG>4)console.log('ENCODING DATE with LONG VALUE');
332 if(LOG>4)console.log(dateTime.msec);
333
334 //var binarydate = DataUtils.unsignedLongToByteArray( Math.round((dateTime.msec/1000) * 4096) );
335
336
337 //parse to hex
338 var binarydate = Math.round((dateTime.msec/1000) * 4096).toString(16) ;
339
340 //HACK
341 var binarydate = DataUtils.toNumbers( '0'.concat(binarydate,'0')) ;
342
343
344 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE');
345 if(LOG>4)console.log(binarydate);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700346 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE(HEX)');
347 if(LOG>4)console.log(DataUtils.toHex(binarydate));
348
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700349 this.writeElement(tag, binarydate);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700350};
351
352BinaryXMLEncoder.prototype.writeString = function(
353 //String
354 input,
355 //CCNTime
356 offset) {
357
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700358 if(typeof input === 'string'){
359 //console.log('went here');
360 if(LOG>4) console.log('GOING TO WRITE A STRING');
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700361 if(LOG>4) console.log(input);
362
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800363 for (i = 0; i < input.length; i++) {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700364 if(LOG>4) console.log('input.charCodeAt(i)=' + input.charCodeAt(i));
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700365 this.ostream[this.offset+i] = (input.charCodeAt(i));
366 }
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700367 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700368 else{
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800369 if(LOG>4) console.log('GOING TO WRITE A STRING IN BINARY FORM');
370 if(LOG>4) console.log(input);
371
372 this.writeBlobArray(input);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700373 }
374 /*
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700375 else if(typeof input === 'object'){
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700376
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700377 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700378 */
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700379};
380
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800381
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700382BinaryXMLEncoder.prototype.writeBlobArray = function(
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800383 //Uint8Array
384 blob,
385 //int
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700386 offset) {
387
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700388 if(LOG>4) console.log('GOING TO WRITE A BLOB');
389
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800390 /*for (var i = 0; i < Blob.length; i++) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700391 this.ostream[this.offset+i] = Blob[i];
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800392 }*/
393 this.ostream.set(blob, this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700394};
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700395
396
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700397BinaryXMLEncoder.prototype.getReducedOstream = function() {
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800398 return this.ostream.subarray(0, this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700399};
400