You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2013/01/22 02:57:59 UTC

[21/52] [partial] support for 2.4.0rc1. "vendored" the platform libs in. added Gord and Braden as contributors. removed dependency on unzip and axed the old download-cordova code.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/JSONObject.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/JSONObject.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/JSONObject.java
new file mode 100644
index 0000000..28c6216
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/JSONObject.java
@@ -0,0 +1,1367 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.cordova.json4j.internal.JSON4JStringReader;
+import org.apache.cordova.json4j.internal.JSON4JStringWriter;
+import org.apache.cordova.json4j.internal.NumberUtil;
+import org.apache.cordova.json4j.internal.Parser;
+import org.apache.cordova.json4j.internal.Serializer;
+import org.apache.cordova.json4j.internal.SerializerVerbose;
+
+/**
+ * Models a JSON Object.
+ *
+ * Extension of Hashtable that only allows String keys, and values which are JSON-able (such as a Java Bean).
+ * <BR><BR>
+ * JSON-able values are: null, and instances of String, Boolean, Number, JSONObject and JSONArray.
+ * <BR><BR>
+ * Instances of this class are not thread-safe.
+ */
+public class JSONObject extends Hashtable implements JSONArtifact {
+
+    private static final long serialVersionUID = -3269263069889337298L;
+
+    /**
+     * A constant definition reference to Java null.
+     * Provided for API compatibility with other JSON parsers.
+     */
+    public static final Object NULL = new Null();
+
+    /**
+     * Return whether the object is a valid value for a property.
+     * @param object The object to check for validity as a JSON property value.
+     * @return boolean indicating if the provided object is directly convertable to JSON.
+     */
+    public static boolean isValidObject(Object object) {
+        if (null == object) return true;
+        return isValidType(object.getClass());
+    }
+
+    /**
+     * Return whether the class is a valid type of value for a property.
+     * @param clazz The class type to check for validity as a JSON object type.
+     * @return boolean indicating if the provided class is directly convertable to JSON.
+     */
+    public static boolean isValidType(Class clazz) {
+        if (null == clazz) throw new IllegalArgumentException();
+
+        if (String.class  == clazz) return true;
+        if (Boolean.class == clazz) return true;
+        if (JSONObject.class.isAssignableFrom(clazz)) return true;
+        if (JSONArray.class == clazz) return true;
+        if (NumberUtil.isNumber(clazz)) return true;
+        if (JSONObject.NULL == clazz) return true;
+        if (JSONString.class.isAssignableFrom(clazz)) return true;
+
+        return false;
+    }
+
+    /**
+     * Create a new instance of this class.
+     */
+    public JSONObject() {
+        super();
+    }
+
+    /**
+     * Create a new instance of this class taking selected values from the underlying one.
+     * @param obj The JSONObject to extract values from.
+     * @param keys The keys to take from the JSONObject and apply to this instance.
+     * @throws JSONException Thrown if a key is duplicated in the string[] keys
+     */
+    public JSONObject(JSONObject obj, String[] keys) throws JSONException{
+        super();
+        if (keys != null && keys.length > 0) {
+            for (int i = 0; i < keys.length; i++) {
+                if (this.containsKey(keys[i])) {
+                    throw new JSONException("Duplicate key: " + keys[i]);
+                }
+                try {
+                    this.put(keys[i], obj.get(keys[i]));
+                } catch (Exception ex) {
+                    JSONException jex = new JSONException("Error occurred during JSONObject creation");
+                    jex.setCause(ex);
+                    throw jex;
+                }
+            }
+        }
+    }
+
+    /**
+     * Create a new instance of this class from the provided JSON object string.
+     * Note:  This is the same as new JSONObject(str, false);  Parsing in non-strict mode.
+     * @param str The JSON string to parse.
+     * @throws JSONException Thrown when the string passed is null, or malformed JSON..
+     */
+    public JSONObject(String str) throws JSONException {
+        super();
+        JSON4JStringReader reader = new JSON4JStringReader(str);
+        (new Parser(reader)).parse(this);
+    }
+
+    /**
+     * Create a new instance of this class from the provided JSON object string.
+     * @param str The JSON string to parse.
+     * @param strict Whether or not to parse in 'strict' mode, meaning all strings must be quoted (including identifiers), and comments are not allowed.
+     * @throws JSONException Thrown when the string passed is null, or malformed JSON..
+     */
+    public JSONObject(String str, boolean strict) throws JSONException {
+        super();
+        JSON4JStringReader reader = new JSON4JStringReader(str);
+        (new Parser(reader, strict)).parse(this);
+    }
+
+    /**
+     * Create a new instance of this class from the data provided from the reader.  The reader content must be a JSON object string.
+     * Note:  The reader will not be closed, that is left to the caller.
+     * Note:  This is the same as new JSONObject(rdr, false);  Parsing in non-strict mode.
+     * @throws JSONException Thrown when the string passed is null, or malformed JSON..
+     */
+    public JSONObject(Reader rdr) throws JSONException {
+        (new Parser(rdr)).parse(this);
+    }
+
+    /**
+     * Create a new instance of this class from the data provided from the reader.  The reader content must be a JSON object string.
+     * Note:  The reader will not be closed, that is left to the caller.
+     * @param rdr The reader from which to read the JSON.
+     * @param strict Whether or not to parse in 'strict' mode, meaning all strings must be quoted (including identifiers), and comments are not allowed.
+     * @throws JSONException Thrown when the string passed is null, or malformed JSON..
+     */
+    public JSONObject(Reader rdr, boolean strict) throws JSONException {
+        (new Parser(rdr, strict)).parse(this);
+    }
+
+    /**
+     * Create a new instance of this class from the data provided from the input stream.  The stream content must be a JSON object string.
+     * Note:  The input stream content is assumed to be UTF-8 encoded.
+     * Note:  The InputStream will not be closed, that is left to the caller.
+     * Note:  This is the same as new JSONObject(is, false);  Parsing in non-strict mode.
+     * @param is The InputStream from which to read the JSON.
+     * @throws JSONException Thrown when the string passed is null, or malformed JSON..
+     */
+    public JSONObject (InputStream is) throws JSONException {
+        InputStreamReader isr = null;
+        if (is != null) {
+            try {
+                isr = new InputStreamReader(is, "UTF-8");
+            } catch (Exception ex) {
+                isr = new InputStreamReader(is);
+            }
+        } else {
+            throw new JSONException("InputStream cannot be null");
+        }
+        (new Parser(isr)).parse(true, this);
+    }
+
+    /**
+     * Create a new instance of this class from the data provided from the input stream.  The stream content must be a JSON object string.
+     * Note:  The input stream content is assumed to be UTF-8 encoded.
+     * Note:  The InputStream will not be closed, that is left to the caller.
+     * @param is The InputStream from which to read the JSON.
+     * @param strict Whether or not to parse in 'strict' mode, meaning all strings must be quoted (including identifiers), and comments are not allowed.
+     * @throws JSONException Thrown when the string passed is null, or malformed JSON..
+     */
+    public JSONObject (InputStream is, boolean strict) throws JSONException {
+        InputStreamReader isr = null;
+        if (is != null) {
+            try {
+                isr = new InputStreamReader(is, "UTF-8");
+            } catch (Exception ex) {
+                isr = new InputStreamReader(is);
+            }
+        } else {
+            throw new JSONException("InputStream cannot be null");
+        }
+        (new Parser(isr, strict)).parse(true, this);
+    }
+
+    /**
+     * Write this object to the stream as JSON text in UTF-8 encoding.  Same as calling write(os,false);
+     * Note that encoding is always written as UTF-8, as per JSON spec.
+     * @param os The output stream to write data to.
+     *
+     * @throws JSONException Thrown on IO errors during serialization.
+     */
+    public OutputStream write(OutputStream os) throws JSONException {
+        write(os,false);
+        return os;
+    }
+
+    /**
+     * Convert this object into a stream of JSON text.  Same as calling write(writer,false);
+     * Note that encoding is always written as UTF-8, as per JSON spec.
+     * @param os The output stream to write data to.
+     * @param verbose Whether or not to write the JSON text in a verbose format.
+     *
+     * @throws JSONException Thrown on IO errors during serialization.
+     */
+    public OutputStream write(OutputStream os, boolean verbose) throws JSONException {
+        Writer writer = null;
+        try {
+            //MSN BUFFERED
+            writer = new OutputStreamWriter(os, "UTF-8");
+        } catch (UnsupportedEncodingException uex) {
+            JSONException jex = new JSONException(uex.toString());
+            jex.setCause(uex);
+            throw jex;
+        }
+        write(writer, verbose);
+        try {
+            writer.flush();
+        } catch (Exception ex) {
+            JSONException jex = new JSONException("Error during buffer flush");
+            jex.setCause(ex);
+            throw jex;
+        }
+        return os;
+    }
+
+    /**
+     * Write this object to the stream as JSON text in UTF-8 encoding, specifying how many spaces should be used for each indent.
+     * @param indentDepth How many spaces to use for each indent level.  Should be one to eight.
+     * Less than one means no intending, greater than 8 and it will just use tab.
+     *
+     * @throws JSONException Thrown on IO errors during serialization.
+     */
+    public OutputStream write(OutputStream os, int indentDepth) throws JSONException {
+        Writer writer = null;
+        try {
+            //MSN BUFFERED
+            writer = new OutputStreamWriter(os, "UTF-8");
+        } catch (UnsupportedEncodingException uex) {
+            JSONException jex = new JSONException(uex.toString());
+            jex.setCause(uex);
+            throw jex;
+        }
+        write(writer, indentDepth);
+        try {
+            writer.flush();
+        } catch (Exception ex) {
+            JSONException jex = new JSONException("Error during buffer flush");
+            jex.setCause(ex);
+            throw jex;
+        }
+        return os;
+    }
+
+    /**
+     * Write this object to the writer as JSON text. Same as calling write(writer,false);
+     * @param writer The writer which to write the JSON text to.
+     *
+     * @throws JSONException Thrown on IO errors during serialization.
+     */
+    public Writer write(Writer writer) throws JSONException {
+        write(writer, false);
+        return writer;
+    }
+
+    /**
+     * Write this object to the writer as JSON text in UTF-8 encoding, specifying whether to use verbose (tab-indented) output or not.
+     * @param writer The writer which to write the JSON text to.
+     *
+     * @throws JSONException Thrown on IO errors during serialization.
+     */
+    public Writer write(Writer writer, boolean verbose) throws JSONException {
+        Serializer serializer;
+
+        //Try to avoid double-buffering or buffering in-memory
+        //writers.
+//        Class writerClass = writer.getClass();
+        boolean flushIt = false;
+//        if (!StringWriter.class.isAssignableFrom(writerClass) &&
+//            !CharArrayWriter.class.isAssignableFrom(writerClass) &&
+//            !BufferedWriter.class.isAssignableFrom(writerClass)) {
+//            writer = new BufferedWriter(writer);
+//            flushIt = true;
+//        }
+
+        if (verbose) {
+            serializer = new SerializerVerbose(writer);
+        } else {
+            serializer = new Serializer(writer);
+        }
+
+        try {
+            serializer.writeObject(this);
+        } catch (IOException iox) {
+            JSONException jex = new JSONException("Error occurred during input read.");
+            jex.setCause(iox);
+            throw jex;
+        }
+        if (flushIt) {
+            try {
+                writer.flush();
+            } catch (Exception ex) {
+                JSONException jex = new JSONException("Error during buffer flush");
+                jex.setCause(ex);
+                throw jex;
+            }
+        }
+        return writer;
+    }
+
+    /**
+     * Write this object to the writer as JSON text, specifying how many spaces should be used for each indent.
+     * This is an alternate indent style to using tabs.
+     * @param writer The writer which to write the JSON text to.
+     * @param indentDepth How many spaces to use for each indent.  The value should be between one to eight.
+     */
+    public Writer write(Writer writer, int indentDepth) throws JSONException {
+        Serializer serializer;
+
+        if (indentDepth < 1) {
+            indentDepth = 0;
+        } else if (indentDepth > 8) {
+            indentDepth = 9;
+        }
+
+        //Try to avoid double-buffering or buffering in-memory
+        //writers.
+//        Class writerClass = writer.getClass();
+        boolean flushIt = false;
+//        if (!StringWriter.class.isAssignableFrom(writerClass) &&
+//            !CharArrayWriter.class.isAssignableFrom(writerClass) &&
+//            !BufferedWriter.class.isAssignableFrom(writerClass)) {
+//            writer = new BufferedWriter(writer);
+//            flushIt = true;
+//        }
+
+        if (indentDepth > 0) {
+            serializer = new SerializerVerbose(writer, indentDepth);
+        } else {
+            serializer = new Serializer(writer);
+        }
+        try {
+            serializer.writeObject(this);
+        } catch (IOException iox) {
+            JSONException jex = new JSONException("Error occurred during input read.");
+            jex.setCause(iox);
+            throw jex;
+        }
+        if (flushIt) {
+            try {
+                writer.flush();
+            } catch (Exception ex) {
+                JSONException jex = new JSONException("Error during buffer flush");
+                jex.setCause(ex);
+                throw jex;
+            }
+        }
+        return writer;
+    }
+
+    /**
+     * Convert this object into a String of JSON text, specifying how many spaces should be used for each indent.
+     * This is an alternate indent style to using tabs.
+     * @param indentDepth How many spaces to use for each indent.  The value should be between one to eight.
+     * Less than one means no indenting, greater than 8 and it will just use tab.
+     *
+     * @throws JSONException Thrown on errors during serialization.
+     */
+    public String write(int indentDepth) throws JSONException {
+        Serializer serializer;
+        JSON4JStringWriter writer = new JSON4JStringWriter();
+
+        if (indentDepth < 1) {
+            indentDepth = 0;
+        } else if (indentDepth > 8) {
+            indentDepth = 9;
+        }
+
+        if (indentDepth > 0) {
+            serializer = new SerializerVerbose(writer, indentDepth);
+        } else {
+            serializer = new Serializer(writer);
+        }
+        try {
+            serializer.writeObject(this).flush();
+        } catch (IOException iox) {
+            JSONException jex = new JSONException("Error occurred during write.");
+            jex.setCause(iox);
+            throw jex;
+        }
+        return writer.toString();
+    }
+
+    /**
+     * Convert this object into a String of JSON text, specifying whether to use verbose (tab-indented) output or not.
+     * @param verbose Whether or not to write in compressed format.
+     *
+     * @throws JSONException Thrown on errors during serialization.
+     */
+    public String write(boolean verbose) throws JSONException {
+        Serializer serializer;
+        JSON4JStringWriter writer = new JSON4JStringWriter();
+
+        if (verbose) {
+            serializer = new SerializerVerbose(writer);
+        } else {
+            serializer = new Serializer(writer);
+        }
+        try {
+            serializer.writeObject(this).flush();
+        } catch (IOException iox) {
+            JSONException jex = new JSONException("Error occurred during write.");
+            jex.setCause(iox);
+            throw jex;
+        }
+        return writer.toString();
+    }
+
+    /**
+     * Convert this object into a String of JSON text.  Same as write(false);
+     *
+     * @throws JSONException Thrown on IO errors during serialization.
+     */
+    public String write() throws JSONException {
+        return write(false);
+    }
+
+    /**
+     * Method to obtain the object value for a key.
+     * This string-based method is provided for API compatibility to other JSON models.
+     * @param key The key  (attribute) name to obtain the value for.
+     * @throws JSONException Thrown if the noted key is not in the map of key/value pairs.
+     */
+    public Object get(String key) throws JSONException {
+        Object val = this.get((Object)key);
+        if (val == null) {
+            if (!this.containsKey(key)) {
+                throw new JSONException("The key [" + key + "] was not in the map");
+            }
+        }
+        return val;
+    }
+
+    /**
+     * Method to obtain the object value for a key.  If the key is not in the map, null is returned.
+     * This string-based method is provided for API compatibility to other JSON models.
+     * @param key The key  (attribute) name to obtain the value for.
+     */
+    public Object opt(String key) {
+        return this.get((Object)key);
+    }
+
+    /**
+     * (non-Javadoc)
+     * @see java.util.HashMap#put(java.lang.Object, java.lang.Object)
+     * @param key The key to put in the JSONObject
+     * @param value The value to put in the JSONObject
+     * @param includeSuperclass Boolean indicating that if the object is a JavaBean, include superclass getter properties.
+     * @throws JSONException.  Thrown if key is null, not a string, or the value could not be converted.
+     */
+    public Object put(Object key, Object value, boolean includeSuperclass) throws JSONException{
+        if (null == key) throw new JSONException("key must not be null");
+        if (!(key instanceof String)) throw new JSONException("key must be a String");
+        if (!isValidObject(value)) {
+            throw new JSONException("Invalid type of value.  Could not convert type: [" + value.getClass().getName() + "]");
+        }
+        if (null == value) {
+            value = NULL;
+        }
+        return super.put(key, value);
+    }
+
+    /**
+     * (non-Javadoc)
+     * @see java.util.HashMap#put(java.lang.Object, java.lang.Object)
+     * This is the same as calling put(key, value, true);
+     */
+    public Object put(Object key, Object value) {
+        try {
+            return put(key, value, true);
+        } catch (Exception e) {
+            IllegalArgumentException iae = new IllegalArgumentException("Error occurred during JSON conversion");
+           //MSN iae.setCause(e);
+            throw iae;
+        }
+    }
+
+    /**
+     * Convenience functions, to help map from other JSON parsers.
+     */
+
+    /**
+     * Similar to default HashMap put, except it returns JSONObject instead of Object.
+     * @see java.util.HashMap#put(java.lang.Object, java.lang.Object)
+     * @return A reference to this object instance.
+     * @throws JSONException.  Thrown if key is null, not a string, or the value could not be converted to JSON.
+     */
+    public JSONObject put(String key, Object value) throws JSONException{
+        this.put((Object)key, value);
+        return this;
+    }
+
+    /**
+     * Method to add an atomic boolean to the JSONObject.
+     * param key The key/attribute name to set the boolean at.
+     * @param value The boolean value.
+     * @throws JSONException.  Thrown if key is null or not a string.
+     * @return A reference to this object instance.
+     */
+    public JSONObject put(String key, boolean value) throws JSONException{
+        this.put(key,new Boolean(value));
+        return this;
+    }
+
+    /**
+     * Method to add an atomic double to the JSONObject.
+     * param key The key/attribute name to set the double at.
+     * @param value The double value.
+     * @throws JSONException.  Thrown if key is null or not a string.
+     * @return A reference to this object instance.
+     */
+    public JSONObject put(String key, double value) throws JSONException{
+        this.put(key, new Double(value));
+        return this;
+    }
+
+    /**
+     * Method to add an atomic integer to the JSONObject.
+     * param key The key/attribute name to set the integer at.
+     * @param value The integer value.
+     * @throws JSONException.  Thrown if key is null or not a string.
+     * @return A reference to this object instance.
+     */
+    public JSONObject put(String key, int value) throws JSONException{
+        this.put(key, new Integer(value));
+        return this;
+    }
+
+    /**
+     * Method to add an atomic short to the JSONObject.
+     * param key The key/attribute name to set the integer at.
+     * @param value The integer value.
+     * @throws JSONException.  Thrown if key is null or not a string.
+     * @return A reference to this object instance.
+     */
+    public JSONObject put(String key, short value) throws JSONException{
+        this.put(key, new Short(value));
+        return this;
+    }
+
+    /**
+     * Method to add an atomic long to the JSONObject.
+     * @param key The key/attribute name to set the long to.
+     * @param value The long value.
+     * @throws JSONException.  Thrown if key is null or not a string.
+     * @return A reference to this object instance.
+     */
+    public JSONObject put(String key, long value) throws JSONException{
+        this.put(key, new Long(value));
+        return this;
+    }
+
+    /**
+     * Method to add an Object array as a new JSONArray contained in this JSONObject
+     * @param key The key/attribute name to set the collection to.
+     * @param value The Object array to convert to a JSONArray and store.
+     * @throws JSONException Thrown when contents in the Collection cannot be converted to something JSONable.
+     * @return A reference to this object instance.
+     */
+     public JSONObject put(String key, Object[] value) throws JSONException {
+         return put (key, new JSONArray(value));
+     }
+
+     /**
+      * Method to add an Object array as a new JSONArray contained in this JSONObject
+      * @param key The key/attribute name to set the collection to.
+      * @param value The Object array to convert to a JSONArray and store.
+      * @param includeSuperclass For values of the Object array which are JavaBeans and are converted, include superclass getter properties.
+      * @throws JSONException Thrown when contents in the Collection cannot be converted to something JSONable.
+      * @return A reference to this object instance.
+      *
+      public JSONObject put(String key, Object[] value, boolean includeSuperclass) throws JSONException {
+          return put (key, new JSONArray(value), includeSuperclass);
+      } */
+
+    /**
+     * Utility method to obtain the specified key as a 'boolean' value
+     * Only boolean true, false, and the String true and false will return.  In this case null, the number 0, and empty string should be treated as false.
+     * everything else is true.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * throws JSONException Thrown when the type returned by get(key) is not a boolean instance, or the strings 'true' or 'false'.
+     * @return A boolean value (true or false), if the value stored for key is a Boolean, or the strings 'true' or 'false'.
+     */
+    public boolean getBoolean(String key) throws JSONException {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (val instanceof Boolean) {
+                return((Boolean)val).booleanValue();
+            } else if (NumberUtil.isNumber(val.getClass())) {
+                throw new JSONException("Value at key: [" + key + "] was not a boolean or string value of 'true' or 'false'.");
+            } else if (String.class.isAssignableFrom(val.getClass())) {
+                String str = (String)val;
+                if (str.equals("true")) {
+                    return true;
+                } else if (str.equals("false")) {
+                    return false;
+                } else {
+                    throw new JSONException("The value for key: [" + key + "]: [" + str + "] was not 'true' or 'false'");
+                }
+            } else {
+                throw new JSONException("The value for key: [" + key + "] was not a type that can be converted to boolean");
+            }
+        } else {
+            throw new JSONException("The value for key: [" + key + "] was null");
+        }
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'boolean' value
+     * Only returns true if the value is boolean true or the string 'true'.  All other values return false.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * @return A boolean value (true or false), if the value stored for key is a Boolean, or the strings 'true' or 'false'.
+     */
+    public boolean optBoolean(String key) {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (val instanceof Boolean) {
+                return((Boolean)val).booleanValue();
+            } else if (NumberUtil.isNumber(val.getClass())) {
+                return false;
+            } else if (String.class.isAssignableFrom(val.getClass())) {
+                String str = (String)val;
+                if (str.equals("true")) {
+                    return true;
+                } else {
+                    return false;
+                }
+            } else {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'boolean' value
+     * Only returns true if the value is boolean true or the string 'true'.  All other values return false.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * @param defaultValue The default value to return.
+     * @return A boolean value (true or false), if the value stored for key is a Boolean, or the strings 'true' or 'false'.
+     */
+    public boolean optBoolean(String key, boolean defaultValue) {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (val instanceof Boolean) {
+                return((Boolean)val).booleanValue();
+            } else if (NumberUtil.isNumber(val.getClass())) {
+                return false;
+            } else if (String.class.isAssignableFrom(val.getClass())) {
+                String str = (String)val;
+                if (str.equals("true")) {
+                    return true;
+                } else if (str.equals("false")) {
+                    return false;
+                } else {
+                    return defaultValue;
+                }
+            } else {
+                return defaultValue;
+            }
+        } else {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'double' value
+     * Only values of Number will be converted to double, all other types will generate an exception
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * throws JSONException Thrown when the type returned by get(key) is not a Double instance, or cannot be converted to a double.
+     * @return A double value if the value stored for key is an instance of Number.
+     */
+    public double getDouble(String key) throws JSONException {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (NumberUtil.isNumber(val.getClass())) {
+                return NumberUtil.getDouble(val);
+            }
+            else {
+                throw new JSONException("The value for key: [" + key + "] was not a type that can be converted to double");
+            }
+        } else {
+            throw new JSONException("The value for key: [" + key + "] was null.  Number required.");
+        }
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'double' value
+     * Only values of Number will be converted to double.  all other values will return Double.NaN.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * @return A double value if the value stored for key is an instance of Number.
+     */
+    public double optDouble(String key) {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (NumberUtil.isNumber(val.getClass())) {
+                return NumberUtil.getDouble(val);
+            }
+        }
+        return Double.NaN;
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'double' value
+     * Only values of Number will be converted to double.  all other values will return Double.NaN.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * @param defaultValue The default double value to return in case of NaN/null values in map.
+     * @return A double value if the value stored for key is an instance of Number.
+     */
+    public double optDouble(String key, double defaultValue) {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (NumberUtil.isNumber(val.getClass())) {
+                return NumberUtil.getDouble(val);
+            }
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'short' value
+     * Only values of Number will be converted to short, all other types will generate an exception.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * throws JSONException Thrown when the type returned by get(key) is not a Short instance, or cannot be converted to a short.
+     * @return A short value if the value stored for key is an instance of Number.
+     */
+    public short getShort(String key) throws JSONException {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (NumberUtil.isNumber(val.getClass())) {
+                return NumberUtil.getShort(val);
+            } else {
+                throw new JSONException("The value for key: [" + key + "] was not a type that can be converted to short");
+            }
+        } else {
+            throw new JSONException("The value for key: [" + key + "] was null.  Number required.");
+        }
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'short' value
+     * Only values of Number will be converted to short.  All other types return 0.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * @return A short value if the value stored for key is an instance of Number.  0 otherwise.
+     */
+    public short optShort(String key) {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (NumberUtil.isNumber(val.getClass())) {
+                return NumberUtil.getShort(val);
+            }
+        }
+        return(short)0;
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'short' value
+     * Only values of Number will be converted to short.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * @param defaultValue The default value to return in the case of null/nonNumber values in the map.
+     * @return A short value if the value stored for key is an instance of Number.  0 otherwise.
+     */
+    public short optShort(String key, short defaultValue) {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (NumberUtil.isNumber(val.getClass())) {
+                return NumberUtil.getShort(val);
+            }
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'int' value
+     * Only values of Number will be converted to integer, all other types will generate an exception.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * throws JSONException Thrown when the type returned by get(key) is not a Double instance, or cannot be converted to a double.
+     * @return A int value if the value stored for key is an instance of Number.
+     */
+    public int getInt(String key) throws JSONException {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (NumberUtil.isNumber(val.getClass())) {
+                return NumberUtil.getInt(val);
+            } else {
+                throw new JSONException("The value for key: [" + key + "] was not a type that can be converted to integer");
+            }
+        } else {
+            throw new JSONException("The value for key: [" + key + "] was null.  Number required.");
+        }
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'int' value
+     * Provided for compatibility to other JSON models.
+     * Only values of Number will be converted to integer, all other types will return 0.
+     * @param key The key to look up.
+     * @return A int value if the value stored for key is an instance of Number.  0 otherwise.
+     */
+    public int optInt(String key) {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (NumberUtil.isNumber(val.getClass())) {
+                return NumberUtil.getInt(val);
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'int' value
+     * Provided for compatibility to other JSON models.
+     * Only values of Number will be converted to integer
+     * @param key The key to look up.
+     * @param defaultValue The default int value to return in case of null/non-number values in the map.
+     * @return A int value if the value stored for key is an instance of Number.
+     */
+    public int optInt(String key, int defaultValue) {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (NumberUtil.isNumber(val.getClass())) {
+                return NumberUtil.getInt(val);
+            }
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'long' value
+     * Only values of Number will be converted to long, all other types will generate an exception.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * throws JSONException Thrown when the type returned by get(key) is not a Long instance, or cannot be converted to a long..
+     * @return A long value if the value stored for key is an instance of Number.
+     */
+    public long getLong(String key) throws JSONException {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (NumberUtil.isNumber(val.getClass())) {
+                return NumberUtil.getLong(val);
+            } else {
+                throw new JSONException("The value for key: [" + key + "] was not a type that can be converted to long");
+            }
+        } else {
+            throw new JSONException("The value for key: [" + key + "] was null.  Number required.");
+        }
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'long' value
+     * Only values of Number will be converted to long.  all other types return 0.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * @return A long value if the value stored for key is an instance of Number, 0 otherwise.
+     */
+    public long optLong(String key) throws JSONException {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (NumberUtil.isNumber(val.getClass())) {
+                return NumberUtil.getLong(val);
+            }
+        }
+        return(long)0;
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'long' value
+     * Only values of Number will be converted to long.  all other types return 0.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * @param defaultValue The default long value to return in case of null/non Number values in the map.
+     * @return A long value if the value stored for key is an instance of Number, defaultValue otherwise.
+     */
+    public long optLong(String key, long defaultValue) throws JSONException {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (NumberUtil.isNumber(val.getClass())) {
+                return NumberUtil.getLong(val);
+            }
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'string' value
+     * Only values that can be easily converted to string will be returned.  A null will generate an exception.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * throws JSONException Thrown when the type returned by get(key) is null.
+     * @return A string value if the value if the value stored for key is not null.
+     */
+    public String getString(String key) throws JSONException {
+        Object val = this.opt(key);
+        if (val != null) {
+            return val.toString();
+        } else {
+            throw new JSONException("The value for key: [" + key + "] was null.  Object required.");
+        }
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'string' value
+     * Only values that can be easily converted to string will be returned.  A null will generate an exception.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * throws JSONException Thrown when the type returned by get(key) is null.
+     * @return A string value if the value if the value stored for key is not null.
+     */
+    public String optString(String key) {
+        Object val = this.opt(key);
+        if (val != null) {
+            return val.toString();
+        }
+        return null;
+    }
+
+    /**
+     * Utility method to obtain the specified key as a 'string' value
+     * Only values that can be easily converted to string will be returned.  A null will generate an exception.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * @param defaultValue The default String value to return in the case of null values in the map.
+     * @return A string value if the value if the value stored for key is not null, defaultValue otherwise.
+     */
+    public String optString(String key, String defaultValue) {
+        Object val = this.opt(key);
+        if (val != null) {
+            return val.toString();
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Utility method to obtain the specified key as a JSONObject
+     * Only values that are instances of JSONObject will be returned.  A null will generate an exception.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * throws JSONException Thrown when the type returned by get(key) is not a JSONObject instance.
+     * @return A JSONObject value if the value stored for key is an instance or subclass of JSONObject.
+     */
+    public JSONObject getJSONObject(String key) throws JSONException {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (JSONObject.class.isAssignableFrom(val.getClass())) {
+                return(JSONObject)val;
+            } else {
+                throw new JSONException("The value for key: [" + key + "] was not a JSONObject");
+            }
+        } else {
+            throw new JSONException("The value for key: [" + key + "] was null.  Object required.");
+        }
+    }
+
+    /**
+     * Utility method to obtain the specified key as a JSONObject
+     * Only values that are instances of JSONObject will be returned.  A null will generate an exception.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * @return A JSONObject value if the value stored for key is an instance or subclass of JSONObject, null otherwise.
+     */
+    public JSONObject optJSONObject(String key) {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (JSONObject.class.isAssignableFrom(val.getClass())) {
+                return(JSONObject)val;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Utility method to obtain the specified key as a JSONObject
+     * Only values that are instances of JSONObject will be returned.  A null will generate an exception.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * @param defaultValue The default JSONObject to return in the case of null/non JSONObject values in the map.
+     * @return A JSONObject value if the value stored for key is an instance or subclass of JSONObject, defaultValue otherwise.
+     */
+    public JSONObject optJSONObject(String key, JSONObject defaultValue) {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (JSONObject.class.isAssignableFrom(val.getClass())) {
+                return(JSONObject)val;
+            }
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Utility method to obtain the specified key as a JSONArray
+     * Only values that are instances of JSONArray will be returned.  A null will generate an exception.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * throws JSONException Thrown when the type returned by get(key) is not a Long instance, or cannot be converted to a long..
+     * @return A JSONArray value if the value stored for key is an instance or subclass of JSONArray.
+     */
+    public JSONArray getJSONArray(String key) throws JSONException {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (JSONArray.class.isAssignableFrom(val.getClass())) {
+                return(JSONArray)val;
+            } else {
+                throw new JSONException("The value for key: [" + key + "] was not a JSONObject");
+            }
+        } else {
+            throw new JSONException("The value for key: [" + key + "] was null.  Object required.");
+        }
+    }
+
+    /**
+     * Utility method to obtain the specified key as a JSONArray
+     * Only values that are instances of JSONArray will be returned.  A null will generate an exception.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * @return A JSONArray value if the value stored for key is an instance or subclass of JSONArray, null otherwise.
+     */
+    public JSONArray optJSONArray(String key) throws JSONException {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (JSONArray.class.isAssignableFrom(val.getClass())) {
+                return(JSONArray)val;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Utility method to obtain the specified key as a JSONArray
+     * Only values that are instances of JSONArray will be returned.  A null will generate an exception.
+     * Provided for compatibility to other JSON models.
+     * @param key The key to look up.
+     * @param defaultValue The default value to return if the value in the map is null/not a JSONArray.
+     * @return A JSONArray value if the value stored for key is an instance or subclass of JSONArray, defaultValue otherwise.
+     */
+    public JSONArray optJSONArray(String key, JSONArray defaultValue) throws JSONException {
+        Object val = this.opt(key);
+        if (val != null) {
+            if (JSONArray.class.isAssignableFrom(val.getClass())) {
+                return(JSONArray)val;
+            }
+        }
+        return defaultValue;
+    }
+
+    /**
+     * Put a key/value pair into the JSONObject, but only if key/value are both not null, and only if the key is not present already.
+     * Provided for compatibility to existing models.
+     * @param key The ket to place in the array
+     * @param value The value to place in the array
+     * @return Reference to the current JSONObject.
+     * @throws JSONException - Thrown if the key already exists or if key or value is null
+     */
+    public JSONObject putOnce(String key, Object value) throws JSONException {
+        if (key == null) {
+            throw new JSONException("Key cannot be null");
+        }
+        if (value == null) {
+            throw new JSONException("Value cannot be null");
+        }
+        if (this.containsKey(key)) {
+            throw new JSONException("Key [" + key + "] already exists in the map");
+        }
+        this.put(key,value);
+        return this;
+    }
+
+    /**
+     * Put a key/value pair into the JSONObject, but only if the key and value are non-null.
+     * @param key The keey (attribute) name to assign to the value.
+     * @param value The value to put into the JSONObject.
+     * @return Reference to the current JSONObject.
+     * @throws JSONException - if the value is a non-finite number
+     */
+    public JSONObject putOpt(String key, Object value) throws JSONException {
+        if (key == null) {
+            throw new JSONException("Key cannot be null");
+        }
+        if (value == null) {
+            throw new JSONException("Value cannot be null");
+        }
+        this.put(key,value);
+        return this;
+    }
+
+    /**
+     * Method to return the number of keys in this JSONObject.
+     * This function merely maps to HashMap.size().  Provided for API compatibility.
+     * @return returns the number of keys in the JSONObject.
+     */
+    public int length() {
+        return this.size();
+    }
+
+    /**
+     * Method to append the 'value' object to the element at entry 'key'.
+     * If JSONObject.has(key) returns false, a new array is created and the value is appended to it.
+     * If the object as position key is not an array, then a new JSONArray is created
+     * and both current and new values are appended to it, then the value of the attribute is set to the new
+     * array.  If the current value is already an array, then 'value' is added to it.
+     *
+     * @param key The key/attribute name to append to.
+     * @param value The value to append to it.
+     *
+     * @throws JSONException Thrown if the value to append is not JSONAble.
+     * @return A reference to this object instance.
+     */
+    public JSONObject append(String key, Object value) throws JSONException {
+        JSONArray array = null;
+        if (!this.has(key)) {
+            array = new JSONArray();
+        }
+        else {
+            Object oldVal = this.get(key);
+            array = new JSONArray();
+            if (oldVal == null) {
+                // Add a null if the key was actually there, but just
+                // had value of null.
+                array.add(null);
+            }
+            else  if (JSONArray.class.isAssignableFrom(oldVal.getClass())) {
+                array = (JSONArray)oldVal;
+            } else {
+                array = new JSONArray();
+                array.add(oldVal);
+            }
+        }
+        array.add(value);
+        return put(key,array);
+    }
+
+    /**
+     * Produce a JSONArray containing the values of the members of this JSONObject
+     * @param names - A JSONArray containing the a list of key strings.  This determines the sequence of values in the result.
+     * @return A JSONArray of the values found for the names provided.
+     * @throws JSONException - if errors occur during storing the values in a JSONArray
+     */
+    public JSONArray toJSONArray(JSONArray names) throws JSONException {
+        Enumeration itr = names.elements();
+        JSONArray array = new JSONArray();
+        //MSN WAS IF, SHOULD BE WHILE?
+        while (itr != null && itr.hasMoreElements()) {
+            array.put(this.get(itr.nextElement()));
+        }
+        return array;
+    }
+
+
+    /**
+     * Method to test if a key exists in the JSONObject.
+     * @param key The key to test.
+     * @return true if the key is defined in the JSONObject (regardless of value), or false if the key is not in the JSONObject
+     */
+    public boolean has(String key) {
+        if (key != null) {
+            return this.containsKey(key);
+        }
+        return false;
+    }
+
+  /**
+   * Method to test if a key is mapped to null. This method will also return
+   * true if the key has not been put in the JSONObject yet,
+   *
+   * @param key   The key to test for null.
+   * @return true if the key is not in the map or if the value referenced by the
+   *         key is null, or if the value is the JSONObject.NULL object.
+   */
+    public boolean isNull(String key) {
+        Object obj = this.opt(key);
+        return JSONObject.NULL.equals(obj);
+    }
+
+    /**
+     * Utility function that returns an iterator of all the keys (attributes) of this JSONObject
+     * @return An iterator of all keys in the object.
+     *
+    public Enumeration keys() {
+        return this.keys();
+
+    } */
+
+    /**
+     * Utility function that returns a JSONArray of all the names of the keys (attributes) of this JSONObject
+     * @return All the keys in the JSONObject as a JSONArray.
+     */
+    public JSONArray names() {
+        Enumeration itr = this.keys();
+        if (itr != null) {
+            JSONArray array = new JSONArray();
+            while (itr.hasMoreElements()) {
+                array.add(itr.nextElement());
+            }
+            return array;
+        }
+        return null;
+    }
+
+    /**
+     * Utility function that returns a String[] of all the names of the keys (attributes) of this JSONObject
+     * @return All the keys in the JSONObject as a String[].
+     */
+    public static String[] getNames(JSONObject obj) {
+        String[] array = null;
+        if (obj != null) {
+            if (obj.size() > 0) {
+                array = new String[obj.size()];
+                int pos = 0;
+                Enumeration itr = obj.keys();
+                if (itr != null) {
+                    while (itr.hasMoreElements()) {
+                        array[pos] = (String)itr.nextElement();
+                        pos++;
+                    }
+                }
+            }
+        }
+        return array;
+    }
+
+//    /**
+//     * Utility function that returns an iterator of all the keys (attributes) of this JSONObject sorted in lexicographic manner (String.compareTo).
+//     * @return An iterator of all keys in the object in lexicographic (character code) sorted order.
+//     */
+//    public Enumeration sortedKeys() {
+//        Enumeration itr = this.keys();
+//        if (itr != null && itr.hasMoreElements()) {
+//            Vector vect = new Vector();
+//            while (itr.hasMoreElements()) {
+//                vect.addElement(itr.nextElement());
+//            }
+//            String[] strs = new String[vect.size()];
+//            vect.copyInto(strs);
+//           // java.util.Arrays.sort(strs);
+//            vect.clear();
+//            for (int i = 0; i < strs.length; i++) {
+//                vect.add(strs[i]);
+//            }
+//            return vect.iterator();
+//        }
+//        return null;
+//    }
+
+    /**
+     * End of convenience methods.
+     */
+
+    /**
+     * Over-ridden toString() method.  Returns the same value as write(), which is a compact JSON String.
+     * If an error occurs in the serialization, the return will be of format: JSON Generation Error: [<some error>]
+     * @return A string of JSON text, if possible.
+     */
+    public String toString() {
+        return toString(false);
+    }
+
+    /**
+     * Verbose capable toString method.
+     * If an error occurs in the serialization, the return will be of format: JSON Generation Error: [<some error>]
+     * @param verbose Whether or not to tab-indent the output.
+     * @return A string of JSON text, if possible.
+     */
+    public String toString(boolean verbose) {
+        String str = null;
+        try {
+            str = write(verbose);
+        } catch (JSONException jex) {
+            str = "JSON Generation Error: [" + jex.toString() + "]";
+        }
+        return str;
+    }
+
+    /**
+     * Function to return a string of JSON text with specified indention.  Returns the same value as write(indentDepth).
+     * If an error occurs in the serialization, a JSONException is thrown.
+     * @return A string of JSON text, if possible.
+     */
+    public String toString(int indentDepth) throws JSONException {
+        return write(indentDepth);
+    }
+
+    public static String quote(String string) {
+        return Serializer.quote(string);
+    }
+
+    /**
+     * An simple class provided for API compatibility to other JSON models that 'represents'
+     * 'null' in an actual object.
+     */
+    private static class Null implements JSONString {
+
+        /**
+         * Equals function that returns true for comparisons to null.
+         */
+        public boolean equals(Object obj) {
+            if (obj == null || obj == this) {
+                return true;
+            }
+            else {
+                return false;
+            }
+        }
+
+        /**
+         * Ensure only one Null object.
+         */
+        protected Object clone() {
+            return this;
+        }
+
+        /**
+         * toString method that just returns 'null' as the string.
+         */
+        public String toString() {
+            return "null";
+        }
+
+        /**
+         * Method to return a JSON compliant representation of this object.
+         * @return a JSON formatted string.
+         */
+        public String toJSONString() {
+            return this.toString();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/JSONString.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/JSONString.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/JSONString.java
new file mode 100644
index 0000000..b887adb
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/JSONString.java
@@ -0,0 +1,32 @@
+/*
+ * 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;
+
+/**
+ * An interface that can be implemented to make a
+ * particular object have an easy to use JSON representation.  Objects that implement this
+ * can be inserted into JSONObject and JSONArray and serialized.
+ */
+public interface JSONString {
+    /**
+     * Method to return a JSON compliant representation of this object.
+     * @return a JSON formatted string.
+     */
+    public String toJSONString();
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/JSONStringer.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/JSONStringer.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/JSONStringer.java
new file mode 100644
index 0000000..10fb7a8
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/JSONStringer.java
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+import java.io.IOException;
+
+import org.apache.cordova.json4j.internal.JSON4JStringWriter;
+
+/**
+ * This class implements a JSONSringer, a basic convenience subclass of JSONWriter to allow for
+ * generating JSON strings quickly.   This class exists for API compatibility to other popular
+ * JSON parsers.
+ */
+public class JSONStringer extends JSONWriter {
+
+    public JSONStringer() {
+        super(new JSON4JStringWriter());
+    }
+
+    /**
+     * Return a string of the stringer contents.  This also terminates the
+     * Stringer and it cannot be used again.  If any errors occur while trying to generate the JSON
+     * it returns an empty string.
+     */
+    public String toString() {
+        try {
+            super.flush();
+            super.close();
+            return ((JSON4JStringWriter)writer).toString();
+        } catch (Exception ex) {
+            /* Squelch */
+            return "";
+        }
+    }
+
+    /**
+     * Over-ride to do nothing for the stringer.  Only toString() terminates the stringer object.
+     */
+    public void close() throws IOException, IllegalStateException {
+        // Do nothing.
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/JSONWriter.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/JSONWriter.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/JSONWriter.java
new file mode 100644
index 0000000..1914f58
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/JSONWriter.java
@@ -0,0 +1,586 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Stack;
+
+import org.apache.cordova.json4j.internal.NumberUtil;
+
+/**
+ * This class implements a JSONWrier, a convenience function for writing out JSON
+ * to a writer or underlying stream.
+ */
+public class JSONWriter {
+
+    /**
+     * The writer to use to output JSON in a semi-streaming fashion.
+     */
+    protected Writer writer = null;
+
+    /**
+     * Flag to denote that the writer is in an object.
+     */
+    private boolean inObject = false;
+
+    /**
+     * Flag to denote that the writer is in an array.
+     */
+    private boolean inArray = false;
+
+    /**
+     * Flag for state checking that a key was placed (if inside an object)
+     * Required to be true for a value to be placed in that situation
+     */
+    private boolean keyPlaced = false;
+
+    /**
+     * Flag denoting if in an array or object, if the first entry has been placed or not.
+     */
+    private boolean firstEntry = false;
+
+    /**
+     * A stack to keep track of all the closures.
+     */
+    private Stack closures = null;
+
+    /**
+     * Flag used to check the state of this writer, if it has been closed, all
+     * operations will throw an IllegalStateException.
+     */
+    private boolean closed = false;
+
+    /**
+     * Constructor.
+     * @param writer The writer to use to do 'streaming' JSON writing.
+     * @throws NullPointerException Thrown if writer is null.
+     */
+    public JSONWriter(Writer writer) throws NullPointerException {
+        //Try to avoid double-buffering or buffering in-memory writers.
+//        Class writerClass = writer.getClass();
+//        if (!StringWriter.class.isAssignableFrom(writerClass) &&
+//            !CharArrayWriter.class.isAssignableFrom(writerClass) &&
+//            !BufferedWriter.class.isAssignableFrom(writerClass)) {
+//            writer = new BufferedWriter(writer);
+//        }
+        this.writer = writer;
+        this.closures = new Stack();
+    }
+
+    /**
+     * Open a new JSON Array in the output stream.
+     * @throws IOException Thrown if an error occurs on the underlying writer.
+     * @throws IllegalstateException Thrown if the current writer position does not permit an array.
+     * @return A reference to this writer.
+     */
+    public JSONWriter array() throws IOException, IllegalStateException {
+        if (closed) {
+            throw new IllegalStateException("The writer has been closed.  No further operations allowed.");
+        }
+        if (inObject) {
+            if (!keyPlaced) {
+                throw new IllegalStateException("Current containment is a JSONObject, but a key has not been specified to contain a new array");
+            }
+        } else if (inArray) {
+            if (!firstEntry) {
+                writer.write(",");
+            }
+        }
+        writer.write("[");
+        inArray = true;
+        inObject = false;
+        keyPlaced = false;
+        firstEntry = true;
+        closures.push("]");
+        return this;
+    }
+
+    /**
+     * Method to close the current JSON Array in the stream.
+     * @throws IOException Thrown if an IO error occurs on the underlying writer.
+     * @throws IllegalStateException Thrown if the writer position is not inside an array.
+     * @return A reference to this writer.
+     */
+    public JSONWriter endArray() throws IOException {
+        if (closed) {
+            throw new IllegalStateException("The writer has been closed.  No further operations allowed.");
+        }
+        if (!inArray) {
+            throw new IllegalStateException("Current writer position is not within a JSON array");
+        } else {
+            writer.write(((String)closures.pop()));
+            // Set our current positional/control state.
+            if (!closures.isEmpty()) {
+                String nextClosure = (String)closures.peek();
+                if (nextClosure.equals("}")) {
+                    inObject = true;
+                    inArray = false;
+                } else {
+                    inObject = false;
+                    inArray = true;
+                }
+                firstEntry = false;
+            } else {
+                inArray = false;
+                inObject = false;
+                firstEntry = true;
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Method to close a current JSON object in the stream.
+     * @throws IOException Thrown if an IO error occurs on the underlying writer.
+     * @throws IllegalStateException Thrown if the writer position is not inside an object, or if the object has a key placed, but no value.
+     * @return A reference to this writer.
+     */
+    public JSONWriter endObject() throws IOException, IllegalStateException {
+        if (closed) {
+            throw new IllegalStateException("The writer has been closed.  No further operations allowed.");
+        }
+        if (!inObject) {
+            throw new IllegalStateException("Current writer position is not within a JSON object");
+        } else {
+            if (keyPlaced) {
+                throw new IllegalStateException("Current writer position in an object and has a key placed, but no value has been assigned to the key.  Cannot end.");
+            } else {
+                writer.write((String)closures.pop());
+                // Set our current positional/control state.
+                if (!closures.isEmpty()) {
+                    String nextClosure = (String)closures.peek();
+                    if (nextClosure.equals("}")) {
+                        inObject = true;
+                        inArray = false;
+                    } else {
+                        inObject = false;
+                        inArray = true;
+                    }
+                    firstEntry = false;
+                } else {
+                    inArray = false;
+                    inObject = false;
+                    firstEntry = true;
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Place a key in the current JSON Object.
+     * @throws IOException Thrown if an IO error occurs on the underlying writer.
+     * @throws IllegalStateException Thrown if the current writer position is not within an object.
+     * @return A reference to this writer.
+     */
+    public JSONWriter key(String s) throws IOException, IllegalStateException, NullPointerException {
+        if (closed) {
+            throw new IllegalStateException("The writer has been closed.  No further operations allowed.");
+        }
+        if (s == null) {
+            throw new NullPointerException("Key cannot be null");
+        } else {
+            if (!inObject) {
+                throw new IllegalStateException("Current writer position is not inside a JSON Object, a key cannot be placed.");
+            } else {
+                if (!keyPlaced) {
+                    if (firstEntry) {
+                        firstEntry = false;
+                    } else {
+                        writer.write(",");
+                    }
+                    keyPlaced = true;
+                    writeString(s);
+                    writer.write(":");
+                } else {
+                    throw new IllegalStateException("Current writer position is inside a JSON Object an with an open key waiting for a value.  Another key cannot be placed.");
+                }
+            }
+        }
+        return this;
+    }
+
+    /**
+     * Open a new JSON Object in the output stream.
+     * @throws IllegalStateException Thrown if an object cannot currently be created in the stream.
+     * @throws IOException Thrown if an IO error occurs in the underlying writer.
+     * @return A reference to this writer.
+     */
+    public JSONWriter object() throws IOException, IllegalStateException {
+        if (closed) {
+            throw new IllegalStateException("The writer has been closed.  No further operations allowed.");
+        }
+        if (inObject) {
+            if (!keyPlaced) {
+                throw new IllegalStateException("Current containment is a JSONObject, but a key has not been specified to contain a new object");
+            }
+        } else if (inArray) {
+            if (!firstEntry) {
+                writer.write(",");
+            }
+        }
+        writer.write("{");
+        inObject = true;
+        inArray = false;
+        keyPlaced = false;
+        firstEntry = true;
+        closures.push("}");
+        return this;
+    }
+
+    /**
+     * Method to write a boolean to the current writer position.
+     * @throws IOException Thrown if an IO error occurs on the underlying writer.
+     * @throws IllegalStateException Thrown if the current writer position will not accept a boolean value.
+     * @return A reference to this writer.
+     */
+    public JSONWriter value(boolean b) throws IOException, IllegalStateException {
+        if (closed) {
+            throw new IllegalStateException("The writer has been closed.  No further operations allowed.");
+        }
+        if (inArray) {
+            if (firstEntry) {
+                firstEntry = false;
+            } else {
+                writer.write(",");
+            }
+            if (b)
+                writer.write("true");
+            else
+                writer.write("false");
+
+        } else if (inObject) {
+            if (keyPlaced) {
+                if (b)
+                    writer.write("true");
+                else
+                    writer.write("false");
+                keyPlaced = false;
+            } else {
+                throw new IllegalStateException("Current containment is a JSONObject, but a key has not been specified for the boolean value.");
+            }
+        } else {
+            throw new IllegalStateException("Writer is currently not in an array or object, cannot write value");
+        }
+        return this;
+    }
+
+    /**
+     * Method to write a double to the current writer position.
+     * @param d The Double to write.
+     * @throws IOException Thrown if an IO error occurs on the underlying writer.
+     * @throws IllegalStateException Thrown if the current writer position will not accept a double value.
+     * @return A reference to this writer.
+     */
+    public JSONWriter value(double d) throws IOException, IllegalStateException {
+        if (closed) {
+            throw new IllegalStateException("The writer has been closed.  No further operations allowed.");
+        }
+        if (inArray) {
+            if (firstEntry) {
+                firstEntry = false;
+            } else {
+                writer.write(",");
+            }
+            writer.write(Double.toString(d));
+        } else if (inObject) {
+            if (keyPlaced) {
+                writer.write(Double.toString(d));
+                keyPlaced = false;
+            } else {
+                throw new IllegalStateException("Current containment is a JSONObject, but a key has not been specified for the double value.");
+            }
+        } else {
+            throw new IllegalStateException("Writer is currently not in an array or object, cannot write value");
+        }
+        return this;
+    }
+
+    /**
+     * Method to write a double to the current writer position.
+     * @param l The long to write.
+     * @throws IOException Thrown if an IO error occurs on the underlying writer.
+     * @throws IllegalStateException Thrown if the current writer position will not accept a double value.
+     * @return A reference to this writer.
+     */
+    public JSONWriter value(long l) throws IOException, IllegalStateException {
+        if (closed) {
+            throw new IllegalStateException("The writer has been closed.  No further operations allowed.");
+        }
+        if (inArray) {
+            if (firstEntry) {
+                firstEntry = false;
+            } else {
+                writer.write(",");
+            }
+            writer.write(Long.toString(l));
+        } else if (inObject) {
+            if (keyPlaced) {
+                writer.write(Long.toString(l));
+                keyPlaced = false;
+            } else {
+                throw new IllegalStateException("Current containment is a JSONObject, but a key has not been specified for the long value.");
+            }
+        } else {
+            throw new IllegalStateException("Writer is currently not in an array or object, cannot write value");
+        }
+        return this;
+    }
+
+    /**
+     * Method to write an int to the current writer position.
+     * @param i The int to write.
+     * @throws IOException Thrown if an IO error occurs on the underlying writer.
+     * @throws IllegalStateException Thrown if the current writer position will not accept a double value.
+     * @return A reference to this writer.
+     */
+    public JSONWriter value(int i) throws IOException, IllegalStateException {
+        if (closed) {
+            throw new IllegalStateException("The writer has been closed.  No further operations allowed.");
+        }
+        if (inArray) {
+            if (firstEntry) {
+                firstEntry = false;
+            } else {
+                writer.write(",");
+            }
+            writer.write(Integer.toString(i));
+        } else if (inObject) {
+            if (keyPlaced) {
+                writer.write(Integer.toString(i));
+                keyPlaced = false;
+            } else {
+                throw new IllegalStateException("Current containment is a JSONObject, but a key has not been specified for the int value.");
+            }
+        } else {
+            throw new IllegalStateException("Writer is currently not in an array or object, cannot write value");
+        }
+        return this;
+    }
+
+    /**
+     * Method to write a short to the current writer position.
+     * @param s The short to write.
+     * @throws IOException Thrown if an IO error occurs on the underlying writer.
+     * @throws IllegalStateException Thrown if the current writer position will not accept a double value.
+     * @return A reference to this writer.
+     */
+    public JSONWriter value(short s) throws IOException, IllegalStateException {
+        if (closed) {
+            throw new IllegalStateException("The writer has been closed.  No further operations allowed.");
+        }
+        if (inArray) {
+            if (firstEntry) {
+                firstEntry = false;
+            } else {
+                writer.write(",");
+            }
+            writer.write(Integer.toString(s));
+        } else if (inObject) {
+            if (keyPlaced) {
+                writer.write(Integer.toString(s));
+                keyPlaced = false;
+            } else {
+                throw new IllegalStateException("Current containment is a JSONObject, but a key has not been specified for the short value.");
+            }
+        } else {
+            throw new IllegalStateException("Writer is currently not in an array or object, cannot write value");
+        }
+        return this;
+    }
+
+    /**
+     * Method to write an Object to the current writer position.
+     * @param o The object to write.
+     * @throws IOException Thrown if an IO error occurs on the underlying writer.
+     * @throws JSONException Thrown if the object is not JSONAble.
+     * @return A reference to this writer.
+     */
+    public JSONWriter value(Object o) throws IOException, IllegalStateException, JSONException {
+        if (closed) {
+            throw new IllegalStateException("The writer has been closed.  No further operations allowed.");
+        }
+        if (inArray) {
+            if (firstEntry) {
+                firstEntry = false;
+            } else {
+                writer.write(",");
+            }
+            writeObject(o);
+        } else if (inObject) {
+            if (keyPlaced) {
+                writeObject(o);
+                keyPlaced = false;
+            } else {
+                throw new IllegalStateException("Current containment is a JSONObject, but a key has not been specified for the boolean value.");
+            }
+        } else {
+            throw new IllegalStateException("Writer is currently not in an array or object, cannot write value");
+        }
+        return this;
+    }
+
+    /**
+     * Method to close the JSON Writer.  All current object depths will be closed out and the writer closed.
+     * @throws IOException Thrown if an IO error occurs on the underlying writer.
+     * @throws IllegalStateException Thrown if the writer position is in an object and a key has been placed, but a value has not been assigned or if the writer was already closed.
+     */
+    public void close() throws IOException, IllegalStateException {
+        if (!closed) {
+            if (inObject && keyPlaced) {
+                throw new IllegalStateException("Object has key without value.  Cannot close.");
+            } else {
+                while (!closures.isEmpty()) {
+                    writer.write((String)closures.pop());
+                }
+                writer.flush();
+                writer.close();
+                closed = true;
+            }
+        }
+    }
+
+    /**
+     * Method to flush the underlying writer so that all buffered content, if any, is written out.
+     * @return A reference to this writer.
+     */
+    public JSONWriter flush() throws IOException {
+        writer.flush();
+        return this;
+    }
+
+    /**
+     * Method to write a String out to the writer, encoding special characters and unicode characters properly.
+     * @param value The string to write out.
+     * @throws IOException Thrown if an error occurs during write.
+     */
+    private void writeString(String value) throws IOException {
+        writer.write('"');
+        char[] chars = value.toCharArray();
+        for (int i=0; i<chars.length; i++) {
+            char c = chars[i];
+            switch (c) {
+                case  '"': writer.write("\\\""); break;
+                case '\\': writer.write("\\\\"); break;
+                case    0: writer.write("\\0"); break;
+                case '\b': writer.write("\\b"); break;
+                case '\t': writer.write("\\t"); break;
+                case '\n': writer.write("\\n"); break;
+                case '\f': writer.write("\\f"); break;
+                case '\r': writer.write("\\r"); break;
+                case '/': writer.write("\\/"); break;
+                default:
+                    if ((c >= 32) && (c <= 126)) {
+                        writer.write(c);
+                    } else {
+                        writer.write("\\u");
+                        writer.write(rightAlignedZero(Integer.toHexString(c),4));
+                    }
+            }
+        }
+        writer.write('"');
+    }
+
+    /**
+     * Method to generate a string with a particular width.  Alignment is done using zeroes if it does not meet the width requirements.
+     * @param s The string to write
+     * @param len The minimum length it should be, and to align with zeroes if length is smaller.
+     * @return A string properly aligned/correct width.
+     */
+    private String rightAlignedZero(String s, int len) {
+        if (len == s.length()) return s;
+        StringBuffer sb = new StringBuffer(s);
+        while (sb.length() < len) {
+            sb.insert(0, '0');
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Method to write a number to the current writer.
+     * @param value The number to write to the JSON output string.
+     * @throws IOException Thrown if an error occurs during write.
+     */
+    private void writeNumber(Object value) throws IOException {
+        if (null == value) {
+            writeNull();
+        }
+        if (value instanceof Float) {
+            if (((Float)value).isNaN()) {
+                writeNull();
+            }
+            if (Float.NEGATIVE_INFINITY == ((Float)value).floatValue()) {
+                writeNull();
+            }
+            if (Float.POSITIVE_INFINITY == ((Float)value).floatValue()) {
+                writeNull();
+            }
+        }
+        if (value instanceof Double) {
+            if (((Double)value).isNaN()) {
+                writeNull();
+            }
+            if (Double.NEGATIVE_INFINITY == ((Double)value).doubleValue()) {
+                writeNull();
+            }
+            if (Double.POSITIVE_INFINITY == ((Double)value).doubleValue()) {
+                writeNull();
+            }
+        }
+        writer.write(value.toString());
+    }
+
+    /**
+     * Method to write an object to the current writer.
+     * @param o The object to write.
+     * @throws IOException Thrown if an IO error occurs on the underlying writer.
+     * @throws JSONException Thrown if the specified object is not JSONAble.
+     */
+    private void writeObject(Object o) throws IOException, JSONException {
+        // Handle the object!
+        if (o == null) {
+            writeNull();
+        } else {
+            Class clazz = o.getClass();
+            if (JSONArtifact.class.isAssignableFrom(clazz)) {
+                writer.write(((JSONArtifact)o).toString());
+            } else if (NumberUtil.isNumber(clazz)) {
+                writeNumber(o);
+            } else if (Boolean.class.isAssignableFrom(clazz)) {
+                writer.write(((Boolean)o).toString());
+            } else if (String.class.isAssignableFrom(clazz)) {
+                writeString((String)o);
+            } else if (JSONString.class.isAssignableFrom(clazz)) {
+                writer.write(((JSONString)o).toJSONString());
+            }// else {
+             //   // Unknown type, we'll just try to serialize it like a Java Bean.
+             //   writer.write(BeanSerializer.toJson(o, true).write());
+           // }
+        }
+    }
+
+    /**
+     * Method to write the text string 'null' to the output stream (null JSON object).
+     * @throws IOException Thrown if an error occurs during write.
+     */
+    private void writeNull() throws IOException {
+        writer.write("null");
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JNumber.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JNumber.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JNumber.java
new file mode 100644
index 0000000..99d244c
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JNumber.java
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+public class JSON4JNumber {
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JPBackReader.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JPBackReader.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JPBackReader.java
new file mode 100644
index 0000000..a2ed87b
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JPBackReader.java
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+public class JSON4JPBackReader extends Reader {
+
+    private Reader _reader = null;
+
+    private int _lastChar = 0;
+
+    public JSON4JPBackReader(Reader reader) {
+        _reader = reader;
+    }
+
+    public void close() throws IOException {
+        _reader.close();
+    }
+
+    public void unread(int c) {
+    }
+
+    public int read(char[] cbuf, int off, int len) throws IOException {
+        cbuf[off] = (char)_lastChar;
+        _reader.read(cbuf, off + 1, len -1);
+        _lastChar = cbuf[off + len];
+        return 0;
+    }
+}