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]

Reply via email to