Skip to content

Commit a4b18fc

Browse files
committed
More efficient parsing and serialization of JSON strings with non-ASCII characters
1 parent 2364570 commit a4b18fc

File tree

6 files changed

+147
-123
lines changed

6 files changed

+147
-123
lines changed

jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala

+35-31
Original file line numberDiff line numberDiff line change
@@ -3549,27 +3549,28 @@ final class JsonReader private[jsoniter_scala](
35493549
if (buf(pos + 6) != '\\') escapeSequenceError(pos + 6)
35503550
if (buf(pos + 7) != 'u') escapeSequenceError(pos + 7)
35513551
val ch2 = readEscapedUnicode(pos + 8, buf)
3552-
if (ch1 >= 0xDC00 || (ch2 & 0xFC00) != 0xDC00) decodeError("illegal surrogate character pair", pos + 11)
35533552
charBuf(i + 1) = ch2
3553+
if (ch1 >= 0xDC00 || (ch2 & 0xFC00) != 0xDC00) decodeError("illegal surrogate character pair", pos + 11)
35543554
parseEncodedString(i + 2, lim, charBuf, pos + 12)
35553555
} else parseEncodedString(i, lim, charBuf, loadMoreOrError(pos))
35563556
} else parseEncodedString(i, lim, charBuf, loadMoreOrError(pos))
35573557
} else parseEncodedString(i, lim, charBuf, loadMoreOrError(pos))
35583558
} else if ((b1 & 0xE0) == 0xC0) { // 110bbbbb 10aaaaaa (UTF-8 bytes) -> 00000bbbbbaaaaaa (UTF-16 char)
35593559
if (remaining > 1) {
35603560
val b2 = buf(pos + 1)
3561-
if ((b1 & 0x1E) == 0 || (b2 & 0xC0) != 0x80) malformedBytesError(b1, b2, pos)
3562-
charBuf(i) = (b1 << 6 ^ b2 ^ 0xF80).toChar // 0xF80 == 0xC0.toByte << 6 ^ 0x80.toByte
3561+
val ch = (b1 << 6 ^ b2 ^ 0xF80).toChar // 0xF80 == 0xC0.toByte << 6 ^ 0x80.toByte
3562+
charBuf(i) = ch
3563+
if ((b2 & 0xC0) != 0x80 || ch < 0x80) malformedBytesError(b1, b2, pos)
35633564
parseEncodedString(i + 1, lim, charBuf, pos + 2)
35643565
} else parseEncodedString(i, lim, charBuf, loadMoreOrError(pos))
35653566
} else if ((b1 & 0xF0) == 0xE0) { // 1110cccc 10bbbbbb 10aaaaaa (UTF-8 bytes) -> ccccbbbbbbaaaaaa (UTF-16 char)
35663567
if (remaining > 2) {
35673568
val b2 = buf(pos + 1)
35683569
val b3 = buf(pos + 2)
3569-
val ch = (b1 << 12 ^ b2 << 6 ^ b3 ^ 0xFFFE1F80).toChar // 0xFFFE1F80 == 0xE0.toByte << 12 ^ 0x80.toByte << 6 ^ 0x80.toByte
3570-
if ((b1 == -32 && (b2 & 0xE0) == 0x80) || (b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 ||
3571-
(ch & 0xF800) == 0xD800) malformedBytesError(b1, b2, b3, pos)
3570+
val ch = (b1 << 12 ^ b2 << 6 ^ b3 ^ 0x1F80).toChar // 0x1F80 == (0x80.toByte << 6 ^ 0x80.toByte).toChar
35723571
charBuf(i) = ch
3572+
if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || ch < 0x800 ||
3573+
(ch & 0xF800) == 0xD800) malformedBytesError(b1, b2, b3, pos)
35733574
parseEncodedString(i + 1, lim, charBuf, pos + 3)
35743575
} else parseEncodedString(i, lim, charBuf, loadMoreOrError(pos))
35753576
} else if ((b1 & 0xF8) == 0xF0) { // 11110ddd 10ddcccc 10bbbbbb 10aaaaaa (UTF-8 bytes) -> 110110uuuuccccbb 110111bbbbaaaaaa (UTF-16 chars), where uuuu = ddddd - 1
@@ -3578,10 +3579,11 @@ final class JsonReader private[jsoniter_scala](
35783579
val b3 = buf(pos + 2)
35793580
val b4 = buf(pos + 3)
35803581
val cp = b1 << 18 ^ b2 << 12 ^ b3 << 6 ^ b4 ^ 0x381F80 // 0x381F80 == 0xF0.toByte << 18 ^ 0x80.toByte << 12 ^ 0x80.toByte << 6 ^ 0x80.toByte
3581-
if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || (b4 & 0xC0) != 0x80 ||
3582-
cp < 0x10000 || cp > 0x10FFFF) malformedBytesError(b1, b2, b3, b4, pos)
3583-
charBuf(i) = ((cp >>> 10) + 0xD7C0).toChar // 0xD7C0 == 0xD800 - (0x10000 >>> 10)
3582+
val ch1 = ((cp >>> 10) + 0xD7C0).toChar // 0xD7C0 == 0xD800 - (0x10000 >>> 10)
3583+
charBuf(i) = ch1
35843584
charBuf(i + 1) = ((cp & 0x3FF) + 0xDC00).toChar
3585+
if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || (b4 & 0xC0) != 0x80 ||
3586+
(ch1 & 0xF800) != 0xD800) malformedBytesError(b1, b2, b3, b4, pos)
35853587
parseEncodedString(i + 2, lim, charBuf, pos + 4)
35863588
} else parseEncodedString(i, lim, charBuf, loadMoreOrError(pos))
35873589
} else malformedBytesError(b1, pos)
@@ -3599,49 +3601,51 @@ final class JsonReader private[jsoniter_scala](
35993601
else if (b1 != '\\') { // 0aaaaaaa (UTF-8 byte) -> 000000000aaaaaaa (UTF-16 char)
36003602
if (b1 < ' ') unescapedControlCharacterError(pos)
36013603
head = pos + 1
3602-
b1.toChar
3604+
return b1.toChar
36033605
} else if (remaining > 1) {
36043606
val b2 = buf(pos + 1)
36053607
if (b2 != 'u') {
36063608
head = pos + 2
36073609
(b2: @switch) match {
3608-
case 'b' => '\b'
3609-
case 'f' => '\f'
3610-
case 'n' => '\n'
3611-
case 'r' => '\r'
3612-
case 't' => '\t'
3613-
case '"' => '"'
3614-
case '/' => '/'
3615-
case '\\' => '\\'
3610+
case 'b' => return '\b'
3611+
case 'f' => return '\f'
3612+
case 'n' => return '\n'
3613+
case 'r' => return '\r'
3614+
case 't' => return '\t'
3615+
case '"' => return '"'
3616+
case '/' => return '/'
3617+
case '\\' => return '\\'
36163618
case _ => escapeSequenceError(pos + 1)
36173619
}
36183620
} else if (remaining > 5) {
36193621
val ch = readEscapedUnicode(pos + 2, buf)
3620-
if ((ch & 0xF800) == 0xD800) surrogateCharacterError(pos + 5)
36213622
head = pos + 6
3622-
ch
3623-
} else parseChar(loadMoreOrError(pos))
3624-
} else parseChar(loadMoreOrError(pos))
3623+
if ((ch & 0xF800) == 0xD800) surrogateCharacterError(pos + 5)
3624+
return ch
3625+
}
3626+
}
36253627
} else if ((b1 & 0xE0) == 0xC0) { // 110bbbbb 10aaaaaa (UTF-8 bytes) -> 00000bbbbbaaaaaa (UTF-16 char)
36263628
if (remaining > 1) {
36273629
val b2 = buf(pos + 1)
3628-
if ((b1 & 0x1E) == 0 || (b2 & 0xC0) != 0x80) malformedBytesError(b1, b2, pos)
3630+
val ch = (b1 << 6 ^ b2 ^ 0xF80).toChar // 0xF80 == 0xC0.toByte << 6 ^ 0x80.toByte
36293631
head = pos + 2
3630-
(b1 << 6 ^ b2 ^ 0xF80).toChar // 0xF80 == 0xC0.toByte << 6 ^ 0x80.toByte
3631-
} else parseChar(loadMoreOrError(pos))
3632+
if ((b2 & 0xC0) != 0x80 || ch < 0x80) malformedBytesError(b1, b2, pos)
3633+
return ch
3634+
}
36323635
} else if ((b1 & 0xF0) == 0xE0) { // 1110cccc 10bbbbbb 10aaaaaa (UTF-8 bytes) -> ccccbbbbbbaaaaaa (UTF-16 char)
36333636
if (remaining > 2) {
36343637
val b2 = buf(pos + 1)
36353638
val b3 = buf(pos + 2)
3636-
val ch = (b1 << 12 ^ b2 << 6 ^ b3 ^ 0xFFFE1F80).toChar // 0xFFFE1F80 == 0xE0.toByte << 12 ^ 0x80.toByte << 6 ^ 0x80.toByte
3637-
if ((b1 == -32 && (b2 & 0xE0) == 0x80) || (b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 ||
3638-
(ch & 0xF800) == 0xD800) malformedBytesError(b1, b2, b3, pos)
3639+
val ch = (b1 << 12 ^ b2 << 6 ^ b3 ^ 0x1F80).toChar // 0x1F80 == (0x80.toByte << 6 ^ 0x80.toByte).toChar
36393640
head = pos + 3
3640-
ch
3641-
} else parseChar(loadMoreOrError(pos))
3641+
if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || ch < 0x800 ||
3642+
(ch & 0xF800) == 0xD800) malformedBytesError(b1, b2, b3, pos)
3643+
return ch
3644+
}
36423645
} else if ((b1 & 0xF8) == 0xF0) surrogateCharacterError(pos + 3)
36433646
else malformedBytesError(b1, pos)
3644-
} else parseChar(loadMoreOrError(pos))
3647+
}
3648+
parseChar(loadMoreOrError(pos))
36453649
}
36463650

