blob: fc90fd05c09539e971f43199a157dd9cb732da57 [file] [log] [blame]
/* ------------------------------------------------------------------
* Copyright (C) 1998-2009 PacketVideo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
* -------------------------------------------------------------------
*/
#include "bitstreamparser.h"
#include "oscl_assert.h"
#include "oscl_byte_order.h"
#include "oscl_dll.h"
OSCL_EXPORT_REF BitStreamParser::BitStreamParser(uint8* stream, uint32 size)
{
ResetBitStreamParser(stream, size);
}
OSCL_EXPORT_REF void BitStreamParser::ResetBitStreamParser(uint8* stream, uint32 size)
{
this->size = size;
start = OSCL_STATIC_CAST(uint8*, stream);
bytepos = OSCL_STATIC_CAST(uint8*, start);
bitpos = MOST_SIG_BIT;
}
OSCL_EXPORT_REF uint32 BitStreamParser::ReadBits(uint8 numberOfBits)
{
// Make sure bytepos won't exceed the size of the buffer while reading
if ((bytepos + numberOfBits) >= (start + size))
{
OSCL_LEAVE(OsclErrOverflow);
}
//Initialize output to zero before shifting out bits.
uint32 output = 0;
OSCL_ASSERT(numberOfBits <= BITS_PER_UINT32);
//In case OSCL_ASSERT is defined to do nothing, set the max size.
if (numberOfBits > BITS_PER_UINT32) numberOfBits = BITS_PER_UINT32;
//Note: Using the host's native shift operator will automatically
//convert from big endian to host's endianness.
while (numberOfBits)
{
//Optimize reads for special cases such as byte-aligned reads and
//processing multiple bits at a time.
if ((numberOfBits >= BITS_PER_UINT8) && (bitpos == MOST_SIG_BIT))
{
//This is the special case where a read is a whole byte (aligned).
//Shift the output over 8 bits.
output <<= BITS_PER_UINT8;
//OR the current byte from the stream into the output.
output |= *bytepos;
//Advance the stream byte pointer.
bytepos++;
//Decrement the number of bits left to read.
numberOfBits -= BITS_PER_UINT8;
}
else //Read one or more bits at a time.
{
//Define the bitmask corresponding to the number of bits
//to read from the current byte.
//This is implemented as a static look-up table for efficiency.
static const uint8 bitmask[] =
{
0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff
};
//Process the bits in the current byte...
//Determine the number of bits remaining in the current byte of the stream.
//This is the upper limit on the number of bits we will read
//this through the loop.
uint8 bitsFromThisByte = bitpos + 1;
//If more bits remain then we need, only take what we need.
if (bitsFromThisByte > numberOfBits) bitsFromThisByte = numberOfBits;
//Shift the output value over to make room for the new bits to read.
output <<= bitsFromThisByte;
//OR in the bits from the stream.
//This reads the current byte from the stream,
//shifts it over so the bits we want are at the LS end,
//and masks off all of the bits except the ones we want.
output |= ((*bytepos) >> (bitpos - (bitsFromThisByte - 1))) & bitmask[bitsFromThisByte];
//Decrement the numberOfBits remaining...
numberOfBits -= bitsFromThisByte;
//...and advance the bitpos and bytepos pointers.
NextBits(bitsFromThisByte);
}
}
return output;
}
OSCL_EXPORT_REF uint8 BitStreamParser::ReadUInt8(void)
{
//If bitpos is not on a byte boundary, have to use ReadBits...
if (bitpos != MOST_SIG_BIT) return ReadBits(BITS_PER_UINT8);
// Make sure the current bytepos doesn't exceed the size of the buffer
if (bytepos >= (start + size))
{
OSCL_LEAVE(OsclErrOverflow);
}
uint8 read = *bytepos;
bytepos++;
return read;
}
OSCL_EXPORT_REF uint16 BitStreamParser::ReadUInt16(void)
{
uint16 read;
((uint8*)&read)[0] = ReadUInt8();
((uint8*)&read)[1] = ReadUInt8();
big_endian_to_host((char*)&read, sizeof(read));
return read;
}
OSCL_EXPORT_REF uint32 BitStreamParser::ReadUInt32(void)
{
uint32 read;
((uint8*)&read)[0] = ReadUInt8();
((uint8*)&read)[1] = ReadUInt8();
((uint8*)&read)[2] = ReadUInt8();
((uint8*)&read)[3] = ReadUInt8();
big_endian_to_host((char*)&read, sizeof(read));
return read;
}
OSCL_EXPORT_REF void BitStreamParser::WriteBits(uint8 numberOfBits, const uint8* data)
{
//This is not the most efficient algorithm, but it is the least complex.
//Treat "data" as an input stream.
BitStreamParser input(const_cast<uint8*>(data), BITS_TO_BYTES(numberOfBits));
//Skip over the unused bits.
input.NextBits(input.BitsLeft() - numberOfBits);
//Loop through each bit to process...
while (numberOfBits)
{
uint8 bitmask = 1 << bitpos;
//READ
uint8 byte = *bytepos;
//MODIFY
byte &= ~(bitmask); //Clear the bit being written.
byte |= (input.ReadBits(1) << bitpos); //Write the bit.
//WRITE
*bytepos = byte;
//Advance the bit pointer
NextBit();
numberOfBits--;
}
}
OSCL_EXPORT_REF void BitStreamParser::WriteUInt8(uint8 data)
{
if (bitpos != MOST_SIG_BIT)
{
WriteBits(BITS_PER_BYTE, &data);
}
else
{
if (bytepos >= (start + size))
{
OSCL_LEAVE(OsclErrOverflow);
}
*bytepos = data;
bytepos++;
}
}
OSCL_EXPORT_REF void BitStreamParser::WriteUInt16(uint16 data)
{
uint16 be = data;
host_to_big_endian((char*)&be, sizeof(be));
WriteUInt8(((uint8*)&be)[0]);
WriteUInt8(((uint8*)&be)[1]);
}
OSCL_EXPORT_REF void BitStreamParser::WriteUInt32(uint32 data)
{
uint32 be = data;
host_to_big_endian((char*)&be, sizeof(be));
WriteUInt8(((uint8*)&be)[0]);
WriteUInt8(((uint8*)&be)[1]);
WriteUInt8(((uint8*)&be)[2]);
WriteUInt8(((uint8*)&be)[3]);
}
OSCL_EXPORT_REF void BitStreamParser::NextBits(uint32 numberOfBits)
{
// Make sure bytepos won't exceed the size of the buffer while reading
if ((bytepos + numberOfBits) >= (start + size))
{
OSCL_LEAVE(OsclErrOverflow);
}
//bitpos counts down from 7 to 0, so subtract it from 7 to get the ascending position.
uint32 newbitpos = numberOfBits + (MOST_SIG_BIT - bitpos);
//Convert the ascending bit position to a descending position using only the least-significant bits.
bitpos = MOST_SIG_BIT - (newbitpos & LEAST_SIG_3_BITS_MASK);
//Calculate the number of bytes advanced.
bytepos += (newbitpos / BITS_PER_BYTE);
}