Source Home >> Java Source 1.6.0 >> java.util.zip.ZipFile V 0.09
  • 001/*
  • 002 * @(#)ZipFile.java 1.78 06/07/31
  • 003 *
  • 004 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
  • 005 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  • 006 */
  • 007
  • 008package java.util.zip;
  • 009
  • 010import java.io.InputStream;
  • 011import java.io.IOException;
  • 012import java.io.EOFException;
  • 013import java.io.File;
  • 014import java.util.Vector;
  • 015import java.util.Enumeration;
  • 016import java.util.NoSuchElementException;
  • 017
  • 018/**
  • 019 * This class is used to read entries from a zip file.
  • 020 *
  • 021 * <p> Unless otherwise noted, passing a <tt>null</tt> argument to a constructor
  • 022 * or method in this class will cause a {@link NullPointerException} to be
  • 023 * thrown.
  • 024 *
  • 025 * @version 1.78, 07/31/06
  • 026 * @author David Connelly
  • 027 */
  • 028public
  • 029class ZipFile implements ZipConstants {
  • 030 private long jzfile; // address of jzfile data
  • 031 private String name; // zip file name
  • 032 private int total; // total number of entries
  • 033 private boolean closeRequested;
  • 034
  • 035 private static final int STORED = ZipEntry.STORED;
  • 036 private static final int DEFLATED = ZipEntry.DEFLATED;
  • 037
  • 038 /**
  • 039 * Mode flag to open a zip file for reading.
  • 040 */
  • 041 public static final int OPEN_READ = 0x1;
  • 042
  • 043 /**
  • 044 * Mode flag to open a zip file and mark it for deletion. The file will be
  • 045 * deleted some time between the moment that it is opened and the moment
  • 046 * that it is closed, but its contents will remain accessible via the
  • 047 * <tt>ZipFile</tt> object until either the close method is invoked or the
  • 048 * virtual machine exits.
  • 049 */
  • 050 public static final int OPEN_DELETE = 0x4;
  • 051
  • 052 static {
  • 053 /* Zip library is loaded from System.initializeSystemClass */
  • 054 initIDs();
  • 055 }
  • 056
  • 057 private static native void initIDs();
  • 058
  • 059 /**
  • 060 * Opens a zip file for reading.
  • 061 *
  • 062 * <p>First, if there is a security
  • 063 * manager, its <code>checkRead</code> method
  • 064 * is called with the <code>name</code> argument
  • 065 * as its argument to ensure the read is allowed.
  • 066 *
  • 067 * @param name the name of the zip file
  • 068 * @throws ZipException if a ZIP format error has occurred
  • 069 * @throws IOException if an I/O error has occurred
  • 070 * @throws SecurityException if a security manager exists and its
  • 071 * <code>checkRead</code> method doesn't allow read access to the file.
  • 072 * @see SecurityManager#checkRead(java.lang.String)
  • 073 */
  • 074 public ZipFile(String name) throws IOException {
  • 075 this(new File(name), OPEN_READ);
  • 076 }
  • 077
  • 078 /**
  • 079 * Opens a new <code>ZipFile</code> to read from the specified
  • 080 * <code>File</code> object in the specified mode. The mode argument
  • 081 * must be either <tt>OPEN_READ</tt> or <tt>OPEN_READ | OPEN_DELETE</tt>.
  • 082 *
  • 083 * <p>First, if there is a security manager, its <code>checkRead</code>
  • 084 * method is called with the <code>name</code> argument as its argument to
  • 085 * ensure the read is allowed.
  • 086 *
  • 087 * @param file the ZIP file to be opened for reading
  • 088 * @param mode the mode in which the file is to be opened
  • 089 * @throws ZipException if a ZIP format error has occurred
  • 090 * @throws IOException if an I/O error has occurred
  • 091 * @throws SecurityException if a security manager exists and
  • 092 * its <code>checkRead</code> method
  • 093 * doesn't allow read access to the file,
  • 094 * or its <code>checkDelete</code> method doesn't allow deleting
  • 095 * the file when the <tt>OPEN_DELETE</tt> flag is set.
  • 096 * @throws IllegalArgumentException if the <tt>mode</tt> argument is invalid
  • 097 * @see SecurityManager#checkRead(java.lang.String)
  • 098 * @since 1.3
  • 099 */
  • 100 public ZipFile(File file, int mode) throws IOException {
  • 101 if (((mode & OPEN_READ) == 0) ||
  • 102 ((mode & ~(OPEN_READ | OPEN_DELETE)) != 0)) {
  • 103 throw new IllegalArgumentException("Illegal mode: 0x"+
  • 104 Integer.toHexString(mode));
  • 105 }
  • 106 String name = file.getPath();
  • 107 SecurityManager sm = System.getSecurityManager();
  • 108 if (sm != null) {
  • 109 sm.checkRead(name);
  • 110 if ((mode & OPEN_DELETE) != 0) {
  • 111 sm.checkDelete(name);
  • 112 }
  • 113 }
  • 114 jzfile = open(name, mode, file.lastModified());
  • 115
  • 116 this.name = name;
  • 117 this.total = getTotal(jzfile);
  • 118 }
  • 119
  • 120 private static native long open(String name, int mode, long lastModified);
  • 121 private static native int getTotal(long jzfile);
  • 122
  • 123
  • 124 /**
  • 125 * Opens a ZIP file for reading given the specified File object.
  • 126 * @param file the ZIP file to be opened for reading
  • 127 * @throws ZipException if a ZIP error has occurred
  • 128 * @throws IOException if an I/O error has occurred
  • 129 */
  • 130 public ZipFile(File file) throws ZipException, IOException {
  • 131 this(file, OPEN_READ);
  • 132 }
  • 133
  • 134 /**
  • 135 * Returns the zip file entry for the specified name, or null
  • 136 * if not found.
  • 137 *
  • 138 * @param name the name of the entry
  • 139 * @return the zip file entry, or null if not found
  • 140 * @throws IllegalStateException if the zip file has been closed
  • 141 */
  • 142 public ZipEntry getEntry(String name) {
  • 143 if (name == null) {
  • 144 throw new NullPointerException("name");
  • 145 }
  • 146 long jzentry = 0;
  • 147 synchronized (this) {
  • 148 ensureOpen();
  • 149 jzentry = getEntry(jzfile, name, true);
  • 150 if (jzentry != 0) {
  • 151 ZipEntry ze = new ZipEntry(name, jzentry);
  • 152 freeEntry(jzfile, jzentry);
  • 153 return ze;
  • 154 }
  • 155 }
  • 156 return null;
  • 157 }
  • 158
  • 159 private static native long getEntry(long jzfile, String name,
  • 160 boolean addSlash);
  • 161
  • 162 // freeEntry releases the C jzentry struct.
  • 163 private static native void freeEntry(long jzfile, long jzentry);
  • 164
  • 165 /**
  • 166 * Returns an input stream for reading the contents of the specified
  • 167 * zip file entry.
  • 168 *
  • 169 * <p> Closing this ZIP file will, in turn, close all input
  • 170 * streams that have been returned by invocations of this method.
  • 171 *
  • 172 * @param entry the zip file entry
  • 173 * @return the input stream for reading the contents of the specified
  • 174 * zip file entry.
  • 175 * @throws ZipException if a ZIP format error has occurred
  • 176 * @throws IOException if an I/O error has occurred
  • 177 * @throws IllegalStateException if the zip file has been closed
  • 178 */
  • 179 public InputStream getInputStream(ZipEntry entry) throws IOException {
  • 180 return getInputStream(entry.name);
  • 181 }
  • 182
  • 183 /**
  • 184 * Returns an input stream for reading the contents of the specified
  • 185 * entry, or null if the entry was not found.
  • 186 */
  • 187 private InputStream getInputStream(String name) throws IOException {
  • 188 if (name == null) {
  • 189 throw new NullPointerException("name");
  • 190 }
  • 191 long jzentry = 0;
  • 192 ZipFileInputStream in = null;
  • 193 synchronized (this) {
  • 194 ensureOpen();
  • 195 jzentry = getEntry(jzfile, name, false);
  • 196 if (jzentry == 0) {
  • 197 return null;
  • 198 }
  • 199
  • 200 in = new ZipFileInputStream(jzentry);
  • 201
  • 202 }
  • 203 final ZipFileInputStream zfin = in;
  • 204 switch (getMethod(jzentry)) {
  • 205 case STORED:
  • 206 return zfin;
  • 207 case DEFLATED:
  • 208 // MORE: Compute good size for inflater stream:
  • 209 long size = getSize(jzentry) + 2; // Inflater likes a bit of slack
  • 210 if (size > 65536) size = 8192;
  • 211 if (size <= 0) size = 4096;
  • 212 return new InflaterInputStream(zfin, getInflater(), (int)size) {
  • 213 private boolean isClosed = false;
  • 214
  • 215 public void close() throws IOException {
  • 216 if (!isClosed) {
  • 217 releaseInflater(inf);
  • 218 this.in.close();
  • 219 isClosed = true;
  • 220 }
  • 221 }
  • 222 // Override fill() method to provide an extra "dummy" byte
  • 223 // at the end of the input stream. This is required when
  • 224 // using the "nowrap" Inflater option.
  • 225 protected void fill() throws IOException {
  • 226 if (eof) {
  • 227 throw new EOFException(
  • 228 "Unexpected end of ZLIB input stream");
  • 229 }
  • 230 len = this.in.read(buf, 0, buf.length);
  • 231 if (len == -1) {
  • 232 buf[0] = 0;
  • 233 len = 1;
  • 234 eof = true;
  • 235 }
  • 236 inf.setInput(buf, 0, len);
  • 237 }
  • 238 private boolean eof;
  • 239
  • 240 public int available() throws IOException {
  • 241 if (isClosed)
  • 242 return 0;
  • 243 long avail = zfin.size() - inf.getBytesWritten();
  • 244 return avail > (long) Integer.MAX_VALUE ?
  • 245 Integer.MAX_VALUE : (int) avail;
  • 246 }
  • 247 };
  • 248 default:
  • 249 throw new ZipException("invalid compression method");
  • 250 }
  • 251 }
  • 252
  • 253 private static native int getMethod(long jzentry);
  • 254
  • 255 /*
  • 256 * Gets an inflater from the list of available inflaters or allocates
  • 257 * a new one.
  • 258 */
  • 259 private Inflater getInflater() {
  • 260 synchronized (inflaters) {
  • 261 int size = inflaters.size();
  • 262 if (size > 0) {
  • 263 Inflater inf = (Inflater)inflaters.remove(size - 1);
  • 264 inf.reset();
  • 265 return inf;
  • 266 } else {
  • 267 return new Inflater(true);
  • 268 }
  • 269 }
  • 270 }
  • 271
  • 272 /*
  • 273 * Releases the specified inflater to the list of available inflaters.
  • 274 */
  • 275 private void releaseInflater(Inflater inf) {
  • 276 synchronized (inflaters) {
  • 277 inflaters.add(inf);
  • 278 }
  • 279 }
  • 280
  • 281 // List of available Inflater objects for decompression
  • 282 private Vector inflaters = new Vector();
  • 283
  • 284 /**
  • 285 * Returns the path name of the ZIP file.
  • 286 * @return the path name of the ZIP file
  • 287 */
  • 288 public String getName() {
  • 289 return name;
  • 290 }
  • 291
  • 292 /**
  • 293 * Returns an enumeration of the ZIP file entries.
  • 294 * @return an enumeration of the ZIP file entries
  • 295 * @throws IllegalStateException if the zip file has been closed
  • 296 */
  • 297 public Enumeration<? extends ZipEntry> entries() {
  • 298 ensureOpen();
  • 299 return new Enumeration<ZipEntry>() {
  • 300 private int i = 0;
  • 301 public boolean hasMoreElements() {
  • 302 synchronized (ZipFile.this) {
  • 303 ensureOpen();
  • 304 return i < total;
  • 305 }
  • 306 }
  • 307 public ZipEntry nextElement() throws NoSuchElementException {
  • 308 synchronized (ZipFile.this) {
  • 309 ensureOpen();
  • 310 if (i >= total) {
  • 311 throw new NoSuchElementException();
  • 312 }
  • 313 long jzentry = getNextEntry(jzfile, i++);
  • 314 if (jzentry == 0) {
  • 315 String message;
  • 316 if (closeRequested) {
  • 317 message = "ZipFile concurrently closed";
  • 318 } else {
  • 319 message = getZipMessage(ZipFile.this.jzfile);
  • 320 }
  • 321 throw new ZipError("jzentry == 0" +
  • 322 ",\n jzfile = " + ZipFile.this.jzfile +
  • 323 ",\n total = " + ZipFile.this.total +
  • 324 ",\n name = " + ZipFile.this.name +
  • 325 ",\n i = " + i +
  • 326 ",\n message = " + message
  • 327 );
  • 328 }
  • 329 ZipEntry ze = new ZipEntry(jzentry);
  • 330 freeEntry(jzfile, jzentry);
  • 331 return ze;
  • 332 }
  • 333 }
  • 334 };
  • 335 }
  • 336
  • 337 private static native long getNextEntry(long jzfile, int i);
  • 338
  • 339 /**
  • 340 * Returns the number of entries in the ZIP file.
  • 341 * @return the number of entries in the ZIP file
  • 342 * @throws IllegalStateException if the zip file has been closed
  • 343 */
  • 344 public int size() {
  • 345 ensureOpen();
  • 346 return total;
  • 347 }
  • 348
  • 349 /**
  • 350 * Closes the ZIP file.
  • 351 * <p> Closing this ZIP file will close all of the input streams
  • 352 * previously returned by invocations of the {@link #getInputStream
  • 353 * getInputStream} method.
  • 354 *
  • 355 * @throws IOException if an I/O error has occurred
  • 356 */
  • 357 public void close() throws IOException {
  • 358 synchronized (this) {
  • 359 closeRequested = true;
  • 360
  • 361 if (jzfile != 0) {
  • 362 // Close the zip file
  • 363 long zf = this.jzfile;
  • 364 jzfile = 0;
  • 365
  • 366 close(zf);
  • 367
  • 368 // Release inflaters
  • 369 synchronized (inflaters) {
  • 370 int size = inflaters.size();
  • 371 for (int i = 0; i < size; i++) {
  • 372 Inflater inf = (Inflater)inflaters.get(i);
  • 373 inf.end();
  • 374 }
  • 375 }
  • 376 }
  • 377 }
  • 378 }
  • 379
  • 380
  • 381 /**
  • 382 * Ensures that the <code>close</code> method of this ZIP file is
  • 383 * called when there are no more references to it.
  • 384 *
  • 385 * <p>
  • 386 * Since the time when GC would invoke this method is undetermined,
  • 387 * it is strongly recommended that applications invoke the <code>close</code>
  • 388 * method as soon they have finished accessing this <code>ZipFile</code>.
  • 389 * This will prevent holding up system resources for an undetermined
  • 390 * length of time.
  • 391 *
  • 392 * @throws IOException if an I/O error has occurred
  • 393 * @see java.util.zip.ZipFile#close()
  • 394 */
  • 395 protected void finalize() throws IOException {
  • 396 close();
  • 397 }
  • 398
  • 399 private static native void close(long jzfile);
  • 400
  • 401 private void ensureOpen() {
  • 402 if (closeRequested) {
  • 403 throw new IllegalStateException("zip file closed");
  • 404 }
  • 405
  • 406 if (jzfile == 0) {
  • 407 throw new IllegalStateException("The object is not initialized.");
  • 408 }
  • 409 }
  • 410
  • 411 private void ensureOpenOrZipException() throws IOException {
  • 412 if (closeRequested) {
  • 413 throw new ZipException("ZipFile closed");
  • 414 }
  • 415 }
  • 416
  • 417 /*
  • 418 * Inner class implementing the input stream used to read a
  • 419 * (possibly compressed) zip file entry.
  • 420 */
  • 421 private class ZipFileInputStream extends InputStream {
  • 422 protected long jzentry; // address of jzentry data
  • 423 private long pos; // current position within entry data
  • 424 protected long rem; // number of remaining bytes within entry
  • 425 protected long size; // uncompressed size of this entry
  • 426
  • 427 ZipFileInputStream(long jzentry) {
  • 428 pos = 0;
  • 429 rem = getCSize(jzentry);
  • 430 size = getSize(jzentry);
  • 431 this.jzentry = jzentry;
  • 432 }
  • 433
  • 434 public int read(byte b[], int off, int len) throws IOException {
  • 435 if (rem == 0) {
  • 436 return -1;
  • 437 }
  • 438 if (len <= 0) {
  • 439 return 0;
  • 440 }
  • 441 if (len > rem) {
  • 442 len = (int) rem;
  • 443 }
  • 444 synchronized (ZipFile.this) {
  • 445 ensureOpenOrZipException();
  • 446
  • 447 len = ZipFile.read(ZipFile.this.jzfile, jzentry, pos, b,
  • 448 off, len);
  • 449 }
  • 450 if (len > 0) {
  • 451 pos += len;
  • 452 rem -= len;
  • 453 }
  • 454 if (rem == 0) {
  • 455 close();
  • 456 }
  • 457 return len;
  • 458 }
  • 459
  • 460 public int read() throws IOException {
  • 461 byte[] b = new byte[1];
  • 462 if (read(b, 0, 1) == 1) {
  • 463 return b[0] & 0xff;
  • 464 } else {
  • 465 return -1;
  • 466 }
  • 467 }
  • 468
  • 469 public long skip(long n) {
  • 470 if (n > rem)
  • 471 n = rem;
  • 472 pos += n;
  • 473 rem -= n;
  • 474 if (rem == 0) {
  • 475 close();
  • 476 }
  • 477 return n;
  • 478 }
  • 479
  • 480 public int available() {
  • 481 return rem > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) rem;
  • 482 }
  • 483
  • 484 public long size() {
  • 485 return size;
  • 486 }
  • 487
  • 488 public void close() {
  • 489 rem = 0;
  • 490 synchronized (ZipFile.this) {
  • 491 if (jzentry != 0 && ZipFile.this.jzfile != 0) {
  • 492 freeEntry(ZipFile.this.jzfile, jzentry);
  • 493 jzentry = 0;
  • 494 }
  • 495 }
  • 496 }
  • 497
  • 498 }
  • 499
  • 500 private static native int read(long jzfile, long jzentry,
  • 501 long pos, byte[] b, int off, int len);
  • 502
  • 503 private static native long getCSize(long jzentry);
  • 504
  • 505 private static native long getSize(long jzentry);
  • 506
  • 507 // Temporary add on for bug troubleshooting
  • 508 private static native String getZipMessage(long jzfile);
  • 509}

文件:ZipFile.java
包名:java.util.zip
类名:ZipFile
继承:
接口:[ZipConstants]