blob: f600fa362fcc7273e5dfcbd9a8e21b8b71179136 [file] [log] [blame]
// 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;
}
}