Exemple #1
0
        private unsafe string GetString(char *charBuffer)
        {
            Consume();
            var len = 0;

            while (true)
            {
                if (_isEnd)
                {
                    throw JsonParserException.UnexpectedEnd(_position);
                }
                var ch = _nextChar;
                if (ch == '"')
                {
                    Consume();
                    return(_stringBuffer.GetString(charBuffer, len));
                }
                if (ch == '\\')
                {
                    ch = UnEscape();
                }
                else if (ch < ' ')
                {
                    throw JsonParserException.UnexpectedError(ch, _position);
                }
                if (len >= StringInitialCapacity)
                {
                    _stringBuffer.Append(charBuffer, len);
                    len = 0;
                }
                charBuffer[len++] = ch;
                Consume();
            }
        }
Exemple #2
0
        private char UnEscapeUnicode()
        {
            var code = 0;

            for (var i = 0; i < 4; i++)
            {
                Consume();
                var ch = _nextChar;
                code <<= 4;
                if ('0' <= ch && ch <= '9')
                {
                    code += ch - '0';
                }
                else if ('a' <= ch && ch <= 'f')
                {
                    code += 10 + ch - 'a';
                }
                else if ('A' <= ch && ch <= 'F')
                {
                    code += 10 + ch - 'A';
                }
                else
                {
                    throw JsonParserException.InvalidError($"unicode escape '{ch}'", _position);
                }
            }
            return((char)code);
        }
Exemple #3
0
        private double GetNumber()
        {
            var result = 0d;
            var sign   = 1;

            if (_nextChar == '-')
            {
                sign = -1;
                Consume();
                if (!IsNumber())
                {
                    throw JsonParserException.ExpectingError("digit", _position);
                }
            }
            do
            {
                result = result * 10.0 + (_nextChar - '0');
                Consume();
            } while (IsNumber());
            if (_nextChar == '.')
            {
                Consume();
                if (!IsNumber())
                {
                    throw JsonParserException.ExpectingError("digit", _position);
                }
                var exp = 0.1;
                do
                {
                    result += (_nextChar - '0') * exp;
                    exp    *= 0.1;
                    Consume();
                } while (IsNumber());
            }
            if (_nextChar == 'e' || _nextChar == 'E')
            {
                Consume();
                var expSign = 1;
                var exp     = 0;
                if (_nextChar == '-' || _nextChar == '+')
                {
                    if (_nextChar == '-')
                    {
                        expSign = -1;
                    }
                    Consume();
                }
                if (!IsNumber())
                {
                    throw JsonParserException.ExpectingError("digit", _position);
                }
                do
                {
                    exp = exp * 10 + (_nextChar - '0');
                    Consume();
                } while (IsNumber());
                result = result * Math.Pow(10, expSign * exp);
            }
            return(sign * result);
        }
Exemple #4
0
        private string GetString()
        {
            Consume();
            var start = _position;
            var len   = 0;

            while (true)
            {
                if (_isEnd)
                {
                    throw JsonParserException.UnexpectedEnd(start + len);
                }
                var ch = _nextChar;
                if (ch == '"')
                {
                    Consume();
                    return(new string(_charBuffer, 0, len));
                }
                if (ch == '\\')
                {
                    ch = UnEscape();
                }
                else if (ch < ' ')
                {
                    throw JsonParserException.UnexpectedError(ch, _position);
                }
                if (len >= _charBuffer.Length)
                {
                    Array.Resize(ref _charBuffer, _charBuffer.Length * 2);
                }
                _charBuffer[len++] = ch;
                Consume();
            }
        }
Exemple #5
0
 private void CheckToken(string s)
 {
     Consume();
     foreach (var ch in s)
     {
         if (ch != _nextChar)
         {
             throw JsonParserException.ExpectingError($"'{ch}'", _position);
         }
         Consume();
     }
 }
