715 lines
15 KiB
C++
715 lines
15 KiB
C++
#ifndef N_BITSTREAM_H
|
|
#define N_BITSTREAM_H
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
@author
|
|
- RadonLabs GmbH
|
|
|
|
@since
|
|
- 2005.6.30
|
|
@remarks
|
|
- Áö¿Ï Ãß°¡
|
|
*/
|
|
|
|
#include <memory.h>
|
|
#include "../ProgramCommon/Define.h"
|
|
#include "nnode.h"
|
|
|
|
//------------------------------------------------------------------------------
|
|
class nBitStream : public nNode
|
|
{
|
|
public:
|
|
/// standard constructor, requires separate SetSize()
|
|
nBitStream();
|
|
/// constructor, expects stream size in bytes
|
|
nBitStream(int size);
|
|
/// the destructor
|
|
virtual ~nBitStream();
|
|
|
|
/// directly set contents of stream
|
|
void Set(const uchar* s, int size);
|
|
/// directly get contents of stream
|
|
const uchar* Get() const;
|
|
/// Set size of stream.
|
|
void SetSize(int size);
|
|
/// get the byte size of the stream
|
|
int GetSize() const;
|
|
/// set the current bit position in the stream
|
|
void SetPos(int pos);
|
|
/// return the current bit position in the stream
|
|
int GetPos() const;
|
|
/// return the number of bits left in the stream
|
|
int BitsLeft() const;
|
|
|
|
/// write a bool to the stream
|
|
void WriteBool(bool flag);
|
|
/// read a bool from the stream
|
|
bool ReadBool();
|
|
/// write a compressed integer to the stream
|
|
void WriteInt(int value, int numBits);
|
|
/// read a compressed integer from the stream
|
|
int ReadInt(int numBits);
|
|
/// write a float to the stream
|
|
void WriteFloat(float value);
|
|
/// read a float from the stream
|
|
float ReadFloat();
|
|
/// write a custom byte array to the stream
|
|
void WriteCustom(const void* ptr, int size);
|
|
/// read a custom byte array from the stream
|
|
void ReadCustom(void* ptr, int size);
|
|
/// write bitstream
|
|
void WriteBitStream(nBitStream& stream);
|
|
/// read bitstream
|
|
void ReadBitStream(nBitStream& stream);
|
|
/// copy data from source stream into this stream
|
|
void Copy(const nBitStream& source);
|
|
|
|
/// Lock for writing.
|
|
void BeginWrite();
|
|
/// Unlock for writing.
|
|
void EndWrite();
|
|
/// Lock for reading.
|
|
void BeginRead();
|
|
/// Unlock for reading.
|
|
void EndRead();
|
|
/// Writeable?
|
|
bool IsWriteable() const;
|
|
/// Readable?
|
|
bool IsReadable() const;
|
|
|
|
/// Assignment operator.
|
|
nBitStream& operator = (const nBitStream& s);
|
|
/// Equality operator.
|
|
bool operator == (const nBitStream& s) const;
|
|
/// Inequality operator.
|
|
bool operator != (const nBitStream& s) const;
|
|
|
|
// output
|
|
void Print(int lines);
|
|
|
|
protected:
|
|
/// clear stream contents, do not rewind bit pointer
|
|
void Clear();
|
|
/// Write bit at current position to stream.
|
|
void WriteBit(bool bit);
|
|
/// Read bit at currernt position from stream.
|
|
bool ReadBit();
|
|
|
|
private:
|
|
unsigned char* stream;
|
|
int streamSize;
|
|
int currentByte; /// Current index in the stream buffer.
|
|
int currentBit; /// Current bit offset int currentByte.
|
|
bool writeable;
|
|
bool readable;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
nBitStream::nBitStream()
|
|
{
|
|
streamSize = 0;
|
|
currentByte = 0;
|
|
currentBit = 0;
|
|
writeable = false;
|
|
readable = false;
|
|
stream = 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
@param size the byte size of the bit stream (rounded up)
|
|
*/
|
|
inline
|
|
nBitStream::nBitStream(int size)
|
|
{
|
|
// require
|
|
ASSERT(size > 0);
|
|
|
|
streamSize = size;
|
|
currentByte = 0;
|
|
currentBit = 0;
|
|
writeable = false;
|
|
readable = false;
|
|
|
|
stream = new unsigned char[size];
|
|
if (stream != 0)
|
|
{
|
|
memset(stream, 0, streamSize);
|
|
}
|
|
|
|
// ensure
|
|
ASSERT(stream != 0);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
nBitStream::~nBitStream()
|
|
{
|
|
if (stream != 0)
|
|
{
|
|
delete[] stream;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::Clear()
|
|
{
|
|
// require
|
|
ASSERT( stream != 0 );
|
|
ASSERT( streamSize > 0 );
|
|
|
|
memset(stream, 0, streamSize);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Write a bool value (always encoded into 1 bit) to the current
|
|
stream position.
|
|
|
|
@param flag the bool value
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::WriteBool(bool flag)
|
|
{
|
|
ASSERT(writeable);
|
|
|
|
WriteBit(flag);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Reads a bool value (always encoded into 1 bit) from the current
|
|
stream position.
|
|
|
|
@return the bool value
|
|
*/
|
|
inline
|
|
bool
|
|
nBitStream::ReadBool()
|
|
{
|
|
ASSERT(readable);
|
|
|
|
return ReadBit();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Write a signed integer clamped to numBits bits.
|
|
|
|
@param value the integer value to write
|
|
@param numBits number of bits to write
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::WriteInt(int value, int numBits)
|
|
{
|
|
ASSERT(writeable);
|
|
ASSERT((1 < numBits) && (numBits <= 32));
|
|
ASSERT(BitsLeft() >= numBits);
|
|
|
|
// Write sign
|
|
int tmp = (1 << 31);
|
|
int tmp2 = (value & tmp);
|
|
WriteBit(tmp2 != 0);
|
|
numBits -= 2; // I use numBits for shifting
|
|
// 1 Bit less for sign
|
|
// 1 Bit less for shifting
|
|
|
|
// Make absolute value;
|
|
// write sign and value separate
|
|
value = n_abs(value);
|
|
|
|
// Write value
|
|
while (numBits >= 0)
|
|
{
|
|
tmp = (1 << numBits);
|
|
tmp2 = (value & tmp);
|
|
WriteBit(tmp2 != 0);
|
|
numBits--;
|
|
}
|
|
|
|
ASSERT(numBits == -1);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Read a signed integer clamped to numBits bits, the rest of the
|
|
32 bytes will be filled with the correct sign bit.
|
|
|
|
@param numBits number of bits to read
|
|
@return the integer, correclty expanded to 32 bits
|
|
*/
|
|
inline
|
|
int
|
|
nBitStream::ReadInt(int numBits)
|
|
{
|
|
ASSERT(readable);
|
|
ASSERT((1 < numBits) && (numBits <= 32));
|
|
ASSERT(BitsLeft() >= numBits);
|
|
|
|
int value = 0;
|
|
|
|
// Read sign
|
|
bool sign = ReadBit();
|
|
numBits -= 2; // I use numBits for shifting
|
|
// 1 Bit less for sign
|
|
// 1 Bit less for shifting
|
|
|
|
// Read data
|
|
while (numBits >= 0)
|
|
{
|
|
int v = ReadBit() ? 1 : 0;
|
|
value |= (v << numBits);
|
|
numBits--;
|
|
}
|
|
|
|
ASSERT(numBits == -1);
|
|
|
|
// set sign
|
|
if (sign)
|
|
{
|
|
value = -value;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Write a float value into the stream, the float value will always be
|
|
encoded into 32 bits.
|
|
|
|
@param value the float value to write
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::WriteFloat(float value)
|
|
{
|
|
ASSERT(writeable);
|
|
ASSERT(BitsLeft() >= 32);
|
|
|
|
int tmp;
|
|
memcpy(&tmp, &value, 4);
|
|
WriteInt(tmp, 32); // Write floats as ints; use 32 BITS
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Read a float value (encoded in 32 bit) from the stream.
|
|
|
|
@return the float value
|
|
*/
|
|
inline
|
|
float
|
|
nBitStream::ReadFloat()
|
|
{
|
|
ASSERT(readable);
|
|
ASSERT(BitsLeft() >= 32);
|
|
|
|
int tmp = ReadInt(32); // Read floats as int; use 32 BITS
|
|
float value;
|
|
memcpy(&value, &tmp, 4);
|
|
|
|
return value;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Write a custom byte array to the stream.
|
|
|
|
@param ptr pointer to byte array to write to the stream
|
|
@param size number of bytes to write
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::WriteCustom(const void* ptr, int size)
|
|
{
|
|
ASSERT(writeable);
|
|
ASSERT(ptr != 0);
|
|
ASSERT(size > 0);
|
|
ASSERT(BitsLeft() >= size * 8);
|
|
|
|
// advance to next byte in stream
|
|
// if current bit offset is greater 0
|
|
if (currentBit > 0)
|
|
{
|
|
currentByte++;
|
|
currentBit = 0;
|
|
}
|
|
memcpy(&stream[currentByte], ptr, size);
|
|
currentByte += size;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Read a custom byte array from the stream.
|
|
|
|
@param ptr pointer to byte array
|
|
@param size size in bytes to read
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::ReadCustom(void* ptr, int size)
|
|
{
|
|
ASSERT(readable);
|
|
ASSERT(ptr != 0);
|
|
ASSERT(size > 0);
|
|
ASSERT(BitsLeft() >= size * 8);
|
|
|
|
// advance to next byte in stream
|
|
// if current bit offset is greater 0
|
|
if (currentBit > 0)
|
|
{
|
|
currentByte++;
|
|
currentBit = 0;
|
|
}
|
|
memcpy(ptr, &stream[currentByte], size);
|
|
currentByte += size;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::ReadBitStream(nBitStream& stream)
|
|
{
|
|
ASSERT(stream.streamSize <= (BitsLeft() * 8));
|
|
|
|
ReadCustom(stream.stream, stream.streamSize);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::WriteBitStream(nBitStream& stream)
|
|
{
|
|
ASSERT(stream.streamSize <= (BitsLeft() * 8));
|
|
|
|
WriteCustom(stream.stream, stream.streamSize);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::Set(const uchar* s, int size)
|
|
{
|
|
// require
|
|
ASSERT(s != 0);
|
|
ASSERT(size > 0);
|
|
|
|
// delete old stream, if exits
|
|
if (stream != 0) delete[] stream;
|
|
|
|
// create and copy stream
|
|
stream = new unsigned char[size];
|
|
ASSERT(stream != 0);
|
|
streamSize = size;
|
|
memcpy(stream, s, size);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
const uchar*
|
|
nBitStream::Get() const
|
|
{
|
|
return stream;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::SetSize(int size)
|
|
{
|
|
ASSERT(size > 0);
|
|
|
|
if (stream != 0)
|
|
{
|
|
delete stream;
|
|
}
|
|
stream = new unsigned char[size];
|
|
ASSERT(stream != 0);
|
|
streamSize = size;
|
|
Clear();
|
|
|
|
ASSERT(streamSize == size);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
int
|
|
nBitStream::GetSize() const
|
|
{
|
|
return streamSize;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::SetPos(int pos)
|
|
{
|
|
ASSERT(!writeable); // Can't change bit pos while writing!!!
|
|
ASSERT((0 <= pos) && (pos <= streamSize * 8));
|
|
|
|
currentByte = pos / 8;
|
|
currentBit = pos % 8;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
int
|
|
nBitStream::GetPos() const
|
|
{
|
|
return (currentByte * 8) + currentBit;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
int
|
|
nBitStream::BitsLeft() const
|
|
{
|
|
return (GetSize() * 8) - GetPos();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::Copy(const nBitStream& source)
|
|
{
|
|
ASSERT(source.streamSize > 0);
|
|
ASSERT(source.streamSize == streamSize);
|
|
ASSERT(stream != 0);
|
|
ASSERT(source.stream != 0);
|
|
|
|
memcpy(stream, source.stream, source.streamSize);
|
|
currentBit = streamSize * 8;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::BeginWrite()
|
|
{
|
|
ASSERT(!writeable);
|
|
ASSERT(!readable);
|
|
Clear();
|
|
SetPos(0);
|
|
writeable = true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::EndWrite()
|
|
{
|
|
ASSERT(writeable);
|
|
ASSERT(!readable);
|
|
writeable = false;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::BeginRead()
|
|
{
|
|
ASSERT(!readable);
|
|
ASSERT(!writeable);
|
|
SetPos(0);
|
|
readable = true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::EndRead()
|
|
{
|
|
ASSERT(readable);
|
|
ASSERT(!writeable);
|
|
readable = false;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
bool
|
|
nBitStream::IsWriteable() const
|
|
{
|
|
return writeable;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
bool
|
|
nBitStream::IsReadable() const
|
|
{
|
|
return readable;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Print debug data to stdout.
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::Print(int lines)
|
|
{
|
|
// require
|
|
ASSERT(stream != 0);
|
|
|
|
// print out the first bits
|
|
for (int i = 0; i < lines; i++)
|
|
{
|
|
n_printf("%4.d: ", i + 1);
|
|
char ch = stream[i];
|
|
for (int j = 0; j < 8; j++)
|
|
{
|
|
if ( ch & ( 1 << ( 7 - j ) ) )
|
|
{
|
|
n_printf( "%d", 1 );
|
|
}
|
|
else
|
|
{
|
|
n_printf( "%d", 0 );
|
|
}
|
|
}
|
|
n_printf( "\n" );
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Assignment operator.
|
|
*/
|
|
inline
|
|
nBitStream&
|
|
nBitStream::operator = (const nBitStream& s)
|
|
{
|
|
ASSERT(s.streamSize > 0);
|
|
ASSERT(s.streamSize == streamSize);
|
|
ASSERT(stream != 0);
|
|
ASSERT(s.stream != 0);
|
|
|
|
Copy(s);
|
|
|
|
return *this;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Equality operator.
|
|
*/
|
|
inline
|
|
bool
|
|
nBitStream::operator == (const nBitStream& s) const
|
|
{
|
|
if (streamSize != s.streamSize) return false;
|
|
|
|
return (memcmp(stream, s.stream, streamSize) == 0);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
Inequality operator.
|
|
*/
|
|
inline
|
|
bool
|
|
nBitStream::operator != (const nBitStream& s) const
|
|
{
|
|
if (streamSize != s.streamSize) return true;
|
|
|
|
return (memcmp(stream, s.stream, streamSize) != 0);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
void
|
|
nBitStream::WriteBit(bool bit)
|
|
{
|
|
ASSERT(stream != 0);
|
|
ASSERT(BitsLeft() >= 1);
|
|
ASSERT(IsWriteable());
|
|
|
|
// Set bit at current bit in current byte;
|
|
// assume that all upcomming bits are cleared
|
|
if (bit)
|
|
{
|
|
int v = (bit) ? 1 : 0;
|
|
stream[currentByte] |= (v << (7 - currentBit));
|
|
}
|
|
|
|
// Advance to next byte if current bit is 8!
|
|
if (++currentBit == 8)
|
|
{
|
|
currentByte++;
|
|
currentBit = 0;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/**
|
|
*/
|
|
inline
|
|
bool
|
|
nBitStream::ReadBit()
|
|
{
|
|
ASSERT(stream != 0);
|
|
ASSERT(BitsLeft() >= 1);
|
|
ASSERT(IsReadable());
|
|
|
|
// Read current bit
|
|
bool flag = ((stream[currentByte] & (1 << (7 - currentBit))) != 0);
|
|
|
|
// Advance to next byte if current bit is 8!
|
|
if (++currentBit == 8)
|
|
{
|
|
currentByte++;
|
|
currentBit = 0;
|
|
}
|
|
|
|
return flag;
|
|
}
|
|
|
|
#endif
|