diff --git a/SharpNBT.Tests/ParseTest.cs b/SharpNBT.Tests/ParseTest.cs new file mode 100644 index 0000000..fb64e6c --- /dev/null +++ b/SharpNBT.Tests/ParseTest.cs @@ -0,0 +1,44 @@ +using System.IO; +using System.IO.Compression; +using System.Reflection; +using Xunit; +using Xunit.Abstractions; + +namespace SharpNBT.Tests +{ + public class ReadWriteTest + { + private readonly ITestOutputHelper output; + + public ReadWriteTest(ITestOutputHelper output) + { + this.output = output; + } + + private static Stream GetFile(string filename) + { + var assembly = Assembly.GetExecutingAssembly(); + return assembly.GetManifestResourceStream($"SharpNBT.Tests.Data.{filename}"); + } + + [Fact] + public void ReadUncompressed() + { + using var stream = GetFile("hello_world.nbt"); + using var reader = new TagReader(stream, FormatOptions.Java); + var compound = reader.ReadTag(); + output.WriteLine(compound.PrettyPrinted()); + } + + [Fact] + public void ReadGZipped() + { + using var stream = GetFile("bigtest.nbt"); + using var gzip = new GZipStream(stream, CompressionMode.Decompress); + using var reader = new TagReader(gzip, FormatOptions.Java); + var compound = reader.ReadTag(); + output.WriteLine(compound.PrettyPrinted()); + } + + } +} \ No newline at end of file diff --git a/SharpNBT/TagWriter.cs b/SharpNBT/TagWriter.cs index 01df401..c06908c 100644 --- a/SharpNBT/TagWriter.cs +++ b/SharpNBT/TagWriter.cs @@ -56,7 +56,10 @@ namespace SharpNBT public virtual void WriteShort(ShortTag tag) { WriteTypeAndName(tag); - BaseStream.Write(GetBytes(tag.Value), 0, sizeof(short)); + if (UseVarInt) + VarInt.Write(BaseStream, tag.Value, ZigZagEncoding); + else + BaseStream.Write(GetBytes(tag.Value), 0, sizeof(short)); } /// @@ -66,7 +69,10 @@ namespace SharpNBT public virtual void WriteInt(IntTag tag) { WriteTypeAndName(tag); - BaseStream.Write(GetBytes(tag.Value), 0, sizeof(int)); + if (UseVarInt) + VarInt.Write(BaseStream, tag.Value, ZigZagEncoding); + else + BaseStream.Write(GetBytes(tag.Value), 0, sizeof(int)); } /// @@ -76,7 +82,10 @@ namespace SharpNBT public virtual void WriteLong(LongTag tag) { WriteTypeAndName(tag); - BaseStream.Write(GetBytes(tag.Value), 0, sizeof(long)); + if (UseVarInt) + VarLong.Write(BaseStream, tag.Value, ZigZagEncoding); + else + BaseStream.Write(GetBytes(tag.Value), 0, sizeof(long)); } /// @@ -116,7 +125,7 @@ namespace SharpNBT public virtual void WriteByteArray(ByteArrayTag tag) { WriteTypeAndName(tag); - BaseStream.Write(GetBytes(tag.Count), 0, sizeof(int)); + WriteCount(tag); BaseStream.Write(tag.ToArray(), 0, tag.Count); } @@ -127,15 +136,21 @@ namespace SharpNBT public virtual void WriteIntArray(IntArrayTag tag) { WriteTypeAndName(tag); - BaseStream.Write(GetBytes(tag.Count), 0, sizeof(int)); + WriteCount(tag); var values = new Span(tag.ToArray()); + if (UseVarInt) + { + // VarInt is effectively always little-endian + foreach (var n in values) + VarInt.Write(BaseStream, n, ZigZagEncoding); + return; + } if (SwapEndian) { for (var i = 0; i < values.Length; i++) values[i] = values[i].SwapEndian(); } - BaseStream.Write(MemoryMarshal.AsBytes(values)); } @@ -147,15 +162,22 @@ namespace SharpNBT { WriteTypeAndName(tag); - BaseStream.Write(GetBytes(tag.Count), 0, sizeof(int)); + WriteCount(tag); var values = new Span(tag.ToArray()); + if (UseVarInt) + { + // VarLong is effectively always little-endian + foreach (var n in values) + VarLong.Write(BaseStream, n, ZigZagEncoding); + return; + } if (SwapEndian) { for (var i = 0; i < values.Length; i++) values[i] = values[i].SwapEndian(); + } - BaseStream.Write(MemoryMarshal.AsBytes(values)); } @@ -167,7 +189,7 @@ namespace SharpNBT { WriteTypeAndName(tag); BaseStream.WriteByte((byte) tag.ChildType); - BaseStream.Write(GetBytes(tag.Count), 0, sizeof(int)); + WriteCount(tag); foreach (var child in tag) WriteTag(child); @@ -281,7 +303,7 @@ namespace SharpNBT if (!leaveOpen) await BaseStream.DisposeAsync(); } - + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteTypeAndName(Tag tag) { @@ -295,14 +317,23 @@ namespace SharpNBT [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteUTF8String(string value) { + // String length prefixes never use ZigZag encoding + if (string.IsNullOrEmpty(value)) { - BaseStream.Write(GetBytes((ushort) 0), 0, sizeof(ushort)); + if (UseVarInt) + VarInt.Write(BaseStream, 0); + else + BaseStream.Write(GetBytes((ushort) 0), 0, sizeof(ushort)); } else { var utf8 = Encoding.UTF8.GetBytes(value); - BaseStream.Write(GetBytes((ushort) utf8.Length), 0, sizeof(ushort)); + if (UseVarInt) + VarInt.Write(BaseStream, utf8.Length); + else + BaseStream.Write(GetBytes((ushort) utf8.Length), 0, sizeof(ushort)); + BaseStream.Write(utf8, 0, utf8.Length); } } @@ -346,5 +377,13 @@ namespace SharpNBT Array.Reverse(bytes); return bytes; } + + private void WriteCount(EnumerableTag tag) + { + if (UseVarInt) + VarInt.Write(BaseStream, tag.Count, ZigZagEncoding); + else + BaseStream.Write(GetBytes(tag.Count), 0, sizeof(int)); + } } } \ No newline at end of file