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:
243: return;
244: }
245: csize -= inf.getTotalIn();
246: avail = inf.getRemaining();
247: }
248:
249: if (avail > csize && csize >= 0)
250: avail -= csize;
251: else
252: {
253: csize -= avail;
254: avail = 0;
255: while (csize != 0)
256: {
257: long skipped = in.skip(csize & 0xffffffffL);
258: if (skipped <= 0)
259: throw new ZipException("zip archive ends early.");
260: csize -= skipped;
261: }
262: }
263:
264: size = 0;
265: crc.reset();
266: if (method == ZipOutputStream.DEFLATED)
267: inf.reset();
268: entry = null;
269: entryAtEOF = true;
270: }
271:
272: public int available() throws IOException
273: {
274: return entryAtEOF ? 0 : 1;
275: }
276:
277:
283: public int read() throws IOException
284: {
285: byte[] b = new byte[1];
286: if (read(b, 0, 1) <= 0)
287: return -1;
288: return b[0] & 0xff;
289: }
290:
291:
298: public int read(byte[] b, int off, int len) throws IOException
299: {
300: if (len == 0)
301: return 0;
302: if (crc == null)
303: throw new IOException("Stream closed.");
304: if (entry == null)
305: return -1;
306: boolean finished = false;
307: switch (method)
308: {
309: case ZipOutputStream.DEFLATED:
310: len = super.read(b, off, len);
311: if (len < 0)
312: {
313: if (!inf.finished())
314: throw new ZipException("Inflater not finished!?");
315: avail = inf.getRemaining();
316: if ((flags & 8) != 0)
317: readDataDescr();
318:
319: if (inf.getTotalIn() != csize
320: || inf.getTotalOut() != size)
321: throw new ZipException("size mismatch: "+csize+";"+size+" <-> "+inf.getTotalIn()+";"+inf.getTotalOut());
322: inf.reset();
323: finished = true;
324: }
325: break;
326:
327: case ZipOutputStream.STORED:
328:
329: if (len > csize && csize >= 0)
330: len = csize;
331:
332: len = readBuf(b, off, len);
333: if (len > 0)
334: {
335: csize -= len;
336: size -= len;
337: }
338:
339: if (csize == 0)
340: finished = true;
341: else if (len < 0)
342: throw new ZipException("EOF in stored block");
343: break;
344: }
345:
346: if (len > 0)
347: crc.update(b, off, len);
348:
349: if (finished)
350: {
351: if ((crc.getValue() & 0xffffffffL) != entry.getCrc())
352: throw new ZipException("CRC mismatch");
353: crc.reset();
354: entry = null;
355: entryAtEOF = true;
356: }
357: return len;
358: }
359:
360:
364: public void close() throws IOException
365: {
366: super.close();
367: crc = null;
368: entry = null;
369: entryAtEOF = true;
370: }
371:
372:
377: protected ZipEntry createZipEntry(String name)
378: {
379: return new ZipEntry(name);
380: }
381: }