1 // BitlDecoder.h -- the Least Significant Bit of byte is First 2 3 #ifndef ZIP7_INC_BITL_DECODER_H 4 #define ZIP7_INC_BITL_DECODER_H 5 6 #include "../../../C/CpuArch.h" 7 8 #include "../IStream.h" 9 10 namespace NBitl { 11 12 const unsigned kNumBigValueBits = 8 * 4; 13 const unsigned kNumValueBytes = 3; 14 const unsigned kNumValueBits = 8 * kNumValueBytes; 15 const UInt32 kMask = (1 << kNumValueBits) - 1; 16 17 #if !defined(Z7_BITL_USE_REVERSE_BITS_TABLE) 18 #if 1 && defined(MY_CPU_ARM_OR_ARM64) \ 19 && (defined(MY_CPU_ARM64) || defined(__ARM_ARCH_6T2__) \ 20 || defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) \ 21 && (defined(__GNUC__) && (__GNUC__ >= 4) \ 22 || defined(__clang__) && (__clang_major__ >= 4)) 23 #define Z7_BITL_USE_REVERSE_BITS_INSTRUCTION 24 #elif 1 25 #define Z7_BITL_USE_REVERSE_BITS_TABLE 26 #endif 27 #endif 28 29 #if defined(Z7_BITL_USE_REVERSE_BITS_TABLE) 30 extern Byte kReverseTable[256]; 31 #endif 32 ReverseBits8(unsigned i)33inline unsigned ReverseBits8(unsigned i) 34 { 35 #if defined(Z7_BITL_USE_REVERSE_BITS_TABLE) 36 return kReverseTable[i]; 37 #elif defined(Z7_BITL_USE_REVERSE_BITS_INSTRUCTION) 38 // rbit is available in ARMv6T2 and above 39 asm ("rbit " 40 #if defined(MY_CPU_ARM) 41 "%0,%0" // it uses default register size, 42 // but we need 32-bit register here. 43 // we must use it only if default register size is 32-bit. 44 // it will work incorrectly for ARM64. 45 #else 46 "%w0,%w0" // it uses 32-bit registers in ARM64. 47 // compiler for (MY_CPU_ARM) can't compile it. 48 #endif 49 : "+r" (i)); 50 return i >> 24; 51 #else 52 unsigned 53 x = ((i & 0x55) << 1) | ((i >> 1) & 0x55); 54 x = ((x & 0x33) << 2) | ((x >> 2) & 0x33); 55 return ((x & 0x0f) << 4) | (x >> 4); 56 #endif 57 } 58 59 60 /* TInByte must support "Extra Bytes" (bytes that can be read after the end of stream 61 TInByte::ReadByte() returns 0xFF after the end of stream 62 TInByte::NumExtraBytes contains the number "Extra Bytes" 63 64 Bitl decoder can read up to 4 bytes ahead to internal buffer. */ 65 66 template<class TInByte> 67 class CBaseDecoder 68 { 69 protected: 70 unsigned _bitPos; 71 UInt32 _value; 72 TInByte _stream; 73 public: Create(UInt32 bufSize)74 bool Create(UInt32 bufSize) { return _stream.Create(bufSize); } SetStream(ISequentialInStream * inStream)75 void SetStream(ISequentialInStream *inStream) { _stream.SetStream(inStream); } ClearStreamPtr()76 void ClearStreamPtr() { _stream.ClearStreamPtr(); } Init()77 void Init() 78 { 79 _stream.Init(); 80 _bitPos = kNumBigValueBits; 81 _value = 0; 82 } 83 84 // the size of portion data in real stream that was already read from this object. 85 // it doesn't include unused data in BitStream object buffer (up to 4 bytes) 86 // it doesn't include unused data in TInByte buffers 87 // it doesn't include virtual Extra bytes after the end of real stream data GetStreamSize()88 UInt64 GetStreamSize() const 89 { 90 return ExtraBitsWereRead() ? 91 _stream.GetStreamSize(): 92 GetProcessedSize(); 93 } 94 95 // the size of virtual data that was read from this object. GetProcessedSize()96 UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); } 97 ThereAreDataInBitsBuffer()98 bool ThereAreDataInBitsBuffer() const { return this->_bitPos != kNumBigValueBits; } 99 100 Z7_FORCE_INLINE Normalize()101 void Normalize() 102 { 103 for (; _bitPos >= 8; _bitPos -= 8) 104 _value = ((UInt32)_stream.ReadByte() << (kNumBigValueBits - _bitPos)) | _value; 105 } 106 107 Z7_FORCE_INLINE ReadBits(unsigned numBits)108 UInt32 ReadBits(unsigned numBits) 109 { 110 Normalize(); 111 UInt32 res = _value & ((1 << numBits) - 1); 112 _bitPos += numBits; 113 _value >>= numBits; 114 return res; 115 } 116 ExtraBitsWereRead()117 bool ExtraBitsWereRead() const 118 { 119 return (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3)); 120 } 121 ExtraBitsWereRead_Fast()122 bool ExtraBitsWereRead_Fast() const 123 { 124 // full version is not inlined in vc6. 125 // return _stream.NumExtraBytes != 0 && (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3)); 126 127 // (_stream.NumExtraBytes > 4) is fast overread detection. It's possible that 128 // it doesn't return true, if small number of extra bits were read. 129 return (_stream.NumExtraBytes > 4); 130 } 131 132 // it must be fixed !!! with extra bits 133 // UInt32 GetNumExtraBytes() const { return _stream.NumExtraBytes; } 134 }; 135 136 template<class TInByte> 137 class CDecoder: public CBaseDecoder<TInByte> 138 { 139 UInt32 _normalValue; 140 141 public: Init()142 void Init() 143 { 144 CBaseDecoder<TInByte>::Init(); 145 _normalValue = 0; 146 } 147 148 Z7_FORCE_INLINE Normalize()149 void Normalize() 150 { 151 for (; this->_bitPos >= 8; this->_bitPos -= 8) 152 { 153 const unsigned b = this->_stream.ReadByte(); 154 _normalValue = ((UInt32)b << (kNumBigValueBits - this->_bitPos)) | _normalValue; 155 this->_value = (this->_value << 8) | ReverseBits8(b); 156 } 157 } 158 159 Z7_FORCE_INLINE GetValue(unsigned numBits)160 UInt32 GetValue(unsigned numBits) 161 { 162 Normalize(); 163 return ((this->_value >> (8 - this->_bitPos)) & kMask) >> (kNumValueBits - numBits); 164 } 165 166 Z7_FORCE_INLINE GetValue_InHigh32bits()167 UInt32 GetValue_InHigh32bits() 168 { 169 Normalize(); 170 return this->_value << this->_bitPos; 171 } 172 173 Z7_FORCE_INLINE MovePos(size_t numBits)174 void MovePos(size_t numBits) 175 { 176 this->_bitPos += (unsigned)numBits; 177 _normalValue >>= numBits; 178 } 179 180 Z7_FORCE_INLINE ReadBits(unsigned numBits)181 UInt32 ReadBits(unsigned numBits) 182 { 183 Normalize(); 184 UInt32 res = _normalValue & ((1 << numBits) - 1); 185 MovePos(numBits); 186 return res; 187 } 188 AlignToByte()189 void AlignToByte() { MovePos((32 - this->_bitPos) & 7); } 190 191 Z7_FORCE_INLINE ReadDirectByte()192 Byte ReadDirectByte() { return this->_stream.ReadByte(); } 193 194 Z7_FORCE_INLINE ReadDirectBytesPart(Byte * buf,size_t size)195 size_t ReadDirectBytesPart(Byte *buf, size_t size) { return this->_stream.ReadBytesPart(buf, size); } 196 197 Z7_FORCE_INLINE ReadAlignedByte()198 Byte ReadAlignedByte() 199 { 200 if (this->_bitPos == kNumBigValueBits) 201 return this->_stream.ReadByte(); 202 Byte b = (Byte)(_normalValue & 0xFF); 203 MovePos(8); 204 return b; 205 } 206 207 // call it only if the object is aligned for byte. 208 Z7_FORCE_INLINE ReadAlignedByte_FromBuf(Byte & b)209 bool ReadAlignedByte_FromBuf(Byte &b) 210 { 211 if (this->_stream.NumExtraBytes != 0) 212 if (this->_stream.NumExtraBytes >= 4 213 || kNumBigValueBits - this->_bitPos <= (this->_stream.NumExtraBytes << 3)) 214 return false; 215 if (this->_bitPos == kNumBigValueBits) 216 return this->_stream.ReadByte_FromBuf(b); 217 b = (Byte)(_normalValue & 0xFF); 218 MovePos(8); 219 return true; 220 } 221 }; 222 223 } 224 225 #endif 226