ZipInputStream brokenness

Tom Tromey tromey@redhat.com
Tue Jun 4 11:37:00 GMT 2002


>>>>> "Adam" == Adam Megacz <gcj@lists.megacz.com> writes:

Adam> Here's an idea -- what if we replace only
Adam> java.util.zip.ZipInputStream with the JazzLib
Adam> version. ZipInputStream is already broken, so this can't in any
Adam> way increase the level of brokenness.
I have a partial patch for this. It is appended. It still has at
least one bug, since your test program still fails. I don't have time
to work on it any more right now; I'm going out of town again tomorrow
and I have a lot of other stuff to do. Feel free to debug the last
couple things if you're motivated. If not, I'll resurrect it sometime
after I get back.
Tom
Index: ChangeLog
from Tom Tromey <tromey@redhat.com>
	* java/util/zip/InflaterInputStream.java (read): Loop if data has
	been read but none output by inflater.
	* java/util/zip/natDeflater.cc (reset): Set is_finished.
	* java/util/zip/natInflater.cc (reset): Set dist_needed and
	is_finished.
	* java/util/zip/ZipOutputStream.java: Replaced with Classpath
	version.
	* java/util/zip/ZipFile.java: Replaced with Classpath version.
	* java/util/zip/ZipEntry.java: Replaced with Classpath version.
	* java/util/zip/ZipInputStream.java: Replaced with Classpath
	version.
	* java/util/zip/ZipConstants.java: Replaced with Classpath version.
Index: java/util/zip/InflaterInputStream.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/zip/InflaterInputStream.java,v
retrieving revision 1.13
diff -u -r1.13 InflaterInputStream.java
--- java/util/zip/InflaterInputStream.java 22 Jan 2002 22:40:41 -0000 1.13
+++ java/util/zip/InflaterInputStream.java 4 Jun 2002 18:14:46 -0000
@@ -1,5 +1,5 @@
 /* InflaterInputStream.java - Input stream filter for decompressing
- Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -92,23 +92,30 @@
 throw new IOException ("stream closed");
 if (inf.finished())
 return -1;
- if (inf.needsInput())
- fill ();
- int count;
- try
+
+ int count = 0;
+ while (count == 0)
 {
-	count = inf.inflate(buf, off, len);	
-	if (count == 0)
+	if (inf.needsInput())
+	 fill ();
+	try
 	 {
-	 if (this.len == -1)
-	 return -1; // Couldn't get any more data to feed to the Inflater
-	 if (inf.needsDictionary())
-	 throw new ZipException ("Inflater needs Dictionary");
-	 }	 
- }
- catch (DataFormatException dfe)
- {
-	throw new ZipException (dfe.getMessage());
+	 count = inf.inflate(buf, off, len);	
+	 if (count == 0)
+	 {
+		if (this.len == -1)
+		 {
+		 // Couldn't get any more data to feed to the Inflater
+		 return -1;
+		 }
+		if (inf.needsDictionary())
+		 throw new ZipException ("Inflater needs Dictionary");
+	 }
+	 }
+	catch (DataFormatException dfe)
+	 {
+	 throw new ZipException (dfe.getMessage());
+	 }
 }
 return count;
 }
Index: java/util/zip/ZipConstants.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/zip/ZipConstants.java,v
retrieving revision 1.6
diff -u -r1.6 ZipConstants.java
--- java/util/zip/ZipConstants.java 22 Jan 2002 22:40:41 -0000 1.6
+++ java/util/zip/ZipConstants.java 4 Jun 2002 18:14:46 -0000
@@ -1,5 +1,5 @@
-/* ZipConstants.java - Some constants used in the zip package
- Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+/* java.util.zip.ZipConstants
+ Copyright (C) 2001 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -7,7 +7,7 @@
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
- 
+
 GNU Classpath is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -37,19 +37,61 @@
 
 package java.util.zip;
 
-/**
- * Some constants used in the zip package.
- * <p>
- * Since this package local interface is completely undocumented no effort
- * is made to make it compatible with other implementations.
- * If someone is really interested you can probably come up with the right
- * constants and documentation by studying the Info-ZIP zipfile.c constants.
- */
 interface ZipConstants
 {
- // Size in bytes of local file header, including signature.
- public static final int LOCAL_FILE_HEADER_SIZE = 30;
-
- // Size in bytes of the "end of central directory" record, with signature.
- public static final int END_CENTRAL_DIR_SIZE = 22;
+ /* The local file header */
+ public final static int LOCHDR = 30;
+ public final static int LOCSIG = 'P'|('K'<<8)|(3<<16)|(4<<24);
+
+ public final static int LOCVER = 4;
+ public final static int LOCFLG = 6;
+ public final static int LOCHOW = 8;
+ public final static int LOCTIM = 10;
+ public final static int LOCCRC = 14;
+ public final static int LOCSIZ = 18;
+ public final static int LOCLEN = 22;
+ public final static int LOCNAM = 26;
+ public final static int LOCEXT = 28;
+
+ /* The Data descriptor */
+ public final static int EXTSIG = 'P'|('K'<<8)|(7<<16)|(8<<24);
+ public final static int EXTHDR = 16;
+
+ public final static int EXTCRC = 4;
+ public final static int EXTSIZ = 8;
+ public final static int EXTLEN = 12;
+
+ /* The central directory file header */
+ public final static int CENSIG = 'P'|('K'<<8)|(1<<16)|(2<<24);
+ public final static int CENHDR = 46;
+
+ public final static int CENVEM = 4;
+ public final static int CENVER = 6;
+ public final static int CENFLG = 8;
+ public final static int CENHOW = 10;
+ public final static int CENTIM = 12;
+ public final static int CENCRC = 16;
+ public final static int CENSIZ = 20;
+ public final static int CENLEN = 24;
+ public final static int CENNAM = 28;
+ public final static int CENEXT = 30;
+ public final static int CENCOM = 32;
+ public final static int CENDSK = 34;
+ public final static int CENATT = 36;
+ public final static int CENATX = 38;
+ public final static int CENOFF = 42;
+
+ /* The entries in the end of central directory */
+ public final static int ENDSIG = 'P'|('K'<<8)|(5<<16)|(6<<24);
+ public final static int ENDHDR = 22;
+
+ /* The following two fields are missing in SUN JDK */
+ final static int ENDNRD = 4;
+ final static int ENDDCD = 6;
+ public final static int ENDSUB = 8;
+ public final static int ENDTOT = 10;
+ public final static int ENDSIZ = 12;
+ public final static int ENDOFF = 16;
+ public final static int ENDCOM = 20;
 }
+
Index: java/util/zip/ZipEntry.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/zip/ZipEntry.java,v
retrieving revision 1.13
diff -u -r1.13 ZipEntry.java
--- java/util/zip/ZipEntry.java 22 Jan 2002 22:40:41 -0000 1.13
+++ java/util/zip/ZipEntry.java 4 Jun 2002 18:14:46 -0000
@@ -1,5 +1,5 @@
-/* ZipEntry.java - Represents entries in a zip file archive
- Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+/* java.util.zip.ZipEntry
+ Copyright (C) 2001, 2002 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -7,7 +7,7 @@
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
- 
+
 GNU Classpath is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -36,201 +36,361 @@
 exception statement from your version. */
 
 package java.util.zip;
