1 /*
   2  * Copyright (c) 2011, 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 7040220
  26    @summary Test if StringCoding and NIO result have the same de/encoding result for UTF-8
  27  * @run main/othervm/timeout=2000 TestStringCodingUTF8
  28  */
  29 
  30 import java.util.*;
  31 import java.nio.*;
  32 import java.nio.charset.*;
  33 
  34 public class TestStringCodingUTF8 {
  35     public static void main(String[] args) throws Throwable {
  36         test();
  37         // security manager on
  38         System.setSecurityManager(new PermissiveSecurityManger());
  39         test();
  40     }
  41 
  42     static void test() throws Throwable {
  43         Charset cs = Charset.forName("UTF-8");
  44         char[] bmp = new char[0x10000];
  45         for (int i = 0; i < 0x10000; i++) {
  46             bmp[i] = (char)i;
  47         }
  48         test(cs, bmp, 0, bmp.length);
  49 
  50         ArrayList<Integer> list = new ArrayList<>(0x20000);
  51         for (int i = 0; i < 0x20000; i++) {
  52             list.add(i, i);
  53         }
  54         Collections.shuffle(list);
  55         int j = 0;
  56         char[] bmpsupp = new char[0x30000];
  57         for (int i = 0; i < 0x20000; i++) {
  58             j += Character.toChars(list.get(i), bmpsupp, j);
  59         }
  60         assert (j == bmpsupp.length);
  61         test(cs, bmpsupp, 0, bmpsupp.length);
  62 
  63         // randomed "off" and "len" on shuffled data
  64         Random rnd = new Random();
  65         int maxlen = 1000;
  66         int itr = 5000;
  67         for (int i = 0; i < itr; i++) {
  68             int off = rnd.nextInt(bmpsupp.length - maxlen);
  69             int len = rnd.nextInt(maxlen);
  70             test(cs, bmpsupp, off, len);
  71         }
  72 
  73         // random length of bytes, test the edge corner case
  74         for (int i = 0; i < itr; i++) {
  75             byte[] ba = new byte[rnd.nextInt(maxlen)];
  76             rnd.nextBytes(ba);
  77             //new String(csn);
  78             if (!new String(ba, cs.name()).equals(
  79                  new String(decode(cs, ba, 0, ba.length))))
  80                 throw new RuntimeException("new String(csn) failed");
  81             //new String(cs);
  82             if (!new String(ba, cs).equals(
  83                  new String(decode(cs, ba, 0, ba.length))))
  84                 throw new RuntimeException("new String(cs) failed");
  85         }
  86         System.out.println("done!");
  87     }
  88 
  89     static void test(Charset cs, char[] ca, int off, int len) throws Throwable {
  90         String str = new String(ca, off, len);
  91         byte[] ba = encode(cs, ca, off, len);
  92 
  93         //getBytes(csn);
  94         byte[] baStr = str.getBytes(cs.name());
  95         if (!Arrays.equals(ba, baStr))
  96             throw new RuntimeException("getBytes(csn) failed");
  97 
  98         //getBytes(cs);
  99         baStr = str.getBytes(cs);
 100         if (!Arrays.equals(ba, baStr))
 101             throw new RuntimeException("getBytes(cs) failed");
 102 
 103         //new String(csn);
 104         if (!new String(ba, cs.name()).equals(new String(decode(cs, ba, 0, ba.length))))
 105             throw new RuntimeException("new String(csn) failed");
 106 
 107         //new String(cs);
 108         if (!new String(ba, cs).equals(new String(decode(cs, ba, 0, ba.length))))
 109             throw new RuntimeException("new String(cs) failed");
 110     }
 111 
 112     // copy/paste of the StringCoding.decode()
 113     static char[] decode(Charset cs, byte[] ba, int off, int len) {
 114         CharsetDecoder cd = cs.newDecoder();
 115         int en = (int)(len * cd.maxCharsPerByte());
 116         char[] ca = new char[en];
 117         if (len == 0)
 118             return ca;
 119         cd.onMalformedInput(CodingErrorAction.REPLACE)
 120           .onUnmappableCharacter(CodingErrorAction.REPLACE)
 121           .reset();
 122 
 123         ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
 124         CharBuffer cb = CharBuffer.wrap(ca);
 125         try {
 126             CoderResult cr = cd.decode(bb, cb, true);
 127             if (!cr.isUnderflow())
 128                 cr.throwException();
 129             cr = cd.flush(cb);
 130             if (!cr.isUnderflow())
 131                 cr.throwException();
 132         } catch (CharacterCodingException x) {
 133             throw new Error(x);
 134         }
 135         return Arrays.copyOf(ca, cb.position());
 136     }
 137 
 138     // copy/paste of the StringCoding.encode()
 139     static byte[] encode(Charset cs, char[] ca, int off, int len) {
 140         CharsetEncoder ce = cs.newEncoder();
 141         int en = (int)(len * ce.maxBytesPerChar());
 142         byte[] ba = new byte[en];
 143         if (len == 0)
 144             return ba;
 145         ce.onMalformedInput(CodingErrorAction.REPLACE)
 146           .onUnmappableCharacter(CodingErrorAction.REPLACE)
 147           .reset();
 148         ByteBuffer bb = ByteBuffer.wrap(ba);
 149         CharBuffer cb = CharBuffer.wrap(ca, off, len);
 150         try {
 151             CoderResult cr = ce.encode(cb, bb, true);
 152             if (!cr.isUnderflow())
 153                 cr.throwException();
 154             cr = ce.flush(bb);
 155             if (!cr.isUnderflow())
 156                 cr.throwException();
 157         } catch (CharacterCodingException x) {
 158             throw new Error(x);
 159         }
 160         return Arrays.copyOf(ba, bb.position());
 161     }
 162 
 163     static class PermissiveSecurityManger extends SecurityManager {
 164         @Override public void checkPermission(java.security.Permission p) {}
 165     }
 166 }