diff options
author | Tom Tromey <tromey@cygnus.com> | 1999-05-18 15:33:03 +0000 |
---|---|---|
committer | Tom Tromey <tromey@gcc.gnu.org> | 1999-05-18 15:33:03 +0000 |
commit | 0ffac8322f8825c0d696d9c700b0d0f1a395d11a (patch) | |
tree | c538fe74824c64ba74944a357c354f0c77e93be5 /libjava/java/util | |
parent | 5a9e5c6fb6c140bd80a2986f1d537a250a62ea59 (diff) | |
download | gcc-0ffac8322f8825c0d696d9c700b0d0f1a395d11a.zip gcc-0ffac8322f8825c0d696d9c700b0d0f1a395d11a.tar.gz gcc-0ffac8322f8825c0d696d9c700b0d0f1a395d11a.tar.bz2 |
ZipOutputStream.java (level): Initial value is Deflater.DEFAULT_COMPRESSION.
* java/util/zip/ZipOutputStream.java (level): Initial value is
Deflater.DEFAULT_COMPRESSION.
(close): New method.
(closeEntry): Likewise.
(finish): Likewise.
(put_version): Likewise.
(write_entry): Likewise.
(put2, put4): Now return `int'.
(comment): Default to empty string.
(bytes_written): New instance variable.
(chain): Likewise.
* java/util/zip/ZipEntry.java (setComment): Limit length of
comment string.
(setCrc): Check CRC validity.
(setExtra): Check argument validity.
(setMethod): Likewise.
(setSize): Likewise.
(ZipEntry): Likewise.
* include/javaprims.h: Updated namespace declarations.
* Makefile.in: Rebuilt.
* Makefile.am (ordinary_java_source_files): Mention new files.
(nat_source_files): Likewise.
* java/util/zip/ZipFile.java (readu2): Throw ZipException, not
EOFException.
(read4): Likewise.
(getInputStream): Handle compressed entries.
* java/util/zip/GZIPOutputStream.java: New file.
* java/util/zip/GZIPInputStream.java: New file.
* java/util/zip/DataFormatException.java: New file.
* java/util/zip/CheckedInputStream.java: New file.
* java/util/zip/CheckedOutputStream.java: New file.
* java/util/zip/InflaterInputStream.java: Implemented.
* java/util/zip/natInflater.cc: New file.
* java/util/zip/Deflater.java: Implemented.
* java/util/zip/natDeflater.cc: New file.
* java/util/zip/DeflaterOutputStream.java: Implemented.
* java/util/zip/ZipInputStream.java (closeZipEntry): Throw
ZipException, not IOException.
* java/util/zip/ZipFile.java (readDirectory): Throw ZipException,
not IOException.
From-SVN: r26996
Diffstat (limited to 'libjava/java/util')
-rw-r--r-- | libjava/java/util/zip/CheckedInputStream.java | 80 | ||||
-rw-r--r-- | libjava/java/util/zip/CheckedOutputStream.java | 54 | ||||
-rw-r--r-- | libjava/java/util/zip/DataFormatException.java | 33 | ||||
-rw-r--r-- | libjava/java/util/zip/Deflater.java | 119 | ||||
-rw-r--r-- | libjava/java/util/zip/DeflaterOutputStream.java | 65 | ||||
-rw-r--r-- | libjava/java/util/zip/GZIPInputStream.java | 154 | ||||
-rw-r--r-- | libjava/java/util/zip/GZIPOutputStream.java | 88 | ||||
-rw-r--r-- | libjava/java/util/zip/Inflater.java | 101 | ||||
-rw-r--r-- | libjava/java/util/zip/InflaterInputStream.java | 90 | ||||
-rw-r--r-- | libjava/java/util/zip/ZipEntry.java | 44 | ||||
-rw-r--r-- | libjava/java/util/zip/ZipFile.java | 34 | ||||
-rw-r--r-- | libjava/java/util/zip/ZipInputStream.java | 4 | ||||
-rw-r--r-- | libjava/java/util/zip/ZipOutputStream.java | 263 | ||||
-rw-r--r-- | libjava/java/util/zip/natDeflater.cc | 209 | ||||
-rw-r--r-- | libjava/java/util/zip/natInflater.cc | 202 |
15 files changed, 1472 insertions, 68 deletions
diff --git a/libjava/java/util/zip/CheckedInputStream.java b/libjava/java/util/zip/CheckedInputStream.java new file mode 100644 index 0000000..a6a9058 --- /dev/null +++ b/libjava/java/util/zip/CheckedInputStream.java @@ -0,0 +1,80 @@ +// CheckedInputStream.java - Compute checksum of data being read. + +/* Copyright (C) 1999 Cygnus Solutions + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +package java.util.zip; + +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; + +/** + * @author Tom Tromey + * @date May 17, 1999 + */ + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + +public class CheckedInputStream extends FilterInputStream +{ + public CheckedInputStream (InputStream in, Checksum sum) + { + super (in); + this.sum = sum; + } + + public Checksum getChecksum () + { + return sum; + } + + public int read () throws IOException + { + int x = in.read(); + if (x != -1) + sum.update(x); + return x; + } + + public int read (byte[] buf, int off, int len) throws IOException + { + int r = in.read(buf, off, len); + if (r != -1) + sum.update(buf, off, r); + return r; + } + + public long skip (long n) throws IOException + { + if (n == 0) + return 0; + + int min = (int) Math.min(n, 1024); + byte[] buf = new byte[min]; + + long s = 0; + while (n > 0) + { + int r = in.read(buf, 0, min); + if (r == -1) + break; + n -= r; + s += r; + sum.update(buf, 0, r); + } + + return s; + } + + // The checksum object. + private Checksum sum; +} diff --git a/libjava/java/util/zip/CheckedOutputStream.java b/libjava/java/util/zip/CheckedOutputStream.java new file mode 100644 index 0000000..30dbc73 --- /dev/null +++ b/libjava/java/util/zip/CheckedOutputStream.java @@ -0,0 +1,54 @@ +// CheckedOutputStream.java - Compute checksum of data being written. + +/* Copyright (C) 1999 Cygnus Solutions + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +package java.util.zip; + +import java.io.FilterOutputStream; +import java.io.OutputStream; +import java.io.IOException; + +/** + * @author Tom Tromey + * @date May 17, 1999 + */ + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + +public class CheckedOutputStream extends FilterOutputStream +{ + public CheckedOutputStream (OutputStream out, Checksum cksum) + { + super (out); + this.sum = cksum; + } + + public Checksum getChecksum () + { + return sum; + } + + public void write (int bval) throws IOException + { + out.write(bval); + sum.update(bval); + } + + public void write (byte[] buf, int off, int len) throws IOException + { + out.write(buf, off, len); + sum.update(buf, off, len); + } + + // The checksum object. + private Checksum sum; +} diff --git a/libjava/java/util/zip/DataFormatException.java b/libjava/java/util/zip/DataFormatException.java new file mode 100644 index 0000000..258f47f --- /dev/null +++ b/libjava/java/util/zip/DataFormatException.java @@ -0,0 +1,33 @@ +// DataFormatException.java + +/* Copyright (C) 1999 Cygnus Solutions + + This file is part of libjava. + +This software is copyrighted work licensed under the terms of the +Libjava License. Please consult the file "LIBJAVA_LICENSE" for +details. */ + +package java.util.zip; + +/** + * @author Tom Tromey + * @date May 17, 1999 + */ + +/* Written using on-line Java Platform 1.2 API Specification. + * Believed complete and correct. + */ + +public class DataFormatException extends java.io.IOException +{ + public DataFormatException () + { + super(); + } + + public DataFormatException (String msg) + { + super(msg); + } +} diff --git a/libjava/java/util/zip/Deflater.java b/libjava/java/util/zip/Deflater.java index 81312e2..70855c5 100644 --- a/libjava/java/util/zip/Deflater.java +++ b/libjava/java/util/zip/Deflater.java @@ -1,3 +1,5 @@ +// Deflater.java - Compress a data stream. + /* Copyright (C) 1999 Cygnus Solutions This file is part of libgcj. @@ -8,6 +10,123 @@ details. */ package java.util.zip; +import gnu.gcj.RawData; + +/** + * @author Tom Tromey + * @date May 17, 1999 + */ + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + public class Deflater { + public static final int BEST_COMPRESSION = 9; + public static final int BEST_SPEED = 1; + public static final int DEFAULT_COMPRESSION = -1; + public static final int NO_COMPRESSION = 0; + + public static final int DEFAULT_STRATEGY = 0; + public static final int FILTERED = 1; + public static final int HUFFMAN_ONLY = 2; + + public static final int DEFLATED = 8; + + public int deflate (byte[] buf) + { + return deflate (buf, 0, buf.length); + } + + public native int deflate (byte[] buf, int off, int len); + public native void init (int level, boolean noHeader); + public native void update (); + + public Deflater () + { + this (DEFAULT_COMPRESSION, false); + } + + public Deflater (int lvl) + { + this (lvl, false); + } + + public Deflater (int lvl, boolean noHeader) + { + this.strategy = DEFAULT_STRATEGY; + init (lvl, noHeader); + setLevel (lvl); + } + + public native void end (); + + public void finalize () + { + end (); + } + + public native void finish (); + + public synchronized boolean finished () + { + return is_finished; + } + + public native int getAdler (); + public native int getTotalIn (); + public native int getTotalOut (); + public native boolean needsInput (); + public native void reset (); + + public void setDictionary (byte[] buf) + { + setDictionary (buf, 0, buf.length); + } + + public native void setDictionary (byte[] buf, int off, int len); + + public void setInput (byte[] buf) + { + setInput (buf, 0, buf.length); + } + + public native void setInput (byte[] buf, int off, int len); + + public synchronized void setLevel (int lvl) + { + if (lvl != -1 && (lvl < 0 || lvl > 9)) + throw new IllegalArgumentException (); + level = (lvl == -1) ? 6 : lvl; + update (); + } + + public synchronized void setStrategy (int stgy) + { + if (stgy != DEFAULT_STRATEGY && stgy != FILTERED + && stgy != HUFFMAN_ONLY) + throw new IllegalArgumentException (); + strategy = stgy; + update (); + } + + // Compression level. + private int level; + + // Compression strategy. + private int strategy; + + // The zlib stream. + private RawData zstream; + + // True if finished. + private boolean is_finished; + + // Total number of bytes made available at last setInput. + private int last_input_count; + + // `Flush' flag to pass to next call to deflate. + private int flush_flag; } diff --git a/libjava/java/util/zip/DeflaterOutputStream.java b/libjava/java/util/zip/DeflaterOutputStream.java index 4f0b8b4..ce5ae23 100644 --- a/libjava/java/util/zip/DeflaterOutputStream.java +++ b/libjava/java/util/zip/DeflaterOutputStream.java @@ -1,3 +1,5 @@ +// DeflaterOutputStream.java - Output filter for compressing. + /* Copyright (C) 1999 Cygnus Solutions This file is part of libgcj. @@ -7,40 +9,79 @@ Libgcj License. Please consult the file "LIBGCJ_LICENSE" for details. */ package java.util.zip; -import java.io.*; -/** JUST AN INCOMPLETE STUB! */ +import java.io.FilterOutputStream; +import java.io.OutputStream; +import java.io.IOException; + +/** + * @author Tom Tromey + * @date May 17, 1999 + */ + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ public class DeflaterOutputStream extends FilterOutputStream { - protected byte[] buf; + public void close () throws IOException + { + finish (); + out.close(); + } - protected Deflater def; + protected void deflate () throws IOException + { + while (true) + { + int len = def.deflate(buf, 0, buf.length); + if (len == 0 || len == -1) + break; + out.write(buf, 0, len); + } + } - public DeflaterOutputStream(OutputStream out) + public DeflaterOutputStream (OutputStream out) { - this(out, null, 512); + this (out, new Deflater (), 512); } - public DeflaterOutputStream(OutputStream out, Deflater defl) + public DeflaterOutputStream (OutputStream out, Deflater defl) { - this(out, defl, 512); + this (out, defl, 512); } public DeflaterOutputStream(OutputStream out, Deflater defl, int bufsize) { - super(out); + super (out); buf = new byte[bufsize]; def = defl; } public void finish () throws IOException { + def.finish(); + deflate (); } - public void close () throws IOException + public void write (int bval) throws IOException { - finish(); - out.close(); + byte[] b = new byte[1]; + b[0] = (byte) bval; + write (b, 0, 1); + } + + public void write (byte[] buf, int off, int len) throws IOException + { + def.setInput (buf, off, len); + deflate (); } + + // The retrieval buffer. + protected byte[] buf; + + // Deflater used to compress data. + protected Deflater def; } diff --git a/libjava/java/util/zip/GZIPInputStream.java b/libjava/java/util/zip/GZIPInputStream.java new file mode 100644 index 0000000..109ee82 --- /dev/null +++ b/libjava/java/util/zip/GZIPInputStream.java @@ -0,0 +1,154 @@ +// GZIPInputStream.java - Input tiler for reading gzip file. + +/* Copyright (C) 1999 Cygnus Solutions + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +package java.util.zip; + +import java.io.InputStream; +import java.io.IOException; + +/** + * @author Tom Tromey + * @date May 17, 1999 + */ + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + +public class GZIPInputStream extends InflaterInputStream +{ + public static final int GZIP_MAGIC = 0x8b1f; + + public void close () throws IOException + { + // Nothing to do here. + super.close(); + } + + public GZIPInputStream (InputStream istream) throws IOException + { + this (istream, 512); + } + + private final int eof_read () throws IOException + { + int r = in.read(); + if (r == -1) + throw new ZipException ("gzip header corrupted"); + return r & 0xff; + } + + public GZIPInputStream (InputStream istream, int readsize) + throws IOException + { + super (istream, new Inflater (true), readsize); + + // NOTE: header reading code taken from zlib's gzio.c. + + // Read the magic number. + int magic = eof_read () | (eof_read () << 8); + if (magic != GZIP_MAGIC) + throw new ZipException ("gzip header corrupted"); + + int method = eof_read (); + int flags = eof_read (); + // Test from zlib. + if (method != Z_DEFLATED || (flags & RESERVED) != 0) + throw new ZipException ("gzip header corrupted"); + + // Discard time, xflags, OS code. + for (int i = 0; i < 6; ++i) + eof_read (); + + // Skip the extra field. + if ((flags & EXTRA_FIELD) != 0) + { + int len = eof_read () | (eof_read () << 8); + while (len-- != 0) + eof_read (); + } + + if ((flags & ORIG_NAME) != 0) + { + while (true) + { + int c = eof_read (); + if (c == 0) + break; + } + } + + if ((flags & COMMENT) != 0) + { + while (true) + { + int c = eof_read (); + if (c == 0) + break; + } + } + + if ((flags & HEAD_CRC) != 0) + { + // FIXME: consider checking CRC of the header. + eof_read (); + eof_read (); + } + + crc = new CRC32 (); + } + + public int read (byte[] buf, int off, int len) throws IOException + { + if (eos) + return -1; + int r = super.read(buf, off, len); + if (r == -1) + { + eos = true; + int header_crc = read4 (); + if (crc.getValue() != header_crc) + throw new ZipException ("corrupted gzip file"); + // Read final `ISIZE' field. + // FIXME: should we check this length? + read4 (); + return -1; + } + crc.update(buf, off, r); + return r; + } + + private final int read4 () throws IOException + { + int byte0 = in.read(); + int byte1 = in.read(); + int byte2 = in.read(); + int byte3 = in.read(); + if (byte3 < 0) + throw new ZipException (".zip archive ended prematurely"); + return ((byte3 & 0xFF) << 24) + ((byte2 & 0xFF) << 16) + + ((byte1 & 0xFF) << 8) + (byte0 & 0xFF); + } + + // Checksum used by this input stream. + protected CRC32 crc; + + // Indicates whether end-of-stream has been reached. + protected boolean eos; + + // Some constants from zlib. + static final int Z_DEFLATED = 8; + static final int HEAD_CRC = 0x02; + static final int EXTRA_FIELD = 0x04; + static final int ORIG_NAME = 0x08; + static final int COMMENT = 0x10; + static final int RESERVED = 0xe0; +} diff --git a/libjava/java/util/zip/GZIPOutputStream.java b/libjava/java/util/zip/GZIPOutputStream.java new file mode 100644 index 0000000..1d93fd1 --- /dev/null +++ b/libjava/java/util/zip/GZIPOutputStream.java @@ -0,0 +1,88 @@ +// GZIPOutputStream.java - Create a file in gzip format. + +/* Copyright (C) 1999 Cygnus Solutions + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +package java.util.zip; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * @author Tom Tromey + * @date May 17, 1999 + */ + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + +public class GZIPOutputStream extends DeflaterOutputStream +{ + public void close () throws IOException + { + finish (); + out.close (); + } + + public void finish () throws IOException + { + super.finish(); + put4 ((int) crc.getValue()); + put4 (def.getTotalIn()); + } + + public GZIPOutputStream (OutputStream out) throws IOException + { + this (out, 512); + } + + public GZIPOutputStream (OutputStream out, int readsize) throws IOException + { + super (out, new Deflater (Deflater.DEFAULT_COMPRESSION, true), readsize); + + put2 (GZIPInputStream.GZIP_MAGIC); + out.write (GZIPInputStream.Z_DEFLATED); + // No flags for now. + out.write (0); + // No time either. + put2 (0); + put2 (0); + // No xflags either. + out.write (0); + // FIXME: unknown OS. + out.write (255); + + crc = new CRC32 (); + } + + public synchronized void write (byte[] buf, int off, int len) + throws IOException + { + super.write(buf, off, len); + crc.update(buf, off, len); + } + + private final void put2 (int i) throws IOException + { + out.write (i); + out.write (i >> 8); + } + + private final void put4 (int i) throws IOException + { + out.write (i); + out.write (i >> 8); + out.write (i >> 16); + out.write (i >> 24); + } + + // Checksum used by this stream. + protected CRC32 crc; +} diff --git a/libjava/java/util/zip/Inflater.java b/libjava/java/util/zip/Inflater.java new file mode 100644 index 0000000..724b5b4 --- /dev/null +++ b/libjava/java/util/zip/Inflater.java @@ -0,0 +1,101 @@ +// Inflater.java - Decompress a data stream. + +/* Copyright (C) 1999 Cygnus Solutions + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +package java.util.zip; + +import gnu.gcj.RawData; + +/** + * @author Tom Tromey + * @date May 17, 1999 + */ + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + +public class Inflater +{ + public native void end (); + + protected void finalize () + { + end (); + } + + public synchronized boolean finished () + { + return is_finished; + } + + public native int getAdler (); + public native int getRemaining (); + public native int getTotalIn (); + public native int getTotalOut (); + + public int inflate (byte[] buf) throws DataFormatException + { + return inflate (buf, 0, buf.length); + } + + public native int inflate (byte[] buf, int off, int len) + throws DataFormatException; + + private native void init (boolean noHeader); + + public Inflater () + { + this (false); + } + + public Inflater (boolean noHeader) + { + init (noHeader); + } + + public synchronized boolean needsDictionary () + { + return dict_needed; + } + + public synchronized boolean needsInput () + { + return getRemaining () == 0; + } + + public native void reset (); + + public void setDictionary (byte[] buf) + { + setDictionary (buf, 0, buf.length); + } + + public native void setDictionary (byte[] buf, int off, int len); + + public void setInput (byte[] buf) + { + setInput (buf, 0, buf.length); + } + + public native void setInput (byte[] buf, int off, int len); + + // The zlib stream. + private RawData zstream; + + // True if finished. + private boolean is_finished; + + // True if dictionary needed. + private boolean dict_needed; + + // Total number of bytes made available at last setInput. + private int last_input_count; +} diff --git a/libjava/java/util/zip/InflaterInputStream.java b/libjava/java/util/zip/InflaterInputStream.java index 1b6290a..7ee4455 100644 --- a/libjava/java/util/zip/InflaterInputStream.java +++ b/libjava/java/util/zip/InflaterInputStream.java @@ -1,3 +1,5 @@ +// InflaterInputStream.java - Input stream filter for decompressing. + /* Copyright (C) 1999 Cygnus Solutions This file is part of libgcj. @@ -7,14 +9,94 @@ Libgcj License. Please consult the file "LIBGCJ_LICENSE" for details. */ package java.util.zip; -import java.io.*; -/** Placefolder - very incomplete. */ +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; + +/** + * @author Tom Tromey + * @date May 17, 1999 + */ + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ public class InflaterInputStream extends FilterInputStream { - public InflaterInputStream(InputStream in) + protected void fill () throws IOException + { + len = in.read(buf, 0, buf.length); + if (len != -1) + inf.setInput(buf, 0, len); + } + + public InflaterInputStream (InputStream in) + { + this (in, new Inflater (), 512); + } + + public InflaterInputStream (InputStream in, Inflater infl) { - super(in); + this (in, infl, 512); } + + public InflaterInputStream (InputStream in, Inflater infl, int bufsize) + { + super (in); + this.inf = infl; + this.buf = new byte[bufsize]; + } + + public int read () throws IOException + { + byte[] buf = new byte[1]; + int r = read (buf, 0, 1); + if (r != -1) + r = buf[0] & 0xff; + return r; + } + + public int read (byte[] buf, int off, int len) throws IOException + { + if (inf.finished()) + return -1; + if (inf.needsInput()) + fill (); + if (inf.needsDictionary()) + return -1; + return inf.inflate(buf, off, len); + } + + public long skip (long n) throws IOException + { + if (n == 0) + return 0; + + int min = (int) Math.min(n, 1024); + byte[] buf = new byte[min]; + + long s = 0; + while (n > 0) + { + int r = read (buf, 0, min); + if (r == -1) + break; + n -= r; + s += r; + } + + return s; + } + + // Buffer for delivering uncompressed data to inflater. + protected byte[] buf; + + // Inflater used to decompress data. + protected Inflater inf; + + // Number of read bytes in buf. + protected int len; } diff --git a/libjava/java/util/zip/ZipEntry.java b/libjava/java/util/zip/ZipEntry.java index 9eb34ba..7035ab5 100644 --- a/libjava/java/util/zip/ZipEntry.java +++ b/libjava/java/util/zip/ZipEntry.java @@ -39,6 +39,10 @@ public class ZipEntry public ZipEntry (String name) { + if (name == null) + throw new NullPointerException (); + if (name.length() > 65535) + throw new IllegalArgumentException (); this.name = name; } @@ -69,17 +73,45 @@ public class ZipEntry return false; } - public void setComment (String comment) { this.comment = comment; } + public void setComment (String comment) + { + if (comment != null && comment.length() > 65535) + throw new IllegalArgumentException (); + this.comment = comment; + } - public void setCrc (long crc) { this.crc = crc; } + public void setCrc (long crc) + { + if (crc < 0 || crc > 0xffffffff) + throw new IllegalArgumentException (); + this.crc = crc; + } - public void setExtra (byte[] extra) { this.extra = extra; } + public void setExtra (byte[] extra) + { + if (extra != null && extra.length > 65535) + throw new IllegalArgumentException (); + this.extra = extra; + } - public void setMethod(int method) { this.method = method; } + public void setMethod (int method) + { + if (method != DEFLATED && method != STORED) + throw new IllegalArgumentException (); + this.method = method; + } - public void setSize (long size) { this.size = size; } + public void setSize (long size) + { + if (size < 0 || size > 0xffffffff) + throw new IllegalArgumentException (); + this.size = size; + } - public void setTime (long time) { this.time = time; } + public void setTime (long time) + { + this.time = time; + } private final static short[] daysToMonthStart = { //Jan Feb Mar Apr May Jun Jul diff --git a/libjava/java/util/zip/ZipFile.java b/libjava/java/util/zip/ZipFile.java index 9085ec9..bfb077d 100644 --- a/libjava/java/util/zip/ZipFile.java +++ b/libjava/java/util/zip/ZipFile.java @@ -1,3 +1,5 @@ +// ZipFile.java - Read contents of a ZIP file. + /* Copyright (C) 1999 Cygnus Solutions This file is part of libgcj. @@ -9,16 +11,13 @@ details. */ package java.util.zip; import java.io.*; -/** UNFINISHED, but can read non-comrepssed .zip archives. */ +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ public class ZipFile implements ZipConstants { - - ZipEntry entries; - int numEntries; - RandomAccessFile file; - String name; - public ZipFile (String fname) throws IOException { file = new RandomAccessFile(fname, "r"); @@ -35,7 +34,7 @@ public class ZipFile implements ZipConstants { long size = file.length (); if (size < ZipConstants.END_CENTRAL_DIR_SIZE) - throw new IOException ("zipfile too short"); + throw new ZipException ("zipfile too short"); // We do not handle a "zipfile comment", which the appnote says can // be at the end of a .zip file. We could handle this by seeking // to the beginning and reading forwards. @@ -44,7 +43,7 @@ public class ZipFile implements ZipConstants || file.read() != 'K' || file.read() != '\005' || file.read() != '\006') - throw new IOException("not a valid zipfile"); + throw new ZipException("not a valid zipfile"); file.skipBytes(6); numEntries = readu2(); int dir_size = read4 (); // Read "size of the central directory". @@ -103,7 +102,6 @@ public class ZipFile implements ZipConstants public void close() throws IOException { - // FIXME - check this file.close(); entries = null; numEntries = 0; @@ -121,14 +119,17 @@ public class ZipFile implements ZipConstants public InputStream getInputStream(ZipEntry ze) throws IOException { - // FIXME - does not handle compression! byte[] buffer = new byte[(int) ze.getSize()]; int data_offset = ZipConstants.LOCAL_FILE_HEADER_SIZE + name.length(); if (ze.extra != null) data_offset += ze.extra.length; file.seek(ze.relativeOffset + data_offset); file.readFully(buffer); - return new ByteArrayInputStream(buffer); + + InputStream is = new ByteArrayInputStream (buffer); + if (ze.getMethod() == ZipEntry.DEFLATED) + is = new InflaterInputStream (is); + return is; } public String getName () { return name; } @@ -138,7 +139,7 @@ public class ZipFile implements ZipConstants int byte0 = file.read(); int byte1 = file.read(); if (byte0 < 0 || byte1 < 0) - throw new EOFException(".zip archive ended prematurely"); + throw new ZipException (".zip archive ended prematurely"); return ((byte1 & 0xFF) << 8) | (byte0 & 0xFF); } @@ -149,10 +150,15 @@ public class ZipFile implements ZipConstants int byte2 = file.read(); int byte3 = file.read(); if (byte3 < 0) - throw new EOFException(".zip archive ended prematurely"); + throw new ZipException (".zip archive ended prematurely"); return ((byte3 & 0xFF) << 24) + ((byte2 & 0xFF) << 16) + ((byte1 & 0xFF) << 8) + (byte0 & 0xFF); } + + ZipEntry entries; + int numEntries; + RandomAccessFile file; + String name; } class ZipEnumeration implements java.util.Enumeration diff --git a/libjava/java/util/zip/ZipInputStream.java b/libjava/java/util/zip/ZipInputStream.java index 8512896..f2e042b 100644 --- a/libjava/java/util/zip/ZipInputStream.java +++ b/libjava/java/util/zip/ZipInputStream.java @@ -168,14 +168,14 @@ public class ZipInputStream extends InflaterInputStream { int sig = read4(); if (sig != 0x04034b50) - throw new IOException("bad/missing magic number at end of .zip entry"); + throw new ZipException("bad/missing magic number at end of .zip entry"); int crc = read4(); int compressedSize = read4(); int uncompressedSize = read4(); if (current.compressedSize != compressedSize || current.size != uncompressedSize || current.crc != crc) - throw new IOException("bad data descriptor at end of .zip entry"); + throw new ZipException("bad data descriptor at end of .zip entry"); } current = null; avail = 0; diff --git a/libjava/java/util/zip/ZipOutputStream.java b/libjava/java/util/zip/ZipOutputStream.java index 18f4d38..f4ce7ac 100644 --- a/libjava/java/util/zip/ZipOutputStream.java +++ b/libjava/java/util/zip/ZipOutputStream.java @@ -9,65 +9,268 @@ details. */ package java.util.zip; import java.io.*; -/** JUST AN INCOMPLETE STUB! */ +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { - ZipEntry current; - int method = DEFLATED; - int level = 3; // FIXME - should be DEFAULT_COMPRESSION - String comment; - public static final int STORED = 0; public static final int DEFLATED = 8; - public ZipOutputStream (OutputStream out) + public void close () throws IOException { - super(out); + finish (); + out.close(); + } + + public void closeEntry () throws IOException + { + int uncompressed_size = def.getTotalIn(); + int compressed_size = def.getTotalOut(); + int crc = (int) (filter.getChecksum().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); + } + 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())); + + current.next = chain; + chain = current; + current = null; + filter = null; + } + + public void finish () throws IOException + { + if (current != null) + closeEntry (); + + // Write the central directory. + long offset = bytes_written; + int count = 0; + int bytes = 0; + while (chain != null) + { + bytes += write_entry (chain, false); + ++count; + chain = chain.next; + } + + // Write the end of the central directory record. + put4 (0x06054b50); + // Disk number. + put2 (0); + // Another disk number. + put2 (0); + put2 (count); + put4 (bytes); + put4 ((int) offset); + + byte[] c = comment.getBytes("8859_1"); + put2 (c.length); + out.write(c); + out.write((byte) 0); } - public void setLevel (int level) { this.level = level; } - public void setMethod (int method) { this.method = method; } - public void setComment(String comment) { this.comment = comment; } + // 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 (); + bytes += put_version (); + + boolean crc_after = false; + if (is_local + && (current.getCrc() == -1 || current.getCompressedSize() == -1 + || current.getSize() == -1)) + crc_after = true; + // For the bits field we always indicate `normal' compression, + // even if that isn't true. + bytes += put2 (crc_after ? (1 << 3) : 0); + bytes += put2 (entry.method); + + bytes += put2(0); // time - FIXME + bytes += put2(0); // date - FIXME + + if (crc_after) + { + // CRC, compressedSize, and Size are always 0 in this header. + // The actual values are given after the entry. + bytes += put4 (0); + bytes += put4 (0); + bytes += put4 (0); + } + else + { + bytes += put4 ((int) (entry.getCrc())); + bytes += put4 ((int) (entry.getCompressedSize())); + bytes += put4 ((int) (entry.getSize())); + } + + byte[] name = entry.name.getBytes("8859_1"); + bytes += put2 (name.length); + bytes += put2 (entry.extra == null ? 0 : entry.extra.length); + + byte[] comment = null; + if (! is_local) + { + if (entry.getComment() == null) + bytes += put2 (0); + else + { + comment = entry.getComment().getBytes("8859_1"); + bytes += put2 (comment.length); + } + + // Disk number start. + bytes += put2 (0); + // Internal file attributes. + bytes += put2 (0); + // External file attributes. + bytes += put2 (0); + // Relative offset of local header. + bytes += put2 ((int) offset); + } + + out.write (name); + out.write ((byte) 0); + bytes += name.length + 1; + if (entry.extra != null) + { + out.write(entry.extra); + out.write((byte) 0); + bytes += entry.extra.length + 1; + } + if (comment != null) + { + out.write(comment); + out.write((byte) 0); + bytes += comment.length + 1; + } + + bytes_written += bytes; + return bytes; + } public void putNextEntry (ZipEntry entry) throws IOException { - put4(0x04034b50); - put2(0); // version - FIXME - put2(0); // bits - FIXME + if (current != null) + closeEntry (); + if (entry.method < 0 ) entry.method = method; - put2(entry.method); - put2(0); // time - FIXME - put2(0); // date - FIXME - put4((int) entry.crc); - put4((int) entry.compressedSize); // FIXME - put4((int) entry.size); // FIXME - put2(entry.name.length()); - put2(entry.extra == null ? 0 : entry.extra.length); - byte[] name = entry.name.getBytes("8859_1"); - out.write(name); - if (entry.extra != null) - out.write(entry.extra); - throw new Error ("java.util.zip.ZipOutputStream.putNextEntry: not implemented"); + if (entry.method == STORED) + { + if (entry.getSize() == -1 || entry.getCrc() == -1) + throw new ZipException ("required entry not set"); + // Just in case. + entry.compressedSize = entry.getSize(); + } + 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 ()); } - public void closeEntry () throws IOException + public void setLevel (int level) { + if (level != Deflater.DEFAULT_COMPRESSION + && (level < Deflater.NO_COMPRESSION + || level > Deflater.BEST_COMPRESSION)) + throw new IllegalArgumentException (); + this.level = level; } - private void put2 (int i) throws IOException + public void setMethod (int method) + { + if (method != DEFLATED && method != STORED) + throw new IllegalArgumentException (); + this.method = method; + } + + public void setComment (String comment) + { + if (comment.length() > 65535) + throw new IllegalArgumentException (); + 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); + } + + private int put2 (int i) throws IOException { out.write (i); out.write (i >> 8); + return 2; } - private void put4 (int i) throws IOException + private int put4 (int i) throws IOException { out.write (i); out.write (i >> 8); out.write (i >> 16); out.write (i >> 24); + return 4; } + + private int put_version () throws IOException + { + // FIXME: for now we assume Unix, and we ignore the version + // number. + return put2 (3 << 8); + } + + // The entry we are currently writing, or null if we've called + // closeEntry. + 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; + + // The Deflater we use. + private Deflater def; } diff --git a/libjava/java/util/zip/natDeflater.cc b/libjava/java/util/zip/natDeflater.cc new file mode 100644 index 0000000..07cf009 --- /dev/null +++ b/libjava/java/util/zip/natDeflater.cc @@ -0,0 +1,209 @@ +// natDeflater.cc - Implementation of Deflater native methods. + +/* Copyright (C) 1999 Cygnus Solutions + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +// Written by Tom Tromey <tromey@cygnus.com> + +#include <config.h> + +#include <zlib.h> + +#include <cni.h> +#include <jvm.h> + +#include <java/util/zip/Deflater.h> +#include <java/util/zip/DataFormatException.h> + +#include <java/lang/InternalError.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> + +extern void *_Jv_ZMalloc (void *, uInt nitems, uInt size); +extern void _Jv_ZFree (void *, void *addr); + + + +jint +java::util::zip::Deflater::deflate (jbyteArray buf, jint off, jint len) +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + + if (! buf) + _Jv_Throw (new java::lang::NullPointerException); + if (off < 0 || len < 0 || off + len > buf->length) + _Jv_Throw (new java::lang::ArrayIndexOutOfBoundsException); + + s->next_out = (Bytef *) (elements (buf) + off); + s->avail_out = len; + + switch (::deflate (s, flush_flag)) + { + case Z_STREAM_END: + is_finished = true; + if (s->avail_out == len) + return -1; + break; + + case Z_STREAM_ERROR: + case Z_BUF_ERROR: + // FIXME? + _Jv_Throw (new java::lang::InternalError); + break; + + case Z_OK: + break; + } + + return len - s->avail_out; +} + +void +java::util::zip::Deflater::end () +{ + JvSynchronize sync (this); + // Just ignore errors. + deflateEnd ((z_streamp) zstream); + _Jv_Free (zstream); + zstream = NULL; +} + +void +java::util::zip::Deflater::finish () +{ + JvSynchronize sync (this); + flush_flag = Z_FINISH; +} + +jint +java::util::zip::Deflater::getAdler () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + return s->adler; +} + +jint +java::util::zip::Deflater::getTotalIn () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + return s->total_in; +} + +jint +java::util::zip::Deflater::getTotalOut () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + return s->total_out; +} + +jboolean +java::util::zip::Deflater::needsInput () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + return s->avail_in - last_input_count == 0; +} + +void +java::util::zip::Deflater::reset () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + // Just ignore errors. + deflateReset (s); + flush_flag = 0; +} + +void +java::util::zip::Deflater::setDictionary (jbyteArray buf, jint off, jint len) +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + + if (! buf) + _Jv_Throw (new java::lang::NullPointerException); + if (off < 0 || len < 0 || off + len > buf->length) + _Jv_Throw (new java::lang::ArrayIndexOutOfBoundsException); + + // Ignore errors. + deflateSetDictionary (s, (Bytef *) (elements (buf) + off), len); +} + +void +java::util::zip::Deflater::setInput (jbyteArray buf, jint off, jint len) +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + + if (! buf) + _Jv_Throw (new java::lang::NullPointerException); + if (off < 0 || len < 0 || off + len > buf->length) + _Jv_Throw (new java::lang::ArrayIndexOutOfBoundsException); + + last_input_count = len; + s->next_in = (Bytef *) (elements (buf) + off); + s->avail_in = len; +} + +void +java::util::zip::Deflater::update () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + + int strat; + switch (strategy) + { + case DEFAULT_STRATEGY: + strat = Z_DEFAULT_STRATEGY; + break; + case FILTERED: + strat = Z_FILTERED; + break; + case HUFFMAN_ONLY: + strat = Z_HUFFMAN_ONLY; + break; + } + + // Ignore errors. + deflateParams (s, level, strat); +} + +void +java::util::zip::Deflater::init (jint level, jboolean no_header) +{ + z_stream_s *stream = (z_stream_s *) _Jv_Malloc (sizeof (z_stream_s)); + stream->next_in = Z_NULL; + stream->avail_in = 0; + stream->zalloc = _Jv_ZMalloc; + stream->zfree = _Jv_ZFree; + stream->opaque = NULL; + + // Handle NO_HEADER using undocumented zlib feature. + int wbits = MAX_WBITS; + if (no_header) + wbits = - wbits; + +#define DEFAULT_MEM_LEVEL 8 + if (deflateInit2 (stream, level, Z_DEFLATED, wbits, + DEFAULT_MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK) + { + jstring msg = NULL; + if (stream->msg != NULL) + msg = JvNewStringLatin1 (stream->msg); + _Jv_Throw (new java::lang::InternalError (msg)); + } + + zstream = reinterpret_cast<gnu::gcj::RawData *> (stream); + is_finished = false; + flush_flag = 0; +} diff --git a/libjava/java/util/zip/natInflater.cc b/libjava/java/util/zip/natInflater.cc new file mode 100644 index 0000000..b33ab50 --- /dev/null +++ b/libjava/java/util/zip/natInflater.cc @@ -0,0 +1,202 @@ +// natInflater.cc - Implementation of Inflater native methods. + +/* Copyright (C) 1999 Cygnus Solutions + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +// Written by Tom Tromey <tromey@cygnus.com> + +#include <config.h> + +#include <zlib.h> + +#include <cni.h> +#include <jvm.h> + +#include <java/util/zip/Inflater.h> +#include <java/util/zip/DataFormatException.h> + +#include <java/lang/InternalError.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/OutOfMemoryError.h> + + + +// A couple of helper functions used to interface with zlib's +// allocation. + +void * +_Jv_ZMalloc (void *, uInt nitems, uInt size) +{ + return _Jv_Malloc (nitems * size); +} + +void +_Jv_ZFree (void *, void *addr) +{ + _Jv_Free (addr); +} + + + +void +java::util::zip::Inflater::end () +{ + JvSynchronize sync (this); + // Just ignore errors. + inflateEnd ((z_streamp) zstream); + _Jv_Free (zstream); + zstream = NULL; +} + +jint +java::util::zip::Inflater::getAdler () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + return s->adler; +} + +jint +java::util::zip::Inflater::getRemaining () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + return s->avail_in - last_input_count; +} + +jint +java::util::zip::Inflater::getTotalIn () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + return s->total_in; +} + +jint +java::util::zip::Inflater::getTotalOut () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + return s->total_out; +} + +jint +java::util::zip::Inflater::inflate (jbyteArray buf, jint off, jint len) +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + + if (! buf) + _Jv_Throw (new java::lang::NullPointerException); + if (off < 0 || len < 0 || off + len > buf->length) + _Jv_Throw (new java::lang::ArrayIndexOutOfBoundsException); + + s->next_out = (Bytef *) (elements (buf) + off); + s->avail_out = len; + + switch (::inflate (s, Z_SYNC_FLUSH)) + { + case Z_STREAM_END: + is_finished = true; + if (s->avail_out == len) + return -1; + break; + + case Z_NEED_DICT: + dict_needed = true; + break; + + case Z_DATA_ERROR: + _Jv_Throw (new java::util::zip::DataFormatException); + break; + + case Z_MEM_ERROR: + _Jv_Throw (new java::lang::OutOfMemoryError); + break; + + case Z_BUF_ERROR: + // FIXME? + _Jv_Throw (new java::lang::InternalError); + break; + + case Z_OK: + break; + } + + return len - s->avail_out; +} + +void +java::util::zip::Inflater::reset () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + // Just ignore errors. + inflateReset (s); +} + +void +java::util::zip::Inflater::setDictionary (jbyteArray buf, jint off, jint len) +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + + if (! buf) + _Jv_Throw (new java::lang::NullPointerException); + if (off < 0 || len < 0 || off + len > buf->length) + _Jv_Throw (new java::lang::ArrayIndexOutOfBoundsException); + + // Ignore errors. + inflateSetDictionary (s, (Bytef *) (elements (buf) + off), len); + dict_needed = false; +} + +void +java::util::zip::Inflater::setInput (jbyteArray buf, jint off, jint len) +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + + if (! buf) + _Jv_Throw (new java::lang::NullPointerException); + if (off < 0 || len < 0 || off + len > buf->length) + _Jv_Throw (new java::lang::ArrayIndexOutOfBoundsException); + + last_input_count = len; + s->next_in = (Bytef *) (elements (buf) + off); + s->avail_in = len; +} + +void +java::util::zip::Inflater::init (jboolean no_header) +{ + z_stream_s *stream = (z_stream_s *) _Jv_Malloc (sizeof (z_stream_s)); + stream->next_in = Z_NULL; + stream->avail_in = 0; + stream->zalloc = _Jv_ZMalloc; + stream->zfree = _Jv_ZFree; + stream->opaque = NULL; + + // Handle NO_HEADER using undocumented zlib feature. + int wbits = MAX_WBITS; + if (no_header) + wbits = - wbits; + + if (inflateInit2 (stream, wbits) != Z_OK) + { + jstring msg = NULL; + if (stream->msg != NULL) + msg = JvNewStringLatin1 (stream->msg); + _Jv_Throw (new java::lang::InternalError (msg)); + } + + zstream = reinterpret_cast<gnu::gcj::RawData *> (stream); + is_finished = false; + dict_needed = false; +} |