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 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(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(INbtValue 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(INbtValue 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(INbtValue 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 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 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, 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, INbtValue 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, INbtValue 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, INbtValue 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(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 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, 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, INbtValue 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, INbtValue 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, INbtValue 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)); private static void Serialize(TextWriter writer, SerializerOptions? options, Action serialize) { var serializer = new Serializer(writer, options); serialize(serializer); } private static void Serialize(Stream stream, SerializerOptions? options, Action serialize) { using var writer = new StreamWriter(stream, leaveOpen: true); Serialize(writer, options, serialize); } private static string Serialize(SerializerOptions? options, Action 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) { 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 byteArrayTag: Serialize(byteArrayTag); break; case INbtArray intArrayTag: Serialize(intArrayTag); break; case INbtArray longArrayTag: Serialize(longArrayTag); break; } } public void Serialize(INbtValue valueTag) { switch (valueTag) { case INbtValue tag: Serialize(tag); break; case INbtValue tag: Serialize(tag); break; case INbtValue tag: Serialize(tag); break; case INbtValue tag: Serialize(tag); break; case INbtValue tag: Serialize(tag); break; case INbtValue tag: Serialize(tag); break; case INbtValue tag: Serialize(tag); break; } } public void Serialize(INbtArray tag) => Serialize(tag, 'B', Serialize); public void Serialize(INbtArray tag) => Serialize(tag, 'I', Serialize); public void Serialize(INbtArray tag) => Serialize(tag, 'L', Serialize); public void Serialize(INbtValue tag) => Serialize(tag.Value); public void Serialize(INbtValue tag) => Serialize(tag.Value); public void Serialize(INbtValue tag) => Serialize(tag.Value); public void Serialize(INbtValue tag) => Serialize(tag.Value); public void Serialize(INbtValue tag) => Serialize(tag.Value); public void Serialize(INbtValue tag) => Serialize(tag.Value); public void Serialize(INbtValue tag) => Serialize(tag.Value); private void Serialize(INbtArray tag, char decorator, Action 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 }