mirror of
https://github.com/UzixLS/KernelEx.git
synced 2025-07-19 07:21:20 +03:00
315 lines
10 KiB
C
Executable File
315 lines
10 KiB
C
Executable File
/*
|
|
* KernelEx
|
|
*
|
|
* Copyright (C) 2010, Xeno86
|
|
* Copyright (C) 1995, Martin von Loewis, Cameron Heide (Wine project)
|
|
*
|
|
* This file is part of KernelEx source code.
|
|
*
|
|
* KernelEx is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published
|
|
* by the Free Software Foundation; version 2 of the License.
|
|
*
|
|
* KernelEx is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GNU Make; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
*/
|
|
#include "common.h"
|
|
|
|
#define LL2FILETIME( ll, pft )\
|
|
(pft)->dwLowDateTime = (UINT)(ll); \
|
|
(pft)->dwHighDateTime = (UINT)((ll) >> 32);
|
|
#define FILETIME2LL( pft, ll) \
|
|
ll = (((LONGLONG)((pft)->dwHighDateTime))<<32) + (pft)-> dwLowDateTime ;
|
|
|
|
|
|
static const int MonthLengths[2][12] =
|
|
{
|
|
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
|
|
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
|
|
};
|
|
|
|
static inline int IsLeapYear(int Year)
|
|
{
|
|
return Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 1 : 0;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* TIME_DayLightCompareDate
|
|
*
|
|
* Compares two dates without looking at the year.
|
|
*
|
|
* PARAMS
|
|
* date [in] The local time to compare.
|
|
* compareDate [in] The daylight savings begin or end date.
|
|
*
|
|
* RETURNS
|
|
*
|
|
* -1 if date < compareDate
|
|
* 0 if date == compareDate
|
|
* 1 if date > compareDate
|
|
* -2 if an error occurs
|
|
*/
|
|
static int TIME_DayLightCompareDate( const SYSTEMTIME *date,
|
|
const SYSTEMTIME *compareDate )
|
|
{
|
|
int limit_day, dayinsecs;
|
|
|
|
if (date->wMonth < compareDate->wMonth)
|
|
return -1; /* We are in a month before the date limit. */
|
|
|
|
if (date->wMonth > compareDate->wMonth)
|
|
return 1; /* We are in a month after the date limit. */
|
|
|
|
/* if year is 0 then date is in day-of-week format, otherwise
|
|
* it's absolute date.
|
|
*/
|
|
if (compareDate->wYear == 0)
|
|
{
|
|
WORD First;
|
|
/* compareDate->wDay is interpreted as number of the week in the month
|
|
* 5 means: the last week in the month */
|
|
int weekofmonth = compareDate->wDay;
|
|
/* calculate the day of the first DayOfWeek in the month */
|
|
First = ( 6 + compareDate->wDayOfWeek - date->wDayOfWeek + date->wDay
|
|
) % 7 + 1;
|
|
limit_day = First + 7 * (weekofmonth - 1);
|
|
/* check needed for the 5th weekday of the month */
|
|
if(limit_day > MonthLengths[date->wMonth==2 && IsLeapYear(date->wYear)]
|
|
[date->wMonth - 1])
|
|
limit_day -= 7;
|
|
}
|
|
else
|
|
{
|
|
limit_day = compareDate->wDay;
|
|
}
|
|
|
|
/* convert to seconds */
|
|
limit_day = ((limit_day * 24 + compareDate->wHour) * 60 +
|
|
compareDate->wMinute ) * 60;
|
|
dayinsecs = ((date->wDay * 24 + date->wHour) * 60 +
|
|
date->wMinute ) * 60 + date->wSecond;
|
|
/* and compare */
|
|
return dayinsecs < limit_day ? -1 :
|
|
dayinsecs > limit_day ? 1 :
|
|
0; /* date is equal to the date limit. */
|
|
}
|
|
|
|
/***********************************************************************
|
|
* TIME_CompTimeZoneID
|
|
*
|
|
* Computes the local time bias for a given time and time zone.
|
|
*
|
|
* PARAMS
|
|
* pTZinfo [in] The time zone data.
|
|
* lpFileTime [in] The system or local time.
|
|
* islocal [in] it is local time.
|
|
*
|
|
* RETURNS
|
|
* TIME_ZONE_ID_INVALID An error occurred
|
|
* TIME_ZONE_ID_UNKNOWN There are no transition time known
|
|
* TIME_ZONE_ID_STANDARD Current time is standard time
|
|
* TIME_ZONE_ID_DAYLIGHT Current time is daylight savings time
|
|
*/
|
|
static DWORD TIME_CompTimeZoneID ( const TIME_ZONE_INFORMATION *pTZinfo,
|
|
FILETIME *lpFileTime, BOOL islocal )
|
|
{
|
|
int ret;
|
|
BOOL beforeStandardDate, afterDaylightDate;
|
|
DWORD retval = TIME_ZONE_ID_INVALID;
|
|
LONGLONG llTime = 0; /* initialized to prevent gcc complaining */
|
|
SYSTEMTIME SysTime;
|
|
FILETIME ftTemp;
|
|
|
|
if (pTZinfo->DaylightDate.wMonth != 0)
|
|
{
|
|
/* if year is 0 then date is in day-of-week format, otherwise
|
|
* it's absolute date.
|
|
*/
|
|
if (pTZinfo->StandardDate.wMonth == 0 ||
|
|
(pTZinfo->StandardDate.wYear == 0 &&
|
|
(pTZinfo->StandardDate.wDay<1 ||
|
|
pTZinfo->StandardDate.wDay>5 ||
|
|
pTZinfo->DaylightDate.wDay<1 ||
|
|
pTZinfo->DaylightDate.wDay>5)))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return TIME_ZONE_ID_INVALID;
|
|
}
|
|
|
|
if (!islocal) {
|
|
FILETIME2LL( lpFileTime, llTime );
|
|
llTime -= ( pTZinfo->Bias + pTZinfo->DaylightBias )
|
|
* (LONGLONG)600000000;
|
|
LL2FILETIME( llTime, &ftTemp)
|
|
lpFileTime = &ftTemp;
|
|
}
|
|
|
|
FileTimeToSystemTime(lpFileTime, &SysTime);
|
|
|
|
/* check for daylight savings */
|
|
ret = TIME_DayLightCompareDate( &SysTime, &pTZinfo->StandardDate);
|
|
if (ret == -2)
|
|
return TIME_ZONE_ID_INVALID;
|
|
|
|
beforeStandardDate = ret < 0;
|
|
|
|
if (!islocal) {
|
|
llTime -= ( pTZinfo->StandardBias - pTZinfo->DaylightBias )
|
|
* (LONGLONG)600000000;
|
|
LL2FILETIME( llTime, &ftTemp)
|
|
FileTimeToSystemTime(lpFileTime, &SysTime);
|
|
}
|
|
|
|
ret = TIME_DayLightCompareDate( &SysTime, &pTZinfo->DaylightDate);
|
|
if (ret == -2)
|
|
return TIME_ZONE_ID_INVALID;
|
|
|
|
afterDaylightDate = ret >= 0;
|
|
|
|
retval = TIME_ZONE_ID_STANDARD;
|
|
if( pTZinfo->DaylightDate.wMonth < pTZinfo->StandardDate.wMonth ) {
|
|
/* Northern hemisphere */
|
|
if( beforeStandardDate && afterDaylightDate )
|
|
retval = TIME_ZONE_ID_DAYLIGHT;
|
|
} else /* Down south */
|
|
if( beforeStandardDate || afterDaylightDate )
|
|
retval = TIME_ZONE_ID_DAYLIGHT;
|
|
} else
|
|
/* No transition date */
|
|
retval = TIME_ZONE_ID_UNKNOWN;
|
|
|
|
return retval;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* TIME_GetTimezoneBias
|
|
*
|
|
* Calculates the local time bias for a given time zone.
|
|
*
|
|
* PARAMS
|
|
* pTZinfo [in] The time zone data.
|
|
* lpFileTime [in] The system or local time.
|
|
* islocal [in] It is local time.
|
|
* pBias [out] The calculated bias in minutes.
|
|
*
|
|
* RETURNS
|
|
* TRUE when the time zone bias was calculated.
|
|
*/
|
|
static BOOL TIME_GetTimezoneBias( const TIME_ZONE_INFORMATION *pTZinfo,
|
|
FILETIME *lpFileTime, BOOL islocal, LONG *pBias )
|
|
{
|
|
LONG bias = pTZinfo->Bias;
|
|
DWORD tzid = TIME_CompTimeZoneID( pTZinfo, lpFileTime, islocal);
|
|
|
|
if( tzid == TIME_ZONE_ID_INVALID)
|
|
return FALSE;
|
|
if (tzid == TIME_ZONE_ID_DAYLIGHT)
|
|
bias += pTZinfo->DaylightBias;
|
|
else if (tzid == TIME_ZONE_ID_STANDARD)
|
|
bias += pTZinfo->StandardBias;
|
|
*pBias = bias;
|
|
return TRUE;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* SystemTimeToTzSpecificLocalTime (KERNEL32.@)
|
|
*
|
|
* Convert a utc system time to a local time in a given time zone.
|
|
*
|
|
* PARAMS
|
|
* lpTimeZoneInformation [in] The desired time zone.
|
|
* lpUniversalTime [in] The utc time to base local time on.
|
|
* lpLocalTime [out] The local time in the time zone.
|
|
*
|
|
* RETURNS
|
|
* Success: TRUE. lpLocalTime contains the converted time
|
|
* Failure: FALSE.
|
|
*/
|
|
|
|
/* MAKE_EXPORT SystemTimeToTzSpecificLocalTime_new=SystemTimeToTzSpecificLocalTime */
|
|
BOOL WINAPI SystemTimeToTzSpecificLocalTime_new(
|
|
const TIME_ZONE_INFORMATION *lpTimeZoneInformation,
|
|
const SYSTEMTIME *lpUniversalTime, LPSYSTEMTIME lpLocalTime )
|
|
{
|
|
FILETIME ft;
|
|
LONG lBias;
|
|
LONGLONG llTime;
|
|
TIME_ZONE_INFORMATION tzinfo;
|
|
|
|
if (lpTimeZoneInformation != NULL)
|
|
{
|
|
tzinfo = *lpTimeZoneInformation;
|
|
}
|
|
else
|
|
{
|
|
if (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_INVALID)
|
|
return FALSE;
|
|
}
|
|
|
|
if (!SystemTimeToFileTime(lpUniversalTime, &ft))
|
|
return FALSE;
|
|
FILETIME2LL( &ft, llTime)
|
|
if (!TIME_GetTimezoneBias(&tzinfo, &ft, FALSE, &lBias))
|
|
return FALSE;
|
|
/* convert minutes to 100-nanoseconds-ticks */
|
|
llTime -= (LONGLONG)lBias * 600000000;
|
|
LL2FILETIME( llTime, &ft)
|
|
|
|
return FileTimeToSystemTime(&ft, lpLocalTime);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* TzSpecificLocalTimeToSystemTime (KERNEL32.@)
|
|
*
|
|
* Converts a local time to a time in utc.
|
|
*
|
|
* PARAMS
|
|
* lpTimeZoneInformation [in] The desired time zone.
|
|
* lpLocalTime [in] The local time.
|
|
* lpUniversalTime [out] The calculated utc time.
|
|
*
|
|
* RETURNS
|
|
* Success: TRUE. lpUniversalTime contains the converted time.
|
|
* Failure: FALSE.
|
|
*/
|
|
|
|
/* MAKE_EXPORT TzSpecificLocalTimeToSystemTime_new=TzSpecificLocalTimeToSystemTime */
|
|
BOOL WINAPI TzSpecificLocalTimeToSystemTime_new(
|
|
const TIME_ZONE_INFORMATION *lpTimeZoneInformation,
|
|
const SYSTEMTIME *lpLocalTime, LPSYSTEMTIME lpUniversalTime)
|
|
{
|
|
FILETIME ft;
|
|
LONG lBias;
|
|
LONGLONG t;
|
|
TIME_ZONE_INFORMATION tzinfo;
|
|
|
|
if (lpTimeZoneInformation != NULL)
|
|
{
|
|
tzinfo = *lpTimeZoneInformation;
|
|
}
|
|
else
|
|
{
|
|
if (GetTimeZoneInformation(&tzinfo) == TIME_ZONE_ID_INVALID)
|
|
return FALSE;
|
|
}
|
|
|
|
if (!SystemTimeToFileTime(lpLocalTime, &ft))
|
|
return FALSE;
|
|
FILETIME2LL( &ft, t)
|
|
if (!TIME_GetTimezoneBias(&tzinfo, &ft, TRUE, &lBias))
|
|
return FALSE;
|
|
/* convert minutes to 100-nanoseconds-ticks */
|
|
t += (LONGLONG)lBias * 600000000;
|
|
LL2FILETIME( t, &ft)
|
|
return FileTimeToSystemTime(&ft, lpUniversalTime);
|
|
}
|