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 AnyThinkAds.ThirdParty.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]);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|     }
 | |
| }
 |