com.alibaba.fastjson2.JSONReaderASCII Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fastjson2 Show documentation
Show all versions of fastjson2 Show documentation
Fastjson is a JSON processor (JSON parser + JSON generator) written in Java
package com.alibaba.fastjson2;
import com.alibaba.fastjson2.util.*;
import sun.misc.Unsafe;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import static com.alibaba.fastjson2.JSONFactory.*;
import static com.alibaba.fastjson2.util.JDKUtils.*;
final class JSONReaderASCII
extends JSONReaderUTF8 {
final String str;
JSONReaderASCII(Context ctx, String str, byte[] bytes, int offset, int length) {
super(ctx, str, bytes, offset, length);
this.str = str;
nameAscii = true;
}
JSONReaderASCII(Context ctx, InputStream is) {
super(ctx, is);
nameAscii = true;
str = null;
}
@Override
public void next() {
final byte[] bytes = this.bytes;
int offset = this.offset;
int ch = offset >= end ? EOI : bytes[offset++];
while (ch == '\0' || (ch > 0 && ch <= ' ' && ((1L << ch) & SPACE) != 0)) {
ch = offset == end ? EOI : bytes[offset++];
}
this.offset = offset;
this.ch = (char) (ch & 0xFF);
if (ch == '/') {
skipComment();
}
}
public boolean nextIfObjectStart() {
int ch = this.ch;
if (ch != '{') {
return false;
}
final byte[] bytes = this.bytes;
int offset = this.offset;
ch = offset == end ? EOI : bytes[offset++];
while (ch == '\0' || (ch <= ' ' && ((1L << ch) & SPACE) != 0)) {
ch = offset == end ? EOI : bytes[offset++];
}
this.ch = (char) (ch & 0xFF);
this.offset = offset;
if (ch == '/') {
skipComment();
}
return true;
}
@Override
public boolean nextIfNullOrEmptyString() {
final char first = this.ch;
final int end = this.end;
int offset = this.offset;
byte[] bytes = this.bytes;
if (first == 'n'
&& offset + 2 < end
&& bytes[offset] == 'u'
&& bytes[offset + 1] == 'l'
&& bytes[offset + 2] == 'l'
) {
offset += 3;
} else if ((first == '"' || first == '\'') && offset < end && bytes[offset] == first) {
offset++;
} else {
return false;
}
int ch = offset == end ? EOI : bytes[offset++];
while (ch >= 0 && ch <= ' ' && ((1L << ch) & SPACE) != 0) {
ch = offset == end ? EOI : bytes[offset++];
}
if (comma = (ch == ',')) {
ch = offset == end ? EOI : bytes[offset++];
}
while (ch >= 0 && ch <= ' ' && ((1L << ch) & SPACE) != 0) {
ch = offset == end ? EOI : bytes[offset++];
}
this.offset = offset;
this.ch = (char) ch;
return true;
}
@Override
public long readFieldNameHashCode() {
final byte[] bytes = this.bytes;
if (ch != '"' && ch != '\'') {
if ((context.features & Feature.AllowUnQuotedFieldNames.mask) != 0 && isFirstIdentifier(ch)) {
return readFieldNameHashCodeUnquote();
}
if (ch == '}' || isNull()) {
return -1;
}
String errorMsg, preFieldName;
if (ch == '[' && nameBegin > 0 && (preFieldName = getFieldName()) != null) {
errorMsg = "illegal fieldName input " + ch + ", previous fieldName " + preFieldName;
} else {
errorMsg = "illegal fieldName input" + ch;
}
throw new JSONException(info(errorMsg));
}
final char quote = ch;
this.stringValue = null;
this.nameEscape = false;
int offset = this.nameBegin = this.offset;
long nameValue = 0;
if (offset + 9 < end) {
byte c0, c1, c2, c3, c4, c5, c6, c7;
if ((c0 = bytes[offset]) == quote) {
// skip
} else if ((c1 = bytes[offset + 1]) == quote && c0 != 0 && c0 != '\\') {
nameValue = c0;
this.nameLength = 1;
this.nameEnd = offset + 1;
offset += 2;
} else if ((c2 = bytes[offset + 2]) == quote && c1 != 0
&& c0 != '\\' && c1 != '\\'
) {
nameValue = (c1 << 8)
+ (c0 & 0xFF);
this.nameLength = 2;
this.nameEnd = offset + 2;
offset += 3;
} else if ((c3 = bytes[offset + 3]) == quote && c2 != 0
&& c0 != '\\' && c1 != '\\' && c2 != '\\'
) {
nameValue
= (c2 << 16)
+ ((c1 & 0xFF) << 8)
+ (c0 & 0xFF);
this.nameLength = 3;
this.nameEnd = offset + 3;
offset += 4;
} else if ((c4 = bytes[offset + 4]) == quote && c3 != 0
&& c0 != '\\' && c1 != '\\' && c2 != '\\' && c3 != '\\'
) {
nameValue
= (c3 << 24)
+ ((c2 & 0xFF) << 16)
+ ((c1 & 0xFF) << 8)
+ (c0 & 0xFF);
this.nameLength = 4;
this.nameEnd = offset + 4;
offset += 5;
} else if ((c5 = bytes[offset + 5]) == quote && c4 != 0
&& c0 != '\\' && c1 != '\\' && c2 != '\\' && c3 != '\\' && c4 != '\\'
) {
nameValue
= (((long) c4) << 32)
+ ((c3 & 0xFFL) << 24)
+ ((c2 & 0xFFL) << 16)
+ ((c1 & 0xFFL) << 8)
+ (c0 & 0xFFL);
this.nameLength = 5;
this.nameEnd = offset + 5;
offset += 6;
} else if ((c6 = bytes[offset + 6]) == quote && c5 != 0
&& c0 != '\\' && c1 != '\\' && c2 != '\\' && c3 != '\\' && c4 != '\\' && c5 != '\\'
) {
nameValue
= (((long) c5) << 40)
+ ((c4 & 0xFFL) << 32)
+ ((c3 & 0xFFL) << 24)
+ ((c2 & 0xFFL) << 16)
+ ((c1 & 0xFFL) << 8)
+ (c0 & 0xFFL);
this.nameLength = 6;
this.nameEnd = offset + 6;
offset += 7;
} else if ((c7 = bytes[offset + 7]) == quote && c6 != 0
&& c0 != '\\' && c1 != '\\' && c2 != '\\' && c3 != '\\' && c4 != '\\' && c5 != '\\' && c6 != '\\'
) {
nameValue
= (((long) c6) << 48)
+ ((c5 & 0xFFL) << 40)
+ ((c4 & 0xFFL) << 32)
+ ((c3 & 0xFFL) << 24)
+ ((c2 & 0xFFL) << 16)
+ ((c1 & 0xFFL) << 8)
+ (c0 & 0xFFL);
this.nameLength = 7;
this.nameEnd = offset + 7;
offset += 8;
} else if (bytes[offset + 8] == quote && c7 != 0
&& c0 != '\\' && c1 != '\\' && c2 != '\\' && c3 != '\\' && c4 != '\\' && c5 != '\\' && c6 != '\\' && c7 != '\\'
) {
nameValue = getLong(bytes, offset);
this.nameLength = 8;
this.nameEnd = offset + 8;
offset += 9;
}
}
if (nameValue == 0) {
for (int i = 0; offset < end; offset++, i++) {
int c = bytes[offset];
if (c == quote) {
if (i == 0) {
offset = this.nameBegin;
break;
}
this.nameLength = i;
this.nameEnd = offset;
offset++;
break;
}
if (c == '\\') {
nameEscape = true;
c = bytes[++offset];
switch (c) {
case 'u': {
c = char4(bytes[offset + 1], bytes[offset + 2], bytes[offset + 3], bytes[offset + 4]);
offset += 4;
break;
}
case 'x': {
c = char2(bytes[offset + 1], bytes[offset + 2]);
offset += 2;
break;
}
case '\\':
case '"':
default:
c = char1(c);
break;
}
}
if (c > 0xFF || i >= 8 || (i == 0 && c == 0)) {
nameValue = 0;
offset = this.nameBegin;
break;
}
switch (i) {
case 0:
nameValue = (byte) c;
break;
case 1:
nameValue = (((byte) c) << 8) + (nameValue & 0xFFL);
break;
case 2:
nameValue = (((byte) c) << 16) + (nameValue & 0xFFFFL);
break;
case 3:
nameValue = (((byte) c) << 24) + (nameValue & 0xFFFFFFL);
break;
case 4:
nameValue = (((long) (byte) c) << 32) + (nameValue & 0xFFFFFFFFL);
break;
case 5:
nameValue = (((long) (byte) c) << 40L) + (nameValue & 0xFFFFFFFFFFL);
break;
case 6:
nameValue = (((long) (byte) c) << 48L) + (nameValue & 0xFFFFFFFFFFFFL);
break;
case 7:
nameValue = (((long) (byte) c) << 56L) + (nameValue & 0xFFFFFFFFFFFFFFL);
break;
default:
break;
}
}
}
long hashCode;
if (nameValue != 0) {
hashCode = nameValue;
} else {
hashCode = Fnv.MAGIC_HASH_CODE;
for (int i = 0; ; ++i) {
int c = bytes[offset];
if (c == '\\') {
nameEscape = true;
c = bytes[++offset];
switch (c) {
case 'u': {
c = char4(bytes[offset + 1], bytes[offset + 2], bytes[offset + 3], bytes[offset + 4]);
offset += 4;
break;
}
case 'x': {
c = char2(bytes[offset + 1], bytes[offset + 2]);
offset += 2;
break;
}
case '\\':
case '"':
default:
c = char1(c);
break;
}
offset++;
hashCode ^= c;
hashCode *= Fnv.MAGIC_PRIME;
continue;
}
if (c == quote) {
this.nameLength = i;
this.nameEnd = offset;
offset++;
break;
}
offset++;
hashCode ^= (c & 0xFF);
hashCode *= Fnv.MAGIC_PRIME;
}
}
int ch = offset == end ? EOI : bytes[offset++];
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
ch = offset == end ? EOI : bytes[offset++];
}
if (ch != ':') {
throw new JSONException(info("expect ':', but " + ch));
}
ch = offset == end ? EOI : bytes[offset++];
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
ch = offset == end ? EOI : bytes[offset++];
}
this.offset = offset;
this.ch = (char) (ch & 0xFF);
return hashCode;
}
@Override
public final long readFieldNameHashCodeUnquote() {
this.nameEscape = false;
int offset = this.offset, end = this.end;
final byte[] bytes = this.bytes;
int ch = this.ch;
this.nameBegin = offset - 1;
int first = ch;
long nameValue = 0;
_for:
for (int i = 0; offset <= end; ++i) {
switch (ch) {
case ' ':
case '\n':
case '\r':
case '\t':
case '\f':
case '\b':
case '.':
case '-':
case '+':
case '*':
case '/':
case '>':
case '<':
case '=':
case '!':
case '[':
case ']':
case '{':
case '}':
case '(':
case ')':
case ',':
case ':':
case EOI:
nameLength = i;
this.nameEnd = ch == EOI ? offset : offset - 1;
if (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
ch = offset == end ? EOI : (char) bytes[offset++];
}
break _for;
default:
break;
}
if (ch == '\\') {
nameEscape = true;
ch = (char) bytes[offset++];
switch (ch) {
case 'u': {
ch = char4(bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3]);
offset += 4;
break;
}
case 'x': {
ch = char2(bytes[offset], bytes[offset + 1]);
offset += 2;
break;
}
case '\\':
case '"':
case '.':
case '-':
case '+':
case '*':
case '/':
case '>':
case '<':
case '=':
case '@':
case ':':
break;
default:
ch = char1(ch);
break;
}
}
if (ch > 0xFF || i >= 8 || (i == 0 && ch == 0)) {
nameValue = 0;
ch = first;
offset = this.nameBegin + 1;
break;
}
byte c = (byte) ch;
switch (i) {
case 0:
nameValue = c;
break;
case 1:
nameValue = (c << 8) + (nameValue & 0xFFL);
break;
case 2:
nameValue = (c << 16) + (nameValue & 0xFFFFL);
break;
case 3:
nameValue = (c << 24) + (nameValue & 0xFFFFFFL);
break;
case 4:
nameValue = (((long) c) << 32) + (nameValue & 0xFFFFFFFFL);
break;
case 5:
nameValue = (((long) c) << 40L) + (nameValue & 0xFFFFFFFFFFL);
break;
case 6:
nameValue = (((long) c) << 48L) + (nameValue & 0xFFFFFFFFFFFFL);
break;
case 7:
nameValue = (((long) c) << 56L) + (nameValue & 0xFFFFFFFFFFFFFFL);
break;
default:
break;
}
ch = offset == end ? EOI : (bytes[offset++] & 0xFF);
}
long hashCode;
if (nameValue != 0) {
hashCode = nameValue;
} else {
hashCode = Fnv.MAGIC_HASH_CODE;
_for:
for (int i = 0; ; ++i) {
if (ch == '\\') {
nameEscape = true;
ch = bytes[offset++];
switch (ch) {
case 'u': {
ch = char4(bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3]);
offset += 4;
break;
}
case 'x': {
ch = char2(bytes[offset], bytes[offset + 1]);
offset += 2;
break;
}
case '\\':
case '"':
case '.':
case '-':
case '+':
case '*':
case '/':
case '>':
case '<':
case '=':
case '@':
case ':':
break;
default:
ch = char1(ch);
break;
}
hashCode ^= ch;
hashCode *= Fnv.MAGIC_PRIME;
ch = offset == end ? EOI : (bytes[offset++] & 0xFF);
continue;
}
switch (ch) {
case ' ':
case '\n':
case '\r':
case '\t':
case '\f':
case '\b':
case '.':
case '-':
case '+':
case '*':
case '/':
case '>':
case '<':
case '=':
case '!':
case '[':
case ']':
case '{':
case '}':
case '(':
case ')':
case ',':
case ':':
case EOI:
nameLength = i;
this.nameEnd = ch == EOI ? offset : offset - 1;
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
ch = offset == end ? EOI : (bytes[offset++] & 0xFF);
}
break _for;
default:
break;
}
hashCode ^= ch;
hashCode *= Fnv.MAGIC_PRIME;
ch = offset == end ? EOI : (bytes[offset++] & 0xFF);
}
}
if (ch == ':') {
ch = offset == end ? EOI : (bytes[offset++] & 0xFF);
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
ch = offset == end ? EOI : (bytes[offset++] & 0xFF);
}
}
this.offset = offset;
this.ch = (char) ch;
return hashCode;
}
public static long getLong(byte[] bytes, int off) {
if (BIG_ENDIAN) {
return UNSAFE.getLong(
bytes,
(long) Unsafe.ARRAY_BYTE_BASE_OFFSET + off
);
}
return (((long) bytes[off + 7]) << 56)
+ ((bytes[off + 6] & 0xFFL) << 48)
+ ((bytes[off + 5] & 0xFFL) << 40)
+ ((bytes[off + 4] & 0xFFL) << 32)
+ ((bytes[off + 3] & 0xFFL) << 24)
+ ((bytes[off + 2] & 0xFFL) << 16)
+ ((bytes[off + 1] & 0xFFL) << 8)
+ (bytes[off] & 0xFFL);
}
@Override
public long readValueHashCode() {
int ch = this.ch;
if (ch != '"' && ch != '\'') {
return -1;
}
final byte[] bytes = this.bytes;
final int quote = ch;
this.nameAscii = true;
this.nameEscape = false;
int offset = this.nameBegin = this.offset;
long nameValue = 0;
for (int i = 0; offset < end; offset++, i++) {
ch = bytes[offset];
if (ch == quote) {
if (i == 0) {
nameValue = 0;
offset = this.nameBegin;
break;
}
this.nameLength = i;
this.nameEnd = offset;
offset++;
break;
}
if (ch == '\\') {
nameEscape = true;
ch = bytes[++offset];
switch (ch) {
case 'u': {
ch = char4(bytes[offset + 1], bytes[offset + 2], bytes[offset + 3], bytes[offset + 4]);
offset += 4;
break;
}
case 'x': {
ch = char2(bytes[offset + 1], bytes[offset + 2]);
offset += 2;
break;
}
case '\\':
case '"':
default:
ch = char1(ch);
break;
}
} else if (ch == -61 || ch == -62) {
ch = (char) (((ch & 0x1F) << 6) | (bytes[++offset] & 0x3F));
}
if (ch > 0xFF || ch < 0 || i >= 8 || (i == 0 && ch == 0)) {
nameValue = 0;
offset = this.nameBegin;
break;
}
switch (i) {
case 0:
nameValue = (byte) ch;
break;
case 1:
nameValue = (((byte) ch) << 8) + (nameValue & 0xFFL);
break;
case 2:
nameValue = (((byte) ch) << 16) + (nameValue & 0xFFFFL);
break;
case 3:
nameValue = (((byte) ch) << 24) + (nameValue & 0xFFFFFFL);
break;
case 4:
nameValue = (((long) (byte) ch) << 32) + (nameValue & 0xFFFFFFFFL);
break;
case 5:
nameValue = (((long) (byte) ch) << 40L) + (nameValue & 0xFFFFFFFFFFL);
break;
case 6:
nameValue = (((long) (byte) ch) << 48L) + (nameValue & 0xFFFFFFFFFFFFL);
break;
case 7:
nameValue = (((long) (byte) ch) << 56L) + (nameValue & 0xFFFFFFFFFFFFFFL);
break;
default:
break;
}
}
long hashCode;
if (nameValue != 0) {
hashCode = nameValue;
} else {
hashCode = Fnv.MAGIC_HASH_CODE;
for (int i = 0; ; ++i) {
ch = bytes[offset];
if (ch == '\\') {
nameEscape = true;
ch = bytes[++offset];
switch (ch) {
case 'u': {
ch = char4(bytes[offset + 1], bytes[offset + 2], bytes[offset + 3], bytes[offset + 4]);
offset += 4;
break;
}
case 'x': {
ch = char2(bytes[offset + 1], bytes[offset + 2]);
offset += 2;
break;
}
case '\\':
case '"':
default:
ch = char1(ch);
break;
}
offset++;
hashCode ^= ch;
hashCode *= Fnv.MAGIC_PRIME;
continue;
}
if (ch == '"') {
this.nameLength = i;
this.nameEnd = offset;
offset++;
break;
}
offset++;
hashCode ^= ch;
hashCode *= Fnv.MAGIC_PRIME;
}
}
ch = offset == end ? EOI : bytes[offset++];
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
ch = offset == end ? EOI : bytes[offset++];
}
if (comma = (ch == ',')) {
ch = offset == end ? EOI : bytes[offset++];
while (ch <= ' ' && ((1L << ch) & SPACE) != 0) {
ch = offset == end ? EOI : bytes[offset++];
}
}
this.offset = offset;
this.ch = (char) (ch & 0xFF);
return hashCode;
}
@Override
public long getNameHashCodeLCase() {
final byte[] bytes = this.bytes;
int offset = nameBegin;
long nameValue = 0;
for (int i = 0; offset < end; offset++) {
int c = bytes[offset];
if (c == '\\') {
c = bytes[++offset];
switch (c) {
case 'u': {
c = char4(bytes[offset + 1], bytes[offset + 2], bytes[offset + 3], bytes[offset + 4]);
offset += 4;
break;
}
case 'x': {
c = char2(bytes[offset + 1], bytes[offset + 2]);
offset += 2;
break;
}
case '\\':
case '"':
default:
c = char1(c);
break;
}
} else if (c == '"') {
break;
}
if (c > 0xFF || c < 0 || i >= 8 || (i == 0 && c == 0)) {
nameValue = 0;
offset = this.nameBegin;
break;
}
if (c == '_' || c == '-' || c == ' ') {
byte c1 = bytes[offset + 1];
if (c1 != '"' && c1 != '\'' && c1 != c) {
continue;
}
}
if (c >= 'A' && c <= 'Z') {
c = (char) (c + 32);
}
switch (i) {
case 0:
nameValue = (byte) c;
break;
case 1:
nameValue = (((byte) c) << 8) + (nameValue & 0xFFL);
break;
case 2:
nameValue = (((byte) c) << 16) + (nameValue & 0xFFFFL);
break;
case 3:
nameValue = (((byte) c) << 24) + (nameValue & 0xFFFFFFL);
break;
case 4:
nameValue = (((long) (byte) c) << 32) + (nameValue & 0xFFFFFFFFL);
break;
case 5:
nameValue = (((long) (byte) c) << 40) + (nameValue & 0xFFFFFFFFFFL);
break;
case 6:
nameValue = (((long) (byte) c) << 48) + (nameValue & 0xFFFFFFFFFFFFL);
break;
case 7:
nameValue = (((long) (byte) c) << 56) + (nameValue & 0xFFFFFFFFFFFFFFL);
break;
default:
break;
}
++i;
}
if (nameValue != 0) {
return nameValue;
}
long hashCode = Fnv.MAGIC_HASH_CODE;
while (offset < end) {
int c = bytes[offset];
if (c == '\\') {
c = bytes[++offset];
switch (c) {
case 'u': {
c = char4(bytes[offset + 1], bytes[offset + 2], bytes[offset + 3], bytes[offset + 4]);
offset += 4;
break;
}
case 'x': {
c = char2(bytes[offset + 1], bytes[offset + 2]);
offset += 2;
break;
}
case '\\':
case '"':
default:
c = char1(c);
break;
}
} else if (c == '"') {
break;
}
offset++;
if (c == '_' || c == '-' || c == ' ') {
byte c1 = bytes[offset];
if (c1 != '"' && c1 != '\'' && c1 != c) {
continue;
}
}
if (c >= 'A' && c <= 'Z') {
c = (char) (c + 32);
}
hashCode ^= c < 0 ? (c & 0xFF) : c;
hashCode *= Fnv.MAGIC_PRIME;
}
return hashCode;
}
@Override
public String getFieldName() {
final byte[] bytes = this.bytes;
int length = nameEnd - nameBegin;
if (!nameEscape) {
if (this.str != null) {
return this.str.substring(nameBegin, nameEnd);
} else {
return getLatin1String(nameBegin, length);
}
}
char[] chars = this.charBuf;
if (chars == null) {
this.charBuf = chars = CHARS_UPDATER.getAndSet(cacheItem, null);
}
if (chars == null || chars.length < nameLength) {
this.charBuf = chars = new char[nameLength];
}
int offset = nameBegin;
for (int i = 0; offset < nameEnd; ++i) {
char ch = (char) (bytes[offset] & 0xff);
if (ch == '\\') {
ch = (char) bytes[++offset];
switch (ch) {
case 'u': {
ch = char4(bytes[offset + 1], bytes[offset + 2], bytes[offset + 3], bytes[offset + 4]);
offset += 4;
break;
}
case 'x': {
ch = char2(bytes[offset + 1], bytes[offset + 2]);
offset += 2;
break;
}
case '.':
case '-':
case '+':
case '*':
case '/':
case '>':
case '<':
case '=':
case '@':
break;
default:
ch = char1(ch);
break;
}
} else if (ch == '"') {
break;
}
chars[i] = ch;
offset++;
}
return new String(chars, 0, nameLength);
}
@Override
public String readFieldName() {
final char quote = ch;
if (quote != '"' && quote != '\'') {
if ((context.features & Feature.AllowUnQuotedFieldNames.mask) != 0 && isFirstIdentifier(quote)) {
return readFieldNameUnquote();
}
return null;
}
final byte[] bytes = this.bytes;
this.nameEscape = false;
int offset = this.nameBegin = this.offset;
final int nameBegin = this.nameBegin;
for (int i = 0; offset < end; ++i) {
int c = bytes[offset];
if (c == '\\') {
nameEscape = true;
c = bytes[offset + 1];
offset += (c == 'u' ? 6 : (c == 'x' ? 4 : 2));
continue;
}
if (c == quote) {
this.nameLength = i;
this.nameEnd = offset;
offset++;
c = bytes[offset];
while (c <= ' ' && ((1L << c) & SPACE) != 0) {
offset++;
c = bytes[offset];
}
if (c != ':') {
throw syntaxError(offset, ch);
}
offset++;
if (offset >= end) {
this.ch = EOI;
throw syntaxError(offset, ch);
}
c = bytes[offset];
while (c <= ' ' && ((1L << c) & SPACE) != 0) {
offset++;
c = bytes[offset];
}
this.offset = offset + 1;
this.ch = (char) c;
break;
}
offset++;
}
if (nameEnd < nameBegin) {
throw syntaxError(offset, ch);
}
if (!nameEscape) {
long nameValue0 = -1, nameValue1 = -1;
int length = nameEnd - nameBegin;
switch (length) {
case 1:
nameValue0 = (bytes[nameBegin] & 0xFF);
break;
case 2:
nameValue0 = ((bytes[nameBegin + 1] & 0xFF) << 8) + (bytes[nameBegin] & 0xFF);
break;
case 3:
nameValue0
= (bytes[nameBegin + 2] << 16)
+ ((bytes[nameBegin + 1] & 0xFF) << 8)
+ (bytes[nameBegin] & 0xFF);
break;
case 4:
nameValue0
= (bytes[nameBegin + 3] << 24)
+ ((bytes[nameBegin + 2] & 0xFF) << 16)
+ ((bytes[nameBegin + 1] & 0xFF) << 8)
+ (bytes[nameBegin] & 0xFF);
break;
case 5:
nameValue0
= (((long) bytes[nameBegin + 4]) << 32)
+ ((bytes[nameBegin + 3] & 0xFFL) << 24)
+ ((bytes[nameBegin + 2] & 0xFFL) << 16)
+ ((bytes[nameBegin + 1] & 0xFFL) << 8)
+ (bytes[nameBegin] & 0xFFL);
break;
case 6:
nameValue0
= (((long) bytes[nameBegin + 5]) << 40)
+ ((bytes[nameBegin + 4] & 0xFFL) << 32)
+ ((bytes[nameBegin + 3] & 0xFFL) << 24)
+ ((bytes[nameBegin + 2] & 0xFFL) << 16)
+ ((bytes[nameBegin + 1] & 0xFFL) << 8)
+ (bytes[nameBegin] & 0xFFL);
break;
case 7:
nameValue0
= (((long) bytes[nameBegin + 6]) << 48)
+ ((bytes[nameBegin + 5] & 0xFFL) << 40)
+ ((bytes[nameBegin + 4] & 0xFFL) << 32)
+ ((bytes[nameBegin + 3] & 0xFFL) << 24)
+ ((bytes[nameBegin + 2] & 0xFFL) << 16)
+ ((bytes[nameBegin + 1] & 0xFFL) << 8)
+ (bytes[nameBegin] & 0xFFL);
break;
case 8:
nameValue0
= (((long) bytes[nameBegin + 7]) << 56)
+ ((bytes[nameBegin + 6] & 0xFFL) << 48)
+ ((bytes[nameBegin + 5] & 0xFFL) << 40)
+ ((bytes[nameBegin + 4] & 0xFFL) << 32)
+ ((bytes[nameBegin + 3] & 0xFFL) << 24)
+ ((bytes[nameBegin + 2] & 0xFFL) << 16)
+ ((bytes[nameBegin + 1] & 0xFFL) << 8)
+ (bytes[nameBegin] & 0xFFL);
break;
case 9:
nameValue0 = bytes[nameBegin];
nameValue1
= (((long) bytes[nameBegin + 8]) << 56)
+ ((bytes[nameBegin + 7] & 0xFFL) << 48)
+ ((bytes[nameBegin + 6] & 0xFFL) << 40)
+ ((bytes[nameBegin + 5] & 0xFFL) << 32)
+ ((bytes[nameBegin + 4] & 0xFFL) << 24)
+ ((bytes[nameBegin + 3] & 0xFFL) << 16)
+ ((bytes[nameBegin + 2] & 0xFFL) << 8)
+ (bytes[nameBegin + 1] & 0xFFL);
break;
case 10:
nameValue0
= (bytes[nameBegin + 1] << 8)
+ (bytes[nameBegin]);
nameValue1
= (((long) bytes[nameBegin + 9]) << 56)
+ ((bytes[nameBegin + 8] & 0xFFL) << 48)
+ ((bytes[nameBegin + 7] & 0xFFL) << 40)
+ ((bytes[nameBegin + 6] & 0xFFL) << 32)
+ ((bytes[nameBegin + 5] & 0xFFL) << 24)
+ ((bytes[nameBegin + 4] & 0xFFL) << 16)
+ ((bytes[nameBegin + 3] & 0xFFL) << 8)
+ (bytes[nameBegin + 2] & 0xFFL);
break;
case 11:
nameValue0
= (bytes[nameBegin + 2] << 16)
+ (bytes[nameBegin + 1] << 8)
+ (bytes[nameBegin]);
nameValue1
= (((long) bytes[nameBegin + 10]) << 56)
+ ((bytes[nameBegin + 9] & 0xFFL) << 48)
+ ((bytes[nameBegin + 8] & 0xFFL) << 40)
+ ((bytes[nameBegin + 7] & 0xFFL) << 32)
+ ((bytes[nameBegin + 6] & 0xFFL) << 24)
+ ((bytes[nameBegin + 5] & 0xFFL) << 16)
+ ((bytes[nameBegin + 4] & 0xFFL) << 8)
+ (bytes[nameBegin + 3] & 0xFFL);
break;
case 12:
nameValue0
= (bytes[nameBegin + 3] << 24)
+ (bytes[nameBegin + 2] << 16)
+ (bytes[nameBegin + 1] << 8)
+ (bytes[nameBegin]);
nameValue1
= (((long) bytes[nameBegin + 11]) << 56)
+ ((bytes[nameBegin + 10] & 0xFFL) << 48)
+ ((bytes[nameBegin + 9] & 0xFFL) << 40)
+ ((bytes[nameBegin + 8] & 0xFFL) << 32)
+ ((bytes[nameBegin + 7] & 0xFFL) << 24)
+ ((bytes[nameBegin + 6] & 0xFFL) << 16)
+ ((bytes[nameBegin + 5] & 0xFFL) << 8)
+ (bytes[nameBegin + 4] & 0xFFL);
break;
case 13:
nameValue0
= (((long) bytes[nameBegin + 4]) << 32)
+ (((long) bytes[nameBegin + 3]) << 24)
+ (((long) bytes[nameBegin + 2]) << 16)
+ (((long) bytes[nameBegin + 1]) << 8)
+ ((long) bytes[nameBegin]);
nameValue1
= (((long) bytes[nameBegin + 12]) << 56)
+ ((bytes[nameBegin + 11] & 0xFFL) << 48)
+ ((bytes[nameBegin + 10] & 0xFFL) << 40)
+ ((bytes[nameBegin + 9] & 0xFFL) << 32)
+ ((bytes[nameBegin + 8] & 0xFFL) << 24)
+ ((bytes[nameBegin + 7] & 0xFFL) << 16)
+ ((bytes[nameBegin + 6] & 0xFFL) << 8)
+ (bytes[nameBegin + 5] & 0xFFL);
break;
case 14:
nameValue0
= (((long) bytes[nameBegin + 5]) << 40)
+ ((bytes[nameBegin + 4] & 0xFFL) << 32)
+ ((bytes[nameBegin + 3] & 0xFFL) << 24)
+ ((bytes[nameBegin + 2] & 0xFFL) << 16)
+ ((bytes[nameBegin + 1] & 0xFFL) << 8)
+ (bytes[nameBegin] & 0xFFL);
nameValue1
= (((long) bytes[nameBegin + 13]) << 56)
+ ((bytes[nameBegin + 12] & 0xFFL) << 48)
+ ((bytes[nameBegin + 11] & 0xFFL) << 40)
+ ((bytes[nameBegin + 10] & 0xFFL) << 32)
+ ((bytes[nameBegin + 9] & 0xFFL) << 24)
+ ((bytes[nameBegin + 8] & 0xFFL) << 16)
+ ((bytes[nameBegin + 7] & 0xFFL) << 8)
+ (bytes[nameBegin + 6] & 0xFFL);
break;
case 15:
nameValue0
= (((long) bytes[nameBegin + 6]) << 48)
+ ((bytes[nameBegin + 5] & 0xFFL) << 40)
+ ((bytes[nameBegin + 4] & 0xFFL) << 32)
+ ((bytes[nameBegin + 3] & 0xFFL) << 24)
+ ((bytes[nameBegin + 2] & 0xFFL) << 16)
+ ((bytes[nameBegin + 1] & 0xFFL) << 8)
+ (bytes[nameBegin] & 0xFFL);
nameValue1
= (((long) bytes[nameBegin + 14]) << 56)
+ ((bytes[nameBegin + 13] & 0xFFL) << 48)
+ ((bytes[nameBegin + 12] & 0xFFL) << 40)
+ ((bytes[nameBegin + 11] & 0xFFL) << 32)
+ ((bytes[nameBegin + 10] & 0xFFL) << 24)
+ ((bytes[nameBegin + 9] & 0xFFL) << 16)
+ ((bytes[nameBegin + 8] & 0xFFL) << 8)
+ (bytes[nameBegin + 7] & 0xFFL);
break;
case 16:
nameValue0
= (((long) bytes[nameBegin + 7]) << 56)
+ ((bytes[nameBegin + 6] & 0xFFL) << 48)
+ ((bytes[nameBegin + 5] & 0xFFL) << 40)
+ ((bytes[nameBegin + 4] & 0xFFL) << 32)
+ ((bytes[nameBegin + 3] & 0xFFL) << 24)
+ ((bytes[nameBegin + 2] & 0xFFL) << 16)
+ ((bytes[nameBegin + 1] & 0xFFL) << 8)
+ (bytes[nameBegin] & 0xFFL);
nameValue1
= (((long) bytes[nameBegin + 15]) << 56)
+ ((bytes[nameBegin + 14] & 0xFFL) << 48)
+ ((bytes[nameBegin + 13] & 0xFFL) << 40)
+ ((bytes[nameBegin + 12] & 0xFFL) << 32)
+ ((bytes[nameBegin + 11] & 0xFFL) << 24)
+ ((bytes[nameBegin + 10] & 0xFFL) << 16)
+ ((bytes[nameBegin + 9] & 0xFFL) << 8)
+ (bytes[nameBegin + 8] & 0xFFL);
break;
default:
break;
}
if (nameValue0 != -1) {
if (nameValue1 != -1) {
long nameValue01 = nameValue0 ^ nameValue1;
int indexMask = ((int) (nameValue01 ^ (nameValue01 >>> 32))) & (NAME_CACHE2.length - 1);
JSONFactory.NameCacheEntry2 entry = NAME_CACHE2[indexMask];
if (entry == null) {
char[] chars = new char[length];
for (int i = 0; i < length; ++i) {
chars[i] = (char) (bytes[nameBegin + i] & 0xFF);
}
String name = new String(chars);
NAME_CACHE2[indexMask] = new JSONFactory.NameCacheEntry2(name, nameValue0, nameValue1);
return name;
} else if (entry.value0 == nameValue0 && entry.value1 == nameValue1) {
return entry.name;
}
} else {
int indexMask = ((int) (nameValue0 ^ (nameValue0 >>> 32))) & (NAME_CACHE.length - 1);
NameCacheEntry entry = NAME_CACHE[indexMask];
if (entry == null) {
char[] chars = new char[length];
for (int i = 0; i < length; ++i) {
chars[i] = (char) (bytes[nameBegin + i] & 0xFF);
}
String name = new String(chars);
NAME_CACHE[indexMask] = new NameCacheEntry(name, nameValue0);
return name;
} else if (entry.value == nameValue0) {
return entry.name;
}
}
}
}
return getFieldName();
}
@Override
protected void readString0() {
char quote = this.ch;
int start = offset;
int valueLength;
valueEscape = false;
_for:
for (int i = 0; ; ++i) {
int c = bytes[offset];
if (c == '\\') {
valueEscape = true;
c = bytes[++offset];
switch (c) {
case 'u': {
offset += 4;
break;
}
case 'x': {
offset += 2;
break;
}
default:
break;
}
offset++;
continue;
}
if (c == quote) {
valueLength = i;
break _for;
}
offset++;
}
String str;
if (valueEscape) {
char[] chars = new char[valueLength];
offset = start;
for (int i = 0; ; ++i) {
char c = (char) (bytes[offset] & 0xff);
if (c == '\\') {
c = (char) (bytes[++offset]);
switch (c) {
case 'u': {
byte c1 = bytes[++offset];
byte c2 = bytes[++offset];
byte c3 = bytes[++offset];
byte c4 = bytes[++offset];
c = char4(c1, c2, c3, c4);
break;
}
case 'x': {
byte c1 = bytes[++offset];
byte c2 = bytes[++offset];
c = char2(c1, c2);
break;
}
case '\\':
case '"':
break;
default:
c = char1(c);
break;
}
} else if (c == '"') {
break;
}
chars[i] = c;
offset++;
}
str = new String(chars);
} else {
str = getLatin1String(start, this.offset - start);
}
int b = bytes[++offset];
while (b <= ' ' && ((1L << b) & SPACE) != 0) {
b = bytes[++offset];
}
if (comma = (b == ',')) {
this.offset = offset + 1;
next();
} else {
this.offset = offset + 1;
this.ch = (char) b;
}
stringValue = str;
}
@Override
public String readString() {
if (ch == '"' || ch == '\'') {
final byte[] bytes = this.bytes;
final byte quote = (byte) ch;
final byte slash = (byte) '\\';
int offset = this.offset;
final int start = offset, end = this.end;
int valueLength;
boolean valueEscape = false;
_for:
{
int i = 0;
byte c0 = 0, c1 = 0, c2 = 0, c3;
// vector optimize
boolean quoted = false;
int upperBound = offset + ((end - offset) & ~3);
while (offset < upperBound) {
c0 = bytes[offset];
c1 = bytes[offset + 1];
c2 = bytes[offset + 2];
c3 = bytes[offset + 3];
if (c0 == slash || c1 == slash || c2 == slash || c3 == slash) {
break;
}
if (c0 == quote || c1 == quote || c2 == quote || c3 == quote) {
quoted = true;
break;
}
offset += 4;
i += 4;
}
if (quoted) {
if (c0 == quote) {
// skip
} else if (c1 == quote) {
offset++;
i++;
} else if (c2 == quote) {
offset += 2;
i += 2;
} else {
offset += 3;
i += 3;
}
valueLength = i;
} else {
for (; ; ++i) {
if (offset >= end) {
throw new JSONException("invalid escape character EOI");
}
byte c = bytes[offset];
if (c == slash) {
valueEscape = true;
c = bytes[offset + 1];
offset += (c == 'u' ? 6 : (c == 'x' ? 4 : 2));
continue;
}
if (c == quote) {
valueLength = i;
break _for;
}
offset++;
}
}
}
String str;
if (valueEscape) {
char[] chars = this.charBuf;
if (chars == null) {
this.charBuf = chars = CHARS_UPDATER.getAndSet(cacheItem, null);
}
if (chars == null || chars.length < valueLength) {
this.charBuf = chars = new char[valueLength];
}
offset = start;
for (int i = 0; ; ++i) {
char c = (char) (bytes[offset] & 0xff);
if (c == '\\') {
c = (char) bytes[++offset];
switch (c) {
case 'u': {
c = char4(bytes[offset + 1], bytes[offset + 2], bytes[offset + 3], bytes[offset + 4]);
offset += 4;
break;
}
case 'x': {
c = char2(bytes[offset + 1], bytes[offset + 2]);
offset += 2;
break;
}
case '\\':
case '"':
break;
case 'b':
c = '\b';
break;
case 't':
c = '\t';
break;
case 'n':
c = '\n';
break;
case 'f':
c = '\f';
break;
case 'r':
c = '\r';
break;
default:
c = char1(c);
break;
}
} else if (c == quote) {
break;
}
chars[i] = c;
offset++;
}
str = new String(chars, 0, valueLength);
} else {
if (this.str != null) {
str = this.str.substring(start, offset);
} else {
// optimization for android
int strOff = this.offset;
int strlen = offset - strOff;
if (ANDROID_SDK_INT < 34) {
char[] chars = this.charBuf;
if (chars == null) {
this.charBuf = chars = CHARS_UPDATER.getAndSet(cacheItem, null);
}
if (chars == null || chars.length < strlen) {
this.charBuf = chars = new char[strlen];
}
for (int i = 0; i < strlen; i++) {
chars[i] = (char) (bytes[strOff + i] & 0xff);
}
str = new String(chars, 0, strlen);
} else {
str = new String(bytes, strOff, strlen, StandardCharsets.ISO_8859_1);
}
}
}
if ((context.features & Feature.TrimString.mask) != 0) {
str = str.trim();
}
// empty string to null
if (str.isEmpty() && (context.features & Feature.EmptyStringAsNull.mask) != 0) {
str = null;
}
int ch = ++offset == end ? EOI : bytes[offset++];
while (ch <= ' ' && (1L << ch & SPACE) != 0) {
ch = offset == end ? EOI : bytes[offset++];
}
if (comma = ch == ',') {
ch = offset == end ? EOI : bytes[offset++];
while (ch <= ' ' && (1L << ch & SPACE) != 0) {
ch = offset == end ? EOI : bytes[offset++];
}
}
this.ch = (char) (ch & 0xFF);
this.offset = offset;
return str;
}
return readStringNotMatch();
}
}