Ejemplo n.º 1
0
        /// <summary>
        /// Lexes and parses a JSON object as a hash table in the specified text reader.
        /// </summary>
        /// <typeparam name="TValue">The type of the values to deserialize.</typeparam>
        /// <param name="reader">The text reader to lex and parse an object from.</param>
        /// <param name="context">The parser context.</param>
        /// <param name="parseValue">The parser to use for values.</param>
        /// <returns>A hash table, if found; otherwise, a ParseException is thrown.</returns>
        /// <remarks>
        /// This method does not consume whitespace; the character at the specified start index in the string is expected to be the start of a valid JSON object.
        /// </remarks>
        internal static Dictionary <string, TValue> ParseAnyObject <TValue>(System.IO.TextReader reader, ParserContext context, ParseReaderFunc <TValue> parseValue)
        {
            Debug.Assert(reader.Peek() == '{');

            //
            // CONSIDER: Add support for different representations of objects, e.g. ExpandoObject from the DLR. For
            //           now, we'll go with the most obvious choice and users can wrap the resulting value in case
            //           they want to support dynamic behavior.
            //

            var res = new Dictionary <string, TValue>();

            reader.Read();

            SkipWhiteSpace(reader); // NB: We *have* to skip trailing whitespace after the { token.

            var c = reader.Peek();

            if (c < 0)
            {
                throw new ParseException("Unexpected end of stream when parsing object expecting an object body or '}' terminator.", -1, ParseError.PrematureEndOfInput);
            }

            if (c == '}')
            {
                reader.Read();
                SkipWhiteSpace(reader); // NB: We *have* to skip trailing whitespace after the } token.
                return(res);
            }

            while (c >= 0)
            {
                var key = ParseStringNonNull(reader);

                SkipWhiteSpace(reader); // NB: This skips leading whitespace before the : token; we can't rely on the trie to do it.

                c = reader.Peek();

                if (c < 0)
                {
                    throw new ParseException("Unexpected end of stream when parsing object expecting a ':' separator between a key name and a value.", -1, ParseError.PrematureEndOfInput);
                }

                if (c != ':')
                {
                    throw new ParseException(string.Format(CultureInfo.InvariantCulture, "Unexpected character '{0}' encountered when parsing object expecting a ':' token to separate key name and a value.", (char)c), -1, ParseError.UnexpectedToken);
                }

                reader.Read();

                SkipWhiteSpace(reader); // NB: We *have* to skip trailing whitespace after the : token.

                //
                // NB: We're not using Add here in order to allow for duplicate keys. The last one in lexical order wins, which is
                //     consistent with behavior of other popular JSON frameworks and the behavior of our strongly typed object
                //     deserializer.
                //

                res[key] = parseValue(reader, context);

                //
                // CONSIDER: Parsers for primitives don't trim trailing whitespace. We could change this and eliminate the need to
                //           skip whitespace here ourselves. This trimming is duplicate work if we're dealing with objects or
                //           arrays which already guarantee trimming trailing whitespace.
                //

                SkipWhiteSpace(reader);

                c = reader.Peek();

                if (c < 0)
                {
                    throw new ParseException("Unexpected end of stream when parsing object.", -1, ParseError.PrematureEndOfInput);
                }

                switch (c)
                {
                case ',':
                    reader.Read();
                    SkipWhiteSpace(reader);     // NB: We *have* to skip trailing whitespace after the , token.
                    break;

                case '}':
                    reader.Read();
                    SkipWhiteSpace(reader);     // NB: We *have* to skip trailing whitespace after the } token.
                    return(res);

                default:
                    throw new ParseException(string.Format(CultureInfo.InvariantCulture, "Unexpected character '{0}' encountered when parsing object expecting either ',' or '}}'.", (char)c), -1, ParseError.UnexpectedToken);
                }

                c = reader.Peek();
            }

            throw new ParseException("Unexpected end of stream when parsing object and expecting a key.", -1, ParseError.PrematureEndOfInput);
        }
 /// <summary>
 /// Creates a new deserializer given the specified parser implementation.
 /// </summary>
 /// <param name="parseString">The parser to use to deserialize JSON payloads from string inputs.</param>
 /// <param name="parseReader">The parser to use to deserialize JSON payloads from text reader inputs.</param>
 public Deserializer(ParseStringFunc <T> parseString, ParseReaderFunc <T> parseReader)
     : base(parseString, parseReader)
 {
     _context = new ParserContext();
 }
Ejemplo n.º 3
0
 /// <summary>
 /// Creates a new deserializer given the specified parser implementations.
 /// </summary>
 /// <param name="parseString">The parser to use to deserialize JSON payloads from string inputs.</param>
 /// <param name="parseReader">The parser to use to deserialize JSON payloads from text reader inputs.</param>
 public DeserializerBase(ParseStringFunc <T> parseString, ParseReaderFunc <T> parseReader)
 {
     _parseString = parseString;
     _parseReader = parseReader;
 }
 /// <summary>
 /// Creates a new deserializer given the specified parser implementations.
 /// </summary>
 /// <param name="parseString">The parser to use to deserialize JSON payloads from string inputs.</param>
 /// <param name="parseReader">The parser to use to deserialize JSON payloads from text reader inputs.</param>
 public SafeDeserializer(ParseStringFunc <T> parseString, ParseReaderFunc <T> parseReader)
     : base(parseString, parseReader)
 {
     _contextPool = new ObjectPool <ParserContext>(() => new ParserContext());
 }