Author: bodewig Date: Sat Aug 13 03:48:25 2011 New Revision: 1157312 URL: http://svn.apache.org/viewvc?rev=1157312&view=rev Log: It seems WinZip uses 'version needed to extract' from the central directory entry to parse the local file header ignoring the 'version' stored in the LFH. Make sure the two values agree, which they did not in 'Always' mode.
Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportIT.java Modified: commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java?rev=1157312&r1=1157311&r2=1157312&view=diff ============================================================================== --- commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java (original) +++ commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/ZipArchiveOutputStream.java Sat Aug 13 03:48:25 2011 @@ -384,7 +384,7 @@ public class ZipArchiveOutputStream exte * any entry has initially been unknown and create an archive * identical to {@link Zip64Mode#Never Never} otherwise. {@link * Zip64Mode#Always Always} will create an archive that is at - * least 20 bytes per entry bigger than the one {@link + * least 24 bytes per entry bigger than the one {@link * Zip64Mode#Never Never} would create.</p> * * <p>Defaults to {@link Zip64Mode#AsNeeded AsNeeded} unless @@ -1016,7 +1016,8 @@ public class ZipArchiveOutputStream exte written += WORD; final long lfhOffset = offsets.get(ze).longValue(); - final boolean needsZip64Extra = ze.getCompressedSize() >= ZIP64_MAGIC + final boolean needsZip64Extra = hasZip64Extra(ze) + || ze.getCompressedSize() >= ZIP64_MAGIC || ze.getSize() >= ZIP64_MAGIC || lfhOffset >= ZIP64_MAGIC; @@ -1121,8 +1122,7 @@ public class ZipArchiveOutputStream exte /** * If the entry needs Zip64 extra information inside the central - * director then configure its data, otherwise remove it if one is - * present. + * directory then configure its data. */ private void handleZip64Extra(ZipArchiveEntry ze, long lfhOffset, boolean needsZip64Extra) { @@ -1141,11 +1141,6 @@ public class ZipArchiveOutputStream exte z64.setRelativeHeaderOffset(new ZipEightByteInteger(lfhOffset)); } ze.setExtra(); - } else if (hasZip64Extra(ze)) { - // added to LFH but not really needed, probably because of - // Zip64Mode.Always - ze.removeExtraField(Zip64ExtendedInformationExtraField.HEADER_ID); - ze.setExtra(); } } Modified: commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportIT.java URL: http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportIT.java?rev=1157312&r1=1157311&r2=1157312&view=diff ============================================================================== --- commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportIT.java (original) +++ commons/proper/compress/trunk/src/test/java/org/apache/commons/compress/archivers/zip/Zip64SupportIT.java Sat Aug 13 03:48:25 2011 @@ -326,7 +326,10 @@ public class Zip64SupportIT { // skip first two entries a.skipBytes(2 * 47 /* CD entry of file with file name length 1 and no - extra data */); + extra data */ + + 2 * (mode == Zip64Mode.Always ? 4 : 0) + /* empty ZIP64 extra fields if mode is Always */ + ); // grab third entry, verify offset is // 0xFFFFFFFF and it has a ZIP64 extended @@ -1449,8 +1452,7 @@ public class Zip64SupportIT { final long end = getLengthAndPositionAtCentralDirectory(a); // grab first CF entry, verify sizes are 1e6 and it - // has no ZIP64 extended information extra field - // at all + // has an empty ZIP64 extended information extra field byte[] header = new byte[12]; a.readFully(header); assertArrayEquals(new byte[] { @@ -1459,7 +1461,7 @@ public class Zip64SupportIT { // version made by 45, 0, // version needed to extract - 10, 0, + 45, 0, // GPB (EFS bit) 0, 8, // method @@ -1480,7 +1482,7 @@ public class Zip64SupportIT { // file name length 1, 0, // extra field length - 0, 0, + 4, 0, // comment length 0, 0, // disk number @@ -1494,6 +1496,15 @@ public class Zip64SupportIT { (byte) '0' }, rest); + byte[] extra = new byte[4]; + a.readFully(extra); + assertArrayEquals(new byte[] { + // Header-ID + 1, 0, + // size of extra + 0, 0, + }, extra); + // and now validate local file header: this one // has a ZIP64 extra field as the mode was // Always @@ -1530,7 +1541,7 @@ public class Zip64SupportIT { (byte) '0' }, rest); - byte[] extra = new byte[20]; + extra = new byte[20]; a.readFully(extra); assertArrayEquals(new byte[] { // Header-ID @@ -1775,7 +1786,7 @@ public class Zip64SupportIT { long cfhPos = a.getFilePointer(); // grab first entry, verify sizes are not - // 0xFFFFFFF and it has no ZIP64 extended + // 0xFFFFFFF and it has an empty ZIP64 extended // information extra field byte[] header = new byte[12]; a.readFully(header); @@ -1785,7 +1796,7 @@ public class Zip64SupportIT { // version made by 45, 0, // version needed to extract - 20, 0, + 45, 0, // GPB (EFS + Data Descriptor) 8, 8, // method @@ -1810,7 +1821,7 @@ public class Zip64SupportIT { // file name length 1, 0, // extra field length - 0, 0, + 4, 0, // comment length 0, 0, // disk number @@ -1823,6 +1834,14 @@ public class Zip64SupportIT { // file name (byte) '0' }, rest); + byte[] extra = new byte[4]; + a.readFully(extra); + assertArrayEquals(new byte[] { + // Header-ID + 1, 0, + // size of extra + 0, 0, + }, extra); // validate data descriptor a.seek(cfhPos - 24); @@ -1877,7 +1896,7 @@ public class Zip64SupportIT { (byte) '0' }, rest); - byte[] extra = new byte[20]; + extra = new byte[20]; a.readFully(extra); assertArrayEquals(new byte[] { // Header-ID @@ -2124,7 +2143,7 @@ public class Zip64SupportIT { long cfhPos = a.getFilePointer(); // grab first CD entry, verify sizes are not - // 0xFFFFFFFF and it has a no ZIP64 extended + // 0xFFFFFFFF and it has a an empty ZIP64 extended // information extra field byte[] header = new byte[12]; a.readFully(header); @@ -2134,7 +2153,7 @@ public class Zip64SupportIT { // version made by 45, 0, // version needed to extract - 10, 0, + 45, 0, // GPB (EFS + *no* Data Descriptor) 0, 8, // method @@ -2157,7 +2176,7 @@ public class Zip64SupportIT { // file name length 1, 0, // extra field length - 0, 0, + 4, 0, // comment length 0, 0, // disk number @@ -2170,6 +2189,14 @@ public class Zip64SupportIT { // file name (byte) '0' }, rest); + byte[] extra = new byte[4]; + a.readFully(extra); + assertArrayEquals(new byte[] { + // Header-ID + 1, 0, + // size of extra + 0, 0, + }, extra); // and now validate local file header a.seek(0); @@ -2209,7 +2236,7 @@ public class Zip64SupportIT { (byte) '0' }, rest); - byte[] extra = new byte[12]; + extra = new byte[12]; a.readFully(extra); assertArrayEquals(new byte[] { // Header-ID