1 17 18 package net.sourceforge.groboutils.codecoverage.v2.ant.zip; 19 20 import java.io.File ; 21 import java.io.IOException ; 22 import java.io.InputStream ; 23 import java.io.RandomAccessFile ; 24 import java.io.UnsupportedEncodingException ; 25 import java.util.Calendar ; 26 import java.util.Date ; 27 import java.util.Enumeration ; 28 import java.util.Hashtable ; 29 import java.util.zip.Inflater ; 30 import java.util.zip.InflaterInputStream ; 31 import java.util.zip.ZipException ; 32 33 62 public class ZipFile { 63 64 68 private Hashtable entries = new Hashtable (); 69 70 73 private Hashtable nameMap = new Hashtable (); 74 75 78 private Hashtable dataOffsets = new Hashtable (); 79 80 87 private String encoding = null; 88 89 92 private RandomAccessFile archive; 93 94 102 public ZipFile(File f) throws IOException { 103 this(f, null); 104 } 105 106 114 public ZipFile(String name) throws IOException { 115 this(new File (name), null); 116 } 117 118 127 public ZipFile(String name, String encoding) throws IOException { 128 this(new File (name), encoding); 129 } 130 131 140 public ZipFile(File f, String encoding) throws IOException { 141 this.encoding = encoding; 142 archive = new RandomAccessFile (f, "r"); 143 populateFromCentralDirectory(); 144 resolveLocalFileHeaderData(); 145 } 146 147 152 public String getEncoding() { 153 return encoding; 154 } 155 156 160 public void close() throws IOException { 161 archive.close(); 162 } 163 164 169 public Enumeration getEntries() { 170 return entries.keys(); 171 } 172 173 180 public ZipEntry getEntry(String name) { 181 return (ZipEntry) nameMap.get(name); 182 } 183 184 189 public InputStream getInputStream(ZipEntry ze) 190 throws IOException , ZipException { 191 Long start = (Long ) dataOffsets.get(ze); 192 if (start == null) { 193 return null; 194 } 195 BoundedInputStream bis = 196 new BoundedInputStream(start.longValue(), ze.getCompressedSize()); 197 switch (ze.getMethod()) { 198 case ZipEntry.STORED: 199 return bis; 200 case ZipEntry.DEFLATED: 201 bis.addDummy(); 202 return new InflaterInputStream (bis, new Inflater (true)); 203 default: 204 throw new ZipException ("Found unsupported compression method " 205 + ze.getMethod()); 206 } 207 } 208 209 private static final int CFH_LEN = 210 2 + 211 2 + 212 2 + 213 2 + 214 2 + 215 2 + 216 4 + 217 4 + 218 4 + 219 2 + 220 2 + 221 2 + 222 2 + 223 2 + 224 4 + 225 4; 226 227 235 private void populateFromCentralDirectory() 236 throws IOException { 237 positionAtCentralDirectory(); 238 239 byte[] cfh = new byte[CFH_LEN]; 240 241 byte[] signatureBytes = new byte[4]; 242 archive.readFully(signatureBytes); 243 ZipLong sig = new ZipLong(signatureBytes); 244 while (sig.equals(ZipOutputStream.CFH_SIG)) { 245 archive.readFully(cfh); 246 int off = 0; 247 ZipEntry ze = new ZipEntry(); 248 249 ZipShort versionMadeBy = new ZipShort(cfh, off); 250 off += 2; 251 ze.setPlatform((versionMadeBy.getValue() >> 8) & 0x0F); 252 253 off += 4; 255 ze.setMethod((new ZipShort(cfh, off)).getValue()); 256 off += 2; 257 258 ze.setTime(fromDosTime(new ZipLong(cfh, off)).getTime()); 259 off += 4; 260 261 ze.setCrc((new ZipLong(cfh, off)).getValue()); 262 off += 4; 263 264 ze.setCompressedSize((new ZipLong(cfh, off)).getValue()); 265 off += 4; 266 267 ze.setSize((new ZipLong(cfh, off)).getValue()); 268 off += 4; 269 270 int fileNameLen = (new ZipShort(cfh, off)).getValue(); 271 off += 2; 272 273 int extraLen = (new ZipShort(cfh, off)).getValue(); 274 off += 2; 275 276 int commentLen = (new ZipShort(cfh, off)).getValue(); 277 off += 2; 278 279 off += 2; 281 ze.setInternalAttributes((new ZipShort(cfh, off)).getValue()); 282 off += 2; 283 284 ze.setExternalAttributes((new ZipLong(cfh, off)).getValue()); 285 off += 4; 286 287 entries.put(ze, new Long ((new ZipLong(cfh, off)).getValue())); 289 290 byte[] fileName = new byte[fileNameLen]; 291 archive.readFully(fileName); 292 ze.setName(getString(fileName)); 293 294 nameMap.put(ze.getName(), ze); 295 296 archive.skipBytes(extraLen); 297 298 byte[] comment = new byte[commentLen]; 299 archive.readFully(comment); 300 ze.setComment(getString(comment)); 301 302 archive.readFully(signatureBytes); 303 sig = new ZipLong(signatureBytes); 304 } 305 } 306 307 private static final int MIN_EOCD_SIZE = 308 4 + 309 2 + 310 + 311 2 + 312 + 313 2 + 314 + 315 2 + 316 4 + 317 + 318 + 319 4 + 320 2; 321 322 private static final int CFD_LOCATOR_OFFSET = 323 4 + 324 2 + 325 + 326 2 + 327 + 328 2 + 329 + 330 2 + 331 4; 332 333 338 private void positionAtCentralDirectory() 339 throws IOException { 340 long off = archive.length() - MIN_EOCD_SIZE; 341 archive.seek(off); 342 byte[] sig = ZipOutputStream.EOCD_SIG.getBytes(); 343 int curr = archive.read(); 344 boolean found = false; 345 while (curr != -1) { 346 if (curr == sig[0]) { 347 curr = archive.read(); 348 if (curr == sig[1]) { 349 curr = archive.read(); 350 if (curr == sig[2]) { 351 curr = archive.read(); 352 if (curr == sig[3]) { 353 found = true; 354 break; 355 } 356 } 357 } 358 } 359 archive.seek(--off); 360 curr = archive.read(); 361 } 362 if (!found) { 363 throw new ZipException ("archive is not a ZIP archive"); 364 } 365 archive.seek(off + CFD_LOCATOR_OFFSET); 366 byte[] cfdOffset = new byte[4]; 367 archive.readFully(cfdOffset); 368 archive.seek((new ZipLong(cfdOffset)).getValue()); 369 } 370 371 375 private static final long LFH_OFFSET_FOR_FILENAME_LENGTH = 376 4 + 377 2 + 378 2 + 379 2 + 380 2 + 381 2 + 382 4 + 383 4 + 384 4; 385 386 393 private void resolveLocalFileHeaderData() 394 throws IOException { 395 Enumeration e = getEntries(); 396 while (e.hasMoreElements()) { 397 ZipEntry ze = (ZipEntry) e.nextElement(); 398 long offset = ((Long ) entries.get(ze)).longValue(); 399 archive.seek(offset + LFH_OFFSET_FOR_FILENAME_LENGTH); 400 byte[] b = new byte[2]; 401 archive.readFully(b); 402 int fileNameLen = (new ZipShort(b)).getValue(); 403 archive.readFully(b); 404 int extraFieldLen = (new ZipShort(b)).getValue(); 405 archive.skipBytes(fileNameLen); 406 byte[] localExtraData = new byte[extraFieldLen]; 407 archive.readFully(localExtraData); 408 ze.setExtra(localExtraData); 409 dataOffsets.put(ze, 410 new Long (offset + LFH_OFFSET_FOR_FILENAME_LENGTH 411 + 2 + 2 + fileNameLen + extraFieldLen)); 412 } 413 } 414 415 421 protected static Date fromDosTime(ZipLong l) { 422 long dosTime = l.getValue(); 423 Calendar cal = Calendar.getInstance(); 424 cal.set(Calendar.YEAR, (int) ((dosTime >> 25) & 0x7f) + 1980); 425 cal.set(Calendar.MONTH, (int) ((dosTime >> 21) & 0x0f) - 1); 426 cal.set(Calendar.DATE, (int) (dosTime >> 16) & 0x1f); 427 cal.set(Calendar.HOUR_OF_DAY, (int) (dosTime >> 11) & 0x1f); 428 cal.set(Calendar.MINUTE, (int) (dosTime >> 5) & 0x3f); 429 cal.set(Calendar.SECOND, (int) (dosTime << 1) & 0x3e); 430 return cal.getTime(); 431 } 432 433 441 protected String getString(byte[] bytes) throws ZipException { 442 if (encoding == null) { 443 return new String (bytes); 444 } else { 445 try { 446 return new String (bytes, encoding); 447 } catch (UnsupportedEncodingException uee) { 448 throw new ZipException (uee.getMessage()); 449 } 450 } 451 } 452 453 458 private class BoundedInputStream extends InputStream { 459 private long remaining; 460 private long loc; 461 private boolean addDummyByte = false; 462 463 BoundedInputStream(long start, long remaining) { 464 this.remaining = remaining; 465 loc = start; 466 } 467 468 public int read() throws IOException { 469 if (remaining-- <= 0) { 470 if (addDummyByte) { 471 addDummyByte = false; 472 return 0; 473 } 474 return -1; 475 } 476 synchronized (archive) { 477 archive.seek(loc++); 478 return archive.read(); 479 } 480 } 481 482 public int read(byte[] b, int off, int len) throws IOException { 483 if (remaining <= 0) { 484 if (addDummyByte) { 485 addDummyByte = false; 486 b[off] = 0; 487 return 1; 488 } 489 return -1; 490 } 491 492 if (len <= 0) { 493 return 0; 494 } 495 496 if (len > remaining) { 497 len = (int) remaining; 498 } 499 int ret = -1; 500 synchronized (archive) { 501 archive.seek(loc); 502 ret = archive.read(b, off, len); 503 } 504 if (ret > 0) { 505 loc += ret; 506 remaining -= ret; 507 } 508 return ret; 509 } 510 511 515 void addDummy() { 516 addDummyByte = true; 517 } 518 } 519 520 } 521 | Popular Tags |