1
7
8 package java.util.zip;
9
10 import java.io.InputStream;
11 import java.io.IOException;
12 import java.io.EOFException;
13 import java.io.UnsupportedEncodingException;
14 import java.io.PushbackInputStream;
15 import sun.security.action.GetPropertyAction;
16 import java.util.jar.JarInputStream;
17
18
19
27 public
28 class ZipInputStream extends InflaterInputStream implements ZipConstants {
29 private ZipEntry entry;
30 private int flag;
31 private CRC32 crc = new CRC32();
32 private long remaining;
33 private byte[] tmpbuf = new byte[512];
34
35 private static final int STORED = ZipEntry.STORED;
36 private static final int DEFLATED = ZipEntry.DEFLATED;
37
38 private boolean closed = false;
39 private boolean entryEOF = false;
42 private static final String fileEncoding = java.security.AccessController
44 .doPrivileged(new GetPropertyAction("sun.zip.encoding"));
45
46
47
50 private void ensureOpen() throws IOException {
51 if (closed) {
52 throw new IOException("Stream closed");
53 }
54 }
55
56
60 public ZipInputStream(InputStream in) {
61 super(new PushbackInputStream(in, 512), new Inflater(true), 512);
62 usesDefaultInflater = true;
63 if(in == null) {
64 throw new NullPointerException("in is null");
65 }
66 }
67
68
75 public ZipEntry getNextEntry() throws IOException {
76 ensureOpen();
77 if (entry != null) {
78 closeEntry();
79 }
80 crc.reset();
81 inf.reset();
82 if ((entry = readLOC()) == null) {
83 return null;
84 }
85 if (entry.method == STORED) {
86 remaining = entry.size;
87 }
88 entryEOF = false;
89 return entry;
90 }
91
92
98 public void closeEntry() throws IOException {
99 ensureOpen();
100 while (read(tmpbuf, 0, tmpbuf.length) != -1) ;
101 entryEOF = true;
102 }
103
104
115 public int available() throws IOException {
116 ensureOpen();
117 if (entryEOF) {
118 return 0;
119 } else {
120 return 1;
121 }
122 }
123
124
141 public int read(byte[] b, int off, int len) throws IOException {
142 ensureOpen();
143 if (off < 0 || len < 0 || off > b.length - len) {
144 throw new IndexOutOfBoundsException();
145 } else if (len == 0) {
146 return 0;
147 }
148
149 if (entry == null) {
150 return -1;
151 }
152 switch (entry.method) {
153 case DEFLATED:
154 len = super.read(b, off, len);
155 if (len == -1) {
156 readEnd(entry);
157 entryEOF = true;
158 entry = null;
159 } else {
160 crc.update(b, off, len);
161 }
162 return len;
163 case STORED:
164 if (remaining <= 0) {
165 entryEOF = true;
166 entry = null;
167 return -1;
168 }
169 if (len > remaining) {
170 len = (int)remaining;
171 }
172 len = in.read(b, off, len);
173 if (len == -1) {
174 throw new ZipException("unexpected EOF");
175 }
176 crc.update(b, off, len);
177 remaining -= len;
178 if (remaining == 0 && entry.crc != crc.getValue()) {
179 throw new ZipException(
180 "invalid entry CRC (expected 0x" + Long.toHexString(entry.crc) +
181 " but got 0x" + Long.toHexString(crc.getValue()) + ")");
182 }
183 return len;
184 default:
185 throw new ZipException("invalid compression method");
186 }
187 }
188
189
197 public long skip(long n) throws IOException {
198 if (n < 0) {
199 throw new IllegalArgumentException("negative skip length");
200 }
201 ensureOpen();
202 int max = (int)Math.min(n, Integer.MAX_VALUE);
203 int total = 0;
204 while (total < max) {
205 int len = max - total;
206 if (len > tmpbuf.length) {
207 len = tmpbuf.length;
208 }
209 len = read(tmpbuf, 0, len);
210 if (len == -1) {
211 entryEOF = true;
212 break;
213 }
214 total += len;
215 }
216 return total;
217 }
218
219
224 public void close() throws IOException {
225 if (!closed) {
226 super.close();
227 closed = true;
228 }
229 }
230
231 private byte[] b = new byte[256];
232
233
236 private ZipEntry readLOC() throws IOException {
237 try {
238 readFully(tmpbuf, 0, LOCHDR);
239 } catch (EOFException e) {
240 return null;
241 }
242 if (get32(tmpbuf, 0) != LOCSIG) {
243 return null;
244 }
245 int len = get16(tmpbuf, LOCNAM);
247 int blen = b.length;
248 if (len > blen) {
249 do
250 blen = blen * 2;
251 while (len > blen);
252 b = new byte[blen];
253 }
254 readFully(b, 0, len);
255 String name = getFileName(b, len);
256
257 ZipEntry e = createZipEntry(name);
258 flag = get16(tmpbuf, LOCFLG);
260 if ((flag & 1) == 1) {
261 throw new ZipException("encrypted ZIP entry not supported");
262 }
263 e.method = get16(tmpbuf, LOCHOW);
264 e.time = get32(tmpbuf, LOCTIM);
265 if ((flag & 8) == 8) {
266
267 if (e.method != DEFLATED) {
268 throw new ZipException(
269 "only DEFLATED entries can have EXT descriptor");
270 }
271 } else {
272 e.crc = get32(tmpbuf, LOCCRC);
273 e.csize = get32(tmpbuf, LOCSIZ);
274 e.size = get32(tmpbuf, LOCLEN);
275 }
276 len = get16(tmpbuf, LOCEXT);
277 if (len > 0) {
278 byte[] bb = new byte[len];
279 readFully(bb, 0, len);
280 e.setExtra(bb);
281 }
282 return e;
283 }
284
285
288 private static String getUTF8String(byte[] b, int off, int len) {
289 int count = 0;
291 int max = off + len;
292 int i = off;
293 while (i < max) {
294 int c = b[i++] & 0xff;
295 switch (c >> 4) {
296 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
297 count++;
299 break;
300 case 12: case 13:
301 if ((int)(b[i++] & 0xc0) != 0x80) {
303 throw new IllegalArgumentException();
304 }
305 count++;
306 break;
307 case 14:
308 if (((int)(b[i++] & 0xc0) != 0x80) ||
310 ((int)(b[i++] & 0xc0) != 0x80)) {
311 throw new IllegalArgumentException();
312 }
313 count++;
314 break;
315 default:
316 throw new IllegalArgumentException();
318 }
319 }
320 if (i != max) {
321 throw new IllegalArgumentException();
322 }
323 char[] cs = new char[count];
325 i = 0;
326 while (off < max) {
327 int c = b[off++] & 0xff;
328 switch (c >> 4) {
329 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
330 cs[i++] = (char)c;
332 break;
333 case 12: case 13:
334 cs[i++] = (char)(((c & 0x1f) << 6) | (b[off++] & 0x3f));
336 break;
337 case 14:
338 int t = (b[off++] & 0x3f) << 6;
340 cs[i++] = (char)(((c & 0x0f) << 12) | t | (b[off++] & 0x3f));
341 break;
342 default:
343 throw new IllegalArgumentException();
345 }
346 }
347 return new String(cs, 0, count);
348 }
349
350
357 protected ZipEntry createZipEntry(String name) {
358 return new ZipEntry(name);
359 }
360
361
364 private void readEnd(ZipEntry e) throws IOException {
365 int n = inf.getRemaining();
366 if (n > 0) {
367 ((PushbackInputStream)in).unread(buf, len - n, n);
368 }
369 if ((flag & 8) == 8) {
370
371 readFully(tmpbuf, 0, EXTHDR);
372 long sig = get32(tmpbuf, 0);
373 if (sig != EXTSIG) { e.crc = sig;
375 e.csize = get32(tmpbuf, EXTSIZ - EXTCRC);
376 e.size = get32(tmpbuf, EXTLEN - EXTCRC);
377 ((PushbackInputStream)in).unread(
378 tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC);
379 } else {
380 e.crc = get32(tmpbuf, EXTCRC);
381 e.csize = get32(tmpbuf, EXTSIZ);
382 e.size = get32(tmpbuf, EXTLEN);
383 }
384 }
385 if (e.size != inf.getBytesWritten()) {
386 throw new ZipException(
387 "invalid entry size (expected " + e.size +
388 " but got " + inf.getBytesWritten() + " bytes)");
389 }
390 if (e.csize != inf.getBytesRead()) {
391 throw new ZipException(
392 "invalid entry compressed size (expected " + e.csize +
393 " but got " + inf.getBytesRead() + " bytes)");
394 }
395 if (e.crc != crc.getValue()) {
396 throw new ZipException(
397 "invalid entry CRC (expected 0x" + Long.toHexString(e.crc) +
398 " but got 0x" + Long.toHexString(crc.getValue()) + ")");
399 }
400 }
401
402
405 private void readFully(byte[] b, int off, int len) throws IOException {
406 while (len > 0) {
407 int n = in.read(b, off, len);
408 if (n == -1) {
409 throw new EOFException();
410 }
411 off += n;
412 len -= n;
413 }
414 }
415
416
420 private static final int get16(byte b[], int off) {
421 return (b[off] & 0xff) | ((b[off+1] & 0xff) << 8);
422 }
423
424
428 private static final long get32(byte b[], int off) {
429 return get16(b, off) | ((long)get16(b, off+2) << 16);
430 }
431
432 private String getFileName(byte[] b, int len) throws IOException {
433 String name;
434 try {
435 if (fileEncoding == null || fileEncoding.equals("") || this instanceof JarInputStream) {
436 name = getUTF8String(b, 0, len);
437 } else {
438 if (fileEncoding.equalsIgnoreCase("default")) {
439 name = new String(b, 0, len);
441 } else {
442 try {
443 name = new String(b, 0, len, fileEncoding);
444 } catch (UnsupportedEncodingException UEE) {
445 throw new ZipException("Unable to encode entry " +
446 "name (sun.zip.encoding is " + fileEncoding + ")");
447 }
448 }
449 }
450 } catch (IllegalArgumentException e) {
451 String altEncoding = java.security.AccessController
454 .doPrivileged(new GetPropertyAction("sun.zip.altEncoding"));
455 if (altEncoding == null || altEncoding.equals("") ||
456 this instanceof JarInputStream) {
457 throw e;
458 }
459 if (altEncoding.equalsIgnoreCase("default")) {
460 name = new String(b, 0, len);
462 } else {
463 try {
464 name = new String(b, 0, len, altEncoding);
466 } catch (UnsupportedEncodingException UEE) {
467 throw new ZipException("Unable to encode entry " +
468 "name (sun.zip.altEncoding is " + altEncoding + ")");
469 }
470 }
471
472 }
473 return name;
474 }
475 }
476