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