+++ /dev/null
-/*--------------------------------------------------------------------------\r
- * Copyright 2009 Taro L. Saito\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- *--------------------------------------------------------------------------*/\r
-//--------------------------------------\r
-// XerialJ\r
-//\r
-// JSONTokener.java\r
-// Since: 2009/04/23 0:46:57\r
-//\r
-// $URL$\r
-// $Author$\r
-//--------------------------------------\r
-package org.xerial.json.impl;\r
-\r
-import java.io.BufferedReader;\r
-import java.io.IOException;\r
-import java.io.Reader;\r
-import java.io.StringReader;\r
-\r
-import org.xerial.json.JSONArray;\r
-import org.xerial.json.JSONBoolean;\r
-import org.xerial.json.JSONDouble;\r
-import org.xerial.json.JSONErrorCode;\r
-import org.xerial.json.JSONException;\r
-import org.xerial.json.JSONInteger;\r
-import org.xerial.json.JSONLong;\r
-import org.xerial.json.JSONNull;\r
-import org.xerial.json.JSONObject;\r
-import org.xerial.json.JSONString;\r
-import org.xerial.json.JSONValue;\r
-\r
-/*\r
-Copyright (c) 2002 JSON.org\r
-\r
-Permission is hereby granted, free of charge, to any person obtaining a copy\r
-of this software and associated documentation files (the "Software"), to deal\r
-in the Software without restriction, including without limitation the rights\r
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
-copies of the Software, and to permit persons to whom the Software is\r
-furnished to do so, subject to the following conditions:\r
-\r
-The above copyright notice and this permission notice shall be included in all\r
-copies or substantial portions of the Software.\r
-\r
-The Software shall be used for Good, not Evil.\r
-\r
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
-SOFTWARE.\r
-*/\r
-\r
-/**\r
- * A JSONTokener takes a source string and extracts characters and tokens from\r
- * it. It is used by the JSONObject and JSONArray constructors to parse JSON\r
- * source strings.\r
- * \r
- * @author JSON.org\r
- * @version 2008-09-18\r
- */\r
-public class JSONTokenizer\r
-{\r
-\r
- private int index;\r
- private Reader reader;\r
- private char lastChar;\r
- private boolean useLastChar;\r
-\r
- /**\r
- * Construct a JSONTokener from a string.\r
- * \r
- * @param reader\r
- * A reader.\r
- */\r
- public JSONTokenizer(Reader reader)\r
- {\r
- this.reader = reader.markSupported() ? reader : new BufferedReader(reader);\r
- this.useLastChar = false;\r
- this.index = 0;\r
- }\r
-\r
- /**\r
- * Construct a JSONTokener from a string.\r
- * \r
- * @param s\r
- * A source string.\r
- */\r
- public JSONTokenizer(String s)\r
- {\r
- this(new StringReader(s));\r
- }\r
-\r
- /**\r
- * Back up one character. This provides a sort of lookahead capability, so\r
- * that you can test for a digit or letter before attempting to parse the\r
- * next number or identifier.\r
- */\r
- public void back() throws JSONException\r
- {\r
- if (useLastChar || index <= 0)\r
- {\r
- throw new JSONException(JSONErrorCode.InvalidJSONData, "Stepping back two steps is not supported");\r
- }\r
- index -= 1;\r
- useLastChar = true;\r
- }\r
-\r
- /**\r
- * Get the hex value of a character (base16).\r
- * \r
- * @param c\r
- * A character between '0' and '9' or between 'A' and 'F' or\r
- * between 'a' and 'f'.\r
- * @return An int between 0 and 15, or -1 if c was not a hex digit.\r
- */\r
- public static int dehexchar(char c)\r
- {\r
- if (c >= '0' && c <= '9')\r
- {\r
- return c - '0';\r
- }\r
- if (c >= 'A' && c <= 'F')\r
- {\r
- return c - ('A' - 10);\r
- }\r
- if (c >= 'a' && c <= 'f')\r
- {\r
- return c - ('a' - 10);\r
- }\r
- return -1;\r
- }\r
-\r
- /**\r
- * Determine if the source string still contains characters that next() can\r
- * consume.\r
- * \r
- * @return true if not yet at the end of the source.\r
- */\r
- public boolean more() throws JSONException\r
- {\r
- char nextChar = next();\r
- if (nextChar == 0)\r
- {\r
- return false;\r
- }\r
- back();\r
- return true;\r
- }\r
-\r
- /**\r
- * Get the next character in the source string.\r
- * \r
- * @return The next character, or 0 if past the end of the source string.\r
- */\r
- public char next() throws JSONException\r
- {\r
- if (this.useLastChar)\r
- {\r
- this.useLastChar = false;\r
- if (this.lastChar != 0)\r
- {\r
- this.index += 1;\r
- }\r
- return this.lastChar;\r
- }\r
- int c;\r
- try\r
- {\r
- c = this.reader.read();\r
- }\r
- catch (IOException exc)\r
- {\r
- throw new JSONException(JSONErrorCode.InvalidJSONData, exc);\r
- }\r
-\r
- if (c <= 0)\r
- { // End of stream\r
- this.lastChar = 0;\r
- return 0;\r
- }\r
- this.index += 1;\r
- this.lastChar = (char) c;\r
- return this.lastChar;\r
- }\r
-\r
- /**\r
- * Consume the next character, and check that it matches a specified\r
- * character.\r
- * \r
- * @param c\r
- * The character to match.\r
- * @return The character.\r
- * @throws JSONException\r
- * if the character does not match.\r
- */\r
- public char next(char c) throws JSONException\r
- {\r
- char n = next();\r
- if (n != c)\r
- {\r
- throw syntaxError("Expected '" + c + "' and instead saw '" + n + "'");\r
- }\r
- return n;\r
- }\r
-\r
- /**\r
- * Get the next n characters.\r
- * \r
- * @param n\r
- * The number of characters to take.\r
- * @return A string of n characters.\r
- * @throws JSONException\r
- * Substring bounds error if there are not n characters\r
- * remaining in the source string.\r
- */\r
- public String next(int n) throws JSONException\r
- {\r
- if (n == 0)\r
- {\r
- return "";\r
- }\r
-\r
- char[] buffer = new char[n];\r
- int pos = 0;\r
-\r
- if (this.useLastChar)\r
- {\r
- this.useLastChar = false;\r
- buffer[0] = this.lastChar;\r
- pos = 1;\r
- }\r
-\r
- try\r
- {\r
- int len;\r
- while ((pos < n) && ((len = reader.read(buffer, pos, n - pos)) != -1))\r
- {\r
- pos += len;\r
- }\r
- }\r
- catch (IOException exc)\r
- {\r
- throw new JSONException(JSONErrorCode.InvalidJSONData, exc);\r
- }\r
- this.index += pos;\r
-\r
- if (pos < n)\r
- {\r
- throw syntaxError("Substring bounds error");\r
- }\r
-\r
- this.lastChar = buffer[n - 1];\r
- return new String(buffer);\r
- }\r
-\r
- /**\r
- * Get the next char in the string, skipping whitespace.\r
- * \r
- * @throws JSONException\r
- * @return A character, or 0 if there are no more characters.\r
- */\r
- public char nextClean() throws JSONException\r
- {\r
- for (;;)\r
- {\r
- char c = next();\r
- if (c == 0 || c > ' ')\r
- {\r
- return c;\r
- }\r
- }\r
- }\r
-\r
- /**\r
- * Return the characters up to the next close quote character. Backslash\r
- * processing is done. The formal JSON format does not allow strings in\r
- * single quotes, but an implementation is allowed to accept them.\r
- * \r
- * @param quote\r
- * The quoting character, either <code>"</code> <small>(double\r
- * quote)</small> or <code>'</code> <small>(single quote)</small>.\r
- * @return A String.\r
- * @throws JSONException\r
- * Unterminated string.\r
- */\r
- public JSONString nextString(char quote) throws JSONException\r
- {\r
- char c;\r
- StringBuffer sb = new StringBuffer();\r
- for (;;)\r
- {\r
- c = next();\r
- switch (c)\r
- {\r
- case 0:\r
- case '\n':\r
- case '\r':\r
- throw syntaxError("Unterminated string");\r
- case '\\':\r
- c = next();\r
- switch (c)\r
- {\r
- case 'b':\r
- sb.append('\b');\r
- break;\r
- case 't':\r
- sb.append('\t');\r
- break;\r
- case 'n':\r
- sb.append('\n');\r
- break;\r
- case 'f':\r
- sb.append('\f');\r
- break;\r
- case 'r':\r
- sb.append('\r');\r
- break;\r
- case 'u':\r
- sb.append((char) Integer.parseInt(next(4), 16));\r
- break;\r
- case 'x':\r
- sb.append((char) Integer.parseInt(next(2), 16));\r
- break;\r
- default:\r
- sb.append(c);\r
- }\r
- break;\r
- default:\r
- if (c == quote)\r
- {\r
- return new JSONString(sb.toString());\r
- }\r
- sb.append(c);\r
- }\r
- }\r
- }\r
-\r
- /**\r
- * Get the text up but not including the specified character or the end of\r
- * line, whichever comes first.\r
- * \r
- * @param d\r
- * A delimiter character.\r
- * @return A string.\r
- */\r
- public String nextTo(char d) throws JSONException\r
- {\r
- StringBuffer sb = new StringBuffer();\r
- for (;;)\r
- {\r
- char c = next();\r
- if (c == d || c == 0 || c == '\n' || c == '\r')\r
- {\r
- if (c != 0)\r
- {\r
- back();\r
- }\r
- return sb.toString().trim();\r
- }\r
- sb.append(c);\r
- }\r
- }\r
-\r
- /**\r
- * Get the text up but not including one of the specified delimiter\r
- * characters or the end of line, whichever comes first.\r
- * \r
- * @param delimiters\r
- * A set of delimiter characters.\r
- * @return A string, trimmed.\r
- */\r
- public String nextTo(String delimiters) throws JSONException\r
- {\r
- char c;\r
- StringBuffer sb = new StringBuffer();\r
- for (;;)\r
- {\r
- c = next();\r
- if (delimiters.indexOf(c) >= 0 || c == 0 || c == '\n' || c == '\r')\r
- {\r
- if (c != 0)\r
- {\r
- back();\r
- }\r
- return sb.toString().trim();\r
- }\r
- sb.append(c);\r
- }\r
- }\r
-\r
- /**\r
- * Get the next value. The value can be a Boolean, Double, Integer,\r
- * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.\r
- * \r
- * @throws JSONException\r
- * If syntax error.\r
- * \r
- * @return An object.\r
- */\r
- public JSONValue nextValue() throws JSONException\r
- {\r
- char c = nextClean();\r
- String s;\r
-\r
- switch (c)\r
- {\r
- case '"':\r
- case '\'':\r
- return nextString(c);\r
- case '{':\r
- back();\r
- return new JSONObject(this);\r
- case '[':\r
- case '(':\r
- back();\r
- return new JSONArray(this);\r
- }\r
-\r
- /*\r
- * Handle unquoted text. This could be the values true, false, or\r
- * null, or it can be a number. An implementation (such as this one)\r
- * is allowed to also accept non-standard forms.\r
- *\r
- * Accumulate characters until we reach the end of the text or a\r
- * formatting character.\r
- */\r
-\r
- StringBuffer sb = new StringBuffer();\r
- while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0)\r
- {\r
- sb.append(c);\r
- c = next();\r
- }\r
- back();\r
-\r
- s = sb.toString().trim();\r
- if (s.equals(""))\r
- {\r
- throw syntaxError("Missing value");\r
- }\r
- return stringToValue(s);\r
- }\r
-\r
- /**\r
- * Try to convert a string into a number, boolean, or null. If the string\r
- * can't be converted, return the string.\r
- * \r
- * @param s\r
- * A String.\r
- * @return A simple JSON value.\r
- */\r
- public static JSONValue stringToValue(String s)\r
- {\r
- if (s.equals(""))\r
- {\r
- return new JSONString(s);\r
- }\r
- if (s.equalsIgnoreCase("true"))\r
- {\r
- return new JSONBoolean(true);\r
- }\r
- if (s.equalsIgnoreCase("false"))\r
- {\r
- return new JSONBoolean(false);\r
- }\r
- if (s.equalsIgnoreCase("null"))\r
- {\r
- return new JSONNull();\r
- }\r
-\r
- /*\r
- * If it might be a number, try converting it. We support the 0- and 0x-\r
- * conventions. If a number cannot be produced, then the value will just\r
- * be a string. Note that the 0-, 0x-, plus, and implied string\r
- * conventions are non-standard. A JSON parser is free to accept\r
- * non-JSON forms as long as it accepts all correct JSON forms.\r
- */\r
-\r
- char b = s.charAt(0);\r
- if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+')\r
- {\r
- if (b == '0')\r
- {\r
- if (s.length() > 2 && (s.charAt(1) == 'x' || s.charAt(1) == 'X'))\r
- {\r
- try\r
- {\r
- return new JSONInteger(Integer.parseInt(s.substring(2), 16));\r
- }\r
- catch (Exception e)\r
- {\r
- /* Ignore the error */\r
- }\r
- }\r
- else\r
- {\r
- try\r
- {\r
- return new JSONInteger(Integer.parseInt(s, 8));\r
- }\r
- catch (Exception e)\r
- {\r
- /* Ignore the error */\r
- }\r
- }\r
- }\r
- try\r
- {\r
- if (s.indexOf('.') > -1 || s.indexOf('e') > -1 || s.indexOf('E') > -1)\r
- {\r
- return new JSONDouble(Double.valueOf(s));\r
- }\r
- else\r
- {\r
- Long myLong = new Long(s);\r
- if (myLong.longValue() == myLong.intValue())\r
- {\r
- return new JSONInteger(myLong.intValue());\r
- }\r
- else\r
- {\r
- return new JSONLong(myLong);\r
- }\r
- }\r
- }\r
- catch (Exception f)\r
- {\r
- /* Ignore the error */\r
- }\r
- }\r
- return new JSONString(s);\r
- }\r
-\r
- /**\r
- * Skip characters until the next character is the requested character. If\r
- * the requested character is not found, no characters are skipped.\r
- * \r
- * @param to\r
- * A character to skip to.\r
- * @return The requested character, or zero if the requested character is\r
- * not found.\r
- */\r
- public char skipTo(char to) throws JSONException\r
- {\r
- char c;\r
- try\r
- {\r
- int startIndex = this.index;\r
- reader.mark(Integer.MAX_VALUE);\r
- do\r
- {\r
- c = next();\r
- if (c == 0)\r
- {\r
- reader.reset();\r
- this.index = startIndex;\r
- return c;\r
- }\r
- }\r
- while (c != to);\r
- }\r
- catch (IOException exc)\r
- {\r
- throw new JSONException(JSONErrorCode.InvalidJSONData, exc);\r
- }\r
-\r
- back();\r
- return c;\r
- }\r
-\r
- /**\r
- * Make a JSONException to signal a syntax error.\r
- * \r
- * @param message\r
- * The error message.\r
- * @return A JSONException object, suitable for throwing\r
- */\r
- public JSONException syntaxError(String message)\r
- {\r
- return new JSONException(JSONErrorCode.InvalidJSONData, message + toString());\r
- }\r
-\r
- /**\r
- * Make a printable string of this JSONTokener.\r
- * \r
- * @return " at character [this.index]"\r
- */\r
- public String toString()\r
- {\r
- return " at character " + index;\r
- }\r
-}
\ No newline at end of file