summaryrefslogtreecommitdiffstats
path: root/mojo/bindings/java/src/org
diff options
context:
space:
mode:
authorqsr@chromium.org <qsr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-03 12:42:52 +0000
committerqsr@chromium.org <qsr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-03 12:42:52 +0000
commitfe856e352e51a2b83a16d48576a3999524eedb7a (patch)
tree1f950124ae80ee40d13b97b6164f139648378652 /mojo/bindings/java/src/org
parent94d285158732c0685f2f42e85b87d29634c812ee (diff)
downloadchromium_src-fe856e352e51a2b83a16d48576a3999524eedb7a.zip
chromium_src-fe856e352e51a2b83a16d48576a3999524eedb7a.tar.gz
chromium_src-fe856e352e51a2b83a16d48576a3999524eedb7a.tar.bz2
Add serialization/deserialization of structs for mojo java bindings.
R=viettrungluu@chromium.org,rmcilroy@chromium.org Review URL: https://codereview.chromium.org/317273006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@281255 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'mojo/bindings/java/src/org')
-rw-r--r--mojo/bindings/java/src/org/chromium/mojo/bindings/BindingsHelper.java14
-rw-r--r--mojo/bindings/java/src/org/chromium/mojo/bindings/Decoder.java486
-rw-r--r--mojo/bindings/java/src/org/chromium/mojo/bindings/DeserializationException.java26
-rw-r--r--mojo/bindings/java/src/org/chromium/mojo/bindings/Encoder.java458
-rw-r--r--mojo/bindings/java/src/org/chromium/mojo/bindings/Struct.java64
5 files changed, 1047 insertions, 1 deletions
diff --git a/mojo/bindings/java/src/org/chromium/mojo/bindings/BindingsHelper.java b/mojo/bindings/java/src/org/chromium/mojo/bindings/BindingsHelper.java
index f2aa046..0288678 100644
--- a/mojo/bindings/java/src/org/chromium/mojo/bindings/BindingsHelper.java
+++ b/mojo/bindings/java/src/org/chromium/mojo/bindings/BindingsHelper.java
@@ -9,11 +9,23 @@ package org.chromium.mojo.bindings;
*/
public class BindingsHelper {
/**
- * Alignment in byte for mojo serialization.
+ * Alignment in bytes for mojo serialization.
*/
public static final int ALIGNMENT = 8;
/**
+ * The size, in bytes, of a serialized handle. A handle is serialized as an int representing the
+ * offset of the handle in the list of handles.
+ */
+ public static final int SERIALIZED_HANDLE_SIZE = 4;
+
+ /**
+ * The size, in bytes, of a serialized pointer. A pointer is serializaed as an unsigned long
+ * representing the offset from its position to the pointed elemnt.
+ */
+ public static final int POINTER_SIZE = 8;
+
+ /**
* Align |size| on {@link BindingsHelper#ALIGNMENT}.
*/
public static int align(int size) {
diff --git a/mojo/bindings/java/src/org/chromium/mojo/bindings/Decoder.java b/mojo/bindings/java/src/org/chromium/mojo/bindings/Decoder.java
new file mode 100644
index 0000000..86a038f
--- /dev/null
+++ b/mojo/bindings/java/src/org/chromium/mojo/bindings/Decoder.java
@@ -0,0 +1,486 @@
+// 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.bindings.Struct.DataHeader;
+import org.chromium.mojo.system.DataPipe;
+import org.chromium.mojo.system.Handle;
+import org.chromium.mojo.system.InvalidHandle;
+import org.chromium.mojo.system.MessagePipeHandle;
+import org.chromium.mojo.system.SharedBufferHandle;
+
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+/**
+ * A Decoder is a helper class for deserializing a mojo struct. It enables deserialization of basic
+ * types from a {@link Message} object at a given offset into it's byte buffer.
+ */
+public class Decoder {
+
+ /**
+ * Helper class to validate the decoded message.
+ */
+ static final class Validator {
+
+ /**
+ * Minimal value for the next handle to deserialize.
+ */
+ private int mMinNextClaimedHandle = 0;
+ /**
+ * Minimal value of the start of the next memory to claim.
+ */
+ private long mMinNextMemory = 0;
+
+ /**
+ * The maximal memory accessible.
+ */
+ private final long mMaxMemory;
+
+ /**
+ * Constructor.
+ */
+ Validator(long maxMemory) {
+ mMaxMemory = maxMemory;
+ }
+
+ public void claimHandle(int handle) {
+ if (handle < mMinNextClaimedHandle) {
+ throw new DeserializationException(
+ "Trying to access handle out of order.");
+ }
+ mMinNextClaimedHandle = handle + 1;
+ }
+
+ public void claimMemory(long start, long end) {
+ if (start < mMinNextMemory) {
+ throw new DeserializationException("Trying to access memory out of order.");
+ }
+ if (end < start) {
+ throw new DeserializationException("Incorrect memory range.");
+ }
+ if (end > mMaxMemory) {
+ throw new DeserializationException("Trying to access out of range memory.");
+ }
+ if (start % BindingsHelper.ALIGNMENT != 0 || end % BindingsHelper.ALIGNMENT != 0) {
+ throw new DeserializationException("Incorrect alignment.");
+ }
+ mMinNextMemory = end;
+ }
+ }
+
+ /**
+ * The message to deserialize from.
+ */
+ private final Message mMessage;
+
+ /**
+ * The base offset in the byte buffer.
+ */
+ private final int mBaseOffset;
+
+ /**
+ * Validator for the decoded message.
+ */
+ private final Validator mValidator;
+
+ /**
+ * Constructor.
+ *
+ * @param message The message to decode.
+ */
+ public Decoder(Message message) {
+ this(message, new Validator(message.buffer.limit()), 0);
+ }
+
+ private Decoder(Message message, Validator validator, int baseOffset) {
+ mMessage = message;
+ mMessage.buffer.order(ByteOrder.nativeOrder());
+ mBaseOffset = baseOffset;
+ mValidator = validator;
+ // Claim the memory for the header.
+ mValidator.claimMemory(mBaseOffset, mBaseOffset + DataHeader.HEADER_SIZE);
+ }
+
+ /**
+ * Deserializes a {@link DataHeader} at the given offset.
+ */
+ public DataHeader readDataHeader() {
+ int size = readInt(DataHeader.SIZE_OFFSET);
+ int numFields = readInt(DataHeader.NUM_FIELDS_OFFSET);
+ // The memory for the header has already been claimed.
+ mValidator.claimMemory(mBaseOffset + DataHeader.HEADER_SIZE, mBaseOffset + size);
+ DataHeader res = new DataHeader(size, numFields);
+ return res;
+ }
+
+ /**
+ * Deserializes a byte at the given offset.
+ */
+ public byte readByte(int offset) {
+ return mMessage.buffer.get(mBaseOffset + offset);
+ }
+
+ /**
+ * Deserializes a boolean at the given offset, re-using any partially read byte.
+ */
+ public boolean readBoolean(int offset, int bit) {
+ return (readByte(offset) & (1 << bit)) != 0;
+ }
+
+ /**
+ * Deserializes a short at the given offset.
+ */
+ public short readShort(int offset) {
+ return mMessage.buffer.getShort(mBaseOffset + offset);
+ }
+
+ /**
+ * Deserializes an int at the given offset.
+ */
+ public int readInt(int offset) {
+ return mMessage.buffer.getInt(mBaseOffset + offset);
+ }
+
+ /**
+ * Deserializes a float at the given offset.
+ */
+ public float readFloat(int offset) {
+ return mMessage.buffer.getFloat(mBaseOffset + offset);
+ }
+
+ /**
+ * Deserializes a long at the given offset.
+ */
+ public long readLong(int offset) {
+ return mMessage.buffer.getLong(mBaseOffset + offset);
+ }
+
+ /**
+ * Deserializes a double at the given offset.
+ */
+ public double readDouble(int offset) {
+ return mMessage.buffer.getDouble(mBaseOffset + offset);
+ }
+
+ /**
+ * Deserializes a pointer at the given offset. Returns a Decoder suitable to decode the content
+ * of the pointer.
+ */
+ public Decoder readPointer(int offset) {
+ int basePosition = mBaseOffset + offset;
+ long pointerOffset = readLong(offset);
+ if (pointerOffset == 0) {
+ return null;
+ }
+ int newPosition = (int) (basePosition + pointerOffset);
+ // The method |getDecoderAtPosition| will validate that the pointer address is valid.
+ return getDecoderAtPosition(newPosition);
+
+ }
+
+ /**
+ * Deserializes an array of boolean at the given offset.
+ */
+ public boolean[] readBooleans(int offset) {
+ Decoder d = readPointer(offset);
+ if (d == null) {
+ return null;
+ }
+ DataHeader si = d.readDataHeader();
+ byte[] bytes = new byte[si.numFields + 7 / BindingsHelper.ALIGNMENT];
+ d.mMessage.buffer.position(d.mBaseOffset + DataHeader.HEADER_SIZE);
+ d.mMessage.buffer.get(bytes);
+ boolean[] result = new boolean[si.numFields];
+ for (int i = 0; i < bytes.length; ++i) {
+ for (int j = 0; j < BindingsHelper.ALIGNMENT; ++j) {
+ int booleanIndex = i * BindingsHelper.ALIGNMENT + j;
+ if (booleanIndex < result.length) {
+ result[booleanIndex] = (bytes[i] & (1 << j)) != 0;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Deserializes an array of bytes at the given offset.
+ */
+ public byte[] readBytes(int offset) {
+ Decoder d = readPointer(offset);
+ if (d == null) {
+ return null;
+ }
+ DataHeader si = d.readDataHeader();
+ byte[] result = new byte[si.numFields];
+ d.mMessage.buffer.position(d.mBaseOffset + DataHeader.HEADER_SIZE);
+ d.mMessage.buffer.get(result);
+ return result;
+ }
+
+ /**
+ * Deserializes an array of shorts at the given offset.
+ */
+ public short[] readShorts(int offset) {
+ Decoder d = readPointer(offset);
+ if (d == null) {
+ return null;
+ }
+ DataHeader si = d.readDataHeader();
+ short[] result = new short[si.numFields];
+ d.mMessage.buffer.position(d.mBaseOffset + DataHeader.HEADER_SIZE);
+ d.mMessage.buffer.asShortBuffer().get(result);
+ return result;
+ }
+
+ /**
+ * Deserializes an array of ints at the given offset.
+ */
+ public int[] readInts(int offset) {
+ Decoder d = readPointer(offset);
+ if (d == null) {
+ return null;
+ }
+ DataHeader si = d.readDataHeader();
+ int[] result = new int[si.numFields];
+ d.mMessage.buffer.position(d.mBaseOffset + DataHeader.HEADER_SIZE);
+ d.mMessage.buffer.asIntBuffer().get(result);
+ return result;
+ }
+
+ /**
+ * Deserializes an array of floats at the given offset.
+ */
+ public float[] readFloats(int offset) {
+ Decoder d = readPointer(offset);
+ if (d == null) {
+ return null;
+ }
+ DataHeader si = d.readDataHeader();
+ float[] result = new float[si.numFields];
+ d.mMessage.buffer.position(d.mBaseOffset + DataHeader.HEADER_SIZE);
+ d.mMessage.buffer.asFloatBuffer().get(result);
+ return result;
+ }
+
+ /**
+ * Deserializes an array of longs at the given offset.
+ */
+ public long[] readLongs(int offset) {
+ Decoder d = readPointer(offset);
+ if (d == null) {
+ return null;
+ }
+ DataHeader si = d.readDataHeader();
+ long[] result = new long[si.numFields];
+ d.mMessage.buffer.position(d.mBaseOffset + DataHeader.HEADER_SIZE);
+ d.mMessage.buffer.asLongBuffer().get(result);
+ return result;
+ }
+
+ /**
+ * Deserializes an array of doubles at the given offset.
+ */
+ public double[] readDoubles(int offset) {
+ Decoder d = readPointer(offset);
+ if (d == null) {
+ return null;
+ }
+ DataHeader si = d.readDataHeader();
+ double[] result = new double[si.numFields];
+ d.mMessage.buffer.position(d.mBaseOffset + DataHeader.HEADER_SIZE);
+ d.mMessage.buffer.asDoubleBuffer().get(result);
+ return result;
+ }
+
+ /**
+ * Deserializes an |Handle| at the given offset.
+ */
+ public Handle readHandle(int offset) {
+ int index = readInt(offset);
+ if (index == -1) {
+ return InvalidHandle.INSTANCE;
+ }
+ mValidator.claimHandle(index);
+ return mMessage.handles.get(index);
+ }
+
+ /**
+ * Deserializes a |ConsumerHandle| at the given offset.
+ */
+ public DataPipe.ConsumerHandle readConsumerHandle(int offset) {
+ return readHandle(offset).toUntypedHandle().toDataPipeConsumerHandle();
+ }
+
+ /**
+ * Deserializes a |ProducerHandle| at the given offset.
+ */
+ public DataPipe.ProducerHandle readProducerHandle(int offset) {
+ return readHandle(offset).toUntypedHandle().toDataPipeProducerHandle();
+ }
+
+ /**
+ * Deserializes a |MessagePipeHandle| at the given offset.
+ */
+ public MessagePipeHandle readMessagePipeHandle(int offset) {
+ return readHandle(offset).toUntypedHandle().toMessagePipeHandle();
+ }
+
+ /**
+ * Deserializes a |SharedBufferHandle| at the given offset.
+ */
+ public SharedBufferHandle readSharedBufferHandle(int offset) {
+ return readHandle(offset).toUntypedHandle().toSharedBufferHandle();
+ }
+
+ /**
+ * Deserializes a |ServiceHandle| at the given offset.
+ */
+ public <S extends Interface> S readServiceInterface(int offset, Object builder) {
+ // TODO(qsr): To be implemented when interfaces proxy and stubs are implemented.
+ throw new UnsupportedOperationException("Unimplemented operation");
+ }
+
+ /**
+ * Deserializes a |InterfaceRequest| at the given offset.
+ */
+ public <S extends Interface> InterfaceRequest<S> readInterfaceRequest(int offset) {
+ // TODO(qsr): To be implemented when interfaces proxy and stubs are implemented.
+ throw new UnsupportedOperationException("Unimplemented operation");
+ }
+
+ /**
+ * Deserializes a string at the given offset.
+ */
+ public String readString(int offset) {
+ byte[] bytes = readBytes(offset);
+ if (bytes == null) {
+ return null;
+ }
+ return new String(bytes, Charset.forName("utf8"));
+ }
+
+ /**
+ * Deserializes an array of |Handle| at the given offset.
+ */
+ public Handle[] readHandles(int offset) {
+ Decoder d = readPointer(offset);
+ if (d == null) {
+ return null;
+ }
+ DataHeader si = d.readDataHeader();
+ Handle[] result = new Handle[si.numFields];
+ for (int i = 0; i < result.length; ++i) {
+ result[i] = d.readHandle(
+ DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i);
+ }
+ return result;
+ }
+
+ /**
+ * Deserializes an array of |ConsumerHandle| at the given offset.
+ */
+ public DataPipe.ConsumerHandle[] readConsumerHandles(int offset) {
+ Decoder d = readPointer(offset);
+ if (d == null) {
+ return null;
+ }
+ DataHeader si = d.readDataHeader();
+ DataPipe.ConsumerHandle[] result = new DataPipe.ConsumerHandle[si.numFields];
+ for (int i = 0; i < result.length; ++i) {
+ result[i] = d.readConsumerHandle(
+ DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i);
+ }
+ return result;
+ }
+
+ /**
+ * Deserializes an array of |ProducerHandle| at the given offset.
+ */
+ public DataPipe.ProducerHandle[] readProducerHandles(int offset) {
+ Decoder d = readPointer(offset);
+ if (d == null) {
+ return null;
+ }
+ DataHeader si = d.readDataHeader();
+ DataPipe.ProducerHandle[] result = new DataPipe.ProducerHandle[si.numFields];
+ for (int i = 0; i < result.length; ++i) {
+ result[i] = d.readProducerHandle(
+ DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i);
+ }
+ return result;
+
+ }
+
+ /**
+ * Deserializes an array of |MessagePipeHandle| at the given offset.
+ */
+ public MessagePipeHandle[] readMessagePipeHandles(int offset) {
+ Decoder d = readPointer(offset);
+ if (d == null) {
+ return null;
+ }
+ DataHeader si = d.readDataHeader();
+ MessagePipeHandle[] result = new MessagePipeHandle[si.numFields];
+ for (int i = 0; i < result.length; ++i) {
+ result[i] = d.readMessagePipeHandle(
+ DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i);
+ }
+ return result;
+
+ }
+
+ /**
+ * Deserializes an array of |SharedBufferHandle| at the given offset.
+ */
+ public SharedBufferHandle[] readSharedBufferHandles(int offset) {
+ Decoder d = readPointer(offset);
+ if (d == null) {
+ return null;
+ }
+ DataHeader si = d.readDataHeader();
+ SharedBufferHandle[] result = new SharedBufferHandle[si.numFields];
+ for (int i = 0; i < result.length; ++i) {
+ result[i] = d.readSharedBufferHandle(
+ DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i);
+ }
+ return result;
+
+ }
+
+ /**
+ * Deserializes an array of |ServiceHandle| at the given offset.
+ */
+ public <S extends Interface> S[] readServiceInterfaces(int offset, Object builder) {
+ // TODO(qsr): To be implemented when interfaces proxy and stubs are implemented.
+ throw new UnsupportedOperationException("Unimplemented operation");
+ }
+
+ /**
+ * Deserializes an array of |InterfaceRequest| at the given offset.
+ */
+ public <S extends Interface> InterfaceRequest<S>[] readInterfaceRequests(int offset) {
+ Decoder d = readPointer(offset);
+ if (d == null) {
+ return null;
+ }
+ DataHeader si = d.readDataHeader();
+ @SuppressWarnings("unchecked")
+ InterfaceRequest<S>[] result = new InterfaceRequest[si.numFields];
+ for (int i = 0; i < result.length; ++i) {
+ result[i] = d.readInterfaceRequest(
+ DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i);
+ }
+ return result;
+ }
+
+ /**
+ * Returns a view of this decoder at the offset |offset|.
+ */
+ private Decoder getDecoderAtPosition(int offset) {
+ return new Decoder(mMessage, mValidator, offset);
+ }
+
+}
diff --git a/mojo/bindings/java/src/org/chromium/mojo/bindings/DeserializationException.java b/mojo/bindings/java/src/org/chromium/mojo/bindings/DeserializationException.java
new file mode 100644
index 0000000..eeb511c
--- /dev/null
+++ b/mojo/bindings/java/src/org/chromium/mojo/bindings/DeserializationException.java
@@ -0,0 +1,26 @@
+// 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.
+
+package org.chromium.mojo.bindings;
+
+/**
+ * Error when deserializing a mojo message.
+ */
+public class DeserializationException extends RuntimeException {
+
+ /**
+ * Constructs a new deserialization exception with the specified detail message.
+ */
+ public DeserializationException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructs a new deserialization exception with the specified cause.
+ */
+ public DeserializationException(Exception cause) {
+ super(cause);
+ }
+
+}
diff --git a/mojo/bindings/java/src/org/chromium/mojo/bindings/Encoder.java b/mojo/bindings/java/src/org/chromium/mojo/bindings/Encoder.java
new file mode 100644
index 0000000..9ec2cb2
--- /dev/null
+++ b/mojo/bindings/java/src/org/chromium/mojo/bindings/Encoder.java
@@ -0,0 +1,458 @@
+// 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.
+
+package org.chromium.mojo.bindings;
+
+import org.chromium.mojo.bindings.Struct.DataHeader;
+import org.chromium.mojo.system.Core;
+import org.chromium.mojo.system.Handle;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper class to encode a mojo struct. It keeps track of the output buffer, resizing it as needed.
+ * It also keeps track of the associated handles, and the offset of the current data section.
+ */
+public class Encoder {
+
+ /**
+ * Container class for all state that must be shared between the main encoder and any used sub
+ * encoder.
+ */
+ private static class EncoderState {
+
+ /**
+ * The core used to encode interfaces.
+ */
+ public final Core core;
+
+ /**
+ * The ByteBuffer to which the message will be encoded.
+ */
+ public ByteBuffer byteBuffer;
+
+ /**
+ * The list of encountered handles.
+ */
+ public final List<Handle> handles = new ArrayList<Handle>();
+
+ /**
+ * The current absolute position for the next data section.
+ */
+ public int dataEnd;
+
+ /**
+ * @param core the |Core| implementation used to generate handles. Only used if the |Struct|
+ * being encoded contains interfaces, can be |null| otherwise.
+ * @param bufferSize A hint on the size of the message. Used to build the initial byte
+ * buffer.
+ */
+ private EncoderState(Core core, int bufferSize) {
+ assert bufferSize % BindingsHelper.ALIGNMENT == 0;
+ this.core = core;
+ byteBuffer = ByteBuffer.allocateDirect(
+ bufferSize > 0 ? bufferSize : INITIAL_BUFFER_SIZE);
+ byteBuffer.order(ByteOrder.nativeOrder());
+ dataEnd = 0;
+ }
+
+ /**
+ * Claim the given amount of memory at the end of the buffer, resizing it if needed.
+ */
+ public void claimMemory(int size) {
+ dataEnd += size;
+ growIfNeeded();
+ }
+
+ /**
+ * Grow the associated ByteBuffer if needed.
+ */
+ private void growIfNeeded() {
+ if (byteBuffer.capacity() >= dataEnd) {
+ return;
+ }
+ int targetSize = byteBuffer.capacity() * 2;
+ while (targetSize < dataEnd) {
+ targetSize *= 2;
+ }
+ ByteBuffer newBuffer = ByteBuffer.allocateDirect(targetSize);
+ newBuffer.order(ByteOrder.nativeOrder());
+ byteBuffer.position(0);
+ byteBuffer.limit(byteBuffer.capacity());
+ newBuffer.put(byteBuffer);
+ byteBuffer = newBuffer;
+ }
+ }
+
+ /**
+ * Default initial size of the data buffer. This must be a multiple of 8 bytes.
+ */
+ private static final int INITIAL_BUFFER_SIZE = 1024;
+
+ /**
+ * Base offset in the byte buffer for writing.
+ */
+ private int mBaseOffset;
+
+ /**
+ * The encoder state shared by the main encoder and all its sub-encoder.
+ */
+ private final EncoderState mEncoderState;
+
+ /**
+ * Returns the result message.
+ */
+ public Message getMessage() {
+ mEncoderState.byteBuffer.position(0);
+ mEncoderState.byteBuffer.limit(mEncoderState.dataEnd);
+ return new Message(mEncoderState.byteBuffer, mEncoderState.handles);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param core the |Core| implementation used to generate handles. Only used if the |Struct|
+ * being encoded contains interfaces, can be |null| otherwise.
+ * @param sizeHint A hint on the size of the message. Used to build the initial byte buffer.
+ */
+ public Encoder(Core core, int sizeHint) {
+ this(new EncoderState(core, sizeHint));
+ }
+
+ /**
+ * Private constructor for sub-encoders.
+ */
+ private Encoder(EncoderState bufferInformation) {
+ mEncoderState = bufferInformation;
+ mBaseOffset = bufferInformation.dataEnd;
+ }
+
+ /**
+ * Returns a new encoder that will append to the current buffer.
+ */
+ public Encoder getEncoderAtDataOffset(DataHeader dataHeader) {
+ Encoder result = new Encoder(mEncoderState);
+ result.encode(dataHeader);
+ return result;
+
+ }
+
+ /**
+ * Encode a {@link DataHeader} and claim the amount of memory required for the data section
+ * (resizing the buffer if required).
+ */
+ public void encode(DataHeader s) {
+ mEncoderState.claimMemory(s.size);
+ encode(s.size, DataHeader.SIZE_OFFSET);
+ encode(s.numFields, DataHeader.NUM_FIELDS_OFFSET);
+ }
+
+ /**
+ * Encode a byte at the given offset.
+ */
+ public void encode(byte v, int offset) {
+ mEncoderState.byteBuffer.put(mBaseOffset + offset, v);
+ }
+
+ /**
+ * Encode a boolean at the given offset.
+ */
+ public void encode(boolean v, int offset, int bit) {
+ if (v) {
+ byte encodedValue = mEncoderState.byteBuffer.get(mBaseOffset + offset);
+ encodedValue |= 1 << bit;
+ mEncoderState.byteBuffer.put(mBaseOffset + offset, encodedValue);
+ }
+ }
+
+ /**
+ * Encode a short at the given offset.
+ */
+ public void encode(short v, int offset) {
+ mEncoderState.byteBuffer.putShort(mBaseOffset + offset, v);
+ }
+
+ /**
+ * Encode an int at the given offset.
+ */
+ public void encode(int v, int offset) {
+ mEncoderState.byteBuffer.putInt(mBaseOffset + offset, v);
+ }
+
+ /**
+ * Encode a float at the given offset.
+ */
+ public void encode(float v, int offset) {
+ mEncoderState.byteBuffer.putFloat(mBaseOffset + offset, v);
+ }
+
+ /**
+ * Encode a long at the given offset.
+ */
+ public void encode(long v, int offset) {
+ mEncoderState.byteBuffer.putLong(mBaseOffset + offset, v);
+ }
+
+ /**
+ * Encode a double at the given offset.
+ */
+ public void encode(double v, int offset) {
+ mEncoderState.byteBuffer.putDouble(mBaseOffset + offset, v);
+ }
+
+ /**
+ * Encode a {@link Struct} at the given offset.
+ */
+ public void encode(Struct v, int offset) {
+ if (v == null) {
+ encodeNullPointer(offset);
+ return;
+ }
+ encodePointerToNextUnclaimedData(offset);
+ v.encode(this);
+ }
+
+ /**
+ * Encodes a String.
+ */
+ public void encode(String v, int offset) {
+ if (v == null) {
+ encodeNullPointer(offset);
+ return;
+ }
+ encode(v.getBytes(Charset.forName("utf8")), offset);
+ }
+
+ /**
+ * Encodes a {@link Handle}.
+ */
+ public void encode(Handle v, int offset) {
+ if (v == null || !v.isValid()) {
+ encode(-1, offset);
+ } else {
+ encode(mEncoderState.handles.size(), offset);
+ mEncoderState.handles.add(v);
+ }
+ }
+
+ /**
+ * Encode an {@link Interface}.
+ */
+ public <T extends Interface> void encode(T v, int offset, Object builder) {
+ if (mEncoderState.core == null) {
+ throw new UnsupportedOperationException(
+ "The encoder has been created without a Core. It can't encode an interface.");
+ }
+ // TODO(qsr): To be implemented when interfaces proxy and stubs are implemented.
+ throw new UnsupportedOperationException("Unimplemented operation");
+ }
+
+ /**
+ * Encode an {@link InterfaceRequest}.
+ */
+ public <T extends Interface> void encode(InterfaceRequest<T> v, int offset) {
+ if (mEncoderState.core == null) {
+ throw new UnsupportedOperationException(
+ "The encoder has been created without a Core. It can't encode an interface.");
+ }
+ // TODO(qsr): To be implemented when interfaces proxy and stubs are implemented.
+ throw new UnsupportedOperationException("Unimplemented operation");
+ }
+
+ /**
+ * Returns an {@link Encoder} suitable for encoding an array of pointer of the given length.
+ */
+ public Encoder encodePointerArray(int length, int offset) {
+ return encoderForArray(BindingsHelper.POINTER_SIZE, length, offset);
+ }
+
+ /**
+ * Encodes an array of booleans.
+ */
+ public void encode(boolean[] v, int offset) {
+ if (v == null) {
+ encodeNullPointer(offset);
+ return;
+ }
+ byte[] bytes = new byte[(v.length + 7) / BindingsHelper.ALIGNMENT];
+ for (int i = 0; i < bytes.length; ++i) {
+ for (int j = 0; j < BindingsHelper.ALIGNMENT; ++j) {
+ int booleanIndex = BindingsHelper.ALIGNMENT * i + j;
+ if (booleanIndex < v.length && v[booleanIndex]) {
+ bytes[i] |= (1 << j);
+ }
+ }
+ }
+ encodeByteArray(bytes, v.length, offset);
+ }
+
+ /**
+ * Encodes an array of bytes.
+ */
+ public void encode(byte[] v, int offset) {
+ if (v == null) {
+ encodeNullPointer(offset);
+ return;
+ }
+ encodeByteArray(v, v.length, offset);
+ }
+
+ /**
+ * Encodes an array of shorts.
+ */
+ public void encode(short[] v, int offset) {
+ if (v == null) {
+ encodeNullPointer(offset);
+ return;
+ }
+ encoderForArray(2, v.length, offset).append(v);
+ }
+
+ /**
+ * Encodes an array of ints.
+ */
+ public void encode(int[] v, int offset) {
+ if (v == null) {
+ encodeNullPointer(offset);
+ return;
+ }
+ encoderForArray(4, v.length, offset).append(v);
+ }
+
+ /**
+ * Encodes an array of floats.
+ */
+ public void encode(float[] v, int offset) {
+ if (v == null) {
+ encodeNullPointer(offset);
+ return;
+ }
+ encoderForArray(4, v.length, offset).append(v);
+ }
+
+ /**
+ * Encodes an array of longs.
+ */
+ public void encode(long[] v, int offset) {
+ if (v == null) {
+ encodeNullPointer(offset);
+ return;
+ }
+ encoderForArray(8, v.length, offset).append(v);
+ }
+
+ /**
+ * Encodes an array of doubles.
+ */
+ public void encode(double[] v, int offset) {
+ if (v == null) {
+ encodeNullPointer(offset);
+ return;
+ }
+ encoderForArray(8, v.length, offset).append(v);
+ }
+
+ /**
+ * Encodes an array of {@link Handle}.
+ */
+ public void encode(Handle[] v, int offset) {
+ if (v == null) {
+ encodeNullPointer(offset);
+ return;
+ }
+ Encoder e = encoderForArray(BindingsHelper.SERIALIZED_HANDLE_SIZE, v.length, offset);
+ for (int i = 0; i < v.length; ++i) {
+ e.encode(v[i], DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i);
+ }
+ }
+
+ /**
+ * Encodes an array of {@link Interface}.
+ */
+ public <T extends Interface> void encode(T[] v, int offset, Object builder) {
+ if (v == null) {
+ encodeNullPointer(offset);
+ return;
+ }
+ Encoder e = encoderForArray(BindingsHelper.SERIALIZED_HANDLE_SIZE, v.length, offset);
+ for (int i = 0; i < v.length; ++i) {
+ e.encode(v[i], DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
+ builder);
+ }
+ }
+
+ /**
+ * Encodes an array of {@link Interface}.
+ */
+ public <T extends Interface> void encode(InterfaceRequest<T>[] v, int offset) {
+ if (v == null) {
+ encodeNullPointer(offset);
+ return;
+ }
+ Encoder e = encoderForArray(BindingsHelper.SERIALIZED_HANDLE_SIZE, v.length, offset);
+ for (int i = 0; i < v.length; ++i) {
+ e.encode(v[i], DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i);
+ }
+ }
+
+ /**
+ * Encode a <code>null</code> pointer.
+ */
+ public void encodeNullPointer(int offset) {
+ mEncoderState.byteBuffer.putLong(mBaseOffset + offset, 0);
+ }
+
+ private void encodePointerToNextUnclaimedData(int offset) {
+ encode((long) mEncoderState.dataEnd - (mBaseOffset + offset), offset);
+ }
+
+ private Encoder encoderForArray(int elementSizeInByte, int length, int offset) {
+ return encoderForArrayByTotalSize(length * elementSizeInByte, length, offset);
+ }
+
+ private Encoder encoderForArrayByTotalSize(int byteSize, int length, int offset) {
+ encodePointerToNextUnclaimedData(offset);
+ return getEncoderAtDataOffset(
+ new DataHeader(DataHeader.HEADER_SIZE + BindingsHelper.align(byteSize), length));
+ }
+
+ private void encodeByteArray(byte[] bytes, int length, int offset) {
+ encoderForArrayByTotalSize(bytes.length, length, offset).append(bytes);
+ }
+
+ private void append(byte[] v) {
+ mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
+ mEncoderState.byteBuffer.put(v);
+ }
+
+ private void append(short[] v) {
+ mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
+ mEncoderState.byteBuffer.asShortBuffer().put(v);
+ }
+
+ private void append(int[] v) {
+ mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
+ mEncoderState.byteBuffer.asIntBuffer().put(v);
+ }
+
+ private void append(float[] v) {
+ mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
+ mEncoderState.byteBuffer.asFloatBuffer().put(v);
+ }
+
+ private void append(double[] v) {
+ mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
+ mEncoderState.byteBuffer.asDoubleBuffer().put(v);
+ }
+
+ private void append(long[] v) {
+ mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
+ mEncoderState.byteBuffer.asLongBuffer().put(v);
+ }
+
+}
diff --git a/mojo/bindings/java/src/org/chromium/mojo/bindings/Struct.java b/mojo/bindings/java/src/org/chromium/mojo/bindings/Struct.java
index 54bf355..f7c16a2 100644
--- a/mojo/bindings/java/src/org/chromium/mojo/bindings/Struct.java
+++ b/mojo/bindings/java/src/org/chromium/mojo/bindings/Struct.java
@@ -4,9 +4,73 @@
package org.chromium.mojo.bindings;
+import org.chromium.mojo.system.Core;
+
/**
* Base class for all mojo structs.
*/
public abstract class Struct {
+ /**
+ * The header for a mojo complex element.
+ */
+ public static final class DataHeader {
+
+ /**
+ * The size of a serialized header, in bytes.
+ */
+ public static final int HEADER_SIZE = 8;
+
+ /**
+ * The offset of the size field.
+ */
+ public static final int SIZE_OFFSET = 0;
+
+ /**
+ * The offset of the number of fields field.
+ */
+ public static final int NUM_FIELDS_OFFSET = 4;
+
+ public final int size;
+ public final int numFields;
+
+ /**
+ * Constructor.
+ */
+ public DataHeader(int size, int numFields) {
+ super();
+ this.size = size;
+ this.numFields = numFields;
+ }
+ }
+
+ /**
+ * The base size of the struct.
+ */
+ protected final int mEncodedBaseSize;
+
+ /**
+ * Constructor.
+ */
+ protected Struct(int encodedBaseSize) {
+ this.mEncodedBaseSize = encodedBaseSize;
+ }
+
+ /**
+ * Use the given encoder to serialized this struct.
+ */
+ protected abstract void encode(Encoder encoder);
+
+ /**
+ * Returns the serialization of the struct. This method can close Handles.
+ *
+ * @param core the |Core| implementation used to generate handles. Only used if the |Struct|
+ * being encoded contains interfaces, can be |null| otherwise.
+ */
+ public Message serialize(Core core) {
+ Encoder encoder = new Encoder(core, mEncodedBaseSize);
+ encode(encoder);
+ return encoder.getMessage();
+ }
+
}