NT4/private/ole32/com/util/time.cxx
2020-09-30 17:12:29 +02:00

416 lines
11 KiB
C++

//+------------------------------------------------------------
//
// File: time.cxx
//
// Contents: Component object model time utilities
//
// Functions: CoFileTimeToDosDateTime
// CoDosDateTimeToFileTime
// CoFileTimeNow
//
// History: 5-Apr-94 brucema Created
//
//-------------------------------------------------------------
#include <ole2int.h>
#if defined (WIN32)
STDAPI_(BOOL) CoFileTimeToDosDateTime(
FILETIME FAR* lpFileTime, LPWORD lpFatDate, LPWORD lpFatTime)
{
OLETRACEIN((API_CoFileTimeToDosDateTime, PARAMFMT("lpFileTime= %tf, lpFatDate= %p, lpFatTime= %p"),
lpFileTime, lpFatDate, lpFatTime));
BOOL fRet= FALSE;
if ((lpFileTime != NULL) &&
IsValidPtrIn(lpFileTime, sizeof(*lpFileTime)) &&
IsValidPtrOut(lpFatDate, sizeof(*lpFatDate)) &&
IsValidPtrOut(lpFatTime, sizeof(*lpFatTime)))
{
fRet = FileTimeToDosDateTime(lpFileTime, lpFatDate, lpFatTime);
}
OLETRACEOUTEX((API_CoFileTimeToDosDateTime, RETURNFMT("%B"), fRet));
return fRet;
}
STDAPI_(BOOL) CoDosDateTimeToFileTime(
WORD nDosDate, WORD nDosTime, FILETIME FAR* lpFileTime)
{
OLETRACEIN((API_CoDosDateTimeToFileTime, PARAMFMT("nDosDate=%x, nDosTime=%x, lpFileTime=%p"),
nDosDate, nDosTime, lpFileTime));
BOOL fRet= FALSE;
if (IsValidPtrOut(lpFileTime, sizeof(*lpFileTime)))
{
fRet = DosDateTimeToFileTime(nDosDate, nDosTime, lpFileTime);
}
OLETRACEOUTEX((API_CoDosDateTimeToFileTime, RETURNFMT("%B"), fRet));
return fRet;
}
#else
#include <dos.h>
// 64 bit representation of 100ns units between 1-1-1601 and (excluding) 1-1-80
// in two 32 bit values (H1980:L1980) and
// in four 16 bit values (HH1980:HL1980:LH1980:LL1980)
//
#define H1980 0x01A8E79F
#define L1980 0xE1D59586
#define HH1980 0x01A8
#define HL1980 0xE79F
#define LH1980 0xE1D5
#define LL1980 0x9586
// Number of 100ns units in one second represented as one 32 bit value
//
#define ONESEC 10000000
// ONESEC0 * ONESEC1 = ONESEC both are 16 bits values
//
#define ONESEC0 4000
#define ONESEC1 2500
// Non-leap year accumulating days, excluding current month, jan is month[0]
static const UINT MonthTab[] = {0,31,59,90,120,151,181,212,243,273,304,334};
// Leap year accumulating days, excluding current month, jan is month[0]
static const UINT LeapmTab[] = {0,31,60,91,121,152,182,213,244,274,305,335};
// Accumulating days, excluding current year, year[0] is leap year
static const UINT YearTab[] = {0,366,731,1096};
// Number of days in a four years period that includes a leap year
static const UINT FourYear = 1461;
// Number of days in a 100 years period that does not start with a leap year
static const DWORD HundredYear = 36524;
// Number of days in a 400 years period (starts with a leap year)
static const DWORD FourHundredYear = 146097;
#pragma SEG(CoFileTimeToDosDateTime)
STDAPI_(BOOL) CoFileTimeToDosDateTime(
FILETIME FAR* lpFileTime, LPWORD lpFatDate, LPWORD lpFatTime)
{
DWORD Year,Month,Day,Hour,Min,Sec;
DWORD Days, Seconds;
DWORD LowNs, HighNs;
int i;
if ((lpFileTime == NULL) ||
!IsValidPtrIn(lpFileTime, sizeof(*lpFileTime)) ||
!IsValidPtrOut(lpFatDate, sizeof(*lpFatDate)) ||
!IsValidPtrOut(lpFatTime, sizeof(*lpFatTime)))
{
return(FALSE);
}
LowNs = lpFileTime->dwLowDateTime;
HighNs = lpFileTime->dwHighDateTime;
i = 1;
// Note that the following code works because 2000 is a leap year
// and DosDate year range is 1980 - 2099
//
_asm {
mov ax,word ptr LowNs
mov bx,word ptr LowNs+2
mov cx,word ptr HighNs
mov dx,word ptr HighNs+2 ; (dx:cx:bx:ax) = time in NT format
sub ax,LL1980
sbb bx,LH1980
sbb cx,HL1980
sbb dx,HH1980 ; (dx:cx:bx:ax) = 100ns since 1-1-1980
jc cvt0 ; Before the beginning of DosDateTime
; Divide (dx:cx:bx:ax) by ONESEC.
; Note that for any time before year 2100 the bumber of 100ns
; since 1-1-1980 divided by ONESEC0 < 2^48 (that is can be stored
; in three registers) and that the result divided by ONESEC1 < 2^32
;
mov si,cx ; (dx:si:bx:ax) = 100ns since 1-1-1980
mov cx,ONESEC0
mov di,ax ; (dx:si:bx:di) = 100ns since 1-1-1980
mov ax,dx ; divide
xor dx,dx
div cx ; ax = q (should be 0) dx = r (used in next div)
or ax,ax
jnz cvt0 ; past 1-1-2100
mov ax,si
div cx ; ax = q (should be 0) dx = r (used in next div)
mov si,ax
mov ax,bx
div cx
mov bx,ax
mov ax,di
div cx
mov di,ax ; (si:bx:di) = 100ns since 1-1-1980 / ONESEC0
mov ax,si
mov cx,ONESEC1
xor dx,dx
div cx ; ax = q (should be 0) dx = r (used in next div)
or ax,ax
jnz cvt0 ; past 1-1-2100
mov ax,bx
div cx
mov word ptr Seconds+2,ax
mov ax,di
div cx
mov word ptr Seconds,ax
mov i,0 ; No error
cvt0:
}
if (i)
return FALSE;
// Min, Hour, Days since 1980
//
Sec = Seconds % 60;
Seconds /= 60;
Min = Seconds % 60;
Seconds /= 60;
Hour = Seconds % 24;
Days = Seconds / 24;
// Find year number (1980 = 0)
//
Year = (Days / FourYear) * 4;
Days %= FourYear;
for (i = 1; i < 4; i++)
if (Days < YearTab[i])
break;
i--;
Year += i;
Days -= YearTab[i];
if (Year + 1980 > 2099)
return FALSE;
// Find month (jan == 1)
//
if (Year % 4) { // Non Leap year
for (i = 1; i < 12; i++)
if (Days < MonthTab[i])
break;
Month = i;
Day = Days - MonthTab[i - 1] + 1;
}
else {
for (i = 1; i < 12; i++)
if (Days < LeapmTab[i])
break;
Month = i;
Day = Days - LeapmTab[i - 1] + 1;
}
// The Dos time and date are stored in two packed 16-bit words
// as follows:
// Date: | 9-15 Year | 5-8 Month | 0-4 Day |
// Time: | 11-15 Hour| 5-10 Min | 0-4 Sec |
// Year 1980 = 0
// Month jan = 1
// Day first = 1
// Hours 0-23
// Min 0-59
// Seconds are delinated in 2sec increments (0-29).
//
*lpFatTime= (WORD) ((Hour << 11) + (Min << 5) + Sec / 2);
*lpFatDate= (WORD) ((Year << 9) + (Month << 5) + Day);
return (TRUE);
}
#pragma SEG(CoDosDateTimeToFileTime)
STDAPI_(BOOL) CoDosDateTimeToFileTime(
WORD nDosDate, WORD nDosTime, FILETIME FAR* lpFileTime)
{
DWORD Year,Month,Day,Hour,Min,Sec;
DWORD Days, Seconds;
DWORD LowNs, HighNs;
if (!IsValidPtrOut(lpFileTime, sizeof(*lpFileTime))
{
return(FALSE);
}
// Note that the following code works because 2000 is a leap year
// and DosDate year range is 1980 - 2099
//
// All operations done in Seconds, then multiply by 10^7.
//
// The Dos time and date are stored in two packed 16-bit words
// as follows:
// Date: | 9-15 Year | 5-8 Month | 0-4 Day |
// Time: | 11-15 Hour| 5-10 Min | 0-4 Sec |
// Year 1980 = 0
// Month jan = 1
// Day first = 1
// Hours 0-23
// Min 0-59
// Seconds are delinated in 2sec increments (0-29).
//
Year = ((nDosDate >> 9) & 0x0000007f);
Month = ((nDosDate >> 5) & 0x0000000f) - 1;
Day = ((nDosDate) & 0x0000001f) - 1;
Hour = ((nDosTime >> 11) & 0x0000001f);
Min = ((nDosTime >> 5) & 0x0000003f);
Sec = ((nDosTime << 1) & 0x0000003e);
if (Year < 0 || Month < 0 || Day < 0 || Hour < 0 || Min < 0 || Sec < 0 ||
Month > 11 || Day > 30 || Hour > 23 || Min > 59 || Sec > 59)
return FALSE;
if (Year + 1980 > 2099)
return FALSE;
//
// Calculate days since 1980
Days = (Year / 4) * FourYear + YearTab[Year % 4] +
((Year % 4) ? MonthTab[Month] : LeapmTab[Month]) + Day;
Seconds = ((Days * 24 + Hour) * 60 + Min) * 60 + Sec;
LowNs = L1980;
HighNs = H1980;
_asm {
mov ax,word ptr Seconds
mov bx,word ptr Seconds+2
; Multiply (bx:ax) by ONESEC.
; Note that for any time before year 2100 the bumber of seconds
; since 1-1-1980 multiplied by ONESEC0 < 2^48 (that is can be stored
; in three registers)
;
mov cx,ONESEC0
mul cx
mov di,dx
mov si,ax ; di:si = ax * ONESEC0
mov ax,bx
xor bx,bx
mul cx ; dx:ax = bx * ONESEC0
add di,ax
adc bx,dx ; bx:di:si = Seconds * ONESEC0
mov ax,si
mov cx,ONESEC1
mul cx
add word ptr LowNs,ax
adc word ptr LowNs+2,dx
adc word ptr HighNs,0
adc word ptr HighNs+2,0
mov ax,di
mul cx
add word ptr LowNs+2,ax
adc word ptr HighNs,dx
adc word ptr HighNs+2,0
mov ax,bx
mul cx
add word ptr HighNs,ax
adc word ptr HighNs+2,dx
}
lpFileTime->dwLowDateTime = LowNs;
lpFileTime->dwHighDateTime= HighNs;
return (TRUE);
}
#endif // WIN32
#pragma SEG(CoFileTimeNow)
//
// Get the current UTC time, in the FILETIME format.
//
STDAPI CoFileTimeNow(FILETIME *pfiletime )
{
// Validate the input
if (!IsValidPtrOut(pfiletime, sizeof(*pfiletime)))
{
return(E_INVALIDARG);
}
#ifdef WIN32
// Get the time in SYSTEMTIME format.
SYSTEMTIME stNow;
GetSystemTime(&stNow);
// Convert it to FILETIME format.
if( !SystemTimeToFileTime(&stNow, pfiletime) )
{
pfiletime->dwLowDateTime = 0;
pfiletime->dwHighDateTime = 0;
return( HRESULT_FROM_WIN32( GetLastError() ));
}
else
return( NOERROR );
#else // WIN32
static struct _dosdate_t date; // declared static so it will be in
static struct _dostime_t time;
WORD wDate;
WORD wTime;
DWORD dw;
BOOL fHighBitSet;
_dos_getdate( &date );
_dos_gettime( &time );
// build wDate
wDate = date.day;
wDate |= (date.month << 5);
wDate |= ((date.year - 1980) << 9);
// build wTime;
wTime = time.second / 2;
wTime |= (time.minute << 5);
wTime |= (time.hour << 11);
if (!CoDosDateTimeToFileTime( wDate, wTime, pfiletime ))
{
return E_UNSPEC;
}
// so far our resolution is only 2 seconds.
dw = (time.second % 2)*100 + time.hsecond;
dw *= 10000;
// add the difference and check for carry
fHighBitSet = (((pfiletime->dwLowDateTime)& 0x80000000) != 0);
pfiletime->dwLowDateTime += dw;
if (fHighBitSet && ((pfiletime->dwLowDateTime & 0x80000000) == 0))
{
pfiletime->dwHighDateTime++;
}
return NOERROR;
#endif // WIN32
}