< prev index next >

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

Print this page
8200124: Various cleanups in jar/zip
Reviewed-by: sherman


  47 import java.util.HashMap;
  48 import java.util.Iterator;
  49 import java.util.Objects;
  50 import java.util.NoSuchElementException;
  51 import java.util.Set;
  52 import java.util.Spliterator;
  53 import java.util.Spliterators;
  54 import java.util.WeakHashMap;
  55 
  56 import java.util.function.Consumer;
  57 import java.util.function.Function;
  58 import java.util.function.IntFunction;
  59 import java.util.jar.JarEntry;
  60 import java.util.stream.Stream;
  61 import java.util.stream.StreamSupport;
  62 import jdk.internal.misc.JavaUtilZipFileAccess;
  63 import jdk.internal.misc.SharedSecrets;
  64 import jdk.internal.misc.VM;
  65 import jdk.internal.perf.PerfCounter;
  66 import jdk.internal.ref.CleanerFactory;

  67 
  68 import static java.util.zip.ZipConstants64.*;
  69 import static java.util.zip.ZipUtils.*;
  70 
  71 /**
  72  * This class is used to read entries from a zip file.
  73  *
  74  * <p> Unless otherwise noted, passing a {@code null} argument to a constructor
  75  * or method in this class will cause a {@link NullPointerException} to be
  76  * thrown.
  77  *
  78  * @apiNote
  79  * To release resources used by this {@code ZipFile}, the {@link #close()} method
  80  * should be called explicitly or by try-with-resources. Subclasses are responsible
  81  * for the cleanup of resources acquired by the subclass. Subclasses that override
  82  * {@link #finalize()} in order to perform cleanup should be modified to use alternative
  83  * cleanup mechanisms such as {@link java.lang.ref.Cleaner} and remove the overriding
  84  * {@code finalize} method.
  85  *
  86  * @implSpec
  87  * If this {@code ZipFile} has been subclassed and the {@code close} method has
  88  * been overridden, the {@code close} method will be called by the finalization
  89  * when {@code ZipFile} is unreachable. But the subclasses should not depend on
  90  * this specific implementation; the finalization is not reliable and the
  91  * {@code finalize} method is deprecated to be removed.
  92  *
  93  * @author      David Connelly
  94  * @since 1.1
  95  */
  96 public
  97 class ZipFile implements ZipConstants, Closeable {
  98 
  99     private final String name;     // zip file name
 100     private volatile boolean closeRequested;
 101     private ZipCoder zc;
 102 
 103     // The "resource" used by this zip file that needs to be
 104     // cleaned after use.
 105     // a) the input streams that need to be closed
 106     // b) the list of cached Inflater objects
 107     // c) the "native" source of this zip file.
 108     private final CleanableResource res;
 109 
 110     private static final int STORED = ZipEntry.STORED;
 111     private static final int DEFLATED = ZipEntry.DEFLATED;
 112 
 113     /**
 114      * Mode flag to open a zip file for reading.
 115      */
 116     public static final int OPEN_READ = 0x1;
 117 
 118     /**
 119      * Mode flag to open a zip file and mark it for deletion.  The file will be
 120      * deleted some time between the moment that it is opened and the moment
 121      * that it is closed, but its contents will remain accessible via the
 122      * {@code ZipFile} object until either the close method is invoked or the
 123      * virtual machine exits.
 124      */
 125     public static final int OPEN_DELETE = 0x4;
 126 
 127     /**
 128      * Opens a zip file for reading.


 352         return null;
 353     }
 354 
 355     /**
 356      * Returns an input stream for reading the contents of the specified
 357      * zip file entry.
 358      * <p>
 359      * Closing this ZIP file will, in turn, close all input streams that
 360      * have been returned by invocations of this method.
 361      *
 362      * @param entry the zip file entry
 363      * @return the input stream for reading the contents of the specified
 364      * zip file entry.
 365      * @throws ZipException if a ZIP format error has occurred
 366      * @throws IOException if an I/O error has occurred
 367      * @throws IllegalStateException if the zip file has been closed
 368      */
 369     public InputStream getInputStream(ZipEntry entry) throws IOException {
 370         Objects.requireNonNull(entry, "entry");
 371         int pos = -1;
 372         ZipFileInputStream in = null;
 373         Source zsrc = res.zsrc;
 374         Set<InputStream> istreams = res.istreams;
 375         synchronized (this) {
 376             ensureOpen();
 377             if (Objects.equals(lastEntryName, entry.name)) {
 378                 pos = lastEntryPos;
 379             } else if (!zc.isUTF8() && (entry.flag & EFS) != 0) {
 380                 pos = zsrc.getEntryPos(zc.getBytesUTF8(entry.name), false);
 381             } else {
 382                 pos = zsrc.getEntryPos(zc.getBytes(entry.name), false);
 383             }
 384             if (pos == -1) {
 385                 return null;
 386             }
 387             in = new ZipFileInputStream(zsrc.cen, pos);
 388             switch (CENHOW(zsrc.cen, pos)) {
 389             case STORED:
 390                 synchronized (istreams) {
 391                     istreams.add(in);
 392                 }


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


1201                     Key key = (Key)obj;
1202                     if (!attrs.lastModifiedTime().equals(key.attrs.lastModifiedTime())) {
1203                         return false;
1204                     }
1205                     Object fk = attrs.fileKey();
1206                     if (fk != null) {
1207                         return  fk.equals(key.attrs.fileKey());
1208                     } else {
1209                         return file.equals(key.file);
1210                     }
1211                 }
1212                 return false;
1213             }
1214         }
1215         private static final HashMap<Key, Source> files = new HashMap<>();
1216 
1217 
1218         static Source get(File file, boolean toDelete) throws IOException {
1219             Key key = new Key(file,
1220                               Files.readAttributes(file.toPath(), BasicFileAttributes.class));
1221             Source src = null;
1222             synchronized (files) {
1223                 src = files.get(key);
1224                 if (src != null) {
1225                     src.refs++;
1226                     return src;
1227                 }
1228             }
1229             src = new Source(key, toDelete);
1230 
1231             synchronized (files) {
1232                 if (files.containsKey(key)) {    // someone else put in first
1233                     src.close();                 // close the newly created one
1234                     src = files.get(key);
1235                     src.refs++;
1236                     return src;
1237                 }
1238                 files.put(key, src);
1239                 return src;
1240             }
1241         }




  47 import java.util.HashMap;
  48 import java.util.Iterator;
  49 import java.util.Objects;
  50 import java.util.NoSuchElementException;
  51 import java.util.Set;
  52 import java.util.Spliterator;
  53 import java.util.Spliterators;
  54 import java.util.WeakHashMap;
  55 
  56 import java.util.function.Consumer;
  57 import java.util.function.Function;
  58 import java.util.function.IntFunction;
  59 import java.util.jar.JarEntry;
  60 import java.util.stream.Stream;
  61 import java.util.stream.StreamSupport;
  62 import jdk.internal.misc.JavaUtilZipFileAccess;
  63 import jdk.internal.misc.SharedSecrets;
  64 import jdk.internal.misc.VM;
  65 import jdk.internal.perf.PerfCounter;
  66 import jdk.internal.ref.CleanerFactory;
  67 import jdk.internal.vm.annotation.Stable;
  68 
  69 import static java.util.zip.ZipConstants64.*;
  70 import static java.util.zip.ZipUtils.*;
  71 
  72 /**
  73  * This class is used to read entries from a zip file.
  74  *
  75  * <p> Unless otherwise noted, passing a {@code null} argument to a constructor
  76  * or method in this class will cause a {@link NullPointerException} to be
  77  * thrown.
  78  *
  79  * @apiNote
  80  * To release resources used by this {@code ZipFile}, the {@link #close()} method
  81  * should be called explicitly or by try-with-resources. Subclasses are responsible
  82  * for the cleanup of resources acquired by the subclass. Subclasses that override
  83  * {@link #finalize()} in order to perform cleanup should be modified to use alternative
  84  * cleanup mechanisms such as {@link java.lang.ref.Cleaner} and remove the overriding
  85  * {@code finalize} method.
  86  *
  87  * @implSpec
  88  * If this {@code ZipFile} has been subclassed and the {@code close} method has
  89  * been overridden, the {@code close} method will be called by the finalization
  90  * when {@code ZipFile} is unreachable. But the subclasses should not depend on
  91  * this specific implementation; the finalization is not reliable and the
  92  * {@code finalize} method is deprecated to be removed.
  93  *
  94  * @author      David Connelly
  95  * @since 1.1
  96  */
  97 public
  98 class ZipFile implements ZipConstants, Closeable {
  99 
 100     private final String name;     // zip file name
 101     private volatile boolean closeRequested;
 102     private final @Stable ZipCoder zc;
 103 
 104     // The "resource" used by this zip file that needs to be
 105     // cleaned after use.
 106     // a) the input streams that need to be closed
 107     // b) the list of cached Inflater objects
 108     // c) the "native" source of this zip file.
 109     private final @Stable CleanableResource res;
 110 
 111     private static final int STORED = ZipEntry.STORED;
 112     private static final int DEFLATED = ZipEntry.DEFLATED;
 113 
 114     /**
 115      * Mode flag to open a zip file for reading.
 116      */
 117     public static final int OPEN_READ = 0x1;
 118 
 119     /**
 120      * Mode flag to open a zip file and mark it for deletion.  The file will be
 121      * deleted some time between the moment that it is opened and the moment
 122      * that it is closed, but its contents will remain accessible via the
 123      * {@code ZipFile} object until either the close method is invoked or the
 124      * virtual machine exits.
 125      */
 126     public static final int OPEN_DELETE = 0x4;
 127 
 128     /**
 129      * Opens a zip file for reading.


 353         return null;
 354     }
 355 
 356     /**
 357      * Returns an input stream for reading the contents of the specified
 358      * zip file entry.
 359      * <p>
 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                 }


 588      * Returns an ordered {@code Stream} over the ZIP file entries.
 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(


1200                     Key key = (Key)obj;
1201                     if (!attrs.lastModifiedTime().equals(key.attrs.lastModifiedTime())) {
1202                         return false;
1203                     }
1204                     Object fk = attrs.fileKey();
1205                     if (fk != null) {
1206                         return  fk.equals(key.attrs.fileKey());
1207                     } else {
1208                         return file.equals(key.file);
1209                     }
1210                 }
1211                 return false;
1212             }
1213         }
1214         private static final HashMap<Key, Source> files = new HashMap<>();
1215 
1216 
1217         static Source get(File file, boolean toDelete) throws IOException {
1218             Key key = new Key(file,
1219                               Files.readAttributes(file.toPath(), BasicFileAttributes.class));
1220             Source src;
1221             synchronized (files) {
1222                 src = files.get(key);
1223                 if (src != null) {
1224                     src.refs++;
1225                     return src;
1226                 }
1227             }
1228             src = new Source(key, toDelete);
1229 
1230             synchronized (files) {
1231                 if (files.containsKey(key)) {    // someone else put in first
1232                     src.close();                 // close the newly created one
1233                     src = files.get(key);
1234                     src.refs++;
1235                     return src;
1236                 }
1237                 files.put(key, src);
1238                 return src;
1239             }
1240         }


< prev index next >