001/* Copyright 2006 FangYidong
002
003   Licensed under the Apache License, Version 2.0 (the "License");
004   you may not use this file except in compliance with the License.
005   You may obtain a copy of the License at
006
007       http://www.apache.org/licenses/LICENSE-2.0
008
009   Unless required by applicable law or agreed to in writing, software
010   distributed under the License is distributed on an "AS IS" BASIS,
011   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012   See the License for the specific language governing permissions and
013   limitations under the License. */
014package org.json.simple.parser;
015
016import java.io.IOException;
017import java.io.Reader;
018import java.io.StringReader;
019import java.util.LinkedList;
020import java.util.List;
021import java.util.Map;
022
023import org.json.simple.JSONArray;
024import org.json.simple.JSONObject;
025
026
027/**
028 * Parser for JSON text. Please note that JSONParser is NOT thread-safe.
029 * 
030 * @author FangYidong<fangyidong@yahoo.com.cn>
031 * @deprecated since 2.0.0, copied to a new package {@link org.json.simple.Jsoner}.
032 */
033@Deprecated
034public class JSONParser {
035        /**
036         * description omitted.
037         */
038        public static final int S_INIT=0;
039        /**
040         * description omitted.
041         */
042        public static final int S_IN_FINISHED_VALUE=1;//string,number,boolean,null,object,array
043        /**
044         * description omitted.
045         */
046        public static final int S_IN_OBJECT=2;
047        /**
048         * description omitted.
049         */
050        public static final int S_IN_ARRAY=3;
051        /**
052         * description omitted.
053         */
054        public static final int S_PASSED_PAIR_KEY=4;
055        /**
056         * description omitted.
057         */
058        public static final int S_IN_PAIR_VALUE=5;
059        /**
060         * description omitted.
061         */
062        public static final int S_END=6;
063        /**
064         * description omitted.
065         */
066        public static final int S_IN_ERROR=-1;
067        
068        private LinkedList handlerStatusStack;
069        private Yylex lexer = new Yylex((Reader)null);
070        private Yytoken token = null;
071        private int status = S_INIT;
072        
073        private int peekStatus(LinkedList statusStack){
074                if(statusStack.size()==0)
075                        return -1;
076                Integer status=(Integer)statusStack.getFirst();
077                return status.intValue();
078        }
079        
080    /**
081     *  Reset the parser to the initial state without resetting the underlying reader.
082     *
083     */
084    public void reset(){
085        token = null;
086        status = S_INIT;
087        handlerStatusStack = null;
088    }
089    
090    /**
091     * Reset the parser to the initial state with a new character reader.
092     * 
093     * @param in - The new character reader.
094     */
095        public void reset(Reader in){
096                lexer.yyreset(in);
097                reset();
098        }
099        
100        /**
101         * @return The position of the beginning of the current token.
102         */
103        public int getPosition(){
104                return lexer.getPosition();
105        }
106        
107        /**
108         * description omitted.
109         *
110         * @param s description omitted.
111         * @return description omitted.
112         * @throws ParseException description omitted.
113         */
114        public Object parse(String s) throws ParseException{
115                return parse(s, (ContainerFactory)null);
116        }
117        
118        /**
119         * description omitted.
120         *
121         * @param s description omitted.
122         * @param containerFactory description omitted.
123         * @return description omitted.
124         * @throws ParseException description omitted.
125         */
126        public Object parse(String s, ContainerFactory containerFactory) throws ParseException{
127                StringReader in=new StringReader(s);
128                try{
129                        return parse(in, containerFactory);
130                }
131                catch(IOException ie){
132                        /*
133                         * Actually it will never happen.
134                         */
135                        throw new ParseException(-1, ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
136                }
137        }
138        
139        /**
140         * description omitted.
141         *
142         * @param in description omitted.
143         * @return description omitted.
144         * @throws IOException description omitted.
145         * @throws ParseException description omitted.
146         */
147        public Object parse(Reader in) throws IOException, ParseException{
148                return parse(in, (ContainerFactory)null);
149        }
150        
151        /**
152         * Parse JSON text into java object from the input source.
153         *      
154         * @param in description omitted.
155     * @param containerFactory - Use this factory to createyour own JSON object and JSON array containers.
156         * @return Instance of the following:
157         *  org.json.simple.JSONObject,
158         *      org.json.simple.JSONArray,
159         *      java.lang.String,
160         *      java.lang.Number,
161         *      java.lang.Boolean,
162         *      null
163         * 
164         * @throws IOException description omitted.
165         * @throws ParseException description omitted.
166         */
167        public Object parse(Reader in, ContainerFactory containerFactory) throws IOException, ParseException{
168                reset(in);
169                LinkedList statusStack = new LinkedList();
170                LinkedList valueStack = new LinkedList();
171                
172                try{
173                        do{
174                                nextToken();
175                                switch(status){
176                                case S_INIT:
177                                        switch(token.type){
178                                        case Yytoken.TYPE_VALUE:
179                                                status=S_IN_FINISHED_VALUE;
180                                                statusStack.addFirst(new Integer(status));
181                                                valueStack.addFirst(token.value);
182                                                break;
183                                        case Yytoken.TYPE_LEFT_BRACE:
184                                                status=S_IN_OBJECT;
185                                                statusStack.addFirst(new Integer(status));
186                                                valueStack.addFirst(createObjectContainer(containerFactory));
187                                                break;
188                                        case Yytoken.TYPE_LEFT_SQUARE:
189                                                status=S_IN_ARRAY;
190                                                statusStack.addFirst(new Integer(status));
191                                                valueStack.addFirst(createArrayContainer(containerFactory));
192                                                break;
193                                        default:
194                                                status=S_IN_ERROR;
195                                        }//inner switch
196                                        break;
197                                        
198                                case S_IN_FINISHED_VALUE:
199                                        if(token.type==Yytoken.TYPE_EOF)
200                                                return valueStack.removeFirst();
201                                        else
202                                                throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
203                                        
204                                case S_IN_OBJECT:
205                                        switch(token.type){
206                                        case Yytoken.TYPE_COMMA:
207                                                break;
208                                        case Yytoken.TYPE_VALUE:
209                                                if(token.value instanceof String){
210                                                        String key=(String)token.value;
211                                                        valueStack.addFirst(key);
212                                                        status=S_PASSED_PAIR_KEY;
213                                                        statusStack.addFirst(new Integer(status));
214                                                }
215                                                else{
216                                                        status=S_IN_ERROR;
217                                                }
218                                                break;
219                                        case Yytoken.TYPE_RIGHT_BRACE:
220                                                if(valueStack.size()>1){
221                                                        statusStack.removeFirst();
222                                                        valueStack.removeFirst();
223                                                        status=peekStatus(statusStack);
224                                                }
225                                                else{
226                                                        status=S_IN_FINISHED_VALUE;
227                                                }
228                                                break;
229                                        default:
230                                                status=S_IN_ERROR;
231                                                break;
232                                        }//inner switch
233                                        break;
234                                        
235                                case S_PASSED_PAIR_KEY:
236                                        switch(token.type){
237                                        case Yytoken.TYPE_COLON:
238                                                break;
239                                        case Yytoken.TYPE_VALUE:
240                                                statusStack.removeFirst();
241                                                String key=(String)valueStack.removeFirst();
242                                                Map parent=(Map)valueStack.getFirst();
243                                                parent.put(key,token.value);
244                                                status=peekStatus(statusStack);
245                                                break;
246                                        case Yytoken.TYPE_LEFT_SQUARE:
247                                                statusStack.removeFirst();
248                                                key=(String)valueStack.removeFirst();
249                                                parent=(Map)valueStack.getFirst();
250                                                List newArray=createArrayContainer(containerFactory);
251                                                parent.put(key,newArray);
252                                                status=S_IN_ARRAY;
253                                                statusStack.addFirst(new Integer(status));
254                                                valueStack.addFirst(newArray);
255                                                break;
256                                        case Yytoken.TYPE_LEFT_BRACE:
257                                                statusStack.removeFirst();
258                                                key=(String)valueStack.removeFirst();
259                                                parent=(Map)valueStack.getFirst();
260                                                Map newObject=createObjectContainer(containerFactory);
261                                                parent.put(key,newObject);
262                                                status=S_IN_OBJECT;
263                                                statusStack.addFirst(new Integer(status));
264                                                valueStack.addFirst(newObject);
265                                                break;
266                                        default:
267                                                status=S_IN_ERROR;
268                                        }
269                                        break;
270                                        
271                                case S_IN_ARRAY:
272                                        switch(token.type){
273                                        case Yytoken.TYPE_COMMA:
274                                                break;
275                                        case Yytoken.TYPE_VALUE:
276                                                List val=(List)valueStack.getFirst();
277                                                val.add(token.value);
278                                                break;
279                                        case Yytoken.TYPE_RIGHT_SQUARE:
280                                                if(valueStack.size()>1){
281                                                        statusStack.removeFirst();
282                                                        valueStack.removeFirst();
283                                                        status=peekStatus(statusStack);
284                                                }
285                                                else{
286                                                        status=S_IN_FINISHED_VALUE;
287                                                }
288                                                break;
289                                        case Yytoken.TYPE_LEFT_BRACE:
290                                                val=(List)valueStack.getFirst();
291                                                Map newObject=createObjectContainer(containerFactory);
292                                                val.add(newObject);
293                                                status=S_IN_OBJECT;
294                                                statusStack.addFirst(new Integer(status));
295                                                valueStack.addFirst(newObject);
296                                                break;
297                                        case Yytoken.TYPE_LEFT_SQUARE:
298                                                val=(List)valueStack.getFirst();
299                                                List newArray=createArrayContainer(containerFactory);
300                                                val.add(newArray);
301                                                status=S_IN_ARRAY;
302                                                statusStack.addFirst(new Integer(status));
303                                                valueStack.addFirst(newArray);
304                                                break;
305                                        default:
306                                                status=S_IN_ERROR;
307                                        }//inner switch
308                                        break;
309                                case S_IN_ERROR:
310                                        throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
311                                }//switch
312                                if(status==S_IN_ERROR){
313                                        throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
314                                }
315                        }while(token.type!=Yytoken.TYPE_EOF);
316                }
317                catch(IOException ie){
318                        throw ie;
319                }
320                
321                throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
322        }
323        
324        private void nextToken() throws ParseException, IOException{
325                token = lexer.yylex();
326                if(token == null)
327                        token = new Yytoken(Yytoken.TYPE_EOF, null);
328        }
329        
330        private Map createObjectContainer(ContainerFactory containerFactory){
331                if(containerFactory == null)
332                        return new JSONObject();
333                Map m = containerFactory.createObjectContainer();
334                
335                if(m == null)
336                        return new JSONObject();
337                return m;
338        }
339        
340        private List createArrayContainer(ContainerFactory containerFactory){
341                if(containerFactory == null)
342                        return new JSONArray();
343                List l = containerFactory.creatArrayContainer();
344                
345                if(l == null)
346                        return new JSONArray();
347                return l;
348        }
349        
350        /**
351         * description omitted.
352         *
353         * @param s description omitted.
354         * @param contentHandler description omitted.
355         * @throws ParseException description omitted.
356         */
357        public void parse(String s, ContentHandler contentHandler) throws ParseException{
358                parse(s, contentHandler, false);
359        }
360        
361        /**
362         * description omitted.
363         *
364         * @param s description omitted.
365         * @param contentHandler description omitted.
366         * @param isResume description omitted.
367         * @throws ParseException description omitted.
368         */
369        public void parse(String s, ContentHandler contentHandler, boolean isResume) throws ParseException{
370                StringReader in=new StringReader(s);
371                try{
372                        parse(in, contentHandler, isResume);
373                }
374                catch(IOException ie){
375                        /*
376                         * Actually it will never happen.
377                         */
378                        throw new ParseException(-1, ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
379                }
380        }
381        
382        /**
383         * description omitted.
384         *
385         * @param in description omitted.
386         * @param contentHandler description omitted.
387         * @throws IOException description omitted.
388         * @throws ParseException description omitted.
389         */
390        public void parse(Reader in, ContentHandler contentHandler) throws IOException, ParseException{
391                parse(in, contentHandler, false);
392        }
393        
394        /**
395         * Stream processing of JSON text.
396         * 
397         * @see ContentHandler
398         * 
399         * @param in description omitted.
400         * @param contentHandler description omitted.
401         * @param isResume - Indicates if it continues previous parsing operation.
402     *                   If set to true, resume parsing the old stream, and parameter 'in' will be ignored. 
403         *                   If this method is called for the first time in this instance, isResume will be ignored.
404         * 
405         * @throws IOException description omitted.
406         * @throws ParseException description omitted.
407         */
408        public void parse(Reader in, ContentHandler contentHandler, boolean isResume) throws IOException, ParseException{
409                if(!isResume){
410                        reset(in);
411                        handlerStatusStack = new LinkedList();
412                }
413                else{
414                        if(handlerStatusStack == null){
415                                isResume = false;
416                                reset(in);
417                                handlerStatusStack = new LinkedList();
418                        }
419                }
420                
421                LinkedList statusStack = handlerStatusStack;    
422                
423                try{
424                        do{
425                                switch(status){
426                                case S_INIT:
427                                        contentHandler.startJSON();
428                                        nextToken();
429                                        switch(token.type){
430                                        case Yytoken.TYPE_VALUE:
431                                                status=S_IN_FINISHED_VALUE;
432                                                statusStack.addFirst(new Integer(status));
433                                                if(!contentHandler.primitive(token.value))
434                                                        return;
435                                                break;
436                                        case Yytoken.TYPE_LEFT_BRACE:
437                                                status=S_IN_OBJECT;
438                                                statusStack.addFirst(new Integer(status));
439                                                if(!contentHandler.startObject())
440                                                        return;
441                                                break;
442                                        case Yytoken.TYPE_LEFT_SQUARE:
443                                                status=S_IN_ARRAY;
444                                                statusStack.addFirst(new Integer(status));
445                                                if(!contentHandler.startArray())
446                                                        return;
447                                                break;
448                                        default:
449                                                status=S_IN_ERROR;
450                                        }//inner switch
451                                        break;
452                                        
453                                case S_IN_FINISHED_VALUE:
454                                        nextToken();
455                                        if(token.type==Yytoken.TYPE_EOF){
456                                                contentHandler.endJSON();
457                                                status = S_END;
458                                                return;
459                                        }
460                                        else{
461                                                status = S_IN_ERROR;
462                                                throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
463                                        }
464                        
465                                case S_IN_OBJECT:
466                                        nextToken();
467                                        switch(token.type){
468                                        case Yytoken.TYPE_COMMA:
469                                                break;
470                                        case Yytoken.TYPE_VALUE:
471                                                if(token.value instanceof String){
472                                                        String key=(String)token.value;
473                                                        status=S_PASSED_PAIR_KEY;
474                                                        statusStack.addFirst(new Integer(status));
475                                                        if(!contentHandler.startObjectEntry(key))
476                                                                return;
477                                                }
478                                                else{
479                                                        status=S_IN_ERROR;
480                                                }
481                                                break;
482                                        case Yytoken.TYPE_RIGHT_BRACE:
483                                                if(statusStack.size()>1){
484                                                        statusStack.removeFirst();
485                                                        status=peekStatus(statusStack);
486                                                }
487                                                else{
488                                                        status=S_IN_FINISHED_VALUE;
489                                                }
490                                                if(!contentHandler.endObject())
491                                                        return;
492                                                break;
493                                        default:
494                                                status=S_IN_ERROR;
495                                                break;
496                                        }//inner switch
497                                        break;
498                                        
499                                case S_PASSED_PAIR_KEY:
500                                        nextToken();
501                                        switch(token.type){
502                                        case Yytoken.TYPE_COLON:
503                                                break;
504                                        case Yytoken.TYPE_VALUE:
505                                                statusStack.removeFirst();
506                                                status=peekStatus(statusStack);
507                                                if(!contentHandler.primitive(token.value))
508                                                        return;
509                                                if(!contentHandler.endObjectEntry())
510                                                        return;
511                                                break;
512                                        case Yytoken.TYPE_LEFT_SQUARE:
513                                                statusStack.removeFirst();
514                                                statusStack.addFirst(new Integer(S_IN_PAIR_VALUE));
515                                                status=S_IN_ARRAY;
516                                                statusStack.addFirst(new Integer(status));
517                                                if(!contentHandler.startArray())
518                                                        return;
519                                                break;
520                                        case Yytoken.TYPE_LEFT_BRACE:
521                                                statusStack.removeFirst();
522                                                statusStack.addFirst(new Integer(S_IN_PAIR_VALUE));
523                                                status=S_IN_OBJECT;
524                                                statusStack.addFirst(new Integer(status));
525                                                if(!contentHandler.startObject())
526                                                        return;
527                                                break;
528                                        default:
529                                                status=S_IN_ERROR;
530                                        }
531                                        break;
532                                
533                                case S_IN_PAIR_VALUE:
534                                        /*
535                                         * S_IN_PAIR_VALUE is just a marker to indicate the end of an object entry, it doesn't proccess any token,
536                                         * therefore delay consuming token until next round.
537                                         */
538                                        statusStack.removeFirst();
539                                        status = peekStatus(statusStack);
540                                        if(!contentHandler.endObjectEntry())
541                                                return;
542                                        break;
543                                        
544                                case S_IN_ARRAY:
545                                        nextToken();
546                                        switch(token.type){
547                                        case Yytoken.TYPE_COMMA:
548                                                break;
549                                        case Yytoken.TYPE_VALUE:
550                                                if(!contentHandler.primitive(token.value))
551                                                        return;
552                                                break;
553                                        case Yytoken.TYPE_RIGHT_SQUARE:
554                                                if(statusStack.size()>1){
555                                                        statusStack.removeFirst();
556                                                        status=peekStatus(statusStack);
557                                                }
558                                                else{
559                                                        status=S_IN_FINISHED_VALUE;
560                                                }
561                                                if(!contentHandler.endArray())
562                                                        return;
563                                                break;
564                                        case Yytoken.TYPE_LEFT_BRACE:
565                                                status=S_IN_OBJECT;
566                                                statusStack.addFirst(new Integer(status));
567                                                if(!contentHandler.startObject())
568                                                        return;
569                                                break;
570                                        case Yytoken.TYPE_LEFT_SQUARE:
571                                                status=S_IN_ARRAY;
572                                                statusStack.addFirst(new Integer(status));
573                                                if(!contentHandler.startArray())
574                                                        return;
575                                                break;
576                                        default:
577                                                status=S_IN_ERROR;
578                                        }//inner switch
579                                        break;
580                                        
581                                case S_END:
582                                        return;
583                                        
584                                case S_IN_ERROR:
585                                        throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
586                                }//switch
587                                if(status==S_IN_ERROR){
588                                        throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
589                                }
590                        }while(token.type!=Yytoken.TYPE_EOF);
591                }
592                catch(IOException ie){
593                        status = S_IN_ERROR;
594                        throw ie;
595                }
596                catch(ParseException pe){
597                        status = S_IN_ERROR;
598                        throw pe;
599                }
600                catch(RuntimeException re){
601                        status = S_IN_ERROR;
602                        throw re;
603                }
604                catch(Error e){
605                        status = S_IN_ERROR;
606                        throw e;
607                }
608                
609                status = S_IN_ERROR;
610                throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
611        }
612}