OLD | NEW |
| (Empty) |
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.Interface.Proxy; | |
8 import org.chromium.mojo.system.DataPipe; | |
9 import org.chromium.mojo.system.Handle; | |
10 import org.chromium.mojo.system.InvalidHandle; | |
11 import org.chromium.mojo.system.MessagePipeHandle; | |
12 import org.chromium.mojo.system.SharedBufferHandle; | |
13 import org.chromium.mojo.system.UntypedHandle; | |
14 | |
15 import java.nio.ByteOrder; | |
16 import java.nio.charset.Charset; | |
17 | |
18 /** | |
19 * A Decoder is a helper class for deserializing a mojo struct. It enables deser
ialization of basic | |
20 * types from a {@link Message} object at a given offset into it's byte buffer. | |
21 */ | |
22 public class Decoder { | |
23 | |
24 /** | |
25 * Helper class to validate the decoded message. | |
26 */ | |
27 static final class Validator { | |
28 | |
29 /** | |
30 * Minimal value for the next handle to deserialize. | |
31 */ | |
32 private int mMinNextClaimedHandle = 0; | |
33 /** | |
34 * Minimal value of the start of the next memory to claim. | |
35 */ | |
36 private long mMinNextMemory = 0; | |
37 | |
38 /** | |
39 * The maximal memory accessible. | |
40 */ | |
41 private final long mMaxMemory; | |
42 | |
43 /** | |
44 * The number of handles in the message. | |
45 */ | |
46 private final long mNumberOfHandles; | |
47 | |
48 /** | |
49 * Constructor. | |
50 */ | |
51 Validator(long maxMemory, int numberOfHandles) { | |
52 mMaxMemory = maxMemory; | |
53 mNumberOfHandles = numberOfHandles; | |
54 } | |
55 | |
56 public void claimHandle(int handle) { | |
57 if (handle < mMinNextClaimedHandle) { | |
58 throw new DeserializationException( | |
59 "Trying to access handle out of order."); | |
60 } | |
61 if (handle >= mNumberOfHandles) { | |
62 throw new DeserializationException("Trying to access non present
handle."); | |
63 } | |
64 mMinNextClaimedHandle = handle + 1; | |
65 } | |
66 | |
67 public void claimMemory(long start, long end) { | |
68 if (start % BindingsHelper.ALIGNMENT != 0) { | |
69 throw new DeserializationException("Incorrect starting alignment
: " + start + "."); | |
70 } | |
71 if (start < mMinNextMemory) { | |
72 throw new DeserializationException("Trying to access memory out
of order."); | |
73 } | |
74 if (end < start) { | |
75 throw new DeserializationException("Incorrect memory range."); | |
76 } | |
77 if (end > mMaxMemory) { | |
78 throw new DeserializationException("Trying to access out of rang
e memory."); | |
79 } | |
80 mMinNextMemory = BindingsHelper.align(end); | |
81 } | |
82 } | |
83 | |
84 /** | |
85 * The message to deserialize from. | |
86 */ | |
87 private final Message mMessage; | |
88 | |
89 /** | |
90 * The base offset in the byte buffer. | |
91 */ | |
92 private final int mBaseOffset; | |
93 | |
94 /** | |
95 * Validator for the decoded message. | |
96 */ | |
97 private final Validator mValidator; | |
98 | |
99 /** | |
100 * Constructor. | |
101 * | |
102 * @param message The message to decode. | |
103 */ | |
104 public Decoder(Message message) { | |
105 this(message, new Validator(message.getData().limit(), message.getHandle
s().size()), 0); | |
106 } | |
107 | |
108 private Decoder(Message message, Validator validator, int baseOffset) { | |
109 mMessage = message; | |
110 mMessage.getData().order(ByteOrder.LITTLE_ENDIAN); | |
111 mBaseOffset = baseOffset; | |
112 mValidator = validator; | |
113 } | |
114 | |
115 /** | |
116 * Deserializes a {@link DataHeader} at the current position. | |
117 */ | |
118 public DataHeader readDataHeader() { | |
119 // Claim the memory for the header. | |
120 mValidator.claimMemory(mBaseOffset, mBaseOffset + DataHeader.HEADER_SIZE
); | |
121 DataHeader result = readDataHeaderAtOffset(0, false); | |
122 // Claim the rest of the memory. | |
123 mValidator.claimMemory(mBaseOffset + DataHeader.HEADER_SIZE, mBaseOffset
+ result.size); | |
124 return result; | |
125 } | |
126 | |
127 /** | |
128 * Deserializes a {@link DataHeader} for an union at the given offset. | |
129 */ | |
130 public DataHeader readDataHeaderForUnion(int offset) { | |
131 DataHeader result = readDataHeaderAtOffset(offset, true); | |
132 if (result.size == 0) { | |
133 if (result.elementsOrVersion != 0) { | |
134 throw new DeserializationException( | |
135 "Unexpected version tag for a null union. Expecting 0, f
ound: " | |
136 + result.elementsOrVersion); | |
137 } | |
138 } else if (result.size != BindingsHelper.UNION_SIZE) { | |
139 throw new DeserializationException( | |
140 "Unexpected size of an union. The size must be 0 for a null
union, or 16 for " | |
141 + "a non-null union."); | |
142 } | |
143 return result; | |
144 } | |
145 | |
146 /** | |
147 * @returns a decoder suitable to decode an union defined as the root object
of a message. | |
148 */ | |
149 public Decoder decoderForSerializedUnion() { | |
150 mValidator.claimMemory(0, BindingsHelper.UNION_SIZE); | |
151 return this; | |
152 } | |
153 | |
154 /** | |
155 * Deserializes a {@link DataHeader} at the given offset. | |
156 */ | |
157 private DataHeader readDataHeaderAtOffset(int offset, boolean isUnion) { | |
158 int size = readInt(offset + DataHeader.SIZE_OFFSET); | |
159 int elementsOrVersion = readInt(offset + DataHeader.ELEMENTS_OR_VERSION_
OFFSET); | |
160 if (size < 0) { | |
161 throw new DeserializationException( | |
162 "Negative size. Unsigned integers are not valid for java."); | |
163 } | |
164 if (elementsOrVersion < 0 && (!isUnion || elementsOrVersion != -1)) { | |
165 throw new DeserializationException( | |
166 "Negative elements or version. Unsigned integers are not val
id for java."); | |
167 } | |
168 | |
169 return new DataHeader(size, elementsOrVersion); | |
170 } | |
171 | |
172 public DataHeader readAndValidateDataHeader(DataHeader[] versionArray) { | |
173 DataHeader header = readDataHeader(); | |
174 int maxVersionIndex = versionArray.length - 1; | |
175 if (header.elementsOrVersion <= versionArray[maxVersionIndex].elementsOr
Version) { | |
176 DataHeader referenceHeader = null; | |
177 for (int index = maxVersionIndex; index >= 0; index--) { | |
178 DataHeader dataHeader = versionArray[index]; | |
179 if (header.elementsOrVersion >= dataHeader.elementsOrVersion) { | |
180 referenceHeader = dataHeader; | |
181 break; | |
182 } | |
183 } | |
184 if (referenceHeader == null || referenceHeader.size != header.size)
{ | |
185 throw new DeserializationException( | |
186 "Header doesn't correspond to any known version."); | |
187 } | |
188 } else { | |
189 if (header.size < versionArray[maxVersionIndex].size) { | |
190 throw new DeserializationException("Message newer than the last
known version" | |
191 + " cannot be shorter than required by the last known ve
rsion."); | |
192 } | |
193 } | |
194 return header; | |
195 } | |
196 | |
197 /** | |
198 * Deserializes a {@link DataHeader} at the given offset and checks if it is
correct for an | |
199 * array where elements are pointers. | |
200 */ | |
201 public DataHeader readDataHeaderForPointerArray(int expectedLength) { | |
202 return readDataHeaderForArray(BindingsHelper.POINTER_SIZE, expectedLengt
h); | |
203 } | |
204 | |
205 /** | |
206 * Deserializes a {@link DataHeader} at the given offset and checks if it is
correct for an | |
207 * array where elements are unions. | |
208 */ | |
209 public DataHeader readDataHeaderForUnionArray(int expectedLength) { | |
210 return readDataHeaderForArray(BindingsHelper.UNION_SIZE, expectedLength)
; | |
211 } | |
212 | |
213 /** | |
214 * Deserializes a {@link DataHeader} at the given offset and checks if it is
correct for a map. | |
215 */ | |
216 public void readDataHeaderForMap() { | |
217 DataHeader si = readDataHeader(); | |
218 if (si.size != BindingsHelper.MAP_STRUCT_HEADER.size) { | |
219 throw new DeserializationException( | |
220 "Incorrect header for map. The size is incorrect."); | |
221 } | |
222 if (si.elementsOrVersion != BindingsHelper.MAP_STRUCT_HEADER.elementsOrV
ersion) { | |
223 throw new DeserializationException( | |
224 "Incorrect header for map. The version is incorrect."); | |
225 } | |
226 } | |
227 | |
228 /** | |
229 * Deserializes a byte at the given offset. | |
230 */ | |
231 public byte readByte(int offset) { | |
232 validateBufferSize(offset, 1); | |
233 return mMessage.getData().get(mBaseOffset + offset); | |
234 } | |
235 | |
236 /** | |
237 * Deserializes a boolean at the given offset, re-using any partially read b
yte. | |
238 */ | |
239 public boolean readBoolean(int offset, int bit) { | |
240 validateBufferSize(offset, 1); | |
241 return (readByte(offset) & (1 << bit)) != 0; | |
242 } | |
243 | |
244 /** | |
245 * Deserializes a short at the given offset. | |
246 */ | |
247 public short readShort(int offset) { | |
248 validateBufferSize(offset, 2); | |
249 return mMessage.getData().getShort(mBaseOffset + offset); | |
250 } | |
251 | |
252 /** | |
253 * Deserializes an int at the given offset. | |
254 */ | |
255 public int readInt(int offset) { | |
256 validateBufferSize(offset, 4); | |
257 return mMessage.getData().getInt(mBaseOffset + offset); | |
258 } | |
259 | |
260 /** | |
261 * Deserializes a float at the given offset. | |
262 */ | |
263 public float readFloat(int offset) { | |
264 validateBufferSize(offset, 4); | |
265 return mMessage.getData().getFloat(mBaseOffset + offset); | |
266 } | |
267 | |
268 /** | |
269 * Deserializes a long at the given offset. | |
270 */ | |
271 public long readLong(int offset) { | |
272 validateBufferSize(offset, 8); | |
273 return mMessage.getData().getLong(mBaseOffset + offset); | |
274 } | |
275 | |
276 /** | |
277 * Deserializes a double at the given offset. | |
278 */ | |
279 public double readDouble(int offset) { | |
280 validateBufferSize(offset, 8); | |
281 return mMessage.getData().getDouble(mBaseOffset + offset); | |
282 } | |
283 | |
284 /** | |
285 * Deserializes a pointer at the given offset. Returns a Decoder suitable to
decode the content | |
286 * of the pointer. | |
287 */ | |
288 public Decoder readPointer(int offset, boolean nullable) { | |
289 int basePosition = mBaseOffset + offset; | |
290 long pointerOffset = readLong(offset); | |
291 if (pointerOffset == 0) { | |
292 if (!nullable) { | |
293 throw new DeserializationException( | |
294 "Trying to decode null pointer for a non-nullable type."
); | |
295 } | |
296 return null; | |
297 } | |
298 int newPosition = (int) (basePosition + pointerOffset); | |
299 // The method |getDecoderAtPosition| will validate that the pointer addr
ess is valid. | |
300 return getDecoderAtPosition(newPosition); | |
301 | |
302 } | |
303 | |
304 /** | |
305 * Deserializes an array of boolean at the given offset. | |
306 */ | |
307 public boolean[] readBooleans(int offset, int arrayNullability, int expected
Length) { | |
308 Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNull
ability)); | |
309 if (d == null) { | |
310 return null; | |
311 } | |
312 DataHeader si = d.readDataHeaderForBooleanArray(expectedLength); | |
313 byte[] bytes = new byte[(si.elementsOrVersion + 7) / BindingsHelper.ALIG
NMENT]; | |
314 d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE); | |
315 d.mMessage.getData().get(bytes); | |
316 boolean[] result = new boolean[si.elementsOrVersion]; | |
317 for (int i = 0; i < bytes.length; ++i) { | |
318 for (int j = 0; j < BindingsHelper.ALIGNMENT; ++j) { | |
319 int booleanIndex = i * BindingsHelper.ALIGNMENT + j; | |
320 if (booleanIndex < result.length) { | |
321 result[booleanIndex] = (bytes[i] & (1 << j)) != 0; | |
322 } | |
323 } | |
324 } | |
325 return result; | |
326 } | |
327 | |
328 /** | |
329 * Deserializes an array of bytes at the given offset. | |
330 */ | |
331 public byte[] readBytes(int offset, int arrayNullability, int expectedLength
) { | |
332 Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNull
ability)); | |
333 if (d == null) { | |
334 return null; | |
335 } | |
336 DataHeader si = d.readDataHeaderForArray(1, expectedLength); | |
337 byte[] result = new byte[si.elementsOrVersion]; | |
338 d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE); | |
339 d.mMessage.getData().get(result); | |
340 return result; | |
341 } | |
342 | |
343 /** | |
344 * Deserializes an array of shorts at the given offset. | |
345 */ | |
346 public short[] readShorts(int offset, int arrayNullability, int expectedLeng
th) { | |
347 Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNull
ability)); | |
348 if (d == null) { | |
349 return null; | |
350 } | |
351 DataHeader si = d.readDataHeaderForArray(2, expectedLength); | |
352 short[] result = new short[si.elementsOrVersion]; | |
353 d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE); | |
354 d.mMessage.getData().asShortBuffer().get(result); | |
355 return result; | |
356 } | |
357 | |
358 /** | |
359 * Deserializes an array of ints at the given offset. | |
360 */ | |
361 public int[] readInts(int offset, int arrayNullability, int expectedLength)
{ | |
362 Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNull
ability)); | |
363 if (d == null) { | |
364 return null; | |
365 } | |
366 DataHeader si = d.readDataHeaderForArray(4, expectedLength); | |
367 int[] result = new int[si.elementsOrVersion]; | |
368 d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE); | |
369 d.mMessage.getData().asIntBuffer().get(result); | |
370 return result; | |
371 } | |
372 | |
373 /** | |
374 * Deserializes an array of floats at the given offset. | |
375 */ | |
376 public float[] readFloats(int offset, int arrayNullability, int expectedLeng
th) { | |
377 Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNull
ability)); | |
378 if (d == null) { | |
379 return null; | |
380 } | |
381 DataHeader si = d.readDataHeaderForArray(4, expectedLength); | |
382 float[] result = new float[si.elementsOrVersion]; | |
383 d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE); | |
384 d.mMessage.getData().asFloatBuffer().get(result); | |
385 return result; | |
386 } | |
387 | |
388 /** | |
389 * Deserializes an array of longs at the given offset. | |
390 */ | |
391 public long[] readLongs(int offset, int arrayNullability, int expectedLength
) { | |
392 Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNull
ability)); | |
393 if (d == null) { | |
394 return null; | |
395 } | |
396 DataHeader si = d.readDataHeaderForArray(8, expectedLength); | |
397 long[] result = new long[si.elementsOrVersion]; | |
398 d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE); | |
399 d.mMessage.getData().asLongBuffer().get(result); | |
400 return result; | |
401 } | |
402 | |
403 /** | |
404 * Deserializes an array of doubles at the given offset. | |
405 */ | |
406 public double[] readDoubles(int offset, int arrayNullability, int expectedLe
ngth) { | |
407 Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNull
ability)); | |
408 if (d == null) { | |
409 return null; | |
410 } | |
411 DataHeader si = d.readDataHeaderForArray(8, expectedLength); | |
412 double[] result = new double[si.elementsOrVersion]; | |
413 d.mMessage.getData().position(d.mBaseOffset + DataHeader.HEADER_SIZE); | |
414 d.mMessage.getData().asDoubleBuffer().get(result); | |
415 return result; | |
416 } | |
417 | |
418 /** | |
419 * Deserializes an |Handle| at the given offset. | |
420 */ | |
421 public Handle readHandle(int offset, boolean nullable) { | |
422 int index = readInt(offset); | |
423 if (index == -1) { | |
424 if (!nullable) { | |
425 throw new DeserializationException( | |
426 "Trying to decode an invalid handle for a non-nullable t
ype."); | |
427 } | |
428 return InvalidHandle.INSTANCE; | |
429 } | |
430 mValidator.claimHandle(index); | |
431 return mMessage.getHandles().get(index); | |
432 } | |
433 | |
434 /** | |
435 * Deserializes an |UntypedHandle| at the given offset. | |
436 */ | |
437 public UntypedHandle readUntypedHandle(int offset, boolean nullable) { | |
438 return readHandle(offset, nullable).toUntypedHandle(); | |
439 } | |
440 | |
441 /** | |
442 * Deserializes a |ConsumerHandle| at the given offset. | |
443 */ | |
444 public DataPipe.ConsumerHandle readConsumerHandle(int offset, boolean nullab
le) { | |
445 return readUntypedHandle(offset, nullable).toDataPipeConsumerHandle(); | |
446 } | |
447 | |
448 /** | |
449 * Deserializes a |ProducerHandle| at the given offset. | |
450 */ | |
451 public DataPipe.ProducerHandle readProducerHandle(int offset, boolean nullab
le) { | |
452 return readUntypedHandle(offset, nullable).toDataPipeProducerHandle(); | |
453 } | |
454 | |
455 /** | |
456 * Deserializes a |MessagePipeHandle| at the given offset. | |
457 */ | |
458 public MessagePipeHandle readMessagePipeHandle(int offset, boolean nullable)
{ | |
459 return readUntypedHandle(offset, nullable).toMessagePipeHandle(); | |
460 } | |
461 | |
462 /** | |
463 * Deserializes a |SharedBufferHandle| at the given offset. | |
464 */ | |
465 public SharedBufferHandle readSharedBufferHandle(int offset, boolean nullabl
e) { | |
466 return readUntypedHandle(offset, nullable).toSharedBufferHandle(); | |
467 } | |
468 | |
469 /** | |
470 * Deserializes an interface at the given offset. | |
471 * | |
472 * @return a proxy to the service. | |
473 */ | |
474 public <P extends Proxy> P readServiceInterface(int offset, boolean nullable
, | |
475 Interface.Manager<?, P> manager) { | |
476 MessagePipeHandle handle = readMessagePipeHandle(offset, nullable); | |
477 if (!handle.isValid()) { | |
478 return null; | |
479 } | |
480 int version = readInt(offset + BindingsHelper.SERIALIZED_HANDLE_SIZE); | |
481 return manager.attachProxy(handle, version); | |
482 } | |
483 | |
484 /** | |
485 * Deserializes a |InterfaceRequest| at the given offset. | |
486 */ | |
487 public <I extends Interface> InterfaceRequest<I> readInterfaceRequest(int of
fset, | |
488 boolean nullable) { | |
489 MessagePipeHandle handle = readMessagePipeHandle(offset, nullable); | |
490 if (handle == null) { | |
491 return null; | |
492 } | |
493 return new InterfaceRequest<I>(handle); | |
494 } | |
495 | |
496 /** | |
497 * Deserializes a string at the given offset. | |
498 */ | |
499 public String readString(int offset, boolean nullable) { | |
500 final int arrayNullability = nullable ? BindingsHelper.ARRAY_NULLABLE :
0; | |
501 byte[] bytes = readBytes(offset, arrayNullability, BindingsHelper.UNSPEC
IFIED_ARRAY_LENGTH); | |
502 if (bytes == null) { | |
503 return null; | |
504 } | |
505 return new String(bytes, Charset.forName("utf8")); | |
506 } | |
507 | |
508 /** | |
509 * Deserializes an array of |Handle| at the given offset. | |
510 */ | |
511 public Handle[] readHandles(int offset, int arrayNullability, int expectedLe
ngth) { | |
512 Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNull
ability)); | |
513 if (d == null) { | |
514 return null; | |
515 } | |
516 DataHeader si = d.readDataHeaderForArray(4, expectedLength); | |
517 Handle[] result = new Handle[si.elementsOrVersion]; | |
518 for (int i = 0; i < result.length; ++i) { | |
519 result[i] = d.readHandle( | |
520 DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SI
ZE * i, | |
521 BindingsHelper.isElementNullable(arrayNullability)); | |
522 } | |
523 return result; | |
524 } | |
525 | |
526 /** | |
527 * Deserializes an array of |UntypedHandle| at the given offset. | |
528 */ | |
529 public UntypedHandle[] readUntypedHandles( | |
530 int offset, int arrayNullability, int expectedLength) { | |
531 Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNull
ability)); | |
532 if (d == null) { | |
533 return null; | |
534 } | |
535 DataHeader si = d.readDataHeaderForArray(4, expectedLength); | |
536 UntypedHandle[] result = new UntypedHandle[si.elementsOrVersion]; | |
537 for (int i = 0; i < result.length; ++i) { | |
538 result[i] = d.readUntypedHandle( | |
539 DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SI
ZE * i, | |
540 BindingsHelper.isElementNullable(arrayNullability)); | |
541 } | |
542 return result; | |
543 } | |
544 | |
545 /** | |
546 * Deserializes an array of |ConsumerHandle| at the given offset. | |
547 */ | |
548 public DataPipe.ConsumerHandle[] readConsumerHandles( | |
549 int offset, int arrayNullability, int expectedLength) { | |
550 Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNull
ability)); | |
551 if (d == null) { | |
552 return null; | |
553 } | |
554 DataHeader si = d.readDataHeaderForArray(4, expectedLength); | |
555 DataPipe.ConsumerHandle[] result = new DataPipe.ConsumerHandle[si.elemen
tsOrVersion]; | |
556 for (int i = 0; i < result.length; ++i) { | |
557 result[i] = d.readConsumerHandle( | |
558 DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SI
ZE * i, | |
559 BindingsHelper.isElementNullable(arrayNullability)); | |
560 } | |
561 return result; | |
562 } | |
563 | |
564 /** | |
565 * Deserializes an array of |ProducerHandle| at the given offset. | |
566 */ | |
567 public DataPipe.ProducerHandle[] readProducerHandles( | |
568 int offset, int arrayNullability, int expectedLength) { | |
569 Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNull
ability)); | |
570 if (d == null) { | |
571 return null; | |
572 } | |
573 DataHeader si = d.readDataHeaderForArray(4, expectedLength); | |
574 DataPipe.ProducerHandle[] result = new DataPipe.ProducerHandle[si.elemen
tsOrVersion]; | |
575 for (int i = 0; i < result.length; ++i) { | |
576 result[i] = d.readProducerHandle( | |
577 DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SI
ZE * i, | |
578 BindingsHelper.isElementNullable(arrayNullability)); | |
579 } | |
580 return result; | |
581 | |
582 } | |
583 | |
584 /** | |
585 * Deserializes an array of |MessagePipeHandle| at the given offset. | |
586 */ | |
587 public MessagePipeHandle[] readMessagePipeHandles( | |
588 int offset, int arrayNullability, int expectedLength) { | |
589 Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNull
ability)); | |
590 if (d == null) { | |
591 return null; | |
592 } | |
593 DataHeader si = d.readDataHeaderForArray(4, expectedLength); | |
594 MessagePipeHandle[] result = new MessagePipeHandle[si.elementsOrVersion]
; | |
595 for (int i = 0; i < result.length; ++i) { | |
596 result[i] = d.readMessagePipeHandle( | |
597 DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SI
ZE * i, | |
598 BindingsHelper.isElementNullable(arrayNullability)); | |
599 } | |
600 return result; | |
601 | |
602 } | |
603 | |
604 /** | |
605 * Deserializes an array of |SharedBufferHandle| at the given offset. | |
606 */ | |
607 public SharedBufferHandle[] readSharedBufferHandles( | |
608 int offset, int arrayNullability, int expectedLength) { | |
609 Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNull
ability)); | |
610 if (d == null) { | |
611 return null; | |
612 } | |
613 DataHeader si = d.readDataHeaderForArray(4, expectedLength); | |
614 SharedBufferHandle[] result = new SharedBufferHandle[si.elementsOrVersio
n]; | |
615 for (int i = 0; i < result.length; ++i) { | |
616 result[i] = d.readSharedBufferHandle( | |
617 DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SI
ZE * i, | |
618 BindingsHelper.isElementNullable(arrayNullability)); | |
619 } | |
620 return result; | |
621 | |
622 } | |
623 | |
624 /** | |
625 * Deserializes an array of |ServiceHandle| at the given offset. | |
626 */ | |
627 public <S extends Interface, P extends Proxy> S[] readServiceInterfaces( | |
628 int offset, int arrayNullability, int expectedLength, Interface.Mana
ger<S, P> manager) { | |
629 Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNull
ability)); | |
630 if (d == null) { | |
631 return null; | |
632 } | |
633 DataHeader si = | |
634 d.readDataHeaderForArray(BindingsHelper.SERIALIZED_INTERFACE_SIZ
E, expectedLength); | |
635 S[] result = manager.buildArray(si.elementsOrVersion); | |
636 for (int i = 0; i < result.length; ++i) { | |
637 // This cast is necessary because java 6 doesn't handle wildcard cor
rectly when using | |
638 // Manager<S, ? extends S> | |
639 @SuppressWarnings("unchecked") | |
640 S value = (S) d.readServiceInterface( | |
641 DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_INTERFACE
_SIZE * i, | |
642 BindingsHelper.isElementNullable(arrayNullability), manager)
; | |
643 result[i] = value; | |
644 } | |
645 return result; | |
646 } | |
647 | |
648 /** | |
649 * Deserializes an array of |InterfaceRequest| at the given offset. | |
650 */ | |
651 public <I extends Interface> InterfaceRequest<I>[] readInterfaceRequests( | |
652 int offset, int arrayNullability, int expectedLength) { | |
653 Decoder d = readPointer(offset, BindingsHelper.isArrayNullable(arrayNull
ability)); | |
654 if (d == null) { | |
655 return null; | |
656 } | |
657 DataHeader si = d.readDataHeaderForArray(4, expectedLength); | |
658 @SuppressWarnings("unchecked") | |
659 InterfaceRequest<I>[] result = new InterfaceRequest[si.elementsOrVersion
]; | |
660 for (int i = 0; i < result.length; ++i) { | |
661 result[i] = d.readInterfaceRequest( | |
662 DataHeader.HEADER_SIZE + BindingsHelper.SERIALIZED_HANDLE_SI
ZE * i, | |
663 BindingsHelper.isElementNullable(arrayNullability)); | |
664 } | |
665 return result; | |
666 } | |
667 | |
668 /** | |
669 * Returns a view of this decoder at the offset |offset|. | |
670 */ | |
671 private Decoder getDecoderAtPosition(int offset) { | |
672 return new Decoder(mMessage, mValidator, offset); | |
673 } | |
674 | |
675 /** | |
676 * Deserializes a {@link DataHeader} at the given offset and checks if it is
correct for an | |
677 * array of booleans. | |
678 */ | |
679 private DataHeader readDataHeaderForBooleanArray(int expectedLength) { | |
680 DataHeader dataHeader = readDataHeader(); | |
681 if (dataHeader.size < DataHeader.HEADER_SIZE + (dataHeader.elementsOrVer
sion + 7) / 8) { | |
682 throw new DeserializationException("Array header is incorrect."); | |
683 } | |
684 if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH | |
685 && dataHeader.elementsOrVersion != expectedLength) { | |
686 throw new DeserializationException("Incorrect array length. Expected
: " + expectedLength | |
687 + ", but got: " + dataHeader.elementsOrVersion + "."); | |
688 } | |
689 return dataHeader; | |
690 } | |
691 | |
692 /** | |
693 * Deserializes a {@link DataHeader} of an array at the given offset. | |
694 */ | |
695 private DataHeader readDataHeaderForArray(long elementSize, int expectedLeng
th) { | |
696 DataHeader dataHeader = readDataHeader(); | |
697 if (dataHeader.size | |
698 < (DataHeader.HEADER_SIZE + elementSize * dataHeader.elementsOrV
ersion)) { | |
699 throw new DeserializationException("Array header is incorrect."); | |
700 } | |
701 if (expectedLength != BindingsHelper.UNSPECIFIED_ARRAY_LENGTH | |
702 && dataHeader.elementsOrVersion != expectedLength) { | |
703 throw new DeserializationException("Incorrect array length. Expected
: " + expectedLength | |
704 + ", but got: " + dataHeader.elementsOrVersion + "."); | |
705 } | |
706 return dataHeader; | |
707 } | |
708 | |
709 private void validateBufferSize(int offset, int size) { | |
710 if (mMessage.getData().limit() < offset + size) { | |
711 throw new DeserializationException("Buffer is smaller than expected.
"); | |
712 } | |
713 } | |
714 } | |
OLD | NEW |