blob: 13b4e2e81ae2e74064c8fbdeb627ed84d693d133 [file] [log] [blame]
import 'dart:typed_data';
import 'input_buffer.dart';
class OutputBuffer {
int length;
bool bigEndian;
/// Create a byte buffer for writing.
OutputBuffer({int? size = _BLOCK_SIZE, this.bigEndian = false})
: _buffer = Uint8List(size ?? _BLOCK_SIZE),
length = 0;
void rewind() {
length = 0;
}
/// Get the resulting bytes from the buffer.
List<int> getBytes() => Uint8List.view(_buffer.buffer, 0, length);
/// Clear the buffer.
void clear() {
_buffer = Uint8List(_BLOCK_SIZE);
length = 0;
}
/// Write a byte to the end of the buffer.
void writeByte(int value) {
if (length == _buffer.length) {
_expandBuffer();
}
_buffer[length++] = value & 0xff;
}
/// Write a set of bytes to the end of the buffer.
void writeBytes(List<int> bytes, [int? len]) {
len ??= bytes.length;
while (length + len > _buffer.length) {
_expandBuffer((length + len) - _buffer.length);
}
_buffer.setRange(length, length + len, bytes);
length += len;
}
void writeBuffer(InputBuffer bytes) {
while (length + bytes.length > _buffer.length) {
_expandBuffer((length + bytes.length) - _buffer.length);
}
_buffer.setRange(length, length + bytes.length, bytes.buffer, bytes.offset);
length += bytes.length;
}
/// Write a 16-bit word to the end of the buffer.
void writeUint16(int value) {
if (bigEndian) {
writeByte((value >> 8) & 0xff);
writeByte(value & 0xff);
return;
}
writeByte(value & 0xff);
writeByte((value >> 8) & 0xff);
}
/// Write a 32-bit word to the end of the buffer.
void writeUint32(int value) {
if (bigEndian) {
writeByte((value >> 24) & 0xff);
writeByte((value >> 16) & 0xff);
writeByte((value >> 8) & 0xff);
writeByte((value) & 0xff);
return;
}
writeByte((value) & 0xff);
writeByte((value >> 8) & 0xff);
writeByte((value >> 16) & 0xff);
writeByte((value >> 24) & 0xff);
}
void writeFloat32(double value) {
final fb = Float32List(1);
fb[0] = value;
final b = Uint8List.view(fb.buffer);
if (bigEndian) {
writeByte(b[3]);
writeByte(b[2]);
writeByte(b[1]);
writeByte(b[0]);
return;
}
writeByte(b[0]);
writeByte(b[1]);
writeByte(b[2]);
writeByte(b[3]);
}
void writeFloat64(double value) {
final fb = Float64List(1);
fb[0] = value;
final b = Uint8List.view(fb.buffer);
if (bigEndian) {
writeByte(b[7]);
writeByte(b[6]);
writeByte(b[5]);
writeByte(b[4]);
writeByte(b[3]);
writeByte(b[2]);
writeByte(b[1]);
writeByte(b[0]);
return;
}
writeByte(b[0]);
writeByte(b[1]);
writeByte(b[2]);
writeByte(b[3]);
writeByte(b[4]);
writeByte(b[5]);
writeByte(b[6]);
writeByte(b[7]);
}
/// Return the subset of the buffer in the range [start:end].
/// If [start] or [end] are < 0 then it is relative to the end of the buffer.
/// If [end] is not specified (or null), then it is the end of the buffer.
/// This is equivalent to the python list range operator.
List<int> subset(int start, [int? end]) {
if (start < 0) {
start = (length) + start;
}
if (end == null) {
end = length;
} else if (end < 0) {
end = length + end;
}
return Uint8List.view(_buffer.buffer, start, end - start);
}
/// Grow the buffer to accommodate additional data.
void _expandBuffer([int? required]) {
final blockSize = (required != null)
? required
: (_buffer.isEmpty)
? _BLOCK_SIZE
: (_buffer.length * 2);
final newBuffer = Uint8List(_buffer.length + blockSize);
newBuffer.setRange(0, _buffer.length, _buffer);
_buffer = newBuffer;
}
static const _BLOCK_SIZE = 0x2000; // 8k block-size
Uint8List _buffer;
}