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