Repository: commons-compress Updated Branches: refs/heads/master 992911d0f -> 9052f4df8
COMPRESS-416 Use signed integers for extended timestamps, per spec Signed-off-by: Simon Spero <sesunc...@gmail.com> Project: http://git-wip-us.apache.org/repos/asf/commons-compress/repo Commit: http://git-wip-us.apache.org/repos/asf/commons-compress/commit/cd1d329d Tree: http://git-wip-us.apache.org/repos/asf/commons-compress/tree/cd1d329d Diff: http://git-wip-us.apache.org/repos/asf/commons-compress/diff/cd1d329d Branch: refs/heads/master Commit: cd1d329dba95dae161317c123269c24282001a66 Parents: d0595b7 Author: Simon Spero <sesunc...@gmail.com> Authored: Mon Jul 3 19:10:10 2017 -0400 Committer: Stefan Bodewig <bode...@apache.org> Committed: Tue Jul 4 08:51:32 2017 +0200 ---------------------------------------------------------------------- .../archivers/zip/X5455_ExtendedTimestamp.java | 24 ++++-- .../zip/X5455_ExtendedTimestampTest.java | 86 +++++++------------- 2 files changed, 43 insertions(+), 67 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/commons-compress/blob/cd1d329d/src/main/java/org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestamp.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestamp.java b/src/main/java/org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestamp.java index 90bd750..f050874 100644 --- a/src/main/java/org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestamp.java +++ b/src/main/java/org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestamp.java @@ -25,14 +25,14 @@ import java.util.zip.ZipException; /** * <p>An extra field that stores additional file and directory timestamp data * for zip entries. Each zip entry can include up to three timestamps - * (modify, access, create*). The timestamps are stored as 32 bit unsigned + * (modify, access, create*). The timestamps are stored as 32 bit signed * integers representing seconds since UNIX epoch (Jan 1st, 1970, UTC). * This field improves on zip's default timestamp granularity, since it * allows one to store additional timestamps, and, in addition, the timestamps * are stored using per-second granularity (zip's default behaviour can only store * timestamps to the nearest <em>even</em> second). * </p><p> - * Unfortunately, 32 (unsigned) bits can only store dates up to the year 2106, + * Unfortunately, 32 (signed) bits can only store dates up to the year 2037, * and so this extra field will eventually be obsolete. Enjoy it while it lasts! * </p> * <ul> @@ -370,7 +370,7 @@ public class X5455_ExtendedTimestamp implements ZipExtraField, Cloneable, Serial * @return modify time as java.util.Date or null. */ public Date getModifyJavaTime() { - return modifyTime != null ? new Date(modifyTime.getValue() * 1000) : null; + return zipLongToDate(modifyTime); } /** @@ -382,7 +382,11 @@ public class X5455_ExtendedTimestamp implements ZipExtraField, Cloneable, Serial * @return access time as java.util.Date or null. */ public Date getAccessJavaTime() { - return accessTime != null ? new Date(accessTime.getValue() * 1000) : null; + return zipLongToDate(accessTime); + } + + private static Date zipLongToDate(ZipLong unixTime) { + return unixTime != null ? new Date(unixTime.getIntValue() * 1000L) : null; } /** @@ -400,7 +404,7 @@ public class X5455_ExtendedTimestamp implements ZipExtraField, Cloneable, Serial * @return create time as java.util.Date or null. */ public Date getCreateJavaTime() { - return createTime != null ? new Date(createTime.getValue() * 1000) : null; + return zipLongToDate(createTime); } /** @@ -518,10 +522,12 @@ public class X5455_ExtendedTimestamp implements ZipExtraField, Cloneable, Serial private static ZipLong dateToZipLong(final Date d) { if (d == null) { return null; } - final long TWO_TO_32 = 0x100000000L; - final long l = d.getTime() / 1000; - if (l >= TWO_TO_32) { - throw new IllegalArgumentException("Cannot set an X5455 timestamp larger than 2^32: " + l); + return unixTimeToZipLong(d.getTime() / 1000); + } + + private static ZipLong unixTimeToZipLong(long l) { + if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) { + throw new IllegalArgumentException("X5455 timestamps must fit in a signed 32 bit integer: " + l); } return new ZipLong(l); } http://git-wip-us.apache.org/repos/asf/commons-compress/blob/cd1d329d/src/test/java/org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestampTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestampTest.java b/src/test/java/org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestampTest.java index 06c77d3..a0d9666 100644 --- a/src/test/java/org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestampTest.java +++ b/src/test/java/org/apache/commons/compress/archivers/zip/X5455_ExtendedTimestampTest.java @@ -50,7 +50,7 @@ public class X5455_ExtendedTimestampTest { private final static ZipShort X5455 = new ZipShort(0x5455); private final static ZipLong ZERO_TIME = new ZipLong(0); - private final static ZipLong MAX_TIME_SECONDS = new ZipLong(0xFFFFFFFFL); + private final static ZipLong MAX_TIME_SECONDS = new ZipLong(Integer.MAX_VALUE); private final static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd/HH:mm:ss Z"); static { @@ -142,51 +142,19 @@ public class X5455_ExtendedTimestampTest { } if (year >= 0) { switch (year) { - case 2107: - if (!zipTimeUsesExtendedTimestamp) { - // Zip time is okay up to 2107. - assertEquals(year + "-01-01/00:00:02 +0000", zipTime); - } - // But the X5455 data has overflowed: - assertEquals("1970-11-24/17:31:45 +0000", modTime); - assertEquals("1970-11-24/17:31:47 +0000", accTime); - break; - case 2108: - if (!zipTimeUsesExtendedTimestamp) { - // Zip time is still okay at Jan 1st midnight (UTC) in 2108 - // because we created the zip file in pacific time zone, so it's - // actually still 2107 in the zip file! - assertEquals(year + "-01-01/00:00:02 +0000", zipTime); - } - // The X5455 data is still overflowed, of course: - assertEquals("1971-11-24/17:31:45 +0000", modTime); - assertEquals("1971-11-24/17:31:47 +0000", accTime); - break; - case 2109: - // All three timestamps have overflowed by 2109. - if (!zipTimeUsesExtendedTimestamp) { - assertEquals("1981-01-01/00:00:02 +0000", zipTime); - } - assertEquals("1972-11-24/17:31:45 +0000", modTime); - assertEquals("1972-11-24/17:31:47 +0000", accTime); - - // Hmmm.... looks like one could examine both DOS time - // and the Unix time together to hack a nice workaround to - // get timestamps past 2106 in a reverse-compatible way. - - break; default: if (!zipTimeUsesExtendedTimestamp) { - // X5455 time is good from epoch (1970) to 2106. + // X5455 time is good from epoch (1970) to 2037. // Zip time is good from 1980 to 2107. if (year < 1980) { assertEquals("1980-01-01/08:00:00 +0000", zipTime); } else { assertEquals(year + "-01-01/00:00:02 +0000", zipTime); } - } + }if(year <2038) { assertEquals(year + "-01-01/00:00:01 +0000", modTime); assertEquals(year + "-01-01/00:00:03 +0000", accTime); + } break; } } @@ -235,9 +203,10 @@ public class X5455_ExtendedTimestampTest { cal.set(Calendar.DATE, 1); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); - final Date timeMillis = cal.getTime(); - final ZipLong time = new ZipLong(timeMillis.getTime() / 1000); + final long timeMillis = cal.getTimeInMillis(); + final ZipLong time = new ZipLong(timeMillis / 1000); // set too big try { @@ -251,14 +220,15 @@ public class X5455_ExtendedTimestampTest { // get/set modify time xf.setModifyTime(time); assertEquals(time, xf.getModifyTime()); - assertEquals(timeMillis, xf.getModifyJavaTime()); - xf.setModifyJavaTime(timeMillis); + Date xfModifyJavaTime = xf.getModifyJavaTime(); + assertEquals(timeMillis, xfModifyJavaTime.getTime()); + xf.setModifyJavaTime(new Date(timeMillis)); assertEquals(time, xf.getModifyTime()); - assertEquals(timeMillis, xf.getModifyJavaTime()); + assertEquals(timeMillis, xf.getModifyJavaTime().getTime()); // Make sure milliseconds get zeroed out: - xf.setModifyJavaTime(new Date(timeMillis.getTime() + 123)); + xf.setModifyJavaTime(new Date(timeMillis + 123)); assertEquals(time, xf.getModifyTime()); - assertEquals(timeMillis, xf.getModifyJavaTime()); + assertEquals(timeMillis, xf.getModifyJavaTime().getTime()); // Null xf.setModifyTime(null); assertNull(xf.getModifyJavaTime()); @@ -268,14 +238,14 @@ public class X5455_ExtendedTimestampTest { // get/set access time xf.setAccessTime(time); assertEquals(time, xf.getAccessTime()); - assertEquals(timeMillis, xf.getAccessJavaTime()); - xf.setAccessJavaTime(timeMillis); + assertEquals(timeMillis, xf.getAccessJavaTime().getTime()); + xf.setAccessJavaTime(new Date(timeMillis)); assertEquals(time, xf.getAccessTime()); - assertEquals(timeMillis, xf.getAccessJavaTime()); + assertEquals(timeMillis, xf.getAccessJavaTime().getTime()); // Make sure milliseconds get zeroed out: - xf.setAccessJavaTime(new Date(timeMillis.getTime() + 123)); + xf.setAccessJavaTime(new Date(timeMillis + 123)); assertEquals(time, xf.getAccessTime()); - assertEquals(timeMillis, xf.getAccessJavaTime()); + assertEquals(timeMillis, xf.getAccessJavaTime().getTime()); // Null xf.setAccessTime(null); assertNull(xf.getAccessJavaTime()); @@ -285,14 +255,14 @@ public class X5455_ExtendedTimestampTest { // get/set create time xf.setCreateTime(time); assertEquals(time, xf.getCreateTime()); - assertEquals(timeMillis, xf.getCreateJavaTime()); - xf.setCreateJavaTime(timeMillis); + assertEquals(timeMillis, xf.getCreateJavaTime().getTime()); + xf.setCreateJavaTime(new Date(timeMillis)); assertEquals(time, xf.getCreateTime()); - assertEquals(timeMillis, xf.getCreateJavaTime()); + assertEquals(timeMillis, xf.getCreateJavaTime().getTime()); // Make sure milliseconds get zeroed out: - xf.setCreateJavaTime(new Date(timeMillis.getTime() + 123)); + xf.setCreateJavaTime(new Date(timeMillis + 123)); assertEquals(time, xf.getCreateTime()); - assertEquals(timeMillis, xf.getCreateJavaTime()); + assertEquals(timeMillis, xf.getCreateJavaTime().getTime()); // Null xf.setCreateTime(null); assertNull(xf.getCreateJavaTime()); @@ -388,15 +358,15 @@ public class X5455_ExtendedTimestampTest { final byte[] CR_CENTRAL = {4}; // central data only dontains the CR flag and no actual data final byte[] MOD_ZERO = {1, 0, 0, 0, 0}; - final byte[] MOD_MAX = {1, -1, -1, -1, -1}; + final byte[] MOD_MAX = {1, -1, -1, -1, 0x7f}; final byte[] AC_ZERO = {2, 0, 0, 0, 0}; - final byte[] AC_MAX = {2, -1, -1, -1, -1}; + final byte[] AC_MAX = {2, -1, -1, -1, 0x7f}; final byte[] CR_ZERO = {4, 0, 0, 0, 0}; - final byte[] CR_MAX = {4, -1, -1, -1, -1}; + final byte[] CR_MAX = {4, -1, -1, -1, 0x7f}; final byte[] MOD_AC_ZERO = {3, 0, 0, 0, 0, 0, 0, 0, 0}; - final byte[] MOD_AC_MAX = {3, -1, -1, -1, -1, -1, -1, -1, -1}; + final byte[] MOD_AC_MAX = {3, -1, -1, -1, 0x7f, -1, -1, -1, 0x7f}; final byte[] MOD_AC_CR_ZERO = {7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - final byte[] MOD_AC_CR_MAX = {7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + final byte[] MOD_AC_CR_MAX = {7, -1, -1, -1, 0x7f, -1, -1, -1, 0x7f, -1, -1, -1, 0x7f}; parseReparse(null, NULL_FLAGS, NULL_FLAGS); parseReparse(ZERO_TIME, MOD_ZERO, MOD_ZERO);