123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478 |
- #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) {
- double n_double;
- if (double.TryParse (number, NumberStyles.Any, CultureInfo.InvariantCulture, out n_double)) {
- token = JsonToken.Double;
- token_value = n_double;
- 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]);
- }
- }
- }
- }
|