增强输入处理和文件保存功能
在 `Scanner.cs` 中添加了对 `System.Diagnostics` 的引用,并优化了 `MoveNext` 方法以简化空白字符处理和错误处理逻辑。 在 `StringNbt.cs` 中引入了 `System.IO` 和 `System.Numerics`,并修改了解析逻辑以增强输入处理和错误检查。新增了 `IsLineEnd` 方法,并简化了 `MoveNext` 的调用。添加了 `SaveToFile` 和 `SaveToStream` 方法,以支持将 `CompoundTag` 保存为 SNBT 格式。
This commit is contained in:
parent
760c75cadc
commit
ca2d7f49e1
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
|
||||
|
@ -44,12 +45,26 @@ internal ref struct Scanner
|
|||
SyntaxError("Unexpected end of input.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (skipWhitespace && char.IsWhiteSpace(Current))
|
||||
//Debug.Write(Current);
|
||||
if (skipWhitespace && string.IsNullOrWhiteSpace(Current.ToString()))
|
||||
goto ReadChar;
|
||||
return true;
|
||||
}
|
||||
public bool MoveNext(bool fail)
|
||||
{
|
||||
ReadChar:
|
||||
Position++;
|
||||
if (Position >= Source.Length)
|
||||
{
|
||||
if (fail)
|
||||
SyntaxError("Unexpected end of input.");
|
||||
return false;
|
||||
}
|
||||
//Debug.Write(Current);
|
||||
if (char.IsWhiteSpace(Current) && Current != '\n')
|
||||
goto ReadChar;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void AssertChar(char c)
|
||||
{
|
||||
if (Current != c)
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
using JetBrains.Annotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace SharpNBT.SNBT;
|
||||
|
||||
|
@ -83,6 +84,12 @@ public static class StringNbt
|
|||
|
||||
while (!scanner.IsEndOfInput)
|
||||
{
|
||||
// Closing brace encountered, break loop.
|
||||
if (scanner.Current == '}')
|
||||
{
|
||||
// scanner.MoveNext(true, false);
|
||||
break;
|
||||
}
|
||||
// Read the name of the tag
|
||||
var childName = ParseString(ref scanner, out _);
|
||||
|
||||
|
@ -94,22 +101,22 @@ public static class StringNbt
|
|||
scanner.MoveNext(true, true);
|
||||
var tag = ParseTag(childName, ref scanner);
|
||||
result.Add(tag);
|
||||
scanner.MoveNext(true, true);
|
||||
scanner.MoveNext( true);
|
||||
|
||||
// Comma encountered, read another tag.
|
||||
if (scanner.Current == ',')
|
||||
if (IsLineEnd(scanner.Current))
|
||||
{
|
||||
scanner.MoveNext(true, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Closing brace encountered, break loop.
|
||||
if (scanner.Current == '}')
|
||||
{
|
||||
// scanner.MoveNext(true, false);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Invalid character
|
||||
scanner.SyntaxError($"Expected ',' or '}}', got '{scanner.Current}'.");
|
||||
}
|
||||
|
@ -309,24 +316,28 @@ public static class StringNbt
|
|||
var list = new List<Tag>();
|
||||
while (true)
|
||||
{
|
||||
var child = ParseTag(null, ref scanner);
|
||||
list.Add(child);
|
||||
|
||||
scanner.MoveNext(true, true);
|
||||
|
||||
// Comma encountered, read another tag.
|
||||
if (scanner.Current == ',')
|
||||
{
|
||||
scanner.MoveNext(true, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Closing brace encountered, break loop.
|
||||
if (scanner.Current == ']')
|
||||
{
|
||||
break;
|
||||
}
|
||||
var child = ParseTag(null, ref scanner);
|
||||
list.Add(child);
|
||||
|
||||
scanner.MoveNext(true);
|
||||
|
||||
// Comma encountered, read another tag.
|
||||
if (IsLineEnd(scanner.Current))
|
||||
{
|
||||
scanner.MoveNext(true, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (scanner.Current == ']')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Invalid character
|
||||
scanner.SyntaxError($"Expected ',' or ']', got '{scanner.Current}'.");
|
||||
}
|
||||
|
@ -349,7 +360,7 @@ public static class StringNbt
|
|||
var c = char.ToLowerInvariant(scanner.Current);
|
||||
if (c == ']')
|
||||
break;
|
||||
if (char.IsNumber(c) || c == ',')
|
||||
if (char.IsNumber(c) ||c == ',' || c == '-')
|
||||
continue;
|
||||
if (c is not ('b' or 'l'))
|
||||
scanner.SyntaxError($"Invalid character '{c}' in integer array.");
|
||||
|
@ -366,5 +377,62 @@ public static class StringNbt
|
|||
}
|
||||
|
||||
private const StringSplitOptions SplitOpts = StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries;
|
||||
private static readonly char[] SplitSeparators = new[] { ',', 'b', 'B', 'l', 'L' };
|
||||
private static readonly char[] SplitSeparators = new[] { ',', 'b', 'B', 'l', 'L','\n' };
|
||||
|
||||
private static bool IsLineEnd(char c)
|
||||
{
|
||||
return c == ',' || c == '\n' || c == '\r';
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Saves a <see cref="CompoundTag"/> to a file in SNBT format.
|
||||
/// </summary>
|
||||
/// <param name="tag">The <see cref="CompoundTag"/> to save.</param>
|
||||
/// <param name="filePath">The path to the file where the SNBT data will be saved.</param>
|
||||
/// <param name="prettyPrint">Whether to format the output in a human-readable format.</param>
|
||||
/// <exception cref="ArgumentNullException">When <paramref name="tag"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="IOException">When there is an error writing to the file.</exception>
|
||||
public static void SaveToFile(CompoundTag tag, string filePath, bool prettyPrint = false)
|
||||
{
|
||||
if (tag == null)
|
||||
throw new ArgumentNullException(nameof(tag));
|
||||
|
||||
string snbt = prettyPrint ? tag.PrettyPrinted() : tag.Stringify(true);
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(filePath, snbt, Encoding.UTF8);
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or DirectoryNotFoundException)
|
||||
{
|
||||
throw new IOException($"Failed to write SNBT to file '{filePath}': {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a <see cref="CompoundTag"/> to a file in SNBT format.
|
||||
/// </summary>
|
||||
/// <param name="tag">The <see cref="CompoundTag"/> to save.</param>
|
||||
/// <param name="stream">The stream where the SNBT data will be written.</param>
|
||||
/// <param name="prettyPrint">Whether to format the output in a human-readable format.</param>
|
||||
/// <param name="encoding">The text encoding to use. Defaults to UTF-8 if null.</param>
|
||||
/// <exception cref="ArgumentNullException">When <paramref name="tag"/> or <paramref name="stream"/> is <see langword="null"/>.</exception>
|
||||
/// <exception cref="IOException">When there is an error writing to the stream.</exception>
|
||||
public static void SaveToStream(CompoundTag tag, Stream stream, bool prettyPrint = false, Encoding? encoding = null)
|
||||
{
|
||||
if (tag == null)
|
||||
throw new ArgumentNullException(nameof(tag));
|
||||
if (stream == null)
|
||||
throw new ArgumentNullException(nameof(stream));
|
||||
if (!stream.CanWrite)
|
||||
throw new IOException("Cannot write to the specified stream.");
|
||||
|
||||
string snbt = prettyPrint ? tag.PrettyPrinted() : tag.Stringify(true);
|
||||
encoding ??= Encoding.UTF8;
|
||||
|
||||
using var writer = new StreamWriter(stream, encoding, leaveOpen: true);
|
||||
writer.Write(snbt);
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue