altos/telefireone-v2.0: Remove build of ao_product.h from Makefile
[fw/altos] / altoslib / AltosJson.java
index 80d83e48c94c89cb9621d327a04b56dcff543910..b981c36513939a7de503de3ce111473bf2b13a4e 100644 (file)
@@ -3,7 +3,8 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -15,7 +16,7 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
-package org.altusmetrum.altoslib_11;
+package org.altusmetrum.altoslib_13;
 
 import java.io.*;
 import java.util.*;
@@ -24,62 +25,66 @@ import java.lang.*;
 import java.lang.reflect.*;
 
 class JsonUtil {
-       StringBuffer quote(StringBuffer result, String a) {
-               result.append("\"");
+       Writer quote(Writer writer, String a) throws IOException {
+               writer.append("\"");
                for (int i = 0; i < a.length(); i++) {
                        char c = a.charAt(i);
 
                        switch (c) {
                        case '"':
                        case '\\':
-                               result.append('\\').append(c);
+                               writer.append('\\').append(c);
                                break;
                        case '\n':
-                               result.append("\\n");
+                               writer.append("\\n");
                                break;
                        default:
-                               result.append(c);
+                               writer.append(c);
                                break;
                        }
                }
-               result.append("\"");
-               return result;
+               writer.append("\"");
+               return writer;
        }
 
-       StringBuffer append(StringBuffer result, AltosJson value, int indent, boolean pretty) {
+       Writer append(Writer result, AltosJson value, int indent, boolean pretty) throws IOException {
                value.append(result, indent, pretty);
                return result;
        }
 
-       StringBuffer append(StringBuffer result, String string) {
+       Writer append(Writer result, String string) throws IOException {
                result.append(string);
                return result;
        }
 
-       StringBuffer indent(StringBuffer result, int indent) {
+       Writer indent(Writer result, int indent) throws IOException {
                result.append("\n");
                for (int i = 0; i < indent; i++)
                        result.append("\t");
                return result;
        }
-       static NumberFormat get_nf_json() {
-               DecimalFormat nf = (DecimalFormat) NumberFormat.getNumberInstance(Locale.ROOT);
-               nf.setParseIntegerOnly(false);
-               nf.setGroupingUsed(false);
-               nf.setMaximumFractionDigits(17);
-               nf.setMinimumFractionDigits(0);
-               nf.setMinimumIntegerDigits(1);
-               nf.setDecimalSeparatorAlwaysShown(false);
-               return nf;
-       }
 
-       static NumberFormat nf_json = get_nf_json();
+       NumberFormat _nf_json;
+
+       NumberFormat nf_json() {
+               if (_nf_json == null) {
+                       DecimalFormat nf = (DecimalFormat) NumberFormat.getNumberInstance(Locale.ROOT);
+                       nf.setParseIntegerOnly(false);
+                       nf.setGroupingUsed(false);
+                       nf.setMaximumFractionDigits(17);
+                       nf.setMinimumFractionDigits(0);
+                       nf.setMinimumIntegerDigits(1);
+                       nf.setDecimalSeparatorAlwaysShown(false);
+                       _nf_json = nf;
+               }
+               return _nf_json;
+       }
 }
 
 class JsonHash extends JsonUtil {
        Hashtable<String,AltosJson> hash;
 
-       void append_hash(StringBuffer result, int indent, boolean pretty) {
+       void append_hash(Writer result, int indent, boolean pretty) throws IOException {
                boolean         first = true;
 
                result.append("{");
@@ -124,7 +129,7 @@ class JsonHash extends JsonUtil {
 class JsonArray extends JsonUtil {
        ArrayList<AltosJson> array;
 
-       void append_array(StringBuffer result, int indent, boolean pretty) {
+       void append_array(Writer result, int indent, boolean pretty) throws IOException {
                boolean first = true;
 
                append(result, "[");
@@ -184,6 +189,7 @@ class JsonToken {
        static final int _colon = 9;
        static final int _end = 10;
        static final int _error = 11;
+       static final int _none = 12;
 
        static String token_name(int token) {
                switch (token) {
@@ -244,7 +250,7 @@ class JsonToken {
                this.sval = sval;
        }
 
-       JsonToken(int token, StringBuffer bval) {
+       JsonToken(int token, Writer bval) {
                this(token, bval.toString());
        }
 }
@@ -253,11 +259,11 @@ class JsonToken {
  * Lexer for json
  */
 class JsonLexer extends JsonUtil {
-       StringReader    f;
-       int             line;
-       int             ungot = -2;
-       StringBuffer    pending_token;
-       JsonToken       token;
+       InputStream             f;
+       int                     line;
+       int                     ungot = -2;
+       StringBuffer            pending_token;
+       private JsonToken       token;
 
        static class keyword {
                String          word;
@@ -370,7 +376,7 @@ class JsonLexer extends JsonUtil {
                                        String dstr = dbuf.toString();
                                        double dval;
                                        try {
-                                               dval = nf_json.parse(dstr).doubleValue();
+                                               dval = nf_json().parse(dstr).doubleValue();
                                        } catch (ParseException pe) {
                                                return new JsonToken(JsonToken._error, dstr);
                                        }
@@ -381,7 +387,7 @@ class JsonLexer extends JsonUtil {
                                                return new JsonToken(JsonToken._long, lval);
                                        }
                                case '"':
-                                       StringBuffer bval = new StringBuffer();
+                                       Writer bval = new StringWriter();
                                        for (;;) {
                                                c = ch();
                                                if (c == '"')
@@ -399,7 +405,7 @@ class JsonLexer extends JsonUtil {
                                                                break;
                                                        }
                                                }
-                                               bval.appendCodePoint(c);
+                                               bval.write(c);
                                        }
                                        return new JsonToken(JsonToken._string, bval);
                                default:
@@ -423,11 +429,17 @@ class JsonLexer extends JsonUtil {
        }
 
        void next() {
-               token = lex();
+               token = null;
+       }
+
+       JsonToken token() {
+               if (token == null)
+                       token = lex();
+               return token;
        }
 
        JsonToken expect(int e) {
-               JsonToken t = token;
+               JsonToken t = token();
                if (t.token != e)
                        throw new IllegalArgumentException(String.format("got \"%s\" while expecting \"%s\"",
                                                                         token.token_name(),
@@ -437,7 +449,13 @@ class JsonLexer extends JsonUtil {
        }
 
        JsonLexer(String s) {
-               f = new StringReader(s);
+               f = new AltosStringInputStream(s);
+               line = 1;
+               token = null;
+       }
+
+       JsonLexer(InputStream f) {
+               this.f = f;
                line = 1;
                token = null;
        }
@@ -463,7 +481,7 @@ class JsonParse {
                lexer.next();
                for (;;) {
                        /* Allow for empty hashes */
-                       if (lexer.token.token == JsonToken._cc) {
+                       if (lexer.token().token == JsonToken._cc) {
                                lexer.next();
                                return hash;
                        }
@@ -474,7 +492,7 @@ class JsonParse {
                        AltosJson value = value();
                        hash.put(key, value);
 
-                       switch (lexer.token.token) {
+                       switch (lexer.token().token) {
                        case JsonToken._comma:
                                lexer.next();
                                break;
@@ -482,7 +500,7 @@ class JsonParse {
                                lexer.next();
                                return hash;
                        default:
-                               parse_error("got %s expect \",\" or \"}\"", lexer.token.token_name());
+                               parse_error("got %s expect \",\" or \"}\"", lexer.token().token_name());
                                return null;
                        }
                }
@@ -495,14 +513,14 @@ class JsonParse {
                lexer.next();
                for (int i = 0;; i++) {
                        /* Allow for empty arrays */
-                       if (lexer.token.token == JsonToken._cs) {
+                       if (lexer.token().token == JsonToken._cs) {
                                lexer.next();
                                return array;
                        }
 
                        AltosJson value = value();
                        array.put(i, value);
-                       switch (lexer.token.token) {
+                       switch (lexer.token().token) {
                        case JsonToken._comma:
                                lexer.next();
                                break;
@@ -510,7 +528,7 @@ class JsonParse {
                                lexer.next();
                                return array;
                        default:
-                               parse_error("got %s expect \",\" or \"]\"", lexer.token.token_name());
+                               parse_error("got %s expect \",\" or \"]\"", lexer.token().token_name());
                                return null;
                        }
                }
@@ -520,29 +538,29 @@ class JsonParse {
         * identify the next object in the input
         */
        AltosJson value() {
-               switch (lexer.token.token) {
+               switch (lexer.token().token) {
                case JsonToken._oc:
                        return new AltosJson(hash());
                case JsonToken._os:
                        return new AltosJson(array());
                case JsonToken._double:
-                       double dval = lexer.token.dval;
+                       double dval = lexer.token().dval;
                        lexer.next();
                        return new AltosJson(dval);
                case JsonToken._long:
-                       long lval = lexer.token.lval;
+                       long lval = lexer.token().lval;
                        lexer.next();
                        return new AltosJson(lval);
                case JsonToken._string:
-                       String sval = lexer.token.sval;
+                       String sval = lexer.token().sval;
                        lexer.next();
                        return new AltosJson(sval);
                case JsonToken._boolean:
-                       boolean bval = lexer.token.bval;
+                       boolean bval = lexer.token().bval;
                        lexer.next();
                        return new AltosJson(bval);
                default:
-                       parse_error("Unexpected token \"%s\"", lexer.token.token_name());
+                       parse_error("Unexpected token \"%s\"", lexer.token().token_name());
                }
                return null;
        }
@@ -555,6 +573,10 @@ class JsonParse {
        JsonParse(String s) {
                lexer = new JsonLexer(s);
        }
+
+       JsonParse(InputStream f) {
+               lexer = new JsonLexer(f);
+       }
 }
 
 public class AltosJson extends JsonUtil {
@@ -577,7 +599,7 @@ public class AltosJson extends JsonUtil {
 
        /* Generate string representation of the value
         */
-       StringBuffer append(StringBuffer result, int indent, boolean pretty) {
+       Writer append(Writer result, int indent, boolean pretty) throws IOException {
                switch (type) {
                case type_hash:
                        hash.append_hash(result, indent, pretty);
@@ -594,7 +616,7 @@ public class AltosJson extends JsonUtil {
                        } else if (Double.isNaN(d_number)) {
                                result.append("NaN");
                        } else {
-                               String dval = nf_json.format(d_number);
+                               String dval = nf_json().format(d_number);
                                if (dval.equals("-0"))
                                        dval = "0";
                                result.append(dval);
@@ -614,9 +636,13 @@ public class AltosJson extends JsonUtil {
        }
 
        private String toString(int indent, boolean pretty) {
-               StringBuffer result = new StringBuffer();
-               append(result, indent, pretty);
-               return result.toString();
+               try {
+                       Writer result = new StringWriter();
+                       append(result, indent, pretty);
+                       return result.toString();
+               } catch (Exception e) {
+                       return null;
+               }
        }
 
        public String toString() {
@@ -627,6 +653,14 @@ public class AltosJson extends JsonUtil {
                return toString(0, true);
        }
 
+       public void write(Writer w, int indent, boolean pretty) throws IOException {
+               append(w, indent, pretty);
+       }
+
+       public void write(Writer w) throws IOException {
+               write(w, 0, true);
+       }
+
        /* Parse string representation to a value
         */
 
@@ -640,6 +674,16 @@ public class AltosJson extends JsonUtil {
                }
        }
 
+       public static AltosJson fromInputStream(InputStream f) {
+               JsonParse       parse = new JsonParse(f);
+               try {
+                       return parse.parse();
+               } catch (IllegalArgumentException ie) {
+                       System.out.printf("json:\n%s\n", ie.getMessage());
+                       return null;
+               }
+       }
+
        /* Accessor functions
         */
        private boolean assert_type(boolean setting, int type, int other_type, String error) {
@@ -1063,7 +1107,7 @@ public class AltosJson extends JsonUtil {
                                } else {
                                        object = c.newInstance();
                                }
-                               for (; c != null; c = c.getSuperclass()) {
+                               for (; c != Object.class; c = c.getSuperclass()) {
                                        for (Field field : c.getDeclaredFields()) {
                                                String  fieldName = field.getName();
                                                Class   fieldClass = field.getType();
@@ -1080,17 +1124,27 @@ public class AltosJson extends JsonUtil {
                                                                field.set(object, val);
                                                        }
                                                } catch (IllegalAccessException ie) {
+                                                       System.out.printf("%s:%s %s\n",
+                                                                         c.getName(), fieldName, ie.toString());
                                                }
                                        }
                                }
                                ret = object;
                        } catch (InvocationTargetException ie) {
+                               System.out.printf("%s: %s\n",
+                                                 c.getName(), ie.toString());
                                ret = null;
                        } catch (NoSuchMethodException ie) {
+                               System.out.printf("%s: %s\n",
+                                                 c.getName(), ie.toString());
                                ret = null;
                        } catch (InstantiationException ie) {
+                               System.out.printf("%s: %s\n",
+                                                 c.getName(), ie.toString());
                                ret = null;
                        } catch (IllegalAccessException ie) {
+                               System.out.printf("%s: %s\n",
+                                                 c.getName(), ie.toString());
                                ret = null;
                        }
                }
@@ -1198,10 +1252,14 @@ public class AltosJson extends JsonUtil {
                        }
                } else {
                        assert_hash(true);
-                       for (Class c = object.getClass(); c != null; c = c.getSuperclass()) {
+                       for (Class c = object.getClass(); c != Object.class; c = c.getSuperclass()) {
                                for (Field field : c.getDeclaredFields()) {
                                        String  fieldName = field.getName();
 
+                                       /* XXX hack to allow fields to be not converted */
+                                       if (fieldName.startsWith("__"))
+                                               continue;
+
                                        /* Skip static fields */
                                        if (Modifier.isStatic(field.getModifiers()))
                                                continue;
@@ -1223,6 +1281,8 @@ public class AltosJson extends JsonUtil {
                                                        put(fieldName, json);
                                                }
                                        } catch (IllegalAccessException ie) {
+                                               System.out.printf("%s:%s %s\n",
+                                                                 c.getName(), fieldName, ie.toString());
                                        }
                                }
                        }