Author: fanningpj
Date: Wed Jun 17 20:20:27 2026
New Revision: 1935461

Log:
fix pi terminator breakout after bad char in entitizeProcinst. Thanks to 
aizu-m. This closes #54

Added:
   xmlbeans/trunk/src/test/java/misc/checkin/ProcInstEscapeTest.java
Modified:
   xmlbeans/trunk/src/main/java/org/apache/xmlbeans/impl/store/Saver.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      
Wed Jun 17 20:11:31 2026        (r1935460)
+++ xmlbeans/trunk/src/main/java/org/apache/xmlbeans/impl/store/Saver.java      
Wed Jun 17 20:20:27 2026        (r1935461)
@@ -547,7 +547,7 @@ abstract class Saver {
     }
 
     private void addNewFrameMapping(String prefix, String uri, boolean 
ensureDefaultEmpty) {
-        // If the prefix maps to "", then don't include this mapping 'cause 
it's not well formed.
+        // If the prefix maps to "", then don't include this mapping 'cause 
it's not well-formed.
         // Also, if we want to make sure that the default namespace is always 
"", then check that
         // here as well.
 
@@ -562,7 +562,7 @@ abstract class Saver {
             }
 
             // Also make sure that the prefix declaration is not redundant
-            // This has the side-effect of making it impossible to set a
+            // This has the side effect of making it impossible to set a
             // redundant prefix declaration, but seems that it's better
             // to just never issue a duplicate prefix declaration.
             if (uri.equals(getNamespaceForPrefix(prefix))) {
@@ -1413,7 +1413,7 @@ abstract class Saver {
                     i = replace(i, "?");
                 } else if (ch == '-') {
                     if (lastWasDash) {
-                        // Replace "--" with "- " to make well formed
+                        // Replace "--" with "- " to make well-formed
                         i = replace(i, " ");
                         lastWasDash = false;
                     } else {
@@ -1452,11 +1452,12 @@ abstract class Saver {
                 char ch = _cbuf[i];
 
                 if (isBadChar(ch)) {
-                    i = replace(i, "?");
+                    replace(i, "?");
+                    ch = '?';
                 }
 
                 if (ch == '>') {
-                    // TODO - Had to convert to a space here ... imples not 
well formed XML
+                    // TODO - Had to convert to a space here ... implies not 
well-formed XML
                     if (lastWasQuestion) {
                         i = replace(i, " ");
                     } else {
@@ -2141,7 +2142,7 @@ abstract class Saver {
                     _buf[i] = '?';
                 } else if (ch == '-') {
                     if (lastWasDash) {
-                        // Replace "--" with "- " to make well formed
+                        // Replace "--" with "- " to make well-formed
                         _buf[i] = ' ';
                         lastWasDash = false;
                     } else {
@@ -2175,7 +2176,7 @@ abstract class Saver {
                 }
 
                 if (ch == '>') {
-                    // Had to convert to a space here ... imples not well 
formed XML
+                    // Had to convert to a space here ... implies not 
well-formed XML
                     if (lastWasQuestion) {
                         _buf[i] = ' ';
                     }

Added: xmlbeans/trunk/src/test/java/misc/checkin/ProcInstEscapeTest.java
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ xmlbeans/trunk/src/test/java/misc/checkin/ProcInstEscapeTest.java   Wed Jun 
17 20:20:27 2026        (r1935461)
@@ -0,0 +1,67 @@
+/*   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package misc.checkin;
+
+import org.apache.xmlbeans.XmlCursor;
+import org.apache.xmlbeans.XmlObject;
+import org.apache.xmlbeans.XmlOptions;
+import org.junit.jupiter.api.Test;
+
+import java.io.StringWriter;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+public class ProcInstEscapeTest {
+
+    private static XmlObject docWithProcInst(String piText) throws Exception {
+        XmlObject o = XmlObject.Factory.parse("<root>x</root>");
+        try (XmlCursor c = o.newCursor()) {
+            c.toNextToken();
+            c.toNextToken();
+            c.insertProcInst("tgt", piText);
+        }
+        return o;
+    }
+
+    private static String saveForSpeed(XmlObject o) throws Exception {
+        XmlOptions opts = new XmlOptions();
+        opts.setSaveOptimizeForSpeed(true);
+        StringWriter sw = new StringWriter();
+        o.save(sw, opts);
+        return sw.toString();
+    }
+
+    // a bad char immediately before "?>" used to make the default saver skip 
the
+    // "?>" so it survived inside the processing instruction
+    @Test
+    void testBadCharBeforePiEnd() throws Exception {
+        XmlObject o = docWithProcInst("\u0007?>");
+        String out = o.xmlText();
+        assertEquals("<root><?tgt ?? ?>x</root>", out);
+        // the only "?>" in the output is the PI terminator
+        assertFalse(out.substring(0, out.indexOf("?>x")).contains("?>"));
+        // round-trips and both savers agree
+        XmlObject.Factory.parse(out);
+        assertEquals(out, saveForSpeed(o));
+    }
+
+    @Test
+    void testPlainQuestionGtStillEscaped() throws Exception {
+        XmlObject o = docWithProcInst("a?>b");
+        assertEquals("<root><?tgt a? b?>x</root>", o.xmlText());
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to