src/share/classes/java/util/zip/ZipOutputStream.java
Print this page
@@ -57,12 +57,13 @@
java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction(
"jdk.util.zip.inhibitZip64", "false")));
private static class XEntry {
- public final ZipEntry entry;
- public final long offset;
+ final ZipEntry entry;
+ final long offset;
+ long dostime; // last modification time in msdos format
public XEntry(ZipEntry entry, long offset) {
this.entry = entry;
this.offset = offset;
}
}
@@ -189,11 +190,13 @@
public void putNextEntry(ZipEntry e) throws IOException {
ensureOpen();
if (current != null) {
closeEntry(); // close previous entry
}
- if (e.mtime == -1) {
+ if (e.time == -1) {
+ // by default, do NOT use extended timestamps in extra
+ // data, for now.
e.setTime(System.currentTimeMillis());
}
if (e.method == -1) {
e.method = method; // use default method
}
@@ -382,29 +385,24 @@
*/
private void writeLOC(XEntry xentry) throws IOException {
ZipEntry e = xentry.entry;
int flag = e.flag;
boolean hasZip64 = false;
- int elen = (e.extra != null) ? e.extra.length : 0;
- int eoff = 0;
- boolean foundEXTT = false; // if EXTT already present
- // do nothing.
- while (eoff + 4 < elen) {
- int tag = get16(e.extra, eoff);
- int sz = get16(e.extra, eoff + 2);
- if (tag == EXTID_EXTT) {
- foundEXTT = true;
- }
- eoff += (4 + sz);
- }
+ int elen = getExtraLen(e.extra);
+
+ // keep a copy of dostime for writeCEN(), otherwise the tz
+ // sensitive local time entries in loc and cen might be
+ // different if the default tz get changed during writeLOC()
+ // and writeCEN()
+ xentry.dostime = javaToDosTime(e.time);
+
writeInt(LOCSIG); // LOC header signature
if ((flag & 8) == 8) {
writeShort(version(e)); // version needed to extract
writeShort(flag); // general purpose bit flag
writeShort(e.method); // compression method
- writeInt(javaToDosTime(e.mtime)); // last modification time
-
+ writeInt(xentry.dostime); // last modification time
// store size, uncompressed size, and crc-32 in data descriptor
// immediately following compressed entry data
writeInt(0);
writeInt(0);
writeInt(0);
@@ -415,11 +413,11 @@
} else {
writeShort(version(e)); // version needed to extract
}
writeShort(flag); // general purpose bit flag
writeShort(e.method); // compression method
- writeInt(javaToDosTime(e.mtime)); // last modification time
+ writeInt(xentry.dostime); // last modification time
writeInt(e.crc); // crc-32
if (hasZip64) {
writeInt(ZIP64_MAGICVAL);
writeInt(ZIP64_MAGICVAL);
elen += 20; //headid(2) + size(2) + size(8) + csize(8)
@@ -428,29 +426,47 @@
writeInt(e.size); // uncompressed size
}
}
byte[] nameBytes = zc.getBytes(e.name);
writeShort(nameBytes.length);
- if (!foundEXTT)
- elen += 9; // use Info-ZIP's ext time in extra
+
+ int elenEXTT = 0; // info-zip extended timestamp
+ int flagEXTT = 0;
+ if (e.mtime != null) {
+ elenEXTT += 4;
+ flagEXTT |= EXTT_FLAG_LMT;
+ }
+ if (e.atime != null) {
+ elenEXTT += 4;
+ flagEXTT |= EXTT_FLAG_LAT;
+ }
+ if (e.ctime != null) {
+ elenEXTT += 4;
+ flagEXTT |= EXTT_FLAT_CT;
+ }
+ if (flagEXTT != 0)
+ elen += (elenEXTT + 5); // headid(2) + size(2) + flag(1) + data
writeShort(elen);
writeBytes(nameBytes, 0, nameBytes.length);
if (hasZip64) {
writeShort(ZIP64_EXTID);
writeShort(16);
writeLong(e.size);
writeLong(e.csize);
}
- if (!foundEXTT) {
+ if (flagEXTT != 0) {
writeShort(EXTID_EXTT);
- writeShort(5); // size for the folowing data block
- writeByte(0x1); // flags byte, mtime only
- writeInt(javaToUnixTime(e.mtime));
- }
- if (e.extra != null) {
- writeBytes(e.extra, 0, e.extra.length);
+ writeShort(elenEXTT + 1); // flag + data
+ writeByte(flagEXTT);
+ if (e.mtime != null)
+ writeInt(fileTimeToUnixTime(e.mtime));
+ if (e.atime != null)
+ writeInt(fileTimeToUnixTime(e.atime));
+ if (e.ctime != null)
+ writeInt(fileTimeToUnixTime(e.ctime));
}
+ writeExtra(e.extra);
locoff = written;
}
/*
* Writes extra data descriptor (EXT) for specified entry.
@@ -504,35 +520,39 @@
writeShort(version); // version made by
writeShort(version); // version needed to extract
}
writeShort(flag); // general purpose bit flag
writeShort(e.method); // compression method
- writeInt(javaToDosTime(e.mtime)); // last modification time
+ // use the copy in xentry, which has been converted
+ // from e.time in writeLOC()
+ writeInt(xentry.dostime); // last modification time
writeInt(e.crc); // crc-32
writeInt(csize); // compressed size
writeInt(size); // uncompressed size
byte[] nameBytes = zc.getBytes(e.name);
writeShort(nameBytes.length);
- int elen = (e.extra != null) ? e.extra.length : 0;
- int eoff = 0;
- boolean foundEXTT = false; // if EXTT already present
- // do nothing.
- while (eoff + 4 < elen) {
- int tag = get16(e.extra, eoff);
- int sz = get16(e.extra, eoff + 2);
- if (tag == EXTID_EXTT) {
- foundEXTT = true;
+ int elen = getExtraLen(e.extra);
+ if (hasZip64) {
+ elen += (elenZIP64 + 4);// + headid(2) + datasize(2)
}
- eoff += (4 + sz);
+ // cen info-zip extended timestamp only outputs mtime
+ // but set the flag for a/ctime, if present in loc
+ int flagEXTT = 0;
+ if (e.mtime != null) {
+ elen += 4; // + mtime(4)
+ flagEXTT |= EXTT_FLAG_LMT;
}
- if (hasZip64) {
- // + headid(2) + datasize(2)
- elen += (elenZIP64 + 4);
+ if (e.atime != null) {
+ flagEXTT |= EXTT_FLAG_LAT;
+ }
+ if (e.ctime != null) {
+ flagEXTT |= EXTT_FLAT_CT;
+ }
+ if (flagEXTT != 0) {
+ elen += 5; // headid + sz + flag
}
- if (!foundEXTT)
- elen += 9; // Info-ZIP's Extended Timestamp
writeShort(elen);
byte[] commentBytes;
if (e.comment != null) {
commentBytes = zc.getBytes(e.comment);
writeShort(Math.min(commentBytes.length, 0xffff));
@@ -543,29 +563,34 @@
writeShort(0); // starting disk number
writeShort(0); // internal file attributes (unused)
writeInt(0); // external file attributes (unused)
writeInt(offset); // relative offset of local header
writeBytes(nameBytes, 0, nameBytes.length);
+
+ // take care of EXTID_ZIP64 and EXTID_EXTT
if (hasZip64) {
writeShort(ZIP64_EXTID);// Zip64 extra
writeShort(elenZIP64);
if (size == ZIP64_MAGICVAL)
writeLong(e.size);
if (csize == ZIP64_MAGICVAL)
writeLong(e.csize);
if (offset == ZIP64_MAGICVAL)
writeLong(xentry.offset);
}
- if (!foundEXTT) {
+ if (flagEXTT != 0) {
writeShort(EXTID_EXTT);
- writeShort(5);
- writeByte(0x1); // flags byte
- writeInt(javaToUnixTime(e.mtime));
+ if (e.mtime != null) {
+ writeShort(5); // flag + mtime
+ writeByte(flagEXTT);
+ writeInt(fileTimeToUnixTime(e.mtime));
+ } else {
+ writeShort(1); // flag only
+ writeByte(flagEXTT);
}
- if (e.extra != null) {
- writeBytes(e.extra, 0, e.extra.length);
}
+ writeExtra(e.extra);
if (commentBytes != null) {
writeBytes(commentBytes, 0, Math.min(commentBytes.length, 0xffff));
}
}
@@ -625,10 +650,51 @@
writeShort(0);
}
}
/*
+ * Returns the length of extra data without EXTT and ZIP64.
+ */
+ private int getExtraLen(byte[] extra) {
+ if (extra == null)
+ return 0;
+ int skipped = 0;
+ int len = extra.length;
+ int off = 0;
+ while (off + 4 <= len) {
+ int tag = get16(extra, off);
+ int sz = get16(extra, off + 2);
+ if (tag == EXTID_EXTT || tag == EXTID_ZIP64) {
+ skipped += (sz + 4);
+ }
+ off += (sz + 4);
+ }
+ return len - skipped;
+ }
+
+ /*
+ * Writes extra data without EXTT and ZIP64.
+ *
+ * Extra timestamp and ZIP64 data is handled/output separately
+ * in writeLOC and writeCEN.
+ */
+ private void writeExtra(byte[] extra) throws IOException {
+ if (extra != null) {
+ int len = extra.length;
+ int off = 0;
+ while (off + 4 <= len) {
+ int tag = get16(extra, off);
+ int sz = get16(extra, off + 2);
+ if (tag != EXTID_EXTT && tag != EXTID_ZIP64) {
+ writeBytes(extra, off, sz + 4);
+ }
+ off += (sz + 4);
+ }
+ }
+ }
+
+ /*
* Writes a 8-bit byte to the output stream.
*/
private void writeByte(int v) throws IOException {
OutputStream out = this.out;
out.write(v & 0xff);