Converted DataContract members to ISerializable interface for finer control

This commit is contained in:
ForeverZer0 2021-08-24 20:31:13 -04:00
parent 4aa2959e7e
commit 22aef3be81
21 changed files with 149 additions and 38 deletions

View File

@ -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));
}
}
}

View File

@ -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<CompoundTag>();
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<CompoundTag>();
var compound = TestHelper.GetTag("bigtest.nbt", CompressionType.GZip);
output.WriteLine(compound.PrettyPrinted());
}

View File

@ -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<CompoundTag>();
}
}
}

View File

@ -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();
/// <summary>
/// Reads a 64-bit signed (big-endian) integer from the stream, converting to native endian when necessary.

View File

@ -12,7 +12,7 @@ namespace SharpNBT
/// While this class uses the CLS compliant <see cref="byte"/> (0..255), the NBT specification uses a signed value with a range of -128..127, so ensure
/// the bits are equivalent for your values.
/// </remarks>
[PublicAPI][DataContract(Name = "byte_array")]
[PublicAPI][Serializable]
public class ByteArrayTag : EnumerableTag<byte>
{
/// <summary>

View File

@ -12,7 +12,7 @@ namespace SharpNBT
/// recommended to use the <see cref="SignedValue"/> property if your language supports a signed 8-bit value, otherwise simply ensure the bits are
/// equivalent.
/// </remarks>
[PublicAPI][DataContract(Name = "byte")]
[PublicAPI][Serializable]
public class ByteTag : Tag<byte>
{
/// <summary>

View File

@ -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 <see cref="ListTag"/> class define the structure of the NBT format. Children are not order-dependent, nor is order guaranteed. The
/// closing <see cref="EndTag"/> does not require to be explicitly added, it will be added automatically during serialization.
/// </remarks>
[PublicAPI][DataContract(Name = "compound")]
[PublicAPI][Serializable]
public class CompoundTag : TagContainer
{
/// <summary>

View File

@ -1,3 +1,4 @@
using System;
using System.Runtime.Serialization;
using JetBrains.Annotations;
@ -6,7 +7,7 @@ namespace SharpNBT
/// <summary>
/// A tag that contains a single IEEE-754 double-precision floating point number.
/// </summary>
[PublicAPI][DataContract(Name = "double")]
[PublicAPI][Serializable]
public class DoubleTag : Tag<double>
{
/// <summary>

View File

@ -7,7 +7,7 @@ namespace SharpNBT
/// <summary>
/// Represents the end of <see cref="CompoundTag"/>.
/// </summary>
[PublicAPI][DataContract(Name = "end")]
[PublicAPI]
public class EndTag : Tag
{
/// <summary>

View File

@ -12,13 +12,12 @@ namespace SharpNBT
/// Base class for tags that contain a collection of values and can be enumerated.
/// </summary>
/// <typeparam name="T">The type of the item the tag contains.</typeparam>
[PublicAPI][DataContract(Name = "array")]
[PublicAPI][Serializable]
public abstract class EnumerableTag<T> : Tag, IList<T>
{
/// <summary>
/// Internal list implementation.
/// </summary>
[DataMember(Name = "values")]
private readonly List<T> internalList = new List<T>();
/// <summary>
@ -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[])));
}
/// <summary>Populates a <see cref="T:System.Runtime.Serialization.SerializationInfo" /> with the data needed to serialize the target object.</summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> to populate with data.</param>
/// <param name="context">The destination (see <see cref="T:System.Runtime.Serialization.StreamingContext" />) for this serialization.</param>
/// <exception cref="T:System.Security.SecurityException">The caller does not have the required permission.</exception>
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("count", Count);
info.AddValue("values", internalList.ToArray(), typeof(T[]));
}
/// <summary>Returns an enumerator that iterates through the collection.</summary>
/// <returns>An enumerator that can be used to iterate through the collection.</returns>
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.IEnumerable-1.GetEnumerator?view=netcore-5.0">`IEnumerable.GetEnumerator` on docs.microsoft.com</a></footer>

View File

@ -1,3 +1,4 @@
using System;
using System.Runtime.Serialization;
using JetBrains.Annotations;
@ -6,7 +7,7 @@ namespace SharpNBT
/// <summary>
/// A tag that contains a single IEEE-754 single-precision floating point number.
/// </summary>
[PublicAPI][DataContract(Name = "float")]
[PublicAPI][Serializable]
public class FloatTag : Tag<float>
{
/// <summary>

View File

@ -8,7 +8,7 @@ namespace SharpNBT
/// <summary>
/// A tag that whose value is a contiguous sequence of 32-bit integers.
/// </summary>
[PublicAPI][DataContract(Name = "int_array")]
[PublicAPI][Serializable]
public class IntArrayTag : EnumerableTag<int>
{
/// <summary>

View File

@ -7,7 +7,7 @@ namespace SharpNBT
/// <summary>
/// A tag that contains a single 32-bit integer value.
/// </summary>
[PublicAPI][DataContract(Name = "int")]
[PublicAPI][Serializable]
public class IntTag : Tag<int>
{
/// <summary>

View File

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Text;
@ -11,13 +12,12 @@ namespace SharpNBT
/// <remarks>
/// All child tags <b>must</b> be have the same <see cref="Tag.Type"/> value, and their <see cref="Tag.Name"/> value will be omitted during serialization.
/// </remarks>
[PublicAPI][DataContract(Name = "list")]
[PublicAPI][Serializable]
public class ListTag : TagContainer
{
/// <summary>
/// Gets the NBT type of this tag's children.
/// </summary>
[DataMember(IsRequired = true, Name = "child_type", Order = 2)]
public TagType ChildType { get; private set; }
/// <summary>

View File

@ -8,7 +8,7 @@ namespace SharpNBT
/// <summary>
/// A tag that whose value is a contiguous sequence of 64-bit integers.
/// </summary>
[PublicAPI][DataContract(Name = "long_array")]
[PublicAPI][Serializable]
public class LongArrayTag : EnumerableTag<long>
{
/// <summary>

View File

@ -7,7 +7,7 @@ namespace SharpNBT
/// <summary>
/// A tag that contains a single 64-bit integer value.
/// </summary>
[PublicAPI][DataContract(Name = "long")]
[PublicAPI][Serializable]
public class LongTag : Tag<long>
{
/// <summary>

View File

@ -7,7 +7,7 @@ namespace SharpNBT
/// <summary>
/// A tag that contains a single 16-bit integer value.
/// </summary>
[PublicAPI][DataContract(Name = "short")]
[PublicAPI][Serializable]
public class ShortTag : Tag<short>
{
/// <summary>

View File

@ -1,3 +1,4 @@
using System;
using System.Runtime.Serialization;
using JetBrains.Annotations;
@ -6,7 +7,7 @@ namespace SharpNBT
/// <summary>
/// A tag the contains a UTF-8 string.
/// </summary>
[PublicAPI][DataContract(Name = "string")]
[PublicAPI][Serializable]
public class StringTag : Tag<string>
{
/// <summary>

View File

@ -13,8 +13,8 @@ namespace SharpNBT
/// <summary>
/// Abstract base class that all NBT tags inherit from.
/// </summary>
[PublicAPI][DataContract][KnownType("GetKnownTypes")]
public abstract class Tag : IEquatable<Tag>
[PublicAPI][Serializable]
public abstract class Tag : IEquatable<Tag>, ISerializable
{
private static IEnumerable<Type> GetKnownTypes()
{
@ -47,7 +47,6 @@ namespace SharpNBT
/// <summary>
/// Gets a constant describing the NBT type this object represents.
/// </summary>
[DataMember(IsRequired = true, Name = "type", Order = 0)]
public TagType Type { get; private set; }
/// <summary>
@ -59,7 +58,6 @@ namespace SharpNBT
/// <summary>
/// Gets the name assigned to this <see cref="Tag"/>.
/// </summary>
[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");
}
/// <summary>Populates a <see cref="T:System.Runtime.Serialization.SerializationInfo" /> with the data needed to serialize the target object.</summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> to populate with data.</param>
/// <param name="context">The destination (see <see cref="T:System.Runtime.Serialization.StreamingContext" />) for this serialization.</param>
/// <exception cref="T:System.Security.SecurityException">The caller does not have the required permission.</exception>
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 <see cref="Tag"/> types that contain a single primitive value.
/// </summary>
/// <typeparam name="T">The type of the value the tag represents.</typeparam>
[PublicAPI][DataContract]
[PublicAPI][Serializable]
public abstract class Tag<T> : Tag, IEquatable<Tag<T>>
{
/// <summary>
/// Gets or sets the value of the tag.
/// </summary>
[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));
}
/// <summary>Populates a <see cref="T:System.Runtime.Serialization.SerializationInfo" /> with the data needed to serialize the target object.</summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> to populate with data.</param>
/// <param name="context">The destination (see <see cref="T:System.Runtime.Serialization.StreamingContext" />) for this serialization.</param>
/// <exception cref="T:System.Security.SecurityException">The caller does not have the required permission.</exception>
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue("value", Value, typeof(T));
}
/// <summary>
/// Creates a new instance of the <see cref="DoubleTag"/> class with the specified <paramref name="value"/>.

View File

@ -10,7 +10,7 @@ namespace SharpNBT
/// <summary>
/// Base class for tags that contain a collection of other <see cref="Tag"/> objects and can be enumerated.
/// </summary>
[PublicAPI][DataContract]
[PublicAPI][Serializable]
public abstract class TagContainer : EnumerableTag<Tag>
{
protected bool NamedChildren;
@ -34,6 +34,23 @@ namespace SharpNBT
protected TagContainer(TagType type, [CanBeNull] string name, [NotNull][ItemNotNull] IEnumerable<Tag> 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;
}
/// <summary>Populates a <see cref="T:System.Runtime.Serialization.SerializationInfo" /> with the data needed to serialize the target object.</summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> to populate with data.</param>
/// <param name="context">The destination (see <see cref="T:System.Runtime.Serialization.StreamingContext" />) for this serialization.</param>
/// <exception cref="T:System.Security.SecurityException">The caller does not have the required permission.</exception>
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
if (RequiredType.HasValue)
info.AddValue("child_type", RequiredType.Value);
}
/// <summary>Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1" />.</summary>
/// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1" />.</param>

View File

@ -1,3 +1,4 @@
using System;
using JetBrains.Annotations;
namespace SharpNBT
@ -5,7 +6,7 @@ namespace SharpNBT
/// <summary>
/// Strongly-typed numerical constants that are prefixed to tags to denote their type.
/// </summary>
[PublicAPI]
[PublicAPI][Serializable]
public enum TagType : byte
{
/// <summary>