Merge pull request #2444 from RadWolfie/update-time-api

Fix RtlTimeFieldsToTime and RtlTimeToTimeFields implements
This commit is contained in:
ergo720 2024-01-15 15:38:03 +01:00 committed by GitHub
commit 3edc388abf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 57 additions and 58 deletions

View File

@ -42,7 +42,6 @@ namespace NtDll
#include "core\kernel\init\CxbxKrnl.h" // For CxbxrAbort()
#include "core\kernel\support\Emu.h" // For EmuLog(LOG_LEVEL::WARNING, )
#include "EmuKrnlKi.h"
#include <assert.h>
#ifdef _WIN32
@ -1545,6 +1544,7 @@ no_mapping:
#define TICKSPERSEC 10000000
#define TICKSPERMSEC 10000
#define MSECSPERSEC 1000
#define SECSPERDAY 86400
#define SECSPERHOUR 3600
#define SECSPERMIN 60
@ -1563,6 +1563,11 @@ no_mapping:
#define SECS_1601_TO_1980 ((379 * 365 + 91) * (ULONGLONG)SECSPERDAY)
#define TICKS_1601_TO_1980 (SECS_1601_TO_1980 * TICKSPERSEC)
const xbox::LARGE_INTEGER Magic10000 = { .QuadPart = 0xd1b71758e219652ci64 };
#define SHIFT10000 13
xbox::LARGE_INTEGER Magic86400000 = { .QuadPart = 0xc6d750ebfa67b90ei64 };
#define SHIFT86400000 26
static const int MonthLengths[2][MONSPERYEAR] =
{
@ -1616,26 +1621,31 @@ XBSYSAPI EXPORTNUM(304) xbox::boolean_xt NTAPI xbox::RtlTimeFieldsToTime
OUT PLARGE_INTEGER Time
)
{
LOG_FUNC_BEGIN
LOG_FUNC_ARG(TimeFields)
LOG_FUNC_ARG_OUT(Time)
LOG_FUNC_END;
int month, year, cleaps, day;
/* FIXME: normalize the TIME_FIELDS structure here */
/* No, native just returns 0 (error) if the fields are not */
if (TimeFields->Millisecond < 0 || TimeFields->Millisecond > 999 ||
TimeFields->Second < 0 || TimeFields->Second > 59 ||
TimeFields->Minute < 0 || TimeFields->Minute > 59 ||
TimeFields->Hour < 0 || TimeFields->Hour > 23 ||
TimeFields->Month < 1 || TimeFields->Month > 12 ||
TimeFields->Day < 1 ||
TimeFields->Day > MonthLengths
[TimeFields->Month == 2 || IsLeapYear(TimeFields->Year)]
[TimeFields->Month - 1] ||
TimeFields->Year < 1601)
/* Verify each TimeFields' variables are within range */
if (TimeFields->Millisecond < 0 || TimeFields->Millisecond > 999) {
return FALSE;
}
if (TimeFields->Second < 0 || TimeFields->Second > 59) {
return FALSE;
}
if (TimeFields->Minute < 0 || TimeFields->Minute > 59) {
return FALSE;
}
if (TimeFields->Hour < 0 || TimeFields->Hour > 23) {
return FALSE;
}
if (TimeFields->Month < 1 || TimeFields->Month > 12) {
return FALSE;
}
if (TimeFields->Day < 1 ||
TimeFields->Day > MonthLengths[IsLeapYear(TimeFields->Year)][TimeFields->Month - 1]) {
return FALSE;
}
if (TimeFields->Year < 1601) {
return FALSE;
}
/* now calculate a day count from the date
* First start counting years from March. This way the leap days
@ -1651,23 +1661,21 @@ XBSYSAPI EXPORTNUM(304) xbox::boolean_xt NTAPI xbox::RtlTimeFieldsToTime
month = TimeFields->Month + 1;
year = TimeFields->Year;
}
cleaps = (3 * (year / 100) + 3) / 4; /* nr of "century leap years"*/
day = (36525 * year) / 100 - cleaps + /* year * dayperyr, corrected */
(1959 * month) / 64 + /* months * daypermonth */
TimeFields->Day - /* day of the month */
584817; /* zero that on 1601-01-01 */
cleaps = (3 * (year / 100) + 3) / 4; /* nr of "century leap years"*/
day = (36525 * year) / 100 - cleaps + /* year * DayPerYear, corrected */
(1959 * month) / 64 + /* months * DayPerMonth */
TimeFields->Day - /* day of the month */
584817; /* zero that on 1601-01-01 */
/* done */
Time->QuadPart = (((((LONGLONG)day * HOURSPERDAY +
TimeFields->Hour) * MINSPERHOUR +
TimeFields->Minute) * SECSPERMIN +
TimeFields->Second) * 1000 +
TimeFields->Millisecond);
/* Convert into Time format */
Time->QuadPart = day * HOURSPERDAY;
Time->QuadPart = (Time->QuadPart + TimeFields->Hour) * MINSPERHOUR;
Time->QuadPart = (Time->QuadPart + TimeFields->Minute) * SECSPERMIN;
Time->QuadPart = (Time->QuadPart + TimeFields->Second) * MSECSPERSEC;
Time->QuadPart = (Time->QuadPart + TimeFields->Millisecond) * TICKSPERMSEC;
// This function must return a time expressed in 100ns units (the Windows time interval), so it needs a final multiplication here
*Time = RtlExtendedIntegerMultiply(*Time, CLOCK_TIME_INCREMENT);
RETURN(TRUE);
return TRUE;
}
// ******************************************************************
@ -1679,36 +1687,27 @@ XBSYSAPI EXPORTNUM(305) xbox::void_xt NTAPI xbox::RtlTimeToTimeFields
OUT PTIME_FIELDS TimeFields
)
{
LOG_FUNC_BEGIN
LOG_FUNC_ARG(Time)
LOG_FUNC_ARG_OUT(TimeFields)
LOG_FUNC_END;
LONGLONG Days, cleaps, years, yearday, months;
int SecondsInDay;
long int cleaps, years, yearday, months;
long int Days;
LONGLONG _Time;
/* Extract millisecond from time and convert time into seconds */
TimeFields->Millisecond =
(cshort_xt)((Time->QuadPart % TICKSPERSEC) / TICKSPERMSEC);
_Time = Time->QuadPart / TICKSPERSEC;
/* The native version of RtlTimeToTimeFields does not take leap seconds
* into account */
/* Split the time into days and seconds within the day */
Days = (long int )(_Time / SECSPERDAY);
SecondsInDay = _Time % SECSPERDAY;
/* Extract milliseconds from time and days from milliseconds */
// NOTE: Reverse engineered native kernel uses RtlExtendedMagicDivide calls.
// Using similar code of ReactOS does not emulate native kernel's implement for
// one increment over large integer's max value.
xbox::LARGE_INTEGER MillisecondsTotal = RtlExtendedMagicDivide(*Time, Magic10000, SHIFT10000);
Days = RtlExtendedMagicDivide(MillisecondsTotal, Magic86400000, SHIFT86400000).u.LowPart;
MillisecondsTotal.QuadPart -= Days * SECSPERDAY * MSECSPERSEC;
/* compute time of day */
TimeFields->Hour = (cshort_xt)(SecondsInDay / SECSPERHOUR);
SecondsInDay = SecondsInDay % SECSPERHOUR;
TimeFields->Minute = (cshort_xt)(SecondsInDay / SECSPERMIN);
TimeFields->Second = (cshort_xt)(SecondsInDay % SECSPERMIN);
TimeFields->Millisecond = MillisecondsTotal.u.LowPart % MSECSPERSEC;
dword_xt RemainderTime = MillisecondsTotal.u.LowPart / MSECSPERSEC;
TimeFields->Second = RemainderTime % SECSPERMIN;
RemainderTime /= SECSPERMIN;
TimeFields->Minute = RemainderTime % MINSPERHOUR;
RemainderTime /= MINSPERHOUR;
TimeFields->Hour = RemainderTime; // NOTE: Remaining hours did not received 24 hours modulo treatment.
/* compute day of week */
TimeFields->Weekday = (cshort_xt)((EPOCHWEEKDAY + Days) % DAYSPERWEEK);
TimeFields->Weekday = (EPOCHWEEKDAY + Days) % DAYSPERWEEK;
/* compute year, month and day of month. */
cleaps = (3 * ((4 * Days + 1227) / DAYSPERQUADRICENTENNIUM) + 3) / 4;
@ -1717,7 +1716,7 @@ XBSYSAPI EXPORTNUM(305) xbox::void_xt NTAPI xbox::RtlTimeToTimeFields
yearday = Days - (years * DAYSPERNORMALQUADRENNIUM) / 4;
months = (64 * yearday) / 1959;
/* the result is based on a year starting on March.
* To convert take 12 from Januari and Februari and
* To convert take 12 from January and February and
* increase the year by one. */
if (months < 14) {
TimeFields->Month = (USHORT)(months - 1);