Removed unneeded classes, reimplemented ListTag
This commit is contained in:
parent
a4ecca89a8
commit
95af348ddc
|
|
@ -1,3 +1,6 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
|
@ -19,5 +22,24 @@ namespace SharpNBT.Tests
|
||||||
{
|
{
|
||||||
output.WriteLine(tag.ToJsonString(true));
|
output.WriteLine(tag.ToJsonString(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public unsafe void PinTest()
|
||||||
|
{
|
||||||
|
const int length = 69;
|
||||||
|
var ary = Enumerable.Range(420, length);
|
||||||
|
var intTag = new IntArrayTag("Foobar", ary);
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
fixed (int* ptr = &intTag.GetPinnableReference())
|
||||||
|
{
|
||||||
|
for (var i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
sb.Append(ptr[i]);
|
||||||
|
sb.Append(',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output.WriteLine(sb.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,6 +8,8 @@
|
||||||
<LangVersion>latestmajor</LangVersion>
|
<LangVersion>latestmajor</LangVersion>
|
||||||
|
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,14 @@ namespace SharpNBT.Tests
|
||||||
output.WriteLine(tag.Stringify(true));
|
output.WriteLine(tag.Stringify(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ParseBugged()
|
||||||
|
{
|
||||||
|
var testString = "{Count:1b,id:\"minecraft:netherite_sword\",tag:{Damage:0,Enchantments:[{id:\"minecraft:looting\",lvl:3s},{id:\"minecraft:smite\",lvl:5s},{id:\"minecraft:sweeping\",lvl:3s}],RepairCost:7,display:{Name:'{\"extra\":[{\"text\":\"我是修改的名字\"}],\"text\":\"\"}'}}}";
|
||||||
|
var tag = StringNbt.Parse(testString);
|
||||||
|
output.WriteLine(tag.PrettyPrinted());
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void ParseSmall()
|
public void ParseSmall()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -21,7 +22,7 @@ public static class NbtFile
|
||||||
/// <param name="options">Bitwise flags to configure how data should be handled for compatibility between different specifications.</param>
|
/// <param name="options">Bitwise flags to configure how data should be handled for compatibility between different specifications.</param>
|
||||||
/// <typeparam name="T">The type of tag to deserialize.</typeparam>
|
/// <typeparam name="T">The type of tag to deserialize.</typeparam>
|
||||||
/// <returns>The deserialized <see cref="Tag"/> instance.</returns>
|
/// <returns>The deserialized <see cref="Tag"/> instance.</returns>
|
||||||
public static T Read<T>(string path, FormatOptions options, CompressionType compression = CompressionType.AutoDetect) where T : TagContainer
|
public static T Read<T>(string path, FormatOptions options, CompressionType compression = CompressionType.AutoDetect) where T : Tag, ICollection<Tag>
|
||||||
{
|
{
|
||||||
using var reader = new TagReader(GetReadStream(path, compression), options);
|
using var reader = new TagReader(GetReadStream(path, compression), options);
|
||||||
return reader.ReadTag<T>();
|
return reader.ReadTag<T>();
|
||||||
|
|
@ -47,7 +48,7 @@ public static class NbtFile
|
||||||
/// <param name="compression">Indicates the compression algorithm used to compress the file.</param>
|
/// <param name="compression">Indicates the compression algorithm used to compress the file.</param>
|
||||||
/// <param name="options">Bitwise flags to configure how data should be handled for compatibility between different specifications.</param>
|
/// <param name="options">Bitwise flags to configure how data should be handled for compatibility between different specifications.</param>
|
||||||
/// <returns>The deserialized <see cref="Tag"/> instance.</returns>
|
/// <returns>The deserialized <see cref="Tag"/> instance.</returns>
|
||||||
public static async Task<T> ReadAsync<T>(string path, FormatOptions options, CompressionType compression = CompressionType.AutoDetect) where T : TagContainer
|
public static async Task<T> ReadAsync<T>(string path, FormatOptions options, CompressionType compression = CompressionType.AutoDetect) where T : Tag, ICollection<Tag>
|
||||||
{
|
{
|
||||||
await using var reader = new TagReader(GetReadStream(path, compression), options);
|
await using var reader = new TagReader(GetReadStream(path, compression), options);
|
||||||
return await reader.ReadTagAsync<T>();
|
return await reader.ReadTagAsync<T>();
|
||||||
|
|
|
||||||
|
|
@ -1,203 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.Serialization;
|
|
||||||
using System.Text;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;
|
|
||||||
|
|
||||||
namespace SharpNBT;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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][Serializable]
|
|
||||||
public abstract class EnumerableTag<T> : Tag, IList<T>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Internal list implementation.
|
|
||||||
/// </summary>
|
|
||||||
[ItemNotNull]
|
|
||||||
private readonly List<T> internalList = new List<T>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="EnumerableTag{T}"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">A constant describing the NBT type for this tag.</param>
|
|
||||||
/// <param name="name">The name of the tag, or <see langword="null"/> if tag has no name.</param>
|
|
||||||
protected EnumerableTag(TagType type, string? name) : base(type, name)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="EnumerableTag{T}"/> with the specified <paramref name="values"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">A constant describing the NBT type for this tag.</param>
|
|
||||||
/// <param name="name">The name of the tag, or <see langword="null"/> if tag has no name.</param>
|
|
||||||
/// <param name="values">A collection of values to include in this tag.</param>
|
|
||||||
protected EnumerableTag(TagType type, string? name, T[] values) : base(type, name)
|
|
||||||
{
|
|
||||||
internalList.AddRange(values);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="EnumerableTag{T}"/> with the specified <paramref name="values"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">A constant describing the NBT type for this tag.</param>
|
|
||||||
/// <param name="name">The name of the tag, or <see langword="null"/> if tag has no name.</param>
|
|
||||||
/// <param name="values">A collection of values to include in this tag.</param>
|
|
||||||
protected EnumerableTag(TagType type, string? name, IEnumerable<T> values) : base(type, name)
|
|
||||||
{
|
|
||||||
internalList.AddRange(values);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="EnumerableTag{T}"/> with the specified <paramref name="values"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">A constant describing the NBT type for this tag.</param>
|
|
||||||
/// <param name="name">The name of the tag, or <see langword="null"/> if tag has no name.</param>
|
|
||||||
/// <param name="values">A collection of values to include in this tag.</param>
|
|
||||||
protected EnumerableTag(TagType type, string? name, ReadOnlySpan<T> values) : base(type, name)
|
|
||||||
{
|
|
||||||
internalList.AddRange(values.ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Required constructor for ISerializable implementation.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> to describing this instance.</param>
|
|
||||||
/// <param name="context">The destination (see <see cref="T:System.Runtime.Serialization.StreamingContext" />) for this serialization.</param>
|
|
||||||
protected EnumerableTag(SerializationInfo info, StreamingContext context) : base(info, context)
|
|
||||||
{
|
|
||||||
var dummy = info.GetInt32("count");
|
|
||||||
var obj = info.GetValue("values", typeof(T[])) as T[];
|
|
||||||
if (obj is IEnumerable<T> e)
|
|
||||||
internalList.AddRange(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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>
|
|
||||||
public IEnumerator<T> GetEnumerator() => internalList.GetEnumerator();
|
|
||||||
|
|
||||||
/// <summary>Returns an enumerator that iterates through a collection.</summary>
|
|
||||||
/// <returns>An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.</returns>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.IEnumerable.GetEnumerator?view=netcore-5.0">`IEnumerable.GetEnumerator` on docs.microsoft.com</a></footer>
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)internalList).GetEnumerator();
|
|
||||||
|
|
||||||
/// <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>
|
|
||||||
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only.</exception>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.ICollection-1.Add?view=netcore-5.0">`ICollection.Add` on docs.microsoft.com</a></footer>
|
|
||||||
[SuppressMessage("ReSharper", "AnnotationConflictInHierarchy")]
|
|
||||||
public virtual void Add(T item) => internalList.Add(item);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the elements of the specified collection to the <see cref="EnumerableTag{T}"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="items">A collection containing the items to add.</param>
|
|
||||||
public void AddRange([ItemNotNull] IEnumerable<T> items)
|
|
||||||
{
|
|
||||||
foreach (var item in items)
|
|
||||||
Add(item!);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Inserts an item to the <see cref="T:System.Collections.Generic.IList`1" /> at the specified index.</summary>
|
|
||||||
/// <param name="index">The zero-based index at which <paramref name="item" /> should be inserted.</param>
|
|
||||||
/// <param name="item">The object to insert into the <see cref="T:System.Collections.Generic.IList`1" />.</param>
|
|
||||||
/// <exception cref="T:System.ArgumentOutOfRangeException">
|
|
||||||
/// <paramref name="index" /> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1" />.</exception>
|
|
||||||
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IList`1" /> is read-only.</exception>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.IList-1.Insert?view=netcore-5.0">`IList.Insert` on docs.microsoft.com</a></footer>
|
|
||||||
[SuppressMessage("ReSharper", "AnnotationConflictInHierarchy")]
|
|
||||||
public virtual void Insert(int index, T item) => internalList.Insert(index, item);
|
|
||||||
|
|
||||||
/// <summary>Gets or sets the element at the specified index.</summary>
|
|
||||||
/// <param name="index">The zero-based index of the element to get or set.</param>
|
|
||||||
/// <exception cref="T:System.ArgumentOutOfRangeException">
|
|
||||||
/// <paramref name="index" /> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1" />.</exception>
|
|
||||||
/// <exception cref="T:System.NotSupportedException">The property is set and the <see cref="T:System.Collections.Generic.IList`1" /> is read-only.</exception>
|
|
||||||
/// <returns>The element at the specified index.</returns>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.IList-1.Item?view=netcore-5.0">`IList.Item` on docs.microsoft.com</a></footer>
|
|
||||||
public virtual T this[int index]
|
|
||||||
{
|
|
||||||
get => internalList[index];
|
|
||||||
set => internalList[index] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1" />.</summary>
|
|
||||||
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only.</exception>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.ICollection-1.Clear?view=netcore-5.0">`ICollection.Clear` on docs.microsoft.com</a></footer>
|
|
||||||
public virtual void Clear() => internalList.Clear();
|
|
||||||
|
|
||||||
/// <summary>Determines whether the <see cref="T:System.Collections.Generic.ICollection`1" /> contains a specific value.</summary>
|
|
||||||
/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1" />.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// <see langword="true" /> if <paramref name="item" /> is found in the <see cref="T:System.Collections.Generic.ICollection`1" />; otherwise, <see langword="false" />.</returns>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.ICollection-1.Contains?view=netcore-5.0">`ICollection.Contains` on docs.microsoft.com</a></footer>
|
|
||||||
public bool Contains(T item) => internalList.Contains(item);
|
|
||||||
|
|
||||||
/// <summary>Copies the elements of the <see cref="T:System.Collections.Generic.ICollection`1" /> to an <see cref="T:System.Array" />, starting at a particular <see cref="T:System.Array" /> index.</summary>
|
|
||||||
/// <param name="array">The one-dimensional <see cref="T:System.Array" /> that is the destination of the elements copied from <see cref="T:System.Collections.Generic.ICollection`1" />. The <see cref="T:System.Array" /> must have zero-based indexing.</param>
|
|
||||||
/// <param name="arrayIndex">The zero-based index in <paramref name="array" /> at which copying begins.</param>
|
|
||||||
/// <exception cref="T:System.ArgumentNullException">
|
|
||||||
/// <paramref name="array" /> is <see langword="null" />.</exception>
|
|
||||||
/// <exception cref="T:System.ArgumentOutOfRangeException">
|
|
||||||
/// <paramref name="arrayIndex" /> is less than 0.</exception>
|
|
||||||
/// <exception cref="T:System.ArgumentException">The number of elements in the source <see cref="T:System.Collections.Generic.ICollection`1" /> is greater than the available space from <paramref name="arrayIndex" /> to the end of the destination <paramref name="array" />.</exception>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.ICollection-1.CopyTo?view=netcore-5.0">`ICollection.CopyTo` on docs.microsoft.com</a></footer>
|
|
||||||
public void CopyTo(T[] array, int arrayIndex) => internalList.CopyTo(array, arrayIndex);
|
|
||||||
|
|
||||||
/// <summary>Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1" />.</summary>
|
|
||||||
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1" />.</param>
|
|
||||||
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only.</exception>
|
|
||||||
/// <returns>
|
|
||||||
/// <see langword="true" /> if <paramref name="item" /> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1" />; otherwise, <see langword="false" />. This method also returns <see langword="false" /> if <paramref name="item" /> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1" />.</returns>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.ICollection-1.Remove?view=netcore-5.0">`ICollection.Remove` on docs.microsoft.com</a></footer>
|
|
||||||
public virtual bool Remove(T item) => internalList.Remove(item);
|
|
||||||
|
|
||||||
/// <summary>Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1" />.</summary>
|
|
||||||
/// <returns>The number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1" />.</returns>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.ICollection-1.Count?view=netcore-5.0">`ICollection.Count` on docs.microsoft.com</a></footer>
|
|
||||||
public int Count => internalList.Count;
|
|
||||||
|
|
||||||
/// <summary>Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only.</summary>
|
|
||||||
/// <returns>
|
|
||||||
/// <see langword="true" /> if the <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only; otherwise, <see langword="false" />.</returns>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.ICollection-1.IsReadOnly?view=netcore-5.0">`ICollection.IsReadOnly` on docs.microsoft.com</a></footer>
|
|
||||||
public bool IsReadOnly => false;
|
|
||||||
|
|
||||||
/// <summary>Determines the index of a specific item in the <see cref="T:System.Collections.Generic.IList`1" />.</summary>
|
|
||||||
/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.IList`1" />.</param>
|
|
||||||
/// <returns>The index of <paramref name="item" /> if found in the list; otherwise, -1.</returns>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.IList-1.IndexOf?view=netcore-5.0">`IList.IndexOf` on docs.microsoft.com</a></footer>
|
|
||||||
public int IndexOf(T item) => internalList.IndexOf(item);
|
|
||||||
|
|
||||||
/// <summary>Removes the <see cref="T:System.Collections.Generic.IList`1" /> item at the specified index.</summary>
|
|
||||||
/// <param name="index">The zero-based index of the item to remove.</param>
|
|
||||||
/// <exception cref="T:System.ArgumentOutOfRangeException">
|
|
||||||
/// <paramref name="index" /> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1" />.</exception>
|
|
||||||
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IList`1" /> is read-only.</exception>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.IList-1.RemoveAt?view=netcore-5.0">`IList.RemoveAt` on docs.microsoft.com</a></footer>
|
|
||||||
public virtual void RemoveAt(int index) => internalList.RemoveAt(index);
|
|
||||||
|
|
||||||
/// <inheritdoc cref="Tag.PrettyPrinted(StringBuilder,int,string)"/>
|
|
||||||
protected internal override void PrettyPrinted(StringBuilder buffer, int level, string indent)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < level; i++)
|
|
||||||
buffer.Append(indent);
|
|
||||||
buffer.AppendLine(ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|
@ -13,7 +15,7 @@ namespace SharpNBT;
|
||||||
/// 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.
|
/// 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>
|
/// </remarks>
|
||||||
[PublicAPI][Serializable]
|
[PublicAPI][Serializable]
|
||||||
public class ListTag : TagContainer
|
public class ListTag : Tag, IList<Tag>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the NBT type of this tag's children.
|
/// Gets the NBT type of this tag's children.
|
||||||
|
|
@ -27,9 +29,20 @@ public class ListTag : TagContainer
|
||||||
/// <param name="childType">A constant describing the NBT type for children in this tag.</param>
|
/// <param name="childType">A constant describing the NBT type for children in this tag.</param>
|
||||||
public ListTag(string? name, TagType childType) : base(TagType.List, name)
|
public ListTag(string? name, TagType childType) : base(TagType.List, name)
|
||||||
{
|
{
|
||||||
RequiredType = childType;
|
|
||||||
NamedChildren = false;
|
|
||||||
ChildType = childType;
|
ChildType = childType;
|
||||||
|
list = new List<Tag>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of the <see cref="ListTag"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the tag, or <see langword="null"/> if tag has no name.</param>
|
||||||
|
/// <param name="childType">A constant describing the NBT type for children in this tag.</param>
|
||||||
|
/// <param name="capacity">The initial capacity of the list.</param>
|
||||||
|
public ListTag(string? name, TagType childType, int capacity) : base(TagType.List, name)
|
||||||
|
{
|
||||||
|
ChildType = childType;
|
||||||
|
list = new List<Tag>(capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -40,7 +53,8 @@ public class ListTag : TagContainer
|
||||||
/// <param name="children">A collection of values to include in this tag.</param>
|
/// <param name="children">A collection of values to include in this tag.</param>
|
||||||
public ListTag(string? name, TagType childType, IEnumerable<Tag> children) : this(name, childType)
|
public ListTag(string? name, TagType childType, IEnumerable<Tag> children) : this(name, childType)
|
||||||
{
|
{
|
||||||
AddRange(children);
|
foreach (var item in children)
|
||||||
|
list.Add(AssertType(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -50,15 +64,98 @@ public class ListTag : TagContainer
|
||||||
/// <param name="context">The destination (see <see cref="T:System.Runtime.Serialization.StreamingContext" />) for this serialization.</param>
|
/// <param name="context">The destination (see <see cref="T:System.Runtime.Serialization.StreamingContext" />) for this serialization.</param>
|
||||||
protected ListTag(SerializationInfo info, StreamingContext context) : base(info, context)
|
protected ListTag(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||||
{
|
{
|
||||||
|
ChildType = (TagType)info.GetByte("child_type");
|
||||||
|
var count = info.GetInt32("count");
|
||||||
|
list = new List<Tag>(count);
|
||||||
|
if (info.GetValue("values", typeof(Tag[])) is Tag[] ary)
|
||||||
|
AddRange(ary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||||
|
{
|
||||||
|
base.GetObjectData(info, context);
|
||||||
|
info.AddValue("child_type", (byte) ChildType);
|
||||||
|
info.AddValue("count", list.Count);
|
||||||
|
info.AddValue("values", list.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IEnumerator<Tag> GetEnumerator() => list.GetEnumerator();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => list.GetEnumerator();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Add(Tag item) => list.Add(AssertType(item));
|
||||||
|
|
||||||
|
public void AddRange(IEnumerable<Tag> items)
|
||||||
|
{
|
||||||
|
foreach (var item in items)
|
||||||
|
list.Add(AssertType(item));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Clear() => list.Clear();
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Contains(Tag item) => list.Contains(item);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void CopyTo(Tag[] array, int arrayIndex) => list.CopyTo(array, arrayIndex);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool Remove(Tag item) => list.Remove(item);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int Count => list.Count;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
bool ICollection<Tag>.IsReadOnly => false;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int IndexOf(Tag item) => list.IndexOf(item);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Insert(int index, Tag item) => list.Insert(index, AssertType(item));
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void RemoveAt(int index) => list.RemoveAt(index);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Tag this[int index]
|
||||||
|
{
|
||||||
|
get => list[index];
|
||||||
|
set => list[index] = AssertType(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <inheritdoc cref="object.ToString"/>
|
/// <inheritdoc cref="object.ToString"/>
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
var word = Count == 1 ? Strings.WordEntry : Strings.WordEntries;
|
var word = Count == 1 ? Strings.WordEntry : Strings.WordEntries;
|
||||||
return $"TAG_List({PrettyName}): [{Count} {word}]";
|
return $"TAG_List({PrettyName}): [{Count} {word}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <inheritdoc cref="Tag.PrettyPrinted(StringBuilder,int,string)"/>
|
/// <inheritdoc cref="Tag.PrettyPrinted(StringBuilder,int,string)"/>
|
||||||
protected internal override void PrettyPrinted(StringBuilder buffer, int level, string indent)
|
protected internal override void PrettyPrinted(StringBuilder buffer, int level, string indent)
|
||||||
{
|
{
|
||||||
|
|
@ -100,4 +197,16 @@ public class ListTag : TagContainer
|
||||||
|
|
||||||
return $"{StringifyName}:[{string.Join(',', strings)}]";
|
return $"{StringifyName}:[{string.Join(',', strings)}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private Tag AssertType(Tag tag)
|
||||||
|
{
|
||||||
|
if (tag.Type != ChildType)
|
||||||
|
throw new ArrayTypeMismatchException(Strings.ChildWrongType);
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly List<Tag> list;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -35,8 +35,6 @@ public abstract class Tag : IEquatable<Tag>, ISerializable, ICloneable
|
||||||
typeof(NumericTag<>),
|
typeof(NumericTag<>),
|
||||||
typeof(ArrayTag<>),
|
typeof(ArrayTag<>),
|
||||||
typeof(Tag[]),
|
typeof(Tag[]),
|
||||||
typeof(EnumerableTag<>),
|
|
||||||
typeof(TagContainer),
|
|
||||||
typeof(ByteTag),
|
typeof(ByteTag),
|
||||||
typeof(ShortTag),
|
typeof(ShortTag),
|
||||||
typeof(IntTag),
|
typeof(IntTag),
|
||||||
|
|
|
||||||
|
|
@ -1,173 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.Serialization;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;
|
|
||||||
|
|
||||||
namespace SharpNBT;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Base class for tags that contain a collection of other <see cref="Tag"/> objects and can be enumerated.
|
|
||||||
/// </summary>
|
|
||||||
[PublicAPI][Serializable]
|
|
||||||
public abstract class TagContainer : EnumerableTag<Tag>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A value indicating if children of this container are required to have be named.
|
|
||||||
/// </summary>
|
|
||||||
protected bool NamedChildren;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// When not <see langword="null"/>, indicates that a child must be of a specific type to be added.
|
|
||||||
/// </summary>
|
|
||||||
protected TagType? RequiredType;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="TagContainer"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">A constant describing the NBT type for this tag.</param>
|
|
||||||
/// <param name="name">The name of the tag, or <see langword="null"/> if tag has no name.</param>
|
|
||||||
protected TagContainer(TagType type, string? name) : base(type, name)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="TagContainer"/> with the specified <paramref name="values"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">A constant describing the NBT type for this tag.</param>
|
|
||||||
/// <param name="name">The name of the tag, or <see langword="null"/> if tag has no name.</param>
|
|
||||||
/// <param name="values">A collection of values to include in this tag.</param>
|
|
||||||
protected TagContainer(TagType type, string? name, IEnumerable<Tag> values) : base(type, name, values)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Required constructor for ISerializable implementation.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo" /> to describing this instance.</param>
|
|
||||||
/// <param name="context">The destination (see <see cref="T:System.Runtime.Serialization.StreamingContext" />) for this serialization.</param>
|
|
||||||
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>
|
|
||||||
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only.</exception>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.ICollection-1.Add?view=netcore-5.0">`ICollection.Add` on docs.microsoft.com</a></footer>
|
|
||||||
[SuppressMessage("ReSharper", "AnnotationConflictInHierarchy")]
|
|
||||||
public sealed override void Add(Tag item)
|
|
||||||
{
|
|
||||||
base.Add(AssertConventions(item));
|
|
||||||
item.Parent = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Inserts an item to the <see cref="T:System.Collections.Generic.IList`1" /> at the specified index.</summary>
|
|
||||||
/// <param name="index">The zero-based index at which <paramref name="item" /> should be inserted.</param>
|
|
||||||
/// <param name="item">The object to insert into the <see cref="T:System.Collections.Generic.IList`1" />.</param>
|
|
||||||
/// <exception cref="T:System.ArgumentOutOfRangeException">
|
|
||||||
/// <paramref name="index" /> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1" />.</exception>
|
|
||||||
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IList`1" /> is read-only.</exception>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.IList-1.Insert?view=netcore-5.0">`IList.Insert` on docs.microsoft.com</a></footer>
|
|
||||||
[SuppressMessage("ReSharper", "AnnotationConflictInHierarchy")]
|
|
||||||
public sealed override void Insert(int index, Tag item)
|
|
||||||
{
|
|
||||||
base.Insert(index, AssertConventions(item));
|
|
||||||
item.Parent = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Gets or sets the element at the specified index.</summary>
|
|
||||||
/// <param name="index">The zero-based index of the element to get or set.</param>
|
|
||||||
/// <exception cref="T:System.ArgumentOutOfRangeException">
|
|
||||||
/// <paramref name="index" /> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1" />.</exception>
|
|
||||||
/// <exception cref="T:System.NotSupportedException">The property is set and the <see cref="T:System.Collections.Generic.IList`1" /> is read-only.</exception>
|
|
||||||
/// <returns>The element at the specified index.</returns>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.IList-1.Item?view=netcore-5.0">`IList.Item` on docs.microsoft.com</a></footer>
|
|
||||||
public sealed override Tag this[int index]
|
|
||||||
{
|
|
||||||
get => base[index];
|
|
||||||
set
|
|
||||||
{
|
|
||||||
base[index] = AssertConventions(value);
|
|
||||||
value.Parent = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1" />.</summary>
|
|
||||||
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only.</exception>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.ICollection-1.Clear?view=netcore-5.0">`ICollection.Clear` on docs.microsoft.com</a></footer>
|
|
||||||
public sealed override void Clear()
|
|
||||||
{
|
|
||||||
foreach (var item in this)
|
|
||||||
item.Parent = null;
|
|
||||||
base.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1" />.</summary>
|
|
||||||
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1" />.</param>
|
|
||||||
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1" /> is read-only.</exception>
|
|
||||||
/// <returns>
|
|
||||||
/// <see langword="true" /> if <paramref name="item" /> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1" />; otherwise, <see langword="false" />. This method also returns <see langword="false" /> if <paramref name="item" /> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1" />.</returns>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.ICollection-1.Remove?view=netcore-5.0">`ICollection.Remove` on docs.microsoft.com</a></footer>
|
|
||||||
public sealed override bool Remove(Tag item)
|
|
||||||
{
|
|
||||||
if (item is null || !base.Remove(item))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
item.Parent = null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Removes the <see cref="T:System.Collections.Generic.IList`1" /> item at the specified index.</summary>
|
|
||||||
/// <param name="index">The zero-based index of the item to remove.</param>
|
|
||||||
/// <exception cref="T:System.ArgumentOutOfRangeException">
|
|
||||||
/// <paramref name="index" /> is not a valid index in the <see cref="T:System.Collections.Generic.IList`1" />.</exception>
|
|
||||||
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IList`1" /> is read-only.</exception>
|
|
||||||
/// <footer><a href="https://docs.microsoft.com/en-us/dotnet/api/System.Collections.Generic.IList-1.RemoveAt?view=netcore-5.0">`IList.RemoveAt` on docs.microsoft.com</a></footer>
|
|
||||||
public sealed override void RemoveAt(int index)
|
|
||||||
{
|
|
||||||
this[index].Parent = null;
|
|
||||||
base.RemoveAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Performs routine checks to ensure that the given <paramref name="tag"/> complies with the NBT standard for this collection type.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tag">A <see cref="Tag"/> instance to validate.</param>
|
|
||||||
/// <returns>Returns the <paramref name="tag"/> instance.</returns>
|
|
||||||
/// <exception cref="ArgumentNullException"></exception>
|
|
||||||
/// <exception cref="FormatException"></exception>
|
|
||||||
/// <exception cref="ArrayTypeMismatchException"></exception>
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
protected Tag AssertConventions(Tag? tag)
|
|
||||||
{
|
|
||||||
if (tag is null)
|
|
||||||
throw new ArgumentNullException(nameof(tag), Strings.ChildCannotBeNull);
|
|
||||||
|
|
||||||
switch (NamedChildren)
|
|
||||||
{
|
|
||||||
case true when tag.Name is null:
|
|
||||||
throw new FormatException(Strings.ChildrenMustBeNamed);
|
|
||||||
case false when tag.Name != null:
|
|
||||||
throw new FormatException(Strings.ChildrenMustNotBeNamed);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RequiredType.HasValue && RequiredType.Value != tag.Type)
|
|
||||||
throw new ArrayTypeMismatchException(Strings.ChildWrongType);
|
|
||||||
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue