JsonReader.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. #region Header
  2. /**
  3. * JsonReader.cs
  4. * Stream-like access to JSON text.
  5. *
  6. * The authors disclaim copyright to this source code. For more details, see
  7. * the COPYING file included with this distribution.
  8. **/
  9. #endregion
  10. using System;
  11. using System.Collections.Generic;
  12. using System.IO;
  13. using System.Text;
  14. namespace LitJson
  15. {
  16. public enum JsonToken
  17. {
  18. None,
  19. ObjectStart,
  20. PropertyName,
  21. ObjectEnd,
  22. ArrayStart,
  23. ArrayEnd,
  24. Int,
  25. Long,
  26. Double,
  27. String,
  28. Boolean,
  29. Null
  30. }
  31. public class JsonReader
  32. {
  33. #region Fields
  34. private static IDictionary<int, IDictionary<int, int[]>> parse_table;
  35. private Stack<int> automaton_stack;
  36. private int current_input;
  37. private int current_symbol;
  38. private bool end_of_json;
  39. private bool end_of_input;
  40. private Lexer lexer;
  41. private bool parser_in_string;
  42. private bool parser_return;
  43. private bool read_started;
  44. private TextReader reader;
  45. private bool reader_is_owned;
  46. private bool skip_non_members;
  47. private object token_value;
  48. private JsonToken token;
  49. #endregion
  50. #region Public Properties
  51. public bool AllowComments {
  52. get { return lexer.AllowComments; }
  53. set { lexer.AllowComments = value; }
  54. }
  55. public bool AllowSingleQuotedStrings {
  56. get { return lexer.AllowSingleQuotedStrings; }
  57. set { lexer.AllowSingleQuotedStrings = value; }
  58. }
  59. public bool SkipNonMembers {
  60. get { return skip_non_members; }
  61. set { skip_non_members = value; }
  62. }
  63. public bool EndOfInput {
  64. get { return end_of_input; }
  65. }
  66. public bool EndOfJson {
  67. get { return end_of_json; }
  68. }
  69. public JsonToken Token {
  70. get { return token; }
  71. }
  72. public object Value {
  73. get { return token_value; }
  74. }
  75. #endregion
  76. #region Constructors
  77. static JsonReader ()
  78. {
  79. PopulateParseTable ();
  80. }
  81. public JsonReader (string json_text) :
  82. this (new StringReader (json_text), true)
  83. {
  84. }
  85. public JsonReader (TextReader reader) :
  86. this (reader, false)
  87. {
  88. }
  89. private JsonReader (TextReader reader, bool owned)
  90. {
  91. if (reader == null)
  92. throw new ArgumentNullException ("reader");
  93. parser_in_string = false;
  94. parser_return = false;
  95. read_started = false;
  96. automaton_stack = new Stack<int> ();
  97. automaton_stack.Push ((int) ParserToken.End);
  98. automaton_stack.Push ((int) ParserToken.Text);
  99. lexer = new Lexer (reader);
  100. end_of_input = false;
  101. end_of_json = false;
  102. skip_non_members = true;
  103. this.reader = reader;
  104. reader_is_owned = owned;
  105. }
  106. #endregion
  107. #region Static Methods
  108. private static void PopulateParseTable ()
  109. {
  110. // See section A.2. of the manual for details
  111. parse_table = new Dictionary<int, IDictionary<int, int[]>> ();
  112. TableAddRow (ParserToken.Array);
  113. TableAddCol (ParserToken.Array, '[',
  114. '[',
  115. (int) ParserToken.ArrayPrime);
  116. TableAddRow (ParserToken.ArrayPrime);
  117. TableAddCol (ParserToken.ArrayPrime, '"',
  118. (int) ParserToken.Value,
  119. (int) ParserToken.ValueRest,
  120. ']');
  121. TableAddCol (ParserToken.ArrayPrime, '[',
  122. (int) ParserToken.Value,
  123. (int) ParserToken.ValueRest,
  124. ']');
  125. TableAddCol (ParserToken.ArrayPrime, ']',
  126. ']');
  127. TableAddCol (ParserToken.ArrayPrime, '{',
  128. (int) ParserToken.Value,
  129. (int) ParserToken.ValueRest,
  130. ']');
  131. TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.Number,
  132. (int) ParserToken.Value,
  133. (int) ParserToken.ValueRest,
  134. ']');
  135. TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.True,
  136. (int) ParserToken.Value,
  137. (int) ParserToken.ValueRest,
  138. ']');
  139. TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.False,
  140. (int) ParserToken.Value,
  141. (int) ParserToken.ValueRest,
  142. ']');
  143. TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.Null,
  144. (int) ParserToken.Value,
  145. (int) ParserToken.ValueRest,
  146. ']');
  147. TableAddRow (ParserToken.Object);
  148. TableAddCol (ParserToken.Object, '{',
  149. '{',
  150. (int) ParserToken.ObjectPrime);
  151. TableAddRow (ParserToken.ObjectPrime);
  152. TableAddCol (ParserToken.ObjectPrime, '"',
  153. (int) ParserToken.Pair,
  154. (int) ParserToken.PairRest,
  155. '}');
  156. TableAddCol (ParserToken.ObjectPrime, '}',
  157. '}');
  158. TableAddRow (ParserToken.Pair);
  159. TableAddCol (ParserToken.Pair, '"',
  160. (int) ParserToken.String,
  161. ':',
  162. (int) ParserToken.Value);
  163. TableAddRow (ParserToken.PairRest);
  164. TableAddCol (ParserToken.PairRest, ',',
  165. ',',
  166. (int) ParserToken.Pair,
  167. (int) ParserToken.PairRest);
  168. TableAddCol (ParserToken.PairRest, '}',
  169. (int) ParserToken.Epsilon);
  170. TableAddRow (ParserToken.String);
  171. TableAddCol (ParserToken.String, '"',
  172. '"',
  173. (int) ParserToken.CharSeq,
  174. '"');
  175. TableAddRow (ParserToken.Text);
  176. TableAddCol (ParserToken.Text, '[',
  177. (int) ParserToken.Array);
  178. TableAddCol (ParserToken.Text, '{',
  179. (int) ParserToken.Object);
  180. TableAddRow (ParserToken.Value);
  181. TableAddCol (ParserToken.Value, '"',
  182. (int) ParserToken.String);
  183. TableAddCol (ParserToken.Value, '[',
  184. (int) ParserToken.Array);
  185. TableAddCol (ParserToken.Value, '{',
  186. (int) ParserToken.Object);
  187. TableAddCol (ParserToken.Value, (int) ParserToken.Number,
  188. (int) ParserToken.Number);
  189. TableAddCol (ParserToken.Value, (int) ParserToken.True,
  190. (int) ParserToken.True);
  191. TableAddCol (ParserToken.Value, (int) ParserToken.False,
  192. (int) ParserToken.False);
  193. TableAddCol (ParserToken.Value, (int) ParserToken.Null,
  194. (int) ParserToken.Null);
  195. TableAddRow (ParserToken.ValueRest);
  196. TableAddCol (ParserToken.ValueRest, ',',
  197. ',',
  198. (int) ParserToken.Value,
  199. (int) ParserToken.ValueRest);
  200. TableAddCol (ParserToken.ValueRest, ']',
  201. (int) ParserToken.Epsilon);
  202. }
  203. private static void TableAddCol (ParserToken row, int col,
  204. params int[] symbols)
  205. {
  206. parse_table[(int) row].Add (col, symbols);
  207. }
  208. private static void TableAddRow (ParserToken rule)
  209. {
  210. parse_table.Add ((int) rule, new Dictionary<int, int[]> ());
  211. }
  212. #endregion
  213. #region Private Methods
  214. private void ProcessNumber (string number)
  215. {
  216. if (number.IndexOf ('.') != -1 ||
  217. number.IndexOf ('e') != -1 ||
  218. number.IndexOf ('E') != -1) {
  219. double n_double;
  220. if (Double.TryParse (number, out n_double)) {
  221. token = JsonToken.Double;
  222. token_value = n_double;
  223. return;
  224. }
  225. }
  226. int n_int32;
  227. if (Int32.TryParse (number, out n_int32)) {
  228. token = JsonToken.Int;
  229. token_value = n_int32;
  230. return;
  231. }
  232. long n_int64;
  233. if (Int64.TryParse (number, out n_int64)) {
  234. token = JsonToken.Long;
  235. token_value = n_int64;
  236. return;
  237. }
  238. ulong n_uint64;
  239. if (UInt64.TryParse(number, out n_uint64))
  240. {
  241. token = JsonToken.Long;
  242. token_value = n_uint64;
  243. return;
  244. }
  245. // Shouldn't happen, but just in case, return something
  246. token = JsonToken.Int;
  247. token_value = 0;
  248. }
  249. private void ProcessSymbol ()
  250. {
  251. if (current_symbol == '[') {
  252. token = JsonToken.ArrayStart;
  253. parser_return = true;
  254. } else if (current_symbol == ']') {
  255. token = JsonToken.ArrayEnd;
  256. parser_return = true;
  257. } else if (current_symbol == '{') {
  258. token = JsonToken.ObjectStart;
  259. parser_return = true;
  260. } else if (current_symbol == '}') {
  261. token = JsonToken.ObjectEnd;
  262. parser_return = true;
  263. } else if (current_symbol == '"') {
  264. if (parser_in_string) {
  265. parser_in_string = false;
  266. parser_return = true;
  267. } else {
  268. if (token == JsonToken.None)
  269. token = JsonToken.String;
  270. parser_in_string = true;
  271. }
  272. } else if (current_symbol == (int) ParserToken.CharSeq) {
  273. token_value = lexer.StringValue;
  274. } else if (current_symbol == (int) ParserToken.False) {
  275. token = JsonToken.Boolean;
  276. token_value = false;
  277. parser_return = true;
  278. } else if (current_symbol == (int) ParserToken.Null) {
  279. token = JsonToken.Null;
  280. parser_return = true;
  281. } else if (current_symbol == (int) ParserToken.Number) {
  282. ProcessNumber (lexer.StringValue);
  283. parser_return = true;
  284. } else if (current_symbol == (int) ParserToken.Pair) {
  285. token = JsonToken.PropertyName;
  286. } else if (current_symbol == (int) ParserToken.True) {
  287. token = JsonToken.Boolean;
  288. token_value = true;
  289. parser_return = true;
  290. }
  291. }
  292. private bool ReadToken ()
  293. {
  294. if (end_of_input)
  295. return false;
  296. lexer.NextToken ();
  297. if (lexer.EndOfInput) {
  298. Close ();
  299. return false;
  300. }
  301. current_input = lexer.Token;
  302. return true;
  303. }
  304. #endregion
  305. public void Close ()
  306. {
  307. if (end_of_input)
  308. return;
  309. end_of_input = true;
  310. end_of_json = true;
  311. if (reader_is_owned)
  312. reader.Close ();
  313. reader = null;
  314. }
  315. public bool Read ()
  316. {
  317. if (end_of_input)
  318. return false;
  319. if (end_of_json) {
  320. end_of_json = false;
  321. automaton_stack.Clear ();
  322. automaton_stack.Push ((int) ParserToken.End);
  323. automaton_stack.Push ((int) ParserToken.Text);
  324. }
  325. parser_in_string = false;
  326. parser_return = false;
  327. token = JsonToken.None;
  328. token_value = null;
  329. if (! read_started) {
  330. read_started = true;
  331. if (! ReadToken ())
  332. return false;
  333. }
  334. int[] entry_symbols;
  335. while (true) {
  336. if (parser_return) {
  337. if (automaton_stack.Peek () == (int) ParserToken.End)
  338. end_of_json = true;
  339. return true;
  340. }
  341. current_symbol = automaton_stack.Pop ();
  342. ProcessSymbol ();
  343. if (current_symbol == current_input) {
  344. if (! ReadToken ()) {
  345. if (automaton_stack.Peek () != (int) ParserToken.End)
  346. throw new JsonException (
  347. "Input doesn't evaluate to proper JSON text");
  348. if (parser_return)
  349. return true;
  350. return false;
  351. }
  352. continue;
  353. }
  354. try {
  355. entry_symbols =
  356. parse_table[current_symbol][current_input];
  357. } catch (KeyNotFoundException e) {
  358. throw new JsonException ((ParserToken) current_input, e);
  359. }
  360. if (entry_symbols[0] == (int) ParserToken.Epsilon)
  361. continue;
  362. for (int i = entry_symbols.Length - 1; i >= 0; i--)
  363. automaton_stack.Push (entry_symbols[i]);
  364. }
  365. }
  366. }
  367. }