479 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C#
		
	
			
		
		
	
	
			479 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C#
		
	
#region Header
 | 
						|
/**
 | 
						|
 * JsonReader.cs
 | 
						|
 *   Stream-like access to JSON text.
 | 
						|
 *
 | 
						|
 * The authors disclaim copyright to this source code. For more details, see
 | 
						|
 * the COPYING file included with this distribution.
 | 
						|
 **/
 | 
						|
#endregion
 | 
						|
 | 
						|
 | 
						|
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Globalization;
 | 
						|
using System.IO;
 | 
						|
using System.Text;
 | 
						|
 | 
						|
 | 
						|
namespace LitJson
 | 
						|
{
 | 
						|
    public enum JsonToken
 | 
						|
    {
 | 
						|
        None,
 | 
						|
 | 
						|
        ObjectStart,
 | 
						|
        PropertyName,
 | 
						|
        ObjectEnd,
 | 
						|
 | 
						|
        ArrayStart,
 | 
						|
        ArrayEnd,
 | 
						|
 | 
						|
        Int,
 | 
						|
        Long,
 | 
						|
        Double,
 | 
						|
 | 
						|
        String,
 | 
						|
 | 
						|
        Boolean,
 | 
						|
        Null
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    public class JsonReader
 | 
						|
    {
 | 
						|
        #region Fields
 | 
						|
        private static readonly IDictionary<int, IDictionary<int, int[]>> parse_table;
 | 
						|
 | 
						|
        private Stack<int>    automaton_stack;
 | 
						|
        private int           current_input;
 | 
						|
        private int           current_symbol;
 | 
						|
        private bool          end_of_json;
 | 
						|
        private bool          end_of_input;
 | 
						|
        private Lexer         lexer;
 | 
						|
        private bool          parser_in_string;
 | 
						|
        private bool          parser_return;
 | 
						|
        private bool          read_started;
 | 
						|
        private TextReader    reader;
 | 
						|
        private bool          reader_is_owned;
 | 
						|
        private bool          skip_non_members;
 | 
						|
        private object        token_value;
 | 
						|
        private JsonToken     token;
 | 
						|
        #endregion
 | 
						|
 | 
						|
 | 
						|
        #region Public Properties
 | 
						|
        public bool AllowComments {
 | 
						|
            get { return lexer.AllowComments; }
 | 
						|
            set { lexer.AllowComments = value; }
 | 
						|
        }
 | 
						|
 | 
						|
        public bool AllowSingleQuotedStrings {
 | 
						|
            get { return lexer.AllowSingleQuotedStrings; }
 | 
						|
            set { lexer.AllowSingleQuotedStrings = value; }
 | 
						|
        }
 | 
						|
 | 
						|
        public bool SkipNonMembers {
 | 
						|
            get { return skip_non_members; }
 | 
						|
            set { skip_non_members = value; }
 | 
						|
        }
 | 
						|
 | 
						|
        public bool EndOfInput {
 | 
						|
            get { return end_of_input; }
 | 
						|
        }
 | 
						|
 | 
						|
        public bool EndOfJson {
 | 
						|
            get { return end_of_json; }
 | 
						|
        }
 | 
						|
 | 
						|
        public JsonToken Token {
 | 
						|
            get { return token; }
 | 
						|
        }
 | 
						|
 | 
						|
        public object Value {
 | 
						|
            get { return token_value; }
 | 
						|
        }
 | 
						|
        #endregion
 | 
						|
 | 
						|
 | 
						|
        #region Constructors
 | 
						|
        static JsonReader ()
 | 
						|
        {
 | 
						|
            parse_table = PopulateParseTable ();
 | 
						|
        }
 | 
						|
 | 
						|
        public JsonReader (string json_text) :
 | 
						|
            this (new StringReader (json_text), true)
 | 
						|
        {
 | 
						|
        }
 | 
						|
 | 
						|
        public JsonReader (TextReader reader) :
 | 
						|
            this (reader, false)
 | 
						|
        {
 | 
						|
        }
 | 
						|
 | 
						|
        private JsonReader (TextReader reader, bool owned)
 | 
						|
        {
 | 
						|
            if (reader == null)
 | 
						|
                throw new ArgumentNullException ("reader");
 | 
						|
 | 
						|
            parser_in_string = false;
 | 
						|
            parser_return    = false;
 | 
						|
 | 
						|
            read_started = false;
 | 
						|
            automaton_stack = new Stack<int> ();
 | 
						|
            automaton_stack.Push ((int) ParserToken.End);
 | 
						|
            automaton_stack.Push ((int) ParserToken.Text);
 | 
						|
 | 
						|
            lexer = new Lexer (reader);
 | 
						|
 | 
						|
            end_of_input = false;
 | 
						|
            end_of_json  = false;
 | 
						|
 | 
						|
            skip_non_members = true;
 | 
						|
 | 
						|
            this.reader = reader;
 | 
						|
            reader_is_owned = owned;
 | 
						|
        }
 | 
						|
        #endregion
 | 
						|
 | 
						|
 | 
						|
        #region Static Methods
 | 
						|
        private static IDictionary<int, IDictionary<int, int[]>> PopulateParseTable ()
 | 
						|
        {
 | 
						|
            // See section A.2. of the manual for details
 | 
						|
            IDictionary<int, IDictionary<int, int[]>> parse_table = new Dictionary<int, IDictionary<int, int[]>> ();
 | 
						|
 | 
						|
            TableAddRow (parse_table, ParserToken.Array);
 | 
						|
            TableAddCol (parse_table, ParserToken.Array, '[',
 | 
						|
                            '[',
 | 
						|
                            (int) ParserToken.ArrayPrime);
 | 
						|
 | 
						|
            TableAddRow (parse_table, ParserToken.ArrayPrime);
 | 
						|
            TableAddCol (parse_table, ParserToken.ArrayPrime, '"',
 | 
						|
                            (int) ParserToken.Value,
 | 
						|
 | 
						|
                            (int) ParserToken.ValueRest,
 | 
						|
                            ']');
 | 
						|
            TableAddCol (parse_table, ParserToken.ArrayPrime, '[',
 | 
						|
                            (int) ParserToken.Value,
 | 
						|
                            (int) ParserToken.ValueRest,
 | 
						|
                            ']');
 | 
						|
            TableAddCol (parse_table, ParserToken.ArrayPrime, ']',
 | 
						|
                            ']');
 | 
						|
            TableAddCol (parse_table, ParserToken.ArrayPrime, '{',
 | 
						|
                            (int) ParserToken.Value,
 | 
						|
                            (int) ParserToken.ValueRest,
 | 
						|
                            ']');
 | 
						|
            TableAddCol (parse_table, ParserToken.ArrayPrime, (int) ParserToken.Number,
 | 
						|
                            (int) ParserToken.Value,
 | 
						|
                            (int) ParserToken.ValueRest,
 | 
						|
                            ']');
 | 
						|
            TableAddCol (parse_table, ParserToken.ArrayPrime, (int) ParserToken.True,
 | 
						|
                            (int) ParserToken.Value,
 | 
						|
                            (int) ParserToken.ValueRest,
 | 
						|
                            ']');
 | 
						|
            TableAddCol (parse_table, ParserToken.ArrayPrime, (int) ParserToken.False,
 | 
						|
                            (int) ParserToken.Value,
 | 
						|
                            (int) ParserToken.ValueRest,
 | 
						|
                            ']');
 | 
						|
            TableAddCol (parse_table, ParserToken.ArrayPrime, (int) ParserToken.Null,
 | 
						|
                            (int) ParserToken.Value,
 | 
						|
                            (int) ParserToken.ValueRest,
 | 
						|
                            ']');
 | 
						|
 | 
						|
            TableAddRow (parse_table, ParserToken.Object);
 | 
						|
            TableAddCol (parse_table, ParserToken.Object, '{',
 | 
						|
                            '{',
 | 
						|
                            (int) ParserToken.ObjectPrime);
 | 
						|
 | 
						|
            TableAddRow (parse_table, ParserToken.ObjectPrime);
 | 
						|
            TableAddCol (parse_table, ParserToken.ObjectPrime, '"',
 | 
						|
                            (int) ParserToken.Pair,
 | 
						|
                            (int) ParserToken.PairRest,
 | 
						|
                            '}');
 | 
						|
            TableAddCol (parse_table, ParserToken.ObjectPrime, '}',
 | 
						|
                            '}');
 | 
						|
 | 
						|
            TableAddRow (parse_table, ParserToken.Pair);
 | 
						|
            TableAddCol (parse_table, ParserToken.Pair, '"',
 | 
						|
                            (int) ParserToken.String,
 | 
						|
                            ':',
 | 
						|
                            (int) ParserToken.Value);
 | 
						|
 | 
						|
            TableAddRow (parse_table, ParserToken.PairRest);
 | 
						|
            TableAddCol (parse_table, ParserToken.PairRest, ',',
 | 
						|
                            ',',
 | 
						|
                            (int) ParserToken.Pair,
 | 
						|
                            (int) ParserToken.PairRest);
 | 
						|
            TableAddCol (parse_table, ParserToken.PairRest, '}',
 | 
						|
                            (int) ParserToken.Epsilon);
 | 
						|
 | 
						|
            TableAddRow (parse_table, ParserToken.String);
 | 
						|
            TableAddCol (parse_table, ParserToken.String, '"',
 | 
						|
                            '"',
 | 
						|
                            (int) ParserToken.CharSeq,
 | 
						|
                            '"');
 | 
						|
 | 
						|
            TableAddRow (parse_table, ParserToken.Text);
 | 
						|
            TableAddCol (parse_table, ParserToken.Text, '[',
 | 
						|
                            (int) ParserToken.Array);
 | 
						|
            TableAddCol (parse_table, ParserToken.Text, '{',
 | 
						|
                            (int) ParserToken.Object);
 | 
						|
 | 
						|
            TableAddRow (parse_table, ParserToken.Value);
 | 
						|
            TableAddCol (parse_table, ParserToken.Value, '"',
 | 
						|
                            (int) ParserToken.String);
 | 
						|
            TableAddCol (parse_table, ParserToken.Value, '[',
 | 
						|
                            (int) ParserToken.Array);
 | 
						|
            TableAddCol (parse_table, ParserToken.Value, '{',
 | 
						|
                            (int) ParserToken.Object);
 | 
						|
            TableAddCol (parse_table, ParserToken.Value, (int) ParserToken.Number,
 | 
						|
                            (int) ParserToken.Number);
 | 
						|
            TableAddCol (parse_table, ParserToken.Value, (int) ParserToken.True,
 | 
						|
                            (int) ParserToken.True);
 | 
						|
            TableAddCol (parse_table, ParserToken.Value, (int) ParserToken.False,
 | 
						|
                            (int) ParserToken.False);
 | 
						|
            TableAddCol (parse_table, ParserToken.Value, (int) ParserToken.Null,
 | 
						|
                            (int) ParserToken.Null);
 | 
						|
 | 
						|
            TableAddRow (parse_table, ParserToken.ValueRest);
 | 
						|
            TableAddCol (parse_table, ParserToken.ValueRest, ',',
 | 
						|
                            ',',
 | 
						|
                            (int) ParserToken.Value,
 | 
						|
                            (int) ParserToken.ValueRest);
 | 
						|
            TableAddCol (parse_table, ParserToken.ValueRest, ']',
 | 
						|
                            (int) ParserToken.Epsilon);
 | 
						|
 | 
						|
            return parse_table;
 | 
						|
        }
 | 
						|
 | 
						|
        private static void TableAddCol (IDictionary<int, IDictionary<int, int[]>> parse_table, ParserToken row, int col,
 | 
						|
                                         params int[] symbols)
 | 
						|
        {
 | 
						|
            parse_table[(int) row].Add (col, symbols);
 | 
						|
        }
 | 
						|
 | 
						|
        private static void TableAddRow (IDictionary<int, IDictionary<int, int[]>> parse_table, ParserToken rule)
 | 
						|
        {
 | 
						|
            parse_table.Add ((int) rule, new Dictionary<int, int[]> ());
 | 
						|
        }
 | 
						|
        #endregion
 | 
						|
 | 
						|
 | 
						|
        #region Private Methods
 | 
						|
        private void ProcessNumber (string number)
 | 
						|
        {
 | 
						|
            if (number.IndexOf ('.') != -1 ||
 | 
						|
                number.IndexOf ('e') != -1 ||
 | 
						|
                number.IndexOf ('E') != -1) {
 | 
						|
 | 
						|
                float n_float;
 | 
						|
                if (float.TryParse (number, NumberStyles.Any, CultureInfo.InvariantCulture, out n_float)) {
 | 
						|
                    token = JsonToken.Double;
 | 
						|
                    token_value = n_float;
 | 
						|
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            int n_int32;
 | 
						|
            if (int.TryParse (number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_int32)) {
 | 
						|
                token = JsonToken.Int;
 | 
						|
                token_value = n_int32;
 | 
						|
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            long n_int64;
 | 
						|
            if (long.TryParse (number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_int64)) {
 | 
						|
                token = JsonToken.Long;
 | 
						|
                token_value = n_int64;
 | 
						|
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            ulong n_uint64;
 | 
						|
            if (ulong.TryParse(number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_uint64))
 | 
						|
            {
 | 
						|
                token = JsonToken.Long;
 | 
						|
                token_value = n_uint64;
 | 
						|
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            // Shouldn't happen, but just in case, return something
 | 
						|
            token = JsonToken.Int;
 | 
						|
            token_value = 0;
 | 
						|
        }
 | 
						|
 | 
						|
        private void ProcessSymbol ()
 | 
						|
        {
 | 
						|
            if (current_symbol == '[')  {
 | 
						|
                token = JsonToken.ArrayStart;
 | 
						|
                parser_return = true;
 | 
						|
 | 
						|
            } else if (current_symbol == ']')  {
 | 
						|
                token = JsonToken.ArrayEnd;
 | 
						|
                parser_return = true;
 | 
						|
 | 
						|
            } else if (current_symbol == '{')  {
 | 
						|
                token = JsonToken.ObjectStart;
 | 
						|
                parser_return = true;
 | 
						|
 | 
						|
            } else if (current_symbol == '}')  {
 | 
						|
                token = JsonToken.ObjectEnd;
 | 
						|
                parser_return = true;
 | 
						|
 | 
						|
            } else if (current_symbol == '"')  {
 | 
						|
                if (parser_in_string) {
 | 
						|
                    parser_in_string = false;
 | 
						|
 | 
						|
                    parser_return = true;
 | 
						|
 | 
						|
                } else {
 | 
						|
                    if (token == JsonToken.None)
 | 
						|
                        token = JsonToken.String;
 | 
						|
 | 
						|
                    parser_in_string = true;
 | 
						|
                }
 | 
						|
 | 
						|
            } else if (current_symbol == (int) ParserToken.CharSeq) {
 | 
						|
                token_value = lexer.StringValue;
 | 
						|
 | 
						|
            } else if (current_symbol == (int) ParserToken.False)  {
 | 
						|
                token = JsonToken.Boolean;
 | 
						|
                token_value = false;
 | 
						|
                parser_return = true;
 | 
						|
 | 
						|
            } else if (current_symbol == (int) ParserToken.Null)  {
 | 
						|
                token = JsonToken.Null;
 | 
						|
                parser_return = true;
 | 
						|
 | 
						|
            } else if (current_symbol == (int) ParserToken.Number)  {
 | 
						|
                ProcessNumber (lexer.StringValue);
 | 
						|
 | 
						|
                parser_return = true;
 | 
						|
 | 
						|
            } else if (current_symbol == (int) ParserToken.Pair)  {
 | 
						|
                token = JsonToken.PropertyName;
 | 
						|
 | 
						|
            } else if (current_symbol == (int) ParserToken.True)  {
 | 
						|
                token = JsonToken.Boolean;
 | 
						|
                token_value = true;
 | 
						|
                parser_return = true;
 | 
						|
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        private bool ReadToken ()
 | 
						|
        {
 | 
						|
            if (end_of_input)
 | 
						|
                return false;
 | 
						|
 | 
						|
            lexer.NextToken ();
 | 
						|
 | 
						|
            if (lexer.EndOfInput) {
 | 
						|
                Close ();
 | 
						|
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
 | 
						|
            current_input = lexer.Token;
 | 
						|
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
        #endregion
 | 
						|
 | 
						|
 | 
						|
        public void Close ()
 | 
						|
        {
 | 
						|
            if (end_of_input)
 | 
						|
                return;
 | 
						|
 | 
						|
            end_of_input = true;
 | 
						|
            end_of_json  = true;
 | 
						|
 | 
						|
            if (reader_is_owned)
 | 
						|
            {
 | 
						|
                using(reader){}
 | 
						|
            }
 | 
						|
 | 
						|
            reader = null;
 | 
						|
        }
 | 
						|
 | 
						|
        public bool Read ()
 | 
						|
        {
 | 
						|
            if (end_of_input)
 | 
						|
                return false;
 | 
						|
 | 
						|
            if (end_of_json) {
 | 
						|
                end_of_json = false;
 | 
						|
                automaton_stack.Clear ();
 | 
						|
                automaton_stack.Push ((int) ParserToken.End);
 | 
						|
                automaton_stack.Push ((int) ParserToken.Text);
 | 
						|
            }
 | 
						|
 | 
						|
            parser_in_string = false;
 | 
						|
            parser_return    = false;
 | 
						|
 | 
						|
            token       = JsonToken.None;
 | 
						|
            token_value = null;
 | 
						|
 | 
						|
            if (! read_started) {
 | 
						|
                read_started = true;
 | 
						|
 | 
						|
                if (! ReadToken ())
 | 
						|
                    return false;
 | 
						|
            }
 | 
						|
 | 
						|
 | 
						|
            int[] entry_symbols;
 | 
						|
 | 
						|
            while (true) {
 | 
						|
                if (parser_return) {
 | 
						|
                    if (automaton_stack.Peek () == (int) ParserToken.End)
 | 
						|
                        end_of_json = true;
 | 
						|
 | 
						|
                    return true;
 | 
						|
                }
 | 
						|
 | 
						|
                current_symbol = automaton_stack.Pop ();
 | 
						|
 | 
						|
                ProcessSymbol ();
 | 
						|
 | 
						|
                if (current_symbol == current_input) {
 | 
						|
                    if (! ReadToken ()) {
 | 
						|
                        if (automaton_stack.Peek () != (int) ParserToken.End)
 | 
						|
                            throw new JsonException (
 | 
						|
                                "Input doesn't evaluate to proper JSON text");
 | 
						|
 | 
						|
                        if (parser_return)
 | 
						|
                            return true;
 | 
						|
 | 
						|
                        return false;
 | 
						|
                    }
 | 
						|
 | 
						|
                    continue;
 | 
						|
                }
 | 
						|
 | 
						|
                try {
 | 
						|
 | 
						|
                    entry_symbols =
 | 
						|
                        parse_table[current_symbol][current_input];
 | 
						|
 | 
						|
                } catch (KeyNotFoundException e) {
 | 
						|
                    throw new JsonException ((ParserToken) current_input, e);
 | 
						|
                }
 | 
						|
 | 
						|
                if (entry_symbols[0] == (int) ParserToken.Epsilon)
 | 
						|
                    continue;
 | 
						|
 | 
						|
                for (int i = entry_symbols.Length - 1; i >= 0; i--)
 | 
						|
                    automaton_stack.Push (entry_symbols[i]);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
}
 |