Author: bodewig
Date: Tue Aug 9 09:08:00 2011
New Revision: 1155274
URL: http://svn.apache.org/viewvc?rev=1155274&view=rev
Log:
Implement Zip64Mode.Never. COMPRESS-36 and COMPRESS-150
Modified:
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/Zip64RequiredException.java
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/Zip64SupportTest.java
Modified:
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/Zip64RequiredException.java
URL:
http://svn.apache.org/viewvc/commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/Zip64RequiredException.java?rev=1155274&r1=1155273&r2=1155274&view=diff
==============================================================================
---
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/Zip64RequiredException.java
(original)
+++
commons/proper/compress/trunk/src/main/java/org/apache/commons/compress/archivers/zip/Zip64RequiredException.java
Tue Aug 9 09:08:00 2011
@@ -30,6 +30,19 @@ public class Zip64RequiredException exte
private static final long serialVersionUID = 20110809L;
+ /**
+ * Helper to format "entry too big" messages.
+ */
+ static String getEntryTooBigMessage(ZipArchiveEntry ze) {
+ return ze.getName() + "'s size exceeds the limit of 4GByte.";
+ }
+
+ static final String ARCHIVE_TOO_BIG_MESSAGE =
+ "archive's size exceeds the limit of 4GByte.";
+
+ static final String TOO_MANY_ENTRIES_MESSAGE =
+ "archive contains more than 65535 entries.";
+
public Zip64RequiredException(String reason) {
super(reason);
}
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=1155274&r1=1155273&r2=1155274&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
Tue Aug 9 09:08:00 2011
@@ -390,7 +390,11 @@ public class ZipArchiveOutputStream exte
zip64Mode = mode;
}
- /** {@inheritDoc} */
+ /**
+ * {@inheritDoc}
+ * @throws Zip64RequiredException if the archive's size exceeds 4
+ * GByte or there are more than 65535 entries inside the archive
+ */
@Override
public void finish() throws IOException {
if (finished) {
@@ -417,6 +421,8 @@ public class ZipArchiveOutputStream exte
/**
* Writes all necessary data for this entry.
* @throws IOException on error
+ * @throws Zip64RequiredException if the entry's uncompressed or
+ * compressed size exceeds 4 GByte
*/
@Override
public void closeArchiveEntry() throws IOException {
@@ -475,12 +481,17 @@ public class ZipArchiveOutputStream exte
entry.entry.setCrc(realCrc);
}
+ boolean actuallyNeedsZip64 = entry.entry.getSize() >= ZIP64_MAGIC
+ || entry.entry.getCompressedSize() >= ZIP64_MAGIC;
+ if (actuallyNeedsZip64 && zip64Mode == Zip64Mode.Never) {
+ throw new Zip64RequiredException(Zip64RequiredException
+
.getEntryTooBigMessage(entry.entry));
+ }
+
// If random access output, write the local file header containing
// the correct CRC and compressed/uncompressed sizes
if (raf != null) {
long save = raf.getFilePointer();
- boolean actuallyNeedsZip64 = entry.entry.getSize() >= ZIP64_MAGIC
- || entry.entry.getCompressedSize() >= ZIP64_MAGIC;
raf.seek(entry.localDataStart);
writeOut(ZipLong.getBytes(entry.entry.getCrc()));
@@ -530,6 +541,8 @@ public class ZipArchiveOutputStream exte
/**
* {@inheritDoc}
* @throws ClassCastException if entry is not an instance of
ZipArchiveEntry
+ * @throws Zip64RequiredException if the entry's uncompressed or
+ * compressed size is known to exceed 4 GByte
*/
@Override
public void putArchiveEntry(ArchiveEntry archiveEntry) throws IOException {
@@ -566,6 +579,13 @@ public class ZipArchiveOutputStream exte
entry.entry.setCompressedSize(entry.entry.getSize());
}
+ if ((entry.entry.getSize() >= ZIP64_MAGIC
+ || entry.entry.getCompressedSize() >= ZIP64_MAGIC)
+ && zip64Mode == Zip64Mode.Never) {
+ throw new Zip64RequiredException(Zip64RequiredException
+
.getEntryTooBigMessage(entry.entry));
+ }
+
// add a ZIP64 extended information extra field if we already
// know it is going to be needed or the size is unknown and we
// can ensure it won't hurt other implementations if we add it
@@ -693,6 +713,8 @@ public class ZipArchiveOutputStream exte
* associated with the stream.
*
* @exception IOException if an I/O error occurs.
+ * @throws Zip64RequiredException if the archive's size exceeds 4
+ * GByte or there are more than 65535 entries inside the archive
*/
@Override
public void close() throws IOException {
@@ -893,6 +915,8 @@ public class ZipArchiveOutputStream exte
* Writes the central file header entry.
* @param ze the entry to write
* @throws IOException on error
+ * @throws Zip64RequiredException if the archive's size exceeds 4
+ * GByte
*/
protected void writeCentralFileHeader(ZipArchiveEntry ze) throws
IOException {
writeOut(CFH_SIG);
@@ -903,6 +927,14 @@ public class ZipArchiveOutputStream exte
|| ze.getSize() >= ZIP64_MAGIC
|| lfhOffset >= ZIP64_MAGIC;
+ if (needsZip64Extra && zip64Mode == Zip64Mode.Never) {
+ // must be the offset that is too big, otherwise an
+ // exception would have been throw in putArchiveEntry or
+ // closeArchiveEntry
+ throw new Zip64RequiredException(Zip64RequiredException
+ .ARCHIVE_TOO_BIG_MESSAGE);
+ }
+
if (needsZip64Extra) {
Zip64ExtendedInformationExtraField z64 = getZip64Extra(ze);
if (ze.getCompressedSize() >= ZIP64_MAGIC
@@ -1012,6 +1044,8 @@ public class ZipArchiveOutputStream exte
/**
* Writes the "End of central dir record".
* @throws IOException on error
+ * @throws Zip64RequiredException if the archive's size exceeds 4
+ * GByte or there are more than 65535 entries inside the archive
*/
protected void writeCentralDirectoryEnd() throws IOException {
writeOut(EOCD_SIG);
@@ -1021,7 +1055,18 @@ public class ZipArchiveOutputStream exte
writeOut(ZERO);
// number of entries
- byte[] num = ZipShort.getBytes(Math.min(entries.size(),
+ int numberOfEntries = entries.size();
+ if (numberOfEntries > ZIP64_MAGIC_SHORT
+ && zip64Mode == Zip64Mode.Never) {
+ throw new Zip64RequiredException(Zip64RequiredException
+ .TOO_MANY_ENTRIES_MESSAGE);
+ }
+ if (cdOffset > ZIP64_MAGIC && zip64Mode == Zip64Mode.Never) {
+ throw new Zip64RequiredException(Zip64RequiredException
+ .ARCHIVE_TOO_BIG_MESSAGE);
+ }
+
+ byte[] num = ZipShort.getBytes(Math.min(numberOfEntries,
ZIP64_MAGIC_SHORT));
writeOut(num);
writeOut(num);
@@ -1045,6 +1090,10 @@ public class ZipArchiveOutputStream exte
* @since Apache Commons Compress 1.3
*/
protected void writeZip64CentralDirectory() throws IOException {
+ if (zip64Mode == Zip64Mode.Never) {
+ return;
+ }
+
if (!hasUsedZip64) {
if (cdOffset >= ZIP64_MAGIC || cdLength >= ZIP64_MAGIC
|| entries.size() >= ZIP64_MAGIC_SHORT) {
@@ -1238,6 +1287,22 @@ public class ZipArchiveOutputStream exte
}
/**
+ * Closes the underlying stream/file without finishing the
+ * archive, the result will likely be a corrupt archive.
+ *
+ * <p>This method only exists to support tests that generate
+ * corrupt archives so they can clean up any temporary files.</p>
+ */
+ void destroy() throws IOException {
+ if (raf != null) {
+ raf.close();
+ }
+ if (out != null) {
+ out.close();
+ }
+ }
+
+ /**
* enum that represents the possible policies for creating Unicode
* extra fields.
*/
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=1155274&r1=1155273&r2=1155274&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
Tue Aug 9 09:08:00 2011
@@ -38,6 +38,7 @@ import static org.junit.Assert.assertFal
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.junit.Assume.assumeNotNull;
import static org.junit.Assume.assumeTrue;
@@ -218,16 +219,39 @@ public class Zip64SupportTest {
}
};
- @Ignore
@Test public void write100KFilesFile() throws Throwable {
withTemporaryArchive("write100KFilesFile", write100KFiles, true);
}
- @Ignore
@Test public void write100KFilesStream() throws Throwable {
withTemporaryArchive("write100KFilesStream", write100KFiles, false);
}
+ private static final ZipOutputTest write100KFilesModeNever =
+ new ZipOutputTest() {
+ public void test(File f, ZipArchiveOutputStream zos)
+ throws IOException {
+ zos.setUseZip64(Zip64Mode.Never);
+ try {
+ write100KFilesToStream(zos);
+ fail("expected a Zip64RequiredException");
+ } catch (Zip64RequiredException ex) {
+
assertEquals(Zip64RequiredException.TOO_MANY_ENTRIES_MESSAGE,
+ ex.getMessage());
+ }
+ }
+ };
+
+ @Test public void write100KFilesFileModeNever() throws Throwable {
+ withTemporaryArchive("write100KFilesFileModeNever",
+ write100KFilesModeNever, true);
+ }
+
+ @Test public void write100KFilesStreamModeNever() throws Throwable {
+ withTemporaryArchive("write100KFilesStreamModeNever",
+ write100KFilesModeNever, false);
+ }
+
@Ignore
@Test public void readSelfGenerated100KFilesUsingZipFile()
throws Throwable {
@@ -330,20 +354,47 @@ public class Zip64SupportTest {
}
};
- @Ignore
@Test public void write3EntriesCreatingBigArchiveFile() throws Throwable {
withTemporaryArchive("write3EntriesCreatingBigArchiveFile",
write3EntriesCreatingBigArchive,
true);
}
- @Ignore
@Test public void write3EntriesCreatingBigArchiveStream() throws Throwable
{
withTemporaryArchive("write3EntriesCreatingBigArchiveStream",
write3EntriesCreatingBigArchive,
false);
}
+ private static final ZipOutputTest
write3EntriesCreatingBigArchiveModeNever =
+ new ZipOutputTest() {
+ public void test(File f, ZipArchiveOutputStream zos)
+ throws IOException {
+ zos.setUseZip64(Zip64Mode.Never);
+ try {
+ write3EntriesCreatingBigArchiveToStream(zos);
+ fail("expected a Zip64RequiredException");
+ } catch (Zip64RequiredException ex) {
+
assertEquals(Zip64RequiredException.ARCHIVE_TOO_BIG_MESSAGE,
+ ex.getMessage());
+ }
+ }
+ };
+
+ @Test public void write3EntriesCreatingBigArchiveFileModeNever()
+ throws Throwable {
+ withTemporaryArchive("write3EntriesCreatingBigArchiveFileModeNever",
+ write3EntriesCreatingBigArchiveModeNever,
+ true);
+ }
+
+ @Test public void write3EntriesCreatingBigArchiveStreamModeNever()
+ throws Throwable {
+ withTemporaryArchive("write3EntriesCreatingBigArchiveStreamModeNever",
+ write3EntriesCreatingBigArchiveModeNever,
+ false);
+ }
+
@Ignore
@Test public void read3EntriesCreatingBigArchiveFileUsingZipFile()
throws Throwable {
@@ -537,27 +588,70 @@ public class Zip64SupportTest {
* No Compression + Stream => sizes must be known before data is
* written.
*/
- @Ignore
@Test public void writeBigStoredEntryToStream() throws Throwable {
withTemporaryArchive("writeBigStoredEntryToStream",
writeBigStoredEntry(true),
false);
}
- @Ignore
@Test public void writeBigStoredEntryKnownSizeToFile() throws Throwable {
withTemporaryArchive("writeBigStoredEntryKnownSizeToFile",
writeBigStoredEntry(true),
true);
}
- @Ignore
@Test public void writeBigStoredEntryUnnownSizeToFile() throws Throwable {
withTemporaryArchive("writeBigStoredEntryUnknownSizeToFile",
writeBigStoredEntry(false),
true);
}
+ private static ZipOutputTest writeBigStoredEntryModeNever(final boolean
knownSize) {
+ return new ZipOutputTest() {
+ public void test(File f, ZipArchiveOutputStream zos)
+ throws IOException {
+ zos.setUseZip64(Zip64Mode.Never);
+ try {
+ byte[] buf = new byte[ONE_MILLION];
+ ZipArchiveEntry zae = new ZipArchiveEntry("0");
+ if (knownSize) {
+ zae.setSize(FIVE_BILLION);
+ zae.setCrc(0x5c316f50L);
+ }
+ zae.setMethod(ZipArchiveEntry.STORED);
+ zos.putArchiveEntry(zae);
+ for (int j = 0; j < FIVE_BILLION / 1000 / 1000; j++) {
+ zos.write(buf);
+ }
+ zos.closeArchiveEntry();
+ fail("expected a Zip64RequiredException");
+ } catch (Zip64RequiredException ex) {
+ assertTrue(ex.getMessage().startsWith("0's size"));
+ }
+ }
+ };
+ }
+
+ @Test public void writeBigStoredEntryToStreamModeNever() throws Throwable {
+ withTemporaryArchive("writeBigStoredEntryToStreamModeNever",
+ writeBigStoredEntryModeNever(true),
+ false);
+ }
+
+ @Test public void writeBigStoredEntryKnownSizeToFileModeNever()
+ throws Throwable {
+ withTemporaryArchive("writeBigStoredEntryKnownSizeToFileModeNever",
+ writeBigStoredEntryModeNever(true),
+ true);
+ }
+
+ @Test public void writeBigStoredEntryUnnownSizeToFileModeNever()
+ throws Throwable {
+ withTemporaryArchive("writeBigStoredEntryUnknownSizeToFile",
+ writeBigStoredEntryModeNever(false),
+ true);
+ }
+
/*
* One entry of length 5 billion bytes, written with
* compression to a stream.
@@ -567,7 +661,6 @@ public class Zip64SupportTest {
*
* Creates a temporary archive of approx 4MB in size
*/
- @Ignore
@Test public void writeBigDeflatedEntryKnownSizeToStream()
throws Throwable {
withTemporaryArchive("writeBigDeflatedEntryKnownSizeToStream",
@@ -886,7 +979,6 @@ public class Zip64SupportTest {
};
}
- @Ignore
@Test public void writeBigDeflatedEntryKnownSizeToFile()
throws Throwable {
withTemporaryArchive("writeBigDeflatedEntryKnownSizeToFile",
@@ -894,7 +986,6 @@ public class Zip64SupportTest {
true);
}
- @Ignore
@Test public void writeBigDeflatedEntryUnknownSizeToFile()
throws Throwable {
withTemporaryArchive("writeBigDeflatedEntryUnknownSizeToFile",
@@ -902,6 +993,82 @@ public class Zip64SupportTest {
true);
}
+ @Test public void writeBigDeflatedEntryKnownSizeToStreamModeNever()
+ throws Throwable {
+ withTemporaryArchive("writeBigDeflatedEntryKnownSizeToStreamModeNever",
+ new ZipOutputTest() {
+ public void test(File f,
+ ZipArchiveOutputStream zos)
+ throws IOException {
+ zos.setUseZip64(Zip64Mode.Never);
+ try {
+ byte[] buf = new byte[ONE_MILLION];
+ ZipArchiveEntry zae =
+ new ZipArchiveEntry("0");
+ zae.setSize(FIVE_BILLION);
+
zae.setMethod(ZipArchiveEntry.DEFLATED);
+ zos.putArchiveEntry(zae);
+ fail("expected a"
+ + " Zip64RequiredException");
+ } catch (Zip64RequiredException ex) {
+ assertTrue(ex.getMessage()
+ .startsWith("0's size"));
+ }
+ }
+ },
+ false);
+ }
+
+ /*
+ * One entry of length 5 billion bytes, written with
+ * compression to a file.
+ *
+ * Writing to a file => sizes are stored directly inside the LFH.
+ * No Data Descriptor at all.
+ *
+ * Creates a temporary archive of approx 4MB in size
+ */
+ private static ZipOutputTest writeBigDeflatedEntryToFileModeNever(final
boolean knownSize) {
+ return new ZipOutputTest() {
+ public void test(File f, ZipArchiveOutputStream zos)
+ throws IOException {
+ zos.setUseZip64(Zip64Mode.Never);
+ try {
+ byte[] buf = new byte[ONE_MILLION];
+ ZipArchiveEntry zae = new ZipArchiveEntry("0");
+ if (knownSize) {
+ zae.setSize(FIVE_BILLION);
+ }
+ zae.setMethod(ZipArchiveEntry.DEFLATED);
+ zos.putArchiveEntry(zae);
+ for (int j = 0;
+ j < FIVE_BILLION / 1000 / 1000;
+ j++) {
+ zos.write(buf);
+ }
+ zos.closeArchiveEntry();
+ fail("expected a Zip64RequiredException");
+ } catch (Zip64RequiredException ex) {
+ assertTrue(ex.getMessage().startsWith("0's size"));
+ }
+ }
+ };
+ }
+
+ @Test public void writeBigDeflatedEntryKnownSizeToFileModeNever()
+ throws Throwable {
+ withTemporaryArchive("writeBigDeflatedEntryKnownSizeToFileModeNever",
+ writeBigDeflatedEntryToFileModeNever(true),
+ true);
+ }
+
+ @Test public void writeBigDeflatedEntryUnknownSizeToFileModeNever()
+ throws Throwable {
+ withTemporaryArchive("writeBigDeflatedEntryUnknownSizeToFileModeNever",
+ writeBigDeflatedEntryToFileModeNever(false),
+ true);
+ }
+
/*
* One entry of length 1 million bytes, written without compression.
*
@@ -1370,13 +1537,13 @@ public class Zip64SupportTest {
assumeTrue(false);
} finally {
try {
- zos.close();
+ zos.destroy();
} finally {
if (os != null) {
os.close();
}
+ f.delete();
}
- f.delete();
}
}