From b359400c83611d894b22b332ab7d206e670f014e Mon Sep 17 00:00:00 2001 From: zontreck Date: Mon, 6 May 2024 01:16:08 -0700 Subject: [PATCH] Fix #6, testsuite implemented. --- lib/nbt/Stream.dart | 55 ++++++++++++++++++++++++++++-- lib/nbt/Tag.dart | 61 ++++++++++++++++++++++++++++++++++ lib/nbt/impl/ByteArrayTag.dart | 12 +++++++ lib/nbt/impl/ByteTag.dart | 6 ++++ lib/nbt/impl/CompoundTag.dart | 28 ++++++++++++++++ lib/nbt/impl/DoubleTag.dart | 6 ++++ lib/nbt/impl/EndTag.dart | 5 +++ lib/nbt/impl/FloatTag.dart | 6 ++++ lib/nbt/impl/IntArrayTag.dart | 12 +++++++ lib/nbt/impl/IntTag.dart | 6 ++++ lib/nbt/impl/ListTag.dart | 14 ++++++++ lib/nbt/impl/LongArrayTag.dart | 12 +++++++ lib/nbt/impl/LongTag.dart | 6 ++++ lib/nbt/impl/ShortTag.dart | 6 ++++ lib/nbt/impl/StringTag.dart | 6 ++++ test/nbt_test.dart | 30 +++++++++++++++++ 16 files changed, 268 insertions(+), 3 deletions(-) diff --git a/lib/nbt/Stream.dart b/lib/nbt/Stream.dart index b6baf75..0dfacd1 100644 --- a/lib/nbt/Stream.dart +++ b/lib/nbt/Stream.dart @@ -155,16 +155,20 @@ class ByteLayer { 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 += 2; + _position += 4; } double readFloat() { final value = _byteBuffer.buffer.asByteData().getFloat32(_position, Endian.big); - _position += 2; - return value; + _position += 4; + + // Round the float to 8 decimal places after reading + return double.parse(value.toStringAsFixed(8)); } void writeTagName(String name) { @@ -234,4 +238,49 @@ class ByteLayer { _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)); + } } diff --git a/lib/nbt/Tag.dart b/lib/nbt/Tag.dart index 24fb210..aa41423 100644 --- a/lib/nbt/Tag.dart +++ b/lib/nbt/Tag.dart @@ -57,6 +57,10 @@ abstract class Tag { return (_key == null ? "" : _key!); } + void setKey(String key) { + _key = key; + } + static Tag readNamedTag(ByteLayer data) { var type = data.readByte(); if (type == 0) { @@ -227,4 +231,61 @@ abstract class Tag { return ""; } } + + void prettyPrint(int indent, bool recurse); + + static String getCanonicalName(TagType type) { + switch (type) { + case TagType.String: + return "TAG_String"; + case TagType.List: + return "TAG_List"; + case TagType.LongArray: + return "TAG_LongArray"; + case TagType.Long: + return "TAG_Long"; + case TagType.IntArray: + return "TAG_IntArray"; + case TagType.Int: + return "TAG_Int"; + case TagType.Compound: + return "TAG_Compound"; + case TagType.ByteArray: + return "TAG_ByteArray"; + case TagType.Byte: + return "TAG_Byte"; + case TagType.Double: + return "TAG_Double"; + case TagType.Float: + return "TAG_Float"; + case TagType.Short: + return "TAG_Short"; + case TagType.End: + return "TAG_End"; + } + } +} + +class NBTAccountant { + static int _prettyIndex = 0; + static void printRead(Tag tag) { + tag.prettyPrint(_prettyIndex, false); + } + + static void visitTag() { + _prettyIndex++; + } + + static void leaveTag(Tag tag) { + if (tag is CompoundTag || tag is ListTag) { + if (tag is CompoundTag) { + CompoundTag ct = tag as CompoundTag; + ct.endPrettyPrint(_prettyIndex); + } else if (tag is ListTag) { + ListTag lt = tag as ListTag; + lt.endPrettyPrint(_prettyIndex); + } + } + _prettyIndex--; + } } diff --git a/lib/nbt/impl/ByteArrayTag.dart b/lib/nbt/impl/ByteArrayTag.dart index 86cbf40..d3a1852 100644 --- a/lib/nbt/impl/ByteArrayTag.dart +++ b/lib/nbt/impl/ByteArrayTag.dart @@ -34,4 +34,16 @@ class ByteArrayTag extends Tag { TagType getTagType() { return TagType.ByteArray; } + + @override + void prettyPrint(int indent, bool recurse) { + String array = ""; + for (int b in value) { + array += "${b}, "; + } + array = array.substring(0, array.length - 2); + + print( + "${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: [${array}]"); + } } diff --git a/lib/nbt/impl/ByteTag.dart b/lib/nbt/impl/ByteTag.dart index ca6c756..72c17ec 100644 --- a/lib/nbt/impl/ByteTag.dart +++ b/lib/nbt/impl/ByteTag.dart @@ -28,4 +28,10 @@ class ByteTag extends Tag { TagType getTagType() { return TagType.Byte; } + + @override + void prettyPrint(int indent, bool recurse) { + print( + "${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: ${value}"); + } } diff --git a/lib/nbt/impl/CompoundTag.dart b/lib/nbt/impl/CompoundTag.dart index a4a50a0..048ba75 100644 --- a/lib/nbt/impl/CompoundTag.dart +++ b/lib/nbt/impl/CompoundTag.dart @@ -10,13 +10,24 @@ class CompoundTag extends Tag { void readValue(ByteLayer data) { value.clear(); + NBTAccountant.visitTag(); + NBTAccountant.printRead(this); + while (true) { Tag tag = Tag.readNamedTag(data); if (tag.getType() == 0) { + NBTAccountant.leaveTag(this); return; } put(tag.getKey(), tag); + + if (tag.getTagType() != TagType.Compound && + tag.getTagType() != TagType.List) { + NBTAccountant.visitTag(); + NBTAccountant.printRead(tag); + NBTAccountant.leaveTag(tag); + } } } @@ -34,6 +45,7 @@ class CompoundTag extends Tag { void put(String name, Tag tag) { value[name] = tag; + tag.setKey(name); } bool contains(String name) { @@ -57,4 +69,20 @@ class CompoundTag extends Tag { TagType getTagType() { return TagType.Compound; } + + @override + void prettyPrint(int indent, bool recurse) { + print( + "${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: [${value.length} entries]"); + print("${"".padLeft(indent, '\t')}{"); + if (recurse) { + for (Tag tag in value.values) { + tag.prettyPrint(indent + 1, true); + } + } + } + + void endPrettyPrint(int indent) { + print("${"".padLeft(indent, '\t')}}"); + } } diff --git a/lib/nbt/impl/DoubleTag.dart b/lib/nbt/impl/DoubleTag.dart index eaf2195..d45752f 100644 --- a/lib/nbt/impl/DoubleTag.dart +++ b/lib/nbt/impl/DoubleTag.dart @@ -28,4 +28,10 @@ class DoubleTag extends Tag { TagType getTagType() { return TagType.Double; } + + @override + void prettyPrint(int indent, bool recurse) { + print( + "${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: ${value}"); + } } diff --git a/lib/nbt/impl/EndTag.dart b/lib/nbt/impl/EndTag.dart index f5e038f..24b1ab2 100644 --- a/lib/nbt/impl/EndTag.dart +++ b/lib/nbt/impl/EndTag.dart @@ -14,4 +14,9 @@ class EndTag extends Tag { TagType getTagType() { return TagType.End; } + + @override + void prettyPrint(int indent, bool recurse) { + print("${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}"); + } } diff --git a/lib/nbt/impl/FloatTag.dart b/lib/nbt/impl/FloatTag.dart index 450a5ef..a9bd6e0 100644 --- a/lib/nbt/impl/FloatTag.dart +++ b/lib/nbt/impl/FloatTag.dart @@ -27,4 +27,10 @@ class FloatTag extends Tag { TagType getTagType() { return TagType.Float; } + + @override + void prettyPrint(int indent, bool recurse) { + print( + "${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: ${value}"); + } } diff --git a/lib/nbt/impl/IntArrayTag.dart b/lib/nbt/impl/IntArrayTag.dart index e5412e9..4bbcaed 100644 --- a/lib/nbt/impl/IntArrayTag.dart +++ b/lib/nbt/impl/IntArrayTag.dart @@ -29,4 +29,16 @@ class IntArrayTag extends Tag { TagType getTagType() { return TagType.IntArray; } + + @override + void prettyPrint(int indent, bool recurse) { + String array = ""; + for (int b in value) { + array += "${b}, "; + } + array = array.substring(0, array.length - 2); + + print( + "${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: [${array}]"); + } } diff --git a/lib/nbt/impl/IntTag.dart b/lib/nbt/impl/IntTag.dart index 877996e..d2b8805 100644 --- a/lib/nbt/impl/IntTag.dart +++ b/lib/nbt/impl/IntTag.dart @@ -27,4 +27,10 @@ class IntTag extends Tag { TagType getTagType() { return TagType.Int; } + + @override + void prettyPrint(int indent, bool recurse) { + print( + "${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: ${value}"); + } } diff --git a/lib/nbt/impl/ListTag.dart b/lib/nbt/impl/ListTag.dart index e7e1c1e..3b6739d 100644 --- a/lib/nbt/impl/ListTag.dart +++ b/lib/nbt/impl/ListTag.dart @@ -62,4 +62,18 @@ class ListTag extends Tag { int size() { return value.length; } + + @override + void prettyPrint(int indent, bool recurse) { + print( + "${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: [${value.length} entries]"); + print("${"".padLeft(indent, '\t')}["); + for (Tag tag in value) { + tag.prettyPrint(indent + 1, true); + } + } + + void endPrettyPrint(int indent) { + print("${"".padLeft(indent, '\t')}]"); + } } diff --git a/lib/nbt/impl/LongArrayTag.dart b/lib/nbt/impl/LongArrayTag.dart index 5f6bd37..4eebcd2 100644 --- a/lib/nbt/impl/LongArrayTag.dart +++ b/lib/nbt/impl/LongArrayTag.dart @@ -37,4 +37,16 @@ class LongArrayTag extends Tag { TagType getTagType() { return TagType.LongArray; } + + @override + void prettyPrint(int indent, bool recurse) { + String array = ""; + for (int b in value) { + array += "${b}, "; + } + array = array.substring(0, array.length - 2); + + print( + "${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: [${array}]"); + } } diff --git a/lib/nbt/impl/LongTag.dart b/lib/nbt/impl/LongTag.dart index 4a9e5ec..1b04bd0 100644 --- a/lib/nbt/impl/LongTag.dart +++ b/lib/nbt/impl/LongTag.dart @@ -27,4 +27,10 @@ class LongTag extends Tag { TagType getTagType() { return TagType.Long; } + + @override + void prettyPrint(int indent, bool recurse) { + print( + "${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: ${value}"); + } } diff --git a/lib/nbt/impl/ShortTag.dart b/lib/nbt/impl/ShortTag.dart index 1341d72..57ecd1d 100644 --- a/lib/nbt/impl/ShortTag.dart +++ b/lib/nbt/impl/ShortTag.dart @@ -27,4 +27,10 @@ class ShortTag extends Tag { TagType getTagType() { return TagType.Short; } + + @override + void prettyPrint(int indent, bool recurse) { + print( + "${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: ${value}"); + } } diff --git a/lib/nbt/impl/StringTag.dart b/lib/nbt/impl/StringTag.dart index 19f5aa9..ebbc446 100644 --- a/lib/nbt/impl/StringTag.dart +++ b/lib/nbt/impl/StringTag.dart @@ -27,4 +27,10 @@ class StringTag extends Tag { TagType getTagType() { return TagType.String; } + + @override + void prettyPrint(int indent, bool recurse) { + print( + "${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: ${value}"); + } } diff --git a/test/nbt_test.dart b/test/nbt_test.dart index e047433..ca18009 100644 --- a/test/nbt_test.dart +++ b/test/nbt_test.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:libac_flutter/nbt/NbtIo.dart'; import 'package:libac_flutter/nbt/impl/CompoundTag.dart'; +import 'package:libac_flutter/nbt/impl/StringTag.dart'; void main() { test('read non-compressed helloworld NBT', () async { @@ -14,4 +15,33 @@ void main() { expect(tag.get("name")!.asString(), "Bananrama"); }); + + test("write a hello-world NBT", () async { + CompoundTag tag = CompoundTag(); + tag.setKey("hello world"); + tag.put("name", StringTag.valueOf("Bananrama")); + + var path = "${Directory.current.path}/build/hello_world.nbt"; + await NbtIo.write(path, tag); + expect(File(path).existsSync(), true); + }); + + test('read non-compressed self-made helloworld NBT', () async { + print("READING : ${Directory.current.path}/build/hello_world.nbt"); + CompoundTag tag = + await NbtIo.read("${Directory.current.path}/build/hello_world.nbt"); + expect(tag.getKey(), "hello world"); + expect(tag.contains("name"), true); + + expect(tag.get("name")!.asString(), "Bananrama"); + }); + + test('read compressed bigtest.nbt', () async { + var path = "${Directory.current.path}/test/bigtest.nbt"; + CompoundTag tag = await NbtIo.read(path); + expect(tag.getKey(), "Level"); + expect(tag.get("shortTest")!.asShort(), 32767); + expect(tag.get("doubleTest")!.asDouble(), 0.4931287132182315); + expect(tag.get("floatTest")!.asFloat(), 0.49823147); + }); }