+import java.util.Calendar;
+import java.util.TimeZone;
+import java.util.Date;
 
 /**
- * @author Per Bothner
- * @date January 6, 1999.
- */
-
-/*
- * Written using on-line Java Platform 1.2 API Specification, as well
- * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
- * Status: Believed complete and correct.
- */
-
-/**
- * Represents entries in a zip file archive.
- * An Entry cn be created by giving a name or by giving an already existing
- * ZipEntries whose values should be copied. The name normally represents a
- * file path name or directory name.
+ * This class represents a member of a zip archive. ZipFile and
+ * ZipInputStream will give you instances of this class as information
+ * about the members in an archive. On the other hand ZipOutputStream
+ * needs an instance of this class to create a new member.
+ *
+ * @author Jochen Hoenicke 
 */
 public class ZipEntry implements ZipConstants, Cloneable
 {
- // These values were determined using a simple test program.
- public static final int STORED = 0;
- public static final int DEFLATED = 8;
-
- String comment;
- long compressedSize = -1;
- long crc = -1;
- byte[] extra;
- int method = -1;
- String name;
- long size = -1;
- long time = -1;
- long relativeOffset = -1;
+ private static int KNOWN_SIZE = 1;
+ private static int KNOWN_CSIZE = 2;
+ private static int KNOWN_CRC = 4;
+ private static int KNOWN_TIME = 8;
+
+ private static Calendar cal = Calendar.getInstance();
+
+ private String name;
+ private int size;
+ private int compressedSize;
+ private int crc;
+ private int time;
+ private short known = 0;
+ private short method = -1;
+ private byte[] extra = null;
+ private String comment = null;
+
+ int zipFileIndex = -1; /* used by ZipFile */
+ int flags; /* used by ZipOutputStream */
+ int offset; /* used by ZipFile and ZipOutputStream */
 
- ZipEntry next;
 
- public ZipEntry (String name)
+ /**
+ * Compression method. This method doesn't compress at all.
+ */
+ public final static int STORED = 0;
+ /**
+ * Compression method. This method uses the Deflater.
+ */
+ public final static int DEFLATED = 8;
+
+ /**
+ * Creates a zip entry with the given name.
+ * @param name the name. May include directory components separated
+ * by '/'.
+ */
+ public ZipEntry(String name)
 {
- if (name.length() > 65535)
- throw new IllegalArgumentException ();
+ if (name == null)
+ throw new NullPointerException();
 this.name = name;
 }
 
 /**
- * Creates a new ZipEntry using the fields of a given ZipEntry.
- * The comment, compressedSize, crc, extra, method, name, size, time and
- * relativeOffset fields are copied from the given entry.
- * Note that the contents of the extra byte array field is not cloned,
- * only the reference is copied.
- * The clone() method does clone the contents of the extra byte array if
- * needed.
- * @since 1.2
+ * Creates a copy of the given zip entry.
+ * @param e the entry to copy.
 */
- public ZipEntry (ZipEntry ent)
+ public ZipEntry(ZipEntry e)
+ {
+ name = e.name;
+ known = e.known;
+ size = e.size;
+ compressedSize = e.compressedSize;
+ crc = e.crc;
+ time = e.time;
+ method = e.method;
+ extra = e.extra;
+ comment = e.comment;
+ }
+
+ void setDOSTime(int dostime)
+ {
+ 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 */
+ 
+ // Guard against invalid or missing date causing
+ // IndexOutOfBoundsException.
+ try
+ {
+	synchronized (cal)
+	 {
+	 cal.set(year, mon, day, hrs, min, sec);
+	 time = (int) (cal.getTime().getTime() / 1000L);
+	 }
+	known |= KNOWN_TIME;
+ }
+ catch (RuntimeException ex)
+ {
+	/* Ignore illegal time stamp */
+	known &= ~KNOWN_TIME;
+ }
+ }
+
+ int getDOSTime()
 {
- comment = ent.comment;
- compressedSize = ent.compressedSize;
- crc = ent.crc;
- extra = ent.extra;
- method = ent.method;
- name = ent.name;
- size = ent.size;
- time = ent.time;
- relativeOffset = ent.relativeOffset;
+ if ((known & KNOWN_TIME) == 0)
+ return 0;
+ synchronized (cal)
+ {
+	cal.setTime(new Date(time*1000L));
+	return (cal.get(cal.YEAR) - 1980 & 0x7f) << 25
+	 | (cal.get(cal.MONTH) + 1) << 21
+	 | (cal.get(cal.DAY_OF_MONTH)) << 16
+	 | (cal.get(cal.HOUR_OF_DAY)) << 11
+	 | (cal.get(cal.MINUTE)) << 5
+	 | (cal.get(cal.SECOND)) >> 1;
+ }
 }
- 
+
+ /**
+ * Creates a copy of this zip entry.
+ */
 /**
- * Creates a clone of this ZipEntry. Calls <code>new ZipEntry (this)</code>
- * and creates a clone of the contents of the extra byte array field.
- *
- * @since 1.2
+ * Clones the entry.
 */
- public Object clone ()
+ public Object clone()
 {
- // JCL defines this as being the same as the copy constructor above,
- // except that value of the "extra" field is also copied.
- ZipEntry clone = new ZipEntry (this);
- clone.extra = (byte[]) extra.clone ();
- return clone;
+ try
+ {
+	// The JCL says that the `extra' field is also copied.
+	ZipEntry clone = (ZipEntry) super.clone();
+	if (extra != null)
+	 clone.extra = (byte[]) extra.clone();
+	return clone;
+ }
+ catch (CloneNotSupportedException ex)
+ {
+	throw new InternalError();
+ }
 }
 
- public String getComment () { return comment; }
-
- public long getCompressedSize () { return compressedSize; }
+ /**
+ * Returns the entry name. The path components in the entry are
+ * always separated by slashes ('/'). 
+ */
+ public String getName()
+ {
+ return name;
+ }
 
- public long getCrc () { return crc; }
+ /**
+ * Sets the time of last modification of the entry.
+ * @time the time of last modification of the entry.
+ */
+ public void setTime(long time)
+ {
+ this.time = (int) (time / 1000L);
+ this.known |= KNOWN_TIME;
+ }
 
- public byte[] getExtra() { return extra; }
+ /**
+ * Gets the time of last modification of the entry.
+ * @return the time of last modification of the entry, or -1 if unknown.
+ */
+ public long getTime()
+ {
+ return (known & KNOWN_TIME) != 0 ? time * 1000L : -1;
+ }
 
- public int getMethod () { return method; }
+ /**
+ * Sets the size of the uncompressed data.
+ * @exception IllegalArgumentException if size is not in 0..0xffffffffL
+ */
+ public void setSize(long size)
+ {
+ if ((size & 0xffffffff00000000L) != 0)
+	throw new IllegalArgumentException();
+ this.size = (int) size;
+ this.known |= KNOWN_SIZE;
+ }
 
- public String getName () { return name; }
+ /**
+ * Gets the size of the uncompressed data.
+ * @return the size or -1 if unknown.
+ */
+ public long getSize()
+ {
+ return (known & KNOWN_SIZE) != 0 ? size & 0xffffffffL : -1L;
+ }
 
- public long getSize () { return size; }
+ /**
+ * Sets the size of the compressed data.
+ * @exception IllegalArgumentException if size is not in 0..0xffffffffL
+ */
+ public void setCompressedSize(long csize)
+ {
+ if ((csize & 0xffffffff00000000L) != 0)
+	throw new IllegalArgumentException();
+ this.compressedSize = (int) csize;
+ this.known |= KNOWN_CSIZE;
+ }
 
- public long getTime () { return time; }
+ /**
+ * Gets the size of the compressed data.
+ * @return the size or -1 if unknown.
+ */
+ public long getCompressedSize()
+ {
+ return (known & KNOWN_CSIZE) != 0 ? compressedSize & 0xffffffffL : -1L;
+ }
 
- public boolean isDirectory ()
+ /**
+ * Sets the crc of the uncompressed data.
+ * @exception IllegalArgumentException if crc is not in 0..0xffffffffL
+ */
+ public void setCrc(long crc)
 {
- if (name != null)
- {
-	int nlen = name.length();
-	if (nlen > 0 && name.charAt(nlen-1) == '/')
-	 return true;
- }
- return false;
+ if ((crc & 0xffffffff00000000L) != 0)
+	throw new IllegalArgumentException();
+ this.crc = (int) crc;
+ this.known |= KNOWN_CRC;
 }
 
- public void setComment (String comment)
+ /**
+ * Gets the crc of the uncompressed data.
+ * @return the crc or -1 if unknown.
+ */
+ public long getCrc()
 {
- if (comment != null && comment.length() > 65535)
- throw new IllegalArgumentException ();
- this.comment = comment;
+ return (known & KNOWN_CRC) != 0 ? crc & 0xffffffffL : -1L;
 }
- 
+
 /**
- * Sets the compressedSize of this ZipEntry.
- * The new size must be between 0 and 0xffffffffL.
- * @since 1.2
+ * Sets the compression method. Only DEFLATED and STORED are
+ * supported.
+ * @exception IllegalArgumentException if method is not supported.
+ * @see ZipOutputStream#DEFLATED
+ * @see ZipOutputStream#STORED 
 */
- public void setCompressedSize (long compressedSize)
+ public void setMethod(int method)
 {
- if (compressedSize < 0 || compressedSize > 0xffffffffL)
- throw new IllegalArgumentException ();
- this.compressedSize = compressedSize;
+ if (method != ZipOutputStream.STORED
+	&& method != ZipOutputStream.DEFLATED)
+	throw new IllegalArgumentException();
+ this.method = (short) method;
 }
 
- public void setCrc (long crc) 
+ /**
+ * Gets the compression method. 
+ * @return the compression method or -1 if unknown.
+ */
+ public int getMethod()
 {
- if (crc < 0 || crc > 0xffffffffL)
- throw new IllegalArgumentException ();
- this.crc = crc;
+ return method;
 }
 
- public void setExtra (byte[] extra)
+ /**
+ * Sets the extra data.
+ * @exception IllegalArgumentException if extra is longer than 0xffff bytes.
+ */
+ public void setExtra(byte[] extra)
 {
- if (extra != null && extra.length > 65535)
- throw new IllegalArgumentException ();
+ if (extra == null) 
+ {
+	this.extra = null;
+	return;
+ }
+
+ if (extra.length > 0xffff)
+ throw new IllegalArgumentException();
 this.extra = extra;
+ try
+ {
+	int pos = 0;
+	while (pos < extra.length) 
+	 {
+	 int sig = (extra[pos++] & 0xff)
+	 | (extra[pos++] & 0xff) << 8;
+	 int len = (extra[pos++] & 0xff)
+	 | (extra[pos++] & 0xff) << 8;
+	 if (sig == 0x5455) 
+	 {
+		/* extended time stamp */
+		int flags = extra[pos];
+		if ((flags & 1) != 0)
+		 {
+		 time = ((extra[pos+1] & 0xff)
+			 | (extra[pos+2] & 0xff) << 8
+			 | (extra[pos+3] & 0xff) << 16
+			 | (extra[pos+4] & 0xff) << 24);
+		 known |= KNOWN_TIME;
+		 }
+	 }
+	 pos += len;
+	 }
+ }
+ catch (ArrayIndexOutOfBoundsException ex)
+ {
+	/* be lenient */
+	return;
+ }
 }
 
- public void setMethod (int method)
+ /**
+ * Gets the extra data.
+ * @return the extra data or null if not set.
+ */
+ public byte[] getExtra()
 {
- if (method != DEFLATED && method != STORED)
- throw new IllegalArgumentException ();
- this.method = method;
+ return extra;
 }
 
- public void setSize (long size)
+ /**
+ * Sets the entry comment.
+ * @exception IllegalArgumentException if comment is longer than 0xffff.
+ */
+ public void setComment(String comment)
 {
- if (size < 0 || size > 0xffffffffL)
- throw new IllegalArgumentException ();
- this.size = size;
+ if (comment.length() > 0xffff)
+ throw new IllegalArgumentException();
+ this.comment = comment;
 }
 
- public void setTime (long time)
+ /**
+ * Gets the comment.
+ * @return the comment or null if not set.
+ */
+ public String getComment()
 {
- this.time = time;
+ return comment;
 }
 
- private final static short[] daysToMonthStart = {
- //Jan Feb Mar Apr May Jun Jul
- 0, 31, 31+28, 2*31+28, 2*31+28+30, 3*31+28+30, 3*31+28+2*30,
- // Aug Sep Oct Nov Dec
- 4*31+28+2*30, 5*31+28+2*30, 5*31+28+3*30, 6*31+28+3*30, 6*31+28+4*30};
-
- /** Convert a DOS-style type value to milliseconds since 1970. */
- static long timeFromDOS (int date, int time)
+ /**
+ * Gets true, if the entry is a directory. This is solely
+ * determined by the name, a trailing slash '/' marks a directory. 
+ */
+ public boolean isDirectory()
 {
- int sec = 2 * (time & 0x1f);
- int min = (time >> 5) & 0x3f;
- int hrs = (time >> 11) & 0x1f;
- int day = date & 0x1f;
- int mon = ((date >> 5) & 0xf) - 1;
- int year = ((date >> 9) & 0x7f) + 10; /* Since 1970. */
-
- // Guard against invalid or missing date causing IndexOutOfBoundsException.
- if (mon < 0 || mon > 11)
- return -1;
-
- long mtime = (((hrs * 60) + min) * 60 + sec) * 1000;
+ int nlen = name.length();
+ return nlen > 0 && name.charAt(nlen - 1) == '/';
+ }
 
- // Leap year calculations are rather trivial in this case ...
- int days = 365 * year + ((year+1)>>2);
- days += daysToMonthStart[mon];
- if ((year & 3) == 0 && mon > 1)
- days++;
- days += day;
- return (days * 24*60*60L + ((hrs * 60) + min) * 60 + sec) * 1000L;
+ /**
+ * Gets the string representation of this ZipEntry. This is just
+ * the name as returned by getName().
+ */
+ public String toString()
+ {
+ return name;
 }
 
- public String toString () { return name; }
- 
 /**
- * Returns the hashcode of the name of this ZipEntry.
+ * Gets the hashCode of this ZipEntry. This is just the hashCode
+ * of the name. Note that the equals method isn't changed, though.
 */
- public int hashCode () { return name.hashCode (); }
+ public int hashCode()
+ {
+ return name.hashCode();
+ }
 }
