예제 #1
0
        public ReaderStatus ReadToObject <TObject>(ReaderState state,
                                                   ILookupNode <char, ReaderCallback <ReaderState, string, char, TObject> > root, ref TObject target)
        {
            if (state.Current == -1)
            {
                return(ReaderStatus.Succeeded);
            }

            while (true)
            {
                // Parse field name
                var empty = true;

                // FIXME: handle % encoding in field names
                var node = root;

                while (QueryStringCharacter.IsUnreserved(state.Current))
                {
                    empty = false;
                    node  = node.Follow((char)state.Current);

                    state.Pull();
                }

                if (empty)
                {
                    state.Error("empty field name");

                    return(ReaderStatus.Failed);
                }

                // Parse field value
                switch (state.Current)
                {
                case '=':
                    state.Pull();
                    state.Location = QueryStringLocation.ValueBegin;

                    if (!(node.HasValue ? node.Value(this, state, ref target) == ReaderStatus.Succeeded : this.ReadToValue(state, out _) == ReaderStatus.Succeeded))
                    {
                        return(ReaderStatus.Failed);
                    }

                    break;

                default:
                    state.Location = QueryStringLocation.ValueEnd;

                    if (node.HasValue && node.Value(this, state, ref target) != ReaderStatus.Succeeded)
                    {
                        return(ReaderStatus.Failed);
                    }

                    break;
                }

                if (state.Location != QueryStringLocation.ValueEnd)
                {
                    throw new InvalidOperationException(
                              "internal error, please report an issue on GitHub: https://github.com/r3c/verse/issues");
                }

                // Expect either field separator or end of stream
                if (state.Current == -1)
                {
                    return(ReaderStatus.Succeeded);
                }

                if (!QueryStringCharacter.IsSeparator(state.Current))
                {
                    state.Error("unexpected character");

                    return(ReaderStatus.Failed);
                }

                state.Pull();

                // Check for end of stream (in case of dangling separator e.g. "?k&") and resume loop
                if (state.Current == -1)
                {
                    return(ReaderStatus.Succeeded);
                }

                state.Location = QueryStringLocation.Sequence;
            }
        }
예제 #2
0
        private static bool ReadValue(ReaderState state, out string value)
        {
            var buffer  = new byte[state.Encoding.GetMaxByteCount(1)];
            var builder = new StringBuilder(32);

            while (true)
            {
                int current = state.Current;

                if (QueryStringCharacter.IsUnreserved(current))
                {
                    builder.Append((char)current);

                    state.Pull();
                }
                else if (current == '+')
                {
                    builder.Append(' ');

                    state.Pull();
                }
                else if (current == '%')
                {
                    int count;

                    for (count = 0; state.Current == '%'; ++count)
                    {
                        if (count >= buffer.Length)
                        {
                            value = default;

                            return(false);
                        }

                        state.Pull();

                        if (state.Current == -1)
                        {
                            value = default;

                            return(false);
                        }

                        var hex1 = QueryStringCharacter.HexaToDecimal(state.Current);

                        state.Pull();

                        if (state.Current == -1)
                        {
                            value = default;

                            return(false);
                        }

                        var hex2 = QueryStringCharacter.HexaToDecimal(state.Current);

                        state.Pull();

                        if (hex1 < 0 || hex2 < 0)
                        {
                            value = default;

                            return(false);
                        }

                        buffer[count] = (byte)((hex1 << 4) + hex2);
                    }

                    builder.Append(state.Encoding.GetChars(buffer, 0, count));
                }
                else
                {
                    state.Location = QueryStringLocation.ValueEnd;

                    value = builder.ToString();

                    return(true);
                }
            }
        }