diff --git a/src/main/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriter.java b/src/main/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriter.java index e089c5c..cd35289 100644 --- a/src/main/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriter.java +++ b/src/main/java/org/codehaus/plexus/util/xml/PrettyPrintXMLWriter.java @@ -24,9 +24,9 @@ import java.util.regex.Pattern; /** - * Implementation of XMLWriter which emits nicely formatted documents. - * + *

Implementation of XMLWriter which emits nicely formatted documents.

* + *

C0n control characters except \n, \r, and \t are omitted from output

*/ public class PrettyPrintXMLWriter implements XMLWriter { /** Line separator ("\n" on UNIX) */ @@ -186,7 +186,7 @@ private void writeText(String text, boolean escapeXml) { finishTag(); if (escapeXml) { - text = escapeXml(text); + text = escapeXmlText(text); } write(StringUtils.unifyLineSeparators(text, lineSeparator)); @@ -226,10 +226,12 @@ private static String escapeXml(String text) { private static final Pattern crlf = Pattern.compile(crlf_str); - private static final Pattern lowers = Pattern.compile("([\000-\037])"); + private static final Pattern lowers = Pattern.compile("([\\x00-\\x1F])"); + + private static final Pattern illegalC0Characters = Pattern.compile("([\\x00-\\x08\\x0B-\\x0C\\x0E-\\x1F])"); private static String escapeXmlAttribute(String text) { - text = escapeXml(text); + text = escapeXmlText(text); // Windows Matcher crlfmatcher = crlf.matcher(text); @@ -247,6 +249,19 @@ private static String escapeXmlAttribute(String text) { return b.toString(); } + private static String escapeXmlText(String text) { + text = escapeXml(text); + + Matcher matcher = illegalC0Characters.matcher(text); + StringBuffer b = new StringBuffer(); + while (matcher.find()) { + matcher = matcher.appendReplacement(b, ""); + } + matcher.appendTail(b); + + return b.toString(); + } + /** {@inheritDoc} */ @Override public void addAttribute(String key, String value) { diff --git a/src/main/java/org/codehaus/plexus/util/xml/pull/MXSerializer.java b/src/main/java/org/codehaus/plexus/util/xml/pull/MXSerializer.java index e69d28f..ffd0ede 100644 --- a/src/main/java/org/codehaus/plexus/util/xml/pull/MXSerializer.java +++ b/src/main/java/org/codehaus/plexus/util/xml/pull/MXSerializer.java @@ -24,6 +24,7 @@ *
  • PROPERTY_SERIALIZER_INDENTATION *
  • PROPERTY_SERIALIZER_LINE_SEPARATOR * + *

    C0n control characters except \n, \r, and \t are omitted from output

    */ public class MXSerializer implements XmlSerializer { protected static final String XML_URI = "http://www.w3.org/XML/1998/namespace"; @@ -943,19 +944,9 @@ protected void writeElementContent(String text, Writer out) throws IOException { // out.write(';'); // pos = i + 1; } else { - throw new IllegalStateException( - "character " + Integer.toString(ch) + " is not allowed in output" + getLocation()); - // in XML 1.1 legal are [#x1-#xD7FF] - // if(ch > 0) { - // if(i > pos) out.write(text.substring(pos, i)); - // out.write("&#"); - // out.write(Integer.toString(ch)); - // out.write(';'); - // pos = i + 1; - // } else { - // throw new IllegalStateException( - // "character zero is not allowed in XML 1.1 output"+getLocation()); - // } + // skip special char + if (i > pos) out.write(text.substring(pos, i)); + pos = i + 1; } } if (seenBracket) { diff --git a/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomWriterTest.java b/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomWriterTest.java index 7f7f321..233bdd5 100644 --- a/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomWriterTest.java +++ b/src/test/java/org/codehaus/plexus/util/xml/Xpp3DomWriterTest.java @@ -82,6 +82,12 @@ private String createExpectedXML(boolean escape) { buf.append(LS); buf.append(" "); buf.append(LS); + if (escape) { + buf.append(" special-char-"); + } else { + buf.append(" special-char-" + (char) 7 + ""); + } + buf.append(LS); buf.append(""); return buf.toString(); @@ -95,7 +101,7 @@ private Xpp3Dom createXpp3Dom() { dom.addChild(el1); Xpp3Dom el2 = new Xpp3Dom("el2"); - el2.setAttribute("att2", "attribute2\nnextline"); + el2.setAttribute("att2", "attribute2\nnextline" + (char) 7); dom.addChild(el2); Xpp3Dom el3 = new Xpp3Dom("el3"); @@ -119,6 +125,10 @@ private Xpp3Dom createXpp3Dom() { el7.setValue("element7\n&\"\'<>"); el6.addChild(el7); + Xpp3Dom el8 = new Xpp3Dom("el8"); + el8.setValue("special-char-" + (char) 7); + + dom.addChild(el8); return dom; } } diff --git a/src/test/java/org/codehaus/plexus/util/xml/pull/MXSerializerTest.java b/src/test/java/org/codehaus/plexus/util/xml/pull/MXSerializerTest.java new file mode 100644 index 0000000..8b66c23 --- /dev/null +++ b/src/test/java/org/codehaus/plexus/util/xml/pull/MXSerializerTest.java @@ -0,0 +1,58 @@ +package org.codehaus.plexus.util.xml.pull; + +import java.io.StringReader; +import java.io.StringWriter; +import java.util.Arrays; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class MXSerializerTest { + + @Test + void testSerialize() throws Exception { + + StringWriter writer = new StringWriter(); + + MXSerializer sr = new MXSerializer(); + sr.setOutput(writer); + + sr.startDocument(null, Boolean.TRUE); + sr.startTag(null, "root"); + for (int i : Arrays.asList(8, 9, 10, 11, 13, 15)) { + sr.startTag(null, "char"); + sr.text(Character.getName(i) + ": " + ((char) i)); + sr.endTag(null, "char"); + } + + sr.endTag(null, "root"); + sr.endDocument(); + assertEquals(expectedOutput(), writer.toString()); + } + + @Test + void testDeserialize() throws Exception { + MXParser parser = new MXParser(); + parser.setInput(new StringReader(expectedOutput())); + int eventType = parser.getEventType(); + + while (eventType != XmlPullParser.END_DOCUMENT) { + eventType = parser.next(); + } + } + + private String expectedOutput() { + StringBuilder out = new StringBuilder(); + out.append(""); + out.append(""); + out.append("BACKSPACE: "); + out.append("CHARACTER TABULATION: \t"); + out.append("LINE FEED (LF): \n"); + out.append("LINE TABULATION: "); + out.append("CARRIAGE RETURN (CR): \r"); + out.append("SHIFT IN: "); + out.append(""); + return out.toString(); + } +}