327
328 // the outstanding inputstreams that need to be closed,
329 // mapped to the inflater objects they use.
330 private final Map<InputStream, Inflater> streams = new WeakHashMap<>();
331
332 /**
333 * Returns an input stream for reading the contents of the specified
334 * zip file entry.
335 *
336 * <p> Closing this ZIP file will, in turn, close all input
337 * streams that have been returned by invocations of this method.
338 *
339 * @param entry the zip file entry
340 * @return the input stream for reading the contents of the specified
341 * zip file entry.
342 * @throws ZipException if a ZIP format error has occurred
343 * @throws IOException if an I/O error has occurred
344 * @throws IllegalStateException if the zip file has been closed
345 */
346 public InputStream getInputStream(ZipEntry entry) throws IOException {
347 if (entry == null) {
348 throw new NullPointerException("entry");
349 }
350 long jzentry = 0;
351 ZipFileInputStream in = null;
352 synchronized (this) {
353 ensureOpen();
354 if (!zc.isUTF8() && (entry.flag & EFS) != 0) {
355 jzentry = getEntry(jzfile, zc.getBytesUTF8(entry.name), false);
356 } else {
357 jzentry = getEntry(jzfile, zc.getBytes(entry.name), false);
358 }
359 if (jzentry == 0) {
360 return null;
361 }
362 in = new ZipFileInputStream(jzentry);
363
364 switch (getEntryMethod(jzentry)) {
365 case STORED:
366 synchronized (streams) {
367 streams.put(in, null);
368 }
369 return in;
370 case DEFLATED:
371 // MORE: Compute good size for inflater stream:
372 long size = getEntrySize(jzentry) + 2; // Inflater likes a bit of slack
373 if (size > 65536) size = 8192;
374 if (size <= 0) size = 4096;
375 Inflater inf = getInflater();
376 InputStream is =
377 new ZipFileInflaterInputStream(in, inf, (int)size);
378 synchronized (streams) {
379 streams.put(is, inf);
380 }
381 return is;
382 default:
383 throw new ZipException("invalid compression method");
384 }
385 }
386 }
387
388 private class ZipFileInflaterInputStream extends InflaterInputStream {
389 private volatile boolean closeRequested = false;
390 private boolean eof = false;
391 private final ZipFileInputStream zfin;
392
393 ZipFileInflaterInputStream(ZipFileInputStream zfin, Inflater inf,
394 int size) {
395 super(zfin, inf, size);
679 throw new IllegalStateException("The object is not initialized.");
680 }
681 }
682
683 private void ensureOpenOrZipException() throws IOException {
684 if (closeRequested) {
685 throw new ZipException("ZipFile closed");
686 }
687 }
688
689 /*
690 * Inner class implementing the input stream used to read a
691 * (possibly compressed) zip file entry.
692 */
693 private class ZipFileInputStream extends InputStream {
694 private volatile boolean zfisCloseRequested = false;
695 protected long jzentry; // address of jzentry data
696 private long pos; // current position within entry data
697 protected long rem; // number of remaining bytes within entry
698 protected long size; // uncompressed size of this entry
699
700 ZipFileInputStream(long jzentry) {
701 pos = 0;
702 rem = getEntryCSize(jzentry);
703 size = getEntrySize(jzentry);
704 this.jzentry = jzentry;
705 }
706
707 public int read(byte b[], int off, int len) throws IOException {
708 synchronized (ZipFile.this) {
709 long rem = this.rem;
710 long pos = this.pos;
711 if (rem == 0) {
712 return -1;
713 }
714 if (len <= 0) {
715 return 0;
716 }
717 if (len > rem) {
718 len = (int) rem;
719 }
720
721 // Check if ZipFile open
722 ensureOpenOrZipException();
723 len = ZipFile.read(ZipFile.this.jzfile, jzentry, pos, b,
724 off, len);
725 if (len > 0) {
726 this.pos = (pos + len);
727 this.rem = (rem - len);
|
327
328 // the outstanding inputstreams that need to be closed,
329 // mapped to the inflater objects they use.
330 private final Map<InputStream, Inflater> streams = new WeakHashMap<>();
331
332 /**
333 * Returns an input stream for reading the contents of the specified
334 * zip file entry.
335 *
336 * <p> Closing this ZIP file will, in turn, close all input
337 * streams that have been returned by invocations of this method.
338 *
339 * @param entry the zip file entry
340 * @return the input stream for reading the contents of the specified
341 * zip file entry.
342 * @throws ZipException if a ZIP format error has occurred
343 * @throws IOException if an I/O error has occurred
344 * @throws IllegalStateException if the zip file has been closed
345 */
346 public InputStream getInputStream(ZipEntry entry) throws IOException {
347 return getInputStream(entry, null);
348 }
349
350 /**
351 * Returns an input stream for reading the contents of the specified
352 * zip file entry.
353 *
354 * <p> Closing this ZIP file will, in turn, close all input
355 * streams that have been returned by invocations of this method.
356 *
357 * @param entry the zip file entry
358 * @param zipCryption instance of ZipCryption
359 * @return the input stream for reading the contents of the specified
360 * zip file entry.
361 * @throws ZipException if a ZIP format error has occurred
362 * @throws IOException if an I/O error has occurred
363 * @throws IllegalStateException if the zip file has been closed
364 */
365 public InputStream getInputStream(ZipEntry entry, ZipCryption zipCryption)
366 throws IOException {
367 if (entry == null) {
368 throw new NullPointerException("entry");
369 }
370
371 if ((entry.flag & 1) == 1) {
372 if (zipCryption == null) {
373 throw new ZipException("Passphrase is required.");
374 } else {
375 zipCryption.reset();
376 }
377 }
378
379 long jzentry = 0;
380 ZipFileInputStream in = null;
381 synchronized (this) {
382 ensureOpen();
383 if (!zc.isUTF8() && (entry.flag & EFS) != 0) {
384 jzentry = getEntry(jzfile, zc.getBytesUTF8(entry.name), false);
385 } else {
386 jzentry = getEntry(jzfile, zc.getBytes(entry.name), false);
387 }
388 if (jzentry == 0) {
389 return null;
390 }
391 in = new ZipFileInputStream(jzentry, zipCryption);
392
393 switch (getEntryMethod(jzentry)) {
394 case STORED:
395
396 if ((entry.flag & 1) == 1) {
397 byte[] encryptionHeader =
398 new byte[zipCryption.getEncryptionHeaderSize()];
399 in.readRaw(encryptionHeader, 0, encryptionHeader.length);
400 zipCryption.decryptBytes(encryptionHeader);
401
402 if (!zipCryption.isValid(entry, encryptionHeader)) {
403 throw new ZipException("possibly incorrect passphrase");
404 }
405 }
406
407 synchronized (streams) {
408 streams.put(in, null);
409 }
410 return in;
411 case DEFLATED:
412 // MORE: Compute good size for inflater stream:
413 long size = getEntrySize(jzentry) + 2; // Inflater likes a bit of slack
414 if (size > 65536) size = 8192;
415 if (size <= 0) size = 4096;
416 Inflater inf = getInflater();
417
418 if ((entry.flag & 1) == 1) {
419 byte[] encryptionHeader =
420 new byte[zipCryption.getEncryptionHeaderSize()];
421 in.readRaw(encryptionHeader, 0, encryptionHeader.length);
422 zipCryption.decryptBytes(encryptionHeader);
423
424 if (!zipCryption.isValid(entry, encryptionHeader)) {
425 throw new ZipException("possibly incorrect passphrase");
426 }
427 }
428
429 InputStream is =
430 new ZipFileInflaterInputStream(in, inf, (int)size);
431 synchronized (streams) {
432 streams.put(is, inf);
433 }
434 return is;
435 default:
436 throw new ZipException("invalid compression method");
437 }
438 }
439 }
440
441 private class ZipFileInflaterInputStream extends InflaterInputStream {
442 private volatile boolean closeRequested = false;
443 private boolean eof = false;
444 private final ZipFileInputStream zfin;
445
446 ZipFileInflaterInputStream(ZipFileInputStream zfin, Inflater inf,
447 int size) {
448 super(zfin, inf, size);
732 throw new IllegalStateException("The object is not initialized.");
733 }
734 }
735
736 private void ensureOpenOrZipException() throws IOException {
737 if (closeRequested) {
738 throw new ZipException("ZipFile closed");
739 }
740 }
741
742 /*
743 * Inner class implementing the input stream used to read a
744 * (possibly compressed) zip file entry.
745 */
746 private class ZipFileInputStream extends InputStream {
747 private volatile boolean zfisCloseRequested = false;
748 protected long jzentry; // address of jzentry data
749 private long pos; // current position within entry data
750 protected long rem; // number of remaining bytes within entry
751 protected long size; // uncompressed size of this entry
752 private ZipCryption zipCryption; // ZIP encrypt/decrypt engine
753
754 ZipFileInputStream(long jzentry, ZipCryption zipCryption) {
755 pos = 0;
756 rem = getEntryCSize(jzentry);
757 size = getEntrySize(jzentry);
758 this.jzentry = jzentry;
759 this.zipCryption = zipCryption;
760 }
761
762 public int read(byte b[], int off, int len) throws IOException {
763 len = readRaw(b, off, len);
764
765 if (zipCryption != null) {
766 zipCryption.decryptBytes(b, off, len);
767 }
768
769 return len;
770 }
771
772 public int readRaw(byte b[], int off, int len) throws IOException {
773 synchronized (ZipFile.this) {
774 long rem = this.rem;
775 long pos = this.pos;
776 if (rem == 0) {
777 return -1;
778 }
779 if (len <= 0) {
780 return 0;
781 }
782 if (len > rem) {
783 len = (int) rem;
784 }
785
786 // Check if ZipFile open
787 ensureOpenOrZipException();
788 len = ZipFile.read(ZipFile.this.jzfile, jzentry, pos, b,
789 off, len);
790 if (len > 0) {
791 this.pos = (pos + len);
792 this.rem = (rem - len);
|