1 /* ZipInputStream.java --
2 Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package java
.util
.zip
;
41 import java
.io
.EOFException
;
42 import java
.io
.IOException
;
43 import java
.io
.InputStream
;
44 import java
.io
.UnsupportedEncodingException
;
47 * This is a FilterInputStream that reads the files in an zip archive
48 * one after another. It has a special method to get the zip entry of
49 * the next file. The zip entry contains information about the file name
50 * size, compressed size, CRC, etc.
52 * It includes support for STORED and DEFLATED entries.
54 * @author Jochen Hoenicke
56 public class ZipInputStream
extends InflaterInputStream
implements ZipConstants
58 private CRC32 crc
= new CRC32();
59 private ZipEntry entry
= null;
66 private boolean entryAtEOF
;
69 * Creates a new Zip input stream, reading a zip archive.
71 public ZipInputStream(InputStream in
)
73 super(in
, new Inflater(true));
76 private void fillBuf() throws IOException
78 avail
= len
= in
.read(buf
, 0, buf
.length
);
81 private int readBuf(byte[] out
, int offset
, int length
) throws IOException
91 System
.arraycopy(buf
, len
- avail
, out
, offset
, length
);
96 private void readFully(byte[] out
) throws IOException
102 int count
= readBuf(out
, off
, len
);
104 throw new EOFException();
110 private int readLeByte() throws IOException
116 throw new ZipException("EOF in header");
118 return buf
[len
- avail
--] & 0xff;
122 * Read an unsigned short in little endian byte order.
124 private int readLeShort() throws IOException
126 return readLeByte() | (readLeByte() << 8);
130 * Read an int in little endian byte order.
132 private int readLeInt() throws IOException
134 return readLeShort() | (readLeShort() << 16);
138 * Open the next entry from the zip archive, and return its description.
139 * If the previous entry wasn't closed, this method will close it.
141 public ZipEntry
getNextEntry() throws IOException
144 throw new IOException("Stream closed.");
148 int header
= readLeInt();
149 if (header
== CENSIG
)
151 /* Central Header reached. */
155 if (header
!= LOCSIG
)
156 throw new ZipException("Wrong Local header signature: "
157 + Integer
.toHexString(header
));
160 flags
= readLeShort();
161 method
= readLeShort();
162 int dostime
= readLeInt();
163 int crc
= readLeInt();
166 int nameLen
= readLeShort();
167 int extraLen
= readLeShort();
169 if (method
== ZipOutputStream
.STORED
&& csize
!= size
)
170 throw new ZipException("Stored, but compressed != uncompressed");
173 byte[] buffer
= new byte[nameLen
];
178 name
= new String(buffer
, "UTF-8");
180 catch (UnsupportedEncodingException uee
)
182 throw new AssertionError(uee
);
185 entry
= createZipEntry(name
);
187 entry
.setMethod(method
);
188 if ((flags
& 8) == 0)
190 entry
.setCrc(crc
& 0xffffffffL
);
191 entry
.setSize(size
& 0xffffffffL
);
192 entry
.setCompressedSize(csize
& 0xffffffffL
);
194 entry
.setDOSTime(dostime
);
197 byte[] extra
= new byte[extraLen
];
199 entry
.setExtra(extra
);
202 if (method
== ZipOutputStream
.DEFLATED
&& avail
> 0)
204 System
.arraycopy(buf
, len
- avail
, buf
, 0, avail
);
207 inf
.setInput(buf
, 0, len
);
212 private void readDataDescr() throws IOException
214 if (readLeInt() != EXTSIG
)
215 throw new ZipException("Data descriptor signature not found");
216 entry
.setCrc(readLeInt() & 0xffffffffL
);
219 entry
.setSize(size
& 0xffffffffL
);
220 entry
.setCompressedSize(csize
& 0xffffffffL
);
224 * Closes the current zip entry and moves to the next one.
226 public void closeEntry() throws IOException
229 throw new IOException("Stream closed.");
233 if (method
== ZipOutputStream
.DEFLATED
)
235 if ((flags
& 8) != 0)
237 /* We don't know how much we must skip, read until end. */
238 byte[] tmp
= new byte[2048];
239 while (read(tmp
) > 0)
241 /* read will close this entry */
244 csize
-= inf
.getTotalIn();
245 avail
= inf
.getRemaining();
248 if (avail
> csize
&& csize
>= 0)
256 long skipped
= in
.skip(csize
& 0xffffffffL
);
258 throw new ZipException("zip archive ends early.");
265 if (method
== ZipOutputStream
.DEFLATED
)
271 public int available() throws IOException
273 return entryAtEOF ?
0 : 1;
277 * Reads a byte from the current zip entry.
278 * @return the byte or -1 on EOF.
279 * @exception IOException if a i/o error occured.
280 * @exception ZipException if the deflated stream is corrupted.
282 public int read() throws IOException
284 byte[] b
= new byte[1];
285 if (read(b
, 0, 1) <= 0)
291 * Reads a block of bytes from the current zip entry.
292 * @return the number of bytes read (may be smaller, even before
293 * EOF), or -1 on EOF.
294 * @exception IOException if a i/o error occured.
295 * @exception ZipException if the deflated stream is corrupted.
297 public int read(byte[] b
, int off
, int len
) throws IOException
302 throw new IOException("Stream closed.");
305 boolean finished
= false;
308 case ZipOutputStream
.DEFLATED
:
309 len
= super.read(b
, off
, len
);
313 throw new ZipException("Inflater not finished!?");
314 avail
= inf
.getRemaining();
315 if ((flags
& 8) != 0)
318 if (inf
.getTotalIn() != csize
319 || inf
.getTotalOut() != size
)
320 throw new ZipException("size mismatch: "+csize
+";"+size
+" <-> "+inf
.getTotalIn()+";"+inf
.getTotalOut());
326 case ZipOutputStream
.STORED
:
328 if (len
> csize
&& csize
>= 0)
331 len
= readBuf(b
, off
, len
);
341 throw new ZipException("EOF in stored block");
346 crc
.update(b
, off
, len
);
350 if ((crc
.getValue() & 0xffffffffL
) != entry
.getCrc())
351 throw new ZipException("CRC mismatch");
360 * Closes the zip file.
361 * @exception IOException if a i/o error occured.
363 public void close() throws IOException
372 * Creates a new zip entry for the given name. This is equivalent
373 * to new ZipEntry(name).
374 * @param name the name of the zip entry.
376 protected ZipEntry
createZipEntry(String name
)
378 return new ZipEntry(name
);