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