36473651
private[this] def readEscapedUnicode(pos: Int, buf: Array[Byte]): Char = {

jsoniter-scala-core/js/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonWriter.scala

+14-10
Original file line numberDiff line numberDiff line change
@@ -1472,15 +1472,17 @@ final class JsonWriter private[jsoniter_scala](
14721472
buf(pos) = (ch1 >> 6 | 0xC0).toByte
14731473
buf(pos + 1) = (ch1 & 0x3F | 0x80).toByte
14741474
writeEncodedString(s, from + 1, to, pos + 2, posLim, escapedChars)
1475-
} else if (ch1 < 0xD800 || ch1 > 0xDFFF) { // ccccbbbbbbaaaaaa (UTF-16 char) -> 1110cccc 10bbbbbb 10aaaaaa (UTF-8 bytes)
1475+
} else if ((ch1 & 0xF800) != 0xD800) { // ccccbbbbbbaaaaaa (UTF-16 char) -> 1110cccc 10bbbbbb 10aaaaaa (UTF-8 bytes)
14761476
buf(pos) = (ch1 >> 12 | 0xE0).toByte
14771477
buf(pos + 1) = (ch1 >> 6 & 0x3F | 0x80).toByte
14781478
buf(pos + 2) = (ch1 & 0x3F | 0x80).toByte
14791479
writeEncodedString(s, from + 1, to, pos + 3, posLim, escapedChars)
14801480
} else { // 110110uuuuccccbb 110111bbbbaaaaaa (UTF-16 chars) -> 11110ddd 10ddcccc 10bbbbbb 10aaaaaa (UTF-8 bytes), where ddddd = uuuu + 1
1481-
if (ch1 >= 0xDC00 || from + 1 >= to) illegalSurrogateError()
1482-
val ch2 = s.charAt(from + 1)
1483-
if ((ch2 & 0xFC00) != 0xDC00) illegalSurrogateError()
1481+
var ch2 = 0
1482+
if (ch1 >= 0xDC00 || from + 1 >= to || {
1483+
ch2 = s.charAt(from + 1).toInt
1484+
(ch2 & 0xFC00) != 0xDC00
1485+
}) illegalSurrogateError()
14841486
val cp = (ch1 << 10) + (ch2 - 56613888) // -56613888 == 0x10000 - (0xD800 << 10) - 0xDC00
14851487
buf(pos) = (cp >> 18 | 0xF0).toByte
14861488
buf(pos + 1) = (cp >> 12 & 0x3F | 0x80).toByte
@@ -1506,12 +1508,14 @@ final class JsonWriter private[jsoniter_scala](
15061508
buf(pos + 1) = esc
15071509
writeEscapedString(s, from + 1, to, pos + 2, posLim, escapedChars)
15081510
} else writeEscapedString(s, from + 1, to, writeEscapedUnicode(ch1.toByte, pos, buf), posLim, escapedChars)
1509-
} else if (ch1 < 0xD800 || ch1 > 0xDFFF) {
1511+
} else if ((ch1 & 0xF800) != 0xD800) {
15101512
writeEscapedString(s, from + 1, to, writeEscapedUnicode(ch1, pos, buf), posLim, escapedChars)
15111513
} else {
1512-
if (ch1 >= 0xDC00 || from + 1 >= to) illegalSurrogateError()
1513-
val ch2 = s.charAt(from + 1).toInt
1514-
if ((ch2 & 0xFC00) != 0xDC00) illegalSurrogateError()
1514+
var ch2 = 0
1515+
if (ch1 >= 0xDC00 || from + 1 >= to || {
1516+
ch2 = s.charAt(from + 1).toInt
1517+
(ch2 & 0xFC00) != 0xDC00
1518+
}) illegalSurrogateError()
15151519
writeEscapedString(s, from + 2, to, writeEscapedUnicode(ch2, writeEscapedUnicode(ch1, pos, buf), buf), posLim, escapedChars)
15161520
}
15171521
}
@@ -1532,13 +1536,13 @@ final class JsonWriter private[jsoniter_scala](
15321536
pos += 2
15331537
} else pos = writeEscapedUnicode(ch.toByte, pos, buf)
15341538
} else if (config.escapeUnicode) {
1535-
if (ch >= 0xD800 && ch <= 0xDFFF) illegalSurrogateError()
1539+
if ((ch & 0xF800) == 0xD800) illegalSurrogateError()
15361540
pos = writeEscapedUnicode(ch, pos, buf)
15371541
} else if (ch < 0x800) { // 00000bbbbbaaaaaa (UTF-16 char) -> 110bbbbb 10aaaaaa (UTF-8 bytes)
15381542
buf(pos) = (ch >> 6 | 0xC0).toByte
15391543
buf(pos + 1) = (ch & 0x3F | 0x80).toByte
15401544
pos += 2
1541-
} else if (ch < 0xD800 || ch > 0xDFFF) { // ccccbbbbbbaaaaaa (UTF-16 char) -> 1110cccc 10bbbbbb 10aaaaaa (UTF-8 bytes)
1545+
} else if ((ch & 0xF800) != 0xD800) { // ccccbbbbbbaaaaaa (UTF-16 char) -> 1110cccc 10bbbbbb 10aaaaaa (UTF-8 bytes)
15421546
buf(pos) = (ch >> 12 | 0xE0).toByte
15431547
buf(pos + 1) = (ch >> 6 & 0x3F | 0x80).toByte
15441548
buf(pos + 2) = (ch & 0x3F | 0x80).toByte

jsoniter-scala-core/jvm/src/main/scala/com/github/plokhotnyuk/jsoniter_scala/core/JsonReader.scala

+35-31
Original file line numberDiff line numberDiff line change
@@ -4014,27 +4014,28 @@ final class JsonReader private[jsoniter_scala](
40144014
if (buf(pos + 6) != '\\') escapeSequenceError(pos + 6)
40154015
if (buf(pos + 7) != 'u') escapeSequenceError(pos + 7)
40164016
val ch2 = readEscapedUnicode(pos + 8, buf)
4017-
if (ch1 >= 0xDC00 || (ch2 & 0xFC00) != 0xDC00) decodeError("illegal surrogate character pair", pos + 11)
40184017
charBuf(i + 1) = ch2
4018+
if (ch1 >= 0xDC00 || (ch2 & 0xFC00) != 0xDC00) decodeError("illegal surrogate character pair", pos + 11)
40194019
parseEncodedString(i + 2, lim, charBuf, pos + 12)
40204020
} else parseEncodedString(i, lim, charBuf, loadMoreOrError(pos))
40214021
} else parseEncodedString(i, lim, charBuf, loadMoreOrError(pos))
40224022
} else parseEncodedString(i, lim, charBuf, loadMoreOrError(pos))
40234023
} else if ((b1 & 0xE0) == 0xC0) { // 110bbbbb 10aaaaaa (UTF-8 bytes) -> 00000bbbbbaaaaaa (UTF-16 char)
40244024
if (remaining > 1) {
40254025
val b2 = buf(pos + 1)
4026-
if ((b1 & 0x1E) == 0 || (b2 & 0xC0) != 0x80) malformedBytesError(b1, b2, pos)
4027-
charBuf(i) = (b1 << 6 ^ b2 ^ 0xF80).toChar // 0xF80 == 0xC0.toByte << 6 ^ 0x80.toByte
4026+
val ch = (b1 << 6 ^ b2 ^ 0xF80).toChar // 0xF80 == 0xC0.toByte << 6 ^ 0x80.toByte
4027+
charBuf(i) = ch
4028+
if ((b2 & 0xC0) != 0x80 || ch < 0x80) malformedBytesError(b1, b2, pos)
40284029
parseEncodedString(i + 1, lim, charBuf, pos + 2)
40294030
} else parseEncodedString(i, lim, charBuf, loadMoreOrError(pos))
40304031
} else if ((b1 & 0xF0) == 0xE0) { // 1110cccc 10bbbbbb 10aaaaaa (UTF-8 bytes) -> ccccbbbbbbaaaaaa (UTF-16 char)
40314032
if (remaining > 2) {
40324033
val b2 = buf(pos + 1)
40334034
val b3 = buf(pos + 2)
4034-
val ch = (b1 << 12 ^ b2 << 6 ^ b3 ^ 0xFFFE1F80).toChar // 0xFFFE1F80 == 0xE0.toByte << 12 ^ 0x80.toByte << 6 ^ 0x80.toByte
4035-
if ((b1 == -32 && (b2 & 0xE0) == 0x80) || (b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 ||
4036-
(ch & 0xF800) == 0xD800) malformedBytesError(b1, b2, b3, pos)
4035+
val ch = (b1 << 12 ^ b2 << 6 ^ b3 ^ 0x1F80).toChar // 0x1F80 == (0x80.toByte << 6 ^ 0x80.toByte).toChar
40374036
charBuf(i) = ch
4037+
if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || ch < 0x800 ||
4038+
(ch & 0xF800) == 0xD800) malformedBytesError(b1, b2, b3, pos)
40384039
parseEncodedString(i + 1, lim, charBuf, pos + 3)
40394040
} else parseEncodedString(i, lim, charBuf, loadMoreOrError(pos))
40404041
} else if ((b1 & 0xF8) == 0xF0) { // 11110ddd 10ddcccc 10bbbbbb 10aaaaaa (UTF-8 bytes) -> 110110uuuuccccbb 110111bbbbaaaaaa (UTF-16 chars), where uuuu = ddddd - 1
@@ -4043,10 +4044,11 @@ final class JsonReader private[jsoniter_scala](
40434044
val b3 = buf(pos + 2)
40444045
val b4 = buf(pos + 3)
40454046
val cp = b1 << 18 ^ b2 << 12 ^ b3 << 6 ^ b4 ^ 0x381F80 // 0x381F80 == 0xF0.toByte << 18 ^ 0x80.toByte << 12 ^ 0x80.toByte << 6 ^ 0x80.toByte
4046-
if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || (b4 & 0xC0) != 0x80 ||
4047-
cp < 0x10000 || cp > 0x10FFFF) malformedBytesError(b1, b2, b3, b4, pos)
4048-
charBuf(i) = ((cp >>> 10) + 0xD7C0).toChar // 0xD7C0 == 0xD800 - (0x10000 >>> 10)
4047+
val ch1 = ((cp >>> 10) + 0xD7C0).toChar // 0xD7C0 == 0xD800 - (0x10000 >>> 10)
4048+
charBuf(i) = ch1
40494049
charBuf(i + 1) = ((cp & 0x3FF) + 0xDC00).toChar
4050+
if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || (b4 & 0xC0) != 0x80 ||
4051+
(ch1 & 0xF800) != 0xD800) malformedBytesError(b1, b2, b3, b4, pos)
40504052
parseEncodedString(i + 2, lim, charBuf, pos + 4)
40514053
} else parseEncodedString(i, lim, charBuf, loadMoreOrError(pos))
40524054
} else malformedBytesError(b1, pos)
@@ -4064,49 +4066,51 @@ final class JsonReader private[jsoniter_scala](
40644066
else if (b1 != '\\') { // 0aaaaaaa (UTF-8 byte) -> 000000000aaaaaaa (UTF-16 char)
40654067
if (b1 < ' ') unescapedControlCharacterError(pos)
40664068
head = pos + 1
4067-
b1.toChar
4069+
return b1.toChar
40684070
} else if (remaining > 1) {
40694071
val b2 = buf(pos + 1)
40704072
if (b2 != 'u') {
40714073
head = pos + 2
40724074
(b2: @switch) match {
4073-
case 'b' => '\b'
4074-
case 'f' => '\f'
4075-
case 'n' => '\n'
4076-
case 'r' => '\r'
4077-
case 't' => '\t'
4078-
case '"' => '"'
4079-
case '/' => '/'
4080-
case '\\' => '\\'
4075+
case 'b' => return '\b'
4076+
case 'f' => return '\f'
4077+
case 'n' => return '\n'
4078+
case 'r' => return '\r'
4079+
case 't' => return '\t'
4080+
case '"' => return '"'
4081+
case '/' => return '/'
4082+
case '\\' => return '\\'
40814083
case _ => escapeSequenceError(pos + 1)
40824084
}
40834085
} else if (remaining > 5) {
40844086
val ch = readEscapedUnicode(pos + 2, buf)
4085-
if ((ch & 0xF800) == 0xD800) surrogateCharacterError(pos + 5)
40864087
head = pos + 6
4087-
ch
4088-
} else parseChar(loadMoreOrError(pos))
4089-
} else parseChar(loadMoreOrError(pos))
4088+
if ((ch & 0xF800) == 0xD800) surrogateCharacterError(pos + 5)
4089+
return ch
4090+
}
4091+
}
40904092
} else if ((b1 & 0xE0) == 0xC0) { // 110bbbbb 10aaaaaa (UTF-8 bytes) -> 00000bbbbbaaaaaa (UTF-16 char)
40914093
if (remaining > 1) {
40924094
val b2 = buf(pos + 1)
4093-
if ((b1 & 0x1E) == 0 || (b2 & 0xC0) != 0x80) malformedBytesError(b1, b2, pos)
4095+
val ch = (b1 << 6 ^ b2 ^ 0xF80).toChar // 0xF80 == 0xC0.toByte << 6 ^ 0x80.toByte
40944096
head = pos + 2
4095-
(b1 << 6 ^ b2 ^ 0xF80).toChar // 0xF80 == 0xC0.toByte << 6 ^ 0x80.toByte
4096-
} else parseChar(loadMoreOrError(pos))
4097+
if ((b2 & 0xC0) != 0x80 || ch < 0x80) malformedBytesError(b1, b2, pos)
4098+
return ch
4099+
}
40974100
} else if ((b1 & 0xF0) == 0xE0) { // 1110cccc 10bbbbbb 10aaaaaa (UTF-8 bytes) -> ccccbbbbbbaaaaaa (UTF-16 char)
40984101
if (remaining > 2) {
40994102
val b2 = buf(pos + 1)
41004103
val b3 = buf(pos + 2)
4101-
val ch = (b1 << 12 ^ b2 << 6 ^ b3 ^ 0xFFFE1F80).toChar // 0xFFFE1F80 == 0xE0.toByte << 12 ^ 0x80.toByte << 6 ^ 0x80.toByte
4102-
if ((b1 == -32 && (b2 & 0xE0) == 0x80) || (b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 ||
4103-
(ch & 0xF800) == 0xD800) malformedBytesError(b1, b2, b3, pos)
4104+
val ch = (b1 << 12 ^ b2 << 6 ^ b3 ^ 0x1F80).toChar // 0x1F80 == (0x80.toByte << 6 ^ 0x80.toByte).toChar
41044105
head = pos + 3
4105-
ch
4106-
} else parseChar(loadMoreOrError(pos))
4106+
if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80 || ch < 0x800 ||
4107+
(ch & 0xF800) == 0xD800) malformedBytesError(b1, b2, b3, pos)
4108+
return ch
4109+
}
41074110
} else if ((b1 & 0xF8) == 0xF0) surrogateCharacterError(pos + 3)
41084111
else malformedBytesError(b1, pos)
4109-
} else parseChar(loadMoreOrError(pos))
4112+
}
4113+
parseChar(loadMoreOrError(pos))
41104114
}
41114115

41124116
private[this] def readEscapedUnicode(pos: Int, buf: Array[Byte]): Char = {

0 commit comments

Comments
 (0)