X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=unused%2Fjavajs%2Futil%2FJSJSONParser.java;fp=unused%2Fjavajs%2Futil%2FJSJSONParser.java;h=552270d51942cee4201c87a00040d702141aaf8c;hb=4f30214e8098748469c6a4269ac2ed6c5750e4b0;hp=0000000000000000000000000000000000000000;hpb=9dabc02511e3a334a5749a504f57f69d6c9017bd;p=jalview.git diff --git a/unused/javajs/util/JSJSONParser.java b/unused/javajs/util/JSJSONParser.java new file mode 100644 index 0000000..552270d --- /dev/null +++ b/unused/javajs/util/JSJSONParser.java @@ -0,0 +1,325 @@ +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 parseMap(String str, boolean asHashTable) { + index = 0; + this.asHashTable = asHashTable; + this.str = str; + len = str.length(); + if (getChar() != '{') + return null; + returnChar(); + return (Map) getValue(false); + } + + /** + * Could return Integer, Float, Boolean, String, Map, Lst, 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 map = (asHashTable ? new Hashtable() : new HashMap()); + 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 l = new Lst(); + 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))); + } + +}