1 /* 2 * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * - Neither the name of Oracle nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This source code is provided to illustrate the usage of a given feature 34 * or technique and has been deliberately simplified. Additional steps 35 * required for a production-quality application, such as security checks, 36 * input validation and proper error handling, might not be present in 37 * this sample code. 38 */ 39 40 41 package com.sun.nio.zipfs; 42 43 import java.nio.ByteBuffer; 44 import java.nio.CharBuffer; 45 import java.nio.charset.Charset; 46 import java.nio.charset.CharsetDecoder; 47 import java.nio.charset.CharsetEncoder; 48 import java.nio.charset.CoderResult; 49 import java.nio.charset.CodingErrorAction; 50 import java.util.Arrays; 51 52 /** 53 * Utility class for zipfile name and comment decoding and encoding 54 * 55 * @author Xueming Shen 56 */ 57 58 final class ZipCoder { 59 60 String toString(byte[] ba, int length) { 61 CharsetDecoder cd = decoder().reset(); 62 int len = (int)(length * cd.maxCharsPerByte()); 63 char[] ca = new char[len]; 64 if (len == 0) 65 return new String(ca); 66 ByteBuffer bb = ByteBuffer.wrap(ba, 0, length); 67 CharBuffer cb = CharBuffer.wrap(ca); 68 CoderResult cr = cd.decode(bb, cb, true); 69 if (!cr.isUnderflow()) 70 throw new IllegalArgumentException(cr.toString()); 71 cr = cd.flush(cb); 72 if (!cr.isUnderflow()) 73 throw new IllegalArgumentException(cr.toString()); 74 return new String(ca, 0, cb.position()); 75 } 76 77 String toString(byte[] ba) { 78 return toString(ba, ba.length); 79 } 80 81 byte[] getBytes(String s) { 82 CharsetEncoder ce = encoder().reset(); 83 char[] ca = s.toCharArray(); 84 int len = (int)(ca.length * ce.maxBytesPerChar()); 85 byte[] ba = new byte[len]; 86 if (len == 0) 87 return ba; 88 ByteBuffer bb = ByteBuffer.wrap(ba); 89 CharBuffer cb = CharBuffer.wrap(ca); 90 CoderResult cr = ce.encode(cb, bb, true); 91 if (!cr.isUnderflow()) 92 throw new IllegalArgumentException(cr.toString()); 93 cr = ce.flush(bb); 94 if (!cr.isUnderflow()) 95 throw new IllegalArgumentException(cr.toString()); 96 if (bb.position() == ba.length) // defensive copy? 97 return ba; 98 else 99 return Arrays.copyOf(ba, bb.position()); 100 } 101 102 // assume invoked only if "this" is not utf8 103 byte[] getBytesUTF8(String s) { 104 if (isutf8) 105 return getBytes(s); 106 if (utf8 == null) 107 utf8 = new ZipCoder(Charset.forName("UTF-8")); 108 return utf8.getBytes(s); 109 } 110 111 String toStringUTF8(byte[] ba, int len) { 112 if (isutf8) 113 return toString(ba, len); 114 if (utf8 == null) 115 utf8 = new ZipCoder(Charset.forName("UTF-8")); 116 return utf8.toString(ba, len); 117 } 118 119 boolean isUTF8() { 120 return isutf8; 121 } 122 123 private Charset cs; 124 private boolean isutf8; 125 private ZipCoder utf8; 126 127 private ZipCoder(Charset cs) { 128 this.cs = cs; 129 this.isutf8 = cs.name().equals("UTF-8"); 130 } 131 132 static ZipCoder get(Charset charset) { 133 return new ZipCoder(charset); 134 } 135 136 static ZipCoder get(String csn) { 137 try { 138 return new ZipCoder(Charset.forName(csn)); 139 } catch (Throwable t) { 140 t.printStackTrace(); 141 } 142 return new ZipCoder(Charset.defaultCharset()); 143 } 144 145 private final ThreadLocal<CharsetDecoder> decTL = new ThreadLocal<>(); 146 private final ThreadLocal<CharsetEncoder> encTL = new ThreadLocal<>(); 147 148 private CharsetDecoder decoder() { 149 CharsetDecoder dec = decTL.get(); 150 if (dec == null) { 151 dec = cs.newDecoder() 152 .onMalformedInput(CodingErrorAction.REPORT) 153 .onUnmappableCharacter(CodingErrorAction.REPORT); 154 decTL.set(dec); 155 } 156 return dec; 157 } 158 159 private CharsetEncoder encoder() { 160 CharsetEncoder enc = encTL.get(); 161 if (enc == null) { 162 enc = cs.newEncoder() 163 .onMalformedInput(CodingErrorAction.REPORT) 164 .onUnmappableCharacter(CodingErrorAction.REPORT); 165 encTL.set(enc); 166 } 167 return enc; 168 } 169 }