1103 lines
28 KiB
C
1103 lines
28 KiB
C
/*
|
|
* NTDLL bitmap functions
|
|
*
|
|
* Copyright 2002 Jon Griffiths
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* NOTES
|
|
* Bitmaps are an efficient type for manipulating large arrays of bits. They
|
|
* are commonly used by device drivers (e.g. For holding dirty/free blocks),
|
|
* but are also available to applications that need this functionality.
|
|
*
|
|
* Bits are set LSB to MSB in each consecutive byte, making this implementation
|
|
* binary compatible with Win32.
|
|
*
|
|
* Note that to avoid unexpected behaviour, the size of a bitmap should be set
|
|
* to a multiple of 32.
|
|
*/
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "ntstatus.h"
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winreg.h"
|
|
#include "winternl.h"
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
|
|
|
|
/* Bits set from LSB to MSB; used as mask for runs < 8 bits */
|
|
static const BYTE NTDLL_maskBits[8] = { 0, 1, 3, 7, 15, 31, 63, 127 };
|
|
|
|
/* Number of set bits for each value of a nibble; used for counting */
|
|
static const BYTE NTDLL_nibbleBitCount[16] = {
|
|
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
|
|
};
|
|
|
|
/* First set bit in a nibble; used for determining least significant bit */
|
|
static const BYTE NTDLL_leastSignificant[16] = {
|
|
0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
|
|
};
|
|
|
|
/* Last set bit in a nibble; used for determining most significant bit */
|
|
static const signed char NTDLL_mostSignificant[16] = {
|
|
-1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
|
|
};
|
|
|
|
/*************************************************************************
|
|
* RtlInitializeBitMap [NTDLL.@]
|
|
*
|
|
* Initialise a new bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* lpBuff [I] Memory for the bitmap
|
|
* ulSize [I] Size of lpBuff in bits
|
|
*
|
|
* RETURNS
|
|
* Nothing.
|
|
*
|
|
* NOTES
|
|
* lpBuff must be aligned on a ULONG suitable boundary, to a multiple of 32 bytes
|
|
* in size (irrespective of ulSize given).
|
|
*/
|
|
VOID WINAPI RtlInitializeBitMap(PRTL_BITMAP lpBits, PULONG lpBuff, ULONG ulSize)
|
|
{
|
|
TRACE("(%p,%p,%ld)\n", lpBits,lpBuff,ulSize);
|
|
lpBits->SizeOfBitMap = ulSize;
|
|
lpBits->Buffer = lpBuff;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlSetAllBits [NTDLL.@]
|
|
*
|
|
* Set all bits in a bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
*
|
|
* RETURNS
|
|
* Nothing.
|
|
*/
|
|
VOID WINAPI RtlSetAllBits(PRTL_BITMAP lpBits)
|
|
{
|
|
TRACE("(%p)\n", lpBits);
|
|
memset(lpBits->Buffer, 0xff, ((lpBits->SizeOfBitMap + 31) & ~31) >> 3);
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlClearAllBits [NTDLL.@]
|
|
*
|
|
* Clear all bits in a bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBit [I] Bitmap pointer
|
|
*
|
|
* RETURNS
|
|
* Nothing.
|
|
*/
|
|
VOID WINAPI RtlClearAllBits(PRTL_BITMAP lpBits)
|
|
{
|
|
TRACE("(%p)\n", lpBits);
|
|
memset(lpBits->Buffer, 0, ((lpBits->SizeOfBitMap + 31) & ~31) >> 3);
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlSetBits [NTDLL.@]
|
|
*
|
|
* Set a range of bits in a bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* ulStart [I] First bit to set
|
|
* ulCount [I] Number of consecutive bits to set
|
|
*
|
|
* RETURNS
|
|
* Nothing.
|
|
*/
|
|
VOID WINAPI RtlSetBits(PRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
|
|
{
|
|
LPBYTE lpOut;
|
|
|
|
TRACE("(%p,%ld,%ld)\n", lpBits, ulStart, ulCount);
|
|
|
|
if (!lpBits || !ulCount ||
|
|
ulStart >= lpBits->SizeOfBitMap ||
|
|
ulCount > lpBits->SizeOfBitMap - ulStart)
|
|
return;
|
|
|
|
/* FIXME: It might be more efficient/cleaner to manipulate four bytes
|
|
* at a time. But beware of the pointer arithmetics...
|
|
*/
|
|
lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
|
|
|
|
/* Set bits in first byte, if ulStart isn't a byte boundary */
|
|
if (ulStart & 7)
|
|
{
|
|
if (ulCount > 7)
|
|
{
|
|
/* Set from start bit to the end of the byte */
|
|
*lpOut++ |= 0xff << (ulStart & 7);
|
|
ulCount -= (8 - (ulStart & 7));
|
|
}
|
|
else
|
|
{
|
|
/* Set from the start bit, possibly into the next byte also */
|
|
USHORT initialWord = NTDLL_maskBits[ulCount] << (ulStart & 7);
|
|
|
|
*lpOut++ |= (initialWord & 0xff);
|
|
*lpOut |= (initialWord >> 8);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Set bits up to complete byte count */
|
|
if (ulCount >> 3)
|
|
{
|
|
memset(lpOut, 0xff, ulCount >> 3);
|
|
lpOut = lpOut + (ulCount >> 3);
|
|
}
|
|
|
|
/* Set remaining bits, if any */
|
|
*lpOut |= NTDLL_maskBits[ulCount & 0x7];
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlClearBits [NTDLL.@]
|
|
*
|
|
* Clear bits in a bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* ulStart [I] First bit to set
|
|
* ulCount [I] Number of consecutive bits to clear
|
|
*
|
|
* RETURNS
|
|
* Nothing.
|
|
*/
|
|
VOID WINAPI RtlClearBits(PRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
|
|
{
|
|
LPBYTE lpOut;
|
|
|
|
TRACE("(%p,%ld,%ld)\n", lpBits, ulStart, ulCount);
|
|
|
|
if (!lpBits || !ulCount ||
|
|
ulStart >= lpBits->SizeOfBitMap ||
|
|
ulCount > lpBits->SizeOfBitMap - ulStart)
|
|
return;
|
|
|
|
/* FIXME: It might be more efficient/cleaner to manipulate four bytes
|
|
* at a time. But beware of the pointer arithmetics...
|
|
*/
|
|
lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
|
|
|
|
/* Clear bits in first byte, if ulStart isn't a byte boundary */
|
|
if (ulStart & 7)
|
|
{
|
|
if (ulCount > 7)
|
|
{
|
|
/* Clear from start bit to the end of the byte */
|
|
*lpOut++ &= ~(0xff << (ulStart & 7));
|
|
ulCount -= (8 - (ulStart & 7));
|
|
}
|
|
else
|
|
{
|
|
/* Clear from the start bit, possibly into the next byte also */
|
|
USHORT initialWord = ~(NTDLL_maskBits[ulCount] << (ulStart & 7));
|
|
|
|
*lpOut++ &= (initialWord & 0xff);
|
|
*lpOut &= (initialWord >> 8);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Clear bits (in blocks of 8) on whole byte boundaries */
|
|
if (ulCount >> 3)
|
|
{
|
|
memset(lpOut, 0, ulCount >> 3);
|
|
lpOut = lpOut + (ulCount >> 3);
|
|
}
|
|
|
|
/* Clear remaining bits, if any */
|
|
if (ulCount & 0x7)
|
|
*lpOut &= ~NTDLL_maskBits[ulCount & 0x7];
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlAreBitsSet [NTDLL.@]
|
|
*
|
|
* Determine if part of a bitmap is set.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* ulStart [I] First bit to check from
|
|
* ulCount [I] Number of consecutive bits to check
|
|
*
|
|
* RETURNS
|
|
* TRUE, If ulCount bits from ulStart are set.
|
|
* FALSE, Otherwise.
|
|
*/
|
|
BOOLEAN WINAPI RtlAreBitsSet(PCRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
|
|
{
|
|
LPBYTE lpOut;
|
|
ULONG ulRemainder;
|
|
|
|
TRACE("(%p,%ld,%ld)\n", lpBits, ulStart, ulCount);
|
|
|
|
if (!lpBits || !ulCount ||
|
|
ulStart >= lpBits->SizeOfBitMap ||
|
|
ulCount > lpBits->SizeOfBitMap - ulStart)
|
|
return FALSE;
|
|
|
|
/* FIXME: It might be more efficient/cleaner to manipulate four bytes
|
|
* at a time. But beware of the pointer arithmetics...
|
|
*/
|
|
lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
|
|
|
|
/* Check bits in first byte, if ulStart isn't a byte boundary */
|
|
if (ulStart & 7)
|
|
{
|
|
if (ulCount > 7)
|
|
{
|
|
/* Check from start bit to the end of the byte */
|
|
if ((*lpOut &
|
|
((0xff << (ulStart & 7))) & 0xff) != ((0xff << (ulStart & 7) & 0xff)))
|
|
return FALSE;
|
|
lpOut++;
|
|
ulCount -= (8 - (ulStart & 7));
|
|
}
|
|
else
|
|
{
|
|
/* Check from the start bit, possibly into the next byte also */
|
|
USHORT initialWord = NTDLL_maskBits[ulCount] << (ulStart & 7);
|
|
|
|
if ((*lpOut & (initialWord & 0xff)) != (initialWord & 0xff))
|
|
return FALSE;
|
|
if ((initialWord & 0xff00) &&
|
|
((lpOut[1] & (initialWord >> 8)) != (initialWord >> 8)))
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/* Check bits in blocks of 8 bytes */
|
|
ulRemainder = ulCount & 7;
|
|
ulCount >>= 3;
|
|
while (ulCount--)
|
|
{
|
|
if (*lpOut++ != 0xff)
|
|
return FALSE;
|
|
}
|
|
|
|
/* Check remaining bits, if any */
|
|
if (ulRemainder &&
|
|
(*lpOut & NTDLL_maskBits[ulRemainder]) != NTDLL_maskBits[ulRemainder])
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlAreBitsClear [NTDLL.@]
|
|
*
|
|
* Determine if part of a bitmap is clear.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* ulStart [I] First bit to check from
|
|
* ulCount [I] Number of consecutive bits to check
|
|
*
|
|
* RETURNS
|
|
* TRUE, If ulCount bits from ulStart are clear.
|
|
* FALSE, Otherwise.
|
|
*/
|
|
BOOLEAN WINAPI RtlAreBitsClear(PCRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
|
|
{
|
|
LPBYTE lpOut;
|
|
ULONG ulRemainder;
|
|
|
|
TRACE("(%p,%ld,%ld)\n", lpBits, ulStart, ulCount);
|
|
|
|
if (!lpBits || !ulCount ||
|
|
ulStart >= lpBits->SizeOfBitMap ||
|
|
ulCount > lpBits->SizeOfBitMap - ulStart)
|
|
return FALSE;
|
|
|
|
/* FIXME: It might be more efficient/cleaner to manipulate four bytes
|
|
* at a time. But beware of the pointer arithmetics...
|
|
*/
|
|
lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
|
|
|
|
/* Check bits in first byte, if ulStart isn't a byte boundary */
|
|
if (ulStart & 7)
|
|
{
|
|
if (ulCount > 7)
|
|
{
|
|
/* Check from start bit to the end of the byte */
|
|
if (*lpOut & ((0xff << (ulStart & 7)) & 0xff))
|
|
return FALSE;
|
|
lpOut++;
|
|
ulCount -= (8 - (ulStart & 7));
|
|
}
|
|
else
|
|
{
|
|
/* Check from the start bit, possibly into the next byte also */
|
|
USHORT initialWord = NTDLL_maskBits[ulCount] << (ulStart & 7);
|
|
|
|
if (*lpOut & (initialWord & 0xff))
|
|
return FALSE;
|
|
if ((initialWord & 0xff00) && (lpOut[1] & (initialWord >> 8)))
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
/* Check bits in blocks of 8 bytes */
|
|
ulRemainder = ulCount & 7;
|
|
ulCount >>= 3;
|
|
while (ulCount--)
|
|
{
|
|
if (*lpOut++)
|
|
return FALSE;
|
|
}
|
|
|
|
/* Check remaining bits, if any */
|
|
if (ulRemainder && *lpOut & NTDLL_maskBits[ulRemainder])
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlFindSetBits [NTDLL.@]
|
|
*
|
|
* Find a block of set bits in a bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* ulCount [I] Number of consecutive set bits to find
|
|
* ulHint [I] Suggested starting position for set bits
|
|
*
|
|
* RETURNS
|
|
* The bit at which the match was found, or -1 if no match was found.
|
|
*/
|
|
ULONG WINAPI RtlFindSetBits(PCRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
|
|
{
|
|
ULONG ulPos, ulEnd;
|
|
|
|
TRACE("(%p,%ld,%ld)\n", lpBits, ulCount, ulHint);
|
|
|
|
if (!lpBits || !ulCount || ulCount > lpBits->SizeOfBitMap)
|
|
return ~0UL;
|
|
|
|
ulEnd = lpBits->SizeOfBitMap;
|
|
|
|
if (ulHint + ulCount > lpBits->SizeOfBitMap)
|
|
ulHint = 0;
|
|
|
|
ulPos = ulHint;
|
|
|
|
while (ulPos < ulEnd)
|
|
{
|
|
/* FIXME: This could be made a _lot_ more efficient */
|
|
if (RtlAreBitsSet(lpBits, ulPos, ulCount))
|
|
return ulPos;
|
|
|
|
/* Start from the beginning if we hit the end and had a hint */
|
|
if (ulPos == ulEnd - 1 && ulHint)
|
|
{
|
|
ulEnd = ulHint;
|
|
ulPos = ulHint = 0;
|
|
}
|
|
else
|
|
ulPos++;
|
|
}
|
|
return ~0UL;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlFindClearBits [NTDLL.@]
|
|
*
|
|
* Find a block of clear bits in a bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* ulCount [I] Number of consecutive clear bits to find
|
|
* ulHint [I] Suggested starting position for clear bits
|
|
*
|
|
* RETURNS
|
|
* The bit at which the match was found, or -1 if no match was found.
|
|
*/
|
|
ULONG WINAPI RtlFindClearBits(PCRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
|
|
{
|
|
ULONG ulPos, ulEnd;
|
|
|
|
TRACE("(%p,%ld,%ld)\n", lpBits, ulCount, ulHint);
|
|
|
|
if (!lpBits || !ulCount || ulCount > lpBits->SizeOfBitMap)
|
|
return ~0UL;
|
|
|
|
ulEnd = lpBits->SizeOfBitMap;
|
|
|
|
if (ulHint + ulCount > lpBits->SizeOfBitMap)
|
|
ulHint = 0;
|
|
|
|
ulPos = ulHint;
|
|
|
|
while (ulPos < ulEnd)
|
|
{
|
|
/* FIXME: This could be made a _lot_ more efficient */
|
|
if (RtlAreBitsClear(lpBits, ulPos, ulCount))
|
|
return ulPos;
|
|
|
|
/* Start from the beginning if we hit the end and started from ulHint */
|
|
if (ulPos == ulEnd - 1 && ulHint)
|
|
{
|
|
ulEnd = ulHint;
|
|
ulPos = ulHint = 0;
|
|
}
|
|
else
|
|
ulPos++;
|
|
}
|
|
return ~0UL;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlFindSetBitsAndClear [NTDLL.@]
|
|
*
|
|
* Find a block of set bits in a bitmap, and clear them if found.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* ulCount [I] Number of consecutive set bits to find
|
|
* ulHint [I] Suggested starting position for set bits
|
|
*
|
|
* RETURNS
|
|
* The bit at which the match was found, or -1 if no match was found.
|
|
*/
|
|
ULONG WINAPI RtlFindSetBitsAndClear(PRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
|
|
{
|
|
ULONG ulPos;
|
|
|
|
TRACE("(%p,%ld,%ld)\n", lpBits, ulCount, ulHint);
|
|
|
|
ulPos = RtlFindSetBits(lpBits, ulCount, ulHint);
|
|
if (ulPos != ~0UL)
|
|
RtlClearBits(lpBits, ulPos, ulCount);
|
|
return ulPos;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlFindClearBitsAndSet [NTDLL.@]
|
|
*
|
|
* Find a block of clear bits in a bitmap, and set them if found.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* ulCount [I] Number of consecutive clear bits to find
|
|
* ulHint [I] Suggested starting position for clear bits
|
|
*
|
|
* RETURNS
|
|
* The bit at which the match was found, or -1 if no match was found.
|
|
*/
|
|
ULONG WINAPI RtlFindClearBitsAndSet(PRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
|
|
{
|
|
ULONG ulPos;
|
|
|
|
TRACE("(%p,%ld,%ld)\n", lpBits, ulCount, ulHint);
|
|
|
|
ulPos = RtlFindClearBits(lpBits, ulCount, ulHint);
|
|
if (ulPos != ~0UL)
|
|
RtlSetBits(lpBits, ulPos, ulCount);
|
|
return ulPos;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlNumberOfSetBits [NTDLL.@]
|
|
*
|
|
* Find the number of set bits in a bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
*
|
|
* RETURNS
|
|
* The number of set bits.
|
|
*/
|
|
ULONG WINAPI RtlNumberOfSetBits(PCRTL_BITMAP lpBits)
|
|
{
|
|
ULONG ulSet = 0;
|
|
|
|
TRACE("(%p)\n", lpBits);
|
|
|
|
if (lpBits)
|
|
{
|
|
LPBYTE lpOut = (BYTE *)lpBits->Buffer;
|
|
ULONG ulCount, ulRemainder;
|
|
BYTE bMasked;
|
|
|
|
ulCount = lpBits->SizeOfBitMap >> 3;
|
|
ulRemainder = lpBits->SizeOfBitMap & 0x7;
|
|
|
|
while (ulCount--)
|
|
{
|
|
ulSet += NTDLL_nibbleBitCount[*lpOut >> 4];
|
|
ulSet += NTDLL_nibbleBitCount[*lpOut & 0xf];
|
|
lpOut++;
|
|
}
|
|
|
|
bMasked = *lpOut & NTDLL_maskBits[ulRemainder];
|
|
ulSet += NTDLL_nibbleBitCount[bMasked >> 4];
|
|
ulSet += NTDLL_nibbleBitCount[bMasked & 0xf];
|
|
}
|
|
return ulSet;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlNumberOfClearBits [NTDLL.@]
|
|
*
|
|
* Find the number of clear bits in a bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
*
|
|
* RETURNS
|
|
* The number of clear bits.
|
|
*/
|
|
ULONG WINAPI RtlNumberOfClearBits(PCRTL_BITMAP lpBits)
|
|
{
|
|
TRACE("(%p)\n", lpBits);
|
|
|
|
if (lpBits)
|
|
return lpBits->SizeOfBitMap - RtlNumberOfSetBits(lpBits);
|
|
return 0;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlFindMostSignificantBit [NTDLL.@]
|
|
*
|
|
* Find the most significant bit in a 64 bit integer.
|
|
*
|
|
* RETURNS
|
|
* The position of the most significant bit.
|
|
*/
|
|
CCHAR WINAPI RtlFindMostSignificantBit(ULONGLONG ulLong)
|
|
{
|
|
signed char ret = 32;
|
|
DWORD dw;
|
|
|
|
if (!(dw = (ulLong >> 32)))
|
|
{
|
|
ret = 0;
|
|
dw = (DWORD)ulLong;
|
|
}
|
|
if (dw & 0xffff0000)
|
|
{
|
|
dw >>= 16;
|
|
ret += 16;
|
|
}
|
|
if (dw & 0xff00)
|
|
{
|
|
dw >>= 8;
|
|
ret += 8;
|
|
}
|
|
if (dw & 0xf0)
|
|
{
|
|
dw >>= 4;
|
|
ret += 4;
|
|
}
|
|
return ret + NTDLL_mostSignificant[dw];
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlFindLeastSignificantBit [NTDLL.@]
|
|
*
|
|
* Find the least significant bit in a 64 bit integer.
|
|
*
|
|
* RETURNS
|
|
* The position of the least significant bit.
|
|
*/
|
|
CCHAR WINAPI RtlFindLeastSignificantBit(ULONGLONG ulLong)
|
|
{
|
|
signed char ret = 0;
|
|
DWORD dw;
|
|
|
|
if (!(dw = (DWORD)ulLong))
|
|
{
|
|
ret = 32;
|
|
if (!(dw = ulLong >> 32)) return -1;
|
|
}
|
|
if (!(dw & 0xffff))
|
|
{
|
|
dw >>= 16;
|
|
ret += 16;
|
|
}
|
|
if (!(dw & 0xff))
|
|
{
|
|
dw >>= 8;
|
|
ret += 8;
|
|
}
|
|
if (!(dw & 0x0f))
|
|
{
|
|
dw >>= 4;
|
|
ret += 4;
|
|
}
|
|
return ret + NTDLL_leastSignificant[dw & 0x0f];
|
|
}
|
|
|
|
/*************************************************************************
|
|
* NTDLL_RunSortFn
|
|
*
|
|
* Internal helper: qsort comparison function for RTL_BITMAP_RUN arrays
|
|
*/
|
|
static int NTDLL_RunSortFn(const void *lhs, const void *rhs)
|
|
{
|
|
if (((const RTL_BITMAP_RUN*)lhs)->NumberOfBits > ((const RTL_BITMAP_RUN*)rhs)->NumberOfBits)
|
|
return -1;
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* NTDLL_FindSetRun
|
|
*
|
|
* Internal helper: Find the next run of set bits in a bitmap.
|
|
*/
|
|
static ULONG NTDLL_FindSetRun(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpSize)
|
|
{
|
|
LPBYTE lpOut;
|
|
ULONG ulFoundAt = 0, ulCount = 0;
|
|
|
|
/* FIXME: It might be more efficient/cleaner to manipulate four bytes
|
|
* at a time. But beware of the pointer arithmetics...
|
|
*/
|
|
lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
|
|
|
|
while (1)
|
|
{
|
|
/* Check bits in first byte */
|
|
const BYTE bMask = (0xff << (ulStart & 7)) & 0xff;
|
|
const BYTE bFirst = *lpOut & bMask;
|
|
|
|
if (bFirst)
|
|
{
|
|
/* Have a set bit in first byte */
|
|
if (bFirst != bMask)
|
|
{
|
|
/* Not every bit is set */
|
|
ULONG ulOffset;
|
|
|
|
if (bFirst & 0x0f)
|
|
ulOffset = NTDLL_leastSignificant[bFirst & 0x0f];
|
|
else
|
|
ulOffset = 4 + NTDLL_leastSignificant[bFirst >> 4];
|
|
ulStart += ulOffset;
|
|
ulFoundAt = ulStart;
|
|
for (;ulOffset < 8; ulOffset++)
|
|
{
|
|
if (!(bFirst & (1 << ulOffset)))
|
|
{
|
|
*lpSize = ulCount;
|
|
return ulFoundAt; /* Set from start, but not until the end */
|
|
}
|
|
ulCount++;
|
|
ulStart++;
|
|
}
|
|
/* Set to the end - go on to count further bits */
|
|
lpOut++;
|
|
break;
|
|
}
|
|
/* every bit from start until the end of the byte is set */
|
|
ulFoundAt = ulStart;
|
|
ulCount = 8 - (ulStart & 7);
|
|
ulStart = (ulStart & ~7u) + 8;
|
|
lpOut++;
|
|
break;
|
|
}
|
|
ulStart = (ulStart & ~7u) + 8;
|
|
lpOut++;
|
|
if (ulStart >= lpBits->SizeOfBitMap)
|
|
return ~0UL;
|
|
}
|
|
|
|
/* Count blocks of 8 set bits */
|
|
while (*lpOut == 0xff)
|
|
{
|
|
ulCount += 8;
|
|
ulStart += 8;
|
|
if (ulStart >= lpBits->SizeOfBitMap)
|
|
{
|
|
*lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap);
|
|
return ulFoundAt;
|
|
}
|
|
lpOut++;
|
|
}
|
|
|
|
/* Count remaining contigious bits, if any */
|
|
if (*lpOut & 1)
|
|
{
|
|
ULONG ulOffset = 0;
|
|
|
|
for (;ulOffset < 7u; ulOffset++)
|
|
{
|
|
if (!(*lpOut & (1 << ulOffset)))
|
|
break;
|
|
ulCount++;
|
|
}
|
|
}
|
|
*lpSize = ulCount;
|
|
return ulFoundAt;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* NTDLL_FindClearRun
|
|
*
|
|
* Internal helper: Find the next run of set bits in a bitmap.
|
|
*/
|
|
static ULONG NTDLL_FindClearRun(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpSize)
|
|
{
|
|
LPBYTE lpOut;
|
|
ULONG ulFoundAt = 0, ulCount = 0;
|
|
|
|
/* FIXME: It might be more efficient/cleaner to manipulate four bytes
|
|
* at a time. But beware of the pointer arithmetics...
|
|
*/
|
|
lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
|
|
|
|
while (1)
|
|
{
|
|
/* Check bits in first byte */
|
|
const BYTE bMask = (0xff << (ulStart & 7)) & 0xff;
|
|
const BYTE bFirst = (~*lpOut) & bMask;
|
|
|
|
if (bFirst)
|
|
{
|
|
/* Have a clear bit in first byte */
|
|
if (bFirst != bMask)
|
|
{
|
|
/* Not every bit is clear */
|
|
ULONG ulOffset;
|
|
|
|
if (bFirst & 0x0f)
|
|
ulOffset = NTDLL_leastSignificant[bFirst & 0x0f];
|
|
else
|
|
ulOffset = 4 + NTDLL_leastSignificant[bFirst >> 4];
|
|
ulStart += ulOffset;
|
|
ulFoundAt = ulStart;
|
|
for (;ulOffset < 8; ulOffset++)
|
|
{
|
|
if (!(bFirst & (1 << ulOffset)))
|
|
{
|
|
*lpSize = ulCount;
|
|
return ulFoundAt; /* Clear from start, but not until the end */
|
|
}
|
|
ulCount++;
|
|
ulStart++;
|
|
}
|
|
/* Clear to the end - go on to count further bits */
|
|
lpOut++;
|
|
break;
|
|
}
|
|
/* Every bit from start until the end of the byte is clear */
|
|
ulFoundAt = ulStart;
|
|
ulCount = 8 - (ulStart & 7);
|
|
ulStart = (ulStart & ~7u) + 8;
|
|
lpOut++;
|
|
break;
|
|
}
|
|
ulStart = (ulStart & ~7u) + 8;
|
|
lpOut++;
|
|
if (ulStart >= lpBits->SizeOfBitMap)
|
|
return ~0UL;
|
|
}
|
|
|
|
/* Count blocks of 8 clear bits */
|
|
while (!*lpOut)
|
|
{
|
|
ulCount += 8;
|
|
ulStart += 8;
|
|
if (ulStart >= lpBits->SizeOfBitMap)
|
|
{
|
|
*lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap);
|
|
return ulFoundAt;
|
|
}
|
|
lpOut++;
|
|
}
|
|
|
|
/* Count remaining contigious bits, if any */
|
|
if (!(*lpOut & 1))
|
|
{
|
|
ULONG ulOffset = 0;
|
|
|
|
for (;ulOffset < 7u; ulOffset++)
|
|
{
|
|
if (*lpOut & (1 << ulOffset))
|
|
break;
|
|
ulCount++;
|
|
}
|
|
}
|
|
*lpSize = ulCount;
|
|
return ulFoundAt;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlFindNextForwardRunSet [NTDLL.@]
|
|
*
|
|
* Find the next run of set bits in a bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* ulStart [I] Bit position to start searching from
|
|
* lpPos [O] Start of run
|
|
*
|
|
* RETURNS
|
|
* Success: The length of the next set run in the bitmap. lpPos is set to
|
|
* the start of the run.
|
|
* Failure: 0, if no run is found or any parameters are invalid.
|
|
*/
|
|
ULONG WINAPI RtlFindNextForwardRunSet(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
|
|
{
|
|
ULONG ulSize = 0;
|
|
|
|
TRACE("(%p,%ld,%p)\n", lpBits, ulStart, lpPos);
|
|
|
|
if (lpBits && ulStart < lpBits->SizeOfBitMap && lpPos)
|
|
*lpPos = NTDLL_FindSetRun(lpBits, ulStart, &ulSize);
|
|
|
|
return ulSize;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlFindNextForwardRunClear [NTDLL.@]
|
|
*
|
|
* Find the next run of clear bits in a bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* ulStart [I] Bit position to start searching from
|
|
* lpPos [O] Start of run
|
|
*
|
|
* RETURNS
|
|
* Success: The length of the next clear run in the bitmap. lpPos is set to
|
|
* the start of the run.
|
|
* Failure: 0, if no run is found or any parameters are invalid.
|
|
*/
|
|
ULONG WINAPI RtlFindNextForwardRunClear(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
|
|
{
|
|
ULONG ulSize = 0;
|
|
|
|
TRACE("(%p,%ld,%p)\n", lpBits, ulStart, lpPos);
|
|
|
|
if (lpBits && ulStart < lpBits->SizeOfBitMap && lpPos)
|
|
*lpPos = NTDLL_FindClearRun(lpBits, ulStart, &ulSize);
|
|
|
|
return ulSize;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlFindLastBackwardRunSet [NTDLL.@]
|
|
*
|
|
* Find a previous run of set bits in a bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* ulStart [I] Bit position to start searching from
|
|
* lpPos [O] Start of run
|
|
*
|
|
* RETURNS
|
|
* Success: The length of the previous set run in the bitmap. lpPos is set to
|
|
* the start of the run.
|
|
* Failure: 0, if no run is found or any parameters are invalid.
|
|
*/
|
|
ULONG WINAPI RtlFindLastBackwardRunSet(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
|
|
{
|
|
FIXME("(%p,%ld,%p)-stub!\n", lpBits, ulStart, lpPos);
|
|
return 0;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlFindLastBackwardRunClear [NTDLL.@]
|
|
*
|
|
* Find a previous run of clear bits in a bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* ulStart [I] Bit position to start searching from
|
|
* lpPos [O] Start of run
|
|
*
|
|
* RETURNS
|
|
* Success: The length of the previous clear run in the bitmap. lpPos is set
|
|
* to the start of the run.
|
|
* Failure: 0, if no run is found or any parameters are invalid.
|
|
*/
|
|
ULONG WINAPI RtlFindLastBackwardRunClear(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
|
|
{
|
|
FIXME("(%p,%ld,%p)-stub!\n", lpBits, ulStart, lpPos);
|
|
return 0;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* NTDLL_FindRuns
|
|
*
|
|
* Internal implementation of RtlFindSetRuns/RtlFindClearRuns.
|
|
*/
|
|
static ULONG WINAPI NTDLL_FindRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
|
|
ULONG ulCount, BOOLEAN bLongest,
|
|
ULONG (*fn)(PCRTL_BITMAP,ULONG,PULONG))
|
|
{
|
|
BOOL bNeedSort = ulCount > 1 ? TRUE : FALSE;
|
|
ULONG ulPos = 0, ulRuns = 0;
|
|
|
|
TRACE("(%p,%p,%ld,%d)\n", lpBits, lpSeries, ulCount, bLongest);
|
|
|
|
if (!ulCount)
|
|
return ~0UL;
|
|
|
|
while (ulPos < lpBits->SizeOfBitMap)
|
|
{
|
|
/* Find next set/clear run */
|
|
ULONG ulSize, ulNextPos = fn(lpBits, ulPos, &ulSize);
|
|
|
|
if (ulNextPos == ~0UL)
|
|
break;
|
|
|
|
if (bLongest && ulRuns == ulCount)
|
|
{
|
|
/* Sort runs with shortest at end, if they are out of order */
|
|
if (bNeedSort)
|
|
qsort(lpSeries, ulRuns, sizeof(RTL_BITMAP_RUN), NTDLL_RunSortFn);
|
|
|
|
/* Replace last run if this one is bigger */
|
|
if (ulSize > lpSeries[ulRuns - 1].NumberOfBits)
|
|
{
|
|
lpSeries[ulRuns - 1].StartingIndex = ulNextPos;
|
|
lpSeries[ulRuns - 1].NumberOfBits = ulSize;
|
|
|
|
/* We need to re-sort the array, _if_ we didn't leave it sorted */
|
|
if (ulRuns > 1 && ulSize > lpSeries[ulRuns - 2].NumberOfBits)
|
|
bNeedSort = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Append to found runs */
|
|
lpSeries[ulRuns].StartingIndex = ulNextPos;
|
|
lpSeries[ulRuns].NumberOfBits = ulSize;
|
|
ulRuns++;
|
|
|
|
if (!bLongest && ulRuns == ulCount)
|
|
break;
|
|
}
|
|
ulPos = ulNextPos + ulSize;
|
|
}
|
|
return ulRuns;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlFindSetRuns [NTDLL.@]
|
|
*
|
|
* Find a series of set runs in a bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* lpSeries [O] Array for each run found
|
|
* ulCount [I] Number of runs to find
|
|
* bLongest [I] Whether to find the very longest runs or not
|
|
*
|
|
* RETURNS
|
|
* The number of set runs found.
|
|
*/
|
|
ULONG WINAPI RtlFindSetRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
|
|
ULONG ulCount, BOOLEAN bLongest)
|
|
{
|
|
TRACE("(%p,%p,%ld,%d)\n", lpBits, lpSeries, ulCount, bLongest);
|
|
|
|
return NTDLL_FindRuns(lpBits, lpSeries, ulCount, bLongest, NTDLL_FindSetRun);
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlFindClearRuns [NTDLL.@]
|
|
*
|
|
* Find a series of clear runs in a bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* ulSeries [O] Array for each run found
|
|
* ulCount [I] Number of runs to find
|
|
* bLongest [I] Whether to find the very longest runs or not
|
|
*
|
|
* RETURNS
|
|
* The number of clear runs found.
|
|
*/
|
|
ULONG WINAPI RtlFindClearRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
|
|
ULONG ulCount, BOOLEAN bLongest)
|
|
{
|
|
TRACE("(%p,%p,%ld,%d)\n", lpBits, lpSeries, ulCount, bLongest);
|
|
|
|
return NTDLL_FindRuns(lpBits, lpSeries, ulCount, bLongest, NTDLL_FindClearRun);
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlFindLongestRunSet [NTDLL.@]
|
|
*
|
|
* Find the longest set run in a bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* pulStart [O] Destination for start of run
|
|
*
|
|
* RETURNS
|
|
* The length of the run found, or 0 if no run is found.
|
|
*/
|
|
ULONG WINAPI RtlFindLongestRunSet(PCRTL_BITMAP lpBits, PULONG pulStart)
|
|
{
|
|
RTL_BITMAP_RUN br;
|
|
|
|
TRACE("(%p,%p)\n", lpBits, pulStart);
|
|
|
|
if (RtlFindSetRuns(lpBits, &br, 1, TRUE) == 1)
|
|
{
|
|
if (pulStart)
|
|
*pulStart = br.StartingIndex;
|
|
return br.NumberOfBits;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*************************************************************************
|
|
* RtlFindLongestRunClear [NTDLL.@]
|
|
*
|
|
* Find the longest clear run in a bitmap.
|
|
*
|
|
* PARAMS
|
|
* lpBits [I] Bitmap pointer
|
|
* pulStart [O] Destination for start of run
|
|
*
|
|
* RETURNS
|
|
* The length of the run found, or 0 if no run is found.
|
|
*/
|
|
ULONG WINAPI RtlFindLongestRunClear(PCRTL_BITMAP lpBits, PULONG pulStart)
|
|
{
|
|
RTL_BITMAP_RUN br;
|
|
|
|
TRACE("(%p,%p)\n", lpBits, pulStart);
|
|
|
|
if (RtlFindClearRuns(lpBits, &br, 1, TRUE) == 1)
|
|
{
|
|
if (pulStart)
|
|
*pulStart = br.StartingIndex;
|
|
return br.NumberOfBits;
|
|
}
|
|
return 0;
|
|
}
|