blob: 2a67e054f6a5bcbe2f736ab53b1a18fb3108bb33 [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(){
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) {
Meki Cherkaoui8f173612012-06-06 01:05:40 -070051 this.encodeUString(this.ostream, 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
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070057 //, /*int*/ offset, /*int*/ length
Jeff Thompsonc92706b2012-11-11 19:12:58 -080058 ) {
Meki Cherkaouiabb973b2012-05-09 14:25:57 -070059
60 if(LOG >3) console.log(binaryContent);
61
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070062 this.encodeBlob(this.ostream, binaryContent, this.offset, binaryContent.length);
63};
64
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070065
Jeff Thompsonc92706b2012-11-11 19:12:58 -080066BinaryXMLEncoder.prototype.writeStartElement = function(
67 /*String*/ tag,
68 /*TreeMap<String,String>*/ attributes
69 ) {
70
71 /*Long*/ dictionaryVal = tag; //stringToTag(tag);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070072
73 if (null == dictionaryVal) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070074 this.encodeUString(this.ostream, tag, XML_TAG);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070075 } else {
76 this.encodeTypeAndVal(XML_DTAG, dictionaryVal, this.ostream);
77 }
78
79 if (null != attributes) {
80 this.writeAttributes(attributes);
81 }
82};
83
84
Jeff Thompsonc92706b2012-11-11 19:12:58 -080085BinaryXMLEncoder.prototype.writeEndElement = function() {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070086 this.ostream[this.offset] = XML_CLOSE;
Jeff Thompsonc92706b2012-11-11 19:12:58 -080087 this.offset += 1;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070088}
89
Jeff Thompsonc92706b2012-11-11 19:12:58 -080090
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070091BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070092 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 }
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700116}
117
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800118
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700119//returns a string
120stringToTag = function(/*long*/ tagVal) {
121 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
122 return CCNProtocolDTagsStrings[tagVal];
123 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
124 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
125 }
126 return null;
127};
128
129//returns a Long
130tagToString = function(/*String*/ tagName) {
131 // the slow way, but right now we don't care.... want a static lookup for the forward direction
132 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
133 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
134 return i;
135 }
136 }
137 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
138 return CCNProtocolDTags.CCNProtocolDataUnit;
139 }
140 return null;
141};
142
143
144BinaryXMLEncoder.prototype.writeElement = function(
145 //long
146 tag,
147 //byte[]
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700148 Content,
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700149 //TreeMap<String, String>
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800150 attributes
151 ) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700152 this.writeStartElement(tag, attributes);
153 // Will omit if 0-length
154
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700155 if(typeof Content === 'number') {
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800156 if(LOG>4) console.log('GOING TO WRITE THE NUMBER .charCodeAt(0) ' + Content.toString().charCodeAt(0) );
157 if(LOG>4) console.log('GOING TO WRITE THE NUMBER ' + Content.toString() );
158 if(LOG>4) console.log('type of number is ' + typeof Content.toString() );
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700159
160 this.writeUString(Content.toString());
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700161 //whatever
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700162 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700163 else if(typeof Content === 'string'){
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800164 if(LOG>4) console.log('GOING TO WRITE THE STRING ' + Content );
165 if(LOG>4) console.log('type of STRING is ' + typeof Content );
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700166
167 this.writeUString(Content);
168 }
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700169 else{
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800170 if(LOG>4) console.log('GOING TO WRITE A BLOB ' + Content );
171
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700172 this.writeBlob(Content);
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700173 }
174
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700175 this.writeEndElement();
176}
177
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800178
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700179
180var TypeAndVal = function TypeAndVal(_type,_val) {
181 this.type = _type;
182 this.val = _val;
183
184};
185
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800186
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700187BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
188 //int
189 type,
190 //long
191 val,
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800192 //ArrayBufferView
193 ostream
194 ) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700195
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800196 if(LOG>4) console.log('Encoding type '+ type+ ' and value '+ val);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700197
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800198 if(LOG>4) console.log('OFFSET IS ' + this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700199
200 if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
Jeff Thompson34a2ec02012-09-29 21:47:05 -0700201 throw new Error("Tag and value must be positive, and tag valid.");
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700202 }
203
204 // Encode backwards. Calculate how many bytes we need:
205 var numEncodingBytes = this.numEncodingBytes(val);
206
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800207 if ((this.offset + numEncodingBytes) > ostream.length) {
208 throw new Error("Buffer space of " + (ostream.length - this.offset) +
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700209 " bytes insufficient to hold " +
210 numEncodingBytes + " of encoded type and value.");
211 }
212
213 // Bottom 4 bits of val go in last byte with tag.
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800214 ostream[this.offset + numEncodingBytes - 1] =
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700215 //(byte)
216 (BYTE_MASK &
217 (((XML_TT_MASK & type) |
218 ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
219 XML_TT_NO_MORE); // set top bit for last byte
220 val = val >>> XML_TT_VAL_BITS;;
221
222 // Rest of val goes into preceding bytes, 7 bits per byte, top bit
223 // is "more" flag.
224 var i = this.offset + numEncodingBytes - 2;
225 while ((0 != val) && (i >= this.offset)) {
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800226 ostream[i] = //(byte)
227 (BYTE_MASK & (val & XML_REG_VAL_MASK)); // leave top bit unset
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700228 val = val >>> XML_REG_VAL_BITS;
229 --i;
230 }
231 if (val != 0) {
Jeff Thompson34a2ec02012-09-29 21:47:05 -0700232 throw new Error( "This should not happen: miscalculated encoding");
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700233 //Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
234 }
235 this.offset+= numEncodingBytes;
236
237 return numEncodingBytes;
238};
239
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800240
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700241BinaryXMLEncoder.prototype.encodeUString = function(
242 //OutputStream
243 ostream,
244 //String
245 ustring,
246 //byte
247 type) {
248
249 if ((null == ustring) || (ustring.length == 0)) {
250 return;
251 }
252
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700253 if(LOG>3) console.log("The string to write is ");
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700254 if(LOG>3) console.log(ustring);
255
256 //COPY THE STRING TO AVOID PROBLEMS
257 strBytes = new Array(ustring.length);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700258
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800259 for (i = 0; i < ustring.length; i++) //in InStr.ToCharArray())
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700260 {
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800261 if(LOG>3) console.log('ustring[' + i + '] = ' + ustring[i]);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700262 strBytes[i] = ustring.charCodeAt(i);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700263 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700264
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700265 //strBytes = DataUtils.getBytesFromUTF8String(ustring);
266
267 this.encodeTypeAndVal(type,
268 (((type == XML_TAG) || (type == XML_ATTR)) ?
269 (strBytes.length-1) :
270 strBytes.length), ostream);
271
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700272 if(LOG>3) console.log("THE string to write is ");
273
274 if(LOG>3) console.log(strBytes);
275
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700276 this.writeString(strBytes,this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700277 this.offset+= strBytes.length;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700278};
279
280
281
282BinaryXMLEncoder.prototype.encodeBlob = function(
283 //OutputStream
284 ostream,
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800285 //Uint8Array
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700286 blob,
287 //int
288 offset,
289 //int
290 length) {
291
292
Jeff Thompson84ca9502012-11-04 13:11:36 -0800293 if (null == blob)
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700294 return;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700295
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700296 if(LOG>4) console.log('LENGTH OF XML_BLOB IS '+length);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700297
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800298 /*blobCopy = new Array(blob.Length);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700299
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800300 for (i = 0; i < blob.length; i++) //in InStr.ToCharArray())
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700301 {
302 blobCopy[i] = blob[i];
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800303 }*/
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700304
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800305 this.encodeTypeAndVal(XML_BLOB, length, ostream, offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700306
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800307 this.writeBlobArray(blob, this.offset);
308 this.offset += length;
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700309};
310
311var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
312var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
313var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
314
315BinaryXMLEncoder.prototype.numEncodingBytes = function(
316 //long
317 x) {
318 if (x <= ENCODING_LIMIT_1_BYTE) return (1);
319 if (x <= ENCODING_LIMIT_2_BYTES) return (2);
320 if (x <= ENCODING_LIMIT_3_BYTES) return (3);
321
322 var numbytes = 1;
323
324 // Last byte gives you XML_TT_VAL_BITS
325 // Remainder each give you XML_REG_VAL_BITS
326 x = x >>> XML_TT_VAL_BITS;
327 while (x != 0) {
328 numbytes++;
329 x = x >>> XML_REG_VAL_BITS;
330 }
331 return (numbytes);
332};
333
334BinaryXMLEncoder.prototype.writeDateTime = function(
335 //String
336 tag,
337 //CCNTime
338 dateTime) {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700339
340 if(LOG>4)console.log('ENCODING DATE with LONG VALUE');
341 if(LOG>4)console.log(dateTime.msec);
342
343 //var binarydate = DataUtils.unsignedLongToByteArray( Math.round((dateTime.msec/1000) * 4096) );
344
345
346 //parse to hex
347 var binarydate = Math.round((dateTime.msec/1000) * 4096).toString(16) ;
348
349 //HACK
350 var binarydate = DataUtils.toNumbers( '0'.concat(binarydate,'0')) ;
351
352
353 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE');
354 if(LOG>4)console.log(binarydate);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700355 if(LOG>4)console.log('ENCODING DATE with BINARY VALUE(HEX)');
356 if(LOG>4)console.log(DataUtils.toHex(binarydate));
357
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700358 this.writeElement(tag, binarydate);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700359};
360
361BinaryXMLEncoder.prototype.writeString = function(
362 //String
363 input,
364 //CCNTime
365 offset) {
366
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700367 if(typeof input === 'string'){
368 //console.log('went here');
369 if(LOG>4) console.log('GOING TO WRITE A STRING');
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700370 if(LOG>4) console.log(input);
371
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800372 for (i = 0; i < input.length; i++) {
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700373 if(LOG>4) console.log('input.charCodeAt(i)=' + input.charCodeAt(i));
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700374 this.ostream[this.offset+i] = (input.charCodeAt(i));
375 }
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700376 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700377 else{
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800378 if(LOG>4) console.log('GOING TO WRITE A STRING IN BINARY FORM');
379 if(LOG>4) console.log(input);
380
381 this.writeBlobArray(input);
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700382 }
383 /*
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700384 else if(typeof input === 'object'){
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700385
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700386 }
Meki Cherkaoui8f173612012-06-06 01:05:40 -0700387 */
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700388};
389
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800390
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700391BinaryXMLEncoder.prototype.writeBlobArray = function(
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800392 //Uint8Array
393 blob,
394 //int
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700395 offset) {
396
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700397 if(LOG>4) console.log('GOING TO WRITE A BLOB');
398
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800399 /*for (var i = 0; i < Blob.length; i++) {
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700400 this.ostream[this.offset+i] = Blob[i];
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800401 }*/
402 this.ostream.set(blob, this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700403};
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700404
405
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700406BinaryXMLEncoder.prototype.getReducedOstream = function() {
Jeff Thompsonc92706b2012-11-11 19:12:58 -0800407 return this.ostream.subarray(0, this.offset);
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700408};
409