403 lines
18 KiB
C#
Executable File
403 lines
18 KiB
C#
Executable File
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;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
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 void WriteIndent()
|
|
{
|
|
for (var i = 0u; i < depth; i++)
|
|
{
|
|
writer.Write(options.Indent);
|
|
}
|
|
}
|
|
|
|
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('[');
|
|
|
|
depth++;
|
|
|
|
var style = options.Style;
|
|
var isSpaced = style is SerializationStyle.Spaced;
|
|
var isIndented = style is SerializationStyle.Indented;
|
|
|
|
var b = false;
|
|
|
|
foreach (var entry in tag)
|
|
{
|
|
if (b)
|
|
{
|
|
writer.Write(',');
|
|
if (isSpaced)
|
|
{
|
|
writer.Write(' ');
|
|
}
|
|
}
|
|
else
|
|
{
|
|
b = true;
|
|
}
|
|
|
|
if (isIndented)
|
|
{
|
|
writer.WriteLine();
|
|
WriteIndent();
|
|
}
|
|
|
|
Serialize(entry);
|
|
}
|
|
|
|
depth--;
|
|
|
|
if (b && isIndented)
|
|
{
|
|
writer.WriteLine();
|
|
WriteIndent();
|
|
}
|
|
|
|
writer.Write(']');
|
|
}
|
|
|
|
public void Serialize(INbtCompound tag)
|
|
{
|
|
writer.Write('{');
|
|
|
|
depth++;
|
|
|
|
var style = options.Style;
|
|
var isSpaced = style is SerializationStyle.Spaced;
|
|
var isIndented = style is SerializationStyle.Indented;
|
|
|
|
var b = false;
|
|
|
|
foreach (var entry in tag as IEnumerable<NamedTag>)
|
|
{
|
|
if (b)
|
|
{
|
|
writer.Write(',');
|
|
if (isSpaced)
|
|
{
|
|
writer.Write(' ');
|
|
}
|
|
}
|
|
else
|
|
{
|
|
b = true;
|
|
}
|
|
|
|
if (isIndented)
|
|
{
|
|
writer.WriteLine();
|
|
WriteIndent();
|
|
}
|
|
|
|
Serialize(entry);
|
|
}
|
|
|
|
depth--;
|
|
|
|
if (b && isIndented)
|
|
{
|
|
writer.WriteLine();
|
|
WriteIndent();
|
|
}
|
|
|
|
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(';');
|
|
|
|
if (tag.Value.Length > 0)
|
|
{
|
|
var isNotCompact = options.Style is not SerializationStyle.Compact;
|
|
|
|
if (isNotCompact)
|
|
{
|
|
writer.Write(' ');
|
|
}
|
|
|
|
var b = false;
|
|
|
|
foreach (var e in tag)
|
|
{
|
|
if (b)
|
|
{
|
|
writer.Write(',');
|
|
if (isNotCompact)
|
|
{
|
|
writer.Write(' ');
|
|
}
|
|
}
|
|
else
|
|
{
|
|
b = true;
|
|
}
|
|
|
|
writeValue(e);
|
|
}
|
|
}
|
|
|
|
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));
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|