commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bode...@apache.org
Subject svn commit: r1153738 - in /commons/proper/compress/trunk/src: main/java/org/apache/commons/compress/archivers/zip/ZipFile.java test/java/org/apache/commons/compress/archivers/zip/Zip64SupportTest.java
Date Thu, 04 Aug 2011 03:33:55 GMT
Author: bodewig
Date: Thu Aug  4 03:33:54 2011
New Revision: 1153738

URL: http://svn.apache.org/viewvc?rev=1153738&view=rev
Log:
Use the ZIP64 structures to locate the central directory in ZipFile if the archive is a ZIP64
archive, fallback to 'the old way' if it is not a ZIP64 archive.  COMPRESS-149

Modified:
    commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
    commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportTest.java

Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java?rev=1153738&r1=1153737&r2=1153738&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
(original)
+++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipFile.java
Thu Aug  4 03:33:54 2011
@@ -32,6 +32,7 @@ import java.util.zip.Inflater;
 import java.util.zip.InflaterInputStream;
 import java.util.zip.ZipException;
 
+import static org.apache.commons.compress.archivers.zip.ZipConstants.DWORD;
 import static org.apache.commons.compress.archivers.zip.ZipConstants.SHORT;
 import static org.apache.commons.compress.archivers.zip.ZipConstants.WORD;
 import static org.apache.commons.compress.archivers.zip.ZipConstants.ZIP64_MAGIC;
@@ -354,6 +355,10 @@ public class ZipFile {
         }
     }
 
+    /**
+     * Length of a "central directory" entry structure without file
+     * name, extra fields or comment.
+     */
     private static final int CFH_LEN =
         /* version made by                 */ SHORT
         /* version needed to extract       */ + SHORT
@@ -485,6 +490,11 @@ public class ZipFile {
         return noUTF8Flag;
     }
 
+    /**
+     * Length of the "End of central directory record" - which is
+     * supposed to be the last structure of the archive - without file
+     * comment.
+     */
     private static final int MIN_EOCD_SIZE =
         /* end of central dir signature    */ WORD
         /* number of this disk             */ + SHORT
