in core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF8.java [4902:5145]
public String readString() {
char quote = this.ch;
if (quote == '"' || quote == '\'') {
final byte[] bytes = this.bytes;
int valueLength;
int offset = this.offset;
final int start = offset, end = this.end;
final long byteVectorQuote = quote == '\'' ? 0x2727_2727_2727_2727L : 0x2222_2222_2222_2222L;
boolean ascii = true;
valueEscape = false;
{
int i = 0;
int upperBound = offset + ((end - offset) & ~7);
while (offset < upperBound) {
long v = getLongLE(bytes, offset);
if ((v & 0x8080808080808080L) != 0 || JSONReaderUTF8.containsSlashOrQuote(v, byteVectorQuote)) {
break;
}
offset += 8;
i += 8;
}
// ...
for (; ; ++i) {
if (offset >= end) {
throw new JSONException("invalid escape character EOI");
}
int c = bytes[offset];
if (c == '\\') {
valueEscape = true;
c = bytes[offset + 1];
offset += (c == 'u' ? 6 : (c == 'x' ? 4 : 2));
if (ascii && (c == 'u' || c == 'x')) {
ascii = false;
}
continue;
}
if (c >= 0) {
if (c == quote) {
valueLength = i;
break;
}
offset++;
} else {
ascii = false;
switch ((c & 0xFF) >> 4) {
case 12:
case 13: {
/* 110x xxxx 10xx xxxx*/
offset += 2;
break;
}
case 14: {
offset += 3;
break;
}
default: {
/* 10xx xxxx, 1111 xxxx */
if ((c >> 3) == -2) {
offset += 4;
i++;
break;
}
throw new JSONException("malformed input around byte " + offset);
}
}
}
}
}
String str;
if (valueEscape) {
if (ascii && STRING_CREATOR_JDK11 != null) {
byte[] chars = new byte[valueLength];
offset = start;
for (int i = 0; ; ++i) {
byte ch = bytes[offset];
if (ch == '\\') {
ch = bytes[++offset];
switch (ch) {
case '\\':
case '"':
break;
case 'b':
ch = '\b';
break;
case 't':
ch = '\t';
break;
case 'n':
ch = '\n';
break;
case 'f':
ch = '\f';
break;
case 'r':
ch = '\r';
break;
default:
ch = (byte) char1(ch);
break;
}
}
else if (ch == quote) {
break;
}
chars[i] = ch;
offset++;
}
str = STRING_CREATOR_JDK11.apply(chars, LATIN1);
} else {
char[] chars = new char[valueLength];
offset = start;
for (int i = 0; ; ++i) {
int ch = bytes[offset];
if (ch == '\\') {
ch = bytes[++offset];
switch (ch) {
case 'u': {
ch = hexDigit4(bytes, check3(offset + 1, end));
offset += 4;
break;
}
case 'x': {
ch = char2(bytes[offset + 1], bytes[offset + 2]);
offset += 2;
break;
}
case '\\':
case '"':
break;
case 'b':
ch = '\b';
break;
case 't':
ch = '\t';
break;
case 'n':
ch = '\n';
break;
case 'f':
ch = '\f';
break;
case 'r':
ch = '\r';
break;
default:
ch = char1(ch);
break;
}
chars[i] = (char) ch;
offset++;
}
else if (ch == quote) {
break;
}
else {
if (ch >= 0) {
chars[i] = (char) ch;
offset++;
}
else {
switch ((ch & 0xFF) >> 4) {
case 12:
case 13: {
/* 110x xxxx 10xx xxxx*/
chars[i] = (char) (((ch & 0x1F) << 6) | (bytes[offset + 1] & 0x3F));
offset += 2;
break;
}
case 14: {
chars[i] = (char)
(((ch & 0x0F) << 12) |
((bytes[offset + 1] & 0x3F) << 6) |
((bytes[offset + 2] & 0x3F) << 0));
offset += 3;
break;
}
default: {
/* 10xx xxxx, 1111 xxxx */
char2_utf8(bytes, offset, ch, chars, i);
offset += 4;
i++;
}
}
}
}
}
str = new String(chars);
}
} else if (ascii) {
int strlen = offset - start;
if (strlen == 1) {
str = TypeUtils.toString((char) (bytes[start] & 0xff));
} else if (strlen == 2) {
str = TypeUtils.toString(
(char) (bytes[start] & 0xff),
(char) (bytes[start + 1] & 0xff)
);
} else if (STRING_CREATOR_JDK11 != null) {
str = STRING_CREATOR_JDK11.apply(
Arrays.copyOfRange(this.bytes, this.offset, offset),
LATIN1);
} else {
str = new String(bytes, start, offset - start, StandardCharsets.US_ASCII);
}
} else {
str = new String(bytes, start, offset - start, StandardCharsets.UTF_8);
}
long features = context.features;
if ((features & (MASK_TRIM_STRING | MASK_EMPTY_STRING_AS_NULL)) != 0) {
str = stringValue(str, features);
}
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;
this.offset = offset;
return str;
} else if (quote == 'n') {
readNull();
return null;
}
return readStringNotMatch();
}