3008 lines
75 KiB
C
3008 lines
75 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
BitMap.c
|
||
|
||
Abstract:
|
||
|
||
Implementation of the bit map routines for the NT rtl.
|
||
|
||
Bit numbers within the bit map are zero based. The first is numbered
|
||
zero.
|
||
|
||
The bit map routines keep track of the number of bits clear or set by
|
||
subtracting or adding the number of bits operated on as bit ranges
|
||
are cleared or set; individual bit states are not tested.
|
||
This means that if a range of bits is set,
|
||
it is assumed that the total range is currently clear.
|
||
|
||
Author:
|
||
|
||
Gary Kimura (GaryKi) & Lou Perazzoli (LouP) 29-Jan-1990
|
||
|
||
Revision History:
|
||
|
||
Eric Rehm 9-Nov-1995 - Rename to Rtl to Halp for use in Rawhide HAL
|
||
|
||
--*/
|
||
|
||
// #include "ntrtlp.h"
|
||
|
||
#include "halp.h"
|
||
#include "rawhide.h"
|
||
|
||
#define RightShiftUlong(E1,E2) ((E2) < 32 ? (E1) >> (E2) : 0)
|
||
#define LeftShiftUlong(E1,E2) ((E2) < 32 ? (E1) << (E2) : 0)
|
||
|
||
//
|
||
// Macro that tells how many contiguous bits are set (i.e., 1) in
|
||
// a byte
|
||
//
|
||
|
||
#define HalppBitSetAnywhere( Byte ) HalppBitsClearAnywhere[ (~(Byte) & 0xFF) ]
|
||
|
||
|
||
//
|
||
// Macro that tells how many contiguous LOW order bits are set
|
||
// (i.e., 1) in a byte
|
||
//
|
||
|
||
#define HalppBitsSetLow( Byte ) HalppBitsClearLow[ (~(Byte) & 0xFF) ]
|
||
|
||
|
||
//
|
||
// Macro that tells how many contiguous HIGH order bits are set
|
||
// (i.e., 1) in a byte
|
||
//
|
||
|
||
#define HalppBitsSetHigh( Byte ) HalppBitsClearHigh[ (~(Byte) & 0xFF) ]
|
||
|
||
|
||
//
|
||
// Macro that tells how many set bits (i.e., 1) there are in a byte
|
||
//
|
||
|
||
#define HalppBitsSetTotal( Byte ) HalppBitsClearTotal[ (~(Byte) & 0xFF) ]
|
||
|
||
|
||
#if DBG
|
||
VOID
|
||
HalpDumpBitMap (
|
||
PRTL_BITMAP BitMap
|
||
)
|
||
{
|
||
ULONG i;
|
||
BOOLEAN AllZeros, AllOnes;
|
||
|
||
DbgPrint(" BitMap:%08lx", BitMap);
|
||
|
||
KdPrint((" (%08x)", BitMap->SizeOfBitMap));
|
||
KdPrint((" %08lx\n", BitMap->Buffer));
|
||
|
||
AllZeros = FALSE;
|
||
AllOnes = FALSE;
|
||
|
||
for (i = 0; i < ((BitMap->SizeOfBitMap + 31) / 32); i += 1) {
|
||
|
||
if (BitMap->Buffer[i] == 0) {
|
||
|
||
if (AllZeros) {
|
||
|
||
NOTHING;
|
||
|
||
} else {
|
||
|
||
DbgPrint("%4d:", i);
|
||
DbgPrint(" %08lx\n", BitMap->Buffer[i]);
|
||
}
|
||
|
||
AllZeros = TRUE;
|
||
|
||
} else if (BitMap->Buffer[i] == 0xFFFFFFFF) {
|
||
|
||
if (AllOnes) {
|
||
|
||
NOTHING;
|
||
|
||
} else {
|
||
|
||
DbgPrint("%4d:", i);
|
||
DbgPrint(" %08lx\n", BitMap->Buffer[i]);
|
||
}
|
||
|
||
AllOnes = TRUE;
|
||
|
||
} else {
|
||
|
||
AllZeros = FALSE;
|
||
AllOnes = FALSE;
|
||
|
||
DbgPrint("%4d:", i);
|
||
DbgPrint(" %08lx\n", BitMap->Buffer[i]);
|
||
}
|
||
}
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
//
|
||
// There are three macros to make reading the bytes in a bitmap easier.
|
||
//
|
||
|
||
#define GET_BYTE_DECLARATIONS() \
|
||
PUCHAR _CURRENT_POSITION;
|
||
|
||
#define GET_BYTE_INITIALIZATION(RTL_BITMAP,BYTE_INDEX) { \
|
||
_CURRENT_POSITION = &((PUCHAR)((RTL_BITMAP)->Buffer))[BYTE_INDEX]; \
|
||
}
|
||
|
||
#define GET_BYTE(THIS_BYTE) ( \
|
||
THIS_BYTE = *(_CURRENT_POSITION++) \
|
||
)
|
||
|
||
|
||
//
|
||
// Lookup table that tells how many contiguous bits are clear (i.e., 0) in
|
||
// a byte
|
||
//
|
||
|
||
CCHAR HalppBitsClearAnywhere[] =
|
||
{ 8,7,6,6,5,5,5,5,4,4,4,4,4,4,4,4,
|
||
4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||
5,4,3,3,2,2,2,2,3,2,2,2,2,2,2,2,
|
||
4,3,2,2,2,2,2,2,3,2,2,2,2,2,2,2,
|
||
6,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2,
|
||
4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,1,
|
||
5,4,3,3,2,2,2,2,3,2,1,1,2,1,1,1,
|
||
4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,1,
|
||
7,6,5,5,4,4,4,4,3,3,3,3,3,3,3,3,
|
||
4,3,2,2,2,2,2,2,3,2,2,2,2,2,2,2,
|
||
5,4,3,3,2,2,2,2,3,2,1,1,2,1,1,1,
|
||
4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,1,
|
||
6,5,4,4,3,3,3,3,3,2,2,2,2,2,2,2,
|
||
4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,1,
|
||
5,4,3,3,2,2,2,2,3,2,1,1,2,1,1,1,
|
||
4,3,2,2,2,1,1,1,3,2,1,1,2,1,1,0 };
|
||
|
||
//
|
||
// Lookup table that tells how many contiguous LOW order bits are clear
|
||
// (i.e., 0) in a byte
|
||
//
|
||
|
||
CCHAR HalppBitsClearLow[] =
|
||
{ 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
|
||
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
|
||
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
|
||
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
|
||
6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
|
||
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
|
||
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
|
||
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
|
||
7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
|
||
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
|
||
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
|
||
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
|
||
6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
|
||
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
|
||
5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,
|
||
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 };
|
||
|
||
//
|
||
// Lookup table that tells how many contiguous HIGH order bits are clear
|
||
// (i.e., 0) in a byte
|
||
//
|
||
|
||
CCHAR HalppBitsClearHigh[] =
|
||
{ 8,7,6,6,5,5,5,5,4,4,4,4,4,4,4,4,
|
||
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
|
||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
|
||
|
||
//
|
||
// Lookup table that tells how many clear bits (i.e., 0) there are in a byte
|
||
//
|
||
|
||
CCHAR HalppBitsClearTotal[] =
|
||
{ 8,7,7,6,7,6,6,5,7,6,6,5,6,5,5,4,
|
||
7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3,
|
||
7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3,
|
||
6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2,
|
||
7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3,
|
||
6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2,
|
||
6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2,
|
||
5,4,4,3,4,3,3,2,4,3,3,2,3,2,2,1,
|
||
7,6,6,5,6,5,5,4,6,5,5,4,5,4,4,3,
|
||
6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2,
|
||
6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2,
|
||
5,4,4,3,4,3,3,2,4,3,3,2,3,2,2,1,
|
||
6,5,5,4,5,4,4,3,5,4,4,3,4,3,3,2,
|
||
5,4,4,3,4,3,3,2,4,3,3,2,3,2,2,1,
|
||
5,4,4,3,4,3,3,2,4,3,3,2,3,2,2,1,
|
||
4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 };
|
||
|
||
//
|
||
// Bit Mask for clearing and setting bits within bytes
|
||
//
|
||
|
||
static UCHAR FillMask[] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
|
||
|
||
static UCHAR ZeroMask[] = { 0xFF, 0xFE, 0xFC, 0xF8, 0xf0, 0xe0, 0xc0, 0x80, 0x00 };
|
||
|
||
|
||
VOID
|
||
HalpInitializeBitMap (
|
||
IN PRTL_BITMAP BitMapHeader,
|
||
IN PULONG BitMapBuffer,
|
||
IN ULONG SizeOfBitMap
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure initializes a bit map.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the BitMap Header to initialize
|
||
|
||
BitMapBuffer - Supplies a pointer to the buffer that is to serve as the
|
||
BitMap. This must be an a multiple number of longwords in size.
|
||
|
||
SizeOfBitMap - Supplies the number of bits required in the Bit Map.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//RTL_PAGED_CODE();
|
||
|
||
//
|
||
// Initialize the BitMap header.
|
||
//
|
||
|
||
BitMapHeader->SizeOfBitMap = SizeOfBitMap;
|
||
BitMapHeader->Buffer = BitMapBuffer;
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
//DbgPrint("InitializeBitMap"); DumpBitMap(BitMapHeader);
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
HalpClearAllBits (
|
||
IN PRTL_BITMAP BitMapHeader
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure clears all bits in the specified Bit Map.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the previously initialized BitMap
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Clear all the bits
|
||
//
|
||
|
||
RtlZeroMemory( BitMapHeader->Buffer,
|
||
((BitMapHeader->SizeOfBitMap + 31) / 32) * 4
|
||
);
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
//DbgPrint("ClearAllBits"); DumpBitMap(BitMapHeader);
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
HalpSetAllBits (
|
||
IN PRTL_BITMAP BitMapHeader
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure sets all bits in the specified Bit Map.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the previously initialized BitMap
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Set all the bits
|
||
//
|
||
|
||
RtlFillMemoryUlong( BitMapHeader->Buffer,
|
||
((BitMapHeader->SizeOfBitMap + 31) / 32) * 4,
|
||
0xffffffff
|
||
);
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
//DbgPrint("SetAllBits"); DumpBitMap(BitMapHeader);
|
||
return;
|
||
}
|
||
|
||
|
||
ULONG
|
||
HalpFindClearBits (
|
||
IN PRTL_BITMAP BitMapHeader,
|
||
IN ULONG NumberToFind,
|
||
IN ULONG HintIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure searches the specified bit map for the specified
|
||
contiguous region of clear bits. If a run is not found from the
|
||
hint to the end of the bitmap, we will search again from the
|
||
beginning of the bitmap.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the previously initialized BitMap.
|
||
|
||
NumberToFind - Supplies the size of the contiguous region to find.
|
||
|
||
HintIndex - Supplies the index (zero based) of where we should start
|
||
the search from within the bitmap.
|
||
|
||
Return Value:
|
||
|
||
ULONG - Receives the starting index (zero based) of the contiguous
|
||
region of clear bits found. If not such a region cannot be found
|
||
a -1 (i.e. 0xffffffff) is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG SizeOfBitMap;
|
||
ULONG SizeInBytes;
|
||
|
||
ULONG HintBit;
|
||
ULONG MainLoopIndex;
|
||
|
||
GET_BYTE_DECLARATIONS();
|
||
|
||
//
|
||
// To make the loops in our test run faster we'll extract the
|
||
// fields from the bitmap header
|
||
//
|
||
|
||
SizeOfBitMap = BitMapHeader->SizeOfBitMap;
|
||
SizeInBytes = (SizeOfBitMap + 7) / 8;
|
||
|
||
//
|
||
// Set any unused bits in the last byte so we won't count them. We do
|
||
// this by first checking if there is any odd bits in the last byte.
|
||
//
|
||
|
||
if ((SizeOfBitMap % 8) != 0) {
|
||
|
||
//
|
||
// The last byte has some odd bits so we'll set the high unused
|
||
// bits in the last byte to 1's
|
||
//
|
||
|
||
((PUCHAR)BitMapHeader->Buffer)[SizeInBytes - 1] |=
|
||
ZeroMask[SizeOfBitMap % 8];
|
||
}
|
||
|
||
//
|
||
// Calculate from the hint index where the hint byte is and set ourselves
|
||
// up to read the hint on the next call to GET_BYTE. To make the
|
||
// algorithm run fast we'll only honor hints down to the byte level of
|
||
// granularity. There is a possibility that we'll need to execute
|
||
// our main logic twice. Once to test from the hint byte to the end of
|
||
// the bitmap and the other to test from the start of the bitmap. First
|
||
// we need to make sure the Hint Index is within range.
|
||
//
|
||
|
||
if (HintIndex >= SizeOfBitMap) {
|
||
|
||
HintIndex = 0;
|
||
}
|
||
|
||
HintBit = HintIndex % 8;
|
||
|
||
for (MainLoopIndex = 0; MainLoopIndex < 2; MainLoopIndex += 1) {
|
||
|
||
ULONG StartByteIndex;
|
||
ULONG EndByteIndex;
|
||
|
||
UCHAR CurrentByte;
|
||
|
||
//
|
||
// Check for the first time through the main loop, which indicates
|
||
// that we are going to start our search at our hint byte
|
||
//
|
||
|
||
if (MainLoopIndex == 0) {
|
||
|
||
StartByteIndex = HintIndex / 8;
|
||
EndByteIndex = SizeInBytes;
|
||
|
||
//
|
||
// This is the second time through the loop, make sure there is
|
||
// actually something to check before the hint byte
|
||
//
|
||
|
||
} else if (HintIndex != 0) {
|
||
|
||
//
|
||
// The end index for the second time around is based on the
|
||
// number of bits we need to find. We need to use this inorder
|
||
// to take the case where the preceding byte to the hint byte
|
||
// is the start of our run, and the run includes the hint byte
|
||
// and some following bytes, based on the number of bits needed
|
||
// The computation is to take the number of bits needed minus
|
||
// 2 divided by 8 and then add 2. This will take in to account
|
||
// the worst possible case where we have one bit hanging off
|
||
// of each end byte, and all intervening bytes are all zero.
|
||
//
|
||
|
||
if (NumberToFind < 2) {
|
||
|
||
EndByteIndex = 0;
|
||
|
||
} else {
|
||
|
||
EndByteIndex = (HintIndex / 8) + ((NumberToFind - 2) / 8) + 2;
|
||
|
||
//
|
||
// Make sure we don't overrun the end of the bitmap
|
||
//
|
||
|
||
if (EndByteIndex > SizeInBytes) {
|
||
|
||
EndByteIndex = SizeInBytes;
|
||
}
|
||
}
|
||
|
||
HintIndex = 0;
|
||
HintBit = 0;
|
||
StartByteIndex = 0;
|
||
|
||
//
|
||
// Otherwise we already did a complete loop through the bitmap
|
||
// so we should simply return -1 to say nothing was found
|
||
//
|
||
|
||
} else {
|
||
|
||
return 0xffffffff;
|
||
}
|
||
|
||
//
|
||
// Set ourselves up to get the next byte
|
||
//
|
||
|
||
GET_BYTE_INITIALIZATION(BitMapHeader, StartByteIndex);
|
||
|
||
//
|
||
// Get the first byte, and set any bits before the hint bit.
|
||
//
|
||
|
||
GET_BYTE( CurrentByte );
|
||
|
||
CurrentByte |= FillMask[HintBit];
|
||
|
||
//
|
||
// If the number of bits can only fit in 1 or 2 bytes (i.e., 9 bits or
|
||
// less) we do the following test case.
|
||
//
|
||
|
||
if (NumberToFind <= 9) {
|
||
|
||
ULONG CurrentBitIndex;
|
||
UCHAR PreviousByte;
|
||
|
||
PreviousByte = 0xff;
|
||
|
||
//
|
||
// Examine all the bytes within our test range searching
|
||
// for a fit
|
||
//
|
||
|
||
CurrentBitIndex = StartByteIndex * 8;
|
||
|
||
while (TRUE) {
|
||
|
||
//
|
||
// If this is the first itteration of the loop, mask Current
|
||
// byte with the real hint.
|
||
//
|
||
|
||
//
|
||
// The current byte does not satisfy our requirements so we'll
|
||
// check the previous and current byte together to see if
|
||
// we'll fit. To check uses the high part of the previous
|
||
// byte and low part of the current byte.
|
||
//
|
||
|
||
if (((ULONG)HalppBitsClearHigh[PreviousByte] +
|
||
(ULONG)HalppBitsClearLow[CurrentByte]) >= NumberToFind) {
|
||
|
||
ULONG StartingIndex;
|
||
|
||
//
|
||
// It all fits in these two bytes, so we can compute
|
||
// the starting index. This is done by taking the
|
||
// index of the current byte (bit 0) and subtracting the
|
||
// number of bits its takes to get to the first cleared
|
||
// high bit.
|
||
//
|
||
|
||
StartingIndex = CurrentBitIndex -
|
||
(LONG)HalppBitsClearHigh[PreviousByte];
|
||
|
||
//
|
||
// Now make sure the total size isn't beyond the bitmap
|
||
//
|
||
|
||
if ((StartingIndex + NumberToFind) <= SizeOfBitMap) {
|
||
|
||
return StartingIndex;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Check to see if a single byte will satisfy the requirement
|
||
//
|
||
|
||
if ((ULONG)HalppBitsClearAnywhere[CurrentByte] >= NumberToFind) {
|
||
|
||
UCHAR BitMask;
|
||
ULONG i;
|
||
|
||
//
|
||
// It all fits in a single byte, so calculate the bit
|
||
// number. We do this by taking a mask of the appropriate
|
||
// size and shifting it over until it fits. It fits when
|
||
// we can bitwise-and the current byte with the bitmask
|
||
// and get a zero back.
|
||
//
|
||
|
||
BitMask = FillMask[ NumberToFind ];
|
||
for (i = 0; (BitMask & CurrentByte) != 0; i += 1) {
|
||
|
||
BitMask <<= 1;
|
||
}
|
||
|
||
//
|
||
// return to our caller the located bit index, and the
|
||
// number that we found.
|
||
//
|
||
|
||
return CurrentBitIndex + i;
|
||
}
|
||
|
||
//
|
||
// For the next iteration through our loop we need to make
|
||
// the current byte into the previous byte, and go to the
|
||
// top of the loop again.
|
||
//
|
||
|
||
PreviousByte = CurrentByte;
|
||
|
||
//
|
||
// Increment our Bit Index, and either exit, or get the
|
||
// next byte.
|
||
//
|
||
|
||
CurrentBitIndex += 8;
|
||
|
||
if ( CurrentBitIndex < EndByteIndex * 8 ) {
|
||
|
||
GET_BYTE( CurrentByte );
|
||
|
||
} else {
|
||
|
||
break;
|
||
}
|
||
|
||
} // end loop CurrentBitIndex
|
||
|
||
//
|
||
// The number to find is greater than 9 but if it is less than 15
|
||
// then we know it can be satisfied with at most 2 bytes, or 3 bytes
|
||
// if the middle byte (of the 3) is all zeros.
|
||
//
|
||
|
||
} else if (NumberToFind < 15) {
|
||
|
||
ULONG CurrentBitIndex;
|
||
|
||
UCHAR PreviousPreviousByte;
|
||
UCHAR PreviousByte;
|
||
|
||
PreviousPreviousByte = 0xff;
|
||
PreviousByte = 0xff;
|
||
|
||
//
|
||
// Examine all the bytes within our test range searching
|
||
// for a fit
|
||
//
|
||
|
||
CurrentBitIndex = StartByteIndex * 8;
|
||
|
||
while (TRUE) {
|
||
|
||
//
|
||
// Check to see if the Previous byte and current byte
|
||
// together satisfy the request.
|
||
//
|
||
|
||
if (((ULONG)HalppBitsClearHigh[PreviousByte] +
|
||
(ULONG)HalppBitsClearLow[CurrentByte]) >= NumberToFind) {
|
||
|
||
ULONG StartingIndex;
|
||
|
||
//
|
||
// It all fits in these two bytes, so we can compute
|
||
// the starting index. This is done by taking the
|
||
// index of the current byte (bit 0) and subtracting the
|
||
// number of bits its takes to get to the first cleared
|
||
// high bit.
|
||
//
|
||
|
||
StartingIndex = CurrentBitIndex -
|
||
(LONG)HalppBitsClearHigh[PreviousByte];
|
||
|
||
//
|
||
// Now make sure the total size isn't beyond the bitmap
|
||
//
|
||
|
||
if ((StartingIndex + NumberToFind) <= SizeOfBitMap) {
|
||
|
||
return StartingIndex;
|
||
}
|
||
}
|
||
|
||
//
|
||
// if the previous byte is all zeros then maybe the
|
||
// request can be satisfied using the Previous Previous Byte
|
||
// Previous Byte, and the Current Byte.
|
||
//
|
||
|
||
if ((PreviousByte == 0)
|
||
|
||
&&
|
||
|
||
(((ULONG)HalppBitsClearHigh[PreviousPreviousByte] + 8 +
|
||
(ULONG)HalppBitsClearLow[CurrentByte]) >= NumberToFind)) {
|
||
|
||
ULONG StartingIndex;
|
||
|
||
//
|
||
// It all fits in these three bytes, so we can compute
|
||
// the starting index. This is done by taking the
|
||
// index of the previous byte (bit 0) and subtracting
|
||
// the number of bits its takes to get to the first
|
||
// cleared high bit.
|
||
//
|
||
|
||
StartingIndex = (CurrentBitIndex - 8) -
|
||
(LONG)HalppBitsClearHigh[PreviousPreviousByte];
|
||
|
||
//
|
||
// Now make sure the total size isn't beyond the bitmap
|
||
//
|
||
|
||
if ((StartingIndex + NumberToFind) <= SizeOfBitMap) {
|
||
|
||
return StartingIndex;
|
||
}
|
||
}
|
||
|
||
//
|
||
// For the next iteration through our loop we need to make
|
||
// the current byte into the previous byte, the previous
|
||
// byte into the previous previous byte, and go to the
|
||
// top of the loop again.
|
||
//
|
||
|
||
PreviousPreviousByte = PreviousByte;
|
||
PreviousByte = CurrentByte;
|
||
|
||
//
|
||
// Increment our Bit Index, and either exit, or get the
|
||
// next byte.
|
||
//
|
||
|
||
CurrentBitIndex += 8;
|
||
|
||
if ( CurrentBitIndex < EndByteIndex * 8 ) {
|
||
|
||
GET_BYTE( CurrentByte );
|
||
|
||
} else {
|
||
|
||
break;
|
||
}
|
||
|
||
} // end loop CurrentBitIndex
|
||
|
||
//
|
||
// The number to find is greater than or equal to 15. This request
|
||
// has to have at least one byte of all zeros to be satisfied
|
||
//
|
||
|
||
} else {
|
||
|
||
ULONG CurrentByteIndex;
|
||
|
||
ULONG ZeroBytesNeeded;
|
||
ULONG ZeroBytesFound;
|
||
|
||
UCHAR StartOfRunByte;
|
||
LONG StartOfRunIndex;
|
||
|
||
//
|
||
// First precalculate how many zero bytes we're going to need
|
||
//
|
||
|
||
ZeroBytesNeeded = (NumberToFind - 7) / 8;
|
||
|
||
//
|
||
// Indicate for the first time through our loop that we haven't
|
||
// found a zero byte yet, and indicate that the start of the
|
||
// run is the byte just before the start byte index
|
||
//
|
||
|
||
ZeroBytesFound = 0;
|
||
StartOfRunByte = 0xff;
|
||
StartOfRunIndex = StartByteIndex - 1;
|
||
|
||
//
|
||
// Examine all the bytes in our test range searching for a fit
|
||
//
|
||
|
||
CurrentByteIndex = StartByteIndex;
|
||
|
||
while (TRUE) {
|
||
|
||
//
|
||
// If the number of zero bytes fits our minimum requirements
|
||
// then we can do the additional test to see if we
|
||
// actually found a fit
|
||
//
|
||
|
||
if ((ZeroBytesFound >= ZeroBytesNeeded)
|
||
|
||
&&
|
||
|
||
((ULONG)HalppBitsClearHigh[StartOfRunByte] + ZeroBytesFound*8 +
|
||
(ULONG)HalppBitsClearLow[CurrentByte]) >= NumberToFind) {
|
||
|
||
ULONG StartingIndex;
|
||
|
||
//
|
||
// It all fits in these bytes, so we can compute
|
||
// the starting index. This is done by taking the
|
||
// StartOfRunIndex times 8 and adding the number of bits
|
||
// it takes to get to the first cleared high bit.
|
||
//
|
||
|
||
StartingIndex = (StartOfRunIndex * 8) +
|
||
(8 - (LONG)HalppBitsClearHigh[StartOfRunByte]);
|
||
|
||
//
|
||
// Now make sure the total size isn't beyond the bitmap
|
||
//
|
||
|
||
if ((StartingIndex + NumberToFind) <= SizeOfBitMap) {
|
||
|
||
return StartingIndex;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Check to see if the byte is zero and increment
|
||
// the number of zero bytes found
|
||
//
|
||
|
||
if (CurrentByte == 0) {
|
||
|
||
ZeroBytesFound += 1;
|
||
|
||
//
|
||
// The byte isn't a zero so we need to start over again
|
||
// looking for zero bytes.
|
||
//
|
||
|
||
} else {
|
||
|
||
ZeroBytesFound = 0;
|
||
StartOfRunByte = CurrentByte;
|
||
StartOfRunIndex = CurrentByteIndex;
|
||
}
|
||
|
||
//
|
||
// Increment our Byte Index, and either exit, or get the
|
||
// next byte.
|
||
//
|
||
|
||
CurrentByteIndex += 1;
|
||
|
||
if ( CurrentByteIndex < EndByteIndex ) {
|
||
|
||
GET_BYTE( CurrentByte );
|
||
|
||
} else {
|
||
|
||
break;
|
||
}
|
||
|
||
} // end loop CurrentByteIndex
|
||
}
|
||
}
|
||
|
||
//
|
||
// We never found a fit so we'll return -1
|
||
//
|
||
|
||
return 0xffffffff;
|
||
}
|
||
|
||
|
||
ULONG
|
||
HalpFindSetBits (
|
||
IN PRTL_BITMAP BitMapHeader,
|
||
IN ULONG NumberToFind,
|
||
IN ULONG HintIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure searches the specified bit map for the specified
|
||
contiguous region of set bits.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the previously initialized BitMap.
|
||
|
||
NumberToFind - Supplies the size of the contiguous region to find.
|
||
|
||
HintIndex - Supplies the index (zero based) of where we should start
|
||
the search from within the bitmap.
|
||
|
||
Return Value:
|
||
|
||
ULONG - Receives the starting index (zero based) of the contiguous
|
||
region of set bits found. If such a region cannot be found then
|
||
a -1 (i.e., 0xffffffff) is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG SizeOfBitMap;
|
||
ULONG SizeInBytes;
|
||
|
||
ULONG HintByte;
|
||
|
||
ULONG MainLoopIndex;
|
||
|
||
GET_BYTE_DECLARATIONS();
|
||
|
||
//
|
||
// To make the loops in our test run faster we'll extract the
|
||
// fields from the bitmap header
|
||
//
|
||
|
||
SizeOfBitMap = BitMapHeader->SizeOfBitMap;
|
||
SizeInBytes = (SizeOfBitMap + 7) / 8;
|
||
|
||
//
|
||
// Set any unused bits in the last byte so we won't count them. We do
|
||
// this by first checking if there is any odd bits in the last byte.
|
||
//
|
||
|
||
if ((SizeOfBitMap % 8) != 0) {
|
||
|
||
//
|
||
// The last byte has some odd bits so we'll set the high unused
|
||
// bits in the last byte to 0's
|
||
//
|
||
|
||
((PUCHAR)BitMapHeader->Buffer)[SizeInBytes - 1] &=
|
||
FillMask[SizeOfBitMap % 8];
|
||
}
|
||
|
||
//
|
||
// Calculate from the hint index where the hint byte is and set ourselves
|
||
// up to read the hint on the next call to GET_BYTE. To make the
|
||
// algorithm run fast we'll only honor hints down to the byte level of
|
||
// granularity. There is a possibility that we'll need to execute
|
||
// our main logic twice. Once to test from the hint byte to the end of
|
||
// the bitmap and the other to test from the start of the bitmap. First
|
||
// we need to make sure the Hint Index is within range.
|
||
//
|
||
|
||
if (HintIndex >= SizeOfBitMap) {
|
||
|
||
HintIndex = 0;
|
||
}
|
||
|
||
HintByte = HintIndex / 8;
|
||
|
||
for (MainLoopIndex = 0; MainLoopIndex < 2; MainLoopIndex += 1) {
|
||
|
||
ULONG StartByteIndex;
|
||
ULONG EndByteIndex;
|
||
|
||
//
|
||
// Check for the first time through the main loop, which indicates
|
||
// that we are going to start our search at our hint byte
|
||
//
|
||
|
||
if (MainLoopIndex == 0) {
|
||
|
||
StartByteIndex = HintByte;
|
||
EndByteIndex = SizeInBytes;
|
||
|
||
//
|
||
// This is the second time through the loop, make sure there is
|
||
// actually something to check before the hint byte
|
||
//
|
||
|
||
} else if (HintByte != 0) {
|
||
|
||
StartByteIndex = 0;
|
||
|
||
//
|
||
// The end index for the second time around is based on the
|
||
// number of bits we need to find. We need to use this inorder
|
||
// to take the case where the preceding byte to the hint byte
|
||
// is the start of our run, and the run includes the hint byte
|
||
// and some following bytes, based on the number of bits needed
|
||
// The computation is to take the number of bits needed minus
|
||
// 2 divided by 8 and then add 2. This will take in to account
|
||
// the worst possible case where we have one bit hanging off
|
||
// of each end byte, and all intervening bytes are all zero.
|
||
// We only need to add one in the following equation because
|
||
// HintByte is already counted.
|
||
//
|
||
|
||
if (NumberToFind < 2) {
|
||
|
||
EndByteIndex = HintByte;
|
||
|
||
} else {
|
||
|
||
EndByteIndex = HintByte + ((NumberToFind - 2) / 8) + 1;
|
||
|
||
//
|
||
// Make sure we don't overrun the end of the bitmap
|
||
//
|
||
|
||
if (EndByteIndex > SizeInBytes) {
|
||
|
||
EndByteIndex = SizeInBytes;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Otherwise we already did a complete loop through the bitmap
|
||
// so we should simply return -1 to say nothing was found
|
||
//
|
||
|
||
} else {
|
||
|
||
return 0xffffffff;
|
||
|
||
}
|
||
|
||
//
|
||
// Set ourselves up to get the next byte
|
||
//
|
||
|
||
GET_BYTE_INITIALIZATION(BitMapHeader, StartByteIndex);
|
||
|
||
//
|
||
// If the number of bits can only fit in 1 or 2 bytes (i.e., 9 bits or
|
||
// less) we do the following test case.
|
||
//
|
||
|
||
if (NumberToFind <= 9) {
|
||
|
||
ULONG CurrentBitIndex;
|
||
|
||
UCHAR PreviousByte;
|
||
UCHAR CurrentByte;
|
||
|
||
PreviousByte = 0x00;
|
||
|
||
//
|
||
// Examine all the bytes within our test range searching
|
||
// for a fit
|
||
//
|
||
|
||
for (CurrentBitIndex = StartByteIndex * 8;
|
||
CurrentBitIndex < EndByteIndex * 8;
|
||
CurrentBitIndex += 8) {
|
||
|
||
//
|
||
// Get the current byte
|
||
//
|
||
|
||
GET_BYTE( CurrentByte );
|
||
|
||
//
|
||
// Check to see if a single byte will satisfy the requirement
|
||
//
|
||
|
||
if ((ULONG)HalppBitSetAnywhere(CurrentByte) >= NumberToFind) {
|
||
|
||
UCHAR BitMask;
|
||
ULONG i;
|
||
|
||
//
|
||
// It all fits in a single byte, so calculate the bit
|
||
// number. We do this by taking a mask of the appropriate
|
||
// size and shifting it over until it fits. It fits when
|
||
// we can bitwise-and the current byte with the bit mask
|
||
// and get back the bit mask.
|
||
//
|
||
|
||
BitMask = FillMask[ NumberToFind ];
|
||
for (i = 0; (BitMask & CurrentByte) != BitMask; i += 1) {
|
||
|
||
BitMask <<= 1;
|
||
}
|
||
|
||
//
|
||
// return to our caller the located bit index, and the
|
||
// number that we found.
|
||
//
|
||
|
||
return CurrentBitIndex + i;
|
||
}
|
||
|
||
//
|
||
// The current byte does not satisfy our requirements so we'll
|
||
// check the previous and current byte together to see if
|
||
// we'll fit. To check uses the high part of the previous
|
||
// byte and low part of the current byte.
|
||
//
|
||
|
||
if (((ULONG)HalppBitsSetHigh(PreviousByte) +
|
||
(ULONG)HalppBitsSetLow(CurrentByte)) >= NumberToFind) {
|
||
|
||
ULONG StartingIndex;
|
||
|
||
//
|
||
// It all fits in these two bytes, so we can compute
|
||
// the starting index. This is done by taking the
|
||
// index of the current byte (bit 0) and subtracting the
|
||
// number of bits its takes to get to the first set
|
||
// high bit.
|
||
//
|
||
|
||
StartingIndex = CurrentBitIndex -
|
||
(LONG)HalppBitsSetHigh(PreviousByte);
|
||
|
||
//
|
||
// Now make sure the total size isn't beyond the bitmap
|
||
//
|
||
|
||
if ((StartingIndex + NumberToFind) <= SizeOfBitMap) {
|
||
|
||
return StartingIndex;
|
||
}
|
||
}
|
||
|
||
//
|
||
// For the next iteration through our loop we need to make
|
||
// the current byte into the previous byte, and go to the
|
||
// top of the loop again.
|
||
//
|
||
|
||
PreviousByte = CurrentByte;
|
||
|
||
} // end loop CurrentBitIndex
|
||
|
||
//
|
||
// The number to find is greater than 9 but if it is less than 15
|
||
// then we know it can be satisfied with at most 2 bytes, or 3 bytes
|
||
// if the middle byte (of the 3) is all ones.
|
||
//
|
||
|
||
} else if (NumberToFind < 15) {
|
||
|
||
ULONG CurrentBitIndex;
|
||
|
||
UCHAR PreviousPreviousByte;
|
||
UCHAR PreviousByte;
|
||
UCHAR CurrentByte;
|
||
|
||
PreviousPreviousByte = 0x00;
|
||
PreviousByte = 0x00;
|
||
|
||
//
|
||
// Examine all the bytes within our test range searching
|
||
// for a fit
|
||
//
|
||
|
||
for (CurrentBitIndex = StartByteIndex * 8;
|
||
CurrentBitIndex < EndByteIndex * 8;
|
||
CurrentBitIndex += 8) {
|
||
|
||
//
|
||
// Get the current byte
|
||
//
|
||
|
||
GET_BYTE( CurrentByte );
|
||
|
||
//
|
||
// Check to see if the Previous byte and current byte
|
||
// together satisfy the request.
|
||
//
|
||
|
||
if (((ULONG)HalppBitsSetHigh(PreviousByte) +
|
||
(ULONG)HalppBitsSetLow(CurrentByte)) >= NumberToFind) {
|
||
|
||
ULONG StartingIndex;
|
||
|
||
//
|
||
// It all fits in these two bytes, so we can compute
|
||
// the starting index. This is done by taking the
|
||
// index of the current byte (bit 0) and subtracting the
|
||
// number of bits its takes to get to the first set
|
||
// high bit.
|
||
//
|
||
|
||
StartingIndex = CurrentBitIndex -
|
||
(LONG)HalppBitsSetHigh(PreviousByte);
|
||
|
||
//
|
||
// Now make sure the total size isn't beyond the bitmap
|
||
//
|
||
|
||
if ((StartingIndex + NumberToFind) <= SizeOfBitMap) {
|
||
|
||
return StartingIndex;
|
||
}
|
||
}
|
||
|
||
//
|
||
// if the previous byte is all ones then maybe the
|
||
// request can be satisfied using the Previous Previous Byte
|
||
// Previous Byte, and the Current Byte.
|
||
//
|
||
|
||
if ((PreviousByte == 0xff)
|
||
|
||
&&
|
||
|
||
(((ULONG)HalppBitsSetHigh(PreviousPreviousByte) + 8 +
|
||
(ULONG)HalppBitsSetLow(CurrentByte)) >= NumberToFind)) {
|
||
|
||
ULONG StartingIndex;
|
||
|
||
//
|
||
// It all fits in these three bytes, so we can compute
|
||
// the starting index. This is done by taking the
|
||
// index of the previous byte (bit 0) and subtracting
|
||
// the number of bits its takes to get to the first
|
||
// set high bit.
|
||
//
|
||
|
||
StartingIndex = (CurrentBitIndex - 8) -
|
||
(LONG)HalppBitsSetHigh(PreviousPreviousByte);
|
||
|
||
//
|
||
// Now make sure the total size isn't beyond the bitmap
|
||
//
|
||
|
||
if ((StartingIndex + NumberToFind) <= SizeOfBitMap) {
|
||
|
||
return StartingIndex;
|
||
}
|
||
}
|
||
|
||
//
|
||
// For the next iteration through our loop we need to make
|
||
// the current byte into the previous byte, the previous
|
||
// byte into the previous previous byte, and go to the
|
||
// top of the loop again.
|
||
//
|
||
|
||
PreviousPreviousByte = PreviousByte;
|
||
PreviousByte = CurrentByte;
|
||
|
||
} // end loop CurrentBitIndex
|
||
|
||
//
|
||
// The number to find is greater than or equal to 15. This request
|
||
// has to have at least one byte of all ones to be satisfied
|
||
//
|
||
|
||
} else {
|
||
|
||
ULONG CurrentByteIndex;
|
||
|
||
UCHAR CurrentByte;
|
||
|
||
ULONG OneBytesNeeded;
|
||
ULONG OneBytesFound;
|
||
|
||
UCHAR StartOfRunByte;
|
||
LONG StartOfRunIndex;
|
||
|
||
//
|
||
// First precalculate how many one bytes we're going to need
|
||
//
|
||
|
||
OneBytesNeeded = (NumberToFind - 7) / 8;
|
||
|
||
//
|
||
// Indicate for the first time through our loop that we haven't
|
||
// found a one byte yet, and indicate that the start of the
|
||
// run is the byte just before the start byte index
|
||
//
|
||
|
||
OneBytesFound = 0;
|
||
StartOfRunByte = 0x00;
|
||
StartOfRunIndex = StartByteIndex - 1;
|
||
|
||
//
|
||
// Examine all the bytes in our test range searching for a fit
|
||
//
|
||
|
||
for (CurrentByteIndex = StartByteIndex;
|
||
CurrentByteIndex < EndByteIndex;
|
||
CurrentByteIndex += 1) {
|
||
|
||
//
|
||
// Get the current byte
|
||
//
|
||
|
||
GET_BYTE( CurrentByte );
|
||
|
||
//
|
||
// If the number of zero bytes fits our minimum requirements
|
||
// then we can do the additional test to see if we
|
||
// actually found a fit
|
||
//
|
||
|
||
if ((OneBytesFound >= OneBytesNeeded)
|
||
|
||
&&
|
||
|
||
((ULONG)HalppBitsSetHigh(StartOfRunByte) + OneBytesFound*8 +
|
||
(ULONG)HalppBitsSetLow(CurrentByte)) >= NumberToFind) {
|
||
|
||
ULONG StartingIndex;
|
||
|
||
//
|
||
// It all fits in these bytes, so we can compute
|
||
// the starting index. This is done by taking the
|
||
// StartOfRunIndex times 8 and adding the number of bits
|
||
// it takes to get to the first set high bit.
|
||
//
|
||
|
||
StartingIndex = (StartOfRunIndex * 8) +
|
||
(8 - (LONG)HalppBitsSetHigh(StartOfRunByte));
|
||
|
||
//
|
||
// Now make sure the total size isn't beyond the bitmap
|
||
//
|
||
|
||
if ((StartingIndex + NumberToFind) <= SizeOfBitMap) {
|
||
|
||
return StartingIndex;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Check to see if the byte is all ones and increment
|
||
// the number of one bytes found
|
||
//
|
||
|
||
if (CurrentByte == 0xff) {
|
||
|
||
OneBytesFound += 1;
|
||
|
||
//
|
||
// The byte isn't all ones so we need to start over again
|
||
// looking for one bytes.
|
||
//
|
||
|
||
} else {
|
||
|
||
OneBytesFound = 0;
|
||
StartOfRunByte = CurrentByte;
|
||
StartOfRunIndex = CurrentByteIndex;
|
||
}
|
||
|
||
} // end loop CurrentByteIndex
|
||
}
|
||
}
|
||
|
||
//
|
||
// We never found a fit so we'll return -1
|
||
//
|
||
|
||
return 0xffffffff;
|
||
}
|
||
|
||
|
||
ULONG
|
||
HalpFindClearBitsAndSet (
|
||
IN PRTL_BITMAP BitMapHeader,
|
||
IN ULONG NumberToFind,
|
||
IN ULONG HintIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure searches the specified bit map for the specified
|
||
contiguous region of clear bits, sets the bits and returns the
|
||
number of bits found, and the starting bit number which was clear
|
||
then set.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the previously initialized BitMap.
|
||
|
||
NumberToFind - Supplies the size of the contiguous region to find.
|
||
|
||
HintIndex - Supplies the index (zero based) of where we should start
|
||
the search from within the bitmap.
|
||
|
||
Return Value:
|
||
|
||
ULONG - Receives the starting index (zero based) of the contiguous
|
||
region found. If such a region cannot be located a -1 (i.e.,
|
||
0xffffffff) is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG StartingIndex;
|
||
|
||
//
|
||
// First look for a run of clear bits that equals the size requested
|
||
//
|
||
|
||
StartingIndex = HalpFindClearBits( BitMapHeader,
|
||
NumberToFind,
|
||
HintIndex );
|
||
|
||
//DbgPrint("FindClearBits %08lx, ", NumberToFind);
|
||
//DbgPrint("%08lx", StartingIndex);
|
||
//DumpBitMap(BitMapHeader);
|
||
|
||
if (StartingIndex != 0xffffffff) {
|
||
|
||
//
|
||
// We found a large enough run of clear bits so now set them
|
||
//
|
||
|
||
HalpSetBits( BitMapHeader, StartingIndex, NumberToFind );
|
||
}
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
return StartingIndex;
|
||
|
||
}
|
||
|
||
|
||
ULONG
|
||
HalpFindSetBitsAndClear (
|
||
IN PRTL_BITMAP BitMapHeader,
|
||
IN ULONG NumberToFind,
|
||
IN ULONG HintIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure searches the specified bit map for the specified
|
||
contiguous region of set bits, clears the bits and returns the
|
||
number of bits found and the starting bit number which was set then
|
||
clear.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the previously initialized BitMap.
|
||
|
||
NumberToFind - Supplies the size of the contiguous region to find.
|
||
|
||
HintIndex - Supplies the index (zero based) of where we should start
|
||
the search from within the bitmap.
|
||
|
||
Return Value:
|
||
|
||
ULONG - Receives the starting index (zero based) of the contiguous
|
||
region found. If such a region cannot be located a -1 (i.e.,
|
||
0xffffffff) is returned.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG StartingIndex;
|
||
|
||
//
|
||
// First look for a run of set bits that equals the size requested
|
||
//
|
||
|
||
if ((StartingIndex = HalpFindSetBits( BitMapHeader,
|
||
NumberToFind,
|
||
HintIndex )) != 0xffffffff) {
|
||
|
||
//
|
||
// We found a large enough run of set bits so now clear them
|
||
//
|
||
|
||
HalpClearBits( BitMapHeader, StartingIndex, NumberToFind );
|
||
}
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
return StartingIndex;
|
||
}
|
||
|
||
|
||
VOID
|
||
HalpClearBits (
|
||
IN PRTL_BITMAP BitMapHeader,
|
||
IN ULONG StartingIndex,
|
||
IN ULONG NumberToClear
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure clears the specified range of bits within the
|
||
specified bit map.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the previously initialized Bit Map.
|
||
|
||
StartingIndex - Supplies the index (zero based) of the first bit to clear.
|
||
|
||
NumberToClear - Supplies the number of bits to clear.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG BitOffset;
|
||
PULONG CurrentLong;
|
||
|
||
//DbgPrint("ClearBits %08lx, ", NumberToClear);
|
||
//DbgPrint("%08lx", StartingIndex);
|
||
|
||
ASSERT( StartingIndex + NumberToClear <= BitMapHeader->SizeOfBitMap );
|
||
|
||
//
|
||
// Special case the situation where the number of bits to clear is
|
||
// zero. Turn this into a noop.
|
||
//
|
||
|
||
if (NumberToClear == 0) {
|
||
|
||
return;
|
||
}
|
||
|
||
BitOffset = StartingIndex % 32;
|
||
|
||
//
|
||
// Get a pointer to the first longword that needs to be zeroed out
|
||
//
|
||
|
||
CurrentLong = &BitMapHeader->Buffer[ StartingIndex / 32 ];
|
||
|
||
//
|
||
// Check if we can only need to clear out one longword.
|
||
//
|
||
|
||
if ((BitOffset + NumberToClear) <= 32) {
|
||
|
||
//
|
||
// To build a mask of bits to clear we shift left to get the number
|
||
// of bits we're clearing and then shift right to put it in position.
|
||
// We'll typecast the right shift to ULONG to make sure it doesn't
|
||
// do a sign extend.
|
||
//
|
||
|
||
*CurrentLong &= ~LeftShiftUlong(RightShiftUlong(((ULONG)0xFFFFFFFF),(32 - NumberToClear)),
|
||
BitOffset);
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
//DumpBitMap(BitMapHeader);
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
// We can clear out to the end of the first longword so we'll
|
||
// do that right now.
|
||
//
|
||
|
||
*CurrentLong &= ~LeftShiftUlong(0xFFFFFFFF, BitOffset);
|
||
|
||
//
|
||
// And indicate what the next longword to clear is and how many
|
||
// bits are left to clear
|
||
//
|
||
|
||
CurrentLong += 1;
|
||
NumberToClear -= 32 - BitOffset;
|
||
|
||
//
|
||
// The bit position is now long aligned, so we can continue
|
||
// clearing longwords until the number to clear is less than 32
|
||
//
|
||
|
||
while (NumberToClear >= 32) {
|
||
|
||
*CurrentLong = 0;
|
||
CurrentLong += 1;
|
||
NumberToClear -= 32;
|
||
}
|
||
|
||
//
|
||
// And now we can clear the remaining bits, if there are any, in the
|
||
// last longword
|
||
//
|
||
|
||
if (NumberToClear > 0) {
|
||
|
||
*CurrentLong &= LeftShiftUlong(0xFFFFFFFF, NumberToClear);
|
||
}
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
//DumpBitMap(BitMapHeader);
|
||
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
HalpSetBits (
|
||
IN PRTL_BITMAP BitMapHeader,
|
||
IN ULONG StartingIndex,
|
||
IN ULONG NumberToSet
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure sets the specified range of bits within the
|
||
specified bit map.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the previously initialied BitMap.
|
||
|
||
StartingIndex - Supplies the index (zero based) of the first bit to set.
|
||
|
||
NumberToSet - Supplies the number of bits to set.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
ULONG BitOffset;
|
||
PULONG CurrentLong;
|
||
|
||
//DbgPrint("SetBits %08lx, ", NumberToSet);
|
||
//DbgPrint("%08lx", StartingIndex);
|
||
|
||
ASSERT( StartingIndex + NumberToSet <= BitMapHeader->SizeOfBitMap );
|
||
|
||
//
|
||
// Special case the situation where the number of bits to set is
|
||
// zero. Turn this into a noop.
|
||
//
|
||
|
||
if (NumberToSet == 0) {
|
||
|
||
return;
|
||
}
|
||
|
||
BitOffset = StartingIndex % 32;
|
||
|
||
//
|
||
// Get a pointer to the first longword that needs to be set
|
||
//
|
||
|
||
CurrentLong = &BitMapHeader->Buffer[ StartingIndex / 32 ];
|
||
|
||
//
|
||
// Check if we can only need to set one longword.
|
||
//
|
||
|
||
if ((BitOffset + NumberToSet) <= 32) {
|
||
|
||
//
|
||
// To build a mask of bits to set we shift left to get the number
|
||
// of bits we're setting and then shift right to put it in position.
|
||
// We'll typecast the right shift to ULONG to make sure it doesn't
|
||
// do a sign extend.
|
||
//
|
||
|
||
*CurrentLong |= LeftShiftUlong(RightShiftUlong(((ULONG)0xFFFFFFFF),(32 - NumberToSet)),
|
||
BitOffset);
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
//DumpBitMap(BitMapHeader);
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
// We can set bits out to the end of the first longword so we'll
|
||
// do that right now.
|
||
//
|
||
|
||
*CurrentLong |= LeftShiftUlong(0xFFFFFFFF, BitOffset);
|
||
|
||
//
|
||
// And indicate what the next longword to set is and how many
|
||
// bits are left to set
|
||
//
|
||
|
||
CurrentLong += 1;
|
||
NumberToSet -= 32 - BitOffset;
|
||
|
||
//
|
||
// The bit position is now long aligned, so we can continue
|
||
// setting longwords until the number to set is less than 32
|
||
//
|
||
|
||
while (NumberToSet >= 32) {
|
||
|
||
*CurrentLong = 0xffffffff;
|
||
CurrentLong += 1;
|
||
NumberToSet -= 32;
|
||
}
|
||
|
||
//
|
||
// And now we can set the remaining bits, if there are any, in the
|
||
// last longword
|
||
//
|
||
|
||
if (NumberToSet > 0) {
|
||
|
||
*CurrentLong |= ~LeftShiftUlong(0xFFFFFFFF, NumberToSet);
|
||
}
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
//DumpBitMap(BitMapHeader);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
ULONG
|
||
HalpFindLongestRunClear (
|
||
IN PRTL_BITMAP BitMapHeader,
|
||
OUT PULONG StartingIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure finds the largest contiguous range of clear bits
|
||
within the specified bit map.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the previously initialized BitMap.
|
||
|
||
StartingIndex - Receives the index (zero based) of the first run
|
||
equal to the longest run of clear bits in the BitMap.
|
||
|
||
Return Value:
|
||
|
||
ULONG - Receives the number of bits contained in the largest contiguous
|
||
run of clear bits.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG SizeOfBitMap;
|
||
ULONG SizeInBytes;
|
||
|
||
ULONG LongestRunSize;
|
||
ULONG LongestRunIndex;
|
||
|
||
ULONG CurrentRunSize;
|
||
ULONG CurrentRunIndex;
|
||
ULONG CurrentByteIndex;
|
||
UCHAR CurrentByte;
|
||
|
||
GET_BYTE_DECLARATIONS();
|
||
|
||
//
|
||
// Reference the bitmap header to make the loop run faster
|
||
//
|
||
|
||
SizeOfBitMap = BitMapHeader->SizeOfBitMap;
|
||
SizeInBytes = (SizeOfBitMap + 7) / 8;
|
||
|
||
//
|
||
// Set any unused bits in the last byte so we won't count them. We do
|
||
// this by first checking if there is any odd bits in the last byte.
|
||
//
|
||
|
||
if ((SizeOfBitMap % 8) != 0) {
|
||
|
||
//
|
||
// The last byte has some odd bits so we'll set the high unused
|
||
// bits in the last byte to 1's
|
||
//
|
||
|
||
((PUCHAR)BitMapHeader->Buffer)[SizeInBytes - 1] |=
|
||
ZeroMask[SizeOfBitMap % 8];
|
||
}
|
||
|
||
//
|
||
// Set it up so we can the use GET_BYTE macro
|
||
//
|
||
|
||
GET_BYTE_INITIALIZATION( BitMapHeader, 0);
|
||
|
||
//
|
||
// Set our longest and current run variables
|
||
//
|
||
|
||
LongestRunSize = 0;
|
||
LongestRunIndex = 0;
|
||
|
||
CurrentRunSize = 0;
|
||
CurrentRunIndex = 0;
|
||
|
||
//
|
||
// Examine every byte in the BitMap
|
||
//
|
||
|
||
for (CurrentByteIndex = 0;
|
||
CurrentByteIndex < SizeInBytes;
|
||
CurrentByteIndex += 1) {
|
||
|
||
GET_BYTE( CurrentByte );
|
||
|
||
//
|
||
// If the current byte is not all zeros we need to
|
||
// (1) check if the current run is big enough to supercede the
|
||
// longest run, and (2) check if the current byte inside of
|
||
// itself can supercede the longest run, and (3) start a new
|
||
// current run
|
||
//
|
||
|
||
if (CurrentByte != 0x00) {
|
||
|
||
UCHAR Temp;
|
||
|
||
//
|
||
// Compute the final size of the current run
|
||
//
|
||
|
||
CurrentRunSize += HalppBitsClearLow[CurrentByte];
|
||
|
||
//
|
||
// Check if the current run is larger than the longest run that
|
||
// we've found so far
|
||
//
|
||
|
||
if (CurrentRunSize > LongestRunSize) {
|
||
|
||
LongestRunSize = CurrentRunSize;
|
||
LongestRunIndex = CurrentRunIndex;
|
||
}
|
||
|
||
//
|
||
// The next run starts with the remaining clear bits in the
|
||
// current byte. We set this up before we check inside the
|
||
// current byte for a longer run, because the latter test
|
||
// might require extra work.
|
||
//
|
||
|
||
CurrentRunSize = HalppBitsClearHigh[ CurrentByte ];
|
||
CurrentRunIndex = (CurrentByteIndex * 8) + (8 - CurrentRunSize);
|
||
|
||
//
|
||
// Check if the current byte contains a run inside of it that
|
||
// is both greater than the longest run size, and the current
|
||
// run size. But we'll only both with this test if the
|
||
// longest run size, and current run size are both less than 8.
|
||
//
|
||
|
||
if ((LongestRunSize < 8) && (CurrentRunSize < 8) &&
|
||
((ULONG)(Temp = HalppBitsClearAnywhere[CurrentByte]) > LongestRunSize) &&
|
||
((ULONG)Temp > CurrentRunSize)) {
|
||
|
||
UCHAR BitMask;
|
||
ULONG i;
|
||
|
||
//
|
||
// Somewhere in the current byte is a run longer than the
|
||
// longest run, or the current run. All we need to do now
|
||
// is find the index for this new longest run.
|
||
//
|
||
|
||
BitMask = FillMask[ Temp ];
|
||
|
||
for (i = 0; (BitMask & CurrentByte) != 0; i += 1) {
|
||
|
||
BitMask <<= 1;
|
||
}
|
||
|
||
LongestRunIndex = (CurrentByteIndex * 8) + i;
|
||
LongestRunSize = Temp;
|
||
}
|
||
|
||
//
|
||
// Otherwise the current byte is all zeros and
|
||
// we simply continue with the current run
|
||
//
|
||
|
||
} else {
|
||
|
||
CurrentRunSize += 8;
|
||
}
|
||
}
|
||
|
||
//
|
||
// See if we finished looking over the bitmap with an open current
|
||
// run that is longer than the longest saved run
|
||
//
|
||
|
||
if (CurrentRunSize > LongestRunSize) {
|
||
|
||
LongestRunSize = CurrentRunSize;
|
||
LongestRunIndex = CurrentRunIndex;
|
||
}
|
||
|
||
//
|
||
// Set our output variables and return to our caller
|
||
//
|
||
|
||
*StartingIndex = LongestRunIndex;
|
||
return LongestRunSize;
|
||
}
|
||
|
||
|
||
ULONG
|
||
HalpFindLongestRunSet (
|
||
IN PRTL_BITMAP BitMapHeader,
|
||
OUT PULONG StartingIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure finds the largest contiguous range of set bits
|
||
within the specified bit map.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the previously initialized BitMap.
|
||
|
||
StartingIndex - Receives the index (zero based) of the first run
|
||
equal to the longest run of set bits in the BitMap.
|
||
|
||
Return Value:
|
||
|
||
ULONG - Receives the number of bits contained in the largest contiguous
|
||
run of set bits.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG SizeOfBitMap;
|
||
ULONG SizeInBytes;
|
||
|
||
ULONG LongestRunSize;
|
||
ULONG LongestRunIndex;
|
||
|
||
ULONG CurrentRunSize;
|
||
ULONG CurrentRunIndex;
|
||
ULONG CurrentByteIndex;
|
||
UCHAR CurrentByte;
|
||
|
||
GET_BYTE_DECLARATIONS();
|
||
|
||
//
|
||
// Reference the bitmap header to make the loop run faster
|
||
//
|
||
|
||
SizeOfBitMap = BitMapHeader->SizeOfBitMap;
|
||
SizeInBytes = (SizeOfBitMap + 7) / 8;
|
||
|
||
//
|
||
// Set any unused bits in the last byte so we won't count them. We do
|
||
// this by first checking if there is any odd bits in the last byte.
|
||
//
|
||
|
||
if ((SizeOfBitMap % 8) != 0) {
|
||
|
||
//
|
||
// The last byte has some odd bits so we'll set the high unused
|
||
// bits in the last byte to 0's
|
||
//
|
||
|
||
((PUCHAR)BitMapHeader->Buffer)[SizeInBytes - 1] &=
|
||
FillMask[SizeOfBitMap % 8];
|
||
}
|
||
|
||
//
|
||
// Set it up so we can the use GET_BYTE macro
|
||
//
|
||
|
||
GET_BYTE_INITIALIZATION( BitMapHeader, 0);
|
||
|
||
//
|
||
// Set our longest and current run variables
|
||
//
|
||
|
||
LongestRunSize = 0;
|
||
LongestRunIndex = 0;
|
||
|
||
CurrentRunSize = 0;
|
||
CurrentRunIndex = 0;
|
||
|
||
//
|
||
// Examine every byte in the BitMap
|
||
//
|
||
|
||
for (CurrentByteIndex = 0;
|
||
CurrentByteIndex < SizeInBytes;
|
||
CurrentByteIndex += 1) {
|
||
|
||
GET_BYTE( CurrentByte );
|
||
|
||
//
|
||
// If the current byte is not all ones we need to
|
||
// (1) check if the current run is big enough to supercede the
|
||
// longest run, and (2) check if the current byte inside of
|
||
// itself can supercede the longest run, and (3) start a new
|
||
// current run
|
||
//
|
||
|
||
if (CurrentByte != 0xff) {
|
||
|
||
UCHAR Temp;
|
||
|
||
//
|
||
// Compute the final size of the current run
|
||
//
|
||
|
||
CurrentRunSize += HalppBitsSetLow(CurrentByte);
|
||
|
||
//
|
||
// Check if the current run is larger than the longest run that
|
||
// we've found so far
|
||
//
|
||
|
||
if (CurrentRunSize > LongestRunSize) {
|
||
|
||
LongestRunSize = CurrentRunSize;
|
||
LongestRunIndex = CurrentRunIndex;
|
||
}
|
||
|
||
//
|
||
// The next run starts with the remaining set bits in the
|
||
// current byte. We set this up before we check inside the
|
||
// current byte for a longer run, because the latter test
|
||
// might require extra work.
|
||
//
|
||
|
||
CurrentRunSize = HalppBitsSetHigh( CurrentByte );
|
||
CurrentRunIndex = (CurrentByteIndex * 8) + (8 - CurrentRunSize);
|
||
|
||
//
|
||
// Check if the current byte contains a run inside of it that
|
||
// is both greater than the longest run size, and the current
|
||
// run size. But we'll only both with this test if the
|
||
// longest run size, and current run size are both less than 8.
|
||
//
|
||
|
||
if ((LongestRunSize < 8) && (CurrentRunSize < 8) &&
|
||
((ULONG)(Temp = HalppBitSetAnywhere(CurrentByte)) > LongestRunSize) &&
|
||
((ULONG)Temp > CurrentRunSize)) {
|
||
|
||
UCHAR BitMask;
|
||
ULONG i;
|
||
|
||
//
|
||
// Somewhere in the current byte is a run longer than the
|
||
// longest run, or the current run. All we need to do now
|
||
// is find the index for this new longest run.
|
||
//
|
||
|
||
BitMask = FillMask[ Temp ];
|
||
|
||
for (i = 0; (BitMask & CurrentByte) != BitMask; i += 1) {
|
||
|
||
BitMask <<= 1;
|
||
}
|
||
|
||
LongestRunIndex = (CurrentByteIndex * 8) + i;
|
||
LongestRunSize = Temp;
|
||
}
|
||
|
||
//
|
||
// Otherwise the current byte is all ones and
|
||
// we simply continue with the current run
|
||
//
|
||
|
||
} else {
|
||
|
||
CurrentRunSize += 8;
|
||
}
|
||
}
|
||
|
||
//
|
||
// See if we finished looking over the bitmap with an open current
|
||
// run that is longer than the longest saved run
|
||
//
|
||
|
||
if (CurrentRunSize > LongestRunSize) {
|
||
|
||
LongestRunSize = CurrentRunSize;
|
||
LongestRunIndex = CurrentRunIndex;
|
||
}
|
||
|
||
//
|
||
// Set our output variables and return to our caller
|
||
//
|
||
|
||
*StartingIndex = LongestRunIndex;
|
||
return LongestRunSize;
|
||
}
|
||
|
||
|
||
ULONG
|
||
HalpFindFirstRunClear (
|
||
IN PRTL_BITMAP BitMapHeader,
|
||
OUT PULONG StartingIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure finds the first contiguous range of clear bits
|
||
within the specified bit map.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the previously initialized BitMap.
|
||
|
||
StartingIndex - Receives the index (zero based) of the first run
|
||
equal to the longest run of clear bits in the BitMap.
|
||
|
||
Return Value:
|
||
|
||
ULONG - Receives the number of bits contained in the first contiguous
|
||
run of clear bits.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG SizeOfBitMap;
|
||
ULONG SizeInBytes;
|
||
|
||
ULONG CurrentRunSize;
|
||
ULONG CurrentRunIndex;
|
||
ULONG CurrentByteIndex;
|
||
UCHAR CurrentByte;
|
||
|
||
GET_BYTE_DECLARATIONS();
|
||
|
||
//
|
||
// Reference the bitmap header to make the loop run faster
|
||
//
|
||
|
||
SizeOfBitMap = BitMapHeader->SizeOfBitMap;
|
||
SizeInBytes = (SizeOfBitMap + 7) / 8;
|
||
|
||
//
|
||
// Set any unused bits in the last byte so we won't count them. We do
|
||
// this by first checking if there is any odd bits in the last byte.
|
||
//
|
||
|
||
if ((SizeOfBitMap % 8) != 0) {
|
||
|
||
//
|
||
// The last byte has some odd bits so we'll set the high unused
|
||
// bits in the last byte to 1's
|
||
//
|
||
|
||
((PUCHAR)BitMapHeader->Buffer)[SizeInBytes - 1] |=
|
||
ZeroMask[SizeOfBitMap % 8];
|
||
|
||
}
|
||
|
||
//
|
||
// Set it up so we can the use GET_BYTE macro
|
||
//
|
||
|
||
GET_BYTE_INITIALIZATION( BitMapHeader, 0);
|
||
|
||
//
|
||
// Set our current run variables
|
||
//
|
||
|
||
CurrentRunSize = 0;
|
||
CurrentRunIndex = 0xffffffff;
|
||
|
||
//
|
||
// Examine every byte in the BitMap. We'll also break out of this
|
||
// loop if ever we finish off a run.
|
||
//
|
||
|
||
for (CurrentByteIndex = 0;
|
||
CurrentByteIndex < SizeInBytes;
|
||
CurrentByteIndex += 1) {
|
||
|
||
GET_BYTE( CurrentByte );
|
||
|
||
//
|
||
// If the current byte is all ones and the run size is zero then
|
||
// skip over this byte because we haven't found the start of a
|
||
// run yet.
|
||
//
|
||
|
||
if ((CurrentByte == 0xff) && (CurrentRunSize == 0)) {
|
||
|
||
NOTHING;
|
||
|
||
//
|
||
// See if the current byte is all zeros, because if it is then
|
||
// we simply continue with the current run
|
||
//
|
||
|
||
} else if (CurrentByte == 0x00) {
|
||
|
||
CurrentRunSize += 8;
|
||
|
||
if (CurrentRunIndex == 0xffffffff) {
|
||
|
||
CurrentRunIndex = (CurrentByteIndex * 8);
|
||
}
|
||
|
||
//
|
||
// Otherwise the current byte is not all zeros, so we need to
|
||
// (1) check if we have a current run, or (2) check if the
|
||
// current byte inside of itself is a run, or (3) start a
|
||
// current run.
|
||
//
|
||
// Check if we have a current run, we do that by checking
|
||
// if the low bits are clear.
|
||
//
|
||
|
||
} else if (CurrentRunSize != 0) {
|
||
|
||
CurrentRunSize += HalppBitsClearLow[CurrentByte];
|
||
break;
|
||
|
||
//
|
||
// Check if we have an internal run, we do that by checking
|
||
// if the high bits are not clear. This check actually cheats
|
||
// a bit in that the current byte might have an inside run
|
||
// but we'll skip over it because we can start a run at the
|
||
// end of the byte.
|
||
//
|
||
|
||
} else if (HalppBitsClearHigh[CurrentByte] == 0) {
|
||
|
||
UCHAR BitMask;
|
||
ULONG i;
|
||
|
||
ASSERT( HalppBitsClearAnywhere[CurrentByte] != 0 );
|
||
|
||
CurrentRunSize = HalppBitsClearAnywhere[CurrentByte];
|
||
|
||
//
|
||
// Somewhere in the current byte is a run. All we need to do now
|
||
// is find the index for this new run.
|
||
//
|
||
|
||
BitMask = FillMask[ CurrentRunSize ];
|
||
|
||
for (i = 0; (BitMask & CurrentByte) != 0; i += 1) {
|
||
|
||
BitMask <<= 1;
|
||
}
|
||
|
||
CurrentRunIndex = (CurrentByteIndex * 8) + i;
|
||
break;
|
||
|
||
//
|
||
// Otherwise we start a new current run. It starts with the
|
||
// remaining clear bits in the current byte.
|
||
//
|
||
|
||
} else {
|
||
|
||
CurrentRunSize = HalppBitsClearHigh[ CurrentByte ];
|
||
CurrentRunIndex = (CurrentByteIndex * 8) + (8 - CurrentRunSize);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Set our output variables and return to our caller
|
||
//
|
||
|
||
*StartingIndex = CurrentRunIndex;
|
||
return CurrentRunSize;
|
||
}
|
||
|
||
|
||
ULONG
|
||
HalpFindFirstRunSet (
|
||
IN PRTL_BITMAP BitMapHeader,
|
||
OUT PULONG StartingIndex
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure finds the first contiguous range of set bits
|
||
within the specified bit map.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the previously initialized BitMap.
|
||
|
||
StartingIndex - Receives the index (zero based) of the first run
|
||
equal to the longest run of set bits in the BitMap.
|
||
|
||
Return Value:
|
||
|
||
ULONG - Receives the number of bits contained in the largest contiguous
|
||
run of set bits.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG SizeOfBitMap;
|
||
ULONG SizeInBytes;
|
||
|
||
ULONG CurrentRunSize;
|
||
ULONG CurrentRunIndex;
|
||
ULONG CurrentByteIndex;
|
||
UCHAR CurrentByte;
|
||
|
||
GET_BYTE_DECLARATIONS();
|
||
|
||
//
|
||
// Reference the bitmap header to make the loop run faster
|
||
//
|
||
|
||
SizeOfBitMap = BitMapHeader->SizeOfBitMap;
|
||
SizeInBytes = (SizeOfBitMap + 7) / 8;
|
||
|
||
//
|
||
// Set any unused bits in the last byte so we won't count them. We do
|
||
// this by first checking if there is any odd bits in the last byte.
|
||
//
|
||
|
||
if ((SizeOfBitMap % 8) != 0) {
|
||
|
||
//
|
||
// The last byte has some odd bits so we'll set the high unused
|
||
// bits in the last byte to 0's
|
||
//
|
||
|
||
((PUCHAR)BitMapHeader->Buffer)[SizeInBytes - 1] &=
|
||
FillMask[SizeOfBitMap % 8];
|
||
}
|
||
|
||
//
|
||
// Set it up so we can the use GET_BYTE macro
|
||
//
|
||
|
||
GET_BYTE_INITIALIZATION( BitMapHeader, 0);
|
||
|
||
//
|
||
// Set our current run variables
|
||
//
|
||
|
||
CurrentRunSize = 0;
|
||
CurrentRunIndex = 0xffffffff;
|
||
|
||
//
|
||
// Examine every byte in the BitMap. We'll also break out of this
|
||
// loop if ever we finish off a run.
|
||
//
|
||
|
||
for (CurrentByteIndex = 0;
|
||
CurrentByteIndex < SizeInBytes;
|
||
CurrentByteIndex += 1) {
|
||
|
||
GET_BYTE( CurrentByte );
|
||
|
||
//
|
||
// If the current byte is all zeros and the run size is zero then
|
||
// skip over this byte because we haven't found the start of a
|
||
// run yet.
|
||
//
|
||
|
||
if ((CurrentByte == 0x00) && (CurrentRunSize == 0)) {
|
||
|
||
NOTHING;
|
||
|
||
//
|
||
// See if the current byte is all ones, because if it is then
|
||
// we simply continue with the current run
|
||
//
|
||
|
||
} else if (CurrentByte == 0xff) {
|
||
|
||
CurrentRunSize += 8;
|
||
|
||
if (CurrentRunIndex == 0xffffffff) {
|
||
|
||
CurrentRunIndex = (CurrentByteIndex * 8);
|
||
}
|
||
|
||
//
|
||
// Otherwise the current byte is not all ones, so we need to
|
||
// (1) check if we have the current run, or (2) check if the
|
||
// current byte inside of itself is a run, or (3) start a
|
||
// current run.
|
||
//
|
||
// Check if we have a current run, we do that by checking
|
||
// if the low bits are set.
|
||
//
|
||
|
||
} else if (CurrentRunSize != 0) {
|
||
|
||
CurrentRunSize += HalppBitsSetLow(CurrentByte);
|
||
break;
|
||
|
||
//
|
||
// Check if we have an internal run, we do that by checking
|
||
// if the high bits are not set. This check actually cheats
|
||
// a bit in that the current byte might have an inside run
|
||
// but we'll skip over it because we can start a run at the
|
||
// end of the byte.
|
||
//
|
||
|
||
} else if (HalppBitsSetHigh(CurrentByte) == 0) {
|
||
|
||
UCHAR BitMask;
|
||
ULONG i;
|
||
|
||
ASSERT( HalppBitSetAnywhere(CurrentByte) != 0 );
|
||
|
||
CurrentRunSize = HalppBitSetAnywhere(CurrentByte);
|
||
|
||
//
|
||
// Somewhere in the current byte is a run. All we need to do now
|
||
// is find the index for this new run.
|
||
//
|
||
|
||
BitMask = FillMask[ CurrentRunSize ];
|
||
|
||
for (i = 0; (BitMask & CurrentByte) != BitMask; i += 1) {
|
||
|
||
BitMask <<= 1;
|
||
}
|
||
|
||
CurrentRunIndex = (CurrentByteIndex * 8) + i;
|
||
break;
|
||
|
||
//
|
||
// Otherwise we start a new current run. It starts with the
|
||
// remaining set bits in the current byte.
|
||
//
|
||
|
||
} else {
|
||
|
||
CurrentRunSize = HalppBitsSetHigh( CurrentByte );
|
||
CurrentRunIndex = (CurrentByteIndex * 8) + (8 - CurrentRunSize);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Set our output variables and return to our caller
|
||
//
|
||
|
||
*StartingIndex = CurrentRunIndex;
|
||
return CurrentRunSize;
|
||
}
|
||
|
||
|
||
ULONG
|
||
HalpNumberOfClearBits (
|
||
IN PRTL_BITMAP BitMapHeader
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure counts and returns the number of clears bits within
|
||
the specified bitmap.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the previously initialized bitmap.
|
||
|
||
Return Value:
|
||
|
||
ULONG - The total number of clear bits in the bitmap
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG SizeOfBitMap;
|
||
ULONG SizeInBytes;
|
||
|
||
ULONG i;
|
||
UCHAR CurrentByte;
|
||
|
||
ULONG TotalClear;
|
||
|
||
GET_BYTE_DECLARATIONS();
|
||
|
||
//
|
||
// Reference the bitmap header to make the loop run faster
|
||
//
|
||
|
||
SizeOfBitMap = BitMapHeader->SizeOfBitMap;
|
||
SizeInBytes = (SizeOfBitMap + 7) / 8;
|
||
|
||
//
|
||
// Set any unused bits in the last byte so we don't count them. We
|
||
// do this by first checking if there are any odd bits in the last byte
|
||
//
|
||
|
||
if ((SizeOfBitMap % 8) != 0) {
|
||
|
||
//
|
||
// The last byte has some odd bits so we'll set the high unused
|
||
// bits in the last byte to 1's
|
||
//
|
||
|
||
((PUCHAR)BitMapHeader->Buffer)[SizeInBytes - 1] |=
|
||
ZeroMask[SizeOfBitMap % 8];
|
||
}
|
||
|
||
//
|
||
// Set if up so we can use the GET_BYTE macro
|
||
//
|
||
|
||
GET_BYTE_INITIALIZATION( BitMapHeader, 0 );
|
||
|
||
//
|
||
// Examine every byte in the bitmap
|
||
//
|
||
|
||
TotalClear = 0;
|
||
for (i = 0; i < SizeInBytes; i += 1) {
|
||
|
||
GET_BYTE( CurrentByte );
|
||
|
||
TotalClear += HalppBitsClearTotal[CurrentByte];
|
||
}
|
||
|
||
return TotalClear;
|
||
}
|
||
|
||
|
||
ULONG
|
||
HalpNumberOfSetBits (
|
||
IN PRTL_BITMAP BitMapHeader
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure counts and returns the number of set bits within
|
||
the specified bitmap.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the previously initialized bitmap.
|
||
|
||
Return Value:
|
||
|
||
ULONG - The total number of set bits in the bitmap
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG SizeOfBitMap;
|
||
ULONG SizeInBytes;
|
||
|
||
ULONG i;
|
||
UCHAR CurrentByte;
|
||
|
||
ULONG TotalSet;
|
||
|
||
GET_BYTE_DECLARATIONS();
|
||
|
||
//
|
||
// Reference the bitmap header to make the loop run faster
|
||
//
|
||
|
||
SizeOfBitMap = BitMapHeader->SizeOfBitMap;
|
||
SizeInBytes = (SizeOfBitMap + 7) / 8;
|
||
|
||
//
|
||
// Clear any unused bits in the last byte so we don't count them. We
|
||
// do this by first checking if there are any odd bits in the last byte
|
||
//
|
||
|
||
if ((SizeOfBitMap % 8) != 0) {
|
||
|
||
//
|
||
// The last byte has some odd bits so we'll set the high unused
|
||
// bits in the last byte to 0's
|
||
//
|
||
|
||
((PUCHAR)BitMapHeader->Buffer)[SizeInBytes - 1] &=
|
||
FillMask[SizeOfBitMap % 8];
|
||
}
|
||
|
||
//
|
||
// Set if up so we can use the GET_BYTE macro
|
||
//
|
||
|
||
GET_BYTE_INITIALIZATION( BitMapHeader, 0 );
|
||
|
||
//
|
||
// Examine every byte in the bitmap
|
||
//
|
||
|
||
TotalSet = 0;
|
||
for (i = 0; i < SizeInBytes; i += 1) {
|
||
|
||
GET_BYTE( CurrentByte );
|
||
|
||
TotalSet += HalppBitsSetTotal(CurrentByte);
|
||
}
|
||
|
||
return TotalSet;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
HalpAreBitsClear (
|
||
IN PRTL_BITMAP BitMapHeader,
|
||
IN ULONG StartingIndex,
|
||
IN ULONG Length
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure determines if the range of specified bits are all clear.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the previously initialized bitmap.
|
||
|
||
StartingIndex - Supplies the starting bit index to examine
|
||
|
||
Length - Supplies the number of bits to examine
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE if the specified bits in the bitmap are all clear, and
|
||
FALSE if any are set or if the range is outside the bitmap or if
|
||
Length is zero.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG SizeOfBitMap;
|
||
ULONG SizeInBytes;
|
||
|
||
ULONG EndingIndex;
|
||
|
||
ULONG StartingByte;
|
||
ULONG EndingByte;
|
||
|
||
ULONG StartingOffset;
|
||
ULONG EndingOffset;
|
||
|
||
ULONG i;
|
||
UCHAR Byte;
|
||
|
||
GET_BYTE_DECLARATIONS();
|
||
|
||
//
|
||
// To make the loops in our test run faster we'll extract the fields
|
||
// from the bitmap header
|
||
//
|
||
|
||
SizeOfBitMap = BitMapHeader->SizeOfBitMap;
|
||
SizeInBytes = (SizeOfBitMap + 7) / 8;
|
||
|
||
//
|
||
// First make sure that the specified range is contained within the
|
||
// bitmap, and the length is not zero.
|
||
//
|
||
|
||
if ((StartingIndex + Length > SizeOfBitMap) || (Length == 0)) {
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Compute the ending index, starting and ending byte, and the starting
|
||
// and ending offset within each byte
|
||
//
|
||
|
||
EndingIndex = StartingIndex + Length - 1;
|
||
|
||
StartingByte = StartingIndex / 8;
|
||
EndingByte = EndingIndex / 8;
|
||
|
||
StartingOffset = StartingIndex % 8;
|
||
EndingOffset = EndingIndex % 8;
|
||
|
||
//
|
||
// Set ourselves up to get the next byte
|
||
//
|
||
|
||
GET_BYTE_INITIALIZATION( BitMapHeader, StartingByte );
|
||
|
||
//
|
||
// Special case the situation where the starting byte and ending
|
||
// byte are one in the same
|
||
//
|
||
|
||
if (StartingByte == EndingByte) {
|
||
|
||
//
|
||
// Get the single byte we are to look at
|
||
//
|
||
|
||
GET_BYTE( Byte );
|
||
|
||
//
|
||
// Now we compute the mask of bits we're after and then AND it with
|
||
// the byte. If it is zero then the bits in question are all clear
|
||
// otherwise at least one of them is set.
|
||
//
|
||
|
||
if ((ZeroMask[StartingOffset] & FillMask[EndingOffset+1] & Byte) == 0) {
|
||
|
||
return TRUE;
|
||
|
||
} else {
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Get the first byte that we're after, and then
|
||
// compute the mask of bits we're after for the first byte then
|
||
// AND it with the byte itself.
|
||
//
|
||
|
||
GET_BYTE( Byte );
|
||
|
||
if ((ZeroMask[StartingOffset] & Byte) != 0) {
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Now for every whole byte inbetween read in the byte,
|
||
// and make sure it is all zeros
|
||
//
|
||
|
||
for (i = StartingByte+1; i < EndingByte; i += 1) {
|
||
|
||
GET_BYTE( Byte );
|
||
|
||
if (Byte != 0) {
|
||
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Get the last byte we're after, and then
|
||
// compute the mask of bits we're after for the last byte then
|
||
// AND it with the byte itself.
|
||
//
|
||
|
||
GET_BYTE( Byte );
|
||
|
||
if ((FillMask[EndingOffset+1] & Byte) != 0) {
|
||
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
HalpAreBitsSet (
|
||
IN PRTL_BITMAP BitMapHeader,
|
||
IN ULONG StartingIndex,
|
||
IN ULONG Length
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This procedure determines if the range of specified bits are all set.
|
||
|
||
Arguments:
|
||
|
||
BitMapHeader - Supplies a pointer to the previously initialized bitmap.
|
||
|
||
StartingIndex - Supplies the starting bit index to examine
|
||
|
||
Length - Supplies the number of bits to examine
|
||
|
||
Return Value:
|
||
|
||
BOOLEAN - TRUE if the specified bits in the bitmap are all set, and
|
||
FALSE if any are clear or if the range is outside the bitmap or if
|
||
Length is zero.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG SizeOfBitMap;
|
||
ULONG SizeInBytes;
|
||
|
||
ULONG EndingIndex;
|
||
|
||
ULONG StartingByte;
|
||
ULONG EndingByte;
|
||
|
||
ULONG StartingOffset;
|
||
ULONG EndingOffset;
|
||
|
||
ULONG i;
|
||
UCHAR Byte;
|
||
|
||
GET_BYTE_DECLARATIONS();
|
||
|
||
//
|
||
// To make the loops in our test run faster we'll extract the fields
|
||
// from the bitmap header
|
||
//
|
||
|
||
SizeOfBitMap = BitMapHeader->SizeOfBitMap;
|
||
SizeInBytes = (SizeOfBitMap + 7) / 8;
|
||
|
||
//
|
||
// First make sure that the specified range is contained within the
|
||
// bitmap, and the length is not zero.
|
||
//
|
||
|
||
if ((StartingIndex + Length > SizeOfBitMap) || (Length == 0)) {
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Compute the ending index, starting and ending byte, and the starting
|
||
// and ending offset within each byte
|
||
//
|
||
|
||
EndingIndex = StartingIndex + Length - 1;
|
||
|
||
StartingByte = StartingIndex / 8;
|
||
EndingByte = EndingIndex / 8;
|
||
|
||
StartingOffset = StartingIndex % 8;
|
||
EndingOffset = EndingIndex % 8;
|
||
|
||
//
|
||
// Set ourselves up to get the next byte
|
||
//
|
||
|
||
GET_BYTE_INITIALIZATION( BitMapHeader, StartingByte );
|
||
|
||
//
|
||
// Special case the situation where the starting byte and ending
|
||
// byte are one in the same
|
||
//
|
||
|
||
if (StartingByte == EndingByte) {
|
||
|
||
//
|
||
// Get the single byte we are to look at
|
||
//
|
||
|
||
GET_BYTE( Byte );
|
||
|
||
//
|
||
// Now we compute the mask of bits we're after and then AND it with
|
||
// the complement of the byte If it is zero then the bits in question
|
||
// are all clear otherwise at least one of them is clear.
|
||
//
|
||
|
||
if ((ZeroMask[StartingOffset] & FillMask[EndingOffset+1] & ~Byte) == 0) {
|
||
|
||
return TRUE;
|
||
|
||
} else {
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Get the first byte that we're after, and then
|
||
// compute the mask of bits we're after for the first byte then
|
||
// AND it with the complement of the byte itself.
|
||
//
|
||
|
||
GET_BYTE( Byte );
|
||
|
||
if ((ZeroMask[StartingOffset] & ~Byte) != 0) {
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Now for every whole byte inbetween read in the byte,
|
||
// and make sure it is all ones
|
||
//
|
||
|
||
for (i = StartingByte+1; i < EndingByte; i += 1) {
|
||
|
||
GET_BYTE( Byte );
|
||
|
||
if (Byte != 0xff) {
|
||
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Get the last byte we're after, and then
|
||
// compute the mask of bits we're after for the last byte then
|
||
// AND it with the complement of the byte itself.
|
||
//
|
||
|
||
GET_BYTE( Byte );
|
||
|
||
if ((FillMask[EndingOffset+1] & ~Byte) != 0) {
|
||
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
//ULONG
|
||
//HalpCheckBit (
|
||
// IN PRTL_BITMAP BitMapHeader,
|
||
// IN ULONG BitPosition
|
||
// )
|
||
//
|
||
///*++
|
||
//
|
||
//Routine Description:
|
||
//
|
||
// This procedure returns the state of the specified bit within the
|
||
// specified bit map.
|
||
//
|
||
//Arguments:
|
||
//
|
||
// BitMapHeader - Supplies a pointer to the previously initialized BitMap.
|
||
//
|
||
// BitPosition - Supplies the bit number of which to return the state.
|
||
//
|
||
//Return Value:
|
||
//
|
||
// ULONG - The state of the specified bit.
|
||
//
|
||
//--*/
|
||
//
|
||
//{
|
||
// ULONG results;
|
||
//
|
||
// results = ((BitMapHeader->Buffer[BitPosition / 32]) >> (BitPosition % 32)) & 0x00000001;
|
||
//
|
||
// //DbgPrint("CheckBit %08lx", BitPosition);
|
||
// //DbgPrint(" %08lx", results);
|
||
// //DumpBitMap(BitMapHeader);
|
||
//
|
||
// return results;
|
||
//}
|
||
|