OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 define("mojo/public/js/codec", [ | |
6 "mojo/public/js/unicode", | |
7 "mojo/public/js/buffer", | |
8 ], function(unicode, buffer) { | |
9 | |
10 var kErrorUnsigned = "Passing negative value to unsigned"; | |
11 var kErrorArray = "Passing non Array for array type"; | |
12 var kErrorString = "Passing non String for string type"; | |
13 var kErrorMap = "Passing non Map for map type"; | |
14 | |
15 // Memory ------------------------------------------------------------------- | |
16 | |
17 var kAlignment = 8; | |
18 | |
19 function align(size) { | |
20 return size + (kAlignment - (size % kAlignment)) % kAlignment; | |
21 } | |
22 | |
23 function isAligned(offset) { | |
24 return offset >= 0 && (offset % kAlignment) === 0; | |
25 } | |
26 | |
27 // Constants ---------------------------------------------------------------- | |
28 | |
29 var kArrayHeaderSize = 8; | |
30 var kStructHeaderSize = 8; | |
31 var kMessageHeaderSize = 16; | |
32 var kMessageWithRequestIDHeaderSize = 24; | |
33 var kMapStructPayloadSize = 16; | |
34 | |
35 var kStructHeaderNumBytesOffset = 0; | |
36 var kStructHeaderNumFieldsOffset = 4; | |
37 | |
38 var kEncodedInvalidHandleValue = 0xFFFFFFFF; | |
39 | |
40 // Decoder ------------------------------------------------------------------ | |
41 | |
42 function Decoder(buffer, handles, base) { | |
43 this.buffer = buffer; | |
44 this.handles = handles; | |
45 this.base = base; | |
46 this.next = base; | |
47 } | |
48 | |
49 Decoder.prototype.skip = function(offset) { | |
50 this.next += offset; | |
51 }; | |
52 | |
53 Decoder.prototype.readInt8 = function() { | |
54 var result = this.buffer.getInt8(this.next); | |
55 this.next += 1; | |
56 return result; | |
57 }; | |
58 | |
59 Decoder.prototype.readUint8 = function() { | |
60 var result = this.buffer.getUint8(this.next); | |
61 this.next += 1; | |
62 return result; | |
63 }; | |
64 | |
65 Decoder.prototype.readInt16 = function() { | |
66 var result = this.buffer.getInt16(this.next); | |
67 this.next += 2; | |
68 return result; | |
69 }; | |
70 | |
71 Decoder.prototype.readUint16 = function() { | |
72 var result = this.buffer.getUint16(this.next); | |
73 this.next += 2; | |
74 return result; | |
75 }; | |
76 | |
77 Decoder.prototype.readInt32 = function() { | |
78 var result = this.buffer.getInt32(this.next); | |
79 this.next += 4; | |
80 return result; | |
81 }; | |
82 | |
83 Decoder.prototype.readUint32 = function() { | |
84 var result = this.buffer.getUint32(this.next); | |
85 this.next += 4; | |
86 return result; | |
87 }; | |
88 | |
89 Decoder.prototype.readInt64 = function() { | |
90 var result = this.buffer.getInt64(this.next); | |
91 this.next += 8; | |
92 return result; | |
93 }; | |
94 | |
95 Decoder.prototype.readUint64 = function() { | |
96 var result = this.buffer.getUint64(this.next); | |
97 this.next += 8; | |
98 return result; | |
99 }; | |
100 | |
101 Decoder.prototype.readFloat = function() { | |
102 var result = this.buffer.getFloat32(this.next); | |
103 this.next += 4; | |
104 return result; | |
105 }; | |
106 | |
107 Decoder.prototype.readDouble = function() { | |
108 var result = this.buffer.getFloat64(this.next); | |
109 this.next += 8; | |
110 return result; | |
111 }; | |
112 | |
113 Decoder.prototype.decodePointer = function() { | |
114 // TODO(abarth): To correctly decode a pointer, we need to know the real | |
115 // base address of the array buffer. | |
116 var offsetPointer = this.next; | |
117 var offset = this.readUint64(); | |
118 if (!offset) | |
119 return 0; | |
120 return offsetPointer + offset; | |
121 }; | |
122 | |
123 Decoder.prototype.decodeAndCreateDecoder = function(pointer) { | |
124 return new Decoder(this.buffer, this.handles, pointer); | |
125 }; | |
126 | |
127 Decoder.prototype.decodeHandle = function() { | |
128 return this.handles[this.readUint32()] || null; | |
129 }; | |
130 | |
131 Decoder.prototype.decodeString = function() { | |
132 var numberOfBytes = this.readUint32(); | |
133 var numberOfElements = this.readUint32(); | |
134 var base = this.next; | |
135 this.next += numberOfElements; | |
136 return unicode.decodeUtf8String( | |
137 new Uint8Array(this.buffer.arrayBuffer, base, numberOfElements)); | |
138 }; | |
139 | |
140 Decoder.prototype.decodeArray = function(cls) { | |
141 var numberOfBytes = this.readUint32(); | |
142 var numberOfElements = this.readUint32(); | |
143 var val = new Array(numberOfElements); | |
144 if (cls === PackedBool) { | |
145 var byte; | |
146 for (var i = 0; i < numberOfElements; ++i) { | |
147 if (i % 8 === 0) | |
148 byte = this.readUint8(); | |
149 val[i] = (byte & (1 << i % 8)) ? true : false; | |
150 } | |
151 } else { | |
152 for (var i = 0; i < numberOfElements; ++i) { | |
153 val[i] = cls.decode(this); | |
154 } | |
155 } | |
156 return val; | |
157 }; | |
158 | |
159 Decoder.prototype.decodeStruct = function(cls) { | |
160 return cls.decode(this); | |
161 }; | |
162 | |
163 Decoder.prototype.decodeStructPointer = function(cls) { | |
164 var pointer = this.decodePointer(); | |
165 if (!pointer) { | |
166 return null; | |
167 } | |
168 return cls.decode(this.decodeAndCreateDecoder(pointer)); | |
169 }; | |
170 | |
171 Decoder.prototype.decodeArrayPointer = function(cls) { | |
172 var pointer = this.decodePointer(); | |
173 if (!pointer) { | |
174 return null; | |
175 } | |
176 return this.decodeAndCreateDecoder(pointer).decodeArray(cls); | |
177 }; | |
178 | |
179 Decoder.prototype.decodeStringPointer = function() { | |
180 var pointer = this.decodePointer(); | |
181 if (!pointer) { | |
182 return null; | |
183 } | |
184 return this.decodeAndCreateDecoder(pointer).decodeString(); | |
185 }; | |
186 | |
187 Decoder.prototype.decodeMap = function(keyClass, valueClass) { | |
188 this.skip(4); // numberOfBytes | |
189 this.skip(4); // numberOfFields | |
190 var keys = this.decodeArrayPointer(keyClass); | |
191 var values = this.decodeArrayPointer(valueClass); | |
192 var val = new Map(); | |
193 for (var i = 0; i < keys.length; i++) | |
194 val.set(keys[i], values[i]); | |
195 return val; | |
196 }; | |
197 | |
198 Decoder.prototype.decodeMapPointer = function(keyClass, valueClass) { | |
199 var pointer = this.decodePointer(); | |
200 if (!pointer) { | |
201 return null; | |
202 } | |
203 var decoder = this.decodeAndCreateDecoder(pointer); | |
204 return decoder.decodeMap(keyClass, valueClass); | |
205 }; | |
206 | |
207 // Encoder ------------------------------------------------------------------ | |
208 | |
209 function Encoder(buffer, handles, base) { | |
210 this.buffer = buffer; | |
211 this.handles = handles; | |
212 this.base = base; | |
213 this.next = base; | |
214 } | |
215 | |
216 Encoder.prototype.skip = function(offset) { | |
217 this.next += offset; | |
218 }; | |
219 | |
220 Encoder.prototype.writeInt8 = function(val) { | |
221 this.buffer.setInt8(this.next, val); | |
222 this.next += 1; | |
223 }; | |
224 | |
225 Encoder.prototype.writeUint8 = function(val) { | |
226 if (val < 0) { | |
227 throw new Error(kErrorUnsigned); | |
228 } | |
229 this.buffer.setUint8(this.next, val); | |
230 this.next += 1; | |
231 }; | |
232 | |
233 Encoder.prototype.writeInt16 = function(val) { | |
234 this.buffer.setInt16(this.next, val); | |
235 this.next += 2; | |
236 }; | |
237 | |
238 Encoder.prototype.writeUint16 = function(val) { | |
239 if (val < 0) { | |
240 throw new Error(kErrorUnsigned); | |
241 } | |
242 this.buffer.setUint16(this.next, val); | |
243 this.next += 2; | |
244 }; | |
245 | |
246 Encoder.prototype.writeInt32 = function(val) { | |
247 this.buffer.setInt32(this.next, val); | |
248 this.next += 4; | |
249 }; | |
250 | |
251 Encoder.prototype.writeUint32 = function(val) { | |
252 if (val < 0) { | |
253 throw new Error(kErrorUnsigned); | |
254 } | |
255 this.buffer.setUint32(this.next, val); | |
256 this.next += 4; | |
257 }; | |
258 | |
259 Encoder.prototype.writeInt64 = function(val) { | |
260 this.buffer.setInt64(this.next, val); | |
261 this.next += 8; | |
262 }; | |
263 | |
264 Encoder.prototype.writeUint64 = function(val) { | |
265 if (val < 0) { | |
266 throw new Error(kErrorUnsigned); | |
267 } | |
268 this.buffer.setUint64(this.next, val); | |
269 this.next += 8; | |
270 }; | |
271 | |
272 Encoder.prototype.writeFloat = function(val) { | |
273 this.buffer.setFloat32(this.next, val); | |
274 this.next += 4; | |
275 }; | |
276 | |
277 Encoder.prototype.writeDouble = function(val) { | |
278 this.buffer.setFloat64(this.next, val); | |
279 this.next += 8; | |
280 }; | |
281 | |
282 Encoder.prototype.encodePointer = function(pointer) { | |
283 if (!pointer) | |
284 return this.writeUint64(0); | |
285 // TODO(abarth): To correctly encode a pointer, we need to know the real | |
286 // base address of the array buffer. | |
287 var offset = pointer - this.next; | |
288 this.writeUint64(offset); | |
289 }; | |
290 | |
291 Encoder.prototype.createAndEncodeEncoder = function(size) { | |
292 var pointer = this.buffer.alloc(align(size)); | |
293 this.encodePointer(pointer); | |
294 return new Encoder(this.buffer, this.handles, pointer); | |
295 }; | |
296 | |
297 Encoder.prototype.encodeHandle = function(handle) { | |
298 this.handles.push(handle); | |
299 this.writeUint32(this.handles.length - 1); | |
300 }; | |
301 | |
302 Encoder.prototype.encodeString = function(val) { | |
303 var base = this.next + kArrayHeaderSize; | |
304 var numberOfElements = unicode.encodeUtf8String( | |
305 val, new Uint8Array(this.buffer.arrayBuffer, base)); | |
306 var numberOfBytes = kArrayHeaderSize + numberOfElements; | |
307 this.writeUint32(numberOfBytes); | |
308 this.writeUint32(numberOfElements); | |
309 this.next += numberOfElements; | |
310 }; | |
311 | |
312 Encoder.prototype.encodeArray = | |
313 function(cls, val, numberOfElements, encodedSize) { | |
314 if (numberOfElements === undefined) | |
315 numberOfElements = val.length; | |
316 if (encodedSize === undefined) | |
317 encodedSize = kArrayHeaderSize + cls.encodedSize * numberOfElements; | |
318 | |
319 this.writeUint32(encodedSize); | |
320 this.writeUint32(numberOfElements); | |
321 | |
322 if (cls === PackedBool) { | |
323 var byte = 0; | |
324 for (i = 0; i < numberOfElements; ++i) { | |
325 if (val[i]) | |
326 byte |= (1 << i % 8); | |
327 if (i % 8 === 7 || i == numberOfElements - 1) { | |
328 Uint8.encode(this, byte); | |
329 byte = 0; | |
330 } | |
331 } | |
332 } else { | |
333 for (var i = 0; i < numberOfElements; ++i) | |
334 cls.encode(this, val[i]); | |
335 } | |
336 }; | |
337 | |
338 Encoder.prototype.encodeStruct = function(cls, val) { | |
339 return cls.encode(this, val); | |
340 }; | |
341 | |
342 Encoder.prototype.encodeStructPointer = function(cls, val) { | |
343 if (val == null) { | |
344 // Also handles undefined, since undefined == null. | |
345 this.encodePointer(val); | |
346 return; | |
347 } | |
348 var encoder = this.createAndEncodeEncoder(cls.encodedSize); | |
349 cls.encode(encoder, val); | |
350 }; | |
351 | |
352 Encoder.prototype.encodeArrayPointer = function(cls, val) { | |
353 if (val == null) { | |
354 // Also handles undefined, since undefined == null. | |
355 this.encodePointer(val); | |
356 return; | |
357 } | |
358 | |
359 var numberOfElements = val.length; | |
360 if (!Number.isSafeInteger(numberOfElements) || numberOfElements < 0) | |
361 throw new Error(kErrorArray); | |
362 | |
363 var encodedSize = kArrayHeaderSize + ((cls === PackedBool) ? | |
364 Math.ceil(numberOfElements / 8) : cls.encodedSize * numberOfElements); | |
365 var encoder = this.createAndEncodeEncoder(encodedSize); | |
366 encoder.encodeArray(cls, val, numberOfElements, encodedSize); | |
367 }; | |
368 | |
369 Encoder.prototype.encodeStringPointer = function(val) { | |
370 if (val == null) { | |
371 // Also handles undefined, since undefined == null. | |
372 this.encodePointer(val); | |
373 return; | |
374 } | |
375 // Only accepts string primivites, not String Objects like new String("foo") | |
376 if (typeof(val) !== "string") { | |
377 throw new Error(kErrorString); | |
378 } | |
379 var encodedSize = kArrayHeaderSize + unicode.utf8Length(val); | |
380 var encoder = this.createAndEncodeEncoder(encodedSize); | |
381 encoder.encodeString(val); | |
382 }; | |
383 | |
384 Encoder.prototype.encodeMap = function(keyClass, valueClass, val) { | |
385 var keys = new Array(val.size); | |
386 var values = new Array(val.size); | |
387 var i = 0; | |
388 val.forEach(function(value, key) { | |
389 values[i] = value; | |
390 keys[i++] = key; | |
391 }); | |
392 this.writeUint32(kStructHeaderSize + kMapStructPayloadSize); | |
393 this.writeUint32(2); // two fields: keys, values | |
394 this.encodeArrayPointer(keyClass, keys); | |
395 this.encodeArrayPointer(valueClass, values); | |
396 } | |
397 | |
398 Encoder.prototype.encodeMapPointer = function(keyClass, valueClass, val) { | |
399 if (val == null) { | |
400 // Also handles undefined, since undefined == null. | |
401 this.encodePointer(val); | |
402 return; | |
403 } | |
404 if (!(val instanceof Map)) { | |
405 throw new Error(kErrorMap); | |
406 } | |
407 var encodedSize = kStructHeaderSize + kMapStructPayloadSize; | |
408 var encoder = this.createAndEncodeEncoder(encodedSize); | |
409 encoder.encodeMap(keyClass, valueClass, val); | |
410 }; | |
411 | |
412 // Message ------------------------------------------------------------------ | |
413 | |
414 var kMessageNameOffset = kStructHeaderSize; | |
415 var kMessageFlagsOffset = kMessageNameOffset + 4; | |
416 var kMessageRequestIDOffset = kMessageFlagsOffset + 4; | |
417 | |
418 var kMessageExpectsResponse = 1 << 0; | |
419 var kMessageIsResponse = 1 << 1; | |
420 | |
421 function Message(buffer, handles) { | |
422 this.buffer = buffer; | |
423 this.handles = handles; | |
424 } | |
425 | |
426 Message.prototype.getHeaderNumBytes = function() { | |
427 return this.buffer.getUint32(kStructHeaderNumBytesOffset); | |
428 }; | |
429 | |
430 Message.prototype.getHeaderNumFields = function() { | |
431 return this.buffer.getUint32(kStructHeaderNumFieldsOffset); | |
432 }; | |
433 | |
434 Message.prototype.getName = function() { | |
435 return this.buffer.getUint32(kMessageNameOffset); | |
436 }; | |
437 | |
438 Message.prototype.getFlags = function() { | |
439 return this.buffer.getUint32(kMessageFlagsOffset); | |
440 }; | |
441 | |
442 Message.prototype.isResponse = function() { | |
443 return (this.getFlags() & kMessageIsResponse) != 0; | |
444 }; | |
445 | |
446 Message.prototype.expectsResponse = function() { | |
447 return (this.getFlags() & kMessageExpectsResponse) != 0; | |
448 }; | |
449 | |
450 Message.prototype.setRequestID = function(requestID) { | |
451 // TODO(darin): Verify that space was reserved for this field! | |
452 this.buffer.setUint64(kMessageRequestIDOffset, requestID); | |
453 }; | |
454 | |
455 | |
456 // MessageBuilder ----------------------------------------------------------- | |
457 | |
458 function MessageBuilder(messageName, payloadSize) { | |
459 // Currently, we don't compute the payload size correctly ahead of time. | |
460 // Instead, we resize the buffer at the end. | |
461 var numberOfBytes = kMessageHeaderSize + payloadSize; | |
462 this.buffer = new buffer.Buffer(numberOfBytes); | |
463 this.handles = []; | |
464 var encoder = this.createEncoder(kMessageHeaderSize); | |
465 encoder.writeUint32(kMessageHeaderSize); | |
466 encoder.writeUint32(2); // num_fields. | |
467 encoder.writeUint32(messageName); | |
468 encoder.writeUint32(0); // flags. | |
469 } | |
470 | |
471 MessageBuilder.prototype.createEncoder = function(size) { | |
472 var pointer = this.buffer.alloc(size); | |
473 return new Encoder(this.buffer, this.handles, pointer); | |
474 }; | |
475 | |
476 MessageBuilder.prototype.encodeStruct = function(cls, val) { | |
477 cls.encode(this.createEncoder(cls.encodedSize), val); | |
478 }; | |
479 | |
480 MessageBuilder.prototype.finish = function() { | |
481 // TODO(abarth): Rather than resizing the buffer at the end, we could | |
482 // compute the size we need ahead of time, like we do in C++. | |
483 this.buffer.trim(); | |
484 var message = new Message(this.buffer, this.handles); | |
485 this.buffer = null; | |
486 this.handles = null; | |
487 this.encoder = null; | |
488 return message; | |
489 }; | |
490 | |
491 // MessageWithRequestIDBuilder ----------------------------------------------- | |
492 | |
493 function MessageWithRequestIDBuilder(messageName, payloadSize, flags, | |
494 requestID) { | |
495 // Currently, we don't compute the payload size correctly ahead of time. | |
496 // Instead, we resize the buffer at the end. | |
497 var numberOfBytes = kMessageWithRequestIDHeaderSize + payloadSize; | |
498 this.buffer = new buffer.Buffer(numberOfBytes); | |
499 this.handles = []; | |
500 var encoder = this.createEncoder(kMessageWithRequestIDHeaderSize); | |
501 encoder.writeUint32(kMessageWithRequestIDHeaderSize); | |
502 encoder.writeUint32(3); // num_fields. | |
503 encoder.writeUint32(messageName); | |
504 encoder.writeUint32(flags); | |
505 encoder.writeUint64(requestID); | |
506 } | |
507 | |
508 MessageWithRequestIDBuilder.prototype = | |
509 Object.create(MessageBuilder.prototype); | |
510 | |
511 MessageWithRequestIDBuilder.prototype.constructor = | |
512 MessageWithRequestIDBuilder; | |
513 | |
514 // MessageReader ------------------------------------------------------------ | |
515 | |
516 function MessageReader(message) { | |
517 this.decoder = new Decoder(message.buffer, message.handles, 0); | |
518 var messageHeaderSize = this.decoder.readUint32(); | |
519 this.payloadSize = message.buffer.byteLength - messageHeaderSize; | |
520 var numFields = this.decoder.readUint32(); | |
521 this.messageName = this.decoder.readUint32(); | |
522 this.flags = this.decoder.readUint32(); | |
523 if (numFields >= 3) | |
524 this.requestID = this.decoder.readUint64(); | |
525 this.decoder.skip(messageHeaderSize - this.decoder.next); | |
526 } | |
527 | |
528 MessageReader.prototype.decodeStruct = function(cls) { | |
529 return cls.decode(this.decoder); | |
530 }; | |
531 | |
532 // Built-in types ----------------------------------------------------------- | |
533 | |
534 // This type is only used with ArrayOf(PackedBool). | |
535 function PackedBool() { | |
536 } | |
537 | |
538 function Int8() { | |
539 } | |
540 | |
541 Int8.encodedSize = 1; | |
542 | |
543 Int8.decode = function(decoder) { | |
544 return decoder.readInt8(); | |
545 }; | |
546 | |
547 Int8.encode = function(encoder, val) { | |
548 encoder.writeInt8(val); | |
549 }; | |
550 | |
551 Uint8.encode = function(encoder, val) { | |
552 encoder.writeUint8(val); | |
553 }; | |
554 | |
555 function Uint8() { | |
556 } | |
557 | |
558 Uint8.encodedSize = 1; | |
559 | |
560 Uint8.decode = function(decoder) { | |
561 return decoder.readUint8(); | |
562 }; | |
563 | |
564 Uint8.encode = function(encoder, val) { | |
565 encoder.writeUint8(val); | |
566 }; | |
567 | |
568 function Int16() { | |
569 } | |
570 | |
571 Int16.encodedSize = 2; | |
572 | |
573 Int16.decode = function(decoder) { | |
574 return decoder.readInt16(); | |
575 }; | |
576 | |
577 Int16.encode = function(encoder, val) { | |
578 encoder.writeInt16(val); | |
579 }; | |
580 | |
581 function Uint16() { | |
582 } | |
583 | |
584 Uint16.encodedSize = 2; | |
585 | |
586 Uint16.decode = function(decoder) { | |
587 return decoder.readUint16(); | |
588 }; | |
589 | |
590 Uint16.encode = function(encoder, val) { | |
591 encoder.writeUint16(val); | |
592 }; | |
593 | |
594 function Int32() { | |
595 } | |
596 | |
597 Int32.encodedSize = 4; | |
598 | |
599 Int32.decode = function(decoder) { | |
600 return decoder.readInt32(); | |
601 }; | |
602 | |
603 Int32.encode = function(encoder, val) { | |
604 encoder.writeInt32(val); | |
605 }; | |
606 | |
607 function Uint32() { | |
608 } | |
609 | |
610 Uint32.encodedSize = 4; | |
611 | |
612 Uint32.decode = function(decoder) { | |
613 return decoder.readUint32(); | |
614 }; | |
615 | |
616 Uint32.encode = function(encoder, val) { | |
617 encoder.writeUint32(val); | |
618 }; | |
619 | |
620 function Int64() { | |
621 } | |
622 | |
623 Int64.encodedSize = 8; | |
624 | |
625 Int64.decode = function(decoder) { | |
626 return decoder.readInt64(); | |
627 }; | |
628 | |
629 Int64.encode = function(encoder, val) { | |
630 encoder.writeInt64(val); | |
631 }; | |
632 | |
633 function Uint64() { | |
634 } | |
635 | |
636 Uint64.encodedSize = 8; | |
637 | |
638 Uint64.decode = function(decoder) { | |
639 return decoder.readUint64(); | |
640 }; | |
641 | |
642 Uint64.encode = function(encoder, val) { | |
643 encoder.writeUint64(val); | |
644 }; | |
645 | |
646 function String() { | |
647 }; | |
648 | |
649 String.encodedSize = 8; | |
650 | |
651 String.decode = function(decoder) { | |
652 return decoder.decodeStringPointer(); | |
653 }; | |
654 | |
655 String.encode = function(encoder, val) { | |
656 encoder.encodeStringPointer(val); | |
657 }; | |
658 | |
659 function NullableString() { | |
660 } | |
661 | |
662 NullableString.encodedSize = String.encodedSize; | |
663 | |
664 NullableString.decode = String.decode; | |
665 | |
666 NullableString.encode = String.encode; | |
667 | |
668 function Float() { | |
669 } | |
670 | |
671 Float.encodedSize = 4; | |
672 | |
673 Float.decode = function(decoder) { | |
674 return decoder.readFloat(); | |
675 }; | |
676 | |
677 Float.encode = function(encoder, val) { | |
678 encoder.writeFloat(val); | |
679 }; | |
680 | |
681 function Double() { | |
682 } | |
683 | |
684 Double.encodedSize = 8; | |
685 | |
686 Double.decode = function(decoder) { | |
687 return decoder.readDouble(); | |
688 }; | |
689 | |
690 Double.encode = function(encoder, val) { | |
691 encoder.writeDouble(val); | |
692 }; | |
693 | |
694 function PointerTo(cls) { | |
695 this.cls = cls; | |
696 } | |
697 | |
698 PointerTo.prototype.encodedSize = 8; | |
699 | |
700 PointerTo.prototype.decode = function(decoder) { | |
701 var pointer = decoder.decodePointer(); | |
702 if (!pointer) { | |
703 return null; | |
704 } | |
705 return this.cls.decode(decoder.decodeAndCreateDecoder(pointer)); | |
706 }; | |
707 | |
708 PointerTo.prototype.encode = function(encoder, val) { | |
709 if (!val) { | |
710 encoder.encodePointer(val); | |
711 return; | |
712 } | |
713 var objectEncoder = encoder.createAndEncodeEncoder(this.cls.encodedSize); | |
714 this.cls.encode(objectEncoder, val); | |
715 }; | |
716 | |
717 function NullablePointerTo(cls) { | |
718 PointerTo.call(this, cls); | |
719 } | |
720 | |
721 NullablePointerTo.prototype = Object.create(PointerTo.prototype); | |
722 | |
723 function ArrayOf(cls, length) { | |
724 this.cls = cls; | |
725 this.length = length || 0; | |
726 } | |
727 | |
728 ArrayOf.prototype.encodedSize = 8; | |
729 | |
730 ArrayOf.prototype.dimensions = function() { | |
731 return [this.length].concat( | |
732 (this.cls instanceof ArrayOf) ? this.cls.dimensions() : []); | |
733 } | |
734 | |
735 ArrayOf.prototype.decode = function(decoder) { | |
736 return decoder.decodeArrayPointer(this.cls); | |
737 }; | |
738 | |
739 ArrayOf.prototype.encode = function(encoder, val) { | |
740 encoder.encodeArrayPointer(this.cls, val); | |
741 }; | |
742 | |
743 function NullableArrayOf(cls) { | |
744 ArrayOf.call(this, cls); | |
745 } | |
746 | |
747 NullableArrayOf.prototype = Object.create(ArrayOf.prototype); | |
748 | |
749 function Handle() { | |
750 } | |
751 | |
752 Handle.encodedSize = 4; | |
753 | |
754 Handle.decode = function(decoder) { | |
755 return decoder.decodeHandle(); | |
756 }; | |
757 | |
758 Handle.encode = function(encoder, val) { | |
759 encoder.encodeHandle(val); | |
760 }; | |
761 | |
762 function NullableHandle() { | |
763 } | |
764 | |
765 NullableHandle.encodedSize = Handle.encodedSize; | |
766 | |
767 NullableHandle.decode = Handle.decode; | |
768 | |
769 NullableHandle.encode = Handle.encode; | |
770 | |
771 function MapOf(keyClass, valueClass) { | |
772 this.keyClass = keyClass; | |
773 this.valueClass = valueClass; | |
774 } | |
775 | |
776 MapOf.prototype.encodedSize = 8; | |
777 | |
778 MapOf.prototype.decode = function(decoder) { | |
779 return decoder.decodeMapPointer(this.keyClass, this.valueClass); | |
780 }; | |
781 | |
782 MapOf.prototype.encode = function(encoder, val) { | |
783 encoder.encodeMapPointer(this.keyClass, this.valueClass, val); | |
784 }; | |
785 | |
786 function NullableMapOf(keyClass, valueClass) { | |
787 MapOf.call(this, keyClass, valueClass); | |
788 } | |
789 | |
790 NullableMapOf.prototype = Object.create(MapOf.prototype); | |
791 | |
792 var exports = {}; | |
793 exports.align = align; | |
794 exports.isAligned = isAligned; | |
795 exports.Message = Message; | |
796 exports.MessageBuilder = MessageBuilder; | |
797 exports.MessageWithRequestIDBuilder = MessageWithRequestIDBuilder; | |
798 exports.MessageReader = MessageReader; | |
799 exports.kArrayHeaderSize = kArrayHeaderSize; | |
800 exports.kMapStructPayloadSize = kMapStructPayloadSize; | |
801 exports.kStructHeaderSize = kStructHeaderSize; | |
802 exports.kEncodedInvalidHandleValue = kEncodedInvalidHandleValue; | |
803 exports.kMessageHeaderSize = kMessageHeaderSize; | |
804 exports.kMessageWithRequestIDHeaderSize = kMessageWithRequestIDHeaderSize; | |
805 exports.kMessageExpectsResponse = kMessageExpectsResponse; | |
806 exports.kMessageIsResponse = kMessageIsResponse; | |
807 exports.Int8 = Int8; | |
808 exports.Uint8 = Uint8; | |
809 exports.Int16 = Int16; | |
810 exports.Uint16 = Uint16; | |
811 exports.Int32 = Int32; | |
812 exports.Uint32 = Uint32; | |
813 exports.Int64 = Int64; | |
814 exports.Uint64 = Uint64; | |
815 exports.Float = Float; | |
816 exports.Double = Double; | |
817 exports.String = String; | |
818 exports.NullableString = NullableString; | |
819 exports.PointerTo = PointerTo; | |
820 exports.NullablePointerTo = NullablePointerTo; | |
821 exports.ArrayOf = ArrayOf; | |
822 exports.NullableArrayOf = NullableArrayOf; | |
823 exports.PackedBool = PackedBool; | |
824 exports.Handle = Handle; | |
825 exports.NullableHandle = NullableHandle; | |
826 exports.MapOf = MapOf; | |
827 exports.NullableMapOf = NullableMapOf; | |
828 return exports; | |
829 }); | |
OLD | NEW |