コード例 #1
0
            private TextToken GetToken(ITokenMaker tokenMaker, string stringValue)
            {
                if ((state & State.StartOfDocument) == State.StartOfDocument)
                {
                    var next = ReadNoisyContent();

                    if (next == null)
                    {
                        state = State.ExpectedEndOfDocument;
                        return(tokenMaker.CreateValueToken(stringValue));
                    }
                    else
                    {
                        reader.PushBack(next.Value);
                        PushBack(TextToken.Name(stringValue));
                        state = State.ObjectBeforeColon;
                        containerStack.Push(ContainerType.Object);
                        return(TextToken.StartObject);
                    }
                }

                if ((state & (State.ObjectStart | State.ObjectAfterComma | State.ObjectAfterProperty)) != 0)
                {
                    state = State.ObjectBeforeColon;
                    return(tokenMaker.CreateNameToken(stringValue));
                }
                else
                {
                    ValidateAndModifyStateForValue("Invalid state to read a double quote: ");
                    return(tokenMaker.CreateValueToken(stringValue));
                }
            }
コード例 #2
0
        /// <summary>
        /// Returns the next text token in the stream. An EndDocument token is returned to indicate the end of the stream,
        /// after which point <c>Next()</c> should not be called again.
        /// </summary>
        /// <remarks>This implementation provides single-token buffering, and calls <see cref="NextImpl"/> if there is no buffered token.</remarks>
        /// <returns>The next token in the stream. This is never null.</returns>
        /// <exception cref="InvalidOperationException">This method is called after an EndDocument token has been returned</exception>
        /// <exception cref="InvalidTextException">The input text does not comply with RFC 7159</exception>
        internal virtual TextToken Next()
        {
            TextToken tokenToReturn;

            if (bufferedToken != null)
            {
                tokenToReturn = bufferedToken;
                bufferedToken = null;

                if (bufferedToken2 != null)
                {
                    bufferedToken  = bufferedToken2;
                    bufferedToken2 = null;
                }
            }
            else
            {
                tokenToReturn = NextImpl();
            }
            if (tokenToReturn.Type == TokenType.StartObject)
            {
                ObjectDepth++;
            }
            else if (tokenToReturn.Type == TokenType.EndObject)
            {
                ObjectDepth--;
            }

            return(tokenToReturn);
        }
コード例 #3
0
            private TextToken ConsumeLiteral(string text, TextToken exptectedToken)
            {
                var           matchCount     = 1;
                var           macthCountToBe = text.Length;
                StringBuilder sb             = null;

                while (true)
                {
                    char?next = reader.Read();

                    if (next == null || char.IsWhiteSpace(next.Value) || next.Value == ':')
                    {
                        if (next != null && next.Value == ':')
                        {
                            reader.PushBack(next.Value);
                        }

                        if (sb == null && matchCount < macthCountToBe)
                        {
                            return(GetToken(text.Substring(0, matchCount)));
                        }

                        break;
                    }

                    if (sb == null) // trying to match
                    {
                        if (matchCount < macthCountToBe)
                        {
                            if (next.Value == text[matchCount])
                            {
                                matchCount++;
                                continue;
                            }
                        }

                        sb = new StringBuilder();
                        sb.Append(text.Substring(0, matchCount));
                        sb.Append(next.Value);
                    }
                    else // read normal string
                    {
                        sb.Append(next.Value);
                    }
                }

                if (matchCount == macthCountToBe)
                {
                    ModifyStateForValue();
                    return(exptectedToken);
                }

                return(GetToken(sb.ToString()));
            }
コード例 #4
0
 private TextToken GetValueString(string stringValue)
 {
     if ((state & (State.ObjectStart | State.ObjectAfterComma)) != 0)
     {
         state = State.ObjectBeforeColon;
         return(TextToken.Name(stringValue));
     }
     else
     {
         ValidateAndModifyStateForValue("Invalid state to read a double quote: ");
         return(TextToken.Value(stringValue));
     }
 }
コード例 #5
0
                public TextToken CreateValueToken(string text)
                {
                    try
                    {
                        var num = double.Parse(text,
                                               NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent,
                                               CultureInfo.InvariantCulture);

                        return(TextToken.Value(num));
                    }
                    catch (OverflowException)
                    {
                        throw new InvalidTextException("Unable parse the number: " + text);
                    }
                }
コード例 #6
0
 // TODO: Why do we allow a different token to be pushed back? It might be better to always remember the previous
 // token returned, and allow a parameterless Rewind() method (which could only be called once, just like the current PushBack).
 internal void PushBack(TextToken token)
 {
     if (bufferedToken != null)
     {
         throw new InvalidOperationException("Can't push back twice");
     }
     bufferedToken = token;
     if (token.Type == TokenType.StartObject)
     {
         ObjectDepth--;
     }
     else if (token.Type == TokenType.EndObject)
     {
         ObjectDepth++;
     }
 }
コード例 #7
0
 public TextToken CreateNameToken(string text)
 {
     return(TextToken.Name(text));
 }
コード例 #8
0
 public TextToken CreateValueToken(string text)
 {
     return(TextToken.Value(text));
 }
コード例 #9
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 TextToken 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(TextToken.EndDocument);
                    }

                    if (state == State.StartOfDocument)
                    {
                        reader.PushBack(next.Value);

                        next = ReadNoisyContent();

                        if (next.Value == '{')
                        {
                            state = State.ArrayStart;
                            containerStack.Push(ContainerType.Array);
                            return(TextToken.StartArray);
                        }
                        else
                        {
                            if (next.Value != '\"')
                            {
                                reader.PushBack(next.Value);
                            }

                            containerStack.Push(ContainerType.Object);

                            var name = ReadName();

                            if (reader.LastChar == null)
                            {
                                // single value
                                state = State.ExpectedEndOfDocument;

                                if ("null".Equals(name, StringComparison.OrdinalIgnoreCase))
                                {
                                    return(TextToken.Null);
                                }
                                else
                                {
                                    return(TextToken.Value(name));
                                }
                            }

                            PushBack(TextToken.Name(name));

                            state = State.ObjectStart;
                            return(TextToken.StartObject);
                        }
                    }
                    else if (state == State.ObjectAfterProperty)
                    {
                        if (char.IsWhiteSpace(next.Value))
                        {
                            continue;
                        }

                        if (next.Value != '}')
                        {
                            reader.PushBack(next.Value);

                            var name = ReadName();

                            state = State.ObjectAfterColon;
                            return(TextToken.Name(name));
                        }
                    }
                    else if (state == State.ObjectStart)
                    {
                        next = ReadNoisyContent();

                        if (next.Value != '}')
                        {
                            reader.PushBack(next.Value);

                            var name = ReadName();
                            state = State.ObjectAfterColon;
                            return(TextToken.Name(name));
                        }
                    }

                    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 comma: ");
                        state = state == State.ObjectAfterProperty ? State.ObjectAfterComma : State.ArrayAfterComma;
                        break;

                    case '\'':
                    case '"':
                        return(GetValueString(next.Value));

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

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

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

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

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

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

                    case 'f':     // Start of false
                        ConsumeLiteral("false");
                        ValidateAndModifyStateForValue("Invalid state to read a false literal: ");
                        return(TextToken.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(TextToken.Value(number));

                    default:
                        reader.PushBack(next.Value);
                        return(GetValueString(ReadName()));
                    }
                }
            }