From 65a5d4d33c7dcb27ce99ce59535733a28991c544 Mon Sep 17 00:00:00 2001 From: Karsten Heimrich Date: Tue, 23 Jun 2015 12:09:55 +0200 Subject: Follow description on MSDN to implement time utils. Task-number: QTIFW-445 Change-Id: I8c3bc221f57043cc876f1927edf0d591303b5687 Reviewed-by: Kai Koehne --- src/libs/7zip/unix/CPP/Common/MyWindows.h | 12 +- src/libs/7zip/unix/CPP/myWindows/myDateAndTime.cpp | 160 +++++++++++++-------- 2 files changed, 110 insertions(+), 62 deletions(-) (limited to 'src/libs/7zip') diff --git a/src/libs/7zip/unix/CPP/Common/MyWindows.h b/src/libs/7zip/unix/CPP/Common/MyWindows.h index 3376dd6aa..83a896283 100644 --- a/src/libs/7zip/unix/CPP/Common/MyWindows.h +++ b/src/libs/7zip/unix/CPP/Common/MyWindows.h @@ -40,7 +40,17 @@ typedef UINT32 DWORD; typedef Int64 LONGLONG; typedef UInt64 ULONGLONG; -typedef struct LARGE_INTEGER { LONGLONG QuadPart; }LARGE_INTEGER; +typedef union _LARGE_INTEGER { + struct { + DWORD LowPart; + LONG HighPart; + }; + struct { + DWORD LowPart; + LONG HighPart; + } u; + LONGLONG QuadPart; +} LARGE_INTEGER; typedef struct _ULARGE_INTEGER { ULONGLONG QuadPart;} ULARGE_INTEGER; typedef const CHAR *LPCSTR; diff --git a/src/libs/7zip/unix/CPP/myWindows/myDateAndTime.cpp b/src/libs/7zip/unix/CPP/myWindows/myDateAndTime.cpp index 48cb17c9a..000544046 100644 --- a/src/libs/7zip/unix/CPP/myWindows/myDateAndTime.cpp +++ b/src/libs/7zip/unix/CPP/myWindows/myDateAndTime.cpp @@ -38,102 +38,130 @@ #include -void FileTimeToDateTime(const FILETIME *source, QDateTime *target) -{ - ULARGE_INTEGER store; - store.QuadPart = source->dwHighDateTime; - store.QuadPart = store.QuadPart << 32; - store.QuadPart += source->dwLowDateTime; +/* + MSDN description about FILETIME structure: - const QDateTime tempDateTime(QDate(1601, 1, 1), QTime(0, 0, 0, 0), Qt::UTC); - *target = tempDateTime.addMSecs(store.QuadPart / 10000); -} + The FILETIME structure is a 64-bit value representing the number of 100-nanosecond intervals + since January 1, 1601 (UTC). + + The DeltaToEpochInMsec can be calculated like this: -void DateTimeToSystemTime(const QDateTime *source, SYSTEMTIME *target) + \code + quint64 delta = quint64(QDateTime(QDate(1601, 1, 1)).msecsTo(QDateTime(QDate(1970, 1, 1)))) + * 10000ULL; + \endcode + + But since the value is static, we use a precalculated number here. +*/ +static const ULONGLONG DeltaToEpochInMsec = 116444736000000000ULL; + +inline void LocalDateTimeToFileTime(const QDateTime &dt, ULONGLONG utcOffsetInMsec, FILETIME *ft) { - target->wYear = source->date().year(); - target->wMonth = source->date().month(); - target->wDayOfWeek = source->date().dayOfWeek(); - target->wDay = source->date().day(); - target->wHour = source->time().hour(); - target->wMinute = source->time().minute(); - target->wSecond = source->time().second(); - target->wMilliseconds = source->time().msec(); + const ULONGLONG msec = dt.toMSecsSinceEpoch() + utcOffsetInMsec; + const ULONGLONG nano100 = (msec * 10000ULL) + DeltaToEpochInMsec; + + ft->dwLowDateTime = nano100; + ft->dwHighDateTime = nano100 >> 32; + } -void DateTimeToFileTime(const QDateTime &dateTime, FILETIME *target) +inline void UTCDateTimeToSystemTime(const QDateTime &dt, SYSTEMTIME *st) { - const qint64 nsecs = QDateTime(QDate(1601, 1, 1), QTime(0, 0, 0, 0), Qt::UTC) - .msecsTo(dateTime) * 10000; - target->dwLowDateTime = nsecs; - target->dwHighDateTime = nsecs >> 32; + const QDate date = dt.date(); + const QTime time = dt.time(); + + st->wYear = date.year(); + st->wMonth = date.month(); + st->wDayOfWeek = date.dayOfWeek(); + st->wDay = date.day(); + st->wHour = time.hour(); + st->wMinute = time.minute(); + st->wSecond = time.second(); + st->wMilliseconds = time.msec(); } + +// -- WINAPI + BOOL WINAPI FileTimeToSystemTime(CONST FILETIME *source,SYSTEMTIME *target) { - QDateTime tempDateTime; - FileTimeToDateTime(source, &tempDateTime); - DateTimeToSystemTime(&tempDateTime, target); - + const QDateTime dt = QDateTime(QDate(1601, 1, 1), QTime(0, 0, 0, 1), Qt::UTC).addMSecs + ((ULONGLONG(source->dwLowDateTime) + (ULONGLONG(source->dwHighDateTime) << 32)) / 10000ULL); + UTCDateTimeToSystemTime(dt.toUTC(), target); return TRUE; } BOOL WINAPI FileTimeToLocalFileTime(CONST FILETIME *source,FILETIME *target) { - target->dwHighDateTime = source->dwHighDateTime; - target->dwLowDateTime = source->dwLowDateTime; - - QDateTime tempDateTime; - FileTimeToDateTime(source, &tempDateTime); - - tempDateTime = tempDateTime.toLocalTime(); + const QDateTime dt = QDateTime(QDate(1601, 1, 1), QTime(0, 0, 0, 1), Qt::UTC).addMSecs + ((ULONGLONG(source->dwLowDateTime) + (ULONGLONG(source->dwHighDateTime) << 32)) / 10000ULL); + LocalDateTimeToFileTime(dt.toLocalTime(), ULONGLONG(QDateTime::currentDateTime() + .offsetFromUtc()) * 1000ULL, target); return TRUE; } BOOLEAN WINAPI RtlTimeToSecondsSince1970(const LARGE_INTEGER *Time, DWORD *Seconds) { - SYSTEMTIME tempSystemTime; - FILETIME fileTime; - - fileTime.dwLowDateTime = Time->QuadPart; - fileTime.dwHighDateTime = Time->QuadPart >> 32; - - FileTimeToSystemTime(&fileTime, &tempSystemTime); - - QDate targetDate(tempSystemTime.wYear, tempSystemTime.wMonth, tempSystemTime.wDay); - QTime targetTime(tempSystemTime.wHour, tempSystemTime.wMinute, tempSystemTime.wSecond, tempSystemTime.wMilliseconds); - QDateTime targetDateTime(targetDate, targetTime, Qt::UTC); - - quint64 secsSince1970 = targetDateTime.toMSecsSinceEpoch() / 1000; - - *Seconds = secsSince1970; + /* + MSDN suggests to implement the function like this: + + 1. Call SystemTimeToFileTime to copy the system time to a FILETIME structure. Call + GetSystemTime to get the current system time to pass to SystemTimeToFileTime. + 2. Copy the contents of the FILETIME structure to a ULARGE_INTEGER structure. + 3. Initialize a SYSTEMTIME structure with the date and time of the first second of + January 1, 1970. + 4. Call SystemTimeToFileTime, passing the SYSTEMTIME structure initialized in Step 3 + to the call. + 5. Copy the contents of the FILETIME structure returned by SystemTimeToFileTime in Step 4 + to a second ULARGE_INTEGER. The copied value should be less than or equal to the value + copied in Step 2. + 6. Subtract the 64-bit value in the ULARGE_INTEGER structure initialized in Step 5 + (January 1, 1970) from the 64-bit value of the ULARGE_INTEGER structure initialized + in Step 2 (the current system time). This produces a value in 100-nanosecond intervals + since January 1, 1970. To convert this value to seconds, divide by 10,000,000. + + We can omit step 1 and 2, cause we get the LARGE_INTEGER passed as function argument. + */ + SYSTEMTIME stFirstSecondOf1979; + stFirstSecondOf1979.wSecond = 1; + stFirstSecondOf1979.wMinute = 0; + stFirstSecondOf1979.wHour = 0; + stFirstSecondOf1979.wDay = 1; + stFirstSecondOf1979.wMonth = 1; + stFirstSecondOf1979.wYear = 1970; + stFirstSecondOf1979.wDayOfWeek = 4; + + FILETIME ftFirstSecondOf1979; + SystemTimeToFileTime(&stFirstSecondOf1979, &ftFirstSecondOf1979); + + LARGE_INTEGER liFirstSecondOf1979; + liFirstSecondOf1979.LowPart = ftFirstSecondOf1979.dwLowDateTime; + liFirstSecondOf1979.HighPart = ftFirstSecondOf1979.dwHighDateTime; + + const ULONGLONG diffNano100 = Time->QuadPart - liFirstSecondOf1979.QuadPart; + *Seconds = diffNano100 / 10000000ULL; return TRUE; } void WINAPI RtlSecondsSince1970ToFileTime(DWORD Seconds, FILETIME *ft) { - QDateTime fileTimeStartDate(QDate(1601, 1, 1)); - quint64 hnseconds = Seconds; - QDateTime sourceDateTime = QDateTime::fromMSecsSinceEpoch(hnseconds * 1000); - - hnseconds = fileTimeStartDate.msecsTo(sourceDateTime); - hnseconds *= 10000; - - ft->dwLowDateTime = hnseconds; - ft->dwHighDateTime = hnseconds >> 32; + const ULONGLONG nano100 = (ULONGLONG(Seconds) * 10000000ULL) + DeltaToEpochInMsec; + ft->dwLowDateTime = nano100; + ft->dwHighDateTime = nano100 >> 32; } VOID WINAPI GetSystemTime(SYSTEMTIME *st) { - QDateTime nowDateTime = QDateTime::currentDateTimeUtc(); - DateTimeToSystemTime(&nowDateTime, st); + UTCDateTimeToSystemTime(QDateTime::currentDateTimeUtc(), st); } VOID WINAPI GetSystemTimeAsFileTime(FILETIME *time) { - DateTimeToFileTime(QDateTime::currentDateTimeUtc(), time); + SYSTEMTIME st; + GetSystemTime(&st); + SystemTimeToFileTime(&st, time); } DWORD WINAPI GetTickCount() @@ -141,3 +169,13 @@ DWORD WINAPI GetTickCount() using namespace std::chrono; return duration_cast(steady_clock::now().time_since_epoch()).count(); } + +BOOL WINAPI SystemTimeToFileTime(const SYSTEMTIME *lpSystemTime, FILETIME *lpFileTime) +{ + const QDateTime dt(QDate(lpSystemTime->wYear, lpSystemTime->wMonth, lpSystemTime->wDay), + QTime(lpSystemTime->wHour, lpSystemTime->wMinute, lpSystemTime->wSecond, + lpSystemTime->wMilliseconds), Qt::UTC); + + LocalDateTimeToFileTime(dt.toLocalTime(), 0ULL, lpFileTime); + return TRUE; +} -- cgit v1.2.3