| /* 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; |
| } |