/src/main/java/com/alibaba/fastjson/parser/JSONLexerBase.java
https://github.com/alibaba/fastjson · Java · 1655 lines · 1500 code · 118 blank · 37 comment · 191 complexity · 45138a622e29189f258784728b7ec1fa MD5 · raw file
- /*
- * Copyright 1999-2019 Alibaba Group.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.alibaba.fastjson.parser;
-
- import java.io.Closeable;
- import java.math.BigDecimal;
- import java.math.BigInteger;
- import java.math.MathContext;
- import java.util.*;
-
- import com.alibaba.fastjson.JSON;
- import com.alibaba.fastjson.JSONException;
- import com.alibaba.fastjson.util.IOUtils;
-
- import static com.alibaba.fastjson.parser.JSONToken.*;
- import static com.alibaba.fastjson.util.TypeUtils.fnv1a_64_magic_hashcode;
- import static com.alibaba.fastjson.util.TypeUtils.fnv1a_64_magic_prime;
-
- /**
- * @author wenshao[szujobs@hotmail.com]
- */
- public abstract class JSONLexerBase implements JSONLexer, Closeable {
-
- protected void lexError(String key, Object... args) {
- token = ERROR;
- }
-
- protected int token;
- protected int pos;
- protected int features;
-
- protected char ch;
- protected int bp;
-
- protected int eofPos;
-
- /**
- * A character buffer for literals.
- */
- protected char[] sbuf;
- protected int sp;
-
- /**
- * number start position
- */
- protected int np;
-
- protected boolean hasSpecial;
-
- protected Calendar calendar = null;
- protected TimeZone timeZone = JSON.defaultTimeZone;
- protected Locale locale = JSON.defaultLocale;
-
- public int matchStat = UNKNOWN;
-
- private final static ThreadLocal<char[]> SBUF_LOCAL = new ThreadLocal<char[]>();
-
- protected String stringDefaultValue = null;
- protected int nanos = 0;
-
- public JSONLexerBase(int features){
- this.features = features;
-
- if ((features & Feature.InitStringFieldAsEmpty.mask) != 0) {
- stringDefaultValue = "";
- }
-
- sbuf = SBUF_LOCAL.get();
-
- if (sbuf == null) {
- sbuf = new char[512];
- }
- }
-
- public final int matchStat() {
- return matchStat;
- }
-
- /**
- * internal method, don't invoke
- * @param token
- */
- public void setToken(int token) {
- this.token = token;
- }
-
- public final void nextToken() {
- sp = 0;
-
- for (;;) {
- pos = bp;
-
- if (ch == '/') {
- skipComment();
- continue;
- }
-
- if (ch == '"') {
- scanString();
- return;
- }
-
- if (ch == ',') {
- next();
- token = COMMA;
- return;
- }
-
- if (ch >= '0' && ch <= '9') {
- scanNumber();
- return;
- }
-
- if (ch == '-') {
- scanNumber();
- return;
- }
-
- switch (ch) {
- case '\'':
- if (!isEnabled(Feature.AllowSingleQuotes)) {
- throw new JSONException("Feature.AllowSingleQuotes is false");
- }
- scanStringSingleQuote();
- return;
- case ' ':
- case '\t':
- case '\b':
- case '\f':
- case '\n':
- case '\r':
- next();
- break;
- case 't': // true
- scanTrue();
- return;
- case 'f': // false
- scanFalse();
- return;
- case 'n': // new,null
- scanNullOrNew();
- return;
- case 'T':
- case 'N': // NULL
- case 'S':
- case 'u': // undefined
- scanIdent();
- return;
- case '(':
- next();
- token = LPAREN;
- return;
- case ')':
- next();
- token = RPAREN;
- return;
- case '[':
- next();
- token = LBRACKET;
- return;
- case ']':
- next();
- token = RBRACKET;
- return;
- case '{':
- next();
- token = LBRACE;
- return;
- case '}':
- next();
- token = RBRACE;
- return;
- case ':':
- next();
- token = COLON;
- return;
- case ';':
- next();
- token = SEMI;
- return;
- case '.':
- next();
- token = DOT;
- return;
- case '+':
- next();
- scanNumber();
- return;
- case 'x':
- scanHex();
- return;
- default:
- if (isEOF()) { // JLS
- if (token == EOF) {
- throw new JSONException("EOF error");
- }
-
- token = EOF;
- eofPos = pos = bp;
- } else {
- if (ch <= 31 || ch == 127) {
- next();
- break;
- }
-
- lexError("illegal.char", String.valueOf((int) ch));
- next();
- }
-
- return;
- }
- }
-
- }
-
- public final void nextToken(int expect) {
- sp = 0;
-
- for (;;) {
- switch (expect) {
- case JSONToken.LBRACE:
- if (ch == '{') {
- token = JSONToken.LBRACE;
- next();
- return;
- }
- if (ch == '[') {
- token = JSONToken.LBRACKET;
- next();
- return;
- }
- break;
- case JSONToken.COMMA:
- if (ch == ',') {
- token = JSONToken.COMMA;
- next();
- return;
- }
-
- if (ch == '}') {
- token = JSONToken.RBRACE;
- next();
- return;
- }
-
- if (ch == ']') {
- token = JSONToken.RBRACKET;
- next();
- return;
- }
-
- if (ch == EOI) {
- token = JSONToken.EOF;
- return;
- }
-
- if (ch == 'n') {
- scanNullOrNew(false);
- return;
- }
- break;
- case JSONToken.LITERAL_INT:
- if (ch >= '0' && ch <= '9') {
- pos = bp;
- scanNumber();
- return;
- }
-
- if (ch == '"') {
- pos = bp;
- scanString();
- return;
- }
-
- if (ch == '[') {
- token = JSONToken.LBRACKET;
- next();
- return;
- }
-
- if (ch == '{') {
- token = JSONToken.LBRACE;
- next();
- return;
- }
-
- break;
- case JSONToken.LITERAL_STRING:
- if (ch == '"') {
- pos = bp;
- scanString();
- return;
- }
-
- if (ch >= '0' && ch <= '9') {
- pos = bp;
- scanNumber();
- return;
- }
-
- if (ch == '[') {
- token = JSONToken.LBRACKET;
- next();
- return;
- }
-
- if (ch == '{') {
- token = JSONToken.LBRACE;
- next();
- return;
- }
- break;
- case JSONToken.LBRACKET:
- if (ch == '[') {
- token = JSONToken.LBRACKET;
- next();
- return;
- }
-
- if (ch == '{') {
- token = JSONToken.LBRACE;
- next();
- return;
- }
- break;
- case JSONToken.RBRACKET:
- if (ch == ']') {
- token = JSONToken.RBRACKET;
- next();
- return;
- }
- case JSONToken.EOF:
- if (ch == EOI) {
- token = JSONToken.EOF;
- return;
- }
- break;
- case JSONToken.IDENTIFIER:
- nextIdent();
- return;
- default:
- break;
- }
-
- if (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f' || ch == '\b') {
- next();
- continue;
- }
-
- nextToken();
- break;
- }
- }
-
- public final void nextIdent() {
- while (isWhitespace(ch)) {
- next();
- }
- if (ch == '_' || ch == '$' || Character.isLetter(ch)) {
- scanIdent();
- } else {
- nextToken();
- }
- }
-
- public final void nextTokenWithColon() {
- nextTokenWithChar(':');
- }
-
- public final void nextTokenWithChar(char expect) {
- sp = 0;
-
- for (;;) {
- if (ch == expect) {
- next();
- nextToken();
- return;
- }
-
- if (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f' || ch == '\b') {
- next();
- continue;
- }
-
- throw new JSONException("not match " + expect + " - " + ch + ", info : " + this.info());
- }
- }
-
- public final int token() {
- return token;
- }
-
- public final String tokenName() {
- return JSONToken.name(token);
- }
-
- public final int pos() {
- return pos;
- }
-
- public final String stringDefaultValue() {
- return stringDefaultValue;
- }
-
- public final Number integerValue() throws NumberFormatException {
- long result = 0;
- boolean negative = false;
- if (np == -1) {
- np = 0;
- }
- int i = np, max = np + sp;
- long limit;
- long multmin;
- int digit;
-
- char type = ' ';
-
- switch (charAt(max - 1)) {
- case 'L':
- max--;
- type = 'L';
- break;
- case 'S':
- max--;
- type = 'S';
- break;
- case 'B':
- max--;
- type = 'B';
- break;
- default:
- break;
- }
-
- if (charAt(np) == '-') {
- negative = true;
- limit = Long.MIN_VALUE;
- i++;
- } else {
- limit = -Long.MAX_VALUE;
- }
- multmin = MULTMIN_RADIX_TEN;
- if (i < max) {
- digit = charAt(i++) - '0';
- result = -digit;
- }
- while (i < max) {
- // Accumulating negatively avoids surprises near MAX_VALUE
- digit = charAt(i++) - '0';
- if (result < multmin) {
- return new BigInteger(numberString(), 10);
- }
- result *= 10;
- if (result < limit + digit) {
- return new BigInteger(numberString(), 10);
- }
- result -= digit;
- }
-
- if (negative) {
- if (i > np + 1) {
- if (result >= Integer.MIN_VALUE && type != 'L') {
- if (type == 'S') {
- return (short) result;
- }
-
- if (type == 'B') {
- return (byte) result;
- }
-
- return (int) result;
- }
- return result;
- } else { /* Only got "-" */
- throw new JSONException("illegal number format : " + numberString());
- }
- } else {
- result = -result;
- if (result <= Integer.MAX_VALUE && type != 'L') {
- if (type == 'S') {
- return (short) result;
- }
-
- if (type == 'B') {
- return (byte) result;
- }
-
- return (int) result;
- }
- return result;
- }
- }
-
- public final void nextTokenWithColon(int expect) {
- nextTokenWithChar(':');
- }
-
- public float floatValue() {
- String strVal = numberString();
- float floatValue = Float.parseFloat(strVal);
- if (floatValue == 0 || floatValue == Float.POSITIVE_INFINITY) {
- char c0 = strVal.charAt(0);
- if (c0 > '0' && c0 <= '9') {
- throw new JSONException("float overflow : " + strVal);
- }
- }
- return floatValue;
- }
-
- public double doubleValue() {
- return Double.parseDouble(numberString());
- }
-
- public void config(Feature feature, boolean state) {
- features = Feature.config(features, feature, state);
-
- if ((features & Feature.InitStringFieldAsEmpty.mask) != 0) {
- stringDefaultValue = "";
- }
- }
-
- public final boolean isEnabled(Feature feature) {
- return isEnabled(feature.mask);
- }
-
- public final boolean isEnabled(int feature) {
- return (this.features & feature) != 0;
- }
-
- public final boolean isEnabled(int features, int feature) {
- return (this.features & feature) != 0 || (features & feature) != 0;
- }
-
- public abstract String numberString();
-
- public abstract boolean isEOF();
-
- public final char getCurrent() {
- return ch;
- }
-
- public abstract char charAt(int index);
-
- // public final char next() {
- // ch = doNext();
- //// if (ch == '/' && (this.features & Feature.AllowComment.mask) != 0) {
- //// skipComment();
- //// }
- // return ch;
- // }
-
- public abstract char next();
-
- protected void skipComment() {
- next();
- if (ch == '/') {
- for (;;) {
- next();
- if (ch == '\n') {
- next();
- return;
- } else if (ch == EOI) {
- return;
- }
- }
- } else if (ch == '*') {
- next();
-
- for (; ch != EOI;) {
- if (ch == '*') {
- next();
- if (ch == '/') {
- next();
- return;
- } else {
- continue;
- }
- }
- next();
- }
- } else {
- throw new JSONException("invalid comment");
- }
- }
-
- public final String scanSymbol(final SymbolTable symbolTable) {
- skipWhitespace();
-
- if (ch == '"') {
- return scanSymbol(symbolTable, '"');
- }
-
- if (ch == '\'') {
- if (!isEnabled(Feature.AllowSingleQuotes)) {
- throw new JSONException("syntax error");
- }
-
- return scanSymbol(symbolTable, '\'');
- }
-
- if (ch == '}') {
- next();
- token = JSONToken.RBRACE;
- return null;
- }
-
- if (ch == ',') {
- next();
- token = JSONToken.COMMA;
- return null;
- }
-
- if (ch == EOI) {
- token = JSONToken.EOF;
- return null;
- }
-
- if (!isEnabled(Feature.AllowUnQuotedFieldNames)) {
- throw new JSONException("syntax error");
- }
-
- return scanSymbolUnQuoted(symbolTable);
- }
-
- // public abstract String scanSymbol(final SymbolTable symbolTable, final char quote);
-
- protected abstract void arrayCopy(int srcPos, char[] dest, int destPos, int length);
-
- public final String scanSymbol(final SymbolTable symbolTable, final char quote) {
- int hash = 0;
-
- np = bp;
- sp = 0;
- boolean hasSpecial = false;
- char chLocal;
- for (;;) {
- chLocal = next();
-
- if (chLocal == quote) {
- break;
- }
-
- if (chLocal == EOI) {
- throw new JSONException("unclosed.str");
- }
-
- if (chLocal == '\\') {
- if (!hasSpecial) {
- hasSpecial = true;
-
- if (sp >= sbuf.length) {
- int newCapcity = sbuf.length * 2;
- if (sp > newCapcity) {
- newCapcity = sp;
- }
- char[] newsbuf = new char[newCapcity];
- System.arraycopy(sbuf, 0, newsbuf, 0, sbuf.length);
- sbuf = newsbuf;
- }
-
- // text.getChars(np + 1, np + 1 + sp, sbuf, 0);
- // System.arraycopy(this.buf, np + 1, sbuf, 0, sp);
- arrayCopy(np + 1, sbuf, 0, sp);
- }
-
- chLocal = next();
-
- switch (chLocal) {
- case '0':
- hash = 31 * hash + (int) chLocal;
- putChar('\0');
- break;
- case '1':
- hash = 31 * hash + (int) chLocal;
- putChar('\1');
- break;
- case '2':
- hash = 31 * hash + (int) chLocal;
- putChar('\2');
- break;
- case '3':
- hash = 31 * hash + (int) chLocal;
- putChar('\3');
- break;
- case '4':
- hash = 31 * hash + (int) chLocal;
- putChar('\4');
- break;
- case '5':
- hash = 31 * hash + (int) chLocal;
- putChar('\5');
- break;
- case '6':
- hash = 31 * hash + (int) chLocal;
- putChar('\6');
- break;
- case '7':
- hash = 31 * hash + (int) chLocal;
- putChar('\7');
- break;
- case 'b': // 8
- hash = 31 * hash + (int) '\b';
- putChar('\b');
- break;
- case 't': // 9
- hash = 31 * hash + (int) '\t';
- putChar('\t');
- break;
- case 'n': // 10
- hash = 31 * hash + (int) '\n';
- putChar('\n');
- break;
- case 'v': // 11
- hash = 31 * hash + (int) '\u000B';
- putChar('\u000B');
- break;
- case 'f': // 12
- case 'F':
- hash = 31 * hash + (int) '\f';
- putChar('\f');
- break;
- case 'r': // 13
- hash = 31 * hash + (int) '\r';
- putChar('\r');
- break;
- case '"': // 34
- hash = 31 * hash + (int) '"';
- putChar('"');
- break;
- case '\'': // 39
- hash = 31 * hash + (int) '\'';
- putChar('\'');
- break;
- case '/': // 47
- hash = 31 * hash + (int) '/';
- putChar('/');
- break;
- case '\\': // 92
- hash = 31 * hash + (int) '\\';
- putChar('\\');
- break;
- case 'x':
- char x1 = ch = next();
- char x2 = ch = next();
-
- int x_val = digits[x1] * 16 + digits[x2];
- char x_char = (char) x_val;
- hash = 31 * hash + (int) x_char;
- putChar(x_char);
- break;
- case 'u':
- char c1 = chLocal = next();
- char c2 = chLocal = next();
- char c3 = chLocal = next();
- char c4 = chLocal = next();
- int val = Integer.parseInt(new String(new char[] { c1, c2, c3, c4 }), 16);
- hash = 31 * hash + val;
- putChar((char) val);
- break;
- default:
- this.ch = chLocal;
- throw new JSONException("unclosed.str.lit");
- }
- continue;
- }
-
- hash = 31 * hash + chLocal;
-
- if (!hasSpecial) {
- sp++;
- continue;
- }
-
- if (sp == sbuf.length) {
- putChar(chLocal);
- } else {
- sbuf[sp++] = chLocal;
- }
- }
-
- token = LITERAL_STRING;
-
- String value;
- if (!hasSpecial) {
- // return this.text.substring(np + 1, np + 1 + sp).intern();
- int offset;
- if (np == -1) {
- offset = 0;
- } else {
- offset = np + 1;
- }
- value = addSymbol(offset, sp, hash, symbolTable);
- } else {
- value = symbolTable.addSymbol(sbuf, 0, sp, hash);
- }
-
- sp = 0;
- this.next();
-
- return value;
- }
-
- public final void resetStringPosition() {
- this.sp = 0;
- }
-
- public String info() {
- return "";
- }
-
- public final String scanSymbolUnQuoted(final SymbolTable symbolTable) {
- if (token == JSONToken.ERROR && pos == 0 && bp == 1) {
- bp = 0; // adjust
- }
- final boolean[] firstIdentifierFlags = IOUtils.firstIdentifierFlags;
- final char first = ch;
-
- final boolean firstFlag = ch >= firstIdentifierFlags.length || firstIdentifierFlags[first];
- if (!firstFlag) {
- throw new JSONException("illegal identifier : " + ch //
- + info());
- }
-
- final boolean[] identifierFlags = IOUtils.identifierFlags;
-
- int hash = first;
-
- np = bp;
- sp = 1;
- char chLocal;
- for (;;) {
- chLocal = next();
-
- if (chLocal < identifierFlags.length) {
- if (!identifierFlags[chLocal]) {
- break;
- }
- }
-
- hash = 31 * hash + chLocal;
-
- sp++;
- continue;
- }
-
- this.ch = charAt(bp);
- token = JSONToken.IDENTIFIER;
-
- final int NULL_HASH = 3392903;
- if (sp == 4 && hash == NULL_HASH && charAt(np) == 'n' && charAt(np + 1) == 'u' && charAt(np + 2) == 'l'
- && charAt(np + 3) == 'l') {
- return null;
- }
-
- // return text.substring(np, np + sp).intern();
-
- if (symbolTable == null) {
- return subString(np, sp);
- }
-
- return this.addSymbol(np, sp, hash, symbolTable);
- // return symbolTable.addSymbol(buf, np, sp, hash);
- }
-
- protected abstract void copyTo(int offset, int count, char[] dest);
-
- public final void scanString() {
- np = bp;
- hasSpecial = false;
- char ch;
- for (;;) {
- ch = next();
-
- if (ch == '\"') {
- break;
- }
-
- if (ch == EOI) {
- if (!isEOF()) {
- putChar((char) EOI);
- continue;
- }
- throw new JSONException("unclosed string : " + ch);
- }
-
- if (ch == '\\') {
- if (!hasSpecial) {
- hasSpecial = true;
-
- if (sp >= sbuf.length) {
- int newCapcity = sbuf.length * 2;
- if (sp > newCapcity) {
- newCapcity = sp;
- }
- char[] newsbuf = new char[newCapcity];
- System.arraycopy(sbuf, 0, newsbuf, 0, sbuf.length);
- sbuf = newsbuf;
- }
-
- copyTo(np + 1, sp, sbuf);
- // text.getChars(np + 1, np + 1 + sp, sbuf, 0);
- // System.arraycopy(buf, np + 1, sbuf, 0, sp);
- }
-
- ch = next();
-
- switch (ch) {
- case '0':
- putChar('\0');
- break;
- case '1':
- putChar('\1');
- break;
- case '2':
- putChar('\2');
- break;
- case '3':
- putChar('\3');
- break;
- case '4':
- putChar('\4');
- break;
- case '5':
- putChar('\5');
- break;
- case '6':
- putChar('\6');
- break;
- case '7':
- putChar('\7');
- break;
- case 'b': // 8
- putChar('\b');
- break;
- case 't': // 9
- putChar('\t');
- break;
- case 'n': // 10
- putChar('\n');
- break;
- case 'v': // 11
- putChar('\u000B');
- break;
- case 'f': // 12
- case 'F':
- putChar('\f');
- break;
- case 'r': // 13
- putChar('\r');
- break;
- case '"': // 34
- putChar('"');
- break;
- case '\'': // 39
- putChar('\'');
- break;
- case '/': // 47
- putChar('/');
- break;
- case '\\': // 92
- putChar('\\');
- break;
- case 'x':
- char x1 = next();
- char x2 = next();
-
- boolean hex1 = (x1 >= '0' && x1 <= '9')
- || (x1 >= 'a' && x1 <= 'f')
- || (x1 >= 'A' && x1 <= 'F');
- boolean hex2 = (x2 >= '0' && x2 <= '9')
- || (x2 >= 'a' && x2 <= 'f')
- || (x2 >= 'A' && x2 <= 'F');
- if (!hex1 || !hex2) {
- throw new JSONException("invalid escape character \\x" + x1 + x2);
- }
-
- char x_char = (char) (digits[x1] * 16 + digits[x2]);
- putChar(x_char);
- break;
- case 'u':
- char u1 = next();
- char u2 = next();
- char u3 = next();
- char u4 = next();
- int val = Integer.parseInt(new String(new char[] { u1, u2, u3, u4 }), 16);
- putChar((char) val);
- break;
- default:
- this.ch = ch;
- throw new JSONException("unclosed string : " + ch);
- }
- continue;
- }
-
- if (!hasSpecial) {
- sp++;
- continue;
- }
-
- if (sp == sbuf.length) {
- putChar(ch);
- } else {
- sbuf[sp++] = ch;
- }
- }
-
- token = JSONToken.LITERAL_STRING;
- this.ch = next();
- }
-
- public Calendar getCalendar() {
- return this.calendar;
- }
-
- public TimeZone getTimeZone() {
- return timeZone;
- }
-
- public void setTimeZone(TimeZone timeZone) {
- this.timeZone = timeZone;
- }
-
- public Locale getLocale() {
- return locale;
- }
-
- public void setLocale(Locale locale) {
- this.locale = locale;
- }
-
- public final int intValue() {
- if (np == -1) {
- np = 0;
- }
-
- int result = 0;
- boolean negative = false;
- int i = np, max = np + sp;
- int limit;
- int digit;
-
- if (charAt(np) == '-') {
- negative = true;
- limit = Integer.MIN_VALUE;
- i++;
- } else {
- limit = -Integer.MAX_VALUE;
- }
- long multmin = INT_MULTMIN_RADIX_TEN;
- if (i < max) {
- digit = charAt(i++) - '0';
- result = -digit;
- }
- while (i < max) {
- // Accumulating negatively avoids surprises near MAX_VALUE
- char chLocal = charAt(i++);
-
- if (chLocal == 'L' || chLocal == 'S' || chLocal == 'B') {
- break;
- }
-
- digit = chLocal - '0';
-
- if (result < multmin) {
- throw new NumberFormatException(numberString());
- }
- result *= 10;
- if (result < limit + digit) {
- throw new NumberFormatException(numberString());
- }
- result -= digit;
- }
-
- if (negative) {
- if (i > np + 1) {
- return result;
- } else { /* Only got "-" */
- throw new NumberFormatException(numberString());
- }
- } else {
- return -result;
- }
- }
-
- public abstract byte[] bytesValue();
-
- public void close() {
- if (sbuf.length <= 1024 * 8) {
- SBUF_LOCAL.set(sbuf);
- }
- this.sbuf = null;
- }
-
- public final boolean isRef() {
- if (sp != 4) {
- return false;
- }
-
- return charAt(np + 1) == '$' //
- && charAt(np + 2) == 'r' //
- && charAt(np + 3) == 'e' //
- && charAt(np + 4) == 'f';
- }
-
- public String scanTypeName(SymbolTable symbolTable) {
- return null;
- }
-
- protected final static char[] typeFieldName = ("\"" + JSON.DEFAULT_TYPE_KEY + "\":\"").toCharArray();
-
- public final int scanType(String type) {
- matchStat = UNKNOWN;
-
- if (!charArrayCompare(typeFieldName)) {
- return NOT_MATCH_NAME;
- }
-
- int bpLocal = this.bp + typeFieldName.length;
-
- final int typeLength = type.length();
- for (int i = 0; i < typeLength; ++i) {
- if (type.charAt(i) != charAt(bpLocal + i)) {
- return NOT_MATCH;
- }
- }
- bpLocal += typeLength;
- if (charAt(bpLocal) != '"') {
- return NOT_MATCH;
- }
-
- this.ch = charAt(++bpLocal);
-
- if (ch == ',') {
- this.ch = charAt(++bpLocal);
- this.bp = bpLocal;
- token = JSONToken.COMMA;
- return VALUE;
- } else if (ch == '}') {
- ch = charAt(++bpLocal);
- if (ch == ',') {
- token = JSONToken.COMMA;
- this.ch = charAt(++bpLocal);
- } else if (ch == ']') {
- token = JSONToken.RBRACKET;
- this.ch = charAt(++bpLocal);
- } else if (ch == '}') {
- token = JSONToken.RBRACE;
- this.ch = charAt(++bpLocal);
- } else if (ch == EOI) {
- token = JSONToken.EOF;
- } else {
- return NOT_MATCH;
- }
- matchStat = END;
- }
-
- this.bp = bpLocal;
- return matchStat;
- }
-
- public final boolean matchField(char[] fieldName) {
- for (;;) {
- if (!charArrayCompare(fieldName)) {
- if (isWhitespace(ch)) {
- next();
- continue;
- }
- return false;
- } else {
- break;
- }
- }
-
- bp = bp + fieldName.length;
- ch = charAt(bp);
-
- if (ch == '{') {
- next();
- token = JSONToken.LBRACE;
- } else if (ch == '[') {
- next();
- token = JSONToken.LBRACKET;
- } else if (ch == 'S' && charAt(bp + 1) == 'e' && charAt(bp + 2) == 't' && charAt(bp + 3) == '[') {
- bp += 3;
- ch = charAt(bp);
- token = JSONToken.SET;
- } else {
- nextToken();
- }
-
- return true;
- }
-
- public int matchField(long fieldNameHash) {
- throw new UnsupportedOperationException();
- }
-
- public boolean seekArrayToItem(int index) {
- throw new UnsupportedOperationException();
- }
-
- public int seekObjectToField(long fieldNameHash, boolean deepScan) {
- throw new UnsupportedOperationException();
- }
-
- public int seekObjectToField(long[] fieldNameHash) {
- throw new UnsupportedOperationException();
- }
-
- public int seekObjectToFieldDeepScan(long fieldNameHash) {
- throw new UnsupportedOperationException();
- }
-
- public void skipObject() {
- throw new UnsupportedOperationException();
- }
-
- public void skipObject(boolean valid) {
- throw new UnsupportedOperationException();
- }
-
- public void skipArray() {
- throw new UnsupportedOperationException();
- }
-
- public abstract int indexOf(char ch, int startIndex);
-
- public abstract String addSymbol(int offset, int len, int hash, final SymbolTable symbolTable);
-
- public String scanFieldString(char[] fieldName) {
- matchStat = UNKNOWN;
-
- if (!charArrayCompare(fieldName)) {
- matchStat = NOT_MATCH_NAME;
- return stringDefaultValue();
- }
-
- // int index = bp + fieldName.length;
-
- int offset = fieldName.length;
- char chLocal = charAt(bp + (offset++));
-
- if (chLocal != '"') {
- matchStat = NOT_MATCH;
-
- return stringDefaultValue();
- }
-
- final String strVal;
- {
- int startIndex = bp + fieldName.length + 1;
- int endIndex = indexOf('"', startIndex);
- if (endIndex == -1) {
- throw new JSONException("unclosed str");
- }
-
- int startIndex2 = bp + fieldName.length + 1; // must re compute
- String stringVal = subString(startIndex2, endIndex - startIndex2);
- if (stringVal.indexOf('\\') != -1) {
- for (;;) {
- int slashCount = 0;
- for (int i = endIndex - 1; i >= 0; --i) {
- if (charAt(i) == '\\') {
- slashCount++;
- } else {
- break;
- }
- }
- if (slashCount % 2 == 0) {
- break;
- }
- endIndex = indexOf('"', endIndex + 1);
- }
-
- int chars_len = endIndex - (bp + fieldName.length + 1);
- char[] chars = sub_chars( bp + fieldName.length + 1, chars_len);
-
- stringVal = readString(chars, chars_len);
- }
-
- offset += (endIndex - (bp + fieldName.length + 1) + 1);
- chLocal = charAt(bp + (offset++));
- strVal = stringVal;
- }
-
- if (chLocal == ',') {
- bp += offset;
- this.ch = this.charAt(bp);
- matchStat = VALUE;
- return strVal;
- }
-
- if (chLocal == '}') {
- chLocal = charAt(bp + (offset++));
- if (chLocal == ',') {
- token = JSONToken.COMMA;
- bp += offset;
- this.ch = this.charAt(bp);
- } else if (chLocal == ']') {
- token = JSONToken.RBRACKET;
- bp += offset;
- this.ch = this.charAt(bp);
- } else if (chLocal == '}') {
- token = JSONToken.RBRACE;
- bp += offset;
- this.ch = this.charAt(bp);
- } else if (chLocal == EOI) {
- token = JSONToken.EOF;
- bp += (offset - 1);
- ch = EOI;
- } else {
- matchStat = NOT_MATCH;
- return stringDefaultValue();
- }
- matchStat = END;
- } else {
- matchStat = NOT_MATCH;
- return stringDefaultValue();
- }
-
- return strVal;
- }
-
- public String scanString(char expectNextChar) {
- matchStat = UNKNOWN;
-
- int offset = 0;
- char chLocal = charAt(bp + (offset++));
-
- if (chLocal == 'n') {
- if (charAt(bp + offset) == 'u' && charAt(bp + offset + 1) == 'l' && charAt(bp + offset + 2) == 'l') {
- offset += 3;
- chLocal = charAt(bp + (offset++));
- } else {
- matchStat = NOT_MATCH;
- return null;
- }
-
- if (chLocal == expectNextChar) {
- bp += offset;
- this.ch = this.charAt(bp);
- matchStat = VALUE;
- return null;
- } else {
- matchStat = NOT_MATCH;
- return null;
- }
- }
-
- final String strVal;
- for (;;) {
- if (chLocal == '"') {
- int startIndex = bp + offset;
- int endIndex = indexOf('"', startIndex);
- if (endIndex == -1) {
- throw new JSONException("unclosed str");
- }
-
- String stringVal = subString(bp + offset, endIndex - startIndex);
- if (stringVal.indexOf('\\') != -1) {
- for (; ; ) {
- int slashCount = 0;
- for (int i = endIndex - 1; i >= 0; --i) {
- if (charAt(i) == '\\') {
- slashCount++;
- } else {
- break;
- }
- }
- if (slashCount % 2 == 0) {
- break;
- }
- endIndex = indexOf('"', endIndex + 1);
- }
-
- int chars_len = endIndex - startIndex;
- char[] chars = sub_chars(bp + 1, chars_len);
-
- stringVal = readString(chars, chars_len);
- }
-
- offset += (endIndex - startIndex + 1);
- chLocal = charAt(bp + (offset++));
- strVal = stringVal;
- break;
- } else if (isWhitespace(chLocal)) {
- chLocal = charAt(bp + (offset++));
- continue;
- } else {
- matchStat = NOT_MATCH;
-
- return stringDefaultValue();
- }
- }
-
- for (;;) {
- if (chLocal == expectNextChar) {
- bp += offset;
- this.ch = charAt(bp);
- matchStat = VALUE;
- token = JSONToken.COMMA;
- return strVal;
- } else if (isWhitespace(chLocal)) {
- chLocal = charAt(bp + (offset++));
- continue;
- } else {
- if (chLocal == ']') {
- bp += offset;
- this.ch = charAt(bp);
- matchStat = NOT_MATCH;
- }
- return strVal;
- }
- }
- }
-
- public long scanFieldSymbol(char[] fieldName) {
- matchStat = UNKNOWN;
-
- if (!charArrayCompare(fieldName)) {
- matchStat = NOT_MATCH_NAME;
- return 0;
- }
-
- int offset = fieldName.length;
- char chLocal = charAt(bp + (offset++));
-
- if (chLocal != '"') {
- matchStat = NOT_MATCH;
- return 0;
- }
-
- long hash = fnv1a_64_magic_hashcode;
- for (;;) {
- chLocal = charAt(bp + (offset++));
- if (chLocal == '\"') {
- chLocal = charAt(bp + (offset++));
- break;
- }
-
- hash ^= chLocal;
- hash *= fnv1a_64_magic_prime;
-
- if (chLocal == '\\') {
- matchStat = NOT_MATCH;
- return 0;
- }
- }
-
- if (chLocal == ',') {
- bp += offset;
- this.ch = this.charAt(bp);
- matchStat = VALUE;
- return hash;
- }
-
- if (chLocal == '}') {
- chLocal = charAt(bp + (offset++));
- if (chLocal == ',') {
- token = JSONToken.COMMA;
- bp += offset;
- this.ch = this.charAt(bp);
- } else if (chLocal == ']') {
- token = JSONToken.RBRACKET;
- bp += offset;
- this.ch = this.charAt(bp);
- } else if (chLocal == '}') {
- token = JSONToken.RBRACE;
- bp += offset;
- this.ch = this.charAt(bp);
- } else if (chLocal == EOI) {
- token = JSONToken.EOF;
- bp += (offset - 1);
- ch = EOI;
- } else {
- matchStat = NOT_MATCH;
- return 0;
- }
- matchStat = END;
- } else {
- matchStat = NOT_MATCH;
- return 0;
- }
-
- return hash;
- }
-
- public long scanEnumSymbol(char[] fieldName) {
- matchStat = UNKNOWN;
-
- if (!charArrayCompare(fieldName)) {
- matchStat = NOT_MATCH_NAME;
- return 0;
- }
-
- int offset = fieldName.length;
- char chLocal = charAt(bp + (offset++));
-
- if (chLocal != '"') {
- matchStat = NOT_MATCH;
- return 0;
- }
-
- long hash = fnv1a_64_magic_hashcode;
- for (;;) {
- chLocal = charAt(bp + (offset++));
- if (chLocal == '\"') {
- chLocal = charAt(bp + (offset++));
- break;
- }
-
- hash ^= ((chLocal >= 'A' && chLocal <= 'Z') ? (chLocal + 32) : chLocal);
- hash *= fnv1a_64_magic_prime;
-
- if (chLocal == '\\') {
- matchStat = NOT_MATCH;
- return 0;
- }
- }
-
- if (chLocal == ',') {
- bp += offset;
- this.ch = this.charAt(bp);
- matchStat = VALUE;
- return hash;
- }
-
- if (chLocal == '}') {
- chLocal = charAt(bp + (offset++));
- if (chLocal == ',') {
- token = JSONToken.COMMA;
- bp += offset;
- this.ch = this.charAt(bp);
- } else if (chLocal == ']') {
- token = JSONToken.RBRACKET;
- bp += offset;
- this.ch = this.charAt(bp);
- } else if (chLocal == '}') {
- token = JSONToken.RBRACE;
- bp += offset;
- this.ch = this.charAt(bp);
- } else if (chLocal == EOI) {
- token = JSONToken.EOF;
- bp += (offset - 1);
- ch = EOI;
- } else {
- matchStat = NOT_MATCH;
- return 0;
- }
- matchStat = END;
- } else {
- matchStat = NOT_MATCH;
- return 0;
- }
-
- return hash;
- }
-
- @SuppressWarnings({ "unchecked", "rawtypes" })
- public Enum<?> scanEnum(Class<?> enumClass, final SymbolTable symbolTable, char serperator) {
- String name = scanSymbolWithSeperator(symbolTable, serperator);
- if (name == null) {
- return null;
- }
- return Enum.valueOf((Class<? extends Enum>) enumClass, name);
- }
-
- public String scanSymbolWithSeperator(final SymbolTable symbolTable, char serperator) {
- matchStat = UNKNOWN;
-
- int offset = 0;
- char chLocal = charAt(bp + (offset++));
-
- if (chLocal == 'n') {
- if (charAt(bp + offset) == 'u' && charAt(bp + offset + 1) == 'l' && charAt(bp + offset + 2) == 'l') {
- offset += 3;
- chLocal = charAt(bp + (offset++));
- } else {
- matchStat = NOT_MATCH;
- return null;
- }
-
- if (chLocal == serperator) {
- bp += offset;
- this.ch = this.charAt(bp);
- matchStat = VALUE;
- return null;
- } else {
- matchStat = NOT_MATCH;
- return null;
- }
- }
-
- if (chLocal != '"') {
- matchStat = NOT_MATCH;
- return null;
- }
-
- String strVal;
- // int start = index;
- int hash = 0;
- for (;;) {
- chLocal = charAt(bp + (offset++));
- if (chLocal == '\"') {
- // bp = index;
- // this.ch = chLocal = charAt(bp);
- int start = bp + 0 + 1;
- int len = bp + offset - start - 1;
- strVal = addSymbol(start, len, hash, symbolTable);
- chLocal = charAt(bp + (offset++));
- break;
- }
-
- hash = 31 * hash + chLocal;
-
- if (chLocal == '\\') {
- matchStat = NOT_MATCH;
- return null;
- }
- }
-
- for (;;) {
- if (chLocal == serperator) {
- bp += offset;
- this.ch = this.charAt(bp);
- matchStat = VALUE;
- return strVal;
- } else {
- if (isWhitespace(chLocal)) {
- chLocal = charAt(bp + (offset++));
- continue;
- }
-
- matchStat = NOT_MATCH;
- return strVal;
- }
- }
- }
-
- public Collection<String> newCollectionByType(Class<?> type){
- if (type.isAssignableFrom(HashSet.class)) {