1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
// QuantumDecoder.h
#ifndef __COMPRESS_QUANTUM_DECODER_H
#define __COMPRESS_QUANTUM_DECODER_H
#include "../../Common/MyCom.h"
#include "LzOutWindow.h"
namespace NCompress {
namespace NQuantum {
class CBitDecoder
{
UInt32 Value;
bool _extra;
const Byte *_buf;
const Byte *_bufLim;
public:
void SetStreamAndInit(const Byte *inData, size_t inSize)
{
_buf = inData;
_bufLim = inData + inSize;
Value = 0x10000;
_extra = false;
}
bool WasExtraRead() const { return _extra; }
bool WasFinishedOK() const
{
return !_extra && _buf == _bufLim;
}
UInt32 ReadBit()
{
if (Value >= 0x10000)
{
Byte b;
if (_buf >= _bufLim)
{
b = 0xFF;
_extra = true;
}
else
b = *_buf++;
Value = 0x100 | b;
}
UInt32 res = (Value >> 7) & 1;
Value <<= 1;
return res;
}
UInt32 ReadStart16Bits()
{
// we use check for extra read in another code.
UInt32 val = ((UInt32)*_buf << 8) | _buf[1];
_buf += 2;
return val;
}
UInt32 ReadBits(unsigned numBits) // numBits > 0
{
UInt32 res = 0;
do
res = (res << 1) | ReadBit();
while (--numBits);
return res;
}
};
class CRangeDecoder
{
UInt32 Low;
UInt32 Range;
UInt32 Code;
public:
CBitDecoder Stream;
void Init()
{
Low = 0;
Range = 0x10000;
Code = Stream.ReadStart16Bits();
}
bool Finish()
{
// do all streams use these two bits at end?
if (Stream.ReadBit() != 0) return false;
if (Stream.ReadBit() != 0) return false;
return Stream.WasFinishedOK();
}
UInt32 GetThreshold(UInt32 total) const
{
return ((Code + 1) * total - 1) / Range; // & 0xFFFF is not required;
}
void Decode(UInt32 start, UInt32 end, UInt32 total)
{
UInt32 high = Low + end * Range / total - 1;
UInt32 offset = start * Range / total;
Code -= offset;
Low += offset;
for (;;)
{
if ((Low & 0x8000) != (high & 0x8000))
{
if ((Low & 0x4000) == 0 || (high & 0x4000) != 0)
break;
Low &= 0x3FFF;
high |= 0x4000;
}
Low = (Low << 1) & 0xFFFF;
high = ((high << 1) | 1) & 0xFFFF;
Code = ((Code << 1) | Stream.ReadBit());
}
Range = high - Low + 1;
}
};
const unsigned kNumLitSelectorBits = 2;
const unsigned kNumLitSelectors = (1 << kNumLitSelectorBits);
const unsigned kNumLitSymbols = 1 << (8 - kNumLitSelectorBits);
const unsigned kNumMatchSelectors = 3;
const unsigned kNumSelectors = kNumLitSelectors + kNumMatchSelectors;
const unsigned kNumSymbolsMax = kNumLitSymbols; // 64
class CModelDecoder
{
unsigned NumItems;
unsigned ReorderCount;
UInt16 Freqs[kNumSymbolsMax + 1];
Byte Vals[kNumSymbolsMax];
public:
void Init(unsigned numItems);
unsigned Decode(CRangeDecoder *rc);
};
class CDecoder:
public IUnknown,
public CMyUnknownImp
{
CLzOutWindow _outWindow;
unsigned _numDictBits;
CModelDecoder m_Selector;
CModelDecoder m_Literals[kNumLitSelectors];
CModelDecoder m_PosSlot[kNumMatchSelectors];
CModelDecoder m_LenSlot;
void Init();
HRESULT CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize);
public:
MY_UNKNOWN_IMP
HRESULT Code(const Byte *inData, size_t inSize,
ISequentialOutStream *outStream, UInt32 outSize,
bool keepHistory);
HRESULT SetParams(unsigned numDictBits);
CDecoder(): _numDictBits(0) {}
virtual ~CDecoder() {}
};
}}
#endif
|