1 7 8 package java.util.zip; 9 10 import java.io.InputStream ; 11 import java.io.IOException ; 12 import java.io.EOFException ; 13 import java.io.File ; 14 import java.util.Vector ; 15 import java.util.Enumeration ; 16 import java.util.NoSuchElementException ; 17 import java.security.AccessController ; 18 import java.security.PrivilegedAction ; 19 import java.nio.ByteBuffer ; 20 import java.nio.MappedByteBuffer ; 21 import sun.nio.ByteBuffered; 22 import java.lang.reflect.*; 23 24 34 public 35 class ZipFile implements ZipConstants { 36 private long jzfile; private String name; private int total; private MappedByteBuffer mappedBuffer; private ZipCloser closer; private boolean mbUsed; private boolean closeRequested; 43 44 private static final int STORED = ZipEntry.STORED; 45 private static final int DEFLATED = ZipEntry.DEFLATED; 46 47 50 public static final int OPEN_READ = 0x1; 51 52 59 public static final int OPEN_DELETE = 0x4; 60 61 static { 62 63 initIDs(); 64 } 65 66 private static native void initIDs(); 67 68 83 public ZipFile(String name) throws IOException { 84 this(new File (name), OPEN_READ); 85 } 86 87 100 private static class ZipCloser 101 implements Runnable 102 { 103 private long mappedFileID; 104 105 private ZipCloser(long jzFile) { 106 mappedFileID = jzFile; 107 } 108 109 public synchronized void setClosed() { 110 mappedFileID = 0; 111 } 112 113 public synchronized void run() { 114 if (mappedFileID != 0) { 115 ZipFile.close(mappedFileID); 116 mappedFileID = 0; 117 } 118 } 119 } 120 121 private static Constructor directByteBufferConstructor = null; 122 123 private static void initDBBConstructor() { 124 AccessController.doPrivileged(new PrivilegedAction () { 125 public Object run() { 126 try { 127 Class th = Class.forName("java.nio.DirectByteBuffer"); 128 directByteBufferConstructor 129 = th.getDeclaredConstructor( 130 new Class [] { int.class, 131 long.class, 132 Runnable .class }); 133 directByteBufferConstructor.setAccessible(true); 134 } catch (ClassNotFoundException x) { 135 throw new InternalError (); 136 } catch (NoSuchMethodException x) { 137 throw new InternalError (); 138 } catch (IllegalArgumentException x) { 139 throw new InternalError (); 140 } catch (ClassCastException x) { 141 throw new InternalError (); 142 } 143 return null; 144 }}); 145 } 146 147 private static MappedByteBuffer newMappedByteBuffer(int size, long addr, 148 Runnable unmapper) 149 { 150 MappedByteBuffer dbb; 151 if (directByteBufferConstructor == null) 152 initDBBConstructor(); 153 try { 154 dbb = (MappedByteBuffer )directByteBufferConstructor.newInstance( 155 new Object [] { new Integer (size), 156 new Long (addr), 157 unmapper }); 158 } catch (InstantiationException e) { 159 throw new InternalError (); 160 } catch (IllegalAccessException e) { 161 throw new InternalError (); 162 } catch (InvocationTargetException e) { 163 throw new InternalError (); 164 } 165 return dbb; 166 } 167 168 189 public ZipFile(File file, int mode) throws IOException { 190 if (((mode & OPEN_READ) == 0) || 191 ((mode & ~(OPEN_READ | OPEN_DELETE)) != 0)) { 192 throw new IllegalArgumentException ("Illegal mode: 0x"+ 193 Integer.toHexString(mode)); 194 } 195 String name = file.getPath(); 196 SecurityManager sm = System.getSecurityManager(); 197 if (sm != null) { 198 sm.checkRead(name); 199 if ((mode & OPEN_DELETE) != 0) { 200 sm.checkDelete(name); 201 } 202 } 203 long jzfileCopy = open(name, mode, file.lastModified()); 204 this.name = name; 205 this.total = getTotal(jzfileCopy); 206 this.mbUsed = false; 207 long mappedAddr = getMappedAddr(jzfileCopy); 208 long len = getMappedLen(jzfileCopy); 209 210 if (mappedAddr != 0 && len < Integer.MAX_VALUE) { 211 this.closer = new ZipCloser(jzfileCopy); 214 this.mappedBuffer = newMappedByteBuffer((int)len, mappedAddr, 215 this.closer); 216 } 217 218 jzfile = jzfileCopy; 219 } 220 221 private static native long open(String name, int mode, long lastModified); 222 private static native int getTotal(long jzfile); 223 private static native long getMappedAddr(long jzfile); 224 private static native long getMappedLen(long jzfile); 225 226 227 233 public ZipFile(File file) throws ZipException , IOException { 234 this(file, OPEN_READ); 235 } 236 237 245 public ZipEntry getEntry(String name) { 246 if (name == null) { 247 throw new NullPointerException ("name"); 248 } 249 long jzentry = 0; 250 synchronized (this) { 251 ensureOpen(); 252 jzentry = getEntry(jzfile, name, true); 253 if (jzentry != 0) { 254 ZipEntry ze = new ZipEntry (name, jzentry); 255 freeEntry(jzfile, jzentry); 256 return ze; 257 } 258 } 259 return null; 260 } 261 262 private static native long getEntry(long jzfile, String name, 263 boolean addSlash); 264 265 private static native void freeEntry(long jzfile, long jzentry); 267 268 285 public InputStream getInputStream(ZipEntry entry) throws IOException { 286 return getInputStream(entry.name); 287 } 288 289 293 private InputStream getInputStream(String name) throws IOException { 294 if (name == null) { 295 throw new NullPointerException ("name"); 296 } 297 long jzentry = 0; 298 ZipFileInputStream in = null; 299 synchronized (this) { 300 ensureOpen(); 301 jzentry = getEntry(jzfile, name, false); 302 if (jzentry == 0) { 303 return null; 304 } 305 if (mappedBuffer != null) { 306 in = new MappedZipFileInputStream(jzentry, name); 307 } else { 308 in = new ZipFileInputStream(jzentry); 309 } 310 } 311 final ZipFileInputStream zfin = in; 312 switch (getMethod(jzentry)) { 313 case STORED: 314 return zfin; 315 case DEFLATED: 316 long size = getSize(jzentry) + 2; if (size > 65536) size = 8192; 319 if (size <= 0) size = 4096; 320 return new InflaterInputStream (zfin, getInflater(), (int)size) { 321 private boolean isClosed = false; 322 323 public void close() throws IOException { 324 if (!isClosed) { 325 releaseInflater(inf); 326 this.in.close(); 327 isClosed = true; 328 } 329 } 330 protected void fill() throws IOException { 334 if (eof) { 335 throw new EOFException ( 336 "Unexpected end of ZLIB input stream"); 337 } 338 len = this.in.read(buf, 0, buf.length); 339 if (len == -1) { 340 buf[0] = 0; 341 len = 1; 342 eof = true; 343 } 344 inf.setInput(buf, 0, len); 345 } 346 private boolean eof; 347 348 public int available() throws IOException { 349 if (isClosed) 350 return 0; 351 long avail = zfin.size() - inf.getBytesWritten(); 352 return avail > (long) Integer.MAX_VALUE ? 353 Integer.MAX_VALUE : (int) avail; 354 } 355 }; 356 default: 357 throw new ZipException ("invalid compression method"); 358 } 359 } 360 361 private static native int getMethod(long jzentry); 362 363 367 private Inflater getInflater() { 368 synchronized (inflaters) { 369 int size = inflaters.size(); 370 if (size > 0) { 371 Inflater inf = (Inflater )inflaters.remove(size - 1); 372 inf.reset(); 373 return inf; 374 } else { 375 return new Inflater (true); 376 } 377 } 378 } 379 380 383 private void releaseInflater(Inflater inf) { 384 synchronized (inflaters) { 385 inflaters.add(inf); 386 } 387 } 388 389 private Vector inflaters = new Vector (); 391 392 396 public String getName() { 397 return name; 398 } 399 400 405 public Enumeration <? extends ZipEntry > entries() { 406 ensureOpen(); 407 return new Enumeration <ZipEntry >() { 408 private int i = 0; 409 public boolean hasMoreElements() { 410 synchronized (ZipFile.this) { 411 ensureOpen(); 412 return i < total; 413 } 414 } 415 public ZipEntry nextElement() throws NoSuchElementException { 416 synchronized (ZipFile.this) { 417 ensureOpen(); 418 if (i >= total) { 419 throw new NoSuchElementException (); 420 } 421 long jzentry = getNextEntry(jzfile, i++); 422 if (jzentry == 0) { 423 String message; 424 if (closeRequested) { 425 message = "ZipFile concurrently closed"; 426 } else { 427 message = getZipMessage(ZipFile.this.jzfile); 428 } 429 throw new InternalError ("jzentry == 0" + 430 ",\n jzfile = " + ZipFile.this.jzfile + 431 ",\n total = " + ZipFile.this.total + 432 ",\n name = " + ZipFile.this.name + 433 ",\n i = " + i + 434 ",\n message = " + message 435 ); 436 } 437 ZipEntry ze = new ZipEntry (jzentry); 438 freeEntry(jzfile, jzentry); 439 return ze; 440 } 441 } 442 }; 443 } 444 445 private static native long getNextEntry(long jzfile, int i); 446 447 452 public int size() { 453 ensureOpen(); 454 return total; 455 } 456 457 465 public void close() throws IOException { 466 synchronized (this) { 467 closeRequested = true; 468 469 if (jzfile != 0) { 470 long zf = this.jzfile; 472 jzfile = 0; 473 if (closer != null) { 474 if (!mbUsed) { closer.setClosed(); close(zf); 477 } 478 } else { 481 close(zf); 482 } 483 synchronized (inflaters) { 485 int size = inflaters.size(); 486 for (int i = 0; i < size; i++) { 487 Inflater inf = (Inflater )inflaters.get(i); 488 inf.end(); 489 } 490 } 491 } 492 } 493 } 494 495 496 510 protected void finalize() throws IOException { 511 close(); 512 } 513 514 private static native void close(long jzfile); 515 516 private void ensureOpen() { 517 if (closeRequested) { 518 throw new IllegalStateException ("zip file closed"); 519 } 520 } 521 522 private void ensureOpenOrZipException() throws IOException { 523 if (closeRequested) { 524 throw new ZipException ("ZipFile closed"); 525 } 526 } 527 528 532 private class ZipFileInputStream extends InputStream { 533 protected long jzentry; private long pos; protected long rem; protected long size; 538 ZipFileInputStream(long jzentry) { 539 pos = 0; 540 rem = getCSize(jzentry); 541 size = getSize(jzentry); 542 this.jzentry = jzentry; 543 } 544 545 public int read(byte b[], int off, int len) throws IOException { 546 if (rem == 0) { 547 return -1; 548 } 549 if (len <= 0) { 550 return 0; 551 } 552 if (len > rem) { 553 len = (int) rem; 554 } 555 synchronized (ZipFile.this) { 556 ensureOpenOrZipException(); 557 558 len = ZipFile.read(ZipFile.this.jzfile, jzentry, pos, b, 559 off, len); 560 } 561 if (len > 0) { 562 pos += len; 563 rem -= len; 564 } 565 if (rem == 0) { 566 close(); 567 } 568 return len; 569 } 570 571 public int read() throws IOException { 572 byte[] b = new byte[1]; 573 if (read(b, 0, 1) == 1) { 574 return b[0] & 0xff; 575 } else { 576 return -1; 577 } 578 } 579 580 public long skip(long n) { 581 if (n > rem) 582 n = rem; 583 pos += n; 584 rem -= n; 585 if (rem == 0) { 586 close(); 587 } 588 return n; 589 } 590 591 public int available() { 592 return rem > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) rem; 593 } 594 595 public long size() { 596 return size; 597 } 598 599 public void close() { 600 rem = 0; 601 synchronized (ZipFile.this) { 602 if (jzentry != 0 && ZipFile.this.jzfile != 0) { 603 freeEntry(ZipFile.this.jzfile, jzentry); 604 jzentry = 0; 605 } 606 } 607 } 608 609 } 610 611 616 private class MappedZipFileInputStream extends ZipFileInputStream 617 implements ByteBuffered { 618 619 private ByteBuffer directBuffer = null; 620 private String name; 621 622 MappedZipFileInputStream(long jzentry, String name) { 623 super(jzentry); 624 this.name = name; 625 int offset = (int)getEntryOffset(jzentry); 626 MappedByteBuffer bb = ZipFile.this.mappedBuffer; 627 synchronized (bb) { 628 bb.position(offset); 629 bb.limit((int)(offset + rem)); 631 this.directBuffer = bb.slice(); 632 633 bb.position(0); bb.limit(bb.capacity()); } 636 } 637 638 641 public ByteBuffer getByteBuffer() throws IOException { 642 synchronized (ZipFile.this) { 643 ensureOpenOrZipException(); 644 ZipFile.this.mbUsed = true; 646 return directBuffer; 647 } 648 } 649 650 public int read(byte b[], int off, int len) throws IOException { 651 int rem = directBuffer.remaining(); 652 if (rem == 0) { 653 return -1; 654 } 655 if (len <= 0) { 656 return 0; 657 } 658 if (len > rem) { 659 len = rem; 660 } 661 synchronized (ZipFile.this) { 662 ensureOpenOrZipException(); 663 664 directBuffer.get(b, off, len); 665 } 666 667 if (len == rem) { 668 close(); 669 } 670 return len; 671 } 672 673 public int read() throws IOException { 674 synchronized (ZipFile.this) { 675 ensureOpenOrZipException(); 676 677 if (directBuffer.remaining() == 0) { 678 return -1; 679 } else { 680 return directBuffer.get() & 0xff; 681 } 682 } 683 } 684 685 public long skip(long n) { 686 int rem = directBuffer.remaining(); 687 int len = n > rem ? rem : (int)n; 688 directBuffer.position(directBuffer.position() + len); 689 if (len == rem) { 690 close(); 691 } 692 return len; 693 } 694 695 public int available() { 696 return directBuffer.remaining(); 697 } 698 699 public long size() { 700 return size; 701 } 702 703 public void close() { 704 directBuffer.position(directBuffer.limit()); 705 synchronized (ZipFile.this) { 706 if (jzentry != 0 && ZipFile.this.jzfile != 0) { 707 freeEntry(ZipFile.this.jzfile, jzentry); 708 jzentry = 0; 709 } 710 } 711 } 712 713 } 714 715 private static native int read(long jzfile, long jzentry, 716 long pos, byte[] b, int off, int len); 717 718 private static native long getCSize(long jzentry); 719 720 private static native long getSize(long jzentry); 721 722 724 private static native long getEntryOffset(long jzentry); 725 726 private static native String getZipMessage(long jzfile); 728 } 729 | Popular Tags |