/*
* Copyright 1999-2101 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 static com.alibaba.fastjson.parser.JSONToken.COLON;
import static com.alibaba.fastjson.parser.JSONToken.COMMA;
import static com.alibaba.fastjson.parser.JSONToken.EOF;
import static com.alibaba.fastjson.parser.JSONToken.ERROR;
import static com.alibaba.fastjson.parser.JSONToken.LBRACE;
import static com.alibaba.fastjson.parser.JSONToken.LBRACKET;
import static com.alibaba.fastjson.parser.JSONToken.LITERAL_STRING;
import static com.alibaba.fastjson.parser.JSONToken.LPAREN;
import static com.alibaba.fastjson.parser.JSONToken.RBRACE;
import static com.alibaba.fastjson.parser.JSONToken.RBRACKET;
import static com.alibaba.fastjson.parser.JSONToken.RPAREN;
import java.lang.ref.SoftReference;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashSet;
import java.util.Locale;
import java.util.TimeZone;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.util.Base64;
//这个类,为了性能优化做了很多特别处理,一切都是为了性能!!!
/**
* @author wenshao<szujobs@hotmail.com>
*/
public final class JSONScanner implements JSONLexer {
public final static byte EOI = 0x1A;
private final char[] buf;
private int bp;
private final int buflen;
private int eofPos;
/**
* The current character.
*/
private char ch;
/**
* The token's position, 0-based offset from beginning of text.
*/
private int pos;
/**
* A character buffer for literals.
*/
private char[] sbuf;
private int sp;
/**
* number start position
*/
private int np;
/**
* The token, set by nextToken().
*/
private int token;
private Keywords keywods = Keywords.DEFAULT_KEYWORDS;
private final static ThreadLocal<SoftReference<char[]>> sbufRefLocal = new ThreadLocal<SoftReference<char[]>>();
private int features = JSON.DEFAULT_PARSER_FEATURE;
private Calendar calendar = null;
private boolean resetFlag = false;
public int resetCount = 0;
public JSONScanner(String input) {
this(input, JSON.DEFAULT_PARSER_FEATURE);
}
public JSONScanner(String input, int features) {
this(input.toCharArray(), input.length(), features);
}
public JSONScanner(char[] input, int inputLength) {
this(input, inputLength, JSON.DEFAULT_PARSER_FEATURE);
}
public JSONScanner(char[] input, int inputLength, int features) {
this.features = features;
SoftReference<char[]> sbufRef = sbufRefLocal.get();
if (sbufRef != null) {
sbuf = sbufRef.get();
sbufRefLocal.set(null);
}
if (sbuf == null) {
sbuf = new char[64];
}
eofPos = inputLength;
if (inputLength == input.length) {
if (input.length > 0 && isWhitespace(input[input.length - 1])) {
inputLength--;
} else {
char[] newInput = new char[inputLength + 1];
System.arraycopy(input, 0, newInput, 0, input.length);
input = newInput;
}
}
buf = input;
buflen = inputLength;
buf[buflen] = EOI;
bp = -1;
ch = buf[++bp];
if (ch == 65279) {
ch = buf[++bp];
}
}
public boolean isResetFlag() {
return resetFlag;
}
public void setResetFlag(boolean resetFlag) {
this.resetFlag = resetFlag;
}
public final int getBufferPosition() {
return bp;
}
public void reset(int mark, char mark_ch, int token) {
this.bp = mark;
this.ch = mark_ch;
this.token = token;
resetFlag = true;
resetCount++;
}
public boolean isBlankInput() {
for (int i = 0; i < buflen; ++i) {
if (!isWhitespace(buf[i])) {
return false;
}
}
return true;
}
public static final boolean isWhitespace(char ch) {
// 专门调整了判断顺序
return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f' || ch == '\b';
}
/**
* Report an error at the current token position using the provided arguments.
*/
private void lexError(String key, Object... args) {
token = ERROR;
}
/**
* Return the current token, set by nextToken().
*/
public final int token() {
return token;
}
public final String tokenName() {
return JSONToken.name(token);
}
private static boolean[] whitespaceFlags = new boolean[256];
static {
whitespaceFlags[' '] = true;
whitespaceFlags['\n'] = true;
whitespaceFlags['\r'] = true;
whitespaceFlags['\t'] = true;
whitespaceFlags['\f'] = true;
whitespaceFlags['\b'] = true;
}
public final void skipWhitespace() {
for (;;) {
if (whitespaceFlags[ch]) {
ch = buf[++bp];
continue;
} else {
break;
}
}
}
public final char getCurrent() {
return ch;
}
public final void nextTokenWithColon() {
for (;;) {
if (ch == ':') {
ch = buf[++bp];
nextToken();
return;
}
if (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f' || ch == '\b') {
ch = buf[++bp];
continue;
}
throw new JSONException("not match ':' - " + ch);
}
}
public final void nextTokenWithColon(int expect) {
for (;;) {
if (ch == ':') {
ch = buf[++bp];
break;
}
if (isWhitespace(ch)) {
ch = buf[++bp];
continue;
}
throw new JSONException("not match ':', actual " + ch);
}
for (;;) {
if (expect == JSONToken.LITERAL_INT) {
if (ch >= '0' && ch <= '9') {
sp = 0;
pos = bp;
scanNumber();
return;
}
if (ch == '"') {
sp = 0;
pos = bp;
scanString();
return;
}
} else if (expect == JSONToken.LITERAL_STRING) {
if (ch == '"') {
sp = 0;
pos = bp;
scanString();
return;
}
if (ch >= '0' && ch <= '9') {
sp = 0;
pos = bp;
scanNumber();
return;
}
} else if (expect == JSONToken.LBRACE) {
if (ch == '{') {
token = JSONToken.LBRACE;
ch = buf[++bp];
return;
}
if (ch == '[') {
token = JSONToken.LBRACKET;
ch = buf[++bp];
return;
}
} else if (expect == JSONToken.LBRACKET) {
if (ch == '[') {
token = JSONToken.LBRACKET;
ch = buf[++bp];
return;
}
if (ch == '{') {
token = JSONToken.LBRACE;
ch = buf[++bp];
return;
}
}
if (isWhitespace(ch)) {
ch = buf[++bp];
continue;
}
nextToken();
break;
}
}
public final void incrementBufferPosition() {
ch = buf[++bp];
}
public final void resetStringPosition() {
this.sp = 0;
}
public void nextToken(int expect) {
for (;;) {
switch (expect) {
case JSONToken.LBRACE:
if (ch == '{') {
token = JSONToken.LBRACE;
ch = buf[++bp];
return;
}
if (ch == '[') {
token = JSONToken.LBRACKET;
ch = buf[++bp];
return;
}
break;
case JSONToken.COMMA:
if (ch == ',') {
token = JSONToken.COMMA;
ch = buf[++bp];
return;
}
if (ch == '}') {
token = JSONToken.RBRACE;
ch = buf[++bp];
return;
}
if (ch == ']') {
token = JSONToken.RBRACKET;
ch = buf[++bp];
return;
}
if (ch == EOI) {
token = JSONToken.EOF;
return;
}
break;
case JSONToken.LITERAL_INT:
if (ch >= '0' && ch <= '9') {
sp = 0;
pos = bp;
scanNumber();
return;
}
if (ch == '"') {
sp = 0;
pos = bp;
scanString();
return;
}
if (ch == '[') {
token = JSONToken.LBRACKET;
ch = buf[++bp];
return;
}
if (ch == '{') {
token = JSONToken.LBRACE;
ch = buf[++bp];
return;
}
break;
case JSONToken.LITERAL_STRING:
if (ch == '"') {
sp = 0;
pos = bp;
scanString();
return;
}
if (ch >= '0' && ch <= '9') {
sp = 0;
pos = bp;
scanNumber();
return;
}
if (ch == '[') {
token = JSONToken.LBRACKET;
ch = buf[++bp];
return;
}
if (ch == '{') {
token = JSONToken.LBRACE;
ch = buf[++bp];
return;
}
break;
case JSONToken.LBRACKET:
if (ch == '[') {
token = JSONToken.LBRACKET;
ch = buf[++bp];
return;
}
if (ch == '{') {
token = JSONToken.LBRACE;
ch = buf[++bp];
return;
}
break;
case JSONToken.RBRACKET:
if (ch == ']') {
token = JSONToken.RBRACKET;
ch = buf[++bp];
return;
}
case JSONToken.EOF:
if (ch == EOI) {
token = JSONToken.EOF;
return;
}
break;
default:
break;
}
if (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f' || ch == '\b') {
ch = buf[++bp];
continue;
}
nextToken();
break;
}
}
public final void nextToken() {
sp = 0;
for (;;) {
pos = bp;
if (ch == '"') {
scanString();
return;
}
if (ch == ',') {
ch = buf[++bp];
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':
ch = buf[++bp];
break;
case 't': // true
scanTrue();
return;
case 'T': // true
scanTreeSet();
return;
case 'S': // set
scanSet();
return;
case 'f': // false
scanFalse();
return;
case 'n': // new,null
scanNullOrNew();
return;
case 'D': // Date
scanIdent();
return;
case '(':
ch = buf[++bp];
token = LPAREN;
return;
case ')':
ch = buf[++bp];
token = RPAREN;
return;
case '[':
ch = buf[++bp];
token = LBRACKET;
return;
case ']':
ch = buf[++bp];
token = RBRACKET;
return;
case '{':
ch = buf[++bp];
token = LBRACE;
return;
case '}':
ch = buf[++bp];
token = RBRACE;
return;
case ':':
ch = buf[++bp];
token = COLON;
return;
default:
if (bp == buflen || ch == EOI && bp + 1 == buflen) { // JLS
if (token == EOF) {
throw new JSONException("EOF error");
}
token = EOF;
pos = bp = eofPos;
} else {
lexError("illegal.char", String.valueOf((int) ch));
ch = buf[++bp];
}
return;
}
}
}
boolean hasSpecial;
public final void scanStringSingleQuote() {
np = bp;
hasSpecial = false;
char ch;
for (;;) {
ch = buf[++bp];
if (ch == '\'') {
break;
}
if (ch == EOI) {
throw new JSONException("unclosed single-quote string");
}
if (ch == '\\') {
if (!hasSpecial) {
hasSpecial = true;
if (sp > sbuf.length) {
char[] newsbuf = new char[sp * 2];
System.arraycopy(sbuf, 0, newsbuf, 0, sbuf.length);
sbuf = newsbuf;
}
System.arraycopy(buf, np + 1, sbuf, 0, sp);
}
ch = buf[++bp];
switch (ch) {
case '"':
putChar('"');
break;
case '\\':
putChar('\\');
break;
case '/':
putChar('/');
break;
case '\'':
putChar('\'');
break;
case 'b':
putChar('\b');
break;
case 'f':
case 'F':
putChar('\f');
break;
case 'n':
putChar('\n');
break;
case 'r':
putChar('\r');
break;
case 't':
putChar('\t');
break;
case 'x':
char x1 = ch = buf[++bp];
char x2 = ch = buf[++bp];
int x_val = digits[x1] * 16 + digits[x2];
char x_char = (char) x_val;
putChar(x_char);
break;
case 'u':
char c1 = ch = buf[++bp];
char c2 = ch = buf[++bp];
char c3 = ch = buf[++bp];
char c4 = ch = buf[++bp];
int val = Integer.parseInt(new String(new char[]{c1, c2, c3, c4}), 16);
putChar((char) val);
break;
default:
this.ch = ch;
throw new JSONException("unclosed single-quote string");
}
continue;
}
if (!hasSpecial) {
sp++;
continue;
}
if (sp == sbuf.length) {
putChar(ch);
} else {
sbuf[sp++] = ch;
}
}
token = LITERAL_STRING;
this.ch = buf[++bp];
}
public final void scanString() {
np = bp;
hasSpecial = false;
char ch;
for (;;) {
ch = buf[++bp];
if (ch == '\"') {
break;
}
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;
}
System.arraycopy(buf, np + 1, sbuf, 0, sp);
}
ch = buf[++bp];
switch (ch) {
case '"':
putChar('"');
break;
case '\\':
putChar('\\');
break;
case '/':
putChar('/');
break;
case 'b':
putChar('\b');
break;
case 'f':
case 'F':
putChar('\f');
break;
case 'n':
putChar('\n');
break;
case 'r':
putChar('\r');
break;
case 't':
putChar('\t');
break;
case 'x':
char x1 = ch = buf[++bp];
char x2 = ch = buf[++bp];
int x_val = digits[x1] * 16 + digits[x2];
char x_char = (char) x_val;
putChar(x_char);
break;
case 'u':
char u1 = ch = buf[++bp];
char u2 = ch = buf[++bp];
char u3 = ch = buf[++bp];
char u4 = ch = buf[++bp];
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 = LITERAL_STRING;
this.ch = buf[++bp];
}
public final String scanSymbolUnQuoted(final SymbolTable symbolTable) {
final boolean[] firstIdentifierFlags = CharTypes.firstIdentifierFlags;
final char first = ch;
final boolean firstFlag = ch >= firstIdentifierFlags.length || firstIdentifierFlags[first];
if (!firstFlag) {
throw new JSONException("illegal identifier : " + ch);
}
final boolean[] identifierFlags = CharTypes.identifierFlags;
int hash = first;
np = bp;
sp = 1;
char ch;
for (;;) {
ch = buf[++bp];
if (ch < identifierFlags.length) {
if (!identifierFlags[ch]) {
break;
}
}
hash = 31 * hash + ch;
sp++;
continue;
}
this.ch = buf[bp];
token = JSONToken.IDENTIFIER;
final int NULL_HASH = 3392903;
if (sp == 4 && hash == NULL_HASH && buf[np] == 'n' && buf[np + 1] == 'u' && buf[np + 2] == 'l'
&& buf[np + 3] == 'l') {
return null;
}
return symbolTable.addSymbol(buf, np, sp, hash);
}
public final static int NOT_MATCH = -1;
public final static int NOT_MATCH_NAME = -2;
public final static int UNKOWN = 0;
public final static int OBJECT = 1;
public final static int ARRAY = 2;
public final static int VALUE = 3;
public final static int END = 4;
private final static char[] typeFieldName = "\"@type\":\"".toCharArray();
public int scanType(String type) {
matchStat = UNKOWN;
if (!charArrayCompare(buf, bp, typeFieldName)) {
return NOT_MATCH_NAME;
}
int bp = this.bp + typeFieldName.length;
final int typeLength = type.length();
for (int i = 0; i < typeLength; ++i) {
if (type.charAt(i) != buf[bp + i]) {
return NOT_MATCH;
}
}
bp += typeLength;
if (buf[bp] != '"') {
return NOT_MATCH;
}
this.ch = buf[++bp];
if (ch == ',') {
this.ch = buf[++bp];
this.bp = bp;
token = JSONToken.COMMA;
return VALUE;
} else if (ch == '}') {
ch = buf[++bp];
if (ch == ',') {
token = JSONToken.COMMA;
this.ch = buf[++bp];
} else if (ch == ']') {
token = JSONToken.RBRACKET;
this.ch = buf[++bp];
} else if (ch == '}') {
token = JSONToken.RBRACE;
this.ch = buf[++bp];
} else if (ch == EOI) {
token = JSONToken.EOF;
} else {
return NOT_MATCH;
}
matchStat = END;
}
this.bp = bp;
return matchStat;
}
public boolean matchField(char[] fieldName) {
if (!charArrayCompare(buf, bp, fieldName)) {
return false;
}
bp = bp + fieldName.length;
ch = buf[bp];
if (ch == '{') {
ch = buf[++bp];
token = JSONToken.LBRACE;
} else if (ch == '[') {
ch = buf[++bp];
token = JSONToken.LBRACKET;
} else {
nextToken();
}
return true;
}
public int matchStat = UNKOWN;
// sun.misc.Unsafe.byteArrayCompare(byte[], int, int, byte[], int, int)
static final boolean charArrayCompare(char[] src, int offset, char[] dest) {
final int destLen = dest.length;
// if (destLen + offset > src.length) {
// return false;
// }
for (int i = 0; i < destLen; ++i) {
if (dest[i] != src[offset + i]) {
return false;
}
}
return true;
}
public String scanFieldString(char[] fieldName) {
matchStat = UNKOWN;
// final int fieldNameLength = fieldName.length;
// for (int i = 0; i < fieldNameLength; ++i) {
// if (fieldName[i] != buf[bp + i]) {
// matchStat = NOT_MATCH_NAME;
//
// return stringDefaultValue();
// }
// }
if (!charArrayCompare(buf, bp, fieldName)) {
matchStat = NOT_MATCH_NAME;
return stringDefaultValue();
}
int index = bp + fieldName.length;
char ch = buf[index++];
if (ch != '"') {
matchStat = NOT_MATCH;
return stringDefaultValue();
}
final String strVal;
final int start = index;
for (;;) {
ch = buf[index++];
if (ch == '\"') {
bp = index;
this.ch = ch = buf[bp];
strVal = new String(buf, start, index - start - 1);
break;
}
if (ch == '\\') {
matchStat = NOT_MATCH;
return stringDefaultValue();
}
}
if (ch == ',') {
this.ch = buf[++bp];
matchStat = VALUE;
return strVal;
} else if (ch == '}') {
ch = buf[++bp];
if (ch == ',') {
token = JSONToken.COMMA;
this.ch = buf[++bp];
} else if (ch == ']') {
token = JSONToken.RBRACKET;
this.ch = buf[++bp];
} else if (ch == '}') {
token = JSONToken.RBRACE;
this.ch = buf[++bp];
} else if (ch == EOI) {
token = JSONToken.EOF;
} else {
matchStat = NOT_MATCH;
return stringDefaultValue();
}
matchStat = END;
} else {
matchStat = NOT_MATCH;
return stringDefaultValue();
}
return strVal;
}
public String stringDefaultValue() {
if (this.isEnabled(Feature.InitStringFieldAsEmpty)) {
return "";
}
return null;
}
public String scanFieldSymbol(char[] fieldName, final SymbolTable symbolTable) {
matchStat = UNKOWN;
if (!charArrayCompare(buf, bp, fieldName)) {
matchStat = NOT_MATCH_NAME;
return null;
}
int index = bp + fieldName.length;
char ch = buf[index++];
if (ch != '"') {
matchStat = NOT_MATCH;
return null;
}
String strVal;
int start = index;
int hash = 0;
for (;;) {
ch = buf[index++];
if (ch == '\"') {
bp = index;
this.ch = ch = buf[bp];
strVal = symbolTable.addSymbol(buf, start, index - start - 1, hash);
break;
}
hash = 31 * hash + ch;
if (ch == '\\') {
matchStat = NOT_MATCH;
return null;
}
}
if (ch == ',') {
this.ch = buf[++bp];
matchStat = VALUE;
return strVal;
} else if (ch == '}') {
ch = buf[++bp];
if (ch == ',') {
token = JSONToken.COMMA;
this.ch = buf[++bp];
} else if (ch == ']') {
token = JSONToken.RBRACKET;
this.ch = buf[++bp];
} else if (ch == '}') {
token = JSONToken.RBRACE;
this.ch = buf[++bp];
} else if (ch == EOI) {
token = JSONToken.EOF;
} else {
matchStat = NOT_MATCH;
return null;
}
matchStat = END;
} else {
matchStat = NOT_MATCH;
return null;
}
return strVal;
}
public ArrayList<String> scanFieldStringArray(char[] fieldName) {
return (ArrayList<String>) scanFieldStringArray(fieldName, null);
}
@SuppressWarnings("unchecked")
public Collection<String> scanFieldStringArray(char[] fieldName, Class<?> type) {
matchStat = UNKOWN;
if (!charArrayCompare(buf, bp, fieldName)) {
matchStat = NOT_MATCH_NAME;
return null;
}
Collection<String> list;
if (type.isAssignableFrom(HashSet.class)) {
list = new HashSet<String>();
} else if (type.isAssignableFrom(ArrayList.class)) {
list = new ArrayList<String>();
} else {
try {
list = (Collection<String>) type.newInstance();
} catch (Exception e) {
throw new JSONException(e.getMessage(), e);
}
}
int index = bp + fieldName.length;
char ch = buf[index++];
if (ch != '[') {
matchStat = NOT_MATCH;
return null;
}
ch = buf[index++];
for (;;) {
if (ch != '"') {
matchStat = NOT_MATCH;
return null;
}
String strVal;
int start = index;
for (;;) {
ch = buf[index++];
if (ch == '\"') {
strVal = new String(buf, start, index - start - 1);
list.add(strVal);
ch = buf[index++];
break;
}
if (ch == '\\') {
matchStat = NOT_MATCH;
return null;
}
}
if (ch == ',') {
ch = buf[index++];
continue;
}
if (ch == ']') {
ch = buf[index++];
break;
}
matchStat = NOT_MATCH;
return null;
}
bp = index;
if (ch == ',') {
this.ch = buf[bp];
matchStat = VALUE;
return list;
} else if (ch == '}') {
ch = buf[bp];
if (ch == ',') {
token = JSONToken.COMMA;
this.ch = buf[++bp];
} else if (ch == ']') {
token = JSONToken.RBRACKET;
this.ch = buf[++bp];
} else if (ch == '}') {
token = JSONToken.RBRACE;
this.ch = buf[++bp];
} else if (ch == EOI) {
token = JSONToken.EOF;
this.ch = ch;
} else {
matchStat = NOT_MATCH;
return null;
}
matchStat = END;
} else {
matchStat = NOT_MATCH;
return null;
}
return list;
}
public int scanFieldInt(char[] fieldName) {
matchStat = UNKOWN;
if (!charArrayCompare(buf, bp, fieldName)) {
matchStat = NOT_MATCH_NAME;
return 0;
}
int index = bp + fieldName.length;
char ch = buf[index++];
int value;
if (ch >= '0' && ch <= '9') {
value = digits[ch];
for (;;) {
ch = buf[index++];
if (ch >= '0' && ch <= '9') {
value = value * 10 + digits[ch];
} else if (ch == '.') {
matchStat = NOT_MATCH;
return 0;
} else {
bp = index - 1;
break;
}
}
if (value < 0) {
matchStat = NOT_MATCH;
return 0;
}
} else {
matchStat = NOT_MATCH;
return 0;
}
if (ch == ',') {
ch = buf[++bp];
matchStat = VALUE;
token = JSONToken.COMMA;
return value;
}
if (ch == '}') {
ch = buf[++bp];
if (ch == ',') {
token = JSONToken.COMMA;
this.ch = buf[++bp];
} else if (ch == ']') {
token = JSONToken.RBRACKET;
this.ch = buf[++bp];
} else if (ch == '}') {
token = JSONToken.RBRACE;
this.ch = buf[++bp];
} else if (ch == EOI) {
token = JSONToken.EOF;
} else {
matchStat = NOT_MATCH;
return 0;
}
matchStat = END;
}
return value;
}
public boolean scanFieldBoolean(char[] fieldName) {
matchStat = UNKOWN;
if (!charArrayCompare(buf, bp, fieldName)) {
matchStat = NOT_MATCH_NAME;
return false;
}
int index = bp + fieldName.length;
char ch = buf[index++];
boolean value;
if (ch == 't') {
if (buf[index++] != 'r') {
matchStat = NOT_MATCH;
return false;
}
if (buf[index++] != 'u') {
matchStat = NOT_MATCH;
return false;
}
if (buf[index++] != 'e') {
matchStat = NOT_MATCH;
return false;
}
bp = index;
ch = buf[bp];
value = true;
} else if (ch == 'f') {
if (buf[index++] != 'a') {
matchStat = NOT_MATCH;
return false;
}
if (buf[index++] != 'l') {
matchStat = NOT_MATCH;
return false;
}
if (buf[index++] != 's') {
matchStat = NOT_MATCH;
return false;
}
if (buf[index++] != 'e') {
matchStat = NOT_MATCH;
return false;
}
bp = index;
ch = buf[bp];
value = false;
} else {
matchStat = NOT_MATCH;
return false;
}
if (ch == ',') {
ch = buf[++bp];
matchStat = VALUE;
token = JSONToken.COMMA;
} else if (ch == '}') {
ch = buf[++bp];
if (ch == ',') {
token = JSONToken.COMMA;
this.ch = buf[++bp];
} else if (ch == ']') {
token = JSONToken.RBRACKET;
this.ch = buf[++bp];
} else if (ch == '}') {
token = JSONToken.RBRACE;
this.ch = buf[++bp];
} else if (ch == EOI) {
token = JSONToken.EOF;
} else {
matchStat = NOT_MATCH;
return false;
}
matchStat = END;
} else {
matchStat = NOT_MATCH;
return false;
}
return value;
}
public long scanFieldLong(char[] fieldName) {
matchStat = UNKOWN;
if (!charArrayCompare(buf, bp, fieldName)) {
matchStat = NOT_MATCH_NAME;
return 0;
}
int index = bp + fieldName.length;
char ch = buf[index++];
long value;
if (ch >= '0' && ch <= '9') {
value = digits[ch];
for (;;) {
ch = buf[index++];
if (ch >= '0' && ch <= '9') {
value = value * 10 + digits[ch];
} else if (ch == '.') {
token = NOT_MATCH;
return 0;
} else {
bp = index - 1;
break;
}
}
if (value < 0) {
matchStat = NOT_MATCH;
return 0;
}
} else {
matchStat = NOT_MATCH;
return 0;
}
if (ch == ',') {
ch = buf[++bp];
matchStat = VALUE;
token = JSONToken.COMMA;
return value;
} else if (ch == '}') {
ch = buf[++bp];
if (ch == ',') {
token = JSONToken.COMMA;
this.ch = buf[++bp];
} else if (ch == ']') {
token = JSONToken.RBRACKET;
this.ch = buf[++bp];
} else if (ch == '}') {
token = JSONToken.RBRACE;
this.ch = buf[++bp];
} else if (ch == EOI) {
token = JSONToken.EOF;
} else {
matchStat = NOT_MATCH;
return 0;
}
matchStat = END;
} else {
matchStat = NOT_MATCH;
return 0;
}
return value;
}
public float scanFieldFloat(char[] fieldName) {
matchStat = UNKOWN;
if (!charArrayCompare(buf, bp, fieldName)) {
matchStat = NOT_MATCH_NAME;
return 0;
}
int index = bp + fieldName.length;
char ch = buf[index++];
float value;
if (ch >= '0' && ch <= '9') {
int start = index - 1;
for (;;) {
ch = buf[index++];
if (ch >= '0' && ch <= '9') {
continue;
} else {
break;
}
}
if (ch == '.') {
ch = buf[index++];
if (ch >= '0' && ch <= '9') {
for (;;) {
ch = buf[index++];
if (ch >= '0' && ch <= '9') {
continue;
} else {
break;
}
}
} else {
matchStat = NOT_MATCH;
return 0;
}
}
bp = index - 1;
String text = new String(buf, start, index - start - 1);
value = Float.parseFloat(text);
} else {
matchStat = NOT_MATCH;
return 0;
}
if (ch == ',') {
ch = buf[++bp];
matchStat = VALUE;
token = JSONToken.COMMA;
return value;
} else if (ch == '}') {
ch = buf[++bp];
if (ch == ',') {
token = JSONToken.COMMA;
this.ch = buf[++bp];
} else if (ch == ']') {
token = JSONToken.RBRACKET;
this.ch = buf[++bp];
} else if (ch == '}') {
token = JSONToken.RBRACE;
this.ch = buf[++bp];
} else if (ch == EOI) {
token = JSONToken.EOF;
} else {
matchStat = NOT_MATCH;
return 0;
}
matchStat = END;
} else {
matchStat = NOT_MATCH;
return 0;
}
return value;
}
public byte[] bytesValue() {
return Base64.decodeFast(buf, np + 1, sp);
}
public double scanFieldDouble(char[] fieldName) {
matchStat = UNKOWN;
if (!charArrayCompare(buf, bp, fieldName)) {
matchStat = NOT_MATCH_NAME;
return 0;
}
int index = bp + fieldName.length;
char ch = buf[index++];
double value;
if (ch >= '0' && ch <= '9') {
int start = index - 1;
for (;;) {
ch = buf[index++];
if (ch >= '0' && ch <= '9') {
continue;
} else {
break;
}
}
if (ch == '.') {
ch = buf[index++];
if (ch >= '0' && ch <= '9') {
for (;;) {
ch = buf[index++];
if (ch >= '0' && ch <= '9') {
continue;
} else {
break;
}
}
} else {
matchStat = NOT_MATCH;
return 0;
}
}
bp = index - 1;
String text = new String(buf, start, index - start - 1);
value = Double.parseDouble(text);
} else {
matchStat = NOT_MATCH;
return 0;
}
if (ch == ',') {
ch = buf[++bp];
matchStat = VALUE;
token = JSONToken.COMMA;
} else if (ch == '}') {
ch = buf[++bp];
if (ch == ',') {
token = JSONToken.COMMA;
this.ch = buf[++bp];
} else if (ch == ']') {
token = JSONToken.RBRACKET;
this.ch = buf[++bp];
} else if (ch == '}') {
token = JSONToken.RBRACE;
this.ch = buf[++bp];
} else if (ch == EOI) {
token = JSONToken.EOF;
} else {
matchStat = NOT_MATCH;
return 0;
}
matchStat = END;
} else {
matchStat = NOT_MATCH;
return 0;
}
return value;
}
// public int scanField2(char[] fieldName, Object object, FieldDeserializer fieldDeserializer) {
// return NOT_MATCH;
// }
public 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 == '}') {
ch = buf[++bp];
token = JSONToken.RBRACE;
return null;
}
if (ch == ',') {
ch = buf[++bp];
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 final String scanSymbol(final SymbolTable symbolTable, final char quote) {
int hash = 0;
np = bp;
sp = 0;
boolean hasSpecial = false;
char ch;
for (;;) {
ch = buf[++bp];
if (ch == quote) {
break;
}
if (ch == EOI) {
throw new JSONException("unclosed.str");
}
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;
}
System.arraycopy(buf, np + 1, sbuf, 0, sp);
}
ch = buf[++bp];
switch (ch) {
case '"':
hash = 31 * hash + (int) '"';
putChar('"');
break;
case '\\':
hash = 31 * hash + (int) '\\';
putChar('\\');
break;
case '/':
hash = 31 * hash + (int) '/';
putChar('/');
break;
case 'b':
hash = 31 * hash + (int) '\b';
putChar('\b');
break;
case 'f':
case 'F':
hash = 31 * hash + (int) '\f';
putChar('\f');
break;
case 'n':
hash = 31 * hash + (int) '\n';
putChar('\n');
break;
case 'r':
hash = 31 * hash + (int) '\r';
putChar('\r');
break;
case 't':
hash = 31 * hash + (int) '\t';
putChar('\t');
break;
case 'u':
char c1 = ch = buf[++bp];
char c2 = ch = buf[++bp];
char c3 = ch = buf[++bp];
char c4 = ch = buf[++bp];
int val = Integer.parseInt(new String(new char[]{c1, c2, c3, c4}), 16);
hash = 31 * hash + val;
putChar((char) val);
break;
default:
this.ch = ch;
throw new JSONException("unclosed.str.lit");
}
continue;
}
hash = 31 * hash + ch;
if (!hasSpecial) {
sp++;
continue;
}
if (sp == sbuf.length) {
putChar(ch);
} else {
sbuf[sp++] = ch;
}
}
token = LITERAL_STRING;
this.ch = buf[++bp];
if (!hasSpecial) {
return symbolTable.addSymbol(buf, np + 1, sp, hash);
} else {
return symbolTable.addSymbol(sbuf, 0, sp, hash);
}
}
public void scanTrue() {
if (buf[bp++] != 't') {
throw new JSONException("error parse true");
}
if (buf[bp++] != 'r') {
throw new JSONException("error parse true");
}
if (buf[bp++] != 'u') {
throw new JSONException("error parse true");
}
if (buf[bp++] != 'e') {
throw new JSONException("error parse true");
}
ch = buf[bp];
if (ch == ' ' || ch == ',' || ch == '}' || ch == ']' || ch == '\n' || ch == '\r' || ch == '\t' || ch == EOI
|| ch == '\f' || ch == '\b') {
token = JSONToken.TRUE;
} else {
throw new JSONException("scan true error");
}
}
public void scanSet() {
if (buf[bp++] != 'S') {
throw new JSONException("error parse true");
}
if (buf[bp++] != 'e') {
throw new JSONException("error parse true");
}
if (buf[bp++] != 't') {
throw new JSONException("error parse true");
}
ch = buf[bp];
if (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f' || ch == '\b' || ch == '[' || ch == '(') {
token = JSONToken.SET;
} else {
throw new JSONException("scan set error");
}
}
public void scanTreeSet() {
if (buf[bp++] != 'T') {
throw new JSONException("error parse true");
}
if (buf[bp++] != 'r') {
throw new JSONException("error parse true");
}
if (buf[bp++] != 'e') {
throw new JSONException("error parse true");
}
if (buf[bp++] != 'e') {
throw new JSONException("error parse true");
}
if (buf[bp++] != 'S') {
throw new JSONException("error parse true");
}
if (buf[bp++] != 'e') {
throw new JSONException("error parse true");
}
if (buf[bp++] != 't') {
throw new JSONException("error parse true");
}
ch = buf[bp];
if (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f' || ch == '\b' || ch == '[' || ch == '(') {
token = JSONToken.TREE_SET;
} else {
throw new JSONException("scan set error");
}
}
public void scanNullOrNew() {
if (buf[bp++] != 'n') {
throw new JSONException("error parse null or new");
}
if (buf[bp] == 'u') {
bp++;
if (buf[bp++] != 'l') {
throw new JSONException("error parse true");
}
if (buf[bp++] != 'l') {
throw new JSONException("error parse true");
}
ch = buf[bp];
if (ch == ' ' || ch == ',' || ch == '}' || ch == ']' || ch == '\n' || ch == '\r' || ch == '\t' || ch == EOI
|| ch == '\f' || ch == '\b') {
token = JSONToken.NULL;
} else {
throw new JSONException("scan true error");
}
return;
}
if (buf[bp] != 'e') {
throw new JSONException("error parse e");
}
bp++;
if (buf[bp++] != 'w') {
throw new JSONException("error parse w");
}
ch = buf[bp];
if (ch == ' ' || ch == ',' || ch == '}' || ch == ']' || ch == '\n' || ch == '\r' || ch == '\t' || ch == EOI
|| ch == '\f' || ch == '\b') {
token = JSONToken.NEW;
} else {
throw new JSONException("scan true error");
}
}
public void scanFalse() {
if (buf[bp++] != 'f') {
throw new JSONException("error parse false");
}
if (buf[bp++] != 'a') {
throw new JSONException("error parse false");
}
if (buf[bp++] != 'l') {
throw new JSONException("error parse false");
}
if (buf[bp++] != 's') {
throw new JSONException("error parse false");
}
if (buf[bp++] != 'e') {
throw new JSONException("error parse false");
}
ch = buf[bp];
if (ch == ' ' || ch == ',' || ch == '}' || ch == ']' || ch == '\n' || ch == '\r' || ch == '\t' || ch == EOI
|| ch == '\f' || ch == '\b') {
token = JSONToken.FALSE;
} else {
throw new JSONException("scan false error");
}
}
public void scanIdent() {
np = bp - 1;
hasSpecial = false;
for (;;) {
sp++;
ch = buf[++bp];
if (Character.isLetterOrDigit(ch)) {
continue;
}
String ident = stringVal();
Integer tok = keywods.getKeyword(ident);
if (tok != null) {
token = tok;
} else {
token = JSONToken.IDENTIFIER;
}
return;
}
}
public void scanNumber() {
np = bp;
if (ch == '-') {
sp++;
ch = buf[++bp];
}
for (;;) {
if (ch >= '0' && ch <= '9') {
sp++;
} else {
break;
}
ch = buf[++bp];
}
boolean isDouble = false;
if (ch == '.') {
sp++;
ch = buf[++bp];
isDouble = true;
for (;;) {
if (ch >= '0' && ch <= '9') {
sp++;
} else {
break;
}
ch = buf[++bp];
}
}
if (ch == 'L') {
sp++;
ch = buf[++bp];
} else if (ch == 'S') {
sp++;
ch = buf[++bp];
} else if (ch == 'B') {
sp++;
ch = buf[++bp];
} else if (ch == 'F') {
sp++;
ch = buf[++bp];
isDouble = true;
} else if (ch == 'D') {
sp++;
ch = buf[++bp];
isDouble = true;
} else if (ch == 'e' || ch == 'E') {
sp++;
ch = buf[++bp];
if (ch == '+' || ch == '-') {
sp++;
ch = buf[++bp];
}
for (;;) {
if (ch >= '0' && ch <= '9') {
sp++;
} else {
break;
}
ch = buf[++bp];
}
if (ch == 'D' || ch == 'F') {
ch = buf[++bp];
}
isDouble = true;
}
if (isDouble) {
token = JSONToken.LITERAL_FLOAT;
} else {
token = JSONToken.LITERAL_INT;
}
}
/**
* Append a character to sbuf.
*/
private final void putChar(char ch) {
if (sp == sbuf.length) {
char[] newsbuf = new char[sbuf.length * 2];
System.arraycopy(sbuf, 0, newsbuf, 0, sbuf.length);
sbuf = newsbuf;
}
sbuf[sp++] = ch;
}
/**
* Return the current token's position: a 0-based offset from beginning of the raw input stream
* (before unicode translation)
*/
public final int pos() {
return pos;
}
/**
* The value of a literal token, recorded as a string. For integers, leading 0x and 'l' suffixes
* are suppressed.
*/
public final String stringVal() {
if (!hasSpecial) {
return new String(buf, np + 1, sp);
} else {
return new String(sbuf, 0, sp);
}
}
//
public boolean isRef() {
if (hasSpecial) {
return false;
}
if (sp != 4) {
return false;
}
return buf[np + 1] == '$' && buf[np + 2] == 'r' && buf[np + 3] == 'e' && buf[np + 4] == 'f';
}
public final String symbol(SymbolTable symbolTable) {
if (symbolTable == null) {
if (!hasSpecial) {
return new String(buf, np + 1, sp);
} else {
return new String(sbuf, 0, sp);
}
}
if (!hasSpecial) {
return symbolTable.addSymbol(buf, np + 1, sp);
} else {
return symbolTable.addSymbol(sbuf, 0, sp);
}
}
private static final long MULTMIN_RADIX_TEN = Long.MIN_VALUE / 10;
private static final long N_MULTMAX_RADIX_TEN = -Long.MAX_VALUE / 10;
private static final int INT_MULTMIN_RADIX_TEN = Integer.MIN_VALUE / 10;
private static final int INT_N_MULTMAX_RADIX_TEN = -Integer.MAX_VALUE / 10;
private final static int[] digits = new int[(int) 'f' + 1];
static {
for (int i = '0'; i <= '9'; ++i) {
digits[i] = i - '0';
}
for (int i = 'a'; i <= 'f'; ++i) {
digits[i] = (i - 'a') + 10;
}
for (int i = 'A'; i <= 'F'; ++i) {
digits[i] = (i - 'A') + 10;
}
}
public Number integerValue() throws NumberFormatException {
long result = 0;
boolean negative = false;
int i = np, max = np + sp;
long limit;
long multmin;
int digit;
char type = ' ';
if (max > 0) {
switch (buf[max - 1]) {
case 'L':
max--;
type = 'L';
break;
case 'S':
max--;
type = 'S';
break;
case 'B':
max--;
type = 'B';
break;
default:
break;
}
}
if (buf[np] == '-') {
negative = true;
limit = Long.MIN_VALUE;
i++;
} else {
limit = -Long.MAX_VALUE;
}
multmin = negative ? MULTMIN_RADIX_TEN : N_MULTMAX_RADIX_TEN;
if (i < max) {
digit = digits[buf[i++]];
result = -digit;
}
while (i < max) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = digits[buf[i++]];
if (result < multmin) {
return new BigInteger(numberString());
}
result *= 10;
if (result < limit + digit) {
return new BigInteger(numberString());
}
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 NumberFormatException(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 long longValue() throws NumberFormatException {
long result = 0;
boolean negative = false;
int i = np, max = np + sp;
long limit;
long multmin;
int digit;
if (buf[np] == '-') {
negative = true;
limit = Long.MIN_VALUE;
i++;
} else {
limit = -Long.MAX_VALUE;
}
multmin = negative ? MULTMIN_RADIX_TEN : N_MULTMAX_RADIX_TEN;
if (i < max) {
digit = digits[buf[i++]];
result = -digit;
}
while (i < max) {
// Accumulating negatively avoids surprises near MAX_VALUE
char ch = buf[i++];
if (ch == 'L' || ch == 'S' || ch == 'B') {
break;
}
digit = digits[ch];
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 int intValue() {
int result = 0;
boolean negative = false;
int i = np, max = np + sp;
int limit;
int multmin;
int digit;
if (buf[np] == '-') {
negative = true;
limit = Integer.MIN_VALUE;
i++;
} else {
limit = -Integer.MAX_VALUE;
}
multmin = negative ? INT_MULTMIN_RADIX_TEN : INT_N_MULTMAX_RADIX_TEN;
if (i < max) {
digit = digits[buf[i++]];
result = -digit;
}
while (i < max) {
// Accumulating negatively avoids surprises near MAX_VALUE
char ch = buf[i++];
if (ch == 'L' || ch == 'S' || ch == 'B') {
break;
}
digit = digits[ch];
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 final String numberString() {
char ch = buf[np + sp - 1];
int sp = this.sp;
if (ch == 'L' || ch == 'S' || ch == 'B' || ch == 'F' || ch == 'D') {
sp--;
}
return new String(buf, np, sp);
}
public float floatValue() {
return Float.parseFloat(numberString());
}
public double doubleValue() {
return Double.parseDouble(numberString());
}
public Number decimalValue(boolean decimal) {
char ch = buf[np + sp - 1];
if (ch == 'F') {
return Float.parseFloat(new String(buf, np, sp - 1));
}
if (ch == 'D') {
return Double.parseDouble(new String(buf, np, sp - 1));
}
if (decimal) {
return decimalValue();
} else {
return doubleValue();
}
}
public BigDecimal decimalValue() {
char ch = buf[np + sp - 1];
int sp = this.sp;
if (ch == 'L' || ch == 'S' || ch == 'B' || ch == 'F' || ch == 'D') {
sp--;
}
return new BigDecimal(buf, np, sp);
}
public void config(Feature feature, boolean state) {
features = Feature.config(features, feature, state);
}
public boolean isEnabled(Feature feature) {
return Feature.isEnabled(this.features, feature);
}
public final int ISO8601_LEN_0 = "0000-00-00".length();
public final int ISO8601_LEN_1 = "0000-00-00T00:00:00".length();
public final int ISO8601_LEN_2 = "0000-00-00T00:00:00.000".length();
public boolean scanISO8601DateIfMatch() {
int rest = buflen - bp;
if (rest < ISO8601_LEN_0) {
return false;
}
char y0 = buf[bp];
char y1 = buf[bp + 1];
char y2 = buf[bp + 2];
char y3 = buf[bp + 3];
if (y0 != '1' && y0 != '2') {
return false;
}
if (y1 < '0' || y1 > '9') {
return false;
}
if (y2 < '0' || y2 > '9') {
return false;
}
if (y3 < '0' || y3 > '9') {
return false;
}
if (buf[bp + 4] != '-') {
return false;
}
char M0 = buf[bp + 5];
char M1 = buf[bp + 6];
if (M0 == '0') {
if (M1 < '1' || M1 > '9') {
return false;
}
} else if (M0 == '1') {
if (M1 != '0' && M1 != '1' && M1 != '2') {
return false;
}
} else {
return false;
}
if (buf[bp + 7] != '-') {
return false;
}
char d0 = buf[bp + 8];
char d1 = buf[bp + 9];
if (d0 == '0') {
if (d1 < '1' || d1 > '9') {
return false;
}
} else if (d0 == '1' || d0 == '2') {
if (d1 < '0' || d1 > '9') {
return false;
}
} else if (d0 == '3') {
if (d1 != '0' && d1 != '1') {
return false;
}
} else {
return false;
}
Locale local = Locale.getDefault();
calendar = Calendar.getInstance(TimeZone.getDefault(), local);
int year = digits[y0] * 1000 + digits[y1] * 100 + digits[y2] * 10 + digits[y3];
int month = digits[M0] * 10 + digits[M1] - 1;
int day = digits[d0] * 10 + digits[d1];
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, day);
char t = buf[bp + 10];
if (t == 'T') {
if (rest < ISO8601_LEN_1) {
return false;
}
} else if (t == '"' || t == EOI) {
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
ch = buf[bp += 10];
token = JSONToken.LITERAL_ISO8601_DATE;
return true;
} else {
return false;
}
char h0 = buf[bp + 11];
char h1 = buf[bp + 12];
if (h0 == '0') {
if (h1 < '0' || h1 > '9') {
return false;
}
} else if (h0 == '1') {
if (h1 < '0' || h1 > '9') {
return false;
}
} else if (h0 == '2') {
if (h1 < '0' || h1 > '4') {
return false;
}
} else {
return false;
}
if (buf[bp + 13] != ':') {
return false;
}
char m0 = buf[bp + 14];
char m1 = buf[bp + 15];
if (m0 >= '0' && m0 <= '5') {
if (m1 < '0' || m1 > '9') {
return false;
}
} else if (m0 == '6') {
if (m1 != '0') {
return false;
}
} else {
return false;
}
if (buf[bp + 16] != ':') {
return false;
}
char s0 = buf[bp + 17];
char s1 = buf[bp + 18];
if (s0 >= '0' && s0 <= '5') {
if (s1 < '0' || s1 > '9') {
return false;
}
} else if (s0 == '6') {
if (s1 != '0') {
return false;
}
} else {
return false;
}
int hour = digits[h0] * 10 + digits[h1];
int minute = digits[m0] * 10 + digits[m1];
int seconds = digits[s0] * 10 + digits[s1];
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, seconds);
char dot = buf[bp + 19];
if (dot == '.') {
if (rest < ISO8601_LEN_2) {
return false;
}
} else {
calendar.set(Calendar.MILLISECOND, 0);
ch = buf[bp += 19];
token = JSONToken.LITERAL_ISO8601_DATE;
return true;
}
char S0 = buf[bp + 20];
char S1 = buf[bp + 21];
char S2 = buf[bp + 22];
if (S0 < '0' || S0 > '9') {
return false;
}
if (S1 < '0' || S1 > '9') {
return false;
}
if (S2 < '0' || S2 > '9') {
return false;
}
int millis = digits[S0] * 100 + digits[S1] * 10 + digits[S2];
calendar.set(Calendar.MILLISECOND, millis);
ch = buf[bp += 23];
token = JSONToken.LITERAL_ISO8601_DATE;
return true;
}
public Calendar getCalendar() {
return this.calendar;
}
public boolean isEOF() {
switch (token) {
case JSONToken.EOF:
return true;
case JSONToken.ERROR:
return false;
case JSONToken.RBRACE:
return false;
default:
return false;
}
}
public void close() {
if (sbuf.length <= 1024 * 8) {
sbufRefLocal.set(new SoftReference<char[]>(sbuf));
}
this.sbuf = null;
}
}