196 lines
5.1 KiB
C#
196 lines
5.1 KiB
C#
using System;
|
|
using System.Text;
|
|
|
|
namespace LibAC.NBT.API
|
|
{
|
|
public class StringReader
|
|
{
|
|
private readonly string _buffer;
|
|
private int _position = 0;
|
|
private int _lastPosition = 0;
|
|
private bool _quotedString = false;
|
|
|
|
public StringReader(string buffer)
|
|
{
|
|
_buffer = buffer;
|
|
}
|
|
|
|
// Check if there's more to read
|
|
public bool CanRead => _CanRead();
|
|
|
|
private bool _CanRead()
|
|
{
|
|
SkipWhitespace();
|
|
return _position < _buffer.Length;
|
|
}
|
|
|
|
// Get the number of chars seeked
|
|
public int Seeked => _lastPosition - _position;
|
|
|
|
// Read the next character
|
|
public char Next()
|
|
{
|
|
if (CanRead)
|
|
{
|
|
SkipWhitespace();
|
|
return _buffer[_position++];
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("End of buffer reached");
|
|
}
|
|
}
|
|
|
|
// Generates a snapshot of the text location if applicable
|
|
public string GetSnapshot()
|
|
{
|
|
if (CanRead)
|
|
{
|
|
if (_position + 64 < _buffer.Length)
|
|
{
|
|
return _buffer.Substring(_position, 64);
|
|
}
|
|
else
|
|
{
|
|
return _buffer.Substring(_position);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
// Peek the next character without advancing the position
|
|
public char Peek()
|
|
{
|
|
SkipWhitespace();
|
|
if (CanRead)
|
|
{
|
|
return _buffer[_position];
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("End of buffer reached");
|
|
}
|
|
}
|
|
|
|
// Skip any whitespace characters
|
|
public void SkipWhitespace()
|
|
{
|
|
if (_quotedString) return; // We need whitespace for strings
|
|
while (_position < _buffer.Length && IsWhitespace(_buffer[_position]))
|
|
{
|
|
_position++;
|
|
}
|
|
}
|
|
|
|
// Check if a character is a whitespace
|
|
private bool IsWhitespace(char character)
|
|
{
|
|
return char.IsWhiteSpace(character);
|
|
}
|
|
|
|
// Read until a specific character is found
|
|
public string ReadUntil(char stopChar, int maxChars)
|
|
{
|
|
var result = new StringBuilder();
|
|
int index = 0;
|
|
while (CanRead && Peek() != stopChar && index < maxChars)
|
|
{
|
|
result.Append(Next().ToString());
|
|
index++;
|
|
}
|
|
return result.ToString();
|
|
}
|
|
|
|
// Read a string enclosed in double quotes
|
|
public string ReadQuotedString()
|
|
{
|
|
_quotedString = true;
|
|
if (Next() != '"')
|
|
{
|
|
throw new Exception("Expected double quotes at the start of a string");
|
|
}
|
|
var result = new StringBuilder();
|
|
while (CanRead)
|
|
{
|
|
char character = Next();
|
|
if (character == '"')
|
|
{
|
|
break;
|
|
}
|
|
result.Append(character.ToString());
|
|
}
|
|
_quotedString = false;
|
|
return result.ToString();
|
|
}
|
|
|
|
// Read a number (int or double)
|
|
public string ReadNumber()
|
|
{
|
|
var result = new StringBuilder();
|
|
while (CanRead && (IsDigit(Peek()) || Peek() == '.' || Peek() == '-'))
|
|
{
|
|
result.Append(Next().ToString());
|
|
}
|
|
return result.ToString();
|
|
}
|
|
|
|
// Check if a character is a digit
|
|
private bool IsDigit(char character)
|
|
{
|
|
return char.IsDigit(character);
|
|
}
|
|
|
|
// Read an unquoted string (used for keys in SNBT)
|
|
public string ReadUnquotedString()
|
|
{
|
|
var result = new StringBuilder();
|
|
while (CanRead &&
|
|
!IsWhitespace(Peek()) &&
|
|
Peek() != ':' &&
|
|
Peek() != ',' &&
|
|
Peek() != '{' &&
|
|
Peek() != '}' &&
|
|
Peek() != '[' &&
|
|
Peek() != ']')
|
|
{
|
|
result.Append(Next().ToString());
|
|
}
|
|
return result.ToString();
|
|
}
|
|
|
|
public string ReadString()
|
|
{
|
|
if (Peek() == '"')
|
|
{
|
|
return ReadQuotedString();
|
|
}
|
|
else
|
|
{
|
|
return ReadUnquotedString();
|
|
}
|
|
}
|
|
|
|
// Read a specific character and throw an exception if it's not found
|
|
public void Expect(char expectedChar)
|
|
{
|
|
if (char.ToLower(Next()) != char.ToLower(expectedChar))
|
|
{
|
|
throw new Exception($"Expected {expectedChar}");
|
|
}
|
|
}
|
|
|
|
public void StartSeek()
|
|
{
|
|
_lastPosition = _position;
|
|
}
|
|
|
|
public void EndSeek()
|
|
{
|
|
_position = _lastPosition;
|
|
_lastPosition = 0;
|
|
}
|
|
}
|
|
}
|