Exemple #6
0
        private char UnEscape()
        {
            Consume();
            var ch = _nextChar;

            switch (ch)
            {
            case '\\':
            case '/':
            case '"':
                break;

            case 'b':
                ch = '\b';
                break;

            case 'f':
                ch = '\f';
                break;

            case 'n':
                ch = '\n';
                break;

            case 'r':
                ch = '\r';
                break;

            case 't':
                ch = '\t';
                break;

            case 'u':
                ch = UnEscapeUnicode();
                break;

            default:
                throw JsonParserException.InvalidError($"escape character '{ch}'", _position);
            }
            return(ch);
        }
Exemple #7
0
        private unsafe object ParseInternal(TextReader reader, int maxDepth)
        {
            Setup(reader);
            var context    = new Context();
            var charBuffer = stackalloc char[StringInitialCapacity];

            SkipWhiteSpaces();
            while (true)
            {
                var value = new InternalObject();
                switch (_nextChar)
                {
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                case '-':
                    value.Number = GetNumber();
                    break;

                case 'n':
                    CheckToken("ull");
                    value.Type = JsonType.Null;
                    break;

                case 't':
                    CheckToken("rue");
                    value.Type = JsonType.True;
                    break;

                case 'f':
                    // ReSharper disable once StringLiteralTypo
                    CheckToken("alse");
                    value.Type = JsonType.False;
                    break;

                case '"':
                    value.Type   = JsonType.String;
                    value.String = GetString(charBuffer);
                    break;

                case '[':
                    if (_stack.Count == maxDepth)
                    {
                        throw JsonParserException.TooDeepNesting(_stack.Count, _position);
                    }
                    Consume();
                    _stack.Push(context);
                    context = new Context
                    {
                        Array = new JsonArray()
                    };
                    SkipWhiteSpaces();
                    continue;

                case ']':
                    if (context.Array == null)
                    {
                        throw JsonParserException.UnexpectedError(_nextChar, _position);
                    }
                    Consume();
                    value.Type  = JsonType.Array;
                    value.Array = context.Array;
                    context     = _stack.Pop();
                    break;

                case '{':
                    if (_stack.Count == maxDepth)
                    {
                        throw JsonParserException.TooDeepNesting(_stack.Count, _position);
                    }
                    Consume();
                    _stack.Push(context);
                    context = new Context
                    {
                        Dictionary = new JsonDictionary()
                    };
                    goto GetKey;

                case '}':
                    if (context.Dictionary == null)
                    {
                        throw JsonParserException.UnexpectedError(_nextChar, _position);
                    }
                    Consume();
                    value.Type       = JsonType.Object;
                    value.Dictionary = context.Dictionary;
                    context          = _stack.Pop();
                    break;

                default:
                    if (_isEnd)
                    {
                        throw JsonParserException.UnexpectedEnd(_position);
                    }
                    throw JsonParserException.UnexpectedError(_nextChar, _position);
                }

                SkipWhiteSpaces();
                // Start
                if (_stack.Count == 0)
                {
                    // The buffer intentionally leaks in exceptional cases to simplify the code for exceptions.
                    BufferPool.Return(_buffer);
                    if (_isEnd)
                    {
                        return(JsonObject.ToValue(value));
                    }
                    throw JsonParserException.UnexpectedError(_nextChar, _position);
                }
                // Array
                if (context.Key == null)
                {
                    context.Array.Add(value);
                    if (_nextChar == ']')
                    {
                        continue;
                    }
                    if (_nextChar != ',')
                    {
                        throw JsonParserException.ExpectingError("',' or ']'", _position);
                    }
                    Consume();
                    SkipWhiteSpaces();
                    continue;
                }
                // Object
                context.Dictionary.Add(context.Key, value);
                if (_nextChar == '}')
                {
                    continue;
                }
                if (_nextChar != ',')
                {
                    throw JsonParserException.ExpectingError("',' or '}'", _position);
                }
                Consume();

GetKey:
                SkipWhiteSpaces();
                if (_nextChar == '}')
                {
                    continue;
                }
                if (_nextChar != '"')
                {
                    throw JsonParserException.ExpectingError("string", _position);
                }
                context.Key = GetString(charBuffer);
                SkipWhiteSpaces();
                if (_nextChar != ':')
                {
                    throw JsonParserException.ExpectingError("':'", _position);
                }
                Consume();
                SkipWhiteSpaces();
            }
        }
