| Index: mojo/bindings/java/src/org/chromium/mojo/bindings/Decoder.java
|
| 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 0000000000000000000000000000000000000000..86a038fc503fab3261a4f038c043686ef3fbeebb
|
| --- /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);
|
| + }
|
| +
|
| +}
|
|
|