Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / mojo / public / java / bindings / src / org / chromium / mojo / bindings / Encoder.java
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.mojo.bindings;
6
7 import org.chromium.mojo.bindings.Struct.DataHeader;
8 import org.chromium.mojo.system.Core;
9 import org.chromium.mojo.system.Handle;
10 import org.chromium.mojo.system.MessagePipeHandle;
11 import org.chromium.mojo.system.Pair;
12
13 import java.nio.ByteBuffer;
14 import java.nio.ByteOrder;
15 import java.nio.charset.Charset;
16 import java.util.ArrayList;
17 import java.util.List;
18
19 /**
20  * Helper class to encode a mojo struct. It keeps track of the output buffer, resizing it as needed.
21  * It also keeps track of the associated handles, and the offset of the current data section.
22  */
23 public class Encoder {
24
25     /**
26      * Container class for all state that must be shared between the main encoder and any used sub
27      * encoder.
28      */
29     private static class EncoderState {
30
31         /**
32          * The core used to encode interfaces.
33          */
34         public final Core core;
35
36         /**
37          * The ByteBuffer to which the message will be encoded.
38          */
39         public ByteBuffer byteBuffer;
40
41         /**
42          * The list of encountered handles.
43          */
44         public final List<Handle> handles = new ArrayList<Handle>();
45
46         /**
47          * The current absolute position for the next data section.
48          */
49         public int dataEnd;
50
51         /**
52          * @param core the |Core| implementation used to generate handles. Only used if the |Struct|
53          *            being encoded contains interfaces, can be |null| otherwise.
54          * @param bufferSize A hint on the size of the message. Used to build the initial byte
55          *            buffer.
56          */
57         private EncoderState(Core core, int bufferSize) {
58             assert bufferSize % BindingsHelper.ALIGNMENT == 0;
59             this.core = core;
60             byteBuffer = ByteBuffer.allocateDirect(
61                     bufferSize > 0 ? bufferSize : INITIAL_BUFFER_SIZE);
62             byteBuffer.order(ByteOrder.nativeOrder());
63             dataEnd = 0;
64         }
65
66         /**
67          * Claim the given amount of memory at the end of the buffer, resizing it if needed.
68          */
69         public void claimMemory(int size) {
70             dataEnd += size;
71             growIfNeeded();
72         }
73
74         /**
75          * Grow the associated ByteBuffer if needed.
76          */
77         private void growIfNeeded() {
78             if (byteBuffer.capacity() >= dataEnd) {
79                 return;
80             }
81             int targetSize = byteBuffer.capacity() * 2;
82             while (targetSize < dataEnd) {
83                 targetSize *= 2;
84             }
85             ByteBuffer newBuffer = ByteBuffer.allocateDirect(targetSize);
86             newBuffer.order(ByteOrder.nativeOrder());
87             byteBuffer.position(0);
88             byteBuffer.limit(byteBuffer.capacity());
89             newBuffer.put(byteBuffer);
90             byteBuffer = newBuffer;
91         }
92     }
93
94     /**
95      * Default initial size of the data buffer. This must be a multiple of 8 bytes.
96      */
97     private static final int INITIAL_BUFFER_SIZE = 1024;
98
99     /**
100      * Base offset in the byte buffer for writing.
101      */
102     private int mBaseOffset;
103
104     /**
105      * The encoder state shared by the main encoder and all its sub-encoder.
106      */
107     private final EncoderState mEncoderState;
108
109     /**
110      * Returns the result message.
111      */
112     public Message getMessage() {
113         mEncoderState.byteBuffer.position(0);
114         mEncoderState.byteBuffer.limit(mEncoderState.dataEnd);
115         return new Message(mEncoderState.byteBuffer, mEncoderState.handles);
116     }
117
118     /**
119      * Constructor.
120      *
121      * @param core the |Core| implementation used to generate handles. Only used if the |Struct|
122      *            being encoded contains interfaces, can be |null| otherwise.
123      * @param sizeHint A hint on the size of the message. Used to build the initial byte buffer.
124      */
125     public Encoder(Core core, int sizeHint) {
126         this(new EncoderState(core, sizeHint));
127     }
128
129     /**
130      * Private constructor for sub-encoders.
131      */
132     private Encoder(EncoderState bufferInformation) {
133         mEncoderState = bufferInformation;
134         mBaseOffset = bufferInformation.dataEnd;
135     }
136
137     /**
138      * Returns a new encoder that will append to the current buffer.
139      */
140     public Encoder getEncoderAtDataOffset(DataHeader dataHeader) {
141         Encoder result = new Encoder(mEncoderState);
142         result.encode(dataHeader);
143         return result;
144     }
145
146     /**
147      * Encode a {@link DataHeader} and claim the amount of memory required for the data section
148      * (resizing the buffer if required).
149      */
150     public void encode(DataHeader s) {
151         mEncoderState.claimMemory(BindingsHelper.align(s.size));
152         encode(s.size, DataHeader.SIZE_OFFSET);
153         encode(s.numFields, DataHeader.NUM_FIELDS_OFFSET);
154     }
155
156     /**
157      * Encode a byte at the given offset.
158      */
159     public void encode(byte v, int offset) {
160         mEncoderState.byteBuffer.put(mBaseOffset + offset, v);
161     }
162
163     /**
164      * Encode a boolean at the given offset.
165      */
166     public void encode(boolean v, int offset, int bit) {
167         if (v) {
168             byte encodedValue = mEncoderState.byteBuffer.get(mBaseOffset + offset);
169             encodedValue |= 1 << bit;
170             mEncoderState.byteBuffer.put(mBaseOffset + offset, encodedValue);
171         }
172     }
173
174     /**
175      * Encode a short at the given offset.
176      */
177     public void encode(short v, int offset) {
178         mEncoderState.byteBuffer.putShort(mBaseOffset + offset, v);
179     }
180
181     /**
182      * Encode an int at the given offset.
183      */
184     public void encode(int v, int offset) {
185         mEncoderState.byteBuffer.putInt(mBaseOffset + offset, v);
186     }
187
188     /**
189      * Encode a float at the given offset.
190      */
191     public void encode(float v, int offset) {
192         mEncoderState.byteBuffer.putFloat(mBaseOffset + offset, v);
193     }
194
195     /**
196      * Encode a long at the given offset.
197      */
198     public void encode(long v, int offset) {
199         mEncoderState.byteBuffer.putLong(mBaseOffset + offset, v);
200     }
201
202     /**
203      * Encode a double at the given offset.
204      */
205     public void encode(double v, int offset) {
206         mEncoderState.byteBuffer.putDouble(mBaseOffset + offset, v);
207     }
208
209     /**
210      * Encode a {@link Struct} at the given offset.
211      */
212     public void encode(Struct v, int offset, boolean nullable) {
213         if (v == null) {
214             encodeNullPointer(offset, nullable);
215             return;
216         }
217         encodePointerToNextUnclaimedData(offset);
218         v.encode(this);
219     }
220
221     /**
222      * Encodes a String.
223      */
224     public void encode(String v, int offset, boolean nullable) {
225         if (v == null) {
226             encodeNullPointer(offset, nullable);
227             return;
228         }
229         final int arrayNullability = nullable ?
230                 BindingsHelper.ARRAY_NULLABLE : BindingsHelper.NOTHING_NULLABLE;
231         encode(v.getBytes(Charset.forName("utf8")), offset, arrayNullability,
232                 BindingsHelper.UNSPECIFIED_ARRAY_LENGTH);
233     }
234
235     /**
236      * Encodes a {@link Handle}.
237      */
238     public void encode(Handle v, int offset, boolean nullable) {
239         if (v == null || !v.isValid()) {
240             encodeInvalidHandle(offset, nullable);
241         } else {
242             encode(mEncoderState.handles.size(), offset);
243             mEncoderState.handles.add(v);
244         }
245     }
246
247     /**
248      * Encode an {@link Interface}.
249      */
250     public <T extends Interface> void encode(T v, int offset, boolean nullable,
251             Interface.Manager<T, ?> manager) {
252         if (v == null) {
253             encodeInvalidHandle(offset, nullable);
254             return;
255         }
256         if (mEncoderState.core == null) {
257             throw new UnsupportedOperationException(
258                     "The encoder has been created without a Core. It can't encode an interface.");
259         }
260         // If the instance is a proxy, pass the proxy's handle instead of creating a new stub.
261         if (v instanceof Interface.AbstractProxy) {
262             Interface.AbstractProxy proxy = (Interface.AbstractProxy) v;
263             if (proxy.getMessageReceiver() instanceof HandleOwner) {
264                 encode(((HandleOwner<?>) proxy.getMessageReceiver()).passHandle(), offset,
265                         nullable);
266                 return;
267             }
268             // If the proxy is not over a message pipe, the default case applies.
269         }
270         Pair<MessagePipeHandle, MessagePipeHandle> handles =
271                 mEncoderState.core.createMessagePipe(null);
272         manager.bind(v, handles.first);
273         encode(handles.second, offset, nullable);
274     }
275
276     /**
277      * Encode an {@link InterfaceRequest}.
278      */
279     public <I extends Interface> void encode(InterfaceRequest<I> v, int offset, boolean nullable) {
280         if (v == null) {
281             encodeInvalidHandle(offset, nullable);
282             return;
283         }
284         if (mEncoderState.core == null) {
285             throw new UnsupportedOperationException(
286                     "The encoder has been created without a Core. It can't encode an interface.");
287         }
288         encode(v.passHandle(), offset, nullable);
289     }
290
291     /**
292      * Returns an {@link Encoder} suitable for encoding an array of pointer of the given length.
293      */
294     public Encoder encodePointerArray(int length, int offset, int expectedLength) {
295         return encoderForArray(BindingsHelper.POINTER_SIZE, length, offset, expectedLength);
296     }
297
298     /**
299      * Encodes an array of booleans.
300      */
301     public void encode(boolean[] v, int offset, int arrayNullability, int expectedLength) {
302         if (v == null) {
303             encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
304             return;
305         }
306         if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH &&
307                 expectedLength != v.length) {
308             throw new SerializationException("Trying to encode a fixed array of incorrect length.");
309         }
310         byte[] bytes = new byte[(v.length + 7) / BindingsHelper.ALIGNMENT];
311         for (int i = 0; i < bytes.length; ++i) {
312             for (int j = 0; j < BindingsHelper.ALIGNMENT; ++j) {
313                 int booleanIndex = BindingsHelper.ALIGNMENT * i + j;
314                 if (booleanIndex < v.length && v[booleanIndex]) {
315                     bytes[i] |= (1 << j);
316                 }
317             }
318         }
319         encodeByteArray(bytes, v.length, offset);
320     }
321
322     /**
323      * Encodes an array of bytes.
324      */
325     public void encode(byte[] v, int offset, int arrayNullability, int expectedLength) {
326         if (v == null) {
327             encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
328             return;
329         }
330         if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH &&
331                 expectedLength != v.length) {
332             throw new SerializationException("Trying to encode a fixed array of incorrect length.");
333         }
334         encodeByteArray(v, v.length, offset);
335     }
336
337     /**
338      * Encodes an array of shorts.
339      */
340     public void encode(short[] v, int offset, int arrayNullability, int expectedLength) {
341         if (v == null) {
342             encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
343             return;
344         }
345         encoderForArray(2, v.length, offset, expectedLength).append(v);
346     }
347
348     /**
349      * Encodes an array of ints.
350      */
351     public void encode(int[] v, int offset, int arrayNullability, int expectedLength) {
352         if (v == null) {
353             encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
354             return;
355         }
356         encoderForArray(4, v.length, offset, expectedLength).append(v);
357     }
358
359     /**
360      * Encodes an array of floats.
361      */
362     public void encode(float[] v, int offset, int arrayNullability, int expectedLength) {
363         if (v == null) {
364             encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
365             return;
366         }
367         encoderForArray(4, v.length, offset, expectedLength).append(v);
368     }
369
370     /**
371      * Encodes an array of longs.
372      */
373     public void encode(long[] v, int offset, int arrayNullability, int expectedLength) {
374         if (v == null) {
375             encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
376             return;
377         }
378         encoderForArray(8, v.length, offset, expectedLength).append(v);
379     }
380
381     /**
382      * Encodes an array of doubles.
383      */
384     public void encode(double[] v, int offset, int arrayNullability, int expectedLength) {
385         if (v == null) {
386             encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
387             return;
388         }
389         encoderForArray(8, v.length, offset, expectedLength).append(v);
390     }
391
392     /**
393      * Encodes an array of {@link Handle}.
394      */
395     public void encode(Handle[] v, int offset, int arrayNullability, int expectedLength) {
396         if (v == null) {
397             encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
398             return;
399         }
400         Encoder e = encoderForArray(
401                 BindingsHelper.SERIALIZED_HANDLE_SIZE, v.length, offset, expectedLength);
402         for (int i = 0; i < v.length; ++i) {
403             e.encode(v[i], DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
404                     BindingsHelper.isElementNullable(arrayNullability));
405         }
406     }
407
408     /**
409      * Encodes an array of {@link Interface}.
410      */
411     public <T extends Interface> void encode(T[] v, int offset, int arrayNullability,
412             int expectedLength, Interface.Manager<T, ?> manager) {
413         if (v == null) {
414             encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
415             return;
416         }
417         Encoder e = encoderForArray(
418                 BindingsHelper.SERIALIZED_HANDLE_SIZE, v.length, offset, expectedLength);
419         for (int i = 0; i < v.length; ++i) {
420             e.encode(v[i], DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
421                     BindingsHelper.isElementNullable(arrayNullability), manager);
422         }
423     }
424
425     public Encoder encoderForMap(int offset) {
426         encodePointerToNextUnclaimedData(offset);
427         return getEncoderAtDataOffset(BindingsHelper.MAP_STRUCT_HEADER);
428     }
429
430     /**
431      * Encodes an array of {@link InterfaceRequest}.
432      */
433     public <I extends Interface> void encode(InterfaceRequest<I>[] v, int offset,
434             int arrayNullability, int expectedLength) {
435         if (v == null) {
436             encodeNullPointer(offset, BindingsHelper.isArrayNullable(arrayNullability));
437             return;
438         }
439         Encoder e = encoderForArray(
440                 BindingsHelper.SERIALIZED_HANDLE_SIZE, v.length, offset, expectedLength);
441         for (int i = 0; i < v.length; ++i) {
442             e.encode(v[i], DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SIZE * i,
443                     BindingsHelper.isElementNullable(arrayNullability));
444         }
445     }
446
447     /**
448      * Encodes a <code>null</code> pointer iff the object is nullable, raises an exception
449      * otherwise.
450      */
451     public void encodeNullPointer(int offset, boolean nullable) {
452         if (!nullable) {
453             throw new SerializationException(
454                     "Trying to encode a null pointer for a non-nullable type.");
455         }
456         mEncoderState.byteBuffer.putLong(mBaseOffset + offset, 0);
457     }
458
459     /**
460      * Encodes an invalid handle iff the object is nullable, raises an exception otherwise.
461      */
462     public void encodeInvalidHandle(int offset, boolean nullable) {
463         if (!nullable) {
464             throw new SerializationException(
465                     "Trying to encode an invalid handle for a non-nullable type.");
466         }
467         mEncoderState.byteBuffer.putInt(mBaseOffset + offset, -1);
468     }
469
470     private void encodePointerToNextUnclaimedData(int offset) {
471         encode((long) mEncoderState.dataEnd - (mBaseOffset + offset), offset);
472     }
473
474     private Encoder encoderForArray(
475             int elementSizeInByte, int length, int offset, int expectedLength) {
476         if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH &&
477                 expectedLength != length) {
478             throw new SerializationException("Trying to encode a fixed array of incorrect length.");
479         }
480         return encoderForArrayByTotalSize(length * elementSizeInByte, length, offset);
481     }
482
483     private Encoder encoderForArrayByTotalSize(int byteSize, int length, int offset) {
484         encodePointerToNextUnclaimedData(offset);
485         return getEncoderAtDataOffset(
486                 new DataHeader(DataHeader.HEADER_SIZE + byteSize, length));
487     }
488
489     private void encodeByteArray(byte[] bytes, int length, int offset) {
490         encoderForArrayByTotalSize(bytes.length, length, offset).append(bytes);
491     }
492
493     private void append(byte[] v) {
494         mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
495         mEncoderState.byteBuffer.put(v);
496     }
497
498     private void append(short[] v) {
499         mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
500         mEncoderState.byteBuffer.asShortBuffer().put(v);
501     }
502
503     private void append(int[] v) {
504         mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
505         mEncoderState.byteBuffer.asIntBuffer().put(v);
506     }
507
508     private void append(float[] v) {
509         mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
510         mEncoderState.byteBuffer.asFloatBuffer().put(v);
511     }
512
513     private void append(double[] v) {
514         mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
515         mEncoderState.byteBuffer.asDoubleBuffer().put(v);
516     }
517
518     private void append(long[] v) {
519         mEncoderState.byteBuffer.position(mBaseOffset + DataHeader.HEADER_SIZE);
520         mEncoderState.byteBuffer.asLongBuffer().put(v);
521     }
522
523 }