+++ /dev/null
-package javajs.util;
-
-import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Map;
-
-
-/**
- * a very simple JSON parser for JSON objects that are compatible with JavaScript
- * A gross simplification of https://github.com/douglascrockford/JSON-java
- *
- * A SUBSET of JSON with similarly to window.JSON.parse():
- *
- * In JavaScript returns "null" for a null value, not null
- *
- * -- requires quoted strings for keys and values
- *
- * -- does not allow /xxx/ objects
- *
- * @author Bob Hanson
- *
- */
-public class JSJSONParser {
-
- private String str;
- private int index;
- private int len;
- private boolean asHashTable;
-
- public JSJSONParser () {
- // for reflection
- }
-
- /**
- * requires { "key":"value", "key":"value",....}
- *
- * @param str
- * @param asHashTable TODO
- *
- * @return Map or null
- */
- @SuppressWarnings("unchecked")
- public Map<String, Object> parseMap(String str, boolean asHashTable) {
- index = 0;
- this.asHashTable = asHashTable;
- this.str = str;
- len = str.length();
- if (getChar() != '{')
- return null;
- returnChar();
- return (Map<String, Object>) getValue(false);
- }
-
- /**
- * Could return Integer, Float, Boolean, String, Map<String, Object>, Lst<Object>, or null
- *
- * @param str
- * @param asHashTable
- * @return a object equivalent to the JSON string str
- *
- */
- public Object parse(String str, boolean asHashTable) {
- index = 0;
- this.asHashTable = asHashTable;
- this.str = str;
- len = str.length();
- return getValue(false);
- }
-
- private char next() {
- return (index < len ? str.charAt(index++) : '\0');
- }
-
- private void returnChar() {
- index--;
- }
-
- /**
- * Get the next char in the string, skipping whitespace.
- *
- * @throws JSONException
- * @return one character, or 0 if there are no more characters.
- */
- private char getChar() throws JSONException {
- for (;;) {
- char c = next();
- if (c == 0 || c > ' ') {
- return c;
- }
- }
- }
-
- /**
- * only allowing the following values:
- *
- * {...} object
- *
- * [...] array
- *
- * Integer
- *
- * Float
- *
- * "quoted string"
- *
- *
- * @param isKey if we should allow {...} and [...]
- * @return a subclass of Object
- * @throws JSONException
- */
- private Object getValue(boolean isKey) throws JSONException {
- int i = index;
- char c = getChar();
- switch (c) {
- case '\0':
- return null;
- case '"':
- case '\'':
- return getString(c);
- case '{':
- if (!isKey)
- return getObject();
- c = 0;
- break;
- case '[':
- if (!isKey)
- return getArray();
- c = 0;
- break;
- default:
- // standard syntax is assumed; not checking all possible invalid keys
- // for example, "-" is not allowed in JavaScript, which is what this is for
- returnChar();
- while (c >= ' ' && "[,]{:}'\"".indexOf(c) < 0)
- c = next();
- returnChar();
- if (isKey && c != ':')
- c = 0;
- break;
- }
- if (isKey && c == 0)
- throw new JSONException("invalid key");
-
- String string = str.substring(i, index).trim();
-
- // check for the only valid simple words: true, false, null (lower case)
- // and in this case, only for
-
- if (!isKey) {
- if (string.equals("true")) {
- return Boolean.TRUE;
- }
- if (string.equals("false")) {
- return Boolean.FALSE;
- }
- if (string.equals("null")) {
- return (asHashTable ? string : null);
- }
- }
- // only numbers from here on:
- c = string.charAt(0);
- if (c >= '0' && c <= '9' || c == '-')
- try {
- if (string.indexOf('.') < 0 && string.indexOf('e') < 0
- && string.indexOf('E') < 0)
- return new Integer(string);
- // not allowing infinity or NaN
- // using float here because Jmol does not use Double
- Float d = Float.valueOf(string);
- if (!d.isInfinite() && !d.isNaN())
- return d;
- } catch (Exception e) {
- }
- // not a valid number
- System.out.println("JSON parser cannot parse " + string);
- throw new JSONException("invalid value");
- }
-
- private String getString(char quote) throws JSONException {
- char c;
- SB sb = null;
- int i0 = index;
- for (;;) {
- int i1 = index;
- switch (c = next()) {
- case '\0':
- case '\n':
- case '\r':
- throw syntaxError("Unterminated string");
- case '\\':
- switch (c = next()) {
- case '"':
- case '\'':
- case '\\':
- case '/':
- break;
- case 'b':
- c = '\b';
- break;
- case 't':
- c = '\t';
- break;
- case 'n':
- c = '\n';
- break;
- case 'f':
- c = '\f';
- break;
- case 'r':
- c = '\r';
- break;
- case 'u':
- int i = index;
- index += 4;
- try {
- c = (char) Integer.parseInt(str.substring(i, index), 16);
- } catch (Exception e) {
- throw syntaxError("Substring bounds error");
- }
- break;
- default:
- throw syntaxError("Illegal escape.");
- }
- break;
- default:
- if (c == quote)
- return (sb == null ? str.substring(i0, i1) : sb.toString());
- break;
- }
- if (index > i1 + 1) {
- if (sb == null) {
- sb = new SB();
- sb.append(str.substring(i0, i1));
- }
- }
- if (sb != null)
- sb.appendC(c);
- }
- }
-
- private Object getObject() {
- Map<String, Object> map = (asHashTable ? new Hashtable<String, Object>() : new HashMap<String, Object>());
- String key = null;
- switch (getChar()) {
- case '}':
- return map;
- case 0:
- throw new JSONException("invalid object");
- }
- returnChar();
- boolean isKey = false;
- for (;;) {
- if ((isKey = !isKey) == true)
- key = getValue(true).toString();
- else
- map.put(key, getValue(false));
- switch (getChar()) {
- case '}':
- return map;
- case ':':
- if (isKey)
- continue;
- isKey = true;
- //$FALL-THROUGH$
- case ',':
- if (!isKey)
- continue;
- //$FALL-THROUGH$
- default:
- throw syntaxError("Expected ',' or ':' or '}'");
- }
- }
- }
-
- private Object getArray() {
- Lst<Object> l = new Lst<Object>();
- switch (getChar()) {
- case ']':
- return l;
- case '\0':
- throw new JSONException("invalid array");
- }
- returnChar();
- boolean isNull = false;
- for (;;) {
- if (isNull) {
- l.addLast(null);
- isNull = false;
- } else {
- l.addLast(getValue(false));
- }
- switch (getChar()) {
- case ',':
- switch (getChar()) {
- case ']':
- // terminal ,
- return l;
- case ',':
- // empty value
- isNull = true;
- //$FALL-THROUGH$
- default:
- returnChar();
- }
- continue;
- case ']':
- return l;
- default:
- throw syntaxError("Expected ',' or ']'");
- }
- }
- }
-
- /**
- * Make a JSONException to signal a syntax error.
- *
- * @param message
- * The error message.
- * @return A JSONException object, suitable for throwing
- */
- public JSONException syntaxError(String message) {
- return new JSONException(message + " for " + str.substring(0, Math.min(index, len)));
- }
-
-}