Compare commits

...

5 Commits

Author SHA1 Message Date
wenshao
c3ab5ab381 code style 2025-01-20 00:32:10 +08:00
wenshao
ff47d668df add comments 2025-01-20 00:27:52 +08:00
wenshao
69836ec2f3 code style 2025-01-20 00:27:13 +08:00
wenshao
17cedf9b85 use getLongUnaligned 2025-01-20 00:24:57 +08:00
wenshao
d6c828e3b1 simplify containsEscaped 2025-01-20 00:16:32 +08:00
3 changed files with 102 additions and 29 deletions

View File

@ -20,7 +20,7 @@ import java.util.UUID;
import static com.alibaba.fastjson2.JSONFactory.*;
import static com.alibaba.fastjson2.JSONWriter.Feature.*;
import static com.alibaba.fastjson2.JSONWriterUTF8.containsEscaped;
import static com.alibaba.fastjson2.JSONWriterUTF8.noneEscaped;
import static com.alibaba.fastjson2.util.IOUtils.*;
import static com.alibaba.fastjson2.util.JDKUtils.*;
import static com.alibaba.fastjson2.util.TypeUtils.*;
@ -75,7 +75,7 @@ class JSONWriterUTF16
chars = new char[8192];
}
this.chars = chars;
this.byteVectorQuote = this.useSingleQuote ? 0x2727_2727_2727_2727L : 0x2222_2222_2222_2222L;
this.byteVectorQuote = this.useSingleQuote ? ~0x2727_2727_2727_2727L : ~0x2222_2222_2222_2222L;
}
public final void writeNull() {
@ -280,12 +280,8 @@ class JSONWriterUTF16
int i = 0;
final long vecQuote = this.byteVectorQuote;
final int upperBound = (value.length - i) & ~7;
for (; i < upperBound; i += 8) {
long vec64 = getLongLE(value, i);
if (containsEscaped(vec64, vecQuote)) {
escape = true;
break;
}
long vec64;
for (; i < upperBound && noneEscaped(vec64 = getLongLE(value, i), vecQuote); i += 8) {
IOUtils.putLongLE(chars, off, expand(vec64));
IOUtils.putLongLE(chars, off + 4, expand(vec64 >>> 32));
off += 8;
@ -372,7 +368,7 @@ class JSONWriterUTF16
if (i + 8 < char_len) {
long v0 = getLongLE(value, i << 1);
long v1 = getLongLE(value, (i + 4) << 1);
if (((v0 | v1) & 0xFF00FF00FF00FF00L) == 0 && !containsEscaped((v0 << 8) | v1, vecQuote)) {
if (((v0 | v1) & 0xFF00FF00FF00FF00L) == 0 && noneEscaped((v0 << 8) | v1, vecQuote)) {
putLongLE(chars, off, v0);
putLongLE(chars, off + 4, v1);
i += 8;
@ -2999,7 +2995,7 @@ class JSONWriterUTF16
if (i + 8 < char_len) {
long v0 = getLongLE(value, i);
long v1 = getLongLE(value, i + 4);
if (((v0 | v1) & 0xFF00FF00FF00FF00L) == 0 && !containsEscaped((v0 << 8) | v1, vecQuote)) {
if (((v0 | v1) & 0xFF00FF00FF00FF00L) == 0 && noneEscaped((v0 << 8) | v1, vecQuote)) {
putLongLE(chars, off, v0);
putLongLE(chars, off + 4, v1);
i += 8;

View File

@ -63,7 +63,7 @@ class JSONWriterUTF8
bytes = new byte[8192];
}
this.bytes = bytes;
this.byteVectorQuote = this.useSingleQuote ? 0x2727_2727_2727_2727L : 0x2222_2222_2222_2222L;
this.byteVectorQuote = this.useSingleQuote ? ~0x2727_2727_2727_2727L : ~0x2222_2222_2222_2222L;
}
public final void writeNull() {
@ -468,7 +468,7 @@ class JSONWriterUTF8
int i = 0;
final int upperBound = (value.length - i) & ~7;
for (; i < upperBound; i += 8) {
if (containsEscaped(IOUtils.getLongLE(value, i), vecQuote)) {
if (!noneEscaped(getLongUnaligned(value, i), vecQuote)) {
break;
}
}
@ -498,24 +498,20 @@ class JSONWriterUTF8
this.off = off + 1;
}
static boolean containsEscaped(long v, long quote) {
static boolean noneEscaped(long v, long quote) {
/*
for (int i = 0; i < 8; ++i) {
byte c = (byte) data;
if (c == quote || c == '\\' || c < ' ') {
return true;
if (c == (byte) quote || c == '\\' || c < ' ') {
return false;
}
data >>>= 8;
}
return false;
return true;
*/
long x22 = v ^ quote; // " -> 0x22, ' -> 0x27
long x5c = v ^ 0x5C5C5C5C5C5C5C5CL;
x22 = (x22 - 0x0101010101010101L) & ~x22;
x5c = (x5c - 0x0101010101010101L) & ~x5c;
return ((x22 | x5c | (0x7F7F7F7F7F7F7F7FL - v + 0x2020202020202020L) | v) & 0x8080808080808080L) != 0;
return ((v + 0x6060606060606060L) & 0x8080808080808080L) == 0x8080808080808080L // all >= 32
&& ((v ^ quote) + 0x0101010101010101L & 0x8080808080808080L) == 0x8080808080808080L // != quote
&& ((v ^ 0xA3A3A3A3A3A3A3A3L) + 0x0101010101010101L & 0x8080808080808080L) == 0x8080808080808080L; // != '\\'
}
protected final void writeStringLatin1BrowserSecure(byte[] values) {

View File

@ -1131,14 +1131,95 @@ public class JSONWriterUTF8Test {
assertEquals("\\u0001", new String(bytes));
}
@Test
public void testSpecial1() {
byte[] buf = new byte[] {'a', 'a', 'a', 'a', 'a', 'a', 'a', 31};
assertEquals("\"aaaaaaa\\u001f\"", new String(JSON.toJSONBytes(new String(buf))));
static boolean containsEscaped(long v, long quote) {
/*
for (int i = 0; i < 8; ++i) {
byte c = (byte) data;
if (c == quote || c == '\\' || c < ' ') {
return true;
}
data >>>= 8;
}
return false;
*/
long x22 = v ^ quote; // " -> 0x22, ' -> 0x27
long x5c = v ^ 0x5C5C5C5C5C5C5C5CL;
x22 = (x22 - 0x0101010101010101L) & ~x22;
x5c = (x5c - 0x0101010101010101L) & ~x5c;
return ((x22 | x5c | (0x7F7F7F7F7F7F7F7FL - v + 0x2020202020202020L) | v) & 0x8080808080808080L) != 0;
}
@Test
public void testSpecial_false() {
long quote = 0x2222_2222_2222_2222L;
byte[] escaped = new byte[32 + 2 + 128];
for (int i = 0; i < 32; i++) {
buf[7] = (byte) i;
assertTrue(JSONWriterUTF8.containsEscaped(IOUtils.getLongUnaligned(buf, 0), 0x2222_2222_2222_2222L));
escaped[i] = (byte) i;
}
escaped[32] = (byte) quote;
escaped[33] = '\\';
for (int i = 0; i < 128; i++) {
escaped[i + 32 + 2] = (byte) (i + 128);
}
byte[] buf = new byte[8];
for (byte c : escaped) {
for (int i = 0; i < 8; i++) {
Arrays.fill(buf, (byte) 'a');
buf[i] = c;
long v = IOUtils.getLongUnaligned(buf, 0);
assertTrue(containsEscaped(v, quote));
assertFalse(JSONWriterUTF8.noneEscaped(v, ~quote));
}
}
quote = 0x2727_2727_2727_2727L;
escaped[32] = (byte) quote;
for (byte c : escaped) {
for (int i = 0; i < 8; i++) {
Arrays.fill(buf, (byte) 'a');
buf[i] = c;
long v = IOUtils.getLongUnaligned(buf, 0);
assertTrue(containsEscaped(v, quote));
assertFalse(JSONWriterUTF8.noneEscaped(v, ~quote));
}
}
}
@Test
public void testSpecial_true() {
long vectorQuote = 0x2222_2222_2222_2222L;
byte quote = (byte) vectorQuote;
byte[] buf = new byte[8];
for (int i = 33; i < 128; i++) {
if (i == quote || i == '\\') {
continue;
}
Arrays.fill(buf, (byte) i);
long v = IOUtils.getLongUnaligned(buf, 0);
assertTrue(JSONWriterUTF8.noneEscaped(v, ~vectorQuote));
assertFalse(containsEscaped(v, vectorQuote));
}
}
@Test
public void testSpecial_true_singleQuote() {
long vectorQuote = 0x2727_2727_2727_2727L;
byte quote = (byte) vectorQuote;
byte[] buf = new byte[8];
for (int i = 33; i < 128; i++) {
if (i == quote || i == '\\') {
continue;
}
Arrays.fill(buf, (byte) i);
long v = IOUtils.getLongUnaligned(buf, 0);
assertTrue(JSONWriterUTF8.noneEscaped(v, ~vectorQuote));
assertFalse(containsEscaped(v, vectorQuote));
}
}
}