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 * @throws NumberFormatException if any unicode escape sequences are 19251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * malformed. 19351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson */ 19451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson public String nextString(char quote) throws JSONException { 19551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /* 19651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * For strings that are free of escape sequences, we can just extract 19751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * the result as a substring of the input. But if we encounter an escape 19851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * sequence, we need to use a StringBuilder to compose the result. 19951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson */ 20051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson StringBuilder builder = null; 20151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 20251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /* the index of the first character not yet appended to the builder. */ 20351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson int start = pos; 20451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 20551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson while (pos < in.length()) { 20651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson int c = in.charAt(pos++); 20751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (c == quote) { 20851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (builder == null) { 20951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson // a new string avoids leaking memory 21051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return new String(in.substring(start, pos - 1)); 21151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } else { 21251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson builder.append(in, start, pos - 1); 21351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return builder.toString(); 21451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 21551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 21651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 21751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (c == '\\') { 21851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (pos == in.length()) { 21951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson throw syntaxError("Unterminated escape sequence"); 22051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 22151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (builder == null) { 22251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson builder = new StringBuilder(); 22351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 22451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson builder.append(in, start, pos - 1); 22551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson builder.append(readEscapeCharacter()); 22651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson start = pos; 22751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 22851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 22951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 23051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson throw syntaxError("Unterminated string"); 23151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 23251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 23351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /** 23451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * Unescapes the character identified by the character or characters that 23551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * immediately follow a backslash. The backslash '\' should have already 23651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * been read. This supports both unicode escapes "u000A" and two-character 23751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * escapes "\n". 23851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * 23951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * @throws NumberFormatException if any unicode escape sequences are 24051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * malformed. 24151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson */ 24251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson private char readEscapeCharacter() throws JSONException { 24351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson char escaped = in.charAt(pos++); 24451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson switch (escaped) { 24551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case 'u': 24651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (pos + 4 > in.length()) { 24751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson throw syntaxError("Unterminated escape sequence"); 24851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 24951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson String hex = in.substring(pos, pos + 4); 25051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson pos += 4; 25151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return (char) Integer.parseInt(hex, 16); 25251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 25351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case 't': 25451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return '\t'; 25551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 25651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case 'b': 25751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return '\b'; 25851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 25951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case 'n': 26051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return '\n'; 26151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 26251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case 'r': 26351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return '\r'; 26451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 26551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case 'f': 26651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return '\f'; 26751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 26851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case '\'': 26951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case '"': 27051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case '\\': 27151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson default: 27251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return escaped; 27351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 27451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 27551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 27651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /** 27751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * Reads a null, boolean, numeric or unquoted string literal value. Numeric 27851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * values will be returned as an Integer, Long, or Double, in that order of 27951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * preference. 28051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson */ 28151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson private Object readLiteral() throws JSONException { 28251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson String literal = nextToInternal("{}[]/\\:,=;# \t\f"); 28351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 28451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (literal.length() == 0) { 28551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson throw syntaxError("Expected literal value"); 28651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } else if ("null".equalsIgnoreCase(literal)) { 28751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return JSONObject.NULL; 28851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } else if ("true".equalsIgnoreCase(literal)) { 28951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return Boolean.TRUE; 29051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } else if ("false".equalsIgnoreCase(literal)) { 29151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return Boolean.FALSE; 29251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 29351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 29451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /* try to parse as an integral type... */ 29551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (literal.indexOf('.') == -1) { 29651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson int base = 10; 29751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson String number = literal; 29851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (number.startsWith("0x") || number.startsWith("0X")) { 29951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson number = number.substring(2); 30051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson base = 16; 30151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } else if (number.startsWith("0") && number.length() > 1) { 30251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson number = number.substring(1); 30351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson base = 8; 30451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 30551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson try { 30651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson long longValue = Long.parseLong(number, base); 30751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) { 30851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return (int) longValue; 30951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } else { 31051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return longValue; 31151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 31251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } catch (NumberFormatException e) { 31351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /* 31451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * This only happens for integral numbers greater than 31551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * Long.MAX_VALUE, numbers in exponential form (5e-10) and 31651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * unquoted strings. Fall through to try floating point. 31751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson */ 31851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 31951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 32051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 32151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /* ...next try to parse as a floating point... */ 32251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson try { 32351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return Double.valueOf(literal); 324661054f5a2f7f8f5f3ceffb97e803211b546e7fcJesse Wilson } catch (NumberFormatException ignored) { 32551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 32651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 32751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /* ... finally give up. We have an unquoted string */ 32851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return new String(literal); // a new string avoids leaking memory 32951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 33051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 33151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /** 332c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * Returns the string up to but not including any of the given characters or 333c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * a newline character. This does not consume the excluded character. 33451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson */ 33551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson private String nextToInternal(String excluded) { 33651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson int start = pos; 33751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson for (; pos < in.length(); pos++) { 33851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson char c = in.charAt(pos); 33951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (c == '\r' || c == '\n' || excluded.indexOf(c) != -1) { 34051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return in.substring(start, pos); 34151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 34251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 34351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return in.substring(start); 34451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 34551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 34651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /** 34751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * Reads a sequence of key/value pairs and the trailing closing brace '}' of 34851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * an object. The opening brace '{' should have already been read. 34951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson */ 35051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson private JSONObject readObject() throws JSONException { 35151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson JSONObject result = new JSONObject(); 35251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 35351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /* Peek to see if this is the empty object. */ 35451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson int first = nextCleanInternal(); 35551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (first == '}') { 35651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return result; 35751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } else if (first != -1) { 35851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson pos--; 35951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 36051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 36151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson while (true) { 36251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson Object name = nextValue(); 36351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (!(name instanceof String)) { 36451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (name == null) { 36551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson throw syntaxError("Names cannot be null"); 36651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } else { 36751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson throw syntaxError("Names must be strings, but " + name 36851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson + " is of type " + name.getClass().getName()); 36951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 37051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 37151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 37251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /* 37351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * Expect the name/value separator to be either a colon ':', an 37451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * equals sign '=', or an arrow "=>". The last two are bogus but we 37551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * include them because that's what the original implementation did. 37651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson */ 37751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson int separator = nextCleanInternal(); 37851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (separator != ':' && separator != '=') { 37951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson throw syntaxError("Expected ':' after " + name); 38051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 38151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (pos < in.length() && in.charAt(pos) == '>') { 38251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson pos++; 38351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 38451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 38551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson result.put((String) name, nextValue()); 38651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 38751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson switch (nextCleanInternal()) { 38851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case '}': 38951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return result; 39051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case ';': 39151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case ',': 39251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson continue; 39351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson default: 39451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson throw syntaxError("Unterminated object"); 39551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 39651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 39751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 39851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 39951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /** 40051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * Reads a sequence of values and the trailing closing brace ']' of an 40151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * array. The opening brace '[' should have already been read. Note that 40251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * "[]" yields an empty array, but "[,]" returns a two-element array 40351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * equivalent to "[null,null]". 40451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson */ 40551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson private JSONArray readArray() throws JSONException { 40651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson JSONArray result = new JSONArray(); 40751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 40851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /* to cover input that ends with ",]". */ 40951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson boolean hasTrailingSeparator = false; 41051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 41151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson while (true) { 41251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson switch (nextCleanInternal()) { 41351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case -1: 41451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson throw syntaxError("Unterminated array"); 41551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case ']': 41651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (hasTrailingSeparator) { 41751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson result.put(null); 41851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 41951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return result; 42051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case ',': 42151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case ';': 42251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /* A separator without a value first means "null". */ 42351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson result.put(null); 42451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson hasTrailingSeparator = true; 42551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson continue; 42651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson default: 42751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson pos--; 42851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 42951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 43051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson result.put(nextValue()); 43151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 43251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson switch (nextCleanInternal()) { 43351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case ']': 43451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return result; 43551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case ',': 43651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson case ';': 43751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson hasTrailingSeparator = true; 43851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson continue; 43951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson default: 44051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson throw syntaxError("Unterminated array"); 44151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 44251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 44351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 44451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 445c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson /** 446c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * Returns an exception containing the given message plus the current 447c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * position and the entire input string. 448c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson */ 449c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson public JSONException syntaxError(String message) { 450c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson return new JSONException(message + this); 45151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 45251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 453c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson /** 454c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * Returns the current position and the entire input string. 455c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson */ 45651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson @Override public String toString() { 45751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson // consistent with the original implementation 45851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return " at character " + pos + " of " + in; 45951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 46051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 46151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /* 46251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * Legacy APIs. 46351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * 46451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * None of the methods below are on the critical path of parsing JSON 46551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * documents. They exist only because they were exposed by the original 46651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson * implementation and may be used by some clients. 46751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson */ 46851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 469c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson /** 470c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * Returns true until the input has been exhausted. 471c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson */ 47251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson public boolean more() { 47351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return pos < in.length(); 47451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 47551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 476c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson /** 477c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * Returns the next available character, or the null character '\0' if all 478c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * input has been exhausted. The return value of this method is ambiguous 479c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * for JSON strings that contain the character '\0'. 480c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson */ 48151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson public char next() { 48251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return pos < in.length() ? in.charAt(pos++) : '\0'; 48351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 48451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 485c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson /** 486c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * Returns the next available character if it equals {@code c}. Otherwise an 487c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * exception is thrown. 488c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson */ 48951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson public char next(char c) throws JSONException { 49051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson char result = next(); 49151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (result != c) { 49251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson throw syntaxError("Expected " + c + " but was " + result); 49351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 49451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return result; 49551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 49651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 497c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson /** 498c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * Returns the next character that is not whitespace and does not belong to 499c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * a comment. If the input is exhausted before such a character can be 500c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * found, the null character '\0' is returned. The return value of this 501c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * method is ambiguous for JSON strings that contain the character '\0'. 502c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson */ 50351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson public char nextClean() throws JSONException { 50451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson int nextCleanInt = nextCleanInternal(); 50551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return nextCleanInt == -1 ? '\0' : (char) nextCleanInt; 50651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 50751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 50851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /** 509c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * Returns the next {@code length} characters of the input. 510c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * 511c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * <p>The returned string shares its backing character array with this 512c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * tokener's input string. If a reference to the returned string may be held 513d79a9eede731ac48cfeb152ca59f8dd574ae1284Jesse Wilson * indefinitely, you should use {@code new String(result)} to copy it first 514d79a9eede731ac48cfeb152ca59f8dd574ae1284Jesse Wilson * to avoid memory leaks. 515c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * 516c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * @throws JSONException if the remaining input is not long enough to 517c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * satisfy this request. 51851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson */ 51951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson public String next(int length) throws JSONException { 52051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (pos + length > in.length()) { 52151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson throw syntaxError(length + " is out of bounds"); 52251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 52351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson String result = in.substring(pos, pos + length); 52451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson pos += length; 52551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return result; 52651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 52751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 52851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /** 529c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * Returns the {@link String#trim trimmed} string holding the characters up 530c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * to but not including the first of: 531c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * <ul> 532c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * <li>any character in {@code excluded} 533c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * <li>a newline character '\n' 534c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * <li>a carriage return '\r' 535c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * </ul> 536c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * 537c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * <p>The returned string shares its backing character array with this 538c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * tokener's input string. If a reference to the returned string may be held 539d79a9eede731ac48cfeb152ca59f8dd574ae1284Jesse Wilson * indefinitely, you should use {@code new String(result)} to copy it first 540d79a9eede731ac48cfeb152ca59f8dd574ae1284Jesse Wilson * to avoid memory leaks. 541c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * 542c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * @return a possibly-empty string 54351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson */ 54451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson public String nextTo(String excluded) { 54551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (excluded == null) { 54651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson throw new NullPointerException(); 54751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 54851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return nextToInternal(excluded).trim(); 54951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 55051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 55151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson /** 552c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * Equivalent to {@code nextTo(String.valueOf(excluded))}. 55351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson */ 55451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson public String nextTo(char excluded) { 55551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return nextToInternal(String.valueOf(excluded)).trim(); 55651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 55751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 558c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson /** 559c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * Advances past all input up to and including the next occurrence of 560c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * {@code thru}. If the remaining input doesn't contain {@code thru}, the 561c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * input is exhausted. 562c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson */ 56351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson public void skipPast(String thru) { 56451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson int thruStart = in.indexOf(thru, pos); 56551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson pos = thruStart == -1 ? in.length() : (thruStart + thru.length()); 56651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 56751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 568c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson /** 569c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * Advances past all input up to but not including the next occurrence of 570c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * {@code to}. If the remaining input doesn't contain {@code to}, the input 571c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * is unchanged. 572c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson */ 57351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson public char skipTo(char to) { 574c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson int index = in.indexOf(to, pos); 575c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson if (index != -1) { 576c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson pos = index; 577c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson return to; 578c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson } else { 579c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson return '\0'; 58051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 58151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 58251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 583c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson /** 584c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * Unreads the most recent character of input. If no input characters have 585c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * been read, the input is unchanged. 586c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson */ 58751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson public void back() { 58851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (--pos == -1) { 58951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson pos = 0; 59051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 59151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 59251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson 593c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson /** 594c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * Returns the integer [0..15] value for the given hex character, or -1 595c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * for non-hex input. 596c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * 597c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * @param hex a character in the ranges [0-9], [A-F] or [a-f]. Any other 598c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson * character will yield a -1 result. 599c78ca6700830460f671652ce3efd4cc2c0cf7a6aJesse Wilson */ 60051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson public static int dehexchar(char hex) { 60151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson if (hex >= '0' && hex <= '9') { 60251a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return hex - '0'; 60351a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } else if (hex >= 'A' && hex <= 'F') { 60451a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return hex - 'A' + 10; 60551a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } else if (hex >= 'a' && hex <= 'f') { 60651a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return hex - 'a' + 10; 60751a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } else { 60851a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson return -1; 60951a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 61051a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson } 61151a095f0bc7aadfcc7e6b3873b97c050c523d102Jesse Wilson} 612