Implemented generating SNBT from tags
This commit is contained in:
parent
5b6fcd2d4c
commit
16369b68e3
|
@ -0,0 +1,30 @@
|
||||||
|
using Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace SharpNBT.Tests
|
||||||
|
{
|
||||||
|
public class StringifiedTest
|
||||||
|
{
|
||||||
|
private readonly ITestOutputHelper output;
|
||||||
|
|
||||||
|
|
||||||
|
public StringifiedTest(ITestOutputHelper output)
|
||||||
|
{
|
||||||
|
this.output = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BigOutput()
|
||||||
|
{
|
||||||
|
var tag = TestHelper.GetTag("bigtest.nbt", CompressionType.GZip);
|
||||||
|
output.WriteLine(tag.Stringify(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void HelloWorldOutput()
|
||||||
|
{
|
||||||
|
var tag = TestHelper.GetTag("hello_world.nbt", CompressionType.None);
|
||||||
|
output.WriteLine(tag.Stringify(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace SharpNBT.SNBT
|
||||||
|
{
|
||||||
|
internal enum TokenType
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
CompoundBegin,
|
||||||
|
CompoundEnd,
|
||||||
|
Identifier,
|
||||||
|
String,
|
||||||
|
Separator,
|
||||||
|
Comma,
|
||||||
|
ByteArray,
|
||||||
|
IntArray,
|
||||||
|
LongArray,
|
||||||
|
ListArray,
|
||||||
|
EndArray,
|
||||||
|
Float,
|
||||||
|
Double,
|
||||||
|
Byte,
|
||||||
|
Short,
|
||||||
|
Long,
|
||||||
|
Int,
|
||||||
|
WhiteSpace,
|
||||||
|
Char
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class LexerRule
|
||||||
|
{
|
||||||
|
internal delegate string PostProcessHandler(string input);
|
||||||
|
|
||||||
|
private readonly Regex regex;
|
||||||
|
|
||||||
|
public TokenType Type { get; }
|
||||||
|
|
||||||
|
public LexerRule(TokenType type, string pattern) : this(type, new Regex(pattern, RegexOptions.Multiline | RegexOptions.CultureInvariant))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public LexerRule(TokenType type, Regex regex)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
this.regex = regex ?? throw new ArgumentNullException(nameof(regex));
|
||||||
|
}
|
||||||
|
|
||||||
|
public LexerRule(TokenType type, Regex regex, PostProcessHandler handler)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class Lexer
|
||||||
|
{
|
||||||
|
private static readonly List<LexerRule> rules;
|
||||||
|
|
||||||
|
static Lexer()
|
||||||
|
{
|
||||||
|
rules = new List<LexerRule>
|
||||||
|
{
|
||||||
|
new LexerRule(TokenType.CompoundBegin, @"\{[\s]*"),
|
||||||
|
new LexerRule(TokenType.CompoundEnd, @"[\s]*\}"),
|
||||||
|
new LexerRule(TokenType.Identifier, "\".+?\"(?=:)"),
|
||||||
|
new LexerRule(TokenType.Identifier, "'.+?'(?=:) "),
|
||||||
|
new LexerRule(TokenType.Identifier, "A-Za-z0-9_-]+?(?=:) "),
|
||||||
|
new LexerRule(TokenType.String, "\".*?\""),
|
||||||
|
new LexerRule(TokenType.String, "'.*?'"),
|
||||||
|
new LexerRule(TokenType.Separator, @"[\s]*:[\s]*"),
|
||||||
|
new LexerRule(TokenType.Comma, @"[\s]*,[\s]*"),
|
||||||
|
new LexerRule(TokenType.ByteArray, @"\[B;[\s]*?"),
|
||||||
|
new LexerRule(TokenType.IntArray, @"\[I;[\s]*?"),
|
||||||
|
new LexerRule(TokenType.LongArray, @"\[L;[\s]*?"),
|
||||||
|
new LexerRule(TokenType.ListArray, @"\[[\s]*?"),
|
||||||
|
new LexerRule(TokenType.EndArray, @"[\s]*\]"),
|
||||||
|
new LexerRule(TokenType.Float, @"-?[0-9]*\.[0-9]+[Ff]"),
|
||||||
|
new LexerRule(TokenType.Double, @"-?[0-9]*\.[0-9]+[Dd]?"),
|
||||||
|
new LexerRule(TokenType.Byte, "-?([0-9]+)[Bb]"),
|
||||||
|
new LexerRule(TokenType.Short, "-?([0-9]+)[Ss]"),
|
||||||
|
new LexerRule(TokenType.Long, "-?([0-9]+)[Ll]"),
|
||||||
|
new LexerRule(TokenType.Int, "-?([0-9]+)"),
|
||||||
|
new LexerRule(TokenType.WhiteSpace, @"[\s]+"),
|
||||||
|
new LexerRule(TokenType.String, @"[\S]+"),
|
||||||
|
new LexerRule(TokenType.Char, ".")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Lexer()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -57,5 +57,12 @@ namespace SharpNBT
|
||||||
var word = Count == 1 ? Strings.WordElement : Strings.WordElements;
|
var word = Count == 1 ? Strings.WordElement : Strings.WordElements;
|
||||||
return $"TAG_Byte_Array({PrettyName}): [{Count} {word}]";
|
return $"TAG_Byte_Array({PrettyName}): [{Count} {word}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <i>string</i> representation of this NBT tag (SNBT).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>This NBT tag in SNBT format.</returns>
|
||||||
|
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
|
||||||
|
public override string Stringify() => $"{StringifyName}[B;{string.Join(',', this)}]";
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
|
using System.Text;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
namespace SharpNBT
|
namespace SharpNBT
|
||||||
|
@ -69,5 +70,12 @@ namespace SharpNBT
|
||||||
/// <returns>The tag represented as a <see cref="sbyte"/>.</returns>
|
/// <returns>The tag represented as a <see cref="sbyte"/>.</returns>
|
||||||
[CLSCompliant(false)]
|
[CLSCompliant(false)]
|
||||||
public static implicit operator sbyte(ByteTag tag) => unchecked((sbyte)tag.Value);
|
public static implicit operator sbyte(ByteTag tag) => unchecked((sbyte)tag.Value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <i>string</i> representation of this NBT tag (SNBT).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>This NBT tag in SNBT format.</returns>
|
||||||
|
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
|
||||||
|
public override string Stringify() => $"{StringifyName}{Value}B";
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
@ -112,5 +113,31 @@ namespace SharpNBT
|
||||||
tag.PrettyPrinted(buffer, level + 1, indent);
|
tag.PrettyPrinted(buffer, level + 1, indent);
|
||||||
buffer.AppendLine(space + "}");
|
buffer.AppendLine(space + "}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <i>string</i> representation of this NBT tag (SNBT).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>This NBT tag in SNBT format.</returns>
|
||||||
|
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
|
||||||
|
public override string Stringify()
|
||||||
|
{
|
||||||
|
var strings = new string[Count];
|
||||||
|
for (var i = 0; i < strings.Length; i++)
|
||||||
|
strings[i] = this[i].Stringify();
|
||||||
|
|
||||||
|
return $"{StringifyName}{{{string.Join(',', strings)}}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <i>string</i> representation of this NBT tag (SNBT).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="topLevel">Flag indicating if this is the top-level tag that should be wrapped in braces.</param>
|
||||||
|
/// <returns>This NBT tag in SNBT format.</returns>
|
||||||
|
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
|
||||||
|
public string Stringify(bool topLevel)
|
||||||
|
{
|
||||||
|
var str = Stringify();
|
||||||
|
return topLevel ? $"{{{str}}}" : str;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -37,5 +37,12 @@ namespace SharpNBT
|
||||||
/// <param name="tag">The tag to convert.</param>
|
/// <param name="tag">The tag to convert.</param>
|
||||||
/// <returns>The tag represented as a <see cref="double"/>.</returns>
|
/// <returns>The tag represented as a <see cref="double"/>.</returns>
|
||||||
public static implicit operator double(DoubleTag tag) => tag.Value;
|
public static implicit operator double(DoubleTag tag) => tag.Value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <i>string</i> representation of this NBT tag (SNBT).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>This NBT tag in SNBT format.</returns>
|
||||||
|
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
|
||||||
|
public override string Stringify() => $"{StringifyName}{Value:0.0}D";
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -24,5 +24,12 @@ namespace SharpNBT
|
||||||
{
|
{
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <i>string</i> representation of this NBT tag (SNBT).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>This NBT tag in SNBT format.</returns>
|
||||||
|
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
|
||||||
|
public override string Stringify() => string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -36,5 +36,12 @@ namespace SharpNBT
|
||||||
/// <param name="tag">The tag to convert.</param>
|
/// <param name="tag">The tag to convert.</param>
|
||||||
/// <returns>The tag represented as a <see cref="float"/>.</returns>
|
/// <returns>The tag represented as a <see cref="float"/>.</returns>
|
||||||
public static implicit operator float(FloatTag tag) => tag.Value;
|
public static implicit operator float(FloatTag tag) => tag.Value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <i>string</i> representation of this NBT tag (SNBT).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>This NBT tag in SNBT format.</returns>
|
||||||
|
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
|
||||||
|
public override string Stringify() => $"{StringifyName}{Value:0.0}F";
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -61,5 +61,12 @@ namespace SharpNBT
|
||||||
var word = Count == 1 ? Strings.WordElement : Strings.WordElements;
|
var word = Count == 1 ? Strings.WordElement : Strings.WordElements;
|
||||||
return $"TAG_Int_Array({PrettyName}): [{Count} {word}]";
|
return $"TAG_Int_Array({PrettyName}): [{Count} {word}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <i>string</i> representation of this NBT tag (SNBT).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>This NBT tag in SNBT format.</returns>
|
||||||
|
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
|
||||||
|
public override string Stringify() => $"{StringifyName}[I;{string.Join(',', this)}]";
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -64,5 +64,12 @@ namespace SharpNBT
|
||||||
/// <returns>The tag represented as a <see cref="uint"/>.</returns>
|
/// <returns>The tag represented as a <see cref="uint"/>.</returns>
|
||||||
[CLSCompliant(false)]
|
[CLSCompliant(false)]
|
||||||
public static implicit operator uint(IntTag tag) => unchecked((uint)tag.Value);
|
public static implicit operator uint(IntTag tag) => unchecked((uint)tag.Value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <i>string</i> representation of this NBT tag (SNBT).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>This NBT tag in SNBT format.</returns>
|
||||||
|
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
|
||||||
|
public override string Stringify() => $"{StringifyName}{Value}";
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -72,7 +72,7 @@ namespace SharpNBT
|
||||||
tag.PrettyPrinted(buffer, level + 1, indent);
|
tag.PrettyPrinted(buffer, level + 1, indent);
|
||||||
buffer.AppendLine(space + "}");
|
buffer.AppendLine(space + "}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves a "pretty-printed" multiline string representing the complete tree structure of the tag.
|
/// Retrieves a "pretty-printed" multiline string representing the complete tree structure of the tag.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -85,5 +85,19 @@ namespace SharpNBT
|
||||||
PrettyPrinted(buffer, 0, indent);
|
PrettyPrinted(buffer, 0, indent);
|
||||||
return buffer.ToString();
|
return buffer.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <i>string</i> representation of this NBT tag (SNBT).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>This NBT tag in SNBT format.</returns>
|
||||||
|
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
|
||||||
|
public override string Stringify()
|
||||||
|
{
|
||||||
|
var strings = new string[Count];
|
||||||
|
for (var i = 0; i < strings.Length; i++)
|
||||||
|
strings[i] = this[i].Stringify();
|
||||||
|
|
||||||
|
return $"{StringifyName}[{string.Join(',', strings)}]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -60,5 +60,12 @@ namespace SharpNBT
|
||||||
var word = Count == 1 ? Strings.WordElement : Strings.WordElements;
|
var word = Count == 1 ? Strings.WordElement : Strings.WordElements;
|
||||||
return $"TAG_Long_Array({PrettyName}): [{Count} {word}]";
|
return $"TAG_Long_Array({PrettyName}): [{Count} {word}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <i>string</i> representation of this NBT tag (SNBT).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>This NBT tag in SNBT format.</returns>
|
||||||
|
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
|
||||||
|
public override string Stringify() => $"{StringifyName}[L;{string.Join(',', this)}]";
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -64,5 +64,12 @@ namespace SharpNBT
|
||||||
/// <returns>The tag represented as a <see cref="ulong"/>.</returns>
|
/// <returns>The tag represented as a <see cref="ulong"/>.</returns>
|
||||||
[CLSCompliant(false)]
|
[CLSCompliant(false)]
|
||||||
public static implicit operator ulong(LongTag tag) => unchecked((ulong)tag.Value);
|
public static implicit operator ulong(LongTag tag) => unchecked((ulong)tag.Value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <i>string</i> representation of this NBT tag (SNBT).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>This NBT tag in SNBT format.</returns>
|
||||||
|
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
|
||||||
|
public override string Stringify() => $"{StringifyName}{Value}L";
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -64,5 +64,12 @@ namespace SharpNBT
|
||||||
/// <returns>The tag represented as a <see cref="ushort"/>.</returns>
|
/// <returns>The tag represented as a <see cref="ushort"/>.</returns>
|
||||||
[CLSCompliant(false)]
|
[CLSCompliant(false)]
|
||||||
public static implicit operator ushort(ShortTag tag) => unchecked((ushort)tag.Value);
|
public static implicit operator ushort(ShortTag tag) => unchecked((ushort)tag.Value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <i>string</i> representation of this NBT tag (SNBT).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>This NBT tag in SNBT format.</returns>
|
||||||
|
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
|
||||||
|
public override string Stringify() => $"{StringifyName}{Value}S";
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -37,5 +37,12 @@ namespace SharpNBT
|
||||||
/// <param name="tag">The tag to convert.</param>
|
/// <param name="tag">The tag to convert.</param>
|
||||||
/// <returns>The tag represented as a <see cref="string"/>.</returns>
|
/// <returns>The tag represented as a <see cref="string"/>.</returns>
|
||||||
public static implicit operator string(StringTag tag) => tag.Value;
|
public static implicit operator string(StringTag tag) => tag.Value;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <i>string</i> representation of this NBT tag (SNBT).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>This NBT tag in SNBT format.</returns>
|
||||||
|
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
|
||||||
|
public override string Stringify() => $"{StringifyName}\"{Value}\"";
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,6 +4,7 @@ using System.IO;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Runtime.Serialization.Json;
|
using System.Runtime.Serialization.Json;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
|
||||||
[assembly: CLSCompliant(true)]
|
[assembly: CLSCompliant(true)]
|
||||||
|
@ -208,6 +209,27 @@ namespace SharpNBT
|
||||||
/// <param name="right">Second value to compare.</param>
|
/// <param name="right">Second value to compare.</param>
|
||||||
/// <returns>Result of comparison.</returns>
|
/// <returns>Result of comparison.</returns>
|
||||||
public static bool operator !=(Tag left, Tag right) => !Equals(left, right);
|
public static bool operator !=(Tag left, Tag right) => !Equals(left, right);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <i>string</i> representation of this NBT tag (SNBT).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>This NBT tag in SNBT format.</returns>
|
||||||
|
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
|
||||||
|
public abstract string Stringify();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name in a formatted properly for SNBT.
|
||||||
|
/// </summary>
|
||||||
|
[NotNull]
|
||||||
|
protected internal string StringifyName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(Name))
|
||||||
|
return string.Empty;
|
||||||
|
return Regex.IsMatch(Name, @"^[A-Ba-z0-9_-]+$") ? $"{Name}: " : $"\"{Name}\": ";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
Loading…
Reference in New Issue