package com.google.gson.stream;
import com.google.gson.internal.JsonReaderInternalAccess;
import com.google.gson.internal.bind.JsonTreeReader;
import java.io.Closeable;
import java.io.EOFException;
import java.io.IOException;
import java.io.Reader;
public class JsonReader
implements Closeable
{
private static final char[] NON_EXECUTE_PREFIX = ")]}'\n".toCharArray();
private final StringPool stringPool = new StringPool();
private final Reader in;
private boolean lenient = false;
private final char[] buffer = new char[1024];
private int pos = 0;
private int limit = 0;
private int bufferStartLine = 1;
private int bufferStartColumn = 1;
private JsonScope[] stack = new JsonScope[32];
private int stackSize = 0;
private JsonToken token;
private String name;
private String value;
private int valuePos;
private int valueLength;
private boolean skipping;
public JsonReader(Reader in)
{
push(JsonScope.EMPTY_DOCUMENT);
this.skipping = false;
if (in == null) {
throw new NullPointerException("in == null");
}
this.in = in;
}
public final void setLenient(boolean lenient)
{
this.lenient = lenient;
}
public final boolean isLenient()
{
return this.lenient;
}
public void beginArray()
throws IOException
{
expect(JsonToken.BEGIN_ARRAY);
}
public void endArray()
throws IOException
{
expect(JsonToken.END_ARRAY);
}
public void beginObject()
throws IOException
{
expect(JsonToken.BEGIN_OBJECT);
}
public void endObject()
throws IOException
{
expect(JsonToken.END_OBJECT);
}
private void expect(JsonToken expected)
throws IOException
{
peek();
if (this.token != expected) {
throw new IllegalStateException("Expected " + expected + " but was " + peek() + " at line " + getLineNumber() + " column " + getColumnNumber());
}
advance();
}
public boolean hasNext()
throws IOException
{
peek();
return (this.token != JsonToken.END_OBJECT) && (this.token != JsonToken.END_ARRAY);
}
public JsonToken peek()
throws IOException
{
if (this.token != null) {
return this.token;
}
switch (2.$SwitchMap$com$google$gson$stream$JsonScope[this.stack[(this.stackSize - 1)].ordinal()]) {
case 1:
if (this.lenient) {
consumeNonExecutePrefix();
}
this.stack[(this.stackSize - 1)] = JsonScope.NONEMPTY_DOCUMENT;
JsonToken firstToken = nextValue();
if ((!this.lenient) && (this.token != JsonToken.BEGIN_ARRAY) && (this.token != JsonToken.BEGIN_OBJECT)) {
throw new IOException("Expected JSON document to start with '[' or '{' but was " + this.token + " at line " + getLineNumber() + " column " + getColumnNumber());
}
return firstToken;
case 2:
return nextInArray(true);
case 3:
return nextInArray(false);
case 4:
return nextInObject(true);
case 5:
return objectValue();
case 6:
return nextInObject(false);
case 7:
int c = nextNonWhitespace(false);
if (c == -1) {
return JsonToken.END_DOCUMENT;
}
this.pos -= 1;
if (!this.lenient) {
throw syntaxError("Expected EOF");
}
return nextValue();
case 8:
throw new IllegalStateException("JsonReader is closed");
}
throw new AssertionError();
}
private void consumeNonExecutePrefix()
throws IOException
{
nextNonWhitespace(true);
this.pos -= 1;
if ((this.pos + NON_EXECUTE_PREFIX.length > this.limit) && (!fillBuffer(NON_EXECUTE_PREFIX.length))) {
return;
}
for (int i = 0; i < NON_EXECUTE_PREFIX.length; i++) {
if (this.buffer[(this.pos + i)] != NON_EXECUTE_PREFIX[i]) {
return;
}
}
this.pos += NON_EXECUTE_PREFIX.length;
}
private JsonToken advance()
throws IOException
{
peek();
JsonToken result = this.token;
this.token = null;
this.value = null;
this.name = null;
return result;
}
public String nextName()
throws IOException
{
peek();
if (this.token != JsonToken.NAME) {
throw new IllegalStateException("Expected a name but was " + peek() + " at line " + getLineNumber() + " column " + getColumnNumber());
}
String result = this.name;
advance();
return result;
}
public String nextString()
throws IOException
{
peek();
if ((this.token != JsonToken.STRING) && (this.token != JsonToken.NUMBER)) {
throw new IllegalStateException("Expected a string but was " + peek() + " at line " + getLineNumber() + " column " + getColumnNumber());
}
String result = this.value;
advance();
return result;
}
public boolean nextBoolean()
throws IOException
{
peek();
if (this.token != JsonToken.BOOLEAN) {
throw new IllegalStateException("Expected a boolean but was " + this.token + " at line " + getLineNumber() + " column " + getColumnNumber());
}
boolean result = this.value == "true";
advance();
return result;
}
public void nextNull()
throws IOException
{
peek();
if (this.token != JsonToken.NULL) {
throw new IllegalStateException("Expected null but was " + this.token + " at line " + getLineNumber() + " column " + getColumnNumber());
}
advance();
}
public double nextDouble()
throws IOException
{
peek();
if ((this.token != JsonToken.STRING) && (this.token != JsonToken.NUMBER)) {
throw new IllegalStateException("Expected a double but was " + this.token + " at line " + getLineNumber() + " column " + getColumnNumber());
}
double result = Double.parseDouble(this.value);
if ((result >= 1.0D) && (this.value.startsWith("0"))) {
throw new MalformedJsonException("JSON forbids octal prefixes: " + this.value + " at line " + getLineNumber() + " column " + getColumnNumber());
}
if ((!this.lenient) && ((Double.isNaN(result)) || (Double.isInfinite(result)))) {
throw new MalformedJsonException("JSON forbids NaN and infinities: " + this.value + " at line " + getLineNumber() + " column " + getColumnNumber());
}
advance();
return result;
}
public long nextLong()
throws IOException
{
peek();
if ((this.token != JsonToken.STRING) && (this.token != JsonToken.NUMBER)) {
throw new IllegalStateException("Expected a long but was " + this.token + " at line " + getLineNumber() + " column " + getColumnNumber());
}
long result;
try
{
result = Long.parseLong(this.value);
} catch (NumberFormatException ignored) {
double asDouble = Double.parseDouble(this.value);
result = ()asDouble;
if (result != asDouble) {
throw new NumberFormatException("Expected a long but was " + this.value + " at line " + getLineNumber() + " column " + getColumnNumber());
}
}
if ((result >= 1L) && (this.value.startsWith("0"))) {
throw new MalformedJsonException("JSON forbids octal prefixes: " + this.value + " at line " + getLineNumber() + " column " + getColumnNumber());
}
advance();
return result;
}
public int nextInt()
throws IOException
{
peek();
if ((this.token != JsonToken.STRING) && (this.token != JsonToken.NUMBER)) {
throw new IllegalStateException("Expected an int but was " + this.token + " at line " + getLineNumber() + " column " + getColumnNumber());
}
int result;
try
{
result = Integer.parseInt(this.value);
} catch (NumberFormatException ignored) {
double asDouble = Double.parseDouble(this.value);
result = (int)asDouble;
if (result != asDouble) {
throw new NumberFormatException("Expected an int but was " + this.value + " at line " + getLineNumber() + " column " + getColumnNumber());
}
}
if ((result >= 1L) && (this.value.startsWith("0"))) {
throw new MalformedJsonException("JSON forbids octal prefixes: " + this.value + " at line " + getLineNumber() + " column " + getColumnNumber());
}
advance();
return result;
}
public void close()
throws IOException
{
this.value = null;
this.token = null;
this.stack[0] = JsonScope.CLOSED;
this.stackSize = 1;
this.in.close();
}
public void skipValue()
throws IOException
{
this.skipping = true;
try {
int count = 0;
do {
JsonToken token = advance();
if ((token == JsonToken.BEGIN_ARRAY) || (token == JsonToken.BEGIN_OBJECT))
count++;
else if ((token == JsonToken.END_ARRAY) || (token == JsonToken.END_OBJECT))
count--;
}
while (count != 0);
} finally {
this.skipping = false;
}
}
private void push(JsonScope newTop) {
if (this.stackSize == this.stack.length) {
JsonScope[] newStack = new JsonScope[this.stackSize * 2];
System.arraycopy(this.stack, 0, newStack, 0, this.stackSize);
this.stack = newStack;
}
this.stack[(this.stackSize++)] = newTop;
}
private JsonToken nextInArray(boolean firstElement) throws IOException
{
if (firstElement) {
this.stack[(this.stackSize - 1)] = JsonScope.NONEMPTY_ARRAY;
}
else {
switch (nextNonWhitespace(true)) {
case 93:
this.stackSize -= 1;
return this.token = JsonToken.END_ARRAY;
case 59:
checkLenient();
case 44:
break;
default:
throw syntaxError("Unterminated array");
}
}
switch (nextNonWhitespace(true)) {
case 93:
if (firstElement) {
this.stackSize -= 1;
return this.token = JsonToken.END_ARRAY;
}
case 44:
case 59:
checkLenient();
this.pos -= 1;
this.value = "null";
return this.token = JsonToken.NULL;
}
this.pos -= 1;
return nextValue();
}
private JsonToken nextInObject(boolean firstElement)
throws IOException
{
if (firstElement)
{
switch (nextNonWhitespace(true)) {
case 125:
this.stackSize -= 1;
return this.token = JsonToken.END_OBJECT;
}
this.pos -= 1;
}
else {
switch (nextNonWhitespace(true)) {
case 125:
this.stackSize -= 1;
return this.token = JsonToken.END_OBJECT;
case 44:
case 59:
break;
default:
throw syntaxError("Unterminated object");
}
}
int quote = nextNonWhitespace(true);
switch (quote) {
case 39:
checkLenient();
case 34:
this.name = nextString((char)quote);
break;
default:
checkLenient();
this.pos -= 1;
this.name = nextLiteral(false);
if (this.name.length() == 0) {
throw syntaxError("Expected name");
}
break;
}
this.stack[(this.stackSize - 1)] = JsonScope.DANGLING_NAME;
return this.token = JsonToken.NAME;
}
private JsonToken objectValue()
throws IOException
{
switch (nextNonWhitespace(true)) {
case 58:
break;
case 61:
checkLenient();
if (((this.pos < this.limit) || (fillBuffer(1))) && (this.buffer[this.pos] == '>'))
this.pos += 1; break;
default:
throw syntaxError("Expected ':'");
}
this.stack[(this.stackSize - 1)] = JsonScope.NONEMPTY_OBJECT;
return nextValue();
}
private JsonToken nextValue() throws IOException
{
int c = nextNonWhitespace(true);
switch (c) {
case 123:
push(JsonScope.EMPTY_OBJECT);
return this.token = JsonToken.BEGIN_OBJECT;
case 91:
push(JsonScope.EMPTY_ARRAY);
return this.token = JsonToken.BEGIN_ARRAY;
case 39:
checkLenient();
case 34:
this.value = nextString((char)c);
return this.token = JsonToken.STRING;
}
this.pos -= 1;
return readLiteral();
}
private boolean fillBuffer(int minimum)
throws IOException
{
char[] buffer = this.buffer;
int line = this.bufferStartLine;
int column = this.bufferStartColumn;
int i = 0; for (int p = this.pos; i < p; i++) {
if (buffer[i] == '\n') {
line++;
column = 1;
} else {
column++;
}
}
this.bufferStartLine = line;
this.bufferStartColumn = column;
if (this.limit != this.pos) {
this.limit -= this.pos;
System.arraycopy(buffer, this.pos, buffer, 0, this.limit);
} else {
this.limit = 0;
}
this.pos = 0;
int total;
while ((total = this.in.read(buffer, this.limit, buffer.length - this.limit)) != -1) {
this.limit += total;
if ((this.bufferStartLine == 1) && (this.bufferStartColumn == 1) && (this.limit > 0) && (buffer[0] == 65279)) {
this.pos += 1;
this.bufferStartColumn -= 1;
}
if (this.limit >= minimum) {
return true;
}
}
return false;
}
private int getLineNumber() {
int result = this.bufferStartLine;
for (int i = 0; i < this.pos; i++) {
if (this.buffer[i] == '\n') {
result++;
}
}
return result;
}
private int getColumnNumber() {
int result = this.bufferStartColumn;
for (int i = 0; i < this.pos; i++) {
if (this.buffer[i] == '\n')
result = 1;
else {
result++;
}
}
return result;
}
private int nextNonWhitespace(boolean throwOnEof)
throws IOException
{
char[] buffer = this.buffer;
int p = this.pos;
int l = this.limit;
int c;
while (true)
{
if (p == l) {
this.pos = p;
if (!fillBuffer(1)) {
break;
}
p = this.pos;
l = this.limit;
}
c = buffer[(p++)];
switch (c) {
case 9:
case 10:
case 13:
case 32:
break;
case 47:
this.pos = p;
if (p == l) {
this.pos -= 1;
boolean charsLoaded = fillBuffer(2);
this.pos += 1;
if (!charsLoaded) {
return c;
}
}
checkLenient();
char peek = buffer[this.pos];
switch (peek)
{
case '*':
this.pos += 1;
if (!skipTo("*/")) {
throw syntaxError("Unterminated comment");
}
p = this.pos + 2;
l = this.limit;
break;
case '/':
this.pos += 1;
skipToEndOfLine();
p = this.pos;
l = this.limit;
break;
default:
return c;
}
break;
case 35:
this.pos = p;
checkLenient();
skipToEndOfLine();
p = this.pos;
l = this.limit;
}
}
this.pos = p;
return c;
if (throwOnEof) {
throw new EOFException("End of input at line " + getLineNumber() + " column " + getColumnNumber());
}
return -1;
}
private void checkLenient() throws IOException
{
if (!this.lenient)
throw syntaxError("Use JsonReader.setLenient(true) to accept malformed JSON");
}
private void skipToEndOfLine()
throws IOException
{
while ((this.pos < this.limit) || (fillBuffer(1))) {
char c = this.buffer[(this.pos++)];
if ((c == '\r') || (c == '\n'))
break;
}
}
private boolean skipTo(String toFind)
throws IOException
{
label67: for (; (this.pos + toFind.length() <= this.limit) || (fillBuffer(toFind.length())); this.pos += 1) {
for (int c = 0; c < toFind.length(); c++) {
if (this.buffer[(this.pos + c)] != toFind.charAt(c)) {
break label67;
}
}
return true;
}
return false;
}
private String nextString(char quote)
throws IOException
{
char[] buffer = this.buffer;
StringBuilder builder = null;
while (true) {
int p = this.pos;
int l = this.limit;
int start = p;
while (p < l) {
int c = buffer[(p++)];
if (c == quote) {
this.pos = p;
if (this.skipping)
return "skipped!";
if (builder == null) {
return this.stringPool.get(buffer, start, p - start - 1);
}
builder.append(buffer, start, p - start - 1);
return builder.toString();
}
if (c == 92) {
this.pos = p;
if (builder == null) {
builder = new StringBuilder();
}
builder.append(buffer, start, p - start - 1);
builder.append(readEscapeCharacter());
p = this.pos;
l = this.limit;
start = p;
}
}
if (builder == null) {
builder = new StringBuilder();
}
builder.append(buffer, start, p - start);
this.pos = p;
if (!fillBuffer(1))
throw syntaxError("Unterminated string");
}
}
private String nextLiteral(boolean assignOffsetsOnly)
throws IOException
{
StringBuilder builder = null;
this.valuePos = -1;
this.valueLength = 0;
int i = 0;
while (true)
{
if (this.pos + i < this.limit) {
switch (this.buffer[(this.pos + i)]) {
case '#':
case '/':
case ';':
case '=':
case '\\':
checkLenient();
case '\t':
case '\n':
case '\f':
case '\r':
case ' ':
case ',':
case ':':
case '[':
case ']':
case '{':
case '}':
break;
default:
i++; break;
}
}
else if (i < this.buffer.length) {
if (!fillBuffer(i + 1))
{
this.buffer[this.limit] = '\000';
}
}
else
{
if (builder == null) {
builder = new StringBuilder();
}
builder.append(this.buffer, this.pos, i);
this.valueLength += i;
this.pos += i;
i = 0;
if (!fillBuffer(1))
break;
}
}
String result;
String result;
if ((assignOffsetsOnly) && (builder == null)) {
this.valuePos = this.pos;
result = null;
}
else
{
String result;
if (this.skipping) {
result = "skipped!";
}
else
{
String result;
if (builder == null) {
result = this.stringPool.get(this.buffer, this.pos, i);
} else {
builder.append(this.buffer, this.pos, i);
result = builder.toString();
}
}
}
this.valueLength += i;
this.pos += i;
return result;
}
public String toString() {
return getClass().getSimpleName() + " at line " + getLineNumber() + " column " + getColumnNumber();
}
private char readEscapeCharacter()
throws IOException
{
if ((this.pos == this.limit) && (!fillBuffer(1))) {
throw syntaxError("Unterminated escape sequence");
}
char escaped = this.buffer[(this.pos++)];
switch (escaped) {
case 'u':
if ((this.pos + 4 > this.limit) && (!fillBuffer(4))) {
throw syntaxError("Unterminated escape sequence");
}
char result = '\000';
int i = this.pos; for (int end = i + 4; i < end; i++) {
char c = this.buffer[i];
result = (char)(result << '\004');
if ((c >= '0') && (c <= '9'))
result = (char)(result + (c - '0'));
else if ((c >= 'a') && (c <= 'f'))
result = (char)(result + (c - 'a' + 10));
else if ((c >= 'A') && (c <= 'F'))
result = (char)(result + (c - 'A' + 10));
else {
throw new NumberFormatException("\\u" + this.stringPool.get(this.buffer, this.pos, 4));
}
}
this.pos += 4;
return result;
case 't':
return '\t';
case 'b':
return '\b';
case 'n':
return '\n';
case 'r':
return '\r';
case 'f':
return '\f';
case '"':
case '\'':
case '\\':
}
return escaped;
}
private JsonToken readLiteral()
throws IOException
{
this.value = nextLiteral(true);
if (this.valueLength == 0) {
throw syntaxError("Expected literal value");
}
this.token = decodeLiteral();
if (this.token == JsonToken.STRING) {
checkLenient();
}
return this.token;
}
private JsonToken decodeLiteral()
throws IOException
{
if (this.valuePos == -1)
{
return JsonToken.STRING;
}if ((this.valueLength == 4) && (('n' == this.buffer[this.valuePos]) || ('N' == this.buffer[this.valuePos])) && (('u' == this.buffer[(this.valuePos + 1)]) || ('U' == this.buffer[(this.valuePos + 1)])) && (('l' == this.buffer[(this.valuePos + 2)]) || ('L' == this.buffer[(this.valuePos + 2)])) && (('l' == this.buffer[(this.valuePos + 3)]) || ('L' == this.buffer[(this.valuePos + 3)])))
{
this.value = "null";
return JsonToken.NULL;
}if ((this.valueLength == 4) && (('t' == this.buffer[this.valuePos]) || ('T' == this.buffer[this.valuePos])) && (('r' == this.buffer[(this.valuePos + 1)]) || ('R' == this.buffer[(this.valuePos + 1)])) && (('u' == this.buffer[(this.valuePos + 2)]) || ('U' == this.buffer[(this.valuePos + 2)])) && (('e' == this.buffer[(this.valuePos + 3)]) || ('E' == this.buffer[(this.valuePos + 3)])))
{
this.value = "true";
return JsonToken.BOOLEAN;
}if ((this.valueLength == 5) && (('f' == this.buffer[this.valuePos]) || ('F' == this.buffer[this.valuePos])) && (('a' == this.buffer[(this.valuePos + 1)]) || ('A' == this.buffer[(this.valuePos + 1)])) && (('l' == this.buffer[(this.valuePos + 2)]) || ('L' == this.buffer[(this.valuePos + 2)])) && (('s' == this.buffer[(this.valuePos + 3)]) || ('S' == this.buffer[(this.valuePos + 3)])) && (('e' == this.buffer[(this.valuePos + 4)]) || ('E' == this.buffer[(this.valuePos + 4)])))
{
this.value = "false";
return JsonToken.BOOLEAN;
}
this.value = this.stringPool.get(this.buffer, this.valuePos, this.valueLength);
return decodeNumber(this.buffer, this.valuePos, this.valueLength);
}
private JsonToken decodeNumber(char[] chars, int offset, int length)
{
int i = offset;
int c = chars[i];
if (c == 45) {
c = chars[(++i)];
}
if (c == 48) {
c = chars[(++i)]; } else {
if ((c >= 49) && (c <= 57))
c = chars[(++i)];
while ((c >= 48) && (c <= 57)) {
c = chars[(++i)]; continue;
return JsonToken.STRING;
}
}
if (c == 46) {
c = chars[(++i)];
while ((c >= 48) && (c <= 57)) {
c = chars[(++i)];
}
}
if ((c == 101) || (c == 69)) {
c = chars[(++i)];
if ((c == 43) || (c == 45)) {
c = chars[(++i)];
}
if ((c >= 48) && (c <= 57))
c = chars[(++i)];
while ((c >= 48) && (c <= 57)) {
c = chars[(++i)]; continue;
return JsonToken.STRING;
}
}
if (i == offset + length) {
return JsonToken.NUMBER;
}
return JsonToken.STRING;
}
private IOException syntaxError(String message)
throws IOException
{
throw new MalformedJsonException(message + " at line " + getLineNumber() + " column " + getColumnNumber());
}
static
{
JsonReaderInternalAccess.INSTANCE = new JsonReaderInternalAccess() {
public void promoteNameToValue(JsonReader reader) throws IOException {
if ((reader instanceof JsonTreeReader)) {
((JsonTreeReader)reader).promoteNameToValue();
return;
}
reader.peek();
if (reader.token != JsonToken.NAME) {
throw new IllegalStateException("Expected a name but was " + reader.peek() + " " + " at line " + reader.getLineNumber() + " column " + reader.getColumnNumber());
}
reader.value = reader.name;
reader.name = null;
reader.token = JsonToken.STRING;
}
};
}
}