예제 #1
0
 /// <summary>
 /// Constructs a new JsonParseException
 /// </summary>
 /// <param name="inner">The inner exception</param>
 /// <param name="context">A string describing the context of the serialization (parent key path)</param>
 /// <param name="position">The position in the JSON stream where the error occured</param>
 public JsonParseException(Exception inner, string context, LineOffset position) :
     base(string.Format("JSON parse error at {0}{1} - {2}", position, string.IsNullOrEmpty(context) ? "" : string.Format(", context {0}", context), inner.Message), inner)
 {
     Position = position;
     Context  = context;
 }
예제 #2
0
        // Read the next token from the input stream
        // (Mostly inline for performance)
        public void NextToken()
        {
            while (true)
            {
                // Skip whitespace and handle line numbers
                while (true)
                {
                    if (_currentChar == '\r')
                    {
                        if (NextChar() == '\n')
                        {
                            NextChar();
                        }
                        _currentCharPos.Line++;
                        _currentCharPos.Offset = 0;
                    }
                    else if (_currentChar == '\n')
                    {
                        if (NextChar() == '\r')
                        {
                            NextChar();
                        }
                        _currentCharPos.Line++;
                        _currentCharPos.Offset = 0;
                    }
                    else if (_currentChar == ' ')
                    {
                        NextChar();
                    }
                    else if (_currentChar == '\t')
                    {
                        NextChar();
                    }
                    else
                    {
                        break;
                    }
                }

                // Remember position of token
                CurrentTokenPosition = _currentCharPos;

                // Handle common characters first
                switch (_currentChar)
                {
                case '/':
                    // Comments not support in strict mode
                    if ((_options & JsonOptions.StrictParser) != 0)
                    {
                        throw new InvalidDataException(string.Format("syntax error, unexpected character '{0}'", _currentChar));
                    }

                    // Process comment
                    NextChar();
                    switch (_currentChar)
                    {
                    case '/':
                        NextChar();
                        while (_currentChar != '\0' && _currentChar != '\r' && _currentChar != '\n')
                        {
                            NextChar();
                        }
                        break;

                    case '*':
                        bool endFound = false;
                        while (!endFound && _currentChar != '\0')
                        {
                            if (_currentChar == '*')
                            {
                                NextChar();
                                if (_currentChar == '/')
                                {
                                    endFound = true;
                                }
                            }
                            NextChar();
                        }
                        break;

                    default:
                        throw new InvalidDataException("syntax error, unexpected character after slash");
                    }
                    continue;

                case '\"':
                case '\'':
                {
                    _sb.Length = 0;
                    var quoteKind = _currentChar;
                    NextChar();
                    while (_currentChar != '\0')
                    {
                        if (_currentChar == '\\')
                        {
                            NextChar();
                            var escape = _currentChar;
                            switch (escape)
                            {
                            case '\"': _sb.Append('\"'); break;

                            case '\\': _sb.Append('\\'); break;

                            case '/': _sb.Append('/'); break;

                            case 'b': _sb.Append('\b'); break;

                            case 'f': _sb.Append('\f'); break;

                            case 'n': _sb.Append('\n'); break;

                            case 'r': _sb.Append('\r'); break;

                            case 't': _sb.Append('\t'); break;

                            case 'u':
                                var sbHex = new StringBuilder();
                                for (int i = 0; i < 4; i++)
                                {
                                    NextChar();
                                    sbHex.Append(_currentChar);
                                }
                                _sb.Append((char)Convert.ToUInt16(sbHex.ToString(), 16));
                                break;

                            default:
                                throw new InvalidDataException(string.Format("Invalid escape sequence in string literal: '\\{0}'", _currentChar));
                            }
                        }
                        else if (_currentChar == quoteKind)
                        {
                            String       = _sb.ToString();
                            CurrentToken = Token.Literal;
                            LiteralKind  = LiteralKind.String;
                            NextChar();
                            return;
                        }
                        else
                        {
                            _sb.Append(_currentChar);
                        }

                        NextChar();
                    }
                    throw new InvalidDataException("syntax error, unterminated string literal");
                }

                case '{': CurrentToken = Token.OpenBrace; NextChar(); return;

                case '}': CurrentToken = Token.CloseBrace; NextChar(); return;

                case '[': CurrentToken = Token.OpenSquare; NextChar(); return;

                case ']': CurrentToken = Token.CloseSquare; NextChar(); return;

                case '=': CurrentToken = Token.Equal; NextChar(); return;

                case ':': CurrentToken = Token.Colon; NextChar(); return;

                case ';': CurrentToken = Token.SemiColon; NextChar(); return;

                case ',': CurrentToken = Token.Comma; NextChar(); return;

                case '\0': CurrentToken = Token.EOF; return;
                }

                // Number?
                if (char.IsDigit(_currentChar) || _currentChar == '-')
                {
                    TokenizeNumber();
                    return;
                }

                // Identifier?  (checked for after everything else as identifiers are actually quite rare in valid json)
                if (Char.IsLetter(_currentChar) || _currentChar == '_' || _currentChar == '$')
                {
                    // Find end of identifier
                    _sb.Length = 0;
                    while (Char.IsLetterOrDigit(_currentChar) || _currentChar == '_' || _currentChar == '$')
                    {
                        _sb.Append(_currentChar);
                        NextChar();
                    }
                    String = _sb.ToString();

                    // Handle special identifiers
                    switch (String)
                    {
                    case "true":
                        LiteralKind  = LiteralKind.True;
                        CurrentToken = Token.Literal;
                        return;

                    case "false":
                        LiteralKind  = LiteralKind.False;
                        CurrentToken = Token.Literal;
                        return;

                    case "null":
                        LiteralKind  = LiteralKind.Null;
                        CurrentToken = Token.Literal;
                        return;
                    }

                    CurrentToken = Token.Identifier;
                    return;
                }

                // What the?
                throw new InvalidDataException(string.Format("syntax error, unexpected character '{0}'", _currentChar));
            }
        }