]> source.dussan.org Git - poi.git/commitdiff
#62451 - Document last printed in the year 27321
authorAndreas Beeker <kiwiwings@apache.org>
Sun, 17 Jun 2018 16:59:48 +0000 (16:59 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Sun, 17 Jun 2018 16:59:48 +0000 (16:59 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1833668 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hpsf/Filetime.java
src/testcases/org/apache/poi/hpsf/basic/TestHPSFBugs.java

index 42d864d23820c276ad0c997ebd82f3ae8948f29d..98b2c27c6ce0e0e398aa3e7f076f9f43bd32bcb5 100644 (file)
 ==================================================================== */
 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);
+    }
 }
index 0600ffea9bd311044ec3432e9ad722850194289c..2fff500a0967a7669147f02b5b53556e72652585 100644 (file)
@@ -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());
+            }
+        }
+    }
 }