1 18 19 package org.apache.tools.zip; 20 21 import java.io.File ; 22 import java.io.FileOutputStream ; 23 import java.io.FilterOutputStream ; 24 import java.io.IOException ; 25 import java.io.OutputStream ; 26 import java.io.RandomAccessFile ; 27 import java.io.UnsupportedEncodingException ; 28 import java.util.Date ; 29 import java.util.Hashtable ; 30 import java.util.Vector ; 31 import java.util.zip.CRC32 ; 32 import java.util.zip.Deflater ; 33 import java.util.zip.ZipException ; 34 35 55 public class ZipOutputStream extends FilterOutputStream { 56 57 62 public static final int DEFLATED = java.util.zip.ZipEntry.DEFLATED; 63 64 69 public static final int DEFAULT_COMPRESSION = Deflater.DEFAULT_COMPRESSION; 70 71 76 public static final int STORED = java.util.zip.ZipEntry.STORED; 77 78 83 private ZipEntry entry; 84 85 90 private String comment = ""; 91 92 97 private int level = DEFAULT_COMPRESSION; 98 99 105 private boolean hasCompressionLevelChanged = false; 106 107 112 private int method = java.util.zip.ZipEntry.DEFLATED; 113 114 119 private Vector entries = new Vector (); 120 121 126 private CRC32 crc = new CRC32 (); 127 128 133 private long written = 0; 134 135 140 private long dataStart = 0; 141 142 148 private long localDataStart = 0; 149 150 155 private long cdOffset = 0; 156 157 162 private long cdLength = 0; 163 164 169 private static final byte[] ZERO = {0, 0}; 170 171 176 private static final byte[] LZERO = {0, 0, 0, 0}; 177 178 183 private Hashtable offsets = new Hashtable (); 184 185 194 private String encoding = null; 195 196 198 208 protected Deflater def = new Deflater (level, true); 209 210 220 protected byte[] buf = new byte[512]; 221 222 224 229 private RandomAccessFile raf = null; 230 231 236 public ZipOutputStream(OutputStream out) { 237 super(out); 238 } 239 240 247 public ZipOutputStream(File file) throws IOException { 248 super(null); 249 250 try { 251 raf = new RandomAccessFile (file, "rw"); 252 raf.setLength(0); 253 } catch (IOException e) { 254 if (raf != null) { 255 try { 256 raf.close(); 257 } catch (IOException inner) { 258 } 260 raf = null; 261 } 262 out = new FileOutputStream (file); 263 } 264 } 265 266 276 public boolean isSeekable() { 277 return raf != null; 278 } 279 280 289 public void setEncoding(String encoding) { 290 this.encoding = encoding; 291 } 292 293 300 public String getEncoding() { 301 return encoding; 302 } 303 304 311 public void finish() throws IOException { 312 closeEntry(); 313 cdOffset = written; 314 for (int i = 0, entriesSize = entries.size(); i < entriesSize; i++) { 315 writeCentralFileHeader((ZipEntry) entries.elementAt(i)); 316 } 317 cdLength = written - cdOffset; 318 writeCentralDirectoryEnd(); 319 offsets.clear(); 320 entries.removeAllElements(); 321 } 322 323 329 public void closeEntry() throws IOException { 330 if (entry == null) { 331 return; 332 } 333 334 long realCrc = crc.getValue(); 335 crc.reset(); 336 337 if (entry.getMethod() == DEFLATED) { 338 def.finish(); 339 while (!def.finished()) { 340 deflate(); 341 } 342 343 entry.setSize(adjustToLong(def.getTotalIn())); 344 entry.setCompressedSize(adjustToLong(def.getTotalOut())); 345 entry.setCrc(realCrc); 346 347 def.reset(); 348 349 written += entry.getCompressedSize(); 350 } else if (raf == null) { 351 if (entry.getCrc() != realCrc) { 352 throw new ZipException ("bad CRC checksum for entry " 353 + entry.getName() + ": " 354 + Long.toHexString(entry.getCrc()) 355 + " instead of " 356 + Long.toHexString(realCrc)); 357 } 358 359 if (entry.getSize() != written - dataStart) { 360 throw new ZipException ("bad size for entry " 361 + entry.getName() + ": " 362 + entry.getSize() 363 + " instead of " 364 + (written - dataStart)); 365 } 366 } else { 367 long size = written - dataStart; 368 369 entry.setSize(size); 370 entry.setCompressedSize(size); 371 entry.setCrc(realCrc); 372 } 373 374 if (raf != null) { 377 long save = raf.getFilePointer(); 378 379 raf.seek(localDataStart); 380 writeOut(ZipLong.getBytes(entry.getCrc())); 381 writeOut(ZipLong.getBytes(entry.getCompressedSize())); 382 writeOut(ZipLong.getBytes(entry.getSize())); 383 raf.seek(save); 384 } 385 386 writeDataDescriptor(entry); 387 entry = null; 388 } 389 390 396 public void putNextEntry(ZipEntry ze) throws IOException { 397 closeEntry(); 398 399 entry = ze; 400 entries.addElement(entry); 401 402 if (entry.getMethod() == -1) { entry.setMethod(method); 404 } 405 406 if (entry.getTime() == -1) { entry.setTime(System.currentTimeMillis()); 408 } 409 410 if (entry.getMethod() == STORED && raf == null) { 412 if (entry.getSize() == -1) { 413 throw new ZipException ("uncompressed size is required for" 414 + " STORED method when not writing to a" 415 + " file"); 416 } 417 if (entry.getCrc() == -1) { 418 throw new ZipException ("crc checksum is required for STORED" 419 + " method when not writing to a file"); 420 } 421 entry.setCompressedSize(entry.getSize()); 422 } 423 424 if (entry.getMethod() == DEFLATED && hasCompressionLevelChanged) { 425 def.setLevel(level); 426 hasCompressionLevelChanged = false; 427 } 428 writeLocalFileHeader(entry); 429 } 430 431 436 public void setComment(String comment) { 437 this.comment = comment; 438 } 439 440 448 public void setLevel(int level) { 449 if (level < Deflater.DEFAULT_COMPRESSION 450 || level > Deflater.BEST_COMPRESSION) { 451 throw new IllegalArgumentException ( 452 "Invalid compression level: " + level); 453 } 454 hasCompressionLevelChanged = (this.level != level); 455 this.level = level; 456 } 457 458 465 public void setMethod(int method) { 466 this.method = method; 467 } 468 469 476 public void write(byte[] b, int offset, int length) throws IOException { 477 if (entry.getMethod() == DEFLATED) { 478 if (length > 0) { 479 if (!def.finished()) { 480 def.setInput(b, offset, length); 481 while (!def.needsInput()) { 482 deflate(); 483 } 484 } 485 } 486 } else { 487 writeOut(b, offset, length); 488 written += length; 489 } 490 crc.update(b, offset, length); 491 } 492 493 501 public void write(int b) throws IOException { 502 byte[] buff = new byte[1]; 503 buff[0] = (byte) (b & 0xff); 504 write(buff, 0, 1); 505 } 506 507 514 public void close() throws IOException { 515 finish(); 516 517 if (raf != null) { 518 raf.close(); 519 } 520 if (out != null) { 521 out.close(); 522 } 523 } 524 525 532 public void flush() throws IOException { 533 if (out != null) { 534 out.flush(); 535 } 536 } 537 538 541 546 protected static final byte[] LFH_SIG = ZipLong.getBytes(0X04034B50L); 547 552 protected static final byte[] DD_SIG = ZipLong.getBytes(0X08074B50L); 553 558 protected static final byte[] CFH_SIG = ZipLong.getBytes(0X02014B50L); 559 564 protected static final byte[] EOCD_SIG = ZipLong.getBytes(0X06054B50L); 565 566 572 protected final void deflate() throws IOException { 573 int len = def.deflate(buf, 0, buf.length); 574 if (len > 0) { 575 writeOut(buf, 0, len); 576 } 577 } 578 579 586 protected void writeLocalFileHeader(ZipEntry ze) throws IOException { 587 offsets.put(ze, ZipLong.getBytes(written)); 588 589 writeOut(LFH_SIG); 590 written += 4; 591 592 final int zipMethod = ze.getMethod(); 594 595 if (zipMethod == DEFLATED && raf == null) { 598 writeOut(ZipShort.getBytes(20)); 601 602 writeOut(ZipShort.getBytes(8)); 604 } else { 605 writeOut(ZipShort.getBytes(10)); 606 writeOut(ZERO); 607 } 608 written += 4; 609 610 writeOut(ZipShort.getBytes(zipMethod)); 612 written += 2; 613 614 writeOut(toDosTime(ze.getTime())); 616 written += 4; 617 618 localDataStart = written; 622 if (zipMethod == DEFLATED || raf != null) { 623 writeOut(LZERO); 624 writeOut(LZERO); 625 writeOut(LZERO); 626 } else { 627 writeOut(ZipLong.getBytes(ze.getCrc())); 628 writeOut(ZipLong.getBytes(ze.getSize())); 629 writeOut(ZipLong.getBytes(ze.getSize())); 630 } 631 written += 12; 632 633 byte[] name = getBytes(ze.getName()); 635 writeOut(ZipShort.getBytes(name.length)); 636 written += 2; 637 638 byte[] extra = ze.getLocalFileDataExtra(); 640 writeOut(ZipShort.getBytes(extra.length)); 641 written += 2; 642 643 writeOut(name); 645 written += name.length; 646 647 writeOut(extra); 649 written += extra.length; 650 651 dataStart = written; 652 } 653 654 661 protected void writeDataDescriptor(ZipEntry ze) throws IOException { 662 if (ze.getMethod() != DEFLATED || raf != null) { 663 return; 664 } 665 writeOut(DD_SIG); 666 writeOut(ZipLong.getBytes(entry.getCrc())); 667 writeOut(ZipLong.getBytes(entry.getCompressedSize())); 668 writeOut(ZipLong.getBytes(entry.getSize())); 669 written += 16; 670 } 671 672 679 protected void writeCentralFileHeader(ZipEntry ze) throws IOException { 680 writeOut(CFH_SIG); 681 written += 4; 682 683 writeOut(ZipShort.getBytes((ze.getPlatform() << 8) | 20)); 685 written += 2; 686 687 if (ze.getMethod() == DEFLATED && raf == null) { 690 writeOut(ZipShort.getBytes(20)); 693 694 writeOut(ZipShort.getBytes(8)); 696 } else { 697 writeOut(ZipShort.getBytes(10)); 698 writeOut(ZERO); 699 } 700 written += 4; 701 702 writeOut(ZipShort.getBytes(ze.getMethod())); 704 written += 2; 705 706 writeOut(toDosTime(ze.getTime())); 708 written += 4; 709 710 writeOut(ZipLong.getBytes(ze.getCrc())); 714 writeOut(ZipLong.getBytes(ze.getCompressedSize())); 715 writeOut(ZipLong.getBytes(ze.getSize())); 716 written += 12; 717 718 byte[] name = getBytes(ze.getName()); 720 writeOut(ZipShort.getBytes(name.length)); 721 written += 2; 722 723 byte[] extra = ze.getCentralDirectoryExtra(); 725 writeOut(ZipShort.getBytes(extra.length)); 726 written += 2; 727 728 String comm = ze.getComment(); 730 if (comm == null) { 731 comm = ""; 732 } 733 byte[] commentB = getBytes(comm); 734 writeOut(ZipShort.getBytes(commentB.length)); 735 written += 2; 736 737 writeOut(ZERO); 739 written += 2; 740 741 writeOut(ZipShort.getBytes(ze.getInternalAttributes())); 743 written += 2; 744 745 writeOut(ZipLong.getBytes(ze.getExternalAttributes())); 747 written += 4; 748 749 writeOut((byte[]) offsets.get(ze)); 751 written += 4; 752 753 writeOut(name); 755 written += name.length; 756 757 writeOut(extra); 759 written += extra.length; 760 761 writeOut(commentB); 763 written += commentB.length; 764 } 765 766 772 protected void writeCentralDirectoryEnd() throws IOException { 773 writeOut(EOCD_SIG); 774 775 writeOut(ZERO); 777 writeOut(ZERO); 778 779 byte[] num = ZipShort.getBytes(entries.size()); 781 writeOut(num); 782 writeOut(num); 783 784 writeOut(ZipLong.getBytes(cdLength)); 786 writeOut(ZipLong.getBytes(cdOffset)); 787 788 byte[] data = getBytes(comment); 790 writeOut(ZipShort.getBytes(data.length)); 791 writeOut(data); 792 } 793 794 799 private static final byte[] DOS_TIME_MIN = ZipLong.getBytes(0x00002100L); 800 801 807 protected static ZipLong toDosTime(Date time) { 808 return new ZipLong(toDosTime(time.getTime())); 809 } 810 811 819 protected static byte[] toDosTime(long t) { 820 Date time = new Date (t); 821 int year = time.getYear() + 1900; 822 if (year < 1980) { 823 return DOS_TIME_MIN; 824 } 825 int month = time.getMonth() + 1; 826 long value = ((year - 1980) << 25) 827 | (month << 21) 828 | (time.getDate() << 16) 829 | (time.getHours() << 11) 830 | (time.getMinutes() << 5) 831 | (time.getSeconds() >> 1); 832 return ZipLong.getBytes(value); 833 } 834 835 844 protected byte[] getBytes(String name) throws ZipException { 845 if (encoding == null) { 846 return name.getBytes(); 847 } else { 848 try { 849 return name.getBytes(encoding); 850 } catch (UnsupportedEncodingException uee) { 851 throw new ZipException (uee.getMessage()); 852 } 853 } 854 } 855 856 863 protected final void writeOut(byte[] data) throws IOException { 864 writeOut(data, 0, data.length); 865 } 866 867 876 protected final void writeOut(byte[] data, int offset, int length) 877 throws IOException { 878 if (raf != null) { 879 raf.write(data, offset, length); 880 } else { 881 out.write(data, offset, length); 882 } 883 } 884 885 892 protected static long adjustToLong(int i) { 893 if (i < 0) { 894 return 2 * ((long) Integer.MAX_VALUE) + 2 + i; 895 } else { 896 return i; 897 } 898 } 899 900 } 901 | Popular Tags |