Index: java/util/zip/ZipFile.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/zip/ZipFile.java,v
retrieving revision 1.16
diff -u -r1.16 ZipFile.java
--- java/util/zip/ZipFile.java 22 Jan 2002 22:40:41 -0000 1.16
+++ java/util/zip/ZipFile.java 4 Jun 2002 18:14:46 -0000
@@ -1,5 +1,5 @@
-/* ZipFile.java - Read contents of a ZIP file
- Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+/* java.util.zip.ZipFile
+ Copyright (C) 2001 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -7,7 +7,7 @@
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
- 
+
 GNU Classpath is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -36,233 +36,422 @@
 exception statement from your version. */
 
 package java.util.zip;
-
-import java.io.*;
-
-/* Written using on-line Java Platform 1.2 API Specification
- * and JCL book.
- * Believed complete and correct.
+import java.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.EOFException;
+import java.io.RandomAccessFile;
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+/**
+ * This class represents a Zip archive. You can ask for the contained
+ * entries, or get an input stream for a file entry. The entry is
+ * automatically decompressed.
+ *
+ * This class is thread safe: You can open input streams for arbitrary
+ * entries in different threads.
+ *
+ * @author Jochen Hoenicke
 */
-
 public class ZipFile implements ZipConstants
 {
- public static final int OPEN_READ = 1;
- public static final int OPEN_DELETE = 4;
 
- public ZipFile (String fname) throws IOException
+ /** Mode flag to open a zip file for reading 
+ *
+ */
+
+ public static final int OPEN_READ = 0x1;
+
+ /** Mode flag to delete a zip file after reading 
+ *
+ */
+
+ public static final int OPEN_DELETE = 0x4;
+
+ private String name;
+ RandomAccessFile raf;
+ ZipEntry[] entries;
+
+ /**
+ * 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. 
+ */
+ public ZipFile(String name) throws ZipException, IOException
 {
- this(new File(fname));
+ this.raf = new RandomAccessFile(name, "r");
+ this.name = name;
+ readEntries();
 }
 
- public ZipFile (File f) throws IOException
+ /**
+ * 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. 
+ */
+ public ZipFile(File file) throws ZipException, IOException
 {
- this(f, OPEN_READ);
+ this.raf = new RandomAccessFile(file, "r");
+ this.name = file.getName();
+ readEntries();
 }
 
- public ZipFile (File f, int mode) throws IOException
+ /**
+ * 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.
+ *
+ * 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
+ *
+ * @exception IOException if a i/o error occured.
+ * @exception ZipException if the file doesn't contain a valid zip
+ * archive. 
+ */
+ public ZipFile(File file, int mode) throws ZipException, IOException
 {
- if (mode != OPEN_READ && mode != (OPEN_READ | OPEN_DELETE))
- throw new IllegalArgumentException
- ("mode can only be OPEN_READ or OPEN_READ | OPEN_DELETE");
-
 if ((mode & OPEN_DELETE) != 0)
 {
-	delete_on_close = f;
-	f.deleteOnExit();
- }
- else
- {
-	delete_on_close = null;
+	throw new IllegalArgumentException("OPEN_DELETE mode not supported yet in java.util.zip.ZipFile");
 }
+ this.raf = new RandomAccessFile(file, "r");
+ this.name = file.getName();
+ readEntries();
+ }
 
- file = new RandomAccessFile(f, "r");
- name = f.getName();
- readDirectory ();
- }
-
- void readDirectory () throws IOException
- {
- long size = file.length ();
- if (size < ZipConstants.END_CENTRAL_DIR_SIZE)
- 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.
- file.seek(size - ZipConstants.END_CENTRAL_DIR_SIZE);
- if (file.read() != 'P'
-	|| file.read() != 'K'
-	|| file.read() != '005円'
-	|| file.read() != '006円')
- throw new ZipException("not a valid zipfile");
- file.skipBytes(6);
- numEntries = readu2();
- int dir_size = read4 (); // Read "size of the central directory".
- file.seek(size - (dir_size + ZipConstants.END_CENTRAL_DIR_SIZE));
+ /**
+ * Read an unsigned short in little endian byte order.
+ * @exception IOException if a i/o error occured.
+ * @exception EOFException if the file ends prematurely
+ */
+ private final int readLeShort() throws IOException {
+ return raf.readUnsignedByte() | raf.readUnsignedByte() << 8;
+ }
 
- ZipEntry last = null;
- for (int i = 0; i < numEntries; i++)
+ /**
+ * Read an int in little endian byte order.
+ * @exception IOException if a i/o error occured.
+ * @exception EOFException if the file ends prematurely
+ */
+ private final int readLeInt() throws IOException {
+ return readLeShort() | readLeShort() << 16;
+ }
+
+ /**
+ * Read the central directory of a zip file and fill the entries
+ * array. This is called exactly once by the constructors.
+ * @exception IOException if a i/o error occured.
+ * @exception ZipException if the central directory is malformed 
+ */
+ private void readEntries() throws ZipException, IOException
+ {
+ /* 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;
+ do
+ {
+	if (pos < 0)
+	 throw new ZipException
+	 ("central directory not found, probably not a zip file");
+	raf.seek(pos--);
+ }
+ while (readLeInt() != ENDSIG);
+ if (raf.skipBytes(ENDTOT - ENDNRD) != ENDTOT - ENDNRD)
+ throw new EOFException();
+ int count = readLeShort();
+ if (raf.skipBytes(ENDOFF - ENDSIZ) != ENDOFF - ENDSIZ)
+ throw new EOFException();
+ int centralOffset = readLeInt();
+
+ entries = new ZipEntry[count];
+ raf.seek(centralOffset);
+ for (int i = 0; i < count; i++)
 {
-	file.skipBytes(10);
-	int method = readu2();
-	int modtime = readu2();
-	int moddate = readu2();
-	int crc = read4();
-	int compressedSize = read4();
-	int uncompressedSize = read4();
-	int filenameLength = readu2();
-	int extraLength = readu2();
-	int commentLength = readu2();
-	int diskNumberStart = readu2();
-	int intAttributes = readu2();
-	int extAttributes = read4();
-	int relativeOffset = read4();
-	byte[] bname = new byte[filenameLength];
-	file.readFully(bname);
-	ZipEntry entry = new ZipEntry(new String(bname, "8859_1"));
-	if (extraLength > 0)
+	if (readLeInt() != CENSIG)
+	 throw new ZipException("Wrong Central Directory signature");
+	if (raf.skipBytes(CENHOW - CENVEM) != CENHOW - CENVEM)
+	 throw new EOFException();
+	int method = readLeShort();
+	int dostime = readLeInt();
+	int crc = readLeInt();
+	int csize = readLeInt();
+	int size = readLeInt();
+	int nameLen = readLeShort();
+	int extraLen = readLeShort();
+	int commentLen = readLeShort();
+	if (raf.skipBytes(CENOFF - CENDSK) != CENOFF - CENDSK)
+	 throw new EOFException();
+	int offset = readLeInt();
+
+	byte[] buffer = new byte[Math.max(nameLen, commentLen)];
+
+	raf.readFully(buffer, 0, nameLen);
+	String name = new String(buffer, 0, nameLen);
+
+	ZipEntry entry = new ZipEntry(name);
+	entry.setMethod(method);
+	entry.setCrc(crc & 0xffffffffL);
+	entry.setSize(size & 0xffffffffL);
+	entry.setCompressedSize(csize & 0xffffffffL);
+	entry.setDOSTime(dostime);
+	if (extraLen > 0)
 	 {
-	 byte[] bextra = new byte[extraLength];
-	 file.readFully(bextra);
-	 entry.extra = bextra;
+	 byte[] extra = new byte[extraLen];
+	 raf.readFully(extra);
+	 entry.setExtra(extra);
 	 }
-	if (commentLength > 0)
+	if (commentLen > 0)
 	 {
-	 byte[] bcomment = new byte[commentLength];
-	 file.readFully(bcomment);
-	 entry.comment = new String(bcomment, "8859_1");
+	 raf.readFully(buffer, 0, commentLen);
+	 entry.setComment(new String(buffer, 0, commentLen));
 	 }
-	entry.compressedSize = compressedSize;
-	entry.size = uncompressedSize;
-	entry.crc = (long) crc & 0xffffffffL;
-	entry.method = method;
-	entry.relativeOffset = relativeOffset;
-	entry.time = ZipEntry.timeFromDOS(moddate, modtime);
-	if (last == null)
-	 entries = entry;
-	else
-	 last.next = entry;
-	last = entry;
+	entry.zipFileIndex = i;
+	entry.offset = offset;
+	entries[i] = entry;
 }
 }
 
- public java.util.Enumeration entries()
- {
- return new ZipEnumeration(this);
- }
-
+ /**
+ * 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.
+ */
 public void close() throws IOException
 {
- file.close();
 entries = null;
- numEntries = 0;
- if (delete_on_close != null)
-	delete_on_close.delete();
- }
-
- public ZipEntry getEntry(String name)
- {
- for (ZipEntry entry = entries; entry != null; entry = entry.next)
+ synchronized (raf)
 {
-	if (name.equals(entry.getName()))
-	 return entry;
+	raf.close();
 }
- return null;
 }
 
- public InputStream getInputStream(ZipEntry ze) throws IOException
+ /**
+ * Returns an enumeration of all Zip entries in this Zip file.
+ */
+ public Enumeration entries()
 {
- byte[] buffer = new byte[(int) ze.getCompressedSize()];
-
- /* Read the size of the extra field, and skip to the start of the
- data. */
- file.seek (ze.relativeOffset + ZipConstants.LOCAL_FILE_HEADER_SIZE - 2);
- int extraFieldLength = readu2();
- file.skipBytes (ze.getName().length() + extraFieldLength);
-
- file.readFully(buffer);
-
- InputStream is = new ByteArrayInputStream (buffer);
- if (ze.getMethod() == ZipEntry.DEFLATED)
- // Data in zipfile entries does not have a zlib header, so construct
- // an Inflater with the `nowrapper' option.
- is = new InflaterInputStream (is, new Inflater (true), 512);
- return is;
+ if (entries == null)
+ throw new IllegalStateException("ZipFile has closed");
+ return new ZipEntryEnumeration(entries);
 }
 
- public String getName ()
+ private int getEntryIndex(String name)
 {
- return name;
+ for (int i = 0; i < entries.length; i++)
+ if (name.equals(entries[i].getName()))
+	return i;
+ return -1;
 }
 
 /**
- * Returns the number of entries in this ZipFile.
- * @exception IllegalStateException if the ZipFile has been closed.
- *
- * @since 1.2
- */
- public int size ()
+ * 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.
+ * @see #entries */
+ public ZipEntry getEntry(String name)
 {
 if (entries == null)
- throw new IllegalStateException("ZipFile already closed");
- else
- return numEntries;
+ throw new IllegalStateException("ZipFile has closed");
+ int index = getEntryIndex(name);
+ return index >= 0 ? (ZipEntry) entries[index].clone() : null;
 }
 
- protected void finalize () throws IOException
+ /**
+ * Checks, if the local header of the entry at index i matches the
+ * central directory, and returns the offset to the data.
+ * @return the start offset of the (compressed) data.
+ * @exception IOException if a i/o error occured.
+ * @exception ZipException if the local header doesn't match the 
+ * central directory header
+ */
+ private long checkLocalHeader(ZipEntry entry) throws IOException
 {
- close();
- }
+ synchronized (raf)
+ {
+	raf.seek(entry.offset);
+	if (readLeInt() != LOCSIG)
+	 throw new ZipException("Wrong Local header signature");
+
+	/* skip version and flags */
+	if (raf.skipBytes(LOCHOW - LOCVER) != LOCHOW - LOCVER)
+	 throw new EOFException();
+
+	if (entry.getMethod() != readLeShort())
+	 throw new ZipException("Compression method mismatch");
+
+	/* Skip time, crc, size and csize */
+	if (raf.skipBytes(LOCNAM - LOCTIM) != LOCNAM - LOCTIM)
+	 throw new EOFException();
 
- private int readu2 () throws IOException
- {
- int byte0 = file.read();
- int byte1 = file.read();
- if (byte0 < 0 || byte1 < 0)
- throw new ZipException (".zip archive ended prematurely");
- return ((byte1 & 0xFF) << 8) | (byte0 & 0xFF);
- }
+	if (entry.getName().length() != readLeShort())
+	 throw new ZipException("file name length mismatch");
 
- private int read4 () throws IOException
- {
- int byte0 = file.read();
- int byte1 = file.read();
- int byte2 = file.read();
- int byte3 = file.read();
- if (byte3 < 0)
- throw new ZipException (".zip archive ended prematurely");
- return ((byte3 & 0xFF) << 24) + ((byte2 & 0xFF) << 16)
- + ((byte1 & 0xFF) << 8) + (byte0 & 0xFF);
+	int extraLen = entry.getName().length() + readLeShort();
+	return entry.offset + LOCHDR + extraLen;
+ }
 }
 
- ZipEntry entries;
- int numEntries;
- RandomAccessFile file;
- String name;
- /** File to delete on close or null. */
- File delete_on_close;
- 
-}
-
-final class ZipEnumeration implements java.util.Enumeration
-{
- ZipEntry entry;
+ /**
+ * Creates an input stream reading the given zip entry as
+ * uncompressed data. Normally zip entry should be an entry
+ * returned by getEntry() or entries().
+ * @return the input stream.
+ * @exception IOException if a i/o error occured.
+ * @exception ZipException if the Zip archive is malformed. 
+ */
+ public InputStream getInputStream(ZipEntry entry) throws IOException
+ {
+ if (entries == null)
+ throw new IllegalStateException("ZipFile has closed");
+ int index = entry.zipFileIndex;
+ if (index < 0 || index >= entries.length
+	|| entries[index].getName() != entry.getName())
+ {
+	index = getEntryIndex(entry.getName());
+	if (index < 0)
+	 throw new NoSuchElementException();
+ }
 
- ZipEnumeration (ZipFile zfile)
+ long start = checkLocalHeader(entries[index]);
+ int method = entries[index].getMethod();
+ InputStream is = new PartialInputStream
+ (raf, start, entries[index].getCompressedSize());
+ switch (method)
+ {
+ case ZipOutputStream.STORED:
+	return is;
+ case ZipOutputStream.DEFLATED:
+	return new InflaterInputStream(is, new Inflater(true));
+ default:
+	throw new ZipException("Unknown compression method " + method);
+ }
+ }
+ 
+ /**
+ * Returns the name of this zip file.
+ */
+ public String getName()
 {
- entry = zfile.entries;
+ return name;
 }
 
- public boolean hasMoreElements ()
+ /**
+ * Returns the number of entries in this zip file.
+ */
+ public int size()
 {
- return entry != null;
+ try
+ {
+	return entries.length;
+ }
+ catch (NullPointerException ex)
+ {
+	throw new IllegalStateException("ZipFile has closed");
+ }
 }
-
- public Object nextElement ()
+ 
+ private static class ZipEntryEnumeration implements Enumeration
 {
- ZipEntry cur = entry;
- if (cur == null)
- throw new java.util.NoSuchElementException();
- entry = cur.next;
- return cur;
+ ZipEntry[] array;
+ int ptr = 0;
+
+ public ZipEntryEnumeration(ZipEntry[] arr)
+ {
+ array = arr;
+ }
+
+ public boolean hasMoreElements()
+ {
+ return ptr < array.length;
+ }
+
+ public Object nextElement()
+ {
+ try
+	{
+	 /* We return a clone, just to be safe that the user doesn't
+	 * change the entry. 
+	 */
+	 return array[ptr++].clone();
+	}
+ catch (ArrayIndexOutOfBoundsException ex)
+	{
+	 throw new NoSuchElementException();
+	}
+ }
+ }
+
+ private static class PartialInputStream extends InputStream
+ {
+ RandomAccessFile raf;
+ long filepos, end;
+
+ public PartialInputStream(RandomAccessFile raf, long start, long len)
+ {
+ this.raf = raf;
+ filepos = start;
+ end = start + len;
+ }
+ 
+ public int available()
+ {
+ long amount = end - filepos;
+ if (amount > Integer.MAX_VALUE)
+	return Integer.MAX_VALUE;
+ return (int) amount;
+ }
+ 
+ public int read() throws IOException
+ {
+ if (filepos == end)
+	return -1;
+ synchronized (raf)
+	{
+	 raf.seek(filepos++);
+	 return raf.read();
+	}
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException
+ {
+ if (len > end - filepos)
+	{
+	 len = (int) (end - filepos);
+	 if (len == 0)
+	 return -1;
+	}
+ synchronized (raf)
+	{
+	 raf.seek(filepos);
+	 int count = raf.read(b, off, len);
+	 if (count > 0)
+	 filepos += len;
+	 return count;
+	}
+ }
+
+ public long skip(long amount)
+ {
+ if (amount < 0)
+	throw new IllegalArgumentException();
+ if (amount > end - filepos)
+	amount = end - filepos;
+ filepos += amount;
+ return amount;
+ }
 }
 }
Index: java/util/zip/ZipInputStream.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/zip/ZipInputStream.java,v
retrieving revision 1.13
diff -u -r1.13 ZipInputStream.java
--- java/util/zip/ZipInputStream.java 22 Jan 2002 22:40:41 -0000 1.13
+++ java/util/zip/ZipInputStream.java 4 Jun 2002 18:14:46 -0000
@@ -1,5 +1,5 @@
-/* ZipInputStream.java - Input filter for reading zip file
- Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+/* java.util.zip.ZipInputStream
+ Copyright (C) 2001, 2002 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -7,7 +7,7 @@
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
- 
+
 GNU Classpath is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -36,259 +36,327 @@
 exception statement from your version. */
 
 package java.util.zip;
-import java.io.*;
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Enumeration;
 
 /**
- * @author Per Bothner
- * @date May 1999.
- */
-
-/*
- * Written using on-line Java Platform 1.2 API Specification, as well
- * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
- * Status: Quite incomplete, but can read uncompressed .zip archives.
+ * This is a FilterInputStream that reads the files in an zip archive
+ * one after another. It has a special method to get the zip entry of
+ * the next file. The zip entry contains information about the file name
+ * size, compressed size, CRC, etc.
+ *
+ * It includes support for STORED and DEFLATED entries.
+ *
+ * @author Jochen Hoenicke
 */
-
-// We do not calculate the CRC and compare it with the specified value;
-// we probably should. FIXME.
- 
-
 public class ZipInputStream extends InflaterInputStream implements ZipConstants
 {
- public ZipInputStream (InputStream in)
+ private CRC32 crc = new CRC32();
+ private ZipEntry entry = null;
+
+ private int csize;
+ private int size;
+ private int method;
+ private int flags;
+ private int avail;
+
+ /**
+ * Creates a new Zip input stream, reading a zip archive.
+ */
+ public ZipInputStream(InputStream in)
 {
- super (in, new Inflater (true));
+ super(in, new Inflater(true));
 }
 
- public ZipEntry getNextEntry () throws IOException
+ private void fillBuf() throws IOException
 {
- if (closed)
- throw new IOException ("stream closed");
- if (current != null)
- closeEntry();
- if (in.read() != 'P'
-	|| in.read() != 'K')
- return null;
- int code = in.read();
- while (code == '001円')
- {
-	code = in.read();
-	if (code != '002円')
-	 return null;
-	in.skip(16);
-	int size = read4();
-	in.skip(4);
-	int fname_length = readu2();
-	int extra_length = readu2();
-	int fcomment_length = readu2();
-	// `12' is the number of bytes between the comment length
-	// field and the end of the fixed part of the header:
-	// 2 bytes for `disk number start'
-	// 2 bytes for `internal file attributes'
-	// 4 bytes for `external file attributes'
-	// 4 bytes for `relative offset of local header'
-	in.skip(12 + fname_length + extra_length + fcomment_length);
-	if (in.read() != 'P' || in.read() != 'K')
-	 return null;
-	code = in.read();
- }
- if (code == '005円')
- {
-	if (in.read() != '006円')
-	 return null;
-	in.skip(16);
-	int comment_size = readu2();
-	in.skip(comment_size);
-	if (in.read() != 'P' || in.read() != 'K')
-	 return null;
-	code = in.read();
- }
- if (code != '003円'
-	|| in.read() != '004円')
- return null;
- int ex_version = readu2();
- current_flags = readu2();
- int method = readu2();
- int modtime = readu2();
- int moddate = readu2();
- int crc = read4();
- int compressedSize = read4();
- int uncompressedSize = read4();
- int filenameLength = readu2();
- int extraLength = readu2();
- byte[] bname = new byte[filenameLength];
- readFully(bname);
- ZipEntry entry = createZipEntry(new String(bname, "8859_1"));
- if (extraLength > 0)
- {
-	byte[] bextra = new byte[extraLength];
-	readFully(bextra);
-	entry.extra = bextra;
- }
- entry.compressedSize = compressedSize;
- entry.size = uncompressedSize;
- entry.crc = (long) crc & 0xffffffffL;
- entry.method = method;
- entry.time = ZipEntry.timeFromDOS(moddate, modtime);
- current = entry;
- avail = uncompressedSize;
- compressed_bytes = compressedSize;
- return entry;
+ avail = len = in.read(buf, 0, buf.length);
 }
 
- // We override fill to let us control how much data gets read from
- // the underlying input stream. This lets us avoid having to push
- // back data.
- protected void fill () throws IOException
- {
- if (closed)
- throw new IOException ("stream closed");
- int count = buf.length;
- if (count > compressed_bytes)
- count = compressed_bytes;
- len = in.read(buf, 0, count);
- if (len != -1)
+ private int readBuf(byte[] out, int offset, int length) throws IOException
+ {
+ if (avail <= 0)
 {
-	compressed_bytes -= len;
-	inf.setInput(buf, 0, len);
+	fillBuf();
+	if (avail <= 0)
+	 return -1;
 }
+ if (length > avail)
+ length = avail;
+ System.arraycopy(buf, len - avail, out, offset, length);
+ avail -= length;
+ return length;
+ }
+ 
+ private void readFully(byte[] out) throws IOException
+ {
+ int off = 0;
+ int len = out.length;
+ while (len > 0)
+ {
+	int count = readBuf(out, off, len);
+	if (count == -1)
+	 throw new EOFException();
+	off += count;
+	len -= count;
+ }
+ }
+ 
+ private final int readLeByte() throws IOException
+ {
+ if (avail <= 0)
+ {
+	fillBuf();
+	if (avail <= 0)
+	 throw new ZipException("EOF in header");
+ }
+ return buf[len - avail--] & 0xff;
 }
 
 /**
- * Creates a new ZipEntry with the given name.
- * Used by ZipInputStream when normally <code>new ZipEntry (name)</code>
- * would be called. This gives subclasses such as JarInputStream a change
- * to override this method and add aditional information to the ZipEntry
- * (subclass).
+ * Read an unsigned short in little endian byte order.
 */
- protected ZipEntry createZipEntry (String name)
+ private final int readLeShort() throws IOException 
 {
- return new ZipEntry (name);
+ return readLeByte() | (readLeByte() << 8);
 }
 
- public int read (byte[] b, int off, int len) throws IOException
+ /**
+ * Read an int in little endian byte order.
+ */
+ private final int readLeInt() throws IOException 
 {
- if (closed)
- throw new IOException ("stream closed");
- if (len > avail)
- len = avail;
- int count;
- if (current.method == Deflater.DEFLATED)
- count = super.read(b, off, len);
- else
- count = in.read(b, off, len);
- if (count == -1 || avail == 0)
+ return readLeShort() | (readLeShort() << 16);
+ }
+
+ /**
+ * Open the next entry from the zip archive, and return its description.
+ * If the previous entry wasn't closed, this method will close it.
+ */
+ public ZipEntry getNextEntry() throws IOException
+ {
+ if (crc == null)
+ throw new IllegalStateException("Closed.");
+ if (entry != null)
+ closeEntry();
+
+ int header = readLeInt();
+ if (header == CENSIG)
 {
-	inf.reset();
-	count = -1;
+	/* Central Header reached. */
+	close();
+	return null;
 }
- else
- avail -= count;
- return count;
+ if (header != LOCSIG)
+ throw new ZipException("Wrong Local header signature" + Integer.toHexString(header));
+ /* skip version */
+ readLeShort();
+ flags = readLeShort();
+ method = readLeShort();
+ int dostime = readLeInt();
+ int crc = readLeInt();
+ csize = readLeInt();
+ size = readLeInt();
+ int nameLen = readLeShort();
+ int extraLen = readLeShort();
+
+ if (method == ZipOutputStream.STORED && csize != size)
+ throw new ZipException("Stored, but compressed != uncompressed");
+
+
+ byte[] buffer = new byte[nameLen];
+ readFully(buffer);
+ String name = new String(buffer);
+ 
+ entry = createZipEntry(name);
+ entry.setMethod(method);
+ if ((flags & 8) == 0)
+ {
+	entry.setCrc(crc & 0xffffffffL);
+	entry.setSize(size & 0xffffffffL);
+	entry.setCompressedSize(csize & 0xffffffffL);
+ }
+ entry.setDOSTime(dostime);
+ if (extraLen > 0)
+ {
+	byte[] extra = new byte[extraLen];
+	readFully(extra);
+	entry.setExtra(extra);
+ }
+
+ if (method == ZipOutputStream.DEFLATED && avail > 0)
+ {
+	System.arraycopy(buf, len - avail, buf, 0, avail);
+	len = avail;
+	avail = 0;
+	inf.setInput(buf, 0, len);
+ }
+ return entry;
 }
 
- public long skip (long n) throws IOException
+ private void readDataDescr() throws IOException
 {
- if (closed)
- throw new IOException ("stream closed");
- if (n > avail)
- n = avail;
- long count;
- if (current.method == Deflater.DEFLATED)
- count = super.skip(n);
- else
- count = in.skip(n);
- avail = avail - (int) count;
- return count;
+ if (readLeInt() != EXTSIG)
+ throw new ZipException("Data descriptor signature not found");
+ entry.setCrc(readLeInt() & 0xffffffffL);
+ csize = readLeInt();
+ size = readLeInt();
+ entry.setSize(size & 0xffffffffL);
+ entry.setCompressedSize(csize & 0xffffffffL);
 }
 
 /**
- * Returns 0 if the ZipInputStream is closed and 1 otherwise.
- *
- * @since 1.2
+ * Closes the current zip entry and moves to the next one.
 */
- public int available()
+ public void closeEntry() throws IOException
 {
- return closed ? 0 : 1;
- }
+ if (crc == null)
+ throw new IllegalStateException("Closed.");
+ if (entry == null)
+ return;
 
- private void readFully (byte[] b) throws IOException
- {
- int off = 0;
- int len = b.length;
- while (len > 0)
+ if (method == ZipOutputStream.DEFLATED)
 {
-	int count = in.read(b, off, len);
-	if (count <= 0)
-	 throw new EOFException(".zip archive ended prematurely");
-	off += count;
-	len -= count;
+	if ((flags & 8) != 0)
+	 {
+	 /* We don't know how much we must skip, read until end. */
+	 byte[] tmp = new byte[2048];
+	 while (read(tmp) > 0)
+	 ;
+	 /* read will close this entry */
+	 return;
+	 }
+	csize -= inf.getTotalIn();
+	avail = inf.getRemaining();
+ }
+
+ if (avail > csize && csize >= 0)
+ avail -= csize;
+ else
+ {
+	csize -= avail;
+	avail = 0;
+	while (csize != 0)
+	 {
+	 long skipped = in.skip(csize & 0xffffffffL);
+	 if (skipped <= 0)
+	 throw new ZipException("zip archive ends early.");
+	 csize -= skipped;
+	 }
 }
+
+ size = 0;
+ crc.reset();
+ if (method == ZipOutputStream.DEFLATED)
+ inf.reset();
+ entry = null;
 }
 
- private int readu2 () throws IOException
+ public int available() throws IOException
 {
- int byte0 = in.read();
- int byte1 = in.read();
- if (byte0 < 0 || byte1 < 0)
- throw new EOFException(".zip archive ended prematurely");
- return ((byte1 & 0xFF) << 8) | (byte0 & 0xFF);
+ return entry != null ? 1 : 0;
 }
 
- private int read4 () throws IOException
+ /**
+ * Reads a byte from the current zip entry.
+ * @return the byte or -1 on EOF.
+ * @exception IOException if a i/o error occured.
+ * @exception ZipException if the deflated stream is corrupted.
+ */
+ public int read() throws IOException
 {
- int byte0 = in.read();
- int byte1 = in.read();
- int byte2 = in.read();
- int byte3 = in.read();
- if (byte3 < 0)
- throw new EOFException(".zip archive ended prematurely");
- return ((byte3 & 0xFF) << 24) + ((byte2 & 0xFF) << 16)
- + ((byte1 & 0xFF) << 8) + (byte0 & 0xFF);
+ byte[] b = new byte[1];
+ if (read(b, 0, 1) <= 0)
+ return -1;
+ return b[0] & 0xff;
 }
 
- public void closeEntry () throws IOException
+ /**
+ * Reads a block of bytes from the current zip entry.
+ * @return the number of bytes read (may be smaller, even before
+ * EOF), or -1 on EOF.
+ * @exception IOException if a i/o error occured.
+ * @exception ZipException if the deflated stream is corrupted.
+ */
+ public int read(byte[] b, int off, int len) throws IOException
 {
- if (current != null)
+ if (crc == null)
+ throw new IllegalStateException("Closed.");
+ if (entry == null)
+ return -1;
+ boolean finished = false;
+ switch (method)
 {
-	if (avail > 0)
-	 skip (avail);
-	if ((current_flags & 8) != 0)
+ case ZipOutputStream.DEFLATED:
+	len = super.read(b, off, len);
+	if (len < 0)
 	 {
-	 int sig = read4();
-	 if (sig != 0x04034b50)
-	 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 ZipException("bad data descriptor at end of .zip entry");
+	 if (!inf.finished())
+	 throw new ZipException("Inflater not finished!?");
+	 avail = inf.getRemaining();
+	 if ((flags & 8) != 0)
+	 readDataDescr();
+
+	 if (inf.getTotalIn() != csize
+		|| inf.getTotalOut() != size)
+	 throw new ZipException("size mismatch: "+csize+";"+size+" <-> "+inf.getTotalIn()+";"+inf.getTotalOut());
+	 inf.reset();
+	 finished = true;
 	 }
-	current = null;
-	avail = 0;
+	break;
+	
+ case ZipOutputStream.STORED:
+
+	if (len > csize && csize >= 0)
+	 len = csize;
+	
+	len = readBuf(b, off, len);
+	if (len > 0)
+	 {
+	 csize -= len;
+	 size -= len;
+	 }
+
+	if (csize == 0)
+	 finished = true;
+	else if (len < 0)
+	 throw new ZipException("EOF in stored block");
+	break;
+ }
+
+ if (len > 0)
+ crc.update(b, off, len);
+
+ if (finished)
+ {
+	if ((crc.getValue() & 0xffffffffL) != entry.getCrc())
+	 throw new ZipException("CRC mismatch");
+	crc.reset();
+	entry = null;
 }
+ return len;
 }
 
 /**
- * Closes this InflaterInputStream.
- *
- * @since 1.2
+ * Closes the zip file.
+ * @exception IOException if a i/o error occured.
 */
- public void close () throws IOException
+ public void close() throws IOException
 {
- current = null;
- closed = true;
 super.close();
+ crc = null;
+ entry = null;
 }
 
- private ZipEntry current;
- private int current_flags;
- // Number of uncompressed bytes to be read.
- private int avail;
- // Number of bytes we can read from underlying stream.
- private int compressed_bytes;
- // Is this ZipInputStream closed? Set by the close() method.
- private boolean closed = false;
+ /**
+ * Creates a new zip entry for the given name. This is equivalent
+ * to new ZipEntry(name).
+ * @param name the name of the zip entry.
+ */
+ protected ZipEntry createZipEntry(String name) 
+ {
+ return new ZipEntry(name);
+ }
 }
Index: java/util/zip/ZipOutputStream.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/zip/ZipOutputStream.java,v
retrieving revision 1.11
diff -u -r1.11 ZipOutputStream.java
--- java/util/zip/ZipOutputStream.java 22 Jan 2002 22:40:41 -0000 1.11
+++ java/util/zip/ZipOutputStream.java 4 Jun 2002 18:14:46 -0000
@@ -1,5 +1,5 @@
-/* ZipOutputStream.java - Create a file in zip format
- Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+/* java.util.zip.ZipOutputStream
+ Copyright (C) 2001 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -7,7 +7,7 @@
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
- 
+
 GNU Classpath is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
@@ -36,286 +36,362 @@
 exception statement from your version. */
 
 package java.util.zip;
-
-import java.io.*;
-
-/* Written using on-line Java Platform 1.2 API Specification
- * and JCL book.
- * Believed complete and correct.
+import java.io.OutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Vector;
+import java.util.Enumeration;
+
+/**
+ * This is a FilterOutputStream that writes the files into a zip
+ * archive one after another. It has a special method to start a new
+ * zip entry. The zip entries contains information about the file name
+ * size, compressed size, CRC, etc.
+ *
+ * It includes support for STORED and DEFLATED entries.
+ *
+ * This class is not thread safe.
+ *
+ * @author Jochen Hoenicke 
 */
-
-public class ZipOutputStream extends DeflaterOutputStream
- implements ZipConstants
+public class ZipOutputStream extends DeflaterOutputStream implements ZipConstants
 {
- public static final int STORED = 0;
- public static final int DEFLATED = 8;
-
- public void close () throws IOException
- {
- finish ();
- out.close();
- }
-
- public void closeEntry () throws IOException
- {
- int compressed_size;
- if (current.method == STORED)
- {
-	compressed_size = uncompressed_size;
- }
- else
- {
-	super.finish();
-	compressed_size = def.getTotalOut();
- }
- long crc = sum.getValue();
-
- bytes_written += compressed_size;
-
- if (current.getCrc() == -1 || current.getCompressedSize() == -1
-	|| current.getSize() == -1)
- {
-	current.setCrc(crc);
-	current.compressedSize = compressed_size;
-	current.setSize(uncompressed_size);
-	put4 (0x08074b50);
-	put4 ((int) (current.getCrc()));
-	put4 ((int) (current.getCompressedSize()));
-	put4 ((int) (current.getSize()));
-	bytes_written += 16;
- }
- else if (current.getCrc() != crc
-	 || current.getCompressedSize() != compressed_size
-	 || current.getSize() != uncompressed_size)
- throw new ZipException ("zip entry field incorrect");
-
- current.next = chain;
- chain = current;
- current = null;
- }
-
- public void write (int bval) throws IOException
- {
- if (current.method == STORED)
- {
-	out.write(bval);
- }
- else
- super.write(bval);
- sum.update(bval);
- uncompressed_size += 1;
- }
+ private Vector entries = new Vector();
+ private CRC32 crc = new CRC32();
+ private ZipEntry curEntry = null;
+
+ private int curMethod;
+ private int size;
+ private int offset = 0;
+
+ private byte[] zipComment = new byte[0];
+ private int defaultMethod = DEFLATED;
+
+ /**
+ * Our Zip version is hard coded to 1.0 resp. 2.0
+ */
+ private final static int ZIP_STORED_VERSION = 10;
+ private final static int ZIP_DEFLATED_VERSION = 20;
+
+ /**
+ * Compression method. This method doesn't compress at all.
+ */
+ public final static int STORED = 0;
+ /**
+ * Compression method. This method uses the Deflater.
+ */
+ public final static int DEFLATED = 8;
+
+ /**
+ * Creates a new Zip output stream, writing a zip archive.
+ * @param out the output stream to which the zip archive is written.
+ */
+ public ZipOutputStream(OutputStream out)
+ {
+ super(out, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
+ }
+
+ /**
+ * Set the zip file comment.
+ * @param comment the comment.
+ * @exception IllegalArgumentException if encoding of comment is
+ * longer than 0xffff bytes.
+ */
+ public void setComment(String comment)
+ {
+ byte[] commentBytes;
+ commentBytes = comment.getBytes();
+ if (commentBytes.length > 0xffff)
+ throw new IllegalArgumentException("Comment too long.");
+ zipComment = commentBytes;
+ }
+ 
+ /**
+ * Sets default compression method. If the Zip entry specifies
+ * another method its method takes precedence.
+ * @param method the method.
+ * @exception IllegalArgumentException if method is not supported.
+ * @see #STORED
+ * @see #DEFLATED
+ */
+ public void setMethod(int method)
+ {
+ if (method != STORED && method != DEFLATED)
+ throw new IllegalArgumentException("Method not supported.");
+ defaultMethod = method;
+ }
+
+ /**
+ * Sets default compression level. The new level will be activated
+ * immediately. 
+ * @exception IllegalArgumentException if level is not supported.
+ * @see Deflater
+ */
+ public void setLevel(int level)
+ {
+ def.setLevel(level);
+ }
+ 
+ /**
+ * Write an unsigned short in little endian byte order.
+ */
+ private final void writeLeShort(int value) throws IOException 
+ {
+ out.write(value & 0xff);
+ out.write((value >> 8) & 0xff);
+ }
+
+ /**
+ * Write an int in little endian byte order.
+ */
+ private final void writeLeInt(int value) throws IOException 
+ {
+ writeLeShort(value);
+ writeLeShort(value >> 16);
+ }
+
+ /**
+ * Starts a new Zip entry. It automatically closes the previous
+ * entry if present. If the compression method is stored, the entry
+ * must have a valid size and crc, otherwise all elements (except
+ * name) are optional, but must be correct if present. If the time
+ * is not set in the entry, the current time is used.
+ * @param entry the entry.
+ * @exception IOException if an I/O error occured.
+ * @exception IllegalStateException if stream was finished
+ */
+ public void putNextEntry(ZipEntry entry) throws IOException
+ {
+ if (entries == null)
+ throw new IllegalStateException("ZipOutputStream was finished");
+
+ int method = entry.getMethod();
+ int flags = 0;
+ if (method == -1)
+ method = defaultMethod;
 
- public void write (byte[] buf, int off, int len) throws IOException
- {
- if (current.method == STORED)
- out.write(buf, off, len);
- else
- super.write(buf, off, len);
- sum.update(buf, off, len);
- uncompressed_size += len;
- }
-
- public void finish () throws IOException
- {
- if (current != null)
- 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);
- put2 (count);
- put4 (bytes);
- put4 ((int) offset);
-
- byte[] c = comment.getBytes("8859_1");
- put2 (c.length);
- out.write(c);
- }
-
- // Helper for finish and putNextEntry.
- private int write_entry (ZipEntry entry, boolean is_local)
- throws IOException
- {
- int bytes = put4 (is_local ? 0x04034b50 : 0x02014b50);
- if (! is_local)
- bytes += put_version ();
- bytes += put_version ();
-
- boolean crc_after = false;
- if (is_local
-	&& (entry.getCrc() == -1 || entry.getCompressedSize() == -1
-	 || entry.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
+ if (method == STORED)
 {
-	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
+	if (entry.getCompressedSize() >= 0)
 	 {
-	 comment = entry.getComment().getBytes("8859_1");
-	 bytes += put2 (comment.length);
+	 if (entry.getSize() < 0)
+	 entry.setSize(entry.getCompressedSize());
+	 else if (entry.getSize() != entry.getCompressedSize())
+	 throw new ZipException
+		("Method STORED, but compressed size != size");
 	 }
+	else
+	 entry.setCompressedSize(entry.getSize());
 
-	// Disk number start.
-	bytes += put2 (0);
-	// Internal file attributes.
-	bytes += put2 (0);
-	// External file attributes.
-	bytes += put4 (0);
-	// Relative offset of local header.
-	bytes += put4 ((int) entry.relativeOffset);
- }
-
- out.write (name);
- bytes += name.length;
- if (entry.extra != null)
- {
-	out.write(entry.extra);
-	bytes += entry.extra.length;
+	if (entry.getSize() < 0)
+	 throw new ZipException("Method STORED, but size not set");
+	if (entry.getCrc() < 0)
+	 throw new ZipException("Method STORED, but crc not set");
+ }
+ else if (method == DEFLATED)
+ {
+	if (entry.getCompressedSize() < 0
+	 || entry.getSize() < 0 || entry.getCrc() < 0)
+	 flags |= 8;
+ }
+
+ if (curEntry != null)
+ closeEntry();
+
+ if (entry.getTime() < 0)
+ entry.setTime(System.currentTimeMillis());
+
+ entry.flags = flags;
+ entry.offset = offset;
+ entry.setMethod(method);
+ curMethod = method;
+ /* Write the local file header */
+ writeLeInt(LOCSIG);
+ writeLeShort(method == STORED
+		 ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION);
+ writeLeShort(flags);
+ writeLeShort(method);
+ writeLeInt(entry.getDOSTime());
+ if ((flags & 8) == 0)
+ {
+	writeLeInt((int)entry.getCrc());
+	writeLeInt((int)entry.getCompressedSize());
+	writeLeInt((int)entry.getSize());
 }
- if (comment != null)
+ else
 {
-	out.write(comment);
-	bytes += comment.length;
- }
-
- bytes_written += bytes;
- return bytes;
- }
-
- public void putNextEntry (ZipEntry entry) throws IOException
- {
- if (current != null)
- closeEntry ();
+	writeLeInt(0);
+	writeLeInt(0);
+	writeLeInt(0);
+ }
+ byte[] name = entry.getName().getBytes();
+ if (name.length > 0xffff)
+ throw new ZipException("Name too long.");
+ byte[] extra = entry.getExtra();
+ if (extra == null)
+ extra = new byte[0];
+ writeLeShort(name.length);
+ writeLeShort(extra.length);
+ out.write(name);
+ out.write(extra);
+
+ offset += LOCHDR + name.length + extra.length;
+
+ /* Activate the entry. */
+
+ curEntry = entry;
+ crc.reset();
+ if (method == DEFLATED)
+ def.reset();
+ size = 0;
+ }
+
+ /**
+ * Closes the current entry.
+ * @exception IOException if an I/O error occured.
+ * @exception IllegalStateException if no entry is active.
+ */
+ public void closeEntry() throws IOException
+ {
+ if (curEntry == null)
+ throw new IllegalStateException("No open entry");
+
+ /* First finish the deflater, if appropriate */
+ if (curMethod == DEFLATED)
+ super.finish();
+
+ int csize = curMethod == DEFLATED ? def.getTotalOut() : size;
+
+ if (curEntry.getSize() < 0)
+ curEntry.setSize(size);
+ else if (curEntry.getSize() != size)
+ throw new ZipException("size was "+size
+			 +", but I expected "+curEntry.getSize());
+
+ if (curEntry.getCompressedSize() < 0)
+ curEntry.setCompressedSize(csize);
+ else if (curEntry.getCompressedSize() != csize)
+ throw new ZipException("compressed size was "+csize
+			 +", but I expected "+curEntry.getSize());
+
+ if (curEntry.getCrc() < 0)
+ curEntry.setCrc(crc.getValue());
+ else if (curEntry.getCrc() != crc.getValue())
+ throw new ZipException("crc was " + Long.toHexString(crc.getValue())
+			 + ", but I expected " 
+			 + Long.toHexString(curEntry.getCrc()));
+
+ offset += csize;
+
+ /* Now write the data descriptor entry if needed. */
+ if (curMethod == DEFLATED && (curEntry.flags & 8) != 0)
+ {
+	writeLeInt(EXTSIG);
+	writeLeInt((int)curEntry.getCrc());
+	writeLeInt((int)curEntry.getCompressedSize());
+	writeLeInt((int)curEntry.getSize());
+	offset += EXTHDR;
+ }
+
+ entries.addElement(curEntry);
+ curEntry = null;
+ }
+
+ /**
+ * Writes the given buffer to the current entry.
+ * @exception IOException if an I/O error occured.
+ * @exception IllegalStateException if no entry is active.
+ */
+ public void write(byte[] b, int off, int len) throws IOException
+ {
+ if (curEntry == null)
+ throw new IllegalStateException("No open entry.");
+
+ switch (curMethod)
+ {
+ case DEFLATED:
+	super.write(b, off, len);
+	break;
+	
+ case STORED:
+	out.write(b, off, len);
+	break;
+ }
+
+ crc.update(b, off, len);
+ size += len;
+ }
+
+ /**
+ * Finishes the stream. This will write the central directory at the
+ * end of the zip file and flush the stream.
+ * @exception IOException if an I/O error occured.
+ */
+ public void finish() throws IOException
+ {
+ if (entries == null)
+ return;
+ if (curEntry != null)
+ closeEntry();
+
+ int numEntries = 0;
+ int sizeEntries = 0;
+ 
+ Enumeration enum = entries.elements();
+ while (enum.hasMoreElements())
+ {
+	ZipEntry entry = (ZipEntry) enum.nextElement();
+	
+	int method = entry.getMethod();
+	writeLeInt(CENSIG);
+	writeLeShort(method == STORED
+		 ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION);
+	writeLeShort(method == STORED
+		 ? ZIP_STORED_VERSION : ZIP_DEFLATED_VERSION);
+	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();
+	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];
+	if (comment.length > 0xffff)
+	 throw new ZipException("Comment too long.");
+
+	writeLeShort(name.length);
+	writeLeShort(extra.length);
+	writeLeShort(comment.length);
+	writeLeShort(0); /* disk number */
+	writeLeShort(0); /* internal file attr */
+	writeLeInt(0); /* external file attr */
+	writeLeInt(entry.offset);
 
- if (entry.method < 0 )
- entry.method = method;
- 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();
+	out.write(name);
+	out.write(extra);
+	out.write(comment);
+	numEntries++;
+	sizeEntries += CENHDR + name.length + extra.length + comment.length;
 }
- entry.relativeOffset = bytes_written;
- write_entry (entry, true);
- current = entry;
- int compr = (method == STORED) ? Deflater.NO_COMPRESSION : level;
- def.reset();
- def.setLevel(compr);
- sum.reset();
- uncompressed_size = 0;
- }
 
- public void setLevel (int level)
- {
- if (level != Deflater.DEFAULT_COMPRESSION
-	&& (level < Deflater.NO_COMPRESSION
-	 || level > Deflater.BEST_COMPRESSION))
- throw new IllegalArgumentException ();
- this.level = level;
+ writeLeInt(ENDSIG);
+ writeLeShort(0); /* disk number */
+ writeLeShort(0); /* disk with start of central dir */
+ writeLeShort(numEntries);
+ writeLeShort(numEntries);
+ writeLeInt(sizeEntries);
+ writeLeInt(offset);
+ writeLeShort(zipComment.length);
+ out.write(zipComment);
+ out.flush();
+ entries = null;
 }
-
- 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 ZipOutputStream (OutputStream out)
- {
- super (out, new Deflater (Deflater.DEFAULT_COMPRESSION, true), 8192);
- sum = new CRC32 ();
- }
-
- private int put2 (int i) throws IOException
- {
- out.write (i);
- out.write (i >> 8);
- return 2;
- }
-
- 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;
-
- private int method = DEFLATED;
- private int level = Deflater.DEFAULT_COMPRESSION;
- private String comment = "";
- private long bytes_written;
-
- private int uncompressed_size;
-
- /** The checksum object. */
- private Checksum sum;
 }
Index: java/util/zip/natDeflater.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/zip/natDeflater.cc,v
retrieving revision 1.7
diff -u -r1.7 natDeflater.cc
--- java/util/zip/natDeflater.cc 26 Mar 2001 07:05:32 -0000 1.7
+++ java/util/zip/natDeflater.cc 4 Jun 2002 18:14:46 -0000
@@ -1,6 +1,6 @@
 // natDeflater.cc - Implementation of Deflater native methods.
 
-/* Copyright (C) 1999 Free Software Foundation
+/* Copyright (C) 1999, 2002 Free Software Foundation
 
 This file is part of libgcj.
 
@@ -125,6 +125,7 @@
 // Just ignore errors.
 deflateReset (s);
 flush_flag = 0;
+ is_finished = false;
 }
 
 void
Index: java/util/zip/natInflater.cc
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/zip/natInflater.cc,v
retrieving revision 1.9
diff -u -r1.9 natInflater.cc
--- java/util/zip/natInflater.cc 26 Mar 2001 07:05:32 -0000 1.9
+++ java/util/zip/natInflater.cc 4 Jun 2002 18:14:46 -0000
@@ -1,6 +1,6 @@
 // natInflater.cc - Implementation of Inflater native methods.
 
-/* Copyright (C) 1999 Free Software Foundation
+/* Copyright (C) 1999, 2002 Free Software Foundation
 
 This file is part of libgcj.
 
@@ -149,6 +149,8 @@
 z_streamp s = (z_streamp) zstream;
 // Just ignore errors.
 inflateReset (s);
+ is_finished = false;
+ dict_needed = false;
 }
 
 void


More information about the Java mailing list

AltStyle によって変換されたページ (->オリジナル) /