This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
patches for DeflaterOutputStream.java and ZipOutputStream.java
- To: java-patches at gcc dot gnu dot org
- Subject: patches for DeflaterOutputStream.java and ZipOutputStream.java
- From: Per Bothner <per at bothner dot com>
- Date: 30 Mar 2001 10:36:41 -0800
It is clear that there has been zero testing of ZipOutputStream.java,
since it contains numerous errors in the zip file format emitted.
The patches fixes the problems I found. It seems to work for at
least the case I've tested: a single uncompressed ("STORED") member.
When it comes to deflating with level 0 (no compression), I finally
got it so that the entire input file was written out, but pre-pended
with 5 extra bytes. My guess this is some zlib header that is
emitted even when doing no compression, but the logic of zlib is
convoluted enough I'm not sure. I finally concluded that when using
the STORED method we should by-pass zlib entirely - that is more
efficient anyway.
With the patch (plus the String patch I will check in soon), Kawa
builds *and* the entire Kawa testsuite runs correctly!
I'll give people a chance to comment before I check this in.
2001-03-30 Per Bothner <per@bothner.com>
* DeflaterOutputStream.java (deflate): Loop while def.needsInput.
(finish): def.deflate needs to be called in a loop.
(inbuf, inbufLength): New private fields.
(write(int)): Use inbuf.
(write(byte[],int,int): Check if pending output in inbuf.
* ZipOutputStream.java: Don't use Deflater if stored.
Use a Checksum object directly, not via a CheckedOutputStream.
(uncompressed_size): New field,
(closeEntry): Only write data_directory if needed.
(write): If STORED, write directly.
Always update crc, and uncompressed_size.
(write_entry): Fix lots of protocol erors.
Index: DeflaterOutputStream.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/zip/DeflaterOutputStream.java,v
retrieving revision 1.5
diff -u -r1.5 DeflaterOutputStream.java
--- DeflaterOutputStream.java 2000/11/17 21:42:28 1.5
+++ DeflaterOutputStream.java 2001/03/30 18:12:30
@@ -50,13 +50,13 @@
protected void deflate () throws IOException
{
- while (true)
+ do
{
int len = def.deflate(buf, 0, buf.length);
- if (len == 0 || len == -1)
- break;
- out.write(buf, 0, len);
- }
+ if (len > 0)
+ out.write(buf, 0, len);
+ }
+ while (! def.needsInput());
}
public DeflaterOutputStream (OutputStream out)
@@ -78,22 +78,52 @@
public void finish () throws IOException
{
+ if (inbufLength > 0)
+ {
+ def.setInput (inbuf, 0, inbufLength);
+ deflate ();
+ inbufLength = 0;
+ }
def.finish();
- deflate ();
+ while (! def.finished ())
+ {
+ int len = def.deflate(buf, 0, buf.length);
+ if (len > 0)
+ out.write(buf, 0, len);
+ }
}
public void write (int bval) throws IOException
{
- byte[] b = new byte[1];
- b[0] = (byte) bval;
- write (b, 0, 1);
+ if (inbuf == null)
+ {
+ inbuf = new byte[128];
+ }
+ else if (inbufLength == inbuf.length)
+ {
+ def.setInput (inbuf, 0, inbufLength);
+ deflate ();
+ inbufLength = 0;
+ }
+ inbuf[inbufLength++] = (byte) bval;
}
public void write (byte[] buf, int off, int len) throws IOException
{
+ if (inbufLength > 0)
+ {
+ def.setInput (inbuf, 0, inbufLength);
+ deflate ();
+ inbufLength = 0;
+ }
def.setInput (buf, off, len);
deflate ();
}
+
+ // Used, if needed, for write(int).
+ private byte[] inbuf;
+ // Used length of inbuf.
+ private int inbufLength;
// The retrieval buffer.
protected byte[] buf;
Index: ZipOutputStream.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/zip/ZipOutputStream.java,v
retrieving revision 1.8
diff -u -r1.8 ZipOutputStream.java
--- ZipOutputStream.java 2000/11/17 21:42:28 1.8
+++ ZipOutputStream.java 2001/03/30 18:12:31
@@ -47,37 +47,64 @@
public void closeEntry () throws IOException
{
- int uncompressed_size = def.getTotalIn();
- int compressed_size = def.getTotalOut();
- long crc = filter.getChecksum().getValue();
+ int compressed_size;
+ if (current.method == STORED)
+ {
+ compressed_size = uncompressed_size;
+ }
+ else
+ {
+ super.finish();
+ compressed_size = def.getTotalOut();
+ }
+ long crc = sum.getValue();
bytes_written += compressed_size;
- bytes_written += put4 (0x08074b50);
if (current.getCrc() == -1 || current.getCompressedSize() == -1
|| current.getSize() == -1)
{
current.setCrc(crc);
current.compressedSize = compressed_size;
current.setSize(uncompressed_size);
+ put4 (0x08074b50);
+ put4 ((int) (current.getCrc()));
+ put4 ((int) (current.getCompressedSize()));
+ put4 ((int) (current.getSize()));
+ bytes_written += 16;
}
- else
- {
- if (current.getCrc() != crc
- || current.getCompressedSize() != compressed_size
- || current.getSize() != uncompressed_size)
- throw new ZipException ("zip entry field incorrect");
- }
- bytes_written += put4 ((int) (current.getCrc()));
- bytes_written += put4 ((int) (current.getCompressedSize()));
- bytes_written += put4 ((int) (current.getSize()));
+ else if (current.getCrc() != crc
+ || current.getCompressedSize() != compressed_size
+ || current.getSize() != uncompressed_size)
+ throw new ZipException ("zip entry field incorrect");
current.next = chain;
chain = current;
current = null;
- filter = null;
}
+ public void write (int bval) throws IOException
+ {
+ if (current.method == STORED)
+ {
+ out.write(bval);
+ }
+ else
+ super.write(bval);
+ sum.update(bval);
+ uncompressed_size += 1;
+ }
+
+ public void write (byte[] buf, int off, int len) throws IOException
+ {
+ if (current.method == STORED)
+ out.write(buf, off, len);
+ else
+ super.write(buf, off, len);
+ sum.update(buf, off, len);
+ uncompressed_size += len;
+ }
+
public void finish () throws IOException
{
if (current != null)
@@ -101,21 +128,19 @@
// Another disk number.
put2 (0);
put2 (count);
+ put2 (count);
put4 (bytes);
put4 ((int) offset);
byte[] c = comment.getBytes("8859_1");
put2 (c.length);
out.write(c);
- out.write((byte) 0);
}
// Helper for finish and putNextEntry.
private int write_entry (ZipEntry entry, boolean is_local)
throws IOException
{
- long offset = bytes_written;
-
int bytes = put4 (is_local ? 0x04034b50 : 0x02014b50);
if (! is_local)
bytes += put_version ();
@@ -169,25 +194,22 @@
// Internal file attributes.
bytes += put2 (0);
// External file attributes.
- bytes += put2 (0);
+ bytes += put4 (0);
// Relative offset of local header.
- bytes += put2 ((int) offset);
+ bytes += put4 ((int) entry.relativeOffset);
}
out.write (name);
- out.write ((byte) 0);
- bytes += name.length + 1;
+ bytes += name.length;
if (entry.extra != null)
{
out.write(entry.extra);
- out.write((byte) 0);
- bytes += entry.extra.length + 1;
+ bytes += entry.extra.length;
}
if (comment != null)
{
out.write(comment);
- out.write((byte) 0);
- bytes += comment.length + 1;
+ bytes += comment.length;
}
bytes_written += bytes;
@@ -208,13 +230,13 @@
// Just in case.
entry.compressedSize = entry.getSize();
}
+ entry.relativeOffset = bytes_written;
write_entry (entry, true);
current = entry;
int compr = (method == STORED) ? Deflater.NO_COMPRESSION : level;
def.reset();
def.setLevel(compr);
- filter = new CheckedOutputStream (new DeflaterOutputStream (out, def),
- new CRC32 ());
+ sum.reset();
}
public void setLevel (int level)
@@ -240,18 +262,10 @@
this.comment = comment;
}
- public synchronized void write (byte[] buf, int off, int len)
- throws IOException
- {
- if (filter == null)
- throw new ZipException ("no open zip entry");
- filter.write(buf, off, len);
- }
-
public ZipOutputStream (OutputStream out)
{
- super (out);
- def = new Deflater (level, true);
+ super (out, new Deflater (Deflater.DEFAULT_COMPRESSION, true), 8192);
+ sum = new CRC32 ();
}
private int put2 (int i) throws IOException
@@ -282,14 +296,14 @@
private ZipEntry current;
// The chain of entries which have been written to this file.
private ZipEntry chain;
- // The output stream to which data should be sent.
- private CheckedOutputStream filter;
private int method = DEFLATED;
private int level = Deflater.DEFAULT_COMPRESSION;
private String comment = "";
private long bytes_written;
+
+ private int uncompressed_size;
- // The Deflater we use.
- private Deflater def;
+ /** The checksum object. */
+ private Checksum sum;
}
--
--Per Bothner
per@bothner.com http://www.bothner.com/~per/