Index: mojo/public/bindings/js/codec.js |
diff --git a/mojo/public/bindings/js/codec.js b/mojo/public/bindings/js/codec.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b7dcbeea6442a72443c518a7f6b73e4379da86c9 |
--- /dev/null |
+++ b/mojo/public/bindings/js/codec.js |
@@ -0,0 +1,407 @@ |
+// Copyright 2013 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. |
+ |
+define(function() { |
+ |
+ // Memory ------------------------------------------------------------------- |
+ |
+ function store8(memory, pointer, val) { |
+ memory[pointer] = val; |
+ } |
+ |
+ function store16(memory, pointer, val) { |
+ memory[pointer + 0] = val >> 0; |
+ memory[pointer + 1] = val >> 8; |
+ } |
+ |
+ function store32(memory, pointer, val) { |
+ memory[pointer + 0] = val >> 0; |
+ memory[pointer + 1] = val >> 8; |
+ memory[pointer + 2] = val >> 16; |
+ memory[pointer + 3] = val >> 24; |
+ } |
+ |
+ function store64(memory, pointer, val) { |
+ store32(memory, pointer, val); |
+ var high = (val / 0x10000) | 0; |
+ store32(memory, pointer + 4, high); |
+ } |
+ |
+ function load8(memory, pointer) { |
+ return memory[pointer]; |
+ } |
+ |
+ function load16(memory, pointer) { |
+ return (memory[pointer + 0] << 0) + |
+ (memory[pointer + 1] << 8); |
+ } |
+ |
+ function load32(memory, pointer) { |
+ return (memory[pointer + 0] << 0) + |
+ (memory[pointer + 1] << 8) + |
+ (memory[pointer + 2] << 16) + |
+ (memory[pointer + 3] << 24); |
+ } |
+ |
+ function load64(memory, pointer) { |
+ var low = load32(memory, pointer); |
+ var high = load32(memory, pointer + 4); |
+ return low + high * 0x10000; |
+ } |
+ |
+ // Buffer ------------------------------------------------------------------- |
+ |
+ function Buffer(size) { |
+ this.memory = new Uint8Array(size); |
+ this.next = 0; |
+ } |
+ |
+ Buffer.prototype.alloc = function(size) { |
+ var pointer = this.next; |
+ this.next += size; |
+ if (this.next > this.memory.length) { |
+ var newSize = (1.5 * (this.memory.length + size)) | 0; |
+ this.grow(newSize); |
+ } |
+ return pointer; |
+ }; |
+ |
+ Buffer.prototype.grow = function(size) { |
+ var newMemory = new Uint8Array(size); |
+ var oldMemory = this.memory; |
+ for (var i = 0; i < oldMemory.length; ++i) |
+ newMemory[i] = oldMemory[i]; |
+ this.memory = newMemory; |
+ }; |
+ |
+ // Constants ---------------------------------------------------------------- |
+ |
+ var kArrayHeaderSize = 8; |
+ var kStructHeaderSize = 8; |
+ var kMessageHeaderSize = 8; |
+ |
+ // Decoder ------------------------------------------------------------------ |
+ |
+ function Decoder(memory, handles, base) { |
+ this.memory = memory; |
+ this.handles = handles; |
+ this.base = base; |
+ this.next = base; |
+ } |
+ |
+ Decoder.prototype.skip = function(offset) { |
+ this.next += offset; |
+ }; |
+ |
+ Decoder.prototype.read8 = function() { |
+ var result = load8(this.memory, this.next); |
+ this.next += 1; |
+ return result; |
+ }; |
+ |
+ Decoder.prototype.read32 = function() { |
+ var result = load32(this.memory, this.next); |
+ this.next += 4; |
+ return result; |
+ }; |
+ |
+ Decoder.prototype.read64 = function() { |
+ var result = load64(this.memory, 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.read64(); |
+ if (!offset) |
+ return 0; |
+ return offsetPointer + offset; |
+ }; |
+ |
+ Decoder.prototype.decodeAndCreateDecoder = function() { |
+ return new Decoder(this.memory, this.handles, this.decodePointer()); |
+ }; |
+ |
+ Decoder.prototype.decodeHandle = function() { |
+ return this.handles[this.read32()]; |
+ }; |
+ |
+ Decoder.prototype.decodeString = function() { |
+ // TODO(abarth): We should really support UTF-8. We might want to |
+ // jump out of the VM to decode the string directly from the array |
+ // buffer using v8::String::NewFromUtf8. |
+ var numberOfBytes = this.read32(); |
+ var numberOfElements = this.read32(); |
+ var val = new Array(numberOfElements); |
+ var memory = this.memory; |
+ var base = this.next; |
+ for (var i = 0; i < numberOfElements; ++i) { |
+ val[i] = String.fromCharCode(memory[base + i] & 0x7F); |
+ } |
+ this.next += numberOfElements; |
+ return val.join(''); |
+ }; |
+ |
+ Decoder.prototype.decodeArray = function(cls) { |
+ var numberOfBytes = this.read32(); |
+ var numberOfElements = this.read32(); |
+ var val = new Array(numberOfElements); |
+ for (var i = 0; i < numberOfElements; ++i) { |
+ val[i] = cls.decode(this); |
+ } |
+ return val; |
+ }; |
+ |
+ Decoder.prototype.decodeStructPointer = function(cls) { |
+ return cls.decode(this.decodeAndCreateDecoder()); |
+ }; |
+ |
+ Decoder.prototype.decodeArrayPointer = function(cls) { |
+ return this.decodeAndCreateDecoder().decodeArray(cls); |
+ }; |
+ |
+ Decoder.prototype.decodeStringPointer = function() { |
+ return this.decodeAndCreateDecoder().decodeString(); |
+ }; |
+ |
+ // Encoder ------------------------------------------------------------------ |
+ |
+ function Encoder(buffer, handles, base) { |
+ this.buffer = buffer; |
+ this.handles = handles; |
+ this.base = base; |
+ this.next = base; |
+ } |
+ |
+ Encoder.prototype.skip = function(offset) { |
+ this.next += offset; |
+ }; |
+ |
+ Encoder.prototype.write8 = function(val) { |
+ store8(this.buffer.memory, this.next, val); |
+ this.next += 1; |
+ }; |
+ |
+ Encoder.prototype.write32 = function(val) { |
+ store32(this.buffer.memory, this.next, val); |
+ this.next += 4; |
+ }; |
+ |
+ Encoder.prototype.write64 = function(val) { |
+ store64(this.buffer.memory, this.next, val); |
+ this.next += 8; |
+ }; |
+ |
+ Encoder.prototype.encodePointer = function(pointer) { |
+ if (!pointer) |
+ return this.write64(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.write64(offset); |
+ }; |
+ |
+ Encoder.prototype.createAndEncodeEncoder = function(size) { |
+ var pointer = this.buffer.alloc(size); |
+ this.encodePointer(pointer); |
+ return new Encoder(this.buffer, this.handles, pointer); |
+ }; |
+ |
+ Encoder.prototype.encodeHandle = function(handle) { |
+ this.handles.push(handle); |
+ this.write32(this.handles.length - 1); |
+ }; |
+ |
+ Encoder.prototype.encodeString = function(val) { |
+ var numberOfElements = val.length; |
+ var numberOfBytes = kArrayHeaderSize + numberOfElements; |
+ this.write32(numberOfBytes); |
+ this.write32(numberOfElements); |
+ // TODO(abarth): We should really support UTF-8. We might want to |
+ // jump out of the VM to encode the string directly from the array |
+ // buffer using v8::String::WriteUtf8. |
+ var memory = this.buffer.memory; |
+ var base = this.next; |
+ var len = val.length; |
+ for (var i = 0; i < len; ++i) { |
+ memory[base + i] = val.charCodeAt(i) & 0x7F; |
+ } |
+ this.next += len; |
+ }; |
+ |
+ Encoder.prototype.encodeArray = function(cls, val) { |
+ var numberOfElements = val.length; |
+ var numberOfBytes = kArrayHeaderSize + cls.encodedSize * numberOfElements; |
+ this.write32(numberOfBytes); |
+ this.write32(numberOfElements); |
+ for (var i = 0; i < numberOfElements; ++i) { |
+ cls.encode(this, val[i]); |
+ } |
+ }; |
+ |
+ Encoder.prototype.encodeStructPointer = function(cls, val) { |
+ var encoder = this.createAndEncodeEncoder(cls.encodedSize); |
+ cls.encode(encoder, val); |
+ }; |
+ |
+ Encoder.prototype.encodeArrayPointer = function(cls, val) { |
+ var encodedSize = kArrayHeaderSize + cls.encodedSize * val.length; |
+ var encoder = this.createAndEncodeEncoder(encodedSize); |
+ encoder.encodeArray(cls, val); |
+ }; |
+ |
+ Encoder.prototype.encodeStringPointer = function(val) { |
+ // TODO(abarth): This won't be right once we support UTF-8. |
+ var encodedSize = kArrayHeaderSize + val.length; |
+ var encoder = this.createAndEncodeEncoder(encodedSize); |
+ encoder.encodeString(val); |
+ }; |
+ |
+ // Message ------------------------------------------------------------------ |
+ |
+ function Message(memory, handles) { |
+ this.memory = memory; |
+ this.handles = handles; |
+ } |
+ |
+ // MessageBuilder ----------------------------------------------------------- |
+ |
+ function MessageBuilder(messageName, payloadSize) { |
+ var numberOfBytes = kMessageHeaderSize + payloadSize; |
+ this.buffer = new Buffer(numberOfBytes); |
+ this.handles = []; |
+ var encoder = this.createEncoder(kMessageHeaderSize); |
+ encoder.write32(numberOfBytes); |
+ encoder.write32(messageName); |
+ } |
+ |
+ MessageBuilder.prototype.createEncoder = function(size) { |
+ var pointer = this.buffer.alloc(size); |
+ return new Encoder(this.buffer, this.handles, pointer); |
+ } |
+ |
+ MessageBuilder.prototype.encodeStruct = function(cls, val) { |
+ cls.encode(this.createEncoder(cls.encodedSize), val); |
+ }; |
+ |
+ MessageBuilder.prototype.finish = function() { |
+ var message = new Message(this.buffer.memory, this.handles); |
+ this.buffer = null; |
+ this.handles = null; |
+ this.encoder = null; |
+ return message; |
+ }; |
+ |
+ // MessageReader ------------------------------------------------------------ |
+ |
+ function MessageReader(message) { |
+ this.decoder = new Decoder(message.memory, message.handles, 0); |
+ this.payloadSize = this.decoder.read32() - kMessageHeaderSize; |
+ this.messageName = this.decoder.read32(); |
+ } |
+ |
+ MessageReader.prototype.decodeStruct = function(cls) { |
+ return cls.decode(this.decoder); |
+ }; |
+ |
+ // Built-in types ----------------------------------------------------------- |
+ |
+ function Uint8() { |
+ } |
+ |
+ Uint8.encodedSize = 1; |
+ |
+ Uint8.decode = function(decoder) { |
+ return decoder.read8(); |
+ }; |
+ |
+ Uint8.encode = function(encoder, val) { |
+ encoder.write8(val); |
+ }; |
+ |
+ function Uint16() { |
+ } |
+ |
+ Uint16.encodedSize = 2; |
+ |
+ Uint16.decode = function(decoder) { |
+ return decoder.read16(); |
+ }; |
+ |
+ Uint16.encode = function(encoder, val) { |
+ encoder.write16(val); |
+ }; |
+ |
+ function Uint32() { |
+ } |
+ |
+ Uint32.encodedSize = 4; |
+ |
+ Uint32.decode = function(decoder) { |
+ return decoder.read32(); |
+ }; |
+ |
+ Uint32.encode = function(encoder, val) { |
+ encoder.write32(val); |
+ }; |
+ |
+ function Uint64() { |
+ }; |
+ |
+ Uint64.encodedSize = 8; |
+ |
+ Uint64.decode = function(decoder) { |
+ return decoder.read64(); |
+ }; |
+ |
+ Uint64.encode = function(encoder, val) { |
+ encoder.write64(val); |
+ }; |
+ |
+ function PointerTo(cls) { |
+ this.cls = cls; |
+ }; |
+ |
+ PointerTo.prototype.encodedSize = 8; |
+ |
+ PointerTo.prototype.decode = function(decoder) { |
+ return this.cls.decode(decoder.decodeAndCreateDecoder()); |
+ }; |
+ |
+ PointerTo.prototype.encode = function(encoder, val) { |
+ var objectEncoder = encoder.createAndEncodeEncoder(this.cls.encodedSize); |
+ this.cls.encode(objectEncoder, val); |
+ }; |
+ |
+ function Handle() { |
+ } |
+ |
+ Handle.encodedSize = 4; |
+ |
+ Handle.decode = function(decoder) { |
+ return decoder.decodeHandle(); |
+ }; |
+ |
+ Handle.encode = function(encoder, val) { |
+ encoder.encodeHandle(val); |
+ }; |
+ |
+ var exports = {}; |
+ exports.load32 = load32; |
+ exports.MessageBuilder = MessageBuilder; |
+ exports.MessageReader = MessageReader; |
+ exports.kArrayHeaderSize = kArrayHeaderSize; |
+ exports.kStructHeaderSize = kStructHeaderSize; |
+ exports.kMessageHeaderSize = kMessageHeaderSize; |
+ exports.Uint8 = Uint8; |
+ exports.Uint16 = Uint16; |
+ exports.Uint32 = Uint32; |
+ exports.Uint64 = Uint64; |
+ exports.PointerTo = PointerTo; |
+ exports.Handle = Handle; |
+ return exports; |
+}); |