///
// GetBitSlice - Get a bit slice from a stream of bytes
// Input: pBuffer - buffer containing data stream
// cbBuffer - size of buffer in bytes
// dwBitOffset - bit offset from start of buffer
// ucBitCount - number of bits (less than or equal to 32)
// Output:
//
// Return: returns a DWORD contain the bit slice shifted to fill the least significant bits
// Notes: will raise an SEH exception if integer overflow occurs
///
DWORD GetBitSlice(PUCHAR pBuffer, ULONG cbBuffer, DWORD dwBitOffset, UCHAR ucBitCount)
{
UCHAR rgbShifted[4] = { 0 };
DWORD dwUsedBytes; // How many bytes have valid data.
DWORD dwLastByteIndex;
DWORD dwRemainderShift;
DWORD dwRet;
if (ucBitCount > 32) {
DEBUG_CHECK(FALSE, (TEXT("GetBitSlice: invalid number of bits /n")));
return 0;
}
// Shift the pBuffer down by dwBitOffset bits.
ShiftBytes(pBuffer, cbBuffer, dwBitOffset, rgbShifted);
if (ucBitCount % 8 == 0) {
// Return a byte multiple.
dwUsedBytes = ucBitCount / 8;
}
else {
// Clear the last used byte of upper bits.
dwLastByteIndex = (ucBitCount - 1) / 8;
dwRemainderShift = 8 - (ucBitCount % 8);
rgbShifted[dwLastByteIndex] <<= dwRemainderShift;
rgbShifted[dwLastByteIndex] >>= dwRemainderShift;
dwUsedBytes = dwLastByteIndex + 1;
}
// Clear the unused bytes.
if (dwUsedBytes != sizeof(rgbShifted)) {
memset(rgbShifted + dwUsedBytes, 0, sizeof(rgbShifted) - dwUsedBytes);
}
memcpy(&dwRet, rgbShifted, sizeof(dwRet));
return dwRet;
}
static
VOID ShiftBytes(PBYTE pbInput, ULONG cbInput, DWORD dwBitOffset, PBYTE pbOutput)
{
DWORD dwRemainderShift;
DWORD dwByteIndex;
DWORD dwEndIndex;
DWORD dwCurrOutputIndex = 0;
dwByteIndex = dwBitOffset / 8;
dwBitOffset %= 8;
dwRemainderShift = 8 - dwBitOffset;
// Only copy 4 bytes max.
dwEndIndex = min(dwByteIndex + sizeof(DWORD), cbInput);
while (dwByteIndex < dwEndIndex) {
pbOutput[dwCurrOutputIndex] = pbInput[dwByteIndex] >> dwBitOffset;
++dwByteIndex;
if (dwByteIndex != cbInput) {
BYTE bTemp = pbInput[dwByteIndex];
bTemp <<= dwRemainderShift;
pbOutput[dwCurrOutputIndex] |= bTemp;
}
++dwCurrOutputIndex;
}
}