Exemplo n.º 1
0
            /// <remarks>
            /// This method essentially just loops through characters skipping whitespace, validating and
            /// changing state (e.g. from ObjectBeforeColon to ObjectAfterColon)
            /// until it reaches something which will be a genuine token (e.g. a start object, or a value) at which point
            /// it returns the token. Although the method is large, it would be relatively hard to break down further... most
            /// of it is the large switch statement, which sometimes returns and sometimes doesn't.
            /// </remarks>
            protected override JsonToken NextImpl()
            {
                if (state == State.ReaderExhausted)
                {
                    throw new InvalidOperationException("Next() called after end of document");
                }
                while (true)
                {
                    var next = reader.Read();
                    if (next == null)
                    {
                        ValidateState(State.ExpectedEndOfDocument, "Unexpected end of document in state: ");
                        state = State.ReaderExhausted;
                        return(JsonToken.EndDocument);
                    }
                    switch (next.Value)
                    {
                    // Skip whitespace between tokens
                    case ' ':
                    case '\t':
                    case '\r':
                    case '\n':
                        break;

                    case ':':
                        ValidateState(State.ObjectBeforeColon, "Invalid state to read a colon: ");
                        state = State.ObjectAfterColon;
                        break;

                    case ',':
                        ValidateState(State.ObjectAfterProperty | State.ArrayAfterValue, "Invalid state to read a colon: ");
                        state = state == State.ObjectAfterProperty ? State.ObjectAfterComma : State.ArrayAfterComma;
                        break;

                    case '"':
                        string stringValue = ReadString();
                        if ((state & (State.ObjectStart | State.ObjectAfterComma)) != 0)
                        {
                            state = State.ObjectBeforeColon;
                            return(JsonToken.Name(stringValue));
                        }
                        else
                        {
                            ValidateAndModifyStateForValue("Invalid state to read a double quote: ");
                            return(JsonToken.Value(stringValue));
                        }

                    case '{':
                        ValidateState(ValueStates, "Invalid state to read an open brace: ");
                        state = State.ObjectStart;
                        containerStack.Push(ContainerType.Object);
                        return(JsonToken.StartObject);

                    case '}':
                        ValidateState(State.ObjectAfterProperty | State.ObjectStart, "Invalid state to read a close brace: ");
                        PopContainer();
                        return(JsonToken.EndObject);

                    case '[':
                        ValidateState(ValueStates, "Invalid state to read an open square bracket: ");
                        state = State.ArrayStart;
                        containerStack.Push(ContainerType.Array);
                        return(JsonToken.StartArray);

                    case ']':
                        ValidateState(State.ArrayAfterValue | State.ArrayStart, "Invalid state to read a close square bracket: ");
                        PopContainer();
                        return(JsonToken.EndArray);

                    case 'n':     // Start of null
                        ConsumeLiteral("null");
                        ValidateAndModifyStateForValue("Invalid state to read a null literal: ");
                        return(JsonToken.Null);

                    case 't':     // Start of true
                        ConsumeLiteral("true");
                        ValidateAndModifyStateForValue("Invalid state to read a true literal: ");
                        return(JsonToken.True);

                    case 'f':     // Start of false
                        ConsumeLiteral("false");
                        ValidateAndModifyStateForValue("Invalid state to read a false literal: ");
                        return(JsonToken.False);

                    case '-':     // Start of a number
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                        double number = ReadNumber(next.Value);
                        ValidateAndModifyStateForValue("Invalid state to read a number token: ");
                        return(JsonToken.Value(number));

                    default:
                        throw new InvalidJsonException("Invalid first character of token: " + next.Value);
                    }
                }
            }