diff --git a/src/main/org/apache/tools/ant/taskdefs/Jar.java b/src/main/org/apache/tools/ant/taskdefs/Jar.java index 5aaca03fc..567c33892 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Jar.java +++ b/src/main/org/apache/tools/ant/taskdefs/Jar.java @@ -181,6 +181,7 @@ public class Jar extends Zip { archiveType = "jar"; emptyBehavior = "create"; setEncoding("UTF8"); + setZip64Mode(Zip64ModeAttribute.NEVER); rootEntries = new Vector(); } diff --git a/src/main/org/apache/tools/ant/taskdefs/Zip.java b/src/main/org/apache/tools/ant/taskdefs/Zip.java index a58ac1bf5..4bd32c7e9 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Zip.java +++ b/src/main/org/apache/tools/ant/taskdefs/Zip.java @@ -62,6 +62,7 @@ import org.apache.tools.ant.util.IdentityMapper; import org.apache.tools.ant.util.MergingMapper; import org.apache.tools.ant.util.ResourceUtils; import org.apache.tools.zip.UnixStat; +import org.apache.tools.zip.Zip64Mode; import org.apache.tools.zip.ZipEntry; import org.apache.tools.zip.ZipExtraField; import org.apache.tools.zip.ZipFile; @@ -221,6 +222,13 @@ public class Zip extends MatchingTask { */ private boolean fallBackToUTF8 = false; + /** + * Whether to enable Zip64 extensions. + * + * @since Ant 1.9.1 + */ + private Zip64ModeAttribute zip64Mode = Zip64ModeAttribute.AS_NEEDED; + /** * This is the name/location of where to * create the .zip file. @@ -553,6 +561,22 @@ public class Zip extends MatchingTask { return fallBackToUTF8; } + /** + * Whether Zip64 extensions should be used. + * @since Ant 1.9.1 + */ + public void setZip64Mode(Zip64ModeAttribute b) { + zip64Mode = b; + } + + /** + * Whether Zip64 extensions will be used. + * @since Ant 1.9.1 + */ + public Zip64ModeAttribute getZip64Mode() { + return zip64Mode; + } + /** * validate and build * @throws BuildException on error @@ -656,6 +680,7 @@ public class Zip extends MatchingTask { zOut.setMethod(doCompress ? ZipOutputStream.DEFLATED : ZipOutputStream.STORED); zOut.setLevel(level); + zOut.setUseZip64(zip64Mode.getMode()); } initZipOutputStream(zOut); @@ -2173,8 +2198,68 @@ public class Zip extends MatchingTask { } public ZipOutputStream.UnicodeExtraFieldPolicy getPolicy() { - return (ZipOutputStream.UnicodeExtraFieldPolicy) - POLICIES.get(getValue()); + return POLICIES.get(getValue()); } } -} + + + /** + * The choices for Zip64 extensions. + * + *

never: never add any Zip64 extensions. This will + * cause the task to fail if you try to add entries bigger than + * 4GB or create an archive bigger than 4GB or holding more that + * 65535 entries.

+ * + *

as-needed: create Zip64 extensions only when the + * entry's size is bigger than 4GB or one of the archive limits is + * hit. This mode also adds partial Zip64 extensions for all + * deflated entries written by Ant.

+ * + *

always: create Zip64 extensions for all entries.

+ * + *

Note some ZIP implementations don't handle Zip64 + * extensions well and others may fail if the Zip64 extra field + * data is only present inside the local file header but not the + * central directory - which is what as-needed may result + * in. Java5 and Microsoft Visual Studio's Extension loader are + * known to fconsider the archive broken in such cases. If you + * are targeting such an archiver uset the value never + * unless you know you need Zip64 extensions.

+ * + * @since Ant 1.9.1 + */ + public static final class Zip64ModeAttribute extends EnumeratedAttribute { + private static final Map MODES = new HashMap(); + + private static final String NEVER_KEY = "never"; + private static final String ALWAYS_KEY = "always"; + private static final String A_N_KEY = "as-needed"; + static { + MODES.put(NEVER_KEY, Zip64Mode.Never); + MODES.put(ALWAYS_KEY, Zip64Mode.Always); + MODES.put(A_N_KEY, Zip64Mode.AsNeeded); + } + + public String[] getValues() { + return new String[] {NEVER_KEY, ALWAYS_KEY, A_N_KEY}; + } + + public static final Zip64ModeAttribute NEVER = + new Zip64ModeAttribute(NEVER_KEY); + public static final Zip64ModeAttribute AS_NEEDED = + new Zip64ModeAttribute(A_N_KEY); + + private Zip64ModeAttribute(String name) { + setValue(name); + } + + public Zip64ModeAttribute() { + } + + public Zip64Mode getMode() { + return MODES.get(getValue()); + } + + } + } diff --git a/src/tests/junit/org/apache/tools/ant/taskdefs/ZipExtraFieldTest.java b/src/tests/junit/org/apache/tools/ant/taskdefs/ZipExtraFieldTest.java index 8fb20c105..da1b23d7a 100644 --- a/src/tests/junit/org/apache/tools/ant/taskdefs/ZipExtraFieldTest.java +++ b/src/tests/junit/org/apache/tools/ant/taskdefs/ZipExtraFieldTest.java @@ -40,11 +40,20 @@ import org.apache.tools.zip.ZipFile; public class ZipExtraFieldTest extends TestCase { public void testPreservesExtraFields() throws IOException { + testExtraField(new Zip(), true); + } + + public void testDoesntCreateZip64ExtraFieldForJar() throws IOException { + testExtraField(new Jar(), false); + } + + private void testExtraField(Zip testInstance, boolean expectZip64) + throws IOException { + File f = File.createTempFile("ziptest", ".zip"); f.delete(); ZipFile zf = null; try { - Zip testInstance = new Zip(); testInstance.setDestFile(f); final ZipResource r = new ZipResource() { public String getName() { @@ -80,10 +89,12 @@ public class ZipExtraFieldTest extends TestCase { zf = new ZipFile(f); ZipEntry ze = zf.getEntry("x"); assertNotNull(ze); - assertEquals(2, ze.getExtraFields().length); + assertEquals(expectZip64 ? 2 : 1, ze.getExtraFields().length); assertTrue(ze.getExtraFields()[0] instanceof JarMarker); - assertTrue(ze.getExtraFields()[1] - instanceof Zip64ExtendedInformationExtraField); + if (expectZip64) { + assertTrue(ze.getExtraFields()[1] + instanceof Zip64ExtendedInformationExtraField); + } } finally { ZipFile.closeQuietly(zf); if (f.exists()) { @@ -91,5 +102,4 @@ public class ZipExtraFieldTest extends TestCase { } } } - }