|
|
@@ -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); |
|
|
|
} |
|
|
|
} |