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