| /* ==================================================================== |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| ==================================================================== */ |
| 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; |
| |
| /** |
| * 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 { |
| /** |
| * The difference between the Windows epoch (1601-01-01 |
| * 00:00:00) and the Unix epoch (1970-01-01 00:00:00) in |
| * milliseconds. |
| */ |
| private static final BigInteger EPOCH_DIFF = BigInteger.valueOf(-11_644_473_600_000L); |
| |
| /** Factor between filetime long and date milliseconds */ |
| private static final BigInteger NANO_100 = BigInteger.valueOf(10_000L); |
| |
| private long fileTime; |
| |
| public Filetime() {} |
| |
| public Filetime( Date date ) { |
| fileTime = dateToFileTime(date); |
| } |
| |
| public void read( LittleEndianByteArrayInputStream lei ) { |
| fileTime = lei.readLong(); |
| } |
| |
| public byte[] toByteArray() { |
| byte[] result = new byte[LONG_SIZE]; |
| LittleEndian.putLong( result, 0, fileTime); |
| return result; |
| } |
| |
| public int write( OutputStream out ) throws IOException { |
| out.write(toByteArray()); |
| return LONG_SIZE; |
| } |
| |
| public Date getJavaValue() { |
| return filetimeToDate( fileTime ); |
| } |
| |
| /** |
| * 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 BigInteger bi = (filetime < 0) ? twoComplement(filetime) : BigInteger.valueOf(filetime); |
| return new Date(bi.divide(NANO_100).add(EPOCH_DIFF).longValue()); |
| } |
| |
| /** |
| * Converts a {@link Date} into a filetime. |
| * |
| * @param date The date to be converted |
| * @return The filetime |
| * |
| * @see #filetimeToDate(long) |
| */ |
| public static long dateToFileTime(final Date date) { |
| return BigInteger.valueOf(date.getTime()).subtract(EPOCH_DIFF).multiply(NANO_100).longValue(); |
| } |
| |
| /** |
| * Return {@code true} if the date is undefined |
| * |
| * @param date the date |
| * @return {@code true} if the date is undefined |
| */ |
| 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); |
| } |
| } |