blob: d124d5067ffe5f2db7e42e875ad4f932d3df6786 [file] [log] [blame]
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. 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:convert';
import 'dart:typed_data';
class BinaryDataSink {
static const int _initSinkSize = 50 * 1024;
Uint8List _data = Uint8List(_initSinkSize);
int _length = 0;
BinaryDataSink();
int get length => _length;
void _ensure(int size) {
// Ensure space for at least `size` additional bytes.
if (_data.length < _length + size) {
int newLength = _data.length * 2;
while (newLength < _length + size) {
newLength *= 2;
}
_data = Uint8List(newLength)..setRange(0, _data.length, _data);
}
}
void writeByte(int byte) {
assert(byte == byte & 0xFF);
_ensure(1);
_data[_length++] = byte;
}
void writeBytes(Uint8List bytes) {
_ensure(bytes.length);
_data.setRange(_length, _length += bytes.length, bytes);
}
void writeString(String value) {
final bytes = utf8.encode(value);
writeInt(bytes.length);
writeBytes(bytes);
}
void writeBool(bool value) {
writeByte(value ? 1 : 0);
}
void writeInt(int value) {
assert(value >= 0 && value >> 30 == 0);
if (value < 0x80) {
writeByte(value);
} else if (value < 0x4000) {
writeByte((value >> 8) | 0x80);
writeByte(value & 0xFF);
} else {
writeByte((value >> 24) | 0xC0);
writeByte((value >> 16) & 0xFF);
writeByte((value >> 8) & 0xFF);
writeByte(value & 0xFF);
}
}
void writeClassId(int value) {
// Add 1 since some class IDs are -1.
writeInt(value + 1);
}
void writeEnum<E extends Enum>(E value) {
writeInt(value.index);
}
Uint8List takeBytes() {
final result = Uint8List.sublistView(_data, 0, _length);
// Free the reference to the large data list so it can potentially be
// tree-shaken.
_data = Uint8List(0);
return result;
}
}
class BinaryDataSource {
int _byteOffset = 0;
final Uint8List _bytes;
BinaryDataSource(this._bytes);
void begin(String tag) {}
void end(String tag) {}
int _readByte() => _bytes[_byteOffset++];
String readString() {
int length = readInt();
return utf8.decode(
Uint8List.sublistView(_bytes, _byteOffset, _byteOffset += length));
}
bool readBool() {
return _readByte() != 0;
}
int readInt() {
var byte = _readByte();
if (byte & 0x80 == 0) {
// 0xxxxxxx
return byte;
} else if (byte & 0x40 == 0) {
// 10xxxxxx
return ((byte & 0x3F) << 8) | _readByte();
} else {
// 11xxxxxx
return ((byte & 0x3F) << 24) |
(_readByte() << 16) |
(_readByte() << 8) |
_readByte();
}
}
int readClassId() {
// Subtract 1 since some class IDs are -1.
return readInt() - 1;
}
E readEnum<E extends Enum>(List<E> values) {
int index = readInt();
assert(
0 <= index && index < values.length,
"Invalid data kind index. "
"Expected one of $values, found index $index.");
return values[index];
}
int get length => _bytes.length;
int get currentOffset => _byteOffset;
}