diff options
Diffstat (limited to 'libjava/java/util/zip/ZipInputStream.java')
-rw-r--r-- | libjava/java/util/zip/ZipInputStream.java | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/libjava/java/util/zip/ZipInputStream.java b/libjava/java/util/zip/ZipInputStream.java new file mode 100644 index 00000000000..41b092d8133 --- /dev/null +++ b/libjava/java/util/zip/ZipInputStream.java @@ -0,0 +1,223 @@ +/* Copyright (C) 1999 Cygnus Solutions + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +package java.util.zip; +import java.io.*; + +/** + * @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. + */ + +// JDK1.2 has "protected ZipEntry createZipEntry(String)" but is very +// vague about what the method does. FIXME. +// 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) + { + super (in, new Inflater (true)); + } + + public ZipEntry getNextEntry () throws IOException + { + 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(); + in.skip(12+fname_length+extra_length+fcomment_length+size); + 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 = new ZipEntry(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; + } + + // 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 + { + int count = buf.length; + if (count > compressed_bytes) + count = compressed_bytes; + len = in.read(buf, 0, count); + if (len != -1) + { + compressed_bytes -= len; + inf.setInput(buf, 0, len); + } + } + + public int read (byte[] b, int off, int len) throws IOException + { + 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) + { + inf.reset(); + count = -1; + } + else + avail -= count; + return count; + } + + public long skip (long n) throws IOException + { + 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; + } + + private void readFully (byte[] b) throws IOException + { + int off = 0; + int len = b.length; + while (len > 0) + { + int count = in.read(b, off, len); + if (count <= 0) + throw new EOFException(".zip archive ended prematurely"); + off += count; + len -= count; + } + } + + private int readu2 () 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); + } + + private int read4 () throws IOException + { + int byte0 = in.read(); + int byte1 = in.read(); + int byte2 = in.read(); + int byte3 = in.read(); + if (byte3 < 0) + throw new EOFException(".zip archive ended prematurely"); + return ((byte3 & 0xFF) << 24) + ((byte2 & 0xFF) << 16) + + ((byte1 & 0xFF) << 8) + (byte0 & 0xFF); + } + + public void closeEntry () throws IOException + { + if (current != null) + { + if (avail > 0) + skip (avail); + if ((current_flags & 8) != 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"); + } + current = null; + avail = 0; + } + } + + public void close () throws IOException + { + current = null; + super.close(); + } + + 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; +} |