1 /* 2 * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.io.ByteArrayInputStream; 25 import java.io.InputStream; 26 import java.io.StringReader; 27 import java.io.StringWriter; 28 import java.nio.charset.StandardCharsets; 29 import javax.xml.transform.Transformer; 30 import javax.xml.transform.TransformerException; 31 import javax.xml.transform.TransformerFactory; 32 import javax.xml.transform.stream.StreamResult; 33 import javax.xml.transform.stream.StreamSource; 34 35 import org.testng.Assert; 36 import org.testng.annotations.Listeners; 37 import org.testng.annotations.Test; 38 import java.util.Random; 39 import javax.xml.transform.OutputKeys; 40 import org.testng.annotations.DataProvider; 41 42 /* 43 * @test 44 * @run testng/othervm JDK8207760 45 * @summary Verifies that a surrogate pair at the edge of a buffer is properly handled 46 * @bug 8207760 47 */ 48 public class JDK8207760 { 49 final String xsl8207760 = 50 "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n" + 51 " <xsl:output omit-xml-declaration=\"yes\" indent=\"no\" />\n" + 52 "\n" + 53 " <xsl:template match=\"node()|@*\">\n" + 54 " <xsl:copy>\n" + 55 " <xsl:apply-templates select=\"node()|@*\" />\n" + 56 " </xsl:copy>\n" + 57 " </xsl:template>\n" + 58 "</xsl:stylesheet>\n"; 59 60 final String xsl8207760_2 = "<xsl:stylesheet \n" + 61 " version=\"1.0\" \n" + 62 " xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n" + 63 "\n" + 64 " <xsl:output method=\"xml\" indent=\"no\" cdata-section-elements=\"source\"/>\n" + 65 "\n" + 66 " <xsl:template match=\"source\">\n" + 67 " <xsl:copy>\n" + 68 " <xsl:apply-templates select=\"node()\" />\n" + 69 " </xsl:copy>\n" + 70 " </xsl:template>\n" + 71 "\n" + 72 "</xsl:stylesheet>"; 73 74 final String xsl8207760_3 = "<xsl:stylesheet \n" + 75 " version=\"1.0\" \n" + 76 " xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n" + 77 "\n" + 78 " <xsl:output method=\"xml\" indent=\"no\" cdata-section-elements=\"source\"/>\n" + 79 "\n" + 80 " <xsl:template match=\"source\">\n" + 81 " <xsl:copy>\n" + 82 " <!-- Copy the attributes -->\n" + 83 " <xsl:apply-templates select=\"@*\"/>\n" + 84 " <!-- Convert the contained nodes (elements and text) into text -->\n" + 85 " <xsl:variable name=\"subElementsText\">\n" + 86 " <xsl:apply-templates select=\"node()\"/>\n" + 87 " </xsl:variable>\n" + 88 " <!-- Output the XML directive and the converted nodes -->\n" + 89 " <xsl:value-of select=\"$subElementsText\"/>\n" + 90 " </xsl:copy>\n" + 91 " </xsl:template>\n" + 92 "\n" + 93 "</xsl:stylesheet>"; 94 95 @DataProvider(name = "xsls") 96 public Object[][] getDataBug8207760_cdata() { 97 return new Object[][]{ 98 {xsl8207760_2}, 99 {xsl8207760_3}, 100 }; 101 } 102 103 /* 104 * @bug 8207760 105 * Verifies that a surrogate pair at the edge of a buffer is properly handled 106 * when serializing into a Character section. 107 */ 108 @Test 109 public final void testBug8207760() throws Exception { 110 String[] xmls = prepareXML(false); 111 Transformer t = createTransformerFromInputstream( 112 new ByteArrayInputStream(xsl8207760.getBytes(StandardCharsets.UTF_8))); 113 t.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.name()); 114 StringWriter sw = new StringWriter(); 115 t.transform(new StreamSource(new StringReader(xmls[0])), new StreamResult(sw)); 116 Assert.assertEquals(sw.toString().replaceAll(System.lineSeparator(), "\n"), xmls[1]); 117 } 118 119 /* 120 * @bug 8207760 121 * Verifies that a surrogate pair at the edge of a buffer is properly handled 122 * when serializing into a CDATA section. 123 */ 124 @Test(dataProvider = "xsls") 125 public final void testBug8207760_cdata(String xsl) throws Exception { 126 String[] xmls = prepareXML(true); 127 Transformer t = createTransformerFromInputstream( 128 new ByteArrayInputStream(xsl.getBytes(StandardCharsets.UTF_8))); 129 t.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.name()); 130 StringWriter sw = new StringWriter(); 131 t.transform(new StreamSource(new StringReader(xmls[0])), new StreamResult(sw)); 132 Assert.assertEquals(sw.toString().replaceAll(System.lineSeparator(), "\n"), xmls[1]); 133 } 134 135 private String[] prepareXML(boolean cdata) { 136 String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><source>"; 137 if (cdata) { 138 xml += "<![CDATA["; 139 } 140 String tail = "abc 123 </source>"; 141 if (cdata) { 142 tail = "abc 123 ]]></source>"; 143 } 144 String temp = generateString(1023); 145 xml = xml + temp + '\uD83C' + '\uDF42' + tail; 146 //xml = xml + temp + tail; 147 String expected = (!cdata) ? "<source>" + temp + "🍂" + tail 148 : xml; 149 150 return new String[]{xml, expected}; 151 } 152 153 static final char[] CHARS = "abcdefghijklmnopqrstuvwxyz \n".toCharArray(); 154 StringBuilder sb = new StringBuilder(1024 << 4); 155 Random random = new Random(); 156 157 private String generateString(int size) { 158 sb.setLength(0); 159 for (int i = 0; i < size; i++) { 160 char c = CHARS[random.nextInt(CHARS.length)]; 161 sb.append(c); 162 } 163 164 return sb.toString(); 165 } 166 167 private Transformer createTransformerFromInputstream(InputStream xslStream) 168 throws TransformerException { 169 return TransformerFactory.newInstance().newTransformer(new StreamSource(xslStream)); 170 } 171 }