diff --git a/SharpNBT/SNBT/StringNbt.cs b/SharpNBT/SNBT/StringNbt.cs
index c35f190..3619ff9 100644
--- a/SharpNBT/SNBT/StringNbt.cs
+++ b/SharpNBT/SNBT/StringNbt.cs
@@ -24,13 +24,54 @@ public static class StringNbt
public static CompoundTag Parse(string source)
{
var bytes = Encoding.UTF8.GetBytes(source);
- var scanner = new Scanner(bytes, Encoding.UTF8);
-
+ return Parse(bytes, Encoding.UTF8);
+ }
+
+ ///
+ /// Parse the given text into a .
+ ///
+ /// A string containing the SNBT code to parse.
+ /// The instance described in the source text.
+ /// When is .
+ /// When is invalid SNBT code.
+ public static ListTag ParseList(string source)
+ {
+ var bytes = Encoding.UTF8.GetBytes(source);
+ return ParseList(bytes, Encoding.UTF8);
+ }
+
+ ///
+ /// Parse the given text into a .
+ ///
+ /// A string containing the SNBT code to parse.
+ /// Encoding of the .
+ /// The instance described in the source text.
+ /// When is .
+ /// When is invalid SNBT code.
+ public static CompoundTag Parse(ReadOnlySpan source, Encoding? encoding = null)
+ {
+ var scanner = new Scanner(source, encoding ?? Encoding.UTF8);
scanner.MoveNext(true, true);
scanner.AssertChar('{');
return ParseCompound(null, ref scanner);
}
-
+
+ ///
+ /// Parse the given text into a .
+ ///
+ /// A string containing the SNBT code to parse.
+ /// Encoding of the .
+ /// The instance described in the source text.
+ /// When is .
+ /// When is invalid SNBT code.
+ public static ListTag ParseList(ReadOnlySpan source, Encoding? encoding = null)
+ {
+ var scanner = new Scanner(source, encoding ?? Encoding.UTF8);
+ scanner.MoveNext(true, true);
+ scanner.AssertChar('[');
+ return ParseList(null, ref scanner);
+ }
+
private static CompoundTag ParseCompound(string? name, ref Scanner scanner)
{
scanner.MoveNext(true, true);
@@ -40,23 +81,20 @@ public static class StringNbt
if (scanner.Current == '}')
return result;
- while (true)
+ while (!scanner.IsEndOfInput)
{
// Read the name of the tag
var childName = ParseString(ref scanner, out _);
// Move to and asser the next significant character is a deliminator.
- // scanner.MoveNext(true, true);
+ scanner.MoveNext(true, true);
scanner.AssertChar(':');
// Move to and parse the tag value
scanner.MoveNext(true, true);
var tag = ParseTag(childName, ref scanner);
result.Add(tag);
- // scanner.MoveNext(true, true);
-
- if (char.IsWhiteSpace(scanner.Current))
- scanner.MoveNext(true, true);
+ scanner.MoveNext(true, true);
// Comma encountered, read another tag.
if (scanner.Current == ',')
@@ -68,7 +106,7 @@ public static class StringNbt
// Closing brace encountered, break loop.
if (scanner.Current == '}')
{
- scanner.MoveNext(true, false);
+ // scanner.MoveNext(true, false);
break;
}
@@ -79,6 +117,15 @@ public static class StringNbt
return result;
}
+ ///
+ /// Parses the next logical chunk of data as a string.
+ ///
+ /// A reference to the context.
+ ///
+ /// Flag indicating if the value was enclosed in a pair of matching single/double quotes, otherwise
+ /// if it was read as a literal span of characters from the input.
+ ///
+ /// The scanned string.
private static string ParseString(ref Scanner scanner, out bool quoted)
{
var quote = scanner.Current;
@@ -105,7 +152,6 @@ public static class StringNbt
if (scanner.Current == quote)
{
closed = true;
- scanner.Position++;
break;
}
@@ -129,8 +175,12 @@ public static class StringNbt
var start = scanner.Position;
for (var length = 0; scanner.MoveNext(false, true); length++)
{
- if (!AllowedInUnquoted(scanner.Current))
- return new string(scanner.Source.Slice(start, length + 1));
+ if (AllowedInUnquoted(scanner.Current))
+ continue;
+
+ // Step back one character so not to consume the one that failed the permission check.
+ scanner.Position--;
+ return new string(scanner.Source.Slice(start, length + 1));
}
return string.Empty;
@@ -179,11 +229,10 @@ public static class StringNbt
return new IntTag(name, hex);
}
- // When all else fails, assume it is an unquoted string
+ // When all else fails, is could only have been an unquoted string
return new StringTag(name, value);
}
-
-
+
private static bool TryParseNumber(string? name, string value, char suffix, out Tag tag)
{
// A much less complicated char.ToLower()
@@ -239,34 +288,31 @@ public static class StringNbt
if (scanner.Current == ']')
return new ListTag(name, TagType.End);
- if (scanner.Peek() == ';')
+ // No type-prefix, must be a ListTag
+ if (scanner.Peek() != ';')
+ return ParseList(name, ref scanner);
+
+ // This is an array of integral values
+ var prefix = scanner.Current;
+ scanner.Position += 2;
+ return prefix switch
{
- // This is an array of integer values
- var prefix = scanner.Current;
- scanner.Position += 2;
- return prefix switch
- {
- 'B' => new ByteArrayTag(name, ParseArrayValues(ref scanner)),
- 'I' => new IntArrayTag(name, ParseArrayValues(ref scanner)),
- 'L' => new LongArrayTag(name, ParseArrayValues(ref scanner)),
- _ => throw scanner.SyntaxError($"Invalid type specifier. Expected 'B', 'I', or 'L', got '{prefix}'.")
- };
- }
-
- // No prefix, so this must be a list of tags if valid
- return ParseList(name, ref scanner);
+ 'B' => new ByteArrayTag(name, ParseArrayValues(ref scanner)),
+ 'I' => new IntArrayTag(name, ParseArrayValues(ref scanner)),
+ 'L' => new LongArrayTag(name, ParseArrayValues(ref scanner)),
+ _ => throw scanner.SyntaxError($"Invalid type specifier. Expected 'B', 'I', or 'L', got '{prefix}'.")
+ };
}
- private static Tag ParseList(string? name, ref Scanner scanner)
+ private static ListTag ParseList(string? name, ref Scanner scanner)
{
var list = new List();
while (true)
{
var child = ParseTag(null, ref scanner);
list.Add(child);
-
- if (char.IsWhiteSpace(scanner.Current))
- scanner.MoveNext(true, true);
+
+ scanner.MoveNext(true, true);
// Comma encountered, read another tag.
if (scanner.Current == ',')
@@ -278,7 +324,6 @@ public static class StringNbt
// Closing brace encountered, break loop.
if (scanner.Current == ']')
{
- scanner.MoveNext(true, false);
break;
}
@@ -295,7 +340,6 @@ public static class StringNbt
// Early-out for []
if (scanner.Current == ']')
{
- scanner.Position++;
return Array.Empty();
}
@@ -317,8 +361,7 @@ public static class StringNbt
var values = new T[strings.Length];
for (var i = 0; i < values.Length; i++)
values[i] = T.Parse(strings[i], NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
-
- scanner.Position++; // Consume the closing ']'
+
return values;
}