changeset 13278:b0314bbe7c41

8144958: changes by JDK-8142508 seems to have broken jtreg Reviewed-by: darcy
author sherman
date Tue, 08 Dec 2015 16:43:58 -0800
parents a5d8e25767f8
children e6c3d2856593
files make/mapfiles/libzip/mapfile-vers make/mapfiles/libzip/reorder-sparc make/mapfiles/libzip/reorder-sparcv9 make/mapfiles/libzip/reorder-x86 src/java.base/share/classes/java/util/jar/JarFile.java src/java.base/share/classes/java/util/zip/ZipCoder.java src/java.base/share/classes/java/util/zip/ZipFile.java src/java.base/share/classes/java/util/zip/ZipUtils.java src/java.base/share/classes/jdk/internal/misc/JavaUtilZipFileAccess.java src/java.base/share/classes/sun/misc/VM.java src/java.base/share/native/libzip/ZipFile.c test/java/util/zip/ZipFile/ReadZip.java test/java/util/zip/ZipFile/TestZipFile.java
diffstat 13 files changed, 672 insertions(+), 1115 deletions(-) [+]
line wrap: on
line diff
--- a/make/mapfiles/libzip/mapfile-vers	Tue Dec 08 09:25:01 2015 -0800
+++ b/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/make/mapfiles/libzip/reorder-sparc	Tue Dec 08 09:25:01 2015 -0800
+++ b/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/make/mapfiles/libzip/reorder-sparcv9	Tue Dec 08 09:25:01 2015 -0800
+++ b/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/make/mapfiles/libzip/reorder-x86	Tue Dec 08 09:25:01 2015 -0800
+++ b/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/src/java.base/share/classes/java/util/jar/JarFile.java	Tue Dec 08 09:25:01 2015 -0800
+++ b/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/src/java.base/share/classes/java/util/zip/ZipCoder.java	Tue Dec 08 09:25:01 2015 -0800
+++ b/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/src/java.base/share/classes/java/util/zip/ZipFile.java	Tue Dec 08 09:25:01 2015 -0800
+++ b/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 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);
 
-        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)
+    // 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);
 
-        // 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 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);
 
-        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
-        }
-
-        /*
-         * 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<>();
-
-            // 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);
-        }
-
-        /*
-         * 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/src/java.base/share/classes/java/util/zip/ZipUtils.java	Tue Dec 08 09:25:01 2015 -0800
+++ b/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/src/java.base/share/classes/jdk/internal/misc/JavaUtilZipFileAccess.java	Tue Dec 08 09:25:01 2015 -0800
+++ b/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/src/java.base/share/classes/sun/misc/VM.java	Tue Dec 08 09:25:01 2015 -0800
+++ b/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/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/test/java/util/zip/ZipFile/ReadZip.java	Tue Dec 08 09:25:01 2015 -0800
+++ b/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/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");}
-}