Implement NtAccessCheck.
[wine/gsoc-2012-control.git] / dlls / ntdll / rtlbitmap.c
blob4ed95bac003087a6f5e78f636df6396b26d4cfb7
1 /*
2 * NTDLL bitmap functions
4 * Copyright 2002 Jon Griffiths
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * NOTES
21 * Bitmaps are an efficient type for manipulating large arrays of bits. They
22 * are commonly used by device drivers (e.g. For holding dirty/free blocks),
23 * but are also available to applications that need this functionality.
25 * Bits are set LSB to MSB in each consecutive byte, making this implementation
26 * binary compatible with Win32.
28 * Note that to avoid unexpected behaviour, the size of a bitmap should be set
29 * to a multiple of 32.
31 #include <stdarg.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winreg.h"
37 #include "winternl.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
42 /* Bits set from LSB to MSB; used as mask for runs < 8 bits */
43 static const BYTE NTDLL_maskBits[8] = { 0, 1, 3, 7, 15, 31, 63, 127 };
45 /* Number of set bits for each value of a nibble; used for counting */
46 static const BYTE NTDLL_nibbleBitCount[16] = {
47 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
50 /* First set bit in a nibble; used for determining least significant bit */
51 static const BYTE NTDLL_leastSignificant[16] = {
52 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
55 /* Last set bit in a nibble; used for determining most significant bit */
56 static const signed char NTDLL_mostSignificant[16] = {
57 -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
60 /*************************************************************************
61 * RtlInitializeBitMap [NTDLL.@]
63 * Initialise a new bitmap.
65 * PARAMS
66 * lpBits [I] Bitmap pointer
67 * lpBuff [I] Memory for the bitmap
68 * ulSize [I] Size of lpBuff in bits
70 * RETURNS
71 * Nothing.
73 * NOTES
74 * lpBuff must be aligned on a ULONG suitable boundary, to a multiple of 32 bytes
75 * in size (irrespective of ulSize given).
77 VOID WINAPI RtlInitializeBitMap(PRTL_BITMAP lpBits, PULONG lpBuff, ULONG ulSize)
79 TRACE("(%p,%p,%ld)\n", lpBits,lpBuff,ulSize);
80 lpBits->SizeOfBitMap = ulSize;
81 lpBits->Buffer = lpBuff;
84 /*************************************************************************
85 * RtlSetAllBits [NTDLL.@]
87 * Set all bits in a bitmap.
89 * PARAMS
90 * lpBits [I] Bitmap pointer
92 * RETURNS
93 * Nothing.
95 VOID WINAPI RtlSetAllBits(PRTL_BITMAP lpBits)
97 TRACE("(%p)\n", lpBits);
98 memset(lpBits->Buffer, 0xff, ((lpBits->SizeOfBitMap + 31) & ~31) >> 3);
101 /*************************************************************************
102 * RtlClearAllBits [NTDLL.@]
104 * Clear all bits in a bitmap.
106 * PARAMS
107 * lpBit [I] Bitmap pointer
109 * RETURNS
110 * Nothing.
112 VOID WINAPI RtlClearAllBits(PRTL_BITMAP lpBits)
114 TRACE("(%p)\n", lpBits);
115 memset(lpBits->Buffer, 0, ((lpBits->SizeOfBitMap + 31) & ~31) >> 3);
118 /*************************************************************************
119 * RtlSetBits [NTDLL.@]
121 * Set a range of bits in a bitmap.
123 * PARAMS
124 * lpBits [I] Bitmap pointer
125 * ulStart [I] First bit to set
126 * ulCount [I] Number of consecutive bits to set
128 * RETURNS
129 * Nothing.
131 VOID WINAPI RtlSetBits(PRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
133 LPBYTE lpOut;
135 TRACE("(%p,%ld,%ld)\n", lpBits, ulStart, ulCount);
137 if (!lpBits || !ulCount ||
138 ulStart >= lpBits->SizeOfBitMap ||
139 ulCount > lpBits->SizeOfBitMap - ulStart)
140 return;
142 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
143 * at a time. But beware of the pointer arithmetics...
145 lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
147 /* Set bits in first byte, if ulStart isn't a byte boundary */
148 if (ulStart & 7)
150 if (ulCount > 7)
152 /* Set from start bit to the end of the byte */
153 *lpOut++ |= 0xff << (ulStart & 7);
154 ulCount -= (8 - (ulStart & 7));
156 else
158 /* Set from the start bit, possibly into the next byte also */
159 USHORT initialWord = NTDLL_maskBits[ulCount] << (ulStart & 7);
161 *lpOut++ |= (initialWord & 0xff);
162 *lpOut |= (initialWord >> 8);
163 return;
167 /* Set bits up to complete byte count */
168 if (ulCount >> 3)
170 memset(lpOut, 0xff, ulCount >> 3);
171 lpOut = lpOut + (ulCount >> 3);
174 /* Set remaining bits, if any */
175 *lpOut |= NTDLL_maskBits[ulCount & 0x7];
178 /*************************************************************************
179 * RtlClearBits [NTDLL.@]
181 * Clear bits in a bitmap.
183 * PARAMS
184 * lpBits [I] Bitmap pointer
185 * ulStart [I] First bit to set
186 * ulCount [I] Number of consecutive bits to clear
188 * RETURNS
189 * Nothing.
191 VOID WINAPI RtlClearBits(PRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
193 LPBYTE lpOut;
195 TRACE("(%p,%ld,%ld)\n", lpBits, ulStart, ulCount);
197 if (!lpBits || !ulCount ||
198 ulStart >= lpBits->SizeOfBitMap ||
199 ulCount > lpBits->SizeOfBitMap - ulStart)
200 return;
202 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
203 * at a time. But beware of the pointer arithmetics...
205 lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
207 /* Clear bits in first byte, if ulStart isn't a byte boundary */
208 if (ulStart & 7)
210 if (ulCount > 7)
212 /* Clear from start bit to the end of the byte */
213 *lpOut++ &= ~(0xff << (ulStart & 7));
214 ulCount -= (8 - (ulStart & 7));
216 else
218 /* Clear from the start bit, possibly into the next byte also */
219 USHORT initialWord = ~(NTDLL_maskBits[ulCount] << (ulStart & 7));
221 *lpOut++ &= (initialWord & 0xff);
222 *lpOut &= (initialWord >> 8);
223 return;
227 /* Clear bits (in blocks of 8) on whole byte boundaries */
228 if (ulCount >> 3)
230 memset(lpOut, 0, ulCount >> 3);
231 lpOut = lpOut + (ulCount >> 3);
234 /* Clear remaining bits, if any */
235 if (ulCount & 0x7)
236 *lpOut &= ~NTDLL_maskBits[ulCount & 0x7];
239 /*************************************************************************
240 * RtlAreBitsSet [NTDLL.@]
242 * Determine if part of a bitmap is set.
244 * PARAMS
245 * lpBits [I] Bitmap pointer
246 * ulStart [I] First bit to check from
247 * ulCount [I] Number of consecutive bits to check
249 * RETURNS
250 * TRUE, If ulCount bits from ulStart are set.
251 * FALSE, Otherwise.
253 BOOLEAN WINAPI RtlAreBitsSet(PCRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
255 LPBYTE lpOut;
256 ULONG ulRemainder;
258 TRACE("(%p,%ld,%ld)\n", lpBits, ulStart, ulCount);
260 if (!lpBits || !ulCount ||
261 ulStart >= lpBits->SizeOfBitMap ||
262 ulCount > lpBits->SizeOfBitMap - ulStart)
263 return FALSE;
265 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
266 * at a time. But beware of the pointer arithmetics...
268 lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
270 /* Check bits in first byte, if ulStart isn't a byte boundary */
271 if (ulStart & 7)
273 if (ulCount > 7)
275 /* Check from start bit to the end of the byte */
276 if ((*lpOut &
277 ((0xff << (ulStart & 7))) & 0xff) != ((0xff << (ulStart & 7) & 0xff)))
278 return FALSE;
279 lpOut++;
280 ulCount -= (8 - (ulStart & 7));
282 else
284 /* Check from the start bit, possibly into the next byte also */
285 USHORT initialWord = NTDLL_maskBits[ulCount] << (ulStart & 7);
287 if ((*lpOut & (initialWord & 0xff)) != (initialWord & 0xff))
288 return FALSE;
289 if ((initialWord & 0xff00) &&
290 ((lpOut[1] & (initialWord >> 8)) != (initialWord >> 8)))
291 return FALSE;
292 return TRUE;
296 /* Check bits in blocks of 8 bytes */
297 ulRemainder = ulCount & 7;
298 ulCount >>= 3;
299 while (ulCount--)
301 if (*lpOut++ != 0xff)
302 return FALSE;
305 /* Check remaining bits, if any */
306 if (ulRemainder &&
307 (*lpOut & NTDLL_maskBits[ulRemainder]) != NTDLL_maskBits[ulRemainder])
308 return FALSE;
309 return TRUE;
312 /*************************************************************************
313 * RtlAreBitsClear [NTDLL.@]
315 * Determine if part of a bitmap is clear.
317 * PARAMS
318 * lpBits [I] Bitmap pointer
319 * ulStart [I] First bit to check from
320 * ulCount [I] Number of consecutive bits to check
322 * RETURNS
323 * TRUE, If ulCount bits from ulStart are clear.
324 * FALSE, Otherwise.
326 BOOLEAN WINAPI RtlAreBitsClear(PCRTL_BITMAP lpBits, ULONG ulStart, ULONG ulCount)
328 LPBYTE lpOut;
329 ULONG ulRemainder;
331 TRACE("(%p,%ld,%ld)\n", lpBits, ulStart, ulCount);
333 if (!lpBits || !ulCount ||
334 ulStart >= lpBits->SizeOfBitMap ||
335 ulCount > lpBits->SizeOfBitMap - ulStart)
336 return FALSE;
338 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
339 * at a time. But beware of the pointer arithmetics...
341 lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
343 /* Check bits in first byte, if ulStart isn't a byte boundary */
344 if (ulStart & 7)
346 if (ulCount > 7)
348 /* Check from start bit to the end of the byte */
349 if (*lpOut & ((0xff << (ulStart & 7)) & 0xff))
350 return FALSE;
351 lpOut++;
352 ulCount -= (8 - (ulStart & 7));
354 else
356 /* Check from the start bit, possibly into the next byte also */
357 USHORT initialWord = NTDLL_maskBits[ulCount] << (ulStart & 7);
359 if (*lpOut & (initialWord & 0xff))
360 return FALSE;
361 if ((initialWord & 0xff00) && (lpOut[1] & (initialWord >> 8)))
362 return FALSE;
363 return TRUE;
367 /* Check bits in blocks of 8 bytes */
368 ulRemainder = ulCount & 7;
369 ulCount >>= 3;
370 while (ulCount--)
372 if (*lpOut++)
373 return FALSE;
376 /* Check remaining bits, if any */
377 if (ulRemainder && *lpOut & NTDLL_maskBits[ulRemainder])
378 return FALSE;
379 return TRUE;
382 /*************************************************************************
383 * RtlFindSetBits [NTDLL.@]
385 * Find a block of set bits in a bitmap.
387 * PARAMS
388 * lpBits [I] Bitmap pointer
389 * ulCount [I] Number of consecutive set bits to find
390 * ulHint [I] Suggested starting position for set bits
392 * RETURNS
393 * The bit at which the match was found, or -1 if no match was found.
395 ULONG WINAPI RtlFindSetBits(PCRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
397 ULONG ulPos, ulEnd;
399 TRACE("(%p,%ld,%ld)\n", lpBits, ulCount, ulHint);
401 if (!lpBits || !ulCount || ulCount > lpBits->SizeOfBitMap)
402 return ~0UL;
404 ulEnd = lpBits->SizeOfBitMap;
406 if (ulHint + ulCount > lpBits->SizeOfBitMap)
407 ulHint = 0;
409 ulPos = ulHint;
411 while (ulPos < ulEnd)
413 /* FIXME: This could be made a _lot_ more efficient */
414 if (RtlAreBitsSet(lpBits, ulPos, ulCount))
415 return ulPos;
417 /* Start from the beginning if we hit the end and had a hint */
418 if (ulPos == ulEnd - 1 && ulHint)
420 ulEnd = ulHint;
421 ulPos = ulHint = 0;
423 else
424 ulPos++;
426 return ~0UL;
429 /*************************************************************************
430 * RtlFindClearBits [NTDLL.@]
432 * Find a block of clear bits in a bitmap.
434 * PARAMS
435 * lpBits [I] Bitmap pointer
436 * ulCount [I] Number of consecutive clear bits to find
437 * ulHint [I] Suggested starting position for clear bits
439 * RETURNS
440 * The bit at which the match was found, or -1 if no match was found.
442 ULONG WINAPI RtlFindClearBits(PCRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
444 ULONG ulPos, ulEnd;
446 TRACE("(%p,%ld,%ld)\n", lpBits, ulCount, ulHint);
448 if (!lpBits || !ulCount || ulCount > lpBits->SizeOfBitMap)
449 return ~0UL;
451 ulEnd = lpBits->SizeOfBitMap;
453 if (ulHint + ulCount > lpBits->SizeOfBitMap)
454 ulHint = 0;
456 ulPos = ulHint;
458 while (ulPos < ulEnd)
460 /* FIXME: This could be made a _lot_ more efficient */
461 if (RtlAreBitsClear(lpBits, ulPos, ulCount))
462 return ulPos;
464 /* Start from the beginning if we hit the end and started from ulHint */
465 if (ulPos == ulEnd - 1 && ulHint)
467 ulEnd = ulHint;
468 ulPos = ulHint = 0;
470 else
471 ulPos++;
473 return ~0UL;
476 /*************************************************************************
477 * RtlFindSetBitsAndClear [NTDLL.@]
479 * Find a block of set bits in a bitmap, and clear them if found.
481 * PARAMS
482 * lpBits [I] Bitmap pointer
483 * ulCount [I] Number of consecutive set bits to find
484 * ulHint [I] Suggested starting position for set bits
486 * RETURNS
487 * The bit at which the match was found, or -1 if no match was found.
489 ULONG WINAPI RtlFindSetBitsAndClear(PRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
491 ULONG ulPos;
493 TRACE("(%p,%ld,%ld)\n", lpBits, ulCount, ulHint);
495 ulPos = RtlFindSetBits(lpBits, ulCount, ulHint);
496 if (ulPos != ~0UL)
497 RtlClearBits(lpBits, ulPos, ulCount);
498 return ulPos;
501 /*************************************************************************
502 * RtlFindClearBitsAndSet [NTDLL.@]
504 * Find a block of clear bits in a bitmap, and set them if found.
506 * PARAMS
507 * lpBits [I] Bitmap pointer
508 * ulCount [I] Number of consecutive clear bits to find
509 * ulHint [I] Suggested starting position for clear bits
511 * RETURNS
512 * The bit at which the match was found, or -1 if no match was found.
514 ULONG WINAPI RtlFindClearBitsAndSet(PRTL_BITMAP lpBits, ULONG ulCount, ULONG ulHint)
516 ULONG ulPos;
518 TRACE("(%p,%ld,%ld)\n", lpBits, ulCount, ulHint);
520 ulPos = RtlFindClearBits(lpBits, ulCount, ulHint);
521 if (ulPos != ~0UL)
522 RtlSetBits(lpBits, ulPos, ulCount);
523 return ulPos;
526 /*************************************************************************
527 * RtlNumberOfSetBits [NTDLL.@]
529 * Find the number of set bits in a bitmap.
531 * PARAMS
532 * lpBits [I] Bitmap pointer
534 * RETURNS
535 * The number of set bits.
537 ULONG WINAPI RtlNumberOfSetBits(PCRTL_BITMAP lpBits)
539 ULONG ulSet = 0;
541 TRACE("(%p)\n", lpBits);
543 if (lpBits)
545 LPBYTE lpOut = (BYTE *)lpBits->Buffer;
546 ULONG ulCount, ulRemainder;
547 BYTE bMasked;
549 ulCount = lpBits->SizeOfBitMap >> 3;
550 ulRemainder = lpBits->SizeOfBitMap & 0x7;
552 while (ulCount--)
554 ulSet += NTDLL_nibbleBitCount[*lpOut >> 4];
555 ulSet += NTDLL_nibbleBitCount[*lpOut & 0xf];
556 lpOut++;
559 bMasked = *lpOut & NTDLL_maskBits[ulRemainder];
560 ulSet += NTDLL_nibbleBitCount[bMasked >> 4];
561 ulSet += NTDLL_nibbleBitCount[bMasked & 0xf];
563 return ulSet;
566 /*************************************************************************
567 * RtlNumberOfClearBits [NTDLL.@]
569 * Find the number of clear bits in a bitmap.
571 * PARAMS
572 * lpBits [I] Bitmap pointer
574 * RETURNS
575 * The number of clear bits.
577 ULONG WINAPI RtlNumberOfClearBits(PCRTL_BITMAP lpBits)
579 TRACE("(%p)\n", lpBits);
581 if (lpBits)
582 return lpBits->SizeOfBitMap - RtlNumberOfSetBits(lpBits);
583 return 0;
586 /*************************************************************************
587 * RtlFindMostSignificantBit [NTDLL.@]
589 * Find the most significant bit in a 64 bit integer.
591 * RETURNS
592 * The position of the most significant bit.
594 CCHAR WINAPI RtlFindMostSignificantBit(ULONGLONG ulLong)
596 signed char ret = 32;
597 DWORD dw;
599 if (!(dw = (ulLong >> 32)))
601 ret = 0;
602 dw = (DWORD)ulLong;
604 if (dw & 0xffff0000)
606 dw >>= 16;
607 ret += 16;
609 if (dw & 0xff00)
611 dw >>= 8;
612 ret += 8;
614 if (dw & 0xf0)
616 dw >>= 4;
617 ret += 4;
619 return ret + NTDLL_mostSignificant[dw];
622 /*************************************************************************
623 * RtlFindLeastSignificantBit [NTDLL.@]
625 * Find the least significant bit in a 64 bit integer.
627 * RETURNS
628 * The position of the least significant bit.
630 CCHAR WINAPI RtlFindLeastSignificantBit(ULONGLONG ulLong)
632 signed char ret = 0;
633 DWORD dw;
635 if (!(dw = (DWORD)ulLong))
637 ret = 32;
638 if (!(dw = ulLong >> 32)) return -1;
640 if (!(dw & 0xffff))
642 dw >>= 16;
643 ret += 16;
645 if (!(dw & 0xff))
647 dw >>= 8;
648 ret += 8;
650 if (!(dw & 0x0f))
652 dw >>= 4;
653 ret += 4;
655 return ret + NTDLL_leastSignificant[dw & 0x0f];
658 /*************************************************************************
659 * NTDLL_RunSortFn
661 * Internal helper: qsort comparison function for RTL_BITMAP_RUN arrays
663 static int NTDLL_RunSortFn(const void *lhs, const void *rhs)
665 if (((const RTL_BITMAP_RUN*)lhs)->NumberOfBits > ((const RTL_BITMAP_RUN*)rhs)->NumberOfBits)
666 return -1;
667 return 1;
670 /*************************************************************************
671 * NTDLL_FindSetRun
673 * Internal helper: Find the next run of set bits in a bitmap.
675 static ULONG NTDLL_FindSetRun(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpSize)
677 LPBYTE lpOut;
678 ULONG ulFoundAt = 0, ulCount = 0;
680 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
681 * at a time. But beware of the pointer arithmetics...
683 lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
685 while (1)
687 /* Check bits in first byte */
688 const BYTE bMask = (0xff << (ulStart & 7)) & 0xff;
689 const BYTE bFirst = *lpOut & bMask;
691 if (bFirst)
693 /* Have a set bit in first byte */
694 if (bFirst != bMask)
696 /* Not every bit is set */
697 ULONG ulOffset;
699 if (bFirst & 0x0f)
700 ulOffset = NTDLL_leastSignificant[bFirst & 0x0f];
701 else
702 ulOffset = 4 + NTDLL_leastSignificant[bFirst >> 4];
703 ulStart += ulOffset;
704 ulFoundAt = ulStart;
705 for (;ulOffset < 8; ulOffset++)
707 if (!(bFirst & (1 << ulOffset)))
709 *lpSize = ulCount;
710 return ulFoundAt; /* Set from start, but not until the end */
712 ulCount++;
713 ulStart++;
715 /* Set to the end - go on to count further bits */
716 lpOut++;
717 break;
719 /* every bit from start until the end of the byte is set */
720 ulFoundAt = ulStart;
721 ulCount = 8 - (ulStart & 7);
722 ulStart = (ulStart & ~7u) + 8;
723 lpOut++;
724 break;
726 ulStart = (ulStart & ~7u) + 8;
727 lpOut++;
728 if (ulStart >= lpBits->SizeOfBitMap)
729 return ~0UL;
732 /* Count blocks of 8 set bits */
733 while (*lpOut == 0xff)
735 ulCount += 8;
736 ulStart += 8;
737 if (ulStart >= lpBits->SizeOfBitMap)
739 *lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap);
740 return ulFoundAt;
742 lpOut++;
745 /* Count remaining contiguous bits, if any */
746 if (*lpOut & 1)
748 ULONG ulOffset = 0;
750 for (;ulOffset < 7u; ulOffset++)
752 if (!(*lpOut & (1 << ulOffset)))
753 break;
754 ulCount++;
757 *lpSize = ulCount;
758 return ulFoundAt;
761 /*************************************************************************
762 * NTDLL_FindClearRun
764 * Internal helper: Find the next run of set bits in a bitmap.
766 static ULONG NTDLL_FindClearRun(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpSize)
768 LPBYTE lpOut;
769 ULONG ulFoundAt = 0, ulCount = 0;
771 /* FIXME: It might be more efficient/cleaner to manipulate four bytes
772 * at a time. But beware of the pointer arithmetics...
774 lpOut = ((BYTE*)lpBits->Buffer) + (ulStart >> 3u);
776 while (1)
778 /* Check bits in first byte */
779 const BYTE bMask = (0xff << (ulStart & 7)) & 0xff;
780 const BYTE bFirst = (~*lpOut) & bMask;
782 if (bFirst)
784 /* Have a clear bit in first byte */
785 if (bFirst != bMask)
787 /* Not every bit is clear */
788 ULONG ulOffset;
790 if (bFirst & 0x0f)
791 ulOffset = NTDLL_leastSignificant[bFirst & 0x0f];
792 else
793 ulOffset = 4 + NTDLL_leastSignificant[bFirst >> 4];
794 ulStart += ulOffset;
795 ulFoundAt = ulStart;
796 for (;ulOffset < 8; ulOffset++)
798 if (!(bFirst & (1 << ulOffset)))
800 *lpSize = ulCount;
801 return ulFoundAt; /* Clear from start, but not until the end */
803 ulCount++;
804 ulStart++;
806 /* Clear to the end - go on to count further bits */
807 lpOut++;
808 break;
810 /* Every bit from start until the end of the byte is clear */
811 ulFoundAt = ulStart;
812 ulCount = 8 - (ulStart & 7);
813 ulStart = (ulStart & ~7u) + 8;
814 lpOut++;
815 break;
817 ulStart = (ulStart & ~7u) + 8;
818 lpOut++;
819 if (ulStart >= lpBits->SizeOfBitMap)
820 return ~0UL;
823 /* Count blocks of 8 clear bits */
824 while (!*lpOut)
826 ulCount += 8;
827 ulStart += 8;
828 if (ulStart >= lpBits->SizeOfBitMap)
830 *lpSize = ulCount - (ulStart - lpBits->SizeOfBitMap);
831 return ulFoundAt;
833 lpOut++;
836 /* Count remaining contiguous bits, if any */
837 if (!(*lpOut & 1))
839 ULONG ulOffset = 0;
841 for (;ulOffset < 7u; ulOffset++)
843 if (*lpOut & (1 << ulOffset))
844 break;
845 ulCount++;
848 *lpSize = ulCount;
849 return ulFoundAt;
852 /*************************************************************************
853 * RtlFindNextForwardRunSet [NTDLL.@]
855 * Find the next run of set bits in a bitmap.
857 * PARAMS
858 * lpBits [I] Bitmap pointer
859 * ulStart [I] Bit position to start searching from
860 * lpPos [O] Start of run
862 * RETURNS
863 * Success: The length of the next set run in the bitmap. lpPos is set to
864 * the start of the run.
865 * Failure: 0, if no run is found or any parameters are invalid.
867 ULONG WINAPI RtlFindNextForwardRunSet(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
869 ULONG ulSize = 0;
871 TRACE("(%p,%ld,%p)\n", lpBits, ulStart, lpPos);
873 if (lpBits && ulStart < lpBits->SizeOfBitMap && lpPos)
874 *lpPos = NTDLL_FindSetRun(lpBits, ulStart, &ulSize);
876 return ulSize;
879 /*************************************************************************
880 * RtlFindNextForwardRunClear [NTDLL.@]
882 * Find the next run of clear bits in a bitmap.
884 * PARAMS
885 * lpBits [I] Bitmap pointer
886 * ulStart [I] Bit position to start searching from
887 * lpPos [O] Start of run
889 * RETURNS
890 * Success: The length of the next clear run in the bitmap. lpPos is set to
891 * the start of the run.
892 * Failure: 0, if no run is found or any parameters are invalid.
894 ULONG WINAPI RtlFindNextForwardRunClear(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
896 ULONG ulSize = 0;
898 TRACE("(%p,%ld,%p)\n", lpBits, ulStart, lpPos);
900 if (lpBits && ulStart < lpBits->SizeOfBitMap && lpPos)
901 *lpPos = NTDLL_FindClearRun(lpBits, ulStart, &ulSize);
903 return ulSize;
906 /*************************************************************************
907 * RtlFindLastBackwardRunSet [NTDLL.@]
909 * Find a previous run of set bits in a bitmap.
911 * PARAMS
912 * lpBits [I] Bitmap pointer
913 * ulStart [I] Bit position to start searching from
914 * lpPos [O] Start of run
916 * RETURNS
917 * Success: The length of the previous set run in the bitmap. lpPos is set to
918 * the start of the run.
919 * Failure: 0, if no run is found or any parameters are invalid.
921 ULONG WINAPI RtlFindLastBackwardRunSet(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
923 FIXME("(%p,%ld,%p)-stub!\n", lpBits, ulStart, lpPos);
924 return 0;
927 /*************************************************************************
928 * RtlFindLastBackwardRunClear [NTDLL.@]
930 * Find a previous run of clear bits in a bitmap.
932 * PARAMS
933 * lpBits [I] Bitmap pointer
934 * ulStart [I] Bit position to start searching from
935 * lpPos [O] Start of run
937 * RETURNS
938 * Success: The length of the previous clear run in the bitmap. lpPos is set
939 * to the start of the run.
940 * Failure: 0, if no run is found or any parameters are invalid.
942 ULONG WINAPI RtlFindLastBackwardRunClear(PCRTL_BITMAP lpBits, ULONG ulStart, PULONG lpPos)
944 FIXME("(%p,%ld,%p)-stub!\n", lpBits, ulStart, lpPos);
945 return 0;
948 /*************************************************************************
949 * NTDLL_FindRuns
951 * Internal implementation of RtlFindSetRuns/RtlFindClearRuns.
953 static ULONG WINAPI NTDLL_FindRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
954 ULONG ulCount, BOOLEAN bLongest,
955 ULONG (*fn)(PCRTL_BITMAP,ULONG,PULONG))
957 BOOL bNeedSort = ulCount > 1 ? TRUE : FALSE;
958 ULONG ulPos = 0, ulRuns = 0;
960 TRACE("(%p,%p,%ld,%d)\n", lpBits, lpSeries, ulCount, bLongest);
962 if (!ulCount)
963 return ~0UL;
965 while (ulPos < lpBits->SizeOfBitMap)
967 /* Find next set/clear run */
968 ULONG ulSize, ulNextPos = fn(lpBits, ulPos, &ulSize);
970 if (ulNextPos == ~0UL)
971 break;
973 if (bLongest && ulRuns == ulCount)
975 /* Sort runs with shortest at end, if they are out of order */
976 if (bNeedSort)
977 qsort(lpSeries, ulRuns, sizeof(RTL_BITMAP_RUN), NTDLL_RunSortFn);
979 /* Replace last run if this one is bigger */
980 if (ulSize > lpSeries[ulRuns - 1].NumberOfBits)
982 lpSeries[ulRuns - 1].StartingIndex = ulNextPos;
983 lpSeries[ulRuns - 1].NumberOfBits = ulSize;
985 /* We need to re-sort the array, _if_ we didn't leave it sorted */
986 if (ulRuns > 1 && ulSize > lpSeries[ulRuns - 2].NumberOfBits)
987 bNeedSort = TRUE;
990 else
992 /* Append to found runs */
993 lpSeries[ulRuns].StartingIndex = ulNextPos;
994 lpSeries[ulRuns].NumberOfBits = ulSize;
995 ulRuns++;
997 if (!bLongest && ulRuns == ulCount)
998 break;
1000 ulPos = ulNextPos + ulSize;
1002 return ulRuns;
1005 /*************************************************************************
1006 * RtlFindSetRuns [NTDLL.@]
1008 * Find a series of set runs in a bitmap.
1010 * PARAMS
1011 * lpBits [I] Bitmap pointer
1012 * lpSeries [O] Array for each run found
1013 * ulCount [I] Number of runs to find
1014 * bLongest [I] Whether to find the very longest runs or not
1016 * RETURNS
1017 * The number of set runs found.
1019 ULONG WINAPI RtlFindSetRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
1020 ULONG ulCount, BOOLEAN bLongest)
1022 TRACE("(%p,%p,%ld,%d)\n", lpBits, lpSeries, ulCount, bLongest);
1024 return NTDLL_FindRuns(lpBits, lpSeries, ulCount, bLongest, NTDLL_FindSetRun);
1027 /*************************************************************************
1028 * RtlFindClearRuns [NTDLL.@]
1030 * Find a series of clear runs in a bitmap.
1032 * PARAMS
1033 * lpBits [I] Bitmap pointer
1034 * ulSeries [O] Array for each run found
1035 * ulCount [I] Number of runs to find
1036 * bLongest [I] Whether to find the very longest runs or not
1038 * RETURNS
1039 * The number of clear runs found.
1041 ULONG WINAPI RtlFindClearRuns(PCRTL_BITMAP lpBits, PRTL_BITMAP_RUN lpSeries,
1042 ULONG ulCount, BOOLEAN bLongest)
1044 TRACE("(%p,%p,%ld,%d)\n", lpBits, lpSeries, ulCount, bLongest);
1046 return NTDLL_FindRuns(lpBits, lpSeries, ulCount, bLongest, NTDLL_FindClearRun);
1049 /*************************************************************************
1050 * RtlFindLongestRunSet [NTDLL.@]
1052 * Find the longest set run in a bitmap.
1054 * PARAMS
1055 * lpBits [I] Bitmap pointer
1056 * pulStart [O] Destination for start of run
1058 * RETURNS
1059 * The length of the run found, or 0 if no run is found.
1061 ULONG WINAPI RtlFindLongestRunSet(PCRTL_BITMAP lpBits, PULONG pulStart)
1063 RTL_BITMAP_RUN br;
1065 TRACE("(%p,%p)\n", lpBits, pulStart);
1067 if (RtlFindSetRuns(lpBits, &br, 1, TRUE) == 1)
1069 if (pulStart)
1070 *pulStart = br.StartingIndex;
1071 return br.NumberOfBits;
1073 return 0;
1076 /*************************************************************************
1077 * RtlFindLongestRunClear [NTDLL.@]
1079 * Find the longest clear run in a bitmap.
1081 * PARAMS
1082 * lpBits [I] Bitmap pointer
1083 * pulStart [O] Destination for start of run
1085 * RETURNS
1086 * The length of the run found, or 0 if no run is found.
1088 ULONG WINAPI RtlFindLongestRunClear(PCRTL_BITMAP lpBits, PULONG pulStart)
1090 RTL_BITMAP_RUN br;
1092 TRACE("(%p,%p)\n", lpBits, pulStart);
1094 if (RtlFindClearRuns(lpBits, &br, 1, TRUE) == 1)
1096 if (pulStart)
1097 *pulStart = br.StartingIndex;
1098 return br.NumberOfBits;
1100 return 0;