blob: 39ddf982de34c8ae70ac4be8cc1f2c80fa6bc0d4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cordova.json4j.internal;
import java.io.IOException;
import java.io.Reader;
import org.apache.cordova.json4j.JSONArray;
import org.apache.cordova.json4j.JSONException;
import org.apache.cordova.json4j.JSONObject;
/**
* Private parser class which handles doing the parsing of the JSON string into tokens.
*/
public class Parser {
private Tokenizer tokenizer;
private Token lastToken;
/**
* Contructor
* @param reader The Reader to use when reading in the JSON stream/string.
*
* @throws JSONException Thrown if an error occurs in tokenizing the JSON string.
*/
public Parser(Reader reader) throws JSONException {
super();
try {
this.tokenizer = new Tokenizer(reader, false);
} catch (IOException iox) {
JSONException jex = new JSONException("Error occurred during input read.");
jex.setCause(iox);
throw jex;
}
}
/**
* Contructor
* @param reader The Reader to use when reading in the JSON stream/string.
* @param strict Boolean indicating if the parser should parse in strict mode, meaning unqoted strings and comments are not allowed.
*
* @throws JSONException Thrown if an error occurs in tokenizing the JSON string.
*/
public Parser(Reader reader, boolean strict) throws JSONException {
super();
try {
this.tokenizer = new Tokenizer(reader, strict);
} catch (IOException iox) {
JSONException jex = new JSONException("Error occurred during input read.");
jex.setCause(iox);
throw jex;
}
}
/**
* Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within.
* Same as calling parse(false);
*
* @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s).
*/
public JSONObject parse() throws JSONException {
return parse(false, (JSONObject)null);
}
/**
* Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within.
* Same as calling parse(false);
*
* @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s).
*/
public JSONObject parse(JSONObject jObj) throws JSONException {
return parse(false, jObj);
}
/**
* Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within.
* @param ordered Flag to denote if the parse should contruct a JSON object which maintains serialization order of the attributes.
*
* @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s).
*/
public JSONObject parse(boolean ordered) throws JSONException {
try {
lastToken = tokenizer.next();
} catch (IOException iox) {
JSONException jex = new JSONException("Error occurred during input read.");
jex.setCause(iox);
throw jex;
}
return parseObject(ordered, null);
}
/**
* Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within.
* @param ordered Flag to denote if the parse should contruct a JSON object which maintains serialization order of the attributes.
* @param jObj The JSONObjetc to fill out from the parsing. If null, create a new one.
*
* @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s).
*/
public JSONObject parse(boolean ordered, JSONObject jObj) throws JSONException {
try {
lastToken = tokenizer.next();
} catch (IOException iox) {
JSONException jex = new JSONException("Error occurred during input read.");
jex.setCause(iox);
throw jex;
}
return parseObject(ordered, jObj);
}
/**
* Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within.
* @param jObj The JSONArray to fill out from the parsing. If null, create a new one.
*
* @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s).
*/
public JSONArray parse(JSONArray jObj) throws JSONException {
return parse(false, jObj);
}
/**
* Method to initiate the parse of the toplevel JSON object, which will in turn parse all child JSON objects contained within.
* @param ordered Flag to denote if the parse should contruct for all JSON objects encounted, a JSON object which maintains serialization order of the attributes.
* @param jObj The JSONArray to fill out from the parsing. If null, create a new one.
*
* @throws JSONException Thrown if an IO error occurd during parse of the JSON object(s).
*/
public JSONArray parse(boolean ordered, JSONArray jObj) throws JSONException {
try {
lastToken = tokenizer.next();
} catch (IOException iox) {
JSONException jex = new JSONException("Error occurred during input read.");
jex.setCause(iox);
throw jex;
}
return parseArray(ordered, jObj);
}
/**
* Method to parse a JSON object out of the current JSON string position.
* @return JSONObject Returns the parsed out JSON object.
*
* @throws JSONException Thrown if an IO error occurs during parse, such as a malformed JSON object.
*/
public JSONObject parseObject() throws JSONException {
return parseObject(false, null);
}
/**
* Method to parse a JSON object out of the current JSON string position.
* @param ordered Flag to denote if the parse should contruct a JSON object which maintains serialization order of the attributes.
* @return JSONObject Returns the parsed out JSON object.
*
* @throws JSONException Thrown if an IO error occurs during parse, such as a malformed JSON object.
*/
public JSONObject parseObject(boolean ordered, JSONObject rootObject) throws JSONException {
try {
JSONObject result = null;
if (rootObject != null) {
result = rootObject;
} else {
if (!ordered) {
result = new JSONObject();
} else {
//MSN NO ORDERED
result = new JSONObject();
}
}
if (lastToken != Token.TokenBraceL) throw new JSONException("Expecting '{' " + tokenizer.onLineCol() + " instead, obtained token: '" + lastToken + "'");
lastToken = tokenizer.next();
while (true) {
if (lastToken == Token.TokenEOF) throw new JSONException("Unterminated object " + tokenizer.onLineCol());
if (lastToken == Token.TokenBraceR) {
lastToken = tokenizer.next();
break;
}
if (!lastToken.isString()) throw new JSONException("Expecting string key " + tokenizer.onLineCol());
String key = lastToken.getString();
lastToken = tokenizer.next();
if (lastToken != Token.TokenColon) throw new JSONException("Expecting colon " + tokenizer.onLineCol());
lastToken = tokenizer.next();
Object val = parseValue(ordered);
result.put(key, val);
if (lastToken == Token.TokenComma) {
lastToken = tokenizer.next();
}
else if (lastToken != Token.TokenBraceR) {
throw new JSONException("expecting either ',' or '}' " + tokenizer.onLineCol());
}
}
return result;
} catch (IOException iox) {
JSONException jex = new JSONException("Error occurred during object input read.");
jex.setCause(iox);
throw jex;
}
}
/**
* Method to parse out a JSON array from a JSON string
* Same as calling parseArray(false, null)
*
* @throws JSONException Thrown if a parse error occurs, such as a malformed JSON array.
*/
public JSONArray parseArray() throws JSONException {
return parseArray(false, null);
}
/**
* Method to parse out a JSON array from a JSON string
* @param ordered Flag to denote if the parse should contruct JSON objects which maintain serialization order of the attributes for all JSONOjects in the array.
* *param array An array instance to populate instead of creating a new one.
*
* @throws JSONException Thrown if a parse error occurs, such as a malformed JSON array.
*/
public JSONArray parseArray(boolean ordered, JSONArray array) throws JSONException {
JSONArray result = null;
if(array != null){
result = array;
} else {
result = new JSONArray();
}
try {
if (lastToken != Token.TokenBrackL) throw new JSONException("Expecting '[' " + tokenizer.onLineCol());
lastToken = tokenizer.next();
while (true) {
if (lastToken == Token.TokenEOF) throw new JSONException("Unterminated array " + tokenizer.onLineCol());
/**
* End of the array.
*/
if (lastToken == Token.TokenBrackR) {
lastToken = tokenizer.next();
break;
}
Object val = parseValue(ordered);
result.add(val);
if (lastToken == Token.TokenComma) {
lastToken = tokenizer.next();
} else if (lastToken != Token.TokenBrackR) {
throw new JSONException("expecting either ',' or ']' " + tokenizer.onLineCol());
}
}
} catch (IOException iox) {
JSONException jex = new JSONException("Error occurred during array input read.");
jex.setCause(iox);
throw jex;
}
return result;
}
/**
* Method to parse the current JSON property value from the last token.
* @return The java object type that represents the JSON value.
*
* @throws JSONException Thrown if an IO error (read incomplete token) occurs.
*/
public Object parseValue() throws JSONException {
return parseValue(false);
}
/**
* Method to parse the current JSON property value from the last token.
* @return The java object type that represents the JSON value.
* @param ordered Flag to denote if the parse should contruct JSON objects and arrays which maintain serialization order of the attributes.
*
* @throws JSONException Thrown if an IO error (read incomplete token) occurs.
*/
public Object parseValue(boolean ordered) throws JSONException {
if (lastToken == Token.TokenEOF) throw new JSONException("Expecting property value " + tokenizer.onLineCol());
try {
if (lastToken.isNumber()) {
Object result = lastToken.getNumber();
lastToken = tokenizer.next();
return result;
}
if (lastToken.isString()) {
Object result = lastToken.getString();
lastToken = tokenizer.next();
return result;
}
if (lastToken == Token.TokenFalse) {
lastToken = tokenizer.next();
return Boolean.FALSE;
}
if (lastToken == Token.TokenTrue) {
lastToken = tokenizer.next();
return Boolean.TRUE;
}
if (lastToken == Token.TokenNull) {
lastToken = tokenizer.next();
return JSONObject.NULL;
}
if (lastToken == Token.TokenBrackL) return parseArray(ordered, null);
if (lastToken == Token.TokenBraceL) return parseObject(ordered, null);
} catch (IOException iox) {
JSONException jex = new JSONException("Error occurred during value input read.");
jex.setCause(iox);
throw jex;
}
throw new JSONException("Invalid token " + tokenizer.onLineCol());
}
}