Author: fanningpj
Date: Thu Jun 18 19:55:46 2026
New Revision: 1935483
Log:
thread question-mark state across pi text chunks. Thanks to aizu-m. This closes
#60
Modified:
xmlbeans/trunk/src/main/java/org/apache/xmlbeans/impl/store/Saver.java
xmlbeans/trunk/src/test/java/misc/checkin/SaveOptimizeForSpeedTest.java
Modified: xmlbeans/trunk/src/main/java/org/apache/xmlbeans/impl/store/Saver.java
==============================================================================
--- xmlbeans/trunk/src/main/java/org/apache/xmlbeans/impl/store/Saver.java
Thu Jun 18 18:33:42 2026 (r1935482)
+++ xmlbeans/trunk/src/main/java/org/apache/xmlbeans/impl/store/Saver.java
Thu Jun 18 19:55:46 2026 (r1935483)
@@ -2089,10 +2089,11 @@ abstract class Saver {
int cch = c._cchSrc;
int off = c._offSrc;
int index = 0;
+ boolean lastWasQuestion = false;
while (index < cch) {
int indexLimit = Math.min(index + 512, cch);
CharUtil.getChars(_buf, 0, src, off + index, indexLimit -
index);
- entitizeAndWritePIText(indexLimit - index);
+ lastWasQuestion = entitizeAndWritePIText(indexLimit - index,
lastWasQuestion);
index = indexLimit;
}
}
@@ -2164,9 +2165,7 @@ abstract class Saver {
emit(_buf, 0, bufLimit);
}
- private void entitizeAndWritePIText(int bufLimit) {
- boolean lastWasQuestion = false;
-
+ private boolean entitizeAndWritePIText(int bufLimit, boolean
lastWasQuestion) {
for (int i = 0; i < bufLimit; i++) {
char ch = _buf[i];
@@ -2187,6 +2186,7 @@ abstract class Saver {
}
}
emit(_buf, 0, bufLimit);
+ return lastWasQuestion;
}
}
Modified:
xmlbeans/trunk/src/test/java/misc/checkin/SaveOptimizeForSpeedTest.java
==============================================================================
--- xmlbeans/trunk/src/test/java/misc/checkin/SaveOptimizeForSpeedTest.java
Thu Jun 18 18:33:42 2026 (r1935482)
+++ xmlbeans/trunk/src/test/java/misc/checkin/SaveOptimizeForSpeedTest.java
Thu Jun 18 19:55:46 2026 (r1935483)
@@ -15,6 +15,7 @@
package misc.checkin;
+import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.junit.jupiter.api.Test;
@@ -23,6 +24,7 @@ import java.io.StringWriter;
import java.time.Duration;
import java.util.Arrays;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -63,4 +65,23 @@ public class SaveOptimizeForSpeedTest {
XmlObject.Factory.parse(out);
assertTrue(out.contains(LONG));
}
+
+ @Test
+ void testProcInstTerminatorAcrossChunkBoundary() throws Exception {
+ // a '?>' that straddles the 512-char chunk boundary: '?' is the last
char
+ // of the first chunk, '>' the first char of the second. The per-chunk
+ // question-mark state used to reset between chunks, so the '>'
escaped the
+ // processing instruction and the trailing text broke out of the pi.
+ String data = repeat('x', 511) + "?>" + repeat('y', 600);
+ XmlObject o = XmlObject.Factory.parse("<root>z</root>");
+ try (XmlCursor cur = o.newCursor()) {
+ cur.toFirstChild();
+ cur.toFirstContentToken();
+ cur.insertProcInst("tgt", data);
+ }
+ String out = saveForSpeed(o);
+ assertFalse(out.contains("?>" + repeat('y', 600)));
+ // breakout produced text that is not allowed where the pi sat, so
this throws before the fix
+ XmlObject.Factory.parse(out);
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]