Author: bodewig Date: Fri Jul 29 16:40:35 2011 New Revision: 1152298 URL: http://svn.apache.org/viewvc?rev=1152298&view=rev Log: add a test that verifies ZipArchiveOutputStream now creates a ZIP64 extension extra field if the offset of a LFH exceeds 4GB. 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/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=1152298&r1=1152297&r2=1152298&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 Fri Jul 29 16:40:35 2011 @@ -778,16 +778,6 @@ public class ZipArchiveOutputStream exte writeOut(CFH_SIG); written += WORD; - // version made by - // CheckStyle:MagicNumber OFF - writeOut(ZipShort.getBytes((ze.getPlatform() << 8) | - (!hasUsedZip64 ? DEFLATE_MIN_VERSION - : ZIP64_MIN_VERSION))); - written += SHORT; - - final int zipMethod = ze.getMethod(); - final boolean encodable = zipEncoding.canEncode(ze.getName()); - final long lfhOffset = offsets.get(ze).longValue(); final boolean needsZip64Extra = ze.getCompressedSize() >= ZIP64_MAGIC || ze.getSize() >= ZIP64_MAGIC @@ -815,6 +805,15 @@ public class ZipArchiveOutputStream exte ze.setExtra(); } + // version made by + // CheckStyle:MagicNumber OFF + writeOut(ZipShort.getBytes((ze.getPlatform() << 8) | + (!hasUsedZip64 ? DEFLATE_MIN_VERSION + : ZIP64_MIN_VERSION))); + written += SHORT; + + final int zipMethod = ze.getMethod(); + final boolean encodable = zipEncoding.canEncode(ze.getName()); writeVersionNeededToExtractAndGeneralPurposeBits(zipMethod, !encodable && fallbackToUTF8, 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=1152298&r1=1152297&r2=1152298&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 Fri Jul 29 16:40:35 2011 @@ -196,6 +196,119 @@ public class Zip64SupportTest { }); } + /* + * Individual sizes don't require ZIP64 but the offset of the + * third entry is bigger than 0xFFFFFFFF so a ZIP64 extended + * information is needed inside the central directory. + * + * Creates a temporary archive of approx 5GB in size + */ + @Test public void write3EntriesCreatingBigArchive() throws Throwable { + withTemporaryArchive("write3EntriesCreatingBigArchive", + new ZipOutputTest() { + public void test(File f, ZipArchiveOutputStream zos) + throws IOException { + byte[] buf = new byte[1000 * 1000]; + ZipArchiveEntry zae = null; + for (int i = 0; i < 2; i++) { + zae = new ZipArchiveEntry(String.valueOf(i)); + zae.setSize(FIVE_BILLION / 2); + zae.setMethod(ZipArchiveEntry.STORED); + zae.setCrc(0); + zos.putArchiveEntry(zae); + for (int j = 0; j < FIVE_BILLION / 2 / 1000 / 1000; + j++) { + zos.write(buf); + } + zos.closeArchiveEntry(); + } + zae = new ZipArchiveEntry(String.valueOf(2)); + zae.setSize(0); + zos.putArchiveEntry(zae); + zos.closeArchiveEntry(); + zos.close(); + + RandomAccessFile a = new RandomAccessFile(f, "r"); + try { + final long end = a.length(); + long cdOffsetLoc = end - 22 /* eocd.length */ + - 20 /* z64 eocd locator.length */ + - 56 /* z64 eocd without extensible data sector */ + + 48 /* position in z64 eocd */; + // seek to central directory + a.seek(cdOffsetLoc); + byte[] cdOffset = new byte[8]; + a.readFully(cdOffset); + a.seek(ZipEightByteInteger.getLongValue(cdOffset)); + // skip first two entries + a.skipBytes(2 * 47 /* CD entry of file with + file name length 1 and no + extra data */); + + // grab third entry, verify offset is + // 0xFFFFFFFF and it has a ZIP64 extended + // information extra field + byte[] header = new byte[8]; + a.readFully(header); + assertArrayEquals(new byte[] { + // sig + (byte) 0x50, (byte) 0x4b, 1, 2, + // version made by + 45, 0, + // version needed to extract + 45, 0, + }, header); + // ignore GPB, method, timestamp, CRC, compressed size + a.skipBytes(16); + byte[] rest = new byte[23]; + a.readFully(rest); + assertArrayEquals(new byte[] { + // Original Size + 0, 0, 0, 0, + // file name length + 1, 0, + // extra field length + 12, 0, + // comment length + 0, 0, + // disk number + 0, 0, + // attributes + 0, 0, + 0, 0, 0, 0, + // offset + (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF, + // file name + (byte) '2' + }, rest); + byte[] extra = new byte[4]; + a.readFully(extra); + assertArrayEquals(new byte[] { + // Header-ID + 1, 0, + // size + 8, 0 + }, extra); + + // read offset of LFH + byte[] offset = new byte[8]; + a.readFully(offset); + // verify there is a LFH where the CD claims it + a.seek(ZipEightByteInteger.getLongValue(offset)); + byte[] sig = new byte[4]; + a.readFully(sig); + assertArrayEquals(new byte[] { + (byte) 0x50, (byte) 0x4b, 3, 4, + }, sig); + } finally { + a.close(); + } + } + + }); + } + static interface ZipOutputTest { void test(File f, ZipArchiveOutputStream zos) throws IOException; } @@ -215,6 +328,7 @@ public class Zip64SupportTest { } finally { zos.close(); } + f.delete(); } private static File getFile(String name) throws Throwable {