< prev index next >

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

Print this page

        

*** 28,37 **** --- 28,40 ---- import java.io.Closeable; import java.io.InputStream; import java.io.IOException; import java.io.EOFException; import java.io.File; + import java.nio.ByteBuffer; + import java.nio.ByteOrder; + import java.nio.IntBuffer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.Deque; import java.util.Enumeration;
*** 57,66 **** --- 60,72 ---- * @author David Connelly */ public class ZipFile implements ZipConstants, Closeable { private long jzfile; // address of jzfile data + private IntBuffer table; // direct buffer mapping jzfile->table + private ByteBuffer entries; // direct buffer mapping jzfile->entries + private int falsePositiveProbes; 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;
*** 87,103 **** --- 93,116 ---- } private static native void initIDs(); private static final boolean usemmap; + private static final boolean useNativeTableProbe; 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"))); + // A system property to enable mapping of native hash table of entries + // using direct byte buffers to facilitate a probe that speeds-up lookups + // for non-existent entries (important for class loading with large + // class-paths where JAR files are tried in order to find a class/resource) + prop = System.getProperty("sun.zip.useNativeTableProbe"); + useNativeTableProbe = prop != null && prop.equalsIgnoreCase("true"); } /** * Opens a zip file for reading. *
*** 214,224 **** } if (charset == null) throw new NullPointerException("charset is null"); this.zc = ZipCoder.get(charset); long t0 = System.nanoTime(); ! 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); --- 227,242 ---- } if (charset == null) throw new NullPointerException("charset is null"); this.zc = ZipCoder.get(charset); long t0 = System.nanoTime(); ! ByteBuffer[] tableAndEntries = useNativeTableProbe ? new ByteBuffer[2] : null; ! jzfile = open(name, mode, file.lastModified(), usemmap, tableAndEntries); ! if (tableAndEntries != null) { ! table = tableAndEntries[0].order(ByteOrder.nativeOrder()).asIntBuffer(); ! entries = tableAndEntries[1].order(ByteOrder.nativeOrder()); ! } sun.misc.PerfCounter.getZipFileOpenTime().addElapsedTimeFrom(t0); sun.misc.PerfCounter.getZipFileCount().increment(); this.name = name; this.total = getTotal(jzfile); this.locsig = startsWithLOC(jzfile);
*** 302,324 **** */ public ZipEntry getEntry(String name) { if (name == null) { throw new NullPointerException("name"); } - long jzentry = 0; synchronized (this) { ensureOpen(); ! jzentry = getEntry(jzfile, zc.getBytes(name), true); if (jzentry != 0) { ZipEntry ze = getZipEntry(name, jzentry); freeEntry(jzfile, jzentry); return ze; } } return null; } 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); --- 320,406 ---- */ public ZipEntry getEntry(String name) { if (name == null) { throw new NullPointerException("name"); } synchronized (this) { ensureOpen(); ! byte[] nameBytes = zc.getBytes(name); ! int h = hash(nameBytes); ! if (mayContainEntry(h) || ! (name.charAt(name.length()-1) != '/' && mayContainEntry(31 * h + '/'))) { ! long jzentry = getEntry(jzfile, nameBytes, true); if (jzentry != 0) { ZipEntry ze = getZipEntry(name, jzentry); freeEntry(jzfile, jzentry); return ze; + } else { + falsePositiveProbes++; + } } } return null; } + /** + * Lookup into a hash table maintained in two native arrays (table and entries) + * to probe whether there may be an entry present with specified 32 bit hash. + */ + private boolean mayContainEntry(int h) { + // when sun.zip.useNativeTableProbe is not defined, + // any entry hash may be valid... + if (table == null) return true; + + // use unsigned modulus to calculate index into hash table + int i = Integer.remainderUnsigned(h, table.capacity()); + // obtain index into entries array which holds a head of the hash table bucket + int head = table.get(i); + // special -1 value marks end of chain + while (head != -1) { + // + // entries array is composed of the following 16-byte entries (zip_util.h): + // + // typedef struct jzcell { + // unsigned int hash; /* 32 bit hashcode on name */ + // unsigned int next; /* hash chain: index into jzfile->entries */ + // jlong cenpos; /* Offset of central directory file header */ + // } jzcell; + // + int hi = head << 4; // index -> byte offset + if (entries.getInt(hi) == h) { // entries[head].hash + // got it + // TODO: return jzcell.cenpos to save native code from re-executing the same lookup + return true; + } + // advance to next in chain + head = entries.getInt(hi + 4); // entries[head].next + } + // no luck + return false; + } + + /** + * Equivalent to the following from zip_util.c: + * <pre> + * static unsigned int + * hashN(const char *s, int length) + * { + * int h = 0; + * while (length-- > 0) + * h = 31*h + *s++; + * return h; + * } + * </pre> + */ + private static int hash(byte[] bytes) { + int h = 0; + for (int i = 0; i < bytes.length; i++) { + h = 31 * h + ((int) bytes[i] & 0xFF); + } + return h; + } + 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);
*** 640,650 **** if (jzfile != 0) { // Close the zip file long zf = this.jzfile; jzfile = 0; ! close(zf); } } } --- 722,733 ---- if (jzfile != 0) { // Close the zip file long zf = this.jzfile; jzfile = 0; ! table = null; ! entries = null; close(zf); } } }
*** 797,807 **** private boolean startsWithLocHeader() { return locsig; } 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); --- 880,891 ---- private boolean startsWithLocHeader() { return locsig; } private static native long open(String name, int mode, long lastModified, ! boolean usemmap, ! ByteBuffer[] tableAndEntries) 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);
< prev index next >