Fix #6, testsuite implemented.

This commit is contained in:
zontreck 2024-05-06 01:16:08 -07:00
parent 270302bb4b
commit b359400c83
16 changed files with 268 additions and 3 deletions

View file

@ -155,16 +155,20 @@ class ByteLayer {
void writeFloat(double value) { void writeFloat(double value) {
_ensureCapacity(4); _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); _byteBuffer.buffer.asByteData().setFloat32(_position, value, Endian.big);
_position += 2; _position += 4;
} }
double readFloat() { double readFloat() {
final value = final value =
_byteBuffer.buffer.asByteData().getFloat32(_position, Endian.big); _byteBuffer.buffer.asByteData().getFloat32(_position, Endian.big);
_position += 2; _position += 4;
return value;
// Round the float to 8 decimal places after reading
return double.parse(value.toStringAsFixed(8));
} }
void writeTagName(String name) { void writeTagName(String name) {
@ -234,4 +238,49 @@ class ByteLayer {
_position += 8; _position += 8;
return value; 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));
}
} }

View file

@ -57,6 +57,10 @@ abstract class Tag {
return (_key == null ? "" : _key!); return (_key == null ? "" : _key!);
} }
void setKey(String key) {
_key = key;
}
static Tag readNamedTag(ByteLayer data) { static Tag readNamedTag(ByteLayer data) {
var type = data.readByte(); var type = data.readByte();
if (type == 0) { if (type == 0) {
@ -227,4 +231,61 @@ abstract class Tag {
return ""; 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--;
}
} }

View file

@ -34,4 +34,16 @@ class ByteArrayTag extends Tag {
TagType getTagType() { TagType getTagType() {
return TagType.ByteArray; 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}]");
}
} }

View file

@ -28,4 +28,10 @@ class ByteTag extends Tag {
TagType getTagType() { TagType getTagType() {
return TagType.Byte; return TagType.Byte;
} }
@override
void prettyPrint(int indent, bool recurse) {
print(
"${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: ${value}");
}
} }

View file

@ -10,13 +10,24 @@ class CompoundTag extends Tag {
void readValue(ByteLayer data) { void readValue(ByteLayer data) {
value.clear(); value.clear();
NBTAccountant.visitTag();
NBTAccountant.printRead(this);
while (true) { while (true) {
Tag tag = Tag.readNamedTag(data); Tag tag = Tag.readNamedTag(data);
if (tag.getType() == 0) { if (tag.getType() == 0) {
NBTAccountant.leaveTag(this);
return; return;
} }
put(tag.getKey(), tag); 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) { void put(String name, Tag tag) {
value[name] = tag; value[name] = tag;
tag.setKey(name);
} }
bool contains(String name) { bool contains(String name) {
@ -57,4 +69,20 @@ class CompoundTag extends Tag {
TagType getTagType() { TagType getTagType() {
return TagType.Compound; 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')}}");
}
} }

View file

@ -28,4 +28,10 @@ class DoubleTag extends Tag {
TagType getTagType() { TagType getTagType() {
return TagType.Double; return TagType.Double;
} }
@override
void prettyPrint(int indent, bool recurse) {
print(
"${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: ${value}");
}
} }

View file

@ -14,4 +14,9 @@ class EndTag extends Tag {
TagType getTagType() { TagType getTagType() {
return TagType.End; return TagType.End;
} }
@override
void prettyPrint(int indent, bool recurse) {
print("${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}");
}
} }

View file

@ -27,4 +27,10 @@ class FloatTag extends Tag {
TagType getTagType() { TagType getTagType() {
return TagType.Float; return TagType.Float;
} }
@override
void prettyPrint(int indent, bool recurse) {
print(
"${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: ${value}");
}
} }

View file

@ -29,4 +29,16 @@ class IntArrayTag extends Tag {
TagType getTagType() { TagType getTagType() {
return TagType.IntArray; 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}]");
}
} }

View file

@ -27,4 +27,10 @@ class IntTag extends Tag {
TagType getTagType() { TagType getTagType() {
return TagType.Int; return TagType.Int;
} }
@override
void prettyPrint(int indent, bool recurse) {
print(
"${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: ${value}");
}
} }

View file

@ -62,4 +62,18 @@ class ListTag extends Tag {
int size() { int size() {
return value.length; 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')}]");
}
} }

View file

@ -37,4 +37,16 @@ class LongArrayTag extends Tag {
TagType getTagType() { TagType getTagType() {
return TagType.LongArray; 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}]");
}
} }

View file

@ -27,4 +27,10 @@ class LongTag extends Tag {
TagType getTagType() { TagType getTagType() {
return TagType.Long; return TagType.Long;
} }
@override
void prettyPrint(int indent, bool recurse) {
print(
"${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: ${value}");
}
} }

View file

@ -27,4 +27,10 @@ class ShortTag extends Tag {
TagType getTagType() { TagType getTagType() {
return TagType.Short; return TagType.Short;
} }
@override
void prettyPrint(int indent, bool recurse) {
print(
"${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: ${value}");
}
} }

View file

@ -27,4 +27,10 @@ class StringTag extends Tag {
TagType getTagType() { TagType getTagType() {
return TagType.String; return TagType.String;
} }
@override
void prettyPrint(int indent, bool recurse) {
print(
"${"".padLeft(indent, '\t')}${Tag.getCanonicalName(getTagType())}: ${value}");
}
} }

View file

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:libac_flutter/nbt/NbtIo.dart'; import 'package:libac_flutter/nbt/NbtIo.dart';
import 'package:libac_flutter/nbt/impl/CompoundTag.dart'; import 'package:libac_flutter/nbt/impl/CompoundTag.dart';
import 'package:libac_flutter/nbt/impl/StringTag.dart';
void main() { void main() {
test('read non-compressed helloworld NBT', () async { test('read non-compressed helloworld NBT', () async {
@ -14,4 +15,33 @@ void main() {
expect(tag.get("name")!.asString(), "Bananrama"); 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);
});
} }