| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:typed_data'; |
| |
| import 'package:typed_data/typed_buffers.dart' show Uint8Buffer; |
| |
| /// Write-only buffer for incrementally building a [ByteData] instance. |
| /// |
| /// A WriteBuffer instance can be used only once. Attempts to reuse will result |
| /// in [StateError]s being thrown. |
| /// |
| /// The byte order used is [Endian.host] throughout. |
| class WriteBuffer { |
| /// Creates an interface for incrementally building a [ByteData] instance. |
| WriteBuffer() |
| : _buffer = Uint8Buffer(), |
| _isDone = false, |
| _eightBytes = ByteData(8) { |
| _eightBytesAsList = _eightBytes.buffer.asUint8List(); |
| } |
| |
| Uint8Buffer _buffer; |
| bool _isDone; |
| final ByteData _eightBytes; |
| late Uint8List _eightBytesAsList; |
| static final Uint8List _zeroBuffer = Uint8List.fromList(<int>[0, 0, 0, 0, 0, 0, 0, 0]); |
| |
| /// Write a Uint8 into the buffer. |
| void putUint8(int byte) { |
| assert(!_isDone); |
| _buffer.add(byte); |
| } |
| |
| /// Write a Uint16 into the buffer. |
| void putUint16(int value, {Endian? endian}) { |
| assert(!_isDone); |
| _eightBytes.setUint16(0, value, endian ?? Endian.host); |
| _buffer.addAll(_eightBytesAsList, 0, 2); |
| } |
| |
| /// Write a Uint32 into the buffer. |
| void putUint32(int value, {Endian? endian}) { |
| assert(!_isDone); |
| _eightBytes.setUint32(0, value, endian ?? Endian.host); |
| _buffer.addAll(_eightBytesAsList, 0, 4); |
| } |
| |
| /// Write an Int32 into the buffer. |
| void putInt32(int value, {Endian? endian}) { |
| assert(!_isDone); |
| _eightBytes.setInt32(0, value, endian ?? Endian.host); |
| _buffer.addAll(_eightBytesAsList, 0, 4); |
| } |
| |
| /// Write an Int64 into the buffer. |
| void putInt64(int value, {Endian? endian}) { |
| assert(!_isDone); |
| _eightBytes.setInt64(0, value, endian ?? Endian.host); |
| _buffer.addAll(_eightBytesAsList, 0, 8); |
| } |
| |
| /// Write an Float64 into the buffer. |
| void putFloat64(double value, {Endian? endian}) { |
| assert(!_isDone); |
| _alignTo(8); |
| _eightBytes.setFloat64(0, value, endian ?? Endian.host); |
| _buffer.addAll(_eightBytesAsList); |
| } |
| |
| /// Write all the values from a [Uint8List] into the buffer. |
| void putUint8List(Uint8List list) { |
| assert(!_isDone); |
| _buffer.addAll(list); |
| } |
| |
| /// Write all the values from an [Int32List] into the buffer. |
| void putInt32List(Int32List list) { |
| assert(!_isDone); |
| _alignTo(4); |
| _buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 4 * list.length)); |
| } |
| |
| /// Write all the values from an [Int64List] into the buffer. |
| void putInt64List(Int64List list) { |
| assert(!_isDone); |
| _alignTo(8); |
| _buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length)); |
| } |
| |
| /// Write all the values from a [Float32List] into the buffer. |
| void putFloat32List(Float32List list) { |
| assert(!_isDone); |
| _alignTo(4); |
| _buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 4 * list.length)); |
| } |
| |
| /// Write all the values from a [Float64List] into the buffer. |
| void putFloat64List(Float64List list) { |
| assert(!_isDone); |
| _alignTo(8); |
| _buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length)); |
| } |
| |
| void _alignTo(int alignment) { |
| assert(!_isDone); |
| final int mod = _buffer.length % alignment; |
| if (mod != 0) { |
| _buffer.addAll(_zeroBuffer, 0, alignment - mod); |
| } |
| } |
| |
| /// Finalize and return the written [ByteData]. |
| ByteData done() { |
| if (_isDone) { |
| throw StateError('done() must not be called more than once on the same $runtimeType.'); |
| } |
| final ByteData result = _buffer.buffer.asByteData(0, _buffer.lengthInBytes); |
| _buffer = Uint8Buffer(); |
| _isDone = true; |
| return result; |
| } |
| } |
| |
| /// Read-only buffer for reading sequentially from a [ByteData] instance. |
| /// |
| /// The byte order used is [Endian.host] throughout. |
| class ReadBuffer { |
| /// Creates a [ReadBuffer] for reading from the specified [data]. |
| ReadBuffer(this.data) |
| : assert(data != null); |
| |
| /// The underlying data being read. |
| final ByteData data; |
| |
| /// The position to read next. |
| int _position = 0; |
| |
| /// Whether the buffer has data remaining to read. |
| bool get hasRemaining => _position < data.lengthInBytes; |
| |
| /// Reads a Uint8 from the buffer. |
| int getUint8() { |
| return data.getUint8(_position++); |
| } |
| |
| /// Reads a Uint16 from the buffer. |
| int getUint16({Endian? endian}) { |
| final int value = data.getUint16(_position, endian ?? Endian.host); |
| _position += 2; |
| return value; |
| } |
| |
| /// Reads a Uint32 from the buffer. |
| int getUint32({Endian? endian}) { |
| final int value = data.getUint32(_position, endian ?? Endian.host); |
| _position += 4; |
| return value; |
| } |
| |
| /// Reads an Int32 from the buffer. |
| int getInt32({Endian? endian}) { |
| final int value = data.getInt32(_position, endian ?? Endian.host); |
| _position += 4; |
| return value; |
| } |
| |
| /// Reads an Int64 from the buffer. |
| int getInt64({Endian? endian}) { |
| final int value = data.getInt64(_position, endian ?? Endian.host); |
| _position += 8; |
| return value; |
| } |
| |
| /// Reads a Float64 from the buffer. |
| double getFloat64({Endian? endian}) { |
| _alignTo(8); |
| final double value = data.getFloat64(_position, endian ?? Endian.host); |
| _position += 8; |
| return value; |
| } |
| |
| /// Reads the given number of Uint8s from the buffer. |
| Uint8List getUint8List(int length) { |
| final Uint8List list = data.buffer.asUint8List(data.offsetInBytes + _position, length); |
| _position += length; |
| return list; |
| } |
| |
| /// Reads the given number of Int32s from the buffer. |
| Int32List getInt32List(int length) { |
| _alignTo(4); |
| final Int32List list = data.buffer.asInt32List(data.offsetInBytes + _position, length); |
| _position += 4 * length; |
| return list; |
| } |
| |
| /// Reads the given number of Int64s from the buffer. |
| Int64List getInt64List(int length) { |
| _alignTo(8); |
| final Int64List list = data.buffer.asInt64List(data.offsetInBytes + _position, length); |
| _position += 8 * length; |
| return list; |
| } |
| |
| /// Reads the given number of Float32s from the buffer |
| Float32List getFloat32List(int length) { |
| _alignTo(4); |
| final Float32List list = data.buffer.asFloat32List(data.offsetInBytes + _position, length); |
| _position += 4 * length; |
| return list; |
| } |
| |
| /// Reads the given number of Float64s from the buffer. |
| Float64List getFloat64List(int length) { |
| _alignTo(8); |
| final Float64List list = data.buffer.asFloat64List(data.offsetInBytes + _position, length); |
| _position += 8 * length; |
| return list; |
| } |
| |
| void _alignTo(int alignment) { |
| final int mod = _position % alignment; |
| if (mod != 0) |
| _position += alignment - mod; |
| } |
| } |