1 /*
   2  * Copyright (c) 2000, 2013, 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 /* @test
  25    @bug 6636323 6636319 7040220 7096080 7183053
  26    @summary Test if StringCoding and NIO result have the same de/encoding result
  27  * @run main/othervm/timeout=2000 TestStringCoding
  28  * @key randomness
  29  */
  30 
  31 import java.util.*;
  32 import java.nio.*;
  33 import java.nio.charset.*;
  34 
  35 public class TestStringCoding {
  36     public static void main(String[] args) throws Throwable {
  37 
  38         for (Boolean hasSM: new boolean[] { false, true }) {
  39             if (hasSM)
  40                 System.setSecurityManager(new PermissiveSecurityManger());
  41             for (Charset cs:  Charset.availableCharsets().values()) {
  42                 if ("ISO-2022-CN".equals(cs.name()) ||
  43                     "x-COMPOUND_TEXT".equals(cs.name()) ||
  44                     "x-JISAutoDetect".equals(cs.name()))
  45                     continue;
  46                 System.out.printf("Testing(sm=%b) " + cs.name() + "....", hasSM);
  47                 // full bmp first
  48                 char[] bmpCA = new char[0x10000];
  49                 for (int i = 0; i < 0x10000; i++) {
  50                      bmpCA[i] = (char)i;
  51                 }
  52                 byte[] sbBA = new byte[0x100];
  53                 for (int i = 0; i < 0x100; i++) {
  54                     sbBA[i] = (byte)i;
  55                 }
  56                 test(cs, bmpCA, sbBA);
  57                 // "randomed" sizes
  58                 Random rnd = new Random();
  59                 for (int i = 0; i < 10; i++) {
  60                     int clen = rnd.nextInt(0x10000);
  61                     int blen = rnd.nextInt(0x100);
  62                     //System.out.printf("    blen=%d, clen=%d%n", blen, clen);
  63                     test(cs, Arrays.copyOf(bmpCA, clen), Arrays.copyOf(sbBA, blen));
  64                     //add a pair of surrogates
  65                     int pos = clen / 2;
  66                     if ((pos + 1) < blen) {
  67                         bmpCA[pos] = '\uD800';
  68                         bmpCA[pos+1] = '\uDC00';
  69                     }
  70                     test(cs, Arrays.copyOf(bmpCA, clen), Arrays.copyOf(sbBA, blen));
  71                 }
  72 
  73                 testMixed(cs);
  74                 System.out.println("done!");
  75             }
  76         }
  77     }
  78 
  79     static void testMixed(Charset cs) throws Throwable {
  80         CharsetDecoder dec = cs.newDecoder()
  81             .onMalformedInput(CodingErrorAction.REPLACE)
  82             .onUnmappableCharacter(CodingErrorAction.REPLACE);
  83         CharsetEncoder enc = cs.newEncoder()
  84             .onMalformedInput(CodingErrorAction.REPLACE)
  85             .onUnmappableCharacter(CodingErrorAction.REPLACE);
  86         List<Integer> cps = new ArrayList<>(0x10000);
  87         int off = 0;
  88         int cp = 0;
  89         while (cp < 0x10000) {
  90             if (enc.canEncode((char)cp)) {
  91                cps.add(cp);
  92             }
  93             cp++;
  94         }
  95         Collections.shuffle(cps);
  96         char[] bmpCA = new char[cps.size()];
  97         for (int i = 0; i < cps.size(); i++)
  98             bmpCA[i] = (char)(int)cps.get(i);
  99         String bmpStr = new String(bmpCA);
 100         //getBytes(csn);
 101         byte[] bmpBA = bmpStr.getBytes(cs.name());
 102         ByteBuffer bf = enc.reset().encode(CharBuffer.wrap(bmpCA));
 103         byte[] baNIO = new byte[bf.limit()];
 104         bf.get(baNIO, 0, baNIO.length);
 105         if (!Arrays.equals(bmpBA, baNIO)) {
 106             throw new RuntimeException("getBytes(csn) failed  -> " + cs.name());
 107         }
 108 
 109         //getBytes(cs);
 110         bmpBA = bmpStr.getBytes(cs);
 111         if (!Arrays.equals(bmpBA, baNIO))
 112             throw new RuntimeException("getBytes(cs) failed  -> " + cs.name());
 113 
 114         //new String(csn);
 115         String strSC = new String(bmpBA, cs.name());
 116         String strNIO = dec.reset().decode(ByteBuffer.wrap(bmpBA)).toString();
 117         if(!strNIO.equals(strSC)) {
 118             throw new RuntimeException("new String(csn) failed  -> " + cs.name());
 119         }
 120 
 121         //new String(cs);
 122         strSC = new String(bmpBA, cs);
 123         if (!strNIO.equals(strSC))
 124             throw new RuntimeException("new String(cs) failed  -> " + cs.name());
 125 
 126     }
 127 
 128     static void test(Charset cs, char[] bmpCA, byte[] sbBA) throws Throwable {
 129         String bmpStr = new String(bmpCA);
 130         CharsetDecoder dec = cs.newDecoder()
 131             .onMalformedInput(CodingErrorAction.REPLACE)
 132             .onUnmappableCharacter(CodingErrorAction.REPLACE);
 133         CharsetEncoder enc = cs.newEncoder()
 134             .onMalformedInput(CodingErrorAction.REPLACE)
 135             .onUnmappableCharacter(CodingErrorAction.REPLACE);
 136 
 137         //getBytes(csn);
 138         byte[] baSC = bmpStr.getBytes(cs.name());
 139         ByteBuffer bf = enc.reset().encode(CharBuffer.wrap(bmpCA));
 140         byte[] baNIO = new byte[bf.limit()];
 141         bf.get(baNIO, 0, baNIO.length);
 142         if (!Arrays.equals(baSC, baNIO))
 143             throw new RuntimeException("getBytes(csn) failed  -> " + cs.name());
 144 
 145         //getBytes(cs);
 146         baSC = bmpStr.getBytes(cs);
 147         if (!Arrays.equals(baSC, baNIO))
 148             throw new RuntimeException("getBytes(cs) failed  -> " + cs.name());
 149 
 150         //new String(csn);
 151         String strSC = new String(sbBA, cs.name());
 152         String strNIO = dec.reset().decode(ByteBuffer.wrap(sbBA)).toString();
 153 
 154         if(!strNIO.equals(strSC))
 155             throw new RuntimeException("new String(csn) failed  -> " + cs.name());
 156 
 157         //new String(cs);
 158         strSC = new String(sbBA, cs);
 159         if (!strNIO.equals(strSC))
 160             throw new RuntimeException("new String(cs) failed  -> " + cs.name());
 161 
 162         //encode unmappable surrogates
 163         if (enc instanceof sun.nio.cs.ArrayEncoder &&
 164             cs.contains(Charset.forName("ASCII"))) {
 165             if (cs.name().equals("UTF-8") ||     // utf8 handles surrogates
 166                 cs.name().equals("CESU-8"))      // utf8 handles surrogates
 167                 return;
 168             enc.replaceWith(new byte[] { (byte)'A'});
 169             sun.nio.cs.ArrayEncoder cae = (sun.nio.cs.ArrayEncoder)enc;
 170 
 171             String str = "ab\uD800\uDC00\uD800\uDC00cd";
 172             byte[] ba = new byte[str.length() - 2];
 173             int n = cae.encode(str.toCharArray(), 0, str.length(), ba);
 174             if (n != 6 || !"abAAcd".equals(new String(ba, cs.name())))
 175                 throw new RuntimeException("encode1(surrogates) failed  -> "
 176                                            + cs.name());
 177 
 178             ba = new byte[str.length()];
 179             n = cae.encode(str.toCharArray(), 0, str.length(), ba);
 180             if (n != 6 || !"abAAcd".equals(new String(ba, 0, n,
 181                                                      cs.name())))
 182                 throw new RuntimeException("encode2(surrogates) failed  -> "
 183                                            + cs.name());
 184             str = "ab\uD800B\uDC00Bcd";
 185             ba = new byte[str.length()];
 186             n = cae.encode(str.toCharArray(), 0, str.length(), ba);
 187             if (n != 8 || !"abABABcd".equals(new String(ba, 0, n,
 188                                                        cs.name())))
 189                 throw new RuntimeException("encode3(surrogates) failed  -> "
 190                                            + cs.name());
 191             /* sun.nio.cs.ArrayDeEncoder works on the assumption that the
 192                invoker (StringCoder) allocates enough output buf, utf8
 193                and double-byte coder does not check the output buffer limit.
 194             ba = new byte[str.length() - 1];
 195             n = cae.encode(str.toCharArray(), 0, str.length(), ba);
 196             if (n != 7 || !"abABABc".equals(new String(ba, 0, n, cs.name()))) {
 197                 throw new RuntimeException("encode4(surrogates) failed  -> "
 198                                            + cs.name());
 199             }
 200             */
 201         }
 202 
 203     }
 204 
 205     static class PermissiveSecurityManger extends SecurityManager {
 206         @Override public void checkPermission(java.security.Permission p) {}
 207     }
 208 }