You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by bo...@apache.org on 2003/07/22 13:37:21 UTC
cvs commit: ant/src/main/org/apache/tools/zip ZipOutputStream.java
bodewig 2003/07/22 04:37:21
Modified: . WHATSNEW
src/main/org/apache/tools/ant/taskdefs Zip.java
src/main/org/apache/tools/zip ZipOutputStream.java
Log:
Don't use a data descriptor for deflated entries in ZipOutputStream if
we can seek the output. Use this feature in <zip>.
PR: 19195
Submitted by: Richard Evans <ri...@retek.com>
Revision Changes Path
1.464 +7 -2 ant/WHATSNEW
Index: WHATSNEW
===================================================================
RCS file: /home/cvs/ant/WHATSNEW,v
retrieving revision 1.463
retrieving revision 1.464
diff -u -r1.463 -r1.464
--- WHATSNEW 22 Jul 2003 08:19:16 -0000 1.463
+++ WHATSNEW 22 Jul 2003 11:37:21 -0000 1.464
@@ -497,10 +497,15 @@
* OpenVMS is detected as a valid OS family.
-* DirectoryScanner has been optimized for cases where include patterns do not start with wildcards
- Bugzilla Report 20103.
+* DirectoryScanner has been optimized for cases where include patterns do not
+ start with wildcards. Bugzilla Report 20103.
* Added keep-going feature. Bugzilla Report 21144
+
+* The archives generated by <zip> and friends will now contain CRC and
+ size information in the "local file header", thereby providing this
+ information to applications that read the archives using
+ java.util.ZipInputStream. Bugzilla Report 19195.
Changes from Ant 1.5.2 to Ant 1.5.3
===================================
1.111 +1 -1 ant/src/main/org/apache/tools/ant/taskdefs/Zip.java
Index: Zip.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/taskdefs/Zip.java,v
retrieving revision 1.110
retrieving revision 1.111
diff -u -r1.110 -r1.111
--- Zip.java 15 Jul 2003 14:54:14 -0000 1.110
+++ Zip.java 22 Jul 2003 11:37:21 -0000 1.111
@@ -418,7 +418,7 @@
try {
if (!skipWriting) {
- zOut = new ZipOutputStream(new FileOutputStream(zipFile));
+ zOut = new ZipOutputStream(zipFile);
zOut.setEncoding(encoding);
if (doCompress) {
1.15 +242 -79 ant/src/main/org/apache/tools/zip/ZipOutputStream.java
Index: ZipOutputStream.java
===================================================================
RCS file: /home/cvs/ant/src/main/org/apache/tools/zip/ZipOutputStream.java,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- ZipOutputStream.java 15 Jul 2003 14:54:15 -0000 1.14
+++ ZipOutputStream.java 22 Jul 2003 11:37:21 -0000 1.15
@@ -54,15 +54,18 @@
package org.apache.tools.zip;
-import java.io.OutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilterOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Hashtable;
import java.util.Vector;
import java.util.zip.CRC32;
import java.util.zip.Deflater;
-import java.util.zip.DeflaterOutputStream;
import java.util.zip.ZipException;
/**
@@ -72,7 +75,12 @@
* attributes and extra fields with different layouts for local file
* data and central directory entries.
*
- * <p>This implementation will use a Data Descriptor to store size and
+ * <p>This class will try to use {@link java.io.RandomAccessFile
+ * RandomAccessFile} when you know that the output is going to go to a
+ * file.</p>
+ *
+ * <p>If RandomAccessFile cannot be used, this implementation will use
+ * a Data Descriptor to store size and
* CRC information for DEFLATED entries, this means, you don't need to
* calculate them yourself. Unfortunately this is not possible for
* the STORED method, here setting the CRC and uncompressed size
@@ -80,9 +88,10 @@
* will be called.</p>
*
* @author Stefan Bodewig
+ * @author Richard Evans
* @version $Revision$
*/
-public class ZipOutputStream extends DeflaterOutputStream {
+public class ZipOutputStream extends FilterOutputStream {
/**
* Current entry.
@@ -142,13 +151,21 @@
private long written = 0;
/**
- * Data for current entry started here.
+ * Data for local header data
*
* @since 1.1
*/
private long dataStart = 0;
/**
+ * Offset for CRC entry in the local file header data for the
+ * current entry starts here.
+ *
+ * @since 1.15
+ */
+ private long localDataStart = 0;
+
+ /**
* Start of central directory.
*
* @since 1.1
@@ -195,6 +212,27 @@
private String encoding = null;
/**
+ * Deflater object for output
+ *
+ * @since 1.14
+ */
+ protected Deflater def = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
+
+ /**
+ * Deflater buffer
+ *
+ * @since 1.14
+ */
+ protected byte[] buf = new byte[512];
+
+ /**
+ * Optional random access output
+ *
+ * @since 1.14
+ */
+ private RandomAccessFile raf = null;
+
+ /**
* Compression method for deflated entries.
*
* @since 1.1
@@ -214,7 +252,32 @@
* @since 1.1
*/
public ZipOutputStream(OutputStream out) {
- super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
+ super(out);
+ }
+
+ /**
+ * Creates a new ZIP OutputStream writing to a File. Will use
+ * random access if possible.
+ *
+ * @since 1.14
+ */
+ public ZipOutputStream(File file) throws IOException {
+ super(null);
+
+ try {
+ raf = new RandomAccessFile(file, "rw");
+ raf.setLength(0);
+ } catch (IOException e) {
+ if (raf != null) {
+ try {
+ raf.close();
+ } catch (IOException inner) {
+ // ignore
+ }
+ raf = null;
+ }
+ out = new FileOutputStream(file);
+ }
}
/**
@@ -241,12 +304,6 @@
return encoding;
}
- /*
- * Found out by experiment, that DeflaterOutputStream.close()
- * will call finish() - so we don't need to override close
- * ourselves.
- */
-
/**
* Finishs writing the contents and closes this as well as the
* underlying stream.
@@ -291,7 +348,7 @@
def.reset();
written += entry.getCompressedSize();
- } else {
+ } else if (raf == null) {
if (entry.getCrc() != realCrc) {
throw new ZipException("bad CRC checksum for entry "
+ entry.getName() + ": "
@@ -307,12 +364,29 @@
+ " instead of "
+ (written - dataStart));
}
+ } else { /* method is STORED and we used RandomAccessFile */
+ long size = written - dataStart;
+
+ entry.setSize(size);
+ entry.setComprSize(size);
+ entry.setCrc(realCrc);
+ }
+ // If random access output, write the local file header containing
+ // the correct CRC and compressed/uncompressed sizes
+ if (raf != null) {
+ long save = raf.getFilePointer();
+
+ raf.seek(localDataStart);
+ writeOut((new ZipLong(entry.getCrc())).getBytes());
+ writeOut((new ZipLong(entry.getCompressedSize())).getBytes());
+ writeOut((new ZipLong(entry.getSize())).getBytes());
+ raf.seek(save);
}
writeDataDescriptor(entry);
entry = null;
- }
+ }
/**
* Begin writing next entry.
@@ -333,15 +407,21 @@
entry.setTime(System.currentTimeMillis());
}
- if (entry.getMethod() == STORED) {
+ // Size/CRC not required if RandomAccessFile is used
+ if (entry.getMethod() == STORED && raf == null) {
if (entry.getSize() == -1) {
- throw new ZipException("uncompressed size is required for STORED method");
+ throw new ZipException("uncompressed size is required for"
+ + " STORED method when not writing to a"
+ + " file");
}
if (entry.getCrc() == -1) {
- throw new ZipException("crc checksum is required for STORED method");
+ throw new ZipException("crc checksum is required for STORED"
+ + " method when not writing to a file");
}
entry.setComprSize(entry.getSize());
- } else if (hasCompressionLevelChanged) {
+ }
+
+ if (entry.getMethod() == DEFLATED && hasCompressionLevelChanged) {
def.setLevel(level);
hasCompressionLevelChanged = false;
}
@@ -382,20 +462,68 @@
/**
* Writes bytes to ZIP entry.
- *
- * <p>Override is necessary to support STORED entries, as well as
- * calculationg CRC automatically for DEFLATED entries.</p>
*/
public void write(byte[] b, int offset, int length) throws IOException {
if (entry.getMethod() == DEFLATED) {
- super.write(b, offset, length);
+ if (length > 0) {
+ if (!def.finished()) {
+ def.setInput(b, offset, length);
+ while (!def.needsInput()) {
+ deflate();
+ }
+ }
+ }
} else {
- out.write(b, offset, length);
+ writeOut(b, offset, length);
written += length;
}
crc.update(b, offset, length);
}
+ /**
+ * Writes a single byte to ZIP entry.
+ *
+ * <p>Delegates to the three arg method.</p>
+ *
+ * @since 1.14
+ */
+ public void write(int b) throws IOException {
+ byte[] buf = new byte[1];
+ buf[0] = (byte) (b & 0xff);
+ write(buf, 0, 1);
+ }
+
+ /**
+ * Closes this output stream and releases any system resources
+ * associated with the stream.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @since 1.14
+ */
+ public void close() throws IOException {
+ finish();
+
+ if (raf != null) {
+ raf.close();
+ }
+ if (out != null) {
+ out.close();
+ }
+ }
+
+ /**
+ * Flushes this output stream and forces any buffered output bytes
+ * to be written out to the stream.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @since 1.14
+ */
+ public void flush() throws IOException {
+ if (out == null) {
+ out.flush();
+ }
+ }
+
/*
* Various ZIP constants
*/
@@ -425,6 +553,18 @@
protected static final ZipLong EOCD_SIG = new ZipLong(0X06054B50L);
/**
+ * Writes next block of compressed data to the output stream.
+ *
+ * @since 1.14
+ */
+ protected final void deflate() throws IOException {
+ int len = def.deflate(buf, 0, buf.length);
+ if (len > 0) {
+ writeOut(buf, 0, len);
+ }
+ }
+
+ /**
* Writes the local file header entry
*
* @since 1.1
@@ -432,62 +572,63 @@
protected void writeLocalFileHeader(ZipEntry ze) throws IOException {
offsets.put(ze, new ZipLong(written));
- out.write(LFH_SIG.getBytes());
+ writeOut(LFH_SIG.getBytes());
written += 4;
// version needed to extract
// general purpose bit flag
- if (ze.getMethod() == DEFLATED) {
+ if (ze.getMethod() == DEFLATED && raf == null) {
// requires version 2 as we are going to store length info
// in the data descriptor
- out.write((new ZipShort(20)).getBytes());
+ writeOut((new ZipShort(20)).getBytes());
// bit3 set to signal, we use a data descriptor
- out.write((new ZipShort(8)).getBytes());
+ writeOut((new ZipShort(8)).getBytes());
} else {
- out.write((new ZipShort(10)).getBytes());
- out.write(ZERO);
+ writeOut((new ZipShort(10)).getBytes());
+ writeOut(ZERO);
}
written += 4;
// compression method
- out.write((new ZipShort(ze.getMethod())).getBytes());
+ writeOut((new ZipShort(ze.getMethod())).getBytes());
written += 2;
// last mod. time and date
- out.write(toDosTime(new Date(ze.getTime())).getBytes());
+ writeOut(toDosTime(new Date(ze.getTime())).getBytes());
written += 4;
// CRC
// compressed length
// uncompressed length
- if (ze.getMethod() == DEFLATED) {
- out.write(LZERO);
- out.write(LZERO);
- out.write(LZERO);
+ localDataStart = written;
+ if (ze.getMethod() == DEFLATED || raf != null) {
+ writeOut(LZERO);
+ writeOut(LZERO);
+ writeOut(LZERO);
} else {
- out.write((new ZipLong(ze.getCrc())).getBytes());
- out.write((new ZipLong(ze.getSize())).getBytes());
- out.write((new ZipLong(ze.getSize())).getBytes());
+ writeOut((new ZipLong(ze.getCrc())).getBytes());
+ writeOut((new ZipLong(ze.getSize())).getBytes());
+ writeOut((new ZipLong(ze.getSize())).getBytes());
}
written += 12;
// file name length
byte[] name = getBytes(ze.getName());
- out.write((new ZipShort(name.length)).getBytes());
+ writeOut((new ZipShort(name.length)).getBytes());
written += 2;
// extra field length
byte[] extra = ze.getLocalFileDataExtra();
- out.write((new ZipShort(extra.length)).getBytes());
+ writeOut((new ZipShort(extra.length)).getBytes());
written += 2;
// file name
- out.write(name);
+ writeOut(name);
written += name.length;
// extra field
- out.write(extra);
+ writeOut(extra);
written += extra.length;
dataStart = written;
@@ -499,13 +640,13 @@
* @since 1.1
*/
protected void writeDataDescriptor(ZipEntry ze) throws IOException {
- if (ze.getMethod() != DEFLATED) {
+ if (ze.getMethod() != DEFLATED || raf != null) {
return;
}
- out.write(DD_SIG.getBytes());
- out.write((new ZipLong(entry.getCrc())).getBytes());
- out.write((new ZipLong(entry.getCompressedSize())).getBytes());
- out.write((new ZipLong(entry.getSize())).getBytes());
+ writeOut(DD_SIG.getBytes());
+ writeOut((new ZipLong(entry.getCrc())).getBytes());
+ writeOut((new ZipLong(entry.getCompressedSize())).getBytes());
+ writeOut((new ZipLong(entry.getSize())).getBytes());
written += 16;
}
@@ -515,52 +656,52 @@
* @since 1.1
*/
protected void writeCentralFileHeader(ZipEntry ze) throws IOException {
- out.write(CFH_SIG.getBytes());
+ writeOut(CFH_SIG.getBytes());
written += 4;
// version made by
- out.write((new ZipShort((ze.getPlatform() << 8) | 20)).getBytes());
+ writeOut((new ZipShort((ze.getPlatform() << 8) | 20)).getBytes());
written += 2;
// version needed to extract
// general purpose bit flag
- if (ze.getMethod() == DEFLATED) {
+ if (ze.getMethod() == DEFLATED && raf == null) {
// requires version 2 as we are going to store length info
// in the data descriptor
- out.write((new ZipShort(20)).getBytes());
+ writeOut((new ZipShort(20)).getBytes());
// bit3 set to signal, we use a data descriptor
- out.write((new ZipShort(8)).getBytes());
+ writeOut((new ZipShort(8)).getBytes());
} else {
- out.write((new ZipShort(10)).getBytes());
- out.write(ZERO);
+ writeOut((new ZipShort(10)).getBytes());
+ writeOut(ZERO);
}
written += 4;
// compression method
- out.write((new ZipShort(ze.getMethod())).getBytes());
+ writeOut((new ZipShort(ze.getMethod())).getBytes());
written += 2;
// last mod. time and date
- out.write(toDosTime(new Date(ze.getTime())).getBytes());
+ writeOut(toDosTime(new Date(ze.getTime())).getBytes());
written += 4;
// CRC
// compressed length
// uncompressed length
- out.write((new ZipLong(ze.getCrc())).getBytes());
- out.write((new ZipLong(ze.getCompressedSize())).getBytes());
- out.write((new ZipLong(ze.getSize())).getBytes());
+ writeOut((new ZipLong(ze.getCrc())).getBytes());
+ writeOut((new ZipLong(ze.getCompressedSize())).getBytes());
+ writeOut((new ZipLong(ze.getSize())).getBytes());
written += 12;
// file name length
byte[] name = getBytes(ze.getName());
- out.write((new ZipShort(name.length)).getBytes());
+ writeOut((new ZipShort(name.length)).getBytes());
written += 2;
// extra field length
byte[] extra = ze.getCentralDirectoryExtra();
- out.write((new ZipShort(extra.length)).getBytes());
+ writeOut((new ZipShort(extra.length)).getBytes());
written += 2;
// file comment length
@@ -569,35 +710,35 @@
comm = "";
}
byte[] comment = getBytes(comm);
- out.write((new ZipShort(comment.length)).getBytes());
+ writeOut((new ZipShort(comment.length)).getBytes());
written += 2;
// disk number start
- out.write(ZERO);
+ writeOut(ZERO);
written += 2;
// internal file attributes
- out.write((new ZipShort(ze.getInternalAttributes())).getBytes());
+ writeOut((new ZipShort(ze.getInternalAttributes())).getBytes());
written += 2;
// external file attributes
- out.write((new ZipLong(ze.getExternalAttributes())).getBytes());
+ writeOut((new ZipLong(ze.getExternalAttributes())).getBytes());
written += 4;
// relative offset of LFH
- out.write(((ZipLong) offsets.get(ze)).getBytes());
+ writeOut(((ZipLong) offsets.get(ze)).getBytes());
written += 4;
// file name
- out.write(name);
+ writeOut(name);
written += name.length;
// extra field
- out.write(extra);
+ writeOut(extra);
written += extra.length;
// file comment
- out.write(comment);
+ writeOut(comment);
written += comment.length;
}
@@ -607,25 +748,25 @@
* @since 1.1
*/
protected void writeCentralDirectoryEnd() throws IOException {
- out.write(EOCD_SIG.getBytes());
+ writeOut(EOCD_SIG.getBytes());
// disk numbers
- out.write(ZERO);
- out.write(ZERO);
+ writeOut(ZERO);
+ writeOut(ZERO);
// number of entries
byte[] num = (new ZipShort(entries.size())).getBytes();
- out.write(num);
- out.write(num);
+ writeOut(num);
+ writeOut(num);
// length and location of CD
- out.write(cdLength.getBytes());
- out.write(cdOffset.getBytes());
+ writeOut(cdLength.getBytes());
+ writeOut(cdOffset.getBytes());
// ZIP file comment
byte[] data = getBytes(comment);
- out.write((new ZipShort(data.length)).getBytes());
- out.write(data);
+ writeOut((new ZipShort(data.length)).getBytes());
+ writeOut(data);
}
/**
@@ -681,4 +822,26 @@
}
}
+ /**
+ * Write bytes to output or random access file
+ *
+ * @since 1.14
+ */
+ protected final void writeOut(byte [] data) throws IOException {
+ writeOut(data, 0, data.length);
+ }
+
+ /**
+ * Write bytes to output or random access file
+ *
+ * @since 1.14
+ */
+ protected final void writeOut(byte [] data, int offset, int length)
+ throws IOException {
+ if (raf != null) {
+ raf.write(data, offset, length);
+ } else {
+ out.write(data, offset, length);
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org
Re: cvs commit: ant/src/main/org/apache/tools/zip ZipOutputStream.java
Posted by Stefan Bodewig <bo...@apache.org>.
On 22 Jul 2003, <bo...@apache.org> wrote:
> /**
> + * Deflater object for output
> + *
> + * @since 1.14
> + */
> + protected Deflater def = new Deflater(Deflater.DEFAULT_COMPRESSION, true);
> +
> + /**
> + * Deflater buffer
> + *
> + * @since 1.14
> + */
> + protected byte[] buf = new byte[512];
protected and not private (as checkstyle will certainly find out 8-).
The reason for this is that ZipOutputStream used to extend
java.util.zip.DeflaterOutputStream which has those two protected
members. It now extends FilterOutputStream directly and this will
provide a certain level of API compatibility. I'm not sure that we
really want to go that far.
Stefan
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@ant.apache.org
For additional commands, e-mail: dev-help@ant.apache.org