#62451 - Document last printed in the year 27321
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1833668 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
de9b2e0481
commit
0a999d8cd3
@ -16,15 +16,23 @@
|
|||||||
==================================================================== */
|
==================================================================== */
|
||||||
package org.apache.poi.hpsf;
|
package org.apache.poi.hpsf;
|
||||||
|
|
||||||
|
import static org.apache.poi.util.LittleEndianConsts.LONG_SIZE;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import org.apache.poi.util.Internal;
|
import org.apache.poi.util.Internal;
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
import org.apache.poi.util.LittleEndianByteArrayInputStream;
|
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
|
@Internal
|
||||||
public class Filetime {
|
public class Filetime {
|
||||||
/**
|
/**
|
||||||
@ -32,74 +40,47 @@ public class Filetime {
|
|||||||
* 00:00:00) and the Unix epoch (1970-01-01 00:00:00) in
|
* 00:00:00) and the Unix epoch (1970-01-01 00:00:00) in
|
||||||
* milliseconds.
|
* 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;
|
/** Factor between filetime long and date milliseconds */
|
||||||
private static final long UINT_MASK = 0x00000000FFFFFFFFL;
|
private static final BigInteger NANO_100 = BigInteger.valueOf(10_000L);
|
||||||
private static final long NANO_100 = 1000L * 10L;
|
|
||||||
|
|
||||||
private int _dwHighDateTime;
|
private long fileTime;
|
||||||
private int _dwLowDateTime;
|
|
||||||
|
|
||||||
public Filetime() {}
|
public Filetime() {}
|
||||||
|
|
||||||
public Filetime( int low, int high ) {
|
|
||||||
_dwLowDateTime = low;
|
|
||||||
_dwHighDateTime = high;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Filetime( Date date ) {
|
public Filetime( Date date ) {
|
||||||
long filetime = Filetime.dateToFileTime(date);
|
fileTime = dateToFileTime(date);
|
||||||
_dwHighDateTime = (int) ((filetime >>> 32) & UINT_MASK);
|
|
||||||
_dwLowDateTime = (int) (filetime & UINT_MASK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void read( LittleEndianByteArrayInputStream lei ) {
|
public void read( LittleEndianByteArrayInputStream lei ) {
|
||||||
_dwLowDateTime = lei.readInt();
|
fileTime = lei.readLong();
|
||||||
_dwHighDateTime = lei.readInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getHigh() {
|
|
||||||
return _dwHighDateTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getLow() {
|
|
||||||
return _dwLowDateTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] toByteArray() {
|
public byte[] toByteArray() {
|
||||||
byte[] result = new byte[SIZE];
|
byte[] result = new byte[LONG_SIZE];
|
||||||
LittleEndian.putInt( result, 0 * LittleEndianConsts.INT_SIZE, _dwLowDateTime );
|
LittleEndian.putLong( result, 0, fileTime);
|
||||||
LittleEndian.putInt( result, 1 * LittleEndianConsts.INT_SIZE, _dwHighDateTime );
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int write( OutputStream out ) throws IOException {
|
public int write( OutputStream out ) throws IOException {
|
||||||
LittleEndian.putInt( _dwLowDateTime, out );
|
out.write(toByteArray());
|
||||||
LittleEndian.putInt( _dwHighDateTime, out );
|
return LONG_SIZE;
|
||||||
return SIZE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Date getJavaValue() {
|
public Date getJavaValue() {
|
||||||
long l = (((long)_dwHighDateTime) << 32) | (_dwLowDateTime & UINT_MASK);
|
return filetimeToDate( fileTime );
|
||||||
return filetimeToDate( l );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a Windows FILETIME into a {@link Date}. The Windows
|
* Converts a Windows FILETIME (in UTC) into a {@link Date} (in UTC).
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
* @param filetime The filetime to convert.
|
* @param filetime The filetime to convert.
|
||||||
* @return The Windows FILETIME as a {@link Date}.
|
* @return The Windows FILETIME as a {@link Date}.
|
||||||
*/
|
*/
|
||||||
public static Date filetimeToDate(final long filetime) {
|
public static Date filetimeToDate(final long filetime) {
|
||||||
final long ms_since_16010101 = filetime / NANO_100;
|
final BigInteger bi = (filetime < 0) ? twoComplement(filetime) : BigInteger.valueOf(filetime);
|
||||||
final long ms_since_19700101 = ms_since_16010101 + EPOCH_DIFF;
|
return new Date(bi.divide(NANO_100).add(EPOCH_DIFF).longValue());
|
||||||
return new Date(ms_since_19700101);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -111,9 +92,7 @@ public class Filetime {
|
|||||||
* @see #filetimeToDate(long)
|
* @see #filetimeToDate(long)
|
||||||
*/
|
*/
|
||||||
public static long dateToFileTime(final Date date) {
|
public static long dateToFileTime(final Date date) {
|
||||||
long ms_since_19700101 = date.getTime();
|
return BigInteger.valueOf(date.getTime()).subtract(EPOCH_DIFF).multiply(NANO_100).longValue();
|
||||||
long ms_since_16010101 = ms_since_19700101 - EPOCH_DIFF;
|
|
||||||
return ms_since_16010101 * NANO_100;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -125,4 +104,21 @@ public class Filetime {
|
|||||||
public static boolean isUndefined(Date date) {
|
public static boolean isUndefined(Date date) {
|
||||||
return (date == null || dateToFileTime(date) == 0);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,4 +170,21 @@ public final class TestHPSFBugs {
|
|||||||
|
|
||||||
fs.close();
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user