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