blob: a633aa8fbad389bf30e283a9b752b2fbb8c4b2c3 [file] [log] [blame]
Meki Cherkaouif441d3a2012-04-22 15:17:52 -07001/*
2 * This class is used to encode and decode binary elements ( blog, type/value pairs)
3 *
4 * @author: ucla-cs
5 */
6
7var XML_EXT = 0x00;
8
9var XML_TAG = 0x01;
10
11var XML_DTAG = 0x02;
12
13var XML_ATTR = 0x03;
14
15var XML_DATTR = 0x04;
16
17var XML_BLOB = 0x05;
18
19var XML_UDATA = 0x06;
20
21var XML_CLOSE = 0x0;
22
23var XML_SUBTYPE_PROCESSING_INSTRUCTIONS = 16;
Meki Cherkaouiabb973b2012-05-09 14:25:57 -070024
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070025
26var XML_TT_BITS = 3;
27var XML_TT_MASK = ((1 << XML_TT_BITS) - 1);
28var XML_TT_VAL_BITS = XML_TT_BITS + 1;
29var XML_TT_VAL_MASK = ((1 << (XML_TT_VAL_BITS)) - 1);
30var XML_REG_VAL_BITS = 7;
31var XML_REG_VAL_MASK = ((1 << XML_REG_VAL_BITS) - 1);
32var XML_TT_NO_MORE = (1 << XML_REG_VAL_BITS); // 0x80
33var BYTE_MASK = 0xFF;
34var LONG_BYTES = 8;
35var LONG_BITS = 64;
36
37var bits_11 = 0x0000007FF;
38var bits_18 = 0x00003FFFF;
39var bits_32 = 0x0FFFFFFFF;
40
41
42var BinaryXMLEncoder = function BinaryXMLEncoder(){
43
44 this.ostream = new Array(10000);
45
46
47 this.offset =0;
48
49 this.CODEC_NAME = "Binary";
50
51};
52
53BinaryXMLEncoder.prototype.writeUString = function(/*String*/ utf8Content){
54 this.encodeUString(this.ostream, utf8Content);
55};
56
57BinaryXMLEncoder.prototype.writeBlob = function(/*byte []*/ binaryContent
58 //, /*int*/ offset, /*int*/ length
59 ) {
Meki Cherkaouiabb973b2012-05-09 14:25:57 -070060
61 if(LOG >3) console.log(binaryContent);
62
Meki Cherkaouif441d3a2012-04-22 15:17:52 -070063 this.encodeBlob(this.ostream, binaryContent, this.offset, binaryContent.length);
64};
65
66BinaryXMLEncoder.prototype.writeStartElement = function(/*String*/ tag, /*TreeMap<String,String>*/ attributes){
67
68 /*Long*/ dictionaryVal = tag;//stringToTag(tag);
69
70 if (null == dictionaryVal) {
71
72 this.encodeUString(this.ostream, tag, XML_TAG);
73
74 } else {
75 this.encodeTypeAndVal(XML_DTAG, dictionaryVal, this.ostream);
76 }
77
78 if (null != attributes) {
79 this.writeAttributes(attributes);
80 }
81};
82
83
84BinaryXMLEncoder.prototype.writeEndElement = function(){
85
86 this.ostream[this.offset] = XML_CLOSE;
87 this.offset+= 1;
88}
89
90BinaryXMLEncoder.prototype.writeAttributes = function(/*TreeMap<String,String>*/ attributes) {
91
92 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 }
116
117
118}
119
120//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
144
145BinaryXMLEncoder.prototype.writeElement = function(
146 //long
147 tag,
148 //byte[]
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700149 Content,
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700150 //TreeMap<String, String>
151 attributes) {
152 this.writeStartElement(tag, attributes);
153 // Will omit if 0-length
154
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700155 if(typeof Content === 'number') {
156 if(LOG>4) console.log('GOING TO WRITE THE NUMBER ' +Content );
157 this.writeBlob(Content.toString());
158 //whatever
159
160 }
161
162 else{
163 //else if(typeof Content === 'string'){
Meki Cherkaouib21911b2012-05-18 16:54:37 -0700164 //console.log('went here');
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700165 //this.writeBlob(Content);
166 //}
167
168 //else if(typeof Content === 'object'){
169 this.writeBlob(Content);
170 //}
171 }
172
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700173 this.writeEndElement();
174}
175
176//TODO
177
178var TypeAndVal = function TypeAndVal(_type,_val) {
179 this.type = _type;
180 this.val = _val;
181
182};
183
184BinaryXMLEncoder.prototype.encodeTypeAndVal = function(
185 //int
186 type,
187 //long
188 val,
189 //byte []
190 buf) {
191
192 console.log('Encoding type '+ type+ ' and value '+ val);
193
194 if ((type > XML_UDATA) || (type < 0) || (val < 0)) {
195 throw new Exception("Tag and value must be positive, and tag valid.");
196 }
197
198 // Encode backwards. Calculate how many bytes we need:
199 var numEncodingBytes = this.numEncodingBytes(val);
200
201 if ((this.offset + numEncodingBytes) > buf.length) {
202 throw new Exception("Buffer space of " + (buf.length-this.offset) +
203 " bytes insufficient to hold " +
204 numEncodingBytes + " of encoded type and value.");
205 }
206
207 // Bottom 4 bits of val go in last byte with tag.
208 buf[this.offset + numEncodingBytes - 1] =
209 //(byte)
210 (BYTE_MASK &
211 (((XML_TT_MASK & type) |
212 ((XML_TT_VAL_MASK & val) << XML_TT_BITS))) |
213 XML_TT_NO_MORE); // set top bit for last byte
214 val = val >>> XML_TT_VAL_BITS;;
215
216 // Rest of val goes into preceding bytes, 7 bits per byte, top bit
217 // is "more" flag.
218 var i = this.offset + numEncodingBytes - 2;
219 while ((0 != val) && (i >= this.offset)) {
220 buf[i] = //(byte)
221 (BYTE_MASK &
222 (val & XML_REG_VAL_MASK)); // leave top bit unset
223 val = val >>> XML_REG_VAL_BITS;
224 --i;
225 }
226 if (val != 0) {
227 throw new Exception( "This should not happen: miscalculated encoding");
228 //Log.warning(Log.FAC_ENCODING, "This should not happen: miscalculated encoding length, have " + val + " left.");
229 }
230 this.offset+= numEncodingBytes;
231
232 return numEncodingBytes;
233};
234
235BinaryXMLEncoder.prototype.encodeUString = function(
236 //OutputStream
237 ostream,
238 //String
239 ustring,
240 //byte
241 type) {
242
243 if ((null == ustring) || (ustring.length == 0)) {
244 return;
245 }
246
247
248 //byte [] data utils
249 /*custom*/
250 //byte[]
251 strBytes = new Array(ustring.Length);
252 var i = 0;
253 for( ;i<ustring.lengh;i++) //in InStr.ToCharArray())
254 {
255 strBytes[i] = ustring[i];
256 }
257 //strBytes = DataUtils.getBytesFromUTF8String(ustring);
258
259 this.encodeTypeAndVal(type,
260 (((type == XML_TAG) || (type == XML_ATTR)) ?
261 (strBytes.length-1) :
262 strBytes.length), ostream);
263
264
265 this.writeString(strBytes,this.offset);
266
267 this.offset+= strBytes.length;
268
269};
270
271
272
273BinaryXMLEncoder.prototype.encodeBlob = function(
274 //OutputStream
275 ostream,
276 //byte []
277 blob,
278 //int
279 offset,
280 //int
281 length) {
282
283
284 if ((null == blob) || (length == 0)) {
285
286 return;
287 }
288
289
290 this.encodeTypeAndVal(XML_BLOB, length, ostream,offset);
291
292 if (null != blob) {
293
294 this.writeString(blob,this.offset);
295 this.offset += length;
296 }
297};
298
299var ENCODING_LIMIT_1_BYTE = ((1 << (XML_TT_VAL_BITS)) - 1);
300var ENCODING_LIMIT_2_BYTES = ((1 << (XML_TT_VAL_BITS + XML_REG_VAL_BITS)) - 1);
301var ENCODING_LIMIT_3_BYTES = ((1 << (XML_TT_VAL_BITS + 2 * XML_REG_VAL_BITS)) - 1);
302
303BinaryXMLEncoder.prototype.numEncodingBytes = function(
304 //long
305 x) {
306 if (x <= ENCODING_LIMIT_1_BYTE) return (1);
307 if (x <= ENCODING_LIMIT_2_BYTES) return (2);
308 if (x <= ENCODING_LIMIT_3_BYTES) return (3);
309
310 var numbytes = 1;
311
312 // Last byte gives you XML_TT_VAL_BITS
313 // Remainder each give you XML_REG_VAL_BITS
314 x = x >>> XML_TT_VAL_BITS;
315 while (x != 0) {
316 numbytes++;
317 x = x >>> XML_REG_VAL_BITS;
318 }
319 return (numbytes);
320};
321
322BinaryXMLEncoder.prototype.writeDateTime = function(
323 //String
324 tag,
325 //CCNTime
326 dateTime) {
327 this.writeElement(tag, dateTime.toBinaryTime());
328};
329
330BinaryXMLEncoder.prototype.writeString = function(
331 //String
332 input,
333 //CCNTime
334 offset) {
335
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700336 if(typeof input === 'string'){
337 //console.log('went here');
338 if(LOG>4) console.log('GOING TO WRITE A STRING');
339
340 for (var i = 0; i < input.length; i++) {
341 this.ostream[this.offset+i] = (input.charCodeAt(i));
342 }
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700343 }
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700344
345 else if(typeof input === 'object'){
346 this.writeBlobArray(input);
347 }
348
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700349};
350
351BinaryXMLEncoder.prototype.writeBlobArray = function(
352 //String
353 Blob,
354 //CCNTime
355 offset) {
356
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700357 if(LOG>4) console.log('GOING TO WRITE A BLOB');
358
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700359 for (var i = 0; i < Blob.length; i++) {
360 this.ostream[this.offset+i] = Blob[i];
361 }
362
363};
Meki Cherkaouiabb973b2012-05-09 14:25:57 -0700364
365
366
Meki Cherkaouif441d3a2012-04-22 15:17:52 -0700367BinaryXMLEncoder.prototype.getReducedOstream = function() {
368
369 return this.ostream.slice(0,this.offset);
370
371};
372