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