X Tutup
package org.json; /* 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. */ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.nio.charset.Charset; /** * A Scanner takes a source stream and extracts characters and * character sequences from it. It is extended by the various tokener classes * to parse JSON source streams. * * @author JSON.org * @version 2016-06-08 */ public class Scanner { private long character; private boolean eof; private long index; private long line; private char previous; private Reader reader; private boolean usePrevious; /** * Construct a Scanner from a Reader. * * @param reader A reader. */ public Scanner(Reader reader) { this.reader = reader.markSupported() ? reader : new BufferedReader(reader); this.eof = false; this.usePrevious = false; this.previous = (char)0; this.index = 0; this.character = 1; this.line = 1; } /** * Construct a Scanner from an InputStream and supplied Charset. * * @param inputStream the input stream * @param charset the character set with which to interpret the * input stream */ public Scanner(InputStream inputStream, Charset charset) { this(new InputStreamReader(inputStream, charset)); } /** * Construct a Scanner from a string. * * @param s A source string. */ public Scanner(String s) { this(new StringReader(s)); } /** * 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. */ public void back() throws JSONException { if (this.usePrevious || (this.index <= 0)) { throw new JSONException("Stepping back two steps is not supported"); } this.index -= 1; this.character -= 1; this.usePrevious = true; } /** * 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; } /** * Determine if the scanner is at the end of the stream. * * @return {@code true} if this scanner has reached the end of the stream, * otherwise {@code false} */ public boolean end() { return (this.eof) && (!this.usePrevious); } /** * Determine if the source stream still contains characters that next() * can consume. * @return true if not yet at the end of the source. */ public boolean more() throws JSONException { this.next(); if (this.end()) { return false; } this.back(); return true; } /** * Get the next character in the source stream. * * @return The next character, or 0 if past the end of the source stream. */ public char next() throws JSONException { int c; if (this.usePrevious) { this.usePrevious = false; c = this.previous; } else { try { c = this.reader.read(); } catch (IOException exception) { throw new JSONException(exception); } if (c < 0) { // End of stream this.eof = true; c = 0; } } this.index += 1; if (this.previous == '\r') { this.line += 1; this.character = c == '\n' ? 0 : 1; } else if (c == '\n') { this.line += 1; this.character = 0; } else { this.character += 1; } this.previous = (char) c; return this.previous; } /** * 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 = this.next(); if (n != c) { throw this.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 stream. */ public String next(int n) throws JSONException { if (n == 0) { return ""; } char[] chars = new char[n]; int pos = 0; while (pos < n) { chars[pos] = this.next(); if (this.end()) { throw syntaxError("Substring bounds error"); } pos += 1; } return String.valueOf(chars); } /** * 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. */ public char skipTo(char to) throws JSONException { char c; try { long startIndex = this.index; long startCharacter = this.character; long startLine = this.line; this.reader.mark(1000000); do { c = this.next(); if (c == 0) { this.reader.reset(); this.index = startIndex; this.character = startCharacter; this.line = startLine; return c; } } while (c != to); } catch (IOException exc) { throw new JSONException(exc); } this.back(); return c; } /** * Get the text up but not including the specified character or the * end of line, whichever comes first. * @param delimiter A delimiter character. * @return A string. */ public String nextTo(char delimiter) throws JSONException { StringBuilder sb = new StringBuilder(); for (;;) { char c = this.next(); if (c == delimiter || c == 0 || c == '\n' || c == '\r') { if (c != 0) { this.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. */ public String nextTo(String delimiters) throws JSONException { char c; StringBuilder sb = new StringBuilder(); for (;;) { c = this.next(); if (delimiters.indexOf(c) >= 0 || c == 0 || c == '\n' || c == '\r') { if (c != 0) { this.back(); } return sb.toString().trim(); } sb.append(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 JSONParseException(message, parsePosition()); } /** * Make a JSONException to signal a syntax error. * * @param cause The underlying cause. * @return A JSONException object, suitable for throwing */ public JSONException syntaxError(Throwable cause) { return new JSONParseException(cause, parsePosition()); } /** * Make a JSONException to signal a syntax error. * * @param message The error message. * @param cause The underlying cause. * @return A JSONException object, suitable for throwing */ public JSONException syntaxError(String message, Throwable cause) { return new JSONParseException(message, cause, parsePosition()); } /** * Get an object representing the current parse position. The object * represents a point-in-time during the parse. * * @return a {@code ParsePosition} representing the current location of * the scanner */ public ParsePosition parsePosition() { return new ParsePosition(index, character, line, previous); } /** * Make a printable string of this Scanner. * * @return " at {index} [character {character} line {line}]" */ public String toString() { return " at " + this.index + " [character " + this.character + " line " + this.line + "]"; } }
X Tutup