< prev index next >

src/java.base/share/classes/java/util/zip/ZipFile.java

Print this page
0000000: Optimize ZipCoder
Reviewed-by: sherman


 360      * Closing this ZIP file will, in turn, close all input streams that
 361      * have been returned by invocations of this method.
 362      *
 363      * @param entry the zip file entry
 364      * @return the input stream for reading the contents of the specified
 365      * zip file entry.
 366      * @throws ZipException if a ZIP format error has occurred
 367      * @throws IOException if an I/O error has occurred
 368      * @throws IllegalStateException if the zip file has been closed
 369      */
 370     public InputStream getInputStream(ZipEntry entry) throws IOException {
 371         Objects.requireNonNull(entry, "entry");
 372         int pos = -1;
 373         ZipFileInputStream in;
 374         Source zsrc = res.zsrc;
 375         Set<InputStream> istreams = res.istreams;
 376         synchronized (this) {
 377             ensureOpen();
 378             if (Objects.equals(lastEntryName, entry.name)) {
 379                 pos = lastEntryPos;
 380             } else if (!zc.isUTF8() && (entry.flag & EFS) != 0) {
 381                 pos = zsrc.getEntryPos(zc.getBytesUTF8(entry.name), false);
 382             } else {
 383                 pos = zsrc.getEntryPos(zc.getBytes(entry.name), false);
 384             }
 385             if (pos == -1) {
 386                 return null;
 387             }
 388             in = new ZipFileInputStream(zsrc.cen, pos);
 389             switch (CENHOW(zsrc.cen, pos)) {
 390             case STORED:
 391                 synchronized (istreams) {
 392                     istreams.add(in);
 393                 }
 394                 return in;
 395             case DEFLATED:
 396                 // Inflater likes a bit of slack
 397                 // MORE: Compute good size for inflater stream:
 398                 long size = CENLEN(zsrc.cen, pos) + 2;
 399                 if (size > 65536) {
 400                     size = 8192;
 401                 }


 538 
 539     /**
 540      * Returns an enumeration of the ZIP file entries.
 541      * @return an enumeration of the ZIP file entries
 542      * @throws IllegalStateException if the zip file has been closed
 543      */
 544     public Enumeration<? extends ZipEntry> entries() {
 545         synchronized (this) {
 546             ensureOpen();
 547             return new ZipEntryIterator<ZipEntry>(res.zsrc.total, ZipEntry::new);
 548         }
 549     }
 550 
 551     private Enumeration<JarEntry> entries(Function<String, JarEntry> func) {
 552         synchronized (this) {
 553             ensureOpen();
 554             return new ZipEntryIterator<JarEntry>(res.zsrc.total, func);
 555         }
 556     }
 557 


















































 558     private class EntrySpliterator<T> extends Spliterators.AbstractSpliterator<T> {
 559         private int index;
 560         private final int fence;
 561         private final IntFunction<T> gen;
 562 
 563         EntrySpliterator(int index, int fence, IntFunction<T> gen) {
 564             super((long)fence,
 565                   Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.IMMUTABLE |
 566                   Spliterator.NONNULL);
 567             this.index = index;
 568             this.fence = fence;
 569             this.gen = gen;
 570         }
 571 
 572         @Override
 573         public boolean tryAdvance(Consumer<? super T> action) {
 574             if (action == null)
 575                 throw new NullPointerException();
 576             if (index >= 0 && index < fence) {
 577                 synchronized (ZipFile.this) {


 589      *
 590      * Entries appear in the {@code Stream} in the order they appear in
 591      * the central directory of the ZIP file.
 592      *
 593      * @return an ordered {@code Stream} of entries in this ZIP file
 594      * @throws IllegalStateException if the zip file has been closed
 595      * @since 1.8
 596      */
 597     public Stream<? extends ZipEntry> stream() {
 598         synchronized (this) {
 599             ensureOpen();
 600             return StreamSupport.stream(new EntrySpliterator<>(0, res.zsrc.total,
 601                 pos -> getZipEntry(null, null, pos, ZipEntry::new)), false);
 602        }
 603     }
 604 
 605     private String getEntryName(int pos) {
 606         byte[] cen = res.zsrc.cen;
 607         int nlen = CENNAM(cen, pos);
 608         if (!zc.isUTF8() && (CENFLG(cen, pos) & EFS) != 0) {
 609             return zc.toStringUTF8(cen, pos + CENHDR, nlen);
 610         } else {
 611             return zc.toString(cen, pos + CENHDR, nlen);
 612         }
 613     }
 614 
 615     /*
 616      * Returns an ordered {@code Stream} over the zip file entry names.
 617      *
 618      * Entry names appear in the {@code Stream} in the order they appear in
 619      * the central directory of the ZIP file.
 620      *
 621      * @return an ordered {@code Stream} of entry names in this zip file
 622      * @throws IllegalStateException if the zip file has been closed
 623      * @since 10
 624      */
 625     private Stream<String> entryNameStream() {
 626         synchronized (this) {
 627             ensureOpen();
 628             return StreamSupport.stream(
 629                 new EntrySpliterator<>(0, res.zsrc.total, this::getEntryName), false);


 649         }
 650     }
 651 
 652     private String lastEntryName;
 653     private int lastEntryPos;
 654 
 655     /* Checks ensureOpen() before invoke this method */
 656     private ZipEntry getZipEntry(String name, byte[] bname, int pos,
 657                                  Function<String, ? extends ZipEntry> func) {
 658         byte[] cen = res.zsrc.cen;
 659         int nlen = CENNAM(cen, pos);
 660         int elen = CENEXT(cen, pos);
 661         int clen = CENCOM(cen, pos);
 662         int flag = CENFLG(cen, pos);
 663         if (name == null || bname.length != nlen) {
 664             // to use the entry name stored in cen, if the passed in name is
 665             // (1) null, invoked from iterator, or
 666             // (2) not equal to the name stored, a slash is appended during
 667             // getEntryPos() search.
 668             if (!zc.isUTF8() && (flag & EFS) != 0) {
 669                 name = zc.toStringUTF8(cen, pos + CENHDR, nlen);
 670             } else {
 671                 name = zc.toString(cen, pos + CENHDR, nlen);
 672             }
 673         }
 674         ZipEntry e = func.apply(name);    //ZipEntry e = new ZipEntry(name);
 675         e.flag = flag;
 676         e.xdostime = CENTIM(cen, pos);
 677         e.crc = CENCRC(cen, pos);
 678         e.size = CENLEN(cen, pos);
 679         e.csize = CENSIZ(cen, pos);
 680         e.method = CENHOW(cen, pos);
 681         if (elen != 0) {
 682             int start = pos + CENHDR + nlen;
 683             e.setExtra0(Arrays.copyOfRange(cen, start, start + elen), true);
 684         }
 685         if (clen != 0) {
 686             int start = pos + CENHDR + nlen + elen;
 687             if (!zc.isUTF8() && (flag & EFS) != 0) {
 688                 e.comment = zc.toStringUTF8(cen, start, clen);
 689             } else {
 690                 e.comment = zc.toString(cen, start, clen);
 691             }
 692         }
 693         lastEntryName = e.name;
 694         lastEntryPos = pos;
 695         return e;
 696     }
 697 
 698     /**
 699      * Returns the number of entries in the ZIP file.
 700      *
 701      * @return the number of entries in the ZIP file
 702      * @throws IllegalStateException if the zip file has been closed
 703      */
 704     public int size() {
 705         synchronized (this) {
 706             ensureOpen();
 707             return res.zsrc.total;
 708         }




 360      * Closing this ZIP file will, in turn, close all input streams that
 361      * have been returned by invocations of this method.
 362      *
 363      * @param entry the zip file entry
 364      * @return the input stream for reading the contents of the specified
 365      * zip file entry.
 366      * @throws ZipException if a ZIP format error has occurred
 367      * @throws IOException if an I/O error has occurred
 368      * @throws IllegalStateException if the zip file has been closed
 369      */
 370     public InputStream getInputStream(ZipEntry entry) throws IOException {
 371         Objects.requireNonNull(entry, "entry");
 372         int pos = -1;
 373         ZipFileInputStream in;
 374         Source zsrc = res.zsrc;
 375         Set<InputStream> istreams = res.istreams;
 376         synchronized (this) {
 377             ensureOpen();
 378             if (Objects.equals(lastEntryName, entry.name)) {
 379                 pos = lastEntryPos;
 380             } else if (zc.isUTF8() || (entry.flag & EFS) != 0) {
 381                 pos = zsrc.getEntryPos(ZipCoder.getBytesUTF8(entry.name), false);
 382             } else {
 383                 pos = zsrc.getEntryPos(zc.getBytes(entry.name), false);
 384             }
 385             if (pos == -1) {
 386                 return null;
 387             }
 388             in = new ZipFileInputStream(zsrc.cen, pos);
 389             switch (CENHOW(zsrc.cen, pos)) {
 390             case STORED:
 391                 synchronized (istreams) {
 392                     istreams.add(in);
 393                 }
 394                 return in;
 395             case DEFLATED:
 396                 // Inflater likes a bit of slack
 397                 // MORE: Compute good size for inflater stream:
 398                 long size = CENLEN(zsrc.cen, pos) + 2;
 399                 if (size > 65536) {
 400                     size = 8192;
 401                 }


 538 
 539     /**
 540      * Returns an enumeration of the ZIP file entries.
 541      * @return an enumeration of the ZIP file entries
 542      * @throws IllegalStateException if the zip file has been closed
 543      */
 544     public Enumeration<? extends ZipEntry> entries() {
 545         synchronized (this) {
 546             ensureOpen();
 547             return new ZipEntryIterator<ZipEntry>(res.zsrc.total, ZipEntry::new);
 548         }
 549     }
 550 
 551     private Enumeration<JarEntry> entries(Function<String, JarEntry> func) {
 552         synchronized (this) {
 553             ensureOpen();
 554             return new ZipEntryIterator<JarEntry>(res.zsrc.total, func);
 555         }
 556     }
 557 
 558     private static class MartinSpliterator extends Spliterators.AbstractIntSpliterator {
 559         private int index;
 560         private final @Stable int fence;
 561         //private final @Stable byte[] cen;
 562         private final @Stable int[] entries;
 563 
 564         MartinSpliterator(int fence, int[] entries) {
 565             super(fence, Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.IMMUTABLE);
 566             this.index = 0;
 567             this.fence = fence;
 568             this.entries = entries;
 569         }
 570 
 571         @Override
 572         public boolean tryAdvance(java.util.function.IntConsumer action) {
 573             if (action == null) throw new NullPointerException();
 574             //if (closeRequested) throw new IllegalStateException("zip file closed");
 575             if (index >= fence)
 576                 return false;
 577             action.accept(entries[(index++ * 3) + 2]);
 578             return true;
 579         }
 580     }
 581 
 582     private Stream<String> martinNames() {
 583         final byte[] cen;
 584         final java.util.stream.IntStream intStream;
 585         synchronized (this) {
 586             ensureOpen();
 587             cen = res.zsrc.cen;
 588             intStream = StreamSupport.intStream(
 589                     new MartinSpliterator(res.zsrc.total, res.zsrc.entries),
 590                     false);
 591         }
 592         return (zc.isUTF8())
 593             ? intStream.mapToObj(i -> martinNameUTF8(zc, cen, i))
 594             : intStream.mapToObj(i -> martinName(zc, cen, i));
 595     }
 596 
 597     private static String martinNameUTF8(ZipCoder zc, byte[] cen, int pos) {
 598         return ZipCoder.toStringUTF8(cen, pos + CENHDR, CENNAM(cen, pos));
 599     }
 600 
 601     private static String martinName(ZipCoder zc, byte[] cen, int pos) {
 602         int nlen = CENNAM(cen, pos);
 603         return ((CENFLG(cen, pos) & EFS) != 0)
 604             ? ZipCoder.toStringUTF8(cen, pos + CENHDR, nlen)
 605             : zc.toString(cen, pos + CENHDR, nlen);
 606     }
 607 
 608     private class EntrySpliterator<T> extends Spliterators.AbstractSpliterator<T> {
 609         private int index;
 610         private final int fence;
 611         private final IntFunction<T> gen;
 612 
 613         EntrySpliterator(int index, int fence, IntFunction<T> gen) {
 614             super((long)fence,
 615                   Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.IMMUTABLE |
 616                   Spliterator.NONNULL);
 617             this.index = index;
 618             this.fence = fence;
 619             this.gen = gen;
 620         }
 621 
 622         @Override
 623         public boolean tryAdvance(Consumer<? super T> action) {
 624             if (action == null)
 625                 throw new NullPointerException();
 626             if (index >= 0 && index < fence) {
 627                 synchronized (ZipFile.this) {


 639      *
 640      * Entries appear in the {@code Stream} in the order they appear in
 641      * the central directory of the ZIP file.
 642      *
 643      * @return an ordered {@code Stream} of entries in this ZIP file
 644      * @throws IllegalStateException if the zip file has been closed
 645      * @since 1.8
 646      */
 647     public Stream<? extends ZipEntry> stream() {
 648         synchronized (this) {
 649             ensureOpen();
 650             return StreamSupport.stream(new EntrySpliterator<>(0, res.zsrc.total,
 651                 pos -> getZipEntry(null, null, pos, ZipEntry::new)), false);
 652        }
 653     }
 654 
 655     private String getEntryName(int pos) {
 656         byte[] cen = res.zsrc.cen;
 657         int nlen = CENNAM(cen, pos);
 658         if (!zc.isUTF8() && (CENFLG(cen, pos) & EFS) != 0) {
 659             return ZipCoder.toStringUTF8(cen, pos + CENHDR, nlen);
 660         } else {
 661             return zc.toString(cen, pos + CENHDR, nlen);
 662         }
 663     }
 664 
 665     /*
 666      * Returns an ordered {@code Stream} over the zip file entry names.
 667      *
 668      * Entry names appear in the {@code Stream} in the order they appear in
 669      * the central directory of the ZIP file.
 670      *
 671      * @return an ordered {@code Stream} of entry names in this zip file
 672      * @throws IllegalStateException if the zip file has been closed
 673      * @since 10
 674      */
 675     private Stream<String> entryNameStream() {
 676         synchronized (this) {
 677             ensureOpen();
 678             return StreamSupport.stream(
 679                 new EntrySpliterator<>(0, res.zsrc.total, this::getEntryName), false);


 699         }
 700     }
 701 
 702     private String lastEntryName;
 703     private int lastEntryPos;
 704 
 705     /* Checks ensureOpen() before invoke this method */
 706     private ZipEntry getZipEntry(String name, byte[] bname, int pos,
 707                                  Function<String, ? extends ZipEntry> func) {
 708         byte[] cen = res.zsrc.cen;
 709         int nlen = CENNAM(cen, pos);
 710         int elen = CENEXT(cen, pos);
 711         int clen = CENCOM(cen, pos);
 712         int flag = CENFLG(cen, pos);
 713         if (name == null || bname.length != nlen) {
 714             // to use the entry name stored in cen, if the passed in name is
 715             // (1) null, invoked from iterator, or
 716             // (2) not equal to the name stored, a slash is appended during
 717             // getEntryPos() search.
 718             if (!zc.isUTF8() && (flag & EFS) != 0) {
 719                 name = ZipCoder.toStringUTF8(cen, pos + CENHDR, nlen);
 720             } else {
 721                 name = zc.toString(cen, pos + CENHDR, nlen);
 722             }
 723         }
 724         ZipEntry e = func.apply(name);    //ZipEntry e = new ZipEntry(name);
 725         e.flag = flag;
 726         e.xdostime = CENTIM(cen, pos);
 727         e.crc = CENCRC(cen, pos);
 728         e.size = CENLEN(cen, pos);
 729         e.csize = CENSIZ(cen, pos);
 730         e.method = CENHOW(cen, pos);
 731         if (elen != 0) {
 732             int start = pos + CENHDR + nlen;
 733             e.setExtra0(Arrays.copyOfRange(cen, start, start + elen), true);
 734         }
 735         if (clen != 0) {
 736             int start = pos + CENHDR + nlen + elen;
 737             if (!zc.isUTF8() && (flag & EFS) != 0) {
 738                 e.comment = ZipCoder.toStringUTF8(cen, start, clen);
 739             } else {
 740                 e.comment = zc.toString(cen, start, clen);
 741             }
 742         }
 743         lastEntryName = e.name;
 744         lastEntryPos = pos;
 745         return e;
 746     }
 747 
 748     /**
 749      * Returns the number of entries in the ZIP file.
 750      *
 751      * @return the number of entries in the ZIP file
 752      * @throws IllegalStateException if the zip file has been closed
 753      */
 754     public int size() {
 755         synchronized (this) {
 756             ensureOpen();
 757             return res.zsrc.total;
 758         }


< prev index next >