root / Assets / Plugins / LitJson / JsonReader.cs @ 11:01dde4258840
History | View | Annotate | Download (13.5 kB)
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 | |
11 | |
12 | using System; |
13 | using System.Collections.Generic; |
14 | using System.IO; |
15 | using System.Text; |
16 | |
17 | |
18 | namespace LitJson |
19 | { |
20 | public enum JsonToken |
21 | { |
22 | None, |
23 | |
24 | ObjectStart, |
25 | PropertyName, |
26 | ObjectEnd, |
27 | |
28 | ArrayStart, |
29 | ArrayEnd, |
30 | |
31 | Int, |
32 | Long, |
33 | Double, |
34 | |
35 | String, |
36 | |
37 | Boolean, |
38 | Null |
39 | } |
40 | |
41 | |
42 | public class JsonReader |
43 | { |
44 | #region Fields |
45 | private static IDictionary<int, IDictionary<int, int[]>> parse_table; |
46 | |
47 | private Stack<int> automaton_stack; |
48 | private int current_input; |
49 | private int current_symbol; |
50 | private bool end_of_json; |
51 | private bool end_of_input; |
52 | private Lexer lexer; |
53 | private bool parser_in_string; |
54 | private bool parser_return; |
55 | private bool read_started; |
56 | private TextReader reader; |
57 | private bool reader_is_owned; |
58 | private bool skip_non_members; |
59 | private object token_value; |
60 | private JsonToken token; |
61 | #endregion |
62 | |
63 | |
64 | #region Public Properties |
65 | public bool AllowComments { |
66 | get { return lexer.AllowComments; } |
67 | set { lexer.AllowComments = value; } |
68 | } |
69 | |
70 | public bool AllowSingleQuotedStrings { |
71 | get { return lexer.AllowSingleQuotedStrings; } |
72 | set { lexer.AllowSingleQuotedStrings = value; } |
73 | } |
74 | |
75 | public bool SkipNonMembers { |
76 | get { return skip_non_members; } |
77 | set { skip_non_members = value; } |
78 | } |
79 | |
80 | public bool EndOfInput { |
81 | get { return end_of_input; } |
82 | } |
83 | |
84 | public bool EndOfJson { |
85 | get { return end_of_json; } |
86 | } |
87 | |
88 | public JsonToken Token { |
89 | get { return token; } |
90 | } |
91 | |
92 | public object Value { |
93 | get { return token_value; } |
94 | } |
95 | #endregion |
96 | |
97 | |
98 | #region Constructors |
99 | static JsonReader () |
100 | { |
101 | PopulateParseTable (); |
102 | } |
103 | |
104 | public JsonReader (string json_text) : |
105 | this (new StringReader (json_text), true) |
106 | { |
107 | } |
108 | |
109 | public JsonReader (TextReader reader) : |
110 | this (reader, false) |
111 | { |
112 | } |
113 | |
114 | private JsonReader (TextReader reader, bool owned) |
115 | { |
116 | if (reader == null) |
117 | throw new ArgumentNullException ("reader"); |
118 | |
119 | parser_in_string = false; |
120 | parser_return = false; |
121 | |
122 | read_started = false; |
123 | automaton_stack = new Stack<int> (); |
124 | automaton_stack.Push ((int) ParserToken.End); |
125 | automaton_stack.Push ((int) ParserToken.Text); |
126 | |
127 | lexer = new Lexer (reader); |
128 | |
129 | end_of_input = false; |
130 | end_of_json = false; |
131 | |
132 | skip_non_members = true; |
133 | |
134 | this.reader = reader; |
135 | reader_is_owned = owned; |
136 | } |
137 | #endregion |
138 | |
139 | |
140 | #region Static Methods |
141 | private static void PopulateParseTable () |
142 | { |
143 | // See section A.2. of the manual for details |
144 | parse_table = new Dictionary<int, IDictionary<int, int[]>> (); |
145 | |
146 | TableAddRow (ParserToken.Array); |
147 | TableAddCol (ParserToken.Array, '[', |
148 | '[', |
149 | (int) ParserToken.ArrayPrime); |
150 | |
151 | TableAddRow (ParserToken.ArrayPrime); |
152 | TableAddCol (ParserToken.ArrayPrime, '"', |
153 | (int) ParserToken.Value, |
154 | |
155 | (int) ParserToken.ValueRest, |
156 | ']'); |
157 | TableAddCol (ParserToken.ArrayPrime, '[', |
158 | (int) ParserToken.Value, |
159 | (int) ParserToken.ValueRest, |
160 | ']'); |
161 | TableAddCol (ParserToken.ArrayPrime, ']', |
162 | ']'); |
163 | TableAddCol (ParserToken.ArrayPrime, '{', |
164 | (int) ParserToken.Value, |
165 | (int) ParserToken.ValueRest, |
166 | ']'); |
167 | TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.Number, |
168 | (int) ParserToken.Value, |
169 | (int) ParserToken.ValueRest, |
170 | ']'); |
171 | TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.True, |
172 | (int) ParserToken.Value, |
173 | (int) ParserToken.ValueRest, |
174 | ']'); |
175 | TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.False, |
176 | (int) ParserToken.Value, |
177 | (int) ParserToken.ValueRest, |
178 | ']'); |
179 | TableAddCol (ParserToken.ArrayPrime, (int) ParserToken.Null, |
180 | (int) ParserToken.Value, |
181 | (int) ParserToken.ValueRest, |
182 | ']'); |
183 | |
184 | TableAddRow (ParserToken.Object); |
185 | TableAddCol (ParserToken.Object, '{', |
186 | '{', |
187 | (int) ParserToken.ObjectPrime); |
188 | |
189 | TableAddRow (ParserToken.ObjectPrime); |
190 | TableAddCol (ParserToken.ObjectPrime, '"', |
191 | (int) ParserToken.Pair, |
192 | (int) ParserToken.PairRest, |
193 | '}'); |
194 | TableAddCol (ParserToken.ObjectPrime, '}', |
195 | '}'); |
196 | |
197 | TableAddRow (ParserToken.Pair); |
198 | TableAddCol (ParserToken.Pair, '"', |
199 | (int) ParserToken.String, |
200 | ':', |
201 | (int) ParserToken.Value); |
202 | |
203 | TableAddRow (ParserToken.PairRest); |
204 | TableAddCol (ParserToken.PairRest, ',', |
205 | ',', |
206 | (int) ParserToken.Pair, |
207 | (int) ParserToken.PairRest); |
208 | TableAddCol (ParserToken.PairRest, '}', |
209 | (int) ParserToken.Epsilon); |
210 | |
211 | TableAddRow (ParserToken.String); |
212 | TableAddCol (ParserToken.String, '"', |
213 | '"', |
214 | (int) ParserToken.CharSeq, |
215 | '"'); |
216 | |
217 | TableAddRow (ParserToken.Text); |
218 | TableAddCol (ParserToken.Text, '[', |
219 | (int) ParserToken.Array); |
220 | TableAddCol (ParserToken.Text, '{', |
221 | (int) ParserToken.Object); |
222 | |
223 | TableAddRow (ParserToken.Value); |
224 | TableAddCol (ParserToken.Value, '"', |
225 | (int) ParserToken.String); |
226 | TableAddCol (ParserToken.Value, '[', |
227 | (int) ParserToken.Array); |
228 | TableAddCol (ParserToken.Value, '{', |
229 | (int) ParserToken.Object); |
230 | TableAddCol (ParserToken.Value, (int) ParserToken.Number, |
231 | (int) ParserToken.Number); |
232 | TableAddCol (ParserToken.Value, (int) ParserToken.True, |
233 | (int) ParserToken.True); |
234 | TableAddCol (ParserToken.Value, (int) ParserToken.False, |
235 | (int) ParserToken.False); |
236 | TableAddCol (ParserToken.Value, (int) ParserToken.Null, |
237 | (int) ParserToken.Null); |
238 | |
239 | TableAddRow (ParserToken.ValueRest); |
240 | TableAddCol (ParserToken.ValueRest, ',', |
241 | ',', |
242 | (int) ParserToken.Value, |
243 | (int) ParserToken.ValueRest); |
244 | TableAddCol (ParserToken.ValueRest, ']', |
245 | (int) ParserToken.Epsilon); |
246 | } |
247 | |
248 | private static void TableAddCol (ParserToken row, int col, |
249 | params int[] symbols) |
250 | { |
251 | parse_table[(int) row].Add (col, symbols); |
252 | } |
253 | |
254 | private static void TableAddRow (ParserToken rule) |
255 | { |
256 | parse_table.Add ((int) rule, new Dictionary<int, int[]> ()); |
257 | } |
258 | #endregion |
259 | |
260 | |
261 | #region Private Methods |
262 | private void ProcessNumber (string number) |
263 | { |
264 | if (number.IndexOf ('.') != -1 || |
265 | number.IndexOf ('e') != -1 || |
266 | number.IndexOf ('E') != -1) { |
267 | |
268 | double n_double; |
269 | if (Double.TryParse (number, out n_double)) { |
270 | token = JsonToken.Double; |
271 | token_value = n_double; |
272 | |
273 | return; |
274 | } |
275 | } |
276 | |
277 | int n_int32; |
278 | if (Int32.TryParse (number, out n_int32)) { |
279 | token = JsonToken.Int; |
280 | token_value = n_int32; |
281 | |
282 | return; |
283 | } |
284 | |
285 | long n_int64; |
286 | if (Int64.TryParse (number, out n_int64)) { |
287 | token = JsonToken.Long; |
288 | token_value = n_int64; |
289 | |
290 | return; |
291 | } |
292 | |
293 | // Shouldn't happen, but just in case, return something |
294 | token = JsonToken.Int; |
295 | token_value = 0; |
296 | } |
297 | |
298 | private void ProcessSymbol () |
299 | { |
300 | if (current_symbol == '[') { |
301 | token = JsonToken.ArrayStart; |
302 | parser_return = true; |
303 | |
304 | } else if (current_symbol == ']') { |
305 | token = JsonToken.ArrayEnd; |
306 | parser_return = true; |
307 | |
308 | } else if (current_symbol == '{') { |
309 | token = JsonToken.ObjectStart; |
310 | parser_return = true; |
311 | |
312 | } else if (current_symbol == '}') { |
313 | token = JsonToken.ObjectEnd; |
314 | parser_return = true; |
315 | |
316 | } else if (current_symbol == '"') { |
317 | if (parser_in_string) { |
318 | parser_in_string = false; |
319 | |
320 | parser_return = true; |
321 | |
322 | } else { |
323 | if (token == JsonToken.None) |
324 | token = JsonToken.String; |
325 | |
326 | parser_in_string = true; |
327 | } |
328 | |
329 | } else if (current_symbol == (int) ParserToken.CharSeq) { |
330 | token_value = lexer.StringValue; |
331 | |
332 | } else if (current_symbol == (int) ParserToken.False) { |
333 | token = JsonToken.Boolean; |
334 | token_value = false; |
335 | parser_return = true; |
336 | |
337 | } else if (current_symbol == (int) ParserToken.Null) { |
338 | token = JsonToken.Null; |
339 | parser_return = true; |
340 | |
341 | } else if (current_symbol == (int) ParserToken.Number) { |
342 | ProcessNumber (lexer.StringValue); |
343 | |
344 | parser_return = true; |
345 | |
346 | } else if (current_symbol == (int) ParserToken.Pair) { |
347 | token = JsonToken.PropertyName; |
348 | |
349 | } else if (current_symbol == (int) ParserToken.True) { |
350 | token = JsonToken.Boolean; |
351 | token_value = true; |
352 | parser_return = true; |
353 | |
354 | } |
355 | } |
356 | |
357 | private bool ReadToken () |
358 | { |
359 | if (end_of_input) |
360 | return false; |
361 | |
362 | lexer.NextToken (); |
363 | |
364 | if (lexer.EndOfInput) { |
365 | Close (); |
366 | |
367 | return false; |
368 | } |
369 | |
370 | current_input = lexer.Token; |
371 | |
372 | return true; |
373 | } |
374 | #endregion |
375 | |
376 | |
377 | public void Close () |
378 | { |
379 | if (end_of_input) |
380 | return; |
381 | |
382 | end_of_input = true; |
383 | end_of_json = true; |
384 | |
385 | if (reader_is_owned) |
386 | reader.Close (); |
387 | |
388 | reader = null; |
389 | } |
390 | |
391 | public bool Read () |
392 | { |
393 | if (end_of_input) |
394 | return false; |
395 | |
396 | if (end_of_json) { |
397 | end_of_json = false; |
398 | automaton_stack.Clear (); |
399 | automaton_stack.Push ((int) ParserToken.End); |
400 | automaton_stack.Push ((int) ParserToken.Text); |
401 | } |
402 | |
403 | parser_in_string = false; |
404 | parser_return = false; |
405 | |
406 | token = JsonToken.None; |
407 | token_value = null; |
408 | |
409 | if (! read_started) { |
410 | read_started = true; |
411 | |
412 | if (! ReadToken ()) |
413 | return false; |
414 | } |
415 | |
416 | |
417 | int[] entry_symbols; |
418 | |
419 | while (true) { |
420 | if (parser_return) { |
421 | if (automaton_stack.Peek () == (int) ParserToken.End) |
422 | end_of_json = true; |
423 | |
424 | return true; |
425 | } |
426 | |
427 | current_symbol = automaton_stack.Pop (); |
428 | |
429 | ProcessSymbol (); |
430 | |
431 | if (current_symbol == current_input) { |
432 | if (! ReadToken ()) { |
433 | if (automaton_stack.Peek () != (int) ParserToken.End) |
434 | throw new JsonException ( |
435 | "Input doesn't evaluate to proper JSON text"); |
436 | |
437 | if (parser_return) |
438 | return true; |
439 | |
440 | return false; |
441 | } |
442 | |
443 | continue; |
444 | } |
445 | |
446 | try { |
447 | |
448 | entry_symbols = |
449 | parse_table[current_symbol][current_input]; |
450 | |
451 | } catch (KeyNotFoundException e) { |
452 | throw new JsonException ((ParserToken) current_input, e); |
453 | } |
454 | |
455 | if (entry_symbols[0] == (int) ParserToken.Epsilon) |
456 | continue; |
457 | |
458 | for (int i = entry_symbols.Length - 1; i >= 0; i--) |
459 | automaton_stack.Push (entry_symbols[i]); |
460 | } |
461 | } |
462 | |
463 | } |
464 | } |