579 lines
15 KiB
C++
Executable File
579 lines
15 KiB
C++
Executable File
/*===========================================================================
|
|
FILE:
|
|
BitParser.cpp
|
|
|
|
DESCRIPTION:
|
|
Implementation of cBitParser class
|
|
|
|
PUBLIC CLASSES AND METHODS:
|
|
cBitParser
|
|
This class extracts bits from a buffer
|
|
|
|
Copyright (c) 2011, Code Aurora Forum. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
* Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
* Neither the name of Code Aurora Forum nor
|
|
the names of its contributors may be used to endorse or promote
|
|
products derived from this software without specific prior written
|
|
permission.
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
===========================================================================*/
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Include Files
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "StdAfx.h"
|
|
#include "BitParser.h"
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Definitions
|
|
//---------------------------------------------------------------------------
|
|
|
|
static BYTE MASK[BITS_PER_BYTE + 1] =
|
|
{
|
|
0x00,
|
|
0x01,
|
|
0x03,
|
|
0x07,
|
|
0x0F,
|
|
0x1F,
|
|
0x3F,
|
|
0x7F,
|
|
0xFF
|
|
};
|
|
|
|
/*=========================================================================*/
|
|
// Free Methods
|
|
/*=========================================================================*/
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
GetUnsignedVal (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Get an unsigned value from the bit source (reading least significant
|
|
bits first)
|
|
|
|
PARAMETERS:
|
|
pData [ I ] - Data buffer
|
|
currentOffset [I/O] - Current bit offset into above buffer
|
|
maxOffset [ I ] - Maximum bit offset into above buffer
|
|
numBits [ I ] - Number of bits to process
|
|
dataOut [ O ] - Processed value
|
|
bLSB [ I ] - Parse LSB -> MSB?
|
|
|
|
RETURN VALUE:
|
|
DWORD
|
|
===========================================================================*/
|
|
template <class T>
|
|
DWORD GetUnsignedVal(
|
|
const BYTE * pData,
|
|
ULONG & currentOffset,
|
|
ULONG maxOffset,
|
|
ULONG numBits,
|
|
T & dataOut,
|
|
bool bLSB = true )
|
|
{
|
|
ASSERT( pData != 0 );
|
|
|
|
// Number of bits in the passed in type
|
|
const ULONG TYPE_BIT_COUNT = (ULONG)(sizeof( T ) * BITS_PER_BYTE);
|
|
|
|
// Bad parameters?
|
|
if (numBits == 0 || numBits > TYPE_BIT_COUNT || numBits > MAX_TYPE_BITS)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Requesting too much?
|
|
if (currentOffset < maxOffset)
|
|
{
|
|
ULONG bitsToGo = maxOffset - currentOffset;
|
|
if (bitsToGo < numBits)
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No bits left!
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
// Advance to first valid bit
|
|
pData += (currentOffset / BITS_PER_BYTE);
|
|
|
|
// Number of bits left in current byte
|
|
ULONG bitsLeft = BITS_PER_BYTE - (currentOffset % BITS_PER_BYTE);
|
|
|
|
if (bLSB == true)
|
|
{
|
|
// Extracting native types on byte boundaries?
|
|
if (numBits == TYPE_BIT_COUNT && bitsLeft == BITS_PER_BYTE)
|
|
{
|
|
// Yes, a simple cast will suffice
|
|
dataOut = *((T *)pData);
|
|
|
|
currentOffset += numBits;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
// Extracting some small number of bits?
|
|
if (numBits <= bitsLeft)
|
|
{
|
|
// Yes, simply shift back to origin and AND with correct mask
|
|
BYTE tmp = *pData;
|
|
tmp >>= (BITS_PER_BYTE - bitsLeft);
|
|
tmp &= MASK[numBits];
|
|
|
|
dataOut = (T)tmp;
|
|
|
|
currentOffset += numBits;
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
|
|
// Not either of the simple cases - extract the relevant bits
|
|
// and then build the output
|
|
|
|
// Extract bits
|
|
BYTE bits[MAX_TYPE_BITS];
|
|
ULONG bitsExtracted = 0;
|
|
|
|
while (bitsExtracted < numBits)
|
|
{
|
|
BYTE bit = *pData;
|
|
|
|
if (bLSB == true)
|
|
{
|
|
bit <<= (bitsLeft - 1);
|
|
bit >>= (BITS_PER_BYTE - 1);
|
|
bits[bitsExtracted++] = bit;
|
|
}
|
|
else
|
|
{
|
|
bit >>= (bitsLeft - 1);
|
|
bit &= 0x01;
|
|
bits[numBits - ++bitsExtracted] = bit;
|
|
}
|
|
|
|
bitsLeft--;
|
|
if (bitsLeft == 0)
|
|
{
|
|
pData++;
|
|
bitsLeft = BITS_PER_BYTE;
|
|
}
|
|
}
|
|
|
|
// Reassemble to form output value
|
|
dataOut = 0;
|
|
T tmp = 0;
|
|
|
|
for (ULONG b = 0; b < numBits; b++)
|
|
{
|
|
tmp = bits[b];
|
|
tmp <<= b;
|
|
|
|
dataOut |= tmp;
|
|
}
|
|
|
|
currentOffset += numBits;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
GetSignedVal (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Get an signed value from the bit source (reading least significant
|
|
bits first), just gets the equivalent unsigned representation and
|
|
then sign-extends as necessary
|
|
|
|
PARAMETERS:
|
|
pData [ I ] - Data buffer
|
|
currentOffset [I/O] - Current bit offset into above buffer
|
|
maxOffset [ I ] - Maximum bit offset into above buffer
|
|
numBits [ I ] - Number of bits to process
|
|
dataOut [ O ] - Processed value
|
|
bLSB [ I ] - Parse LSB -> MSB?
|
|
|
|
RETURN VALUE:
|
|
DWORD
|
|
===========================================================================*/
|
|
template <class T>
|
|
DWORD GetSignedVal(
|
|
const BYTE * pData,
|
|
ULONG & currentOffset,
|
|
ULONG maxOffset,
|
|
ULONG numBits,
|
|
T & dataOut,
|
|
bool bLSB = true )
|
|
{
|
|
DWORD rc = GetUnsignedVal( pData,
|
|
currentOffset,
|
|
maxOffset,
|
|
numBits,
|
|
dataOut,
|
|
bLSB );
|
|
|
|
if (rc == NO_ERROR)
|
|
{
|
|
// If the highest-order bit is one, we must sign-extend
|
|
bool bSignExtend = (numBits < (sizeof( T ) * BITS_PER_BYTE))
|
|
&& ((dataOut >> (numBits - 1)) & 1) == 1;
|
|
|
|
if (bSignExtend == true)
|
|
{
|
|
T mask = (T)((~0) << numBits);
|
|
dataOut |= mask;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*=========================================================================*/
|
|
// cBitParser Methods
|
|
/*=========================================================================*/
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
cBitParser (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Constructor (default)
|
|
|
|
RETURN VALUE:
|
|
None
|
|
===========================================================================*/
|
|
cBitParser::cBitParser()
|
|
: mpData( 0 ),
|
|
mOffset( 0 ),
|
|
mMaxOffset( 0 ),
|
|
mbLSB( true )
|
|
{
|
|
// Nothing to do
|
|
}
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
cBitParser (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Constructor (from a buffer)
|
|
|
|
PARAMETERS:
|
|
pData [ I ] - Data buffer
|
|
dataBitSize [ I ] - Size of above data buffer (in bits)
|
|
|
|
RETURN VALUE:
|
|
None
|
|
===========================================================================*/
|
|
cBitParser::cBitParser(
|
|
const BYTE * pData,
|
|
ULONG dataBitSize )
|
|
: mpData( 0 ),
|
|
mOffset( 0 ),
|
|
mMaxOffset( 0 ),
|
|
mbLSB( true )
|
|
{
|
|
SetData( pData, dataBitSize );
|
|
}
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
cBitParser (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Destructor
|
|
|
|
RETURN VALUE:
|
|
None
|
|
===========================================================================*/
|
|
cBitParser::~cBitParser()
|
|
{
|
|
// Nothing to do
|
|
}
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
Get (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Return 'numBits' as a CHAR (advances offset)
|
|
|
|
PARAMETERS:
|
|
numBits [ I ] - Number of bits to process
|
|
dataOut [ O ] - Processed value
|
|
|
|
RETURN VALUE:
|
|
DWORD
|
|
===========================================================================*/
|
|
DWORD cBitParser::Get(
|
|
ULONG numBits,
|
|
CHAR & dataOut )
|
|
{
|
|
return GetSignedVal( mpData,
|
|
mOffset,
|
|
mMaxOffset,
|
|
numBits,
|
|
dataOut,
|
|
mbLSB );
|
|
}
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
Get (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Return 'numBits' as a SHORT (advances offset)
|
|
|
|
PARAMETERS:
|
|
numBits [ I ] - Number of bits to process
|
|
dataOut [ O ] - Processed value
|
|
|
|
RETURN VALUE:
|
|
DWORD
|
|
===========================================================================*/
|
|
DWORD cBitParser::Get(
|
|
ULONG numBits,
|
|
SHORT & dataOut )
|
|
{
|
|
return GetSignedVal( mpData,
|
|
mOffset,
|
|
mMaxOffset,
|
|
numBits,
|
|
dataOut,
|
|
mbLSB );
|
|
}
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
Get (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Return 'numBits' as a LONG (advances offset)
|
|
|
|
PARAMETERS:
|
|
numBits [ I ] - Number of bits to process
|
|
dataOut [ O ] - Processed value
|
|
|
|
RETURN VALUE:
|
|
DWORD
|
|
===========================================================================*/
|
|
DWORD cBitParser::Get(
|
|
ULONG numBits,
|
|
LONG & dataOut )
|
|
{
|
|
return GetSignedVal( mpData,
|
|
mOffset,
|
|
mMaxOffset,
|
|
numBits,
|
|
dataOut,
|
|
mbLSB );
|
|
}
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
Get (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Return 'numBits' as a LONGLONG (advances offset)
|
|
|
|
PARAMETERS:
|
|
numBits [ I ] - Number of bits to process
|
|
dataOut [ O ] - Processed value
|
|
|
|
RETURN VALUE:
|
|
DWORD
|
|
===========================================================================*/
|
|
DWORD cBitParser::Get(
|
|
ULONG numBits,
|
|
LONGLONG & dataOut )
|
|
{
|
|
return GetSignedVal( mpData,
|
|
mOffset,
|
|
mMaxOffset,
|
|
numBits,
|
|
dataOut,
|
|
mbLSB );
|
|
}
|
|
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
Get (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Return 'numBits' as a UCHAR (advances offset)
|
|
|
|
PARAMETERS:
|
|
numBits [ I ] - Number of bits to process
|
|
dataOut [ O ] - Processed value
|
|
|
|
RETURN VALUE:
|
|
DWORD
|
|
===========================================================================*/
|
|
DWORD cBitParser::Get(
|
|
ULONG numBits,
|
|
UCHAR & dataOut )
|
|
{
|
|
return GetUnsignedVal( mpData,
|
|
mOffset,
|
|
mMaxOffset,
|
|
numBits,
|
|
dataOut,
|
|
mbLSB );
|
|
}
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
Get (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Return 'numBits' as a USHORT (advances offset)
|
|
|
|
PARAMETERS:
|
|
numBits [ I ] - Number of bits to process
|
|
dataOut [ O ] - Processed value
|
|
|
|
RETURN VALUE:
|
|
DWORD
|
|
===========================================================================*/
|
|
DWORD cBitParser::Get(
|
|
ULONG numBits,
|
|
USHORT & dataOut )
|
|
{
|
|
return GetUnsignedVal( mpData,
|
|
mOffset,
|
|
mMaxOffset,
|
|
numBits,
|
|
dataOut,
|
|
mbLSB );
|
|
}
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
Get (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Return 'numBits' as a ULONG (advances offset)
|
|
|
|
PARAMETERS:
|
|
numBits [ I ] - Number of bits to process
|
|
dataOut [ O ] - Processed value
|
|
|
|
RETURN VALUE:
|
|
DWORD
|
|
===========================================================================*/
|
|
DWORD cBitParser::Get(
|
|
ULONG numBits,
|
|
ULONG & dataOut )
|
|
{
|
|
return GetUnsignedVal( mpData,
|
|
mOffset,
|
|
mMaxOffset,
|
|
numBits,
|
|
dataOut,
|
|
mbLSB );
|
|
}
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
Get (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Return 'numBits' as a ULONGLONG (advances offset)
|
|
|
|
PARAMETERS:
|
|
numBits [ I ] - Number of bits to process
|
|
dataOut [ O ] - Processed value
|
|
|
|
RETURN VALUE:
|
|
DWORD
|
|
===========================================================================*/
|
|
DWORD cBitParser::Get(
|
|
ULONG numBits,
|
|
ULONGLONG & dataOut )
|
|
{
|
|
return GetUnsignedVal( mpData,
|
|
mOffset,
|
|
mMaxOffset,
|
|
numBits,
|
|
dataOut,
|
|
mbLSB );
|
|
}
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
ReleaseData (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Release the data being parsed
|
|
|
|
RETURN VALUE:
|
|
None
|
|
===========================================================================*/
|
|
void cBitParser::ReleaseData()
|
|
{
|
|
// Clear out current buffer
|
|
mpData = 0;
|
|
mOffset = 0;
|
|
mMaxOffset = 0;
|
|
};
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
SetData (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Set the data being parsed
|
|
|
|
PARAMETERS:
|
|
pData [ I ] - Data buffer
|
|
dataBitSize [ I ] - Size of above data buffer (in bits)
|
|
|
|
RETURN VALUE:
|
|
None
|
|
===========================================================================*/
|
|
void cBitParser::SetData(
|
|
const BYTE * pData,
|
|
ULONG dataBitSize )
|
|
{
|
|
// Release current buffer
|
|
ReleaseData();
|
|
|
|
// Anything to parse?
|
|
if (pData != 0)
|
|
{
|
|
// Yes
|
|
mpData = pData;
|
|
mMaxOffset = dataBitSize;
|
|
}
|
|
else
|
|
{
|
|
// No
|
|
ASSERT( mpData != 0 );
|
|
}
|
|
}
|