All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opencms.json.JSONTokener Maven / Gradle / Ivy

Go to download

OpenCms is an enterprise-ready, easy to use website content management system based on Java and XML technology. Offering a complete set of features, OpenCms helps content managers worldwide to create and maintain beautiful websites fast and efficiently.

There is a newer version: 18.0
Show newest version
/*
 * This library is part of OpenCms -
 * the Open Source Content Management System
 *
 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * For further information about Alkacon Software GmbH & Co. KG, please see the
 * company website: http://www.alkacon.com
 *
 * For further information about OpenCms, please see the
 * project website: http://www.opencms.org
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * This file is based on:
 * org.json.JSONTokener
 * from the JSON in Java implementation.
 *
 * Copyright (c) 2002 JSON.org
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * The Software shall be used for Good, not Evil.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package org.opencms.json;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;

/**
 * A JSONTokener takes a source string and extracts characters and tokens from
 * it.

* * It is used by the JSONObject and JSONArray constructors to parse * JSON source strings.

* */ public class JSONTokener { /** The index. */ private int m_index; /** The last character. */ private char m_lastChar; /** Flag which controls whether JSONObjects created by this tokener are ordered. */ private boolean m_ordered; /** The reader. */ private Reader m_reader; /** Flag indicating if the last character should be used. */ private boolean m_useLastChar; /** * Construct a JSONTokener from a string.

* * @param reader a reader. */ public JSONTokener(Reader reader) { m_reader = reader.markSupported() ? reader : new BufferedReader(reader); m_useLastChar = false; m_index = 0; } /** * Construct a JSONTokener from a string.

* * @param s a source string */ public JSONTokener(String s) { this(new StringReader(s)); } /** * Get the hex value of a character (base16).

* * @param c a character between '0' and '9' or between 'A' and 'F' or * between 'a' and 'f' * @return an int between 0 and 15, or -1 if c was not a hex digit */ public static int dehexchar(char c) { if ((c >= '0') && (c <= '9')) { return c - '0'; } if ((c >= 'A') && (c <= 'F')) { return c - ('A' - 10); } if ((c >= 'a') && (c <= 'f')) { return c - ('a' - 10); } return -1; } /** * Back up one character.

* * This provides a sort of lookahead capability, * so that you can test for a digit or letter before attempting to parse * the next number or identifier.

* * @throws JSONException if something goes wrong */ public void back() throws JSONException { if (m_useLastChar || (m_index <= 0)) { throw new JSONException("Stepping back two steps is not supported"); } m_index -= 1; m_useLastChar = true; } /** * Determine if the source string still contains characters that next() * can consume.

* * @return true if not yet at the end of the source * @throws JSONException if something goes wrong */ public boolean more() throws JSONException { char nextChar = next(); if (nextChar == 0) { return false; } back(); return true; } /** * Get the next character in the source string.

* * @return the next character, or 0 if past the end of the source string * @throws JSONException if something goes wrong */ public char next() throws JSONException { if (m_useLastChar) { m_useLastChar = false; if (m_lastChar != 0) { m_index += 1; } return m_lastChar; } int c; try { c = m_reader.read(); } catch (IOException exc) { throw new JSONException(exc); } if (c <= 0) { // End of stream m_lastChar = 0; return 0; } m_index += 1; m_lastChar = (char)c; return m_lastChar; } /** * Consume the next character, and check that it matches a specified * character.

* * @param c the character to match * @return the character * @throws JSONException if the character does not match */ public char next(char c) throws JSONException { char n = next(); if (n != c) { throw syntaxError("Expected '" + c + "' and instead saw '" + n + "'"); } return n; } /** * Get the next n characters.

* * @param n the number of characters to take * @return a string of n characters * * @throws JSONException substring bounds error if there are not n characters remaining in the source string */ public String next(int n) throws JSONException { if (n == 0) { return ""; } char[] buffer = new char[n]; int pos = 0; if (m_useLastChar) { m_useLastChar = false; buffer[0] = m_lastChar; pos = 1; } try { int len = m_reader.read(buffer, pos, n - pos); while ((pos < n) && (len != -1)) { pos += len; len = m_reader.read(buffer, pos, n - pos); } } catch (IOException exc) { throw new JSONException(exc); } m_index += pos; if (pos < n) { throw syntaxError("Substring bounds error"); } m_lastChar = buffer[n - 1]; return new String(buffer); } /** * Get the next char in the string, skipping whitespace * and comments (slashslash, slashstar, and hash).

* * @return a character, or 0 if there are no more characters * @throws JSONException if something goes wrong */ public char nextClean() throws JSONException { for (;;) { char c = next(); if (c == '/') { switch (next()) { case '/': do { c = next(); } while ((c != '\n') && (c != '\r') && (c != 0)); break; case '*': for (;;) { c = next(); if (c == 0) { throw syntaxError("Unclosed comment"); } if (c == '*') { if (next() == '/') { break; } back(); } } break; default: back(); return '/'; } } else if (c == '#') { do { c = next(); } while ((c != '\n') && (c != '\r') && (c != 0)); } else if ((c == 0) || (c > ' ')) { return c; } } } /** * Return the characters up to the next close quote character.

* * Backslash processing is done. The formal JSON format does not * allow strings in single quotes, but an implementation is allowed to * accept them.

* * @param quote The quoting character, either * " (double quote) or * ' (single quote) * @return a String * @throws JSONException in case of an unterminated string */ public String nextString(char quote) throws JSONException { char c; StringBuffer sb = new StringBuffer(); for (;;) { c = next(); switch (c) { case 0: case '\n': case '\r': throw syntaxError("Unterminated string"); case '\\': c = next(); switch (c) { case 'b': sb.append('\b'); break; case 't': sb.append('\t'); break; case 'n': sb.append('\n'); break; case 'f': sb.append('\f'); break; case 'r': sb.append('\r'); break; case 'u': sb.append((char)Integer.parseInt(next(4), 16)); break; case 'x': sb.append((char)Integer.parseInt(next(2), 16)); break; default: sb.append(c); } break; default: if (c == quote) { return sb.toString(); } sb.append(c); } } } /** * Get the text up but not including the specified character or the * end of line, whichever comes first.

* * @param d a delimiter character * @return a string * @throws JSONException if something goes wrong */ public String nextTo(char d) throws JSONException { StringBuffer sb = new StringBuffer(); for (;;) { char c = next(); if ((c == d) || (c == 0) || (c == '\n') || (c == '\r')) { if (c != 0) { back(); } return sb.toString().trim(); } sb.append(c); } } /** * Get the text up but not including one of the specified delimiter * characters or the end of line, whichever comes first.

* * @param delimiters a set of delimiter characters * @return a string, trimmed * @throws JSONException if something goes wrong */ public String nextTo(String delimiters) throws JSONException { char c; StringBuffer sb = new StringBuffer(); for (;;) { c = next(); if ((delimiters.indexOf(c) >= 0) || (c == 0) || (c == '\n') || (c == '\r')) { if (c != 0) { back(); } return sb.toString().trim(); } sb.append(c); } } /** * Get the next value. The value can be a Boolean, Double, Integer, * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.

* * @return an object * @throws JSONException if something goes wrong */ public Object nextValue() throws JSONException { char c = nextClean(); String s; switch (c) { case '"': case '\'': return nextString(c); case '{': back(); return new JSONObject(this, m_ordered); case '[': case '(': back(); return new JSONArray(this); default: } /* * Handle unquoted text. This could be the values true, false, or * null, or it can be a number. An implementation (such as this one) * is allowed to also accept non-standard forms. * * Accumulate characters until we reach the end of the text or a * formatting character. */ StringBuffer sb = new StringBuffer(); char b = c; while ((c >= ' ') && (",:]}/\\\"[{;=#".indexOf(c) < 0)) { sb.append(c); c = next(); } back(); /* * If it is true, false, or null, return the proper value. */ s = sb.toString().trim(); if (s.equals("")) { throw syntaxError("Missing value"); } if (s.equalsIgnoreCase("true")) { return Boolean.TRUE; } if (s.equalsIgnoreCase("false")) { return Boolean.FALSE; } if (s.equalsIgnoreCase("null")) { return JSONObject.NULL; } /* * If it might be a number, try converting it. We support the 0- and 0x- * conventions. If a number cannot be produced, then the value will just * be a string. Note that the 0-, 0x-, plus, and implied string * conventions are non-standard. A JSON parser is free to accept * non-JSON forms as long as it accepts all correct JSON forms. */ if (((b >= '0') && (b <= '9')) || (b == '.') || (b == '-') || (b == '+')) { if (b == '0') { if ((s.length() > 2) && ((s.charAt(1) == 'x') || (s.charAt(1) == 'X'))) { try { return new Integer(Integer.parseInt(s.substring(2), 16)); } catch (Exception e) { /* Ignore the error */ } } else { try { return new Integer(Integer.parseInt(s, 8)); } catch (Exception e) { /* Ignore the error */ } } } try { return new Integer(s); } catch (Exception e) { try { return new Long(s); } catch (Exception f) { try { return new Double(s); } catch (Exception g) { return s; } } } } return s; } /** * Sets a flag which makes JSONObjects created by this tokener ordered.

* * @param ordered true if JSONObjects created by this should be ordered */ public void setOrdered(boolean ordered) { m_ordered = ordered; } /** * Skip characters until the next character is the requested character. * If the requested character is not found, no characters are skipped.

* * @param to a character to skip to * @return the requested character, or zero if the requested character * is not found * @throws JSONException if something goes wrong */ public char skipTo(char to) throws JSONException { char c; try { int startIndex = m_index; m_reader.mark(Integer.MAX_VALUE); do { c = next(); if (c == 0) { m_reader.reset(); m_index = startIndex; return c; } } while (c != to); } catch (IOException exc) { throw new JSONException(exc); } back(); return c; } /** * Make a JSONException to signal a syntax error.

* * @param message the error message * @return a JSONException object, suitable for throwing */ public JSONException syntaxError(String message) { return new JSONException(message + toString()); } /** * Make a printable string of this JSONTokener.

* * @return " at character [this.index]" */ @Override public String toString() { return " at character " + m_index; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy