LibAC-dart/lib/nbt/Stream.dart

531 lines
12 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'dart:typed_data';
class ByteLayer {
Uint8List _byteBuffer = Uint8List(0);
int _position = 0;
ByteLayer() {
_byteBuffer = Uint8List(0); // Initial size, can be adjusted
_position = 0;
}
int get length => _byteBuffer.length;
int get currentPosition => _position;
Uint8List get bytes => _byteBuffer.sublist(0, _position);
void _ensureCapacity(int additionalBytes) {
final requiredCapacity = _position + additionalBytes;
if (requiredCapacity > _byteBuffer.length) {
final newCapacity =
_position + additionalBytes; // Adjust capacity as needed
final newBuffer = Uint8List(newCapacity);
newBuffer.setAll(0, _byteBuffer);
_byteBuffer = newBuffer;
}
}
void writeInt(int value) {
_ensureCapacity(4);
_byteBuffer.buffer.asByteData().setInt32(_position, value, Endian.big);
_position += 4;
}
void writeDouble(double value) {
_ensureCapacity(8);
_byteBuffer.buffer.asByteData().setFloat64(_position, value, Endian.big);
_position += 8;
}
void writeString(String value) {
final encoded = utf8.encode(value);
writeShort(encoded.length);
_ensureCapacity(encoded.length);
_byteBuffer.setAll(_position, encoded);
_position += encoded.length;
}
int readInt() {
final value =
_byteBuffer.buffer.asByteData().getInt32(_position, Endian.big);
_position += 4;
return value;
}
double readDouble() {
final value =
_byteBuffer.buffer.asByteData().getFloat64(_position, Endian.big);
_position += 8;
return value;
}
String readString() {
final length = readShort();
final encoded = _byteBuffer.sublist(_position, _position + length);
_position += length;
return utf8.decode(encoded);
}
void writeIntZigZag(int value) {
final zigzag = (value << 1) ^ (value >> 31);
writeInt(zigzag);
}
int readIntZigZag() {
final zigzag = readInt();
final value = (zigzag >> 1) ^ -(zigzag & 1);
return value;
}
void writeByte(int value) {
_ensureCapacity(1);
_byteBuffer[_position] = value & 0xFF;
_position++;
}
void writeUnsignedByte(int value) {
_ensureCapacity(1);
_byteBuffer.buffer.asByteData().setUint8(_position, value);
_position++;
}
int readByte() {
final value = _byteBuffer[_position];
_position++;
return value;
}
int readUnsignedByte() {
final value = _byteBuffer.buffer.asByteData().getUint8(_position);
_position++;
return value;
}
void writeVarInt(int value) {
while ((value & ~0x7F) != 0) {
writeByte((value & 0x7F) | 0x80);
value = (value >> 7) & 0x1FFFFFFF;
}
writeByte(value & 0x7F);
}
int readVarInt() {
int result = 0;
int shift = 0;
int byte;
do {
byte = readByte();
result |= (byte & 0x7F) << shift;
if ((byte & 0x80) == 0) {
break;
}
shift += 7;
} while (true);
return result;
}
void writeVarIntNoZigZag(int value) {
while ((value & ~0x7F) != 0) {
writeByte((value & 0x7F) | 0x80);
value >>= 7;
}
writeByte(value & 0x7F);
}
int readVarIntNoZigZag() {
int result = 0;
int shift = 0;
int byte;
do {
byte = readByte();
result |= (byte & 0x7F) << shift;
if ((byte & 0x80) == 0) {
break;
}
shift += 7;
} while (true);
return result;
}
void writeShort(int value) {
_ensureCapacity(2);
_byteBuffer.buffer.asByteData().setInt16(_position, value, Endian.big);
_position += 2;
}
int readShort() {
final value =
_byteBuffer.buffer.asByteData().getInt16(_position, Endian.big);
_position += 2;
return value;
}
void writeFloat(double value) {
_ensureCapacity(4);
// Round the float to 8 decimal places before writing
value = double.parse(value.toStringAsFixed(8));
_byteBuffer.buffer.asByteData().setFloat32(_position, value, Endian.big);
_position += 4;
}
double readFloat() {
final value =
_byteBuffer.buffer.asByteData().getFloat32(_position, Endian.big);
_position += 4;
// Round the float to 8 decimal places after reading
return double.parse(value.toStringAsFixed(8));
}
void writeTagName(String name) {
final encodedName = utf8.encode(name);
writeShort(encodedName.length);
_ensureCapacity(encodedName.length);
_byteBuffer.setAll(_position, encodedName);
_position += encodedName.length;
}
String readTagName() {
final length = readShort();
final encodedName = _byteBuffer.sublist(_position, _position + length);
_position += length;
return utf8.decode(encodedName);
}
void resetPosition() {
_position = 0;
}
void clear() {
resetPosition();
_byteBuffer = Uint8List(0);
}
Future<void> writeToFile(String filePath) async {
final file = File(filePath);
if (file.existsSync())
file.deleteSync(); // Ensure we flush the file to 0 bytes
await file.writeAsBytes(bytes);
}
Future<void> readFromFile(String filePath) async {
final file = File(filePath);
final exists = await file.exists();
if (!exists) {
print('File does not exist.');
return;
}
_byteBuffer = await file.readAsBytes();
resetPosition();
}
Future<void> compress() async {
final gzip = GZipCodec();
final compressedData = gzip.encode(_byteBuffer);
_byteBuffer = Uint8List.fromList(compressedData);
_position = _byteBuffer.length;
}
Future<void> decompress() async {
final gzip = GZipCodec();
final decompressedData = gzip.decode(_byteBuffer);
_byteBuffer = Uint8List.fromList(decompressedData);
_position = _byteBuffer.length;
}
void writeLong(int value) {
_ensureCapacity(8);
_byteBuffer.buffer.asByteData().setInt64(_position, value, Endian.big);
_position += 8;
}
void writeUnsignedLong(int value) {
_ensureCapacity(8);
_byteBuffer.buffer.asByteData().setUint64(_position, value, Endian.big);
_position += 8;
}
int readLong() {
final value =
_byteBuffer.buffer.asByteData().getInt64(_position, Endian.big);
_position += 8;
return value;
}
int readUnsignedLong() {
final value =
_byteBuffer.buffer.asByteData().getUint64(_position, Endian.big);
_position += 8;
return value;
}
void writeVarLongNoZigZag(int value) {
while (true) {
if ((value & ~0x7F) == 0) {
writeByte(value);
return;
}
writeByte((value & 0x7F) | 0x80);
value = value >> 7;
}
}
void writeVarLongZigZag(int value) {
value = (value << 1) ^ (value >> 63);
writeVarLongNoZigZag(value);
}
void writeLongZigZag(int value) {
value = (value << 1) & (value >> 63);
_byteBuffer.buffer.asByteData().setInt64(_position, value, Endian.big);
}
int readVarLongNoZigZag() {
int result = 0;
int shift = 0;
int b;
do {
b = readByte();
result |= (b & 0x7F) << shift;
shift += 7;
} while ((b & 0x80) != 0);
return result;
}
int readVarLongZigZag() {
int result = readVarLongNoZigZag();
return (result >> 1) ^ -(result & 1);
}
int readLongZigZag() {
int value = readLong();
return (value >> 1) ^ (-(value & 1));
}
void writeBytes(Iterable<int> bytes) {
for (int byte in bytes) {
writeUnsignedByte(byte);
}
}
List<int> readBytes(int num) {
List<int> lst = [];
for (int i = 0; i < num; i++) {
lst.add(readUnsignedByte());
}
return lst;
}
void setBit(int position, int maskToSet) {
if (position < _byteBuffer.length) {
// Set the value now
seek(position);
int current = readUnsignedByte();
seek(position);
current |= maskToSet;
writeUnsignedByte(current);
}
}
void clearBit(int position, int maskToClear) {
if (position < _byteBuffer.length) {
// Lets clear the bit
seek(position);
int current = readUnsignedByte();
current = current & ~maskToClear;
seek(position);
writeUnsignedByte(current);
}
}
bool checkBit(int position, int mask) {
if (position < _byteBuffer.length) {
seek(position);
int current = readUnsignedByte();
return (current & mask) == mask;
} else {
return false;
}
}
int getBit(int position) {
if (position < _byteBuffer.length) {
seek(position);
return readUnsignedByte();
} else {
return 0;
}
}
void seek(int position) {
_position = 0;
_ensureCapacity(position);
_position = position;
}
/// Unsets a mask, then sets a mask
void unsetSetBit(int position, int maskToClear, int maskToSet) {
clearBit(position, maskToClear);
setBit(position, maskToSet);
}
void insertRandomBytes(int count) {
Random rng = Random();
for (int a = 0; a < count; a++) {
writeByte(rng.nextInt(255));
}
}
}
class StringBuilder {
String _buffer = "";
StringBuilder();
bool get isEmpty => _buffer.isEmpty;
void append(String value) {
_buffer += value;
}
void clear() {
_buffer = "";
}
@override
String toString() {
return "${_buffer}";
}
}
class StringReader {
final String _buffer;
int _position = 0;
int _lastPostion = 0;
StringReader(this._buffer);
// Check if there's more to read
bool get canRead => _position < _buffer.length;
// Read the next character
String next() {
if (canRead) {
skipWhitespace();
return _buffer[_position++];
} else {
throw Exception("End of buffer reached");
}
}
// Peek the next character without advancing the position
String peek() {
skipWhitespace();
if (canRead) {
return _buffer[_position];
} else {
throw Exception("End of buffer reached");
}
}
// Skip any whitespace characters
void skipWhitespace() {
while (canRead && isWhitespace(_buffer[_position])) {
_position++;
}
}
// Check if a character is a whitespace
bool isWhitespace(String char) {
return char.trim().isEmpty;
}
// Read until a specific character is found
String readUntil(String stopChar) {
StringBuffer result = StringBuffer();
while (canRead && peek() != stopChar) {
result.write(next());
}
return result.toString();
}
// Read a string enclosed in double quotes
String readQuotedString() {
if (next() != '"') {
throw Exception('Expected double quotes at the start of a string');
}
StringBuffer result = StringBuffer();
while (canRead) {
String char = next();
if (char == '"') {
break;
}
result.write(char);
}
return result.toString();
}
// Read a number (int or double)
String readNumber() {
StringBuffer result = StringBuffer();
while (canRead && (isDigit(peek()) || peek() == '.' || peek() == '-')) {
result.write(next());
}
return result.toString();
}
// Check if a character is a digit
bool isDigit(String char) {
return int.tryParse(char) != null;
}
// Read an unquoted string (used for keys in SNBT)
String readUnquotedString() {
StringBuffer result = StringBuffer();
while (canRead &&
!isWhitespace(peek()) &&
peek() != ':' &&
peek() != ',' &&
peek() != '{' &&
peek() != '}' &&
peek() != '[' &&
peek() != ']') {
result.write(next());
}
return result.toString();
}
String readString() {
if (peek() == "\"") {
return readQuotedString();
} else
return readUnquotedString();
}
// Read a specific character and throw an exception if it's not found
void expect(String expectedChar) {
if (next().toLowerCase() != expectedChar.toLowerCase()) {
throw Exception('Expected $expectedChar');
}
}
void startSeek() {
_lastPostion = _position;
}
void endSeek() {
_position = _lastPostion;
_lastPostion = 0;
}
}