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 {
|