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")
 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
 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")
 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 
 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 
 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 
 171     private Transformer createTransformerFromInputstream(InputStream xslStream)
 172             throws TransformerException {
 173         return TransformerFactory.newInstance().newTransformer(new StreamSource(xslStream));
 174     }
 175 }