? christiandiffs01 ? jazzlibDiffsSince20040511 ? jazzlib_christian_01.zip ? jazzlibpatch001 ? net-0.08.diff ? java/util/zip/CRC32If.java ? java/util/zip/DeflaterIf.java ? java/util/zip/InflaterIf.java ? java/util/zip/back ? java/util/zip/diffs08 ? lib/net ? lib/jazzlib/dist Index: java/util/zip/Adler32.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/zip/Adler32.java,v retrieving revision 1.5 diff -u -r1.5 Adler32.java --- java/util/zip/Adler32.java 22 Jan 2002 22:27:02 -0000 1.5 +++ java/util/zip/Adler32.java 4 May 2005 02:16:28 -0000 @@ -152,6 +152,19 @@ update(buffer, 0, buffer.length); } + /** Calculated this value like this: + * + * + * static { + * int i=0, a=BASE, b=a; + * for(;b>0;i++) + * b += (a += 255); + * System.out.println("max defer = " + (i-1)); + } + */ + + private final static int DEFER = 3850; + /** * Updates the checksum with the bytes taken from the array. * @@ -161,37 +174,18 @@ */ public void update (byte[] buf, int off, int len) { - //(By Per Bothner) - int s1 = checksum & 0xffff; - int s2 = checksum >>> 16; + int s1 = checksum & 0xffff; + int s2 = checksum >>> 16; - while (len > 0) - { - // We can defer the modulo operation: - // s1 maximally grows from 65521 to 65521 + 255 * 3800 - // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31 - int n = 3800; - if (n > len) - n = len; - len -= n; - while (--n >= 0) - { - s1 = s1 + (buf[off++] & 0xFF); - s2 = s2 + s1; + while (off < len) { + int max = Math.min(off + DEFER, len); + while (off < max) { + s1 = (buf[off++] & 0xff) + s1; + s2 += s1; } - s1 %= BASE; - s2 %= BASE; + s1 %= BASE; + s2 %= BASE; } - - /*Old implementation, borrowed from somewhere: - int n; - - while (len-- > 0) { - - s1 = (s1 + (bs[offset++] & 0xff)) % BASE; - s2 = (s2 + s1) % BASE; - }*/ - checksum = (s2 << 16) | s1; } Index: java/util/zip/CRC32.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/zip/CRC32.java,v retrieving revision 1.4 diff -u -r1.4 CRC32.java --- java/util/zip/CRC32.java 22 Jan 2002 22:27:02 -0000 1.4 +++ java/util/zip/CRC32.java 4 May 2005 02:16:28 -0000 @@ -57,7 +57,7 @@ * @author Per Bothner * @date April 1, 1999. */ -public class CRC32 implements Checksum +public class CRC32 implements CRC32If { /** The crc data checksum so far. */ private int crc = 0; Index: java/util/zip/Deflater.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/zip/Deflater.java,v retrieving revision 1.5 diff -u -r1.5 Deflater.java --- java/util/zip/Deflater.java 29 Apr 2004 15:47:26 -0000 1.5 +++ java/util/zip/Deflater.java 4 May 2005 02:16:29 -0000 @@ -48,48 +48,8 @@ * @author Jochen Hoenicke * @author Tom Tromey */ -public class Deflater +public class Deflater implements DeflaterIf { - /** - * The best and slowest compression level. This tries to find very - * long and distant string repetitions. - */ - public static final int BEST_COMPRESSION = 9; - /** - * The worst but fastest compression level. - */ - public static final int BEST_SPEED = 1; - /** - * The default compression level. - */ - public static final int DEFAULT_COMPRESSION = -1; - /** - * This level won't compress at all but output uncompressed blocks. - */ - public static final int NO_COMPRESSION = 0; - - /** - * The default strategy. - */ - public static final int DEFAULT_STRATEGY = 0; - /** - * This strategy will only allow longer string repetitions. It is - * useful for random data with a small character set. - */ - public static final int FILTERED = 1; - - /** - * This strategy will not look for string repetitions at all. It - * only encodes with Huffman trees (which means, that more common - * characters get a smaller encoding. - */ - public static final int HUFFMAN_ONLY = 2; - - /** - * The compression method. This is the only method supported so far. - * There is no need to use this constant at all. - */ - public static final int DEFLATED = 8; /* * The Deflater can do the following state transitions: Index: java/util/zip/DeflaterEngine.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/zip/DeflaterEngine.java,v retrieving revision 1.7 diff -u -r1.7 DeflaterEngine.java --- java/util/zip/DeflaterEngine.java 22 Oct 2004 18:02:06 -0000 1.7 +++ java/util/zip/DeflaterEngine.java 4 May 2005 02:16:30 -0000 @@ -221,7 +221,7 @@ } } - private void updateHash() { + private final void updateHash() { if (DEBUGGING) System.err.println("updateHash: "+strstart); ins_h = (window[strstart] << HASH_SHIFT) ^ window[strstart + 1]; Index: java/util/zip/DeflaterHuffman.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/zip/DeflaterHuffman.java,v retrieving revision 1.5 diff -u -r1.5 DeflaterHuffman.java --- java/util/zip/DeflaterHuffman.java 22 Oct 2004 18:02:06 -0000 1.5 +++ java/util/zip/DeflaterHuffman.java 4 May 2005 02:16:30 -0000 @@ -59,7 +59,7 @@ private static final int[] BL_ORDER = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; - private static String bit4Reverse = + private final static String bit4Reverse = "\000\010\004\014\002\012\006\016\001\011\005\015\003\013\007\017"; class Tree { Index: java/util/zip/DeflaterOutputStream.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/zip/DeflaterOutputStream.java,v retrieving revision 1.8 diff -u -r1.8 DeflaterOutputStream.java --- java/util/zip/DeflaterOutputStream.java 20 Oct 2004 08:08:52 -0000 1.8 +++ java/util/zip/DeflaterOutputStream.java 4 May 2005 02:16:31 -0000 @@ -1,5 +1,5 @@ /* DeflaterOutputStream.java - Output filter for compressing. - Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2001, 2004, 2005 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -70,7 +70,7 @@ /** * The deflater which is used to deflate the stream. */ - protected Deflater def; + protected final DeflaterIf def; /** * Deflates everything in the def's input buffers. This will call @@ -100,7 +100,7 @@ */ public DeflaterOutputStream(OutputStream out) { - this(out, new Deflater(), 512); + this(out, new Deflater(), 4096); } /** @@ -109,9 +109,9 @@ * @param out the output stream where deflated output should be written. * @param defl the underlying deflater. */ - public DeflaterOutputStream(OutputStream out, Deflater defl) + public DeflaterOutputStream(OutputStream out, DeflaterIf def) { - this(out, defl, 512); + this(out, def, 4096); } /** @@ -122,13 +122,13 @@ * @param bufsize the buffer size. * @exception IllegalArgumentException if bufsize isn't positive. */ - public DeflaterOutputStream(OutputStream out, Deflater defl, int bufsize) + public DeflaterOutputStream(OutputStream out, DeflaterIf def, int bufsize) { super(out); if (bufsize <= 0) throw new IllegalArgumentException("bufsize <= 0"); buf = new byte[bufsize]; - def = defl; + this.def = def; } /** @@ -137,12 +137,12 @@ * flushed. This function doesn't work in Sun's JDK, but only in * jazzlib. */ - public void flush() throws IOException + /*public void flush() throws IOException { def.flush(); deflate(); out.flush(); - } + }*/ /** * Finishes the stream by calling finish() on the deflater. This Index: java/util/zip/Inflater.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/zip/Inflater.java,v retrieving revision 1.6 diff -u -r1.6 Inflater.java --- java/util/zip/Inflater.java 22 May 2003 07:22:39 -0000 1.6 +++ java/util/zip/Inflater.java 4 May 2005 02:16:32 -0000 @@ -66,7 +66,7 @@ * @date May 17, 1999 * @since JDK 1.1 */ -public class Inflater +public class Inflater implements InflaterIf { /* Copy lengths for literal codes 257..285 */ private static final int CPLENS[] = @@ -266,7 +266,7 @@ * returns 0, you should check, whether needsDictionary(), * needsInput() or finished() returns true, to determine why no * further output is produced. - * @param buffer the output buffer. + * @param buf the output buffer. * @return the number of bytes written to the buffer, 0 if no further * output can be produced. * @exception DataFormatException if deflated stream is invalid. @@ -282,7 +282,7 @@ * returns 0, you should check, whether needsDictionary(), * needsInput() or finished() returns true, to determine why no * further output is produced. - * @param buffer the output buffer. + * @param buf the output buffer. * @param off the offset into buffer where the output should start. * @param len the maximum length of the output. * @return the number of bytes written to the buffer, 0 if no further @@ -406,7 +406,7 @@ /** * Sets the input. This should only be called, if needsInput() * returns true. - * @param buffer the input. + * @param buf the input. * @exception IllegalStateException if no input is needed. */ public void setInput (byte[] buf) @@ -417,7 +417,7 @@ /** * Sets the input. This should only be called, if needsInput() * returns true. - * @param buffer the input. + * @param buf the input. * @param off the offset into buffer where the input starts. * @param len the length of the input. * @exception IllegalStateException if no input is needed. Index: java/util/zip/InflaterInputStream.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/zip/InflaterInputStream.java,v retrieving revision 1.16 diff -u -r1.16 InflaterInputStream.java --- java/util/zip/InflaterInputStream.java 23 Nov 2004 13:03:42 -0000 1.16 +++ java/util/zip/InflaterInputStream.java 4 May 2005 02:16:32 -0000 @@ -1,5 +1,5 @@ /* InflaterInputStream.java - Input stream filter for decompressing - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -59,7 +59,7 @@ /** * Decompressor for this filter */ - protected Inflater inf; + protected final InflaterIf inf; /** * Byte array used as a buffer @@ -93,7 +93,7 @@ * @param in the InputStream to read bytes from * @param inf the decompressor used to decompress data read from in */ - public InflaterInputStream(InputStream in, Inflater inf) + public InflaterInputStream(InputStream in, InflaterIf inf) { this(in, inf, 4096); } @@ -106,7 +106,7 @@ * @param inf the decompressor used to decompress data read from in * @param size size of the buffer to use */ - public InflaterInputStream(InputStream in, Inflater inf, int size) + public InflaterInputStream(InputStream in, InflaterIf inf, int size) { super(in); @@ -115,8 +115,7 @@ if (inf == null) throw new NullPointerException("inf may not be null"); if (size < 0) - throw new IllegalArgumentException("size may not be negative"); - + throw new IllegalArgumentException("size may not be negative"); this.inf = inf; this.buf = new byte [size]; } @@ -195,7 +194,7 @@ { count = inf.inflate(b, off, len); } - catch (DataFormatException dfe) + catch (Exception dfe) // Hack for compatibility with InflaterIf { throw new ZipException(dfe.getMessage()); } Index: java/util/zip/OutputWindow.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/zip/OutputWindow.java,v retrieving revision 1.5 diff -u -r1.5 OutputWindow.java --- java/util/zip/OutputWindow.java 22 Oct 2004 18:02:06 -0000 1.5 +++ java/util/zip/OutputWindow.java 4 May 2005 02:16:32 -0000 @@ -63,7 +63,7 @@ window_end &= WINDOW_MASK; } - private void slowRepeat(int rep_start, int len, int dist) + private final void slowRepeat(int rep_start, int len, int dist) { while (len-- > 0) { Index: java/util/zip/ZipConstants.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/zip/ZipConstants.java,v retrieving revision 1.5 diff -u -r1.5 ZipConstants.java --- java/util/zip/ZipConstants.java 4 Nov 2003 10:04:16 -0000 1.5 +++ java/util/zip/ZipConstants.java 4 May 2005 02:16:32 -0000 @@ -39,9 +39,16 @@ interface ZipConstants { + /** + * The default character set used for entry names and comments in a ZIP + * or JAR file. This is UTF-8 for compatibility with Sun's java.util.zip + * package. + */ + String DEFAULT_CHARSET = "UTF-8"; + /* The local file header */ int LOCHDR = 30; - int LOCSIG = 'P'|('K'<<8)|(3<<16)|(4<<24); + long LOCSIG = 'P'|('K'<<8)|(3<<16)|(4<<24); int LOCVER = 4; int LOCFLG = 6; @@ -54,7 +61,7 @@ int LOCEXT = 28; /* The Data descriptor */ - int EXTSIG = 'P'|('K'<<8)|(7<<16)|(8<<24); + long EXTSIG = 'P'|('K'<<8)|(7<<16)|(8<<24); int EXTHDR = 16; int EXTCRC = 4; @@ -62,7 +69,7 @@ int EXTLEN = 12; /* The central directory file header */ - int CENSIG = 'P'|('K'<<8)|(1<<16)|(2<<24); + long CENSIG = 'P'|('K'<<8)|(1<<16)|(2<<24); int CENHDR = 46; int CENVEM = 4; @@ -82,7 +89,7 @@ int CENOFF = 42; /* The entries in the end of central directory */ - int ENDSIG = 'P'|('K'<<8)|(5<<16)|(6<<24); + long ENDSIG = 'P'|('K'<<8)|(5<<16)|(6<<24); int ENDHDR = 22; /* The following two fields are missing in SUN JDK */ Index: java/util/zip/ZipEntry.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/zip/ZipEntry.java,v retrieving revision 1.17 diff -u -r1.17 ZipEntry.java --- java/util/zip/ZipEntry.java 5 Jan 2005 20:47:53 -0000 1.17 +++ java/util/zip/ZipEntry.java 4 May 2005 02:16:33 -0000 @@ -48,29 +48,29 @@ * needs an instance of this class to create a new member. * * @author Jochen Hoenicke + * @author Christian Schlichtherle Fixed some bugs: Noteably the 2 GB Bug, so + * that Jazzlib now supports 4 GB which is the maximum with the ZIP32 + * format. Second the date/time bug, which made it impossible to use + * getTime(). Minor performance enhancements are also implemented. */ + public class ZipEntry implements ZipConstants, Cloneable { - private static final int KNOWN_SIZE = 1; - private static final int KNOWN_CSIZE = 2; - private static final int KNOWN_CRC = 4; - private static final int KNOWN_TIME = 8; private static final int KNOWN_EXTRA = 16; private static Calendar cal; private String name; - private int size; - private long compressedSize = -1; - private int crc; - private int dostime; - private short known = 0; - private short method = -1; - private byte[] extra = null; - private String comment = null; - - int flags; /* used by ZipOutputStream */ - int offset; /* used by ZipFile and ZipOutputStream */ + private long size = -1; + private long csize = -1; + private long crc = -1; + private long dostime = -1; + private int method = -1; + private byte[] extra; + private String comment; + + int flags; + long offset; /** * Compression method. This method doesn't compress at all. @@ -92,7 +92,7 @@ public ZipEntry(String name) { int length = name.length(); - if (length > 65535) + if (length > 0xffff) throw new IllegalArgumentException("name length is " + length); this.name = name; } @@ -109,9 +109,8 @@ ZipEntry(ZipEntry e, String name) { this.name = name; - known = e.known; size = e.size; - compressedSize = e.compressedSize; + csize = e.csize; crc = e.crc; dostime = e.dostime; method = e.method; @@ -119,25 +118,8 @@ comment = e.comment; } - final void setDOSTime(int dostime) - { - this.dostime = dostime; - known |= KNOWN_TIME; - } - - final int getDOSTime() - { - if ((known & KNOWN_TIME) == 0) - return 0; - else - return dostime; - } - - /** - * Creates a copy of this zip entry. - */ /** - * Clones the entry. + * Creates a clone of this zip entry. */ public Object clone() { @@ -155,6 +137,18 @@ } } + final void setDOSTime(long dostime) + { + if(dostime > 0xffffffffL) + throw new IllegalArgumentException(); + this.dostime = dostime; + } + + final long getDOSTime() + { + return dostime; + } + /** * Returns the entry name. The path components in the entry are * always separated by slashes ('/'). @@ -173,7 +167,7 @@ Calendar cal = getCalendar(); synchronized (cal) { - cal.setTime(new Date(time)); + cal.setTimeInMillis(time); dostime = (cal.get(Calendar.YEAR) - 1980 & 0x7f) << 25 | (cal.get(Calendar.MONTH) + 1) << 21 | (cal.get(Calendar.DAY_OF_MONTH)) << 16 @@ -181,7 +175,6 @@ | (cal.get(Calendar.MINUTE)) << 5 | (cal.get(Calendar.SECOND)) >> 1; } - this.known |= KNOWN_TIME; } /** @@ -190,34 +183,25 @@ */ public long getTime() { - if ((known & KNOWN_TIME) == 0) - return -1; + if (dostime == -1) + return -1; // The extra bytes might contain the time (posix/unix extension) parseExtra (); - int sec = 2 * (dostime & 0x1f); - int min = (dostime >> 5) & 0x3f; - int hrs = (dostime >> 11) & 0x1f; - int day = (dostime >> 16) & 0x1f; - int mon = ((dostime >> 21) & 0xf) - 1; - int year = ((dostime >> 25) & 0x7f) + 1980; /* since 1900 */ + int sec = (int) (2 * (dostime & 0x1f)); + int min = (int) ((dostime >> 5) & 0x3f); + int hrs = (int) ((dostime >> 11) & 0x1f); + int day = (int) ((dostime >> 16) & 0x1f); + int mon = (int) (((dostime >> 21) & 0xf) - 1); + int year = (int) (((dostime >> 25) & 0x7f) + 1980); /* since 1900 */ - try - { - cal = getCalendar(); - synchronized (cal) + Calendar cal = getCalendar(); + synchronized (cal) { cal.set(year, mon, day, hrs, min, sec); - return cal.getTime().getTime(); + return cal.getTimeInMillis(); } - } - catch (RuntimeException ex) - { - /* Ignore illegal time stamp */ - known &= ~KNOWN_TIME; - return -1; - } } private static synchronized Calendar getCalendar() @@ -234,10 +218,9 @@ */ public void setSize(long size) { - if ((size & 0xffffffff00000000L) != 0) + if (size > 0xffffffffL) throw new IllegalArgumentException(); - this.size = (int) size; - this.known |= KNOWN_SIZE; + this.size = size; } /** @@ -246,7 +229,7 @@ */ public long getSize() { - return (known & KNOWN_SIZE) != 0 ? size & 0xffffffffL : -1L; + return size; } /** @@ -254,7 +237,9 @@ */ public void setCompressedSize(long csize) { - this.compressedSize = csize; + if(csize > 0xffffffffL) + throw new IllegalArgumentException(); + this.csize = csize; } /** @@ -263,7 +248,7 @@ */ public long getCompressedSize() { - return compressedSize; + return csize; } /** @@ -272,10 +257,9 @@ */ public void setCrc(long crc) { - if ((crc & 0xffffffff00000000L) != 0) + if (crc > 0xffffffffL) throw new IllegalArgumentException(); - this.crc = (int) crc; - this.known |= KNOWN_CRC; + this.crc = crc; } /** @@ -284,7 +268,7 @@ */ public long getCrc() { - return (known & KNOWN_CRC) != 0 ? crc & 0xffffffffL : -1L; + return crc; } /** @@ -299,7 +283,7 @@ if (method != ZipOutputStream.STORED && method != ZipOutputStream.DEFLATED) throw new IllegalArgumentException(); - this.method = (short) method; + this.method = method; } /** @@ -329,6 +313,7 @@ private void parseExtra() { + /* // Already parsed? if ((known & KNOWN_EXTRA) != 0) return; @@ -350,7 +335,6 @@ | (extra[pos++] & 0xff) << 8; if (sig == 0x5455) { - /* extended time stamp */ int flags = extra[pos]; if ((flags & 1) != 0) { @@ -360,17 +344,18 @@ | (extra[pos+4] & 0xff) << 24); setTime(time); } - } + } pos += len; } } catch (ArrayIndexOutOfBoundsException ex) { - /* be lenient */ + return; } known |= KNOWN_EXTRA; +*/ } /** Index: java/util/zip/ZipException.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/zip/ZipException.java,v retrieving revision 1.8 diff -u -r1.8 ZipException.java --- java/util/zip/ZipException.java 24 Feb 2002 04:25:17 -0000 1.8 +++ java/util/zip/ZipException.java 4 May 2005 02:16:33 -0000 @@ -1,5 +1,5 @@ /* ZipException.java - exception representing a zip related error - Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005 Free Software Foundation, Inc. This file is part of GNU Classpath. Index: java/util/zip/ZipFile.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/zip/ZipFile.java,v retrieving revision 1.22 diff -u -r1.22 ZipFile.java --- java/util/zip/ZipFile.java 10 Feb 2005 02:43:17 -0000 1.22 +++ java/util/zip/ZipFile.java 4 May 2005 02:16:35 -0000 @@ -39,8 +39,6 @@ package java.util.zip; -import gnu.java.util.EmptyEnumeration; - import java.io.BufferedInputStream; import java.io.DataInput; import java.io.EOFException; @@ -48,9 +46,11 @@ import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; +import java.io.UnsupportedEncodingException; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; +import java.util.NoSuchElementException; /** * This class represents a Zip archive. You can ask for the contained @@ -62,6 +62,13 @@ * * @author Jochen Hoenicke * @author Artur Biesiadowski + * @author Christian Schlichtherle Added new constructors to support different + * character sets used to encode international entry names and comments. + * Added parameter to getInputStream to support different Inflater + * implementations. + * Fixed some bugs: Noteably the 2 GB Bug, so that Jazzlib now + * supports 4 GB which is the maximum with the ZIP32 format. + * Minor performance enhancements are also implemented. */ public class ZipFile implements ZipConstants { @@ -82,84 +89,142 @@ // File from which zip entries are read. private final RandomAccessFile raf; - // The entries of this zip file when initialized and not yet closed. - private HashMap entries; - + private final String charSet; + private final HashMap entries; private boolean closed = false; /** - * Opens a Zip file with the given name for reading. - * @exception IOException if a i/o error occured. - * @exception ZipException if the file doesn't contain a valid zip - * archive. + * Opens the given ZIP or JAR file. + * + * @exception IOException If a i/o error occured. + * @exception ZipException If the file doesn't contain a valid ZIP or JAR + * archive. */ - public ZipFile(String name) throws ZipException, IOException + public ZipFile(final String name) throws ZipException, IOException { - this.raf = new RandomAccessFile(name, "r"); - this.name = name; - checkZipFile(); + this(new File(name), OPEN_READ, DEFAULT_CHARSET); } /** - * Opens a Zip file reading the given File. - * @exception IOException if a i/o error occured. - * @exception ZipException if the file doesn't contain a valid zip - * archive. + * Opens the given ZIP or JAR file. + * + * @exception IOException If an i/o error occured. + * @exception ZipException If the file doesn't contain a valid ZIP or JAR + * archive. */ public ZipFile(File file) throws ZipException, IOException { - this.raf = new RandomAccessFile(file, "r"); - this.name = file.getPath(); - checkZipFile(); + this(file, OPEN_READ, DEFAULT_CHARSET); } /** - * Opens a Zip file reading the given File in the given mode. - * - * If the OPEN_DELETE mode is specified, the zip file will be deleted at - * some time moment after it is opened. It will be deleted before the zip - * file is closed or the Virtual Machine exits. - * - * The contents of the zip file will be accessible until it is closed. + * Opens the given ZIP or JAR file in the given mode. + *
+ * If the OPEN_DELETE mode is specified, the ZIP or JAR file will be deleted + * at some time after it has been opened and before it is closed or the + * Virtual Machine exits. + *
+ * Note:The OPEN_DELETE mode is currently unimplemented in this + * library. * * @since JDK1.3 - * @param mode Must be one of OPEN_READ or OPEN_READ | OPEN_DELETE + * @param mode Must be one of OPEN_READ or OPEN_READ | OPEN_DELETE. * - * @exception IOException if a i/o error occured. - * @exception ZipException if the file doesn't contain a valid zip - * archive. + * @exception IOException If an i/o error occured. + * @exception ZipException If the file doesn't contain a valid ZIP or JAR + * archive. */ - public ZipFile(File file, int mode) throws ZipException, IOException + public ZipFile(File file, final int mode) throws ZipException, IOException { - if (mode != OPEN_READ && mode != (OPEN_READ | OPEN_DELETE)) - throw new IllegalArgumentException("invalid mode"); - if ((mode & OPEN_DELETE) != 0) - file.deleteOnExit(); - this.raf = new RandomAccessFile(file, "r"); - this.name = file.getPath(); - checkZipFile(); + this(file, mode, DEFAULT_CHARSET); } - private void checkZipFile() throws IOException, ZipException + /** + * Opens a Zip file with the given name for reading. + *
+ * Note: This constructor is not part of the JDK API! + * + * @param charSet The character set to use for entry names and comments. + * + * @exception IOException If an i/o error occured. + * @exception ZipException If the file doesn't contain a valid ZIP or JAR + * archive. + */ + public ZipFile(final String name, final String charSet) + throws ZipException, IOException, UnsupportedEncodingException { + this(new File(name), OPEN_READ, charSet); + } + + /** + * Opens a Zip file reading the given File. + *
+ * Note: This constructor is not part of the JDK API! + * + * @param charSet The character set to use for entry names and comments. + * + * @exception IOException If an i/o error occured. + * @exception ZipException If the file doesn't contain a valid ZIP or JAR + * archive. + */ + public ZipFile(final File file, final String charSet) + throws ZipException, IOException, UnsupportedEncodingException { + this(file, OPEN_READ, charSet); + } + + /** + * Opens the given ZIP or JAR file in the given mode. + *
+ * If the OPEN_DELETE mode is specified, the ZIP or JAR file will be deleted + * at some time after it has been opened and before it is closed or the + * Virtual Machine exits. + *
+ * Note:The OPEN_DELETE mode is currently unimplemented in this + * library. + *
+ * Note: This constructor is not part of the JDK API!
+ *
+ * @param mode Must be one of OPEN_READ or OPEN_READ | OPEN_DELETE.
+ * @param charSet The character set to use for entry names and comments.
+ *
+ * @exception IOException If an i/o error occured.
+ * @exception ZipException If the file doesn't contain a valid ZIP or JAR
+ * archive.
+ */
+ public ZipFile(final File file, final int mode, final String charSet)
+ throws ZipException, IOException, UnsupportedEncodingException {
+ if ((mode & OPEN_DELETE) != 0)
+ {
+ throw new IllegalArgumentException
+
+ ("OPEN_DELETE mode not supported yet in ZipFile");
+ }
+ this.raf = new RandomAccessFile(file, "r");
+ this.name = file.getPath();
+ this.charSet = charSet;
+ new String("").getBytes(charSet); // Fail-fast
+ try {
+ //checkZipFile(); // Does not help in many cases of corrupted ZIP files.
+ this.entries = readEntries();
+ }
+ catch (IOException failure) {
+ // Don't forget to release our resources even on failure!
+ try { close(); }
+ catch (IOException ignore) { }
+ throw failure;
+ }
+ }
+
+ /*private void checkZipFile() throws IOException, ZipException
{
+ raf.seek(0);
byte[] magicBuf = new byte[4];
raf.read(magicBuf);
if (readLeInt(magicBuf, 0) != LOCSIG)
{
- raf.close();
- throw new ZipException("Not a valid zip file");
+ throw new ZipException("Not a valid ZIP or JAR file: " + name);
}
- }
-
- /**
- * Checks if file is closed and throws an exception.
- */
- private void checkClosed()
- {
- if (closed)
- throw new IllegalStateException("ZipFile has closed: " + name);
- }
+ }*/
/**
* Read an unsigned short in little endian byte order from the given
@@ -172,7 +237,7 @@
* @exception IOException if a i/o error occured.
* @exception EOFException if the file ends prematurely
*/
- private int readLeShort(DataInput di, byte[] b) throws IOException
+ private final int readLeShort(DataInput di, byte[] b) throws IOException
{
di.readFully(b, 0, 2);
return (b[0] & 0xff) | (b[1] & 0xff) << 8;
@@ -189,11 +254,11 @@
* @exception IOException if a i/o error occured.
* @exception EOFException if the file ends prematurely
*/
- private int readLeInt(DataInput di, byte[] b) throws IOException
+ private final long readLeInt(DataInput di, byte[] b) throws IOException
{
di.readFully(b, 0, 4);
- return ((b[0] & 0xff) | (b[1] & 0xff) << 8)
- | ((b[2] & 0xff) | (b[3] & 0xff) << 8) << 16;
+ return ((b[0] & 0xffL) | (b[1] & 0xffL) << 8)
+ | ((b[2] & 0xffL) | (b[3] & 0xffL) << 8) << 16;
}
/**
@@ -204,7 +269,7 @@
* @param off the offset to read from.
* @return The value read.
*/
- private int readLeShort(byte[] b, int off)
+ private final int readLeShort(byte[] b, int off)
{
return (b[off] & 0xff) | (b[off+1] & 0xff) << 8;
}
@@ -217,37 +282,40 @@
* @param off the offset to read from.
* @return The value read.
*/
- private int readLeInt(byte[] b, int off)
+ private final long readLeInt(byte[] b, int off)
{
- return ((b[off] & 0xff) | (b[off+1] & 0xff) << 8)
- | ((b[off+2] & 0xff) | (b[off+3] & 0xff) << 8) << 16;
+ return ((b[off] & 0xffL) | (b[off+1] & 0xffL) << 8)
+ | ((b[off+2] & 0xffL) | (b[off+3] & 0xffL) << 8) << 16;
}
-
/**
- * Read the central directory of a zip file and fill the entries
- * array. This is called exactly once when first needed. It is called
- * while holding the lock on raf
.
+ * Read the central directory of a zip file and return the entries.
+ * This is called exactly once from the constructor in order to implement
+ * fail-fast-behaviour.
*
- * @exception IOException if a i/o error occured.
- * @exception ZipException if the central directory is malformed
+ * @return A HashMap containing all ZIP entries.
+ * It's keys are entry name strings and its values are ZipEntry
+ * objects.
+ *
+ * @exception IOException If an i/o error occured.
+ * @exception ZipException If the central directory is malformed.
*/
- private void readEntries() throws ZipException, IOException
+ private HashMap readEntries() throws ZipException, IOException
{
- /* Search for the End Of Central Directory. When a zip comment is
+ /* Search for the End Of Central Directory. When a zip comment is
* present the directory may start earlier.
- * FIXME: This searches the whole file in a very slow manner if the
- * file isn't a zip file.
*/
long pos = raf.length() - ENDHDR;
byte[] ebs = new byte[CENHDR];
+ int centralDirOffset = 0;
do
{
- if (pos < 0)
+ if (pos < 0 || centralDirOffset > 0xffff)
throw new ZipException
- ("central directory not found, probably not a zip file: " + name);
+ ("Central directory not found, probably not a zip file: " + name);
raf.seek(pos--);
+ centralDirOffset++;
}
while (readLeInt(raf, ebs) != ENDSIG);
@@ -256,9 +324,9 @@
int count = readLeShort(raf, ebs);
if (raf.skipBytes(ENDOFF - ENDSIZ) != ENDOFF - ENDSIZ)
throw new EOFException(name);
- int centralOffset = readLeInt(raf, ebs);
+ long centralOffset = readLeInt(raf, ebs);
- entries = new HashMap(count+count/2);
+ HashMap entries = new HashMap(count + count / 4);
raf.seek(centralOffset);
byte[] buffer = new byte[16];
@@ -269,28 +337,35 @@
throw new ZipException("Wrong Central Directory signature: " + name);
int method = readLeShort(ebs, CENHOW);
- int dostime = readLeInt(ebs, CENTIM);
- int crc = readLeInt(ebs, CENCRC);
- int csize = readLeInt(ebs, CENSIZ);
- int size = readLeInt(ebs, CENLEN);
+ long dostime = readLeInt(ebs, CENTIM);
+ long crc = readLeInt(ebs, CENCRC);
+ long csize = readLeInt(ebs, CENSIZ);
+ long size = readLeInt(ebs, CENLEN);
int nameLen = readLeShort(ebs, CENNAM);
int extraLen = readLeShort(ebs, CENEXT);
int commentLen = readLeShort(ebs, CENCOM);
- int offset = readLeInt(ebs, CENOFF);
+ long offset = readLeInt(ebs, CENOFF);
int needBuffer = Math.max(nameLen, commentLen);
if (buffer.length < needBuffer)
buffer = new byte[needBuffer];
raf.readFully(buffer, 0, nameLen);
- String name = new String(buffer, 0, 0, nameLen);
+
+ String name;
+ try {
+ name = new String(buffer, 0, nameLen, charSet);
+ }
+ catch (UnsupportedEncodingException cause) {
+ throw new AssertionError(cause);
+ }
ZipEntry entry = new ZipEntry(name);
entry.setMethod(method);
- entry.setCrc(crc & 0xffffffffL);
- entry.setSize(size & 0xffffffffL);
- entry.setCompressedSize(csize & 0xffffffffL);
+ entry.setCrc(crc);
+ entry.setSize(size);
+ entry.setCompressedSize(csize);
entry.setDOSTime(dostime);
if (extraLen > 0)
{
@@ -301,106 +376,89 @@
if (commentLen > 0)
{
raf.readFully(buffer, 0, commentLen);
- entry.setComment(new String(buffer, 0, commentLen));
+ try {
+ entry.setComment(new String(buffer, 0, commentLen, charSet));
+ }
+ catch (UnsupportedEncodingException cause) {
+ throw new AssertionError(cause);
+ }
}
entry.offset = offset;
entries.put(name, entry);
}
+
+ return entries;
}
/**
- * Closes the ZipFile. This also closes all input streams given by
- * this class. After this is called, no further method should be
+ * Closes the ZipFile. This also closes all input streams given by
+ * this class. After this is called, no further method should be
* called.
*
- * @exception IOException if a i/o error occured.
+ * @exception IOException If an i/o error occured.
*/
public void close() throws IOException
{
+ if (closed)
+ return;
synchronized (raf)
{
+ if (raf != null) // Condition not required, but fail-safe
+ raf.close();
+ if (entries != null) // Guard against call from constructor
+ entries.clear();
closed = true;
- entries = null;
- raf.close();
}
}
- /**
- * Calls the close()
method when this ZipFile has not yet
- * been explicitly closed.
+ /*/
+ * Ensures that the ZIP or JAR file is open.
+ *
+ * @exception IllegalStateException If the ZIP or JAR file has already been
+ * closed.
*/
- protected void finalize() throws IOException
+ private final void ensureOpen()
{
- if (!closed && raf != null) close();
+ if (closed)
+ throw new IllegalStateException("ZIP or JAR file has already been closed: " + name);
}
-
+
/**
- * Returns an enumeration of all Zip entries in this Zip file.
- *
- * @exception IllegalStateException when the ZipFile has already been closed
+ * Calls the close()
method.
*/
- public Enumeration entries()
+ protected void finalize() throws IOException
{
- checkClosed();
-
- try
- {
- return new ZipEntryEnumeration(getEntries().values().iterator());
- }
- catch (IOException ioe)
- {
- return EmptyEnumeration.getInstance();
- }
+ close();
}
/**
- * Checks that the ZipFile is still open and reads entries when necessary.
+ * Returns an enumeration of all Zip entries in this ZIP or JAR file.
*
- * @exception IllegalStateException when the ZipFile has already been closed.
- * @exception IOEexception when the entries could not be read.
+ * @exception IllegalStateException If the ZIP or JAR file has already been
+ * closed.
*/
- private HashMap getEntries() throws IOException
- {
- synchronized(raf)
- {
- checkClosed();
-
- if (entries == null)
- readEntries();
+ public Enumeration entries()
+ {
+ ensureOpen();
+ return new ZipEntryEnumeration(entries.values().iterator());
+ }
- return entries;
- }
- }
/**
* Searches for a zip entry in this archive with the given name.
*
- * @param the name. May contain directory components separated by
- * slashes ('/').
- * @return the zip entry, or null if no entry with that name exists.
+ * @param name May contain directory components separated by slashes ('/').
+ * @return The zip entry, or null if no entry with that name exists.
*
- * @exception IllegalStateException when the ZipFile has already been closed
+ * @exception IllegalStateException If the ZipFile has already been closed.
*/
public ZipEntry getEntry(String name)
{
- checkClosed();
-
- try
- {
- HashMap entries = getEntries();
- ZipEntry entry = (ZipEntry) entries.get(name);
- // If we didn't find it, maybe it's a directory.
- if (entry == null && !name.endsWith("/"))
- entry = (ZipEntry) entries.get(name + '/');
- return entry != null ? new ZipEntry(entry, name) : null;
- }
- catch (IOException ioe)
- {
- return null;
- }
+ ensureOpen();
+ ZipEntry entry = (ZipEntry) entries.get(name);
+ return entry != null ? (ZipEntry) entry.clone() : null;
}
-
//access should be protected by synchronized(raf)
private byte[] locBuf = new byte[LOCHDR];
@@ -429,7 +487,7 @@
throw new ZipException("Compression method mismatch: " + name);
if (entry.getName().length() != readLeShort(locBuf, LOCNAM))
- throw new ZipException("file name length mismatch: " + name);
+ throw new ZipException("File name length mismatch: " + name);
int extraLen = entry.getName().length() + readLeShort(locBuf, LOCEXT);
return entry.offset + LOCHDR + extraLen;
@@ -460,9 +518,31 @@
*/
public InputStream getInputStream(ZipEntry entry) throws IOException
{
- checkClosed();
+ return getInputStream(entry, new Inflater(true));
+ }
+
+ /**
+ * This is the actual implementation of address@hidden #getInputStream(ZipEntry)}
+ * - it allows you to specify a custom Inflater.
+ *
+ * Warning: This method is not part of the JDK API and + * should only be used if you absolutely know what you're doing! It is very + * easy to corrupt your input if you provide this method with the wrong + * parameters! + * + * @param entry The entry to create an InputStream for. + * @param inf An inflater with nowrap set to true. + * + * @return the input stream. + * + * @throws IOException If a i/o error occured. + * @throws ZipException If the Zip archive is malformed. + * @throws IllegalStateException If the ZIP file has been closed. + */ + protected final InputStream getInputStream(ZipEntry entry, InflaterIf inf) + throws IOException { + ensureOpen(); - HashMap entries = getEntries(); String name = entry.getName(); ZipEntry zipEntry = (ZipEntry) entries.get(name); if (zipEntry == null) @@ -477,7 +557,7 @@ case ZipOutputStream.STORED: return is; case ZipOutputStream.DEFLATED: - return new InflaterInputStream(is, new Inflater(true)); + return new PaddedInflaterInputStream(is, inf); default: throw new ZipException("Unknown compression method " + method); } @@ -492,22 +572,14 @@ } /** - * Returns the number of entries in this zip file. + * Returns the number of entries in this ZIP or JAR file. * - * @exception IllegalStateException when the ZipFile has already been closed + * @exception IllegalStateException If the ZipFile has already been closed. */ public int size() { - checkClosed(); - - try - { - return getEntries().size(); - } - catch (IOException ioe) - { - return 0; - } + ensureOpen(); + return entries.size(); } private static class ZipEntryEnumeration implements Enumeration @@ -592,4 +664,30 @@ return amount; } } + + /** + * Provides an extra "dummy" byte at the end of the input stream for + * address@hidden InflaterInputStream#fill()} + * as required by Sun's address@hidden Inflater#Inflater(boolean nowrap)}. + */ + private static class PaddedInflaterInputStream extends InflaterInputStream { + + private boolean eof; + + public PaddedInflaterInputStream(InputStream in, InflaterIf inf) { + super(in, inf); + } + + protected void fill() throws IOException { + if (eof) + throw new EOFException("Unexpected end of ZLIB input stream"); + if ((len = in.read(buf, 0, buf.length)) == -1) { + // Provide dummy byte + buf[0] = 0; + len = 1; + eof = true; + } + inf.setInput(buf, 0, len); + } + } } Index: java/util/zip/ZipInputStream.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/zip/ZipInputStream.java,v retrieving revision 1.14 diff -u -r1.14 ZipInputStream.java --- java/util/zip/ZipInputStream.java 22 Oct 2004 18:02:06 -0000 1.14 +++ java/util/zip/ZipInputStream.java 4 May 2005 02:16:36 -0000 @@ -41,6 +41,7 @@ import java.io.EOFException; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; /** * This is a FilterInputStream that reads the files in an zip archive @@ -51,25 +52,79 @@ * It includes support for STORED and DEFLATED entries. * * @author Jochen Hoenicke + * @author Christian Schlichtherle Added new constructors to support different + * character sets used to encode international entry names and comments. + * Added constructors to support different CRC32 and Inflater + * implementations. + * Fixed some bugs: Noteably the 2 GB Bug, so that Jazzlib now + * supports 4 GB which is the maximum with the ZIP32 format. + * Minor performance enhancements are also implemented. */ public class ZipInputStream extends InflaterInputStream implements ZipConstants { - private CRC32 crc = new CRC32(); + private final CRC32If crc; private ZipEntry entry = null; - private int csize; - private int size; + private long csize; + private long size; private int method; private int flags; private int avail; private boolean entryAtEOF; + private final String charSet; + /** * Creates a new Zip input stream, reading a zip archive. */ - public ZipInputStream(InputStream in) - { - super(in, new Inflater(true)); + public ZipInputStream(final InputStream in) { + this(in, new Inflater(true), new CRC32()); + } + + /** + * Creates a new Zip input stream, reading a zip archive. + * + * @param inf An inflater with nowrap set to true. + * @param crc The CRC23 to use. + */ + protected ZipInputStream(final InputStream in, + final InflaterIf inf, + final CRC32If crc) { + super(in, inf); + this.charSet = DEFAULT_CHARSET; + this.crc = crc; + } + + /** + * Creates a new Zip input stream, reading a zip archive. + *
+ * Warning: This constructor is not part of the JDK API! + * + * @param charSet The character set to use for entry names. + */ + public ZipInputStream(final InputStream in, final String charSet) + throws UnsupportedEncodingException { + this(in, charSet, new Inflater(true), new CRC32()); + } + + /** + * Creates a new Zip input stream, reading a zip archive. + *
+ * Warning: This constructor is not part of the JDK API! + * + * @param charSet The character set to use for entry names. + * @param inf An inflater with nowrap set to true. + * @param crc The CRC23 to use. + */ + protected ZipInputStream(final InputStream in, + final String charSet, + final InflaterIf inf, + final CRC32If crc) + throws UnsupportedEncodingException { + super(in, inf); + this.charSet = charSet; + new String("").getBytes(charSet); // Fail-fast + this.crc = crc; } private void fillBuf() throws IOException @@ -106,7 +161,7 @@ } } - private int readLeByte() throws IOException + private final int readLeByte() throws IOException { if (avail <= 0) { @@ -120,7 +175,7 @@ /** * Read an unsigned short in little endian byte order. */ - private int readLeShort() throws IOException + private final int readLeShort() throws IOException { return readLeByte() | (readLeByte() << 8); } @@ -128,9 +183,9 @@ /** * Read an int in little endian byte order. */ - private int readLeInt() throws IOException + private final long readLeInt() throws IOException { - return readLeShort() | (readLeShort() << 16); + return readLeShort() | ((long) readLeShort() << 16); } /** @@ -144,7 +199,7 @@ if (entry != null) closeEntry(); - int header = readLeInt(); + long header = readLeInt(); if (header == CENSIG) { /* Central Header reached. */ @@ -153,13 +208,13 @@ } if (header != LOCSIG) throw new ZipException("Wrong Local header signature: " - + Integer.toHexString(header)); + + Long.toHexString(header)); /* skip version */ readLeShort(); flags = readLeShort(); method = readLeShort(); - int dostime = readLeInt(); - int crc = readLeInt(); + long dostime = readLeInt(); + long crc = readLeInt(); csize = readLeInt(); size = readLeInt(); int nameLen = readLeShort(); @@ -171,16 +226,23 @@ byte[] buffer = new byte[nameLen]; readFully(buffer); - String name = new String(buffer); + //String name = new String(buffer); + String name; + try { + name = new String(buffer, 0, nameLen, charSet); + } + catch (UnsupportedEncodingException cause) { + throw new AssertionError(cause); + } entry = createZipEntry(name); entryAtEOF = false; entry.setMethod(method); if ((flags & 8) == 0) { - entry.setCrc(crc & 0xffffffffL); - entry.setSize(size & 0xffffffffL); - entry.setCompressedSize(csize & 0xffffffffL); + entry.setCrc(crc); + entry.setSize(size); + entry.setCompressedSize(csize); } entry.setDOSTime(dostime); if (extraLen > 0) @@ -204,11 +266,11 @@ { if (readLeInt() != EXTSIG) throw new ZipException("Data descriptor signature not found"); - entry.setCrc(readLeInt() & 0xffffffffL); + entry.setCrc(readLeInt()); csize = readLeInt(); size = readLeInt(); - entry.setSize(size & 0xffffffffL); - entry.setCompressedSize(csize & 0xffffffffL); + entry.setSize(size); + entry.setCompressedSize(csize); } /** @@ -226,7 +288,7 @@ if ((flags & 8) != 0) { /* We don't know how much we must skip, read until end. */ - byte[] tmp = new byte[2048]; + byte[] tmp = new byte[4096]; while (read(tmp) > 0) ; /* read will close this entry */ @@ -244,7 +306,7 @@ avail = 0; while (csize != 0) { - long skipped = in.skip(csize & 0xffffffffL); + long skipped = in.skip(csize); if (skipped <= 0) throw new ZipException("zip archive ends early."); csize -= skipped; @@ -316,8 +378,8 @@ case ZipOutputStream.STORED: - if (len > csize && csize >= 0) - len = csize; + if ((long) len > csize && csize >= 0) + len = (int) csize; len = readBuf(b, off, len); if (len > 0) @@ -338,7 +400,7 @@ if (finished) { - if ((crc.getValue() & 0xffffffffL) != entry.getCrc()) + if (crc.getValue() != entry.getCrc()) throw new ZipException("CRC mismatch"); crc.reset(); entry = null; @@ -354,7 +416,7 @@ public void close() throws IOException { super.close(); - crc = null; + crc.reset(); entry = null; entryAtEOF = true; } Index: java/util/zip/ZipOutputStream.java =================================================================== RCS file: /cvsroot/classpath/classpath/java/util/zip/ZipOutputStream.java,v retrieving revision 1.9 diff -u -r1.9 ZipOutputStream.java --- java/util/zip/ZipOutputStream.java 22 Oct 2004 18:02:07 -0000 1.9 +++ java/util/zip/ZipOutputStream.java 4 May 2005 02:16:37 -0000 @@ -42,6 +42,7 @@ import java.io.OutputStream; import java.util.Enumeration; import java.util.Vector; +import java.io.UnsupportedEncodingException; /** * This is a FilterOutputStream that writes the files into a zip @@ -54,11 +55,18 @@ * This class is not thread safe. * * @author Jochen Hoenicke + * @author Christian Schlichtherle Added new constructors to support different + * character sets used to encode international entry names and comments. + * Added constructors to support different CRC32 and Deflater + * implementations. + * Fixed some bugs: Noteably the 2 GB Bug, so that Jazzlib now + * supports 4 GB which is the maximum with the ZIP32 format. + * Minor performance enhancements are also implemented. */ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { private Vector entries = new Vector(); - private CRC32 crc = new CRC32(); + private final CRC32If crc; private ZipEntry curEntry = null; private int curMethod; @@ -68,6 +76,8 @@ private byte[] zipComment = new byte[0]; private int defaultMethod = DEFLATED; + private final String charSet; + /** * Our Zip version is hard coded to 1.0 resp. 2.0 */ @@ -86,11 +96,69 @@ /** * Creates a new Zip output stream, writing a zip archive. - * @param out the output stream to which the zip archive is written. + * + * @param out The output stream to which the zip archive is written. */ - public ZipOutputStream(OutputStream out) - { - super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true)); + public ZipOutputStream(final OutputStream out) { + this(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true), new CRC32()); + } + + /** + * Creates a new Zip output stream, writing a zip archive. + *
+ * Warning: This constructor is not part of the JDK API and + * should only be used if you absolutely know what you're doing! It is very + * easy to corrupt your ZIP files if you provide this method with the wrong + * parameters! + * + * @param out The output stream to which the zip archive is written. + * @param def A deflater with nowrap set to true. + * @param crc The CRC23 to use. + */ + protected ZipOutputStream(final OutputStream out, + final DeflaterIf def, + final CRC32If crc) { + super(out, def); + this.charSet = DEFAULT_CHARSET; + this.crc = crc; + } + + /** + * Creates a new Zip output stream, writing a zip archive. + *
+ * Warning: This constructor is not part of the JDK API! + * + * @param out The output stream to which the zip archive is written. + * @param charSet The character set to use for entry names and comments. + */ + public ZipOutputStream(final OutputStream out, final String charSet) + throws UnsupportedEncodingException { + this(out, charSet, + new Deflater(Deflater.DEFAULT_COMPRESSION, true), new CRC32()); + } + + /** + * Creates a new Zip output stream, writing a zip archive. + *
+ * Warning: This method is not part of the JDK API and + * should only be used if you absolutely know what you're doing! It is very + * easy to corrupt your ZIP files if you provide this method with the wrong + * parameters! + * + * @param out The output stream to which the zip archive is written. + * @param charSet The character set to use for entry names and comments. + * @param def A deflater with nowrap set to true. + * @param crc The CRC23 to use. + */ + protected ZipOutputStream(final OutputStream out, + final String charSet, + final DeflaterIf def, + final CRC32If crc) + throws UnsupportedEncodingException { + super(out, def); + this.charSet = charSet; + new String("").getBytes(charSet); // Fail-fast + this.crc = crc; } /** @@ -102,7 +170,12 @@ public void setComment(String comment) { byte[] commentBytes; - commentBytes = comment.getBytes(); + try { + commentBytes = comment.getBytes(charSet); + } + catch (UnsupportedEncodingException cause) { + throw new AssertionError(cause); + } if (commentBytes.length > 0xffff) throw new IllegalArgumentException("Comment too long."); zipComment = commentBytes; @@ -137,7 +210,7 @@ /** * Write an unsigned short in little endian byte order. */ - private void writeLeShort(int value) throws IOException + private final void writeLeShort(int value) throws IOException { out.write(value & 0xff); out.write((value >> 8) & 0xff); @@ -146,10 +219,10 @@ /** * Write an int in little endian byte order. */ - private void writeLeInt(int value) throws IOException + private final void writeLeInt(long value) throws IOException { - writeLeShort(value); - writeLeShort(value >> 16); + writeLeShort((int) (value & 0xffff)); + writeLeShort((int) ((value >> 16) & 0xffff)); } /** @@ -216,9 +289,9 @@ writeLeInt(entry.getDOSTime()); if ((flags & 8) == 0) { - writeLeInt((int)entry.getCrc()); - writeLeInt((int)entry.getCompressedSize()); - writeLeInt((int)entry.getSize()); + writeLeInt(entry.getCrc()); + writeLeInt(entry.getCompressedSize()); + writeLeInt(entry.getSize()); } else { @@ -226,7 +299,13 @@ writeLeInt(0); writeLeInt(0); } - byte[] name = entry.getName().getBytes(); + byte[] name; + try { + name = entry.getName().getBytes(charSet); + } + catch (UnsupportedEncodingException cause) { + throw new AssertionError(cause); + } if (name.length > 0xffff) throw new ZipException("Name too long."); byte[] extra = entry.getExtra(); @@ -289,9 +368,9 @@ if (curMethod == DEFLATED && (curEntry.flags & 8) != 0) { writeLeInt(EXTSIG); - writeLeInt((int)curEntry.getCrc()); - writeLeInt((int)curEntry.getCompressedSize()); - writeLeInt((int)curEntry.getSize()); + writeLeInt(curEntry.getCrc()); + writeLeInt(curEntry.getCompressedSize()); + writeLeInt(curEntry.getSize()); offset += EXTHDR; } @@ -339,10 +418,10 @@ int numEntries = 0; int sizeEntries = 0; - Enumeration e = entries.elements(); - while (e.hasMoreElements()) + Enumeration enumeration = entries.elements(); + while (enumeration.hasMoreElements()) { - ZipEntry entry = (ZipEntry) e.nextElement(); + ZipEntry entry = (ZipEntry) enumeration.nextElement(); int method = entry.getMethod(); writeLeInt(CENSIG); @@ -353,19 +432,31 @@ writeLeShort(entry.flags); writeLeShort(method); writeLeInt(entry.getDOSTime()); - writeLeInt((int)entry.getCrc()); - writeLeInt((int)entry.getCompressedSize()); - writeLeInt((int)entry.getSize()); - - byte[] name = entry.getName().getBytes(); + writeLeInt(entry.getCrc()); + writeLeInt(entry.getCompressedSize()); + writeLeInt(entry.getSize()); + + byte[] name; + try { + name = entry.getName().getBytes(charSet); + } + catch (UnsupportedEncodingException cause) { + throw new AssertionError(cause); + } if (name.length > 0xffff) throw new ZipException("Name too long."); byte[] extra = entry.getExtra(); if (extra == null) extra = new byte[0]; String strComment = entry.getComment(); - byte[] comment = strComment != null - ? strComment.getBytes() : new byte[0]; + byte[] comment; + try { + comment = strComment != null + ? strComment.getBytes(charSet) : new byte[0]; + } + catch (UnsupportedEncodingException cause) { + throw new AssertionError(cause); + } if (comment.length > 0xffff) throw new ZipException("Comment too long."); Index: lib/jazzlib/makeJazzlibDist.sh =================================================================== RCS file: /cvsroot/classpath/classpath/lib/jazzlib/makeJazzlibDist.sh,v retrieving revision 1.5 diff -u -r1.5 makeJazzlibDist.sh --- lib/jazzlib/makeJazzlibDist.sh 13 May 2004 12:50:14 -0000 1.5 +++ lib/jazzlib/makeJazzlibDist.sh 4 May 2005 02:16:57 -0000 @@ -12,7 +12,7 @@ echo "----- Do rm -rf dist when you're finished -----" echo "----- 30 May 2002 John Leuner
-----" -RELEASE_NUMBER=07 +RELEASE_NUMBER=08 # $1 is the archive command, eg "tar czvf" or "zip" or "jar cf" # $2 is the archive suffix, eg ".zip" or ".tar.gz"