Implemented TagWriter class to support Java, Bedrock file, and Bedrock network specs

This commit is contained in:
ForeverZer0 2021-08-24 09:48:49 -04:00
parent b34702d06c
commit 3c12e34eec
2 changed files with 95 additions and 12 deletions

View File

@ -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<CompoundTag>();
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<CompoundTag>();
output.WriteLine(compound.PrettyPrinted());
}
}
}

View File

@ -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));
}
/// <summary>
@ -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));
}
/// <summary>
@ -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));
}
/// <summary>
@ -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<int>(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<long>(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);
@ -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<T>(EnumerableTag<T> tag)
{
if (UseVarInt)
VarInt.Write(BaseStream, tag.Count, ZigZagEncoding);
else
BaseStream.Write(GetBytes(tag.Count), 0, sizeof(int));
}
}
}