1
0
Files
named-binary-tag/Nbt/Serialization/JsonNbt.cs

791 lines
38 KiB
C#
Executable File

using System.Globalization;
using System.Text;
using System.Text.Json;
using Nbt.Tag;
namespace Nbt.Serialization;
public static class JsonNbt
{
private static readonly JsonEncodedText TypeProperty = JsonEncodedText.Encode("type");
private static readonly JsonEncodedText ValueProperty = JsonEncodedText.Encode("value");
#region Serialize
#region Lossless
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 static string Serialize(INbtTag 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, 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, Encoding? encoding = null, SerializerOptions? options = null) => Serialize(stream, encoding, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtList tag, Encoding? encoding = null, SerializerOptions? options = null) => Serialize(stream, encoding, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtCompound tag, Encoding? encoding = null, SerializerOptions? options = null) => Serialize(stream, encoding, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtArray tag, Encoding? encoding = null, SerializerOptions? options = null) => Serialize(stream, encoding, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtValue tag, Encoding? encoding = null, SerializerOptions? options = null) => Serialize(stream, encoding, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtArray<sbyte> tag, Encoding? encoding = null, SerializerOptions? options = null) => Serialize(stream, encoding, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtArray<int> tag, Encoding? encoding = null, SerializerOptions? options = null) => Serialize(stream, encoding, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtArray<long> tag, Encoding? encoding = null, SerializerOptions? options = null) => Serialize(stream, encoding, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtValue<sbyte> tag, Encoding? encoding = null, SerializerOptions? options = null) => Serialize(stream, encoding, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtValue<short> tag, Encoding? encoding = null, SerializerOptions? options = null) => Serialize(stream, encoding, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtValue<int> tag, Encoding? encoding = null, SerializerOptions? options = null) => Serialize(stream, encoding, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtValue<long> tag, Encoding? encoding = null, SerializerOptions? options = null) => Serialize(stream, encoding, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtValue<float> tag, Encoding? encoding = null, SerializerOptions? options = null) => Serialize(stream, encoding, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtValue<double> tag, Encoding? encoding = null, SerializerOptions? options = null) => Serialize(stream, encoding, options, serializer => serializer.Serialize(tag));
public static void Serialize(Stream stream, INbtValue<string> tag, Encoding? encoding = null, SerializerOptions? options = null) => Serialize(stream, encoding, options, serializer => serializer.Serialize(tag));
private static string Serialize(SerializerOptions? options, Action<LosslessSerializer> serialize)
{
using var writer = new StringWriter();
Serialize(writer, options, serialize);
return writer.ToString();
}
private static void Serialize(Stream stream, Encoding? encoding, SerializerOptions? options, Action<LosslessSerializer> serialize)
{
using var writer = new StreamWriter(stream, encoding ?? Encoding.Default);
Serialize(writer, options, serialize);
}
private static void Serialize(TextWriter writer, SerializerOptions? options, Action<LosslessSerializer> serialize)
{
using var serializer = new LosslessSerializer(writer, options);
serialize(serializer);
}
private sealed class LosslessSerializer(TextWriter writer, SerializerOptions? options, bool leaveOpen = false) : IDisposable
{
private readonly JsonWriter writer = new(writer, options, leaveOpen);
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(INbtList tag)
{
using (new NbtObjectMeta(writer, tag))
{
writer.WriteStartArray();
foreach (var entry in tag)
{
writer.WriteElement(entry, Serialize);
}
writer.WriteEndArray();
}
}
public void Serialize(INbtCompound tag)
{
using (new NbtObjectMeta(writer, tag))
{
writer. WriteStartObject();
foreach (var entry in tag as IEnumerable<NamedTag>)
{
writer.WriteProperty(entry.Name, entry.Tag, Serialize);
}
writer.WriteEndObject();
}
}
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, Serialize);
public void Serialize(INbtArray<int> tag) => Serialize(tag, Serialize);
public void Serialize(INbtArray<long> tag) => Serialize(tag, Serialize);
public void Serialize(INbtValue<sbyte> tag) => Serialize(tag, Serialize);
public void Serialize(INbtValue<short> tag) => Serialize(tag, Serialize);
public void Serialize(INbtValue<int> tag) => Serialize(tag, Serialize);
public void Serialize(INbtValue<long> tag) => Serialize(tag, Serialize);
public void Serialize(INbtValue<float> tag) => Serialize(tag, Serialize);
public void Serialize(INbtValue<double> tag) => Serialize(tag, Serialize);
public void Serialize(INbtValue<string> tag) => Serialize(tag, Serialize);
private void Serialize<T>(INbtArray<T> tag, Action<T> writeValue) where T : notnull
{
using (new NbtObjectMeta(writer, tag))
{
writer.WriteStartArray();
foreach (var element in tag)
{
writer.WriteElement(element, writeValue);
}
writer.WriteEndArray();
}
}
private void Serialize<T>(INbtValue<T> tag, Action<T> writeValue) where T : notnull
{
using (new NbtObjectMeta(writer, tag))
{
writeValue(tag.Value);
}
}
private void Serialize(sbyte value) => writer.WriteValue(value);
private void Serialize(short value) => writer.WriteValue(value);
private void Serialize(int value) => writer.WriteValue(value);
private void Serialize(long value) => writer.WriteValue(value);
private void Serialize(float value) => writer.WriteValue(value);
private void Serialize(double value) => writer.WriteValue(value);
private void Serialize(string value) => writer.WriteValue(value);
public void Dispose()
{
writer.Dispose();
GC.SuppressFinalize(this);
}
}
#endregion
#region Lossy
public static string ToJson(INbtTag tag, SerializerOptions? options = null) => ToJson(options, serializer => serializer.ToJson(tag));
public static string ToJson(INbtList tag, SerializerOptions? options = null) => ToJson(options, serializer => serializer.ToJson(tag));
public static string ToJson(INbtCompound tag, SerializerOptions? options = null) => ToJson(options, serializer => serializer.ToJson(tag));
public static string ToJson(INbtArray tag, SerializerOptions? options = null) => ToJson(options, serializer => serializer.ToJson(tag));
public static string ToJson(INbtValue tag, SerializerOptions? options = null) => ToJson(options, serializer => serializer.ToJson(tag));
public static string ToJson(INbtArray<sbyte> tag, SerializerOptions? options = null) => ToJson(options, serializer => serializer.ToJson(tag));
public static string ToJson(INbtArray<int> tag, SerializerOptions? options = null) => ToJson(options, serializer => serializer.ToJson(tag));
public static string ToJson(INbtArray<long> tag, SerializerOptions? options = null) => ToJson(options, serializer => serializer.ToJson(tag));
public static string ToJson(INbtValue<sbyte> tag, SerializerOptions? options = null) => ToJson(options, serializer => serializer.ToJson(tag));
public static string ToJson(INbtValue<short> tag, SerializerOptions? options = null) => ToJson(options, serializer => serializer.ToJson(tag));
public static string ToJson(INbtValue<int> tag, SerializerOptions? options = null) => ToJson(options, serializer => serializer.ToJson(tag));
public static string ToJson(INbtValue<long> tag, SerializerOptions? options = null) => ToJson(options, serializer => serializer.ToJson(tag));
public static string ToJson(INbtValue<float> tag, SerializerOptions? options = null) => ToJson(options, serializer => serializer.ToJson(tag));
public static string ToJson(INbtValue<double> tag, SerializerOptions? options = null) => ToJson(options, serializer => serializer.ToJson(tag));
public static string ToJson(INbtValue<string> tag, SerializerOptions? options = null) => ToJson(options, serializer => serializer.ToJson(tag));
public static void ToJson(TextWriter writer, INbtTag tag, SerializerOptions? options = null) => ToJson(writer, options, serializer => serializer.ToJson(tag));
public static void ToJson(TextWriter writer, INbtList tag, SerializerOptions? options = null) => ToJson(writer, options, serializer => serializer.ToJson(tag));
public static void ToJson(TextWriter writer, INbtCompound tag, SerializerOptions? options = null) => ToJson(writer, options, serializer => serializer.ToJson(tag));
public static void ToJson(TextWriter writer, INbtArray tag, SerializerOptions? options = null) => ToJson(writer, options, serializer => serializer.ToJson(tag));
public static void ToJson(TextWriter writer, INbtValue tag, SerializerOptions? options = null) => ToJson(writer, options, serializer => serializer.ToJson(tag));
public static void ToJson(TextWriter writer, INbtArray<sbyte> tag, SerializerOptions? options = null) => ToJson(writer, options, serializer => serializer.ToJson(tag));
public static void ToJson(TextWriter writer, INbtArray<int> tag, SerializerOptions? options = null) => ToJson(writer, options, serializer => serializer.ToJson(tag));
public static void ToJson(TextWriter writer, INbtArray<long> tag, SerializerOptions? options = null) => ToJson(writer, options, serializer => serializer.ToJson(tag));
public static void ToJson(TextWriter writer, INbtValue<sbyte> tag, SerializerOptions? options = null) => ToJson(writer, options, serializer => serializer.ToJson(tag));
public static void ToJson(TextWriter writer, INbtValue<short> tag, SerializerOptions? options = null) => ToJson(writer, options, serializer => serializer.ToJson(tag));
public static void ToJson(TextWriter writer, INbtValue<int> tag, SerializerOptions? options = null) => ToJson(writer, options, serializer => serializer.ToJson(tag));
public static void ToJson(TextWriter writer, INbtValue<long> tag, SerializerOptions? options = null) => ToJson(writer, options, serializer => serializer.ToJson(tag));
public static void ToJson(TextWriter writer, INbtValue<float> tag, SerializerOptions? options = null) => ToJson(writer, options, serializer => serializer.ToJson(tag));
public static void ToJson(TextWriter writer, INbtValue<double> tag, SerializerOptions? options = null) => ToJson(writer, options, serializer => serializer.ToJson(tag));
public static void ToJson(TextWriter writer, INbtValue<string> tag, SerializerOptions? options = null) => ToJson(writer, options, serializer => serializer.ToJson(tag));
public static void ToJson(Stream stream, INbtTag tag, Encoding? encoding = null, SerializerOptions? options = null) => ToJson(stream, encoding, options, serializer => serializer.ToJson(tag));
public static void ToJson(Stream stream, INbtList tag, Encoding? encoding = null, SerializerOptions? options = null) => ToJson(stream, encoding, options, serializer => serializer.ToJson(tag));
public static void ToJson(Stream stream, INbtCompound tag, Encoding? encoding = null, SerializerOptions? options = null) => ToJson(stream, encoding, options, serializer => serializer.ToJson(tag));
public static void ToJson(Stream stream, INbtArray tag, Encoding? encoding = null, SerializerOptions? options = null) => ToJson(stream, encoding, options, serializer => serializer.ToJson(tag));
public static void ToJson(Stream stream, INbtValue tag, Encoding? encoding = null, SerializerOptions? options = null) => ToJson(stream, encoding, options, serializer => serializer.ToJson(tag));
public static void ToJson(Stream stream, INbtArray<sbyte> tag, Encoding? encoding = null, SerializerOptions? options = null) => ToJson(stream, encoding, options, serializer => serializer.ToJson(tag));
public static void ToJson(Stream stream, INbtArray<int> tag, Encoding? encoding = null, SerializerOptions? options = null) => ToJson(stream, encoding, options, serializer => serializer.ToJson(tag));
public static void ToJson(Stream stream, INbtArray<long> tag, Encoding? encoding = null, SerializerOptions? options = null) => ToJson(stream, encoding, options, serializer => serializer.ToJson(tag));
public static void ToJson(Stream stream, INbtValue<sbyte> tag, Encoding? encoding = null, SerializerOptions? options = null) => ToJson(stream, encoding, options, serializer => serializer.ToJson(tag));
public static void ToJson(Stream stream, INbtValue<short> tag, Encoding? encoding = null, SerializerOptions? options = null) => ToJson(stream, encoding, options, serializer => serializer.ToJson(tag));
public static void ToJson(Stream stream, INbtValue<int> tag, Encoding? encoding = null, SerializerOptions? options = null) => ToJson(stream, encoding, options, serializer => serializer.ToJson(tag));
public static void ToJson(Stream stream, INbtValue<long> tag, Encoding? encoding = null, SerializerOptions? options = null) => ToJson(stream, encoding, options, serializer => serializer.ToJson(tag));
public static void ToJson(Stream stream, INbtValue<float> tag, Encoding? encoding = null, SerializerOptions? options = null) => ToJson(stream, encoding, options, serializer => serializer.ToJson(tag));
public static void ToJson(Stream stream, INbtValue<double> tag, Encoding? encoding = null, SerializerOptions? options = null) => ToJson(stream, encoding, options, serializer => serializer.ToJson(tag));
public static void ToJson(Stream stream, INbtValue<string> tag, Encoding? encoding = null, SerializerOptions? options = null) => ToJson(stream, encoding, options, serializer => serializer.ToJson(tag));
private static string ToJson(SerializerOptions? options, Action<LossySerializer> serialize)
{
using var writer = new StringWriter();
ToJson(writer, options, serialize);
return writer.ToString();
}
private static void ToJson(Stream stream, Encoding? encoding, SerializerOptions? options, Action<LossySerializer> serialize)
{
using var writer = new StreamWriter(stream, encoding ?? Encoding.Default);
ToJson(writer, options, serialize);
}
private static void ToJson(TextWriter writer, SerializerOptions? options, Action<LossySerializer> serialize)
{
using var serializer = new LossySerializer(writer, options);
serialize(serializer);
}
private sealed class LossySerializer(TextWriter writer, SerializerOptions? options, bool leaveOpen = false) : IDisposable
{
private readonly JsonWriter writer = new(writer, options, leaveOpen);
public void ToJson(INbtTag tag)
{
switch (tag)
{
case INbtArray arrayTag:
ToJson(arrayTag);
break;
case INbtValue valueTag:
ToJson(valueTag);
break;
case INbtList listTag:
ToJson(listTag);
break;
case INbtCompound compoundTag:
ToJson(compoundTag);
break;
}
}
public void ToJson(INbtList tag)
{
writer.WriteStartArray();
foreach (var entry in tag)
{
writer.WriteElement(entry, ToJson);
}
writer.WriteEndArray();
}
public void ToJson(INbtCompound tag)
{
writer.WriteStartObject();
foreach (var entry in tag as IEnumerable<NamedTag>)
{
writer.WriteProperty(entry.Name, entry.Tag, ToJson);
}
writer.WriteEndObject();
}
public void ToJson(INbtArray tag)
{
switch (tag)
{
case INbtArray<sbyte> byteArrayTag:
ToJson(byteArrayTag);
break;
case INbtArray<int> intArrayTag:
ToJson(intArrayTag);
break;
case INbtArray<long> longArrayTag:
ToJson(longArrayTag);
break;
}
}
public void ToJson(INbtValue valueTag)
{
switch (valueTag)
{
case INbtValue<sbyte> tag:
ToJson(tag);
break;
case INbtValue<short> tag:
ToJson(tag);
break;
case INbtValue<int> tag:
ToJson(tag);
break;
case INbtValue<long> tag:
ToJson(tag);
break;
case INbtValue<float> tag:
ToJson(tag);
break;
case INbtValue<double> tag:
ToJson(tag);
break;
case INbtValue<string> tag:
ToJson(tag);
break;
}
}
public void ToJson(INbtArray<sbyte> tag) => ToJson(tag, ToJson);
public void ToJson(INbtArray<int> tag) => ToJson(tag, ToJson);
public void ToJson(INbtArray<long> tag) => ToJson(tag, ToJson);
public void ToJson(INbtValue<sbyte> tag) => ToJson(tag, ToJson);
public void ToJson(INbtValue<short> tag) => ToJson(tag, ToJson);
public void ToJson(INbtValue<int> tag) => ToJson(tag, ToJson);
public void ToJson(INbtValue<long> tag) => ToJson(tag, ToJson);
public void ToJson(INbtValue<float> tag) => ToJson(tag, ToJson);
public void ToJson(INbtValue<double> tag) => ToJson(tag, ToJson);
public void ToJson(INbtValue<string> tag) => ToJson(tag, ToJson);
private void ToJson<T>(INbtArray<T> tag, Action<T> writeValue) where T : notnull
{
writer.WriteStartArray();
foreach (var e in tag)
{
writer.WriteElement(e, writeValue);
}
writer.WriteEndArray();
}
private static void ToJson<T>(INbtValue<T> tag, Action<T> writeValue) where T : notnull => writeValue(tag.Value);
private void ToJson(sbyte value) => writer.WriteValue(value);
private void ToJson(short value) => writer.WriteValue(value);
private void ToJson(int value) => writer.WriteValue(value);
private void ToJson(long value) => writer.WriteValue(value);
private void ToJson(float value) => writer.WriteValue(value);
private void ToJson(double value) => writer.WriteValue(value);
private void ToJson(string value) => writer.WriteValue(value);
public void Dispose()
{
writer.Dispose();
GC.SuppressFinalize(this);
}
}
#endregion
private sealed class JsonWriter(TextWriter writer, SerializerOptions? options, bool leaveOpen = false) : IDisposable
{
private readonly TextWriter writer = writer;
private readonly SerializerOptions options = options ?? SerializerOptions.Default;
private readonly bool leaveOpen = leaveOpen;
private int depth = 0;
private Context context = new(null, 0);
public void WriteStartArray()
{
writer.Write('[');
depth++;
context = new(context, 1);
}
public void WriteEndArray()
{
depth--;
if (context.length > 0 && options.Style is SerializationStyle.Indented)
{
writer.WriteLine();
WriteIndent();
}
context = context.parent!;
writer.Write(']');
}
public void WriteStartObject()
{
writer.Write('{');
depth++;
context = new(context, 2);
}
public void WriteEndObject()
{
depth--;
if (context.length > 0 && options.Style is SerializationStyle.Indented)
{
writer.WriteLine();
WriteIndent();
}
context = context.parent!;
writer.Write('}');
}
public void WriteElement(byte value) => WriteElement(value, WriteValue);
public void WriteElement(sbyte value) => WriteElement(value, WriteValue);
public void WriteElement(short value) => WriteElement(value, WriteValue);
public void WriteElement(ushort value) => WriteElement(value, WriteValue);
public void WriteElement(int value) => WriteElement(value, WriteValue);
public void WriteElement(uint value) => WriteElement(value, WriteValue);
public void WriteElement(long value) => WriteElement(value, WriteValue);
public void WriteElement(ulong value) => WriteElement(value, WriteValue);
public void WriteElement(float value) => WriteElement(value, WriteValue);
public void WriteElement(double value) => WriteElement(value, WriteValue);
public void WriteElement(string value) => WriteElement(value, WriteValue);
public void WriteElement<T>(T value, Action<T> elementWriter)
{
WriteSeparator();
elementWriter(value);
context.length++;
}
public void WriteProperty(string name, byte value) => WriteProperty(name, value, WriteValue);
public void WriteProperty(string name, sbyte value) => WriteProperty(name, value, WriteValue);
public void WriteProperty(string name, short value) => WriteProperty(name, value, WriteValue);
public void WriteProperty(string name, ushort value) => WriteProperty(name, value, WriteValue);
public void WriteProperty(string name, int value) => WriteProperty(name, value, WriteValue);
public void WriteProperty(string name, uint value) => WriteProperty(name, value, WriteValue);
public void WriteProperty(string name, long value) => WriteProperty(name, value, WriteValue);
public void WriteProperty(string name, ulong value) => WriteProperty(name, value, WriteValue);
public void WriteProperty(string name, float value) => WriteProperty(name, value, WriteValue);
public void WriteProperty(string name, double value) => WriteProperty(name, value, WriteValue);
public void WriteProperty(string name, string value) => WriteProperty(name, value, WriteValue);
public void WritePropertyName(string name)
{
WriteSeparator();
WriteValue(name);
writer.Write(':');
if (options.Style is not SerializationStyle.Compact)
{
writer.Write(' ');
}
}
public void WriteProperty<T>(string name, T value, Action<T> valueWriter)
{
WritePropertyName(name);
valueWriter(value);
context.length++;
}
public void WriteValue(byte value) => writer.Write(value.ToString(CultureInfo.InvariantCulture));
public void WriteValue(sbyte value) => writer.Write(value.ToString(CultureInfo.InvariantCulture));
public void WriteValue(short value) => writer.Write(value.ToString(CultureInfo.InvariantCulture));
public void WriteValue(ushort value) => writer.Write(value.ToString(CultureInfo.InvariantCulture));
public void WriteValue(int value) => writer.Write(value.ToString(CultureInfo.InvariantCulture));
public void WriteValue(uint value) => writer.Write(value.ToString(CultureInfo.InvariantCulture));
public void WriteValue(long value) => writer.Write(value.ToString(CultureInfo.InvariantCulture));
public void WriteValue(ulong value) => writer.Write(value.ToString(CultureInfo.InvariantCulture));
public void WriteValue(float value) => writer.Write(value.ToString(CultureInfo.InvariantCulture));
public void WriteValue(double value) => writer.Write(value.ToString(CultureInfo.InvariantCulture));
public void WriteValue(string value) => Utils.Quote(writer, value, '"', '\\');
private void WriteSeparator()
{
if (context.length > 0)
{
writer.Write(',');
if (options.Style is SerializationStyle.Spaced)
{
writer.Write(' ');
}
}
if (options.Style is SerializationStyle.Indented)
{
writer.WriteLine();
WriteIndent();
}
}
private void WriteIndent()
{
for (var i = 0; i < depth; i++)
{
writer.Write(options.Indent);
}
}
public void Dispose()
{
if (!leaveOpen)
{
writer.Dispose();
}
GC.SuppressFinalize(this);
}
private class Context(Context? parent, byte type)
{
public readonly Context? parent = parent;
public readonly byte type = type;
public int length = 0;
}
}
private readonly struct NbtObjectMeta : IDisposable
{
private readonly JsonWriter writer;
public NbtObjectMeta(JsonWriter writer, INbtTag tag)
{
this.writer = writer;
writer.WriteStartObject();
writer.WriteProperty(TypeProperty.Value, (int)tag.Type);
writer.WritePropertyName(ValueProperty.Value);
}
public void Dispose()
{
writer.WriteEndObject();
}
}
#endregion
#region Deserialize
public static INbtTag Deserialize(string s)
{
using var reader = new StringReader(s);
return Deserialize(reader);
}
public static INbtTag Deserialize(Stream stream)
{
var doc = JsonDocument.Parse(stream);
return Deserialize(doc.RootElement);
}
public static INbtTag Deserialize(TextReader reader)
{
using var stream = new MemoryStream();
using (var writer = new StreamWriter(stream, encoding: Encoding.UTF8, leaveOpen: true))
{
while (true)
{
var i = reader.Read();
if (i < 0)
{
break;
}
writer.Write((char)i);
}
}
stream.Position = 0L;
return Deserialize(stream);
}
private static INbtTag Deserialize(JsonElement serialized)
{
var tagType = (NbtTagType)serialized.GetProperty(TypeProperty.Value).GetByte();
var value = serialized.GetProperty(ValueProperty.Value);
switch (tagType)
{
case NbtTagType.End:
throw new NbtException($"Invalid tag type: {Enum.GetName(tagType)}");
case NbtTagType.Byte:
return new NbtByte(value.GetSByte());
case NbtTagType.Short:
return new NbtShort(value.GetInt16());
case NbtTagType.Int:
return new NbtInt(value.GetInt32());
case NbtTagType.Long:
return new NbtLong(value.GetInt64());
case NbtTagType.Float:
return new NbtFloat(value.GetSingle());
case NbtTagType.Double:
return new NbtDouble(value.GetDouble());
case NbtTagType.String:
return new NbtString(value.GetString() ?? throw new NbtException("Null string value"));
case NbtTagType.ByteArray:
{
var bytes = new sbyte[value.GetArrayLength()];
var i = 0;
foreach (var element in value.EnumerateArray())
{
bytes[i++] = element.GetSByte();
}
return new NbtByteArray(bytes);
}
case NbtTagType.IntArray:
{
var ints = new int[value.GetArrayLength()];
var i = 0;
foreach (var element in value.EnumerateArray())
{
ints[i++] = element.GetInt32();
}
return new NbtIntArray(ints);
}
case NbtTagType.LongArray:
{
var longs = new long[value.GetArrayLength()];
var i = 0;
foreach (var element in value.EnumerateArray())
{
longs[i++] = element.GetInt64();
}
return new NbtLongArray(longs);
}
case NbtTagType.List:
{
var list = new NbtList();
foreach (var element in value.EnumerateArray())
{
list.Add(Deserialize(element));
}
return list;
}
case NbtTagType.Compound:
{
var compound = new NbtCompound();
foreach (var property in value.EnumerateObject())
{
compound.Add(property.Name, Deserialize(property.Value));
}
return compound;
}
default:
throw new UnknownTagTypeException(tagType);
}
}
#endregion
}