1140 lines
32 KiB
JavaScript
1140 lines
32 KiB
JavaScript
// Copyright 2014 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
(function() {
|
|
var internal = mojo.internal;
|
|
|
|
var kErrorUnsigned = "Passing negative value to unsigned";
|
|
var kErrorArray = "Passing non Array for array type";
|
|
var kErrorString = "Passing non String for string type";
|
|
var kErrorMap = "Passing non Map for map type";
|
|
|
|
// Memory -------------------------------------------------------------------
|
|
|
|
var kAlignment = 8;
|
|
|
|
function align(size) {
|
|
return size + (kAlignment - (size % kAlignment)) % kAlignment;
|
|
}
|
|
|
|
function isAligned(offset) {
|
|
return offset >= 0 && (offset % kAlignment) === 0;
|
|
}
|
|
|
|
// Constants ----------------------------------------------------------------
|
|
|
|
var kArrayHeaderSize = 8;
|
|
var kStructHeaderSize = 8;
|
|
var kMessageV0HeaderSize = 24;
|
|
var kMessageV1HeaderSize = 32;
|
|
var kMessageV2HeaderSize = 48;
|
|
var kMapStructPayloadSize = 16;
|
|
|
|
var kStructHeaderNumBytesOffset = 0;
|
|
var kStructHeaderVersionOffset = 4;
|
|
|
|
var kEncodedInvalidHandleValue = 0xFFFFFFFF;
|
|
|
|
// Decoder ------------------------------------------------------------------
|
|
|
|
function Decoder(buffer, handles, associatedEndpointHandles, base) {
|
|
this.buffer = buffer;
|
|
this.handles = handles;
|
|
this.associatedEndpointHandles = associatedEndpointHandles;
|
|
this.base = base;
|
|
this.next = base;
|
|
}
|
|
|
|
Decoder.prototype.align = function() {
|
|
this.next = align(this.next);
|
|
};
|
|
|
|
Decoder.prototype.skip = function(offset) {
|
|
this.next += offset;
|
|
};
|
|
|
|
Decoder.prototype.readInt8 = function() {
|
|
var result = this.buffer.getInt8(this.next);
|
|
this.next += 1;
|
|
return result;
|
|
};
|
|
|
|
Decoder.prototype.readUint8 = function() {
|
|
var result = this.buffer.getUint8(this.next);
|
|
this.next += 1;
|
|
return result;
|
|
};
|
|
|
|
Decoder.prototype.readInt16 = function() {
|
|
var result = this.buffer.getInt16(this.next);
|
|
this.next += 2;
|
|
return result;
|
|
};
|
|
|
|
Decoder.prototype.readUint16 = function() {
|
|
var result = this.buffer.getUint16(this.next);
|
|
this.next += 2;
|
|
return result;
|
|
};
|
|
|
|
Decoder.prototype.readInt32 = function() {
|
|
var result = this.buffer.getInt32(this.next);
|
|
this.next += 4;
|
|
return result;
|
|
};
|
|
|
|
Decoder.prototype.readUint32 = function() {
|
|
var result = this.buffer.getUint32(this.next);
|
|
this.next += 4;
|
|
return result;
|
|
};
|
|
|
|
Decoder.prototype.readInt64 = function() {
|
|
var result = this.buffer.getInt64(this.next);
|
|
this.next += 8;
|
|
return result;
|
|
};
|
|
|
|
Decoder.prototype.readUint64 = function() {
|
|
var result = this.buffer.getUint64(this.next);
|
|
this.next += 8;
|
|
return result;
|
|
};
|
|
|
|
Decoder.prototype.readFloat = function() {
|
|
var result = this.buffer.getFloat32(this.next);
|
|
this.next += 4;
|
|
return result;
|
|
};
|
|
|
|
Decoder.prototype.readDouble = function() {
|
|
var result = this.buffer.getFloat64(this.next);
|
|
this.next += 8;
|
|
return result;
|
|
};
|
|
|
|
Decoder.prototype.decodePointer = function() {
|
|
// TODO(abarth): To correctly decode a pointer, we need to know the real
|
|
// base address of the array buffer.
|
|
var offsetPointer = this.next;
|
|
var offset = this.readUint64();
|
|
if (!offset)
|
|
return 0;
|
|
return offsetPointer + offset;
|
|
};
|
|
|
|
Decoder.prototype.decodeAndCreateDecoder = function(pointer) {
|
|
return new Decoder(this.buffer, this.handles,
|
|
this.associatedEndpointHandles, pointer);
|
|
};
|
|
|
|
Decoder.prototype.decodeHandle = function() {
|
|
return this.handles[this.readUint32()] || null;
|
|
};
|
|
|
|
Decoder.prototype.decodeAssociatedEndpointHandle = function() {
|
|
return this.associatedEndpointHandles[this.readUint32()] || null;
|
|
};
|
|
|
|
Decoder.prototype.decodeString = function() {
|
|
var numberOfBytes = this.readUint32();
|
|
var numberOfElements = this.readUint32();
|
|
var base = this.next;
|
|
this.next += numberOfElements;
|
|
return internal.decodeUtf8String(
|
|
new Uint8Array(this.buffer.arrayBuffer, base, numberOfElements));
|
|
};
|
|
|
|
Decoder.prototype.decodeArray = function(cls) {
|
|
var numberOfBytes = this.readUint32();
|
|
var numberOfElements = this.readUint32();
|
|
var val = new Array(numberOfElements);
|
|
if (cls === PackedBool) {
|
|
var byte;
|
|
for (var i = 0; i < numberOfElements; ++i) {
|
|
if (i % 8 === 0)
|
|
byte = this.readUint8();
|
|
val[i] = (byte & (1 << i % 8)) ? true : false;
|
|
}
|
|
} else {
|
|
for (var i = 0; i < numberOfElements; ++i) {
|
|
val[i] = cls.decode(this);
|
|
}
|
|
}
|
|
return val;
|
|
};
|
|
|
|
Decoder.prototype.decodeStruct = function(cls) {
|
|
return cls.decode(this);
|
|
};
|
|
|
|
Decoder.prototype.decodeStructPointer = function(cls) {
|
|
var pointer = this.decodePointer();
|
|
if (!pointer) {
|
|
return null;
|
|
}
|
|
return cls.decode(this.decodeAndCreateDecoder(pointer));
|
|
};
|
|
|
|
Decoder.prototype.decodeArrayPointer = function(cls) {
|
|
var pointer = this.decodePointer();
|
|
if (!pointer) {
|
|
return null;
|
|
}
|
|
return this.decodeAndCreateDecoder(pointer).decodeArray(cls);
|
|
};
|
|
|
|
Decoder.prototype.decodeStringPointer = function() {
|
|
var pointer = this.decodePointer();
|
|
if (!pointer) {
|
|
return null;
|
|
}
|
|
return this.decodeAndCreateDecoder(pointer).decodeString();
|
|
};
|
|
|
|
Decoder.prototype.decodeMap = function(keyClass, valueClass) {
|
|
this.skip(4); // numberOfBytes
|
|
this.skip(4); // version
|
|
var keys = this.decodeArrayPointer(keyClass);
|
|
var values = this.decodeArrayPointer(valueClass);
|
|
var val = new Map();
|
|
for (var i = 0; i < keys.length; i++)
|
|
val.set(keys[i], values[i]);
|
|
return val;
|
|
};
|
|
|
|
Decoder.prototype.decodeMapPointer = function(keyClass, valueClass) {
|
|
var pointer = this.decodePointer();
|
|
if (!pointer) {
|
|
return null;
|
|
}
|
|
var decoder = this.decodeAndCreateDecoder(pointer);
|
|
return decoder.decodeMap(keyClass, valueClass);
|
|
};
|
|
|
|
// Encoder ------------------------------------------------------------------
|
|
|
|
function Encoder(buffer, handles, associatedEndpointHandles, base) {
|
|
this.buffer = buffer;
|
|
this.handles = handles;
|
|
this.associatedEndpointHandles = associatedEndpointHandles;
|
|
this.base = base;
|
|
this.next = base;
|
|
}
|
|
|
|
Encoder.prototype.align = function() {
|
|
this.next = align(this.next);
|
|
};
|
|
|
|
Encoder.prototype.skip = function(offset) {
|
|
this.next += offset;
|
|
};
|
|
|
|
Encoder.prototype.writeInt8 = function(val) {
|
|
this.buffer.setInt8(this.next, val);
|
|
this.next += 1;
|
|
};
|
|
|
|
Encoder.prototype.writeUint8 = function(val) {
|
|
if (val < 0) {
|
|
throw new Error(kErrorUnsigned);
|
|
}
|
|
this.buffer.setUint8(this.next, val);
|
|
this.next += 1;
|
|
};
|
|
|
|
Encoder.prototype.writeInt16 = function(val) {
|
|
this.buffer.setInt16(this.next, val);
|
|
this.next += 2;
|
|
};
|
|
|
|
Encoder.prototype.writeUint16 = function(val) {
|
|
if (val < 0) {
|
|
throw new Error(kErrorUnsigned);
|
|
}
|
|
this.buffer.setUint16(this.next, val);
|
|
this.next += 2;
|
|
};
|
|
|
|
Encoder.prototype.writeInt32 = function(val) {
|
|
this.buffer.setInt32(this.next, val);
|
|
this.next += 4;
|
|
};
|
|
|
|
Encoder.prototype.writeUint32 = function(val) {
|
|
if (val < 0) {
|
|
throw new Error(kErrorUnsigned);
|
|
}
|
|
this.buffer.setUint32(this.next, val);
|
|
this.next += 4;
|
|
};
|
|
|
|
Encoder.prototype.writeInt64 = function(val) {
|
|
this.buffer.setInt64(this.next, val);
|
|
this.next += 8;
|
|
};
|
|
|
|
Encoder.prototype.writeUint64 = function(val) {
|
|
if (val < 0) {
|
|
throw new Error(kErrorUnsigned);
|
|
}
|
|
this.buffer.setUint64(this.next, val);
|
|
this.next += 8;
|
|
};
|
|
|
|
Encoder.prototype.writeFloat = function(val) {
|
|
this.buffer.setFloat32(this.next, val);
|
|
this.next += 4;
|
|
};
|
|
|
|
Encoder.prototype.writeDouble = function(val) {
|
|
this.buffer.setFloat64(this.next, val);
|
|
this.next += 8;
|
|
};
|
|
|
|
Encoder.prototype.encodePointer = function(pointer) {
|
|
if (!pointer)
|
|
return this.writeUint64(0);
|
|
// TODO(abarth): To correctly encode a pointer, we need to know the real
|
|
// base address of the array buffer.
|
|
var offset = pointer - this.next;
|
|
this.writeUint64(offset);
|
|
};
|
|
|
|
Encoder.prototype.createAndEncodeEncoder = function(size) {
|
|
var pointer = this.buffer.alloc(align(size));
|
|
this.encodePointer(pointer);
|
|
return new Encoder(this.buffer, this.handles,
|
|
this.associatedEndpointHandles, pointer);
|
|
};
|
|
|
|
Encoder.prototype.encodeHandle = function(handle) {
|
|
if (handle) {
|
|
this.handles.push(handle);
|
|
this.writeUint32(this.handles.length - 1);
|
|
} else {
|
|
this.writeUint32(kEncodedInvalidHandleValue);
|
|
}
|
|
};
|
|
|
|
Encoder.prototype.encodeAssociatedEndpointHandle = function(endpointHandle) {
|
|
if (endpointHandle) {
|
|
this.associatedEndpointHandles.push(endpointHandle);
|
|
this.writeUint32(this.associatedEndpointHandles.length - 1);
|
|
} else {
|
|
this.writeUint32(kEncodedInvalidHandleValue);
|
|
}
|
|
};
|
|
|
|
Encoder.prototype.encodeString = function(val) {
|
|
var base = this.next + kArrayHeaderSize;
|
|
var numberOfElements = internal.encodeUtf8String(
|
|
val, new Uint8Array(this.buffer.arrayBuffer, base));
|
|
var numberOfBytes = kArrayHeaderSize + numberOfElements;
|
|
this.writeUint32(numberOfBytes);
|
|
this.writeUint32(numberOfElements);
|
|
this.next += numberOfElements;
|
|
};
|
|
|
|
Encoder.prototype.encodeArray =
|
|
function(cls, val, numberOfElements, encodedSize) {
|
|
if (numberOfElements === undefined)
|
|
numberOfElements = val.length;
|
|
if (encodedSize === undefined)
|
|
encodedSize = kArrayHeaderSize + cls.encodedSize * numberOfElements;
|
|
|
|
this.writeUint32(encodedSize);
|
|
this.writeUint32(numberOfElements);
|
|
|
|
if (cls === PackedBool) {
|
|
var byte = 0;
|
|
for (i = 0; i < numberOfElements; ++i) {
|
|
if (val[i])
|
|
byte |= (1 << i % 8);
|
|
if (i % 8 === 7 || i == numberOfElements - 1) {
|
|
Uint8.encode(this, byte);
|
|
byte = 0;
|
|
}
|
|
}
|
|
} else {
|
|
for (var i = 0; i < numberOfElements; ++i)
|
|
cls.encode(this, val[i]);
|
|
}
|
|
};
|
|
|
|
Encoder.prototype.encodeStruct = function(cls, val) {
|
|
return cls.encode(this, val);
|
|
};
|
|
|
|
Encoder.prototype.encodeStructPointer = function(cls, val) {
|
|
if (val == null) {
|
|
// Also handles undefined, since undefined == null.
|
|
this.encodePointer(val);
|
|
return;
|
|
}
|
|
var encoder = this.createAndEncodeEncoder(cls.encodedSize);
|
|
cls.encode(encoder, val);
|
|
};
|
|
|
|
Encoder.prototype.encodeArrayPointer = function(cls, val) {
|
|
if (val == null) {
|
|
// Also handles undefined, since undefined == null.
|
|
this.encodePointer(val);
|
|
return;
|
|
}
|
|
|
|
var numberOfElements = val.length;
|
|
if (!Number.isSafeInteger(numberOfElements) || numberOfElements < 0)
|
|
throw new Error(kErrorArray);
|
|
|
|
var encodedSize = kArrayHeaderSize + ((cls === PackedBool) ?
|
|
Math.ceil(numberOfElements / 8) : cls.encodedSize * numberOfElements);
|
|
var encoder = this.createAndEncodeEncoder(encodedSize);
|
|
encoder.encodeArray(cls, val, numberOfElements, encodedSize);
|
|
};
|
|
|
|
Encoder.prototype.encodeStringPointer = function(val) {
|
|
if (val == null) {
|
|
// Also handles undefined, since undefined == null.
|
|
this.encodePointer(val);
|
|
return;
|
|
}
|
|
// Only accepts string primivites, not String Objects like new String("foo")
|
|
if (typeof(val) !== "string") {
|
|
throw new Error(kErrorString);
|
|
}
|
|
var encodedSize = kArrayHeaderSize + internal.utf8Length(val);
|
|
var encoder = this.createAndEncodeEncoder(encodedSize);
|
|
encoder.encodeString(val);
|
|
};
|
|
|
|
Encoder.prototype.encodeMap = function(keyClass, valueClass, val) {
|
|
var keys = new Array(val.size);
|
|
var values = new Array(val.size);
|
|
var i = 0;
|
|
val.forEach(function(value, key) {
|
|
values[i] = value;
|
|
keys[i++] = key;
|
|
});
|
|
this.writeUint32(kStructHeaderSize + kMapStructPayloadSize);
|
|
this.writeUint32(0); // version
|
|
this.encodeArrayPointer(keyClass, keys);
|
|
this.encodeArrayPointer(valueClass, values);
|
|
}
|
|
|
|
Encoder.prototype.encodeMapPointer = function(keyClass, valueClass, val) {
|
|
if (val == null) {
|
|
// Also handles undefined, since undefined == null.
|
|
this.encodePointer(val);
|
|
return;
|
|
}
|
|
if (!(val instanceof Map)) {
|
|
throw new Error(kErrorMap);
|
|
}
|
|
var encodedSize = kStructHeaderSize + kMapStructPayloadSize;
|
|
var encoder = this.createAndEncodeEncoder(encodedSize);
|
|
encoder.encodeMap(keyClass, valueClass, val);
|
|
};
|
|
|
|
// Message ------------------------------------------------------------------
|
|
|
|
var kMessageInterfaceIdOffset = kStructHeaderSize;
|
|
var kMessageNameOffset = kMessageInterfaceIdOffset + 4;
|
|
var kMessageFlagsOffset = kMessageNameOffset + 4;
|
|
var kMessageRequestIDOffset = kMessageFlagsOffset + 8;
|
|
var kMessagePayloadInterfaceIdsPointerOffset = kMessageV2HeaderSize - 8;
|
|
|
|
var kMessageExpectsResponse = 1 << 0;
|
|
var kMessageIsResponse = 1 << 1;
|
|
|
|
function Message(buffer, handles, associatedEndpointHandles) {
|
|
if (associatedEndpointHandles === undefined) {
|
|
associatedEndpointHandles = [];
|
|
}
|
|
|
|
this.buffer = buffer;
|
|
this.handles = handles;
|
|
this.associatedEndpointHandles = associatedEndpointHandles;
|
|
}
|
|
|
|
Message.prototype.getHeaderNumBytes = function() {
|
|
return this.buffer.getUint32(kStructHeaderNumBytesOffset);
|
|
};
|
|
|
|
Message.prototype.getHeaderVersion = function() {
|
|
return this.buffer.getUint32(kStructHeaderVersionOffset);
|
|
};
|
|
|
|
Message.prototype.getName = function() {
|
|
return this.buffer.getUint32(kMessageNameOffset);
|
|
};
|
|
|
|
Message.prototype.getFlags = function() {
|
|
return this.buffer.getUint32(kMessageFlagsOffset);
|
|
};
|
|
|
|
Message.prototype.getInterfaceId = function() {
|
|
return this.buffer.getUint32(kMessageInterfaceIdOffset);
|
|
};
|
|
|
|
Message.prototype.getPayloadInterfaceIds = function() {
|
|
if (this.getHeaderVersion() < 2) {
|
|
return null;
|
|
}
|
|
|
|
var decoder = new Decoder(this.buffer, this.handles,
|
|
this.associatedEndpointHandles,
|
|
kMessagePayloadInterfaceIdsPointerOffset);
|
|
var payloadInterfaceIds = decoder.decodeArrayPointer(Uint32);
|
|
return payloadInterfaceIds;
|
|
};
|
|
|
|
Message.prototype.isResponse = function() {
|
|
return (this.getFlags() & kMessageIsResponse) != 0;
|
|
};
|
|
|
|
Message.prototype.expectsResponse = function() {
|
|
return (this.getFlags() & kMessageExpectsResponse) != 0;
|
|
};
|
|
|
|
Message.prototype.setRequestID = function(requestID) {
|
|
// TODO(darin): Verify that space was reserved for this field!
|
|
this.buffer.setUint64(kMessageRequestIDOffset, requestID);
|
|
};
|
|
|
|
Message.prototype.setInterfaceId = function(interfaceId) {
|
|
this.buffer.setUint32(kMessageInterfaceIdOffset, interfaceId);
|
|
};
|
|
|
|
Message.prototype.setPayloadInterfaceIds_ = function(payloadInterfaceIds) {
|
|
if (this.getHeaderVersion() < 2) {
|
|
throw new Error(
|
|
"Version of message does not support payload interface ids");
|
|
}
|
|
|
|
var decoder = new Decoder(this.buffer, this.handles,
|
|
this.associatedEndpointHandles,
|
|
kMessagePayloadInterfaceIdsPointerOffset);
|
|
var payloadInterfaceIdsOffset = decoder.decodePointer();
|
|
var encoder = new Encoder(this.buffer, this.handles,
|
|
this.associatedEndpointHandles,
|
|
payloadInterfaceIdsOffset);
|
|
encoder.encodeArray(Uint32, payloadInterfaceIds);
|
|
};
|
|
|
|
Message.prototype.serializeAssociatedEndpointHandles = function(
|
|
associatedGroupController) {
|
|
if (this.associatedEndpointHandles.length > 0) {
|
|
if (this.getHeaderVersion() < 2) {
|
|
throw new Error(
|
|
"Version of message does not support associated endpoint handles");
|
|
}
|
|
|
|
var data = [];
|
|
for (var i = 0; i < this.associatedEndpointHandles.length; i++) {
|
|
var handle = this.associatedEndpointHandles[i];
|
|
data.push(associatedGroupController.associateInterface(handle));
|
|
}
|
|
this.associatedEndpointHandles = [];
|
|
this.setPayloadInterfaceIds_(data);
|
|
}
|
|
};
|
|
|
|
Message.prototype.deserializeAssociatedEndpointHandles = function(
|
|
associatedGroupController) {
|
|
if (this.getHeaderVersion() < 2) {
|
|
return true;
|
|
}
|
|
|
|
this.associatedEndpointHandles = [];
|
|
var ids = this.getPayloadInterfaceIds();
|
|
|
|
var result = true;
|
|
for (var i = 0; i < ids.length; i++) {
|
|
var handle = associatedGroupController.createLocalEndpointHandle(ids[i]);
|
|
if (internal.isValidInterfaceId(ids[i]) && !handle.isValid()) {
|
|
// |ids[i]| itself is valid but handle creation failed. In that case,
|
|
// mark deserialization as failed but continue to deserialize the
|
|
// rest of handles.
|
|
result = false;
|
|
}
|
|
this.associatedEndpointHandles.push(handle);
|
|
ids[i] = internal.kInvalidInterfaceId;
|
|
}
|
|
|
|
this.setPayloadInterfaceIds_(ids);
|
|
return result;
|
|
};
|
|
|
|
|
|
// MessageV0Builder ---------------------------------------------------------
|
|
|
|
function MessageV0Builder(messageName, payloadSize) {
|
|
// Currently, we don't compute the payload size correctly ahead of time.
|
|
// Instead, we resize the buffer at the end.
|
|
var numberOfBytes = kMessageV0HeaderSize + payloadSize;
|
|
this.buffer = new internal.Buffer(numberOfBytes);
|
|
this.handles = [];
|
|
var encoder = this.createEncoder(kMessageV0HeaderSize);
|
|
encoder.writeUint32(kMessageV0HeaderSize);
|
|
encoder.writeUint32(0); // version.
|
|
encoder.writeUint32(0); // interface ID.
|
|
encoder.writeUint32(messageName);
|
|
encoder.writeUint32(0); // flags.
|
|
encoder.writeUint32(0); // padding.
|
|
}
|
|
|
|
MessageV0Builder.prototype.createEncoder = function(size) {
|
|
var pointer = this.buffer.alloc(size);
|
|
return new Encoder(this.buffer, this.handles, [], pointer);
|
|
};
|
|
|
|
MessageV0Builder.prototype.encodeStruct = function(cls, val) {
|
|
cls.encode(this.createEncoder(cls.encodedSize), val);
|
|
};
|
|
|
|
MessageV0Builder.prototype.finish = function() {
|
|
// TODO(abarth): Rather than resizing the buffer at the end, we could
|
|
// compute the size we need ahead of time, like we do in C++.
|
|
this.buffer.trim();
|
|
var message = new Message(this.buffer, this.handles);
|
|
this.buffer = null;
|
|
this.handles = null;
|
|
this.encoder = null;
|
|
return message;
|
|
};
|
|
|
|
// MessageV1Builder -----------------------------------------------
|
|
|
|
function MessageV1Builder(messageName, payloadSize, flags,
|
|
requestID) {
|
|
// Currently, we don't compute the payload size correctly ahead of time.
|
|
// Instead, we resize the buffer at the end.
|
|
var numberOfBytes = kMessageV1HeaderSize + payloadSize;
|
|
this.buffer = new internal.Buffer(numberOfBytes);
|
|
this.handles = [];
|
|
var encoder = this.createEncoder(kMessageV1HeaderSize);
|
|
encoder.writeUint32(kMessageV1HeaderSize);
|
|
encoder.writeUint32(1); // version.
|
|
encoder.writeUint32(0); // interface ID.
|
|
encoder.writeUint32(messageName);
|
|
encoder.writeUint32(flags);
|
|
encoder.writeUint32(0); // padding.
|
|
encoder.writeUint64(requestID);
|
|
}
|
|
|
|
MessageV1Builder.prototype =
|
|
Object.create(MessageV0Builder.prototype);
|
|
|
|
MessageV1Builder.prototype.constructor =
|
|
MessageV1Builder;
|
|
|
|
// MessageV2 -----------------------------------------------
|
|
|
|
function MessageV2Builder(messageName, payloadSize, flags, requestID) {
|
|
// Currently, we don't compute the payload size correctly ahead of time.
|
|
// Instead, we resize the buffer at the end.
|
|
var numberOfBytes = kMessageV2HeaderSize + payloadSize;
|
|
this.buffer = new internal.Buffer(numberOfBytes);
|
|
this.handles = [];
|
|
|
|
this.payload = null;
|
|
this.associatedEndpointHandles = [];
|
|
|
|
this.encoder = this.createEncoder(kMessageV2HeaderSize);
|
|
this.encoder.writeUint32(kMessageV2HeaderSize);
|
|
this.encoder.writeUint32(2); // version.
|
|
// Gets set to an appropriate interfaceId for the endpoint by the Router.
|
|
this.encoder.writeUint32(0); // interface ID.
|
|
this.encoder.writeUint32(messageName);
|
|
this.encoder.writeUint32(flags);
|
|
this.encoder.writeUint32(0); // padding.
|
|
this.encoder.writeUint64(requestID);
|
|
}
|
|
|
|
MessageV2Builder.prototype.createEncoder = function(size) {
|
|
var pointer = this.buffer.alloc(size);
|
|
return new Encoder(this.buffer, this.handles,
|
|
this.associatedEndpointHandles, pointer);
|
|
};
|
|
|
|
MessageV2Builder.prototype.setPayload = function(cls, val) {
|
|
this.payload = {cls: cls, val: val};
|
|
};
|
|
|
|
MessageV2Builder.prototype.finish = function() {
|
|
if (!this.payload) {
|
|
throw new Error("Payload needs to be set before calling finish");
|
|
}
|
|
|
|
this.encoder.encodeStructPointer(this.payload.cls, this.payload.val);
|
|
this.encoder.encodeArrayPointer(Uint32,
|
|
new Array(this.associatedEndpointHandles.length));
|
|
|
|
this.buffer.trim();
|
|
var message = new Message(this.buffer, this.handles,
|
|
this.associatedEndpointHandles);
|
|
this.buffer = null;
|
|
this.handles = null;
|
|
this.encoder = null;
|
|
this.payload = null;
|
|
this.associatedEndpointHandles = null;
|
|
|
|
return message;
|
|
};
|
|
|
|
// MessageReader ------------------------------------------------------------
|
|
|
|
function MessageReader(message) {
|
|
this.decoder = new Decoder(message.buffer, message.handles,
|
|
message.associatedEndpointHandles, 0);
|
|
var messageHeaderSize = this.decoder.readUint32();
|
|
this.payloadSize = message.buffer.byteLength - messageHeaderSize;
|
|
var version = this.decoder.readUint32();
|
|
var interface_id = this.decoder.readUint32();
|
|
this.messageName = this.decoder.readUint32();
|
|
this.flags = this.decoder.readUint32();
|
|
// Skip the padding.
|
|
this.decoder.skip(4);
|
|
if (version >= 1)
|
|
this.requestID = this.decoder.readUint64();
|
|
this.decoder.skip(messageHeaderSize - this.decoder.next);
|
|
}
|
|
|
|
MessageReader.prototype.decodeStruct = function(cls) {
|
|
return cls.decode(this.decoder);
|
|
};
|
|
|
|
// Built-in types -----------------------------------------------------------
|
|
|
|
// This type is only used with ArrayOf(PackedBool).
|
|
function PackedBool() {
|
|
}
|
|
|
|
function Int8() {
|
|
}
|
|
|
|
Int8.encodedSize = 1;
|
|
|
|
Int8.decode = function(decoder) {
|
|
return decoder.readInt8();
|
|
};
|
|
|
|
Int8.encode = function(encoder, val) {
|
|
encoder.writeInt8(val);
|
|
};
|
|
|
|
Uint8.encode = function(encoder, val) {
|
|
encoder.writeUint8(val);
|
|
};
|
|
|
|
function Uint8() {
|
|
}
|
|
|
|
Uint8.encodedSize = 1;
|
|
|
|
Uint8.decode = function(decoder) {
|
|
return decoder.readUint8();
|
|
};
|
|
|
|
Uint8.encode = function(encoder, val) {
|
|
encoder.writeUint8(val);
|
|
};
|
|
|
|
function Int16() {
|
|
}
|
|
|
|
Int16.encodedSize = 2;
|
|
|
|
Int16.decode = function(decoder) {
|
|
return decoder.readInt16();
|
|
};
|
|
|
|
Int16.encode = function(encoder, val) {
|
|
encoder.writeInt16(val);
|
|
};
|
|
|
|
function Uint16() {
|
|
}
|
|
|
|
Uint16.encodedSize = 2;
|
|
|
|
Uint16.decode = function(decoder) {
|
|
return decoder.readUint16();
|
|
};
|
|
|
|
Uint16.encode = function(encoder, val) {
|
|
encoder.writeUint16(val);
|
|
};
|
|
|
|
function Int32() {
|
|
}
|
|
|
|
Int32.encodedSize = 4;
|
|
|
|
Int32.decode = function(decoder) {
|
|
return decoder.readInt32();
|
|
};
|
|
|
|
Int32.encode = function(encoder, val) {
|
|
encoder.writeInt32(val);
|
|
};
|
|
|
|
function Uint32() {
|
|
}
|
|
|
|
Uint32.encodedSize = 4;
|
|
|
|
Uint32.decode = function(decoder) {
|
|
return decoder.readUint32();
|
|
};
|
|
|
|
Uint32.encode = function(encoder, val) {
|
|
encoder.writeUint32(val);
|
|
};
|
|
|
|
function Int64() {
|
|
}
|
|
|
|
Int64.encodedSize = 8;
|
|
|
|
Int64.decode = function(decoder) {
|
|
return decoder.readInt64();
|
|
};
|
|
|
|
Int64.encode = function(encoder, val) {
|
|
encoder.writeInt64(val);
|
|
};
|
|
|
|
function Uint64() {
|
|
}
|
|
|
|
Uint64.encodedSize = 8;
|
|
|
|
Uint64.decode = function(decoder) {
|
|
return decoder.readUint64();
|
|
};
|
|
|
|
Uint64.encode = function(encoder, val) {
|
|
encoder.writeUint64(val);
|
|
};
|
|
|
|
function String() {
|
|
};
|
|
|
|
String.encodedSize = 8;
|
|
|
|
String.decode = function(decoder) {
|
|
return decoder.decodeStringPointer();
|
|
};
|
|
|
|
String.encode = function(encoder, val) {
|
|
encoder.encodeStringPointer(val);
|
|
};
|
|
|
|
function NullableString() {
|
|
}
|
|
|
|
NullableString.encodedSize = String.encodedSize;
|
|
|
|
NullableString.decode = String.decode;
|
|
|
|
NullableString.encode = String.encode;
|
|
|
|
function Float() {
|
|
}
|
|
|
|
Float.encodedSize = 4;
|
|
|
|
Float.decode = function(decoder) {
|
|
return decoder.readFloat();
|
|
};
|
|
|
|
Float.encode = function(encoder, val) {
|
|
encoder.writeFloat(val);
|
|
};
|
|
|
|
function Double() {
|
|
}
|
|
|
|
Double.encodedSize = 8;
|
|
|
|
Double.decode = function(decoder) {
|
|
return decoder.readDouble();
|
|
};
|
|
|
|
Double.encode = function(encoder, val) {
|
|
encoder.writeDouble(val);
|
|
};
|
|
|
|
function Enum(cls) {
|
|
this.cls = cls;
|
|
}
|
|
|
|
Enum.prototype.encodedSize = 4;
|
|
|
|
Enum.prototype.decode = function(decoder) {
|
|
return decoder.readInt32();
|
|
};
|
|
|
|
Enum.prototype.encode = function(encoder, val) {
|
|
encoder.writeInt32(val);
|
|
};
|
|
|
|
function PointerTo(cls) {
|
|
this.cls = cls;
|
|
}
|
|
|
|
PointerTo.prototype.encodedSize = 8;
|
|
|
|
PointerTo.prototype.decode = function(decoder) {
|
|
var pointer = decoder.decodePointer();
|
|
if (!pointer) {
|
|
return null;
|
|
}
|
|
return this.cls.decode(decoder.decodeAndCreateDecoder(pointer));
|
|
};
|
|
|
|
PointerTo.prototype.encode = function(encoder, val) {
|
|
if (!val) {
|
|
encoder.encodePointer(val);
|
|
return;
|
|
}
|
|
var objectEncoder = encoder.createAndEncodeEncoder(this.cls.encodedSize);
|
|
this.cls.encode(objectEncoder, val);
|
|
};
|
|
|
|
function NullablePointerTo(cls) {
|
|
PointerTo.call(this, cls);
|
|
}
|
|
|
|
NullablePointerTo.prototype = Object.create(PointerTo.prototype);
|
|
|
|
function ArrayOf(cls, length) {
|
|
this.cls = cls;
|
|
this.length = length || 0;
|
|
}
|
|
|
|
ArrayOf.prototype.encodedSize = 8;
|
|
|
|
ArrayOf.prototype.dimensions = function() {
|
|
return [this.length].concat(
|
|
(this.cls instanceof ArrayOf) ? this.cls.dimensions() : []);
|
|
}
|
|
|
|
ArrayOf.prototype.decode = function(decoder) {
|
|
return decoder.decodeArrayPointer(this.cls);
|
|
};
|
|
|
|
ArrayOf.prototype.encode = function(encoder, val) {
|
|
encoder.encodeArrayPointer(this.cls, val);
|
|
};
|
|
|
|
function NullableArrayOf(cls) {
|
|
ArrayOf.call(this, cls);
|
|
}
|
|
|
|
NullableArrayOf.prototype = Object.create(ArrayOf.prototype);
|
|
|
|
function Handle() {
|
|
}
|
|
|
|
Handle.encodedSize = 4;
|
|
|
|
Handle.decode = function(decoder) {
|
|
return decoder.decodeHandle();
|
|
};
|
|
|
|
Handle.encode = function(encoder, val) {
|
|
encoder.encodeHandle(val);
|
|
};
|
|
|
|
function NullableHandle() {
|
|
}
|
|
|
|
NullableHandle.encodedSize = Handle.encodedSize;
|
|
|
|
NullableHandle.decode = Handle.decode;
|
|
|
|
NullableHandle.encode = Handle.encode;
|
|
|
|
function Interface(cls) {
|
|
this.cls = cls;
|
|
}
|
|
|
|
Interface.prototype.encodedSize = 8;
|
|
|
|
Interface.prototype.decode = function(decoder) {
|
|
var interfacePtrInfo = new mojo.InterfacePtrInfo(
|
|
decoder.decodeHandle(), decoder.readUint32());
|
|
var interfacePtr = new this.cls();
|
|
interfacePtr.ptr.bind(interfacePtrInfo);
|
|
return interfacePtr;
|
|
};
|
|
|
|
Interface.prototype.encode = function(encoder, val) {
|
|
var interfacePtrInfo =
|
|
val ? val.ptr.passInterface() : new mojo.InterfacePtrInfo(null, 0);
|
|
encoder.encodeHandle(interfacePtrInfo.handle);
|
|
encoder.writeUint32(interfacePtrInfo.version);
|
|
};
|
|
|
|
function NullableInterface(cls) {
|
|
Interface.call(this, cls);
|
|
}
|
|
|
|
NullableInterface.prototype = Object.create(Interface.prototype);
|
|
|
|
function AssociatedInterfacePtrInfo() {
|
|
}
|
|
|
|
AssociatedInterfacePtrInfo.prototype.encodedSize = 8;
|
|
|
|
AssociatedInterfacePtrInfo.decode = function(decoder) {
|
|
return new mojo.AssociatedInterfacePtrInfo(
|
|
decoder.decodeAssociatedEndpointHandle(), decoder.readUint32());
|
|
};
|
|
|
|
AssociatedInterfacePtrInfo.encode = function(encoder, val) {
|
|
var associatedinterfacePtrInfo =
|
|
val ? val : new mojo.AssociatedInterfacePtrInfo(null, 0);
|
|
encoder.encodeAssociatedEndpointHandle(
|
|
associatedinterfacePtrInfo.interfaceEndpointHandle);
|
|
encoder.writeUint32(associatedinterfacePtrInfo.version);
|
|
};
|
|
|
|
function NullableAssociatedInterfacePtrInfo() {
|
|
}
|
|
|
|
NullableAssociatedInterfacePtrInfo.encodedSize =
|
|
AssociatedInterfacePtrInfo.encodedSize;
|
|
|
|
NullableAssociatedInterfacePtrInfo.decode =
|
|
AssociatedInterfacePtrInfo.decode;
|
|
|
|
NullableAssociatedInterfacePtrInfo.encode =
|
|
AssociatedInterfacePtrInfo.encode;
|
|
|
|
function InterfaceRequest() {
|
|
}
|
|
|
|
InterfaceRequest.encodedSize = 4;
|
|
|
|
InterfaceRequest.decode = function(decoder) {
|
|
return new mojo.InterfaceRequest(decoder.decodeHandle());
|
|
};
|
|
|
|
InterfaceRequest.encode = function(encoder, val) {
|
|
encoder.encodeHandle(val ? val.handle : null);
|
|
};
|
|
|
|
function NullableInterfaceRequest() {
|
|
}
|
|
|
|
NullableInterfaceRequest.encodedSize = InterfaceRequest.encodedSize;
|
|
|
|
NullableInterfaceRequest.decode = InterfaceRequest.decode;
|
|
|
|
NullableInterfaceRequest.encode = InterfaceRequest.encode;
|
|
|
|
function AssociatedInterfaceRequest() {
|
|
}
|
|
|
|
AssociatedInterfaceRequest.decode = function(decoder) {
|
|
var handle = decoder.decodeAssociatedEndpointHandle();
|
|
return new mojo.AssociatedInterfaceRequest(handle);
|
|
};
|
|
|
|
AssociatedInterfaceRequest.encode = function(encoder, val) {
|
|
encoder.encodeAssociatedEndpointHandle(
|
|
val ? val.interfaceEndpointHandle : null);
|
|
};
|
|
|
|
AssociatedInterfaceRequest.encodedSize = 4;
|
|
|
|
function NullableAssociatedInterfaceRequest() {
|
|
}
|
|
|
|
NullableAssociatedInterfaceRequest.encodedSize =
|
|
AssociatedInterfaceRequest.encodedSize;
|
|
|
|
NullableAssociatedInterfaceRequest.decode =
|
|
AssociatedInterfaceRequest.decode;
|
|
|
|
NullableAssociatedInterfaceRequest.encode =
|
|
AssociatedInterfaceRequest.encode;
|
|
|
|
function MapOf(keyClass, valueClass) {
|
|
this.keyClass = keyClass;
|
|
this.valueClass = valueClass;
|
|
}
|
|
|
|
MapOf.prototype.encodedSize = 8;
|
|
|
|
MapOf.prototype.decode = function(decoder) {
|
|
return decoder.decodeMapPointer(this.keyClass, this.valueClass);
|
|
};
|
|
|
|
MapOf.prototype.encode = function(encoder, val) {
|
|
encoder.encodeMapPointer(this.keyClass, this.valueClass, val);
|
|
};
|
|
|
|
function NullableMapOf(keyClass, valueClass) {
|
|
MapOf.call(this, keyClass, valueClass);
|
|
}
|
|
|
|
NullableMapOf.prototype = Object.create(MapOf.prototype);
|
|
|
|
internal.align = align;
|
|
internal.isAligned = isAligned;
|
|
internal.Message = Message;
|
|
internal.MessageV0Builder = MessageV0Builder;
|
|
internal.MessageV1Builder = MessageV1Builder;
|
|
internal.MessageV2Builder = MessageV2Builder;
|
|
internal.MessageReader = MessageReader;
|
|
internal.kArrayHeaderSize = kArrayHeaderSize;
|
|
internal.kMapStructPayloadSize = kMapStructPayloadSize;
|
|
internal.kStructHeaderSize = kStructHeaderSize;
|
|
internal.kEncodedInvalidHandleValue = kEncodedInvalidHandleValue;
|
|
internal.kMessageV0HeaderSize = kMessageV0HeaderSize;
|
|
internal.kMessageV1HeaderSize = kMessageV1HeaderSize;
|
|
internal.kMessageV2HeaderSize = kMessageV2HeaderSize;
|
|
internal.kMessagePayloadInterfaceIdsPointerOffset =
|
|
kMessagePayloadInterfaceIdsPointerOffset;
|
|
internal.kMessageExpectsResponse = kMessageExpectsResponse;
|
|
internal.kMessageIsResponse = kMessageIsResponse;
|
|
internal.Int8 = Int8;
|
|
internal.Uint8 = Uint8;
|
|
internal.Int16 = Int16;
|
|
internal.Uint16 = Uint16;
|
|
internal.Int32 = Int32;
|
|
internal.Uint32 = Uint32;
|
|
internal.Int64 = Int64;
|
|
internal.Uint64 = Uint64;
|
|
internal.Float = Float;
|
|
internal.Double = Double;
|
|
internal.String = String;
|
|
internal.Enum = Enum;
|
|
internal.NullableString = NullableString;
|
|
internal.PointerTo = PointerTo;
|
|
internal.NullablePointerTo = NullablePointerTo;
|
|
internal.ArrayOf = ArrayOf;
|
|
internal.NullableArrayOf = NullableArrayOf;
|
|
internal.PackedBool = PackedBool;
|
|
internal.Handle = Handle;
|
|
internal.NullableHandle = NullableHandle;
|
|
internal.Interface = Interface;
|
|
internal.NullableInterface = NullableInterface;
|
|
internal.InterfaceRequest = InterfaceRequest;
|
|
internal.NullableInterfaceRequest = NullableInterfaceRequest;
|
|
internal.AssociatedInterfacePtrInfo = AssociatedInterfacePtrInfo;
|
|
internal.NullableAssociatedInterfacePtrInfo =
|
|
NullableAssociatedInterfacePtrInfo;
|
|
internal.AssociatedInterfaceRequest = AssociatedInterfaceRequest;
|
|
internal.NullableAssociatedInterfaceRequest =
|
|
NullableAssociatedInterfaceRequest;
|
|
internal.MapOf = MapOf;
|
|
internal.NullableMapOf = NullableMapOf;
|
|
})();
|