46 |
import java.io.EOFException; |
import java.io.EOFException; |
47 |
import java.io.RandomAccessFile; |
import java.io.RandomAccessFile; |
48 |
import java.util.Enumeration; |
import java.util.Enumeration; |
49 |
|
import java.util.Hashtable; |
50 |
import java.util.NoSuchElementException; |
import java.util.NoSuchElementException; |
51 |
|
|
52 |
/** |
/** |
62 |
public class ZipFile implements ZipConstants |
public class ZipFile implements ZipConstants |
63 |
{ |
{ |
64 |
|
|
65 |
/** Mode flag to open a zip file for reading |
/** |
66 |
* |
* Mode flag to open a zip file for reading. |
67 |
*/ |
*/ |
|
|
|
68 |
public static final int OPEN_READ = 0x1; |
public static final int OPEN_READ = 0x1; |
69 |
|
|
70 |
/** Mode flag to delete a zip file after reading |
/** |
71 |
* |
* Mode flag to delete a zip file after reading. |
72 |
*/ |
*/ |
|
|
|
73 |
public static final int OPEN_DELETE = 0x4; |
public static final int OPEN_DELETE = 0x4; |
74 |
|
|
75 |
private String name; |
// Name of this zip file. |
76 |
RandomAccessFile raf; |
private final String name; |
77 |
ZipEntry[] entries; |
|
78 |
|
// File from which zip entries are read. |
79 |
|
private final RandomAccessFile raf; |
80 |
|
|
81 |
|
// The entries of this zip file when initialized and not yet closed. |
82 |
|
private Hashtable entries; |
83 |
|
|
84 |
|
private boolean closed = false; |
85 |
|
|
86 |
/** |
/** |
87 |
* Opens a Zip file with the given name for reading. |
* Opens a Zip file with the given name for reading. |
93 |
{ |
{ |
94 |
this.raf = new RandomAccessFile(name, "r"); |
this.raf = new RandomAccessFile(name, "r"); |
95 |
this.name = name; |
this.name = name; |
|
readEntries(); |
|
96 |
} |
} |
97 |
|
|
98 |
/** |
/** |
105 |
{ |
{ |
106 |
this.raf = new RandomAccessFile(file, "r"); |
this.raf = new RandomAccessFile(file, "r"); |
107 |
this.name = file.getName(); |
this.name = file.getName(); |
|
readEntries(); |
|
108 |
} |
} |
109 |
|
|
110 |
/** |
/** |
134 |
} |
} |
135 |
this.raf = new RandomAccessFile(file, "r"); |
this.raf = new RandomAccessFile(file, "r"); |
136 |
this.name = file.getName(); |
this.name = file.getName(); |
|
readEntries(); |
|
137 |
} |
} |
138 |
|
|
139 |
/** |
/** |
163 |
|
|
164 |
/** |
/** |
165 |
* Read the central directory of a zip file and fill the entries |
* Read the central directory of a zip file and fill the entries |
166 |
* array. This is called exactly once by the constructors. |
* array. This is called exactly once when first needed. |
167 |
* @exception IOException if a i/o error occured. |
* @exception IOException if a i/o error occured. |
168 |
* @exception ZipException if the central directory is malformed |
* @exception ZipException if the central directory is malformed |
169 |
*/ |
*/ |
190 |
throw new EOFException(name); |
throw new EOFException(name); |
191 |
int centralOffset = readLeInt(raf); |
int centralOffset = readLeInt(raf); |
192 |
|
|
193 |
entries = new ZipEntry[count]; |
entries = new Hashtable(count); |
194 |
raf.seek(centralOffset); |
raf.seek(centralOffset); |
195 |
byte[] ebs = new byte[24]; |
byte[] ebs = new byte[24]; |
196 |
ByteArrayInputStream ebais = new ByteArrayInputStream(ebs); |
ByteArrayInputStream ebais = new ByteArrayInputStream(ebs); |
239 |
raf.readFully(buffer, 0, commentLen); |
raf.readFully(buffer, 0, commentLen); |
240 |
entry.setComment(new String(buffer, 0, commentLen)); |
entry.setComment(new String(buffer, 0, commentLen)); |
241 |
} |
} |
|
entry.zipFileIndex = i; |
|
242 |
entry.offset = offset; |
entry.offset = offset; |
243 |
entries[i] = entry; |
entries.put(name, entry); |
244 |
} |
} |
245 |
} |
} |
246 |
|
|
252 |
*/ |
*/ |
253 |
public void close() throws IOException |
public void close() throws IOException |
254 |
{ |
{ |
|
entries = null; |
|
255 |
synchronized (raf) |
synchronized (raf) |
256 |
{ |
{ |
257 |
|
closed = true; |
258 |
|
entries = null; |
259 |
raf.close(); |
raf.close(); |
260 |
} |
} |
261 |
} |
} |
265 |
*/ |
*/ |
266 |
public Enumeration entries() |
public Enumeration entries() |
267 |
{ |
{ |
268 |
if (entries == null) |
try |
269 |
throw new IllegalStateException("ZipFile has closed: " + name); |
{ |
270 |
return new ZipEntryEnumeration(entries); |
return new ZipEntryEnumeration(getEntries().elements()); |
271 |
|
} |
272 |
|
catch (IOException ioe) |
273 |
|
{ |
274 |
|
return null; |
275 |
|
} |
276 |
} |
} |
277 |
|
|
278 |
private int getEntryIndex(String name) |
/** |
279 |
|
* Checks that the ZipFile is still open and reads entries when necessary. |
280 |
|
* |
281 |
|
* @exception IllegalStateException when the ZipFile has already been closed. |
282 |
|
* @exception IOEexception when the entries could not be read. |
283 |
|
*/ |
284 |
|
private Hashtable getEntries() throws IOException |
285 |
{ |
{ |
286 |
for (int i = 0; i < entries.length; i++) |
synchronized(raf) |
287 |
if (name.equals(entries[i].getName())) |
{ |
288 |
return i; |
if (closed) |
289 |
return -1; |
throw new IllegalStateException("ZipFile has closed: " + name); |
290 |
|
|
291 |
|
if (entries == null) |
292 |
|
readEntries(); |
293 |
|
|
294 |
|
return entries; |
295 |
|
} |
296 |
} |
} |
297 |
|
|
298 |
/** |
/** |
303 |
* @see #entries */ |
* @see #entries */ |
304 |
public ZipEntry getEntry(String name) |
public ZipEntry getEntry(String name) |
305 |
{ |
{ |
306 |
if (entries == null) |
try |
307 |
throw new IllegalStateException("ZipFile has closed: " + name); |
{ |
308 |
int index = getEntryIndex(name); |
Hashtable entries = getEntries(); |
309 |
return index >= 0 ? (ZipEntry) entries[index].clone() : null; |
ZipEntry entry = (ZipEntry) entries.get(name); |
310 |
|
return entry != null ? (ZipEntry) entry.clone() : null; |
311 |
|
} |
312 |
|
catch (IOException ioe) |
313 |
|
{ |
314 |
|
return null; |
315 |
|
} |
316 |
} |
} |
317 |
|
|
318 |
/** |
/** |
360 |
*/ |
*/ |
361 |
public InputStream getInputStream(ZipEntry entry) throws IOException |
public InputStream getInputStream(ZipEntry entry) throws IOException |
362 |
{ |
{ |
363 |
if (entries == null) |
Hashtable entries = getEntries(); |
364 |
throw new IllegalStateException("ZipFile has closed"); |
String name = entry.getName(); |
365 |
int index = entry.zipFileIndex; |
ZipEntry zipEntry = (ZipEntry) entries.get(name); |
366 |
if (index < 0 || index >= entries.length |
if (zipEntry == null) |
367 |
|| entries[index].getName() != entry.getName()) |
throw new NoSuchElementException(name); |
|
{ |
|
|
index = getEntryIndex(entry.getName()); |
|
|
if (index < 0) |
|
|
throw new NoSuchElementException(); |
|
|
} |
|
368 |
|
|
369 |
long start = checkLocalHeader(entries[index]); |
long start = checkLocalHeader(zipEntry); |
370 |
int method = entries[index].getMethod(); |
int method = zipEntry.getMethod(); |
371 |
InputStream is = new PartialInputStream |
InputStream is = new PartialInputStream |
372 |
(raf, start, entries[index].getCompressedSize()); |
(raf, start, zipEntry.getCompressedSize()); |
373 |
switch (method) |
switch (method) |
374 |
{ |
{ |
375 |
case ZipOutputStream.STORED: |
case ZipOutputStream.STORED: |
396 |
{ |
{ |
397 |
try |
try |
398 |
{ |
{ |
399 |
return entries.length; |
return getEntries().size(); |
400 |
} |
} |
401 |
catch (NullPointerException ex) |
catch (IOException ioe) |
402 |
{ |
{ |
403 |
throw new IllegalStateException("ZipFile has closed"); |
return 0; |
404 |
} |
} |
405 |
} |
} |
406 |
|
|
407 |
private static class ZipEntryEnumeration implements Enumeration |
private static class ZipEntryEnumeration implements Enumeration |
408 |
{ |
{ |
409 |
ZipEntry[] array; |
private final Enumeration elements; |
|
int ptr = 0; |
|
410 |
|
|
411 |
public ZipEntryEnumeration(ZipEntry[] arr) |
public ZipEntryEnumeration(Enumeration elements) |
412 |
{ |
{ |
413 |
array = arr; |
this.elements = elements; |
414 |
} |
} |
415 |
|
|
416 |
public boolean hasMoreElements() |
public boolean hasMoreElements() |
417 |
{ |
{ |
418 |
return ptr < array.length; |
return elements.hasMoreElements(); |
419 |
} |
} |
420 |
|
|
421 |
public Object nextElement() |
public Object nextElement() |
422 |
{ |
{ |
423 |
try |
/* We return a clone, just to be safe that the user doesn't |
424 |
{ |
* change the entry. |
425 |
/* We return a clone, just to be safe that the user doesn't |
*/ |
426 |
* change the entry. |
return ((ZipEntry)elements.nextElement()).clone(); |
|
*/ |
|
|
return array[ptr++].clone(); |
|
|
} |
|
|
catch (ArrayIndexOutOfBoundsException ex) |
|
|
{ |
|
|
throw new NoSuchElementException(); |
|
|
} |
|
427 |
} |
} |
428 |
} |
} |
429 |
|
|