Skip to content

Commit 0add567

Browse files
nkuprinsalaahongCopilotdelei
authored
refactor: simplify hex escape pattern scanning (#1003)
* refactor: optimize pattern matching and avoid unnecessary allocations * refactor: extract pattern offset constants * refactor: simplify hex escape scanning * chore: update the comment Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * refactor: extract escaped prefix constant --------- Co-authored-by: ian zhang <ian.zhangzhe@gmail.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: DeleiGuo <delei@apache.org>
1 parent e120395 commit 0add567

1 file changed

Lines changed: 42 additions & 72 deletions

File tree

fesod-sheet/src/main/java/org/apache/fesod/sheet/write/handler/EscapeHexCellWriteHandler.java

Lines changed: 42 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,21 @@
3838
*/
3939
public class EscapeHexCellWriteHandler implements CellWriteHandler {
4040

41+
// ASCII hex digits only. Not Character.digit(c, 16), which also accepts non-ASCII
42+
// digits such as U+0663 that OOXML never uses.
43+
private static final boolean[] HEX_TABLE = new boolean[128];
44+
45+
static {
46+
for (char c = '0'; c <= '9'; c++) HEX_TABLE[c] = true;
47+
for (char c = 'A'; c <= 'F'; c++) HEX_TABLE[c] = true;
48+
for (char c = 'a'; c <= 'f'; c++) HEX_TABLE[c] = true;
49+
}
50+
51+
private static final String PREFIX = "_x";
52+
private static final String ESCAPED_PREFIX = "_x005F" + PREFIX;
53+
private static final int PREFIX_LENGTH = PREFIX.length();
54+
private static final int HEX_DIGIT_COUNT = 4;
55+
4156
@Override
4257
public void afterCellDataConverted(
4358
WriteSheetHolder writeSheetHolder,
@@ -57,101 +72,56 @@ public void afterCellDataConverted(
5772
}
5873
}
5974

60-
// Static hex lookup table for O(1) character validation
61-
private static final boolean[] HEX_TABLE = new boolean[128];
62-
63-
static {
64-
for (char c = '0'; c <= '9'; c++) HEX_TABLE[c] = true;
65-
for (char c = 'A'; c <= 'F'; c++) HEX_TABLE[c] = true;
66-
for (char c = 'a'; c <= 'f'; c++) HEX_TABLE[c] = true;
67-
}
68-
6975
/**
70-
* Escapes hexadecimal-encoded strings with optimized performance Replaces _xHHHH_ with _x005F_xHHHH_ to prevent POI
71-
* from decoding them
76+
* Replaces every _xHHHH_ sequence with _x005F_xHHHH_ to prevent POI from decoding them.
7277
*/
7378
private String escapeHex(String originalString) {
7479
int length = originalString.length();
7580

76-
// Fast path: if string is too short to contain pattern, return original
77-
if (length < 7) {
78-
return originalString;
79-
}
80-
81-
// Fast path: search for first potential pattern
81+
// Lazily allocated: stays null (no allocation) when no valid pattern is found
82+
StringBuilder result = null;
83+
int lastEnd = 0;
8284
int searchStart = 0;
8385
int patternIndex;
84-
while ((patternIndex = originalString.indexOf("_x", searchStart)) != -1) {
85-
// Check if we have enough characters for full pattern
86-
if (patternIndex + 6 >= length) {
86+
while ((patternIndex = originalString.indexOf(PREFIX, searchStart)) != -1) {
87+
int hexStart = patternIndex + PREFIX_LENGTH;
88+
int suffixIndex = hexStart + HEX_DIGIT_COUNT;
89+
int patternEnd = suffixIndex + 1;
90+
// Too few characters left for a full pattern, and any later match has even fewer
91+
if (patternEnd > length) {
8792
break;
8893
}
8994

90-
// Quick validation: check if it ends with '_' and has valid hex
91-
if (originalString.charAt(patternIndex + 6) == '_' && isValidHexFast(originalString, patternIndex + 2)) {
92-
93-
// Found at least one pattern, proceed with full processing
94-
return processWithPatterns(originalString, patternIndex);
95-
}
96-
97-
searchStart = patternIndex + 2;
98-
}
99-
100-
// No valid patterns found
101-
return originalString;
102-
}
103-
104-
/**
105-
* Process string when we know it contains at least one valid pattern
106-
*/
107-
private String processWithPatterns(String originalString, int firstPatternIndex) {
108-
int length = originalString.length();
109-
StringBuilder result = new StringBuilder(length + 64); // More generous pre-allocation
110-
int lastEnd;
111-
112-
// Process the first known pattern
113-
result.append(originalString, 0, firstPatternIndex);
114-
result.append("_x005F_x");
115-
result.append(originalString, firstPatternIndex + 2, firstPatternIndex + 6);
116-
result.append('_');
117-
lastEnd = firstPatternIndex + 7;
118-
119-
// Continue searching for more patterns
120-
int searchStart = firstPatternIndex + 7;
121-
int patternIndex;
122-
while ((patternIndex = originalString.indexOf("_x", searchStart)) != -1) {
123-
if (patternIndex + 6 >= length) {
124-
break;
125-
}
126-
127-
if (originalString.charAt(patternIndex + 6) == '_' && isValidHexFast(originalString, patternIndex + 2)) {
128-
129-
// Append content between patterns
95+
if (originalString.charAt(suffixIndex) == '_' && isHexDigits(originalString, hexStart)) {
96+
if (result == null) {
97+
result = new StringBuilder(length + 64);
98+
}
99+
// Append content since the previous match, then the escaped pattern
130100
result.append(originalString, lastEnd, patternIndex);
131-
// Append escaped pattern
132-
result.append("_x005F_x");
133-
result.append(originalString, patternIndex + 2, patternIndex + 6);
101+
result.append(ESCAPED_PREFIX);
102+
result.append(originalString, hexStart, suffixIndex);
134103
result.append('_');
135-
lastEnd = patternIndex + 7;
136-
searchStart = patternIndex + 7;
104+
lastEnd = patternEnd;
105+
searchStart = patternEnd;
137106
} else {
138-
searchStart = patternIndex + 2;
107+
searchStart = hexStart;
139108
}
140109
}
141110

142-
// Append remaining content
143-
if (lastEnd < length) {
144-
result.append(originalString, lastEnd, length);
111+
// No valid patterns found
112+
if (result == null) {
113+
return originalString;
145114
}
146115

116+
result.append(originalString, lastEnd, length);
147117
return result.toString();
148118
}
149119

150120
/**
151-
* Fast hex validation using lookup table - O(1) per character
121+
* Checks whether the four characters starting at {@code startIndex} are all ASCII hex digits.
152122
*/
153-
private static boolean isValidHexFast(String str, int startIndex) {
154-
for (int i = 0; i < 4; i++) {
123+
private static boolean isHexDigits(String str, int startIndex) {
124+
for (int i = 0; i < HEX_DIGIT_COUNT; i++) {
155125
char c = str.charAt(startIndex + i);
156126
if (c >= 128 || !HEX_TABLE[c]) {
157127
return false;

0 commit comments

Comments
 (0)