src/share/classes/java/util/zip/ZipOutputStream.java

Print this page


   1 /*
   2  * Copyright 1996-2008 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package java.util.zip;
  27 
  28 import java.io.OutputStream;
  29 import java.io.IOException;
  30 import java.util.Vector;
  31 import java.util.HashSet;

  32 
  33 /**
  34  * This class implements an output stream filter for writing files in the
  35  * ZIP file format. Includes support for both compressed and uncompressed
  36  * entries.
  37  *
  38  * @author      David Connelly
  39  */
  40 public
  41 class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
  42 
  43     private static class XEntry {
  44         public final ZipEntry entry;
  45         public final long offset;
  46         public final int flag;
  47         public XEntry(ZipEntry entry, long offset) {
  48             this.entry = entry;
  49             this.offset = offset;
  50             this.flag = (entry.method == DEFLATED &&
  51                          (entry.size  == -1 ||


 326     }
 327 
 328     /**
 329      * Closes the ZIP output stream as well as the stream being filtered.
 330      * @exception ZipException if a ZIP file error has occurred
 331      * @exception IOException if an I/O error has occurred
 332      */
 333     public void close() throws IOException {
 334         if (!closed) {
 335             super.close();
 336             closed = true;
 337         }
 338     }
 339 
 340     /*
 341      * Writes local file (LOC) header for specified entry.
 342      */
 343     private void writeLOC(XEntry xentry) throws IOException {
 344         ZipEntry e = xentry.entry;
 345         int flag = xentry.flag;



 346         writeInt(LOCSIG);           // LOC header signature


 347         writeShort(version(e));     // version needed to extract
 348         writeShort(flag);           // general purpose bit flag
 349         writeShort(e.method);       // compression method
 350         writeInt(e.time);           // last modification time
 351         if ((flag & 8) == 8) {
 352             // store size, uncompressed size, and crc-32 in data descriptor
 353             // immediately following compressed entry data
 354             writeInt(0);
 355             writeInt(0);
 356             writeInt(0);
 357         } else {









 358             writeInt(e.crc);        // crc-32





 359             writeInt(e.csize);      // compressed size
 360             writeInt(e.size);       // uncompressed size
 361         }

 362         byte[] nameBytes = getUTF8Bytes(e.name);
 363         writeShort(nameBytes.length);
 364         writeShort(e.extra != null ? e.extra.length : 0);
 365         writeBytes(nameBytes, 0, nameBytes.length);






 366         if (e.extra != null) {
 367             writeBytes(e.extra, 0, e.extra.length);
 368         }
 369         locoff = written;
 370     }
 371 
 372     /*
 373      * Writes extra data descriptor (EXT) for specified entry.
 374      */
 375     private void writeEXT(ZipEntry e) throws IOException {
 376         writeInt(EXTSIG);           // EXT header signature
 377         writeInt(e.crc);            // crc-32




 378         writeInt(e.csize);          // compressed size
 379         writeInt(e.size);           // uncompressed size
 380     }

 381 
 382     /*
 383      * Write central directory (CEN) header for specified entry.
 384      * REMIND: add support for file attributes
 385      */
 386     private void writeCEN(XEntry xentry) throws IOException {
 387         ZipEntry e  = xentry.entry;
 388         int flag = xentry.flag;
 389         int version = version(e);





















 390         writeInt(CENSIG);           // CEN header signature




 391         writeShort(version);        // version made by
 392         writeShort(version);        // version needed to extract

 393         writeShort(flag);           // general purpose bit flag
 394         writeShort(e.method);       // compression method
 395         writeInt(e.time);           // last modification time
 396         writeInt(e.crc);            // crc-32
 397         writeInt(e.csize);          // compressed size
 398         writeInt(e.size);           // uncompressed size
 399         byte[] nameBytes = getUTF8Bytes(e.name);
 400         writeShort(nameBytes.length);




 401         writeShort(e.extra != null ? e.extra.length : 0);

 402         byte[] commentBytes;
 403         if (e.comment != null) {
 404             commentBytes = getUTF8Bytes(e.comment);
 405             writeShort(commentBytes.length);
 406         } else {
 407             commentBytes = null;
 408             writeShort(0);
 409         }
 410         writeShort(0);              // starting disk number
 411         writeShort(0);              // internal file attributes (unused)
 412         writeInt(0);                // external file attributes (unused)
 413         writeInt(xentry.offset);    // relative offset of local header
 414         writeBytes(nameBytes, 0, nameBytes.length);










 415         if (e.extra != null) {
 416             writeBytes(e.extra, 0, e.extra.length);
 417         }
 418         if (commentBytes != null) {
 419             writeBytes(commentBytes, 0, commentBytes.length);
 420         }
 421     }
 422 
 423     /*
 424      * Writes end of central directory (END) header.
 425      */
 426     private void writeEND(long off, long len) throws IOException {











 427         int count = xentries.size();
























 428         writeInt(ENDSIG);           // END record signature
 429         writeShort(0);              // number of this disk
 430         writeShort(0);              // central directory start disk
 431         writeShort(count);          // number of directory entries on disk
 432         writeShort(count);          // total number of directory entries
 433         writeInt(len);              // length of central directory
 434         writeInt(off);              // offset of central directory
 435         if (comment != null) {      // zip file comment
 436             byte[] b = getUTF8Bytes(comment);
 437             writeShort(b.length);
 438             writeBytes(b, 0, b.length);
 439         } else {
 440             writeShort(0);
 441         }
 442     }
 443 
 444     /*
 445      * Writes a 16-bit short to the output stream in little-endian byte order.
 446      */
 447     private void writeShort(int v) throws IOException {
 448         OutputStream out = this.out;
 449         out.write((v >>> 0) & 0xff);
 450         out.write((v >>> 8) & 0xff);
 451         written += 2;
 452     }
 453 
 454     /*
 455      * Writes a 32-bit int to the output stream in little-endian byte order.
 456      */
 457     private void writeInt(long v) throws IOException {
 458         OutputStream out = this.out;
 459         out.write((int)((v >>>  0) & 0xff));
 460         out.write((int)((v >>>  8) & 0xff));
 461         out.write((int)((v >>> 16) & 0xff));
 462         out.write((int)((v >>> 24) & 0xff));
 463         written += 4;
 464     }
 465 
















 466     /*
 467      * Writes an array of bytes to the output stream.
 468      */
 469     private void writeBytes(byte[] b, int off, int len) throws IOException {
 470         super.out.write(b, off, len);
 471         written += len;
 472     }
 473 
 474     /*
 475      * Returns the length of String's UTF8 encoding.
 476      */
 477     static int getUTF8Length(String s) {
 478         int count = 0;
 479         for (int i = 0; i < s.length(); i++) {
 480             char ch = s.charAt(i);
 481             if (ch <= 0x7f) {
 482                 count++;
 483             } else if (ch <= 0x7ff) {
 484                 count += 2;
 485             } else {


   1 /*
   2  * Copyright 1996-2009 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 package java.util.zip;
  27 
  28 import java.io.OutputStream;
  29 import java.io.IOException;
  30 import java.util.Vector;
  31 import java.util.HashSet;
  32 import static java.util.zip.ZipConstants64.*;
  33 
  34 /**
  35  * This class implements an output stream filter for writing files in the
  36  * ZIP file format. Includes support for both compressed and uncompressed
  37  * entries.
  38  *
  39  * @author      David Connelly
  40  */
  41 public
  42 class ZipOutputStream extends DeflaterOutputStream implements ZipConstants {
  43 
  44     private static class XEntry {
  45         public final ZipEntry entry;
  46         public final long offset;
  47         public final int flag;
  48         public XEntry(ZipEntry entry, long offset) {
  49             this.entry = entry;
  50             this.offset = offset;
  51             this.flag = (entry.method == DEFLATED &&
  52                          (entry.size  == -1 ||


 327     }
 328 
 329     /**
 330      * Closes the ZIP output stream as well as the stream being filtered.
 331      * @exception ZipException if a ZIP file error has occurred
 332      * @exception IOException if an I/O error has occurred
 333      */
 334     public void close() throws IOException {
 335         if (!closed) {
 336             super.close();
 337             closed = true;
 338         }
 339     }
 340 
 341     /*
 342      * Writes local file (LOC) header for specified entry.
 343      */
 344     private void writeLOC(XEntry xentry) throws IOException {
 345         ZipEntry e = xentry.entry;
 346         int flag = xentry.flag;
 347         int elen = (e.extra != null) ? e.extra.length : 0;
 348         boolean hasZip64 = false;
 349 
 350         writeInt(LOCSIG);           // LOC header signature
 351 
 352         if ((flag & 8) == 8) {
 353             writeShort(version(e));     // version needed to extract
 354             writeShort(flag);           // general purpose bit flag
 355             writeShort(e.method);       // compression method
 356             writeInt(e.time);           // last modification time
 357 
 358             // store size, uncompressed size, and crc-32 in data descriptor
 359             // immediately following compressed entry data
 360             writeInt(0);
 361             writeInt(0);
 362             writeInt(0);
 363         } else {
 364             if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) {
 365                 hasZip64 = true;
 366                 writeShort(45);         // ver 4.5 for zip64
 367             } else {
 368                 writeShort(version(e)); // version needed to extract
 369             }
 370             writeShort(flag);           // general purpose bit flag
 371             writeShort(e.method);       // compression method
 372             writeInt(e.time);           // last modification time
 373             writeInt(e.crc);            // crc-32
 374             if (hasZip64) {
 375                 writeInt(ZIP64_MAGICVAL);
 376                 writeInt(ZIP64_MAGICVAL);
 377                 elen += 20;        //headid(2) + size(2) + size(8) + csize(8)
 378             } else {
 379                 writeInt(e.csize);  // compressed size
 380                 writeInt(e.size);   // uncompressed size
 381             }
 382         }
 383         byte[] nameBytes = getUTF8Bytes(e.name);
 384         writeShort(nameBytes.length);
 385         writeShort(elen);
 386         writeBytes(nameBytes, 0, nameBytes.length);
 387         if (hasZip64) {
 388             writeShort(ZIP64_EXTID);
 389             writeShort(16);
 390             writeLong(e.size);
 391             writeLong(e.csize);
 392         }
 393         if (e.extra != null) {
 394             writeBytes(e.extra, 0, e.extra.length);
 395         }
 396         locoff = written;
 397     }
 398 
 399     /*
 400      * Writes extra data descriptor (EXT) for specified entry.
 401      */
 402     private void writeEXT(ZipEntry e) throws IOException {
 403         writeInt(EXTSIG);           // EXT header signature
 404         writeInt(e.crc);            // crc-32
 405         if (e.csize >= ZIP64_MAGICVAL || e.size >= ZIP64_MAGICVAL) {
 406             writeLong(e.csize);
 407             writeLong(e.size);
 408         } else {
 409             writeInt(e.csize);          // compressed size
 410             writeInt(e.size);           // uncompressed size
 411         }
 412     }
 413 
 414     /*
 415      * Write central directory (CEN) header for specified entry.
 416      * REMIND: add support for file attributes
 417      */
 418     private void writeCEN(XEntry xentry) throws IOException {
 419         ZipEntry e  = xentry.entry;
 420         int flag = xentry.flag;
 421         int version = version(e);
 422 
 423         long csize = e.csize;
 424         long size = e.size;
 425         long offset = xentry.offset;
 426         int e64len = 0;
 427         boolean hasZip64 = false; 
 428         if (e.csize >= ZIP64_MAGICVAL) {
 429             csize = ZIP64_MAGICVAL;
 430             e64len += 8;              // csize(8)
 431             hasZip64 = true;
 432         }
 433         if (e.size >= ZIP64_MAGICVAL) {
 434             size = ZIP64_MAGICVAL;    // size(8) 
 435             e64len += 8;
 436             hasZip64 = true;
 437         } 
 438         if (xentry.offset >= ZIP64_MAGICVAL) {
 439             offset = ZIP64_MAGICVAL;
 440             e64len += 8;              // offset(8)
 441             hasZip64 = true;
 442         } 
 443         writeInt(CENSIG);           // CEN header signature
 444         if (hasZip64) {
 445             writeShort(45);         // ver 4.5 for zip64
 446             writeShort(45);
 447         } else {
 448             writeShort(version);    // version made by
 449             writeShort(version);    // version needed to extract
 450         }
 451         writeShort(flag);           // general purpose bit flag
 452         writeShort(e.method);       // compression method
 453         writeInt(e.time);           // last modification time
 454         writeInt(e.crc);            // crc-32
 455         writeInt(csize);            // compressed size
 456         writeInt(size);             // uncompressed size
 457         byte[] nameBytes = getUTF8Bytes(e.name);
 458         writeShort(nameBytes.length);
 459         if (hasZip64) {
 460             // + headid(2) + datasize(2)
 461             writeShort(e64len + 4 + (e.extra != null ? e.extra.length : 0));
 462         } else {
 463             writeShort(e.extra != null ? e.extra.length : 0);
 464         }
 465         byte[] commentBytes;
 466         if (e.comment != null) {
 467             commentBytes = getUTF8Bytes(e.comment);
 468             writeShort(commentBytes.length);
 469         } else {
 470             commentBytes = null;
 471             writeShort(0);
 472         }
 473         writeShort(0);              // starting disk number
 474         writeShort(0);              // internal file attributes (unused)
 475         writeInt(0);                // external file attributes (unused)
 476         writeInt(offset);           // relative offset of local header
 477         writeBytes(nameBytes, 0, nameBytes.length);
 478         if (hasZip64) {
 479             writeShort(ZIP64_EXTID);// Zip64 extra
 480             writeShort(e64len);
 481             if (size == ZIP64_MAGICVAL)
 482                 writeLong(e.size);
 483             if (csize == ZIP64_MAGICVAL)
 484                 writeLong(e.csize);
 485             if (offset == ZIP64_MAGICVAL)
 486                 writeLong(xentry.offset);
 487         }
 488         if (e.extra != null) {
 489             writeBytes(e.extra, 0, e.extra.length);
 490         }
 491         if (commentBytes != null) {
 492             writeBytes(commentBytes, 0, commentBytes.length);
 493         }
 494     }
 495 
 496     /*
 497      * Writes end of central directory (END) header.
 498      */
 499     private void writeEND(long off, long len) throws IOException {
 500         boolean hasZip64 = false;
 501         long xlen = len;
 502         long xoff = off;
 503         if (xlen >= ZIP64_MAGICVAL) {
 504             xlen = ZIP64_MAGICVAL;
 505             hasZip64 = true;
 506         }
 507         if (xoff >= ZIP64_MAGICVAL) {
 508             xoff = ZIP64_MAGICVAL;
 509             hasZip64 = true;
 510         }
 511         int count = xentries.size();
 512         if (count >= ZIP64_MAGICCOUNT) {
 513             count = ZIP64_MAGICCOUNT;
 514             hasZip64 = true;
 515         }
 516         if (hasZip64) {
 517             long off64 = written;
 518             //zip64 end of central directory record
 519             writeInt(ZIP64_ENDSIG);        // zip64 END record signature
 520             writeLong(ZIP64_ENDHDR - 12);  // size of zip64 end
 521             writeShort(45);                // version made by
 522             writeShort(45);                // version needed to extract
 523             writeInt(0);                   // number of this disk
 524             writeInt(0);                   // central directory start disk
 525             writeLong(xentries.size());    // number of directory entires on disk
 526             writeLong(xentries.size());    // number of directory entires
 527             writeLong(len);                // length of central directory
 528             writeLong(off);                // offset of central directory
 529 
 530             //zip64 end of central directory locator
 531             writeInt(ZIP64_LOCSIG);        // zip64 END locator signature
 532             writeInt(0);                   // zip64 END start disk
 533             writeLong(off64);              // offset of zip64 END
 534             writeInt(1);                   // total number of disks (?)
 535         }
 536         writeInt(ENDSIG);                 // END record signature
 537         writeShort(0);                    // number of this disk
 538         writeShort(0);                    // central directory start disk
 539         writeShort(count);                // number of directory entries on disk
 540         writeShort(count);                // total number of directory entries
 541         writeInt(xlen);                   // length of central directory
 542         writeInt(xoff);                   // offset of central directory
 543         if (comment != null) {            // zip file comment
 544             byte[] b = getUTF8Bytes(comment);
 545             writeShort(b.length);
 546             writeBytes(b, 0, b.length);
 547         } else {
 548             writeShort(0);
 549         }
 550     }
 551 
 552     /*
 553      * Writes a 16-bit short to the output stream in little-endian byte order.
 554      */
 555     private void writeShort(int v) throws IOException {
 556         OutputStream out = this.out;
 557         out.write((v >>> 0) & 0xff);
 558         out.write((v >>> 8) & 0xff);
 559         written += 2;
 560     }
 561 
 562     /*
 563      * Writes a 32-bit int to the output stream in little-endian byte order.
 564      */
 565     private void writeInt(long v) throws IOException {
 566         OutputStream out = this.out;
 567         out.write((int)((v >>>  0) & 0xff));
 568         out.write((int)((v >>>  8) & 0xff));
 569         out.write((int)((v >>> 16) & 0xff));
 570         out.write((int)((v >>> 24) & 0xff));
 571         written += 4;
 572     }
 573 
 574     /*
 575      * Writes a 64-bit int to the output stream in little-endian byte order.
 576      */
 577     private void writeLong(long v) throws IOException {
 578         OutputStream out = this.out;
 579         out.write((int)((v >>>  0) & 0xff));
 580         out.write((int)((v >>>  8) & 0xff));
 581         out.write((int)((v >>> 16) & 0xff));
 582         out.write((int)((v >>> 24) & 0xff));
 583         out.write((int)((v >>> 32) & 0xff));
 584         out.write((int)((v >>> 40) & 0xff));
 585         out.write((int)((v >>> 48) & 0xff));
 586         out.write((int)((v >>> 56) & 0xff));
 587         written += 8;
 588     }
 589 
 590     /*
 591      * Writes an array of bytes to the output stream.
 592      */
 593     private void writeBytes(byte[] b, int off, int len) throws IOException {
 594         super.out.write(b, off, len);
 595         written += len;
 596     }
 597 
 598     /*
 599      * Returns the length of String's UTF8 encoding.
 600      */
 601     static int getUTF8Length(String s) {
 602         int count = 0;
 603         for (int i = 0; i < s.length(); i++) {
 604             char ch = s.charAt(i);
 605             if (ch <= 0x7f) {
 606                 count++;
 607             } else if (ch <= 0x7ff) {
 608                 count += 2;
 609             } else {