/* * Copyright 2013 Simon Thiel * * This file is part of SitJar. * * SitJar is free software: you can redistribute it and/or modify * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * SitJar is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with SitJar. If not, see <http://www.gnu.org/licenses/lgpl.txt>. */ /* * Description of JSONParser * * @author Simon Thiel <simon.thiel at gmx.de> * @date 26.03.2012 */ package sit.json; /** * * @author simon */ public class JSONParser { private boolean isWhiteSpace(char chr) { return (chr == ' ' || chr == '\t' || chr == '\n' | chr == '\f' | chr == '\r'); } private int ignoreWhiteSpace(String text, int curC) { while (curC < text.length() && isWhiteSpace(text.charAt(curC))) { curC++; } return curC; } private boolean testForChr(String text, int index, char chr){ if (index>=text.length()){ return false; } return text.charAt(index)==chr; } private int jumpOverNextChr(String text, int curC, char chr){ curC = ignoreWhiteSpace(text, curC); if (testForChr(text, curC, chr)){ curC++; } curC = ignoreWhiteSpace(text, curC); return curC; } private ParseResult getNextTextValue(String text, int curC, char endDelim) throws JSONParseException { ParseResult result = new ParseResult(); if (testForChr(text,curC,'"')){ result.hasQuotes = true; curC++; } boolean escapeFlag=false; int start = curC; while (curC<text.length() && (!result.hasQuotes || (!testForChr(text,curC,'"')) || escapeFlag) && (result.hasQuotes || (!testForChr(text,curC,endDelim))) && (result.hasQuotes || (!testForChr(text,curC,'}')) || escapeFlag) && (result.hasQuotes || (!testForChr(text,curC,']')) || escapeFlag) ){ //missing additonal delim for end of object in case no quotes are set!!!! escapeFlag = (testForChr(text,curC,'\\')); curC++; } result.value = JSONTextHelper.decodeText(text.substring(start,curC)); if (result.hasQuotes){ curC++; curC = ignoreWhiteSpace(text, curC); } result.endPosition = curC; return result; } public ParseResult getNextObject(String key, String text, int curC) throws JSONParseException { curC = ignoreWhiteSpace(text, curC); if (!testForChr(text,curC,'{')){ if (curC>=text.length()){ throw new JSONParseException("curC>text.length() - reached end of text when looking for }\nkey:"+key+"\ntext:\n"+text); }else{ throw new JSONParseException("Found unexpected char "+text.charAt(curC)+" at begining of object at pos: "+curC+" in (starting from "+curC+"-2):\n"+text.substring((0<curC-2)?curC-2:0)); } }//else curC++; ParseResult result = new ParseResult(); result.object = new JSONObject(key); boolean hasNextKey = true; while (curC<text.length() && (!testForChr(text,curC,'}')) && hasNextKey){ ParseResult myKey = getNextKey(text, curC); curC = myKey.endPosition; //proceed to value in the text curC = jumpOverNextChr(text, curC, ':'); if (myKey.value!=null){ ParseResult myValue = getNextValue(myKey.value, text, curC); if (myValue.object!=null){ result.object.addChild(myValue.object); curC = myValue.endPosition; }else{ throw new JSONParseException("unable to parse right side at pos: "+curC+" in:\n"+text); } }else{ hasNextKey=false; } //proceed to next key in the text if there is one curC = jumpOverNextChr(text, curC, ','); } curC = ignoreWhiteSpace(text, curC); if (!testForChr(text,curC,'}')){ if (curC>=text.length()){ throw new JSONParseException("curC>text.length() - reached end of text when looking for }\nkey:"+key+"\ntext:\n"+text); }else{ throw new JSONParseException("Found unexpected char "+text.charAt(curC)+" at end object at pos: "+curC+" in:\n"+text); } } result.endPosition = curC; return result; } private ParseResult getNextValue(String key, String text, int curC) throws JSONParseException { ParseResult result = new ParseResult(); curC = ignoreWhiteSpace(text, curC); if (testForChr(text,curC,'[')) { //we have a collection result.object = new JSONObject(key); result.object.setType(JSONObject.JSON_TYPE_COLLECTION); curC++; curC = ignoreWhiteSpace(text, curC); boolean objectFound = true; int counter = 0; while (curC<text.length() && (!testForChr(text,curC,']')) && objectFound){ ParseResult parseResult = getNextValue(counter+"",text, curC); //we set the index of the object/value in a collection as its key counter++; if (parseResult.object!=null){ result.object.addItem(parseResult.object); }else{ objectFound = false; } curC = parseResult.endPosition; //proceed to next object in the text (if there is one) curC = jumpOverNextChr(text, curC, ','); } curC = jumpOverNextChr(text, curC, ']'); } else if (testForChr(text,curC,'{')) { //we have an object ParseResult parseResult = getNextObject(key, text, curC); if (parseResult.object!=null){ result.object = parseResult.object; }else{ throw new JSONParseException("Found invalid object at pos: "+curC+" in:\n"+text); } curC = parseResult.endPosition; curC = jumpOverNextChr(text, curC, '}'); curC = jumpOverNextChr(text, curC, ','); } else { //we have a leave ParseResult parseResult = getNextTextValue(text, curC, ','); result.object = new JSONObject(key); result.object.setValue(parseResult.value, parseResult.hasQuotes); curC = parseResult.endPosition; } result.endPosition = curC; return result; } private ParseResult getNextKey(String text, int curC) throws JSONParseException { curC = ignoreWhiteSpace(text, curC); ParseResult result = getNextTextValue(text, curC, ':'); return result; } public JSONObject parseJSON(String text) throws JSONParseException{ return getNextObject("root", text, 0).object; } }