mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
272 lines
7.9 KiB
Dart
272 lines
7.9 KiB
Dart
// 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:math' as math;
|
|
import 'dart:typed_data';
|
|
|
|
export 'dart:typed_data' show ByteData, Endian, Float32List, Float64List, Int32List, Int64List, Uint8List;
|
|
|
|
/// 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.
|
|
/// [startCapacity] determines the start size of the [WriteBuffer] in bytes.
|
|
/// The closer that value is to the real size used, the better the
|
|
/// performance.
|
|
factory WriteBuffer({int startCapacity = 8}) {
|
|
assert(startCapacity > 0);
|
|
final ByteData eightBytes = ByteData(8);
|
|
final Uint8List eightBytesAsList = eightBytes.buffer.asUint8List();
|
|
return WriteBuffer._(Uint8List(startCapacity), eightBytes, eightBytesAsList);
|
|
}
|
|
|
|
WriteBuffer._(this._buffer, this._eightBytes, this._eightBytesAsList);
|
|
|
|
Uint8List _buffer;
|
|
int _currentSize = 0;
|
|
bool _isDone = false;
|
|
final ByteData _eightBytes;
|
|
final Uint8List _eightBytesAsList;
|
|
static final Uint8List _zeroBuffer = Uint8List(8);
|
|
|
|
void _add(int byte) {
|
|
if (_currentSize == _buffer.length) {
|
|
_resize();
|
|
}
|
|
_buffer[_currentSize] = byte;
|
|
_currentSize += 1;
|
|
}
|
|
|
|
void _append(Uint8List other) {
|
|
final int newSize = _currentSize + other.length;
|
|
if (newSize >= _buffer.length) {
|
|
_resize(newSize);
|
|
}
|
|
_buffer.setRange(_currentSize, newSize, other);
|
|
_currentSize += other.length;
|
|
}
|
|
|
|
void _addAll(Uint8List data, [int start = 0, int? end]) {
|
|
final int newEnd = end ?? _eightBytesAsList.length;
|
|
final int newSize = _currentSize + (newEnd - start);
|
|
if (newSize >= _buffer.length) {
|
|
_resize(newSize);
|
|
}
|
|
_buffer.setRange(_currentSize, newSize, data);
|
|
_currentSize = newSize;
|
|
}
|
|
|
|
void _resize([int? requiredLength]) {
|
|
final int doubleLength = _buffer.length * 2;
|
|
final int newLength = math.max(requiredLength ?? 0, doubleLength);
|
|
final Uint8List newBuffer = Uint8List(newLength);
|
|
newBuffer.setRange(0, _buffer.length, _buffer);
|
|
_buffer = newBuffer;
|
|
}
|
|
|
|
/// Write a Uint8 into the buffer.
|
|
void putUint8(int byte) {
|
|
assert(!_isDone);
|
|
_add(byte);
|
|
}
|
|
|
|
/// Write a Uint16 into the buffer.
|
|
void putUint16(int value, {Endian? endian}) {
|
|
assert(!_isDone);
|
|
_eightBytes.setUint16(0, value, endian ?? Endian.host);
|
|
_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);
|
|
_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);
|
|
_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);
|
|
_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);
|
|
_addAll(_eightBytesAsList);
|
|
}
|
|
|
|
/// Write all the values from a [Uint8List] into the buffer.
|
|
void putUint8List(Uint8List list) {
|
|
assert(!_isDone);
|
|
_append(list);
|
|
}
|
|
|
|
/// Write all the values from an [Int32List] into the buffer.
|
|
void putInt32List(Int32List list) {
|
|
assert(!_isDone);
|
|
_alignTo(4);
|
|
_append(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);
|
|
_append(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);
|
|
_append(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);
|
|
_append(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length));
|
|
}
|
|
|
|
void _alignTo(int alignment) {
|
|
assert(!_isDone);
|
|
final int mod = _currentSize % alignment;
|
|
if (mod != 0) {
|
|
_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, _currentSize);
|
|
_buffer = Uint8List(0);
|
|
_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;
|
|
}
|
|
}
|
|
}
|