package net.minidev.json.parser;
import static net.minidev.json.parser.ParseException.ERROR_UNEXPECTED_CHAR;
import static net.minidev.json.parser.ParseException.ERROR_UNEXPECTED_EOF;
import static net.minidev.json.parser.ParseException.ERROR_UNEXPECTED_LEADING_0;
import static net.minidev.json.parser.ParseException.ERROR_UNEXPECTED_TOKEN;
import static net.minidev.json.parser.ParseException.ERROR_UNEXPECTED_UNICODE;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import net.minidev.json.writer.JsonReader;
import net.minidev.json.writer.JsonReaderI;
abstract class JSONParserBase {
protected char c;
JsonReader base;
public final static byte EOI = 0x1A;
protected static final char MAX_STOP = 126;
private String lastKey;
protected static boolean[] stopAll = new boolean[MAX_STOP];
protected static boolean[] stopArray = new boolean[MAX_STOP];
protected static boolean[] stopKey = new boolean[MAX_STOP];
protected static boolean[] stopValue = new boolean[MAX_STOP];
protected static boolean[] stopX = new boolean[MAX_STOP];
static {
stopKey[':'] = stopKey[EOI] = true;
stopValue[','] = stopValue['}'] = stopValue[EOI] = true;
stopArray[','] = stopArray[']'] = stopArray[EOI] = true;
stopX[EOI] = true;
stopAll[','] = stopAll[':'] = true;
stopAll[']'] = stopAll['}'] = stopAll[EOI] = true;
}
protected final MSB sb = new MSB(15);
protected Object xo;
protected String xs;
protected int pos;
protected final boolean acceptLeadinZero;
protected final boolean acceptNaN;
protected final boolean acceptNonQuote;
protected final boolean acceptSimpleQuote;
protected final boolean acceptUselessComma;
protected final boolean checkTaillingData;
protected final boolean checkTaillingSpace;
protected final boolean ignoreControlChar;
protected final boolean useHiPrecisionFloat;
protected final boolean useIntegerStorage;
protected final boolean reject127;
public JSONParserBase(int permissiveMode) {
this.acceptNaN = (permissiveMode & JSONParser.ACCEPT_NAN) > 0;
this.acceptNonQuote = (permissiveMode & JSONParser.ACCEPT_NON_QUOTE) > 0;
this.acceptSimpleQuote = (permissiveMode & JSONParser.ACCEPT_SIMPLE_QUOTE) > 0;
this.ignoreControlChar = (permissiveMode & JSONParser.IGNORE_CONTROL_CHAR) > 0;
this.useIntegerStorage = (permissiveMode & JSONParser.USE_INTEGER_STORAGE) > 0;
this.acceptLeadinZero = (permissiveMode & JSONParser.ACCEPT_LEADING_ZERO) > 0;
this.acceptUselessComma = (permissiveMode & JSONParser.ACCEPT_USELESS_COMMA) > 0;
this.useHiPrecisionFloat = (permissiveMode & JSONParser.USE_HI_PRECISION_FLOAT) > 0;
this.checkTaillingData = (permissiveMode & (JSONParser.ACCEPT_TAILLING_DATA | JSONParser.ACCEPT_TAILLING_SPACE)) != (JSONParser.ACCEPT_TAILLING_DATA | JSONParser.ACCEPT_TAILLING_SPACE);
this.checkTaillingSpace = (permissiveMode & JSONParser.ACCEPT_TAILLING_SPACE) == 0;
this.reject127 = (permissiveMode & JSONParser.REJECT_127_CHAR) > 0;
}
public void checkControleChar() throws ParseException {
if (ignoreControlChar)
return;
int l = xs.length();
for (int i = 0; i < l; i++) {
char c = xs.charAt(i);
if (c < 0)
continue;
if (c <= 31)
throw new ParseException(pos + i, ParseException.ERROR_UNEXPECTED_CHAR, c);
if (c == 127) {
if (reject127)
throw new ParseException(pos + i, ParseException.ERROR_UNEXPECTED_CHAR, c);
}
}
}
public void checkLeadinZero() throws ParseException {
int len = xs.length();
if (len == 1)
return;
if (len == 2) {
if (xs.equals("00"))
throw new ParseException(pos, ERROR_UNEXPECTED_LEADING_0, xs);
return;
}
char c1 = xs.charAt(0);
char c2 = xs.charAt(1);
if (c1 == '-') {
char c3 = xs.charAt(2);
if (c2 == '0' && c3 >= '0' && c3 <= '9')
throw new ParseException(pos, ERROR_UNEXPECTED_LEADING_0, xs);
return;
}
if (c1 == '0' && c2 >= '0' && c2 <= '9')
throw new ParseException(pos, ERROR_UNEXPECTED_LEADING_0, xs);
}
protected Number () throws ParseException {
if (!acceptLeadinZero)
checkLeadinZero();
if (!useHiPrecisionFloat)
return Float.parseFloat(xs);
if (xs.length() > 18)
return new BigDecimal(xs);
return Double.parseDouble(xs);
}
protected <T> T parse(JsonReaderI<T> mapper) throws ParseException {
this.pos = -1;
T result;
try {
read();
result = readFirst(mapper);
if (checkTaillingData) {
if (!checkTaillingSpace)
skipSpace();
if (c != EOI)
throw new ParseException(pos - 1, ERROR_UNEXPECTED_TOKEN, c);
}
} catch (IOException e) {
throw new ParseException(pos, e);
}
xs = null;
xo = null;
return result;
}
protected Number parseNumber(String s) throws ParseException {
int p = 0;
int l = s.length();
int max = 19;
boolean neg;
if (s.charAt(0) == '-') {
p++;
max++;
neg = true;
if (!acceptLeadinZero && l >= 3 && s.charAt(1) == '0')
throw new ParseException(pos, ERROR_UNEXPECTED_LEADING_0, s);
} else {
neg = false;
if (!acceptLeadinZero && l >= 2 && s.charAt(0) == '0')
throw new ParseException(pos, ERROR_UNEXPECTED_LEADING_0, s);
}
boolean mustCheck;
if (l < max) {
max = l;
mustCheck = false;
} else if (l > max) {
return new BigInteger(s, 10);
} else {
max = l - 1;
mustCheck = true;
}
long r = 0;
while (p < max) {
r = (r * 10L) + ('0' - s.charAt(p++));
}
if (mustCheck) {
boolean isBig;
if (r > -922337203685477580L) {
isBig = false;
} else if (r < -922337203685477580L) {
isBig = true;
} else {
if (neg)
isBig = (s.charAt(p) > '8');
else
isBig = (s.charAt(p) > '7');
}
if (isBig)
return new BigInteger(s, 10);
r = r * 10L + ('0' - s.charAt(p));
}
if (neg) {
if (this.useIntegerStorage && r >= Integer.MIN_VALUE)
return (int) r;
return r;
}
r = -r;
if (this.useIntegerStorage && r <= Integer.MAX_VALUE)
return (int) r;
return r;
}
abstract protected void read() throws IOException;
protected <T> T readArray(JsonReaderI<T> mapper) throws ParseException, IOException {
Object current = mapper.createArray();
if (c != '[')
throw new RuntimeException("Internal Error");
read();
boolean needData = false;
if (c == ',' && !acceptUselessComma)
throw new ParseException(pos, ERROR_UNEXPECTED_CHAR, (char) c);
for (;;) {
switch (c) {
case ' ':
case '\r':
case '\n':
case '\t':
read();
continue;
case ']':
if (needData && !acceptUselessComma)
throw new ParseException(pos, ERROR_UNEXPECTED_CHAR, (char) c);
read();
return mapper.convert(current);
case ':':
case '}':
throw new ParseException(pos, ERROR_UNEXPECTED_CHAR, (char) c);
case ',':
if (needData && !acceptUselessComma)
throw new ParseException(pos, ERROR_UNEXPECTED_CHAR, (char) c);
read();
needData = true;
continue;
case EOI:
throw new ParseException(pos - 1, ERROR_UNEXPECTED_EOF, "EOF");
default:
mapper.addValue(current, readMain(mapper, stopArray));
needData = false;
continue;
}
}
}
protected <T> T readFirst(JsonReaderI<T> mapper) throws ParseException, IOException {
for (;;) {
switch (c) {
case ' ':
case '\r':
case '\n':
case '\t':
read();
continue;
case ':':
case '}':
case ']':
throw new ParseException(pos, ERROR_UNEXPECTED_CHAR, c);
case '{':
return readObject(mapper);
case '[':
return readArray(mapper);
case '"':
case '\'':
readString();
return mapper.convert(xs);
case 'n':
readNQString(stopX);
if ("null".equals(xs)) {
return null;
}
if (!acceptNonQuote)
throw new ParseException(pos, ERROR_UNEXPECTED_TOKEN, xs);
return mapper.convert(xs);
case 'f':
readNQString(stopX);
if ("false".equals(xs)) {
return mapper.convert(Boolean.FALSE);
}
if (!acceptNonQuote)
throw new ParseException(pos, ERROR_UNEXPECTED_TOKEN, xs);
return mapper.convert(xs);
case 't':
readNQString(stopX);
if ("true".equals(xs)) {
return mapper.convert(Boolean.TRUE);
}
if (!acceptNonQuote)
throw new ParseException(pos, ERROR_UNEXPECTED_TOKEN, xs);
return mapper.convert(xs);
case 'N':
readNQString(stopX);
if (!acceptNaN)
throw new ParseException(pos, ERROR_UNEXPECTED_TOKEN, xs);
if ("NaN".equals(xs)) {
return mapper.convert(Float.valueOf(Float.NaN));
}
if (!acceptNonQuote)
throw new ParseException(pos, ERROR_UNEXPECTED_TOKEN, xs);
return mapper.convert(xs);
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
xo = readNumber(stopX);
return mapper.convert(xo);
default:
readNQString(stopX);
if (!acceptNonQuote)
throw new ParseException(pos, ERROR_UNEXPECTED_TOKEN, xs);
return mapper.convert(xs);
}
}
}
protected Object readMain(JsonReaderI<?> mapper, boolean stop[]) throws ParseException, IOException {
for (;;) {
switch (c) {
case ' ':
case '\r':
case '\n':
case '\t':
read();
continue;
case ':':
case '}':
case ']':
throw new ParseException(pos, ERROR_UNEXPECTED_CHAR, c);
case '{':
return readObject(mapper.startObject(lastKey));
case '[':
return readArray(mapper.startArray(lastKey));
case '"':
case '\'':
readString();
return xs;
case 'n':
readNQString(stop);
if ("null".equals(xs)) {
return null;
}
if (!acceptNonQuote)
throw new ParseException(pos, ERROR_UNEXPECTED_TOKEN, xs);
return xs;
case 'f':
readNQString(stop);
if ("false".equals(xs)) {
return Boolean.FALSE;
}
if (!acceptNonQuote)
throw new ParseException(pos, ERROR_UNEXPECTED_TOKEN, xs);
return xs;
case 't':
readNQString(stop);
if ("true".equals(xs)) {
return Boolean.TRUE;
}
if (!acceptNonQuote)
throw new ParseException(pos, ERROR_UNEXPECTED_TOKEN, xs);
return xs;
case 'N':
readNQString(stop);
if (!acceptNaN)
throw new ParseException(pos, ERROR_UNEXPECTED_TOKEN, xs);
if ("NaN".equals(xs)) {
return Float.valueOf(Float.NaN);
}
if (!acceptNonQuote)
throw new ParseException(pos, ERROR_UNEXPECTED_TOKEN, xs);
return xs;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
return readNumber(stop);
default:
readNQString(stop);
if (!acceptNonQuote)
throw new ParseException(pos, ERROR_UNEXPECTED_TOKEN, xs);
return xs;
}
}
}
abstract protected void readNoEnd() throws ParseException, IOException;
abstract protected void readNQString(boolean[] stop) throws IOException;
abstract protected Object readNumber(boolean[] stop) throws ParseException, IOException;
protected <T> T readObject(JsonReaderI<T> mapper) throws ParseException, IOException {
if (c != '{')
throw new RuntimeException("Internal Error");
Object current = mapper.createObject();
boolean needData = false;
boolean acceptData = true;
for (;;) {
read();
switch (c) {
case ' ':
case '\r':
case '\t':
case '\n':
continue;
case ':':
case ']':
case '[':
case '{':
throw new ParseException(pos, ERROR_UNEXPECTED_CHAR, c);
case '}':
if (needData && !acceptUselessComma)
throw new ParseException(pos, ERROR_UNEXPECTED_CHAR, (char) c);
read();
return mapper.convert(current);
case ',':
if (needData && !acceptUselessComma)
throw new ParseException(pos, ERROR_UNEXPECTED_CHAR, (char) c);
acceptData = needData = true;
continue;
case '"':
case '\'':
default:
if (c == '\"' || c == '\'') {
readString();
} else {
readNQString(stopKey);
if (!acceptNonQuote)
throw new ParseException(pos, ERROR_UNEXPECTED_TOKEN, xs);
}
String key = xs;
if (!acceptData)
throw new ParseException(pos, ERROR_UNEXPECTED_TOKEN, key);
skipSpace();
if (c != ':') {
if (c == EOI)
throw new ParseException(pos - 1, ERROR_UNEXPECTED_EOF, null);
throw new ParseException(pos - 1, ERROR_UNEXPECTED_CHAR, c);
}
readNoEnd();
lastKey = key;
Object value = readMain(mapper, stopValue);
mapper.setValue(current, key, value);
lastKey = null;
skipSpace();
if (c == '}') {
read();
return mapper.convert(current);
}
if (c == EOI)
throw new ParseException(pos - 1, ERROR_UNEXPECTED_EOF, null);
if (c == ',')
acceptData = needData = true;
else
throw new ParseException(pos - 1, ERROR_UNEXPECTED_TOKEN, c);
}
}
}
abstract void readS() throws IOException;
abstract protected void readString() throws ParseException, IOException;
protected void readString2() throws ParseException, IOException {
char sep = c;
for (;;) {
read();
switch (c) {
case EOI:
throw new ParseException(pos - 1, ERROR_UNEXPECTED_EOF, null);
case '"':
case '\'':
if (sep == c) {
read();
xs = sb.toString();
return;
}
sb.append(c);
break;
case '\\':
read();
switch (c) {
case 't':
sb.append('\t');
break;
case 'n':
sb.append('\n');
break;
case 'r':
sb.append('\r');
break;
case 'f':
sb.append('\f');
break;
case 'b':
sb.append('\b');
break;
case '\\':
sb.append('\\');
break;
case '/':
sb.append('/');
break;
case '\'':
sb.append('\'');
break;
case '"':
sb.append('"');
break;
case 'u':
sb.append(readUnicode(4));
break;
case 'x':
sb.append(readUnicode(2));
break;
default:
break;
}
break;
case '\0':
case (char) 1:
case (char) 2:
case (char) 3:
case (char) 4:
case (char) 5:
case (char) 6:
case (char) 7:
case '\b':
case '\t':
case '\n':
case (char) 11:
case '\f':
case '\r':
case (char) 14:
case (char) 15:
case (char) 16:
case (char) 17:
case (char) 18:
case (char) 19:
case (char) 20:
case (char) 21:
case (char) 22:
case (char) 23:
case (char) 24:
case (char) 25:
case (char) 27:
case (char) 28:
case (char) 29:
case (char) 30:
case (char) 31:
if (ignoreControlChar)
continue;
throw new ParseException(pos, ERROR_UNEXPECTED_CHAR, c);
case (char) 127:
if (ignoreControlChar)
continue;
if (reject127)
throw new ParseException(pos, ERROR_UNEXPECTED_CHAR, c);
default:
sb.append(c);
}
}
}
protected char readUnicode(int totalChars) throws ParseException, IOException {
int value = 0;
for (int i = 0; i < totalChars; i++) {
value = value * 16;
read();
if (c <= '9' && c >= '0')
value += c - '0';
else if (c <= 'F' && c >= 'A')
value += (c - 'A') + 10;
else if (c >= 'a' && c <= 'f')
value += (c - 'a') + 10;
else if (c == EOI)
throw new ParseException(pos, ERROR_UNEXPECTED_EOF, "EOF");
else
throw new ParseException(pos, ERROR_UNEXPECTED_UNICODE, c);
}
return (char) value;
}
protected void skipDigits() throws IOException {
for (;;) {
if (c < '0' || c > '9')
return;
readS();
}
}
protected void skipNQString(boolean[] stop) throws IOException {
for (;;) {
if ((c == EOI) || (c >= 0 && c < MAX_STOP && stop[c]))
return;
readS();
}
}
protected void skipSpace() throws IOException {
for (;;) {
if (c > ' ' || c == EOI)
return;
readS();
}
}
public static class MSB {
char b[];
int p;
public MSB(int size) {
b = new char[size];
p = -1;
}
public void append(char c) {
p++;
if (b.length <= p) {
char[] t = new char[b.length * 2 + 1];
System.arraycopy(b, 0, t, 0, b.length);
b = t;
}
b[p] = c;
}
public void append(int c) {
p++;
if (b.length <= p) {
char[] t = new char[b.length * 2 + 1];
System.arraycopy(b, 0, t, 0, b.length);
b = t;
}
b[p] = (char) c;
}
public String toString() {
return new String(b, 0, p + 1);
}
public void clear() {
p = -1;
}
}
}