5
#include "ImplodeDecoder.h"
6
#include "Common/Defs.h"
19
CException(ECauseType cause): m_Cause(cause) {}
22
static const int kNumDistanceLowDirectBitsForBigDict = 7;
23
static const int kNumDistanceLowDirectBitsForSmallDict = 6;
25
static const int kNumBitsInByte = 8;
27
// static const int kLevelStructuresNumberFieldSize = kNumBitsInByte;
28
static const int kLevelStructuresNumberAdditionalValue = 1;
30
static const int kNumLevelStructureLevelBits = 4;
31
static const int kLevelStructureLevelAdditionalValue = 1;
33
static const int kNumLevelStructureRepNumberBits = 4;
34
static const int kLevelStructureRepNumberAdditionalValue = 1;
37
static const int kLiteralTableSize = (1 << kNumBitsInByte);
38
static const int kDistanceTableSize = 64;
39
static const int kLengthTableSize = 64;
41
static const UInt32 kHistorySize =
42
(1 << MyMax(kNumDistanceLowDirectBitsForBigDict,
43
kNumDistanceLowDirectBitsForSmallDict)) *
44
kDistanceTableSize; // = 8 KB;
46
static const int kNumAdditionalLengthBits = 8;
48
static const UInt32 kMatchMinLenWhenLiteralsOn = 3;
49
static const UInt32 kMatchMinLenWhenLiteralsOff = 2;
51
static const UInt32 kMatchMinLenMax = MyMax(kMatchMinLenWhenLiteralsOn,
52
kMatchMinLenWhenLiteralsOff); // 3
54
// static const UInt32 kMatchMaxLenMax = kMatchMinLenMax + (kLengthTableSize - 1) + (1 << kNumAdditionalLengthBits) - 1; // or 2
64
m_LiteralDecoder(kLiteralTableSize),
65
m_LengthDecoder(kLengthTableSize),
66
m_DistanceDecoder(kDistanceTableSize)
70
void CCoder::ReleaseStreams()
72
m_OutWindowStream.ReleaseStream();
73
m_InBitStream.ReleaseStream();
76
bool CCoder::ReadLevelItems(NImplode::NHuffman::CDecoder &decoder,
77
Byte *levels, int numLevelItems)
79
int numCodedStructures = m_InBitStream.ReadBits(kNumBitsInByte) +
80
kLevelStructuresNumberAdditionalValue;
82
for(int i = 0; i < numCodedStructures; i++)
84
int level = m_InBitStream.ReadBits(kNumLevelStructureLevelBits) +
85
kLevelStructureLevelAdditionalValue;
86
int rep = m_InBitStream.ReadBits(kNumLevelStructureRepNumberBits) +
87
kLevelStructureRepNumberAdditionalValue;
88
if (currentIndex + rep > numLevelItems)
89
throw CException(CException::kData);
90
for(int j = 0; j < rep; j++)
91
levels[currentIndex++] = (Byte)level;
93
if (currentIndex != numLevelItems)
95
return decoder.SetCodeLengths(levels);
99
bool CCoder::ReadTables(void)
103
Byte literalLevels[kLiteralTableSize];
104
if (!ReadLevelItems(m_LiteralDecoder, literalLevels, kLiteralTableSize))
108
Byte lengthLevels[kLengthTableSize];
109
if (!ReadLevelItems(m_LengthDecoder, lengthLevels, kLengthTableSize))
112
Byte distanceLevels[kDistanceTableSize];
113
return ReadLevelItems(m_DistanceDecoder, distanceLevels, kDistanceTableSize);
120
CCoderReleaser(CCoder *coder): m_Coder(coder) {}
121
~CCoderReleaser() { m_Coder->ReleaseStreams(); }
124
HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
125
const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
127
if (!m_InBitStream.Create(1 << 20))
128
return E_OUTOFMEMORY;
129
if (!m_OutWindowStream.Create(kHistorySize))
130
return E_OUTOFMEMORY;
133
UInt64 pos = 0, unPackSize = *outSize;
135
m_OutWindowStream.SetStream(outStream);
136
m_OutWindowStream.Init(false);
137
m_InBitStream.SetStream(inStream);
138
m_InBitStream.Init();
139
CCoderReleaser coderReleaser(this);
144
while(pos < unPackSize)
146
if (progress != NULL && pos % (1 << 16) == 0)
148
UInt64 packSize = m_InBitStream.GetProcessedSize();
149
RINOK(progress->SetRatioInfo(&packSize, &pos));
151
if(m_InBitStream.ReadBits(1) == kMatchId) // match
153
UInt32 lowDistBits = m_InBitStream.ReadBits(m_NumDistanceLowDirectBits);
154
UInt32 distance = m_DistanceDecoder.DecodeSymbol(&m_InBitStream);
155
if (distance >= kDistanceTableSize)
157
distance = (distance << m_NumDistanceLowDirectBits) + lowDistBits;
158
UInt32 lengthSymbol = m_LengthDecoder.DecodeSymbol(&m_InBitStream);
159
if (lengthSymbol >= kLengthTableSize)
161
UInt32 length = lengthSymbol + m_MinMatchLength;
162
if (lengthSymbol == kLengthTableSize - 1) // special symbol = 63
163
length += m_InBitStream.ReadBits(kNumAdditionalLengthBits);
164
while(distance >= pos && length > 0)
166
m_OutWindowStream.PutByte(0);
171
m_OutWindowStream.CopyBlock(distance, length);
179
UInt32 temp = m_LiteralDecoder.DecodeSymbol(&m_InBitStream);
180
if (temp >= kLiteralTableSize)
185
b = (Byte)m_InBitStream.ReadBits(kNumBitsInByte);
186
m_OutWindowStream.PutByte(b);
190
if (pos > unPackSize)
192
return m_OutWindowStream.Flush();
195
STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
196
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
198
try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
199
catch(const CLzOutWindowException &e) { return e.ErrorCode; }
200
catch(...) { return S_FALSE; }
203
STDMETHODIMP CCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
208
m_BigDictionaryOn = ((flag & 2) != 0);
209
m_NumDistanceLowDirectBits = m_BigDictionaryOn ?
210
kNumDistanceLowDirectBitsForBigDict:
211
kNumDistanceLowDirectBitsForSmallDict;
212
m_LiteralsOn = ((flag & 4) != 0);
213
m_MinMatchLength = m_LiteralsOn ?
214
kMatchMinLenWhenLiteralsOn :
215
kMatchMinLenWhenLiteralsOff;