src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipCoder.java
changeset 47216 71c04702a3d5
parent 43224 355457152ea8
child 53043 fd2e8f941ded
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2009, 2017, 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.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package jdk.nio.zipfs;
       
    27 
       
    28 import java.nio.ByteBuffer;
       
    29 import java.nio.CharBuffer;
       
    30 import java.nio.charset.Charset;
       
    31 import java.nio.charset.CharsetDecoder;
       
    32 import java.nio.charset.CharsetEncoder;
       
    33 import java.nio.charset.CoderResult;
       
    34 import java.nio.charset.CodingErrorAction;
       
    35 import java.util.Arrays;
       
    36 
       
    37 import static java.nio.charset.StandardCharsets.UTF_8;
       
    38 import static java.nio.charset.StandardCharsets.ISO_8859_1;
       
    39 
       
    40 /**
       
    41  * Utility class for zipfile name and comment decoding and encoding
       
    42  *
       
    43  * @author  Xueming Shen
       
    44  */
       
    45 
       
    46 class ZipCoder {
       
    47 
       
    48     static class UTF8 extends ZipCoder {
       
    49         UTF8() {
       
    50             super(UTF_8);
       
    51         }
       
    52 
       
    53         @Override
       
    54         byte[] getBytes(String s) {        // fast pass for ascii
       
    55             for (int i = 0; i < s.length(); i++) {
       
    56                 if (s.charAt(i) > 0x7f) return super.getBytes(s);
       
    57             }
       
    58             return s.getBytes(ISO_8859_1);
       
    59         }
       
    60 
       
    61         @Override
       
    62         String toString(byte[] ba) {
       
    63             for (byte b : ba) {
       
    64                 if (b < 0) return super.toString(ba);
       
    65             }
       
    66             return new String(ba, ISO_8859_1);
       
    67         }
       
    68     }
       
    69 
       
    70     private static final ZipCoder utf8 = new UTF8();
       
    71 
       
    72     public static ZipCoder get(String csn) {
       
    73         Charset cs = Charset.forName(csn);
       
    74         if (cs.name().equals("UTF-8")) {
       
    75             return utf8;
       
    76         }
       
    77         return new ZipCoder(cs);
       
    78     }
       
    79 
       
    80     String toString(byte[] ba) {
       
    81         CharsetDecoder cd = decoder().reset();
       
    82         int clen = (int)(ba.length * cd.maxCharsPerByte());
       
    83         char[] ca = new char[clen];
       
    84         if (clen == 0)
       
    85             return new String(ca);
       
    86         ByteBuffer bb = ByteBuffer.wrap(ba, 0, ba.length);
       
    87         CharBuffer cb = CharBuffer.wrap(ca);
       
    88         CoderResult cr = cd.decode(bb, cb, true);
       
    89         if (!cr.isUnderflow())
       
    90             throw new IllegalArgumentException(cr.toString());
       
    91         cr = cd.flush(cb);
       
    92         if (!cr.isUnderflow())
       
    93             throw new IllegalArgumentException(cr.toString());
       
    94         return new String(ca, 0, cb.position());
       
    95     }
       
    96 
       
    97     byte[] getBytes(String s) {
       
    98         CharsetEncoder ce = encoder().reset();
       
    99         char[] ca = s.toCharArray();
       
   100         int len = (int)(ca.length * ce.maxBytesPerChar());
       
   101         byte[] ba = new byte[len];
       
   102         if (len == 0)
       
   103             return ba;
       
   104         ByteBuffer bb = ByteBuffer.wrap(ba);
       
   105         CharBuffer cb = CharBuffer.wrap(ca);
       
   106         CoderResult cr = ce.encode(cb, bb, true);
       
   107         if (!cr.isUnderflow())
       
   108             throw new IllegalArgumentException(cr.toString());
       
   109         cr = ce.flush(bb);
       
   110         if (!cr.isUnderflow())
       
   111             throw new IllegalArgumentException(cr.toString());
       
   112         if (bb.position() == ba.length)  // defensive copy?
       
   113             return ba;
       
   114         else
       
   115             return Arrays.copyOf(ba, bb.position());
       
   116     }
       
   117 
       
   118     boolean isUTF8() {
       
   119         return cs == UTF_8;
       
   120     }
       
   121 
       
   122     private Charset cs;
       
   123 
       
   124     private ZipCoder(Charset cs) {
       
   125         this.cs = cs;
       
   126     }
       
   127 
       
   128     private final ThreadLocal<CharsetDecoder> decTL = new ThreadLocal<>();
       
   129     private final ThreadLocal<CharsetEncoder> encTL = new ThreadLocal<>();
       
   130 
       
   131     private CharsetDecoder decoder() {
       
   132         CharsetDecoder dec = decTL.get();
       
   133         if (dec == null) {
       
   134         dec = cs.newDecoder()
       
   135             .onMalformedInput(CodingErrorAction.REPORT)
       
   136             .onUnmappableCharacter(CodingErrorAction.REPORT);
       
   137         decTL.set(dec);
       
   138         }
       
   139         return dec;
       
   140     }
       
   141 
       
   142     private CharsetEncoder encoder() {
       
   143         CharsetEncoder enc = encTL.get();
       
   144         if (enc == null) {
       
   145         enc = cs.newEncoder()
       
   146             .onMalformedInput(CodingErrorAction.REPORT)
       
   147             .onUnmappableCharacter(CodingErrorAction.REPORT);
       
   148         encTL.set(enc);
       
   149         }
       
   150         return enc;
       
   151     }
       
   152 }