From c5b9c7709d137fb90786e3370da2f63f32d0354b Mon Sep 17 00:00:00 2001 From: Pavel Djundik Date: Thu, 11 Aug 2022 20:17:07 +0300 Subject: [PATCH] Put common token reader methods in one class --- .../Deserialization/KVTokenReader.cs | 90 +++++++++++++++++++ .../KeyValues1/KV1TokenReader.cs | 80 +---------------- .../KeyValues3/KV3TextReader.cs | 7 +- .../KeyValues3/KV3TokenReader.cs | 85 +----------------- ValveKeyValue/ValveKeyValue/KVSerializer.cs | 2 +- 5 files changed, 97 insertions(+), 167 deletions(-) create mode 100644 ValveKeyValue/ValveKeyValue/Deserialization/KVTokenReader.cs diff --git a/ValveKeyValue/ValveKeyValue/Deserialization/KVTokenReader.cs b/ValveKeyValue/ValveKeyValue/Deserialization/KVTokenReader.cs new file mode 100644 index 00000000..0bb2a91c --- /dev/null +++ b/ValveKeyValue/ValveKeyValue/Deserialization/KVTokenReader.cs @@ -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; + } +} diff --git a/ValveKeyValue/ValveKeyValue/Deserialization/KeyValues1/KV1TokenReader.cs b/ValveKeyValue/ValveKeyValue/Deserialization/KeyValues1/KV1TokenReader.cs index 71284f41..e93de822 100644 --- a/ValveKeyValue/ValveKeyValue/Deserialization/KeyValues1/KV1TokenReader.cs +++ b/ValveKeyValue/ValveKeyValue/Deserialization/KeyValues1/KV1TokenReader.cs @@ -6,7 +6,7 @@ namespace ValveKeyValue.Deserialization.KeyValues1 { - class KV1TokenReader : IDisposable + class KV1TokenReader : KVTokenReader { const char QuotationMark = '"'; const char ObjectStart = '{'; @@ -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() { @@ -52,17 +47,6 @@ public KVToken ReadNextToken() }; } - public void Dispose() - { - if (!disposed) - { - textReader.Dispose(); - textReader = null; - - disposed = true; - } - } - KVToken ReadString() { var text = ReadStringRaw(); @@ -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(); @@ -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(); @@ -288,7 +214,5 @@ string ReadQuotedStringRaw() ReadChar(QuotationMark); return text; } - - bool IsEndOfFile(int value) => value == -1; } } diff --git a/ValveKeyValue/ValveKeyValue/Deserialization/KeyValues3/KV3TextReader.cs b/ValveKeyValue/ValveKeyValue/Deserialization/KeyValues3/KV3TextReader.cs index 71c340f4..0c94706f 100644 --- a/ValveKeyValue/ValveKeyValue/Deserialization/KeyValues3/KV3TextReader.cs +++ b/ValveKeyValue/ValveKeyValue/Deserialization/KeyValues3/KV3TextReader.cs @@ -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; diff --git a/ValveKeyValue/ValveKeyValue/Deserialization/KeyValues3/KV3TokenReader.cs b/ValveKeyValue/ValveKeyValue/Deserialization/KeyValues3/KV3TokenReader.cs index 2e5c22e9..96a44a9f 100644 --- a/ValveKeyValue/ValveKeyValue/Deserialization/KeyValues3/KV3TokenReader.cs +++ b/ValveKeyValue/ValveKeyValue/Deserialization/KeyValues3/KV3TokenReader.cs @@ -8,7 +8,7 @@ namespace ValveKeyValue.Deserialization.KeyValues3 { - class KV3TokenReader : IDisposable + class KV3TokenReader : KVTokenReader { const char ObjectStart = '{'; const char ObjectEnd = '}'; @@ -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(terminators.Select(t => (int)t)); } - readonly KVSerializerOptions options; readonly HashSet integerTerminators; - TextReader textReader; - bool disposed; - int? peekedNext; public KVToken ReadNextToken() { @@ -63,17 +53,6 @@ public KVToken ReadNextToken() }; } - public void Dispose() - { - if (!disposed) - { - textReader.Dispose(); - textReader = null; - - disposed = true; - } - } - KVToken ReadAssignment() { ReadChar(Assignment); @@ -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++) @@ -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); @@ -512,7 +433,5 @@ string ReadQuotedStringRaw(char quotationMark) return sb.ToString(); } - - bool IsEndOfFile(int value) => value == -1; } } diff --git a/ValveKeyValue/ValveKeyValue/KVSerializer.cs b/ValveKeyValue/ValveKeyValue/KVSerializer.cs index ef54bb9d..ea9836bf 100644 --- a/ValveKeyValue/ValveKeyValue/KVSerializer.cs +++ b/ValveKeyValue/ValveKeyValue/KVSerializer.cs @@ -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."), }; }