1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44:
45:
55: public class ZipInputStream extends InflaterInputStream implements ZipConstants
56: {
57: private CRC32 crc = new CRC32();
58: private ZipEntry entry = null;
59:
60: private int csize;
61: private int size;
62: private int method;
63: private int flags;
64: private int avail;
65: private boolean entryAtEOF;
66:
67:
70: public ZipInputStream(InputStream in)
71: {
72: super(in, new Inflater(true));
73: }
74:
75: private void fillBuf() throws IOException
76: {
77: avail = len = in.read(buf, 0, buf.length);
78: }
79:
80: private int readBuf(byte[] out, int offset, int length) throws IOException
81: {
82: if (avail <= 0)
83: {
84: fillBuf();
85: if (avail <= 0)
86: return -1;
87: }
88: if (length > avail)
89: length = avail;
90: System.arraycopy(buf, len - avail, out, offset, length);
91: avail -= length;
92: return length;
93: }
94:
95: private void readFully(byte[] out) throws IOException
96: {
97: int off = 0;
98: int len = out.length;
99: while (len > 0)
100: {
101: int count = readBuf(out, off, len);
102: if (count == -1)
103: throw new EOFException();
104: off += count;
105: len -= count;
106: }
107: }
108:
109: private int readLeByte() throws IOException
110: {
111: if (avail <= 0)
112: {
113: fillBuf();
114: if (avail <= 0)
115: throw new ZipException("EOF in header");
116: }
117: return buf[len - avail--] & 0xff;
118: }
119:
120:
123: private int readLeShort() throws IOException
124: {
125: return readLeByte() | (readLeByte() << 8);
126: }
127:
128:
131: private int readLeInt() throws IOException
132: {
133: return readLeShort() | (readLeShort() << 16);
134: }
135:
136:
140: public ZipEntry getNextEntry() throws IOException
141: {
142: if (crc == null)
143: throw new IOException("Stream closed.");
144: if (entry != null)
145: closeEntry();
146:
147: int header = readLeInt();
148: if (header == CENSIG)
149: {
150:
151: close();
152: return null;
153: }
154: if (header != LOCSIG)
155: throw new ZipException("Wrong Local header signature: "
156: + Integer.toHexString(header));
157:
158: readLeShort();
159: flags = readLeShort();
160: method = readLeShort();
161: int dostime = readLeInt();
162: int crc = readLeInt();
163: csize = readLeInt();
164: size = readLeInt();
165: int nameLen = readLeShort();
166: int extraLen = readLeShort();
167:
168: if (method == ZipOutputStream.STORED && csize != size)
169: throw new ZipException("Stored, but compressed != uncompressed");
170:
171:
172: byte[] buffer = new byte[nameLen];
173: readFully(buffer);
174: String name = new String(buffer);
175:
176: entry = createZipEntry(name);
177: entryAtEOF = false;
178: entry.setMethod(method);
179: if ((flags & 8) == 0)
180: {
181: entry.setCrc(crc & 0xffffffffL);
182: entry.setSize(size & 0xffffffffL);
183: entry.setCompressedSize(csize & 0xffffffffL);
184: }
185: entry.setDOSTime(dostime);
186: if (extraLen > 0)
187: {
188: byte[] extra = new byte[extraLen];
189: readFully(extra);
190: entry.setExtra(extra);
191: }
192:
193: if (method == ZipOutputStream.DEFLATED && avail > 0)
194: {
195: System.arraycopy(buf, len - avail, buf, 0, avail);
196: len = avail;
197: avail = 0;
198: inf.setInput(buf, 0, len);
199: }
200: return entry;
201: }
202:
203: private void readDataDescr() throws IOException
204: {
205: if (readLeInt() != EXTSIG)
206: throw new ZipException("Data descriptor signature not found");
207: entry.setCrc(readLeInt() & 0xffffffffL);
208: csize = readLeInt();
209: size = readLeInt();
210: entry.setSize(size & 0xffffffffL);
211: entry.setCompressedSize(csize & 0xffffffffL);
212: }
213:
214:
217: public void closeEntry() throws IOException
218: {
219: if (crc == null)
220: throw new IOException("Stream closed.");
221: if (entry == null)
222: return;
223:
224: if (method == ZipOutputStream.DEFLATED)
225: {
226: if ((flags & 8) != 0)
227: {
228:
229: byte[] tmp = new byte[2048];
230: while (read(tmp) > 0)
231: ;
232:
233: return;
234: }
235: csize -= inf.getTotalIn();
236: avail = inf.getRemaining();
237: }
238:
239: if (avail > csize && csize >= 0)
240: avail -= csize;
241: else
242: {
243: csize -= avail;
244: avail = 0;
245: while (csize != 0)
246: {
247: long skipped = in.skip(csize & 0xffffffffL);
248: if (skipped <= 0)
249: throw new ZipException("zip archive ends early.");
250: csize -= skipped;
251: }
252: }
253:
254: size = 0;
255: crc.reset();
256: if (method == ZipOutputStream.DEFLATED)
257: inf.reset();
258: entry = null;
259: entryAtEOF = true;
260: }
261:
262: public int available() throws IOException
263: {
264: return entryAtEOF ? 0 : 1;
265: }
266:
267:
273: public int read() throws IOException
274: {
275: byte[] b = new byte[1];
276: if (read(b, 0, 1) <= 0)
277: return -1;
278: return b[0] & 0xff;
279: }
280:
281:
288: public int read(byte[] b, int off, int len) throws IOException
289: {
290: if (len == 0)
291: return 0;
292: if (crc == null)
293: throw new IOException("Stream closed.");
294: if (entry == null)
295: return -1;
296: boolean finished = false;
297: switch (method)
298: {
299: case ZipOutputStream.DEFLATED:
300: len = super.read(b, off, len);
301: if (len < 0)
302: {
303: if (!inf.finished())
304: throw new ZipException("Inflater not finished!?");
305: avail = inf.getRemaining();
306: if ((flags & 8) != 0)
307: readDataDescr();
308:
309: if (inf.getTotalIn() != csize
310: || inf.getTotalOut() != size)
311: throw new ZipException("size mismatch: "+csize+";"+size+" <-> "+inf.getTotalIn()+";"+inf.getTotalOut());
312: inf.reset();
313: finished = true;
314: }
315: break;
316:
317: case ZipOutputStream.STORED:
318:
319: if (len > csize && csize >= 0)
320: len = csize;
321:
322: len = readBuf(b, off, len);
323: if (len > 0)
324: {
325: csize -= len;
326: size -= len;
327: }
328:
329: if (csize == 0)
330: finished = true;
331: else if (len < 0)
332: throw new ZipException("EOF in stored block");
333: break;
334: }
335:
336: if (len > 0)
337: crc.update(b, off, len);
338:
339: if (finished)
340: {
341: if ((crc.getValue() & 0xffffffffL) != entry.getCrc())
342: throw new ZipException("CRC mismatch");
343: crc.reset();
344: entry = null;
345: entryAtEOF = true;
346: }
347: return len;
348: }
349:
350:
354: public void close() throws IOException
355: {
356: super.close();
357: crc = null;
358: entry = null;
359: entryAtEOF = true;
360: }
361:
362:
367: protected ZipEntry createZipEntry(String name)
368: {
369: return new ZipEntry(name);
370: }
371: }