1 17 18 package net.sourceforge.groboutils.codecoverage.v2.ant.zip; 19 20 import java.io.File ; 21 import java.io.FileOutputStream ; 22 import java.io.FilterOutputStream ; 23 import java.io.IOException ; 24 import java.io.OutputStream ; 25 import java.io.RandomAccessFile ; 26 import java.io.UnsupportedEncodingException ; 27 import java.util.Date ; 28 import java.util.Hashtable ; 29 import java.util.Vector ; 30 import java.util.zip.CRC32 ; 31 import java.util.zip.Deflater ; 32 import java.util.zip.ZipException ; 33 34 57 public class ZipOutputStream extends FilterOutputStream { 58 59 64 private ZipEntry entry; 65 66 71 private String comment = ""; 72 73 78 private int level = Deflater.DEFAULT_COMPRESSION; 79 80 86 private boolean hasCompressionLevelChanged = false; 87 88 93 private int method = DEFLATED; 94 95 100 private Vector entries = new Vector (); 101 102 107 private CRC32 crc = new CRC32 (); 108 109 114 private long written = 0; 115 116 121 private long dataStart = 0; 122 123 129 private long localDataStart = 0; 130 131 136 private ZipLong cdOffset = new ZipLong(0); 137 138 143 private ZipLong cdLength = new ZipLong(0); 144 145 150 private static final byte[] ZERO = {0, 0}; 151 152 157 private static final byte[] LZERO = {0, 0, 0, 0}; 158 159 164 private Hashtable offsets = new Hashtable (); 165 166 175 private String encoding = null; 176 177 187 protected Deflater def = new Deflater (Deflater.DEFAULT_COMPRESSION, true); 188 189 199 protected byte[] buf = new byte[512]; 200 201 206 private RandomAccessFile raf = null; 207 208 213 public static final int DEFLATED = ZipEntry.DEFLATED; 214 215 220 public static final int STORED = ZipEntry.STORED; 221 222 227 public ZipOutputStream(OutputStream out) { 228 super(out); 229 } 230 231 237 public ZipOutputStream(File file) throws IOException { 238 super(null); 239 240 try { 241 raf = new RandomAccessFile (file, "rw"); 242 raf.setLength(0); 243 } catch (IOException e) { 244 if (raf != null) { 245 try { 246 raf.close(); 247 } catch (IOException inner) { 248 } 250 raf = null; 251 } 252 out = new FileOutputStream (file); 253 } 254 } 255 256 266 public boolean isSeekable() { 267 return raf != null; 268 } 269 270 279 public void setEncoding(String encoding) { 280 this.encoding = encoding; 281 } 282 283 290 public String getEncoding() { 291 return encoding; 292 } 293 294 300 public void finish() throws IOException { 301 closeEntry(); 302 cdOffset = new ZipLong(written); 303 for (int i = 0; i < entries.size(); i++) { 304 writeCentralFileHeader((ZipEntry) entries.elementAt(i)); 305 } 306 cdLength = new ZipLong(written - cdOffset.getValue()); 307 writeCentralDirectoryEnd(); 308 offsets.clear(); 309 entries.removeAllElements(); 310 } 311 312 317 public void closeEntry() throws IOException { 318 if (entry == null) { 319 return; 320 } 321 322 long realCrc = crc.getValue(); 323 crc.reset(); 324 325 if (entry.getMethod() == DEFLATED) { 326 def.finish(); 327 while (!def.finished()) { 328 deflate(); 329 } 330 331 entry.setSize(def.getTotalIn()); 332 entry.setComprSize(def.getTotalOut()); 333 entry.setCrc(realCrc); 334 335 def.reset(); 336 337 written += entry.getCompressedSize(); 338 } else if (raf == null) { 339 if (entry.getCrc() != realCrc) { 340 throw new ZipException ("bad CRC checksum for entry " 341 + entry.getName() + ": " 342 + Long.toHexString(entry.getCrc()) 343 + " instead of " 344 + Long.toHexString(realCrc)); 345 } 346 347 if (entry.getSize() != written - dataStart) { 348 throw new ZipException ("bad size for entry " 349 + entry.getName() + ": " 350 + entry.getSize() 351 + " instead of " 352 + (written - dataStart)); 353 } 354 } else { 355 long size = written - dataStart; 356 357 entry.setSize(size); 358 entry.setComprSize(size); 359 entry.setCrc(realCrc); 360 } 361 362 if (raf != null) { 365 long save = raf.getFilePointer(); 366 367 raf.seek(localDataStart); 368 writeOut((new ZipLong(entry.getCrc())).getBytes()); 369 writeOut((new ZipLong(entry.getCompressedSize())).getBytes()); 370 writeOut((new ZipLong(entry.getSize())).getBytes()); 371 raf.seek(save); 372 } 373 374 writeDataDescriptor(entry); 375 entry = null; 376 } 377 378 383 public void putNextEntry(ZipEntry ze) throws IOException { 384 closeEntry(); 385 386 entry = ze; 387 entries.addElement(entry); 388 389 if (entry.getMethod() == -1) { entry.setMethod(method); 391 } 392 393 if (entry.getTime() == -1) { entry.setTime(System.currentTimeMillis()); 395 } 396 397 if (entry.getMethod() == STORED && raf == null) { 399 if (entry.getSize() == -1) { 400 throw new ZipException ("uncompressed size is required for" 401 + " STORED method when not writing to a" 402 + " file"); 403 } 404 if (entry.getCrc() == -1) { 405 throw new ZipException ("crc checksum is required for STORED" 406 + " method when not writing to a file"); 407 } 408 entry.setComprSize(entry.getSize()); 409 } 410 411 if (entry.getMethod() == DEFLATED && hasCompressionLevelChanged) { 412 def.setLevel(level); 413 hasCompressionLevelChanged = false; 414 } 415 writeLocalFileHeader(entry); 416 } 417 418 423 public void setComment(String comment) { 424 this.comment = comment; 425 } 426 427 434 public void setLevel(int level) { 435 hasCompressionLevelChanged = (this.level != level); 436 this.level = level; 437 } 438 439 446 public void setMethod(int method) { 447 this.method = method; 448 } 449 450 453 public void write(byte[] b, int offset, int length) throws IOException { 454 if (entry.getMethod() == DEFLATED) { 455 if (length > 0) { 456 if (!def.finished()) { 457 def.setInput(b, offset, length); 458 while (!def.needsInput()) { 459 deflate(); 460 } 461 } 462 } 463 } else { 464 writeOut(b, offset, length); 465 written += length; 466 } 467 crc.update(b, offset, length); 468 } 469 470 477 public void write(int b) throws IOException { 478 byte[] buf = new byte[1]; 479 buf[0] = (byte) (b & 0xff); 480 write(buf, 0, 1); 481 } 482 483 490 public void close() throws IOException { 491 finish(); 492 493 if (raf != null) { 494 raf.close(); 495 } 496 if (out != null) { 497 out.close(); 498 } 499 } 500 501 508 public void flush() throws IOException { 509 if (out == null) { 510 out.flush(); 511 } 512 } 513 514 517 522 protected static final ZipLong LFH_SIG = new ZipLong(0X04034B50L); 523 528 protected static final ZipLong DD_SIG = new ZipLong(0X08074B50L); 529 534 protected static final ZipLong CFH_SIG = new ZipLong(0X02014B50L); 535 540 protected static final ZipLong EOCD_SIG = new ZipLong(0X06054B50L); 541 542 547 protected final void deflate() throws IOException { 548 int len = def.deflate(buf, 0, buf.length); 549 if (len > 0) { 550 writeOut(buf, 0, len); 551 } 552 } 553 554 559 protected void writeLocalFileHeader(ZipEntry ze) throws IOException { 560 offsets.put(ze, new ZipLong(written)); 561 562 writeOut(LFH_SIG.getBytes()); 563 written += 4; 564 565 if (ze.getMethod() == DEFLATED && raf == null) { 568 writeOut((new ZipShort(20)).getBytes()); 571 572 writeOut((new ZipShort(8)).getBytes()); 574 } else { 575 writeOut((new ZipShort(10)).getBytes()); 576 writeOut(ZERO); 577 } 578 written += 4; 579 580 writeOut((new ZipShort(ze.getMethod())).getBytes()); 582 written += 2; 583 584 writeOut(toDosTime(new Date (ze.getTime())).getBytes()); 586 written += 4; 587 588 localDataStart = written; 592 if (ze.getMethod() == DEFLATED || raf != null) { 593 writeOut(LZERO); 594 writeOut(LZERO); 595 writeOut(LZERO); 596 } else { 597 writeOut((new ZipLong(ze.getCrc())).getBytes()); 598 writeOut((new ZipLong(ze.getSize())).getBytes()); 599 writeOut((new ZipLong(ze.getSize())).getBytes()); 600 } 601 written += 12; 602 603 byte[] name = getBytes(ze.getName()); 605 writeOut((new ZipShort(name.length)).getBytes()); 606 written += 2; 607 608 byte[] extra = ze.getLocalFileDataExtra(); 610 writeOut((new ZipShort(extra.length)).getBytes()); 611 written += 2; 612 613 writeOut(name); 615 written += name.length; 616 617 writeOut(extra); 619 written += extra.length; 620 621 dataStart = written; 622 } 623 624 629 protected void writeDataDescriptor(ZipEntry ze) throws IOException { 630 if (ze.getMethod() != DEFLATED || raf != null) { 631 return; 632 } 633 writeOut(DD_SIG.getBytes()); 634 writeOut((new ZipLong(entry.getCrc())).getBytes()); 635 writeOut((new ZipLong(entry.getCompressedSize())).getBytes()); 636 writeOut((new ZipLong(entry.getSize())).getBytes()); 637 written += 16; 638 } 639 640 645 protected void writeCentralFileHeader(ZipEntry ze) throws IOException { 646 writeOut(CFH_SIG.getBytes()); 647 written += 4; 648 649 writeOut((new ZipShort((ze.getPlatform() << 8) | 20)).getBytes()); 651 written += 2; 652 653 if (ze.getMethod() == DEFLATED && raf == null) { 656 writeOut((new ZipShort(20)).getBytes()); 659 660 writeOut((new ZipShort(8)).getBytes()); 662 } else { 663 writeOut((new ZipShort(10)).getBytes()); 664 writeOut(ZERO); 665 } 666 written += 4; 667 668 writeOut((new ZipShort(ze.getMethod())).getBytes()); 670 written += 2; 671 672 writeOut(toDosTime(new Date (ze.getTime())).getBytes()); 674 written += 4; 675 676 writeOut((new ZipLong(ze.getCrc())).getBytes()); 680 writeOut((new ZipLong(ze.getCompressedSize())).getBytes()); 681 writeOut((new ZipLong(ze.getSize())).getBytes()); 682 written += 12; 683 684 byte[] name = getBytes(ze.getName()); 686 writeOut((new ZipShort(name.length)).getBytes()); 687 written += 2; 688 689 byte[] extra = ze.getCentralDirectoryExtra(); 691 writeOut((new ZipShort(extra.length)).getBytes()); 692 written += 2; 693 694 String comm = ze.getComment(); 696 if (comm == null) { 697 comm = ""; 698 } 699 byte[] comment = getBytes(comm); 700 writeOut((new ZipShort(comment.length)).getBytes()); 701 written += 2; 702 703 writeOut(ZERO); 705 written += 2; 706 707 writeOut((new ZipShort(ze.getInternalAttributes())).getBytes()); 709 written += 2; 710 711 writeOut((new ZipLong(ze.getExternalAttributes())).getBytes()); 713 written += 4; 714 715 writeOut(((ZipLong) offsets.get(ze)).getBytes()); 717 written += 4; 718 719 writeOut(name); 721 written += name.length; 722 723 writeOut(extra); 725 written += extra.length; 726 727 writeOut(comment); 729 written += comment.length; 730 } 731 732 737 protected void writeCentralDirectoryEnd() throws IOException { 738 writeOut(EOCD_SIG.getBytes()); 739 740 writeOut(ZERO); 742 writeOut(ZERO); 743 744 byte[] num = (new ZipShort(entries.size())).getBytes(); 746 writeOut(num); 747 writeOut(num); 748 749 writeOut(cdLength.getBytes()); 751 writeOut(cdOffset.getBytes()); 752 753 byte[] data = getBytes(comment); 755 writeOut((new ZipShort(data.length)).getBytes()); 756 writeOut(data); 757 } 758 759 764 private static final ZipLong DOS_TIME_MIN = new ZipLong(0x00002100L); 765 766 773 protected static ZipLong toDosTime(Date time) { 774 int year = time.getYear() + 1900; 775 int month = time.getMonth() + 1; 776 if (year < 1980) { 777 return DOS_TIME_MIN; 778 } 779 long value = ((year - 1980) << 25) 780 | (month << 21) 781 | (time.getDate() << 16) 782 | (time.getHours() << 11) 783 | (time.getMinutes() << 5) 784 | (time.getSeconds() >> 1); 785 786 byte[] result = new byte[4]; 787 result[0] = (byte) ((value & 0xFF)); 788 result[1] = (byte) ((value & 0xFF00) >> 8); 789 result[2] = (byte) ((value & 0xFF0000) >> 16); 790 result[3] = (byte) ((value & 0xFF000000L) >> 24); 791 return new ZipLong(result); 792 } 793 794 800 protected byte[] getBytes(String name) throws ZipException { 801 if (encoding == null) { 802 return name.getBytes(); 803 } else { 804 try { 805 return name.getBytes(encoding); 806 } catch (UnsupportedEncodingException uee) { 807 throw new ZipException (uee.getMessage()); 808 } 809 } 810 } 811 812 817 protected final void writeOut(byte [] data) throws IOException { 818 writeOut(data, 0, data.length); 819 } 820 821 826 protected final void writeOut(byte [] data, int offset, int length) 827 throws IOException { 828 if (raf != null) { 829 raf.write(data, offset, length); 830 } else { 831 out.write(data, offset, length); 832 } 833 } 834 } 835 | Popular Tags |