geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dschnei...@apache.org
Subject [03/51] [abbrv] geode git commit: GEODE-2142: Adding JSON library from the https://github.com/tdunning/open-json project
Date Tue, 07 Mar 2017 19:21:26 GMT
http://git-wip-us.apache.org/repos/asf/geode/blob/b34e47ff/geode-json/src/main/java/org/json/JSONStringer.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSONStringer.java b/geode-json/src/main/java/org/json/JSONStringer.java
new file mode 100755
index 0000000..db1121e
--- /dev/null
+++ b/geode-json/src/main/java/org/json/JSONStringer.java
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed 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.json;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+// Note: this class was written without inspecting the non-free org.json sourcecode.
+
+/**
+ * Implements {@link JSONObject#toString} and {@link JSONArray#toString}. Most
+ * application developers should use those methods directly and disregard this
+ * API. For example:<pre>
+ * JSONObject object = ...
+ * String json = object.toString();</pre>
+ *
+ * <p>Stringers only encode well-formed JSON strings. In particular:
+ * <ul>
+ * <li>The stringer must have exactly one top-level array or object.
+ * <li>Lexical scopes must be balanced: every call to {@link #array} must
+ * have a matching call to {@link #endArray} and every call to {@link
+ * #object} must have a matching call to {@link #endObject}.
+ * <li>Arrays may not contain keys (property names).
+ * <li>Objects must alternate keys (property names) and values.
+ * <li>Values are inserted with either literal {@link #value(Object) value}
+ * calls, or by nesting arrays or objects.
+ * </ul>
+ * Calls that would result in a malformed JSON string will fail with a
+ * {@link JSONException}.
+ *
+ * <p>This class provides no facility for pretty-printing (ie. indenting)
+ * output. To encode indented output, use {@link JSONObject#toString(int)} or
+ * {@link JSONArray#toString(int)}.
+ *
+ * <p>Some implementations of the API support at most 20 levels of nesting.
+ * Attempts to create more than 20 levels of nesting may fail with a {@link
+ * JSONException}.
+ *
+ * <p>Each stringer may be used to encode a single top level value. Instances of
+ * this class are not thread safe. Although this class is nonfinal, it was not
+ * designed for inheritance and should not be subclassed. In particular,
+ * self-use by overrideable methods is not specified. See <i>Effective Java</i>
+ * Item 17, "Design and Document or inheritance or else prohibit it" for further
+ * information.
+ */
+public class JSONStringer {
+
+    /**
+     * The output data, containing at most one top-level array or object.
+     */
+    final StringBuilder out = new StringBuilder();
+
+    /**
+     * Lexical scoping elements within this stringer, necessary to insert the
+     * appropriate separator characters (ie. commas and colons) and to detect
+     * nesting errors.
+     */
+    enum Scope {
+
+        /**
+         * An array with no elements requires no separators or newlines before
+         * it is closed.
+         */
+        EMPTY_ARRAY,
+
+        /**
+         * A array with at least one value requires a comma and newline before
+         * the next element.
+         */
+        NONEMPTY_ARRAY,
+
+        /**
+         * An object with no keys or values requires no separators or newlines
+         * before it is closed.
+         */
+        EMPTY_OBJECT,
+
+        /**
+         * An object whose most recent element is a key. The next element must
+         * be a value.
+         */
+        DANGLING_KEY,
+
+        /**
+         * An object with at least one name/value pair requires a comma and
+         * newline before the next element.
+         */
+        NONEMPTY_OBJECT,
+
+        /**
+         * A special bracketless array needed by JSONStringer.join() and
+         * JSONObject.quote() only. Not used for JSON encoding.
+         */
+        NULL,
+    }
+
+    /**
+     * Unlike the original implementation, this stack isn't limited to 20
+     * levels of nesting.
+     */
+    private final List<Scope> stack = new ArrayList<Scope>();
+
+    /**
+     * A string containing a full set of spaces for a single level of
+     * indentation, or null for no pretty printing.
+     */
+    private final String indent;
+
+    public JSONStringer() {
+        indent = null;
+    }
+
+    JSONStringer(int indentSpaces) {
+        char[] indentChars = new char[indentSpaces];
+        Arrays.fill(indentChars, ' ');
+        indent = new String(indentChars);
+    }
+
+    /**
+     * Begins encoding a new array. Each call to this method must be paired with
+     * a call to {@link #endArray}.
+     *
+     * @return this stringer.
+     * @throws JSONException On internal errors. Shouldn't happen.
+     */
+    public JSONStringer array() throws JSONException {
+        return open(Scope.EMPTY_ARRAY, "[");
+    }
+
+    /**
+     * Ends encoding the current array.
+     *
+     * @return this stringer.
+     * @throws JSONException On internal errors. Shouldn't happen.
+     */
+    public JSONStringer endArray() throws JSONException {
+        return close(Scope.EMPTY_ARRAY, Scope.NONEMPTY_ARRAY, "]");
+    }
+
+    /**
+     * Begins encoding a new object. Each call to this method must be paired
+     * with a call to {@link #endObject}.
+     *
+     * @return this stringer.
+     * @throws JSONException On internal errors. Shouldn't happen.
+     */
+    public JSONStringer object() throws JSONException {
+        return open(Scope.EMPTY_OBJECT, "{");
+    }
+
+    /**
+     * Ends encoding the current object.
+     *
+     * @return this stringer.
+     * @throws JSONException On internal errors. Shouldn't happen.
+     */
+    public JSONStringer endObject() throws JSONException {
+        return close(Scope.EMPTY_OBJECT, Scope.NONEMPTY_OBJECT, "}");
+    }
+
+    /**
+     * Enters a new scope by appending any necessary whitespace and the given
+     * bracket.
+     */
+    JSONStringer open(Scope empty, String openBracket) throws JSONException {
+        if (stack.isEmpty() && out.length() > 0) {
+            throw new JSONException("Nesting problem: multiple top-level roots");
+        }
+        beforeValue();
+        stack.add(empty);
+        out.append(openBracket);
+        return this;
+    }
+
+    /**
+     * Closes the current scope by appending any necessary whitespace and the
+     * given bracket.
+     */
+    JSONStringer close(Scope empty, Scope nonempty, String closeBracket) throws JSONException {
+        Scope context = peek();
+        if (context != nonempty && context != empty) {
+            throw new JSONException("Nesting problem");
+        }
+
+        stack.remove(stack.size() - 1);
+        if (context == nonempty) {
+            newline();
+        }
+        out.append(closeBracket);
+        return this;
+    }
+
+    /**
+     * Returns the value on the top of the stack.
+     */
+    private Scope peek() throws JSONException {
+        if (stack.isEmpty()) {
+            throw new JSONException("Nesting problem");
+        }
+        return stack.get(stack.size() - 1);
+    }
+
+    /**
+     * Replace the value on the top of the stack with the given value.
+     */
+    private void replaceTop(Scope topOfStack) {
+        stack.set(stack.size() - 1, topOfStack);
+    }
+
+    /**
+     * Encodes {@code value}.
+     *
+     * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
+     *              Integer, Long, Double or null. May not be {@link Double#isNaN() NaNs}
+     *              or {@link Double#isInfinite() infinities}.
+     * @return this stringer.
+     * @throws JSONException On internal errors. Shouldn't happen.
+     */
+    public JSONStringer value(Object value) throws JSONException {
+        if (stack.isEmpty()) {
+            throw new JSONException("Nesting problem");
+        }
+
+        if (value instanceof JSONArray) {
+            ((JSONArray) value).writeTo(this);
+            return this;
+
+        } else if (value instanceof JSONObject) {
+            ((JSONObject) value).writeTo(this);
+            return this;
+        }
+
+        beforeValue();
+
+        if (value instanceof JSONString) {
+          out.append(((JSONString) value).toJSONString());
+          return this;
+        }
+
+        if (value == null
+              || value instanceof Boolean
+              || value == JSONObject.NULL) {
+            out.append(value);
+
+        } else if (value instanceof Number) {
+            out.append(JSONObject.numberToString((Number) value));
+
+        } else {
+            // Hack to make it possible that the value is not surrounded by quotes. (Used for JavaScript function calls)
+            // Example: { "name": "testkey", "value": window.myfunction() }
+            if (value.getClass().getSimpleName().contains("JSONFunction")) {
+                // note that no escaping of quotes (or anything else) is done in this case.
+                // that is fine because the only way to get to this point is to
+                // explicitly put a special kind of object into the JSON data structure.
+                out.append(value);
+            } else {
+                string(value.toString());
+            }
+        }
+
+        return this;
+    }
+
+    /**
+     * Encodes {@code value} to this stringer.
+     *
+     * @param value The value to encode.
+     * @return this stringer.
+     * @throws JSONException On internal errors. Shouldn't happen.
+     */
+    public JSONStringer value(boolean value) throws JSONException {
+        if (stack.isEmpty()) {
+            throw new JSONException("Nesting problem");
+        }
+        beforeValue();
+        out.append(value);
+        return this;
+    }
+
+    /**
+     * Encodes {@code value} to this stringer.
+     *
+     * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
+     *              {@link Double#isInfinite() infinities}.
+     * @return this stringer.
+     * @throws JSONException On internal errors. Shouldn't happen.
+     */
+    public JSONStringer value(double value) throws JSONException {
+        if (stack.isEmpty()) {
+            throw new JSONException("Nesting problem");
+        }
+        beforeValue();
+        out.append(JSONObject.numberToString(value));
+        return this;
+    }
+
+    /**
+     * Encodes {@code value} to this stringer.
+     *
+     * @param value The value to encode.
+     * @return this stringer.
+     * @throws JSONException If we have an internal error. Shouldn't happen.
+     */
+    public JSONStringer value(long value) throws JSONException {
+        if (stack.isEmpty()) {
+            throw new JSONException("Nesting problem");
+        }
+        beforeValue();
+        out.append(value);
+        return this;
+    }
+
+    private void string(String value) {
+        out.append("\"");
+        char currentChar = 0;
+
+        for (int i = 0, length = value.length(); i < length; i++) {
+            char previousChar = currentChar;
+            currentChar = value.charAt(i);
+
+            /*
+             * From RFC 4627, "All Unicode characters may be placed within the
+             * quotation marks except for the characters that must be escaped:
+             * quotation mark, reverse solidus, and the control characters
+             * (U+0000 through U+001F)."
+             */
+            switch (currentChar) {
+                case '"':
+                case '\\':
+                    out.append('\\').append(currentChar);
+                    break;
+
+                case '/':
+                    // it makes life easier for HTML embedding of javascript if we escape </ sequences
+                    if (previousChar == '<') {
+                        out.append('\\');
+                    }
+                    out.append(currentChar);
+                    break;
+
+                case '\t':
+                    out.append("\\t");
+                    break;
+
+                case '\b':
+                    out.append("\\b");
+                    break;
+
+                case '\n':
+                    out.append("\\n");
+                    break;
+
+                case '\r':
+                    out.append("\\r");
+                    break;
+
+                case '\f':
+                    out.append("\\f");
+                    break;
+
+                default:
+                    if (currentChar <= 0x1F) {
+                        out.append(String.format("\\u%04x", (int) currentChar));
+                    } else {
+                        out.append(currentChar);
+                    }
+                    break;
+            }
+
+        }
+        out.append("\"");
+    }
+
+    private void newline() {
+        if (indent == null) {
+            return;
+        }
+
+        out.append("\n");
+        for (int i = 0; i < stack.size(); i++) {
+            out.append(indent);
+        }
+    }
+
+    /**
+     * Encodes the key (property name) to this stringer.
+     *
+     * @param name the name of the forthcoming value. May not be null.
+     * @return this stringer.
+     * @throws JSONException on internal errors, shouldn't happen.
+     */
+    public JSONStringer key(String name) throws JSONException {
+        if (name == null) {
+            throw new JSONException("Names must be non-null");
+        }
+        beforeKey();
+        string(name);
+        return this;
+    }
+
+    /**
+     * Inserts any necessary separators and whitespace before a name. Also
+     * adjusts the stack to expect the key's value.
+     */
+    private void beforeKey() throws JSONException {
+        Scope context = peek();
+        if (context == Scope.NONEMPTY_OBJECT) { // first in object
+            out.append(',');
+        } else if (context != Scope.EMPTY_OBJECT) { // not in an object!
+            throw new JSONException("Nesting problem");
+        }
+        newline();
+        replaceTop(Scope.DANGLING_KEY);
+    }
+
+    /**
+     * Inserts any necessary separators and whitespace before a literal value,
+     * inline array, or inline object. Also adjusts the stack to expect either a
+     * closing bracket or another element.
+     */
+    private void beforeValue() throws JSONException {
+        if (stack.isEmpty()) {
+            return;
+        }
+
+        Scope context = peek();
+        if (context == Scope.EMPTY_ARRAY) { // first in array
+            replaceTop(Scope.NONEMPTY_ARRAY);
+            newline();
+        } else if (context == Scope.NONEMPTY_ARRAY) { // another in array
+            out.append(',');
+            newline();
+        } else if (context == Scope.DANGLING_KEY) { // value for key
+            out.append(indent == null ? ":" : ": ");
+            replaceTop(Scope.NONEMPTY_OBJECT);
+        } else if (context != Scope.NULL) {
+            throw new JSONException("Nesting problem");
+        }
+    }
+
+    /**
+     * Returns the encoded JSON string.
+     *
+     * <p>If invoked with unterminated arrays or unclosed objects, this method's
+     * return value is undefined.
+     *
+     * <p><strong>Warning:</strong> although it contradicts the general contract
+     * of {@link Object#toString}, this method returns null if the stringer
+     * contains no data.
+     */
+    @Override
+    public String toString() {
+        return out.length() == 0 ? null : out.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/b34e47ff/geode-json/src/main/java/org/json/JSONTokener.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSONTokener.java b/geode-json/src/main/java/org/json/JSONTokener.java
new file mode 100755
index 0000000..59eb4bc
--- /dev/null
+++ b/geode-json/src/main/java/org/json/JSONTokener.java
@@ -0,0 +1,658 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed 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.json;
+
+// Note: this class was written without inspecting the non-free org.json sourcecode.
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * Parses a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>)
+ * encoded string into the corresponding object. Most clients of
+ * this class will use only need the {@link #JSONTokener(String) constructor}
+ * and {@link #nextValue} method. Example usage: <pre>
+ * String json = "{"
+ *         + "  \"query\": \"Pizza\", "
+ *         + "  \"locations\": [ 94043, 90210 ] "
+ *         + "}";
+ *
+ * JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
+ * String query = object.getString("query");
+ * JSONArray locations = object.getJSONArray("locations");</pre>
+ *
+ * <p>For best interoperability and performance use JSON that complies with
+ * RFC 4627, such as that generated by {@link JSONStringer}. For legacy reasons
+ * this parser is lenient, so a successful parse does not indicate that the
+ * input string was valid JSON. All of the following syntax errors will be
+ * ignored:
+ * <ul>
+ * <li>End of line comments starting with {@code //} or {@code #} and ending
+ * with a newline character.
+ * <li>C-style comments starting with {@code /*} and ending with
+ * {@code *}{@code /}. Such comments may not be nested.
+ * <li>Strings that are unquoted or {@code 'single quoted'}.
+ * <li>Hexadecimal integers prefixed with {@code 0x} or {@code 0X}.
+ * <li>Octal integers prefixed with {@code 0}.
+ * <li>Array elements separated by {@code ;}.
+ * <li>Unnecessary array separators. These are interpreted as if null was the
+ * omitted value.
+ * <li>Key-value pairs separated by {@code =} or {@code =>}.
+ * <li>Key-value pairs separated by {@code ;}.
+ * </ul>
+ *
+ * <p>Each tokener may be used to parse a single JSON string. Instances of this
+ * class are not thread safe. Although this class is nonfinal, it was not
+ * designed for inheritance and should not be subclassed. In particular,
+ * self-use by overrideable methods is not specified. See <i>Effective Java</i>
+ * Item 17, "Design and Document or inheritance or else prohibit it" for further
+ * information.
+ */
+public class JSONTokener {
+
+    /**
+     * The input JSON.
+     */
+    private final String in;
+
+    /**
+     * The index of the next character to be returned by {@link #next}. When
+     * the input is exhausted, this equals the input's length.
+     */
+    private int pos;
+
+    /**
+     * @param in JSON encoded string. Null is not permitted and will yield a
+     *           tokener that throws {@code NullPointerExceptions} when methods are
+     *           called.
+     */
+    public JSONTokener(String in) {
+        // consume an optional byte order mark (BOM) if it exists
+        if (in != null && in.startsWith("\ufeff")) {
+            in = in.substring(1);
+        }
+        this.in = in;
+    }
+
+    public JSONTokener(Reader input) throws IOException {
+        StringBuilder s = new StringBuilder();
+        char[] readBuf = new char[102400];
+        int n = input.read(readBuf);
+        while (n >= 0) {
+            s.append(readBuf, 0, n);
+            n = input.read(readBuf);
+        }
+        in = s.toString();
+        pos = 0;
+    }
+
+    /**
+     * Returns the next value from the input.
+     *
+     * @return a {@link JSONObject}, {@link JSONArray}, String, Boolean,
+     * Integer, Long, Double or {@link JSONObject#NULL}.
+     * @throws JSONException if the input is malformed.
+     */
+    public Object nextValue() throws JSONException {
+        int c = nextCleanInternal();
+        switch (c) {
+            case -1:
+                throw syntaxError("End of input");
+
+            case '{':
+                return readObject();
+
+            case '[':
+                return readArray();
+
+            case '\'':
+            case '"':
+                return nextString((char) c);
+
+            default:
+                pos--;
+                return readLiteral();
+        }
+    }
+
+    private int nextCleanInternal() throws JSONException {
+        while (pos < in.length()) {
+            int c = in.charAt(pos++);
+            switch (c) {
+                case '\t':
+                case ' ':
+                case '\n':
+                case '\r':
+                    continue;
+
+                case '/':
+                    if (pos == in.length()) {
+                        return c;
+                    }
+
+                    char peek = in.charAt(pos);
+                    switch (peek) {
+                        case '*':
+                            // skip a /* c-style comment */
+                            pos++;
+                            int commentEnd = in.indexOf("*/", pos);
+                            if (commentEnd == -1) {
+                                throw syntaxError("Unterminated comment");
+                            }
+                            pos = commentEnd + 2;
+                            continue;
+
+                        case '/':
+                            // skip a // end-of-line comment
+                            pos++;
+                            skipToEndOfLine();
+                            continue;
+
+                        default:
+                            return c;
+                    }
+
+                case '#':
+                    /*
+                     * Skip a # hash end-of-line comment. The JSON RFC doesn't
+                     * specify this behavior, but it's required to parse
+                     * existing documents. See http://b/2571423.
+                     */
+                    skipToEndOfLine();
+                    continue;
+
+                default:
+                    return c;
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Advances the position until after the next newline character. If the line
+     * is terminated by "\r\n", the '\n' must be consumed as whitespace by the
+     * caller.
+     */
+    private void skipToEndOfLine() {
+        for (; pos < in.length(); pos++) {
+            char c = in.charAt(pos);
+            if (c == '\r' || c == '\n') {
+                pos++;
+                break;
+            }
+        }
+    }
+
+    /**
+     * Returns the string up to but not including {@code quote}, unescaping any
+     * character escape sequences encountered along the way. The opening quote
+     * should have already been read. This consumes the closing quote, but does
+     * not include it in the returned string.
+     *
+     * @param quote either ' or ".
+     * @return The unescaped string.
+     * @throws JSONException if the string isn't terminated by a closing quote correctly.
+     */
+    public String nextString(char quote) throws JSONException {
+        /*
+         * For strings that are free of escape sequences, we can just extract
+         * the result as a substring of the input. But if we encounter an escape
+         * sequence, we need to use a StringBuilder to compose the result.
+         */
+        StringBuilder builder = null;
+
+        /* the index of the first character not yet appended to the builder. */
+        int start = pos;
+
+        while (pos < in.length()) {
+            int c = in.charAt(pos++);
+            if (c == quote) {
+                if (builder == null) {
+                    // a new string avoids leaking memory
+                    //noinspection RedundantStringConstructorCall
+                    return new String(in.substring(start, pos - 1));
+                } else {
+                    builder.append(in, start, pos - 1);
+                    return builder.toString();
+                }
+            }
+
+            if (c == '\\') {
+                if (pos == in.length()) {
+                    throw syntaxError("Unterminated escape sequence");
+                }
+                if (builder == null) {
+                    builder = new StringBuilder();
+                }
+                builder.append(in, start, pos - 1);
+                builder.append(readEscapeCharacter());
+                start = pos;
+            }
+        }
+
+        throw syntaxError("Unterminated string");
+    }
+
+    /**
+     * Unescapes the character identified by the character or characters that
+     * immediately follow a backslash. The backslash '\' should have already
+     * been read. This supports both unicode escapes "u000A" and two-character
+     * escapes "\n".
+     */
+    private char readEscapeCharacter() throws JSONException {
+        char escaped = in.charAt(pos++);
+        switch (escaped) {
+            case 'u':
+                if (pos + 4 > in.length()) {
+                    throw syntaxError("Unterminated escape sequence");
+                }
+                String hex = in.substring(pos, pos + 4);
+                pos += 4;
+                try {
+                    return (char) Integer.parseInt(hex, 16);
+                } catch (NumberFormatException nfe) {
+                    throw syntaxError("Invalid escape sequence: " + hex);
+                }
+
+            case 't':
+                return '\t';
+
+            case 'b':
+                return '\b';
+
+            case 'n':
+                return '\n';
+
+            case 'r':
+                return '\r';
+
+            case 'f':
+                return '\f';
+
+            case '\'':
+            case '"':
+            case '\\':
+            default:
+                return escaped;
+        }
+    }
+
+    /**
+     * Reads a null, boolean, numeric or unquoted string literal value. Numeric
+     * values will be returned as an Integer, Long, or Double, in that order of
+     * preference.
+     */
+    private Object readLiteral() throws JSONException {
+        String literal = nextToInternal("{}[]/\\:,=;# \t\f");
+
+        if (literal.length() == 0) {
+            throw syntaxError("Expected literal value");
+        } else if ("null".equalsIgnoreCase(literal)) {
+            return JSONObject.NULL;
+        } else if ("true".equalsIgnoreCase(literal)) {
+            return Boolean.TRUE;
+        } else if ("false".equalsIgnoreCase(literal)) {
+            return Boolean.FALSE;
+        }
+
+        /* try to parse as an integral type... */
+        if (literal.indexOf('.') == -1) {
+            int base = 10;
+            String number = literal;
+            if (number.startsWith("0x") || number.startsWith("0X")) {
+                number = number.substring(2);
+                base = 16;
+            } else if (number.startsWith("0") && number.length() > 1) {
+                number = number.substring(1);
+                base = 8;
+            }
+            try {
+                long longValue = Long.parseLong(number, base);
+                if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) {
+                    return (int) longValue;
+                } else {
+                    return longValue;
+                }
+            } catch (NumberFormatException e) {
+                /*
+                 * This only happens for integral numbers greater than
+                 * Long.MAX_VALUE, numbers in exponential form (5e-10) and
+                 * unquoted strings. Fall through to try floating point.
+                 */
+            }
+        }
+
+        /* ...next try to parse as a floating point... */
+        try {
+            return Double.valueOf(literal);
+        } catch (NumberFormatException ignored) {
+        }
+
+        /* ... finally give up. We have an unquoted string */
+        //noinspection RedundantStringConstructorCall
+        return new String(literal); // a new string avoids leaking memory
+    }
+
+    /**
+     * Returns the string up to but not including any of the given characters or
+     * a newline character. This does not consume the excluded character.
+     */
+    private String nextToInternal(String excluded) {
+        int start = pos;
+        for (; pos < in.length(); pos++) {
+            char c = in.charAt(pos);
+            if (c == '\r' || c == '\n' || excluded.indexOf(c) != -1) {
+                return in.substring(start, pos);
+            }
+        }
+        return in.substring(start);
+    }
+
+    /**
+     * Reads a sequence of key/value pairs and the trailing closing brace '}' of
+     * an object. The opening brace '{' should have already been read.
+     */
+    private JSONObject readObject() throws JSONException {
+        JSONObject result = new JSONObject();
+
+        /* Peek to see if this is the empty object. */
+        int first = nextCleanInternal();
+        if (first == '}') {
+            return result;
+        } else if (first != -1) {
+            pos--;
+        }
+
+        while (true) {
+            Object name = nextValue();
+            if (!(name instanceof String)) {
+                if (name == null) {
+                    throw syntaxError("Names cannot be null");
+                } else {
+                    throw syntaxError("Names must be strings, but " + name
+                            + " is of type " + name.getClass().getName());
+                }
+            }
+
+            /*
+             * Expect the name/value separator to be either a colon ':', an
+             * equals sign '=', or an arrow "=>". The last two are bogus but we
+             * include them because that's what the original implementation did.
+             */
+            int separator = nextCleanInternal();
+            if (separator != ':' && separator != '=') {
+                throw syntaxError("Expected ':' after " + name);
+            }
+            if (pos < in.length() && in.charAt(pos) == '>') {
+                pos++;
+            }
+
+            result.put((String) name, nextValue());
+
+            switch (nextCleanInternal()) {
+                case '}':
+                    return result;
+                case ';':
+                case ',':
+                    continue;
+                default:
+                    throw syntaxError("Unterminated object");
+            }
+        }
+    }
+
+    /**
+     * Reads a sequence of values and the trailing closing brace ']' of an
+     * array. The opening brace '[' should have already been read. Note that
+     * "[]" yields an empty array, but "[,]" returns a two-element array
+     * equivalent to "[null,null]".
+     */
+    private JSONArray readArray() throws JSONException {
+        JSONArray result = new JSONArray();
+
+        /* to cover input that ends with ",]". */
+        boolean hasTrailingSeparator = false;
+
+        while (true) {
+            switch (nextCleanInternal()) {
+                case -1:
+                    throw syntaxError("Unterminated array");
+                case ']':
+                    if (hasTrailingSeparator) {
+                        result.put(null);
+                    }
+                    return result;
+                case ',':
+                case ';':
+                    /* A separator without a value first means "null". */
+                    result.put(null);
+                    hasTrailingSeparator = true;
+                    continue;
+                default:
+                    pos--;
+            }
+
+            result.put(nextValue());
+
+            switch (nextCleanInternal()) {
+                case ']':
+                    return result;
+                case ',':
+                case ';':
+                    hasTrailingSeparator = true;
+                    continue;
+                default:
+                    throw syntaxError("Unterminated array");
+            }
+        }
+    }
+
+    /**
+     * Returns an exception containing the given message plus the current
+     * position and the entire input string.
+     *
+     * @param message The message we want to include.
+     * @return An exception that we can throw.
+     */
+    public JSONException syntaxError(String message) {
+        return new JSONException(message + this);
+    }
+
+    /**
+     * Returns the current position and the entire input string.
+     */
+    @Override
+    public String toString() {
+        // consistent with the original implementation
+        return " at character " + pos + " of " + in;
+    }
+
+    /*
+     * Legacy APIs.
+     *
+     * None of the methods below are on the critical path of parsing JSON
+     * documents. They exist only because they were exposed by the original
+     * implementation and may be used by some clients.
+     */
+
+    /**
+     * Returns true until the input has been exhausted.
+     *
+     * @return true if more input exists.
+     */
+    public boolean more() {
+        return pos < in.length();
+    }
+
+    /**
+     * Returns the next available character, or the null character '\0' if all
+     * input has been exhausted. The return value of this method is ambiguous
+     * for JSON strings that contain the character '\0'.
+     *
+     * @return the next character.
+     */
+    public char next() {
+        return pos < in.length() ? in.charAt(pos++) : '\0';
+    }
+
+    /**
+     * Returns the next available character if it equals {@code c}. Otherwise an
+     * exception is thrown.
+     *
+     * @param c The character we are looking for.
+     * @return the next character.
+     * @throws JSONException If the next character isn't {@code c}
+     */
+    public char next(char c) throws JSONException {
+        char result = next();
+        if (result != c) {
+            throw syntaxError("Expected " + c + " but was " + result);
+        }
+        return result;
+    }
+
+    /**
+     * Returns the next character that is not whitespace and does not belong to
+     * a comment. If the input is exhausted before such a character can be
+     * found, the null character '\0' is returned. The return value of this
+     * method is ambiguous for JSON strings that contain the character '\0'.
+     *
+     * @return The next non-whitespace character.
+     * @throws JSONException Should not be possible.
+     */
+    public char nextClean() throws JSONException {
+        int nextCleanInt = nextCleanInternal();
+        return nextCleanInt == -1 ? '\0' : (char) nextCleanInt;
+    }
+
+    /**
+     * Returns the next {@code length} characters of the input.
+     *
+     * <p>The returned string shares its backing character array with this
+     * tokener's input string. If a reference to the returned string may be held
+     * indefinitely, you should use {@code new String(result)} to copy it first
+     * to avoid memory leaks.
+     *
+     * @param length The desired number of characters to return.
+     * @return The next few characters.
+     * @throws JSONException if the remaining input is not long enough to
+     *                       satisfy this request.
+     */
+    public String next(int length) throws JSONException {
+        if (pos + length > in.length()) {
+            throw syntaxError(length + " is out of bounds");
+        }
+        String result = in.substring(pos, pos + length);
+        pos += length;
+        return result;
+    }
+
+    /**
+     * Returns the {@link String#trim trimmed} string holding the characters up
+     * to but not including the first of:
+     * <ul>
+     * <li>any character in {@code excluded}
+     * <li>a newline character '\n'
+     * <li>a carriage return '\r'
+     * </ul>
+     *
+     * <p>The returned string shares its backing character array with this
+     * tokener's input string. If a reference to the returned string may be held
+     * indefinitely, you should use {@code new String(result)} to copy it first
+     * to avoid memory leaks.
+     *
+     * @param excluded The limiting string where the search should stop.
+     * @return a possibly-empty string
+     */
+    public String nextTo(String excluded) {
+        if (excluded == null) {
+            throw new NullPointerException("excluded == null");
+        }
+        return nextToInternal(excluded).trim();
+    }
+
+    /**
+     * Equivalent to {@code nextTo(String.valueOf(excluded))}.
+     *
+     * @param excluded The limiting character.
+     * @return a possibly-empty string
+     */
+    public String nextTo(char excluded) {
+        return nextToInternal(String.valueOf(excluded)).trim();
+    }
+
+    /**
+     * Advances past all input up to and including the next occurrence of
+     * {@code thru}. If the remaining input doesn't contain {@code thru}, the
+     * input is exhausted.
+     *
+     * @param thru The string to skip over.
+     */
+    public void skipPast(String thru) {
+        int thruStart = in.indexOf(thru, pos);
+        pos = thruStart == -1 ? in.length() : (thruStart + thru.length());
+    }
+
+    /**
+     * Advances past all input up to but not including the next occurrence of
+     * {@code to}. If the remaining input doesn't contain {@code to}, the input
+     * is unchanged.
+     *
+     * @param to The character we want to skip to.
+     * @return The value of {@code to} or null.
+     */
+    public char skipTo(char to) {
+        int index = in.indexOf(to, pos);
+        if (index != -1) {
+            pos = index;
+            return to;
+        } else {
+            return '\0';
+        }
+    }
+
+    /**
+     * Unreads the most recent character of input. If no input characters have
+     * been read, the input is unchanged.
+     */
+    public void back() {
+        if (--pos == -1) {
+            pos = 0;
+        }
+    }
+
+    /**
+     * Returns the integer [0..15] value for the given hex character, or -1
+     * for non-hex input.
+     *
+     * @param hex a character in the ranges [0-9], [A-F] or [a-f]. Any other
+     *            character will yield a -1 result.
+     * @return The decoded integer.
+     */
+    public static int dehexchar(char hex) {
+        if (hex >= '0' && hex <= '9') {
+            return hex - '0';
+        } else if (hex >= 'A' && hex <= 'F') {
+            return hex - 'A' + 10;
+        } else if (hex >= 'a' && hex <= 'f') {
+            return hex - 'a' + 10;
+        } else {
+            return -1;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/b34e47ff/geode-json/src/test/java/org/json/FileTest.java
----------------------------------------------------------------------
diff --git a/geode-json/src/test/java/org/json/FileTest.java b/geode-json/src/test/java/org/json/FileTest.java
new file mode 100755
index 0000000..dae910b
--- /dev/null
+++ b/geode-json/src/test/java/org/json/FileTest.java
@@ -0,0 +1,287 @@
+package org.json;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Set;
+
+public class FileTest {
+    @Test
+    public void testFile() throws IOException, JSONException {
+        String ref = "[\n" +
+                "  {\n" +
+                "    \"_id\": \"58309f3bd307b72ae49a9b23\",\n" +
+                "    \"index\": 0,\n" +
+                "    \"guid\": \"5764ebd8-b333-469e-8d83-4eb5658f1566\",\n" +
+                "    \"isActive\": true,\n" +
+                "    \"balance\": \"$1,099.93\",\n" +
+                "    \"picture\": \"http://placehold.it/32x32\",\n" +
+                "    \"age\": 37,\n" +
+                "    \"eyeColor\": \"blue\",\n" +
+                "    \"name\": \"Barrera Wilkerson\",\n" +
+                "    \"gender\": \"male\",\n" +
+                "    \"company\": \"VURBO\",\n" +
+                "    \"email\": \"barrerawilkerson@vurbo.com\",\n" +
+                "    \"phone\": \"+1 (817) 429-2473\",\n" +
+                "    \"address\": \"522 Vanderveer Street, Detroit, Wyoming, 4320\",\n" +
+                "    \"about\": \"Et officia aute ullamco magna adipisicing non ut cupidatat cupidatat aliquip. Tempor occaecat ex ad dolore aliquip mollit ea esse ipsum. Est incididunt sunt commodo duis est. Reprehenderit in ut reprehenderit ad culpa ea fugiat et est adipisicing aliquip. Id mollit voluptate qui pariatur officia.\\r\\n\",\n" +
+                "    \"registered\": \"2016-06-29T08:54:14 +07:00\",\n" +
+                "    \"latitude\": -87.548434,\n" +
+                "    \"longitude\": 64.251242,\n" +
+                "    \"tags\": [\n" +
+                "      \"aliqua\",\n" +
+                "      \"ex\",\n" +
+                "      \"sit\",\n" +
+                "      \"magna\",\n" +
+                "      \"dolor\",\n" +
+                "      \"laborum\",\n" +
+                "      \"non\"\n" +
+                "    ],\n" +
+                "    \"friends\": [\n" +
+                "      {\n" +
+                "        \"id\": 0,\n" +
+                "        \"name\": \"Byers Pratt\"\n" +
+                "      },\n" +
+                "      {\n" +
+                "        \"id\": 1,\n" +
+                "        \"name\": \"Kennedy Contreras\"\n" +
+                "      },\n" +
+                "      {\n" +
+                "        \"id\": 2,\n" +
+                "        \"name\": \"Frazier Monroe\"\n" +
+                "      }\n" +
+                "    ],\n" +
+                "    \"greeting\": \"Hello, Barrera Wilkerson! You have 3 unread messages.\",\n" +
+                "    \"favoriteFruit\": \"banana\"\n" +
+                "  },\n" +
+                "  {\n" +
+                "    \"_id\": \"58309f3b1f506440093a41d1\",\n" +
+                "    \"index\": 1,\n" +
+                "    \"guid\": \"de1a6cc9-f8b3-426e-b68a-cc30e1fff3c1\",\n" +
+                "    \"isActive\": false,\n" +
+                "    \"balance\": \"$3,397.60\",\n" +
+                "    \"picture\": \"http://placehold.it/32x32\",\n" +
+                "    \"age\": 32,\n" +
+                "    \"eyeColor\": \"blue\",\n" +
+                "    \"name\": \"Trisha Morris\",\n" +
+                "    \"gender\": \"female\",\n" +
+                "    \"company\": \"AMTAP\",\n" +
+                "    \"email\": \"trishamorris@amtap.com\",\n" +
+                "    \"phone\": \"+1 (805) 423-3375\",\n" +
+                "    \"address\": \"495 Tampa Court, Libertytown, New Hampshire, 5177\",\n" +
+                "    \"about\": \"Elit culpa Lorem dolor sit laborum ut ullamco ullamco nostrud reprehenderit adipisicing eiusmod. Aliqua quis dolor esse sint. Dolore in excepteur laborum anim ut consectetur. Nisi officia est eu ex ex id. Ipsum duis ullamco ad ut labore dolor. In amet tempor deserunt ullamco velit eu fugiat.\\r\\n\",\n" +
+                "    \"registered\": \"2015-02-08T06:14:19 +08:00\",\n" +
+                "    \"latitude\": -81.956277,\n" +
+                "    \"longitude\": 143.685584,\n" +
+                "    \"tags\": [\n" +
+                "      \"cillum\",\n" +
+                "      \"ullamco\",\n" +
+                "      \"magna\",\n" +
+                "      \"cillum\",\n" +
+                "      \"voluptate\",\n" +
+                "      \"magna\",\n" +
+                "      \"exercitation\"\n" +
+                "    ],\n" +
+                "    \"friends\": [\n" +
+                "      {\n" +
+                "        \"id\": 0,\n" +
+                "        \"name\": \"Fuentes Stout\"\n" +
+                "      },\n" +
+                "      {\n" +
+                "        \"id\": 1,\n" +
+                "        \"name\": \"Violet Vargas\"\n" +
+                "      },\n" +
+                "      {\n" +
+                "        \"id\": 2,\n" +
+                "        \"name\": \"Schmidt Wilder\"\n" +
+                "      }\n" +
+                "    ],\n" +
+                "    \"greeting\": \"Hello, Trisha Morris! You have 4 unread messages.\",\n" +
+                "    \"favoriteFruit\": \"strawberry\"\n" +
+                "  },\n" +
+                "  {\n" +
+                "    \"_id\": \"58309f3beaef2f31339b3755\",\n" +
+                "    \"index\": 2,\n" +
+                "    \"guid\": \"0bf387b7-abc2-4828-becc-1269928f7c3d\",\n" +
+                "    \"isActive\": false,\n" +
+                "    \"balance\": \"$1,520.64\",\n" +
+                "    \"picture\": \"http://placehold.it/32x32\",\n" +
+                "    \"age\": 37,\n" +
+                "    \"eyeColor\": \"blue\",\n" +
+                "    \"name\": \"Deanna Santiago\",\n" +
+                "    \"gender\": \"female\",\n" +
+                "    \"company\": \"MEGALL\",\n" +
+                "    \"email\": \"deannasantiago@megall.com\",\n" +
+                "    \"phone\": \"+1 (916) 511-2291\",\n" +
+                "    \"address\": \"919 Fayette Street, Homestead, Utah, 8669\",\n" +
+                "    \"about\": \"Sit amet ex quis velit irure Lorem non quis aliquip dolor pariatur nulla Lorem officia. Deserunt officia sit velit labore sint nostrud elit aliquip labore ullamco consectetur id amet. Ullamco duis commodo sit incididunt. Fugiat consectetur ad incididunt officia. Sint cillum minim laborum laboris id cillum est exercitation in eiusmod qui.\\r\\n\",\n" +
+                "    \"registered\": \"2015-11-18T08:39:28 +08:00\",\n" +
+                "    \"latitude\": 79.105701,\n" +
+                "    \"longitude\": -146.901754,\n" +
+                "    \"tags\": [\n" +
+                "      \"non\",\n" +
+                "      \"ullamco\",\n" +
+                "      \"cillum\",\n" +
+                "      \"ipsum\",\n" +
+                "      \"amet\",\n" +
+                "      \"aliqua\",\n" +
+                "      \"aliquip\"\n" +
+                "    ],\n" +
+                "    \"friends\": [\n" +
+                "      {\n" +
+                "        \"id\": 0,\n" +
+                "        \"name\": \"Hanson Anderson\"\n" +
+                "      },\n" +
+                "      {\n" +
+                "        \"id\": 1,\n" +
+                "        \"name\": \"Pollard Soto\"\n" +
+                "      },\n" +
+                "      {\n" +
+                "        \"id\": 2,\n" +
+                "        \"name\": \"Barlow Campbell\"\n" +
+                "      }\n" +
+                "    ],\n" +
+                "    \"greeting\": \"Hello, Deanna Santiago! You have 7 unread messages.\",\n" +
+                "    \"favoriteFruit\": \"apple\"\n" +
+                "  },\n" +
+                "  {\n" +
+                "    \"_id\": \"58309f3b49a68ad01346f27f\",\n" +
+                "    \"index\": 3,\n" +
+                "    \"guid\": \"d29c0dcc-48fb-4ca4-a63b-b47c0e6d6398\",\n" +
+                "    \"isActive\": false,\n" +
+                "    \"balance\": \"$2,069.96\",\n" +
+                "    \"picture\": \"http://placehold.it/32x32\",\n" +
+                "    \"age\": 29,\n" +
+                "    \"eyeColor\": \"green\",\n" +
+                "    \"name\": \"Brooks Gates\",\n" +
+                "    \"gender\": \"male\",\n" +
+                "    \"company\": \"TERRAGEN\",\n" +
+                "    \"email\": \"brooksgates@terragen.com\",\n" +
+                "    \"phone\": \"+1 (875) 483-2224\",\n" +
+                "    \"address\": \"562 Noll Street, Kipp, Louisiana, 7659\",\n" +
+                "    \"about\": \"Reprehenderit laboris mollit nulla commodo quis laborum commodo. Laborum aliquip laboris officia minim ipsum laborum ipsum reprehenderit quis laboris est sint culpa. Culpa magna aute mollit exercitation.\\r\\n\",\n" +
+                "    \"registered\": \"2016-05-04T10:34:38 +07:00\",\n" +
+                "    \"latitude\": 72.77079,\n" +
+                "    \"longitude\": -134.291768,\n" +
+                "    \"tags\": [\n" +
+                "      \"est\",\n" +
+                "      \"sunt\",\n" +
+                "      \"laboris\",\n" +
+                "      \"ea\",\n" +
+                "      \"proident\",\n" +
+                "      \"aute\",\n" +
+                "      \"excepteur\"\n" +
+                "    ],\n" +
+                "    \"friends\": [\n" +
+                "      {\n" +
+                "        \"id\": 0,\n" +
+                "        \"name\": \"Roxanne Morgan\"\n" +
+                "      },\n" +
+                "      {\n" +
+                "        \"id\": 1,\n" +
+                "        \"name\": \"Tamara Kelly\"\n" +
+                "      },\n" +
+                "      {\n" +
+                "        \"id\": 2,\n" +
+                "        \"name\": \"Cleveland Bush\"\n" +
+                "      }\n" +
+                "    ],\n" +
+                "    \"greeting\": \"Hello, Brooks Gates! You have 1 unread messages.\",\n" +
+                "    \"favoriteFruit\": \"banana\"\n" +
+                "  },\n" +
+                "  {\n" +
+                "    \"_id\": \"58309f3be746700e9af9a645\",\n" +
+                "    \"index\": 4,\n" +
+                "    \"guid\": \"54382bd6-c476-469d-9e1c-e546f959db51\",\n" +
+                "    \"isActive\": true,\n" +
+                "    \"balance\": \"$2,012.57\",\n" +
+                "    \"picture\": \"http://placehold.it/32x32\",\n" +
+                "    \"age\": 40,\n" +
+                "    \"eyeColor\": \"brown\",\n" +
+                "    \"name\": \"Jackie Thomas\",\n" +
+                "    \"gender\": \"female\",\n" +
+                "    \"company\": \"HINWAY\",\n" +
+                "    \"email\": \"jackiethomas@hinway.com\",\n" +
+                "    \"phone\": \"+1 (843) 470-2096\",\n" +
+                "    \"address\": \"910 Emerson Place, Gwynn, Federated States Of Micronesia, 4688\",\n" +
+                "    \"about\": \"Id cupidatat laboris elit est eiusmod esse nostrud. Ex commodo nisi voluptate est nisi laborum officia sint incididunt pariatur qui deserunt ullamco. Fugiat proident magna ipsum sit sint id adipisicing sit nostrud labore sit officia. Eiusmod exercitation non enim excepteur amet irure ullamco consectetur cupidatat proident Lorem reprehenderit aliquip. Veniam esse dolor Lorem incididunt proident officia enim in incididunt culpa. Mollit voluptate commodo aliquip anim ipsum nostrud ut labore enim labore qui do minim incididunt. Quis irure proident voluptate nisi qui sunt aute duis irure.\\r\\n\",\n" +
+                "    \"registered\": \"2014-08-03T09:21:43 +07:00\",\n" +
+                "    \"latitude\": 84.871256,\n" +
+                "    \"longitude\": 2.043339,\n" +
+                "    \"tags\": [\n" +
+                "      \"tempor\",\n" +
+                "      \"ut\",\n" +
+                "      \"deserunt\",\n" +
+                "      \"esse\",\n" +
+                "      \"nostrud\",\n" +
+                "      \"dolore\",\n" +
+                "      \"ex\"\n" +
+                "    ],\n" +
+                "    \"friends\": [\n" +
+                "      {\n" +
+                "        \"id\": 0,\n" +
+                "        \"name\": \"Lois Walters\"\n" +
+                "      },\n" +
+                "      {\n" +
+                "        \"id\": 1,\n" +
+                "        \"name\": \"Brewer Buchanan\"\n" +
+                "      },\n" +
+                "      {\n" +
+                "        \"id\": 2,\n" +
+                "        \"name\": \"Mccormick Fleming\"\n" +
+                "      }\n" +
+                "    ],\n" +
+                "    \"greeting\": \"Hello, Jackie Thomas! You have 2 unread messages.\",\n" +
+                "    \"favoriteFruit\": \"banana\"\n" +
+                "  }\n" +
+                "]";
+
+        JSONArray x1 = (JSONArray) new JSONTokener(new InputStreamReader(this.getClass().getResourceAsStream("/sample-01.json"))).nextValue();
+        JSONArray x2 = (JSONArray) new JSONTokener(ref).nextValue();
+
+        Assert.assertTrue(jsonEquals(x1, x2));
+    }
+
+    private boolean jsonEquals(JSONArray x1, JSONArray x2) throws JSONException {
+        if (x1.length() != x2.length()) {
+            return false;
+        }
+
+        for (int i = 0; i < x1.length(); i++) {
+            Object element1 = x1.get(i);
+            Object element2 = x2.get(i);
+            if (!jsonEquals(element1, element2)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean jsonEquals(JSONObject x1, JSONObject x2) throws JSONException {
+        if (x1.length() != x2.length()) {
+            return false;
+        }
+        Set<String> names = x1.keySet();
+        for (String name : names) {
+            if (!jsonEquals(x1.get(name), x2.get(name))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean jsonEquals(Object element1, Object element2) throws JSONException {
+        if (!element1.getClass().equals(element2.getClass())) {
+            return false;
+        }
+        if (element1 instanceof JSONObject) {
+            return jsonEquals((JSONObject) element1, (JSONObject) element2);
+        }
+        if (element1 instanceof JSONArray) {
+            return jsonEquals((JSONArray) element1, (JSONArray) element2);
+        }
+        return element1.equals(element2);
+    }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/b34e47ff/geode-json/src/test/java/org/json/JSONArrayTest.java
----------------------------------------------------------------------
diff --git a/geode-json/src/test/java/org/json/JSONArrayTest.java b/geode-json/src/test/java/org/json/JSONArrayTest.java
new file mode 100755
index 0000000..8f6632b
--- /dev/null
+++ b/geode-json/src/test/java/org/json/JSONArrayTest.java
@@ -0,0 +1,608 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed 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.json;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.*;
+
+/**
+ * This black box test was written without inspecting the non-free org.json sourcecode.
+ */
+public class JSONArrayTest {
+    @Test
+    public void testEmptyArray() throws JSONException {
+        JSONArray array = new JSONArray();
+        assertEquals(0, array.length());
+        assertEquals("", array.join(" AND "));
+        try {
+            array.get(0);
+            fail();
+        } catch (JSONException ignored) {
+        }
+        try {
+            array.getBoolean(0);
+            fail();
+        } catch (JSONException ignored) {
+        }
+
+        assertEquals("[]", array.toString());
+        assertEquals("[]", array.toString(4));
+
+        // out of bounds is co-opted with defaulting
+        assertTrue(array.isNull(0));
+        assertNull(array.opt(0));
+        assertFalse(array.optBoolean(0));
+        assertTrue(array.optBoolean(0, true));
+
+        // bogus (but documented) behaviour: returns null rather than an empty object!
+        assertNull(array.toJSONObject(new JSONArray()));
+    }
+
+    @Test
+    public void testEqualsAndHashCode() throws JSONException {
+        JSONArray a = new JSONArray();
+        JSONArray b = new JSONArray();
+        assertTrue(a.equals(b));
+        assertEquals("equals() not consistent with hashCode()", a.hashCode(), b.hashCode());
+
+        a.put(true);
+        a.put(false);
+        b.put(true);
+        b.put(false);
+        assertTrue(a.equals(b));
+        assertEquals(a.hashCode(), b.hashCode());
+
+        b.put(true);
+        assertFalse(a.equals(b));
+        assertTrue(a.hashCode() != b.hashCode());
+    }
+
+    @Test
+    public void testBooleans() throws JSONException {
+        JSONArray array = new JSONArray();
+        array.put(true);
+        array.put(false);
+        array.put(2, false);
+        array.put(3, false);
+        array.put(2, true);
+        assertEquals("[true,false,true,false]", array.toString());
+        assertEquals(4, array.length());
+        assertEquals(Boolean.TRUE, array.get(0));
+        assertEquals(Boolean.FALSE, array.get(1));
+        assertEquals(Boolean.TRUE, array.get(2));
+        assertEquals(Boolean.FALSE, array.get(3));
+        assertFalse(array.isNull(0));
+        assertFalse(array.isNull(1));
+        assertFalse(array.isNull(2));
+        assertFalse(array.isNull(3));
+        assertEquals(true, array.optBoolean(0));
+        assertEquals(false, array.optBoolean(1, true));
+        assertEquals(true, array.optBoolean(2, false));
+        assertEquals(false, array.optBoolean(3));
+        assertEquals("true", array.getString(0));
+        assertEquals("false", array.getString(1));
+        assertEquals("true", array.optString(2));
+        assertEquals("false", array.optString(3, "x"));
+        assertEquals("[\n     true,\n     false,\n     true,\n     false\n]", array.toString(5));
+
+        JSONArray other = new JSONArray();
+        other.put(true);
+        other.put(false);
+        other.put(true);
+        other.put(false);
+        assertTrue(array.equals(other));
+        other.put(true);
+        assertFalse(array.equals(other));
+
+        other = new JSONArray();
+        other.put("true");
+        other.put("false");
+        other.put("truE");
+        other.put("FALSE");
+        assertFalse(array.equals(other));
+        assertFalse(other.equals(array));
+        assertEquals(true, other.getBoolean(0));
+        assertEquals(false, other.optBoolean(1, true));
+        assertEquals(true, other.optBoolean(2));
+        assertEquals(false, other.getBoolean(3));
+    }
+
+    // http://code.google.com/p/android/issues/detail?id=16411
+    @Test
+    public void testCoerceStringToBoolean() throws JSONException {
+        JSONArray array = new JSONArray();
+        array.put("maybe");
+        try {
+            array.getBoolean(0);
+            fail();
+        } catch (JSONException ignored) {
+        }
+        assertEquals(false, array.optBoolean(0));
+        assertEquals(true, array.optBoolean(0, true));
+    }
+
+    @Test
+    public void testNulls() throws JSONException {
+        JSONArray array = new JSONArray();
+        array.put(3, null);
+        array.put(0, JSONObject.NULL);
+        assertEquals(4, array.length());
+        assertEquals("[null,null,null,null]", array.toString());
+
+        // there's 2 ways to represent null; each behaves differently!
+        assertEquals(JSONObject.NULL, array.get(0));
+        try {
+            array.get(1);
+            fail();
+        } catch (JSONException ignored) {
+        }
+        try {
+            array.get(2);
+            fail();
+        } catch (JSONException ignored) {
+        }
+        try {
+            array.get(3);
+            fail();
+        } catch (JSONException ignored) {
+        }
+        assertEquals(JSONObject.NULL, array.opt(0));
+        assertEquals(null, array.opt(1));
+        assertEquals(null, array.opt(2));
+        assertEquals(null, array.opt(3));
+        assertTrue(array.isNull(0));
+        assertTrue(array.isNull(1));
+        assertTrue(array.isNull(2));
+        assertTrue(array.isNull(3));
+        assertEquals("null", array.optString(0));
+        assertEquals("", array.optString(1));
+        assertEquals("", array.optString(2));
+        assertEquals("", array.optString(3));
+    }
+
+    /**
+     * Our behaviour is questioned by this bug:
+     * http://code.google.com/p/android/issues/detail?id=7257
+     */
+    @Test
+    public void testParseNullYieldsJSONObjectNull() throws JSONException {
+        JSONArray array = new JSONArray("[\"null\",null]");
+        array.put(null);
+        assertEquals("null", array.get(0));
+        assertEquals(JSONObject.NULL, array.get(1));
+        try {
+            array.get(2);
+            fail();
+        } catch (JSONException ignored) {
+        }
+        assertEquals("null", array.getString(0));
+        assertEquals("null", array.getString(1));
+        try {
+            array.getString(2);
+            fail();
+        } catch (JSONException ignored) {
+        }
+    }
+
+    @Test
+    public void testNumbers() throws JSONException {
+        JSONArray array = new JSONArray();
+        array.put(Double.MIN_VALUE);
+        array.put(9223372036854775806L);
+        array.put(Double.MAX_VALUE);
+        array.put(-0d);
+        assertEquals(4, array.length());
+
+        // toString() and getString(int) return different values for -0d
+        assertEquals("[4.9E-324,9223372036854775806,1.7976931348623157E308,-0]", array.toString());
+
+        assertEquals(Double.MIN_VALUE, array.get(0));
+        assertEquals(9223372036854775806L, array.get(1));
+        assertEquals(Double.MAX_VALUE, array.get(2));
+        assertEquals(-0d, array.get(3));
+        assertEquals(Double.MIN_VALUE, array.getDouble(0), 0);
+        assertEquals(9.223372036854776E18, array.getDouble(1), 0);
+        assertEquals(Double.MAX_VALUE, array.getDouble(2), 0);
+        assertEquals(-0d, array.getDouble(3), 0);
+        assertEquals(0, array.getLong(0));
+        assertEquals(9223372036854775806L, array.getLong(1));
+        assertEquals(Long.MAX_VALUE, array.getLong(2));
+        assertEquals(0, array.getLong(3));
+        assertEquals(0, array.getInt(0));
+        assertEquals(-2, array.getInt(1));
+        assertEquals(Integer.MAX_VALUE, array.getInt(2));
+        assertEquals(0, array.getInt(3));
+        assertEquals(Double.MIN_VALUE, array.opt(0));
+        assertEquals(Double.MIN_VALUE, array.optDouble(0), 0);
+        assertEquals(0, array.optLong(0, 1L));
+        assertEquals(0, array.optInt(0, 1));
+        assertEquals("4.9E-324", array.getString(0));
+        assertEquals("9223372036854775806", array.getString(1));
+        assertEquals("1.7976931348623157E308", array.getString(2));
+        assertEquals("-0.0", array.getString(3));
+
+        JSONArray other = new JSONArray();
+        other.put(Double.MIN_VALUE);
+        other.put(9223372036854775806L);
+        other.put(Double.MAX_VALUE);
+        other.put(-0d);
+        assertTrue(array.equals(other));
+        other.put(0, 0L);
+        assertFalse(array.equals(other));
+    }
+
+    @Test
+    public void testStrings() throws JSONException {
+        JSONArray array = new JSONArray();
+        array.put("true");
+        array.put("5.5");
+        array.put("9223372036854775806");
+        array.put("null");
+        array.put("5\"8' tall");
+        assertEquals(5, array.length());
+        assertEquals("[\"true\",\"5.5\",\"9223372036854775806\",\"null\",\"5\\\"8' tall\"]",
+                array.toString());
+
+        // although the documentation doesn't mention it, join() escapes text and wraps
+        // strings in quotes
+        assertEquals("\"true\" \"5.5\" \"9223372036854775806\" \"null\" \"5\\\"8' tall\"",
+                array.join(" "));
+
+        assertEquals("true", array.get(0));
+        assertEquals("null", array.getString(3));
+        assertEquals("5\"8' tall", array.getString(4));
+        assertEquals("true", array.opt(0));
+        assertEquals("5.5", array.optString(1));
+        assertEquals("9223372036854775806", array.optString(2, null));
+        assertEquals("null", array.optString(3, "-1"));
+        assertFalse(array.isNull(0));
+        assertFalse(array.isNull(3));
+
+        assertEquals(true, array.getBoolean(0));
+        assertEquals(true, array.optBoolean(0));
+        assertEquals(true, array.optBoolean(0, false));
+        assertEquals(0, array.optInt(0));
+        assertEquals(-2, array.optInt(0, -2));
+
+        assertEquals(5.5d, array.getDouble(1), 0);
+        assertEquals(5L, array.getLong(1));
+        assertEquals(5, array.getInt(1));
+        assertEquals(5, array.optInt(1, 3));
+
+        // The last digit of the string is a 6 but getLong returns a 7. It's probably parsing as a
+        // double and then converting that to a long. This is consistent with JavaScript.
+        assertEquals(9223372036854775807L, array.getLong(2));
+        assertEquals(9.223372036854776E18, array.getDouble(2), 0);
+        assertEquals(Integer.MAX_VALUE, array.getInt(2));
+
+        assertFalse(array.isNull(3));
+        try {
+            array.getDouble(3);
+            fail();
+        } catch (JSONException e) {
+            // expected
+        }
+        assertEquals(Double.NaN, array.optDouble(3), 0);
+        assertEquals(-1.0d, array.optDouble(3, -1.0d), 0);
+    }
+
+    @Test
+    public void testJoin() throws JSONException {
+        JSONArray array = new JSONArray();
+        array.put(null);
+        assertEquals("null", array.join(" & "));
+        array.put("\"");
+        assertEquals("null & \"\\\"\"", array.join(" & "));
+        array.put(5);
+        assertEquals("null & \"\\\"\" & 5", array.join(" & "));
+        array.put(true);
+        assertEquals("null & \"\\\"\" & 5 & true", array.join(" & "));
+        array.put(new JSONArray(Arrays.asList(true, false)));
+        assertEquals("null & \"\\\"\" & 5 & true & [true,false]", array.join(" & "));
+        array.put(new JSONObject(Collections.singletonMap("x", 6)));
+        assertEquals("null & \"\\\"\" & 5 & true & [true,false] & {\"x\":6}", array.join(" & "));
+    }
+
+    @Test
+    public void testJoinWithNull() throws JSONException {
+        JSONArray array = new JSONArray(Arrays.asList(5, 6));
+        assertEquals("5null6", array.join(null));
+    }
+
+    @Test
+    public void testJoinWithSpecialCharacters() throws JSONException {
+        JSONArray array = new JSONArray(Arrays.asList(5, 6));
+        assertEquals("5\"6", array.join("\""));
+    }
+
+    @Test
+    public void testToJSONObject() throws JSONException {
+        JSONArray keys = new JSONArray();
+        keys.put("a");
+        keys.put("b");
+
+        JSONArray values = new JSONArray();
+        values.put(5.5d);
+        values.put(false);
+
+        JSONObject object = values.toJSONObject(keys);
+        assertEquals(5.5d, object.get("a"));
+        assertEquals(false, object.get("b"));
+
+        keys.put(0, "a");
+        values.put(0, 11.0d);
+        assertEquals(5.5d, object.get("a"));
+    }
+
+    @Test
+    public void testToJSONObjectWithNulls() throws JSONException {
+        JSONArray keys = new JSONArray();
+        keys.put("a");
+        keys.put("b");
+
+        JSONArray values = new JSONArray();
+        values.put(5.5d);
+        values.put(null);
+
+        // null values are stripped!
+        JSONObject object = values.toJSONObject(keys);
+        assertEquals(1, object.length());
+        assertFalse(object.has("b"));
+        assertEquals("{\"a\":5.5}", object.toString());
+    }
+
+    @Test
+    public void testToJSONObjectMoreNamesThanValues() throws JSONException {
+        JSONArray keys = new JSONArray();
+        keys.put("a");
+        keys.put("b");
+        JSONArray values = new JSONArray();
+        values.put(5.5d);
+        JSONObject object = values.toJSONObject(keys);
+        assertEquals(1, object.length());
+        assertEquals(5.5d, object.get("a"));
+    }
+
+    @Test
+    public void testToJSONObjectMoreValuesThanNames() throws JSONException {
+        JSONArray keys = new JSONArray();
+        keys.put("a");
+        JSONArray values = new JSONArray();
+        values.put(5.5d);
+        values.put(11.0d);
+        JSONObject object = values.toJSONObject(keys);
+        assertEquals(1, object.length());
+        assertEquals(5.5d, object.get("a"));
+    }
+
+    @Test
+    public void testToJSONObjectNullKey() throws JSONException {
+        JSONArray keys = new JSONArray();
+        keys.put(JSONObject.NULL);
+        JSONArray values = new JSONArray();
+        values.put(5.5d);
+        JSONObject object = values.toJSONObject(keys);
+        assertEquals(1, object.length());
+        assertEquals(5.5d, object.get("null"));
+    }
+
+    @Test
+    public void testPutUnsupportedNumbers() throws JSONException {
+        JSONArray array = new JSONArray();
+
+        try {
+            array.put(Double.NaN);
+            fail();
+        } catch (JSONException e) {
+            // expected
+        }
+        try {
+            array.put(0, Double.NEGATIVE_INFINITY);
+            fail();
+        } catch (JSONException e) {
+            // expected
+        }
+        try {
+            array.put(0, Double.POSITIVE_INFINITY);
+            fail();
+        } catch (JSONException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testPutUnsupportedNumbersAsObject() throws JSONException {
+        JSONArray array = new JSONArray();
+        array.put(Double.valueOf(Double.NaN));
+        array.put(Double.valueOf(Double.NEGATIVE_INFINITY));
+        array.put(Double.valueOf(Double.POSITIVE_INFINITY));
+        assertEquals(null, array.toString());
+    }
+
+    /**
+     * Although JSONArray is usually defensive about which numbers it accepts,
+     * it doesn't check inputs in its constructor.
+     */
+    @Test
+    public void testCreateWithUnsupportedNumbers() throws JSONException {
+        JSONArray array = new JSONArray(Arrays.asList(5.5, Double.NaN));
+        assertEquals(2, array.length());
+        assertEquals(5.5, array.getDouble(0), 0);
+        assertEquals(Double.NaN, array.getDouble(1), 0);
+    }
+
+    @Test
+    public void testToStringWithUnsupportedNumbers() throws JSONException {
+        // when the array contains an unsupported number, toString returns null!
+        JSONArray array = new JSONArray(Arrays.asList(5.5, Double.NaN));
+        assertNull(array.toString());
+    }
+
+    @Test
+    public void testListConstructorCopiesContents() throws JSONException {
+        // have to use asList instead of Collections.singleton() to allow mutation
+        //noinspection ArraysAsListWithZeroOrOneArgument
+        List<Object> contents = Arrays.<Object>asList(5);
+        JSONArray array = new JSONArray(contents);
+        contents.set(0, 10);
+        assertEquals(5, array.get(0));
+    }
+
+    @Test
+    public void testTokenerConstructor() throws JSONException {
+        JSONArray object = new JSONArray(new JSONTokener("[false]"));
+        assertEquals(1, object.length());
+        assertEquals(false, object.get(0));
+    }
+
+    @Test
+    public void testTokenerConstructorWrongType() throws JSONException {
+        try {
+            new JSONArray(new JSONTokener("{\"foo\": false}"));
+            fail();
+        } catch (JSONException ignored) {
+        }
+    }
+
+    @Test
+    public void testTokenerConstructorNull() throws JSONException {
+        try {
+            new JSONArray((JSONTokener) null);
+            fail();
+        } catch (NullPointerException ignored) {
+        }
+    }
+
+    @Test
+    public void testTokenerConstructorParseFail() {
+        try {
+            new JSONArray(new JSONTokener("["));
+            fail();
+        } catch (JSONException ignored) {
+        } catch (StackOverflowError e) {
+            fail("Stack overflowed on input: \"[\"");
+        }
+    }
+
+    @Test
+    public void testStringConstructor() throws JSONException {
+        JSONArray object = new JSONArray("[false]");
+        assertEquals(1, object.length());
+        assertEquals(false, object.get(0));
+    }
+
+    @Test
+    public void testStringConstructorWrongType() throws JSONException {
+        try {
+            new JSONArray("{\"foo\": false}");
+            fail();
+        } catch (JSONException ignored) {
+        }
+    }
+
+    @Test
+    public void testStringConstructorNull() throws JSONException {
+        try {
+            new JSONArray((String) null);
+            fail();
+        } catch (NullPointerException ignored) {
+        }
+    }
+
+    @Test
+    public void testStringConstructorParseFail() {
+        try {
+            new JSONArray("[");
+            fail();
+        } catch (JSONException ignored) {
+        } catch (StackOverflowError e) {
+            fail("Stack overflowed on input: \"[\"");
+        }
+    }
+
+    @Test
+    public void testCreate() throws JSONException {
+        JSONArray array = new JSONArray(Arrays.asList(5.5, true));
+        assertEquals(2, array.length());
+        assertEquals(5.5, array.getDouble(0), 0.0);
+        assertEquals(true, array.get(1));
+        assertEquals("[5.5,true]", array.toString());
+    }
+
+    @Test
+    public void testAccessOutOfBounds() throws JSONException {
+        JSONArray array = new JSONArray();
+        array.put("foo");
+        assertEquals(null, array.opt(3));
+        assertEquals(null, array.opt(-3));
+        assertEquals("", array.optString(3));
+        assertEquals("", array.optString(-3));
+        try {
+            array.get(3);
+            fail();
+        } catch (JSONException ignored) {
+        }
+        try {
+            array.get(-3);
+            fail();
+        } catch (JSONException ignored) {
+        }
+        try {
+            array.getString(3);
+            fail();
+        } catch (JSONException ignored) {
+        }
+        try {
+            array.getString(-3);
+            fail();
+        } catch (JSONException ignored) {
+        }
+    }
+
+    @Test
+    public void test_remove() throws Exception {
+        JSONArray a = new JSONArray();
+        assertEquals(null, a.remove(-1));
+        assertEquals(null, a.remove(0));
+
+        a.put("hello");
+        assertEquals(null, a.remove(-1));
+        assertEquals(null, a.remove(1));
+        assertEquals("hello", a.remove(0));
+        assertEquals(null, a.remove(0));
+    }
+
+    enum MyEnum { A, B, C }
+
+    // https://code.google.com/p/android/issues/detail?id=62539
+    // but changed in open-json to return toString for all enums
+    @Test
+    public void testEnums() throws Exception {
+        // This works because it's in java.* and any class in there falls back to toString.
+        JSONArray a1 = new JSONArray(java.lang.annotation.RetentionPolicy.values());
+        assertEquals("[\"SOURCE\",\"CLASS\",\"RUNTIME\"]", a1.toString());
+
+        // This doesn't because it's not.
+        JSONArray a2 = new JSONArray(MyEnum.values());
+        assertEquals("[\"A\",\"B\",\"C\"]", a2.toString());
+    }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/b34e47ff/geode-json/src/test/java/org/json/JSONFunctionTestObject.java
----------------------------------------------------------------------
diff --git a/geode-json/src/test/java/org/json/JSONFunctionTestObject.java b/geode-json/src/test/java/org/json/JSONFunctionTestObject.java
new file mode 100755
index 0000000..fe18ab6
--- /dev/null
+++ b/geode-json/src/test/java/org/json/JSONFunctionTestObject.java
@@ -0,0 +1,17 @@
+package org.json;
+
+/**
+ * Class to test the function hack
+ */
+public class JSONFunctionTestObject {
+    private String value;
+
+    public JSONFunctionTestObject(String value) {
+        this.value = value;
+    }
+
+    @Override
+    public String toString() {
+        return value;
+    }
+}
\ No newline at end of file


Mime
View raw message