commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bode...@apache.org
Subject svn commit: r1152630 - in /commons/proper/compress/branches/zip64/src: main/java/org/apache/commons/compress/archivers/zip/ test/java/org/apache/commons/compress/archivers/zip/
Date Sun, 31 Jul 2011 20:30:33 GMT
Author: bodewig
Date: Sun Jul 31 20:30:32 2011
New Revision: 1152630

URL: http://svn.apache.org/viewvc?rev=1152630&view=rev
Log:
ensure ZIP64 features are kept to a minimum for entries that don't need them.  COMPRESS-150

Modified:
    commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
    commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/ZipConstants.java
    commons/proper/compress/branches/zip64/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportTest.java

Modified: commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java?rev=1152630&r1=1152629&r2=1152630&view=diff
==============================================================================
--- commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
(original)
+++ commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java
Sun Jul 31 20:30:32 2011
@@ -35,8 +35,9 @@ import org.apache.commons.compress.archi
 import org.apache.commons.compress.archivers.ArchiveOutputStream;
 
 import static org.apache.commons.compress.archivers.zip.ZipConstants.BYTE_MASK;
-import static org.apache.commons.compress.archivers.zip.ZipConstants.DEFLATE_MIN_VERSION;
+import static org.apache.commons.compress.archivers.zip.ZipConstants.DATA_DESCRIPTOR_MIN_VERSION;
 import static org.apache.commons.compress.archivers.zip.ZipConstants.DWORD;
+import static org.apache.commons.compress.archivers.zip.ZipConstants.INITIAL_VERSION;
 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;
@@ -254,6 +255,13 @@ public class ZipArchiveOutputStream exte
     private boolean hasUsedZip64 = false;
 
     /**
+     * Whether current entry was the first one using ZIP64 features.
+     *
+     * @since Apache Commons Compress 1.3
+     */
+    private boolean entryCausedUseOfZip64 = false;
+
+    /**
      * Creates a new ZIP OutputStream filtering the underlying stream.
      * @param out the outputstream to zip
      */
