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 part of bindings; | |
6 | |
7 int align(int size) => size + (kAlignment - (size % kAlignment)) % kAlignment; | |
8 | |
9 const int kAlignment = 8; | |
10 const int kSerializedHandleSize = 4; | |
11 const int kSerializedInterfaceSize = 8; // 4-byte handle + 4-byte version | |
12 const int kPointerSize = 8; | |
13 const StructDataHeader kMapStructHeader = const StructDataHeader(24, 0); | |
14 const int kUnspecifiedArrayLength = -1; | |
15 const int kNothingNullable = 0; | |
16 const int kArrayNullable = (1 << 0); | |
17 const int kElementNullable = (1 << 1); | |
18 | |
19 bool isArrayNullable(int nullability) => (nullability & kArrayNullable) > 0; | |
20 bool isElementNullable(int nullability) => (nullability & kElementNullable) > 0; | |
21 | |
22 class StructDataHeader { | |
23 static const int kHeaderSize = 8; | |
24 static const int kSizeOffset = 0; | |
25 static const int kVersionOffset = 4; | |
26 final int size; | |
27 final int version; | |
28 | |
29 const StructDataHeader(this.size, this.version); | |
30 | |
31 String toString() => "StructDataHeader($size, $version)"; | |
32 } | |
33 | |
34 class ArrayDataHeader { | |
35 static const int kHeaderSize = 8; | |
36 static const int kSizeOffset = 0; | |
37 static const int kNumElementsOffset = 4; | |
38 final int size; | |
39 final int numElements; | |
40 | |
41 const ArrayDataHeader(this.size, this.numElements); | |
42 | |
43 String toString() => "ArrayDataHeader($size, $numElements)"; | |
44 } | |
45 | |
46 class MojoCodecError { | |
47 final String message; | |
48 MojoCodecError(this.message); | |
49 String toString() => message; | |
50 } | |
51 | |
52 class _EncoderBuffer { | |
53 ByteData buffer; | |
54 List<core.MojoHandle> handles; | |
55 int extent; | |
56 | |
57 static const int kInitialBufferSize = 1024; | |
58 | |
59 _EncoderBuffer([int size = -1]) | |
60 : buffer = new ByteData(size > 0 ? size : kInitialBufferSize), | |
61 handles = [], | |
62 extent = 0; | |
63 | |
64 void _grow(int newSize) { | |
65 Uint8List newBuffer = new Uint8List(newSize); | |
66 newBuffer.setRange(0, buffer.lengthInBytes, buffer.buffer.asUint8List()); | |
67 buffer = newBuffer.buffer.asByteData(); | |
68 } | |
69 | |
70 void claimMemory(int claimSize) { | |
71 extent += claimSize; | |
72 if (extent > buffer.lengthInBytes) { | |
73 int newSize = buffer.lengthInBytes + claimSize; | |
74 newSize += newSize ~/ 2; | |
75 _grow(newSize); | |
76 } | |
77 } | |
78 | |
79 ByteData get trimmed => new ByteData.view(buffer.buffer, 0, extent); | |
80 } | |
81 | |
82 class Encoder { | |
83 _EncoderBuffer _buffer; | |
84 int _base; | |
85 | |
86 Encoder([int size = -1]) | |
87 : _buffer = new _EncoderBuffer(size), | |
88 _base = 0; | |
89 | |
90 Encoder._fromBuffer(_EncoderBuffer buffer) | |
91 : _buffer = buffer, | |
92 _base = buffer.extent; | |
93 | |
94 Encoder getStructEncoderAtOffset(StructDataHeader dataHeader) { | |
95 var result = new Encoder._fromBuffer(_buffer); | |
96 result.encodeStructDataHeader(dataHeader); | |
97 return result; | |
98 } | |
99 | |
100 Encoder getArrayEncoderAtOffset(ArrayDataHeader dataHeader) { | |
101 var result = new Encoder._fromBuffer(_buffer); | |
102 result.encodeArrayDataHeader(dataHeader); | |
103 return result; | |
104 } | |
105 | |
106 Message get message => new Message(_buffer.trimmed, _buffer.handles); | |
107 | |
108 void encodeStructDataHeader(StructDataHeader dataHeader) { | |
109 _buffer.claimMemory(align(dataHeader.size)); | |
110 encodeUint32(dataHeader.size, StructDataHeader.kSizeOffset); | |
111 encodeUint32(dataHeader.version, StructDataHeader.kVersionOffset); | |
112 } | |
113 | |
114 void encodeArrayDataHeader(ArrayDataHeader dataHeader) { | |
115 _buffer.claimMemory(align(dataHeader.size)); | |
116 encodeUint32(dataHeader.size, ArrayDataHeader.kSizeOffset); | |
117 encodeUint32(dataHeader.numElements, ArrayDataHeader.kNumElementsOffset); | |
118 } | |
119 | |
120 static const String kErrorUnsigned = | |
121 'Passing negative value to unsigned encoder'; | |
122 | |
123 void encodeBool(bool value, int offset, int bit) { | |
124 if (value) { | |
125 int encodedValue = _buffer.buffer.getUint8(_base + offset); | |
126 encodedValue |= (1 << bit); | |
127 _buffer.buffer.setUint8(_base + offset, encodedValue); | |
128 } | |
129 } | |
130 | |
131 void encodeInt8(int value, int offset) => | |
132 _buffer.buffer.setInt8(_base + offset, value); | |
133 | |
134 void encodeUint8(int value, int offset) { | |
135 if (value < 0) { | |
136 throw new MojoCodecError('$kErrorUnsigned: $value'); | |
137 } | |
138 _buffer.buffer.setUint8(_base + offset, value); | |
139 } | |
140 | |
141 void encodeInt16(int value, int offset) => | |
142 _buffer.buffer.setInt16(_base + offset, value, Endianness.LITTLE_ENDIAN); | |
143 | |
144 void encodeUint16(int value, int offset) { | |
145 if (value < 0) { | |
146 throw new MojoCodecError('$kErrorUnsigned: $value'); | |
147 } | |
148 _buffer.buffer.setUint16(_base + offset, value, Endianness.LITTLE_ENDIAN); | |
149 } | |
150 | |
151 void encodeInt32(int value, int offset) => | |
152 _buffer.buffer.setInt32(_base + offset, value, Endianness.LITTLE_ENDIAN); | |
153 | |
154 void encodeUint32(int value, int offset) { | |
155 if (value < 0) { | |
156 throw new MojoCodecError('$kErrorUnsigned: $value'); | |
157 } | |
158 _buffer.buffer.setUint32(_base + offset, value, Endianness.LITTLE_ENDIAN); | |
159 } | |
160 | |
161 void encodeInt64(int value, int offset) => | |
162 _buffer.buffer.setInt64(_base + offset, value, Endianness.LITTLE_ENDIAN); | |
163 | |
164 void encodeUint64(int value, int offset) { | |
165 if (value < 0) { | |
166 throw new MojoCodecError('$kErrorUnsigned: $value'); | |
167 } | |
168 _buffer.buffer.setUint64(_base + offset, value, Endianness.LITTLE_ENDIAN); | |
169 } | |
170 | |
171 void encodeFloat(double value, int offset) => _buffer.buffer.setFloat32( | |
172 _base + offset, value, Endianness.LITTLE_ENDIAN); | |
173 | |
174 void encodeDouble(double value, int offset) => _buffer.buffer.setFloat64( | |
175 _base + offset, value, Endianness.LITTLE_ENDIAN); | |
176 | |
177 void encodeHandle(core.MojoHandle value, int offset, bool nullable) { | |
178 if ((value == null) || !value.isValid) { | |
179 encodeInvalideHandle(offset, nullable); | |
180 } else { | |
181 encodeUint32(_buffer.handles.length, offset); | |
182 _buffer.handles.add(value.pass()); | |
183 } | |
184 } | |
185 | |
186 void encodeMessagePipeHandle( | |
187 core.MojoMessagePipeEndpoint value, int offset, bool nullable) => | |
188 encodeHandle(value != null ? value.handle : null, offset, nullable); | |
189 | |
190 void encodeConsumerHandle( | |
191 core.MojoDataPipeConsumer value, int offset, bool nullable) => | |
192 encodeHandle(value != null ? value.handle : null, offset, nullable); | |
193 | |
194 void encodeProducerHandle( | |
195 core.MojoDataPipeProducer value, int offset, bool nullable) => | |
196 encodeHandle(value != null ? value.handle : null, offset, nullable); | |
197 | |
198 void encodeSharedBufferHandle( | |
199 core.MojoSharedBuffer value, int offset, bool nullable) => | |
200 encodeHandle(value != null ? value.handle : null, offset, nullable); | |
201 | |
202 void encodeInterface( | |
203 core.MojoEventStreamListener interface, int offset, bool nullable) { | |
204 if (interface == null) { | |
205 encodeInvalideHandle(offset, nullable); | |
206 // Set the version field to 0. | |
207 encodeUint32(0, offset + kSerializedHandleSize); | |
208 return; | |
209 } | |
210 if (interface is Stub) { | |
211 assert(!interface.isBound); | |
212 var pipe = new core.MojoMessagePipe(); | |
213 interface.bind(pipe.endpoints[0]); | |
214 interface.listen(); | |
215 encodeMessagePipeHandle(pipe.endpoints[1], offset, nullable); | |
216 // Set the version to the version in the stub. | |
217 encodeUint32(interface.version, offset + kSerializedHandleSize); | |
218 } else if (interface is Proxy) { | |
219 assert(interface.isBound); | |
220 if (!interface.isOpen) { | |
221 // Make sure that we are listening so that state for the proxy is | |
222 // cleaned up when the message is sent and the handle is closed. | |
223 interface.listen(); | |
224 } | |
225 encodeMessagePipeHandle(interface.endpoint, offset, nullable); | |
226 // Set the version to the current version of the proxy. | |
227 encodeUint32(interface.version, offset + kSerializedHandleSize); | |
228 } else { | |
229 throw new MojoCodecError( | |
230 'Trying to encode an unknown MojoEventStreamListener'); | |
231 } | |
232 } | |
233 | |
234 void encodeInterfaceRequest(ProxyBase client, int offset, bool nullable) { | |
235 if (client == null) { | |
236 encodeInvalideHandle(offset, nullable); | |
237 return; | |
238 } | |
239 var pipe = new core.MojoMessagePipe(); | |
240 client.impl.bind(pipe.endpoints[0]); | |
241 client.impl.listen(); | |
242 encodeMessagePipeHandle(pipe.endpoints[1], offset, nullable); | |
243 } | |
244 | |
245 void encodeNullPointer(int offset, bool nullable) { | |
246 if (!nullable) { | |
247 throw new MojoCodecError( | |
248 'Trying to encode a null pointer for a non-nullable type'); | |
249 } | |
250 _buffer.buffer.setUint64(_base + offset, 0, Endianness.LITTLE_ENDIAN); | |
251 } | |
252 | |
253 void encodeInvalideHandle(int offset, bool nullable) { | |
254 if (!nullable) { | |
255 throw new MojoCodecError( | |
256 'Trying to encode a null pointer for a non-nullable type'); | |
257 } | |
258 _buffer.buffer.setInt32(_base + offset, -1, Endianness.LITTLE_ENDIAN); | |
259 } | |
260 | |
261 void encodePointerToNextUnclaimed(int offset) => | |
262 encodeUint64(_buffer.extent - (_base + offset), offset); | |
263 | |
264 void encodeStruct(Struct value, int offset, bool nullable) { | |
265 if (value == null) { | |
266 encodeNullPointer(offset, nullable); | |
267 return; | |
268 } | |
269 encodePointerToNextUnclaimed(offset); | |
270 value.encode(this); | |
271 } | |
272 | |
273 Encoder encodePointerArray(int length, int offset, int expectedLength) => | |
274 encoderForArray(kPointerSize, length, offset, expectedLength); | |
275 | |
276 Encoder encoderForArray( | |
277 int elementSize, int length, int offset, int expectedLength) { | |
278 if ((expectedLength != kUnspecifiedArrayLength) && | |
279 (expectedLength != length)) { | |
280 throw new MojoCodecError( | |
281 'Trying to encode a fixed array of incorrect length'); | |
282 } | |
283 return encoderForArrayByTotalSize(length * elementSize, length, offset); | |
284 } | |
285 | |
286 Encoder encoderForArrayByTotalSize(int size, int length, int offset) { | |
287 encodePointerToNextUnclaimed(offset); | |
288 return getArrayEncoderAtOffset( | |
289 new ArrayDataHeader(ArrayDataHeader.kHeaderSize + size, length)); | |
290 } | |
291 | |
292 void encodeBoolArray( | |
293 List<bool> value, int offset, int nullability, int expectedLength) { | |
294 if (value == null) { | |
295 encodeNullPointer(offset, isArrayNullable(nullability)); | |
296 return; | |
297 } | |
298 if ((expectedLength != kUnspecifiedArrayLength) && | |
299 (expectedLength != value.length)) { | |
300 throw new MojoCodecError( | |
301 'Trying to encode a fixed array of incorrect size.'); | |
302 } | |
303 var bytes = new Uint8List((value.length + 7) ~/ kAlignment); | |
304 for (int i = 0; i < bytes.length; ++i) { | |
305 for (int j = 0; j < kAlignment; ++j) { | |
306 int boolIndex = kAlignment * i + j; | |
307 if ((boolIndex < value.length) && value[boolIndex]) { | |
308 bytes[i] |= (1 << j); | |
309 } | |
310 } | |
311 } | |
312 var encoder = | |
313 encoderForArrayByTotalSize(bytes.length, value.length, offset); | |
314 encoder.appendUint8Array(bytes); | |
315 } | |
316 | |
317 void encodeArray(Function arrayAppend, int elementBytes, List<int> value, | |
318 int offset, int nullability, int expectedLength) { | |
319 if (value == null) { | |
320 encodeNullPointer(offset, isArrayNullable(nullability)); | |
321 return; | |
322 } | |
323 var encoder = | |
324 encoderForArray(elementBytes, value.length, offset, expectedLength); | |
325 arrayAppend(encoder, value); | |
326 } | |
327 | |
328 void encodeInt8Array( | |
329 List<int> value, int offset, int nullability, int expectedLength) => | |
330 encodeArray((e, v) => e.appendInt8Array(v), 1, value, offset, nullability, | |
331 expectedLength); | |
332 | |
333 void encodeUint8Array( | |
334 List<int> value, int offset, int nullability, int expectedLength) => | |
335 encodeArray((e, v) => e.appendUint8Array(v), 1, value, offset, | |
336 nullability, expectedLength); | |
337 | |
338 void encodeInt16Array( | |
339 List<int> value, int offset, int nullability, int expectedLength) => | |
340 encodeArray((e, v) => e.appendInt16Array(v), 2, value, offset, | |
341 nullability, expectedLength); | |
342 | |
343 void encodeUint16Array( | |
344 List<int> value, int offset, int nullability, int expectedLength) => | |
345 encodeArray((e, v) => e.appendUint16Array(v), 2, value, offset, | |
346 nullability, expectedLength); | |
347 | |
348 void encodeInt32Array( | |
349 List<int> value, int offset, int nullability, int expectedLength) => | |
350 encodeArray((e, v) => e.appendInt32Array(v), 4, value, offset, | |
351 nullability, expectedLength); | |
352 | |
353 void encodeUint32Array( | |
354 List<int> value, int offset, int nullability, int expectedLength) => | |
355 encodeArray((e, v) => e.appendUint32Array(v), 4, value, offset, | |
356 nullability, expectedLength); | |
357 | |
358 void encodeInt64Array( | |
359 List<int> value, int offset, int nullability, int expectedLength) => | |
360 encodeArray((e, v) => e.appendInt64Array(v), 8, value, offset, | |
361 nullability, expectedLength); | |
362 | |
363 void encodeUint64Array( | |
364 List<int> value, int offset, int nullability, int expectedLength) => | |
365 encodeArray((e, v) => e.appendUint64Array(v), 8, value, offset, | |
366 nullability, expectedLength); | |
367 | |
368 void encodeFloatArray( | |
369 List<int> value, int offset, int nullability, int expectedLength) => | |
370 encodeArray((e, v) => e.appendFloatArray(v), 4, value, offset, | |
371 nullability, expectedLength); | |
372 | |
373 void encodeDoubleArray( | |
374 List<int> value, int offset, int nullability, int expectedLength) => | |
375 encodeArray((e, v) => e.appendDoubleArray(v), 8, value, offset, | |
376 nullability, expectedLength); | |
377 | |
378 void _handleArrayEncodeHelper(Function elementEncoder, List value, int offset, | |
379 int elementSize, int nullability, int expectedLength) { | |
380 if (value == null) { | |
381 encodeNullPointer(offset, isArrayNullable(nullability)); | |
382 return; | |
383 } | |
384 var encoder = | |
385 encoderForArray(elementSize, value.length, offset, expectedLength); | |
386 for (int i = 0; i < value.length; ++i) { | |
387 int elementOffset = ArrayDataHeader.kHeaderSize + elementSize * i; | |
388 elementEncoder( | |
389 encoder, value[i], elementOffset, isElementNullable(nullability)); | |
390 } | |
391 } | |
392 | |
393 void encodeHandleArray(List<core.MojoHandle> value, int offset, | |
394 int nullability, int expectedLength) => _handleArrayEncodeHelper( | |
395 (e, v, o, n) => e.encodeHandle(v, o, n), value, offset, | |
396 kSerializedHandleSize, nullability, expectedLength); | |
397 | |
398 void encodeMessagePipeHandleArray(List<core.MojoMessagePipeEndpoint> value, | |
399 int offset, int nullability, int expectedLength) => | |
400 _handleArrayEncodeHelper( | |
401 (e, v, o, n) => e.encodeMessagePipeHandle(v, o, n), value, offset, | |
402 kSerializedHandleSize, nullability, expectedLength); | |
403 | |
404 void encodeConsumerHandleArray(List<core.MojoDataPipeConsumer> value, | |
405 int offset, int nullability, int expectedLength) => | |
406 _handleArrayEncodeHelper((e, v, o, n) => e.encodeConsumerHandle(v, o, n), | |
407 value, offset, kSerializedHandleSize, nullability, expectedLength); | |
408 | |
409 void encodeProducerHandleArray(List<core.MojoDataPipeProducer> value, | |
410 int offset, int nullability, int expectedLength) => | |
411 _handleArrayEncodeHelper((e, v, o, n) => e.encodeProducerHandle(v, o, n), | |
412 value, offset, kSerializedHandleSize, nullability, expectedLength); | |
413 | |
414 void encodeSharedBufferHandleArray(List<core.MojoSharedBuffer> value, | |
415 int offset, int nullability, int expectedLength) => | |
416 _handleArrayEncodeHelper( | |
417 (e, v, o, n) => e.encodeSharedBufferHandle(v, o, n), value, offset, | |
418 kSerializedHandleSize, nullability, expectedLength); | |
419 | |
420 void encodeInterfaceRequestArray( | |
421 List<Proxy> value, int offset, int nullability, int expectedLength) => | |
422 _handleArrayEncodeHelper( | |
423 (e, v, o, n) => e.encodeInterfaceRequest(v, o, n), value, offset, | |
424 kSerializedHandleSize, nullability, expectedLength); | |
425 | |
426 void encodeInterfaceArray( | |
427 List<Stub> value, int offset, int nullability, int expectedLength) => | |
428 _handleArrayEncodeHelper((e, v, o, n) => e.encodeInterface(v, o, n), | |
429 value, offset, kSerializedInterfaceSize, nullability, expectedLength); | |
430 | |
431 static Uint8List _utf8OfString(String s) => | |
432 (new Uint8List.fromList((const Utf8Encoder()).convert(s))); | |
433 | |
434 void encodeString(String value, int offset, bool nullable) { | |
435 if (value == null) { | |
436 encodeNullPointer(offset, nullable); | |
437 return; | |
438 } | |
439 int nullability = nullable ? kArrayNullable : kNothingNullable; | |
440 encodeUint8Array( | |
441 _utf8OfString(value), offset, nullability, kUnspecifiedArrayLength); | |
442 } | |
443 | |
444 void appendBytes(Uint8List value) { | |
445 _buffer.buffer.buffer | |
446 .asUint8List() | |
447 .setRange(_base + ArrayDataHeader.kHeaderSize, | |
448 _base + ArrayDataHeader.kHeaderSize + value.lengthInBytes, value); | |
449 } | |
450 | |
451 void appendInt8Array(List<int> value) => | |
452 appendBytes(new Uint8List.view(new Int8List.fromList(value).buffer)); | |
453 | |
454 void appendUint8Array(List<int> value) => | |
455 appendBytes(new Uint8List.fromList(value)); | |
456 | |
457 void appendInt16Array(List<int> value) => | |
458 appendBytes(new Uint8List.view(new Int16List.fromList(value).buffer)); | |
459 | |
460 void appendUint16Array(List<int> value) => | |
461 appendBytes(new Uint8List.view(new Uint16List.fromList(value).buffer)); | |
462 | |
463 void appendInt32Array(List<int> value) => | |
464 appendBytes(new Uint8List.view(new Int32List.fromList(value).buffer)); | |
465 | |
466 void appendUint32Array(List<int> value) => | |
467 appendBytes(new Uint8List.view(new Uint32List.fromList(value).buffer)); | |
468 | |
469 void appendInt64Array(List<int> value) => | |
470 appendBytes(new Uint8List.view(new Int64List.fromList(value).buffer)); | |
471 | |
472 void appendUint64Array(List<int> value) => | |
473 appendBytes(new Uint8List.view(new Uint64List.fromList(value).buffer)); | |
474 | |
475 void appendFloatArray(List<double> value) => | |
476 appendBytes(new Uint8List.view(new Float32List.fromList(value).buffer)); | |
477 | |
478 void appendDoubleArray(List<double> value) => | |
479 appendBytes(new Uint8List.view(new Float64List.fromList(value).buffer)); | |
480 | |
481 Encoder encoderForMap(int offset) { | |
482 encodePointerToNextUnclaimed(offset); | |
483 return getStructEncoderAtOffset(kMapStructHeader); | |
484 } | |
485 } | |
486 | |
487 class _Validator { | |
488 final int _maxMemory; | |
489 final int _numberOfHandles; | |
490 int _minNextClaimedHandle = 0; | |
491 int _minNextMemory = 0; | |
492 List<int> _skippedIndices = []; | |
493 | |
494 _Validator(this._maxMemory, this._numberOfHandles); | |
495 | |
496 void claimHandle(int handle) { | |
497 if (handle < _minNextClaimedHandle) { | |
498 throw new MojoCodecError('Trying to access handle out of order.'); | |
499 } | |
500 if (handle >= _numberOfHandles) { | |
501 throw new MojoCodecError('Trying to access non present handle.'); | |
502 } | |
503 for (int i = _minNextClaimedHandle; i < handle; i++) { | |
504 _skippedIndices.add(i); | |
505 } | |
506 _minNextClaimedHandle = handle + 1; | |
507 } | |
508 | |
509 void claimMemory(int start, int end) { | |
510 if ((start % kAlignment) != 0) { | |
511 throw new MojoCodecError('Incorrect starting alignment: $start.'); | |
512 } | |
513 if (start < _minNextMemory) { | |
514 throw new MojoCodecError('Trying to access memory out of order.'); | |
515 } | |
516 if (end < start) { | |
517 throw new MojoCodecError('Incorrect memory range.'); | |
518 } | |
519 if (end > _maxMemory) { | |
520 throw new MojoCodecError('Trying to access out of range memory.'); | |
521 } | |
522 _minNextMemory = align(end); | |
523 } | |
524 } | |
525 | |
526 class Decoder { | |
527 _Validator _validator; | |
528 Message _message; | |
529 int _base = 0; | |
530 | |
531 Decoder(this._message, [this._base = 0, this._validator = null]) { | |
532 if (_validator == null) { | |
533 _validator = new _Validator( | |
534 _message.buffer.lengthInBytes, _message.handles.length); | |
535 } | |
536 } | |
537 | |
538 Decoder getDecoderAtPosition(int offset) => | |
539 new Decoder(_message, offset, _validator); | |
540 | |
541 factory Decoder.atOffset(Decoder d, int offset, _Validator validator) => | |
542 new Decoder(d._message, offset, validator); | |
543 | |
544 ByteData get _buffer => _message.buffer; | |
545 List<core.MojoHandle> get _handles => _message.handles; | |
546 List<core.MojoHandle> get excessHandles => new List.from(_message.handles | |
547 .getRange(_validator._minNextClaimedHandle, _message.handles.length)) | |
548 ..addAll(_validator._skippedIndices.map((i) => _message.handles[i])); | |
549 | |
550 int decodeInt8(int offset) => _buffer.getInt8(_base + offset); | |
551 int decodeUint8(int offset) => _buffer.getUint8(_base + offset); | |
552 int decodeInt16(int offset) => | |
553 _buffer.getInt16(_base + offset, Endianness.LITTLE_ENDIAN); | |
554 int decodeUint16(int offset) => | |
555 _buffer.getUint16(_base + offset, Endianness.LITTLE_ENDIAN); | |
556 int decodeInt32(int offset) => | |
557 _buffer.getInt32(_base + offset, Endianness.LITTLE_ENDIAN); | |
558 int decodeUint32(int offset) => | |
559 _buffer.getUint32(_base + offset, Endianness.LITTLE_ENDIAN); | |
560 int decodeInt64(int offset) => | |
561 _buffer.getInt64(_base + offset, Endianness.LITTLE_ENDIAN); | |
562 int decodeUint64(int offset) => | |
563 _buffer.getUint64(_base + offset, Endianness.LITTLE_ENDIAN); | |
564 double decodeFloat(int offset) => | |
565 _buffer.getFloat32(_base + offset, Endianness.LITTLE_ENDIAN); | |
566 double decodeDouble(int offset) => | |
567 _buffer.getFloat64(_base + offset, Endianness.LITTLE_ENDIAN); | |
568 | |
569 bool decodeBool(int offset, int bit) => | |
570 (decodeUint8(offset) & (1 << bit)) != 0; | |
571 | |
572 core.MojoHandle decodeHandle(int offset, bool nullable) { | |
573 int index = decodeInt32(offset); | |
574 if (index == -1) { | |
575 if (!nullable) { | |
576 throw new MojoCodecError( | |
577 'Trying to decode an invalid handle from a non-nullable type.'); | |
578 } | |
579 return new core.MojoHandle.invalid(); | |
580 } | |
581 _validator.claimHandle(index); | |
582 return _handles[index]; | |
583 } | |
584 | |
585 core.MojoMessagePipeEndpoint decodeMessagePipeHandle( | |
586 int offset, bool nullable) => | |
587 new core.MojoMessagePipeEndpoint(decodeHandle(offset, nullable)); | |
588 | |
589 core.MojoDataPipeConsumer decodeConsumerHandle(int offset, bool nullable) => | |
590 new core.MojoDataPipeConsumer(decodeHandle(offset, nullable)); | |
591 | |
592 core.MojoDataPipeProducer decodeProducerHandle(int offset, bool nullable) => | |
593 new core.MojoDataPipeProducer(decodeHandle(offset, nullable)); | |
594 | |
595 core.MojoSharedBuffer decodeSharedBufferHandle(int offset, bool nullable) => | |
596 new core.MojoSharedBuffer(decodeHandle(offset, nullable)); | |
597 | |
598 ProxyBase decodeServiceInterface( | |
599 int offset, bool nullable, Function clientFactory) { | |
600 var endpoint = decodeMessagePipeHandle(offset, nullable); | |
601 var version = decodeUint32(offset + kSerializedHandleSize); | |
602 if (!endpoint.handle.isValid) { | |
603 return null; | |
604 } | |
605 ProxyBase client = clientFactory(endpoint); | |
606 client.impl._version = version; | |
607 return client; | |
608 } | |
609 | |
610 Stub decodeInterfaceRequest( | |
611 int offset, bool nullable, Function interfaceFactory) { | |
612 var endpoint = decodeMessagePipeHandle(offset, nullable); | |
613 return endpoint.handle.isValid ? interfaceFactory(endpoint) : null; | |
614 } | |
615 | |
616 Decoder decodePointer(int offset, bool nullable) { | |
617 int basePosition = _base + offset; | |
618 int pointerOffset = decodeUint64(offset); | |
619 if (pointerOffset == 0) { | |
620 if (!nullable) { | |
621 throw new MojoCodecError( | |
622 'Trying to decode a null pointer for a non-nullable type'); | |
623 } | |
624 return null; | |
625 } | |
626 int newPosition = (basePosition + pointerOffset); | |
627 return new Decoder.atOffset(this, newPosition, _validator); | |
628 } | |
629 | |
630 StructDataHeader decodeStructDataHeader() { | |
631 _validator.claimMemory(_base, _base + StructDataHeader.kHeaderSize); | |
632 int size = decodeUint32(StructDataHeader.kSizeOffset); | |
633 int version = decodeUint32(StructDataHeader.kVersionOffset); | |
634 if (size < 0) { | |
635 throw new MojoCodecError('Negative size.'); | |
636 } | |
637 if (version < 0) { | |
638 throw new MojoCodecError('Negative version number.'); | |
639 } | |
640 _validator.claimMemory(_base + StructDataHeader.kHeaderSize, _base + size); | |
641 return new StructDataHeader(size, version); | |
642 } | |
643 | |
644 ArrayDataHeader decodeArrayDataHeader() { | |
645 _validator.claimMemory(_base, _base + ArrayDataHeader.kHeaderSize); | |
646 int size = decodeUint32(ArrayDataHeader.kSizeOffset); | |
647 int numElements = decodeUint32(ArrayDataHeader.kNumElementsOffset); | |
648 if (size < 0) { | |
649 throw new MojoCodecError('Negative size.'); | |
650 } | |
651 if (numElements < 0) { | |
652 throw new MojoCodecError('Negative number of elements.'); | |
653 } | |
654 _validator.claimMemory(_base + ArrayDataHeader.kHeaderSize, _base + size); | |
655 return new ArrayDataHeader(size, numElements); | |
656 } | |
657 | |
658 // Decode arrays. | |
659 ArrayDataHeader decodeDataHeaderForBoolArray(int expectedLength) { | |
660 var header = decodeArrayDataHeader(); | |
661 var arrayByteCount = | |
662 ArrayDataHeader.kHeaderSize + (header.numElements + 7) ~/ 8; | |
663 if (header.size < arrayByteCount) { | |
664 throw new MojoCodecError('Array header is incorrect'); | |
665 } | |
666 if ((expectedLength != kUnspecifiedArrayLength) && | |
667 (header.numElements != expectedLength)) { | |
668 throw new MojoCodecError( | |
669 'Incorrect array length. Expected $expectedLength, but got ' | |
670 '${header.numElements}.'); | |
671 } | |
672 return header; | |
673 } | |
674 | |
675 List<bool> decodeBoolArray(int offset, int nullability, int expectedLength) { | |
676 Decoder d = decodePointer(offset, isArrayNullable(nullability)); | |
677 if (d == null) { | |
678 return null; | |
679 } | |
680 var header = d.decodeDataHeaderForBoolArray(expectedLength); | |
681 var bytes = new Uint8List.view(d._buffer.buffer, | |
682 d._buffer.offsetInBytes + d._base + ArrayDataHeader.kHeaderSize, | |
683 (header.numElements + 7) ~/ kAlignment); | |
684 var result = new List<bool>(header.numElements); | |
685 for (int i = 0; i < bytes.lengthInBytes; ++i) { | |
686 for (int j = 0; j < kAlignment; ++j) { | |
687 int boolIndex = i * kAlignment + j; | |
688 if (boolIndex < result.length) { | |
689 result[boolIndex] = (bytes[i] & (1 << j)) != 0; | |
690 } | |
691 } | |
692 } | |
693 return result; | |
694 } | |
695 | |
696 ArrayDataHeader decodeDataHeaderForArray( | |
697 int elementSize, int expectedLength) { | |
698 var header = decodeArrayDataHeader(); | |
699 var arrayByteCount = | |
700 ArrayDataHeader.kHeaderSize + header.numElements * elementSize; | |
701 if (header.size < arrayByteCount) { | |
702 throw new MojoCodecError( | |
703 'Array header is incorrect: $header, elementSize = $elementSize'); | |
704 } | |
705 if ((expectedLength != kUnspecifiedArrayLength) && | |
706 (header.numElements != expectedLength)) { | |
707 throw new MojoCodecError( | |
708 'Incorrect array length. Expected $expectedLength, but got ' | |
709 '${header.numElements}'); | |
710 } | |
711 return header; | |
712 } | |
713 | |
714 ArrayDataHeader decodeDataHeaderForPointerArray(int expectedLength) => | |
715 decodeDataHeaderForArray(kPointerSize, expectedLength); | |
716 | |
717 List decodeArray(Function arrayViewer, int elementSize, int offset, | |
718 int nullability, int expectedLength) { | |
719 Decoder d = decodePointer(offset, isArrayNullable(nullability)); | |
720 if (d == null) { | |
721 return null; | |
722 } | |
723 var header = d.decodeDataHeaderForArray(elementSize, expectedLength); | |
724 return arrayViewer(d._buffer.buffer, | |
725 d._buffer.offsetInBytes + d._base + ArrayDataHeader.kHeaderSize, | |
726 header.numElements); | |
727 } | |
728 | |
729 List<int> decodeInt8Array(int offset, int nullability, int expectedLength) => | |
730 decodeArray((b, s, l) => new Int8List.view(b, s, l), 1, offset, | |
731 nullability, expectedLength); | |
732 | |
733 List<int> decodeUint8Array(int offset, int nullability, int expectedLength) => | |
734 decodeArray((b, s, l) => new Uint8List.view(b, s, l), 1, offset, | |
735 nullability, expectedLength); | |
736 | |
737 List<int> decodeInt16Array(int offset, int nullability, int expectedLength) => | |
738 decodeArray((b, s, l) => new Int16List.view(b, s, l), 2, offset, | |
739 nullability, expectedLength); | |
740 | |
741 List<int> decodeUint16Array( | |
742 int offset, int nullability, int expectedLength) => decodeArray( | |
743 (b, s, l) => new Uint16List.view(b, s, l), 2, offset, nullability, | |
744 expectedLength); | |
745 | |
746 List<int> decodeInt32Array(int offset, int nullability, int expectedLength) => | |
747 decodeArray((b, s, l) => new Int32List.view(b, s, l), 4, offset, | |
748 nullability, expectedLength); | |
749 | |
750 List<int> decodeUint32Array( | |
751 int offset, int nullability, int expectedLength) => decodeArray( | |
752 (b, s, l) => new Uint32List.view(b, s, l), 4, offset, nullability, | |
753 expectedLength); | |
754 | |
755 List<int> decodeInt64Array(int offset, int nullability, int expectedLength) => | |
756 decodeArray((b, s, l) => new Int64List.view(b, s, l), 8, offset, | |
757 nullability, expectedLength); | |
758 | |
759 List<int> decodeUint64Array( | |
760 int offset, int nullability, int expectedLength) => decodeArray( | |
761 (b, s, l) => new Uint64List.view(b, s, l), 8, offset, nullability, | |
762 expectedLength); | |
763 | |
764 List<double> decodeFloatArray( | |
765 int offset, int nullability, int expectedLength) => decodeArray( | |
766 (b, s, l) => new Float32List.view(b, s, l), 4, offset, nullability, | |
767 expectedLength); | |
768 | |
769 List<double> decodeDoubleArray( | |
770 int offset, int nullability, int expectedLength) => decodeArray( | |
771 (b, s, l) => new Float64List.view(b, s, l), 8, offset, nullability, | |
772 expectedLength); | |
773 | |
774 List _handleArrayDecodeHelper(Function elementDecoder, int offset, | |
775 int elementSize, int nullability, int expectedLength) { | |
776 Decoder d = decodePointer(offset, isArrayNullable(nullability)); | |
777 if (d == null) { | |
778 return null; | |
779 } | |
780 var header = d.decodeDataHeaderForArray(elementSize, expectedLength); | |
781 var result = new List(header.numElements); | |
782 for (int i = 0; i < result.length; ++i) { | |
783 result[i] = elementDecoder(d, | |
784 ArrayDataHeader.kHeaderSize + elementSize * i, | |
785 isElementNullable(nullability)); | |
786 } | |
787 return result; | |
788 } | |
789 | |
790 List<core.MojoHandle> decodeHandleArray( | |
791 int offset, int nullability, int expectedLength) => | |
792 _handleArrayDecodeHelper((d, o, n) => d.decodeHandle(o, n), offset, | |
793 kSerializedHandleSize, nullability, expectedLength); | |
794 | |
795 List<core.MojoDataPipeConsumer> decodeConsumerHandleArray( | |
796 int offset, int nullability, int expectedLength) => | |
797 _handleArrayDecodeHelper((d, o, n) => d.decodeConsumerHandle(o, n), | |
798 offset, kSerializedHandleSize, nullability, expectedLength); | |
799 | |
800 List<core.MojoDataPipeProducer> decodeProducerHandleArray( | |
801 int offset, int nullability, int expectedLength) => | |
802 _handleArrayDecodeHelper((d, o, n) => d.decodeProducerHandle(o, n), | |
803 offset, kSerializedHandleSize, nullability, expectedLength); | |
804 | |
805 List<core.MojoMessagePipeEndpoint> decodeMessagePipeHandleArray( | |
806 int offset, int nullability, int expectedLength) => | |
807 _handleArrayDecodeHelper((d, o, n) => d.decodeMessagePipeHandle(o, n), | |
808 offset, kSerializedHandleSize, nullability, expectedLength); | |
809 | |
810 List<core.MojoSharedBuffer> decodeSharedBufferHandleArray( | |
811 int offset, int nullability, int expectedLength) => | |
812 _handleArrayDecodeHelper((d, o, n) => d.decodeSharedBufferHandle(o, n), | |
813 offset, kSerializedHandleSize, nullability, expectedLength); | |
814 | |
815 List<Stub> decodeInterfaceRequestArray(int offset, int nullability, | |
816 int expectedLength, Function interfaceFactory) => | |
817 _handleArrayDecodeHelper( | |
818 (d, o, n) => d.decodeInterfaceRequest(o, n, interfaceFactory), offset, | |
819 kSerializedHandleSize, nullability, expectedLength); | |
820 | |
821 List<Proxy> decodeServiceInterfaceArray(int offset, int nullability, | |
822 int expectedLength, Function clientFactory) => _handleArrayDecodeHelper( | |
823 (d, o, n) => d.decodeServiceInterface(o, n, clientFactory), offset, | |
824 kSerializedInterfaceSize, nullability, expectedLength); | |
825 | |
826 static String _stringOfUtf8(Uint8List bytes) => | |
827 (const Utf8Decoder()).convert(bytes.toList()); | |
828 | |
829 String decodeString(int offset, bool nullable) { | |
830 int nullability = nullable ? kArrayNullable : 0; | |
831 var bytes = decodeUint8Array(offset, nullability, kUnspecifiedArrayLength); | |
832 if (bytes == null) { | |
833 return null; | |
834 } | |
835 return _stringOfUtf8(bytes); | |
836 } | |
837 | |
838 StructDataHeader decodeDataHeaderForMap() { | |
839 var header = decodeStructDataHeader(); | |
840 if (header.size != kMapStructHeader.size) { | |
841 throw new MojoCodecError( | |
842 'Incorrect header for map. The size is incorrect.'); | |
843 } | |
844 if (header.version != kMapStructHeader.version) { | |
845 throw new MojoCodecError( | |
846 'Incorrect header for map. The version is incorrect.'); | |
847 } | |
848 return header; | |
849 } | |
850 } | |
OLD | NEW |