incubator-callback-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From deedu...@apache.org
Subject [15/19] CB-226 Rename to Cordova.
Date Wed, 08 Feb 2012 20:14:02 GMT
http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JStringReader.java
----------------------------------------------------------------------
diff --git a/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JStringReader.java b/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JStringReader.java
new file mode 100644
index 0000000..5c3583a
--- /dev/null
+++ b/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JStringReader.java
@@ -0,0 +1,54 @@
+/*
+ * 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 JSON4JStringReader extends Reader {
+
+    private char[] _buf = null;
+    private int _mark = 0;
+    private int maxLength = 0;
+
+    public JSON4JStringReader(String str) {
+        _buf = str.toCharArray();
+        maxLength = str.length();
+        _mark = 0;
+    }
+
+    public void close() throws IOException {
+        return;
+    }
+
+    public int read(char[] cbuf, int off, int len) throws IOException {
+        if (_mark == (maxLength))
+            return -1;
+
+        int read = 0;
+        for (int x=0; x<len; x++) {
+            cbuf[x+off] = _buf[_mark];
+            read++;
+            _mark++;
+            if (_mark == (maxLength))
+                return read;
+        }
+        return read;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JStringWriter.java
----------------------------------------------------------------------
diff --git a/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JStringWriter.java b/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JStringWriter.java
new file mode 100644
index 0000000..ce1d2cc
--- /dev/null
+++ b/framework/ext/src/org/apache/cordova/json4j/internal/JSON4JStringWriter.java
@@ -0,0 +1,68 @@
+/*
+ * 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.Writer;
+
+public class JSON4JStringWriter extends Writer {
+
+    public static int BUF_SIZE = 10000;
+
+    private char[] _buffer = null;
+
+    private int _mark = 0;
+
+    public JSON4JStringWriter() {
+        _buffer = new char[BUF_SIZE];
+        _mark = 0;
+    }
+
+    // Resizes an array; doubles up every time.
+    public static char[] resizeArray(char[] expandMe) {
+        int newSize = expandMe.length * 2;
+        char[] newArray = new char[newSize];
+        System.arraycopy(expandMe, 0, newArray, 0, expandMe.length);
+        return newArray;
+    }
+
+
+    public void close() throws IOException {
+        return;
+    }
+
+    public void flush() throws IOException {
+        return;
+    }
+
+    public void write(char[] cbuf, int off, int len) throws IOException {
+        if (((len - off) + _mark) >= _buffer.length) {
+            // Resize the array first.
+            _buffer = JSON4JStringWriter.resizeArray(_buffer);
+        }
+        for (int x=0; x < len; x++) {
+            _buffer[_mark] = cbuf[off+x];
+            _mark++;
+        }
+    }
+
+    public String toString() {
+        return new String(_buffer, 0, _mark);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/json4j/internal/NumberUtil.java
----------------------------------------------------------------------
diff --git a/framework/ext/src/org/apache/cordova/json4j/internal/NumberUtil.java b/framework/ext/src/org/apache/cordova/json4j/internal/NumberUtil.java
new file mode 100644
index 0000000..d63d4db
--- /dev/null
+++ b/framework/ext/src/org/apache/cordova/json4j/internal/NumberUtil.java
@@ -0,0 +1,109 @@
+/*
+ * 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 NumberUtil {
+
+    public static  boolean isNumber(Class clazz) {
+        if ( (clazz == Integer.class) || (clazz == Long.class) || (clazz == Double.class) || (clazz == Short.class) || (clazz == Float.class)) {
+            return true;
+        }
+        return false;
+    }
+
+    public static double getDouble(Object val) {
+        if (val instanceof Double) {
+            return ((Double)val).doubleValue();
+        }
+        else if (val instanceof Long) {
+            return ((Long)val).doubleValue();
+        }
+        else if (val instanceof Short) {
+            Integer i = new Integer( ((Short)val).shortValue() );
+            return i.doubleValue();
+        }
+        else if (val instanceof Float) {
+            return ((Float)val).doubleValue();
+        }
+        else if (val instanceof Integer) {
+            return ((Integer)val).doubleValue();
+        }
+        throw new IllegalArgumentException("Not a number");
+    }
+
+    public static short getShort(Object val) {
+        if (val instanceof Double) {
+            return ((Double)val).shortValue();
+        }
+        else if (val instanceof Long) {
+            Double dg = new Double(((Long)val).longValue());
+            return dg.shortValue();
+        }
+        else if (val instanceof Short) {
+            return ((Short)val).shortValue();
+        }
+        else if (val instanceof Float) {
+            return ((Float)val).shortValue();
+        } else if (val instanceof Integer) {
+            return ((Integer)val).shortValue();
+        }
+        throw new IllegalArgumentException("Not a number");
+    }
+
+    public static int getInt(Object val) {
+        if (val instanceof Double) {
+            return ((Double)val).intValue();
+        }
+        else if (val instanceof Long) {
+            Double dg = new Double(((Long)val).longValue());
+            return dg.intValue();
+        }
+        else if (val instanceof Short) {
+            Double dg = new Double(((Short)val).shortValue());
+            return dg.intValue();
+        }
+        else if (val instanceof Float) {
+            return ((Float)val).intValue();
+        }
+        else if (val instanceof Integer) {
+            return ((Integer)val).intValue();
+        }
+        throw new IllegalArgumentException("Not a number");
+    }
+
+    public static long getLong(Object val) {
+        if (val instanceof Double) {
+            return ((Double)val).longValue();
+        }
+        else if (val instanceof Long) {
+            return ((Long)val).longValue();
+        }
+        else if (val instanceof Short) {
+            Long lg = new Long(((Short)val).shortValue());
+            return lg.longValue();
+        }
+        else if (val instanceof Float) {
+            return ((Float)val).longValue();
+        }
+        else if (val instanceof Integer) {
+            return ((Integer)val).longValue();
+        }
+        throw new IllegalArgumentException("Not a number");
+    }
+}

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

http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/json4j/internal/Serializer.java
----------------------------------------------------------------------
diff --git a/framework/ext/src/org/apache/cordova/json4j/internal/Serializer.java b/framework/ext/src/org/apache/cordova/json4j/internal/Serializer.java
new file mode 100644
index 0000000..50f34d3
--- /dev/null
+++ b/framework/ext/src/org/apache/cordova/json4j/internal/Serializer.java
@@ -0,0 +1,353 @@
+/*
+ * 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.Writer;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.cordova.json4j.JSONArray;
+import org.apache.cordova.json4j.JSONObject;
+import org.apache.cordova.json4j.JSONString;
+
+/**
+ * Class to handle serialization of a JSON object to a JSON string.
+ */
+public class Serializer {
+
+    /**
+     * The writer to use when writing this JSON object.
+     */
+    private Writer writer;
+
+    /**
+     * Create a serializer on the specified output stream writer.
+     */
+    public Serializer(Writer writer) {
+        super();
+        this.writer = writer;
+    }
+
+    /**
+     * Method to flush the current writer.
+     * @throws IOException Thrown if an error occurs during writer flush.
+     */
+    public void flush() throws IOException {
+        writer.flush();
+    }
+
+    /**
+     * Method to close the current writer.
+     * @throws IOException Thrown if an error occurs during writer close.
+     */
+    public void close() throws IOException {
+        writer.close();
+    }
+
+    /**
+     * Method to write a raw string to the writer.
+     * @param s The String to write.
+     * @throws IOException Thrown if an error occurs during write.
+     */
+    public Serializer writeRawString(String s) throws IOException {
+        writer.write(s);
+        return this;
+    }
+
+    /**
+     * Method to write the text string 'null' to the output stream (null JSON object).
+     * @throws IOException Thrown if an error occurs during write.
+     */
+    public Serializer writeNull() throws IOException {
+        writeRawString("null");
+        return this;
+    }
+
+    /**
+     * 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.
+     */
+    public Serializer writeNumber(Object value) throws IOException {
+        if (null == value) return writeNull();
+
+        if (value instanceof Float) {
+            if (((Float)value).isNaN()) return writeNull();
+            if (Float.NEGATIVE_INFINITY == ((Float)value).floatValue()) return writeNull();
+            if (Float.POSITIVE_INFINITY == ((Float)value).floatValue()) return writeNull();
+        }
+
+        if (value instanceof Double) {
+            if (((Double)value).isNaN()) return writeNull();
+            if (Double.NEGATIVE_INFINITY == ((Double)value).doubleValue()) return writeNull();
+            if (Double.POSITIVE_INFINITY == ((Double)value).doubleValue()) return writeNull();
+        }
+
+        writeRawString(value.toString());
+
+        return this;
+    }
+
+    /**
+     * Method to write a boolean value to the output stream.
+     * @param value The Boolean object to write out as a JSON boolean.
+     * @throws IOException Thrown if an error occurs during write.
+     */
+    public Serializer writeBoolean(Boolean value) throws IOException {
+        if (null == value) return writeNull();
+
+        writeRawString(value.toString());
+
+        return this;
+    }
+
+    /**
+     * 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 static 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 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.
+     */
+    public Serializer writeString(String value) throws IOException {
+        if (null == value) return writeNull();
+
+        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('"');
+
+        return this;
+    }
+
+    /**
+     * Method to write out a generic JSON type.
+     * @param object The JSON compatible object to serialize.
+     * @throws IOException Thrown if an error occurs during write, or if a nonJSON compatible Java object is passed..
+     */
+    private Serializer write(Object object) throws IOException {
+        if (null == object) return writeNull();
+
+        // Serialize the various types!
+        Class clazz = object.getClass();
+        if (NumberUtil.isNumber(clazz)) return writeNumber(object);
+        if (Boolean.class.isAssignableFrom(clazz)) return writeBoolean((Boolean) object);
+        if (JSONObject.class.isAssignableFrom(clazz)) return writeObject((JSONObject) object);
+        if (JSONArray.class.isAssignableFrom(clazz)) return writeArray((JSONArray) object);
+        if (JSONString.class.isAssignableFrom(clazz)) return writeRawString(((JSONString) object).toJSONString());
+        if (String.class.isAssignableFrom(clazz)) return writeString((String) object);
+
+        throw new IOException("Attempting to serialize unserializable object: '" + object + "'");
+    }
+
+    /**
+     * Method to write a complete JSON object to the stream.
+     * @param object The JSON object to write out.
+     * @throws IOException Thrown if an error occurs during write.
+     */
+    public Serializer writeObject(JSONObject object) throws IOException {
+        if (null == object) return writeNull();
+
+        // write header
+        writeRawString("{");
+        indentPush();
+
+        Enumeration iter = getPropertyNames(object);
+
+        while ( iter.hasMoreElements() ) {
+            Object key = iter.nextElement();
+            if (!(key instanceof String)) throw new IOException("attempting to serialize object with an invalid property name: '" + key + "'" );
+
+            Object value = object.get(key);
+            if (!JSONObject.isValidObject(value)) throw new IOException("attempting to serialize object with an invalid property value: '" + value + "'");
+
+            newLine();
+            indent();
+            writeString((String)key);
+            writeRawString(":");
+            space();
+            write(value);
+
+            if (iter.hasMoreElements()) writeRawString(",");
+        }
+
+        // write trailer
+        indentPop();
+        newLine();
+        indent();
+        writeRawString("}");
+
+        return this;
+    }
+
+    /**
+     * Method to write a JSON array out to the stream.
+     * @param value The JSON array to write out.
+     * @throws IOException Thrown if an error occurs during write.
+     */
+    public Serializer writeArray(JSONArray value) throws IOException {
+        if (null == value) return writeNull();
+
+        // write header
+        writeRawString("[");
+        indentPush();
+
+        for (Enumeration iter=value.elements(); iter.hasMoreElements(); ) {
+            Object element = iter.nextElement();
+            if (!JSONObject.isValidObject(element)) throw new IOException("attempting to serialize array with an invalid element: '" + value + "'");
+
+            newLine();
+            indent();
+            write(element);
+
+            if (iter.hasMoreElements()) writeRawString(",");
+        }
+
+        // write trailer
+        indentPop();
+        newLine();
+        indent();
+        writeRawString("]");
+
+        return this;
+    }
+
+    //---------------------------------------------------------------
+    // pretty printing overridables
+    //---------------------------------------------------------------
+
+    /**
+     * Method to write a space to the output writer.
+     * @throws IOException Thrown if an error occurs during write.
+     */
+    public void space() throws IOException {
+    }
+
+    /**
+     * Method to write a newline to the output writer.
+     * @throws IOException Thrown if an error occurs during write.
+     */
+    public void newLine() throws IOException {
+    }
+
+    /**
+     * Method to write an indent to the output writer.
+     * @throws IOException Thrown if an error occurs during write.
+     */
+    public void indent() throws IOException {
+    }
+
+    /**
+     * Method to increase the indent depth of the output writer.
+     * @throws IOException Thrown if an error occurs during write.
+     */
+    public void indentPush() {
+    }
+
+    /**
+     * Method to reduce the indent depth of the output writer.
+     */
+    public void indentPop() {
+    }
+
+    /**
+     * Method to get a list of all the property names stored in a map.
+     */
+    public Enumeration getPropertyNames(Hashtable map) {
+        return map.keys();
+    }
+
+    /**
+     * Method to write a String out to the writer, encoding special characters and unicode characters properly.
+     * @param value The string to write out.
+     */
+    public static String quote(String value) {
+        if (value == null || value.length() == 0) {
+            return "\"\"";
+        }
+
+        StringBuffer buf = new StringBuffer();
+        char[] chars = value.toCharArray();
+
+        buf.append('"');
+        for (int i=0; i<chars.length; i++) {
+            char c = chars[i];
+            switch (c) {
+                case  '"': buf.append("\\\""); break;
+                case '\\': buf.append("\\\\"); break;
+                case    0: buf.append("\\0"); break;
+                case '\b': buf.append("\\b"); break;
+                case '\t': buf.append("\\t"); break;
+                case '\n': buf.append("\\n"); break;
+                case '\f': buf.append("\\f"); break;
+                case '\r': buf.append("\\r"); break;
+                case '/': buf.append("\\/"); break;
+                default:
+                    if ((c >= 32) && (c <= 126)) {
+                        buf.append(c);
+                    } else {
+                        buf.append("\\u");
+                        buf.append(rightAlignedZero(Integer.toHexString(c),4));
+                    }
+            }
+        }
+        buf.append('"');
+
+        return buf.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/json4j/internal/SerializerVerbose.java
----------------------------------------------------------------------
diff --git a/framework/ext/src/org/apache/cordova/json4j/internal/SerializerVerbose.java b/framework/ext/src/org/apache/cordova/json4j/internal/SerializerVerbose.java
new file mode 100644
index 0000000..5132591
--- /dev/null
+++ b/framework/ext/src/org/apache/cordova/json4j/internal/SerializerVerbose.java
@@ -0,0 +1,102 @@
+/*
+ * 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.Writer;
+
+/**
+ * Internaql class for handling the serialization of JSON objects in a verbose
+ * format, meaning newlines and indention.
+ */
+public class SerializerVerbose extends Serializer {
+
+    /**
+     * Internal tracker keeping indent position.
+     */
+    private int indent = 0;
+
+    /**
+     * The indent string to use when serializing.
+     */
+    private String indentStr = "\t";
+
+    /**
+     * Constructor.
+     */
+    public SerializerVerbose(Writer writer) {
+        super(writer);
+    }
+
+    /**
+     * Constructor.
+     * @param Writer The writer to serialize JSON to.
+     * @param indentSpaces: How many spaces to indent by (0 to 8).
+     * The default indent is the TAB character.
+     */
+    public SerializerVerbose(Writer writer, int indentSpaces) {
+        super(writer);
+        if(indentSpaces > 0 && indentSpaces < 8){
+            this.indentStr = "";
+            for(int i = 0; i < indentSpaces; i++){
+                this.indentStr += " ";
+            }
+        }
+    }
+
+    /**
+     * Method to write a space to the output writer.
+     * @throws IOException Thrown if an error occurs during write.
+     */
+    public void space() throws IOException {
+        writeRawString(" ");
+    }
+
+    /**
+     * Method to write a newline to the output writer.
+     * @throws IOException Thrown if an error occurs during write.
+     */
+    public void newLine() throws IOException {
+        writeRawString("\n");
+    }
+
+    /**
+     * Method to write an indent to the output writer.
+     * @throws IOException Thrown if an error occurs during write.
+     */
+    public void indent() throws IOException {
+        for (int i=0; i<indent; i++) writeRawString(this.indentStr);
+    }
+
+    /**
+     * Method to increase the indent depth of the output writer.
+     * @throws IOException Thrown if an error occurs during write.
+     */
+    public void indentPush() {
+        indent++;
+    }
+
+    /**
+     * Method to reduce the indent depth of the output writer.
+     */
+    public void indentPop() {
+        indent--;
+        if (indent < 0) throw new IllegalStateException();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/json4j/internal/Token.java
----------------------------------------------------------------------
diff --git a/framework/ext/src/org/apache/cordova/json4j/internal/Token.java b/framework/ext/src/org/apache/cordova/json4j/internal/Token.java
new file mode 100644
index 0000000..1c635e9
--- /dev/null
+++ b/framework/ext/src/org/apache/cordova/json4j/internal/Token.java
@@ -0,0 +1,115 @@
+/*
+ * 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;
+
+/**
+ * Class representing a JSON token.
+ */
+public class Token {
+
+    static final public Token TokenEOF    = new Token();
+    static final public Token TokenBraceL = new Token();
+    static final public Token TokenBraceR = new Token();
+    static final public Token TokenBrackL = new Token();
+    static final public Token TokenBrackR = new Token();
+    static final public Token TokenColon  = new Token();
+    static final public Token TokenComma  = new Token();
+    static final public Token TokenTrue   = new Token();
+    static final public Token TokenFalse  = new Token();
+    static final public Token TokenNull   = new Token();
+
+    private String  valueString;
+    private Object  valueNumber;
+    private boolean  isConstant;
+
+    /**
+     * Constructor
+     */
+    public Token() {
+        super();
+    }
+
+    /**
+     * Constructor
+     * @param value The value of the token as a string
+     */
+    public Token(String value) {
+        super();
+        valueString = value;
+    }
+
+    /**
+     * Constructor
+     * @param value The value of the token as a number
+     */
+    public Token(Object value) {
+        super();
+
+        valueNumber = value;
+    }
+
+    /**
+     * Method to obtain the string value of this token
+     */
+    public String getString() {
+        return valueString;
+    }
+
+    /**
+     * Method to obtain the number value of this token
+     */
+    public Object getNumber() {
+        return valueNumber;
+    }
+
+    /**
+     * Method to indicate if this token is string based or not.
+     */
+    public boolean isString() {
+        return (null != valueString) && !isConstant;
+    }
+
+    /**
+     * Method to indicate if this token is number based or not.
+     */
+    public boolean isNumber() {
+        return null != valueNumber;
+    }
+
+    /**
+     * Method to convert the token to a string representation.
+     */
+    public String toString() {
+        if (this == TokenEOF)    return "Token: EOF";
+        if (this == TokenBraceL) return "Token: {";
+        if (this == TokenBraceR) return "Token: }";
+        if (this == TokenBrackL) return "Token: [";
+        if (this == TokenBrackR) return "Token: ]";
+        if (this == TokenColon)  return "Token: :";
+        if (this == TokenComma)  return "Token: ,";
+        if (this == TokenTrue)   return "Token: true";
+        if (this == TokenFalse)  return "Token: false";
+        if (this == TokenNull)   return "Token: null";
+
+        if (this.isNumber()) return "Token: Number - " + getNumber();
+        if (this.isString()) return "Token: String - '" + getString() + "'";
+
+        return "Token: unknown.";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/json4j/internal/Tokenizer.java
----------------------------------------------------------------------
diff --git a/framework/ext/src/org/apache/cordova/json4j/internal/Tokenizer.java b/framework/ext/src/org/apache/cordova/json4j/internal/Tokenizer.java
new file mode 100644
index 0000000..652106e
--- /dev/null
+++ b/framework/ext/src/org/apache/cordova/json4j/internal/Tokenizer.java
@@ -0,0 +1,619 @@
+/*
+ * 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;
+
+/**
+ * Tokenizes a stream into JSON tokens.
+ */
+public class Tokenizer {
+
+    /**
+     * The reader from which the JSON string is being read.
+     */
+    private Reader reader;
+
+    /**
+     * The current line position in the JSON string.
+     */
+    private int     lineNo;
+
+    /**
+     * The current column position in the JSON string.
+     */
+    private int     colNo;
+
+    /**
+     * The last character read from the JSON string.
+     */
+    private int     lastChar;
+
+    /**
+     * Whether or not the parser should be spec strict, or allow unquoted strings and comments
+     */
+    private boolean strict = false;
+
+    /**
+     * Constructor.
+     * @param reader The reader from which the JSON string is read.  Same as Tokenizer(reader, false);
+     *
+     * @throws IOException Thrown on IOErrors such as invalid JSON or sudden reader closures.
+     */
+    public Tokenizer(Reader reader) throws IOException {
+        super();
+
+//        Class readerClass= reader.getClass();
+        //In-memory readers don't need to be buffered.  Also, skip PushbackReaders
+        //because they probably already wrap a buffered stream.  And lastly, anything
+        //that extends from a BufferedReader also doesn't need buffering!
+//        if (!StringReader.class.isAssignableFrom(readerClass) &&
+//            !CharArrayReader.class.isAssignableFrom(readerClass) &&
+//            !PushbackReader.class.isAssignableFrom(readerClass) &&
+//            !BufferedReader.class.isAssignableFrom(readerClass)) {
+//            reader = new BufferedReader(reader);
+//        }
+        this.reader    = reader;
+        this.lineNo    = 0;
+        this.colNo     = 0;
+        this.lastChar  = '\n';
+        readChar();
+    }
+
+    /**
+     * Constructor.
+     * @param reader The reader from which the JSON string is read.
+     * @param strict Whether or not the parser should be spec strict, or allow unquoted strings and comments.
+     *
+     * @throws IOException Thrown on IOErrors such as invalid JSON or sudden reader closures.
+     */
+    public Tokenizer(Reader reader, boolean strict) throws IOException {
+        super();
+
+//        Class readerClass= reader.getClass();
+        //In-memory readers don't need to be buffered.  Also, skip PushbackReaders
+        //because they probably already wrap a buffered stream.  And lastly, anything
+        //that extends from a BufferedReader also doesn't need buffering!
+//        if (!StringReader.class.isAssignableFrom(readerClass) &&
+//            !CharArrayReader.class.isAssignableFrom(readerClass) &&
+//            !PushbackReader.class.isAssignableFrom(readerClass) &&
+//            !BufferedReader.class.isAssignableFrom(readerClass)) {
+//            reader = new BufferedReader(reader);
+//        }
+        this.reader    = reader;
+        this.lineNo    = 0;
+        this.colNo     = 0;
+        this.lastChar  = '\n';
+        this.strict    = strict;
+
+        readChar();
+    }
+
+    /**
+     * Method to get the next JSON token from the JSON String
+     * @return The next token in the stream, returning Token.TokenEOF when finished.
+     *
+     * @throws IOException Thrown if unexpected read error occurs or invalid character encountered in JSON string.
+     */
+    public Token next() throws IOException {
+
+        // skip whitespace, use our own checker, it seems
+        // a bit faster than Java's default.
+        //while (Character.isWhitespace((char)lastChar)) {
+        while (isWhitespace((char)lastChar)) {
+            readChar();
+        }
+
+        // handle punctuation
+        switch (lastChar) {
+            case -1:  readChar(); return Token.TokenEOF;
+            case '{': readChar(); return Token.TokenBraceL;
+            case '}': readChar(); return Token.TokenBraceR;
+            case '[': readChar(); return Token.TokenBrackL;
+            case ']': readChar(); return Token.TokenBrackR;
+            case ':': readChar(); return Token.TokenColon;
+            case ',': readChar(); return Token.TokenComma;
+
+            case '"':
+            case '\'':
+                String stringValue = readString();
+                return new Token(stringValue);
+
+            case '-':
+            case '.':
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+                Object numberValue = readNumber();
+                return new Token(numberValue);
+
+            case 'n':
+            case 't':
+            case 'f':
+                String ident = readIdentifier();
+
+                if (ident.equals("null"))  return Token.TokenNull;
+                if (ident.equals("true"))  return Token.TokenTrue;
+                if (ident.equals("false")) return Token.TokenFalse;
+
+                // Okay, this was some sort of unquoted string, may be okay
+                if (!this.strict) {
+                    //Unquoted string.  Non-strict mode allows this.  It's still bad input
+                    //from a spec perspective, but allowable in non-strict mode.
+                    return new Token(ident);
+                } else {
+                    throw new IOException("Unexpected unquoted string literal: [" + ident + "].  Unquoted strings are not allowed in strict mode");
+                }
+            case '/':
+                if (!this.strict) {
+                    // Comment mode and not strict.  Lets just devour the comment.
+                    readComment();
+                    return next();
+                } else {
+                    throw new IOException("Unexpected character / encountered " + onLineCol() + ".  Comments are not allowed in strict mode");
+                }
+
+            default:
+                if (!this.strict && isValidUnquotedChar((char)lastChar)) {
+                    // Unquoted string.  Bad form, but ... okay, lets accept it.
+                    // some other parsers do.
+                    String unquotedStr = readIdentifier();
+                    return new Token(unquotedStr);
+                } else {
+                    if (this.strict) {
+                        throw new IOException("Unexpected character '" + (char)lastChar + "' " + onLineCol() + ".  Unquoted strings are not allowed in strict mode.");
+                    } else {
+                        throw new IOException("Unexpected character '" + (char)lastChar + "' " + onLineCol());
+                    }
+                }
+        }
+
+    }
+
+    /**
+     * Method to read out comments in the 'JSON'.  JSON normally should not
+     * have comments, but I guess we need to be more permissive to make some Crockford code
+     * happy.
+     */
+    private void readComment() throws IOException {
+        readChar();
+        if ((char)lastChar == '/') {
+            // Okay, // comment,so just read to \n or end of line
+            while ((char)lastChar != '\n' && lastChar != -1) {
+                readChar();
+            }
+        } else if ((char)lastChar == '*') {
+            // /* comment, so read past it.
+            char[] chars = new char[2];
+            readChar();
+            if (lastChar != -1) {
+                chars[0] = (char)lastChar;
+            } else {
+                return;
+            }
+            readChar();
+            if (lastChar != -1) {
+                chars[1] = (char)lastChar;
+            } else {
+                return;
+            }
+
+            while (chars[0] != '*' || chars[1] != '/') {
+                readChar();
+                if (lastChar != -1) {
+                    chars[0] = chars[1];
+                    chars[1] = (char)lastChar;
+
+                } else {
+                    return;
+                }
+            }
+        }
+    }
+
+    /**
+     * Method to read a string from the JSON string, converting escapes accordingly.
+     * @return The parsed JSON string with all escapes properly converyed.
+     *
+     * @throws IOException Thrown on unterminated strings, invalid characters, bad escapes, and so on.  Basically, invalid JSON.
+     */
+    private String readString() throws IOException {
+        StringBuffer sb    = new StringBuffer();
+        int          delim = lastChar;
+        int          l = lineNo;
+        int          c = colNo;
+
+        readChar();
+        while ((-1 != lastChar) && (delim != lastChar)) {
+            StringBuffer digitBuffer;
+
+            if (lastChar != '\\') {
+                sb.append((char)lastChar);
+                readChar();
+                continue;
+            }
+
+            readChar();
+
+            switch (lastChar) {
+                case 'b':  readChar(); sb.append('\b'); continue;
+                case 'f':  readChar(); sb.append('\f'); continue;
+                case 'n':  readChar(); sb.append('\n'); continue;
+                case 'r':  readChar(); sb.append('\r'); continue;
+                case 't':  readChar(); sb.append('\t'); continue;
+                case '\'': readChar(); sb.append('\''); continue;
+                case '"':  readChar(); sb.append('"');  continue;
+                case '\\': readChar(); sb.append('\\'); continue;
+                case '/': readChar();  sb.append('/'); continue;
+
+                    // hex constant
+                    // unicode constant
+                case 'x':
+                case 'u':
+                    digitBuffer = new StringBuffer();
+
+                    int toRead = 2;
+                    if (lastChar == 'u') toRead = 4;
+
+                    for (int i=0; i<toRead; i++) {
+                        readChar();
+                        if (!isHexDigit(lastChar)) throw new IOException("non-hex digit " + onLineCol());
+                        digitBuffer.append((char) lastChar);
+                    }
+                    readChar();
+
+                    try {
+                        int digitValue = Integer.parseInt(digitBuffer.toString(), 16);
+                        sb.append((char) digitValue);
+                    } catch (NumberFormatException e) {
+                        throw new IOException("non-hex digit " + onLineCol());
+                    }
+
+                    break;
+
+                    // octal constant
+                default:
+                    if (!isOctalDigit(lastChar)) throw new IOException("non-hex digit " + onLineCol());
+
+                    digitBuffer = new StringBuffer();
+                    digitBuffer.append((char) lastChar);
+
+                    for (int i=0; i<2; i++) {
+                        readChar();
+                        if (!isOctalDigit(lastChar)) break;
+
+                        digitBuffer.append((char) lastChar);
+                    }
+
+                    try {
+                        int digitValue = Integer.parseInt(digitBuffer.toString(), 8);
+                        sb.append((char) digitValue);
+                    } catch (NumberFormatException e) {
+                        throw new IOException("non-hex digit " + onLineCol());
+                    }
+            }
+        }
+
+        if (-1 == lastChar) {
+            throw new IOException("String not terminated " + onLineCol(l,c));
+        }
+
+        readChar();
+
+        return sb.toString();
+    }
+
+    /**
+     * Method to read a number from the JSON string.
+     *
+     * (-)(1-9)(0-9)*            : decimal
+     * (-)0(0-7)*               : octal
+     * (-)0(x|X)(0-9|a-f|A-F)*  : hex
+     * [digits][.digits][(E|e)[(+|-)]digits]
+     *
+     * @returns The number as the wrapper Java Number type.
+     *
+     * @throws IOException Thrown in invalid numbers or unexpected end of JSON string
+     * */
+    private Object readNumber() throws IOException {
+        StringBuffer sb = new StringBuffer();
+        int          l    = lineNo;
+        int          c    = colNo;
+
+        boolean isHex = false;
+
+        if (lastChar == '-') {
+            sb.append((char)lastChar);
+            readChar();
+        }
+        if (lastChar == '0') {
+            sb.append((char)lastChar);
+            readChar();
+            if (lastChar == 'x' || lastChar == 'X') {
+                sb.append((char)lastChar);
+                readChar();
+                isHex = true;
+            }
+        }
+
+        if (isHex) {
+            while (isDigitChar(lastChar) || isHexDigit(lastChar)) {
+                sb.append((char)lastChar);
+                readChar();
+            }
+        }
+        else {
+            while (isDigitChar(lastChar)) {
+                sb.append((char)lastChar);
+                readChar();
+            }
+        }
+
+        // convert it!
+        String string = sb.toString();
+
+        try {
+            if (-1 != string.indexOf('.')) {
+                return Double.valueOf(string);
+            }
+
+            String sign = "";
+            if (string.startsWith("-")) {
+                sign = "-";
+                string = string.substring(1);
+            }
+
+//            if (isHex) {
+//            	Long value = Long.valueOf(sign + string.substring(2),16);
+//                if (value.longValue() <= Integer.MAX_VALUE  && (value.longValue() >= Integer.MIN_VALUE)) {
+//                	return new Integer(value.intValue());
+//                }
+//                else {
+//                	return value;
+//                }
+//            }
+
+            if (string.equals("0")) {
+                return new Integer(0);
+//            } else if (string.startsWith("0") && string.length() > 1) {
+//            	Long value = Long.valueOf(sign + string.substring(1),8);
+//                if (value.longValue() <= Integer.MAX_VALUE  && (value.longValue() >= Integer.MIN_VALUE)) {
+//                	return new Integer(value.intValue());
+//                }
+//                else {
+//                	return value;
+//                }
+            }
+
+            /**
+             * We have to check for the exponential and treat appropriately
+             * Exponentials should be treated as Doubles.
+             */
+            if (string.indexOf("e") != -1 || string.indexOf("E") != -1) {
+                return Double.valueOf(sign + string);
+            } else {
+                Long value = new Long(Long.parseLong(sign+ string, 10));
+                //Long value = Long.valueOf(sign + string);
+                if (value.longValue() <= Integer.MAX_VALUE  && (value.longValue() >= Integer.MIN_VALUE)) {
+                    return new Integer(Integer.parseInt(sign + string, 10));
+                }
+                else {
+                    return value;
+                }
+            }
+           // else return new Integer(0);  //MSN
+        } catch (NumberFormatException e) {
+            IOException iox = new IOException("Invalid number literal " + onLineCol(l,c));
+            //MSNiox.setCause(e);
+            throw iox;
+        }
+    }
+
+    /**
+     * Method to indicate if the character read is a HEX digit or not.
+     * @param c The character to check for being a HEX digit.
+     */
+    private boolean isHexDigit(int c) {
+        switch (c) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case 'A':
+            case 'B':
+            case 'C':
+            case 'D':
+            case 'E':
+            case 'F':
+            case 'a':
+            case 'b':
+            case 'c':
+            case 'd':
+            case 'e':
+            case 'f':
+                return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Method to indicate if the character read is an OCTAL digit or not.
+     * @param c The character to check for being a OCTAL digit.
+     */
+    private boolean isOctalDigit(int c) {
+        switch (c) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+                return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Method to indicate if the character read is a digit or not.
+     * @param c The character to check for being a digit.
+     */
+    private boolean isDigitChar(int c) {
+        switch (c) {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case '.':
+            case 'e':
+            case 'E':
+            case 'x':
+            case 'X':
+            case '+':
+            case '-':
+                return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Method to read a partular character string.
+     * only really need to handle 'null', 'true', and 'false'
+     */
+    private String readIdentifier() throws IOException {
+        StringBuffer sb = new StringBuffer();
+
+        if (this.strict) {
+            while ((-1 != lastChar) && ( (Character.isUpperCase((char)lastChar)) || (Character.isLowerCase((char)lastChar)) ) ){
+                sb.append((char)lastChar);
+                readChar();
+            }
+        }
+        else {
+            while ((-1 != lastChar) && isValidUnquotedChar((char)lastChar)) {
+               sb.append((char)lastChar);
+               readChar();
+           }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Method to read the next character from the string, keeping track of line/column position.
+     *
+     * @throws IOEXception Thrown when underlying reader throws an error.
+     */
+    private void readChar() throws IOException {
+        if ('\n' == lastChar) {
+            this.colNo = 0;
+            this.lineNo++;
+        }
+        lastChar = reader.read();
+        if (-1 == lastChar) return ;
+        colNo++;
+    }
+
+    /**
+     * Method to generate a String indicationg the current line and column position in the JSON string.
+     */
+    private String onLineCol(int line, int col) {
+        return "on line " + line + ", column " + col;
+    }
+
+    /**
+     * Method to generate a String indicationg the current line and column position in the JSON string.
+     */
+    public String onLineCol() {
+        return onLineCol(lineNo,colNo);
+    }
+
+    /**
+     * High speed test for whitespace!  Faster than the java one (from some testing).
+     * @return if the indicated character is whitespace.
+     */
+    public boolean isWhitespace(char c) {
+        switch (c) {
+            case 9:  //'unicode: 0009
+            case 10: //'unicode: 000A'
+            case 11: //'unicode: 000B'
+            case 12: //'unicode: 000C'
+            case 13: //'unicode: 000D'
+            case 28: //'unicode: 001C'
+            case 29: //'unicode: 001D'
+            case 30: //'unicode: 001E'
+            case 31: //'unicode: 001F'
+            case ' ': // Space
+                //case Character.SPACE_SEPARATOR:
+                //case Character.LINE_SEPARATOR:
+           //MSN  case Character.PARAGRAPH_SEPARATOR:
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * For non strict mode, check if char is valid when not quoted.
+     * @param c
+     * @return if character is valid unquoted character.
+     */
+    public boolean isValidUnquotedChar(char c) {
+
+        if ( (Character.isDigit(c)) || (Character.isLowerCase(c)) || (Character.isUpperCase(c)) ) {
+            return true;
+        }
+
+        switch (c) {
+        case '@':
+        case '-':
+        case '.':
+        case '$':
+        case '+':
+        case '!':
+        case '_':
+            return true;
+        }
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/media/AudioCaptureListener.java
----------------------------------------------------------------------
diff --git a/framework/ext/src/org/apache/cordova/media/AudioCaptureListener.java b/framework/ext/src/org/apache/cordova/media/AudioCaptureListener.java
new file mode 100644
index 0000000..a99d5b1
--- /dev/null
+++ b/framework/ext/src/org/apache/cordova/media/AudioCaptureListener.java
@@ -0,0 +1,80 @@
+/*
+ * 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.media;
+
+import net.rim.device.api.io.file.FileSystemJournal;
+import net.rim.device.api.io.file.FileSystemJournalEntry;
+import net.rim.device.api.io.file.FileSystemJournalListener;
+
+/**
+ * Listens for audio recording files that are added to file system.
+ * <p>
+ * Audio recordings are added to the file system when the user stops the
+ * recording. The audio recording file extension is '.amr'. Therefore, we listen
+ * for the <code>FileSystemJournalEntry.FILE_ADDED</code> event, capturing when
+ * the new file is written.
+ * <p>
+ * The file system notifications will arrive on the application event thread.
+ * When it receives a notification, it adds the image file path to a MediaQueue
+ * so that the capture thread can process the file.
+ */
+public class AudioCaptureListener implements FileSystemJournalListener {
+    /**
+     * Used to track file system changes.
+     */
+    private long lastUSN = 0;
+
+    /**
+     * Queue to send media files to for processing.
+     */
+    private MediaQueue queue = null;
+
+    /**
+     * Constructor.
+     */
+    AudioCaptureListener(MediaQueue queue) {
+        this.queue = queue;
+    }
+
+    public void fileJournalChanged() {
+        // next sequence number file system will use
+        long USN = FileSystemJournal.getNextUSN();
+
+        for (long i = USN - 1; i >= lastUSN && i < USN; --i) {
+            FileSystemJournalEntry entry = FileSystemJournal.getEntry(i);
+            if (entry == null) {
+                break;
+            }
+
+            // has audio recording file has been added to the file system?
+            String path = entry.getPath();
+            if (entry.getEvent() == FileSystemJournalEntry.FILE_ADDED
+                    && path.endsWith(".amr")) {
+                // add file path to the capture queue
+                queue.add("file://" + path);
+
+                break;
+            }
+        }
+
+        // remember the file journal change number,
+        // so we don't search the same events again and again
+        lastUSN = USN;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/media/AudioCaptureOperation.java
----------------------------------------------------------------------
diff --git a/framework/ext/src/org/apache/cordova/media/AudioCaptureOperation.java b/framework/ext/src/org/apache/cordova/media/AudioCaptureOperation.java
new file mode 100644
index 0000000..cbd274d
--- /dev/null
+++ b/framework/ext/src/org/apache/cordova/media/AudioCaptureOperation.java
@@ -0,0 +1,133 @@
+/*
+ * 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.media;
+
+import java.io.IOException;
+
+import javax.microedition.io.Connector;
+import javax.microedition.io.file.FileConnection;
+
+import org.apache.cordova.file.File;
+import org.apache.cordova.file.FileUtils;
+import org.apache.cordova.util.Logger;
+
+import net.rim.device.api.io.MIMETypeAssociations;
+import net.rim.device.api.ui.UiApplication;
+
+public class AudioCaptureOperation extends CaptureOperation {
+
+    // content type
+    public static final String CONTENT_TYPE = "audio/";
+
+    // maximum duration to capture media (milliseconds)
+    private long duration = 0;
+
+    // file system listener
+    private AudioCaptureListener listener = null;
+
+    /**
+     * Creates and starts an audio capture operation.
+     *
+     * @param limit
+     *            maximum number of media files to capture
+     * @param duration
+     *            maximum duration to capture media (milliseconds)
+     * @param callbackId
+     *            the callback to receive the files
+     * @param queue
+     *            the queue from which to retrieve captured media files
+     */
+    public AudioCaptureOperation(int limit, long duration, String callbackId, MediaQueue queue) {
+        super(limit, callbackId, queue);
+
+        if (duration > 0) {
+            this.duration = duration;
+        }
+
+        // listener to capture image files added to file system
+        this.listener = new AudioCaptureListener(queue);
+
+        start();
+    }
+
+    /**
+     * Registers file system listener and launches native voice notes recorder
+     * application.
+     */
+    protected void setup() {
+        // register listener for files being written
+        synchronized(UiApplication.getEventLock()) {
+            UiApplication.getUiApplication().addFileSystemJournalListener(listener);
+        }
+
+        // launch the native voice notes recorder application
+        AudioControl.launchAudioRecorder();
+    }
+
+    /**
+     * Unregisters file system listener and closes native voice notes recorder
+     * application.
+     */
+    protected void teardown() {
+        // remove file system listener
+        synchronized(UiApplication.getEventLock()) {
+            UiApplication.getUiApplication().removeFileSystemJournalListener(listener);
+        }
+
+        // close the native voice notes recorder application
+        AudioControl.closeAudioRecorder();
+    }
+
+    /**
+     * Retrieves the file properties for the captured audio recording.
+     *
+     * @param filePath
+     *            full path of the audio recording file
+     */
+    protected void processFile(String filePath) {
+        Logger.log(this.getClass().getName() + ": processing file: " + filePath);
+
+        File file = new File(FileUtils.stripSeparator(filePath));
+
+        // grab file properties
+        FileConnection fconn = null;
+        try {
+            fconn = (FileConnection) Connector.open(filePath, Connector.READ);
+            if (fconn.exists()) {
+                long size = fconn.fileSize();
+                Logger.log(this.getClass().getName() + ": " + filePath + " size="
+                        + Long.toString(size) + " bytes");
+                file.setLastModifiedDate(fconn.lastModified());
+                file.setName(FileUtils.stripSeparator(fconn.getName()));
+                file.setSize(size);
+                file.setType(MIMETypeAssociations.getMIMEType(filePath));
+            }
+        }
+        catch (IOException e) {
+            Logger.log(this.getClass().getName() + ": " + e);
+        }
+        finally {
+            try {
+                if (fconn != null) fconn.close();
+            } catch (IOException ignored) {}
+        }
+
+        addCaptureFile(file);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/media/AudioControl.java
----------------------------------------------------------------------
diff --git a/framework/ext/src/org/apache/cordova/media/AudioControl.java b/framework/ext/src/org/apache/cordova/media/AudioControl.java
new file mode 100644
index 0000000..e9d87c3
--- /dev/null
+++ b/framework/ext/src/org/apache/cordova/media/AudioControl.java
@@ -0,0 +1,75 @@
+/*
+ * 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.media;
+
+import org.apache.cordova.util.ApplicationUtils;
+import org.apache.cordova.util.Logger;
+
+import net.rim.device.api.system.ApplicationDescriptor;
+import net.rim.device.api.system.ApplicationManager;
+import net.rim.device.api.system.ApplicationManagerException;
+import net.rim.device.api.system.CodeModuleManager;
+
+public class AudioControl {
+    /**
+     * Determines if the native voice notes recorder application is installed
+     * on the device.
+     *
+     * @return true if native voice notes recorder application is installed
+     */
+    public static boolean hasAudioRecorderApplication() {
+        return ApplicationUtils.isModuleInstalled("net_rim_bb_voicenotesrecorder");
+    }
+
+    /**
+     * Determines if the native voice notes recorder application is running in
+     * the foreground.
+     *
+     * @return true if native voice notes recorder application is running in
+     *         foreground
+     */
+    public static boolean isAudioRecorderActive() {
+        return ApplicationUtils.isApplicationInForeground("net_rim_bb_voicenotesrecorder");
+    }
+
+    /**
+     * Launches the native audio recorder application.
+     */
+    public static void launchAudioRecorder() {
+        int handle = CodeModuleManager.getModuleHandle("net_rim_bb_voicenotesrecorder");
+        ApplicationDescriptor ad = CodeModuleManager.getApplicationDescriptors(handle)[0];
+        ApplicationDescriptor ad2 = new ApplicationDescriptor(ad, null);
+        try {
+            ApplicationManager.getApplicationManager().runApplication(ad2, true);
+        }
+        catch (ApplicationManagerException e) {
+            Logger.log(AudioControl.class.getName() + ": unable to launch net_rim_bb_voicenotesrecorder");
+        }
+    }
+
+    /**
+     * Closes the native audio recorder application.
+     */
+    public static void closeAudioRecorder() {
+        if (!isAudioRecorderActive()) {
+            return;
+        }
+        ApplicationUtils.injectEscKeyPress(1);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/media/CameraControl.java
----------------------------------------------------------------------
diff --git a/framework/ext/src/org/apache/cordova/media/CameraControl.java b/framework/ext/src/org/apache/cordova/media/CameraControl.java
new file mode 100644
index 0000000..16c59cb
--- /dev/null
+++ b/framework/ext/src/org/apache/cordova/media/CameraControl.java
@@ -0,0 +1,87 @@
+/*
+ * 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.media;
+
+import org.apache.cordova.util.ApplicationUtils;
+
+import net.rim.blackberry.api.invoke.CameraArguments;
+import net.rim.blackberry.api.invoke.Invoke;
+import net.rim.device.api.ui.UiApplication;
+
+public class CameraControl {
+    /**
+     * Determines if the native camera application is running in the foreground.
+     *
+     * @return true if native camera application is running in foreground
+     */
+    public static boolean isCameraActive() {
+        return ApplicationUtils.isApplicationInForeground("net_rim_bb_camera");
+    }
+
+    /**
+     * Determines if the native video recorder application is running in the
+     * foreground.
+     *
+     * @return true if native video recorder application is running in
+     *         foreground
+     */
+    public static boolean isVideoRecorderActive() {
+        return ApplicationUtils.isApplicationInForeground("net_rim_bb_videorecorder");
+    }
+
+    /**
+     * Launches the native camera application.
+     */
+    public static void launchCamera() {
+        synchronized(UiApplication.getEventLock()) {
+            Invoke.invokeApplication(Invoke.APP_TYPE_CAMERA,
+                    new CameraArguments());
+        }
+    }
+
+    /**
+     * Launches the native video recorder application.
+     */
+    public static void launchVideoRecorder() {
+        synchronized(UiApplication.getEventLock()) {
+            Invoke.invokeApplication(Invoke.APP_TYPE_CAMERA,
+                    new CameraArguments(CameraArguments.ARG_VIDEO_RECORDER));
+        }
+    }
+
+    /**
+     * Closes the native camera application.
+     */
+    public static void closeCamera() {
+        if (!isCameraActive()) {
+            return;
+        }
+        ApplicationUtils.injectEscKeyPress(2);
+    }
+
+    /**
+     * Closes the native video recorder application.
+     */
+    public static void closeVideoRecorder() {
+        if (!isVideoRecorderActive()) {
+            return;
+        }
+        ApplicationUtils.injectEscKeyPress(2);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-blackberry-webworks/blob/05319d3c/framework/ext/src/org/apache/cordova/media/CaptureControl.java
----------------------------------------------------------------------
diff --git a/framework/ext/src/org/apache/cordova/media/CaptureControl.java b/framework/ext/src/org/apache/cordova/media/CaptureControl.java
new file mode 100644
index 0000000..b57b794
--- /dev/null
+++ b/framework/ext/src/org/apache/cordova/media/CaptureControl.java
@@ -0,0 +1,169 @@
+/*
+ * 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.media;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+public class CaptureControl {
+
+    /**
+     * Pending capture operations.
+     */
+    private Vector pendingOperations = new Vector();
+
+    /**
+     * Singleton.
+     */
+    private CaptureControl() {}
+
+    /**
+     * Holds the singleton for lazy instantiation.
+     */
+    private static class CaptureControlHolder {
+        static final CaptureControl INSTANCE = new CaptureControl();
+    }
+
+    /**
+     * Retrieves a CaptureControl instance.
+     * @return CaptureControl instance.
+     */
+    public static final CaptureControl getCaptureControl() {
+        return CaptureControlHolder.INSTANCE;
+    }
+
+    /**
+     * Add capture operation so we can stop it manually.
+     */
+    public void addCaptureOperation(CaptureOperation operation) {
+        if (operation == null) {
+            return;
+        }
+
+        synchronized (pendingOperations) {
+            pendingOperations.addElement(operation);
+        }
+    }
+
+    /**
+     * Remove capture operation.
+     */
+    public void removeCaptureOperation(CaptureOperation operation) {
+        if (operation == null) {
+            return;
+        }
+
+        synchronized (pendingOperations) {
+            pendingOperations.removeElement(operation);
+        }
+    }
+
+    /**
+     * Starts an image capture operation, during which a user can take multiple
+     * photos. The capture operation runs in the background.
+     *
+     * @param limit
+     *            the maximum number of images to capture during the operation
+     * @param callbackId
+     *            the callback to be invoked with capture file properties
+     */
+    public void startImageCaptureOperation(int limit, String callbackId) {
+        // setup a queue to receive image file paths
+        MediaQueue queue = new MediaQueue();
+
+        // start a capture operation on a background thread
+        CaptureOperation operation = new ImageCaptureOperation(limit,
+                callbackId, queue);
+
+        // track the operation so we can stop or cancel it later
+        addCaptureOperation(operation);
+    }
+
+    /**
+     * Starts a video capture operation, during which a user can record multiple
+     * recordings.  The capture operation runs in the background.
+     *
+     * @param limit
+     *            the maximum number of images to capture during the operation
+     * @param callbackId
+     *            the callback to be invoked with capture file properties
+     */
+    public void startVideoCaptureOperation(int limit, String callbackId) {
+        // setup a queue to receive video recording file paths
+        MediaQueue queue = new MediaQueue();
+
+        // start a capture operation on a background thread
+        CaptureOperation operation = new VideoCaptureOperation(limit,
+                callbackId, queue);
+
+        // track the operation so we can stop or cancel it later
+        addCaptureOperation(operation);
+    }
+
+    /**
+     * Starts an audio capture operation using the native voice notes recorder
+     * application.
+     *
+     * @param limit
+     *            the maximum number of audio clips to capture during the
+     *            operation
+     * @param duration
+     *            the maximum duration of each captured clip
+     * @param callbackId
+     *            the callback to be invoked with the capture results
+     */
+    public void startAudioCaptureOperation(int limit, long duration, String callbackId) {
+        // setup a queue to receive recording file paths
+        MediaQueue queue = new MediaQueue();
+
+        // start a capture operation on a background thread
+        CaptureOperation operation = new AudioCaptureOperation(limit, duration,
+                callbackId, queue);
+
+        // track the operation so we can stop or cancel it later
+        addCaptureOperation(operation);
+    }
+
+    /**
+     * Stops all pending capture operations. If the <code>cancel</code>
+     * parameter is <code>true</code>, no results will be sent via the callback
+     * mechanism and any captured files will be removed from the file system.
+     *
+     * @param cancel
+     *            true if operations should be canceled
+     */
+    public void stopPendingOperations(boolean cancel) {
+        // There are two scenarios where the capture operation would be stopped
+        // manually:
+        // 1- The user stops the capture application, and this application
+        //    returns to the foreground.
+        // 2- It is canceled programmatically.  No results should be sent.
+        synchronized (pendingOperations) {
+            for (Enumeration e = pendingOperations.elements(); e.hasMoreElements(); ) {
+                CaptureOperation operation = (CaptureOperation) e.nextElement();
+                if (cancel) {
+                    operation.cancel();
+                }
+                else {
+                    operation.stop();
+                }
+            }
+        }
+    }
+}


Mime
View raw message