/*++ 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: --*/ #include "ntrtlp.h" #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME) #pragma alloc_text(PAGE,RtlInitializeBitMap) #endif #define RightShiftUlong(E1,E2) ((E2) < 32 ? (E1) >> (E2) : 0) #define LeftShiftUlong(E1,E2) ((E2) < 32 ? (E1) << (E2) : 0) #if DBG VOID DumpBitMap ( 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 RtlpBitsClearAnywhere[] = { 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 RtlpBitsClearLow[] = { 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 RtlpBitsClearHigh[] = { 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 RtlpBitsClearTotal[] = { 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 RtlInitializeBitMap ( 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 RtlClearAllBits ( 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 RtlSetAllBits ( 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 RtlFindClearBits ( 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)RtlpBitsClearHigh[PreviousByte] + (ULONG)RtlpBitsClearLow[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)RtlpBitsClearHigh[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)RtlpBitsClearAnywhere[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)RtlpBitsClearHigh[PreviousByte] + (ULONG)RtlpBitsClearLow[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)RtlpBitsClearHigh[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)RtlpBitsClearHigh[PreviousPreviousByte] + 8 + (ULONG)RtlpBitsClearLow[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)RtlpBitsClearHigh[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)RtlpBitsClearHigh[StartOfRunByte] + ZeroBytesFound*8 + (ULONG)RtlpBitsClearLow[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)RtlpBitsClearHigh[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 RtlFindSetBits ( 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)RtlpBitSetAnywhere(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)RtlpBitsSetHigh(PreviousByte) + (ULONG)RtlpBitsSetLow(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)RtlpBitsSetHigh(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)RtlpBitsSetHigh(PreviousByte) + (ULONG)RtlpBitsSetLow(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)RtlpBitsSetHigh(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)RtlpBitsSetHigh(PreviousPreviousByte) + 8 + (ULONG)RtlpBitsSetLow(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)RtlpBitsSetHigh(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)RtlpBitsSetHigh(StartOfRunByte) + OneBytesFound*8 + (ULONG)RtlpBitsSetLow(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)RtlpBitsSetHigh(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 RtlFindClearBitsAndSet ( 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 = RtlFindClearBits( 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 // RtlSetBits( BitMapHeader, StartingIndex, NumberToFind ); } // // And return to our caller // return StartingIndex; } ULONG RtlFindSetBitsAndClear ( 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 = RtlFindSetBits( BitMapHeader, NumberToFind, HintIndex )) != 0xffffffff) { // // We found a large enough run of set bits so now clear them // RtlClearBits( BitMapHeader, StartingIndex, NumberToFind ); } // // And return to our caller // return StartingIndex; } VOID RtlClearBits ( 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 RtlSetBits ( 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 RtlFindLongestRunClear ( 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 += RtlpBitsClearLow[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 = RtlpBitsClearHigh[ 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 = RtlpBitsClearAnywhere[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 RtlFindLongestRunSet ( 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 += RtlpBitsSetLow(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 = RtlpBitsSetHigh( 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 = RtlpBitSetAnywhere(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 RtlFindFirstRunClear ( 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 += RtlpBitsClearLow[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 (RtlpBitsClearHigh[CurrentByte] == 0) { UCHAR BitMask; ULONG i; ASSERT( RtlpBitsClearAnywhere[CurrentByte] != 0 ); CurrentRunSize = RtlpBitsClearAnywhere[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 = RtlpBitsClearHigh[ CurrentByte ]; CurrentRunIndex = (CurrentByteIndex * 8) + (8 - CurrentRunSize); } } // // Set our output variables and return to our caller // *StartingIndex = CurrentRunIndex; return CurrentRunSize; } ULONG RtlFindFirstRunSet ( 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 += RtlpBitsSetLow(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 (RtlpBitsSetHigh(CurrentByte) == 0) { UCHAR BitMask; ULONG i; ASSERT( RtlpBitSetAnywhere(CurrentByte) != 0 ); CurrentRunSize = RtlpBitSetAnywhere(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 = RtlpBitsSetHigh( CurrentByte ); CurrentRunIndex = (CurrentByteIndex * 8) + (8 - CurrentRunSize); } } // // Set our output variables and return to our caller // *StartingIndex = CurrentRunIndex; return CurrentRunSize; } ULONG RtlNumberOfClearBits ( 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 += RtlpBitsClearTotal[CurrentByte]; } return TotalClear; } ULONG RtlNumberOfSetBits ( 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 += RtlpBitsSetTotal(CurrentByte); } return TotalSet; } BOOLEAN RtlAreBitsClear ( 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 RtlAreBitsSet ( 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 //RtlCheckBit ( // 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; //}