// BitlDecoder.h -- the Least Significant Bit of byte is First #ifndef __BITL_DECODER_H #define __BITL_DECODER_H #include "../IStream.h" namespace NBitl { const unsigned kNumBigValueBits = 8 * 4; const unsigned kNumValueBytes = 3; const unsigned kNumValueBits = 8 * kNumValueBytes; const UInt32 kMask = (1 << kNumValueBits) - 1; extern Byte kInvertTable[256]; /* TInByte must support "Extra Bytes" (bytes that can be read after the end of stream TInByte::ReadByte() returns 0xFF after the end of stream TInByte::NumExtraBytes contains the number "Extra Bytes" Bitl decoder can read up to 4 bytes ahead to internal buffer. */ template class CBaseDecoder { protected: unsigned _bitPos; UInt32 _value; TInByte _stream; public: bool Create(UInt32 bufSize) { return _stream.Create(bufSize); } void SetStream(ISequentialInStream *inStream) { _stream.SetStream(inStream); } void Init() { _stream.Init(); _bitPos = kNumBigValueBits; _value = 0; } UInt64 GetStreamSize() const { return _stream.GetStreamSize(); } UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); } bool ThereAreDataInBitsBuffer() const { return this->_bitPos != kNumBigValueBits; } void Normalize() { for (; _bitPos >= 8; _bitPos -= 8) _value = ((UInt32)_stream.ReadByte() << (kNumBigValueBits - _bitPos)) | _value; } UInt32 ReadBits(unsigned numBits) { Normalize(); UInt32 res = _value & ((1 << numBits) - 1); _bitPos += numBits; _value >>= numBits; return res; } bool ExtraBitsWereRead() const { return (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3)); } bool ExtraBitsWereRead_Fast() const { // full version is not inlined in vc6. // return _stream.NumExtraBytes != 0 && (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3)); // (_stream.NumExtraBytes > 4) is fast overread detection. It's possible that // it doesn't return true, if small number of extra bits were read. return (_stream.NumExtraBytes > 4); } // it must be fixed !!! with extra bits // UInt32 GetNumExtraBytes() const { return _stream.NumExtraBytes; } }; template class CDecoder: public CBaseDecoder { UInt32 _normalValue; public: void Init() { CBaseDecoder::Init(); _normalValue = 0; } void Normalize() { for (; this->_bitPos >= 8; this->_bitPos -= 8) { Byte b = this->_stream.ReadByte(); _normalValue = ((UInt32)b << (kNumBigValueBits - this->_bitPos)) | _normalValue; this->_value = (this->_value << 8) | kInvertTable[b]; } } UInt32 GetValue(unsigned numBits) { Normalize(); return ((this->_value >> (8 - this->_bitPos)) & kMask) >> (kNumValueBits - numBits); } void MovePos(unsigned numBits) { this->_bitPos += numBits; _normalValue >>= numBits; } UInt32 ReadBits(unsigned numBits) { Normalize(); UInt32 res = _normalValue & ((1 << numBits) - 1); MovePos(numBits); return res; } void AlignToByte() { MovePos((32 - this->_bitPos) & 7); } Byte ReadDirectByte() { return this->_stream.ReadByte(); } Byte ReadAlignedByte() { if (this->_bitPos == kNumBigValueBits) return this->_stream.ReadByte(); Byte b = (Byte)(_normalValue & 0xFF); MovePos(8); return b; } }; } #endif