1
2
3
4
5 package net.java.truevfs.comp.zip;
6
7 import java.io.EOFException;
8 import java.io.IOException;
9 import java.io.InputStream;
10 import java.nio.channels.SeekableByteChannel;
11 import java.nio.charset.Charset;
12 import static java.nio.file.Files.newByteChannel;
13 import java.nio.file.Path;
14 import java.util.Enumeration;
15 import java.util.Iterator;
16 import java.util.concurrent.locks.Lock;
17 import java.util.concurrent.locks.ReentrantLock;
18 import java.util.zip.ZipException;
19 import javax.annotation.CheckForNull;
20 import javax.annotation.Nullable;
21 import javax.annotation.concurrent.ThreadSafe;
22 import net.java.truecommons.io.AbstractSource;
23 import net.java.truecommons.io.LockInputStream;
24 import net.java.truecommons.io.OneTimeSource;
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 @ThreadSafe
47 public class ZipFile extends AbstractZipFile<ZipEntry> {
48
49
50 private final Lock lock = new ReentrantLock();
51
52 private final String name;
53
54 private volatile @CheckForNull ZipCryptoParameters cryptoParameters;
55
56
57
58
59
60 public ZipFile(Path file)
61 throws IOException {
62 this(file, DEFAULT_CHARSET, true, false);
63 }
64
65
66
67
68
69 public ZipFile(Path file, Charset charset)
70 throws IOException {
71 this(file, charset, true, false);
72 }
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 public ZipFile(
106 final Path file,
107 final Charset charset,
108 final boolean preambled,
109 final boolean postambled)
110 throws ZipException, EOFException, IOException {
111 super( new ZipSource(file),
112 new DefaultZipFileParameters(charset, preambled, postambled));
113 this.name = file.toString();
114 }
115
116
117
118
119
120 public ZipFile(SeekableByteChannel channel)
121 throws IOException {
122 this(channel, DEFAULT_CHARSET, true, false);
123 }
124
125
126
127
128
129 public ZipFile(SeekableByteChannel channel, Charset charset)
130 throws IOException {
131 this(channel, charset, true, false);
132 }
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165 public ZipFile(
166 SeekableByteChannel channel,
167 Charset charset,
168 boolean preambled,
169 boolean postambled)
170 throws ZipException, EOFException, IOException {
171 super( new OneTimeSource(channel),
172 new DefaultZipFileParameters(charset, preambled, postambled));
173 this.name = channel.toString();
174 }
175
176
177
178
179
180
181 @Override
182 public ZipFile recoverLostEntries() throws IOException {
183 super.recoverLostEntries();
184 return this;
185 }
186
187
188
189
190
191
192 public String getName() {
193 return name;
194 }
195
196
197
198
199
200
201 public Enumeration<? extends ZipEntry> entries() {
202 final class CloneEnumeration implements Enumeration<ZipEntry> {
203 final Iterator<ZipEntry> i = ZipFile.super.iterator();
204
205 @Override
206 public boolean hasMoreElements() {
207 return i.hasNext();
208 }
209
210 @Override
211 public ZipEntry nextElement() {
212 return i.next().clone();
213 }
214 }
215
216 return new CloneEnumeration();
217 }
218
219
220
221
222
223 @Override
224 public Iterator<ZipEntry> iterator() {
225 final class EntryIterator implements Iterator<ZipEntry> {
226 final Iterator<ZipEntry> i = ZipFile.super.iterator();
227
228 @Override
229 public boolean hasNext() {
230 return i.hasNext();
231 }
232
233 @Override
234 public ZipEntry next() {
235 return i.next().clone();
236 }
237
238 @Override
239 public void remove() {
240 throw new UnsupportedOperationException();
241 }
242 }
243
244 return new EntryIterator();
245 }
246
247
248
249
250
251
252
253
254
255 @Override
256 public ZipEntry entry(String name) {
257 final ZipEntry ze = super.entry(name);
258 return ze != null ? ze.clone() : null;
259 }
260
261 @Override
262 @SuppressWarnings("deprecation")
263 public InputStream getPreambleInputStream() throws IOException {
264 final InputStream in;
265 lock.lock();
266 try {
267 in = super.getPreambleInputStream();
268 } finally {
269 lock.unlock();
270 }
271 return new LockInputStream(lock, in);
272 }
273
274 @Override
275 @SuppressWarnings("deprecation")
276 public InputStream getPostambleInputStream() throws IOException {
277 final InputStream in;
278 lock.lock();
279 try {
280 in = super.getPostambleInputStream();
281 } finally {
282 lock.unlock();
283 }
284 return new LockInputStream(lock, in);
285 }
286
287 @Override
288 public boolean busy() {
289 lock.lock();
290 try {
291 return super.busy();
292 } finally {
293 lock.unlock();
294 }
295 }
296
297 @Override
298 public @Nullable ZipCryptoParameters getCryptoParameters() {
299 return cryptoParameters;
300 }
301
302
303
304
305
306
307
308 public void setCryptoParameters(
309 final @CheckForNull ZipCryptoParameters cryptoParameters) {
310 this.cryptoParameters = cryptoParameters;
311 }
312
313 @Override
314 @SuppressWarnings("deprecation")
315 protected InputStream getInputStream(
316 String name, Boolean check, boolean process)
317 throws IOException {
318 final InputStream in;
319 lock.lock();
320 try {
321 in = super.getInputStream(name, check, process);
322 } finally {
323 lock.unlock();
324 }
325 return in == null ? null : new LockInputStream(lock, in);
326 }
327
328 @Override
329 public void close() throws IOException {
330 lock.lock();
331 try {
332 super.close();
333 } finally {
334 lock.unlock();
335 }
336 }
337
338
339
340
341
342 private static final class ZipSource extends AbstractSource {
343 final Path file;
344
345 ZipSource(final Path file) {
346 this.file = file;
347 }
348
349 @Override
350 public SeekableByteChannel channel() throws IOException {
351 return newByteChannel(file);
352 }
353 }
354 }