754 lines
39 KiB
C#
754 lines
39 KiB
C#
namespace Nbt.Serialization;
|
|
|
|
using System.Globalization;
|
|
using Nbt.Tag;
|
|
|
|
public static class SNbt
|
|
{
|
|
#region Serialize
|
|
|
|
public enum SerializationStyle
|
|
{
|
|
Compact, Spaced, Indented
|
|
}
|
|
|
|
public class SerializerOptions
|
|
{
|
|
public static readonly SerializerOptions Default = new();
|
|
|
|
public SerializationStyle Style { get; init; } = SerializationStyle.Compact;
|
|
public string Indent { get; init; } = " ";
|
|
public bool AlwaysQuoteTagNames { get; init; } = false;
|
|
// public bool AlwaysQuoteStringTags { get; init; } = false;
|
|
}
|
|
|
|
#region Sync
|
|
|
|
public static string Serialize(INbtTag tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
|
|
public static string Serialize(NamedTag tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
|
|
public static string Serialize(INbtList tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
|
|
public static string Serialize(INbtCompound tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
|
|
public static string Serialize(INbtArray tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
|
|
public static string Serialize(INbtValue tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
|
|
public static string Serialize(INbtArray<sbyte> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
|
|
public static string Serialize(INbtArray<int> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
|
|
public static string Serialize(INbtArray<long> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
|
|
public static string Serialize(INbtValue<sbyte> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
|
|
public static string Serialize(INbtValue<short> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
|
|
public static string Serialize(INbtValue<int> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
|
|
public static string Serialize(INbtValue<long> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
|
|
public static string Serialize(INbtValue<float> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
|
|
public static string Serialize(INbtValue<double> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
|
|
public static string Serialize(INbtValue<string> tag, SerializerOptions? options = null) => Serialize(options, serializer => serializer.Serialize(tag));
|
|
|
|
public static void Serialize(TextWriter writer, INbtTag tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(TextWriter writer, NamedTag tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(TextWriter writer, INbtList tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(TextWriter writer, INbtCompound tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(TextWriter writer, INbtArray tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(TextWriter writer, INbtArray<sbyte> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(TextWriter writer, INbtArray<int> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(TextWriter writer, INbtArray<long> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(TextWriter writer, INbtValue<sbyte> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(TextWriter writer, INbtValue<short> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(TextWriter writer, INbtValue<int> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(TextWriter writer, INbtValue<long> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(TextWriter writer, INbtValue<float> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(TextWriter writer, INbtValue<double> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(TextWriter writer, INbtValue<string> tag, SerializerOptions? options = null) => Serialize(writer, options, serializer => serializer.Serialize(tag));
|
|
|
|
public static void Serialize(Stream stream, INbtTag tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(Stream stream, NamedTag tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(Stream stream, INbtList tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(Stream stream, INbtCompound tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(Stream stream, INbtArray tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(Stream stream, INbtValue tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(Stream stream, INbtArray<sbyte> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(Stream stream, INbtArray<int> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(Stream stream, INbtArray<long> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(Stream stream, INbtValue<sbyte> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(Stream stream, INbtValue<short> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(Stream stream, INbtValue<int> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(Stream stream, INbtValue<long> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(Stream stream, INbtValue<float> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(Stream stream, INbtValue<double> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
|
|
public static void Serialize(Stream stream, INbtValue<string> tag, SerializerOptions? options = null) => Serialize(stream, options, serializer => serializer.Serialize(tag));
|
|
|
|
private static void Serialize(TextWriter writer, SerializerOptions? options, Action<Serializer> serialize)
|
|
{
|
|
var serializer = new Serializer(writer, options);
|
|
serialize(serializer);
|
|
}
|
|
|
|
private static void Serialize(Stream stream, SerializerOptions? options, Action<Serializer> serialize)
|
|
{
|
|
using var writer = new StreamWriter(stream, leaveOpen: true);
|
|
Serialize(writer, options, serialize);
|
|
}
|
|
|
|
private static string Serialize(SerializerOptions? options, Action<Serializer> serialize)
|
|
{
|
|
using var writer = new StringWriter();
|
|
Serialize(writer, options, serialize);
|
|
return writer.ToString();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Async
|
|
|
|
public static async ValueTask<string> SerializeAsync(INbtTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask<string> SerializeAsync(NamedTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask<string> SerializeAsync(INbtList tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask<string> SerializeAsync(INbtCompound tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask<string> SerializeAsync(INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask<string> SerializeAsync(INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask<string> SerializeAsync(INbtArray<sbyte> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask<string> SerializeAsync(INbtArray<int> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask<string> SerializeAsync(INbtArray<long> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask<string> SerializeAsync(INbtValue<sbyte> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask<string> SerializeAsync(INbtValue<short> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask<string> SerializeAsync(INbtValue<int> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask<string> SerializeAsync(INbtValue<long> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask<string> SerializeAsync(INbtValue<float> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask<string> SerializeAsync(INbtValue<double> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask<string> SerializeAsync(INbtValue<string> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
|
|
public static async ValueTask SerializeAsync(TextWriter writer, INbtTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(TextWriter writer, NamedTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(TextWriter writer, INbtList tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(TextWriter writer, INbtCompound tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(TextWriter writer, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(TextWriter writer, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(TextWriter writer, INbtArray<sbyte> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(TextWriter writer, INbtArray<int> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(TextWriter writer, INbtArray<long> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(TextWriter writer, INbtValue<sbyte> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(TextWriter writer, INbtValue<short> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(TextWriter writer, INbtValue<int> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(TextWriter writer, INbtValue<long> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(TextWriter writer, INbtValue<float> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(TextWriter writer, INbtValue<double> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(TextWriter writer, INbtValue<string> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(writer, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
|
|
public static async ValueTask SerializeAsync(Stream stream, INbtTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(Stream stream, NamedTag tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(Stream stream, INbtList tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(Stream stream, INbtCompound tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(Stream stream, INbtArray tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(Stream stream, INbtValue tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(Stream stream, INbtArray<sbyte> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(Stream stream, INbtArray<int> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(Stream stream, INbtArray<long> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(Stream stream, INbtValue<sbyte> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(Stream stream, INbtValue<short> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(Stream stream, INbtValue<int> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(Stream stream, INbtValue<long> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(Stream stream, INbtValue<float> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(Stream stream, INbtValue<double> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
public static async ValueTask SerializeAsync(Stream stream, INbtValue<string> tag, SerializerOptions? options = null, CancellationToken ct = default) => await SerializeAsync(stream, options, ct, (serializer, ct) => serializer.SerializeAsync(tag, ct));
|
|
|
|
private static async ValueTask SerializeAsync(TextWriter writer, SerializerOptions? options, CancellationToken ct, Func<Serializer, CancellationToken, ValueTask> serialize)
|
|
{
|
|
var serializer = new Serializer(writer, options);
|
|
await serialize(serializer, ct);
|
|
}
|
|
|
|
private static async ValueTask SerializeAsync(Stream stream, SerializerOptions? options, CancellationToken ct, Func<Serializer, CancellationToken, ValueTask> serialize)
|
|
{
|
|
using var writer = new StreamWriter(stream, leaveOpen: true);
|
|
await SerializeAsync(writer, options, ct, serialize);
|
|
}
|
|
|
|
private static async ValueTask<string> SerializeAsync(SerializerOptions? options, CancellationToken ct, Func<Serializer, CancellationToken, ValueTask> serialize)
|
|
{
|
|
using var writer = new StringWriter();
|
|
await SerializeAsync(writer, options, ct, serialize);
|
|
return writer.ToString();
|
|
}
|
|
|
|
#endregion
|
|
|
|
private sealed class Serializer(TextWriter writer, SerializerOptions? options)
|
|
{
|
|
private readonly TextWriter writer = writer;
|
|
private readonly SerializerOptions options = options ?? SerializerOptions.Default;
|
|
private uint depth = 0u;
|
|
private Context? context = null;
|
|
|
|
#region Sync
|
|
|
|
public void Serialize(INbtTag tag)
|
|
{
|
|
switch (tag)
|
|
{
|
|
case INbtArray arrayTag:
|
|
Serialize(arrayTag);
|
|
break;
|
|
|
|
case INbtValue valueTag:
|
|
Serialize(valueTag);
|
|
break;
|
|
|
|
case INbtList listTag:
|
|
Serialize(listTag);
|
|
break;
|
|
|
|
case INbtCompound compoundTag:
|
|
Serialize(compoundTag);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void Serialize(NamedTag namedTag)
|
|
{
|
|
if (!string.IsNullOrEmpty(namedTag.Name))
|
|
{
|
|
writer.Write(NbtUtils.QuoteString(namedTag.Name, onlyIfNeeded: !options.AlwaysQuoteTagNames));
|
|
writer.Write(':');
|
|
if (options.Style is not SerializationStyle.Compact)
|
|
{
|
|
writer.Write(' ');
|
|
}
|
|
}
|
|
|
|
Serialize(namedTag.Tag);
|
|
}
|
|
|
|
public void Serialize(INbtList tag)
|
|
{
|
|
writer.Write('[');
|
|
|
|
EnterContext(true);
|
|
|
|
foreach (var entry in tag)
|
|
{
|
|
WriteSeparator();
|
|
|
|
Serialize(entry);
|
|
|
|
context!.Length++;
|
|
}
|
|
|
|
ExitContext();
|
|
|
|
writer.Write(']');
|
|
}
|
|
|
|
public void Serialize(INbtCompound tag)
|
|
{
|
|
writer.Write('{');
|
|
|
|
EnterContext(true);
|
|
|
|
foreach (var entry in tag as IEnumerable<NamedTag>)
|
|
{
|
|
WriteSeparator();
|
|
|
|
Serialize(entry);
|
|
|
|
context!.Length++;
|
|
}
|
|
|
|
ExitContext();
|
|
|
|
writer.Write('}');
|
|
}
|
|
|
|
public void Serialize(INbtArray tag)
|
|
{
|
|
switch (tag)
|
|
{
|
|
case INbtArray<sbyte> byteArrayTag:
|
|
Serialize(byteArrayTag);
|
|
break;
|
|
|
|
case INbtArray<int> intArrayTag:
|
|
Serialize(intArrayTag);
|
|
break;
|
|
|
|
case INbtArray<long> longArrayTag:
|
|
Serialize(longArrayTag);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void Serialize(INbtValue valueTag)
|
|
{
|
|
switch (valueTag)
|
|
{
|
|
case INbtValue<sbyte> tag:
|
|
Serialize(tag);
|
|
break;
|
|
|
|
case INbtValue<short> tag:
|
|
Serialize(tag);
|
|
break;
|
|
|
|
case INbtValue<int> tag:
|
|
Serialize(tag);
|
|
break;
|
|
|
|
case INbtValue<long> tag:
|
|
Serialize(tag);
|
|
break;
|
|
|
|
case INbtValue<float> tag:
|
|
Serialize(tag);
|
|
break;
|
|
|
|
case INbtValue<double> tag:
|
|
Serialize(tag);
|
|
break;
|
|
|
|
case INbtValue<string> tag:
|
|
Serialize(tag);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void Serialize(INbtArray<sbyte> tag) => Serialize(tag, 'B', Serialize);
|
|
|
|
public void Serialize(INbtArray<int> tag) => Serialize(tag, 'I', Serialize);
|
|
|
|
public void Serialize(INbtArray<long> tag) => Serialize(tag, 'L', Serialize);
|
|
|
|
public void Serialize(INbtValue<sbyte> tag) => Serialize(tag.Value);
|
|
|
|
public void Serialize(INbtValue<short> tag) => Serialize(tag.Value);
|
|
|
|
public void Serialize(INbtValue<int> tag) => Serialize(tag.Value);
|
|
|
|
public void Serialize(INbtValue<long> tag) => Serialize(tag.Value);
|
|
|
|
public void Serialize(INbtValue<float> tag) => Serialize(tag.Value);
|
|
|
|
public void Serialize(INbtValue<double> tag) => Serialize(tag.Value);
|
|
|
|
public void Serialize(INbtValue<string> tag) => Serialize(tag.Value);
|
|
|
|
private void Serialize<T>(INbtArray<T> tag, char decorator, Action<T> writeValue) where T : notnull
|
|
{
|
|
writer.Write('[');
|
|
writer.Write(decorator);
|
|
writer.Write(';');
|
|
|
|
EnterContext(false);
|
|
|
|
if (tag.Value.Length > 0)
|
|
{
|
|
if (options.Style is not SerializationStyle.Compact)
|
|
{
|
|
writer.Write(' ');
|
|
}
|
|
|
|
foreach (var e in tag)
|
|
{
|
|
WriteSeparator();
|
|
|
|
writeValue(e);
|
|
|
|
context!.Length++;
|
|
}
|
|
}
|
|
|
|
ExitContext();
|
|
|
|
writer.Write(']');
|
|
}
|
|
|
|
private void Serialize(sbyte value)
|
|
{
|
|
writer.Write(value.ToString(CultureInfo.InvariantCulture));
|
|
writer.Write('b');
|
|
}
|
|
|
|
private void Serialize(short value)
|
|
{
|
|
writer.Write(value.ToString(CultureInfo.InvariantCulture));
|
|
writer.Write('s');
|
|
}
|
|
|
|
private void Serialize(int value)
|
|
{
|
|
writer.Write(value.ToString(CultureInfo.InvariantCulture));
|
|
}
|
|
|
|
private void Serialize(long value)
|
|
{
|
|
writer.Write(value.ToString(CultureInfo.InvariantCulture));
|
|
writer.Write('L');
|
|
}
|
|
|
|
private void Serialize(float value)
|
|
{
|
|
writer.Write(value.ToString(CultureInfo.InvariantCulture));
|
|
|
|
if (float.IsFinite(value))
|
|
{
|
|
writer.Write('F');
|
|
}
|
|
}
|
|
|
|
private void Serialize(double value)
|
|
{
|
|
writer.Write(value.ToString(CultureInfo.InvariantCulture));
|
|
|
|
if (double.IsFinite(value))
|
|
{
|
|
writer.Write('D');
|
|
}
|
|
}
|
|
|
|
private void Serialize(string value)
|
|
{
|
|
// Utils.Quote(writer, value, NbtUtils.DOUBLE_QUOTE_CHAR, NbtUtils.ESCAPE_CHAR);
|
|
writer.Write(NbtUtils.QuoteString(value, onlyIfNeeded: false));
|
|
}
|
|
|
|
private void EnterContext(bool newLine)
|
|
{
|
|
depth++;
|
|
context = new(context, newLine);
|
|
}
|
|
|
|
private void ExitContext()
|
|
{
|
|
depth--;
|
|
|
|
if (context!.NewLine && context!.Length > 0 && options.Style is SerializationStyle.Indented)
|
|
{
|
|
WriteNewLine();
|
|
}
|
|
|
|
context = context!.Parent;
|
|
}
|
|
|
|
private void WriteSeparator()
|
|
{
|
|
if (context!.Length > 0)
|
|
{
|
|
writer.Write(',');
|
|
|
|
if (options.Style is SerializationStyle.Spaced || !context.NewLine && options.Style is not SerializationStyle.Compact)
|
|
{
|
|
writer.Write(' ');
|
|
}
|
|
}
|
|
|
|
if (context.NewLine && options.Style is SerializationStyle.Indented)
|
|
{
|
|
WriteNewLine();
|
|
}
|
|
}
|
|
|
|
private void WriteNewLine()
|
|
{
|
|
writer.WriteLine();
|
|
|
|
for (var i = 0; i < depth; i++)
|
|
{
|
|
writer.Write(options.Indent);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Async
|
|
|
|
public async ValueTask SerializeAsync(INbtTag tag, CancellationToken ct)
|
|
{
|
|
switch (tag)
|
|
{
|
|
case INbtArray arrayTag:
|
|
await SerializeAsync(arrayTag, ct);
|
|
break;
|
|
|
|
case INbtValue valueTag:
|
|
await SerializeAsync(valueTag, ct);
|
|
break;
|
|
|
|
case INbtList listTag:
|
|
await SerializeAsync(listTag, ct);
|
|
break;
|
|
|
|
case INbtCompound compoundTag:
|
|
await SerializeAsync(compoundTag, ct);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public async ValueTask SerializeAsync(NamedTag namedTag, CancellationToken ct)
|
|
{
|
|
if (!string.IsNullOrEmpty(namedTag.Name))
|
|
{
|
|
await WriteStringAsync(NbtUtils.QuoteString(namedTag.Name, onlyIfNeeded: !options.AlwaysQuoteTagNames), ct);
|
|
await WriteStringAsync(":", ct);
|
|
if (options.Style is not SerializationStyle.Compact)
|
|
{
|
|
await WriteStringAsync(" ", ct);
|
|
}
|
|
}
|
|
|
|
await SerializeAsync(namedTag.Tag, ct);
|
|
}
|
|
|
|
public async ValueTask SerializeAsync(INbtList tag, CancellationToken ct)
|
|
{
|
|
await WriteStringAsync("[", ct);
|
|
|
|
await EnterContextAsync(true, ct);
|
|
|
|
foreach (var entry in tag)
|
|
{
|
|
await WriteSeparatorAsync(ct);
|
|
|
|
await SerializeAsync(entry, ct);
|
|
|
|
context!.Length++;
|
|
}
|
|
|
|
await ExitContextAsync(ct);
|
|
|
|
await WriteStringAsync("]", ct);
|
|
}
|
|
|
|
public async ValueTask SerializeAsync(INbtCompound tag, CancellationToken ct)
|
|
{
|
|
await WriteStringAsync("{", ct);
|
|
|
|
await EnterContextAsync(true, ct);
|
|
|
|
foreach (var entry in tag as IEnumerable<NamedTag>)
|
|
{
|
|
await WriteSeparatorAsync(ct);
|
|
|
|
await SerializeAsync(entry, ct);
|
|
|
|
context!.Length++;
|
|
}
|
|
|
|
await ExitContextAsync(ct);
|
|
|
|
await WriteStringAsync("}", ct);
|
|
}
|
|
|
|
public async ValueTask SerializeAsync(INbtArray tag, CancellationToken ct)
|
|
{
|
|
switch (tag)
|
|
{
|
|
case INbtArray<sbyte> byteArrayTag:
|
|
await SerializeAsync(byteArrayTag, ct);
|
|
break;
|
|
|
|
case INbtArray<int> intArrayTag:
|
|
await SerializeAsync(intArrayTag, ct);
|
|
break;
|
|
|
|
case INbtArray<long> longArrayTag:
|
|
await SerializeAsync(longArrayTag, ct);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public async ValueTask SerializeAsync(INbtValue valueTag, CancellationToken ct)
|
|
{
|
|
switch (valueTag)
|
|
{
|
|
case INbtValue<sbyte> tag:
|
|
await SerializeAsync(tag, ct);
|
|
break;
|
|
|
|
case INbtValue<short> tag:
|
|
await SerializeAsync(tag, ct);
|
|
break;
|
|
|
|
case INbtValue<int> tag:
|
|
await SerializeAsync(tag, ct);
|
|
break;
|
|
|
|
case INbtValue<long> tag:
|
|
await SerializeAsync(tag, ct);
|
|
break;
|
|
|
|
case INbtValue<float> tag:
|
|
await SerializeAsync(tag, ct);
|
|
break;
|
|
|
|
case INbtValue<double> tag:
|
|
await SerializeAsync(tag, ct);
|
|
break;
|
|
|
|
case INbtValue<string> tag:
|
|
await SerializeAsync(tag, ct);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public async ValueTask SerializeAsync(INbtArray<sbyte> tag, CancellationToken ct) => await SerializeAsync(tag, "B", ct, SerializeAsync);
|
|
|
|
public async ValueTask SerializeAsync(INbtArray<int> tag, CancellationToken ct) => await SerializeAsync(tag, "I", ct, SerializeAsync);
|
|
|
|
public async ValueTask SerializeAsync(INbtArray<long> tag, CancellationToken ct) => await SerializeAsync(tag, "L", ct, SerializeAsync);
|
|
|
|
public async ValueTask SerializeAsync(INbtValue<sbyte> tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct);
|
|
|
|
public async ValueTask SerializeAsync(INbtValue<short> tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct);
|
|
|
|
public async ValueTask SerializeAsync(INbtValue<int> tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct);
|
|
|
|
public async ValueTask SerializeAsync(INbtValue<long> tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct);
|
|
|
|
public async ValueTask SerializeAsync(INbtValue<float> tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct);
|
|
|
|
public async ValueTask SerializeAsync(INbtValue<double> tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct);
|
|
|
|
public async ValueTask SerializeAsync(INbtValue<string> tag, CancellationToken ct) => await SerializeAsync(tag.Value, ct);
|
|
|
|
private async ValueTask SerializeAsync<T>(INbtArray<T> tag, string decorator, CancellationToken ct, Func<T, CancellationToken, ValueTask> writeValue) where T : notnull
|
|
{
|
|
await WriteStringAsync("[", ct);
|
|
await WriteStringAsync(decorator, ct);
|
|
await WriteStringAsync(";", ct);
|
|
|
|
await EnterContextAsync(false, ct);
|
|
|
|
if (tag.Value.Length > 0)
|
|
{
|
|
if (options.Style is not SerializationStyle.Compact)
|
|
{
|
|
await WriteStringAsync(" ", ct);
|
|
}
|
|
|
|
foreach (var e in tag)
|
|
{
|
|
await WriteSeparatorAsync(ct);
|
|
|
|
await writeValue(e, ct);
|
|
|
|
context!.Length++;
|
|
}
|
|
}
|
|
|
|
await ExitContextAsync(ct);
|
|
|
|
await WriteStringAsync("]", ct);
|
|
}
|
|
|
|
private async ValueTask SerializeAsync(sbyte value, CancellationToken ct)
|
|
{
|
|
await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct);
|
|
await WriteStringAsync("b", ct);
|
|
}
|
|
|
|
private async ValueTask SerializeAsync(short value, CancellationToken ct)
|
|
{
|
|
await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct);
|
|
await WriteStringAsync("s", ct);
|
|
}
|
|
|
|
private async ValueTask SerializeAsync(int value, CancellationToken ct)
|
|
{
|
|
await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct);
|
|
}
|
|
|
|
private async ValueTask SerializeAsync(long value, CancellationToken ct)
|
|
{
|
|
await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct);
|
|
await WriteStringAsync("L", ct);
|
|
}
|
|
|
|
private async ValueTask SerializeAsync(float value, CancellationToken ct)
|
|
{
|
|
await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct);
|
|
|
|
if (float.IsFinite(value))
|
|
{
|
|
await WriteStringAsync("F", ct);
|
|
}
|
|
}
|
|
|
|
private async ValueTask SerializeAsync(double value, CancellationToken ct)
|
|
{
|
|
await WriteStringAsync(value.ToString(CultureInfo.InvariantCulture), ct);
|
|
|
|
if (double.IsFinite(value))
|
|
{
|
|
await WriteStringAsync("D", ct);
|
|
}
|
|
}
|
|
|
|
private async ValueTask SerializeAsync(string value, CancellationToken ct)
|
|
{
|
|
// Utils.Quote(writer, value, NbtUtils.DOUBLE_QUOTE_CHAR, NbtUtils.ESCAPE_CHAR);
|
|
await WriteStringAsync(NbtUtils.QuoteString(value, onlyIfNeeded: false), ct);
|
|
}
|
|
|
|
private async ValueTask WriteStringAsync(string s, CancellationToken ct)
|
|
{
|
|
await writer.WriteAsync(s.AsMemory(), ct);
|
|
}
|
|
|
|
private ValueTask EnterContextAsync(bool newLine, CancellationToken ct)
|
|
{
|
|
depth++;
|
|
context = new(context, newLine);
|
|
|
|
return ValueTask.CompletedTask;
|
|
}
|
|
|
|
private async ValueTask ExitContextAsync(CancellationToken ct)
|
|
{
|
|
depth--;
|
|
|
|
if (context!.NewLine && context!.Length > 0 && options.Style is SerializationStyle.Indented)
|
|
{
|
|
await WriteNewLineAsync(ct);
|
|
}
|
|
|
|
context = context!.Parent;
|
|
}
|
|
|
|
private async ValueTask WriteSeparatorAsync(CancellationToken ct)
|
|
{
|
|
if (context!.Length > 0)
|
|
{
|
|
await WriteStringAsync(",", ct);
|
|
|
|
if (options.Style is SerializationStyle.Spaced || !context.NewLine && options.Style is not SerializationStyle.Compact)
|
|
{
|
|
await WriteStringAsync(" ", ct);
|
|
}
|
|
}
|
|
|
|
if (context.NewLine && options.Style is SerializationStyle.Indented)
|
|
{
|
|
await WriteNewLineAsync(ct);
|
|
}
|
|
}
|
|
|
|
private async ValueTask WriteNewLineAsync(CancellationToken ct)
|
|
{
|
|
await WriteStringAsync(writer.NewLine, ct);
|
|
|
|
for (var i = 0; i < depth; i++)
|
|
{
|
|
await WriteStringAsync(options.Indent, ct);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
private class Context(Context? parent, bool newLine)
|
|
{
|
|
public Context? Parent => parent;
|
|
public bool NewLine => newLine;
|
|
|
|
public int Length { get; set; } = 0;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|