OSDN Git Service

2c499a5ffb2abe8a216bc3d1f8c6c27362483982
[charactermanaj/CharacterManaJ.git] / src / org / apache / tools / zip / ZipEncodingHelper.java
1 /*\r
2  *  Licensed to the Apache Software Foundation (ASF) under one or more\r
3  *  contributor license agreements.  See the NOTICE file distributed with\r
4  *  this work for additional information regarding copyright ownership.\r
5  *  The ASF licenses this file to You under the Apache License, Version 2.0\r
6  *  (the "License"); you may not use this file except in compliance with\r
7  *  the License.  You may obtain a copy of the License at\r
8  *\r
9  *      http://www.apache.org/licenses/LICENSE-2.0\r
10  *\r
11  *  Unless required by applicable law or agreed to in writing, software\r
12  *  distributed under the License is distributed on an "AS IS" BASIS,\r
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
14  *  See the License for the specific language governing permissions and\r
15  *  limitations under the License.\r
16  *\r
17  */\r
18 \r
19 package org.apache.tools.zip;\r
20 \r
21 import java.nio.ByteBuffer;\r
22 import java.nio.charset.Charset;\r
23 import java.nio.charset.UnsupportedCharsetException;\r
24 import java.util.HashMap;\r
25 import java.util.Map;\r
26 \r
27 /**\r
28  * Static helper functions for robustly encoding filenames in zip files. \r
29  */\r
30 @SuppressWarnings({ "unchecked", "rawtypes" })\r
31 abstract class ZipEncodingHelper {\r
32 \r
33     /**\r
34      * A class, which holds the high characters of a simple encoding\r
35      * and lazily instantiates a Simple8BitZipEncoding instance in a\r
36      * thread-safe manner.\r
37      */\r
38     private static class SimpleEncodingHolder {\r
39 \r
40         private final char [] highChars;\r
41         private Simple8BitZipEncoding encoding;\r
42 \r
43         /**\r
44          * Instantiate a simple encoding holder.\r
45          * \r
46          * @param highChars The characters for byte codes 128 to 255.\r
47          * \r
48          * @see Simple8BitZipEncoding#Simple8BitZipEncoding(char[])\r
49          */\r
50         SimpleEncodingHolder(char [] highChars) {\r
51             this.highChars = highChars;\r
52         }\r
53 \r
54         /**\r
55          * @return The associated {@link Simple8BitZipEncoding}, which\r
56          *         is instantiated if not done so far.\r
57          */\r
58         public synchronized Simple8BitZipEncoding getEncoding() {\r
59             if (this.encoding == null) {\r
60                 this.encoding = new Simple8BitZipEncoding(this.highChars);\r
61             }\r
62             return this.encoding;\r
63         }\r
64     }\r
65 \r
66     private static final Map simpleEncodings;\r
67 \r
68     static {\r
69         simpleEncodings = new HashMap();\r
70 \r
71         char[] cp437_high_chars =\r
72             new char[] { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0,\r
73                          0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef,\r
74                          0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6,\r
75                          0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,\r
76                          0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5,\r
77                          0x20a7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa,\r
78                          0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x2310,\r
79                          0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,\r
80                          0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561,\r
81                          0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557,\r
82                          0x255d, 0x255c, 0x255b, 0x2510, 0x2514, 0x2534,\r
83                          0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,\r
84                          0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550,\r
85                          0x256c, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559,\r
86                          0x2558, 0x2552, 0x2553, 0x256b, 0x256a, 0x2518,\r
87                          0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,\r
88                          0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3,\r
89                          0x00b5, 0x03c4, 0x03a6, 0x0398, 0x03a9, 0x03b4,\r
90                          0x221e, 0x03c6, 0x03b5, 0x2229, 0x2261, 0x00b1,\r
91                          0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,\r
92                          0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2,\r
93                          0x25a0, 0x00a0 };\r
94 \r
95         SimpleEncodingHolder cp437 = new SimpleEncodingHolder(cp437_high_chars);\r
96 \r
97         simpleEncodings.put("CP437",cp437);\r
98         simpleEncodings.put("Cp437",cp437);\r
99         simpleEncodings.put("cp437",cp437);\r
100         simpleEncodings.put("IBM437",cp437);\r
101         simpleEncodings.put("ibm437",cp437);\r
102 \r
103         char[] cp850_high_chars =\r
104             new char[] { 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0,\r
105                          0x00e5, 0x00e7, 0x00ea, 0x00eb, 0x00e8, 0x00ef,\r
106                          0x00ee, 0x00ec, 0x00c4, 0x00c5, 0x00c9, 0x00e6,\r
107                          0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,\r
108                          0x00ff, 0x00d6, 0x00dc, 0x00f8, 0x00a3, 0x00d8,\r
109                          0x00d7, 0x0192, 0x00e1, 0x00ed, 0x00f3, 0x00fa,\r
110                          0x00f1, 0x00d1, 0x00aa, 0x00ba, 0x00bf, 0x00ae,\r
111                          0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,\r
112                          0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00c1,\r
113                          0x00c2, 0x00c0, 0x00a9, 0x2563, 0x2551, 0x2557,\r
114                          0x255d, 0x00a2, 0x00a5, 0x2510, 0x2514, 0x2534,\r
115                          0x252c, 0x251c, 0x2500, 0x253c, 0x00e3, 0x00c3,\r
116                          0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550,\r
117                          0x256c, 0x00a4, 0x00f0, 0x00d0, 0x00ca, 0x00cb,\r
118                          0x00c8, 0x0131, 0x00cd, 0x00ce, 0x00cf, 0x2518,\r
119                          0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580,\r
120                          0x00d3, 0x00df, 0x00d4, 0x00d2, 0x00f5, 0x00d5,\r
121                          0x00b5, 0x00fe, 0x00de, 0x00da, 0x00db, 0x00d9,\r
122                          0x00fd, 0x00dd, 0x00af, 0x00b4, 0x00ad, 0x00b1,\r
123                          0x2017, 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x00b8,\r
124                          0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2,\r
125                          0x25a0, 0x00a0 };\r
126 \r
127         SimpleEncodingHolder cp850 = new SimpleEncodingHolder(cp850_high_chars);\r
128 \r
129         simpleEncodings.put("CP850",cp850);\r
130         simpleEncodings.put("Cp850",cp850);\r
131         simpleEncodings.put("cp850",cp850);\r
132         simpleEncodings.put("IBM850",cp850);\r
133         simpleEncodings.put("ibm850",cp850);\r
134     }\r
135 \r
136     /**\r
137      * Grow a byte buffer, so it has a minimal capacity or at least\r
138      * the double capacity of the original buffer \r
139      * \r
140      * @param b The original buffer.\r
141      * @param newCapacity The minimal requested new capacity.\r
142      * @return A byte buffer <code>r</code> with\r
143      *         <code>r.capacity() = max(b.capacity()*2,newCapacity)</code> and\r
144      *         all the data contained in <code>b</code> copied to the beginning\r
145      *         of <code>r</code>.\r
146      *\r
147      */\r
148     static ByteBuffer growBuffer(ByteBuffer b, int newCapacity) {\r
149         b.limit(b.position());\r
150         b.rewind();\r
151 \r
152         int c2 = b.capacity() * 2;\r
153         ByteBuffer on = ByteBuffer.allocate(c2 < newCapacity ? newCapacity : c2);\r
154 \r
155         on.put(b);\r
156         return on;\r
157     }\r
158 \r
159  \r
160     /**\r
161      * The hexadecimal digits <code>0,...,9,A,...,F</code> encoded as\r
162      * ASCII bytes.\r
163      */\r
164     private static final byte[] HEX_DIGITS =\r
165         new byte [] {\r
166         0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41,\r
167         0x42, 0x43, 0x44, 0x45, 0x46\r
168     };\r
169 \r
170     /**\r
171      * Append <code>%Uxxxx</code> to the given byte buffer.\r
172      * The caller must assure, that <code>bb.remaining()&gt;=6</code>.\r
173      * \r
174      * @param bb The byte buffer to write to.\r
175      * @param c The character to write.\r
176      */\r
177     static void appendSurrogate(ByteBuffer bb, char c) {\r
178 \r
179         bb.put((byte) '%');\r
180         bb.put((byte) 'U');\r
181 \r
182         bb.put(HEX_DIGITS[(c >> 12)&0x0f]);\r
183         bb.put(HEX_DIGITS[(c >> 8)&0x0f]);\r
184         bb.put(HEX_DIGITS[(c >> 4)&0x0f]);\r
185         bb.put(HEX_DIGITS[c & 0x0f]);\r
186     }\r
187 \r
188 \r
189     /**\r
190      * name of the encoding UTF-8\r
191      */\r
192     static final String UTF8 = "UTF8";\r
193 \r
194     /**\r
195      * variant name of the encoding UTF-8 used for comparisions.\r
196      */\r
197     private static final String UTF_DASH_8 = "utf-8";\r
198 \r
199     /**\r
200      * name of the encoding UTF-8\r
201      */\r
202     static final ZipEncoding UTF8_ZIP_ENCODING = new FallbackZipEncoding(UTF8);\r
203 \r
204     /**\r
205      * Instantiates a zip encoding.\r
206      * \r
207      * @param name The name of the zip encoding. Specify <code>null</code> for\r
208      *             the platform's default encoding.\r
209      * @return A zip encoding for the given encoding name.\r
210      */\r
211     static ZipEncoding getZipEncoding(String name) {\r
212  \r
213         // fallback encoding is good enough for utf-8.\r
214         if (isUTF8(name)) {\r
215             return UTF8_ZIP_ENCODING;\r
216         }\r
217 \r
218         if (name == null) {\r
219             return new FallbackZipEncoding();\r
220         }\r
221 \r
222         SimpleEncodingHolder h =\r
223             (SimpleEncodingHolder) simpleEncodings.get(name);\r
224 \r
225         if (h!=null) {\r
226             return h.getEncoding();\r
227         }\r
228 \r
229         try {\r
230 \r
231             Charset cs = Charset.forName(name);\r
232             return new NioZipEncoding(cs);\r
233 \r
234         } catch (UnsupportedCharsetException e) {\r
235             return new FallbackZipEncoding(name);\r
236         }\r
237     }\r
238 \r
239     /**\r
240      * Whether a given encoding - or the platform's default encoding\r
241      * if the parameter is null - is UTF-8.\r
242      */\r
243     static boolean isUTF8(String encoding) {\r
244         if (encoding == null) {\r
245             // check platform's default encoding\r
246             encoding = System.getProperty("file.encoding");\r
247         }\r
248         return UTF8.equalsIgnoreCase(encoding)\r
249             || UTF_DASH_8.equalsIgnoreCase(encoding);\r
250     }\r
251 }\r