1 /*
2  * Copyright (c) 2018, 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 package transform;
25 
26 import java.io.ByteArrayInputStream;
27 import java.io.InputStream;
28 import java.io.StringReader;
29 import java.io.StringWriter;
30 import java.nio.charset.StandardCharsets;
31 import javax.xml.transform.Transformer;
32 import javax.xml.transform.TransformerException;
33 import javax.xml.transform.TransformerFactory;
34 import javax.xml.transform.stream.StreamResult;
35 import javax.xml.transform.stream.StreamSource;
36 
37 import org.testng.Assert;
38 import org.testng.annotations.Listeners;
39 import org.testng.annotations.Test;
40 import java.util.Random;
41 import javax.xml.transform.OutputKeys;
42 import org.testng.annotations.DataProvider;
43 
44 /*
45  * @test
46  * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
47  * @run testng/othervm transform.JDK8207760
48  * @summary Verifies that a surrogate pair at the edge of a buffer is properly handled
49  * @bug 8207760
50  */
51 @Listeners({jaxp.library.FilePolicy.class})
52 public class JDK8207760 {
53     final String xsl8207760 =
54         "<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n" +
55         "    <xsl:output omit-xml-declaration=\"yes\" indent=\"no\" />\n" +
56         "\n" +
57         "    <xsl:template match=\"node()|@*\">\n" +
58         "        <xsl:copy>\n" +
59         "            <xsl:apply-templates select=\"node()|@*\" />\n" +
60         "        </xsl:copy>\n" +
61         "    </xsl:template>\n" +
62         "</xsl:stylesheet>\n";
63 
64     final String xsl8207760_2 = "<xsl:stylesheet \n" +
65         "  version=\"1.0\" \n" +
66         "  xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n" +
67         "\n" +
68         "  <xsl:output method=\"xml\" indent=\"no\" cdata-section-elements=\"source\"/>\n" +
69         "\n" +
70         "  <xsl:template match=\"source\">\n" +
71                 "        <xsl:copy>\n" +
72                 "            <xsl:apply-templates select=\"node()\" />\n" +
73                 "        </xsl:copy>\n" +
74         "  </xsl:template>\n" +
75         "\n" +
76         "</xsl:stylesheet>";
77 
78     final String xsl8207760_3 = "<xsl:stylesheet \n" +
79         "  version=\"1.0\" \n" +
80         "  xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n" +
81         "\n" +
82         "  <xsl:output method=\"xml\" indent=\"no\" cdata-section-elements=\"source\"/>\n" +
83         "\n" +
84         "  <xsl:template match=\"source\">\n" +
85         "    <xsl:copy>\n" +
86         "      <!-- Copy the attributes -->\n" +
87         "      <xsl:apply-templates select=\"@*\"/>\n" +
88         "      <!-- Convert the contained nodes (elements and text) into text -->\n" +
89         "      <xsl:variable name=\"subElementsText\">\n" +
90         "        <xsl:apply-templates select=\"node()\"/>\n" +
91         "      </xsl:variable>\n" +
92         "      <!-- Output the XML directive and the converted nodes -->\n" +
93         "      <xsl:value-of select=\"$subElementsText\"/>\n" +
94         "    </xsl:copy>\n" +
95         "  </xsl:template>\n" +
96         "\n" +
97         "</xsl:stylesheet>";
98 
99     @DataProvider(name = "xsls")
getDataBug8207760_cdata()100     public Object[][] getDataBug8207760_cdata() {
101         return new Object[][]{
102             {xsl8207760_2},
103             {xsl8207760_3},
104         };
105     }
106 
107     /*
108      * @bug 8207760
109      * Verifies that a surrogate pair at the edge of a buffer is properly handled
110      * when serializing into a Character section.
111      */
112     @Test
testBug8207760()113     public final void testBug8207760() throws Exception {
114         String[] xmls = prepareXML(false);
115         Transformer t = createTransformerFromInputstream(
116                 new ByteArrayInputStream(xsl8207760.getBytes(StandardCharsets.UTF_8)));
117         t.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.name());
118         StringWriter sw = new StringWriter();
119         t.transform(new StreamSource(new StringReader(xmls[0])), new StreamResult(sw));
120         Assert.assertEquals(sw.toString().replaceAll(System.lineSeparator(), "\n"), xmls[1]);
121     }
122 
123     /*
124      * @bug 8207760
125      * Verifies that a surrogate pair at the edge of a buffer is properly handled
126      * when serializing into a CDATA section.
127      */
128     @Test(dataProvider = "xsls")
testBug8207760_cdata(String xsl)129     public final void testBug8207760_cdata(String xsl) throws Exception {
130         String[] xmls = prepareXML(true);
131         Transformer t = createTransformerFromInputstream(
132                 new ByteArrayInputStream(xsl.getBytes(StandardCharsets.UTF_8)));
133         t.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.name());
134         StringWriter sw = new StringWriter();
135         t.transform(new StreamSource(new StringReader(xmls[0])), new StreamResult(sw));
136         Assert.assertEquals(sw.toString().replaceAll(System.lineSeparator(), "\n"), xmls[1]);
137     }
138 
prepareXML(boolean cdata)139     private String[] prepareXML(boolean cdata) {
140         String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><source>";
141         if (cdata) {
142             xml += "<![CDATA[";
143         }
144         String tail = "abc 123 </source>";
145         if (cdata) {
146             tail = "abc 123 ]]></source>";
147         }
148         String temp = generateString(1023);
149         xml = xml + temp + '\uD83C' + '\uDF42' + tail;
150         //xml = xml + temp + tail;
151         String expected = (!cdata) ? "<source>" + temp + "&#127810;" + tail
152                 : xml;
153 
154         return new String[]{xml, expected};
155     }
156 
157     static final char[] CHARS = "abcdefghijklmnopqrstuvwxyz \n".toCharArray();
158     StringBuilder sb = new StringBuilder(1024 << 4);
159     Random random = new Random();
160 
generateString(int size)161     private String generateString(int size) {
162         sb.setLength(0);
163         for (int i = 0; i < size; i++) {
164             char c = CHARS[random.nextInt(CHARS.length)];
165             sb.append(c);
166         }
167 
168         return sb.toString();
169     }
170 
createTransformerFromInputstream(InputStream xslStream)171     private Transformer createTransformerFromInputstream(InputStream xslStream)
172             throws TransformerException {
173         return TransformerFactory.newInstance().newTransformer(new StreamSource(xslStream));
174     }
175 }
176