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 }
|