text: /*++
  
  Copyright (c) 1987-1993  Microsoft Corporation
  
  Module Name:
  
      loghours.c
  
  Abstract:
  
      Private routines to support rotation of logon hours between local time
      and GMT time.
  
  Author:
  
      Cliff Van Dyke (cliffv) 16-Mar-93
  
  Environment:
  
      User mode only.
      Contains NT-specific code.
      Requires ANSI C extensions: slash-slash comments, long external names.
  
  Revision History:
  
  --*/
  
  #include <nt.h>
  #include <ntrtl.h>
  #include <nturtl.h>
  
  #include <windef.h>
  #include <winbase.h>
  
  #include <limits.h>
  #include <math.h>
  
  #include <lmcons.h>
  #include <lmaccess.h>
  #include <loghours.h>
  
  
  
  BOOLEAN
  NetpRotateLogonHoursPhase1(
      IN BOOL  ConvertToGmt,
      OUT PULONG RotateCount
      )
  
  /*++
  
  Routine Description:
  
      Determine the amount to rotate the logon hours by to convert to/from GMT
  
  Arguments:
  
      ConvertToGmt -
          True to convert the logon hours from local time to GMT relative
          False to convert the logon hours from GMT relative to local time
  
      RotateCount - Returns the number of bits to shift by.
  
  Return Value:
  
      TRUE if the RotateCount could be computed
      FALSE if a RotateCount could not be computed
  
  --*/
  {
      RTL_TIME_ZONE_INFORMATION tzi;
      LONG BiasInHours;
      NTSTATUS Status;
  
      //
      // Get the timezone data from the registry
      //
  
      Status = RtlQueryTimeZoneInformation( &tzi );
      if ( !NT_SUCCESS(Status) ) {
          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.
      //
  
      ASSERT( tzi.Bias > -(24*60) );
      BiasInHours = ((tzi.Bias + (24*60) + 30)/60) - 24;
  
      if ( !ConvertToGmt ) {
          BiasInHours = - BiasInHours;
      }
  
      *RotateCount = BiasInHours;
      return TRUE;
  
  }
  
  
  BOOLEAN
  NetpRotateLogonHoursPhase2(
      IN PBYTE LogonHours,
      IN DWORD UnitsPerWeek,
      IN LONG  RotateCount
      )
  
  /*++
  
  Routine Description:
  
      Rotate the LogonHours bit mask by the required amount.
  
  
  Arguments:
  
      LogonHours - Pointer to LogonHour bit mask
  
      UnitsPerWeek - Number of bits in the bit mask. Must be UNITS_PER_WEEK (168).
  
      RotateCount - Number of bits to rotate by.  Must be between 31 and -31.
          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
  
  --*/
  {
      //
      // Useful constants
      //
  
  #define DWORDS_PER_WEEK ((UNITS_PER_WEEK+31)/32)
  #define BYTES_PER_WEEK  (UNITS_PER_WEEK/8)
  
      DWORD AlignedLogonHours[DWORDS_PER_WEEK+1];
      LONG i;
  
      BOOLEAN RotateLeft;
  
      //
      // Ensure there are 8 bits per byte,
      //  32 bits per DWORD and
      //  units per week is even number of bytes.
      //
  
      ASSERT( CHAR_BIT == 8 );
      ASSERT( sizeof(DWORD) * CHAR_BIT == 32 );
      ASSERT( UNITS_PER_WEEK/8*8 == UNITS_PER_WEEK );
  
  
      //
      // Validate the input parameters
      //
  
      if ( UnitsPerWeek != UNITS_PER_WEEK ) {
          ASSERT( UnitsPerWeek == UNITS_PER_WEEK );
          return FALSE;
      }
  
      if ( RotateCount == 0 ) {
          return TRUE;
      }
  
      RotateLeft = (RotateCount < 0);
      RotateCount = labs( RotateCount );
      if ( RotateCount > 31 ) {
          ASSERT ( RotateCount <= 31 );
          return FALSE;
      }
  
  
      //
      // Do the left rotate.
      //
  
      if (RotateLeft) {
  
  
          //
          // Copy the logon hours to a DWORD aligned buffer.
          //
          //  Duplicate the first dword at the end of the buffer to make
          //  the rotation code trivial.
          //
  
          RtlCopyMemory(AlignedLogonHours, LogonHours, BYTES_PER_WEEK );
  
          RtlCopyMemory( ((PBYTE)AlignedLogonHours)+BYTES_PER_WEEK,
                          LogonHours,
                          sizeof(DWORD) );
  
          //
          // Actually rotate the data.
          //
  
          for ( i=0; i < DWORDS_PER_WEEK; i++ ) {
              AlignedLogonHours[i] =
                  (AlignedLogonHours[i] >> RotateCount) |
                  (AlignedLogonHours[i+1] << (32-RotateCount));
          }
  
          //
          // Copy the logon hours back to the input buffer.
          //
  
          RtlCopyMemory( LogonHours, AlignedLogonHours, BYTES_PER_WEEK );
  
  
      //
      // Do the right rotate.
      //
  
      } else {
  
  
          //
          // 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( &AlignedLogonHours[1], LogonHours, BYTES_PER_WEEK );
          RtlCopyMemory( AlignedLogonHours,
                         &LogonHours[BYTES_PER_WEEK-4],
                          sizeof(DWORD));
  
          //
          // Actually rotate the data.
          //
  
          for ( i=DWORDS_PER_WEEK-1; i>=0; i-- ) {
              AlignedLogonHours[i+1] =
                  (AlignedLogonHours[i+1] << RotateCount) |
                  (AlignedLogonHours[i] >> (32-RotateCount));
          }
  
          //
          // Copy the logon hours back to the input buffer.
          //
  
          RtlCopyMemory( LogonHours, &AlignedLogonHours[1], BYTES_PER_WEEK );
  
      }
  
      //
      // Done
      //
  
      return TRUE;
  
  }
  
  
  
  BOOLEAN
  NetpRotateLogonHours(
      IN PBYTE LogonHours,
      IN DWORD UnitsPerWeek,
      IN BOOL  ConvertToGmt
      )
  
  /*++
  
  Routine Description:
  
      Rotate the LogonHours bit mask to/from GMT relative time.
  
  
  Arguments:
  
      LogonHours - Pointer to LogonHour bit mask
  
      UnitsPerWeek - Number of bits in the bit mask. Must be UNITS_PER_WEEK (168).
  
      ConvertToGmt -
          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
  
  --*/
  {
      ULONG RotateCount;
  
      //
      // 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( ConvertToGmt, &RotateCount ) ) {
          return FALSE;
      }
  
      return NetpRotateLogonHoursPhase2( LogonHours, UnitsPerWeek, RotateCount );
  
  }
  