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