Skip to content

Commit

Permalink
Put common token reader methods in one class
Browse files Browse the repository at this point in the history
  • Loading branch information
xPaw committed Oct 14, 2022
1 parent c841c7d commit c5b9c77
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 167 deletions.
90 changes: 90 additions & 0 deletions ValveKeyValue/ValveKeyValue/Deserialization/KVTokenReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System;
using System.IO;

namespace ValveKeyValue.Deserialization
{
abstract class KVTokenReader : IDisposable
{
public KVTokenReader(TextReader textReader)
{
Require.NotNull(textReader, nameof(textReader));

this.textReader = textReader;
}

protected TextReader textReader;
protected int? peekedNext;
protected bool disposed;

public void Dispose()
{
if (!disposed)
{
textReader.Dispose();
textReader = null;

disposed = true;
}
}

protected char Next()
{
int next;

if (peekedNext.HasValue)
{
next = peekedNext.Value;
peekedNext = null;
}
else
{
next = textReader.Read();
}

if (IsEndOfFile(next))
{
throw new EndOfStreamException();
}

return (char)next;
}

protected int Peek()
{
if (peekedNext.HasValue)
{
return peekedNext.Value;
}

var next = textReader.Read();
peekedNext = next;

return next;
}

protected void ReadChar(char expectedChar)
{
var next = Next();
if (next != expectedChar)
{
throw new InvalidDataException($"The syntax is incorrect, expected '{expectedChar}' but got '{next}'.");
}
}

protected void SwallowWhitespace()
{
while (PeekWhitespace())
{
Next();
}
}

protected bool PeekWhitespace()
{
var next = Peek();
return !IsEndOfFile(next) && char.IsWhiteSpace((char)next);
}

protected bool IsEndOfFile(int value) => value == -1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace ValveKeyValue.Deserialization.KeyValues1
{
class KV1TokenReader : IDisposable
class KV1TokenReader : KVTokenReader
{
const char QuotationMark = '"';
const char ObjectStart = '{';
Expand All @@ -16,19 +16,14 @@ class KV1TokenReader : IDisposable
const char ConditionEnd = ']';
const char InclusionMark = '#';

public KV1TokenReader(TextReader textReader, KVSerializerOptions options)
public KV1TokenReader(TextReader textReader, KVSerializerOptions options) : base(textReader)
{
Require.NotNull(textReader, nameof(textReader));
Require.NotNull(options, nameof(options));

this.textReader = textReader;
this.options = options;
}

readonly KVSerializerOptions options;
TextReader textReader;
bool disposed;
int? peekedNext;

public KVToken ReadNextToken()
{
Expand All @@ -52,17 +47,6 @@ public KVToken ReadNextToken()
};
}

public void Dispose()
{
if (!disposed)
{
textReader.Dispose();
textReader = null;

disposed = true;
}
}

KVToken ReadString()
{
var text = ReadStringRaw();
Expand Down Expand Up @@ -143,50 +127,6 @@ KVToken ReadInclusion()
throw new InvalidDataException("Unrecognized term after '#' symbol.");
}

char Next()
{
int next;

if (peekedNext.HasValue)
{
next = peekedNext.Value;
peekedNext = null;
}
else
{
next = textReader.Read();
}

if (next == -1)
{
throw new EndOfStreamException();
}

return (char)next;
}

int Peek()
{
if (peekedNext.HasValue)
{
return peekedNext.Value;
}

var next = textReader.Read();
peekedNext = next;

return next;
}

void ReadChar(char expectedChar)
{
var next = Next();
if (next != expectedChar)
{
throw new InvalidDataException($"The syntax is incorrect, expected '{expectedChar}' but got '{next}'.");
}
}

string ReadUntil(params char[] terminators)
{
var sb = new StringBuilder();
Expand Down Expand Up @@ -254,20 +194,6 @@ string ReadUntilWhitespaceOrQuote()
return sb.ToString();
}

void SwallowWhitespace()
{
while (PeekWhitespace())
{
Next();
}
}

bool PeekWhitespace()
{
var next = Peek();
return !IsEndOfFile(next) && char.IsWhiteSpace((char)next);
}

string ReadStringRaw()
{
SwallowWhitespace();
Expand All @@ -288,7 +214,5 @@ string ReadQuotedStringRaw()
ReadChar(QuotationMark);
return text;
}

bool IsEndOfFile(int value) => value == -1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,18 @@ namespace ValveKeyValue.Deserialization.KeyValues3
{
sealed class KV3TextReader : IVisitingReader
{
public KV3TextReader(TextReader textReader, IParsingVisitationListener listener, KVSerializerOptions options)
public KV3TextReader(TextReader textReader, IParsingVisitationListener listener)
{
Require.NotNull(textReader, nameof(textReader));
Require.NotNull(listener, nameof(listener));
Require.NotNull(options, nameof(options));

this.listener = listener;
this.options = options;

tokenReader = new KV3TokenReader(textReader, options);
tokenReader = new KV3TokenReader(textReader);
stateMachine = new KV3TextReaderStateMachine();
}

readonly IParsingVisitationListener listener;
readonly KVSerializerOptions options;

readonly KV3TokenReader tokenReader;
readonly KV3TextReaderStateMachine stateMachine;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace ValveKeyValue.Deserialization.KeyValues3
{
class KV3TokenReader : IDisposable
class KV3TokenReader : KVTokenReader
{
const char ObjectStart = '{';
const char ObjectEnd = '}';
Expand All @@ -19,24 +19,14 @@ class KV3TokenReader : IDisposable
const char Assignment = '=';
const char Comma = ',';

public KV3TokenReader(TextReader textReader, KVSerializerOptions options)
public KV3TokenReader(TextReader textReader) : base(textReader)
{
Require.NotNull(textReader, nameof(textReader));
Require.NotNull(options, nameof(options));

this.textReader = textReader;
this.options = options;

// Dota 2 binary from 2017 used "+" as a terminate (for flagged values), but then they changed it to "|"
var terminators = "{}[]=, \t\n\r'\":|;".ToCharArray();
integerTerminators = new HashSet<int>(terminators.Select(t => (int)t));
}

readonly KVSerializerOptions options;
readonly HashSet<int> integerTerminators;
TextReader textReader;
bool disposed;
int? peekedNext;

public KVToken ReadNextToken()
{
Expand All @@ -63,17 +53,6 @@ public KVToken ReadNextToken()
};
}

public void Dispose()
{
if (!disposed)
{
textReader.Dispose();
textReader = null;

disposed = true;
}
}

KVToken ReadAssignment()
{
ReadChar(Assignment);
Expand Down Expand Up @@ -309,50 +288,6 @@ KVToken ReadComment()
return new KVToken(KVTokenType.Comment, text);
}

char Next()
{
int next;

if (peekedNext.HasValue)
{
next = peekedNext.Value;
peekedNext = null;
}
else
{
next = textReader.Read();
}

if (IsEndOfFile(next))
{
throw new EndOfStreamException();
}

return (char)next;
}

int Peek()
{
if (peekedNext.HasValue)
{
return peekedNext.Value;
}

var next = textReader.Read();
peekedNext = next;

return next;
}

void ReadChar(char expectedChar)
{
var next = Next();
if (next != expectedChar)
{
throw new InvalidDataException($"The syntax is incorrect, expected '{expectedChar}' but got '{next}'.");
}
}

bool IsIdentifier(string text)
{
for (var i = 0; i < text.Length; i++)
Expand Down Expand Up @@ -406,20 +341,6 @@ string ReadToken()
return sb.ToString();
}

void SwallowWhitespace()
{
while (PeekWhitespace())
{
Next();
}
}

bool PeekWhitespace()
{
var next = Peek();
return !IsEndOfFile(next) && char.IsWhiteSpace((char)next);
}

string ReadQuotedStringRaw(char quotationMark)
{
ReadChar(quotationMark);
Expand Down Expand Up @@ -512,7 +433,5 @@ string ReadQuotedStringRaw(char quotationMark)

return sb.ToString();
}

bool IsEndOfFile(int value) => value == -1;
}
}
2 changes: 1 addition & 1 deletion ValveKeyValue/ValveKeyValue/KVSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ IVisitingReader MakeReader(Stream stream, IParsingVisitationListener listener, K
{
KVSerializationFormat.KeyValues1Text => new KV1TextReader(new StreamReader(stream), listener, options),
KVSerializationFormat.KeyValues1Binary => new KV1BinaryReader(stream, listener),
KVSerializationFormat.KeyValues3Text => new KV3TextReader(new StreamReader(stream), listener, options),
KVSerializationFormat.KeyValues3Text => new KV3TextReader(new StreamReader(stream), listener),
_ => throw new ArgumentOutOfRangeException(nameof(format), format, "Invalid serialization format."),
};
}
Expand Down

0 comments on commit c5b9c77

Please sign in to comment.