151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson/*
251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * Copyright (C) 2010 The Android Open Source Project
351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson *
451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * you may not use this file except in compliance with the License.
651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * You may obtain a copy of the License at
751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson *
851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson *
1051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * Unless required by applicable law or agreed to in writing, software
1151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
1251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * See the License for the specific language governing permissions and
1451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * limitations under the License.
1551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson */
1651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
1751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilsonpackage org.json;
1851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
1951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson// Note: this class was written without inspecting the non-free org.json sourcecode.
2051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
2151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson/**
22c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * Parses a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>)
23c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * encoded string into the corresponding object. Most clients of
24c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * this class will use only need the {@link #JSONTokener(String) constructor}
25c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * and {@link #nextValue} method. Example usage: <pre>
26c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * String json = "{"
27c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson *         + "  \"query\": \"Pizza\", "
28c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson *         + "  \"locations\": [ 94043, 90210 ] "
29c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson *         + "}";
3051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson *
31c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
32c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * String query = object.getString("query");
33c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * JSONArray locations = object.getJSONArray("locations");</pre>
34c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson *
3519554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson * <p>For best interoperability and performance use JSON that complies with
3619554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson * RFC 4627, such as that generated by {@link JSONStringer}. For legacy reasons
3719554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson * this parser is lenient, so a successful parse does not indicate that the
3819554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson * input string was valid JSON. All of the following syntax errors will be
3919554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson * ignored:
4019554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson * <ul>
4119554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson *   <li>End of line comments starting with {@code //} or {@code #} and ending
4219554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson *       with a newline character.
4319554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson *   <li>C-style comments starting with {@code /*} and ending with
4419554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson *       {@code *}{@code /}. Such comments may not be nested.
4519554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson *   <li>Strings that are unquoted or {@code 'single quoted'}.
4619554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson *   <li>Hexadecimal integers prefixed with {@code 0x} or {@code 0X}.
4719554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson *   <li>Octal integers prefixed with {@code 0}.
4819554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson *   <li>Array elements separated by {@code ;}.
49661054f5a2f7f8f5f3ceffb97e803211b546e7fcJesse Wilson *   <li>Unnecessary array separators. These are interpreted as if null was the
5019554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson *       omitted value.
5119554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson *   <li>Key-value pairs separated by {@code =} or {@code =>}.
5219554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson *   <li>Key-value pairs separated by {@code ;}.
5319554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson * </ul>
54c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson *
55c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * <p>Each tokener may be used to parse a single JSON string. Instances of this
56c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * class are not thread safe. Although this class is nonfinal, it was not
57c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * designed for inheritance and should not be subclassed. In particular,
58661054f5a2f7f8f5f3ceffb97e803211b546e7fcJesse Wilson * self-use by overrideable methods is not specified. See <i>Effective Java</i>
59c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * Item 17, "Design and Document or inheritance or else prohibit it" for further
60c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * information.
6151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson */
6251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilsonpublic class JSONTokener {
6351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
6451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    /** The input JSON. */
6551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    private final String in;
6651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
6751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    /**
6895cf9534436835291927cb4bcb36842731319da8Jesse Wilson     * The index of the next character to be returned by {@link #next}. When
6951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * the input is exhausted, this equals the input's length.
7051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     */
7151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    private int pos;
7251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
73c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson    /**
74c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * @param in JSON encoded string. Null is not permitted and will yield a
75c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     *     tokener that throws {@code NullPointerExceptions} when methods are
76c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     *     called.
77c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     */
7851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    public JSONTokener(String in) {
79037fb18dd4ba3f54c5b2fb5386c5673e1db5babfJesse Wilson        // consume an optional byte order mark (BOM) if it exists
80037fb18dd4ba3f54c5b2fb5386c5673e1db5babfJesse Wilson        if (in != null && in.startsWith("\ufeff")) {
81037fb18dd4ba3f54c5b2fb5386c5673e1db5babfJesse Wilson            in = in.substring(1);
82037fb18dd4ba3f54c5b2fb5386c5673e1db5babfJesse Wilson        }
8351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        this.in = in;
8451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
8551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
86c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson    /**
87c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * Returns the next value from the input.
88c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     *
89c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * @return a {@link JSONObject}, {@link JSONArray}, String, Boolean,
90c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     *     Integer, Long, Double or {@link JSONObject#NULL}.
91c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * @throws JSONException if the input is malformed.
92c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     */
9351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    public Object nextValue() throws JSONException {
9451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        int c = nextCleanInternal();
9551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        switch (c) {
9651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            case -1:
9751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                throw syntaxError("End of input");
9851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
9951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            case '{':
10051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                return readObject();
10151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
10251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            case '[':
10351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                return readArray();
10451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
10551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            case '\'':
10651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            case '"':
10751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                return nextString((char) c);
10851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
10951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            default:
11051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                pos--;
11151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                return readLiteral();
11251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
11351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
11451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
11551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    private int nextCleanInternal() throws JSONException {
11651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        while (pos < in.length()) {
11751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            int c = in.charAt(pos++);
11851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            switch (c) {
11951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                case '\t':
12051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                case ' ':
12151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                case '\n':
12251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                case '\r':
12351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    continue;
12451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
12551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                case '/':
12651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    if (pos == in.length()) {
12751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                        return c;
12851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    }
12951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
13051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    char peek = in.charAt(pos);
13119554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                    switch (peek) {
13219554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                        case '*':
13319554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                            // skip a /* c-style comment */
13419554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                            pos++;
13519554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                            int commentEnd = in.indexOf("*/", pos);
13619554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                            if (commentEnd == -1) {
13719554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                                throw syntaxError("Unterminated comment");
13819554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                            }
13919554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                            pos = commentEnd + 2;
14019554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                            continue;
14119554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson
14219554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                        case '/':
14319554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                            // skip a // end-of-line comment
14419554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                            pos++;
14519554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                            skipToEndOfLine();
14619554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                            continue;
14719554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson
14819554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                        default:
14919554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                            return c;
15051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    }
15151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
15219554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                case '#':
15319554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                    /*
15419554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                     * Skip a # hash end-of-line comment. The JSON RFC doesn't
1555501a3d4b3d7657c183ed5446fe67fa011fbf70bElliott Hughes                     * specify this behavior, but it's required to parse
15619554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                     * existing documents. See http://b/2571423.
15719554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                     */
15819554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                    skipToEndOfLine();
15951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    continue;
16051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
16151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                default:
16251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    return c;
16351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            }
16451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
16551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
16651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        return -1;
16751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
16851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
16951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    /**
17019554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson     * Advances the position until after the next newline character. If the line
17119554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson     * is terminated by "\r\n", the '\n' must be consumed as whitespace by the
17219554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson     * caller.
17351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     */
17419554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson    private void skipToEndOfLine() {
17519554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson        for (; pos < in.length(); pos++) {
17619554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson            char c = in.charAt(pos);
17719554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson            if (c == '\r' || c == '\n') {
17819554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                pos++;
17919554ec99d57e820a4c9da3bcde93d77b537d515Jesse Wilson                break;
18051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            }
18151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
18251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
18351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
18451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    /**
185c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * Returns the string up to but not including {@code quote}, unescaping any
186c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * character escape sequences encountered along the way. The opening quote
187c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * should have already been read. This consumes the closing quote, but does
188c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * not include it in the returned string.
18951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     *
190c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * @param quote either ' or ".
19151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     */
19251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    public String nextString(char quote) throws JSONException {
19351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        /*
19451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson         * For strings that are free of escape sequences, we can just extract
19551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson         * the result as a substring of the input. But if we encounter an escape
19651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson         * sequence, we need to use a StringBuilder to compose the result.
19751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson         */
19851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        StringBuilder builder = null;
19951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
20051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        /* the index of the first character not yet appended to the builder. */
20151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        int start = pos;
20251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
20351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        while (pos < in.length()) {
20451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            int c = in.charAt(pos++);
20551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            if (c == quote) {
20651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                if (builder == null) {
20751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    // a new string avoids leaking memory
20851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    return new String(in.substring(start, pos - 1));
20951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                } else {
21051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    builder.append(in, start, pos - 1);
21151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    return builder.toString();
21251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                }
21351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            }
21451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
21551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            if (c == '\\') {
21651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                if (pos == in.length()) {
21751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    throw syntaxError("Unterminated escape sequence");
21851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                }
21951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                if (builder == null) {
22051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    builder = new StringBuilder();
22151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                }
22251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                builder.append(in, start, pos - 1);
22351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                builder.append(readEscapeCharacter());
22451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                start = pos;
22551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            }
22651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
22751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
22851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        throw syntaxError("Unterminated string");
22951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
23051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
23151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    /**
23251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * Unescapes the character identified by the character or characters that
23351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * immediately follow a backslash. The backslash '\' should have already
23451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * been read. This supports both unicode escapes "u000A" and two-character
23551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * escapes "\n".
23651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     */
23751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    private char readEscapeCharacter() throws JSONException {
23851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        char escaped = in.charAt(pos++);
23951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        switch (escaped) {
24051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            case 'u':
24151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                if (pos + 4 > in.length()) {
24251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    throw syntaxError("Unterminated escape sequence");
24351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                }
24451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                String hex = in.substring(pos, pos + 4);
24551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                pos += 4;
2468e2f8aff8b2c9493ebffb8ad3825e58d02253471Elliott Hughes                try {
2478e2f8aff8b2c9493ebffb8ad3825e58d02253471Elliott Hughes                    return (char) Integer.parseInt(hex, 16);
2488e2f8aff8b2c9493ebffb8ad3825e58d02253471Elliott Hughes                } catch (NumberFormatException nfe) {
2498e2f8aff8b2c9493ebffb8ad3825e58d02253471Elliott Hughes                    throw syntaxError("Invalid escape sequence: " + hex);
2508e2f8aff8b2c9493ebffb8ad3825e58d02253471Elliott Hughes                }
25151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
25251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            case 't':
25351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                return '\t';
25451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
25551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            case 'b':
25651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                return '\b';
25751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
25851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            case 'n':
25951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                return '\n';
26051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
26151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            case 'r':
26251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                return '\r';
26351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
26451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            case 'f':
26551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                return '\f';
26651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
26751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            case '\'':
26851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            case '"':
26951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            case '\\':
27051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            default:
27151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                return escaped;
27251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
27351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
27451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
27551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    /**
27651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * Reads a null, boolean, numeric or unquoted string literal value. Numeric
27751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * values will be returned as an Integer, Long, or Double, in that order of
27851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * preference.
27951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     */
28051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    private Object readLiteral() throws JSONException {
28151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        String literal = nextToInternal("{}[]/\\:,=;# \t\f");
28251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
28351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        if (literal.length() == 0) {
28451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            throw syntaxError("Expected literal value");
28551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        } else if ("null".equalsIgnoreCase(literal)) {
28651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            return JSONObject.NULL;
28751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        } else if ("true".equalsIgnoreCase(literal)) {
28851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            return Boolean.TRUE;
28951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        } else if ("false".equalsIgnoreCase(literal)) {
29051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            return Boolean.FALSE;
29151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
29251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
29351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        /* try to parse as an integral type... */
29451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        if (literal.indexOf('.') == -1) {
29551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            int base = 10;
29651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            String number = literal;
29751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            if (number.startsWith("0x") || number.startsWith("0X")) {
29851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                number = number.substring(2);
29951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                base = 16;
30051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            } else if (number.startsWith("0") && number.length() > 1) {
30151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                number = number.substring(1);
30251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                base = 8;
30351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            }
30451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            try {
30551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                long longValue = Long.parseLong(number, base);
30651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) {
30751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    return (int) longValue;
30851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                } else {
30951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    return longValue;
31051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                }
31151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            } catch (NumberFormatException e) {
31251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                /*
31351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                 * This only happens for integral numbers greater than
31451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                 * Long.MAX_VALUE, numbers in exponential form (5e-10) and
31551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                 * unquoted strings. Fall through to try floating point.
31651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                 */
31751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            }
31851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
31951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
32051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        /* ...next try to parse as a floating point... */
32151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        try {
32251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            return Double.valueOf(literal);
323661054f5a2f7f8f5f3ceffb97e803211b546e7fcJesse Wilson        } catch (NumberFormatException ignored) {
32451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
32551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
32651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        /* ... finally give up. We have an unquoted string */
32751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        return new String(literal); // a new string avoids leaking memory
32851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
32951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
33051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    /**
331c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * Returns the string up to but not including any of the given characters or
332c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * a newline character. This does not consume the excluded character.
33351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     */
33451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    private String nextToInternal(String excluded) {
33551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        int start = pos;
33651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        for (; pos < in.length(); pos++) {
33751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            char c = in.charAt(pos);
33851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            if (c == '\r' || c == '\n' || excluded.indexOf(c) != -1) {
33951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                return in.substring(start, pos);
34051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            }
34151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
34251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        return in.substring(start);
34351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
34451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
34551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    /**
34651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * Reads a sequence of key/value pairs and the trailing closing brace '}' of
34751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * an object. The opening brace '{' should have already been read.
34851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     */
34951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    private JSONObject readObject() throws JSONException {
35051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        JSONObject result = new JSONObject();
35151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
35251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        /* Peek to see if this is the empty object. */
35351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        int first = nextCleanInternal();
35451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        if (first == '}') {
35551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            return result;
35651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        } else if (first != -1) {
35751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            pos--;
35851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
35951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
36051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        while (true) {
36151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            Object name = nextValue();
36251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            if (!(name instanceof String)) {
36351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                if (name == null) {
36451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    throw syntaxError("Names cannot be null");
36551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                } else {
36651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    throw syntaxError("Names must be strings, but " + name
36751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                            + " is of type " + name.getClass().getName());
36851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                }
36951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            }
37051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
37151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            /*
37251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson             * Expect the name/value separator to be either a colon ':', an
37351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson             * equals sign '=', or an arrow "=>". The last two are bogus but we
37451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson             * include them because that's what the original implementation did.
37551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson             */
37651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            int separator = nextCleanInternal();
37751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            if (separator != ':' && separator != '=') {
37851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                throw syntaxError("Expected ':' after " + name);
37951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            }
38051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            if (pos < in.length() && in.charAt(pos) == '>') {
38151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                pos++;
38251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            }
38351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
38451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            result.put((String) name, nextValue());
38551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
38651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            switch (nextCleanInternal()) {
38751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                case '}':
38851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    return result;
38951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                case ';':
39051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                case ',':
39151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    continue;
39251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                default:
39351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    throw syntaxError("Unterminated object");
39451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            }
39551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
39651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
39751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
39851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    /**
39951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * Reads a sequence of values and the trailing closing brace ']' of an
40051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * array. The opening brace '[' should have already been read. Note that
40151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * "[]" yields an empty array, but "[,]" returns a two-element array
40251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * equivalent to "[null,null]".
40351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     */
40451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    private JSONArray readArray() throws JSONException {
40551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        JSONArray result = new JSONArray();
40651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
40751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        /* to cover input that ends with ",]". */
40851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        boolean hasTrailingSeparator = false;
40951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
41051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        while (true) {
41151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            switch (nextCleanInternal()) {
41251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                case -1:
41351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    throw syntaxError("Unterminated array");
41451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                case ']':
41551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    if (hasTrailingSeparator) {
41651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                        result.put(null);
41751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    }
41851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    return result;
41951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                case ',':
42051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                case ';':
42151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    /* A separator without a value first means "null". */
42251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    result.put(null);
42351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    hasTrailingSeparator = true;
42451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    continue;
42551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                default:
42651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    pos--;
42751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            }
42851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
42951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            result.put(nextValue());
43051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
43151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            switch (nextCleanInternal()) {
43251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                case ']':
43351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    return result;
43451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                case ',':
43551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                case ';':
43651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    hasTrailingSeparator = true;
43751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    continue;
43851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                default:
43951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson                    throw syntaxError("Unterminated array");
44051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            }
44151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
44251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
44351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
444c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson    /**
445c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * Returns an exception containing the given message plus the current
446c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * position and the entire input string.
447c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     */
448c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson    public JSONException syntaxError(String message) {
449c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson        return new JSONException(message + this);
45051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
45151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
452c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson    /**
453c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * Returns the current position and the entire input string.
454c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     */
45551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    @Override public String toString() {
45651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        // consistent with the original implementation
45751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        return " at character " + pos + " of " + in;
45851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
45951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
46051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    /*
46151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * Legacy APIs.
46251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     *
46351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * None of the methods below are on the critical path of parsing JSON
46451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * documents. They exist only because they were exposed by the original
46551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     * implementation and may be used by some clients.
46651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     */
46751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
468c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson    /**
469c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * Returns true until the input has been exhausted.
470c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     */
47151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    public boolean more() {
47251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        return pos < in.length();
47351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
47451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
475c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson    /**
476c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * Returns the next available character, or the null character '\0' if all
477c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * input has been exhausted. The return value of this method is ambiguous
478c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * for JSON strings that contain the character '\0'.
479c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     */
48051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    public char next() {
48151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        return pos < in.length() ? in.charAt(pos++) : '\0';
48251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
48351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
484c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson    /**
485c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * Returns the next available character if it equals {@code c}. Otherwise an
486c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * exception is thrown.
487c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     */
48851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    public char next(char c) throws JSONException {
48951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        char result = next();
49051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        if (result != c) {
49151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            throw syntaxError("Expected " + c + " but was " + result);
49251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
49351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        return result;
49451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
49551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
496c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson    /**
497c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * Returns the next character that is not whitespace and does not belong to
498c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * a comment. If the input is exhausted before such a character can be
499c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * found, the null character '\0' is returned. The return value of this
500c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * method is ambiguous for JSON strings that contain the character '\0'.
501c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     */
50251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    public char nextClean() throws JSONException {
50351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        int nextCleanInt = nextCleanInternal();
50451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        return nextCleanInt == -1 ? '\0' : (char) nextCleanInt;
50551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
50651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
50751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    /**
508c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * Returns the next {@code length} characters of the input.
509c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     *
510c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * <p>The returned string shares its backing character array with this
511c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * tokener's input string. If a reference to the returned string may be held
512d79a9eede731ac48cfeb152ca59f8dd574ae1284Jesse Wilson     * indefinitely, you should use {@code new String(result)} to copy it first
513d79a9eede731ac48cfeb152ca59f8dd574ae1284Jesse Wilson     * to avoid memory leaks.
514c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     *
515c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * @throws JSONException if the remaining input is not long enough to
516c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     *     satisfy this request.
51751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     */
51851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    public String next(int length) throws JSONException {
51951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        if (pos + length > in.length()) {
52051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            throw syntaxError(length + " is out of bounds");
52151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
52251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        String result = in.substring(pos, pos + length);
52351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        pos += length;
52451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        return result;
52551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
52651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
52751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    /**
528c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * Returns the {@link String#trim trimmed} string holding the characters up
529c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * to but not including the first of:
530c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * <ul>
531c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     *   <li>any character in {@code excluded}
532c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     *   <li>a newline character '\n'
533c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     *   <li>a carriage return '\r'
534c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * </ul>
535c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     *
536c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * <p>The returned string shares its backing character array with this
537c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * tokener's input string. If a reference to the returned string may be held
538d79a9eede731ac48cfeb152ca59f8dd574ae1284Jesse Wilson     * indefinitely, you should use {@code new String(result)} to copy it first
539d79a9eede731ac48cfeb152ca59f8dd574ae1284Jesse Wilson     * to avoid memory leaks.
540c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     *
541c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * @return a possibly-empty string
54251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     */
54351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    public String nextTo(String excluded) {
54451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        if (excluded == null) {
545c2d0a1f1bd2c6414c29dd44fe240dcf1f45e59b9Elliott Hughes            throw new NullPointerException("excluded == null");
54651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
54751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        return nextToInternal(excluded).trim();
54851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
54951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
55051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    /**
551c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * Equivalent to {@code nextTo(String.valueOf(excluded))}.
55251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson     */
55351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    public String nextTo(char excluded) {
55451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        return nextToInternal(String.valueOf(excluded)).trim();
55551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
55651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
557c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson    /**
558c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * Advances past all input up to and including the next occurrence of
559c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * {@code thru}. If the remaining input doesn't contain {@code thru}, the
560c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * input is exhausted.
561c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     */
56251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    public void skipPast(String thru) {
56351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        int thruStart = in.indexOf(thru, pos);
56451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        pos = thruStart == -1 ? in.length() : (thruStart + thru.length());
56551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
56651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
567c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson    /**
568c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * Advances past all input up to but not including the next occurrence of
569c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * {@code to}. If the remaining input doesn't contain {@code to}, the input
570c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * is unchanged.
571c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     */
57251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    public char skipTo(char to) {
573c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson        int index = in.indexOf(to, pos);
574c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson        if (index != -1) {
575c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson            pos = index;
576c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson            return to;
577c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson        } else {
578c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson            return '\0';
57951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
58051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
58151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
582c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson    /**
583c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * Unreads the most recent character of input. If no input characters have
584c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * been read, the input is unchanged.
585c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     */
58651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    public void back() {
58751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        if (--pos == -1) {
58851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            pos = 0;
58951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
59051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
59151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson
592c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson    /**
593c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * Returns the integer [0..15] value for the given hex character, or -1
594c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * for non-hex input.
595c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     *
596c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     * @param hex a character in the ranges [0-9], [A-F] or [a-f]. Any other
597c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     *     character will yield a -1 result.
598c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson     */
59951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    public static int dehexchar(char hex) {
60051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        if (hex >= '0' && hex <= '9') {
60151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            return hex - '0';
60251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        } else if (hex >= 'A' && hex <= 'F') {
60351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            return hex - 'A' + 10;
60451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        } else if (hex >= 'a' && hex <= 'f') {
60551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            return hex - 'a' + 10;
60651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        } else {
60751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson            return -1;
60851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson        }
60951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson    }
61051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson}
611