==================================================================== */
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 {
/**
* 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());
}
/**
* @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();
}
/**
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);
+ }
}