<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />

JsonTextReader

Represents a reader that provides fast, non-cached, forward-only access to JSON text data.
using Newtonsoft.Json.Utilities; using System; using System.Globalization; using System.IO; using System.Threading; using System.Threading.Tasks; namespace Newtonsoft.Json { public class JsonTextReader : JsonReader, IJsonLineInfo { private readonly bool _safeAsync; private const char UnicodeReplacementChar = '�'; private const int MaximumJavascriptIntegerCharacterLength = 380; private const int LargeBufferLength = 1073741823; private readonly TextReader _reader; private char[] _chars; private int _charsUsed; private int _charPos; private int _lineStartPos; private int _lineNumber; private bool _isEndOfFile; private StringBuffer _stringBuffer; private StringReference _stringReference; private IArrayPool<char> _arrayPool; internal PropertyNameTable NameTable; public IArrayPool<char> ArrayPool { get { return _arrayPool; } set { if (value == null) throw new ArgumentNullException("value"); _arrayPool = value; } } public int LineNumber { get { if (base.CurrentState == State.Start && LinePosition == 0 && TokenType != JsonToken.Comment) return 0; return _lineNumber; } } public int LinePosition => _charPos - _lineStartPos; public override Task<bool> ReadAsync(CancellationToken cancellationToken = default(CancellationToken)) { if (!_safeAsync) return base.ReadAsync(cancellationToken); return DoReadAsync(cancellationToken); } internal Task<bool> DoReadAsync(CancellationToken cancellationToken) { EnsureBuffer(); Task<bool> task; while (true) { switch (_currentState) { case State.Start: case State.Property: case State.ArrayStart: case State.Array: case State.ConstructorStart: case State.Constructor: return ParseValueAsync(cancellationToken); case State.ObjectStart: case State.Object: return ParseObjectAsync(cancellationToken); case State.PostValue: break; case State.Finished: return ReadFromFinishedAsync(cancellationToken); default: throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, base.CurrentState)); } task = ParsePostValueAsync(false, cancellationToken); if (!task.IsCompletedSucessfully()) break; if (task.Result) return AsyncUtils.True; } return DoReadAsync(task, cancellationToken); } private async Task<bool> DoReadAsync(Task<bool> task, CancellationToken cancellationToken) { if (await task.ConfigureAwait(false)) return true; return await DoReadAsync(cancellationToken).ConfigureAwait(false); } private async Task<bool> ParsePostValueAsync(bool ignoreComments, CancellationToken cancellationToken) { while (true) { char currentChar = _chars[_charPos]; switch (currentChar) { case '': if (_charsUsed == _charPos) { if (await ReadDataAsync(false, cancellationToken).ConfigureAwait(false) == 0) { _currentState = State.Finished; return false; } } else _charPos++; break; case '}': _charPos++; SetToken(JsonToken.EndObject); return true; case ']': _charPos++; SetToken(JsonToken.EndArray); return true; case ')': _charPos++; SetToken(JsonToken.EndConstructor); return true; case '/': await ParseCommentAsync(!ignoreComments, cancellationToken).ConfigureAwait(false); if (!ignoreComments) return true; break; case ',': _charPos++; SetStateBasedOnCurrent(); return false; case '\t': case ' ': _charPos++; break; case '\r': await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false); break; case '\n': ProcessLineFeed(); break; default: if (!char.IsWhiteSpace(currentChar)) { if (base.SupportMultipleContent && Depth == 0) { SetStateBasedOnCurrent(); return false; } throw JsonReaderException.Create(this, "After parsing a value an unexpected character was encountered: {0}.".FormatWith(CultureInfo.InvariantCulture, currentChar)); } _charPos++; break; } } } private async Task<bool> ReadFromFinishedAsync(CancellationToken cancellationToken) { if (await EnsureCharsAsync(0, false, cancellationToken).ConfigureAwait(false)) { await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false); if (_isEndOfFile) { SetToken(JsonToken.None); return false; } if (_chars[_charPos] == '/') { await ParseCommentAsync(true, cancellationToken).ConfigureAwait(false); return true; } throw JsonReaderException.Create(this, "Additional text encountered after finished reading JSON content: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); } SetToken(JsonToken.None); return false; } private Task<int> ReadDataAsync(bool append, CancellationToken cancellationToken) { return ReadDataAsync(append, 0, cancellationToken); } private async Task<int> ReadDataAsync(bool append, int charsRequired, CancellationToken cancellationToken) { if (_isEndOfFile) return 0; PrepareBufferForReadData(append, charsRequired); int num = await _reader.ReadAsync(_chars, _charsUsed, _chars.Length - _charsUsed - 1, cancellationToken).ConfigureAwait(false); _charsUsed += num; if (num == 0) _isEndOfFile = true; _chars[_charsUsed] = ''; return num; } private async Task<bool> ParseValueAsync(CancellationToken cancellationToken) { while (true) { char currentChar = _chars[_charPos]; switch (currentChar) { case '': if (_charsUsed == _charPos) { if (await ReadDataAsync(false, cancellationToken).ConfigureAwait(false) == 0) return false; } else _charPos++; break; case '"': case '\'': await ParseStringAsync(currentChar, ReadType.Read, cancellationToken).ConfigureAwait(false); return true; case 't': await ParseTrueAsync(cancellationToken).ConfigureAwait(false); return true; case 'f': await ParseFalseAsync(cancellationToken).ConfigureAwait(false); return true; case 'n': if (!(await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false))) { _charPos++; throw CreateUnexpectedEndException(); } switch (_chars[_charPos + 1]) { case 'u': await ParseNullAsync(cancellationToken).ConfigureAwait(false); break; case 'e': await ParseConstructorAsync(cancellationToken).ConfigureAwait(false); break; default: throw CreateUnexpectedCharacterException(_chars[_charPos]); } return true; case 'N': await ParseNumberNaNAsync(ReadType.Read, cancellationToken).ConfigureAwait(false); return true; case 'I': await ParseNumberPositiveInfinityAsync(ReadType.Read, cancellationToken).ConfigureAwait(false); return true; case '-': if (!(await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false)) || _chars[_charPos + 1] != 'I') await ParseNumberAsync(ReadType.Read, cancellationToken).ConfigureAwait(false); else await ParseNumberNegativeInfinityAsync(ReadType.Read, cancellationToken).ConfigureAwait(false); return true; case '/': await ParseCommentAsync(true, cancellationToken).ConfigureAwait(false); return true; case 'u': await ParseUndefinedAsync(cancellationToken).ConfigureAwait(false); return true; case '{': _charPos++; SetToken(JsonToken.StartObject); return true; case '[': _charPos++; SetToken(JsonToken.StartArray); return true; case ']': _charPos++; SetToken(JsonToken.EndArray); return true; case ',': SetToken(JsonToken.Undefined); return true; case ')': _charPos++; SetToken(JsonToken.EndConstructor); return true; case '\r': await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false); break; case '\n': ProcessLineFeed(); break; case '\t': case ' ': _charPos++; break; default: if (!char.IsWhiteSpace(currentChar)) { if (char.IsNumber(currentChar) || currentChar == '-' || currentChar == '.') { await ParseNumberAsync(ReadType.Read, cancellationToken).ConfigureAwait(false); return true; } throw CreateUnexpectedCharacterException(currentChar); } _charPos++; break; } } } private async Task ReadStringIntoBufferAsync(char quote, CancellationToken cancellationToken) { int charPos = _charPos; int initialPosition = _charPos; int lastWritePosition = _charPos; _stringBuffer.Position = 0; while (true) { char[] chars = _chars; int num = charPos; charPos = num + 1; switch (chars[num]) { case '': if (_charsUsed == charPos - 1) { charPos--; if (await ReadDataAsync(true, cancellationToken).ConfigureAwait(false) == 0) { _charPos = charPos; throw JsonReaderException.Create(this, "Unterminated string. Expected delimiter: {0}.".FormatWith(CultureInfo.InvariantCulture, quote)); } } break; case '\\': { _charPos = charPos; if (!(await EnsureCharsAsync(0, true, cancellationToken).ConfigureAwait(false))) throw JsonReaderException.Create(this, "Unterminated string. Expected delimiter: {0}.".FormatWith(CultureInfo.InvariantCulture, quote)); int escapeStartPos = charPos - 1; char currentChar = _chars[charPos]; charPos++; char writeChar; switch (currentChar) { case 'b': writeChar = '\b'; break; case 't': writeChar = '\t'; break; case 'n': writeChar = '\n'; break; case 'f': writeChar = ' '; break; case 'r': writeChar = '\r'; break; case '\\': writeChar = '\\'; break; case '"': case '\'': case '/': writeChar = currentChar; break; case 'u': _charPos = charPos; writeChar = await ParseUnicodeAsync(cancellationToken).ConfigureAwait(false); if (StringUtils.IsLowSurrogate(writeChar)) writeChar = '�'; else if (StringUtils.IsHighSurrogate(writeChar)) { bool anotherHighSurrogate; do { anotherHighSurrogate = false; if (await EnsureCharsAsync(2, true, cancellationToken).ConfigureAwait(false) && _chars[_charPos] == '\\' && _chars[_charPos + 1] == 'u') { char highSurrogate = writeChar; _charPos += 2; writeChar = await ParseUnicodeAsync(cancellationToken).ConfigureAwait(false); if (!StringUtils.IsLowSurrogate(writeChar)) { if (StringUtils.IsHighSurrogate(writeChar)) { highSurrogate = '�'; anotherHighSurrogate = true; } else highSurrogate = '�'; } EnsureBufferNotEmpty(); WriteCharToBuffer(highSurrogate, lastWritePosition, escapeStartPos); lastWritePosition = _charPos; } else writeChar = '�'; } while (anotherHighSurrogate); } charPos = _charPos; break; default: _charPos = charPos; throw JsonReaderException.Create(this, "Bad JSON escape sequence: {0}.".FormatWith(CultureInfo.InvariantCulture, "\\" + currentChar.ToString())); } EnsureBufferNotEmpty(); WriteCharToBuffer(writeChar, lastWritePosition, escapeStartPos); lastWritePosition = charPos; break; } case '\r': _charPos = charPos - 1; await ProcessCarriageReturnAsync(true, cancellationToken).ConfigureAwait(false); charPos = _charPos; break; case '\n': _charPos = charPos - 1; ProcessLineFeed(); charPos = _charPos; break; case '"': case '\'': if (_chars[charPos - 1] == quote) { FinishReadStringIntoBuffer(charPos - 1, initialPosition, lastWritePosition); return; } break; } } } private Task ProcessCarriageReturnAsync(bool append, CancellationToken cancellationToken) { _charPos++; Task<bool> task = EnsureCharsAsync(1, append, cancellationToken); if (task.IsCompletedSucessfully()) { SetNewLine(task.Result); return AsyncUtils.CompletedTask; } return ProcessCarriageReturnAsync(task); } private async Task ProcessCarriageReturnAsync(Task<bool> task) { SetNewLine(await task.ConfigureAwait(false)); } private async Task<char> ParseUnicodeAsync(CancellationToken cancellationToken) { return ConvertUnicode(await EnsureCharsAsync(4, true, cancellationToken).ConfigureAwait(false)); } private Task<bool> EnsureCharsAsync(int relativePosition, bool append, CancellationToken cancellationToken) { if (_charPos + relativePosition < _charsUsed) return AsyncUtils.True; if (_isEndOfFile) return AsyncUtils.False; return ReadCharsAsync(relativePosition, append, cancellationToken); } private async Task<bool> ReadCharsAsync(int relativePosition, bool append, CancellationToken cancellationToken) { int charsRequired = _charPos + relativePosition - _charsUsed + 1; do { int num = await ReadDataAsync(append, charsRequired, cancellationToken).ConfigureAwait(false); if (num == 0) return false; charsRequired -= num; } while (charsRequired > 0); return true; } private async Task<bool> ParseObjectAsync(CancellationToken cancellationToken) { while (true) { char currentChar = _chars[_charPos]; switch (currentChar) { case '': if (_charsUsed == _charPos) { if (await ReadDataAsync(false, cancellationToken).ConfigureAwait(false) == 0) return false; } else _charPos++; break; case '}': SetToken(JsonToken.EndObject); _charPos++; return true; case '/': await ParseCommentAsync(true, cancellationToken).ConfigureAwait(false); return true; case '\r': await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false); break; case '\n': ProcessLineFeed(); break; case '\t': case ' ': _charPos++; break; default: if (!char.IsWhiteSpace(currentChar)) return await ParsePropertyAsync(cancellationToken).ConfigureAwait(false); _charPos++; break; } } } private async Task ParseCommentAsync(bool setToken, CancellationToken cancellationToken) { _charPos++; if (await EnsureCharsAsync(1, false, cancellationToken).ConfigureAwait(false)) { bool singlelineComment; if (_chars[_charPos] == '*') singlelineComment = false; else { if (_chars[_charPos] != '/') throw JsonReaderException.Create(this, "Error parsing comment. Expected: *, got {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); singlelineComment = true; } _charPos++; int initialPosition = _charPos; while (true) { switch (_chars[_charPos]) { case '': if (_charsUsed == _charPos) { if (await ReadDataAsync(true, cancellationToken).ConfigureAwait(false) == 0) { if (!singlelineComment) throw JsonReaderException.Create(this, "Unexpected end while parsing comment."); EndComment(setToken, initialPosition, _charPos); return; } } else _charPos++; break; case '*': _charPos++; if (!singlelineComment && await EnsureCharsAsync(0, true, cancellationToken).ConfigureAwait(false) && _chars[_charPos] == '/') { EndComment(setToken, initialPosition, _charPos - 1); _charPos++; return; } break; case '\r': if (singlelineComment) { EndComment(setToken, initialPosition, _charPos); return; } await ProcessCarriageReturnAsync(true, cancellationToken).ConfigureAwait(false); break; case '\n': if (singlelineComment) { EndComment(setToken, initialPosition, _charPos); return; } ProcessLineFeed(); break; default: _charPos++; break; } } } throw JsonReaderException.Create(this, "Unexpected end while parsing comment."); } private async Task EatWhitespaceAsync(CancellationToken cancellationToken) { while (true) { char currentChar = _chars[_charPos]; switch (currentChar) { case '': if (_charsUsed == _charPos) { if (await ReadDataAsync(false, cancellationToken).ConfigureAwait(false) == 0) return; } else _charPos++; break; case '\r': await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false); break; case '\n': ProcessLineFeed(); break; default: if (currentChar != ' ' && !char.IsWhiteSpace(currentChar)) return; _charPos++; break; } } } private async Task ParseStringAsync(char quote, ReadType readType, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); _charPos++; ShiftBufferIfNeeded(); await ReadStringIntoBufferAsync(quote, cancellationToken).ConfigureAwait(false); ParseReadString(quote, readType); } private async Task<bool> MatchValueAsync(string value, CancellationToken cancellationToken) { return MatchValue(await EnsureCharsAsync(value.Length - 1, true, cancellationToken).ConfigureAwait(false), value); } private async Task<bool> MatchValueWithTrailingSeparatorAsync(string value, CancellationToken cancellationToken) { if (!(await MatchValueAsync(value, cancellationToken).ConfigureAwait(false))) return false; if (!(await EnsureCharsAsync(0, false, cancellationToken).ConfigureAwait(false))) return true; return IsSeparator(_chars[_charPos]) || _chars[_charPos] == ''; } private async Task MatchAndSetAsync(string value, JsonToken newToken, object tokenValue, CancellationToken cancellationToken) { if (await MatchValueWithTrailingSeparatorAsync(value, cancellationToken).ConfigureAwait(false)) { SetToken(newToken, tokenValue); return; } throw JsonReaderException.Create(this, "Error parsing " + newToken.ToString().ToLowerInvariant() + " value."); } private Task ParseTrueAsync(CancellationToken cancellationToken) { return MatchAndSetAsync(JsonConvert.True, JsonToken.Boolean, true, cancellationToken); } private Task ParseFalseAsync(CancellationToken cancellationToken) { return MatchAndSetAsync(JsonConvert.False, JsonToken.Boolean, false, cancellationToken); } private Task ParseNullAsync(CancellationToken cancellationToken) { return MatchAndSetAsync(JsonConvert.Null, JsonToken.Null, null, cancellationToken); } private async Task ParseConstructorAsync(CancellationToken cancellationToken) { if (await MatchValueWithTrailingSeparatorAsync("new", cancellationToken).ConfigureAwait(false)) { await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false); int initialPosition = _charPos; int endPosition; while (true) { char currentChar = _chars[_charPos]; if (currentChar == '') { if (_charsUsed != _charPos) { endPosition = _charPos; _charPos++; break; } if (await ReadDataAsync(true, cancellationToken).ConfigureAwait(false) == 0) throw JsonReaderException.Create(this, "Unexpected end while parsing constructor."); } else { if (!char.IsLetterOrDigit(currentChar)) { switch (currentChar) { case '\r': endPosition = _charPos; await ProcessCarriageReturnAsync(true, cancellationToken).ConfigureAwait(false); break; case '\n': endPosition = _charPos; ProcessLineFeed(); break; default: if (char.IsWhiteSpace(currentChar)) { endPosition = _charPos; _charPos++; } else { if (currentChar != '(') throw JsonReaderException.Create(this, "Unexpected character while parsing constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, currentChar)); endPosition = _charPos; } break; } break; } _charPos++; } } _stringReference = new StringReference(_chars, initialPosition, endPosition - initialPosition); string constructorName = _stringReference.ToString(); await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false); if (_chars[_charPos] != '(') throw JsonReaderException.Create(this, "Unexpected character while parsing constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); _charPos++; ClearRecentString(); SetToken(JsonToken.StartConstructor, constructorName); return; } throw JsonReaderException.Create(this, "Unexpected content while parsing JSON."); } private async Task<object> ParseNumberNaNAsync(ReadType readType, CancellationToken cancellationToken) { return ParseNumberNaN(readType, await MatchValueWithTrailingSeparatorAsync(JsonConvert.NaN, cancellationToken).ConfigureAwait(false)); } private async Task<object> ParseNumberPositiveInfinityAsync(ReadType readType, CancellationToken cancellationToken) { return ParseNumberPositiveInfinity(readType, await MatchValueWithTrailingSeparatorAsync(JsonConvert.PositiveInfinity, cancellationToken).ConfigureAwait(false)); } private async Task<object> ParseNumberNegativeInfinityAsync(ReadType readType, CancellationToken cancellationToken) { return ParseNumberNegativeInfinity(readType, await MatchValueWithTrailingSeparatorAsync(JsonConvert.NegativeInfinity, cancellationToken).ConfigureAwait(false)); } private async Task ParseNumberAsync(ReadType readType, CancellationToken cancellationToken) { ShiftBufferIfNeeded(); char firstChar = _chars[_charPos]; int initialPosition = _charPos; await ReadNumberIntoBufferAsync(cancellationToken).ConfigureAwait(false); ParseReadNumber(readType, firstChar, initialPosition); } private Task ParseUndefinedAsync(CancellationToken cancellationToken) { return MatchAndSetAsync(JsonConvert.Undefined, JsonToken.Undefined, null, cancellationToken); } private async Task<bool> ParsePropertyAsync(CancellationToken cancellationToken) { char firstChar = _chars[_charPos]; char quoteChar; if (firstChar == '"' || firstChar == '\'') { _charPos++; quoteChar = firstChar; ShiftBufferIfNeeded(); await ReadStringIntoBufferAsync(quoteChar, cancellationToken).ConfigureAwait(false); } else { if (!ValidIdentifierChar(firstChar)) throw JsonReaderException.Create(this, "Invalid property identifier character: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); quoteChar = ''; ShiftBufferIfNeeded(); await ParseUnquotedPropertyAsync(cancellationToken).ConfigureAwait(false); } string propertyName = (NameTable == null) ? _stringReference.ToString() : (NameTable.Get(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length) ?? _stringReference.ToString()); await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false); if (_chars[_charPos] != ':') throw JsonReaderException.Create(this, "Invalid character after parsing property name. Expected ':' but got: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); _charPos++; SetToken(JsonToken.PropertyName, propertyName); _quoteChar = quoteChar; ClearRecentString(); return true; } private async Task ReadNumberIntoBufferAsync(CancellationToken cancellationToken) { int charPos = _charPos; while (true) { char currentChar = _chars[charPos]; if (currentChar == '') { _charPos = charPos; if (_charsUsed != charPos || await ReadDataAsync(true, cancellationToken).ConfigureAwait(false) == 0) break; } else { if (ReadNumberCharIntoBuffer(currentChar, charPos)) break; charPos++; } } } private async Task ParseUnquotedPropertyAsync(CancellationToken cancellationToken) { int initialPosition = _charPos; while (true) { char currentChar = _chars[_charPos]; if (currentChar == '') { if (_charsUsed != _charPos) break; if (await ReadDataAsync(true, cancellationToken).ConfigureAwait(false) == 0) throw JsonReaderException.Create(this, "Unexpected end while parsing unquoted property name."); } else if (ReadUnquotedPropertyReportIfDone(currentChar, initialPosition)) { return; } } _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition); } private async Task<bool> ReadNullCharAsync(CancellationToken cancellationToken) { if (_charsUsed == _charPos) { if (await ReadDataAsync(false, cancellationToken).ConfigureAwait(false) == 0) { _isEndOfFile = true; return true; } } else _charPos++; return false; } private async Task HandleNullAsync(CancellationToken cancellationToken) { if (await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false)) { if (_chars[_charPos + 1] == 'u') { await ParseNullAsync(cancellationToken).ConfigureAwait(false); return; } _charPos += 2; throw CreateUnexpectedCharacterException(_chars[_charPos - 1]); } _charPos = _charsUsed; throw CreateUnexpectedEndException(); } private async Task ReadFinishedAsync(CancellationToken cancellationToken) { if (await EnsureCharsAsync(0, false, cancellationToken).ConfigureAwait(false)) { await EatWhitespaceAsync(cancellationToken).ConfigureAwait(false); if (_isEndOfFile) { SetToken(JsonToken.None); return; } if (_chars[_charPos] != '/') throw JsonReaderException.Create(this, "Additional text encountered after finished reading JSON content: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); await ParseCommentAsync(false, cancellationToken).ConfigureAwait(false); } SetToken(JsonToken.None); } private async Task<object> ReadStringValueAsync(ReadType readType, CancellationToken cancellationToken) { EnsureBuffer(); switch (_currentState) { case State.PostValue: if (await ParsePostValueAsync(true, cancellationToken).ConfigureAwait(false)) return null; goto case State.Start; case State.Start: case State.Property: case State.ArrayStart: case State.Array: case State.ConstructorStart: case State.Constructor: while (true) { char currentChar = _chars[_charPos]; switch (currentChar) { case '': if (await ReadNullCharAsync(cancellationToken).ConfigureAwait(false)) { SetToken(JsonToken.None, null, false); return null; } break; case '"': case '\'': await ParseStringAsync(currentChar, readType, cancellationToken).ConfigureAwait(false); return FinishReadQuotedStringValue(readType); case '-': if (await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false) && _chars[_charPos + 1] == 'I') return ParseNumberNegativeInfinity(readType); await ParseNumberAsync(readType, cancellationToken).ConfigureAwait(false); return Value; case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (readType != ReadType.ReadAsString) { _charPos++; throw CreateUnexpectedCharacterException(currentChar); } await ParseNumberAsync(ReadType.ReadAsString, cancellationToken).ConfigureAwait(false); return Value; case 'f': case 't': { if (readType != ReadType.ReadAsString) { _charPos++; throw CreateUnexpectedCharacterException(currentChar); } string expected = (currentChar == 't') ? JsonConvert.True : JsonConvert.False; if (!(await MatchValueWithTrailingSeparatorAsync(expected, cancellationToken).ConfigureAwait(false))) throw CreateUnexpectedCharacterException(_chars[_charPos]); SetToken(JsonToken.String, expected); return expected; } case 'I': return await ParseNumberPositiveInfinityAsync(readType, cancellationToken).ConfigureAwait(false); case 'N': return await ParseNumberNaNAsync(readType, cancellationToken).ConfigureAwait(false); case 'n': await HandleNullAsync(cancellationToken).ConfigureAwait(false); return null; case '/': await ParseCommentAsync(false, cancellationToken).ConfigureAwait(false); break; case ',': ProcessValueComma(); break; case ']': _charPos++; if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue) { SetToken(JsonToken.EndArray); return null; } throw CreateUnexpectedCharacterException(currentChar); case '\r': await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false); break; case '\n': ProcessLineFeed(); break; case '\t': case ' ': _charPos++; break; default: _charPos++; if (!char.IsWhiteSpace(currentChar)) throw CreateUnexpectedCharacterException(currentChar); break; } } case State.Finished: await ReadFinishedAsync(cancellationToken).ConfigureAwait(false); return null; default: throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, base.CurrentState)); } } private async Task<object> ReadNumberValueAsync(ReadType readType, CancellationToken cancellationToken) { EnsureBuffer(); switch (_currentState) { case State.PostValue: if (await ParsePostValueAsync(true, cancellationToken).ConfigureAwait(false)) return null; goto case State.Start; case State.Start: case State.Property: case State.ArrayStart: case State.Array: case State.ConstructorStart: case State.Constructor: while (true) { char currentChar = _chars[_charPos]; switch (currentChar) { case '': if (await ReadNullCharAsync(cancellationToken).ConfigureAwait(false)) { SetToken(JsonToken.None, null, false); return null; } break; case '"': case '\'': await ParseStringAsync(currentChar, readType, cancellationToken).ConfigureAwait(false); return FinishReadQuotedNumber(readType); case 'n': await HandleNullAsync(cancellationToken).ConfigureAwait(false); return null; case 'N': return await ParseNumberNaNAsync(readType, cancellationToken).ConfigureAwait(false); case 'I': return await ParseNumberPositiveInfinityAsync(readType, cancellationToken).ConfigureAwait(false); case '-': if (await EnsureCharsAsync(1, true, cancellationToken).ConfigureAwait(false) && _chars[_charPos + 1] == 'I') return await ParseNumberNegativeInfinityAsync(readType, cancellationToken).ConfigureAwait(false); await ParseNumberAsync(readType, cancellationToken).ConfigureAwait(false); return Value; case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': await ParseNumberAsync(readType, cancellationToken).ConfigureAwait(false); return Value; case '/': await ParseCommentAsync(false, cancellationToken).ConfigureAwait(false); break; case ',': ProcessValueComma(); break; case ']': _charPos++; if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue) { SetToken(JsonToken.EndArray); return null; } throw CreateUnexpectedCharacterException(currentChar); case '\r': await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false); break; case '\n': ProcessLineFeed(); break; case '\t': case ' ': _charPos++; break; default: _charPos++; if (!char.IsWhiteSpace(currentChar)) throw CreateUnexpectedCharacterException(currentChar); break; } } case State.Finished: await ReadFinishedAsync(cancellationToken).ConfigureAwait(false); return null; default: throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, base.CurrentState)); } } public override Task<bool?> ReadAsBooleanAsync(CancellationToken cancellationToken = default(CancellationToken)) { if (!_safeAsync) return base.ReadAsBooleanAsync(cancellationToken); return DoReadAsBooleanAsync(cancellationToken); } internal async Task<bool?> DoReadAsBooleanAsync(CancellationToken cancellationToken) { EnsureBuffer(); switch (_currentState) { case State.PostValue: if (await ParsePostValueAsync(true, cancellationToken).ConfigureAwait(false)) return null; goto case State.Start; case State.Start: case State.Property: case State.ArrayStart: case State.Array: case State.ConstructorStart: case State.Constructor: while (true) { char currentChar = _chars[_charPos]; switch (currentChar) { case '': if (await ReadNullCharAsync(cancellationToken).ConfigureAwait(false)) { SetToken(JsonToken.None, null, false); return null; } break; case '"': case '\'': await ParseStringAsync(currentChar, ReadType.Read, cancellationToken).ConfigureAwait(false); return ReadBooleanString(_stringReference.ToString()); case 'n': await HandleNullAsync(cancellationToken).ConfigureAwait(false); return null; case '-': case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { await ParseNumberAsync(ReadType.Read, cancellationToken).ConfigureAwait(false); bool flag = Convert.ToBoolean(Value, CultureInfo.InvariantCulture); SetToken(JsonToken.Boolean, flag, false); return flag; } case 'f': case 't': { bool isTrue = currentChar == 't'; if (!(await MatchValueWithTrailingSeparatorAsync(isTrue ? JsonConvert.True : JsonConvert.False, cancellationToken).ConfigureAwait(false))) throw CreateUnexpectedCharacterException(_chars[_charPos]); SetToken(JsonToken.Boolean, isTrue); return isTrue; } case '/': await ParseCommentAsync(false, cancellationToken).ConfigureAwait(false); break; case ',': ProcessValueComma(); break; case ']': _charPos++; if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue) { SetToken(JsonToken.EndArray); return null; } throw CreateUnexpectedCharacterException(currentChar); case '\r': await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false); break; case '\n': ProcessLineFeed(); break; case '\t': case ' ': _charPos++; break; default: _charPos++; if (!char.IsWhiteSpace(currentChar)) throw CreateUnexpectedCharacterException(currentChar); break; } } case State.Finished: await ReadFinishedAsync(cancellationToken).ConfigureAwait(false); return null; default: throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, base.CurrentState)); } } public override Task<byte[]> ReadAsBytesAsync(CancellationToken cancellationToken = default(CancellationToken)) { if (!_safeAsync) return base.ReadAsBytesAsync(cancellationToken); return DoReadAsBytesAsync(cancellationToken); } internal async Task<byte[]> DoReadAsBytesAsync(CancellationToken cancellationToken) { EnsureBuffer(); bool isWrapped = false; switch (_currentState) { case State.PostValue: if (await ParsePostValueAsync(true, cancellationToken).ConfigureAwait(false)) return null; goto case State.Start; case State.Start: case State.Property: case State.ArrayStart: case State.Array: case State.ConstructorStart: case State.Constructor: while (true) { char currentChar = _chars[_charPos]; switch (currentChar) { case '': if (await ReadNullCharAsync(cancellationToken).ConfigureAwait(false)) { SetToken(JsonToken.None, null, false); return null; } break; case '"': case '\'': { await ParseStringAsync(currentChar, ReadType.ReadAsBytes, cancellationToken).ConfigureAwait(false); byte[] data = (byte[])Value; if (isWrapped) { await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false); if (TokenType != JsonToken.EndObject) throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); SetToken(JsonToken.Bytes, data, false); } return data; } case '{': _charPos++; SetToken(JsonToken.StartObject); await ReadIntoWrappedTypeObjectAsync(cancellationToken).ConfigureAwait(false); isWrapped = true; break; case '[': _charPos++; SetToken(JsonToken.StartArray); return await ReadArrayIntoByteArrayAsync(cancellationToken).ConfigureAwait(false); case 'n': await HandleNullAsync(cancellationToken).ConfigureAwait(false); return null; case '/': await ParseCommentAsync(false, cancellationToken).ConfigureAwait(false); break; case ',': ProcessValueComma(); break; case ']': _charPos++; if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue) { SetToken(JsonToken.EndArray); return null; } throw CreateUnexpectedCharacterException(currentChar); case '\r': await ProcessCarriageReturnAsync(false, cancellationToken).ConfigureAwait(false); break; case '\n': ProcessLineFeed(); break; case '\t': case ' ': _charPos++; break; default: _charPos++; if (!char.IsWhiteSpace(currentChar)) throw CreateUnexpectedCharacterException(currentChar); break; } } case State.Finished: await ReadFinishedAsync(cancellationToken).ConfigureAwait(false); return null; default: throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, base.CurrentState)); } } private async Task ReadIntoWrappedTypeObjectAsync(CancellationToken cancellationToken) { await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false); if (Value != null && Value.ToString() == "$type") { await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false); if (Value != null && Value.ToString().StartsWith("System.Byte[]", StringComparison.Ordinal)) { await ReaderReadAndAssertAsync(cancellationToken).ConfigureAwait(false); if (Value.ToString() == "$value") return; } } throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, JsonToken.StartObject)); } public override Task<DateTime?> ReadAsDateTimeAsync(CancellationToken cancellationToken = default(CancellationToken)) { if (!_safeAsync) return base.ReadAsDateTimeAsync(cancellationToken); return DoReadAsDateTimeAsync(cancellationToken); } internal async Task<DateTime?> DoReadAsDateTimeAsync(CancellationToken cancellationToken) { return (DateTime?)(await ReadStringValueAsync(ReadType.ReadAsDateTime, cancellationToken).ConfigureAwait(false)); } public override Task<DateTimeOffset?> ReadAsDateTimeOffsetAsync(CancellationToken cancellationToken = default(CancellationToken)) { if (!_safeAsync) return base.ReadAsDateTimeOffsetAsync(cancellationToken); return DoReadAsDateTimeOffsetAsync(cancellationToken); } internal async Task<DateTimeOffset?> DoReadAsDateTimeOffsetAsync(CancellationToken cancellationToken) { return (DateTimeOffset?)(await ReadStringValueAsync(ReadType.ReadAsDateTimeOffset, cancellationToken).ConfigureAwait(false)); } public override Task<decimal?> ReadAsDecimalAsync(CancellationToken cancellationToken = default(CancellationToken)) { if (!_safeAsync) return base.ReadAsDecimalAsync(cancellationToken); return DoReadAsDecimalAsync(cancellationToken); } internal async Task<decimal?> DoReadAsDecimalAsync(CancellationToken cancellationToken) { return (decimal?)(await ReadNumberValueAsync(ReadType.ReadAsDecimal, cancellationToken).ConfigureAwait(false)); } public override Task<double?> ReadAsDoubleAsync(CancellationToken cancellationToken = default(CancellationToken)) { if (!_safeAsync) return base.ReadAsDoubleAsync(cancellationToken); return DoReadAsDoubleAsync(cancellationToken); } internal async Task<double?> DoReadAsDoubleAsync(CancellationToken cancellationToken) { return (double?)(await ReadNumberValueAsync(ReadType.ReadAsDouble, cancellationToken).ConfigureAwait(false)); } public override Task<int?> ReadAsInt32Async(CancellationToken cancellationToken = default(CancellationToken)) { if (!_safeAsync) return base.ReadAsInt32Async(cancellationToken); return DoReadAsInt32Async(cancellationToken); } internal async Task<int?> DoReadAsInt32Async(CancellationToken cancellationToken) { return (int?)(await ReadNumberValueAsync(ReadType.ReadAsInt32, cancellationToken).ConfigureAwait(false)); } public override Task<string> ReadAsStringAsync(CancellationToken cancellationToken = default(CancellationToken)) { if (!_safeAsync) return base.ReadAsStringAsync(cancellationToken); return DoReadAsStringAsync(cancellationToken); } internal async Task<string> DoReadAsStringAsync(CancellationToken cancellationToken) { return (string)(await ReadStringValueAsync(ReadType.ReadAsString, cancellationToken).ConfigureAwait(false)); } public JsonTextReader(TextReader reader) { if (reader == null) throw new ArgumentNullException("reader"); _reader = reader; _lineNumber = 1; _safeAsync = ((object)GetType() == typeof(JsonTextReader)); } private void EnsureBufferNotEmpty() { if (_stringBuffer.IsEmpty) _stringBuffer = new StringBuffer(_arrayPool, 1024); } private void SetNewLine(bool hasNextChar) { if (hasNextChar && _chars[_charPos] == '\n') _charPos++; OnNewLine(_charPos); } private void OnNewLine(int pos) { _lineNumber++; _lineStartPos = pos; } private void ParseString(char quote, ReadType readType) { _charPos++; ShiftBufferIfNeeded(); ReadStringIntoBuffer(quote); ParseReadString(quote, readType); } private void ParseReadString(char quote, ReadType readType) { SetPostValueState(true); switch (readType) { case ReadType.ReadAsInt32: case ReadType.ReadAsDecimal: case ReadType.ReadAsBoolean: break; case ReadType.ReadAsBytes: { Guid g; byte[] value2 = (_stringReference.Length == 0) ? CollectionUtils.ArrayEmpty<byte>() : ((_stringReference.Length != 36 || !ConvertUtils.TryConvertGuid(_stringReference.ToString(), out g)) ? Convert.FromBase64CharArray(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length) : g.ToByteArray()); SetToken(JsonToken.Bytes, value2, false); break; } case ReadType.ReadAsString: { string value = _stringReference.ToString(); SetToken(JsonToken.String, value, false); _quoteChar = quote; break; } default: if (_dateParseHandling != 0) { DateParseHandling dateParseHandling; switch (readType) { case ReadType.ReadAsDateTime: dateParseHandling = DateParseHandling.DateTime; break; case ReadType.ReadAsDateTimeOffset: dateParseHandling = DateParseHandling.DateTimeOffset; break; default: dateParseHandling = _dateParseHandling; break; } DateTimeOffset dt2; if (dateParseHandling == DateParseHandling.DateTime) { if (DateTimeUtils.TryParseDateTime(_stringReference, base.DateTimeZoneHandling, base.DateFormatString, base.Culture, out DateTime dt)) { SetToken(JsonToken.Date, dt, false); break; } } else if (DateTimeUtils.TryParseDateTimeOffset(_stringReference, base.DateFormatString, base.Culture, out dt2)) { SetToken(JsonToken.Date, dt2, false); break; } } SetToken(JsonToken.String, _stringReference.ToString(), false); _quoteChar = quote; break; } } private static void BlockCopyChars(char[] src, int srcOffset, char[] dst, int dstOffset, int count) { Buffer.BlockCopy(src, srcOffset * 2, dst, dstOffset * 2, count * 2); } private void ShiftBufferIfNeeded() { int num = _chars.Length; if ((double)(num - _charPos) <= (double)num * 0.1 || num >= 1073741823) { int num2 = _charsUsed - _charPos; if (num2 > 0) BlockCopyChars(_chars, _charPos, _chars, 0, num2); _lineStartPos -= _charPos; _charPos = 0; _charsUsed = num2; _chars[_charsUsed] = ''; } } private int ReadData(bool append) { return ReadData(append, 0); } private void PrepareBufferForReadData(bool append, int charsRequired) { if (_charsUsed + charsRequired >= _chars.Length - 1) { if (append) { int num = _chars.Length * 2; int minSize = Math.Max((num < 0) ? 2147483647 : num, _charsUsed + charsRequired + 1); char[] array = BufferUtils.RentBuffer(_arrayPool, minSize); BlockCopyChars(_chars, 0, array, 0, _chars.Length); BufferUtils.ReturnBuffer(_arrayPool, _chars); _chars = array; } else { int num2 = _charsUsed - _charPos; if (num2 + charsRequired + 1 >= _chars.Length) { char[] array2 = BufferUtils.RentBuffer(_arrayPool, num2 + charsRequired + 1); if (num2 > 0) BlockCopyChars(_chars, _charPos, array2, 0, num2); BufferUtils.ReturnBuffer(_arrayPool, _chars); _chars = array2; } else if (num2 > 0) { BlockCopyChars(_chars, _charPos, _chars, 0, num2); } _lineStartPos -= _charPos; _charPos = 0; _charsUsed = num2; } } } private int ReadData(bool append, int charsRequired) { if (_isEndOfFile) return 0; PrepareBufferForReadData(append, charsRequired); int count = _chars.Length - _charsUsed - 1; int num = _reader.Read(_chars, _charsUsed, count); _charsUsed += num; if (num == 0) _isEndOfFile = true; _chars[_charsUsed] = ''; return num; } private bool EnsureChars(int relativePosition, bool append) { if (_charPos + relativePosition >= _charsUsed) return ReadChars(relativePosition, append); return true; } private bool ReadChars(int relativePosition, bool append) { if (_isEndOfFile) return false; int num = _charPos + relativePosition - _charsUsed + 1; int num2 = 0; do { int num3 = ReadData(append, num - num2); if (num3 == 0) break; num2 += num3; } while (num2 < num); if (num2 < num) return false; return true; } public override bool Read() { EnsureBuffer(); do { switch (_currentState) { case State.Start: case State.Property: case State.ArrayStart: case State.Array: case State.ConstructorStart: case State.Constructor: return ParseValue(); case State.ObjectStart: case State.Object: return ParseObject(); case State.PostValue: break; case State.Finished: if (EnsureChars(0, false)) { EatWhitespace(); if (_isEndOfFile) { SetToken(JsonToken.None); return false; } if (_chars[_charPos] == '/') { ParseComment(true); return true; } throw JsonReaderException.Create(this, "Additional text encountered after finished reading JSON content: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); } SetToken(JsonToken.None); return false; default: throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, base.CurrentState)); } } while (!ParsePostValue(false)); return true; } public override int? ReadAsInt32() { return (int?)ReadNumberValue(ReadType.ReadAsInt32); } public override DateTime? ReadAsDateTime() { return (DateTime?)ReadStringValue(ReadType.ReadAsDateTime); } public override string ReadAsString() { return (string)ReadStringValue(ReadType.ReadAsString); } public override byte[] ReadAsBytes() { EnsureBuffer(); bool flag = false; switch (_currentState) { case State.PostValue: if (ParsePostValue(true)) return null; goto case State.Start; case State.Start: case State.Property: case State.ArrayStart: case State.Array: case State.ConstructorStart: case State.Constructor: while (true) { char c = _chars[_charPos]; switch (c) { case '': if (ReadNullChar()) { SetToken(JsonToken.None, null, false); return null; } break; case '"': case '\'': { ParseString(c, ReadType.ReadAsBytes); byte[] array = (byte[])Value; if (flag) { ReaderReadAndAssert(); if (TokenType != JsonToken.EndObject) throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType)); SetToken(JsonToken.Bytes, array, false); } return array; } case '{': _charPos++; SetToken(JsonToken.StartObject); ReadIntoWrappedTypeObject(); flag = true; break; case '[': _charPos++; SetToken(JsonToken.StartArray); return ReadArrayIntoByteArray(); case 'n': HandleNull(); return null; case '/': ParseComment(false); break; case ',': ProcessValueComma(); break; case ']': _charPos++; if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue) { SetToken(JsonToken.EndArray); return null; } throw CreateUnexpectedCharacterException(c); case '\r': ProcessCarriageReturn(false); break; case '\n': ProcessLineFeed(); break; case '\t': case ' ': _charPos++; break; default: _charPos++; if (!char.IsWhiteSpace(c)) throw CreateUnexpectedCharacterException(c); break; } } case State.Finished: ReadFinished(); return null; default: throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, base.CurrentState)); } } private object ReadStringValue(ReadType readType) { EnsureBuffer(); switch (_currentState) { case State.PostValue: if (ParsePostValue(true)) return null; goto case State.Start; case State.Start: case State.Property: case State.ArrayStart: case State.Array: case State.ConstructorStart: case State.Constructor: while (true) { char c = _chars[_charPos]; switch (c) { case '': if (ReadNullChar()) { SetToken(JsonToken.None, null, false); return null; } break; case '"': case '\'': ParseString(c, readType); return FinishReadQuotedStringValue(readType); case '-': if (EnsureChars(1, true) && _chars[_charPos + 1] == 'I') return ParseNumberNegativeInfinity(readType); ParseNumber(readType); return Value; case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (readType != ReadType.ReadAsString) { _charPos++; throw CreateUnexpectedCharacterException(c); } ParseNumber(ReadType.ReadAsString); return Value; case 'f': case 't': { if (readType != ReadType.ReadAsString) { _charPos++; throw CreateUnexpectedCharacterException(c); } string text = (c == 't') ? JsonConvert.True : JsonConvert.False; if (!MatchValueWithTrailingSeparator(text)) throw CreateUnexpectedCharacterException(_chars[_charPos]); SetToken(JsonToken.String, text); return text; } case 'I': return ParseNumberPositiveInfinity(readType); case 'N': return ParseNumberNaN(readType); case 'n': HandleNull(); return null; case '/': ParseComment(false); break; case ',': ProcessValueComma(); break; case ']': _charPos++; if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue) { SetToken(JsonToken.EndArray); return null; } throw CreateUnexpectedCharacterException(c); case '\r': ProcessCarriageReturn(false); break; case '\n': ProcessLineFeed(); break; case '\t': case ' ': _charPos++; break; default: _charPos++; if (!char.IsWhiteSpace(c)) throw CreateUnexpectedCharacterException(c); break; } } case State.Finished: ReadFinished(); return null; default: throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, base.CurrentState)); } } private object FinishReadQuotedStringValue(ReadType readType) { switch (readType) { case ReadType.ReadAsBytes: case ReadType.ReadAsString: return Value; case ReadType.ReadAsDateTime: { object value; if ((value = Value) is DateTime) { DateTime dateTime = (DateTime)value; return dateTime; } return ReadDateTimeString((string)Value); } case ReadType.ReadAsDateTimeOffset: { object value; if ((value = Value) is DateTimeOffset) { DateTimeOffset dateTimeOffset = (DateTimeOffset)value; return dateTimeOffset; } return ReadDateTimeOffsetString((string)Value); } default: throw new ArgumentOutOfRangeException("readType"); } } private JsonReaderException CreateUnexpectedCharacterException(char c) { return JsonReaderException.Create(this, "Unexpected character encountered while parsing value: {0}.".FormatWith(CultureInfo.InvariantCulture, c)); } public override bool? ReadAsBoolean() { EnsureBuffer(); switch (_currentState) { case State.PostValue: if (ParsePostValue(true)) return null; goto case State.Start; case State.Start: case State.Property: case State.ArrayStart: case State.Array: case State.ConstructorStart: case State.Constructor: while (true) { char c = _chars[_charPos]; switch (c) { case '': if (ReadNullChar()) { SetToken(JsonToken.None, null, false); return null; } break; case '"': case '\'': ParseString(c, ReadType.Read); return ReadBooleanString(_stringReference.ToString()); case 'n': HandleNull(); return null; case '-': case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { ParseNumber(ReadType.Read); bool flag2 = Convert.ToBoolean(Value, CultureInfo.InvariantCulture); SetToken(JsonToken.Boolean, flag2, false); return flag2; } case 'f': case 't': { bool flag = c == 't'; string value = flag ? JsonConvert.True : JsonConvert.False; if (!MatchValueWithTrailingSeparator(value)) throw CreateUnexpectedCharacterException(_chars[_charPos]); SetToken(JsonToken.Boolean, flag); return flag; } case '/': ParseComment(false); break; case ',': ProcessValueComma(); break; case ']': _charPos++; if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue) { SetToken(JsonToken.EndArray); return null; } throw CreateUnexpectedCharacterException(c); case '\r': ProcessCarriageReturn(false); break; case '\n': ProcessLineFeed(); break; case '\t': case ' ': _charPos++; break; default: _charPos++; if (!char.IsWhiteSpace(c)) throw CreateUnexpectedCharacterException(c); break; } } case State.Finished: ReadFinished(); return null; default: throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, base.CurrentState)); } } private void ProcessValueComma() { _charPos++; if (_currentState != State.PostValue) { SetToken(JsonToken.Undefined); JsonReaderException ex = CreateUnexpectedCharacterException(','); _charPos--; throw ex; } SetStateBasedOnCurrent(); } private object ReadNumberValue(ReadType readType) { EnsureBuffer(); switch (_currentState) { case State.PostValue: if (ParsePostValue(true)) return null; goto case State.Start; case State.Start: case State.Property: case State.ArrayStart: case State.Array: case State.ConstructorStart: case State.Constructor: while (true) { char c = _chars[_charPos]; switch (c) { case '': if (ReadNullChar()) { SetToken(JsonToken.None, null, false); return null; } break; case '"': case '\'': ParseString(c, readType); return FinishReadQuotedNumber(readType); case 'n': HandleNull(); return null; case 'N': return ParseNumberNaN(readType); case 'I': return ParseNumberPositiveInfinity(readType); case '-': if (EnsureChars(1, true) && _chars[_charPos + 1] == 'I') return ParseNumberNegativeInfinity(readType); ParseNumber(readType); return Value; case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': ParseNumber(readType); return Value; case '/': ParseComment(false); break; case ',': ProcessValueComma(); break; case ']': _charPos++; if (_currentState == State.Array || _currentState == State.ArrayStart || _currentState == State.PostValue) { SetToken(JsonToken.EndArray); return null; } throw CreateUnexpectedCharacterException(c); case '\r': ProcessCarriageReturn(false); break; case '\n': ProcessLineFeed(); break; case '\t': case ' ': _charPos++; break; default: _charPos++; if (!char.IsWhiteSpace(c)) throw CreateUnexpectedCharacterException(c); break; } } case State.Finished: ReadFinished(); return null; default: throw JsonReaderException.Create(this, "Unexpected state: {0}.".FormatWith(CultureInfo.InvariantCulture, base.CurrentState)); } } private object FinishReadQuotedNumber(ReadType readType) { switch (readType) { case ReadType.ReadAsInt32: return ReadInt32String(_stringReference.ToString()); case ReadType.ReadAsDecimal: return ReadDecimalString(_stringReference.ToString()); case ReadType.ReadAsDouble: return ReadDoubleString(_stringReference.ToString()); default: throw new ArgumentOutOfRangeException("readType"); } } public override DateTimeOffset? ReadAsDateTimeOffset() { return (DateTimeOffset?)ReadStringValue(ReadType.ReadAsDateTimeOffset); } public override decimal? ReadAsDecimal() { return (decimal?)ReadNumberValue(ReadType.ReadAsDecimal); } public override double? ReadAsDouble() { return (double?)ReadNumberValue(ReadType.ReadAsDouble); } private void HandleNull() { if (EnsureChars(1, true)) { if (_chars[_charPos + 1] == 'u') { ParseNull(); return; } _charPos += 2; throw CreateUnexpectedCharacterException(_chars[_charPos - 1]); } _charPos = _charsUsed; throw CreateUnexpectedEndException(); } private void ReadFinished() { if (EnsureChars(0, false)) { EatWhitespace(); if (_isEndOfFile) return; if (_chars[_charPos] != '/') throw JsonReaderException.Create(this, "Additional text encountered after finished reading JSON content: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); ParseComment(false); } SetToken(JsonToken.None); } private bool ReadNullChar() { if (_charsUsed == _charPos) { if (ReadData(false) == 0) { _isEndOfFile = true; return true; } } else _charPos++; return false; } private void EnsureBuffer() { if (_chars == null) { _chars = BufferUtils.RentBuffer(_arrayPool, 1024); _chars[0] = ''; } } private void ReadStringIntoBuffer(char quote) { int num = _charPos; int charPos = _charPos; int lastWritePosition = _charPos; _stringBuffer.Position = 0; while (true) { switch (_chars[num++]) { case '': if (_charsUsed == num - 1) { num--; if (ReadData(true) == 0) { _charPos = num; throw JsonReaderException.Create(this, "Unterminated string. Expected delimiter: {0}.".FormatWith(CultureInfo.InvariantCulture, quote)); } } break; case '\\': { _charPos = num; if (!EnsureChars(0, true)) throw JsonReaderException.Create(this, "Unterminated string. Expected delimiter: {0}.".FormatWith(CultureInfo.InvariantCulture, quote)); int writeToPosition = num - 1; char c = _chars[num]; num++; char c2; switch (c) { case 'b': c2 = '\b'; break; case 't': c2 = '\t'; break; case 'n': c2 = '\n'; break; case 'f': c2 = ' '; break; case 'r': c2 = '\r'; break; case '\\': c2 = '\\'; break; case '"': case '\'': case '/': c2 = c; break; case 'u': _charPos = num; c2 = ParseUnicode(); if (StringUtils.IsLowSurrogate(c2)) c2 = '�'; else if (StringUtils.IsHighSurrogate(c2)) { bool flag; do { flag = false; if (EnsureChars(2, true) && _chars[_charPos] == '\\' && _chars[_charPos + 1] == 'u') { char writeChar = c2; _charPos += 2; c2 = ParseUnicode(); if (!StringUtils.IsLowSurrogate(c2)) { if (StringUtils.IsHighSurrogate(c2)) { writeChar = '�'; flag = true; } else writeChar = '�'; } EnsureBufferNotEmpty(); WriteCharToBuffer(writeChar, lastWritePosition, writeToPosition); lastWritePosition = _charPos; } else c2 = '�'; } while (flag); } num = _charPos; break; default: _charPos = num; throw JsonReaderException.Create(this, "Bad JSON escape sequence: {0}.".FormatWith(CultureInfo.InvariantCulture, "\\" + c.ToString())); } EnsureBufferNotEmpty(); WriteCharToBuffer(c2, lastWritePosition, writeToPosition); lastWritePosition = num; break; } case '\r': _charPos = num - 1; ProcessCarriageReturn(true); num = _charPos; break; case '\n': _charPos = num - 1; ProcessLineFeed(); num = _charPos; break; case '"': case '\'': if (_chars[num - 1] == quote) { FinishReadStringIntoBuffer(num - 1, charPos, lastWritePosition); return; } break; } } } private void FinishReadStringIntoBuffer(int charPos, int initialPosition, int lastWritePosition) { if (initialPosition == lastWritePosition) _stringReference = new StringReference(_chars, initialPosition, charPos - initialPosition); else { EnsureBufferNotEmpty(); if (charPos > lastWritePosition) _stringBuffer.Append(_arrayPool, _chars, lastWritePosition, charPos - lastWritePosition); _stringReference = new StringReference(_stringBuffer.InternalBuffer, 0, _stringBuffer.Position); } _charPos = charPos + 1; } private void WriteCharToBuffer(char writeChar, int lastWritePosition, int writeToPosition) { if (writeToPosition > lastWritePosition) _stringBuffer.Append(_arrayPool, _chars, lastWritePosition, writeToPosition - lastWritePosition); _stringBuffer.Append(_arrayPool, writeChar); } private char ConvertUnicode(bool enoughChars) { if (enoughChars) { if (ConvertUtils.TryHexTextToInt(_chars, _charPos, _charPos + 4, out int value)) { char result = Convert.ToChar(value); _charPos += 4; return result; } throw JsonReaderException.Create(this, "Invalid Unicode escape sequence: \\u{0}.".FormatWith(CultureInfo.InvariantCulture, new string(_chars, _charPos, 4))); } throw JsonReaderException.Create(this, "Unexpected end while parsing Unicode escape sequence."); } private char ParseUnicode() { return ConvertUnicode(EnsureChars(4, true)); } private void ReadNumberIntoBuffer() { int num = _charPos; while (true) { char c = _chars[num]; if (c == '') { _charPos = num; if (_charsUsed != num || ReadData(true) == 0) break; } else { if (ReadNumberCharIntoBuffer(c, num)) break; num++; } } } private bool ReadNumberCharIntoBuffer(char currentChar, int charPos) { switch (currentChar) { case '+': case '-': case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'X': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'x': return false; default: _charPos = charPos; if (char.IsWhiteSpace(currentChar) || currentChar == ',' || currentChar == '}' || currentChar == ']' || currentChar == ')' || currentChar == '/') return true; throw JsonReaderException.Create(this, "Unexpected character encountered while parsing number: {0}.".FormatWith(CultureInfo.InvariantCulture, currentChar)); } } private void ClearRecentString() { _stringBuffer.Position = 0; _stringReference = default(StringReference); } private bool ParsePostValue(bool ignoreComments) { while (true) { char c = _chars[_charPos]; switch (c) { case '': if (_charsUsed == _charPos) { if (ReadData(false) == 0) { _currentState = State.Finished; return false; } } else _charPos++; break; case '}': _charPos++; SetToken(JsonToken.EndObject); return true; case ']': _charPos++; SetToken(JsonToken.EndArray); return true; case ')': _charPos++; SetToken(JsonToken.EndConstructor); return true; case '/': ParseComment(!ignoreComments); if (!ignoreComments) return true; break; case ',': _charPos++; SetStateBasedOnCurrent(); return false; case '\t': case ' ': _charPos++; break; case '\r': ProcessCarriageReturn(false); break; case '\n': ProcessLineFeed(); break; default: if (!char.IsWhiteSpace(c)) { if (base.SupportMultipleContent && Depth == 0) { SetStateBasedOnCurrent(); return false; } throw JsonReaderException.Create(this, "After parsing a value an unexpected character was encountered: {0}.".FormatWith(CultureInfo.InvariantCulture, c)); } _charPos++; break; } } } private bool ParseObject() { while (true) { char c = _chars[_charPos]; switch (c) { case '': if (_charsUsed == _charPos) { if (ReadData(false) == 0) return false; } else _charPos++; break; case '}': SetToken(JsonToken.EndObject); _charPos++; return true; case '/': ParseComment(true); return true; case '\r': ProcessCarriageReturn(false); break; case '\n': ProcessLineFeed(); break; case '\t': case ' ': _charPos++; break; default: if (!char.IsWhiteSpace(c)) return ParseProperty(); _charPos++; break; } } } private bool ParseProperty() { char c = _chars[_charPos]; char c2; if (c == '"' || c == '\'') { _charPos++; c2 = c; ShiftBufferIfNeeded(); ReadStringIntoBuffer(c2); } else { if (!ValidIdentifierChar(c)) throw JsonReaderException.Create(this, "Invalid property identifier character: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); c2 = ''; ShiftBufferIfNeeded(); ParseUnquotedProperty(); } string text; if (NameTable != null) { text = NameTable.Get(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length); if (text == null) text = _stringReference.ToString(); } else text = _stringReference.ToString(); EatWhitespace(); if (_chars[_charPos] != ':') throw JsonReaderException.Create(this, "Invalid character after parsing property name. Expected ':' but got: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); _charPos++; SetToken(JsonToken.PropertyName, text); _quoteChar = c2; ClearRecentString(); return true; } private bool ValidIdentifierChar(char value) { if (!char.IsLetterOrDigit(value) && value != '_') return value == '$'; return true; } private void ParseUnquotedProperty() { int charPos = _charPos; while (true) { char c = _chars[_charPos]; if (c == '') { if (_charsUsed != _charPos) break; if (ReadData(true) == 0) throw JsonReaderException.Create(this, "Unexpected end while parsing unquoted property name."); } else if (ReadUnquotedPropertyReportIfDone(c, charPos)) { return; } } _stringReference = new StringReference(_chars, charPos, _charPos - charPos); } private bool ReadUnquotedPropertyReportIfDone(char currentChar, int initialPosition) { if (ValidIdentifierChar(currentChar)) { _charPos++; return false; } if (char.IsWhiteSpace(currentChar) || currentChar == ':') { _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition); return true; } throw JsonReaderException.Create(this, "Invalid JavaScript property identifier character: {0}.".FormatWith(CultureInfo.InvariantCulture, currentChar)); } private bool ParseValue() { while (true) { char c = _chars[_charPos]; switch (c) { case '': if (_charsUsed == _charPos) { if (ReadData(false) == 0) return false; } else _charPos++; break; case '"': case '\'': ParseString(c, ReadType.Read); return true; case 't': ParseTrue(); return true; case 'f': ParseFalse(); return true; case 'n': if (!EnsureChars(1, true)) { _charPos++; throw CreateUnexpectedEndException(); } switch (_chars[_charPos + 1]) { case 'u': ParseNull(); break; case 'e': ParseConstructor(); break; default: throw CreateUnexpectedCharacterException(_chars[_charPos]); } return true; case 'N': ParseNumberNaN(ReadType.Read); return true; case 'I': ParseNumberPositiveInfinity(ReadType.Read); return true; case '-': if (EnsureChars(1, true) && _chars[_charPos + 1] == 'I') ParseNumberNegativeInfinity(ReadType.Read); else ParseNumber(ReadType.Read); return true; case '/': ParseComment(true); return true; case 'u': ParseUndefined(); return true; case '{': _charPos++; SetToken(JsonToken.StartObject); return true; case '[': _charPos++; SetToken(JsonToken.StartArray); return true; case ']': _charPos++; SetToken(JsonToken.EndArray); return true; case ',': SetToken(JsonToken.Undefined); return true; case ')': _charPos++; SetToken(JsonToken.EndConstructor); return true; case '\r': ProcessCarriageReturn(false); break; case '\n': ProcessLineFeed(); break; case '\t': case ' ': _charPos++; break; default: if (!char.IsWhiteSpace(c)) { if (char.IsNumber(c) || c == '-' || c == '.') { ParseNumber(ReadType.Read); return true; } throw CreateUnexpectedCharacterException(c); } _charPos++; break; } } } private void ProcessLineFeed() { _charPos++; OnNewLine(_charPos); } private void ProcessCarriageReturn(bool append) { _charPos++; SetNewLine(EnsureChars(1, append)); } private void EatWhitespace() { while (true) { char c = _chars[_charPos]; switch (c) { case '': if (_charsUsed == _charPos) { if (ReadData(false) == 0) return; } else _charPos++; break; case '\r': ProcessCarriageReturn(false); break; case '\n': ProcessLineFeed(); break; default: if (!char.IsWhiteSpace(c)) return; goto case ' '; case ' ': _charPos++; break; } } } private void ParseConstructor() { if (MatchValueWithTrailingSeparator("new")) { EatWhitespace(); int charPos = _charPos; int charPos2; while (true) { char c = _chars[_charPos]; if (c == '') { if (_charsUsed != _charPos) { charPos2 = _charPos; _charPos++; break; } if (ReadData(true) == 0) throw JsonReaderException.Create(this, "Unexpected end while parsing constructor."); } else { if (!char.IsLetterOrDigit(c)) { switch (c) { case '\r': charPos2 = _charPos; ProcessCarriageReturn(true); break; case '\n': charPos2 = _charPos; ProcessLineFeed(); break; default: if (char.IsWhiteSpace(c)) { charPos2 = _charPos; _charPos++; } else { if (c != '(') throw JsonReaderException.Create(this, "Unexpected character while parsing constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, c)); charPos2 = _charPos; } break; } break; } _charPos++; } } _stringReference = new StringReference(_chars, charPos, charPos2 - charPos); string value = _stringReference.ToString(); EatWhitespace(); if (_chars[_charPos] != '(') throw JsonReaderException.Create(this, "Unexpected character while parsing constructor: {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); _charPos++; ClearRecentString(); SetToken(JsonToken.StartConstructor, value); return; } throw JsonReaderException.Create(this, "Unexpected content while parsing JSON."); } private void ParseNumber(ReadType readType) { ShiftBufferIfNeeded(); char firstChar = _chars[_charPos]; int charPos = _charPos; ReadNumberIntoBuffer(); ParseReadNumber(readType, firstChar, charPos); } private void ParseReadNumber(ReadType readType, char firstChar, int initialPosition) { SetPostValueState(true); _stringReference = new StringReference(_chars, initialPosition, _charPos - initialPosition); bool flag = char.IsDigit(firstChar) && _stringReference.Length == 1; bool flag2 = firstChar == '0' && _stringReference.Length > 1 && _stringReference.Chars[_stringReference.StartIndex + 1] != '.' && _stringReference.Chars[_stringReference.StartIndex + 1] != 'e' && _stringReference.Chars[_stringReference.StartIndex + 1] != 'E'; JsonToken newToken; object value; switch (readType) { case ReadType.ReadAsString: { string text4 = _stringReference.ToString(); double result3; if (flag2) try { if (text4.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) Convert.ToInt64(text4, 16); else Convert.ToInt64(text4, 8); } catch (Exception ex4) { throw ThrowReaderError("Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, text4), ex4); } else if (!double.TryParse(text4, NumberStyles.Float, CultureInfo.InvariantCulture, out result3)) { throw ThrowReaderError("Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()), null); } newToken = JsonToken.String; value = text4; break; } case ReadType.ReadAsInt32: if (flag) value = firstChar - 48; else if (flag2) { string text5 = _stringReference.ToString(); try { value = (text5.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt32(text5, 16) : Convert.ToInt32(text5, 8)); } catch (Exception ex5) { throw ThrowReaderError("Input string '{0}' is not a valid integer.".FormatWith(CultureInfo.InvariantCulture, text5), ex5); } } else { int value5; switch (ConvertUtils.Int32TryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out value5)) { case ParseResult.Success: break; case ParseResult.Overflow: throw ThrowReaderError("JSON integer {0} is too large or small for an Int32.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()), null); default: throw ThrowReaderError("Input string '{0}' is not a valid integer.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()), null); } value = value5; } newToken = JsonToken.Integer; break; case ReadType.ReadAsDecimal: if (flag) value = (decimal)firstChar - 48; else if (flag2) { string text2 = _stringReference.ToString(); try { value = Convert.ToDecimal(text2.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(text2, 16) : Convert.ToInt64(text2, 8)); } catch (Exception ex2) { throw ThrowReaderError("Input string '{0}' is not a valid decimal.".FormatWith(CultureInfo.InvariantCulture, text2), ex2); } } else { if (ConvertUtils.DecimalTryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out decimal value4) != ParseResult.Success) throw ThrowReaderError("Input string '{0}' is not a valid decimal.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()), null); value = value4; } newToken = JsonToken.Float; break; case ReadType.ReadAsDouble: if (flag) value = (double)(int)firstChar - 48; else if (flag2) { string text3 = _stringReference.ToString(); try { value = Convert.ToDouble(text3.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(text3, 16) : Convert.ToInt64(text3, 8)); } catch (Exception ex3) { throw ThrowReaderError("Input string '{0}' is not a valid double.".FormatWith(CultureInfo.InvariantCulture, text3), ex3); } } else { if (!double.TryParse(_stringReference.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture, out double result2)) throw ThrowReaderError("Input string '{0}' is not a valid double.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()), null); value = result2; } newToken = JsonToken.Float; break; default: if (flag) { value = (long)firstChar - 48; newToken = JsonToken.Integer; } else if (flag2) { string text = _stringReference.ToString(); try { value = (text.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? Convert.ToInt64(text, 16) : Convert.ToInt64(text, 8)); } catch (Exception ex) { throw ThrowReaderError("Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, text), ex); } newToken = JsonToken.Integer; } else { long value2; switch (ConvertUtils.Int64TryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out value2)) { case ParseResult.Success: value = value2; newToken = JsonToken.Integer; break; case ParseResult.Overflow: throw ThrowReaderError("JSON integer {0} is too large or small for an Int64.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()), null); default: if (_floatParseHandling == FloatParseHandling.Decimal) { decimal value3; ParseResult parseResult = ConvertUtils.DecimalTryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out value3); if (parseResult != ParseResult.Success) throw ThrowReaderError("Input string '{0}' is not a valid decimal.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()), null); value = value3; } else { if (!double.TryParse(_stringReference.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture, out double result)) throw ThrowReaderError("Input string '{0}' is not a valid number.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()), null); value = result; } newToken = JsonToken.Float; break; } } break; } ClearRecentString(); SetToken(newToken, value, false); } private JsonReaderException ThrowReaderError(string message, Exception ex = null) { SetToken(JsonToken.Undefined, null, false); return JsonReaderException.Create(this, message, ex); } private void ParseComment(bool setToken) { _charPos++; if (EnsureChars(1, false)) { bool flag; if (_chars[_charPos] == '*') flag = false; else { if (_chars[_charPos] != '/') throw JsonReaderException.Create(this, "Error parsing comment. Expected: *, got {0}.".FormatWith(CultureInfo.InvariantCulture, _chars[_charPos])); flag = true; } _charPos++; int charPos = _charPos; while (true) { switch (_chars[_charPos]) { case '': if (_charsUsed == _charPos) { if (ReadData(true) == 0) { if (!flag) throw JsonReaderException.Create(this, "Unexpected end while parsing comment."); EndComment(setToken, charPos, _charPos); return; } } else _charPos++; break; case '*': _charPos++; if (!flag && EnsureChars(0, true) && _chars[_charPos] == '/') { EndComment(setToken, charPos, _charPos - 1); _charPos++; return; } break; case '\r': if (flag) { EndComment(setToken, charPos, _charPos); return; } ProcessCarriageReturn(true); break; case '\n': if (flag) { EndComment(setToken, charPos, _charPos); return; } ProcessLineFeed(); break; default: _charPos++; break; } } } throw JsonReaderException.Create(this, "Unexpected end while parsing comment."); } private void EndComment(bool setToken, int initialPosition, int endPosition) { if (setToken) SetToken(JsonToken.Comment, new string(_chars, initialPosition, endPosition - initialPosition)); } private bool MatchValue(string value) { return MatchValue(EnsureChars(value.Length - 1, true), value); } private bool MatchValue(bool enoughChars, string value) { if (!enoughChars) { _charPos = _charsUsed; throw CreateUnexpectedEndException(); } for (int i = 0; i < value.Length; i++) { if (_chars[_charPos + i] != value[i]) { _charPos += i; return false; } } _charPos += value.Length; return true; } private bool MatchValueWithTrailingSeparator(string value) { if (!MatchValue(value)) return false; if (!EnsureChars(0, false)) return true; if (!IsSeparator(_chars[_charPos])) return _chars[_charPos] == ''; return true; } private bool IsSeparator(char c) { switch (c) { case ',': case ']': case '}': return true; case '/': { if (!EnsureChars(1, false)) return false; char c2 = _chars[_charPos + 1]; if (c2 != '*') return c2 == '/'; return true; } case ')': if (base.CurrentState == State.Constructor || base.CurrentState == State.ConstructorStart) return true; break; case '\t': case '\n': case '\r': case ' ': return true; default: if (char.IsWhiteSpace(c)) return true; break; } return false; } private void ParseTrue() { if (MatchValueWithTrailingSeparator(JsonConvert.True)) { SetToken(JsonToken.Boolean, true); return; } throw JsonReaderException.Create(this, "Error parsing boolean value."); } private void ParseNull() { if (MatchValueWithTrailingSeparator(JsonConvert.Null)) { SetToken(JsonToken.Null); return; } throw JsonReaderException.Create(this, "Error parsing null value."); } private void ParseUndefined() { if (MatchValueWithTrailingSeparator(JsonConvert.Undefined)) { SetToken(JsonToken.Undefined); return; } throw JsonReaderException.Create(this, "Error parsing undefined value."); } private void ParseFalse() { if (MatchValueWithTrailingSeparator(JsonConvert.False)) { SetToken(JsonToken.Boolean, false); return; } throw JsonReaderException.Create(this, "Error parsing boolean value."); } private object ParseNumberNegativeInfinity(ReadType readType) { return ParseNumberNegativeInfinity(readType, MatchValueWithTrailingSeparator(JsonConvert.NegativeInfinity)); } private object ParseNumberNegativeInfinity(ReadType readType, bool matched) { if (matched) { switch (readType) { case ReadType.Read: case ReadType.ReadAsDouble: if (_floatParseHandling == FloatParseHandling.Double) { SetToken(JsonToken.Float, -Infinity); return -Infinity; } break; case ReadType.ReadAsString: SetToken(JsonToken.String, JsonConvert.NegativeInfinity); return JsonConvert.NegativeInfinity; } throw JsonReaderException.Create(this, "Cannot read -Infinity value."); } throw JsonReaderException.Create(this, "Error parsing -Infinity value."); } private object ParseNumberPositiveInfinity(ReadType readType) { return ParseNumberPositiveInfinity(readType, MatchValueWithTrailingSeparator(JsonConvert.PositiveInfinity)); } private object ParseNumberPositiveInfinity(ReadType readType, bool matched) { if (matched) { switch (readType) { case ReadType.Read: case ReadType.ReadAsDouble: if (_floatParseHandling == FloatParseHandling.Double) { SetToken(JsonToken.Float, Infinity); return Infinity; } break; case ReadType.ReadAsString: SetToken(JsonToken.String, JsonConvert.PositiveInfinity); return JsonConvert.PositiveInfinity; } throw JsonReaderException.Create(this, "Cannot read Infinity value."); } throw JsonReaderException.Create(this, "Error parsing Infinity value."); } private object ParseNumberNaN(ReadType readType) { return ParseNumberNaN(readType, MatchValueWithTrailingSeparator(JsonConvert.NaN)); } private object ParseNumberNaN(ReadType readType, bool matched) { if (matched) { switch (readType) { case ReadType.Read: case ReadType.ReadAsDouble: if (_floatParseHandling == FloatParseHandling.Double) { SetToken(JsonToken.Float, NaN); return NaN; } break; case ReadType.ReadAsString: SetToken(JsonToken.String, JsonConvert.NaN); return JsonConvert.NaN; } throw JsonReaderException.Create(this, "Cannot read NaN value."); } throw JsonReaderException.Create(this, "Error parsing NaN value."); } public override void Close() { base.Close(); if (_chars != null) { BufferUtils.ReturnBuffer(_arrayPool, _chars); _chars = null; } if (base.CloseInput) _reader?.Dispose(); _stringBuffer.Clear(_arrayPool); } public bool HasLineInfo() { return true; } } }