aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/java/org/apache/poi/hpsf/Filetime.java86
-rw-r--r--src/testcases/org/apache/poi/hpsf/basic/TestHPSFBugs.java17
2 files changed, 58 insertions, 45 deletions
diff --git a/src/java/org/apache/poi/hpsf/Filetime.java b/src/java/org/apache/poi/hpsf/Filetime.java
index 42d864d238..98b2c27c6c 100644
--- a/src/java/org/apache/poi/hpsf/Filetime.java
+++ b/src/java/org/apache/poi/hpsf/Filetime.java
@@ -16,15 +16,23 @@
==================================================================== */
package org.apache.poi.hpsf;
+import static org.apache.poi.util.LittleEndianConsts.LONG_SIZE;
+
import java.io.IOException;
import java.io.OutputStream;
+import java.math.BigInteger;
import java.util.Date;
import org.apache.poi.util.Internal;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianByteArrayInputStream;
-import org.apache.poi.util.LittleEndianConsts;
+/**
+ * The Windows FILETIME structure holds a date and time associated with a
+ * file. The structure identifies a 64-bit integer specifying the
+ * number of 100-nanosecond intervals which have passed since
+ * January 1, 1601, Coordinated Universal Time (UTC).
+ */
@Internal
public class Filetime {
/**
@@ -32,74 +40,47 @@ public class Filetime {
* 00:00:00) and the Unix epoch (1970-01-01 00:00:00) in
* milliseconds.
*/
- private static final long EPOCH_DIFF = -11644473600000L;
+ private static final BigInteger EPOCH_DIFF = BigInteger.valueOf(-11_644_473_600_000L);
- private static final int SIZE = LittleEndian.INT_SIZE * 2;
- private static final long UINT_MASK = 0x00000000FFFFFFFFL;
- private static final long NANO_100 = 1000L * 10L;
+ /** Factor between filetime long and date milliseconds */
+ private static final BigInteger NANO_100 = BigInteger.valueOf(10_000L);
- private int _dwHighDateTime;
- private int _dwLowDateTime;
+ private long fileTime;
public Filetime() {}
- public Filetime( int low, int high ) {
- _dwLowDateTime = low;
- _dwHighDateTime = high;
- }
-
public Filetime( Date date ) {
- long filetime = Filetime.dateToFileTime(date);
- _dwHighDateTime = (int) ((filetime >>> 32) & UINT_MASK);
- _dwLowDateTime = (int) (filetime & UINT_MASK);
+ fileTime = dateToFileTime(date);
}
-
public void read( LittleEndianByteArrayInputStream lei ) {
- _dwLowDateTime = lei.readInt();
- _dwHighDateTime = lei.readInt();
- }
-
- public long getHigh() {
- return _dwHighDateTime;
- }
-
- public long getLow() {
- return _dwLowDateTime;
+ fileTime = lei.readLong();
}
public byte[] toByteArray() {
- byte[] result = new byte[SIZE];
- LittleEndian.putInt( result, 0 * LittleEndianConsts.INT_SIZE, _dwLowDateTime );
- LittleEndian.putInt( result, 1 * LittleEndianConsts.INT_SIZE, _dwHighDateTime );
+ byte[] result = new byte[LONG_SIZE];
+ LittleEndian.putLong( result, 0, fileTime);
return result;
}
public int write( OutputStream out ) throws IOException {
- LittleEndian.putInt( _dwLowDateTime, out );
- LittleEndian.putInt( _dwHighDateTime, out );
- return SIZE;
+ out.write(toByteArray());
+ return LONG_SIZE;
}
public Date getJavaValue() {
- long l = (((long)_dwHighDateTime) << 32) | (_dwLowDateTime & UINT_MASK);
- return filetimeToDate( l );
+ return filetimeToDate( fileTime );
}
/**
- * Converts a Windows FILETIME into a {@link Date}. The Windows
- * FILETIME structure holds a date and time associated with a
- * file. The structure identifies a 64-bit integer specifying the
- * number of 100-nanosecond intervals which have passed since
- * January 1, 1601.
+ * Converts a Windows FILETIME (in UTC) into a {@link Date} (in UTC).
*
* @param filetime The filetime to convert.
* @return The Windows FILETIME as a {@link Date}.
*/
public static Date filetimeToDate(final long filetime) {
- final long ms_since_16010101 = filetime / NANO_100;
- final long ms_since_19700101 = ms_since_16010101 + EPOCH_DIFF;
- return new Date(ms_since_19700101);
+ final BigInteger bi = (filetime < 0) ? twoComplement(filetime) : BigInteger.valueOf(filetime);
+ return new Date(bi.divide(NANO_100).add(EPOCH_DIFF).longValue());
}
/**
@@ -111,9 +92,7 @@ public class Filetime {
* @see #filetimeToDate(long)
*/
public static long dateToFileTime(final Date date) {
- long ms_since_19700101 = date.getTime();
- long ms_since_16010101 = ms_since_19700101 - EPOCH_DIFF;
- return ms_since_16010101 * NANO_100;
+ return BigInteger.valueOf(date.getTime()).subtract(EPOCH_DIFF).multiply(NANO_100).longValue();
}
/**
@@ -125,4 +104,21 @@ public class Filetime {
public static boolean isUndefined(Date date) {
return (date == null || dateToFileTime(date) == 0);
}
+
+ private static BigInteger twoComplement(final long val) {
+ // for negative BigInteger, top byte is negative
+ final byte[] contents = {
+ (byte)(val < 0 ? 0 : -1),
+ (byte)((val >> 56) & 0xFF),
+ (byte)((val >> 48) & 0xFF),
+ (byte)((val >> 40) & 0xFF),
+ (byte)((val >> 32) & 0xFF),
+ (byte)((val >> 24) & 0xFF),
+ (byte)((val >> 16) & 0xFF),
+ (byte)((val >> 8) & 0xFF),
+ (byte)(val & 0xFF),
+ };
+
+ return new BigInteger(contents);
+ }
}
diff --git a/src/testcases/org/apache/poi/hpsf/basic/TestHPSFBugs.java b/src/testcases/org/apache/poi/hpsf/basic/TestHPSFBugs.java
index 0600ffea9b..2fff500a09 100644
--- a/src/testcases/org/apache/poi/hpsf/basic/TestHPSFBugs.java
+++ b/src/testcases/org/apache/poi/hpsf/basic/TestHPSFBugs.java
@@ -170,4 +170,21 @@ public final class TestHPSFBugs {
fs.close();
}
+
+ @Test
+ public void bug62451() throws IOException {
+ final long millis = 920355314183864L;
+ try (HSSFWorkbook wb = new HSSFWorkbook()) {
+ wb.createSheet().createRow(0).createCell(0).setCellValue("foo");
+ wb.createInformationProperties();
+ SummaryInformation si = wb.getSummaryInformation();
+ si.setLastPrinted(new Date(millis));
+ try (HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb)) {
+ SummaryInformation si2 = wb2.getSummaryInformation();
+ Date d = si.getLastPrinted();
+ assertNotNull(d);
+ assertEquals(millis, d.getTime());
+ }
+ }
+ }
}