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.
7 const int kAlignment = 8;
8 const int kArrayHeaderSize = 8;
9 const int kStructHeaderSize = 8;
10 const int kMessageHeaderSize = 16;
11 const int kMessageWithRequestIDHeaderSize = 24;
12 const int kMapStructPayloadSize = 16;
13 const int kStructHeaderNumBytesOffset = 0;
14 const int kStructHeaderNumFieldsOffset = 4;
15 const int kEncodedInvalidHandleValue = 0xffffffff;
16 const String kErrorUnsigned = "Passing negative value to unsigned encoder";
19 int align(int size) => size + (kAlignment - (size % kAlignment)) % kAlignment;
20 bool isAligned(offset) => (offset >= 0) && ((offset % kAlignment) == 0);
23 Uint8List utf8OfString(String s) =>
24 (new Uint8List.fromList((const Utf8Encoder()).convert(s)));
27 String stringOfUtf8(Uint8List bytes) =>
28 (const Utf8Decoder()).convert(bytes.toList());
31 // Given an argument that is either a Type or an instance:
32 // Invoke the static method "decode" of the Type, or the instance method
33 // "decode" of the instance, on the MojoDecoder.
34 Object _callDecode(Object typeOrInstance, MojoDecoder decoder) {
35 if (typeOrInstance is Type) {
36 return reflectClass(typeOrInstance).invoke(#decode, [decoder]).reflectee;
38 return typeOrInstance.decode(decoder);
43 // Given an argument that is either a Type or an instance:
44 // Invoke the static method "encode" of the Type, or the instance method
45 // "encode" of the instance, on the MojoEncoder and value to be encoded.
46 void _callEncode(Object typeOrInstance, MojoEncoder encoder, Object val) {
47 if (typeOrInstance is Type) {
48 reflectClass(typeOrInstance).invoke(#encode, [encoder, val]);
50 typeOrInstance.encode(encoder, val);
55 // Given an argument that is either a Type or an instance:
56 // Invoke the static getter "encodedSize" of the Type, or the instance getter
57 // "encodedSize" of the instance, and return the result.
58 int getEncodedSize(Object typeOrInstance) {
59 if (typeOrInstance is Type) {
60 return reflectClass(typeOrInstance).getField(#encodedSize).reflectee;
62 return typeOrInstance.encodedSize;
73 MojoDecoder(this.buffer, this.handles, this.base) {
77 void skip(int offset) {
82 int result = buffer.getInt8(next);
88 int result = buffer.getUint8(next);
94 int result = buffer.getInt16(next, Endianness.LITTLE_ENDIAN);
100 int result = buffer.getUint16(next, Endianness.LITTLE_ENDIAN);
106 int result = buffer.getInt32(next, Endianness.LITTLE_ENDIAN);
112 int result = buffer.getUint32(next, Endianness.LITTLE_ENDIAN);
118 int result = buffer.getInt64(next, Endianness.LITTLE_ENDIAN);
124 int result = buffer.getUint64(next, Endianness.LITTLE_ENDIAN);
130 double result = buffer.getFloat32(next,Endianness.LITTLE_ENDIAN);
135 double readDouble() {
136 double result = buffer.getFloat64(next, Endianness.LITTLE_ENDIAN);
141 int decodePointer() {
142 int offsetPointer = next;
143 int offset = readUint64();
147 return offsetPointer + offset;
150 MojoDecoder decodeAndCreateDecoder(int offset) {
151 return new MojoDecoder(buffer, handles, offset);
155 return handles[readUint32()];
158 String decodeString() {
159 int numBytes = readUint32();
160 int numElements = readUint32();
163 return stringOfUtf8(buffer.buffer.asUint8List(base, numElements));
166 List decodeArray(Object type) {
167 int numBytes = readUint32();
168 int numElements = readUint32();
169 if (type == PackedBool) {
171 List<bool> result = new List<bool>(numElements);
172 for (int i = 0; i < numElements; i++) {
176 result[i] = ((b & (1 << (i % 8)) != 0) ? true : false);
180 List result = new List(numElements);
181 for (int i = 0; i < numElements; i++) {
182 result[i] = _callDecode(type, this);
188 Object decodeStruct(Object t) {
189 return _callDecode(t, this);
192 Object decodeStructPointer(Object t) {
193 int pointer = decodePointer();
197 return _callDecode(t, decodeAndCreateDecoder(pointer));
200 List decodeArrayPointer(Object type) {
201 int pointer = decodePointer();
205 return decodeAndCreateDecoder(pointer).decodeArray(type);
208 String decodeStringPointer() {
209 int pointer = decodePointer();
213 return decodeAndCreateDecoder(pointer).decodeString();
216 Map decodeMap(Object keyType, Object valType) {
217 skip(4); // number of bytes.
218 skip(4); // number of fields.
219 List keys = decodeArrayPointer(keyType);
220 List values = decodeArrayPointer(valType);
221 return new Map.fromIterables(keys, values);
224 Map decodeMapPointer(Object keyType, Object valType) {
225 int pointer = this.decodePointer();
229 MojoDecoder decoder = decodeAndCreateDecoder(pointer);
230 return decoder.decodeMap(keyType, valType);
242 MojoEncoder(this.buffer, this.handles, this.base, this.extent) {
246 void skip(int offset) {
250 void writeInt8(int val) {
251 buffer.setInt8(next, val);
255 void writeUint8(int val) {
257 throw new ArgumentError("$kErrorUnsigned: $val");
259 buffer.setUint8(next, val);
263 void writeInt16(int val) {
264 buffer.setInt16(next, val, Endianness.LITTLE_ENDIAN);
268 void writeUint16(int val) {
270 throw new ArgumentError("$kErrorUnsigned: $val");
272 buffer.setUint16(next, val, Endianness.LITTLE_ENDIAN);
276 void writeInt32(int val) {
277 buffer.setInt32(next, val, Endianness.LITTLE_ENDIAN);
281 void writeUint32(int val) {
283 throw new ArgumentError("$kErrorUnsigned: $val");
285 buffer.setUint32(next, val, Endianness.LITTLE_ENDIAN);
289 void writeInt64(int val) {
290 buffer.setInt64(next, val, Endianness.LITTLE_ENDIAN);
294 void writeUint64(int val) {
296 throw new ArgumentError("$kErrorUnsigned: $val");
298 buffer.setUint64(next, val, Endianness.LITTLE_ENDIAN);
302 void writeFloat(double val) {
303 buffer.setFloat32(next, val, Endianness.LITTLE_ENDIAN);
307 void writeDouble(double val) {
308 buffer.setFloat64(next, val, Endianness.LITTLE_ENDIAN);
312 void encodePointer(int pointer) {
313 if (pointer == null) {
317 int offset = pointer - next;
321 void grow(int new_size) {
322 Uint8List new_buffer = new Uint8List(new_size);
323 new_buffer.setRange(0, next, buffer.buffer.asUint8List());
324 buffer = new_buffer.buffer.asByteData();
327 int alloc(int size_request) {
328 int pointer = extent;
329 extent += size_request;
330 if (extent > buffer.lengthInBytes) {
331 int new_size = buffer.lengthInBytes + size_request;
332 new_size += new_size ~/ 2;
338 MojoEncoder createAndEncodeEncoder(int size) {
339 int pointer = alloc(align(size));
340 encodePointer(pointer);
341 return new MojoEncoder(buffer, handles, pointer, extent);
344 void encodeHandle(int handle) {
346 writeUint32(handles.length - 1);
349 void encodeString(String val) {
350 Uint8List utf8string = utf8OfString(val);
351 int numElements = utf8string.lengthInBytes;
352 int numBytes = kArrayHeaderSize + numElements;
353 writeUint32(numBytes);
354 writeUint32(numElements);
355 buffer.buffer.asUint8List().setRange(next, next + numElements, utf8string);
359 void encodeArray(Object t, List val, [int numElements, int encodedSize]) {
360 if (numElements == null) {
361 numElements = val.length;
363 if (encodedSize == null) {
364 encodedSize = kArrayHeaderSize + (getEncodedSize(t) * numElements);
367 writeUint32(encodedSize);
368 writeUint32(numElements);
370 if (t == PackedBool) {
372 for (int i = 0; i < numElements; i++) {
376 if (((i % 8) == 7) || (i == (numElements - 1))) {
377 Uint8.encode(this, b);
381 for (int i = 0; i < numElements; i++) {
382 _callEncode(t, this, val[i]);
387 void encodeStruct(Object t, Object val) {
388 _callEncode(t, this, val);
391 void encodeStructPointer(Object t, Object val) {
396 MojoEncoder encoder = createAndEncodeEncoder(getEncodedSize(t));
397 _callEncode(t, encoder, val);
398 extent = encoder.extent;
399 buffer = encoder.buffer;
402 void encodeArrayPointer(Object t, List val) {
407 int numElements = val.length;
408 int encodedSize = kArrayHeaderSize + ((t == PackedBool) ?
409 (numElements / 8).ceil() : (getEncodedSize(t) * numElements));
410 MojoEncoder encoder = createAndEncodeEncoder(encodedSize);
411 encoder.encodeArray(t, val, numElements, encodedSize);
412 extent = encoder.extent;
413 buffer = encoder.buffer;
416 void encodeStringPointer(String val) {
421 int encodedSize = kArrayHeaderSize + utf8OfString(val).lengthInBytes;
422 MojoEncoder encoder = createAndEncodeEncoder(encodedSize);
423 encoder.encodeString(val);
424 extent = encoder.extent;
425 buffer = encoder.buffer;
428 void encodeMap(Object keyType, Object valType, Map val) {
429 List keys = val.keys;
430 List vals = val.values;
431 writeUint32(kStructHeaderSize + kMapStructPayloadSize);
433 encodeArrayPointer(keyType, keys);
434 encodeArrayPointer(valType, vals);
437 void encodeMapPointer(Object keyTYpe, Object valType, Map val) {
442 int encodedSize = kStructHeaderSize + kMapStructPayloadSize;
443 MojoEncoder encoder = createAndEncodeEncoder(encodedSize);
444 encoder.encodeMap(keyType, valType, val);
445 extent = encoder.extent;
446 buffer = encoder.buffer;
451 const int kMessageNameOffset = kStructHeaderSize;
452 const int kMessageFlagsOffset = kMessageNameOffset + 4;
453 const int kMessageRequestIDOffset = kMessageFlagsOffset + 4;
454 const int kMessageExpectsResponse = 1 << 0;
455 const int kMessageIsResponse = 1 << 1;
461 Message(this.buffer, this.handles);
463 int getHeaderNumBytes() => buffer.getUint32(kStructHeaderNumBytesOffset);
464 int getHeaderNumFields() => buffer.getUint32(kStructHeaderNumFieldsOffset);
465 int getName() => buffer.getUint32(kMessageNameOffset);
466 int getFlags() => buffer.getUint32(kMessageFlagsOffset);
467 bool isResponse() => (getFlags() & kMessageIsResponse) != 0;
468 bool expectsResponse() => (getFlags() & kMessageExpectsResponse) != 0;
470 void setRequestID(int id) {
471 buffer.setUint64(kMessageRequestIDOffset, id);
476 class MessageBuilder {
480 MessageBuilder(int name, int payloadSize) {
481 int numBytes = kMessageHeaderSize + payloadSize;
482 var buffer = new ByteData(numBytes);
485 encoder = new MojoEncoder(buffer, handles, 0, kMessageHeaderSize);
486 encoder.writeUint32(kMessageHeaderSize);
487 encoder.writeUint32(2); // num_fields;
488 encoder.writeUint32(name);
489 encoder.writeUint32(0); // flags.
492 MojoEncoder createEncoder(int size) {
493 encoder = new MojoEncoder(encoder.buffer,
496 encoder.next + size);
500 void encodeStruct(Object t, Object val) {
501 encoder = createEncoder(getEncodedSize(t));
502 _callEncode(t, encoder, val);
505 ByteData _trimBuffer() {
506 return new ByteData.view(encoder.buffer.buffer, 0, encoder.extent);
510 Message message = new Message(_trimBuffer(), handles);
518 class MessageWithRequestIDBuilder extends MessageBuilder {
519 MessageWithRequestIDBuilder(
520 int name, int payloadSize, int flags, int requestID) {
521 int numBytes = kMessageWithRequestIDHeaderSize + payloadSize;
522 buffer = new ByteData(numBytes);
526 encoder = createEncoder(0, kMessageWithRequestIDHeaderSize);
527 encoder.writeUint32(kMessageWithRequestIDHeaderSize);
528 encoder.writeUint32(3); // num_fields.
529 encoder.writeUint32(name);
530 encoder.writeUint32(flags);
531 encoder.writeUint64(requestID);
533 buffer = encoder.buffer;
538 class MessageReader {
545 MessageReader(Message message) {
546 decoder = new MojoDecoder(message.buffer, message.handles, 0);
548 int messageHeaderSize = decoder.readUint32();
549 payloadSize = message.buffer.lengthInBytes - messageHeaderSize;
551 int num_fields = decoder.readUint32();
552 name = decoder.readUint32();
553 flags = decoder.readUint32();
555 if (num_fields >= 3) {
556 requestID = decoder.readUint64();
558 decoder.skip(messageHeaderSize - decoder.next);
561 Object decodeStruct(Object t) => _callDecode(t, decoder);
565 abstract class MojoType<T> {
566 static const int encodedSize = 0;
567 static T decode(MojoDecoder decoder) { return null }
568 static void encode(MojoEncoder encoder, T val) {}
575 class Int8 implements MojoType<int> {
576 static const int encodedSize = 1;
577 static int decode(MojoDecoder decoder) => decoder.readInt8();
578 static void encode(MojoEncoder encoder, int val) {
579 encoder.writeInt8(val);
584 class Uint8 implements MojoType<int> {
585 static const int encodedSize = 1;
586 static int decode(MojoDecoder decoder) => decoder.readUint8();
587 static void encode(MojoEncoder encoder, int val) {
588 encoder.writeUint8(val);
593 class Int16 implements MojoType<int> {
594 static const int encodedSize = 2;
595 static int decode(MojoDecoder decoder) => decoder.readInt16();
596 static void encode(MojoEncoder encoder, int val) {
597 encoder.writeInt16(val);
602 class Uint16 implements MojoType<int> {
603 static const int encodedSize = 2;
604 static int decode(MojoDecoder decoder) => decoder.readUint16();
605 static void encode(MojoEncoder encoder, int val) {
606 encoder.writeUint16(val);
611 class Int32 implements MojoType<int> {
612 static const int encodedSize = 4;
613 static int decode(MojoDecoder decoder) => decoder.readInt32();
614 static void encode(MojoEncoder encoder, int val) {
615 encoder.writeInt32(val);
620 class Uint32 implements MojoType<int> {
621 static const int encodedSize = 4;
622 static int decode(MojoDecoder decoder) => decoder.readUint32();
623 static void encode(MojoEncoder encoder, int val) {
624 encoder.writeUint32(val);
629 class Int64 implements MojoType<int> {
630 static const int encodedSize = 8;
631 static int decode(MojoDecoder decoder) => decoder.readInt64();
632 static void encode(MojoEncoder encoder, int val) {
633 encoder.writeInt64(val);
638 class Uint64 implements MojoType<int> {
639 static const int encodedSize = 8;
640 static int decode(MojoDecoder decoder) => decoder.readUint64();
641 static void encode(MojoEncoder encoder, int val) {
642 encoder.writeUint64(val);
647 class MojoString implements MojoType<String> {
648 static const int encodedSize = 8;
649 static String decode(MojoDecoder decoder) => decoder.decodeStringPointer();
650 static void encode(MojoEncoder encoder, String val) {
651 encoder.encodeStringPointer(val);
656 class NullableMojoString implements MojoType<String> {
657 static const int encodedSize = MojoString.encodedSize;
658 static var decode = MojoString.decode;
659 static var encode = MojoString.encode;
663 class Float implements MojoType<double> {
664 static const int encodedSize = 4;
665 static double decode(MojoDecoder decoder) => decoder.readFloat();
666 static void encode(MojoEncoder encoder, double val) {
667 encoder.writeFloat(val);
672 class Double implements MojoType<double> {
673 static const int encodedSize = 8;
674 static double decode(MojoDecoder decoder) => decoder.readDouble();
675 static void encode(MojoEncoder encoder, double val) {
676 encoder.writeDouble(val);
687 Object decode(MojoDecoder decoder) {
688 int pointer = decoder.decodePointer();
692 return _callDecode(val, decoder.decodeAndCreateDecoder(pointer));
694 void encode(MojoEncoder encoder, Object val) {
696 encoder.encodePointer(val);
699 MojoEncoder obj_encoder =
700 encoder.createAndEncodeEncoder(getEncodedSize(this.val));
701 _callEncode(this.val, obj_encoder, val);
706 class NullablePointerTo extends PointerTo {
707 static const int encodedSize = PointerTo.encodedSize;
715 ArrayOf(this.val, [this.length = 0]);
717 int dimensions() => [length].addAll((val is ArrayOf) ? val.dimensions() : []);
720 List decode(MojoDecoder decoder) => decoder.decodeArrayPointer(val);
721 void encode(MojoEncoder encoder, List val) {
722 encoder.encodeArrayPointer(this.val, val);
727 class NullableArrayOf extends ArrayOf {
728 static const int encodedSize = ArrayOf.encodedSize;
732 class Handle implements MojoType<int> {
733 static const int encodedSize = 4;
734 static int decode(MojoDecoder decoder) => decoder.decodeHandle();
735 static void encode(MojoEncoder encoder, int val) {
736 encoder.encodeHandle(val);
741 class NullableHandle implements MojoType<int> {
742 static const int encodedSize = Handle.encodedSize;
743 static const decode = Handle.decode;
744 static const encode = Handle.encode;