Statistics
| Branch: | Tag: | Revision:

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
}