@@ -441,12 +449,12 @@ public class ZipArchiveOutputStream exte
         // the correct CRC and compressed/uncompressed sizes
         if (raf != null) {
             long save = raf.getFilePointer();
+            boolean actuallyNeedsZip64 = entry.getSize() >= ZIP64_MAGIC
+                || entry.getCompressedSize() >= ZIP64_MAGIC;
 
             raf.seek(localDataStart);
             writeOut(ZipLong.getBytes(entry.getCrc()));
-            if (!hasZip64Extra(entry)
-                || (entry.getSize() < ZIP64_MAGIC
-                    && entry.getCompressedSize() < ZIP64_MAGIC)) {
+            if (!hasZip64Extra(entry) || !actuallyNeedsZip64) {
                 writeOut(ZipLong.getBytes(entry.getCompressedSize()));
                 writeOut(ZipLong.getBytes(entry.getSize()));
             } else {
@@ -462,6 +470,23 @@ public class ZipArchiveOutputStream exte
                 // first, unlike the LFH, CD or data descriptor
                 writeOut(ZipEightByteInteger.getBytes(entry.getSize()));
                 writeOut(ZipEightByteInteger.getBytes(entry.getCompressedSize()));
+
+                if (!actuallyNeedsZip64) {
+                    // do some cleanup:
+                    // * rewrite version needed to extract
+                    raf.seek(localDataStart  - 5 * SHORT);
+                    writeOut(ZipShort.getBytes(INITIAL_VERSION));
+
+                    // * remove ZIP64 extra so it doesn't get written
+                    //   to the central directory
+                    entry.removeExtraField(Zip64ExtendedInformationExtraField
+                                           .HEADER_ID);
+                    entry.setExtra();
+
+                    // * reset hasUsedZip64 if it has been set because
+                    //   of this entry
+                    hasUsedZip64 &= !entryCausedUseOfZip64;
+                }
             }
             raf.seek(save);
         }
@@ -469,6 +494,7 @@ public class ZipArchiveOutputStream exte
         writeDataDescriptor(entry);
         entry = null;
         bytesRead = 0;
+        entryCausedUseOfZip64 = false;
     }
 
     /**
@@ -856,7 +882,7 @@ public class ZipArchiveOutputStream exte
         // version made by
         // CheckStyle:MagicNumber OFF
         writeOut(ZipShort.getBytes((ze.getPlatform() << 8) | 
-                                   (!hasUsedZip64 ? DEFLATE_MIN_VERSION
+                                   (!hasUsedZip64 ? DATA_DESCRIPTOR_MIN_VERSION
                                                   : ZIP64_MIN_VERSION)));
         written += SHORT;
 
@@ -1076,13 +1102,13 @@ public class ZipArchiveOutputStream exte
         throws IOException {
 
         // CheckStyle:MagicNumber OFF
-        int versionNeededToExtract = 10;
+        int versionNeededToExtract = INITIAL_VERSION;
         GeneralPurposeBit b = new GeneralPurposeBit();
         b.useUTF8ForNames(useUTF8Flag || utfFallback);
         if (zipMethod == DEFLATED && raf == null) {
             // requires version 2 as we are going to store length info
             // in the data descriptor
-            versionNeededToExtract = DEFLATE_MIN_VERSION;
+            versionNeededToExtract = DATA_DESCRIPTOR_MIN_VERSION;
             b.useDataDescriptor(true);
         }
         if (zip64) {
@@ -1153,6 +1179,7 @@ public class ZipArchiveOutputStream exte
      */
     private Zip64ExtendedInformationExtraField
         getZip64Extra(ZipArchiveEntry ze) {
+        entryCausedUseOfZip64 = !hasUsedZip64;
         hasUsedZip64 = true;
         Zip64ExtendedInformationExtraField z64 =
             (Zip64ExtendedInformationExtraField)

Modified: commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/ZipConstants.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/ZipConstants.java?rev=1152630&r1=1152629&r2=1152630&view=diff
==============================================================================
--- commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/ZipConstants.java
(original)
+++ commons/proper/compress/branches/zip64/src/main/java/org/apache/commons/compress/archivers/zip/ZipConstants.java
Sun Jul 31 20:30:32 2011
@@ -37,8 +37,11 @@ final class ZipConstants {
     /** length of a ZipEightByteInteger in bytes */
     static final int DWORD = 8;
 
-    /** ZIP specification version that introduced DEFLATE method */
-    static final int DEFLATE_MIN_VERSION = 20;
+    /** Initial ZIP specification version */
+    static final int INITIAL_VERSION = 10;
+
+    /** ZIP specification version that introduced data descriptor method */
+    static final int DATA_DESCRIPTOR_MIN_VERSION = 20;
 
     /** ZIP specification version that introduced ZIP64 */
     static final int ZIP64_MIN_VERSION = 45;

Modified: commons/proper/compress/branches/zip64/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportTest.java
URL: http://svn.apache.org/viewvc/commons/proper/compress/branches/zip64/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportTest.java?rev=1152630&r1=1152629&r2=1152630&view=diff
==============================================================================
--- commons/proper/compress/branches/zip64/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportTest.java
(original)
+++ commons/proper/compress/branches/zip64/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportTest.java
Sun Jul 31 20:30:32 2011
@@ -39,6 +39,7 @@ import static org.junit.Assume.assumeTru
 public class Zip64SupportTest {
 
     private static final long FIVE_BILLION = 5000000000l;
+    private static final int ONE_MILLION = 1000000;
     private static final int ONE_HUNDRED_THOUSAND = 100000;
 
     @Test public void read5GBOfZerosUsingInputStream() throws Throwable {
@@ -188,7 +189,7 @@ public class Zip64SupportTest {
         new ZipOutputTest() {
             public void test(File f, ZipArchiveOutputStream zos)
                 throws IOException {
-                byte[] buf = new byte[1000 * 1000];
+                byte[] buf = new byte[ONE_MILLION];
                 ZipArchiveEntry zae = null;
                 for (int i = 0; i < 2; i++) {
                     zae = new ZipArchiveEntry(String.valueOf(i));
@@ -312,7 +313,7 @@ public class Zip64SupportTest {
         return new ZipOutputTest() {
             public void test(File f, ZipArchiveOutputStream zos)
                 throws IOException {
-                byte[] buf = new byte[1000 * 1000];
+                byte[] buf = new byte[ONE_MILLION];
                 ZipArchiveEntry zae = new ZipArchiveEntry("0");
                 if (knownSize) {
                     zae.setSize(FIVE_BILLION);
@@ -461,6 +462,7 @@ public class Zip64SupportTest {
                              true);
     }
 
+    @Ignore
     @Test public void writeBigStoredEntryUnnownSizeToFile() throws Throwable {
         withTemporaryArchive("writeBigStoredEntryUnknownSizeToFile",
                              writeBigStoredEntry(false),
@@ -484,7 +486,7 @@ public class Zip64SupportTest {
                                  public void test(File f,
                                                   ZipArchiveOutputStream zos)
                                      throws IOException {
-                                     byte[] buf = new byte[1000 * 1000];
+                                     byte[] buf = new byte[ONE_MILLION];
                                      ZipArchiveEntry zae =
                                          new ZipArchiveEntry("0");
                                      zae.setSize(FIVE_BILLION);
@@ -655,7 +657,7 @@ public class Zip64SupportTest {
         return new ZipOutputTest() {
             public void test(File f, ZipArchiveOutputStream zos)
                 throws IOException {
-                byte[] buf = new byte[1000 * 1000];
+                byte[] buf = new byte[ONE_MILLION];
                 ZipArchiveEntry zae = new ZipArchiveEntry("0");
                 if (knownSize) {
                     zae.setSize(FIVE_BILLION);
@@ -799,6 +801,7 @@ public class Zip64SupportTest {
                              true);
     }
 
+    @Ignore
     @Test public void writeBigDeflatedEntryUnknownSizeToFile()
         throws Throwable {
         withTemporaryArchive("writeBigDeflatedEntryUnknownSizeToFile",
@@ -806,6 +809,452 @@ public class Zip64SupportTest {
                              true);
     }
 
+    /*
+     * One entry of length 1 million bytes, written without compression.
+     *
+     * No Compression => sizes are stored directly inside the LFH.  No
+     * Data Descriptor at all.  Shouldn't contain any ZIP64 extra
+     * field if size was known.
+     *
+     * Creates a temporary archive of approx 1MB in size
+     */
+    private static ZipOutputTest writeSmallStoredEntry(final boolean knownSize) {
+        return new ZipOutputTest() {
+            public void test(File f, ZipArchiveOutputStream zos)
+                throws IOException {
+                byte[] buf = new byte[ONE_MILLION];
+                ZipArchiveEntry zae = new ZipArchiveEntry("0");
+                if (knownSize) {
+                    zae.setSize(ONE_MILLION);
+                    zae.setCrc(0x1279CB9EL);
+                }
+                zae.setMethod(ZipArchiveEntry.STORED);
+                zos.putArchiveEntry(zae);
+                zos.write(buf);
+                zos.closeArchiveEntry();
+                zos.close();
+
+                RandomAccessFile a = new RandomAccessFile(f, "r");
+                try {
+                    final long end = getLengthAndPositionAtCentralDirectory(a);
+
+                    // grab first CF entry, verify sizes are 1e6 and it
+                    // has no ZIP64 extended information extra field
+                    // at all
+                    byte[] header = new byte[12];
+                    a.readFully(header);
+                    assertArrayEquals(new byte[] {
+                            // sig
+                            (byte) 0x50, (byte) 0x4b, 1, 2,
+                            // version made by
+                            20, 0,
+                            // version needed to extract
+                            10, 0,
+                            // GPB (EFS bit)
+                            0, 8,
+                            // method
+                            0, 0
+                        }, header);
+                    // ignore timestamp
+                    a.skipBytes(4);
+                    byte[] rest = new byte[31];
+                    a.readFully(rest);
+                    // 1e6 == 0xF4240
+                    assertArrayEquals(new byte[] {
+                            // CRC
+                            (byte) 0x9E, (byte) 0xCB, (byte) 0x79, (byte) 0x12,
+                            // Compressed Size
+                            (byte) 0x40, (byte) 0x42, (byte) 0x0F, 0,
+                            // Original Size
+                            (byte) 0x40, (byte) 0x42, (byte) 0x0F, 0,
+                            // file name length
+                            1, 0,
+                            // extra field length
+                            0, 0,
+                            // comment length
+                            0, 0,
+                            // disk number
+                            0, 0,
+                            // attributes
+                            0, 0,
+                            0, 0, 0, 0,
+                            // offset
+                            0, 0, 0, 0,
+                            // file name
+                            (byte) '0'
+                        }, rest);
+
+                    // and now validate local file header: this one
+                    // has a ZIP64 extra field if and only if size was
+                    // unknown
+                    a.seek(0);
+                    header = new byte[10];
+                    a.readFully(header);
+                    assertArrayEquals(new byte[] {
+                            // sig
+                            (byte) 0x50, (byte) 0x4b, 3, 4,
+                            // version needed to extract
+                            10, 0,
+                            // GPB (EFS bit)
+                            0, 8,
+                            // method
+                            0, 0
+                        }, header);
+                    // ignore timestamp
+                    a.skipBytes(4);
+                    rest = new byte[17];
+                    a.readFully(rest);
+                    // 1e6 == 0xF4240
+                    assertArrayEquals(new byte[] {
+                            // CRC
+                            (byte) 0x9E, (byte) 0xCB, (byte) 0x79, (byte) 0x12,
+                            // Compressed Size
+                            (byte) 0x40, (byte) 0x42, (byte) 0x0F, 0,
+                            // Original Size
+                            (byte) 0x40, (byte) 0x42, (byte) 0x0F, 0,
+                            // file name length
+                            1, 0,
+                            // extra field length
+                            (byte) (knownSize ? 0 : 20), 0,
+                            // file name
+                            (byte) '0'
+                        }, rest);
+                    if (!knownSize) {
+                        byte[] extra = new byte[20];
+                        a.readFully(extra);
+                        assertArrayEquals(new byte[] {
+                                // Header-ID
+                                1, 0,
+                                // size of extra
+                                16, 0,
+                                // original size
+                                (byte) 0x40, (byte) 0x42, (byte) 0x0F, 0,
+                                0, 0, 0, 0,
+                                // compressed size
+                                (byte) 0x40, (byte) 0x42, (byte) 0x0F, 0,
+                                0, 0, 0, 0,
+                            }, extra);
+                    }
+                } finally {
+                    a.close();
+                }
+            }
+        };
+    }
+
+    @Test public void writeSmallStoredEntryToStream() throws Throwable {
+        withTemporaryArchive("writeSmallStoredEntryToStream",
+                             writeSmallStoredEntry(true),
+                             false);
+    }
+
+    @Test public void writeSmallStoredEntryKnownSizeToFile() throws Throwable {
+        withTemporaryArchive("writeSmallStoredEntryKnownSizeToFile",
+                             writeSmallStoredEntry(true),
+                             true);
+    }
+
+    @Test public void writeSmallStoredEntryUnnownSizeToFile() throws Throwable {
+        withTemporaryArchive("writeSmallStoredEntryUnknownSizeToFile",
+                             writeSmallStoredEntry(false),
+                             true);
+    }
+
+    /*
+     * One entry of length 1 million bytes, written with compression
+     * to a stream.
+     *
+     * Compression + Stream => sizes are set to 0 in LFH, real values
+     * are inside the data descriptor.  No ZIP64 extra field at all.
+     */
+    @Test public void writeSmallDeflatedEntryKnownSizeToStream()
+        throws Throwable {
+        withTemporaryArchive("writeSmallDeflatedEntryKnownSizeToStream",
+                             new ZipOutputTest() {
+                                 public void test(File f,
+                                                  ZipArchiveOutputStream zos)
+                                     throws IOException {
+                                     byte[] buf = new byte[ONE_MILLION];
+                                     ZipArchiveEntry zae =
+                                         new ZipArchiveEntry("0");
+                                     zae.setSize(ONE_MILLION);
+                                     zae.setMethod(ZipArchiveEntry.DEFLATED);
+                                     zos.putArchiveEntry(zae);
+                                     zos.write(buf);
+                                     zos.closeArchiveEntry();
+                                     zos.close();
+
+                                     RandomAccessFile a =
+                                         new RandomAccessFile(f, "r");
+                                     try {
+                                         final long end =
+                                             getLengthAndPositionAtCentralDirectory(a);
+
+                                         long cfhPos = a.getFilePointer();
+                                         // grab first entry, verify
+                                         // sizes are not 0xFFFFFFF
+                                         // and it has no ZIP64
+                                         // extended information extra
+                                         // field
+                                         byte[] header = new byte[12];
+                                         a.readFully(header);
+                                         assertArrayEquals(new byte[] {
+                                                 // sig
+                                                 (byte) 0x50, (byte) 0x4b, 1, 2,
+                                                 // version made by
+                                                 20, 0,
+                                                 // version needed to extract
+                                                 20, 0,
+                                                 // GPB (EFS + Data Descriptor)
+                                                 8, 8,
+                                                 // method
+                                                 8, 0,
+                                             }, header);
+                                         // ignore timestamp
+                                         a.skipBytes(4);
+                                         byte[] crc = new byte[4];
+                                         a.readFully(crc);
+                                         assertArrayEquals(new byte[] {
+                                                 (byte) 0x9E, (byte) 0xCB,
+                                                 (byte) 0x79, (byte) 0x12,
+                                             }, crc);
+                                         // skip compressed size
+                                         a.skipBytes(4);
+                                         byte[] rest = new byte[23];
+                                         a.readFully(rest);
+                                         assertArrayEquals(new byte[] {
+                                                 // Original Size
+                                                 (byte) 0x40, (byte) 0x42,
+                                                 (byte) 0x0F, 0,
+                                                 // file name length
+                                                 1, 0,
+                                                 // extra field length
+                                                 0, 0,
+                                                 // comment length
+                                                 0, 0,
+                                                 // disk number
+                                                 0, 0,
+                                                 // attributes
+                                                 0, 0,
+                                                 0, 0, 0, 0,
+                                                 // offset
+                                                 0, 0, 0, 0,
+                                                 // file name
+                                                 (byte) '0'
+                                             }, rest);
+
+                                         // validate data descriptor
+                                         a.seek(cfhPos - 16);
+                                         byte[] dd = new byte[8];
+                                         a.readFully(dd);
+                                         assertArrayEquals(new byte[] {
+                                                 // sig
+                                                 (byte) 0x50, (byte) 0x4b, 7, 8,
+                                                 // CRC
+                                                 (byte) 0x9E, (byte) 0xCB,
+                                                 (byte) 0x79, (byte) 0x12,
+                                             }, dd);
+                                         // skip uncompressed size
+                                         a.skipBytes(4);
+                                         dd = new byte[4];
+                                         a.readFully(dd);
+                                         assertArrayEquals(new byte[] {
+                                                 // original size
+                                                 (byte) 0x40, (byte) 0x42,
+                                                 (byte) 0x0F, 0,
+                                             }, dd);
+
+                                         // and now validate local file header
+                                         a.seek(0);
+                                         header = new byte[10];
+                                         a.readFully(header);
+                                         assertArrayEquals(new byte[] {
+                                                 // sig
+                                                 (byte) 0x50, (byte) 0x4b, 3, 4,
+                                                 // version needed to extract
+                                                 20, 0,
+                                                 // GPB (EFS + Data Descriptor)
+                                                 8, 8,
+                                                 // method
+                                                 8, 0,
+                                             }, header);
+                                         // ignore timestamp
+                                         a.skipBytes(4);
+                                         rest = new byte[17];
+                                         a.readFully(rest);
+                                         assertArrayEquals(new byte[] {
+                                                 // CRC
+                                                 0, 0, 0, 0,
+                                                 // Compressed Size
+                                                 0, 0, 0, 0,
+                                                 // Original Size
+                                                 0, 0, 0, 0,
+                                                 // file name length
+                                                 1, 0,
+                                                 // extra field length
+                                                 0, 0,
+                                                 // file name
+                                                 (byte) '0'
+                                             }, rest);
+                                     } finally {
+                                         a.close();
+                                     }
+                                 }
+                             },
+                             false);
+    }
+
+    /*
+     * One entry of length 1 million bytes, written with compression
+     * to a file.
+     *
+     * Writing to a file => sizes are stored directly inside the LFH.
+     * No Data Descriptor at all.  Shouldn't contain any ZIP64 extra
+     * field if size was known.
+     */
+    private static ZipOutputTest writeSmallDeflatedEntryToFile(final boolean knownSize) {
+        return new ZipOutputTest() {
+            public void test(File f, ZipArchiveOutputStream zos)
+                throws IOException {
+                byte[] buf = new byte[ONE_MILLION];
+                ZipArchiveEntry zae = new ZipArchiveEntry("0");
+                if (knownSize) {
+                    zae.setSize(ONE_MILLION);
+                }
+                zae.setMethod(ZipArchiveEntry.DEFLATED);
+                zos.putArchiveEntry(zae);
+                zos.write(buf);
+                zos.closeArchiveEntry();
+                zos.close();
+
+                RandomAccessFile a = new RandomAccessFile(f, "r");
+                try {
+                    final long end = getLengthAndPositionAtCentralDirectory(a);
+
+                    long cfhPos = a.getFilePointer();
+                    // grab first CD entry, verify sizes are not
+                    // 0xFFFFFFFF and it has a no ZIP64 extended
+                    // information extra field
+                    byte[] header = new byte[12];
+                    a.readFully(header);
+                    assertArrayEquals(new byte[] {
+                            // sig
+                            (byte) 0x50, (byte) 0x4b, 1, 2,
+                            // version made by
+                            20, 0,
+                            // version needed to extract
+                            10, 0,
+                            // GPB (EFS + *no* Data Descriptor)
+                            0, 8,
+                            // method
+                            8, 0,
+                        }, header);
+                    // ignore timestamp
+                    a.skipBytes(4);
+                    byte[] crc = new byte[4];
+                    a.readFully(crc);
+                    assertArrayEquals(new byte[] {
+                            (byte) 0x9E, (byte) 0xCB,
+                            (byte) 0x79, (byte) 0x12,
+                        }, crc);
+                    // skip compressed size
+                    a.skipBytes(4);
+                    byte[] rest = new byte[23];
+                    a.readFully(rest);
+                    assertArrayEquals(new byte[] {
+                            // Original Size
+                            (byte) 0x40, (byte) 0x42, (byte) 0x0F, 0,
+                            // file name length
+                            1, 0,
+                            // extra field length
+                            0, 0,
+                            // comment length
+                            0, 0,
+                            // disk number
+                            0, 0,
+                            // attributes
+                            0, 0,
+                            0, 0, 0, 0,
+                            // offset
+                            0, 0, 0, 0,
+                            // file name
+                            (byte) '0'
+                        }, rest);
+
+                    // and now validate local file header
+                    a.seek(0);
+                    header = new byte[10];
+                    a.readFully(header);
+                    assertArrayEquals(new byte[] {
+                            // sig
+                            (byte) 0x50, (byte) 0x4b, 3, 4,
+                            // version needed to extract
+                            10, 0,
+                            // GPB (EFS bit, no DD)
+                            0, 8,
+                            // method
+                            8, 0,
+                        }, header);
+                    // ignore timestamp
+                    a.skipBytes(4);
+                    crc = new byte[4];
+                    a.readFully(crc);
+                    assertArrayEquals(new byte[] {
+                            (byte) 0x9E, (byte) 0xCB,
+                            (byte) 0x79, (byte) 0x12,
+                        }, crc);
+                    // skip compressed size
+                    a.skipBytes(4);
+                    rest = new byte[9];
+                    a.readFully(rest);
+                    assertArrayEquals(new byte[] {
+                            // Original Size
+                            (byte) 0x40, (byte) 0x42, (byte) 0x0F, 0,
+                            // file name length
+                            1, 0,
+                            // extra field length
+                            (byte) (knownSize ? 0 : 20), 0,
+                            // file name
+                            (byte) '0'
+                        }, rest);
+                    if (!knownSize) {
+                        byte[] extra = new byte[12];
+                        a.readFully(extra);
+                        assertArrayEquals(new byte[] {
+                                // Header-ID
+                                1, 0,
+                                // size of extra
+                                16, 0,
+                                // original size
+                                (byte) 0x40, (byte) 0x42, (byte) 0x0F, 0,
+                                0, 0, 0, 0,
+                                // don't know the
+                                // compressed size,
+                                // don't want to
+                                // hard-code it
+                            }, extra);
+                    }
+                } finally {
+                    a.close();
+                }
+            }
+        };
+    }
+
+    @Test public void writeSmallDeflatedEntryKnownSizeToFile()
+        throws Throwable {
+        withTemporaryArchive("writeSmallDeflatedEntryKnownSizeToFile",
+                             writeSmallDeflatedEntryToFile(true),
+                             true);
+    }
+
+    @Test public void writeSmallDeflatedEntryUnknownSizeToFile()
+        throws Throwable {
+        withTemporaryArchive("writeSmallDeflatedEntryUnknownSizeToFile",
+                             writeSmallDeflatedEntryToFile(false),
+                             true);
+    }
+
     static interface ZipOutputTest {
         void test(File f, ZipArchiveOutputStream zos) throws IOException;
     }
@@ -897,6 +1346,15 @@ public class Zip64SupportTest {
     private static long getLengthAndPositionAtCentralDirectory(RandomAccessFile a)
         throws IOException {
         final long end = a.length();
+        a.seek(end - 22 - 20);
+        byte[] sig = new byte[4];
+        a.readFully(sig);
+        if (sig[0] != (byte) 0x50 || sig[1] != (byte) 0x4b
+            || sig[2] != 6 || sig[3] != 7) {
+            // not a ZIP64 archive
+            return getLengthAndPositionAtCentralDirectory32(a, end);
+        }
+
         long cdOffsetLoc = end - 22 - 20 - 56 + 48;
         // seek to central directory locator
         a.seek(cdOffsetLoc);
@@ -905,4 +1363,13 @@ public class Zip64SupportTest {
         a.seek(ZipEightByteInteger.getLongValue(cdOffset));
         return end;
     }
+
+    private static long getLengthAndPositionAtCentralDirectory32(RandomAccessFile a, final
long end)
+        throws IOException {
+        a.seek(end - 22 + 16);
+        byte[] cdOffset = new byte[4];
+        a.readFully(cdOffset);
+        a.seek(ZipLong.getValue(cdOffset));
+        return end;
+    }
 }



Mime
View raw message