@@ -500,9 +510,19 @@ public class ZipFile {
         /* the starting disk number        */ + WORD
         /* zipfile comment length          */ + SHORT;
 
+    /**
+     * Maximum length of the "End of central directory record" with a
+     * file comment.
+     */
     private static final int MAX_EOCD_SIZE = MIN_EOCD_SIZE
         /* maximum length of zipfile comment */ + ZIP64_MAGIC_SHORT;
 
+    /**
+     * Offset of the field that holds the location of the first
+     * central directory entry inside the "End of central directory
+     * record" relative to the start of the "End of central directory
+     * record".
+     */
     private static final int CFD_LOCATOR_OFFSET =
         /* end of central dir signature    */ WORD
         /* number of this disk             */ + SHORT
@@ -515,12 +535,98 @@ public class ZipFile {
         /* size of the central directory   */ + WORD;
 
     /**
-     * Searches for the "End of central dir record", parses
+     * Length of the "Zip64 end of central directory locator" - which
+     * should be right in front of the "end of central directory
+     * record" if one is present at all.
+     */
+    private static final int ZIP64_EOCDL_LENGTH =
+        /* zip64 end of central dir locator sig */ WORD
+        /* number of the disk with the start    */
+        /* start of the zip64 end of            */
+        /* central directory                    */ + WORD
+        /* relative offset of the zip64         */
+        /* end of central directory record      */ + DWORD
+        /* total number of disks                */ + WORD;
+
+    /**
+     * Offset of the field that holds the location of the "Zip64 end
+     * of central directory record" inside the "Zip64 end of central
+     * directory locator" relative to the start of the "Zip64 end of
+     * central directory locator".
+     */
+    private static final int ZIP64_EOCDL_LOCATOR_OFFSET =
+        /* zip64 end of central dir locator sig */ WORD
+        /* number of the disk with the start    */
+        /* start of the zip64 end of            */
+        /* central directory                    */ + WORD;
+
+    /**
+     * Offset of the field that holds the location of the first
+     * central directory entry inside the "Zip64 end of central
+     * directory record" relative to the start of the "Zip64 end of
+     * central directory record".
+     */
+    private static final int ZIP64_EOCD_CFD_LOCATOR_OFFSET =
+        /* zip64 end of central dir        */
+        /* signature                       */ WORD
+        /* size of zip64 end of central    */
+        /* directory record                */ + DWORD
+        /* version made by                 */ + SHORT
+        /* version needed to extract       */ + SHORT
+        /* number of this disk             */ + WORD
+        /* number of the disk with the     */
+        /* start of the central directory  */ + WORD
+        /* total number of entries in the  */
+        /* central directory on this disk  */ + DWORD
+        /* total number of entries in the  */
+        /* central directory               */ + DWORD
+        /* size of the central directory   */ + DWORD;
+
+    /**
+     * Searches for either the "Zip64 end of central directory
+     * locator" or the "End of central dir record", parses
      * it and positions the stream at the first central directory
      * record.
      */
     private void positionAtCentralDirectory()
         throws IOException {
+        boolean found = tryToLocateSignature(MIN_EOCD_SIZE + ZIP64_EOCDL_LENGTH,
+                                             MAX_EOCD_SIZE + ZIP64_EOCDL_LENGTH,
+                                             ZipArchiveOutputStream
+                                             .ZIP64_EOCD_LOC_SIG);
+        if (!found) {
+            // not a ZIP64 archive
+            positionAtCentralDirectory32();
+        } else {
+            archive.skipBytes(ZIP64_EOCDL_LOCATOR_OFFSET);
+            byte[] zip64EocdOffset = new byte[DWORD];
+            archive.readFully(zip64EocdOffset);
+            archive.seek(ZipEightByteInteger.getLongValue(zip64EocdOffset));
+            byte[] sig = new byte[WORD];
+            archive.readFully(sig);
+            if (sig[POS_0] != ZipArchiveOutputStream.ZIP64_EOCD_SIG[POS_0]
+                || sig[POS_1] != ZipArchiveOutputStream.ZIP64_EOCD_SIG[POS_1]
+                || sig[POS_2] != ZipArchiveOutputStream.ZIP64_EOCD_SIG[POS_2]
+                || sig[POS_3] != ZipArchiveOutputStream.ZIP64_EOCD_SIG[POS_3]
+                ) {
+                throw new ZipException("archive's ZIP64 end of central "
+                                       + "directory locator is corrupt.");
+            }
+            archive.skipBytes(ZIP64_EOCD_CFD_LOCATOR_OFFSET
+                              - WORD /* signature has already been read */);
+            byte[] cfdOffset = new byte[DWORD];
+            archive.readFully(cfdOffset);
+            archive.seek(ZipEightByteInteger.getLongValue(cfdOffset));
+        }
+    }
+
+    /**
+     * Searches for the "End of central dir record", parses
+     * it and positions the stream at the first central directory
+     * record.
+     */
+    private void positionAtCentralDirectory32()
+        throws IOException {
         boolean found = tryToLocateSignature(MIN_EOCD_SIZE, MAX_EOCD_SIZE,
                                              ZipArchiveOutputStream.EOCD_SIG);
         if (!found) {

Modified: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportTest.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportTest.java?rev=1153738&r1=1153737&r2=1153738&view=diff
==============================================================================
--- commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportTest.java
(original)
+++ commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportTest.java
Thu Aug  4 03:33:54 2011
@@ -26,6 +26,7 @@ import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.net.URI;
 import java.net.URL;
+import java.util.Enumeration;
 import java.util.Random;
 
 import org.junit.Ignore;
@@ -72,18 +73,27 @@ public class Zip64SupportTest {
         read100KFilesImpl(get100KFileFileGeneratedByJava7Jar());
     }
 
+    @Test public void read100KFilesUsingZipFile() throws Throwable {
+        read100KFilesUsingZipFileImpl(get100KFileFile());
+    }
+
+    @Test public void read100KFilesGeneratedBy7ZIPUsingZipFile() throws Throwable {
+        read100KFilesUsingZipFileImpl(get100KFileFileGeneratedBy7ZIP());
+    }
+
+    @Test public void read100KFilesGeneratedByWinCFUsingZipFile() throws Throwable {
+        read100KFilesUsingZipFileImpl(get100KFileFileGeneratedByWinCF());
+    }
+
+    @Test public void read100KFilesGeneratedByJava7JarUsingZipFile() throws Throwable {
+        read100KFilesUsingZipFileImpl(get100KFileFileGeneratedByJava7Jar());
+    }
+
     private static final ZipOutputTest write100KFiles =
         new ZipOutputTest() {
             public void test(File f, ZipArchiveOutputStream zos)
                 throws IOException {
-                for (int i = 0; i < ONE_HUNDRED_THOUSAND; i++) {
-                    ZipArchiveEntry zae =
-                        new ZipArchiveEntry(String.valueOf(i));
-                    zae.setSize(0);
-                    zos.putArchiveEntry(zae);
-                    zos.closeArchiveEntry();
-                }
-                zos.close();
+                write100KFilesToStream(zos);
                 RandomAccessFile a = new RandomAccessFile(f, "r");
                 try {
                     final long end = a.length();
@@ -182,6 +192,20 @@ public class Zip64SupportTest {
         withTemporaryArchive("write100KFilesStream", write100KFiles, false);
     }
 
+    @Test public void readSelfGenerated100KFilesUsingZipFile()
+        throws Throwable {
+        withTemporaryArchive("readSelfGenerated100KFilesUsingZipFile()",
+                             new ZipOutputTest() {
+                                 public void test(File f,
+                                                  ZipArchiveOutputStream zos)
+                                     throws IOException {
+                                     write100KFilesToStream(zos);
+                                     read100KFilesUsingZipFileImpl(f);
+                                 }
+                             },
+                             true);
+    }
+
     /*
      * Individual sizes don't require ZIP64 but the offset of the
      * third entry is bigger than 0xFFFFFFFF so a ZIP64 extended
@@ -1390,6 +1414,25 @@ public class Zip64SupportTest {
         }
     }
 
+    private static void read100KFilesUsingZipFileImpl(File f)
+        throws IOException {
+        ZipFile zf = null;
+        try {
+            zf = new ZipFile(f);
+            int files = 0;
+            for (Enumeration e = zf.getEntries(); e.hasMoreElements(); ) {
+                ZipArchiveEntry zae = (ZipArchiveEntry) e.nextElement();
+                if (!zae.isDirectory()) {
+                    files++;
+                    assertEquals(0, zae.getSize());
+                }
+            }
+            assertEquals(ONE_HUNDRED_THOUSAND, files);
+        } finally {
+            ZipFile.closeQuietly(zf);
+        }
+    }
+
     private static long getLengthAndPositionAtCentralDirectory(RandomAccessFile a)
         throws IOException {
         final long end = a.length();
@@ -1419,4 +1462,15 @@ public class Zip64SupportTest {
         a.seek(ZipLong.getValue(cdOffset));
         return end;
     }
+
+    private static void write100KFilesToStream(ZipArchiveOutputStream zos)
+        throws IOException {
+        for (int i = 0; i < ONE_HUNDRED_THOUSAND; i++) {
+            ZipArchiveEntry zae = new ZipArchiveEntry(String.valueOf(i));
+            zae.setSize(0);
+            zos.putArchiveEntry(zae);
+            zos.closeArchiveEntry();
+        }
+        zos.close();
+    }
 }



Mime
View raw message