|
|
/*++
Copyright (c) 1987-2002 Microsoft Corporation
Module Name:
log_gmt.cpp (originally named loghours.c)
Abstract:
Private routines to support rotation of logon hours between local time and GMT time.
Environment:
User mode only. Contains NT-specific code. Requires ANSI C extensions: slash-slash comments, long external names.
Revision History: 16-Mar-93 cliffv Creation. 22-Jul-97 t-danm Copied from /nt/private/nw/convert/nwconv/loghours.c and adapted to loghours.dll.
--*/
#include "stdafx.h"
#pragma warning (disable : 4514)
#pragma warning (push,3)
#include <limits.h>
#include <math.h>
#include <lmcons.h>
#include <lmaccess.h>
#pragma warning (pop)
#include "log_gmt.h"
#include "debug.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__; #endif
//#pragma hdrstop
/*++
Routine NetpRotateLogonHoursPhase1()
Determine the amount to rotate the logon hours by to convert to/from GMT
Arguments:
bConvertToGmt - True to convert the logon hours from local time to GMT relative False to convert the logon hours from GMT relative to local time
pRotateCount - Returns the number of bits to shift by. Must be non NULL pointer.
Return Value:
TRUE if the pRotateCount could be computed FALSE if a pRotateCount could not be computed
--*/ BOOLEAN NetpRotateLogonHoursPhase1( IN BOOL bConvertToGmt, IN bool bAddDaylightBias, OUT PLONG pRotateCount) { if ( !pRotateCount ) return FALSE;
_TRACE (1, L"Entering NetpRotateLogonHoursPhase1\n"); TIME_ZONE_INFORMATION tzi; LONG lBiasInHours = 0; LONG lDSTBias = 0; const LONG HOURS_IN_DAY = 24;
//
// Get the timezone data from the registry
//
DWORD dwResult = GetTimeZoneInformation( &tzi ); if ( TIME_ZONE_ID_INVALID == dwResult ) { return FALSE; }
//
// Compute the amount to rotate the logon hours by
//
// Round the bias in minutes to the closest bias in hours.
// Take into consideration that Bias can be negative.
// Do this by forcing the Bias to be positive, rounding,
// then adjusting it back negative again.
//
if ( bAddDaylightBias ) { switch (dwResult) { case TIME_ZONE_ID_DAYLIGHT: lDSTBias = tzi.DaylightBias; break;
case TIME_ZONE_ID_UNKNOWN: case TIME_ZONE_ID_STANDARD: lDSTBias = tzi.StandardBias; break;
default: return FALSE; } }
ASSERT( tzi.Bias > -(HOURS_IN_DAY*60) ); lBiasInHours = ((tzi.Bias + lDSTBias + (HOURS_IN_DAY*60) + 30)/60) - HOURS_IN_DAY;
if ( !bConvertToGmt ) { lBiasInHours = - lBiasInHours; }
/// TODO: Account for user changing the locale while the schedule grid is open
// Adjust for first day of week, if nFirstDay == 6, then no adjustment is required
// because the vector passed in starts on Sunday
int nFirstDay = GetFirstDayOfWeek (); LONG lFirstDayShiftInHours = (bConvertToGmt ? 1 : -1); switch (nFirstDay) { case 0: lFirstDayShiftInHours *= 1 * HOURS_IN_DAY; break;
case 1: lFirstDayShiftInHours *= 2 * HOURS_IN_DAY; break;
case 2: lFirstDayShiftInHours *= 3 * HOURS_IN_DAY; break;
case 3: lFirstDayShiftInHours *= 4 * HOURS_IN_DAY; break;
case 4: lFirstDayShiftInHours *= 5 * HOURS_IN_DAY; break;
case 5: lFirstDayShiftInHours *= 6 * HOURS_IN_DAY; break;
case 6: lFirstDayShiftInHours *= 0 * HOURS_IN_DAY; break;
default: ASSERT (0); break; } lBiasInHours += lFirstDayShiftInHours;
// NOTICE-NTRAID#NTBUG9-547513-2002/02/19-artm pRotateCount != NULL validated
// Check was added at beginning of function.
*pRotateCount = lBiasInHours; _TRACE (-1, L"Leaving NetpRotateLogonHoursPhase1\n"); return TRUE; } // NetpRotateLogonHoursPhase1()
/*++
Routine NetpRotateLogonHoursPhase2()
Rotate the pLogonHours bit mask by the required amount.
Arguments:
pLogonHours - Pointer to LogonHour bit mask
dwUnitsPerWeek - Number of bits in the bit mask. Must be UNITS_PER_WEEK (168).
lRotateCount - Number of bits to rotate by. Negative means to rotate left. Positive means to rotate right.
Return Value:
TRUE if the rotation succeeded. FALSE if a parameter was out of range
--*/ BOOLEAN NetpRotateLogonHoursPhase2( IN PBYTE pLogonHours, IN DWORD dwUnitsPerWeek, IN LONG lRotateCount) { if ( !pLogonHours ) return FALSE;
_TRACE (1, L"Entering NetpRotateLogonHoursPhase2\n"); //
// Useful constants
//
const int BYTES_PER_WEEK = (UNITS_PER_WEEK/8);
BYTE byAlignedLogonHours[BYTES_PER_WEEK*2]; ::ZeroMemory (byAlignedLogonHours, BYTES_PER_WEEK*2); LONG i = 0;
BOOLEAN bRotateLeft = FALSE;
//
// Ensure there are 8 bits per byte,
// 32 bits per DWORD and
// units per week is even number of bytes.
//
#pragma warning(disable : 4127)
ASSERT( CHAR_BIT == 8 ); ASSERT( sizeof(DWORD) * CHAR_BIT == 32 ); ASSERT( UNITS_PER_WEEK/8*8 == UNITS_PER_WEEK ); #pragma warning (default : 4127)
//
// Validate the input parameters
//
if ( dwUnitsPerWeek != UNITS_PER_WEEK ) { #pragma warning(disable : 4127)
ASSERT( dwUnitsPerWeek == UNITS_PER_WEEK ); #pragma warning (default : 4127)
return FALSE; }
if ( lRotateCount == 0 ) { return TRUE; }
// NOTICE-NTRAID#NTBUG9-547513-2002/02/19-artm pLogonHours != NULL was checked
// Check was added to the beginning of the function.
bRotateLeft = (lRotateCount < 0); lRotateCount = labs( lRotateCount );
// New algorithm: get numBytes by dividing lRotateCount/32. Shift entire array
// left or right by numBytes and then do the loop below for the remainder.
// Move bytes from the beginning to the end, or bytes from the end to the beginning
// depending on the rotation direction.
LONG lNumBYTES = lRotateCount/8; if ( lNumBYTES > 0 ) { RtlCopyMemory (byAlignedLogonHours, pLogonHours, BYTES_PER_WEEK);
RtlCopyMemory (((PBYTE)byAlignedLogonHours) + BYTES_PER_WEEK, pLogonHours, BYTES_PER_WEEK );
size_t nBytesToEnd = sizeof (byAlignedLogonHours) - lNumBYTES; BYTE* pTemp = new BYTE[lNumBYTES]; if ( pTemp ) { //
// Do the left rotate.
//
if ( bRotateLeft ) { memcpy (pTemp, byAlignedLogonHours, lNumBYTES);
memmove (byAlignedLogonHours, byAlignedLogonHours + lNumBYTES, nBytesToEnd);
memcpy (byAlignedLogonHours + nBytesToEnd, pTemp, lNumBYTES); } else { // Do the right rotate
memcpy (pTemp, byAlignedLogonHours + nBytesToEnd, lNumBYTES);
memmove (byAlignedLogonHours + lNumBYTES, byAlignedLogonHours, nBytesToEnd);
memcpy (byAlignedLogonHours, pTemp, lNumBYTES); } delete [] pTemp; }
lRotateCount = lRotateCount%8;
RtlCopyMemory (pLogonHours, byAlignedLogonHours, BYTES_PER_WEEK ); }
if ( lRotateCount ) { //
// Do the left rotate.
//
if (bRotateLeft) { //
// Copy the logon hours to a buffer.
//
// Duplicate the entire pLogonHours buffer at the end of the
// byAlignedLogonHours buffer to make the rotation code trivial.
//
RtlCopyMemory (byAlignedLogonHours, pLogonHours, BYTES_PER_WEEK);
RtlCopyMemory (((PBYTE)byAlignedLogonHours)+BYTES_PER_WEEK, pLogonHours, BYTES_PER_WEEK);
//
// Actually rotate the data.
//
for ( i=0; i < BYTES_PER_WEEK; i++ ) { byAlignedLogonHours[i] = (byAlignedLogonHours[i] >> (BYTE) lRotateCount) | (byAlignedLogonHours[i+1] << (BYTE) (8-lRotateCount)); }
//
// Copy the logon hours back to the input buffer.
//
RtlCopyMemory (pLogonHours, byAlignedLogonHours, BYTES_PER_WEEK); } else { //
// Do the right rotate.
//
//
// Copy the logon hours to a DWORD aligned buffer.
//
// Duplicate the last DWORD at the front of the buffer to make
// the rotation code trivial.
//
RtlCopyMemory (&byAlignedLogonHours[1], pLogonHours, BYTES_PER_WEEK); RtlCopyMemory (byAlignedLogonHours, &pLogonHours[BYTES_PER_WEEK-1], sizeof(BYTE));
//
// Actually rotate the data.
//
for (i = BYTES_PER_WEEK - 1; i >= 0; i-- ) { byAlignedLogonHours[i+1] = (byAlignedLogonHours[i+1] << (BYTE) lRotateCount) | (byAlignedLogonHours[i] >> (BYTE) (8-lRotateCount)); }
//
// Copy the logon hours back to the input buffer.
//
RtlCopyMemory (pLogonHours, &byAlignedLogonHours[1], BYTES_PER_WEEK);
} } _TRACE (-1, L"Leaving NetpRotateLogonHoursPhase2\n"); return TRUE;
} // NetpRotateLogonHoursPhase2()
/*++
Routine NetpRotateLogonHours()
Rotate the pLogonHours bit mask to/from GMT relative time.
Arguments:
pLogonHours - Pointer to LogonHour bit mask
dwUnitsPerWeek - Number of bits in the bit mask. Must be UNITS_PER_WEEK (168).
bConvertToGmt - True to convert the logon hours from local time to GMT relative False to convert the logon hours from GMT relative to local time
Return Value:
TRUE if the rotation succeeded. FALSE if a parameter was out of range
--*/ BOOLEAN NetpRotateLogonHours( IN OUT PBYTE rgbLogonHours, // Array of 21 bytes
IN DWORD cbitUnitsPerWeek, // Must be 21 * 8 = 168
IN BOOL fConvertToGmt, IN bool bAddDaylightBias) { if ( !rgbLogonHours ) return FALSE;
LONG lRotateCount = 0;
//
// Break the functionality into two phases so that if the caller is doing
// this multiple time, he just calls Phase 1 once and Phase 2 multiple
// times.
//
if ( !NetpRotateLogonHoursPhase1 (fConvertToGmt, bAddDaylightBias, &lRotateCount) ) { return FALSE; }
return NetpRotateLogonHoursPhase2 (rgbLogonHours, cbitUnitsPerWeek, lRotateCount ); } // NetpRotateLogonHours()
/*++
Routine NetpRotateLogonHoursBYTE()
Rotate the pLogonHours BYTE array to/from GMT relative time. Each BYTE is one hour. The contents of a BYTE must not change
Arguments:
pLogonHours - Pointer to LogonHour bit mask
dwUnitsPerWeek - Number of BYTES in the BYTE array. Must be UNITS_PER_WEEK (168).
bConvertToGmt - True to convert the logon hours from local time to GMT relative False to convert the logon hours from GMT relative to local time
Return Value:
TRUE if the rotation succeeded. FALSE if a parameter was out of range
--*/ BOOLEAN NetpRotateLogonHoursBYTE( IN OUT PBYTE rgbLogonHours, // Array of 168 bytes
IN DWORD cbitUnitsPerWeek, // Must be 21 * 8 = 168
IN BOOL fConvertToGmt, IN bool bAddDaylightBias) { if ( !rgbLogonHours ) return FALSE;
LONG lRotateCount = 0;
//
// Break the functionality into two phases so that if the caller is doing
// this multiple time, he just calls Phase 1 once and Phase 2 multiple
// times.
//
if ( !NetpRotateLogonHoursPhase1 (fConvertToGmt, bAddDaylightBias, &lRotateCount) ) { return FALSE; } // NOTICE-NTRAID#NTBUG9-547513-2002/02/19-artm Validate rgbLogonHours
// Check correctly done at beginning of function.
// FUTURE-2002/04/05-artm cbitUnitsPerWeek should be validated
// rgbLogonHours should not be NULL and cbitUnitsPerWeek should equal UNITS_PER_WEEK
BOOLEAN bResult = TRUE;
if ( lRotateCount != 0 ) { size_t numBytes = abs (lRotateCount); PBYTE pTemp = new BYTE[cbitUnitsPerWeek + numBytes]; if ( pTemp ) { if ( lRotateCount < 0 ) // shift left
{ // Copy the entire array and then start over with numBytes BYTES from
// the start of the array to fill up to the end of the temp array.
// Then shift over numBytes BYTES and copy 168 bytes from the temp
// array back to the original array.
memcpy (pTemp, rgbLogonHours, cbitUnitsPerWeek); memcpy (pTemp + cbitUnitsPerWeek, rgbLogonHours, numBytes); memcpy (rgbLogonHours, pTemp + numBytes, cbitUnitsPerWeek); } else // lRotateCount > 0 -- shift right
{ // Copy numBytes BYTES from the end of the array and then copy
// the entire array to fill up to the end of the temp array.
// The copy 168 bytes from the beginning of the temp array back
// to the original array.
memcpy (pTemp, rgbLogonHours + (cbitUnitsPerWeek - numBytes), numBytes); memcpy (pTemp + numBytes, rgbLogonHours, cbitUnitsPerWeek); memcpy (rgbLogonHours, pTemp, cbitUnitsPerWeek); }
delete [] pTemp; } else bResult = FALSE; }
return bResult; } // NetpRotateLogonHours()
//****************************************************************************
//
// GetFirstDayOfWeek
//
// Use the locale API to get the "official" first day of the week.
//
//****************************************************************************
int GetFirstDayOfWeek() { _TRACE (1, L"Entering GetFirstDayOfWeek\n"); int nFirstDay = -1; WCHAR szBuf[10];
int nRet = ::GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, szBuf, sizeof(szBuf)/sizeof(WCHAR)); if ( nRet > 0 ) { int nDay = ::_wtoi( szBuf ); if ( nDay < 0 || nDay > 6 ) { _TRACE (0, L"Out of range, IFIRSTDAYOFWEEK = %d\n", nDay); } else nFirstDay = nDay; } else { _TRACE (0, L"GetLocaleInfo(IFIRSTDAYOFWEEK) failed - %d\n", GetLastError ()); }
_TRACE (-1, L"Leaving GetFirstDayOfWeek: first day = %d\n", nFirstDay); return nFirstDay; }
|