8157069: Assorted ZipFile improvements
authormartin
Mon, 16 May 2016 11:42:31 -0700
changeset 38375 5df893ca926c
parent 38374 3758f3419566
child 38376 08549412f0dc
8157069: Assorted ZipFile improvements Reviewed-by: sherman
jdk/src/java.base/share/classes/java/util/zip/ZipFile.java
jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java	Tue May 17 19:20:05 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java	Mon May 16 11:42:31 2016 -0700
@@ -462,9 +462,13 @@
 
     private class ZipEntryIterator implements Enumeration<ZipEntry>, Iterator<ZipEntry> {
         private int i = 0;
+        private final int entryCount;
 
         public ZipEntryIterator() {
-            ensureOpen();
+            synchronized (ZipFile.this) {
+                ensureOpen();
+                this.entryCount = zsrc.total;
+            }
         }
 
         public boolean hasMoreElements() {
@@ -472,10 +476,7 @@
         }
 
         public boolean hasNext() {
-            synchronized (ZipFile.this) {
-                ensureOpen();
-                return i < zsrc.total;
-            }
+            return i < entryCount;
         }
 
         public ZipEntry nextElement() {
@@ -485,7 +486,7 @@
         public ZipEntry next() {
             synchronized (ZipFile.this) {
                 ensureOpen();
-                if (i >= zsrc.total) {
+                if (!hasNext()) {
                     throw new NoSuchElementException();
                 }
                 // each "entry" has 3 ints in table entries
@@ -526,34 +527,34 @@
     /* Checks ensureOpen() before invoke this method */
     private ZipEntry getZipEntry(String name, int pos) {
         byte[] cen = zsrc.cen;
-        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
-        if (name != null) {
-            e.name = name;
-        } else {
-            if (!zc.isUTF8() && (e.flag & EFS) != 0) {
-                e.name = zc.toStringUTF8(cen, pos + CENHDR, nlen);
+        int flag = CENFLG(cen, pos);
+        if (name == null) {
+            if (!zc.isUTF8() && (flag & EFS) != 0) {
+                name = zc.toStringUTF8(cen, pos + CENHDR, nlen);
             } else {
-                e.name = zc.toString(cen, pos + CENHDR, nlen);
+                name = zc.toString(cen, pos + CENHDR, nlen);
             }
         }
+        ZipEntry e = new ZipEntry(name);
+        e.flag = flag;
         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);
+            int start = pos + CENHDR + nlen;
+            e.setExtra0(Arrays.copyOfRange(cen, start, start + elen), true);
         }
         if (clen != 0) {
-            if (!zc.isUTF8() && (e.flag & EFS) != 0) {
-                e.comment = zc.toStringUTF8(cen, pos + CENHDR + nlen + elen, clen);
+            int start = pos + CENHDR + nlen + elen;
+            if (!zc.isUTF8() && (flag & EFS) != 0) {
+                e.comment = zc.toStringUTF8(cen, start, clen);
             } else {
-                e.comment = zc.toString(cen, pos + CENHDR + nlen + elen, clen);
+                e.comment = zc.toString(cen, start, clen);
             }
         }
         return e;
@@ -817,7 +818,7 @@
         );
     }
 
-    /*
+    /**
      * 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
@@ -827,14 +828,14 @@
     private String[] getMetaInfEntryNames() {
         synchronized (this) {
             ensureOpen();
-            if (zsrc.metanames.size() == 0) {
+            if (zsrc.metanames == null) {
                 return null;
             }
-            String[] names = new String[zsrc.metanames.size()];
+            String[] names = new String[zsrc.metanames.length];
             byte[] cen = zsrc.cen;
             for (int i = 0; i < names.length; i++) {
-                int pos = zsrc.metanames.get(i);
-                names[i] = new String(cen, pos + CENHDR,  CENNAM(cen, pos),
+                int pos = zsrc.metanames[i];
+                names[i] = new String(cen, pos + CENHDR, CENNAM(cen, pos),
                                       StandardCharsets.UTF_8);
             }
             return names;
@@ -850,7 +851,7 @@
         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 int[] metanames;
         private final boolean startsWithLoc; // true, if zip file starts with LOCSIG (usually true)
 
         // A Hashmap for all entries.
@@ -1159,7 +1160,7 @@
             int next = -1;
 
             // list for all meta entries
-            metanames = new ArrayList<>();
+            ArrayList<Integer> metanamesList = null;
 
             // Iterate through the entries in the central directory
             int i = 0;
@@ -1194,13 +1195,21 @@
                 idx = addEntry(idx, hash, next, pos);
                 // Adds name to metanames.
                 if (isMetaName(cen, pos + CENHDR, nlen)) {
-                    metanames.add(pos);
+                    if (metanamesList == null)
+                        metanamesList = new ArrayList<>(4);
+                    metanamesList.add(pos);
                 }
                 // skip ext and comment
                 pos += (CENHDR + nlen + elen + clen);
                 i++;
             }
             total = i;
+            if (metanamesList != null) {
+                metanames = new int[metanamesList.size()];
+                for (int j = 0, len = metanames.length; j < len; j++) {
+                    metanames[j] = metanamesList.get(j);
+                }
+            }
             if (pos + ENDHDR != cen.length) {
                 zerror("invalid CEN header (bad header size)");
             }
@@ -1265,30 +1274,23 @@
             }
         }
 
-        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.
+        /**
+         * Returns true if the bytes represent a non-directory name
+         * beginning with "META-INF/", disregarding ASCII 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;
+        private static boolean isMetaName(byte[] name, int off, int len) {
+            // Use the "oldest ASCII trick in the book"
+            return len > 9                     // "META-INF/".length()
+                && name[off + len - 1] != '/'  // non-directory
+                && (name[off++] | 0x20) == 'm'
+                && (name[off++] | 0x20) == 'e'
+                && (name[off++] | 0x20) == 't'
+                && (name[off++] | 0x20) == 'a'
+                && (name[off++]       ) == '-'
+                && (name[off++] | 0x20) == 'i'
+                && (name[off++] | 0x20) == 'n'
+                && (name[off++] | 0x20) == 'f'
+                && (name[off]         ) == '/';
         }
 
         /*
--- a/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java	Tue May 17 19:20:05 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java	Mon May 16 11:42:31 2016 -0700
@@ -145,11 +145,10 @@
      */
     public static boolean isBlockOrSF(String s) {
         // we currently only support DSA and RSA PKCS7 blocks
-        if (s.endsWith(".SF") || s.endsWith(".DSA") ||
-                s.endsWith(".RSA") || s.endsWith(".EC")) {
-            return true;
-        }
-        return false;
+        return s.endsWith(".SF")
+            || s.endsWith(".DSA")
+            || s.endsWith(".RSA")
+            || s.endsWith(".EC");
     }
 
     /**