blob: e5039eec566baa02a0731807193af2bd84ab254b [file] [log] [blame]
Meki Cherkaoui97e7a592012-04-14 02:50:06 -07001
2var XML_EXT = 0x00;
3
4var XML_TAG = 0x01;
5
6var XML_DTAG = 0x02;
7
8var XML_ATTR = 0x03;
9
10var XML_DATTR = 0x04;
11
12var XML_BLOB = 0x05;
13
14var XML_UDATA = 0x06;
15
16var XML_CLOSE = 0x0;
17
18var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
19
20
21var XML_TT_BITS = 3;
22var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
23var XML_TT_VAL_BITS = XML_TT_BITS + 1;
24var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
25var XML_REG_VAL_BITS = 7;
26var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
27var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
28var BYTE_MASK = 0xFF;
29var LONG_BYTES = 8;
30var LONG_BITS = 64;
31
32var bits_11 = 0x0000007FF;
33var bits_18 = 0x00003FFFF;
34var bits_32 = 0x0FFFFFFFF;
35
36//var BinaryXMLCodec = require('./BinaryXMLCodec').BinaryXMLCodec;
37
38//var codec = new BinaryXMLCodec();
39
40
41var BinaryXMLEncoder = function BinaryXMLEncoder(){
42
43 this.ostream = new Array(1024);
44
45 this.offset =0;
46
47 this.CODEC_NAME = "Binary";
48
49};
50
51
52/*BinaryXMLEncoder.prototype.beginEncoding = function() {
53 this.ostream = new Buffer(1024);
54 this.offset = 0;
55};
56
57BinaryXMLEncoder.prototype.endEncoding = function(){
58 //this.ostream.end();
59};*/
60
61BinaryXMLEncoder.prototype.writeUString = function(/*String*/ utf8Content){
62 this.encodeUString(this.ostream, utf8Content);
63};
64
65BinaryXMLEncoder.prototype.writeBlob = function(/*byte []*/ binaryContent
66 //, /*int*/ offset, /*int*/ length
67 ) {
68 //console.log(binaryContent);
69 this.encodeBlob(this.ostream, binaryContent, this.offset, binaryContent.length);
70};
71
72BinaryXMLEncoder.prototype.writeStartElement = function(/*String*/ tag, /*TreeMap<String,String>*/ attributes){
73
74 /*Long*/ dictionaryVal = tag;//stringToTag(tag);
75
76 if (null == dictionaryVal) {
77
78 this.encodeUString(this.ostream, tag, XML_TAG);
79
80 } else {
81 this.encodeTypeAndVal(XML_DTAG, dictionaryVal, this.ostream);
82 }
83
84 if (null != attributes) {
85 this.writeAttributes(attributes);
86 }
87};
88
89
90BinaryXMLEncoder.prototype.writeEndElement = function(){
91 //console.log(XML_CLOSE);
92 //console.log(tagToString(XML_CLOSE));
93 //this.ostream.writeUInt8( XML_CLOSE ,this.offset);
94 this.ostream[this.offset] = XML_CLOSE;
95 this.offset+= 1;
96}
97
98BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
99
100 if (null == attributes) {
101 return;
102 }
103
104 // the keySet of a TreeMap is sorted.
105 /*Set<String> keySet = attributes.keySet();
106 Iterator<String> it = keySet.iterator();*/
107
108 for(var i=0; i<attributes.length;i++){
109 var strAttr = attributes[i].k;
110 var strValue = attributes[i].v;
111
112 var dictionaryAttr = stringToTag(strAttr);
113 if (null == dictionaryAttr) {
114 // not in dictionary, encode as attr
115 // compressed format wants length of tag represented as length-1
116 // to save that extra bit, as tag cannot be 0 length.
117 // encodeUString knows to do that.
118 this.encodeUString(this.ostream, strAttr, XML_ATTR);
119 } else {
120 this.encodeTypeAndVal(XML_DATTR, dictionaryAttr, this.ostream);
121 }
122 // Write value
123 this.encodeUString(this.ostream, strValue);
124
125 }
126
127
128}
129
130//returns a string
131stringToTag = function(/*long*/ tagVal) {
132 if ((tagVal >= 0) && (tagVal < CCNProtocolDTagsStrings.length)) {
133 return CCNProtocolDTagsStrings[tagVal];
134 } else if (tagVal == CCNProtocolDTags.CCNProtocolDataUnit) {
135 return CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT;
136 }
137 return null;
138};
139
140//returns a Long
141tagToString = function(/*String*/ tagName) {
142 // the slow way, but right now we don't care.... want a static lookup for the forward direction
143 for (var i=0; i < CCNProtocolDTagsStrings.length; ++i) {
144 if ((null != CCNProtocolDTagsStrings[i]) && (CCNProtocolDTagsStrings[i] == tagName)) {
145 return i;
146 }
147 }
148 if (CCNProtocolDTags.CCNPROTOCOL_DATA_UNIT == tagName) {
149 return CCNProtocolDTags.CCNProtocolDataUnit;
150 }
151 return null;
152};
153
154
155BinaryXMLEncoder.prototype.writeElement = function(
156 //long
157 tag,
158 //byte[]
159 binaryContent,
160 //TreeMap<String, String>
161 attributes) {
162 this.writeStartElement(tag, attributes);
163 // Will omit if 0-length
164
165 this.writeBlob(binaryContent);
166 this.writeEndElement();
167}
168
169//TODO
170//console.log(stringToTag(0));
171
172
173
174
175
176
177
178
179
180var TypeAndVal = function TypeAndVal(_type,_val) {
181 this.type = _type;
182 this.val = _val;
183
184};
185
186
187
188/*BinaryXMLEncoder.prototype.encodeTypeAndValOffset = function(
189 //int
190 type,
191 //long
192 val,
193 //byte []
194 buf,
195 //int
196 offset) {
197
198 if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
199 throw new Exception("Tag and value must be positive, and tag valid.");
200 }
201
202 // Encode backwards. Calculate how many bytes we need:
203 //int
204 var numEncodingBytes = numEncodingBytes(val);
205
206 if ((offset + numEncodingBytes) > buf.length) {
207 throw new Exception("Buffer space of " + (buf.length-offset) +
208 " bytes insufficient to hold " +
209 numEncodingBytes + " of encoded type and value.");
210 }
211
212
213 buf[offset + numEncodingBytes - 1] =
214 (BYTE_MASK &
215 (((XML_TT_MASK & type) |
216 ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
217 XML_TT_NO_MORE);
218 val = val >>> XML_TT_VAL_BITS;;
219 //int
220 var i = offset + numEncodingBytes - 2;
221 while ((0 != val) && (i >= offset)) {
222 buf[i] = (BYTE_MASK &
223 (val & XML_REG_VAL_MASK));
224 val = val >>> XML_REG_VAL_BITS;
225 --i;
226 }
227
228 return numEncodingBytes;
229};*/
230
231//BinaryXMLCodec.prototype.encodeTypeAndVal = function(
232 // //final int
233 //type,
234 //final long
235 //value,
236 //final OutputStream
237 //ostream,
238 //offset){
239
240 /*
241 We exploit the fact that encoding is done from the right, so this actually means
242 there is a deterministic encoding from a long to a Type/Value pair:
243
244 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
245 |ABCD.EFGH|IJKL.MNOP|QRST.UVWX|YZ01.2345|6789.abcd|efgh.ijkl|mnop.qrst|uvwx.yz@#
246
247 60> 53> 46> 39> 32> 25> 18> 11> 4>
248 |_000.ABCD|_EFG.HIJK|_LMN.OPQR|_STU.VWXY|_Z01.2345|_678.9abc|_defg.hij|_klm.nopq|_rst.uvwx|_yz@#___
249
250 What we want to do is compute the result in MSB order and write it directly
251 to the channel without any intermediate form.
252 */
253
254 //var/*int*/ bits;
255 //var/*int*/ count = 0;
256
257 // once we start writing bits, we keep writing bits even if they are "0"
258 // var/*bool*/ writing = false;
259
260 // a few heuristic to catch the small-bit length patterns
261 /*if( value < 0 || value > 15 ) {
262 var start = 60;
263 if( 0 <= value ) {
264 if( value < bits_11 )
265 start = 4;
266 else if( value < bits_18 )
267 start = 11;
268 else if( value < bits_32 )
269 start = 25;
270 }
271
272 for( var i = start; i >= 4; i -= 7) {
273 bits = (value >>> i) & BinaryXMLCodec.XML_REG_VAL_MASK;
274 if( bits != 0 || writing ) {
275 ostream.write(bits);
276 count++;
277 writing = true;
278 }
279 }
280 }
281
282 // Explicit computation of the bottom byte
283 bits = type & BinaryXMLCodec.XML_TT_MASK;
284 var bottom4 = value & BinaryXMLCodec.XML_TT_VAL_MASK;
285 bits |= bottom4 << BinaryXMLCodec.XML_TT_BITS;
286 // the bottom byte always has the NO_MORE flag
287 bits |= BinaryXMLCodec.XML_TT_NO_MORE;
288
289 //console.log(ostream.constructor.name);
290 //console.log(ostream);
291
292 //ostream.writable = true;
293 //console.log(ostream.)
294 ostream.write(bits.toString());
295
296 count++;
297
298// byte [] encoding = encodeTypeAndVal(tag, val);
299// ostream.write(encoding);
300 return count;
301
302}*/
303
304
305BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
306 //int
307 type,
308 //long
309 val,
310 //byte []
311 buf) {
312
313 console.log('Encoding type '+ type+ ' and value '+ val);
314
315 if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
316 throw new Exception("Tag and value must be positive, and tag valid.");
317 }
318
319 // Encode backwards. Calculate how many bytes we need:
320 var numEncodingBytes = this.numEncodingBytes(val);
321
322 if ((this.offset + numEncodingBytes) > buf.length) {
323 throw new Exception("Buffer space of " + (buf.length-this.offset) +
324 " bytes insufficient to hold " +
325 numEncodingBytes + " of encoded type and value.");
326 }
327
328 // Bottom 4 bits of val go in last byte with tag.
329 buf[this.offset + numEncodingBytes - 1] =
330 //(byte)
331 (BYTE_MASK &
332 (((XML_TT_MASK & type) |
333 ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
334 XML_TT_NO_MORE); // set top bit for last byte
335 val = val >>> XML_TT_VAL_BITS;;
336
337 // Rest of val goes into preceding bytes, 7 bits per byte, top bit
338 // is "more" flag.
339 var i = this.offset + numEncodingBytes - 2;
340 while ((0 != val) && (i >= this.offset)) {
341 buf[i] = //(byte)
342 (BYTE_MASK &
343 (val & XML_REG_VAL_MASK)); // leave top bit unset
344 val = val >>> XML_REG_VAL_BITS;
345 --i;
346 }
347 if (val != 0) {
348 throw new Exception( "This should not happen: miscalculated encoding");
349 //Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
350 }
351 this.offset+= numEncodingBytes;
352 console.log('offset increased after tag to '+this.offset);
353
354 return numEncodingBytes;
355};
356
357BinaryXMLEncoder.prototype.encodeUString = function(
358 //OutputStream
359 ostream,
360 //String
361 ustring,
362 //byte
363 type) {
364
365 // We elide the encoding of a 0-length UString
366 if ((null == ustring) || (ustring.length == 0)) {
367 //if (Log.isLoggable(Log.FAC_ENCODING, Level.FINER))
368 //Log.finer(Log.FAC_ENCODING, "Eliding 0-length UString.");
369 return;
370 }
371
372 console.log('Writting String to '+ ustring);
373
374 //byte [] data utils
375 /*custom*/
376 //byte[]
377 strBytes = new Array(ustring.Length);
378 var i = 0;
379 for( ;i<ustring.lengh;i++) //in InStr.ToCharArray())
380 {
381 strBytes[i] = ustring[i];
382 }
383 //strBytes = DataUtils.getBytesFromUTF8String(ustring);
384
385 this.encodeTypeAndVal(type,
386 (((type == XML_TAG) || (type == XML_ATTR)) ?
387 (strBytes.length-1) :
388 strBytes.length), ostream);
389
390 //console.log(strBytes.toString());
391
392 ostream.write(strBytes.toString(),this.offset);
393 this.offset+= strBytes.length;
394 console.log('offset increased after String to '+this.offset);
395 //
396};
397
398BinaryXMLEncoder.prototype.encodeBlob = function(
399 //OutputStream
400 ostream,
401 //byte []
402 blob,
403 //int
404 offset,
405 //int
406 length) {
407
408 console.log('Writting Blob ');
409 console.log('length is '+ length);
410
411 // We elide the encoding of a 0-length blob
412 if ((null == blob) || (length == 0)) {
413
414 return;
415 }
416
417
418 this.encodeTypeAndVal(XML_BLOB, length, ostream,offset);
419
420 if (null != blob) {
421 //console.log(blob);
422 //maybe blog.t
423 ostream.write(blob.toString(), this.offset);
424 this.offset += length;
425 console.log('offset increased after blob to '+this.offset);
426 }
427};
428
429
430var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
431var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
432var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
433
434BinaryXMLEncoder.prototype.numEncodingBytes = function(
435 //long
436 x) {
437 if (x <= ENCODING_LIMIT_1_BYTE) return (1);
438 if (x <= ENCODING_LIMIT_2_BYTES) return (2);
439 if (x <= ENCODING_LIMIT_3_BYTES) return (3);
440
441 var numbytes = 1;
442
443 // Last byte gives you XML_TT_VAL_BITS
444 // Remainder each give you XML_REG_VAL_BITS
445 x = x >>> XML_TT_VAL_BITS;
446 while (x != 0) {
447 numbytes++;
448 x = x >>> XML_REG_VAL_BITS;
449 }
450 return (numbytes);
451};
452
453BinaryXMLEncoder.prototype.writeDateTime = function(
454 //String
455 tag,
456 //CCNTime
457 dateTime) {
458 this.writeElement(tag, dateTime.toBinaryTime());
459};