1 /* Copyright (C) 1999, 2000 Free Software Foundation
3 This file is part of libgcj.
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
18 * Written using on-line Java Platform 1.2 API Specification, as well
19 * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
20 * Status: Quite incomplete, but can read uncompressed .zip archives.
23 // JDK1.2 has "protected ZipEntry createZipEntry(String)" but is very
24 // vague about what the method does. FIXME.
25 // We do not calculate the CRC and compare it with the specified value;
26 // we probably should. FIXME.
29 public class ZipInputStream extends InflaterInputStream implements ZipConstants
31 public ZipInputStream (InputStream in)
33 super (in, new Inflater (true));
36 public ZipEntry getNextEntry () throws IOException
44 while (code == '\001')
52 int fname_length = readu2();
53 int extra_length = readu2();
54 int fcomment_length = readu2();
55 // `12' is the number of bytes between the comment length
56 // field and the end of the fixed part of the header:
57 // 2 bytes for `disk number start'
58 // 2 bytes for `internal file attributes'
59 // 4 bytes for `external file attributes'
60 // 4 bytes for `relative offset of local header'
61 in.skip(12 + fname_length + extra_length + fcomment_length);
62 if (in.read() != 'P' || in.read() != 'K')
68 if (in.read() != '\006')
71 int comment_size = readu2();
72 in.skip(comment_size);
73 if (in.read() != 'P' || in.read() != 'K')
78 || in.read() != '\004')
80 int ex_version = readu2();
81 current_flags = readu2();
82 int method = readu2();
83 int modtime = readu2();
84 int moddate = readu2();
86 int compressedSize = read4();
87 int uncompressedSize = read4();
88 int filenameLength = readu2();
89 int extraLength = readu2();
90 byte[] bname = new byte[filenameLength];
92 ZipEntry entry = createZipEntry(new String(bname, "8859_1"));
95 byte[] bextra = new byte[extraLength];
99 entry.compressedSize = compressedSize;
100 entry.size = uncompressedSize;
101 entry.crc = (long) crc & 0xffffffffL;
102 entry.method = method;
103 entry.time = ZipEntry.timeFromDOS(moddate, modtime);
105 avail = uncompressedSize;
106 compressed_bytes = compressedSize;
110 // We override fill to let us control how much data gets read from
111 // the underlying input stream. This lets us avoid having to push
113 protected void fill () throws IOException
115 int count = buf.length;
116 if (count > compressed_bytes)
117 count = compressed_bytes;
118 len = in.read(buf, 0, count);
121 compressed_bytes -= len;
122 inf.setInput(buf, 0, len);
126 protected ZipEntry createZipEntry (String name)
128 return new ZipEntry (name);
131 public int read (byte[] b, int off, int len) throws IOException
136 if (current.method == Deflater.DEFLATED)
137 count = super.read(b, off, len);
139 count = in.read(b, off, len);
140 if (count == -1 || avail == 0)
150 public long skip (long n) throws IOException
155 if (current.method == Deflater.DEFLATED)
156 count = super.skip(n);
159 avail = avail - (int) count;
163 public int available() {
170 private void readFully (byte[] b) throws IOException
176 int count = in.read(b, off, len);
178 throw new EOFException(".zip archive ended prematurely");
184 private int readu2 () throws IOException
186 int byte0 = in.read();
187 int byte1 = in.read();
188 if (byte0 < 0 || byte1 < 0)
189 throw new EOFException(".zip archive ended prematurely");
190 return ((byte1 & 0xFF) << 8) | (byte0 & 0xFF);
193 private int read4 () throws IOException
195 int byte0 = in.read();
196 int byte1 = in.read();
197 int byte2 = in.read();
198 int byte3 = in.read();
200 throw new EOFException(".zip archive ended prematurely");
201 return ((byte3 & 0xFF) << 24) + ((byte2 & 0xFF) << 16)
202 + ((byte1 & 0xFF) << 8) + (byte0 & 0xFF);
205 public void closeEntry () throws IOException
211 if ((current_flags & 8) != 0)
214 if (sig != 0x04034b50)
215 throw new ZipException("bad/missing magic number at end of .zip entry");
217 int compressedSize = read4();
218 int uncompressedSize = read4();
219 if (current.compressedSize != compressedSize
220 || current.size != uncompressedSize
221 || current.crc != crc)
222 throw new ZipException("bad data descriptor at end of .zip entry");
229 public void close () throws IOException
236 private ZipEntry current;
237 private int current_flags;
238 // Number of uncompressed bytes to be read.
240 // Number of bytes we can read from underlying stream.
241 private int compressed_bytes;
242 // Is this ZipInputStream closed? Set by the close() method.
243 private boolean closed = false;