Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
JSONParser | 22 | 321 | 100 |
1 | /* | |
2 | * $Id: JSONParser.java,v 1.1 2006/04/15 14:10:48 platform Exp $ | |
3 | * Created on 2006-4-15 | |
4 | */ | |
5 | package org.json.simple.parser; | |
6 | ||
7 | import java.io.IOException; | |
8 | import java.io.Reader; | |
9 | import java.io.StringReader; | |
10 | import java.util.LinkedList; | |
11 | import java.util.List; | |
12 | import java.util.Map; | |
13 | ||
14 | import org.json.simple.JSONArray; | |
15 | import org.json.simple.JSONObject; | |
16 | ||
17 | /** | |
18 | * Parser for JSON text. Please note that JSONParser is NOT thread-safe. | |
19 | * | |
20 | * @author FangYidong<fangyidong@yahoo.com.cn> | |
21 | */ | |
22 | public class JSONParser | |
23 | { | |
24 | public static final int S_INIT = 0; | |
25 | ||
26 | public static final int S_IN_FINISHED_VALUE = 1;// string,number,boolean,null,object,array | |
27 | ||
28 | public static final int S_IN_OBJECT = 2; | |
29 | ||
30 | public static final int S_IN_ARRAY = 3; | |
31 | ||
32 | public static final int S_PASSED_PAIR_KEY = 4; | |
33 | ||
34 | public static final int S_IN_PAIR_VALUE = 5; | |
35 | ||
36 | public static final int S_END = 6; | |
37 | ||
38 | public static final int S_IN_ERROR = -1; | |
39 | ||
40 | private LinkedList handlerStatusStack; | |
41 | ||
42 | private Yylex lexer = new Yylex((Reader) null); | |
43 | ||
44 | private Yytoken token = null; | |
45 | ||
46 | private int status = S_INIT; | |
47 | ||
48 | 387161 | private int peekStatus(LinkedList statusStack) |
49 | { | |
50 | 387161 | if (statusStack.size() == 0) |
51 | 0 | return -1; |
52 | 387161 | Integer status = (Integer) statusStack.getFirst(); |
53 | 387161 | return status.intValue(); |
54 | } | |
55 | ||
56 | /** | |
57 | * Reset the parser to the initial state without resetting the underlying | |
58 | * reader. | |
59 | * | |
60 | */ | |
61 | 223 | public void reset() |
62 | { | |
63 | 223 | token = null; |
64 | 223 | status = S_INIT; |
65 | 223 | handlerStatusStack = null; |
66 | } | |
67 | ||
68 | /** | |
69 | * Reset the parser to the initial state with a new character reader. | |
70 | * | |
71 | * @param in | |
72 | * - The new character reader. | |
73 | * @throws IOException | |
74 | * @throws ParseException | |
75 | */ | |
76 | 223 | public void reset(Reader in) |
77 | { | |
78 | 223 | lexer.yyreset(in); |
79 | 223 | reset(); |
80 | } | |
81 | ||
82 | /** | |
83 | * @return The position of the beginning of the current token. | |
84 | */ | |
85 | 0 | public int getPosition() |
86 | { | |
87 | 0 | return lexer.getPosition(); |
88 | } | |
89 | ||
90 | 121 | public Object parse(String s) throws ParseException |
91 | { | |
92 | 121 | return parse(s, (ContainerFactory) null); |
93 | } | |
94 | ||
95 | 121 | public Object parse(String s, ContainerFactory containerFactory) |
96 | throws ParseException | |
97 | { | |
98 | 121 | StringReader in = new StringReader(s); |
99 | 121 | try |
100 | { | |
101 | 121 | return parse(in, containerFactory); |
102 | } catch (IOException ie) | |
103 | { | |
104 | /* | |
105 | * Actually it will never happen. | |
106 | */ | |
107 | 0 | throw new ParseException(-1, |
108 | ParseException.ERROR_UNEXPECTED_EXCEPTION, ie); | |
109 | } | |
110 | } | |
111 | ||
112 | 102 | public Object parse(Reader in) throws IOException, ParseException |
113 | { | |
114 | 102 | return parse(in, (ContainerFactory) null); |
115 | } | |
116 | ||
117 | /** | |
118 | * Parse JSON text into java object from the input source. | |
119 | * | |
120 | * @param in | |
121 | * @param containerFactory | |
122 | * - Use this factory to createyour own JSON object and JSON array | |
123 | * containers. | |
124 | * @return Instance of the following: org.json.simple.JSONObject, | |
125 | * org.json.simple.JSONArray, java.lang.String, java.lang.Number, | |
126 | * java.lang.Boolean, null | |
127 | * | |
128 | * @throws IOException | |
129 | * @throws ParseException | |
130 | */ | |
131 | 223 | public Object parse(Reader in, ContainerFactory containerFactory) |
132 | throws IOException, ParseException | |
133 | { | |
134 | 223 | reset(in); |
135 | 223 | LinkedList statusStack = new LinkedList(); |
136 | 223 | LinkedList valueStack = new LinkedList(); |
137 | ||
138 | 223 | try |
139 | { | |
140 | 223 | do |
141 | { | |
142 | 9342705 | nextToken(); |
143 | 9342705 | switch (status) |
144 | { | |
145 | 223 | case S_INIT: |
146 | 223 | switch (token.type) |
147 | { | |
148 | 0 | case Yytoken.TYPE_VALUE: |
149 | 0 | status = S_IN_FINISHED_VALUE; |
150 | 0 | statusStack.addFirst(new Integer(status)); |
151 | 0 | valueStack.addFirst(token.value); |
152 | 0 | break; |
153 | 188 | case Yytoken.TYPE_LEFT_BRACE: |
154 | 188 | status = S_IN_OBJECT; |
155 | 188 | statusStack.addFirst(new Integer(status)); |
156 | 188 | valueStack.addFirst(createObjectContainer(containerFactory)); |
157 | 188 | break; |
158 | 35 | case Yytoken.TYPE_LEFT_SQUARE: |
159 | 35 | status = S_IN_ARRAY; |
160 | 35 | statusStack.addFirst(new Integer(status)); |
161 | 35 | valueStack.addFirst(createArrayContainer(containerFactory)); |
162 | 35 | break; |
163 | 0 | default: |
164 | 0 | status = S_IN_ERROR; |
165 | }// inner switch | |
166 | 223 | break; |
167 | ||
168 | 223 | case S_IN_FINISHED_VALUE: |
169 | 223 | if (token.type == Yytoken.TYPE_EOF) |
170 | 223 | return valueStack.removeFirst(); |
171 | else | |
172 | 0 | throw new ParseException(getPosition(), |
173 | ParseException.ERROR_UNEXPECTED_TOKEN, token); | |
174 | ||
175 | 660865 | case S_IN_OBJECT: |
176 | 660865 | switch (token.type) |
177 | { | |
178 | 276881 | case Yytoken.TYPE_COMMA: |
179 | 276881 | break; |
180 | 330441 | case Yytoken.TYPE_VALUE: |
181 | 330441 | if (token.value instanceof String) |
182 | { | |
183 | 330441 | String key = (String) token.value; |
184 | 330441 | valueStack.addFirst(key); |
185 | 330441 | status = S_PASSED_PAIR_KEY; |
186 | 330441 | statusStack.addFirst(new Integer(status)); |
187 | } | |
188 | else | |
189 | { | |
190 | 0 | status = S_IN_ERROR; |
191 | } | |
192 | 330441 | break; |
193 | 53543 | case Yytoken.TYPE_RIGHT_BRACE: |
194 | 53543 | if (valueStack.size() > 1) |
195 | { | |
196 | 53355 | statusStack.removeFirst(); |
197 | 53355 | valueStack.removeFirst(); |
198 | 53355 | status = peekStatus(statusStack); |
199 | } | |
200 | else | |
201 | { | |
202 | 188 | status = S_IN_FINISHED_VALUE; |
203 | } | |
204 | 53543 | break; |
205 | 0 | default: |
206 | 0 | status = S_IN_ERROR; |
207 | 0 | break; |
208 | }// inner switch | |
209 | 660865 | break; |
210 | ||
211 | 660882 | case S_PASSED_PAIR_KEY: |
212 | 660882 | switch (token.type) |
213 | { | |
214 | 330441 | case Yytoken.TYPE_COLON: |
215 | 330441 | break; |
216 | 292559 | case Yytoken.TYPE_VALUE: |
217 | 292559 | statusStack.removeFirst(); |
218 | 292559 | String key = (String) valueStack.removeFirst(); |
219 | 292559 | Map parent = (Map) valueStack.getFirst(); |
220 | 292559 | parent.put(key, token.value); |
221 | 292559 | status = peekStatus(statusStack); |
222 | 292559 | break; |
223 | 32658 | case Yytoken.TYPE_LEFT_SQUARE: |
224 | 32658 | statusStack.removeFirst(); |
225 | 32658 | key = (String) valueStack.removeFirst(); |
226 | 32658 | parent = (Map) valueStack.getFirst(); |
227 | 32658 | List newArray = createArrayContainer(containerFactory); |
228 | 32658 | parent.put(key, newArray); |
229 | 32658 | status = S_IN_ARRAY; |
230 | 32658 | statusStack.addFirst(new Integer(status)); |
231 | 32658 | valueStack.addFirst(newArray); |
232 | 32658 | break; |
233 | 5224 | case Yytoken.TYPE_LEFT_BRACE: |
234 | 5224 | statusStack.removeFirst(); |
235 | 5224 | key = (String) valueStack.removeFirst(); |
236 | 5224 | parent = (Map) valueStack.getFirst(); |
237 | 5224 | Map newObject = createObjectContainer(containerFactory); |
238 | 5224 | parent.put(key, newObject); |
239 | 5224 | status = S_IN_OBJECT; |
240 | 5224 | statusStack.addFirst(new Integer(status)); |
241 | 5224 | valueStack.addFirst(newObject); |
242 | 5224 | break; |
243 | 0 | default: |
244 | 0 | status = S_IN_ERROR; |
245 | } | |
246 | 660882 | break; |
247 | ||
248 | 8020512 | case S_IN_ARRAY: |
249 | 8020512 | switch (token.type) |
250 | { | |
251 | 3968976 | case Yytoken.TYPE_COMMA: |
252 | 3968976 | break; |
253 | 3953534 | case Yytoken.TYPE_VALUE: |
254 | 3953534 | List val = (List) valueStack.getFirst(); |
255 | 3953534 | val.add(token.value); |
256 | 3953534 | break; |
257 | 41282 | case Yytoken.TYPE_RIGHT_SQUARE: |
258 | 41282 | if (valueStack.size() > 1) |
259 | { | |
260 | 41247 | statusStack.removeFirst(); |
261 | 41247 | valueStack.removeFirst(); |
262 | 41247 | status = peekStatus(statusStack); |
263 | } | |
264 | else | |
265 | { | |
266 | 35 | status = S_IN_FINISHED_VALUE; |
267 | } | |
268 | 41282 | break; |
269 | 48131 | case Yytoken.TYPE_LEFT_BRACE: |
270 | 48131 | val = (List) valueStack.getFirst(); |
271 | 48131 | Map newObject = createObjectContainer(containerFactory); |
272 | 48131 | val.add(newObject); |
273 | 48131 | status = S_IN_OBJECT; |
274 | 48131 | statusStack.addFirst(new Integer(status)); |
275 | 48131 | valueStack.addFirst(newObject); |
276 | 48131 | break; |
277 | 8589 | case Yytoken.TYPE_LEFT_SQUARE: |
278 | 8589 | val = (List) valueStack.getFirst(); |
279 | 8589 | List newArray = createArrayContainer(containerFactory); |
280 | 8589 | val.add(newArray); |
281 | 8589 | status = S_IN_ARRAY; |
282 | 8589 | statusStack.addFirst(new Integer(status)); |
283 | 8589 | valueStack.addFirst(newArray); |
284 | 8589 | break; |
285 | 0 | default: |
286 | 0 | status = S_IN_ERROR; |
287 | }// inner switch | |
288 | 8020512 | break; |
289 | 0 | case S_IN_ERROR: |
290 | 0 | throw new ParseException(getPosition(), |
291 | ParseException.ERROR_UNEXPECTED_TOKEN, token); | |
292 | }// switch | |
293 | 9342482 | if (status == S_IN_ERROR) |
294 | { | |
295 | 0 | throw new ParseException(getPosition(), |
296 | ParseException.ERROR_UNEXPECTED_TOKEN, token); | |
297 | } | |
298 | 9342482 | } while (token.type != Yytoken.TYPE_EOF); |
299 | } catch (IOException ie) | |
300 | { | |
301 | 0 | throw ie; |
302 | } | |
303 | ||
304 | 0 | throw new ParseException(getPosition(), |
305 | ParseException.ERROR_UNEXPECTED_TOKEN, token); | |
306 | } | |
307 | ||
308 | 9342705 | private void nextToken() throws ParseException, IOException |
309 | { | |
310 | 9342705 | token = lexer.yylex(); |
311 | 9342705 | if (token == null) |
312 | 223 | token = new Yytoken(Yytoken.TYPE_EOF, null); |
313 | } | |
314 | ||
315 | 53543 | private Map createObjectContainer(ContainerFactory containerFactory) |
316 | { | |
317 | 53543 | if (containerFactory == null) |
318 | 53543 | return new JSONObject(); |
319 | 0 | Map m = containerFactory.createObjectContainer(); |
320 | ||
321 | 0 | if (m == null) |
322 | 0 | return new JSONObject(); |
323 | 0 | return m; |
324 | } | |
325 | ||
326 | 41282 | private List createArrayContainer(ContainerFactory containerFactory) |
327 | { | |
328 | 41282 | if (containerFactory == null) |
329 | 41282 | return new JSONArray(); |
330 | 0 | List l = containerFactory.creatArrayContainer(); |
331 | ||
332 | 0 | if (l == null) |
333 | 0 | return new JSONArray(); |
334 | 0 | return l; |
335 | } | |
336 | ||
337 | 0 | public void parse(String s, ContentHandler contentHandler) |
338 | throws ParseException | |
339 | { | |
340 | 0 | parse(s, contentHandler, false); |
341 | } | |
342 | ||
343 | 0 | public void parse(String s, ContentHandler contentHandler, |
344 | boolean isResume) throws ParseException | |
345 | { | |
346 | 0 | StringReader in = new StringReader(s); |
347 | 0 | try |
348 | { | |
349 | 0 | parse(in, contentHandler, isResume); |
350 | } catch (IOException ie) | |
351 | { | |
352 | /* | |
353 | * Actually it will never happen. | |
354 | */ | |
355 | 0 | throw new ParseException(-1, |
356 | ParseException.ERROR_UNEXPECTED_EXCEPTION, ie); | |
357 | } | |
358 | } | |
359 | ||
360 | 0 | public void parse(Reader in, ContentHandler contentHandler) |
361 | throws IOException, ParseException | |
362 | { | |
363 | 0 | parse(in, contentHandler, false); |
364 | } | |
365 | ||
366 | /** | |
367 | * Stream processing of JSON text. | |
368 | * | |
369 | * @see ContentHandler | |
370 | * | |
371 | * @param in | |
372 | * @param contentHandler | |
373 | * @param isResume | |
374 | * - Indicates if it continues previous parsing operation. If set to | |
375 | * true, resume parsing the old stream, and parameter 'in' will be | |
376 | * ignored. If this method is called for the first time in this | |
377 | * instance, isResume will be ignored. | |
378 | * | |
379 | * @throws IOException | |
380 | * @throws ParseException | |
381 | */ | |
382 | 0 | public void parse(Reader in, ContentHandler contentHandler, |
383 | boolean isResume) throws IOException, ParseException | |
384 | { | |
385 | 0 | if (!isResume) |
386 | { | |
387 | 0 | reset(in); |
388 | 0 | handlerStatusStack = new LinkedList(); |
389 | } | |
390 | else | |
391 | { | |
392 | 0 | if (handlerStatusStack == null) |
393 | { | |
394 | 0 | isResume = false; |
395 | 0 | reset(in); |
396 | 0 | handlerStatusStack = new LinkedList(); |
397 | } | |
398 | } | |
399 | ||
400 | 0 | LinkedList statusStack = handlerStatusStack; |
401 | ||
402 | 0 | try |
403 | { | |
404 | 0 | do |
405 | { | |
406 | 0 | switch (status) |
407 | { | |
408 | 0 | case S_INIT: |
409 | 0 | contentHandler.startJSON(); |
410 | 0 | nextToken(); |
411 | 0 | switch (token.type) |
412 | { | |
413 | 0 | case Yytoken.TYPE_VALUE: |
414 | 0 | status = S_IN_FINISHED_VALUE; |
415 | 0 | statusStack.addFirst(new Integer(status)); |
416 | 0 | if (!contentHandler.primitive(token.value)) |
417 | 0 | return; |
418 | 0 | break; |
419 | 0 | case Yytoken.TYPE_LEFT_BRACE: |
420 | 0 | status = S_IN_OBJECT; |
421 | 0 | statusStack.addFirst(new Integer(status)); |
422 | 0 | if (!contentHandler.startObject()) |
423 | 0 | return; |
424 | 0 | break; |
425 | 0 | case Yytoken.TYPE_LEFT_SQUARE: |
426 | 0 | status = S_IN_ARRAY; |
427 | 0 | statusStack.addFirst(new Integer(status)); |
428 | 0 | if (!contentHandler.startArray()) |
429 | 0 | return; |
430 | 0 | break; |
431 | 0 | default: |
432 | 0 | status = S_IN_ERROR; |
433 | }// inner switch | |
434 | 0 | break; |
435 | ||
436 | 0 | case S_IN_FINISHED_VALUE: |
437 | 0 | nextToken(); |
438 | 0 | if (token.type == Yytoken.TYPE_EOF) |
439 | { | |
440 | 0 | contentHandler.endJSON(); |
441 | 0 | status = S_END; |
442 | 0 | return; |
443 | } | |
444 | else | |
445 | { | |
446 | 0 | status = S_IN_ERROR; |
447 | 0 | throw new ParseException(getPosition(), |
448 | ParseException.ERROR_UNEXPECTED_TOKEN, token); | |
449 | } | |
450 | ||
451 | 0 | case S_IN_OBJECT: |
452 | 0 | nextToken(); |
453 | 0 | switch (token.type) |
454 | { | |
455 | 0 | case Yytoken.TYPE_COMMA: |
456 | 0 | break; |
457 | 0 | case Yytoken.TYPE_VALUE: |
458 | 0 | if (token.value instanceof String) |
459 | { | |
460 | 0 | String key = (String) token.value; |
461 | 0 | status = S_PASSED_PAIR_KEY; |
462 | 0 | statusStack.addFirst(new Integer(status)); |
463 | 0 | if (!contentHandler.startObjectEntry(key)) |
464 | 0 | return; |
465 | } | |
466 | else | |
467 | { | |
468 | 0 | status = S_IN_ERROR; |
469 | } | |
470 | 0 | break; |
471 | 0 | case Yytoken.TYPE_RIGHT_BRACE: |
472 | 0 | if (statusStack.size() > 1) |
473 | { | |
474 | 0 | statusStack.removeFirst(); |
475 | 0 | status = peekStatus(statusStack); |
476 | } | |
477 | else | |
478 | { | |
479 | 0 | status = S_IN_FINISHED_VALUE; |
480 | } | |
481 | 0 | if (!contentHandler.endObject()) |
482 | 0 | return; |
483 | 0 | break; |
484 | 0 | default: |
485 | 0 | status = S_IN_ERROR; |
486 | 0 | break; |
487 | }// inner switch | |
488 | 0 | break; |
489 | ||
490 | 0 | case S_PASSED_PAIR_KEY: |
491 | 0 | nextToken(); |
492 | 0 | switch (token.type) |
493 | { | |
494 | 0 | case Yytoken.TYPE_COLON: |
495 | 0 | break; |
496 | 0 | case Yytoken.TYPE_VALUE: |
497 | 0 | statusStack.removeFirst(); |
498 | 0 | status = peekStatus(statusStack); |
499 | 0 | if (!contentHandler.primitive(token.value)) |
500 | 0 | return; |
501 | 0 | if (!contentHandler.endObjectEntry()) |
502 | 0 | return; |
503 | 0 | break; |
504 | 0 | case Yytoken.TYPE_LEFT_SQUARE: |
505 | 0 | statusStack.removeFirst(); |
506 | 0 | statusStack.addFirst(new Integer(S_IN_PAIR_VALUE)); |
507 | 0 | status = S_IN_ARRAY; |
508 | 0 | statusStack.addFirst(new Integer(status)); |
509 | 0 | if (!contentHandler.startArray()) |
510 | 0 | return; |
511 | 0 | break; |
512 | 0 | case Yytoken.TYPE_LEFT_BRACE: |
513 | 0 | statusStack.removeFirst(); |
514 | 0 | statusStack.addFirst(new Integer(S_IN_PAIR_VALUE)); |
515 | 0 | status = S_IN_OBJECT; |
516 | 0 | statusStack.addFirst(new Integer(status)); |
517 | 0 | if (!contentHandler.startObject()) |
518 | 0 | return; |
519 | 0 | break; |
520 | 0 | default: |
521 | 0 | status = S_IN_ERROR; |
522 | } | |
523 | 0 | break; |
524 | ||
525 | 0 | case S_IN_PAIR_VALUE: |
526 | /* | |
527 | * S_IN_PAIR_VALUE is just a marker to indicate the end of an object entry, it doesn't proccess any token, | |
528 | * therefore delay consuming token until next round. | |
529 | */ | |
530 | 0 | statusStack.removeFirst(); |
531 | 0 | status = peekStatus(statusStack); |
532 | 0 | if (!contentHandler.endObjectEntry()) |
533 | 0 | return; |
534 | 0 | break; |
535 | ||
536 | 0 | case S_IN_ARRAY: |
537 | 0 | nextToken(); |
538 | 0 | switch (token.type) |
539 | { | |
540 | 0 | case Yytoken.TYPE_COMMA: |
541 | 0 | break; |
542 | 0 | case Yytoken.TYPE_VALUE: |
543 | 0 | if (!contentHandler.primitive(token.value)) |
544 | 0 | return; |
545 | 0 | break; |
546 | 0 | case Yytoken.TYPE_RIGHT_SQUARE: |
547 | 0 | if (statusStack.size() > 1) |
548 | { | |
549 | 0 | statusStack.removeFirst(); |
550 | 0 | status = peekStatus(statusStack); |
551 | } | |
552 | else | |
553 | { | |
554 | 0 | status = S_IN_FINISHED_VALUE; |
555 | } | |
556 | 0 | if (!contentHandler.endArray()) |
557 | 0 | return; |
558 | 0 | break; |
559 | 0 | case Yytoken.TYPE_LEFT_BRACE: |
560 | 0 | status = S_IN_OBJECT; |
561 | 0 | statusStack.addFirst(new Integer(status)); |
562 | 0 | if (!contentHandler.startObject()) |
563 | 0 | return; |
564 | 0 | break; |
565 | 0 | case Yytoken.TYPE_LEFT_SQUARE: |
566 | 0 | status = S_IN_ARRAY; |
567 | 0 | statusStack.addFirst(new Integer(status)); |
568 | 0 | if (!contentHandler.startArray()) |
569 | 0 | return; |
570 | 0 | break; |
571 | 0 | default: |
572 | 0 | status = S_IN_ERROR; |
573 | }// inner switch | |
574 | 0 | break; |
575 | ||
576 | 0 | case S_END: |
577 | 0 | return; |
578 | ||
579 | 0 | case S_IN_ERROR: |
580 | 0 | throw new ParseException(getPosition(), |
581 | ParseException.ERROR_UNEXPECTED_TOKEN, token); | |
582 | }// switch | |
583 | 0 | if (status == S_IN_ERROR) |
584 | { | |
585 | 0 | throw new ParseException(getPosition(), |
586 | ParseException.ERROR_UNEXPECTED_TOKEN, token); | |
587 | } | |
588 | 0 | } while (token.type != Yytoken.TYPE_EOF); |
589 | } catch (IOException ie) | |
590 | { | |
591 | 0 | status = S_IN_ERROR; |
592 | 0 | throw ie; |
593 | } catch (ParseException pe) | |
594 | { | |
595 | 0 | status = S_IN_ERROR; |
596 | 0 | throw pe; |
597 | } catch (RuntimeException re) | |
598 | { | |
599 | 0 | status = S_IN_ERROR; |
600 | 0 | throw re; |
601 | } catch (Error e) | |
602 | { | |
603 | 0 | status = S_IN_ERROR; |
604 | 0 | throw e; |
605 | } | |
606 | ||
607 | 0 | status = S_IN_ERROR; |
608 | 0 | throw new ParseException(getPosition(), |
609 | ParseException.ERROR_UNEXPECTED_TOKEN, token); | |
610 | } | |
611 | } |