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 java.util.zip;
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.CharacterCodingException;
34 import java.nio.charset.CodingErrorAction;
35
36 import static java.nio.charset.StandardCharsets.UTF_8;
37
38 /**
39  * Utility class for zipfile name and comment decoding and encoding
40  */

41
42 class ZipCoder {
43
44     private static final jdk.internal.misc.JavaLangAccess JLA =
45         jdk.internal.misc.SharedSecrets.getJavaLangAccess();
46
47     static final class UTF8 extends ZipCoder {
48
49         UTF8(Charset utf8) {
50             super(utf8);
51         }
52
53         @Override
54         boolean isUTF8() {
55             return true;
56         }
57
58         @Override
59         String toString(byte[] ba, int off, int length) {
60             return JLA.newStringUTF8NoRepl(ba, off, length);
61         }
62
63         @Override
64         byte[] getBytes(String s) {
65             return JLA.getBytesUTF8NoRepl(s);
66         }
67     }
68
69     // UTF_8.ArrayEn/Decoder is stateless, so make it singleton.
70     private static ZipCoder utf8 = new UTF8(UTF_8);
71
72     public static ZipCoder get(Charset charset) {
73         if (charset == UTF_8)
74             return utf8;
75         return new ZipCoder(charset);
76     }
77
78     String toString(byte[] ba, int off, int length) {
79         try {
80             return decoder().decode(ByteBuffer.wrap(ba, off, length)).toString();
81         } catch (CharacterCodingException x) {
82             throw new IllegalArgumentException(x);
83         }
84     }
85
86     String toString(byte[] ba, int length) {
87         return toString(ba, 0, length);
88     }
89
90     String toString(byte[] ba) {
91         return toString(ba, 0, ba.length);
92     }
93
94     byte[] getBytes(String s) {
95         try {
96             ByteBuffer bb = encoder().encode(CharBuffer.wrap(s));
97             int pos = bb.position();
98             int limit = bb.limit();
99             if (bb.hasArray() && pos == 0 && limit == bb.capacity()) {
100                 return bb.array();
101             }
102             byte[] bytes = new byte[bb.limit() - bb.position()];
103             bb.get(bytes);
104             return bytes;
105         } catch (CharacterCodingException x) {
106             throw new IllegalArgumentException(x);
107         }
108     }
109
110     // assume invoked only if "this" is not utf8
111     byte[] getBytesUTF8(String s) {
112         return utf8.getBytes(s);
113     }
114
115     String toStringUTF8(byte[] ba, int len) {
116         return utf8.toString(ba, 0, len);
117     }
118
119     String toStringUTF8(byte[] ba, int off, int len) {
120         return utf8.toString(ba, off, len);
121     }
122
123     boolean isUTF8() {
124         return false;
125     }
126
127     private Charset cs;
128     private CharsetDecoder dec;
129     private CharsetEncoder enc;
130
131     private ZipCoder(Charset cs) {
132         this.cs = cs;
133     }
134
135     protected CharsetDecoder decoder() {
136         if (dec == null) {
137             dec = cs.newDecoder()
138               .onMalformedInput(CodingErrorAction.REPORT)
139               .onUnmappableCharacter(CodingErrorAction.REPORT);
140         }
141         return dec;
142     }
143
144     protected CharsetEncoder encoder() {
145         if (enc == null) {
146             enc = cs.newEncoder()
147               .onMalformedInput(CodingErrorAction.REPORT)
148               .onUnmappableCharacter(CodingErrorAction.REPORT);
149         }
150         return enc;
151     }
152 }
153