diff --git a/SharpNBT.Tests/ConversionTest.cs b/SharpNBT.Tests/ConversionTest.cs new file mode 100644 index 0000000..5d47860 --- /dev/null +++ b/SharpNBT.Tests/ConversionTest.cs @@ -0,0 +1,22 @@ +using Xunit; +using Xunit.Abstractions; + +namespace SharpNBT.Tests +{ + public class ConversionTest + { + private readonly ITestOutputHelper output; + + public ConversionTest(ITestOutputHelper output) + { + this.output = output; + } + + [Fact] + public void JsonOutput1() + { + var bigtest = TestHelper.GetTag("bigtest.nbt", CompressionType.GZip); + output.WriteLine(bigtest.ToJsonString(true)); + } + } +} \ No newline at end of file diff --git a/SharpNBT.Tests/ParseTest.cs b/SharpNBT.Tests/ParseTest.cs index fb64e6c..362061d 100644 --- a/SharpNBT.Tests/ParseTest.cs +++ b/SharpNBT.Tests/ParseTest.cs @@ -15,28 +15,17 @@ namespace SharpNBT.Tests 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(); + var compound = TestHelper.GetTag("hello_world.nbt", CompressionType.None); 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(); + var compound = TestHelper.GetTag("bigtest.nbt", CompressionType.GZip); output.WriteLine(compound.PrettyPrinted()); } diff --git a/SharpNBT.Tests/TestHelper.cs b/SharpNBT.Tests/TestHelper.cs new file mode 100644 index 0000000..809a86e --- /dev/null +++ b/SharpNBT.Tests/TestHelper.cs @@ -0,0 +1,34 @@ +using System; +using System.IO; +using System.IO.Compression; +using System.Reflection; +using SharpNBT.ZLib; + +namespace SharpNBT.Tests +{ + public class TestHelper + { + public static Stream GetFile(string filename, CompressionType compression) + { + var assembly = Assembly.GetExecutingAssembly(); + var stream = assembly.GetManifestResourceStream($"SharpNBT.Tests.Data.{filename}"); + if (stream is null) + throw new FileNotFoundException(filename); + + return compression switch + { + CompressionType.None => stream, + CompressionType.GZip => new GZipStream(stream, CompressionMode.Decompress), + CompressionType.ZLib => new ZLibStream(stream, CompressionMode.Decompress), + _ => throw new Exception() + }; + } + + public static CompoundTag GetTag(string filename, CompressionType compression) + { + using var stream = GetFile(filename, compression); + using var reader = new TagReader(stream, FormatOptions.Java); + return reader.ReadTag(); + } + } +} \ No newline at end of file diff --git a/SharpNBT/TagReader.cs b/SharpNBT/TagReader.cs index 410ad6f..a02a701 100644 --- a/SharpNBT/TagReader.cs +++ b/SharpNBT/TagReader.cs @@ -423,7 +423,7 @@ namespace SharpNBT return Encoding.UTF8.GetString(utf8); } - private int ReadCount() => UseVarInt ? ReadInt32() : VarInt.Read(BaseStream, ZigZagEncoding); + private int ReadCount() => UseVarInt ? VarInt.Read(BaseStream, ZigZagEncoding) : ReadInt32(); /// /// Reads a 64-bit signed (big-endian) integer from the stream, converting to native endian when necessary. diff --git a/SharpNBT/Tags/ByteArrayTag.cs b/SharpNBT/Tags/ByteArrayTag.cs index 0b068fa..e84cb05 100644 --- a/SharpNBT/Tags/ByteArrayTag.cs +++ b/SharpNBT/Tags/ByteArrayTag.cs @@ -12,7 +12,7 @@ namespace SharpNBT /// While this class uses the CLS compliant (0..255), the NBT specification uses a signed value with a range of -128..127, so ensure /// the bits are equivalent for your values. /// - [PublicAPI][DataContract(Name = "byte_array")] + [PublicAPI][Serializable] public class ByteArrayTag : EnumerableTag { /// diff --git a/SharpNBT/Tags/ByteTag.cs b/SharpNBT/Tags/ByteTag.cs index 24a052b..bceb7fa 100644 --- a/SharpNBT/Tags/ByteTag.cs +++ b/SharpNBT/Tags/ByteTag.cs @@ -12,7 +12,7 @@ namespace SharpNBT /// recommended to use the property if your language supports a signed 8-bit value, otherwise simply ensure the bits are /// equivalent. /// - [PublicAPI][DataContract(Name = "byte")] + [PublicAPI][Serializable] public class ByteTag : Tag { /// diff --git a/SharpNBT/Tags/CompoundTag.cs b/SharpNBT/Tags/CompoundTag.cs index b84541f..796ee13 100644 --- a/SharpNBT/Tags/CompoundTag.cs +++ b/SharpNBT/Tags/CompoundTag.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Runtime.Serialization; using System.Text; @@ -12,7 +13,7 @@ namespace SharpNBT /// This along with the class define the structure of the NBT format. Children are not order-dependent, nor is order guaranteed. The /// closing does not require to be explicitly added, it will be added automatically during serialization. /// - [PublicAPI][DataContract(Name = "compound")] + [PublicAPI][Serializable] public class CompoundTag : TagContainer { /// diff --git a/SharpNBT/Tags/DoubleTag.cs b/SharpNBT/Tags/DoubleTag.cs index 1ed5844..089d5e2 100644 --- a/SharpNBT/Tags/DoubleTag.cs +++ b/SharpNBT/Tags/DoubleTag.cs @@ -1,3 +1,4 @@ +using System; using System.Runtime.Serialization; using JetBrains.Annotations; @@ -6,7 +7,7 @@ namespace SharpNBT /// /// A tag that contains a single IEEE-754 double-precision floating point number. /// - [PublicAPI][DataContract(Name = "double")] + [PublicAPI][Serializable] public class DoubleTag : Tag { /// diff --git a/SharpNBT/Tags/EndTag.cs b/SharpNBT/Tags/EndTag.cs index 98e7592..45842ee 100644 --- a/SharpNBT/Tags/EndTag.cs +++ b/SharpNBT/Tags/EndTag.cs @@ -7,7 +7,7 @@ namespace SharpNBT /// /// Represents the end of . /// - [PublicAPI][DataContract(Name = "end")] + [PublicAPI] public class EndTag : Tag { /// diff --git a/SharpNBT/Tags/EnumerableTag.cs b/SharpNBT/Tags/EnumerableTag.cs index 183c6b0..a1bbd83 100644 --- a/SharpNBT/Tags/EnumerableTag.cs +++ b/SharpNBT/Tags/EnumerableTag.cs @@ -12,13 +12,12 @@ namespace SharpNBT /// Base class for tags that contain a collection of values and can be enumerated. /// /// The type of the item the tag contains. - [PublicAPI][DataContract(Name = "array")] + [PublicAPI][Serializable] public abstract class EnumerableTag : Tag, IList { /// /// Internal list implementation. /// - [DataMember(Name = "values")] private readonly List internalList = new List(); /// @@ -63,6 +62,23 @@ namespace SharpNBT internalList.AddRange(values.ToArray()); } + protected EnumerableTag(SerializationInfo info, StreamingContext context) : base(info, context) + { + var dummy = info.GetInt32("count"); + internalList.AddRange((T[]) info.GetValue("values", typeof(T[]))); + } + + /// Populates a with the data needed to serialize the target object. + /// The to populate with data. + /// The destination (see ) for this serialization. + /// The caller does not have the required permission. + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("count", Count); + info.AddValue("values", internalList.ToArray(), typeof(T[])); + } + /// Returns an enumerator that iterates through the collection. /// An enumerator that can be used to iterate through the collection. /// diff --git a/SharpNBT/Tags/FloatTag.cs b/SharpNBT/Tags/FloatTag.cs index d115a0a..a800993 100644 --- a/SharpNBT/Tags/FloatTag.cs +++ b/SharpNBT/Tags/FloatTag.cs @@ -1,3 +1,4 @@ +using System; using System.Runtime.Serialization; using JetBrains.Annotations; @@ -6,7 +7,7 @@ namespace SharpNBT /// /// A tag that contains a single IEEE-754 single-precision floating point number. /// - [PublicAPI][DataContract(Name = "float")] + [PublicAPI][Serializable] public class FloatTag : Tag { /// diff --git a/SharpNBT/Tags/IntArrayTag.cs b/SharpNBT/Tags/IntArrayTag.cs index 1f9a088..33ffd80 100644 --- a/SharpNBT/Tags/IntArrayTag.cs +++ b/SharpNBT/Tags/IntArrayTag.cs @@ -8,7 +8,7 @@ namespace SharpNBT /// /// A tag that whose value is a contiguous sequence of 32-bit integers. /// - [PublicAPI][DataContract(Name = "int_array")] + [PublicAPI][Serializable] public class IntArrayTag : EnumerableTag { /// diff --git a/SharpNBT/Tags/IntTag.cs b/SharpNBT/Tags/IntTag.cs index 431d186..7ffd5db 100644 --- a/SharpNBT/Tags/IntTag.cs +++ b/SharpNBT/Tags/IntTag.cs @@ -7,7 +7,7 @@ namespace SharpNBT /// /// A tag that contains a single 32-bit integer value. /// - [PublicAPI][DataContract(Name = "int")] + [PublicAPI][Serializable] public class IntTag : Tag { /// diff --git a/SharpNBT/Tags/ListTag.cs b/SharpNBT/Tags/ListTag.cs index 65bfa63..e7abc6a 100644 --- a/SharpNBT/Tags/ListTag.cs +++ b/SharpNBT/Tags/ListTag.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Runtime.Serialization; using System.Text; @@ -11,13 +12,12 @@ namespace SharpNBT /// /// All child tags must be have the same value, and their value will be omitted during serialization. /// - [PublicAPI][DataContract(Name = "list")] + [PublicAPI][Serializable] public class ListTag : TagContainer { /// /// Gets the NBT type of this tag's children. /// - [DataMember(IsRequired = true, Name = "child_type", Order = 2)] public TagType ChildType { get; private set; } /// diff --git a/SharpNBT/Tags/LongArrayTag.cs b/SharpNBT/Tags/LongArrayTag.cs index 33f1fcb..9110ad8 100644 --- a/SharpNBT/Tags/LongArrayTag.cs +++ b/SharpNBT/Tags/LongArrayTag.cs @@ -8,7 +8,7 @@ namespace SharpNBT /// /// A tag that whose value is a contiguous sequence of 64-bit integers. /// - [PublicAPI][DataContract(Name = "long_array")] + [PublicAPI][Serializable] public class LongArrayTag : EnumerableTag { /// diff --git a/SharpNBT/Tags/LongTag.cs b/SharpNBT/Tags/LongTag.cs index a538eba..60fe51f 100644 --- a/SharpNBT/Tags/LongTag.cs +++ b/SharpNBT/Tags/LongTag.cs @@ -7,7 +7,7 @@ namespace SharpNBT /// /// A tag that contains a single 64-bit integer value. /// - [PublicAPI][DataContract(Name = "long")] + [PublicAPI][Serializable] public class LongTag : Tag { /// diff --git a/SharpNBT/Tags/ShortTag.cs b/SharpNBT/Tags/ShortTag.cs index 2d2fec6..426d838 100644 --- a/SharpNBT/Tags/ShortTag.cs +++ b/SharpNBT/Tags/ShortTag.cs @@ -7,7 +7,7 @@ namespace SharpNBT /// /// A tag that contains a single 16-bit integer value. /// - [PublicAPI][DataContract(Name = "short")] + [PublicAPI][Serializable] public class ShortTag : Tag { /// diff --git a/SharpNBT/Tags/StringTag.cs b/SharpNBT/Tags/StringTag.cs index f3ef54e..058535a 100644 --- a/SharpNBT/Tags/StringTag.cs +++ b/SharpNBT/Tags/StringTag.cs @@ -1,3 +1,4 @@ +using System; using System.Runtime.Serialization; using JetBrains.Annotations; @@ -6,7 +7,7 @@ namespace SharpNBT /// /// A tag the contains a UTF-8 string. /// - [PublicAPI][DataContract(Name = "string")] + [PublicAPI][Serializable] public class StringTag : Tag { /// diff --git a/SharpNBT/Tags/Tag.cs b/SharpNBT/Tags/Tag.cs index 52abac0..3577842 100644 --- a/SharpNBT/Tags/Tag.cs +++ b/SharpNBT/Tags/Tag.cs @@ -13,8 +13,8 @@ namespace SharpNBT /// /// Abstract base class that all NBT tags inherit from. /// - [PublicAPI][DataContract][KnownType("GetKnownTypes")] - public abstract class Tag : IEquatable + [PublicAPI][Serializable] + public abstract class Tag : IEquatable, ISerializable { private static IEnumerable GetKnownTypes() { @@ -47,7 +47,6 @@ namespace SharpNBT /// /// Gets a constant describing the NBT type this object represents. /// - [DataMember(IsRequired = true, Name = "type", Order = 0)] public TagType Type { get; private set; } /// @@ -59,7 +58,6 @@ namespace SharpNBT /// /// Gets the name assigned to this . /// - [DataMember(IsRequired = false, EmitDefaultValue = false, Name = "name")] [CanBeNull] public string Name { get; set; } @@ -169,6 +167,22 @@ namespace SharpNBT } } + protected Tag(SerializationInfo info, StreamingContext context) + { + Type = (TagType) info.GetByte("type"); + Name = info.GetString("name"); + } + + /// Populates a with the data needed to serialize the target object. + /// The to populate with data. + /// The destination (see ) for this serialization. + /// The caller does not have the required permission. + public virtual void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("type", (byte) Type); + info.AddValue("name", Name); + } + public static bool operator ==(Tag left, Tag right) => Equals(left, right); public static bool operator !=(Tag left, Tag right) => !Equals(left, right); @@ -178,14 +192,28 @@ namespace SharpNBT /// Abstract base class for types that contain a single primitive value. /// /// The type of the value the tag represents. - [PublicAPI][DataContract] + [PublicAPI][Serializable] public abstract class Tag : Tag, IEquatable> { /// /// Gets or sets the value of the tag. /// - [DataMember(IsRequired = false, Name = "value")] public T Value { get; set; } + + protected Tag(SerializationInfo info, StreamingContext context) : base(info, context) + { + Value = (T)info.GetValue("value", typeof(T)); + } + + /// Populates a with the data needed to serialize the target object. + /// The to populate with data. + /// The destination (see ) for this serialization. + /// The caller does not have the required permission. + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("value", Value, typeof(T)); + } /// /// Creates a new instance of the class with the specified . diff --git a/SharpNBT/Tags/TagContainer.cs b/SharpNBT/Tags/TagContainer.cs index 9e6ec09..5a33389 100644 --- a/SharpNBT/Tags/TagContainer.cs +++ b/SharpNBT/Tags/TagContainer.cs @@ -10,7 +10,7 @@ namespace SharpNBT /// /// Base class for tags that contain a collection of other objects and can be enumerated. /// - [PublicAPI][DataContract] + [PublicAPI][Serializable] public abstract class TagContainer : EnumerableTag { protected bool NamedChildren; @@ -34,6 +34,23 @@ namespace SharpNBT protected TagContainer(TagType type, [CanBeNull] string name, [NotNull][ItemNotNull] IEnumerable values) : base(type, name, values) { } + + protected TagContainer(SerializationInfo info, StreamingContext context) : base(info, context) + { + RequiredType = (TagType?) info.GetValue("child_type", typeof(TagType?)); + NamedChildren = !RequiredType.HasValue; + } + + /// Populates a with the data needed to serialize the target object. + /// The to populate with data. + /// The destination (see ) for this serialization. + /// The caller does not have the required permission. + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + if (RequiredType.HasValue) + info.AddValue("child_type", RequiredType.Value); + } /// Adds an item to the . /// The object to add to the . diff --git a/SharpNBT/Tags/TagType.cs b/SharpNBT/Tags/TagType.cs index ee3c4f5..607e69e 100644 --- a/SharpNBT/Tags/TagType.cs +++ b/SharpNBT/Tags/TagType.cs @@ -1,3 +1,4 @@ +using System; using JetBrains.Annotations; namespace SharpNBT @@ -5,7 +6,7 @@ namespace SharpNBT /// /// Strongly-typed numerical constants that are prefixed to tags to denote their type. /// - [PublicAPI] + [PublicAPI][Serializable] public enum TagType : byte { ///