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.PushbackInputStream ; 14 15 23 public 24 class ZipInputStream extends InflaterInputStream implements ZipConstants { 25 private ZipEntry entry; 26 private CRC32 crc = new CRC32 (); 27 private long remaining; 28 private byte[] tmpbuf = new byte[512]; 29 30 private static final int STORED = ZipEntry.STORED; 31 private static final int DEFLATED = ZipEntry.DEFLATED; 32 33 private boolean closed = false; 34 private boolean entryEOF = false; 37 38 41 private void ensureOpen() throws IOException { 42 if (closed) { 43 throw new IOException ("Stream closed"); 44 } 45 } 46 47 51 public ZipInputStream(InputStream in) { 52 super(new PushbackInputStream (in, 512), new Inflater (true), 512); 53 usesDefaultInflater = true; 54 if(in == null) { 55 throw new NullPointerException ("in is null"); 56 } 57 } 58 59 66 public ZipEntry getNextEntry() throws IOException { 67 ensureOpen(); 68 if (entry != null) { 69 closeEntry(); 70 } 71 crc.reset(); 72 inf.reset(); 73 if ((entry = readLOC()) == null) { 74 return null; 75 } 76 if (entry.method == STORED) { 77 remaining = entry.size; 78 } 79 entryEOF = false; 80 return entry; 81 } 82 83 89 public void closeEntry() throws IOException { 90 ensureOpen(); 91 while (read(tmpbuf, 0, tmpbuf.length) != -1) ; 92 entryEOF = true; 93 } 94 95 106 public int available() throws IOException { 107 ensureOpen(); 108 if (entryEOF) { 109 return 0; 110 } else { 111 return 1; 112 } 113 } 114 115 126 public int read(byte[] b, int off, int len) throws IOException { 127 ensureOpen(); 128 if (off < 0 || len < 0 || off > b.length - len) { 129 throw new IndexOutOfBoundsException (); 130 } else if (len == 0) { 131 return 0; 132 } 133 134 if (entry == null) { 135 return -1; 136 } 137 switch (entry.method) { 138 case DEFLATED: 139 len = super.read(b, off, len); 140 if (len == -1) { 141 readEnd(entry); 142 entryEOF = true; 143 entry = null; 144 } else { 145 crc.update(b, off, len); 146 } 147 return len; 148 case STORED: 149 if (remaining <= 0) { 150 entryEOF = true; 151 entry = null; 152 return -1; 153 } 154 if (len > remaining) { 155 len = (int)remaining; 156 } 157 len = in.read(b, off, len); 158 if (len == -1) { 159 throw new ZipException ("unexpected EOF"); 160 } 161 crc.update(b, off, len); 162 remaining -= len; 163 if (remaining == 0 && entry.crc != crc.getValue()) { 164 throw new ZipException ( 165 "invalid entry CRC (expected 0x" + Long.toHexString(entry.crc) + 166 " but got 0x" + Long.toHexString(crc.getValue()) + ")"); 167 } 168 return len; 169 default: 170 throw new InternalError ("invalid compression method"); 171 } 172 } 173 174 182 public long skip(long n) throws IOException { 183 if (n < 0) { 184 throw new IllegalArgumentException ("negative skip length"); 185 } 186 ensureOpen(); 187 int max = (int)Math.min(n, Integer.MAX_VALUE); 188 int total = 0; 189 while (total < max) { 190 int len = max - total; 191 if (len > tmpbuf.length) { 192 len = tmpbuf.length; 193 } 194 len = read(tmpbuf, 0, len); 195 if (len == -1) { 196 entryEOF = true; 197 break; 198 } 199 total += len; 200 } 201 return total; 202 } 203 204 209 public void close() throws IOException { 210 if (!closed) { 211 super.close(); 212 closed = true; 213 } 214 } 215 216 private byte[] b = new byte[256]; 217 218 221 private ZipEntry readLOC() throws IOException { 222 try { 223 readFully(tmpbuf, 0, LOCHDR); 224 } catch (EOFException e) { 225 return null; 226 } 227 if (get32(tmpbuf, 0) != LOCSIG) { 228 return null; 229 } 230 int len = get16(tmpbuf, LOCNAM); 232 if (len == 0) { 233 throw new ZipException ("missing entry name"); 234 } 235 int blen = b.length; 236 if (len > blen) { 237 do 238 blen = blen * 2; 239 while (len > blen); 240 b = new byte[blen]; 241 } 242 readFully(b, 0, len); 243 ZipEntry e = createZipEntry(getUTF8String(b, 0, len)); 244 e.version = get16(tmpbuf, LOCVER); 246 e.flag = get16(tmpbuf, LOCFLG); 247 if ((e.flag & 1) == 1) { 248 throw new ZipException ("encrypted ZIP entry not supported"); 249 } 250 e.method = get16(tmpbuf, LOCHOW); 251 e.time = get32(tmpbuf, LOCTIM); 252 if ((e.flag & 8) == 8) { 253 254 if (e.method != DEFLATED) { 255 throw new ZipException ( 256 "only DEFLATED entries can have EXT descriptor"); 257 } 258 } else { 259 e.crc = get32(tmpbuf, LOCCRC); 260 e.csize = get32(tmpbuf, LOCSIZ); 261 e.size = get32(tmpbuf, LOCLEN); 262 } 263 len = get16(tmpbuf, LOCEXT); 264 if (len > 0) { 265 byte[] bb = new byte[len]; 266 readFully(bb, 0, len); 267 e.extra = bb; 268 } 269 return e; 270 } 271 272 275 private static String getUTF8String(byte[] b, int off, int len) { 276 int count = 0; 278 int max = off + len; 279 int i = off; 280 while (i < max) { 281 int c = b[i++] & 0xff; 282 switch (c >> 4) { 283 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: 284 count++; 286 break; 287 case 12: case 13: 288 if ((int)(b[i++] & 0xc0) != 0x80) { 290 throw new IllegalArgumentException (); 291 } 292 count++; 293 break; 294 case 14: 295 if (((int)(b[i++] & 0xc0) != 0x80) || 297 ((int)(b[i++] & 0xc0) != 0x80)) { 298 throw new IllegalArgumentException (); 299 } 300 count++; 301 break; 302 default: 303 throw new IllegalArgumentException (); 305 } 306 } 307 if (i != max) { 308 throw new IllegalArgumentException (); 309 } 310 char[] cs = new char[count]; 312 i = 0; 313 while (off < max) { 314 int c = b[off++] & 0xff; 315 switch (c >> 4) { 316 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: 317 cs[i++] = (char)c; 319 break; 320 case 12: case 13: 321 cs[i++] = (char)(((c & 0x1f) << 6) | (b[off++] & 0x3f)); 323 break; 324 case 14: 325 int t = (b[off++] & 0x3f) << 6; 327 cs[i++] = (char)(((c & 0x0f) << 12) | t | (b[off++] & 0x3f)); 328 break; 329 default: 330 throw new IllegalArgumentException (); 332 } 333 } 334 return new String (cs, 0, count); 335 } 336 337 344 protected ZipEntry createZipEntry(String name) { 345 return new ZipEntry (name); 346 } 347 348 351 private void readEnd(ZipEntry e) throws IOException { 352 int n = inf.getRemaining(); 353 if (n > 0) { 354 ((PushbackInputStream )in).unread(buf, len - n, n); 355 } 356 if ((e.flag & 8) == 8) { 357 358 readFully(tmpbuf, 0, EXTHDR); 359 long sig = get32(tmpbuf, 0); 360 if (sig != EXTSIG) { e.crc = sig; 362 e.csize = get32(tmpbuf, EXTSIZ - EXTCRC); 363 e.size = get32(tmpbuf, EXTLEN - EXTCRC); 364 ((PushbackInputStream )in).unread( 365 tmpbuf, EXTHDR - EXTCRC - 1, EXTCRC); 366 } else { 367 e.crc = get32(tmpbuf, EXTCRC); 368 e.csize = get32(tmpbuf, EXTSIZ); 369 e.size = get32(tmpbuf, EXTLEN); 370 } 371 } 372 if (e.size != inf.getBytesWritten()) { 373 throw new ZipException ( 374 "invalid entry size (expected " + e.size + 375 " but got " + inf.getBytesWritten() + " bytes)"); 376 } 377 if (e.csize != inf.getBytesRead()) { 378 throw new ZipException ( 379 "invalid entry compressed size (expected " + e.csize + 380 " but got " + inf.getBytesRead() + " bytes)"); 381 } 382 if (e.crc != crc.getValue()) { 383 throw new ZipException ( 384 "invalid entry CRC (expected 0x" + Long.toHexString(e.crc) + 385 " but got 0x" + Long.toHexString(crc.getValue()) + ")"); 386 } 387 } 388 389 392 private void readFully(byte[] b, int off, int len) throws IOException { 393 while (len > 0) { 394 int n = in.read(b, off, len); 395 if (n == -1) { 396 throw new EOFException (); 397 } 398 off += n; 399 len -= n; 400 } 401 } 402 403 407 private static final int get16(byte b[], int off) { 408 return (b[off] & 0xff) | ((b[off+1] & 0xff) << 8); 409 } 410 411 415 private static final long get32(byte b[], int off) { 416 return get16(b, off) | ((long)get16(b, off+2) << 16); 417 } 418 } 419 | Popular Tags |