LibZNI/NBT/API/StringReader.cs

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;
}
}
}