30 import java.nio.charset.Charset; |
30 import java.nio.charset.Charset; |
31 import java.nio.charset.StandardCharsets; |
31 import java.nio.charset.StandardCharsets; |
32 import java.util.Vector; |
32 import java.util.Vector; |
33 import java.util.HashSet; |
33 import java.util.HashSet; |
34 import static java.util.zip.ZipConstants64.*; |
34 import static java.util.zip.ZipConstants64.*; |
|
35 import static java.util.zip.ZipUtils.*; |
35 |
36 |
36 /** |
37 /** |
37 * This class implements an output stream filter for writing files in the |
38 * This class implements an output stream filter for writing files in the |
38 * ZIP file format. Includes support for both compressed and uncompressed |
39 * ZIP file format. Includes support for both compressed and uncompressed |
39 * entries. |
40 * entries. |
188 public void putNextEntry(ZipEntry e) throws IOException { |
189 public void putNextEntry(ZipEntry e) throws IOException { |
189 ensureOpen(); |
190 ensureOpen(); |
190 if (current != null) { |
191 if (current != null) { |
191 closeEntry(); // close previous entry |
192 closeEntry(); // close previous entry |
192 } |
193 } |
193 if (e.time == -1) { |
194 if (e.mtime == -1) { |
194 e.setTime(System.currentTimeMillis()); |
195 e.setTime(System.currentTimeMillis()); |
195 } |
196 } |
196 if (e.method == -1) { |
197 if (e.method == -1) { |
197 e.method = method; // use default method |
198 e.method = method; // use default method |
198 } |
199 } |
380 * Writes local file (LOC) header for specified entry. |
381 * Writes local file (LOC) header for specified entry. |
381 */ |
382 */ |
382 private void writeLOC(XEntry xentry) throws IOException { |
383 private void writeLOC(XEntry xentry) throws IOException { |
383 ZipEntry e = xentry.entry; |
384 ZipEntry e = xentry.entry; |
384 int flag = e.flag; |
385 int flag = e.flag; |
|
386 boolean hasZip64 = false; |
385 int elen = (e.extra != null) ? e.extra.length : 0; |
387 int elen = (e.extra != null) ? e.extra.length : 0; |
386 boolean hasZip64 = false; |
388 int eoff = 0; |
387 |
389 boolean foundEXTT = false; // if EXTT already present |
|
390 // do nothing. |
|
391 while (eoff + 4 < elen) { |
|
392 int tag = get16(e.extra, eoff); |
|
393 int sz = get16(e.extra, eoff + 2); |
|
394 if (tag == EXTID_EXTT) { |
|
395 foundEXTT = true; |
|
396 } |
|
397 eoff += (4 + sz); |
|
398 } |
388 writeInt(LOCSIG); // LOC header signature |
399 writeInt(LOCSIG); // LOC header signature |
389 |
|
390 if ((flag & 8) == 8) { |
400 if ((flag & 8) == 8) { |
391 writeShort(version(e)); // version needed to extract |
401 writeShort(version(e)); // version needed to extract |
392 writeShort(flag); // general purpose bit flag |
402 writeShort(flag); // general purpose bit flag |
393 writeShort(e.method); // compression method |
403 writeShort(e.method); // compression method |
394 writeInt(e.time); // last modification time |
404 writeInt(javaToDosTime(e.mtime)); // last modification time |
395 |
405 |
396 // store size, uncompressed size, and crc-32 in data descriptor |
406 // store size, uncompressed size, and crc-32 in data descriptor |
397 // immediately following compressed entry data |
407 // immediately following compressed entry data |
398 writeInt(0); |
408 writeInt(0); |
399 writeInt(0); |
409 writeInt(0); |
405 } else { |
415 } else { |
406 writeShort(version(e)); // version needed to extract |
416 writeShort(version(e)); // version needed to extract |
407 } |
417 } |
408 writeShort(flag); // general purpose bit flag |
418 writeShort(flag); // general purpose bit flag |
409 writeShort(e.method); // compression method |
419 writeShort(e.method); // compression method |
410 writeInt(e.time); // last modification time |
420 writeInt(javaToDosTime(e.mtime)); // last modification time |
411 writeInt(e.crc); // crc-32 |
421 writeInt(e.crc); // crc-32 |
412 if (hasZip64) { |
422 if (hasZip64) { |
413 writeInt(ZIP64_MAGICVAL); |
423 writeInt(ZIP64_MAGICVAL); |
414 writeInt(ZIP64_MAGICVAL); |
424 writeInt(ZIP64_MAGICVAL); |
415 elen += 20; //headid(2) + size(2) + size(8) + csize(8) |
425 elen += 20; //headid(2) + size(2) + size(8) + csize(8) |
418 writeInt(e.size); // uncompressed size |
428 writeInt(e.size); // uncompressed size |
419 } |
429 } |
420 } |
430 } |
421 byte[] nameBytes = zc.getBytes(e.name); |
431 byte[] nameBytes = zc.getBytes(e.name); |
422 writeShort(nameBytes.length); |
432 writeShort(nameBytes.length); |
|
433 if (!foundEXTT) |
|
434 elen += 9; // use Info-ZIP's ext time in extra |
423 writeShort(elen); |
435 writeShort(elen); |
424 writeBytes(nameBytes, 0, nameBytes.length); |
436 writeBytes(nameBytes, 0, nameBytes.length); |
425 if (hasZip64) { |
437 if (hasZip64) { |
426 writeShort(ZIP64_EXTID); |
438 writeShort(ZIP64_EXTID); |
427 writeShort(16); |
439 writeShort(16); |
428 writeLong(e.size); |
440 writeLong(e.size); |
429 writeLong(e.csize); |
441 writeLong(e.csize); |
|
442 } |
|
443 if (!foundEXTT) { |
|
444 writeShort(EXTID_EXTT); |
|
445 writeShort(5); // size for the folowing data block |
|
446 writeByte(0x1); // flags byte, mtime only |
|
447 writeInt(javaToUnixTime(e.mtime)); |
430 } |
448 } |
431 if (e.extra != null) { |
449 if (e.extra != null) { |
432 writeBytes(e.extra, 0, e.extra.length); |
450 writeBytes(e.extra, 0, e.extra.length); |
433 } |
451 } |
434 locoff = written; |
452 locoff = written; |
455 */ |
473 */ |
456 private void writeCEN(XEntry xentry) throws IOException { |
474 private void writeCEN(XEntry xentry) throws IOException { |
457 ZipEntry e = xentry.entry; |
475 ZipEntry e = xentry.entry; |
458 int flag = e.flag; |
476 int flag = e.flag; |
459 int version = version(e); |
477 int version = version(e); |
460 |
|
461 long csize = e.csize; |
478 long csize = e.csize; |
462 long size = e.size; |
479 long size = e.size; |
463 long offset = xentry.offset; |
480 long offset = xentry.offset; |
464 int e64len = 0; |
481 int elenZIP64 = 0; |
465 boolean hasZip64 = false; |
482 boolean hasZip64 = false; |
|
483 |
466 if (e.csize >= ZIP64_MAGICVAL) { |
484 if (e.csize >= ZIP64_MAGICVAL) { |
467 csize = ZIP64_MAGICVAL; |
485 csize = ZIP64_MAGICVAL; |
468 e64len += 8; // csize(8) |
486 elenZIP64 += 8; // csize(8) |
469 hasZip64 = true; |
487 hasZip64 = true; |
470 } |
488 } |
471 if (e.size >= ZIP64_MAGICVAL) { |
489 if (e.size >= ZIP64_MAGICVAL) { |
472 size = ZIP64_MAGICVAL; // size(8) |
490 size = ZIP64_MAGICVAL; // size(8) |
473 e64len += 8; |
491 elenZIP64 += 8; |
474 hasZip64 = true; |
492 hasZip64 = true; |
475 } |
493 } |
476 if (xentry.offset >= ZIP64_MAGICVAL) { |
494 if (xentry.offset >= ZIP64_MAGICVAL) { |
477 offset = ZIP64_MAGICVAL; |
495 offset = ZIP64_MAGICVAL; |
478 e64len += 8; // offset(8) |
496 elenZIP64 += 8; // offset(8) |
479 hasZip64 = true; |
497 hasZip64 = true; |
480 } |
498 } |
481 writeInt(CENSIG); // CEN header signature |
499 writeInt(CENSIG); // CEN header signature |
482 if (hasZip64) { |
500 if (hasZip64) { |
483 writeShort(45); // ver 4.5 for zip64 |
501 writeShort(45); // ver 4.5 for zip64 |
486 writeShort(version); // version made by |
504 writeShort(version); // version made by |
487 writeShort(version); // version needed to extract |
505 writeShort(version); // version needed to extract |
488 } |
506 } |
489 writeShort(flag); // general purpose bit flag |
507 writeShort(flag); // general purpose bit flag |
490 writeShort(e.method); // compression method |
508 writeShort(e.method); // compression method |
491 writeInt(e.time); // last modification time |
509 writeInt(javaToDosTime(e.mtime)); // last modification time |
492 writeInt(e.crc); // crc-32 |
510 writeInt(e.crc); // crc-32 |
493 writeInt(csize); // compressed size |
511 writeInt(csize); // compressed size |
494 writeInt(size); // uncompressed size |
512 writeInt(size); // uncompressed size |
495 byte[] nameBytes = zc.getBytes(e.name); |
513 byte[] nameBytes = zc.getBytes(e.name); |
496 writeShort(nameBytes.length); |
514 writeShort(nameBytes.length); |
|
515 |
|
516 int elen = (e.extra != null) ? e.extra.length : 0; |
|
517 int eoff = 0; |
|
518 boolean foundEXTT = false; // if EXTT already present |
|
519 // do nothing. |
|
520 while (eoff + 4 < elen) { |
|
521 int tag = get16(e.extra, eoff); |
|
522 int sz = get16(e.extra, eoff + 2); |
|
523 if (tag == EXTID_EXTT) { |
|
524 foundEXTT = true; |
|
525 } |
|
526 eoff += (4 + sz); |
|
527 } |
497 if (hasZip64) { |
528 if (hasZip64) { |
498 // + headid(2) + datasize(2) |
529 // + headid(2) + datasize(2) |
499 writeShort(e64len + 4 + (e.extra != null ? e.extra.length : 0)); |
530 elen += (elenZIP64 + 4); |
500 } else { |
531 } |
501 writeShort(e.extra != null ? e.extra.length : 0); |
532 if (!foundEXTT) |
502 } |
533 elen += 9; // Info-ZIP's Extended Timestamp |
|
534 writeShort(elen); |
503 byte[] commentBytes; |
535 byte[] commentBytes; |
504 if (e.comment != null) { |
536 if (e.comment != null) { |
505 commentBytes = zc.getBytes(e.comment); |
537 commentBytes = zc.getBytes(e.comment); |
506 writeShort(Math.min(commentBytes.length, 0xffff)); |
538 writeShort(Math.min(commentBytes.length, 0xffff)); |
507 } else { |
539 } else { |
513 writeInt(0); // external file attributes (unused) |
545 writeInt(0); // external file attributes (unused) |
514 writeInt(offset); // relative offset of local header |
546 writeInt(offset); // relative offset of local header |
515 writeBytes(nameBytes, 0, nameBytes.length); |
547 writeBytes(nameBytes, 0, nameBytes.length); |
516 if (hasZip64) { |
548 if (hasZip64) { |
517 writeShort(ZIP64_EXTID);// Zip64 extra |
549 writeShort(ZIP64_EXTID);// Zip64 extra |
518 writeShort(e64len); |
550 writeShort(elenZIP64); |
519 if (size == ZIP64_MAGICVAL) |
551 if (size == ZIP64_MAGICVAL) |
520 writeLong(e.size); |
552 writeLong(e.size); |
521 if (csize == ZIP64_MAGICVAL) |
553 if (csize == ZIP64_MAGICVAL) |
522 writeLong(e.csize); |
554 writeLong(e.csize); |
523 if (offset == ZIP64_MAGICVAL) |
555 if (offset == ZIP64_MAGICVAL) |
524 writeLong(xentry.offset); |
556 writeLong(xentry.offset); |
|
557 } |
|
558 if (!foundEXTT) { |
|
559 writeShort(EXTID_EXTT); |
|
560 writeShort(5); |
|
561 writeByte(0x1); // flags byte |
|
562 writeInt(javaToUnixTime(e.mtime)); |
525 } |
563 } |
526 if (e.extra != null) { |
564 if (e.extra != null) { |
527 writeBytes(e.extra, 0, e.extra.length); |
565 writeBytes(e.extra, 0, e.extra.length); |
528 } |
566 } |
529 if (commentBytes != null) { |
567 if (commentBytes != null) { |
587 writeShort(0); |
625 writeShort(0); |
588 } |
626 } |
589 } |
627 } |
590 |
628 |
591 /* |
629 /* |
|
630 * Writes a 8-bit byte to the output stream. |
|
631 */ |
|
632 private void writeByte(int v) throws IOException { |
|
633 OutputStream out = this.out; |
|
634 out.write(v & 0xff); |
|
635 written += 1; |
|
636 } |
|
637 |
|
638 /* |
592 * Writes a 16-bit short to the output stream in little-endian byte order. |
639 * Writes a 16-bit short to the output stream in little-endian byte order. |
593 */ |
640 */ |
594 private void writeShort(int v) throws IOException { |
641 private void writeShort(int v) throws IOException { |
595 OutputStream out = this.out; |
642 OutputStream out = this.out; |
596 out.write((v >>> 0) & 0xff); |
643 out.write((v >>> 0) & 0xff); |