--- a/jdk/make/mapfiles/libzip/mapfile-vers Tue Dec 08 09:25:01 2015 -0800
+++ b/jdk/make/mapfiles/libzip/mapfile-vers Tue Dec 08 16:43:58 2015 -0800
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
SUNWprivate_1.1 {
global:
+ Java_java_util_jar_JarFile_getMetaInfEntryNames;
Java_java_util_zip_Adler32_update;
Java_java_util_zip_Adler32_updateBytes;
Java_java_util_zip_Adler32_updateByteBuffer;
@@ -47,6 +48,25 @@
Java_java_util_zip_Inflater_initIDs;
Java_java_util_zip_Inflater_reset;
Java_java_util_zip_Inflater_setDictionary;
+ Java_java_util_zip_ZipFile_close;
+ Java_java_util_zip_ZipFile_getCommentBytes;
+ Java_java_util_zip_ZipFile_freeEntry;
+ Java_java_util_zip_ZipFile_getEntry;
+ Java_java_util_zip_ZipFile_getEntryBytes;
+ Java_java_util_zip_ZipFile_getEntryCrc;
+ Java_java_util_zip_ZipFile_getEntryCSize;
+ Java_java_util_zip_ZipFile_getEntryFlag;
+ Java_java_util_zip_ZipFile_getEntryMethod;
+ Java_java_util_zip_ZipFile_getEntrySize;
+ Java_java_util_zip_ZipFile_getEntryTime;
+ Java_java_util_zip_ZipFile_getNextEntry;
+ Java_java_util_zip_ZipFile_getZipMessage;
+ Java_java_util_zip_ZipFile_getTotal;
+ Java_java_util_zip_ZipFile_initIDs;
+ Java_java_util_zip_ZipFile_open;
+ Java_java_util_zip_ZipFile_read;
+ Java_java_util_zip_ZipFile_startsWithLOC;
+
ZIP_Close;
ZIP_CRC32;
ZIP_FindEntry;
--- a/jdk/make/mapfiles/libzip/reorder-sparc Tue Dec 08 09:25:01 2015 -0800
+++ b/jdk/make/mapfiles/libzip/reorder-sparc Tue Dec 08 16:43:58 2015 -0800
@@ -16,14 +16,30 @@
text: .text%ZIP_Lock;
text: .text%ZIP_Unlock;
text: .text%ZIP_FreeEntry;
+text: .text%Java_java_util_zip_ZipFile_initIDs;
+text: .text%Java_java_util_zip_ZipFile_open;
+text: .text%Java_java_util_zip_ZipFile_getTotal;
+text: .text%Java_java_util_zip_ZipFile_startsWithLOC;
+text: .text%Java_java_util_zip_ZipFile_getEntry;
+text: .text%Java_java_util_zip_ZipFile_freeEntry;
+text: .text%Java_java_util_zip_ZipFile_getEntryTime;
+text: .text%Java_java_util_zip_ZipFile_getEntryCrc;
+text: .text%Java_java_util_zip_ZipFile_getEntryCSize;
+text: .text%Java_java_util_zip_ZipFile_getEntrySize;
+text: .text%Java_java_util_zip_ZipFile_getEntryFlag;
+text: .text%Java_java_util_zip_ZipFile_getEntryMethod;
+text: .text%Java_java_util_zip_ZipFile_getEntryBytes;
text: .text%Java_java_util_zip_Inflater_initIDs;
text: .text%Java_java_util_zip_Inflater_init;
text: .text%inflateInit2_;
text: .text%zcalloc;
text: .text%Java_java_util_zip_Inflater_inflateBytes;
+text: .text%Java_java_util_zip_ZipFile_read;
text: .text%ZIP_Read;
text: .text%zcfree;
+text: .text%Java_java_util_jar_JarFile_getMetaInfEntryNames;
text: .text%Java_java_util_zip_Inflater_reset;
text: .text%Java_java_util_zip_Inflater_end;
text: .text%inflateEnd;
+text: .text%Java_java_util_zip_ZipFile_close;
text: .text%ZIP_Close;
--- a/jdk/make/mapfiles/libzip/reorder-sparcv9 Tue Dec 08 09:25:01 2015 -0800
+++ b/jdk/make/mapfiles/libzip/reorder-sparcv9 Tue Dec 08 16:43:58 2015 -0800
@@ -15,6 +15,19 @@
text: .text%ZIP_Lock;
text: .text%ZIP_Unlock;
text: .text%ZIP_FreeEntry;
+text: .text%Java_java_util_zip_ZipFile_initIDs;
+text: .text%Java_java_util_zip_ZipFile_open;
+text: .text%Java_java_util_zip_ZipFile_getTotal;
+text: .text%Java_java_util_zip_ZipFile_startsWithLOC;
+text: .text%Java_java_util_zip_ZipFile_getEntry;
+text: .text%Java_java_util_zip_ZipFile_freeEntry;
+text: .text%Java_java_util_zip_ZipFile_getEntryTime;
+text: .text%Java_java_util_zip_ZipFile_getEntryCrc;
+text: .text%Java_java_util_zip_ZipFile_getEntryCSize;
+text: .text%Java_java_util_zip_ZipFile_getEntrySize;
+text: .text%Java_java_util_zip_ZipFile_getEntryFlag;
+text: .text%Java_java_util_zip_ZipFile_getEntryMethod;
+text: .text%Java_java_util_zip_ZipFile_getEntryBytes;
text: .text%Java_java_util_zip_Inflater_initIDs;
text: .text%Java_java_util_zip_Inflater_init;
text: .text%inflateInit2_;
@@ -22,6 +35,7 @@
text: .text%inflateReset;
text: .text%Java_java_util_zip_Inflater_inflateBytes;
text: .text%inflate;
+text: .text%Java_java_util_zip_ZipFile_read;
text: .text%ZIP_Read;
text: .text%zcfree;
text: .text%Java_java_util_jar_JarFile_getMetaInfEntryNames;
@@ -29,5 +43,6 @@
text: .text%InflateFully;
text: .text%inflateEnd;
text: .text%Java_java_util_zip_Inflater_reset;
+text: .text%Java_java_util_zip_ZipFile_close;
text: .text%ZIP_Close;
text: .text%Java_java_util_zip_Inflater_end;
--- a/jdk/make/mapfiles/libzip/reorder-x86 Tue Dec 08 09:25:01 2015 -0800
+++ b/jdk/make/mapfiles/libzip/reorder-x86 Tue Dec 08 16:43:58 2015 -0800
@@ -16,16 +16,34 @@
text: .text%ZIP_Lock;
text: .text%ZIP_Unlock;
text: .text%ZIP_FreeEntry;
+text: .text%Java_java_util_zip_ZipFile_initIDs;
+text: .text%Java_java_util_zip_ZipFile_open;
+text: .text%Java_java_util_zip_ZipFile_getTotal;
+text: .text%Java_java_util_zip_ZipFile_startsWithLOC;
+text: .text%Java_java_util_zip_ZipFile_getEntry;
+text: .text%Java_java_util_zip_ZipFile_freeEntry;
+text: .text%Java_java_util_zip_ZipFile_getEntryTime;
+text: .text%Java_java_util_zip_ZipFile_getEntryCrc;
+text: .text%Java_java_util_zip_ZipFile_getEntryCSize;
+text: .text%Java_java_util_zip_ZipFile_getEntrySize;
+text: .text%Java_java_util_zip_ZipFile_getEntryFlag;
+text: .text%Java_java_util_zip_ZipFile_getEntryMethod;
+text: .text%Java_java_util_zip_ZipFile_getEntryBytes;
+text: .text%Java_java_util_zip_Inflater_initIDs;
+text: .text%Java_java_util_zip_Inflater_init;
text: .text%inflateInit2_;
text: .text%zcalloc;
text: .text%inflateReset;
text: .text%Java_java_util_zip_Inflater_inflateBytes;
text: .text%inflate;
+text: .text%Java_java_util_zip_ZipFile_read;
text: .text%ZIP_Read;
text: .text%zcfree;
+text: .text%Java_java_util_jar_JarFile_getMetaInfEntryNames;
text: .text%ZIP_ReadEntry;
text: .text%InflateFully;
text: .text%inflateEnd;
text: .text%Java_java_util_zip_Inflater_reset;
+text: .text%Java_java_util_zip_ZipFile_close;
text: .text%ZIP_Close;
text: .text%Java_java_util_zip_Inflater_end;
--- a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java Tue Dec 08 09:25:01 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java Tue Dec 08 16:43:58 2015 -0800
@@ -203,10 +203,7 @@
return man;
}
- private String[] getMetaInfEntryNames() {
- return jdk.internal.misc.SharedSecrets.getJavaUtilZipFileAccess()
- .getMetaInfEntryNames((ZipFile)this);
- }
+ private native String[] getMetaInfEntryNames();
/**
* Returns the {@code JarEntry} for the given entry name or
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipCoder.java Tue Dec 08 09:25:01 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipCoder.java Tue Dec 08 16:43:58 2015 -0800
@@ -43,7 +43,7 @@
final class ZipCoder {
- String toString(byte[] ba, int off, int length) {
+ String toString(byte[] ba, int length) {
CharsetDecoder cd = decoder().reset();
int len = (int)(length * cd.maxCharsPerByte());
char[] ca = new char[len];
@@ -53,12 +53,12 @@
// CodingErrorAction.REPLACE mode. ZipCoder uses
// REPORT mode.
if (isUTF8 && cd instanceof ArrayDecoder) {
- int clen = ((ArrayDecoder)cd).decode(ba, off, length, ca);
+ int clen = ((ArrayDecoder)cd).decode(ba, 0, length, ca);
if (clen == -1) // malformed
throw new IllegalArgumentException("MALFORMED");
return new String(ca, 0, clen);
}
- ByteBuffer bb = ByteBuffer.wrap(ba, off, length);
+ ByteBuffer bb = ByteBuffer.wrap(ba, 0, length);
CharBuffer cb = CharBuffer.wrap(ca);
CoderResult cr = cd.decode(bb, cb, true);
if (!cr.isUnderflow())
@@ -69,12 +69,8 @@
return new String(ca, 0, cb.position());
}
- String toString(byte[] ba, int length) {
- return toString(ba, 0, length);
- }
-
String toString(byte[] ba) {
- return toString(ba, 0, ba.length);
+ return toString(ba, ba.length);
}
byte[] getBytes(String s) {
@@ -115,16 +111,13 @@
return utf8.getBytes(s);
}
+
String toStringUTF8(byte[] ba, int len) {
- return toStringUTF8(ba, 0, len);
- }
-
- String toStringUTF8(byte[] ba, int off, int len) {
if (isUTF8)
- return toString(ba, off, len);
+ return toString(ba, len);
if (utf8 == null)
utf8 = new ZipCoder(StandardCharsets.UTF_8);
- return utf8.toString(ba, off, len);
+ return utf8.toString(ba, len);
}
boolean isUTF8() {
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java Tue Dec 08 09:25:01 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java Tue Dec 08 16:43:58 2015 -0800
@@ -30,22 +30,14 @@
import java.io.IOException;
import java.io.EOFException;
import java.io.File;
-import java.io.RandomAccessFile;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.nio.file.Path;
-import java.nio.file.Files;
-
import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Deque;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
-import java.util.Objects;
import java.util.NoSuchElementException;
import java.util.Spliterator;
import java.util.Spliterators;
@@ -55,9 +47,7 @@
import jdk.internal.misc.JavaUtilZipFileAccess;
import jdk.internal.misc.SharedSecrets;
-import static java.util.zip.ZipConstants.*;
import static java.util.zip.ZipConstants64.*;
-import static java.util.zip.ZipUtils.*;
/**
* This class is used to read entries from a zip file.
@@ -70,11 +60,11 @@
*/
public
class ZipFile implements ZipConstants, Closeable {
-
+ private long jzfile; // address of jzfile data
private final String name; // zip file name
+ private final int total; // total number of entries
+ private final boolean locsig; // if zip file starts with LOCSIG (usually true)
private volatile boolean closeRequested = false;
- private Source zsrc;
- private ZipCoder zc;
private static final int STORED = ZipEntry.STORED;
private static final int DEFLATED = ZipEntry.DEFLATED;
@@ -93,6 +83,23 @@
*/
public static final int OPEN_DELETE = 0x4;
+ static {
+ /* Zip library is loaded from System.initializeSystemClass */
+ initIDs();
+ }
+
+ private static native void initIDs();
+
+ private static final boolean usemmap;
+
+ static {
+ // A system prpperty to disable mmap use to avoid vm crash when
+ // in-use zip file is accidently overwritten by others.
+ String prop = sun.misc.VM.getSavedProperty("sun.zip.disableMemoryMapping");
+ usemmap = (prop == null ||
+ !(prop.length() == 0 || prop.equalsIgnoreCase("true")));
+ }
+
/**
* Opens a zip file for reading.
*
@@ -158,6 +165,8 @@
this(file, OPEN_READ);
}
+ private ZipCoder zc;
+
/**
* Opens a new {@code ZipFile} to read from the specified
* {@code File} object in the specified mode. The mode argument
@@ -205,13 +214,16 @@
sm.checkDelete(name);
}
}
- Objects.requireNonNull(charset, "charset");
+ if (charset == null)
+ throw new NullPointerException("charset is null");
this.zc = ZipCoder.get(charset);
- this.name = name;
long t0 = System.nanoTime();
- this.zsrc = Source.get(file, (mode & OPEN_DELETE) != 0);
+ jzfile = open(name, mode, file.lastModified(), usemmap);
sun.misc.PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0);
sun.misc.PerfCounter.getZipFileCount().increment();
+ this.name = name;
+ this.total = getTotal(jzfile);
+ this.locsig = startsWithLOC(jzfile);
}
/**
@@ -245,7 +257,6 @@
/**
* Opens a ZIP file for reading given the specified File object.
- *
* @param file the ZIP file to be opened for reading
* @param charset
* The {@linkplain java.nio.charset.Charset charset} to be
@@ -276,10 +287,10 @@
public String getComment() {
synchronized (this) {
ensureOpen();
- if (zsrc.comment == null) {
+ byte[] bcomm = getCommentBytes(jzfile);
+ if (bcomm == null)
return null;
- }
- return zc.toString(zsrc.comment);
+ return zc.toString(bcomm, bcomm.length);
}
}
@@ -292,27 +303,38 @@
* @throws IllegalStateException if the zip file has been closed
*/
public ZipEntry getEntry(String name) {
- Objects.requireNonNull(name, "name");
+ if (name == null) {
+ throw new NullPointerException("name");
+ }
+ long jzentry = 0;
synchronized (this) {
ensureOpen();
- int pos = zsrc.getEntryPos(zc.getBytes(name), true);
- if (pos != -1) {
- return getZipEntry(name, pos);
+ jzentry = getEntry(jzfile, zc.getBytes(name), true);
+ if (jzentry != 0) {
+ ZipEntry ze = getZipEntry(name, jzentry);
+ freeEntry(jzfile, jzentry);
+ return ze;
}
}
return null;
}
- // The outstanding inputstreams that need to be closed,
+ private static native long getEntry(long jzfile, byte[] name,
+ boolean addSlash);
+
+ // freeEntry releases the C jzentry struct.
+ private static native void freeEntry(long jzfile, long jzentry);
+
+ // the outstanding inputstreams that need to be closed,
// mapped to the inflater objects they use.
private final Map<InputStream, Inflater> streams = new WeakHashMap<>();
/**
* Returns an input stream for reading the contents of the specified
* zip file entry.
- * <p>
- * Closing this ZIP file will, in turn, close all input streams that
- * have been returned by invocations of this method.
+ *
+ * <p> Closing this ZIP file will, in turn, close all input
+ * streams that have been returned by invocations of this method.
*
* @param entry the zip file entry
* @return the input stream for reading the contents of the specified
@@ -322,38 +344,37 @@
* @throws IllegalStateException if the zip file has been closed
*/
public InputStream getInputStream(ZipEntry entry) throws IOException {
- Objects.requireNonNull(entry, "entry");
- int pos = -1;
+ if (entry == null) {
+ throw new NullPointerException("entry");
+ }
+ long jzentry = 0;
ZipFileInputStream in = null;
synchronized (this) {
ensureOpen();
if (!zc.isUTF8() && (entry.flag & EFS) != 0) {
- pos = zsrc.getEntryPos(zc.getBytesUTF8(entry.name), false);
+ jzentry = getEntry(jzfile, zc.getBytesUTF8(entry.name), false);
} else {
- pos = zsrc.getEntryPos(zc.getBytes(entry.name), false);
+ jzentry = getEntry(jzfile, zc.getBytes(entry.name), false);
}
- if (pos == -1) {
+ if (jzentry == 0) {
return null;
}
- in = new ZipFileInputStream(zsrc.cen, pos);
- switch (CENHOW(zsrc.cen, pos)) {
+ in = new ZipFileInputStream(jzentry);
+
+ switch (getEntryMethod(jzentry)) {
case STORED:
synchronized (streams) {
streams.put(in, null);
}
return in;
case DEFLATED:
- // Inflater likes a bit of slack
// MORE: Compute good size for inflater stream:
- long size = CENLEN(zsrc.cen, pos) + 2;
- if (size > 65536) {
- size = 8192;
- }
- if (size <= 0) {
- size = 4096;
- }
+ long size = getEntrySize(jzentry) + 2; // Inflater likes a bit of slack
+ if (size > 65536) size = 8192;
+ if (size <= 0) size = 4096;
Inflater inf = getInflater();
- InputStream is = new ZipFileInflaterInputStream(in, inf, (int)size);
+ InputStream is =
+ new ZipFileInflaterInputStream(in, inf, (int)size);
synchronized (streams) {
streams.put(is, inf);
}
@@ -426,8 +447,8 @@
private Inflater getInflater() {
Inflater inf;
synchronized (inflaterCache) {
- while ((inf = inflaterCache.poll()) != null) {
- if (!inf.ended()) {
+ while (null != (inf = inflaterCache.poll())) {
+ if (false == inf.ended()) {
return inf;
}
}
@@ -439,7 +460,7 @@
* Releases the specified inflater to the list of available inflaters.
*/
private void releaseInflater(Inflater inf) {
- if (!inf.ended()) {
+ if (false == inf.ended()) {
inf.reset();
synchronized (inflaterCache) {
inflaterCache.add(inf);
@@ -448,7 +469,7 @@
}
// List of available Inflater objects for decompression
- private final Deque<Inflater> inflaterCache = new ArrayDeque<>();
+ private Deque<Inflater> inflaterCache = new ArrayDeque<>();
/**
* Returns the path name of the ZIP file.
@@ -472,7 +493,7 @@
public boolean hasNext() {
synchronized (ZipFile.this) {
ensureOpen();
- return i < zsrc.total;
+ return i < total;
}
}
@@ -483,11 +504,28 @@
public ZipEntry next() {
synchronized (ZipFile.this) {
ensureOpen();
- if (i >= zsrc.total) {
+ if (i >= total) {
throw new NoSuchElementException();
}
- // each "entry" has 3 ints in table entries
- return getZipEntry(null, zsrc.getEntryPos(i++ * 3));
+ long jzentry = getNextEntry(jzfile, i++);
+ if (jzentry == 0) {
+ String message;
+ if (closeRequested) {
+ message = "ZipFile concurrently closed";
+ } else {
+ message = getZipMessage(ZipFile.this.jzfile);
+ }
+ throw new ZipError("jzentry == 0" +
+ ",\n jzfile = " + ZipFile.this.jzfile +
+ ",\n total = " + ZipFile.this.total +
+ ",\n name = " + ZipFile.this.name +
+ ",\n i = " + i +
+ ",\n message = " + message
+ );
+ }
+ ZipEntry ze = getZipEntry(null, jzentry);
+ freeEntry(jzfile, jzentry);
+ return ze;
}
}
@@ -521,53 +559,48 @@
Spliterator.IMMUTABLE | Spliterator.NONNULL), false);
}
- /* Checks ensureOpen() before invoke this method */
- private ZipEntry getZipEntry(String name, int pos) {
- byte[] cen = zsrc.cen;
+ private ZipEntry getZipEntry(String name, long jzentry) {
ZipEntry e = new ZipEntry();
- int nlen = CENNAM(cen, pos);
- int elen = CENEXT(cen, pos);
- int clen = CENCOM(cen, pos);
- e.flag = CENFLG(cen, pos); // get the flag first
+ e.flag = getEntryFlag(jzentry); // get the flag first
if (name != null) {
e.name = name;
} else {
+ byte[] bname = getEntryBytes(jzentry, JZENTRY_NAME);
if (!zc.isUTF8() && (e.flag & EFS) != 0) {
- e.name = zc.toStringUTF8(cen, pos + CENHDR, nlen);
+ e.name = zc.toStringUTF8(bname, bname.length);
} else {
- e.name = zc.toString(cen, pos + CENHDR, nlen);
+ e.name = zc.toString(bname, bname.length);
}
}
- e.xdostime = CENTIM(cen, pos);
- e.crc = CENCRC(cen, pos);
- e.size = CENLEN(cen, pos);
- e.csize = CENSIZ(cen, pos);
- e.method = CENHOW(cen, pos);
- if (elen != 0) {
- e.setExtra0(Arrays.copyOfRange(cen, pos + CENHDR + nlen,
- pos + CENHDR + nlen + elen), true);
- }
- if (clen != 0) {
+ e.xdostime = getEntryTime(jzentry);
+ e.crc = getEntryCrc(jzentry);
+ e.size = getEntrySize(jzentry);
+ e.csize = getEntryCSize(jzentry);
+ e.method = getEntryMethod(jzentry);
+ e.setExtra0(getEntryBytes(jzentry, JZENTRY_EXTRA), false);
+ byte[] bcomm = getEntryBytes(jzentry, JZENTRY_COMMENT);
+ if (bcomm == null) {
+ e.comment = null;
+ } else {
if (!zc.isUTF8() && (e.flag & EFS) != 0) {
- e.comment = zc.toStringUTF8(cen, pos + CENHDR + nlen + elen, clen);
+ e.comment = zc.toStringUTF8(bcomm, bcomm.length);
} else {
- e.comment = zc.toString(cen, pos + CENHDR + nlen + elen, clen);
+ e.comment = zc.toString(bcomm, bcomm.length);
}
}
return e;
}
+ private static native long getNextEntry(long jzfile, int i);
+
/**
* Returns the number of entries in the ZIP file.
- *
* @return the number of entries in the ZIP file
* @throws IllegalStateException if the zip file has been closed
*/
public int size() {
- synchronized (this) {
- ensureOpen();
- return zsrc.total;
- }
+ ensureOpen();
+ return total;
}
/**
@@ -579,15 +612,14 @@
* @throws IOException if an I/O error has occurred
*/
public void close() throws IOException {
- if (closeRequested) {
+ if (closeRequested)
return;
- }
closeRequested = true;
synchronized (this) {
// Close streams, release their inflaters
synchronized (streams) {
- if (!streams.isEmpty()) {
+ if (false == streams.isEmpty()) {
Map<InputStream, Inflater> copy = new HashMap<>(streams);
streams.clear();
for (Map.Entry<InputStream, Inflater> e : copy.entrySet()) {
@@ -599,17 +631,21 @@
}
}
}
+
// Release cached inflaters
+ Inflater inf;
synchronized (inflaterCache) {
- Inflater inf;
- while ((inf = inflaterCache.poll()) != null) {
+ while (null != (inf = inflaterCache.poll())) {
inf.end();
}
}
- // Release zip src
- if (zsrc != null) {
- Source.close(zsrc);
- zsrc = null;
+
+ if (jzfile != 0) {
+ // Close the zip file
+ long zf = this.jzfile;
+ jzfile = 0;
+
+ close(zf);
}
}
}
@@ -632,11 +668,14 @@
close();
}
+ private static native void close(long jzfile);
+
private void ensureOpen() {
if (closeRequested) {
throw new IllegalStateException("zip file closed");
}
- if (zsrc == null) {
+
+ if (jzfile == 0) {
throw new IllegalStateException("The object is not initialized.");
}
}
@@ -652,86 +691,23 @@
* (possibly compressed) zip file entry.
*/
private class ZipFileInputStream extends InputStream {
- private volatile boolean closeRequested = false;
+ private volatile boolean zfisCloseRequested = false;
+ protected long jzentry; // address of jzentry data
private long pos; // current position within entry data
protected long rem; // number of remaining bytes within entry
protected long size; // uncompressed size of this entry
- ZipFileInputStream(byte[] cen, int cenpos) throws IOException {
- rem = CENSIZ(cen, cenpos);
- size = CENLEN(cen, cenpos);
- pos = CENOFF(cen, cenpos);
- // zip64
- if (rem == ZIP64_MAGICVAL || size == ZIP64_MAGICVAL ||
- pos == ZIP64_MAGICVAL) {
- checkZIP64(cen, cenpos);
- }
- // negative for lazy initialization, see getDataOffset();
- pos = - (pos + ZipFile.this.zsrc.locpos);
- }
-
- private void checkZIP64(byte[] cen, int cenpos) throws IOException {
- int off = cenpos + CENHDR + CENNAM(cen, cenpos);
- int end = off + CENEXT(cen, cenpos);
- while (off + 4 < end) {
- int tag = get16(cen, off);
- int sz = get16(cen, off + 2);
- off += 4;
- if (off + sz > end) // invalid data
- break;
- if (tag == EXTID_ZIP64) {
- if (size == ZIP64_MAGICVAL) {
- if (sz < 8 || (off + 8) > end)
- break;
- size = get64(cen, off);
- sz -= 8;
- off += 8;
- }
- if (rem == ZIP64_MAGICVAL) {
- if (sz < 8 || (off + 8) > end)
- break;
- rem = get64(cen, off);
- sz -= 8;
- off += 8;
- }
- if (pos == ZIP64_MAGICVAL) {
- if (sz < 8 || (off + 8) > end)
- break;
- pos = get64(cen, off);
- sz -= 8;
- off += 8;
- }
- break;
- }
- off += sz;
- }
- }
-
- /* The Zip file spec explicitly allows the LOC extra data size to
- * be different from the CEN extra data size. Since we cannot trust
- * the CEN extra data size, we need to read the LOC to determine
- * the entry data offset.
- */
- private long initDataOffset() throws IOException {
- if (pos <= 0) {
- byte[] loc = new byte[LOCHDR];
- pos = -pos;
- int len = ZipFile.this.zsrc.readFullyAt(loc, 0, loc.length, pos);
- if (len != LOCHDR) {
- throw new ZipException("ZipFile error reading zip file");
- }
- if (LOCSIG(loc) != LOCSIG) {
- throw new ZipException("ZipFile invalid LOC header (bad signature)");
- }
- pos += LOCHDR + LOCNAM(loc) + LOCEXT(loc);
- }
- return pos;
+ ZipFileInputStream(long jzentry) {
+ pos = 0;
+ rem = getEntryCSize(jzentry);
+ size = getEntrySize(jzentry);
+ this.jzentry = jzentry;
}
public int read(byte b[], int off, int len) throws IOException {
synchronized (ZipFile.this) {
- ensureOpenOrZipException();
- initDataOffset();
+ long rem = this.rem;
+ long pos = this.pos;
if (rem == 0) {
return -1;
}
@@ -741,10 +717,14 @@
if (len > rem) {
len = (int) rem;
}
- len = ZipFile.this.zsrc.readAt(b, off, len, pos);
+
+ // Check if ZipFile open
+ ensureOpenOrZipException();
+ len = ZipFile.read(ZipFile.this.jzfile, jzentry, pos, b,
+ off, len);
if (len > 0) {
- pos += len;
- rem -= len;
+ this.pos = (pos + len);
+ this.rem = (rem - len);
}
}
if (rem == 0) {
@@ -762,16 +742,11 @@
}
}
- public long skip(long n) throws IOException {
- synchronized (ZipFile.this) {
- ensureOpenOrZipException();
- initDataOffset();
- if (n > rem) {
- n = rem;
- }
- pos += n;
- rem -= n;
- }
+ public long skip(long n) {
+ if (n > rem)
+ n = rem;
+ pos += n;
+ rem -= n;
if (rem == 0) {
close();
}
@@ -787,11 +762,17 @@
}
public void close() {
- if (closeRequested) {
+ if (zfisCloseRequested)
return;
+ zfisCloseRequested = true;
+
+ rem = 0;
+ synchronized (ZipFile.this) {
+ if (jzentry != 0 && ZipFile.this.jzfile != 0) {
+ freeEntry(ZipFile.this.jzfile, jzentry);
+ jzentry = 0;
+ }
}
- closeRequested = true;
- rem = 0;
synchronized (streams) {
streams.remove(this);
}
@@ -806,492 +787,40 @@
SharedSecrets.setJavaUtilZipFileAccess(
new JavaUtilZipFileAccess() {
public boolean startsWithLocHeader(ZipFile zip) {
- return zip.zsrc.locsig;
+ return zip.startsWithLocHeader();
}
- public String[] getMetaInfEntryNames(ZipFile zip) {
- return zip.getMetaInfEntryNames();
- }
- }
+ }
);
}
- /*
- * Returns an array of strings representing the names of all entries
- * that begin with "META-INF/" (case ignored). This method is used
- * in JarFile, via SharedSecrets, as an optimization when looking up
- * manifest and signature file entries. Returns null if no entries
- * were found.
+ /**
+ * Returns {@code true} if, and only if, the zip file begins with {@code
+ * LOCSIG}.
*/
- private String[] getMetaInfEntryNames() {
- synchronized (this) {
- ensureOpen();
- if (zsrc.metanames.size() == 0) {
- return null;
- }
- String[] names = new String[zsrc.metanames.size()];
- byte[] cen = zsrc.cen;
- for (int i = 0; i < names.length; i++) {
- int pos = zsrc.metanames.get(i);
- names[i] = zc.toStringUTF8(cen, pos + CENHDR, CENNAM(cen, pos));
- }
- return names;
- }
+ private boolean startsWithLocHeader() {
+ return locsig;
}
- private static class Source {
- private final Key key; // the key in files
- private int refs = 1;
-
- private RandomAccessFile zfile; // zfile of the underlying zip file
- private byte[] cen; // CEN & ENDHDR
- private long locpos; // position of first LOC header (usually 0)
- private byte[] comment; // zip file comment
- // list of meta entries in META-INF dir
- private ArrayList<Integer> metanames = new ArrayList<>();
- private final boolean locsig; // true, if zip file starts with LOCSIG (usually true)
-
- // A Hashmap for all entries.
- //
- // A cen entry of Zip/JAR file. As we have one for every entry in every active Zip/JAR,
- // We might have a lot of these in a typical system. In order to save space we don't
- // keep the name in memory, but merely remember a 32 bit {@code hash} value of the
- // entry name and its offset {@code pos} in the central directory hdeader.
- //
- // private static class Entry {
- // int hash; // 32 bit hashcode on name
- // int next; // hash chain: index into entries
- // int pos; // Offset of central directory file header
- // }
- // private Entry[] entries; // array of hashed cen entry
- //
- // To reduce the total size of entries further, we use a int[] here to store 3 "int"
- // {@code hash}, {@code next and {@code "pos for each entry. The entry can then be
- // referred by their index of their positions in the {@code entries}.
- //
- private int[] entries; // array of hashed cen entry
- private int addEntry(int index, int hash, int next, int pos) {
- entries[index++] = hash;
- entries[index++] = next;
- entries[index++] = pos;
- return index;
- }
- private int getEntryHash(int index) { return entries[index]; }
- private int getEntryNext(int index) { return entries[index + 1]; }
- private int getEntryPos(int index) { return entries[index + 2]; }
- private static final int ZIP_ENDCHAIN = -1;
- private int total; // total number of entries
- private int[] table; // Hash chain heads: indexes into entries
- private int tablelen; // number of hash heads
-
- private static class Key {
- BasicFileAttributes attrs;
- File file;
-
- public Key(File file, BasicFileAttributes attrs) {
- this.attrs = attrs;
- this.file = file;
- }
-
- public int hashCode() {
- long t = attrs.lastModifiedTime().toMillis();
- return ((int)(t ^ (t >>> 32))) + file.hashCode();
- }
-
- public boolean equals(Object obj) {
- if (obj instanceof Key) {
- Key key = (Key)obj;
- if (!attrs.lastModifiedTime().equals(key.attrs.lastModifiedTime())) {
- return false;
- }
- Object fk = attrs.fileKey();
- if (fk != null) {
- return fk.equals(key.attrs.fileKey());
- } else {
- return file.equals(key.file);
- }
- }
- return false;
- }
- }
- private static final HashMap<Key, Source> files = new HashMap<>();
-
- public static Source get(File file, boolean toDelete) throws IOException {
- Key key = new Key(file,
- Files.readAttributes(file.toPath(), BasicFileAttributes.class));
- Source src = null;
- synchronized (files) {
- src = files.get(key);
- if (src != null) {
- src.refs++;
- return src;
- }
- }
- src = new Source(key, toDelete);
- synchronized (files) {
- if (files.containsKey(key)) { // someone else put in first
- src.close(); // close the newly created one
- src = files.get(key);
- src.refs++;
- return src;
- }
- files.put(key, src);
- return src;
- }
- }
-
- private static void close(Source src) throws IOException {
- synchronized (files) {
- if (--src.refs == 0) {
- files.remove(src.key);
- src.close();
- }
- }
- }
-
- private Source(Key key, boolean toDelete) throws IOException {
- this.key = key;
- this.zfile = new RandomAccessFile(key.file, "r");
- if (toDelete) {
- key.file.delete();
- }
- initCEN(-1);
- byte[] buf = new byte[4];
- readFullyAt(buf, 0, 4, 0);
- this.locsig = (LOCSIG(buf) != LOCSIG);
- }
-
- private void close() throws IOException {
- zfile.close();
- zfile = null;
- cen = null;
- entries = null;
- table = null;
- metanames = null;
- }
-
- private static final int BUF_SIZE = 8192;
- private final int readFullyAt(byte[] buf, int off, int len, long pos)
- throws IOException
- {
- synchronized(zfile) {
- zfile.seek(pos);
- int N = len;
- while (N > 0) {
- int n = Math.min(BUF_SIZE, N);
- zfile.readFully(buf, off, n);
- off += n;
- N -= n;
- }
- return len;
- }
- }
-
- private final int readAt(byte[] buf, int off, int len, long pos)
- throws IOException
- {
- synchronized(zfile) {
- zfile.seek(pos);
- return zfile.read(buf, off, len);
- }
- }
-
- private static final int hashN(byte[] a, int off, int len) {
- int h = 1;
- while (len-- > 0) {
- h = 31 * h + a[off++];
- }
- return h;
- }
-
- private static final int hash_append(int hash, byte b) {
- return hash * 31 + b;
- }
-
- private static class End {
- int centot; // 4 bytes
- long cenlen; // 4 bytes
- long cenoff; // 4 bytes
- long endpos; // 4 bytes
- }
+ private static native long open(String name, int mode, long lastModified,
+ boolean usemmap) throws IOException;
+ private static native int getTotal(long jzfile);
+ private static native boolean startsWithLOC(long jzfile);
+ private static native int read(long jzfile, long jzentry,
+ long pos, byte[] b, int off, int len);
- /*
- * Searches for end of central directory (END) header. The contents of
- * the END header will be read and placed in endbuf. Returns the file
- * position of the END header, otherwise returns -1 if the END header
- * was not found or an error occurred.
- */
- private End findEND() throws IOException {
- long ziplen = zfile.length();
- if (ziplen <= 0)
- zerror("zip file is empty");
- End end = new End();
- byte[] buf = new byte[READBLOCKSZ];
- long minHDR = (ziplen - END_MAXLEN) > 0 ? ziplen - END_MAXLEN : 0;
- long minPos = minHDR - (buf.length - ENDHDR);
- for (long pos = ziplen - buf.length; pos >= minPos; pos -= (buf.length - ENDHDR)) {
- int off = 0;
- if (pos < 0) {
- // Pretend there are some NUL bytes before start of file
- off = (int)-pos;
- Arrays.fill(buf, 0, off, (byte)0);
- }
- int len = buf.length - off;
- if (readFullyAt(buf, off, len, pos + off) != len ) {
- zerror("zip END header not found");
- }
- // Now scan the block backwards for END header signature
- for (int i = buf.length - ENDHDR; i >= 0; i--) {
- if (buf[i+0] == (byte)'P' &&
- buf[i+1] == (byte)'K' &&
- buf[i+2] == (byte)'\005' &&
- buf[i+3] == (byte)'\006') {
- // Found ENDSIG header
- byte[] endbuf = Arrays.copyOfRange(buf, i, i + ENDHDR);
- end.centot = ENDTOT(endbuf);
- end.cenlen = ENDSIZ(endbuf);
- end.cenoff = ENDOFF(endbuf);
- end.endpos = pos + i;
- int comlen = ENDCOM(endbuf);
- if (end.endpos + ENDHDR + comlen != ziplen) {
- // ENDSIG matched, however the size of file comment in it does
- // not match the real size. One "common" cause for this problem
- // is some "extra" bytes are padded at the end of the zipfile.
- // Let's do some extra verification, we don't care about the
- // performance in this situation.
- byte[] sbuf = new byte[4];
- long cenpos = end.endpos - end.cenlen;
- long locpos = cenpos - end.cenoff;
- if (cenpos < 0 ||
- locpos < 0 ||
- readFullyAt(sbuf, 0, sbuf.length, cenpos) != 4 ||
- GETSIG(sbuf) != CENSIG ||
- readFullyAt(sbuf, 0, sbuf.length, locpos) != 4 ||
- GETSIG(sbuf) != LOCSIG) {
- continue;
- }
- }
- if (comlen > 0) { // this zip file has comlen
- comment = new byte[comlen];
- if (readFullyAt(comment, 0, comlen, end.endpos + ENDHDR) != comlen) {
- zerror("zip comment read failed");
- }
- }
- if (end.cenlen == ZIP64_MAGICVAL ||
- end.cenoff == ZIP64_MAGICVAL ||
- end.centot == ZIP64_MAGICCOUNT)
- {
- // need to find the zip64 end;
- try {
- byte[] loc64 = new byte[ZIP64_LOCHDR];
- if (readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR)
- != loc64.length || GETSIG(loc64) != ZIP64_LOCSIG) {
- return end;
- }
- long end64pos = ZIP64_LOCOFF(loc64);
- byte[] end64buf = new byte[ZIP64_ENDHDR];
- if (readFullyAt(end64buf, 0, end64buf.length, end64pos)
- != end64buf.length || GETSIG(end64buf) != ZIP64_ENDSIG) {
- return end;
- }
- // end64 found, re-calcualte everything.
- end.cenlen = ZIP64_ENDSIZ(end64buf);
- end.cenoff = ZIP64_ENDOFF(end64buf);
- end.centot = (int)ZIP64_ENDTOT(end64buf); // assume total < 2g
- end.endpos = end64pos;
- } catch (IOException x) {} // no zip64 loc/end
- }
- return end;
- }
- }
- }
- zerror("zip END header not found");
- return null; //make compiler happy
- }
-
- // Reads zip file central directory.
- private void initCEN(int knownTotal) throws IOException {
- if (knownTotal == -1) {
- End end = findEND();
- if (end.endpos == 0) {
- locpos = 0;
- total = 0;
- entries = new int[0];
- cen = null;
- return; // only END header present
- }
- if (end.cenlen > end.endpos)
- zerror("invalid END header (bad central directory size)");
- long cenpos = end.endpos - end.cenlen; // position of CEN table
- // Get position of first local file (LOC) header, taking into
- // account that there may be a stub prefixed to the zip file.
- locpos = cenpos - end.cenoff;
- if (locpos < 0) {
- zerror("invalid END header (bad central directory offset)");
- }
- // read in the CEN and END
- cen = new byte[(int)(end.cenlen + ENDHDR)];
- if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR) {
- zerror("read CEN tables failed");
- }
- total = end.centot;
- } else {
- total = knownTotal;
- }
- // hash table for entries
- entries = new int[total * 3];
- tablelen = ((total/2) | 1); // Odd -> fewer collisions
- table = new int[tablelen];
- Arrays.fill(table, ZIP_ENDCHAIN);
- int idx = 0;
- int hash = 0;
- int next = -1;
-
- // list for all meta entries
- metanames = new ArrayList<>();
+ // access to the native zentry object
+ private static native long getEntryTime(long jzentry);
+ private static native long getEntryCrc(long jzentry);
+ private static native long getEntryCSize(long jzentry);
+ private static native long getEntrySize(long jzentry);
+ private static native int getEntryMethod(long jzentry);
+ private static native int getEntryFlag(long jzentry);
+ private static native byte[] getCommentBytes(long jzfile);
- // Iterate through the entries in the central directory
- int i = 0;
- int hsh = 0;
- int pos = 0;
- int limit = cen.length - ENDHDR;
- while (pos + CENHDR <= limit) {
- if (i >= total) {
- // This will only happen if the zip file has an incorrect
- // ENDTOT field, which usually means it contains more than
- // 65535 entries.
- initCEN(countCENHeaders(cen, limit));
- return;
- }
- if (CENSIG(cen, pos) != CENSIG)
- zerror("invalid CEN header (bad signature)");
- int method = CENHOW(cen, pos);
- int nlen = CENNAM(cen, pos);
- int elen = CENEXT(cen, pos);
- int clen = CENCOM(cen, pos);
- if ((CENFLG(cen, pos) & 1) != 0)
- zerror("invalid CEN header (encrypted entry)");
- if (method != STORED && method != DEFLATED)
- zerror("invalid CEN header (bad compression method: " + method + ")");
- if (pos + CENHDR + nlen > limit)
- zerror("invalid CEN header (bad header size)");
- // Record the CEN offset and the name hash in our hash cell.
- hash = hashN(cen, pos + CENHDR, nlen);
- hsh = (hash & 0x7fffffff) % tablelen;
- next = table[hsh];
- table[hsh] = idx;
- idx = addEntry(idx, hash, next, pos);
- // Adds name to metanames.
- if (isMetaName(cen, pos + CENHDR, nlen)) {
- metanames.add(pos);
- }
- // skip ext and comment
- pos += (CENHDR + nlen + elen + clen);
- i++;
- }
- total = i;
- if (pos + ENDHDR != cen.length) {
- zerror("invalid CEN header (bad header size)");
- }
- }
-
- private static void zerror(String msg) throws ZipException {
- throw new ZipException(msg);
- }
+ private static final int JZENTRY_NAME = 0;
+ private static final int JZENTRY_EXTRA = 1;
+ private static final int JZENTRY_COMMENT = 2;
+ private static native byte[] getEntryBytes(long jzentry, int type);
- /*
- * Returns the {@code pos} of the zip cen entry corresponding to the
- * specified entry name, or -1 if not found.
- */
- private int getEntryPos(byte[] name, boolean addSlash) {
- if (total == 0) {
- return -1;
- }
- int hsh = hashN(name, 0, name.length);
- int idx = table[(hsh & 0x7fffffff) % tablelen];
- /*
- * This while loop is an optimization where a double lookup
- * for name and name+/ is being performed. The name char
- * array has enough room at the end to try again with a
- * slash appended if the first table lookup does not succeed.
- */
- while(true) {
- /*
- * Search down the target hash chain for a entry whose
- * 32 bit hash matches the hashed name.
- */
- while (idx != ZIP_ENDCHAIN) {
- if (getEntryHash(idx) == hsh) {
- // The CEN name must match the specfied one
- int pos = getEntryPos(idx);
- if (name.length == CENNAM(cen, pos)) {
- boolean matched = true;
- int nameoff = pos + CENHDR;
- for (int i = 0; i < name.length; i++) {
- if (name[i] != cen[nameoff++]) {
- matched = false;
- break;
- }
- }
- if (matched) {
- return pos;
- }
- }
- }
- idx = getEntryNext(idx);
- }
- /* If not addSlash, or slash is already there, we are done */
- if (!addSlash || name[name.length - 1] == '/') {
- return -1;
- }
- /* Add slash and try once more */
- name = Arrays.copyOf(name, name.length + 1);
- name[name.length - 1] = '/';
- hsh = hash_append(hsh, (byte)'/');
- //idx = table[hsh % tablelen];
- idx = table[(hsh & 0x7fffffff) % tablelen];
- addSlash = false;
- }
- }
-
- private static byte[] metainf = new byte[] {
- 'M', 'E', 'T', 'A', '-', 'I' , 'N', 'F', '/',
- };
-
- /*
- * Returns true if the specified entry's name begins with the string
- * "META-INF/" irrespective of case.
- */
- private static boolean isMetaName(byte[] name, int off, int len) {
- if (len < 9 || (name[off] != 'M' && name[off] != 'm')) { // sizeof("META-INF/") - 1
- return false;
- }
- off++;
- for (int i = 1; i < metainf.length; i++) {
- byte c = name[off++];
- // Avoid toupper; it's locale-dependent
- if (c >= 'a' && c <= 'z') {
- c += 'A' - 'a';
- }
- if (metainf[i] != c) {
- return false;
- }
- }
- return true;
- }
-
- /*
- * Counts the number of CEN headers in a central directory extending
- * from BEG to END. Might return a bogus answer if the zip file is
- * corrupt, but will not crash.
- */
- static int countCENHeaders(byte[] cen, int end) {
- int count = 0;
- int pos = 0;
- while (pos + CENHDR <= end) {
- count++;
- pos += (CENHDR + CENNAM(cen, pos) + CENEXT(cen, pos) + CENCOM(cen, pos));
- }
- return count;
- }
- }
+ private static native String getZipMessage(long jzfile);
}
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipUtils.java Tue Dec 08 09:25:01 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipUtils.java Tue Dec 08 16:43:58 2015 -0800
@@ -31,8 +31,6 @@
import java.time.ZoneId;
import java.util.concurrent.TimeUnit;
-import static java.util.zip.ZipConstants.ENDHDR;
-
class ZipUtils {
// used to adjust values between Windows and java epoch
@@ -135,7 +133,7 @@
* The bytes are assumed to be in Intel (little-endian) byte order.
*/
public static final int get16(byte b[], int off) {
- return (b[off] & 0xff) | ((b[off + 1] & 0xff) << 8);
+ return Byte.toUnsignedInt(b[off]) | (Byte.toUnsignedInt(b[off+1]) << 8);
}
/**
@@ -162,79 +160,4 @@
public static final int get32S(byte b[], int off) {
return (get16(b, off) | (get16(b, off+2) << 16));
}
-
- // fields access methods
- static final int CH(byte[] b, int n) {
- return b[n] & 0xff ;
- }
-
- static final int SH(byte[] b, int n) {
- return (b[n] & 0xff) | ((b[n + 1] & 0xff) << 8);
- }
-
- static final long LG(byte[] b, int n) {
- return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL;
- }
-
- static final long LL(byte[] b, int n) {
- return (LG(b, n)) | (LG(b, n + 4) << 32);
- }
-
- static final long GETSIG(byte[] b) {
- return LG(b, 0);
- }
-
- // local file (LOC) header fields
- static final long LOCSIG(byte[] b) { return LG(b, 0); } // signature
- static final int LOCVER(byte[] b) { return SH(b, 4); } // version needed to extract
- static final int LOCFLG(byte[] b) { return SH(b, 6); } // general purpose bit flags
- static final int LOCHOW(byte[] b) { return SH(b, 8); } // compression method
- static final long LOCTIM(byte[] b) { return LG(b, 10);} // modification time
- static final long LOCCRC(byte[] b) { return LG(b, 14);} // crc of uncompressed data
- static final long LOCSIZ(byte[] b) { return LG(b, 18);} // compressed data size
- static final long LOCLEN(byte[] b) { return LG(b, 22);} // uncompressed data size
- static final int LOCNAM(byte[] b) { return SH(b, 26);} // filename length
- static final int LOCEXT(byte[] b) { return SH(b, 28);} // extra field length
-
- // extra local (EXT) header fields
- static final long EXTCRC(byte[] b) { return LG(b, 4);} // crc of uncompressed data
- static final long EXTSIZ(byte[] b) { return LG(b, 8);} // compressed size
- static final long EXTLEN(byte[] b) { return LG(b, 12);} // uncompressed size
-
- // end of central directory header (END) fields
- static final int ENDSUB(byte[] b) { return SH(b, 8); } // number of entries on this disk
- static final int ENDTOT(byte[] b) { return SH(b, 10);} // total number of entries
- static final long ENDSIZ(byte[] b) { return LG(b, 12);} // central directory size
- static final long ENDOFF(byte[] b) { return LG(b, 16);} // central directory offset
- static final int ENDCOM(byte[] b) { return SH(b, 20);} // size of zip file comment
- static final int ENDCOM(byte[] b, int off) { return SH(b, off + 20);}
-
- // zip64 end of central directory recoder fields
- static final long ZIP64_ENDTOD(byte[] b) { return LL(b, 24);} // total number of entries on disk
- static final long ZIP64_ENDTOT(byte[] b) { return LL(b, 32);} // total number of entries
- static final long ZIP64_ENDSIZ(byte[] b) { return LL(b, 40);} // central directory size
- static final long ZIP64_ENDOFF(byte[] b) { return LL(b, 48);} // central directory offset
- static final long ZIP64_LOCOFF(byte[] b) { return LL(b, 8);} // zip64 end offset
-
- // central directory header (CEN) fields
- static final long CENSIG(byte[] b, int pos) { return LG(b, pos + 0); }
- static final int CENVEM(byte[] b, int pos) { return SH(b, pos + 4); }
- static final int CENVER(byte[] b, int pos) { return SH(b, pos + 6); }
- static final int CENFLG(byte[] b, int pos) { return SH(b, pos + 8); }
- static final int CENHOW(byte[] b, int pos) { return SH(b, pos + 10);}
- static final long CENTIM(byte[] b, int pos) { return LG(b, pos + 12);}
- static final long CENCRC(byte[] b, int pos) { return LG(b, pos + 16);}
- static final long CENSIZ(byte[] b, int pos) { return LG(b, pos + 20);}
- static final long CENLEN(byte[] b, int pos) { return LG(b, pos + 24);}
- static final int CENNAM(byte[] b, int pos) { return SH(b, pos + 28);}
- static final int CENEXT(byte[] b, int pos) { return SH(b, pos + 30);}
- static final int CENCOM(byte[] b, int pos) { return SH(b, pos + 32);}
- static final int CENDSK(byte[] b, int pos) { return SH(b, pos + 34);}
- static final int CENATT(byte[] b, int pos) { return SH(b, pos + 36);}
- static final long CENATX(byte[] b, int pos) { return LG(b, pos + 38);}
- static final long CENOFF(byte[] b, int pos) { return LG(b, pos + 42);}
-
- // The END header is followed by a variable length comment of size < 64k.
- static final long END_MAXLEN = 0xFFFF + ENDHDR;
- static final int READBLOCKSZ = 128;
}
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilZipFileAccess.java Tue Dec 08 09:25:01 2015 -0800
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilZipFileAccess.java Tue Dec 08 16:43:58 2015 -0800
@@ -29,6 +29,5 @@
public interface JavaUtilZipFileAccess {
public boolean startsWithLocHeader(ZipFile zip);
- public String[] getMetaInfEntryNames(ZipFile zip);
}
--- a/jdk/src/java.base/share/classes/sun/misc/VM.java Tue Dec 08 09:25:01 2015 -0800
+++ b/jdk/src/java.base/share/classes/sun/misc/VM.java Tue Dec 08 16:43:58 2015 -0800
@@ -274,6 +274,9 @@
// used by java.lang.Integer.IntegerCache
props.remove("java.lang.Integer.IntegerCache.high");
+ // used by java.util.zip.ZipFile
+ props.remove("sun.zip.disableMemoryMapping");
+
// used by sun.launcher.LauncherHelper
props.remove("sun.java.launcher.diag");
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/native/libzip/ZipFile.c Tue Dec 08 16:43:58 2015 -0800
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * Native method support for java.util.zip.ZipFile
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <assert.h>
+#include "jlong.h"
+#include "jvm.h"
+#include "jni.h"
+#include "jni_util.h"
+#include "zip_util.h"
+#ifdef WIN32
+#include "io_util_md.h"
+#else
+#include "io_util.h"
+#endif
+
+#include "java_util_zip_ZipFile.h"
+#include "java_util_jar_JarFile.h"
+
+#define DEFLATED 8
+#define STORED 0
+
+static jfieldID jzfileID;
+
+static int OPEN_READ = java_util_zip_ZipFile_OPEN_READ;
+static int OPEN_DELETE = java_util_zip_ZipFile_OPEN_DELETE;
+
+
+/*
+ * Declare library specific JNI_Onload entry if static build
+ */
+DEF_STATIC_JNI_OnLoad
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_ZipFile_initIDs(JNIEnv *env, jclass cls)
+{
+ jzfileID = (*env)->GetFieldID(env, cls, "jzfile", "J");
+ assert(jzfileID != 0);
+}
+
+static void
+ThrowZipException(JNIEnv *env, const char *msg)
+{
+ jstring s = NULL;
+ jobject x;
+
+ if (msg != NULL) {
+ s = JNU_NewStringPlatform(env, msg);
+ }
+ if (s != NULL) {
+ x = JNU_NewObjectByName(env,
+ "java/util/zip/ZipException",
+ "(Ljava/lang/String;)V", s);
+ if (x != NULL) {
+ (*env)->Throw(env, x);
+ }
+ }
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_ZipFile_open(JNIEnv *env, jclass cls, jstring name,
+ jint mode, jlong lastModified,
+ jboolean usemmap)
+{
+ const char *path = JNU_GetStringPlatformChars(env, name, 0);
+ char *msg = 0;
+ jlong result = 0;
+ int flag = 0;
+ jzfile *zip = 0;
+
+ if (mode & OPEN_READ) flag |= O_RDONLY;
+
+ if (path != 0) {
+ zip = ZIP_Get_From_Cache(path, &msg, lastModified);
+ if (zip == 0 && msg == 0) {
+ ZFILE zfd = 0;
+#ifdef WIN32
+ if (mode & OPEN_DELETE) flag |= O_TEMPORARY;
+ zfd = winFileHandleOpen(env, name, flag);
+ if (zfd == -1) {
+ /* Exception already pending. */
+ goto finally;
+ }
+#else
+ zfd = open(path, flag, 0);
+ if (zfd < 0) {
+ throwFileNotFoundException(env, name);
+ goto finally;
+ }
+ if (mode & OPEN_DELETE) {
+ unlink(path);
+ }
+#endif
+ zip = ZIP_Put_In_Cache0(path, zfd, &msg, lastModified, usemmap);
+ }
+
+ if (zip != 0) {
+ result = ptr_to_jlong(zip);
+ } else if (msg != 0) {
+ ThrowZipException(env, msg);
+ free(msg);
+ } else if (errno == ENOMEM) {
+ JNU_ThrowOutOfMemoryError(env, 0);
+ } else {
+ ThrowZipException(env, "error in opening zip file");
+ }
+finally:
+ JNU_ReleaseStringPlatformChars(env, name, path);
+ }
+ return result;
+}
+
+JNIEXPORT jint JNICALL
+Java_java_util_zip_ZipFile_getTotal(JNIEnv *env, jclass cls, jlong zfile)
+{
+ jzfile *zip = jlong_to_ptr(zfile);
+
+ return zip->total;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_java_util_zip_ZipFile_startsWithLOC(JNIEnv *env, jclass cls, jlong zfile)
+{
+ jzfile *zip = jlong_to_ptr(zfile);
+
+ return zip->locsig;
+}
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_ZipFile_close(JNIEnv *env, jclass cls, jlong zfile)
+{
+ ZIP_Close(jlong_to_ptr(zfile));
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_ZipFile_getEntry(JNIEnv *env, jclass cls, jlong zfile,
+ jbyteArray name, jboolean addSlash)
+{
+#define MAXNAME 1024
+ jzfile *zip = jlong_to_ptr(zfile);
+ jsize ulen = (*env)->GetArrayLength(env, name);
+ char buf[MAXNAME+2], *path;
+ jzentry *ze;
+
+ if (ulen > MAXNAME) {
+ path = malloc(ulen + 2);
+ if (path == 0) {
+ JNU_ThrowOutOfMemoryError(env, 0);
+ return 0;
+ }
+ } else {
+ path = buf;
+ }
+ (*env)->GetByteArrayRegion(env, name, 0, ulen, (jbyte *)path);
+ path[ulen] = '\0';
+ ze = ZIP_GetEntry2(zip, path, (jint)ulen, addSlash);
+ if (path != buf) {
+ free(path);
+ }
+ return ptr_to_jlong(ze);
+}
+
+JNIEXPORT void JNICALL
+Java_java_util_zip_ZipFile_freeEntry(JNIEnv *env, jclass cls, jlong zfile,
+ jlong zentry)
+{
+ jzfile *zip = jlong_to_ptr(zfile);
+ jzentry *ze = jlong_to_ptr(zentry);
+ ZIP_FreeEntry(zip, ze);
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_ZipFile_getNextEntry(JNIEnv *env, jclass cls, jlong zfile,
+ jint n)
+{
+ jzentry *ze = ZIP_GetNextEntry(jlong_to_ptr(zfile), n);
+ return ptr_to_jlong(ze);
+}
+
+JNIEXPORT jint JNICALL
+Java_java_util_zip_ZipFile_getEntryMethod(JNIEnv *env, jclass cls, jlong zentry)
+{
+ jzentry *ze = jlong_to_ptr(zentry);
+ return ze->csize != 0 ? DEFLATED : STORED;
+}
+
+JNIEXPORT jint JNICALL
+Java_java_util_zip_ZipFile_getEntryFlag(JNIEnv *env, jclass cls, jlong zentry)
+{
+ jzentry *ze = jlong_to_ptr(zentry);
+ return ze->flag;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_ZipFile_getEntryCSize(JNIEnv *env, jclass cls, jlong zentry)
+{
+ jzentry *ze = jlong_to_ptr(zentry);
+ return ze->csize != 0 ? ze->csize : ze->size;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_ZipFile_getEntrySize(JNIEnv *env, jclass cls, jlong zentry)
+{
+ jzentry *ze = jlong_to_ptr(zentry);
+ return ze->size;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_ZipFile_getEntryTime(JNIEnv *env, jclass cls, jlong zentry)
+{
+ jzentry *ze = jlong_to_ptr(zentry);
+ return (jlong)ze->time & 0xffffffffUL;
+}
+
+JNIEXPORT jlong JNICALL
+Java_java_util_zip_ZipFile_getEntryCrc(JNIEnv *env, jclass cls, jlong zentry)
+{
+ jzentry *ze = jlong_to_ptr(zentry);
+ return (jlong)ze->crc & 0xffffffffUL;
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_java_util_zip_ZipFile_getCommentBytes(JNIEnv *env,
+ jclass cls,
+ jlong zfile)
+{
+ jzfile *zip = jlong_to_ptr(zfile);
+ jbyteArray jba = NULL;
+
+ if (zip->comment != NULL) {
+ if ((jba = (*env)->NewByteArray(env, zip->clen)) == NULL)
+ return NULL;
+ (*env)->SetByteArrayRegion(env, jba, 0, zip->clen, (jbyte*)zip->comment);
+ }
+ return jba;
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_java_util_zip_ZipFile_getEntryBytes(JNIEnv *env,
+ jclass cls,
+ jlong zentry, jint type)
+{
+ jzentry *ze = jlong_to_ptr(zentry);
+ int len = 0;
+ jbyteArray jba = NULL;
+ switch (type) {
+ case java_util_zip_ZipFile_JZENTRY_NAME:
+ if (ze->name != 0) {
+ len = (int)ze->nlen;
+ // Unlike for extra and comment, we never return null for
+ // an (extremely rarely seen) empty name
+ if ((jba = (*env)->NewByteArray(env, len)) == NULL)
+ break;
+ (*env)->SetByteArrayRegion(env, jba, 0, len, (jbyte *)ze->name);
+ }
+ break;
+ case java_util_zip_ZipFile_JZENTRY_EXTRA:
+ if (ze->extra != 0) {
+ unsigned char *bp = (unsigned char *)&ze->extra[0];
+ len = (bp[0] | (bp[1] << 8));
+ if (len <= 0 || (jba = (*env)->NewByteArray(env, len)) == NULL)
+ break;
+ (*env)->SetByteArrayRegion(env, jba, 0, len, &ze->extra[2]);
+ }
+ break;
+ case java_util_zip_ZipFile_JZENTRY_COMMENT:
+ if (ze->comment != 0) {
+ len = (int)strlen(ze->comment);
+ if (len == 0 || (jba = (*env)->NewByteArray(env, len)) == NULL)
+ break;
+ (*env)->SetByteArrayRegion(env, jba, 0, len, (jbyte*)ze->comment);
+ }
+ break;
+ }
+ return jba;
+}
+
+JNIEXPORT jint JNICALL
+Java_java_util_zip_ZipFile_read(JNIEnv *env, jclass cls, jlong zfile,
+ jlong zentry, jlong pos, jbyteArray bytes,
+ jint off, jint len)
+{
+ jzfile *zip = jlong_to_ptr(zfile);
+ char *msg;
+
+#define BUFSIZE 8192
+ /* copy via tmp stack buffer: */
+ jbyte buf[BUFSIZE];
+
+ if (len > BUFSIZE) {
+ len = BUFSIZE;
+ }
+
+ ZIP_Lock(zip);
+ len = ZIP_Read(zip, jlong_to_ptr(zentry), pos, buf, len);
+ msg = zip->msg;
+ ZIP_Unlock(zip);
+ if (len != -1) {
+ (*env)->SetByteArrayRegion(env, bytes, off, len, buf);
+ }
+
+ if (len == -1) {
+ if (msg != 0) {
+ ThrowZipException(env, msg);
+ } else {
+ char errmsg[128];
+ sprintf(errmsg, "errno: %d, error: %s\n",
+ errno, "Error reading ZIP file");
+ JNU_ThrowIOExceptionWithLastError(env, errmsg);
+ }
+ }
+
+ return len;
+}
+
+/*
+ * Returns an array of strings representing the names of all entries
+ * that begin with "META-INF/" (case ignored). This native method is
+ * used in JarFile as an optimization when looking up manifest and
+ * signature file entries. Returns null if no entries were found.
+ */
+JNIEXPORT jobjectArray JNICALL
+Java_java_util_jar_JarFile_getMetaInfEntryNames(JNIEnv *env, jobject obj)
+{
+ jlong zfile = (*env)->GetLongField(env, obj, jzfileID);
+ jzfile *zip;
+ int i, count;
+ jobjectArray result = 0;
+
+ if (zfile == 0) {
+ JNU_ThrowByName(env,
+ "java/lang/IllegalStateException", "zip file closed");
+ return NULL;
+ }
+ zip = jlong_to_ptr(zfile);
+
+ /* count the number of valid ZIP metanames */
+ count = 0;
+ if (zip->metanames != 0) {
+ for (i = 0; i < zip->metacount; i++) {
+ if (zip->metanames[i] != 0) {
+ count++;
+ }
+ }
+ }
+
+ /* If some names were found then build array of java strings */
+ if (count > 0) {
+ jclass cls = JNU_ClassString(env);
+ CHECK_NULL_RETURN(cls, NULL);
+ result = (*env)->NewObjectArray(env, count, cls, 0);
+ CHECK_NULL_RETURN(result, NULL);
+ if (result != 0) {
+ for (i = 0; i < count; i++) {
+ jstring str = (*env)->NewStringUTF(env, zip->metanames[i]);
+ if (str == 0) {
+ break;
+ }
+ (*env)->SetObjectArrayElement(env, result, i, str);
+ (*env)->DeleteLocalRef(env, str);
+ }
+ }
+ }
+ return result;
+}
+
+JNIEXPORT jstring JNICALL
+Java_java_util_zip_ZipFile_getZipMessage(JNIEnv *env, jclass cls, jlong zfile)
+{
+ jzfile *zip = jlong_to_ptr(zfile);
+ char *msg = zip->msg;
+ if (msg == NULL) {
+ return NULL;
+ }
+ return JNU_NewStringPlatform(env, msg);
+}
--- a/jdk/test/java/util/zip/ZipFile/ReadZip.java Tue Dec 08 09:25:01 2015 -0800
+++ b/jdk/test/java/util/zip/ZipFile/ReadZip.java Tue Dec 08 16:43:58 2015 -0800
@@ -30,7 +30,6 @@
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
-import java.nio.file.NoSuchFileException;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.util.zip.*;
@@ -111,6 +110,6 @@
"input"
+ String.valueOf(new java.util.Random().nextInt())
+ ".zip")));
- } catch (NoSuchFileException nsfe) {}
+ } catch (FileNotFoundException fnfe) {}
}
}
--- a/jdk/test/java/util/zip/ZipFile/TestZipFile.java Tue Dec 08 09:25:01 2015 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,361 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 8142508
- * @summary Tests various ZipFile apis
- * @run main/manual TestZipFile
- */
-
-import java.io.*;
-import java.lang.reflect.Method;
-import java.nio.*;
-import java.nio.file.*;
-import java.nio.file.attribute.*;
-import java.util.*;
-import java.util.concurrent.*;
-import java.util.zip.*;
-
-public class TestZipFile {
-
- private static Random r = new Random();
- private static int N = 50;
- private static int NN = 10;
- private static int ENUM = 10000;
- private static int ESZ = 10000;
- private static ExecutorService executor = Executors.newFixedThreadPool(20);
- private static Set<Path> paths = new HashSet<>();
-
- static void realMain (String[] args) throws Throwable {
-
- try {
- for (int i = 0; i < N; i++) {
- test(r.nextInt(ENUM), r.nextInt(ESZ), false, true);
- test(r.nextInt(ENUM), r.nextInt(ESZ), true, true);
- }
-
- for (int i = 0; i < NN; i++) {
- test(r.nextInt(ENUM), 100000 + r.nextInt(ESZ), false, true);
- test(r.nextInt(ENUM), 100000 + r.nextInt(ESZ), true, true);
- testCachedDelete();
- testCachedOverwrite();
- //test(r.nextInt(ENUM), r.nextInt(ESZ), false, true);
- }
-
- test(70000, 1000, false, true); // > 65536 entry number;
- testDelete(); // OPEN_DELETE
-
- executor.shutdown();
- executor.awaitTermination(10, TimeUnit.MINUTES);
- } finally {
- for (Path path : paths) {
- Files.deleteIfExists(path);
- }
- }
- }
-
- static void test(int numEntry, int szMax, boolean addPrefix, boolean cleanOld) {
- String name = "zftest" + r.nextInt() + ".zip";
- Zip zip = new Zip(name, numEntry, szMax, addPrefix, cleanOld);
- for (int i = 0; i < NN; i++) {
- executor.submit(() -> doTest(zip));
- }
- }
-
- // test scenario:
- // (1) open the ZipFile(zip) with OPEN_READ | OPEN_DELETE
- // (2) test the ZipFile works correctly
- // (3) check the zip is deleted after ZipFile gets closed
- static void testDelete() throws Throwable {
- String name = "zftest" + r.nextInt() + ".zip";
- Zip zip = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
- try (ZipFile zf = new ZipFile(new File(zip.name),
- ZipFile.OPEN_READ | ZipFile.OPEN_DELETE ))
- {
- doTest0(zip, zf);
- }
- Path p = Paths.get(name);
- if (Files.exists(p)) {
- fail("Failed to delete " + name + " with OPEN_DELETE");
- }
- }
-
- // test scenario:
- // (1) keep a ZipFile(zip1) alive (in ZipFile's cache), dont close it
- // (2) delete zip1 and create zip2 with the same name the zip1 with zip2
- // (3) zip1 tests should fail, but no crash
- // (4) zip2 tasks should all get zip2, then pass normal testing.
- static void testCachedDelete() throws Throwable {
- String name = "zftest" + r.nextInt() + ".zip";
- Zip zip1 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
-
- try (ZipFile zf = new ZipFile(zip1.name)) {
- for (int i = 0; i < NN; i++) {
- executor.submit(() -> verifyNoCrash(zip1));
- }
- // delete the "zip1" and create a new one to test
- Zip zip2 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
- /*
- System.out.println("========================================");
- System.out.printf(" zip1=%s, mt=%d, enum=%d%n ->attrs=[key=%s, sz=%d, mt=%d]%n",
- zip1.name, zip1.lastModified, zip1.entries.size(),
- zip1.attrs.fileKey(), zip1.attrs.size(), zip1.attrs.lastModifiedTime().toMillis());
- System.out.printf(" zip2=%s, mt=%d, enum=%d%n ->attrs=[key=%s, sz=%d, mt=%d]%n",
- zip2.name, zip2.lastModified, zip2.entries.size(),
- zip2.attrs.fileKey(), zip2.attrs.size(), zip2.attrs.lastModifiedTime().toMillis());
- */
- for (int i = 0; i < NN; i++) {
- executor.submit(() -> doTest(zip2));
- }
- }
- }
-
- // overwrite the "zip1" and create a new one to test. So the two zip files
- // have the same fileKey, but probably different lastModified()
- static void testCachedOverwrite() throws Throwable {
- String name = "zftest" + r.nextInt() + ".zip";
- Zip zip1 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, true);
- try (ZipFile zf = new ZipFile(zip1.name)) {
- for (int i = 0; i < NN; i++) {
- executor.submit(() -> verifyNoCrash(zip1));
- }
- // overwrite the "zip1" with new contents
- Zip zip2 = new Zip(name, r.nextInt(ENUM), r.nextInt(ESZ), false, false);
- for (int i = 0; i < NN; i++) {
- executor.submit(() -> doTest(zip2));
- }
- }
- }
-
- // just check the entries and contents. since the file has been either overwritten
- // or deleted/rewritten, we only care if it crahes or not.
- static void verifyNoCrash(Zip zip) throws RuntimeException {
- try (ZipFile zf = new ZipFile(zip.name)) {
- List<ZipEntry> zlist = new ArrayList(zip.entries.keySet());
- String[] elist = zf.stream().map( e -> e.getName()).toArray(String[]::new);
- if (!Arrays.equals(elist,
- zlist.stream().map( e -> e.getName()).toArray(String[]::new)))
- {
- //System.out.printf("++++++ LIST NG [%s] entries.len=%d, expected=%d+++++++%n",
- // zf.getName(), elist.length, zlist.size());
- return;
- }
- for (ZipEntry ze : zlist) {
- byte[] zdata = zip.entries.get(ze);
- ZipEntry e = zf.getEntry(ze.getName());
- if (e != null) {
- checkEqual(e, ze);
- if (!e.isDirectory()) {
- // check with readAllBytes
- try (InputStream is = zf.getInputStream(e)) {
- if (!Arrays.equals(zdata, is.readAllBytes())) {
- //System.out.printf("++++++ BYTES NG [%s]/[%s] ++++++++%n",
- // zf.getName(), ze.getName());
- }
- }
- }
- }
- }
- } catch (Throwable t) {
- // t.printStackTrace();
- // fail(t.toString());
- }
- }
-
- static void checkEqual(ZipEntry x, ZipEntry y) {
- if (x.getName().equals(y.getName()) &&
- x.isDirectory() == y.isDirectory() &&
- x.getMethod() == y.getMethod() &&
- (x.getTime() / 2000) == y.getTime() / 2000 &&
- x.getSize() == y.getSize() &&
- x.getCompressedSize() == y.getCompressedSize() &&
- x.getCrc() == y.getCrc() &&
- x.getComment().equals(y.getComment())
- ) {
- pass();
- } else {
- fail(x + " not equal to " + y);
- System.out.printf(" %s %s%n", x.getName(), y.getName());
- System.out.printf(" %d %d%n", x.getMethod(), y.getMethod());
- System.out.printf(" %d %d%n", x.getTime(), y.getTime());
- System.out.printf(" %d %d%n", x.getSize(), y.getSize());
- System.out.printf(" %d %d%n", x.getCompressedSize(), y.getCompressedSize());
- System.out.printf(" %d %d%n", x.getCrc(), y.getCrc());
- System.out.println("-----------------");
- }
- }
-
- static void doTest(Zip zip) throws RuntimeException {
- //Thread me = Thread.currentThread();
- try (ZipFile zf = new ZipFile(zip.name)) {
- doTest0(zip, zf);
- } catch (Throwable t) {
- throw new RuntimeException(t);
- }
- }
-
- static void doTest0(Zip zip, ZipFile zf) throws Throwable {
- List<ZipEntry> list = new ArrayList(zip.entries.keySet());
- // (1) check entry list, in expected order
- if (!check(Arrays.equals(
- list.stream().map( e -> e.getName()).toArray(String[]::new),
- zf.stream().map( e -> e.getName()).toArray(String[]::new)))) {
- return;
- }
- // (2) shuffle, and check each entry and its bytes
- Collections.shuffle(list);
- for (ZipEntry ze : list) {
- byte[] data = zip.entries.get(ze);
- ZipEntry e = zf.getEntry(ze.getName());
- checkEqual(e, ze);
- if (!e.isDirectory()) {
- // check with readAllBytes
- try (InputStream is = zf.getInputStream(e)) {
- check(Arrays.equals(data, is.readAllBytes()));
- }
- // check with smaller sized buf
- try (InputStream is = zf.getInputStream(e)) {
- byte[] buf = new byte[(int)e.getSize()];
- int sz = r.nextInt((int)e.getSize()/4 + 1) + 1;
- int off = 0;
- int n;
- while ((n = is.read(buf, off, buf.length - off)) > 0) {
- off += n;
- }
- check(is.read() == -1);
- check(Arrays.equals(data, buf));
- }
- }
- }
- // (3) check getMetaInfEntryNames
- String[] metas = list.stream()
- .map( e -> e.getName())
- .filter( s -> s.startsWith("META-INF/"))
- .sorted()
- .toArray(String[]::new);
- if (metas.length > 0) {
- // meta-inf entries
- Method getMetas = ZipFile.class.getDeclaredMethod("getMetaInfEntryNames");
- getMetas.setAccessible(true);
- String[] names = (String[])getMetas.invoke(zf);
- if (names == null) {
- fail("Failed to get metanames from " + zf);
- } else {
- Arrays.sort(names);
- check(Arrays.equals(names, metas));
- }
- }
- }
-
- private static class Zip {
- String name;
- Map<ZipEntry, byte[]> entries;
- BasicFileAttributes attrs;
- long lastModified;
-
- Zip(String name, int num, int szMax, boolean prefix, boolean clean) {
- this.name = name;
- entries = new LinkedHashMap<>(num);
- try {
- Path p = Paths.get(name);
- if (clean) {
- Files.deleteIfExists(p);
- }
- paths.add(p);
- } catch (Exception x) {
- throw (RuntimeException)x;
- }
-
- try (FileOutputStream fos = new FileOutputStream(name);
- BufferedOutputStream bos = new BufferedOutputStream(fos);
- ZipOutputStream zos = new ZipOutputStream(bos))
- {
- if (prefix) {
- byte[] bytes = new byte[r.nextInt(1000)];
- r.nextBytes(bytes);
- bos.write(bytes);
- }
- CRC32 crc = new CRC32();
- for (int i = 0; i < num; i++) {
- String ename = "entry-" + i + "-name-" + r.nextLong();
- ZipEntry ze = new ZipEntry(ename);
- int method = r.nextBoolean() ? ZipEntry.STORED : ZipEntry.DEFLATED;
- writeEntry(zos, crc, ze, ZipEntry.STORED, szMax);
- }
- // add some manifest entries
- for (int i = 0; i < r.nextInt(20); i++) {
- String meta = "META-INF/" + "entry-" + i + "-metainf-" + r.nextLong();
- ZipEntry ze = new ZipEntry(meta);
- writeEntry(zos, crc, ze, ZipEntry.STORED, szMax);
- }
- } catch (Exception x) {
- throw (RuntimeException)x;
- }
- try {
- this.attrs = Files.readAttributes(Paths.get(name), BasicFileAttributes.class);
- this.lastModified = new File(name).lastModified();
- } catch (Exception x) {
- throw (RuntimeException)x;
- }
- }
-
- private void writeEntry(ZipOutputStream zos, CRC32 crc,
- ZipEntry ze, int method, int szMax)
- throws IOException
- {
- ze.setMethod(method);
- byte[] data = new byte[r.nextInt(szMax + 1)];
- r.nextBytes(data);
- if (method == ZipEntry.STORED) { // must set size/csize/crc
- ze.setSize(data.length);
- ze.setCompressedSize(data.length);
- crc.reset();
- crc.update(data);
- ze.setCrc(crc.getValue());
- }
- ze.setTime(System.currentTimeMillis());
- ze.setComment(ze.getName());
- zos.putNextEntry(ze);
- zos.write(data);
- zos.closeEntry();
- entries.put(ze, data);
- }
- }
-
- //--------------------- Infrastructure ---------------------------
- static volatile int passed = 0, failed = 0;
- static void pass() {passed++;}
- static void pass(String msg) {System.out.println(msg); passed++;}
- static void fail() {failed++; Thread.dumpStack();}
- static void fail(String msg) {System.out.println(msg); fail();}
- static void unexpected(Throwable t) {failed++; t.printStackTrace();}
- static void unexpected(Throwable t, String msg) {
- System.out.println(msg); failed++; t.printStackTrace();}
- static boolean check(boolean cond) {if (cond) pass(); else fail(); return cond;}
-
- public static void main(String[] args) throws Throwable {
- try {realMain(args);} catch (Throwable t) {unexpected(t);}
- System.out.println("\nPassed = " + passed + " failed = " + failed);
- if (failed > 0) throw new AssertionError("Some tests failed");}
-}