Exemple #8
0
        private object ParseInternal(TextReader reader, int maxDepth)
        {
            Setup(reader);
            var stack   = new Context[maxDepth];
            var depth   = 0;
            var context = new Context();

            SkipWhiteSpaces();
            while (true)
            {
                var value = new InternalObject();
                switch (_nextChar)
                {
                case '0':
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                case '-':
                    value.Number = GetNumber();
                    break;

                case 'n':
                    CheckToken("ull");
                    value.Type = JsonType.Null;
                    break;

                case 't':
                    CheckToken("rue");
                    value.Type = JsonType.True;
                    break;

                case 'f':
                    // ReSharper disable once StringLiteralTypo
                    CheckToken("alse");
                    value.Type = JsonType.False;
                    break;

                case '"':
                    value.Type   = JsonType.String;
                    value.String = GetString();
                    break;

                case '[':
                    if (depth == maxDepth)
                    {
                        throw JsonParserException.TooDeepNesting(depth, _position);
                    }
                    Consume();
                    stack[depth++] = context;
                    context        = new Context
                    {
                        Array = new JsonArray()
                    };
                    SkipWhiteSpaces();
                    continue;

                case ']':
                    if (context.Array == null)
                    {
                        throw JsonParserException.UnexpectedError(_nextChar, _position);
                    }
                    Consume();
                    value.Type  = JsonType.Array;
                    value.Array = context.Array;
                    context     = stack[--depth];
                    break;

                case '{':
                    if (depth == maxDepth)
                    {
                        throw JsonParserException.TooDeepNesting(depth, _position);
                    }
                    Consume();
                    stack[depth++] = context;
                    context        = new Context
                    {
                        Dictionary = new JsonDictionary()
                    };
                    goto GetKey;

                case '}':
                    if (context.Dictionary == null)
                    {
                        throw JsonParserException.UnexpectedError(_nextChar, _position);
                    }
                    Consume();
                    value.Type       = JsonType.Object;
                    value.Dictionary = context.Dictionary;
                    context          = stack[--depth];
                    break;

                default:
                    if (_isEnd)
                    {
                        throw JsonParserException.UnexpectedEnd(_position);
                    }
                    throw JsonParserException.UnexpectedError(_nextChar, _position);
                }

                SkipWhiteSpaces();
                // Start
                if (depth == 0)
                {
                    if (_isEnd)
                    {
                        return(JsonObject.ToValue(value));
                    }
                    throw JsonParserException.UnexpectedError(_nextChar, _position);
                }
                // Array
                if (context.Key == null)
                {
                    context.Array.Add(value);
                    if (_nextChar == ']')
                    {
                        continue;
                    }
                    if (_nextChar != ',')
                    {
                        throw JsonParserException.ExpectingError("',' or ']'", _position);
                    }
                    Consume();
                    SkipWhiteSpaces();
                    continue;
                }
                // Object
                context.Dictionary.Add(context.Key, value);
                if (_nextChar == '}')
                {
                    continue;
                }
                if (_nextChar != ',')
                {
                    throw JsonParserException.ExpectingError("',' or '}'", _position);
                }
                Consume();

GetKey:
                SkipWhiteSpaces();
                if (_nextChar == '}')
                {
                    continue;
                }
                if (_nextChar != '"')
                {
                    throw JsonParserException.ExpectingError("string", _position);
                }
                context.Key = GetString();
                SkipWhiteSpaces();
                if (_nextChar != ':')
                {
                    throw JsonParserException.ExpectingError("':'", _position);
                }
                Consume();
                SkipWhiteSpaces();
            }
        }