Hi,
the appended patch adds a boolean compress attribute to the zip task,
which gets inherited by the jar task.
If this attribute is set to false, files will be STORED instead of
DEFLATED. The default is to compress.
Rationale:
Older JVMs don't support compressed JAR files. The command line jar
tool addresses this via the 0 option, Ant doesn't have a way to
achieve the same effect.
Notes:
1. I had thought it would be quite straight forward to implement this
feature, just set the ZipOutputStream's method to STORED instead of
DEFLATED.
Wrong, if you use STORED, you are expected to calculate the CRC32
checksum for the entries yourself - even before writing the data to
the stream. This I've learned the hard way, I couldn't find any hint
in the API docs. If anybody has a pointer to where this is documented
I'd like to hear.
2. While the zip task just ignored directories the jar task
added empty entries to the stream.
Those empty entries really cause problems in STORED mode so I've
dropped them in jar as well. I couldn't see any problems with this
approach during my tests but maybe ...
Stefan
Index: docs/index.html
===================================================================
RCS file: /home/cvspublic/jakarta-ant/docs/index.html,v
retrieving revision 1.17
diff -u -r1.17 index.html
--- docs/index.html 2000/03/29 17:13:31 1.17
+++ docs/index.html 2000/05/18 07:58:46
@@ -1129,6 +1129,11 @@
<td valign="top" align="center">Yes</td>
</tr>
<tr>
+ <td valign="top">compress</td>
+ <td valign="top">Not only store data but also compress them, defaults to true</td>
+ <td align="center" valign="top">No</td>
+ </tr>
+ <tr>
<td valign="top">items</td>
<td valign="top">a comma separated list of the files/directories to jar. All
files are included when omitted. (<b>deprecated</b>, use <i>includes</i>
@@ -2038,6 +2043,11 @@
<td valign="top">basedir</td>
<td valign="top">the directory from which to zip the files.</td>
<td align="center" valign="top">Yes</td>
+ </tr>
+ <tr>
+ <td valign="top">compress</td>
+ <td valign="top">Not only store data but also compress them, defaults to true</td>
+ <td align="center" valign="top">No</td>
</tr>
<tr>
<td valign="top">items</td>
Index: src/main/org/apache/tools/ant/taskdefs/Jar.java
===================================================================
RCS file: /home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Jar.java,v
retrieving revision 1.3
diff -u -r1.3 Jar.java
--- src/main/org/apache/tools/ant/taskdefs/Jar.java 2000/02/09 20:51:47 1.3
+++ src/main/org/apache/tools/ant/taskdefs/Jar.java 2000/05/18 07:58:48
@@ -81,16 +81,19 @@
protected void initZipOutputStream(ZipOutputStream zOut)
throws IOException, BuildException
{
- zOut.setMethod(ZipOutputStream.DEFLATED);
-
// add manifest first
if (manifest != null) {
- ZipEntry ze = new ZipEntry("META-INF/");
- zOut.putNextEntry(ze);
+ super.zipDir(new File(manifest.getParent()), zOut, "META-INF/");
super.zipFile(manifest, zOut, "META-INF/MANIFEST.MF");
} else {
- ZipEntry ze = new ZipEntry("META-INF/");
- zOut.putNextEntry(ze);
+ /*
+ * We don't store directories at all and this one will cause a lot
+ * of problems with STORED Zip-Mode.
+ *
+ * That's why i've removed it -- Stefan Bodewig
+ */
+ // ZipEntry ze = new ZipEntry("META-INF/");
+ // zOut.putNextEntry(ze);
String s = "/org/apache/tools/ant/defaultManifest.mf";
InputStream in = this.getClass().getResourceAsStream(s);
if ( in == null )
@@ -105,8 +108,7 @@
// First add directory to zip entry
if(!vPath.equals("META-INF/")) {
// we already added a META-INF
- ZipEntry ze = new ZipEntry(vPath);
- zOut.putNextEntry(ze);
+ super.zipDir(dir, zOut, vPath);
}
}
Index: src/main/org/apache/tools/ant/taskdefs/Zip.java
===================================================================
RCS file: /home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/Zip.java,v
retrieving revision 1.5
diff -u -r1.5 Zip.java
--- src/main/org/apache/tools/ant/taskdefs/Zip.java 2000/02/13 21:43:34 1.5
+++ src/main/org/apache/tools/ant/taskdefs/Zip.java 2000/05/18 07:58:48
@@ -73,6 +73,7 @@
private File zipFile;
private File baseDir;
+ private boolean doCompress = true;
protected String archiveType = "zip";
/**
@@ -91,6 +92,13 @@
baseDir = project.resolveFile(baseDirname);
}
+ /**
+ * Sets whether we want to compress the files or only store them.
+ */
+ public void setCompress(String compress) {
+ doCompress = Project.toBoolean(compress);
+ }
+
public void execute() throws BuildException {
if (baseDir == null) {
throw new BuildException("basedir attribute must be set!");
@@ -116,6 +124,11 @@
try {
ZipOutputStream zOut = new ZipOutputStream(new FileOutputStream(zipFile));
+ if (doCompress) {
+ zOut.setMethod(ZipOutputStream.DEFLATED);
+ } else {
+ zOut.setMethod(ZipOutputStream.STORED);
+ }
initZipOutputStream(zOut);
for (int i = 0; i < dirs.length; i++) {
@@ -141,7 +154,6 @@
protected void initZipOutputStream(ZipOutputStream zOut)
throws IOException, BuildException
{
- zOut.setMethod(ZipOutputStream.DEFLATED);
}
protected void zipDir(File dir, ZipOutputStream zOut, String vPath)
@@ -153,6 +165,49 @@
throws IOException
{
ZipEntry ze = new ZipEntry(vPath);
+
+ /*
+ * XXX ZipOutputStream.putEntry expects the ZipEntry to know its
+ * size and the CRC sum before you start writing the data when using
+ * STORED mode.
+ *
+ * This forces us to process the data twice.
+ *
+ * I couldn't find any documentation on this, just found out by try
+ * and error.
+ */
+ if (!doCompress) {
+ long size = 0;
+ CRC32 cal = new CRC32();
+ if (!in.markSupported()) {
+ // Store data into a byte[]
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ byte[] buffer = new byte[8 * 1024];
+ int count = 0;
+ do {
+ size += count;
+ cal.update(buffer, 0, count);
+ bos.write(buffer, 0, count);
+ count = in.read(buffer, 0, buffer.length);
+ } while (count != -1);
+ in = new ByteArrayInputStream(bos.toByteArray());
+
+ } else {
+ in.mark(Integer.MAX_VALUE);
+ byte[] buffer = new byte[8 * 1024];
+ int count = 0;
+ do {
+ size += count;
+ cal.update(buffer, 0, count);
+ count = in.read(buffer, 0, buffer.length);
+ } while (count != -1);
+ in.reset();
+ }
+ ze.setSize(size);
+ ze.setCrc(cal.getValue());
+ }
+
zOut.putNextEntry(ze);
byte[] buffer = new byte[8 * 1024];