summaryrefslogtreecommitdiffstats
path: root/libjava/java/util/zip/ZipOutputStream.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/java/util/zip/ZipOutputStream.java')
-rw-r--r--libjava/java/util/zip/ZipOutputStream.java263
1 files changed, 233 insertions, 30 deletions
diff --git a/libjava/java/util/zip/ZipOutputStream.java b/libjava/java/util/zip/ZipOutputStream.java
index 18f4d388652..f4ce7accc01 100644
--- a/libjava/java/util/zip/ZipOutputStream.java
+++ b/libjava/java/util/zip/ZipOutputStream.java
@@ -9,65 +9,268 @@ details. */
package java.util.zip;
import java.io.*;
-/** JUST AN INCOMPLETE STUB! */
+/* Written using on-line Java Platform 1.2 API Specification
+ * and JCL book.
+ * Believed complete and correct.
+ */
public class ZipOutputStream extends DeflaterOutputStream
implements ZipConstants
{
- ZipEntry current;
- int method = DEFLATED;
- int level = 3; // FIXME - should be DEFAULT_COMPRESSION
- String comment;
-
public static final int STORED = 0;
public static final int DEFLATED = 8;
- public ZipOutputStream (OutputStream out)
+ public void close () throws IOException
{
- super(out);
+ finish ();
+ out.close();
+ }
+
+ public void closeEntry () throws IOException
+ {
+ int uncompressed_size = def.getTotalIn();
+ int compressed_size = def.getTotalOut();
+ int crc = (int) (filter.getChecksum().getValue());
+
+ bytes_written += compressed_size;
+
+ bytes_written += put4 (0x08074b50);
+ if (current.getCrc() == -1 || current.getCompressedSize() == -1
+ || current.getSize() == -1)
+ {
+ current.setCrc(crc);
+ current.compressedSize = compressed_size;
+ current.setSize(uncompressed_size);
+ }
+ else
+ {
+ if (current.getCrc() != crc
+ || current.getCompressedSize() != compressed_size
+ || current.getSize() != uncompressed_size)
+ throw new ZipException ("zip entry field incorrect");
+ }
+ bytes_written += put4 ((int) (current.getCrc()));
+ bytes_written += put4 ((int) (current.getCompressedSize()));
+ bytes_written += put4 ((int) (current.getSize()));
+
+ current.next = chain;
+ chain = current;
+ current = null;
+ filter = null;
+ }
+
+ public void finish () throws IOException
+ {
+ if (current != null)
+ closeEntry ();
+
+ // Write the central directory.
+ long offset = bytes_written;
+ int count = 0;
+ int bytes = 0;
+ while (chain != null)
+ {
+ bytes += write_entry (chain, false);
+ ++count;
+ chain = chain.next;
+ }
+
+ // Write the end of the central directory record.
+ put4 (0x06054b50);
+ // Disk number.
+ put2 (0);
+ // Another disk number.
+ put2 (0);
+ put2 (count);
+ put4 (bytes);
+ put4 ((int) offset);
+
+ byte[] c = comment.getBytes("8859_1");
+ put2 (c.length);
+ out.write(c);
+ out.write((byte) 0);
}
- public void setLevel (int level) { this.level = level; }
- public void setMethod (int method) { this.method = method; }
- public void setComment(String comment) { this.comment = comment; }
+ // Helper for finish and putNextEntry.
+ private int write_entry (ZipEntry entry, boolean is_local)
+ throws IOException
+ {
+ long offset = bytes_written;
+
+ int bytes = put4 (is_local ? 0x04034b50 : 0x02014b50);
+ if (! is_local)
+ bytes += put_version ();
+ bytes += put_version ();
+
+ boolean crc_after = false;
+ if (is_local
+ && (current.getCrc() == -1 || current.getCompressedSize() == -1
+ || current.getSize() == -1))
+ crc_after = true;
+ // For the bits field we always indicate `normal' compression,
+ // even if that isn't true.
+ bytes += put2 (crc_after ? (1 << 3) : 0);
+ bytes += put2 (entry.method);
+
+ bytes += put2(0); // time - FIXME
+ bytes += put2(0); // date - FIXME
+
+ if (crc_after)
+ {
+ // CRC, compressedSize, and Size are always 0 in this header.
+ // The actual values are given after the entry.
+ bytes += put4 (0);
+ bytes += put4 (0);
+ bytes += put4 (0);
+ }
+ else
+ {
+ bytes += put4 ((int) (entry.getCrc()));
+ bytes += put4 ((int) (entry.getCompressedSize()));
+ bytes += put4 ((int) (entry.getSize()));
+ }
+
+ byte[] name = entry.name.getBytes("8859_1");
+ bytes += put2 (name.length);
+ bytes += put2 (entry.extra == null ? 0 : entry.extra.length);
+
+ byte[] comment = null;
+ if (! is_local)
+ {
+ if (entry.getComment() == null)
+ bytes += put2 (0);
+ else
+ {
+ comment = entry.getComment().getBytes("8859_1");
+ bytes += put2 (comment.length);
+ }
+
+ // Disk number start.
+ bytes += put2 (0);
+ // Internal file attributes.
+ bytes += put2 (0);
+ // External file attributes.
+ bytes += put2 (0);
+ // Relative offset of local header.
+ bytes += put2 ((int) offset);
+ }
+
+ out.write (name);
+ out.write ((byte) 0);
+ bytes += name.length + 1;
+ if (entry.extra != null)
+ {
+ out.write(entry.extra);
+ out.write((byte) 0);
+ bytes += entry.extra.length + 1;
+ }
+ if (comment != null)
+ {
+ out.write(comment);
+ out.write((byte) 0);
+ bytes += comment.length + 1;
+ }
+
+ bytes_written += bytes;
+ return bytes;
+ }
public void putNextEntry (ZipEntry entry) throws IOException
{
- put4(0x04034b50);
- put2(0); // version - FIXME
- put2(0); // bits - FIXME
+ if (current != null)
+ closeEntry ();
+
if (entry.method < 0 )
entry.method = method;
- put2(entry.method);
- put2(0); // time - FIXME
- put2(0); // date - FIXME
- put4((int) entry.crc);
- put4((int) entry.compressedSize); // FIXME
- put4((int) entry.size); // FIXME
- put2(entry.name.length());
- put2(entry.extra == null ? 0 : entry.extra.length);
- byte[] name = entry.name.getBytes("8859_1");
- out.write(name);
- if (entry.extra != null)
- out.write(entry.extra);
- throw new Error ("java.util.zip.ZipOutputStream.putNextEntry: not implemented");
+ if (entry.method == STORED)
+ {
+ if (entry.getSize() == -1 || entry.getCrc() == -1)
+ throw new ZipException ("required entry not set");
+ // Just in case.
+ entry.compressedSize = entry.getSize();
+ }
+ write_entry (entry, true);
+ current = entry;
+ int compr = (method == STORED) ? Deflater.NO_COMPRESSION : level;
+ def.reset();
+ def.setLevel(compr);
+ filter = new CheckedOutputStream (new DeflaterOutputStream (out, def),
+ new CRC32 ());
}
- public void closeEntry () throws IOException
+ public void setLevel (int level)
{
+ if (level != Deflater.DEFAULT_COMPRESSION
+ && (level < Deflater.NO_COMPRESSION
+ || level > Deflater.BEST_COMPRESSION))
+ throw new IllegalArgumentException ();
+ this.level = level;
}
- private void put2 (int i) throws IOException
+ public void setMethod (int method)
+ {
+ if (method != DEFLATED && method != STORED)
+ throw new IllegalArgumentException ();
+ this.method = method;
+ }
+
+ public void setComment (String comment)
+ {
+ if (comment.length() > 65535)
+ throw new IllegalArgumentException ();
+ this.comment = comment;
+ }
+
+ public synchronized void write (byte[] buf, int off, int len)
+ throws IOException
+ {
+ if (filter == null)
+ throw new ZipException ("no open zip entry");
+ filter.write(buf, off, len);
+ }
+
+ public ZipOutputStream (OutputStream out)
+ {
+ super (out);
+ def = new Deflater (level, true);
+ }
+
+ private int put2 (int i) throws IOException
{
out.write (i);
out.write (i >> 8);
+ return 2;
}
- private void put4 (int i) throws IOException
+ private int put4 (int i) throws IOException
{
out.write (i);
out.write (i >> 8);
out.write (i >> 16);
out.write (i >> 24);
+ return 4;
}
+
+ private int put_version () throws IOException
+ {
+ // FIXME: for now we assume Unix, and we ignore the version
+ // number.
+ return put2 (3 << 8);
+ }
+
+ // The entry we are currently writing, or null if we've called
+ // closeEntry.
+ private ZipEntry current;
+ // The chain of entries which have been written to this file.
+ private ZipEntry chain;
+ // The output stream to which data should be sent.
+ private CheckedOutputStream filter;
+
+ private int method = DEFLATED;
+ private int level = Deflater.DEFAULT_COMPRESSION;
+ private String comment = "";
+ private long bytes_written;
+
+ // The Deflater we use.
+ private Deflater def;
}
OpenPOWER on IntegriCloud