1*f6dc9357SAndroid Build Coastguard Worker // DeflateDecoder.cpp
2*f6dc9357SAndroid Build Coastguard Worker
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker
5*f6dc9357SAndroid Build Coastguard Worker #include "DeflateDecoder.h"
6*f6dc9357SAndroid Build Coastguard Worker
7*f6dc9357SAndroid Build Coastguard Worker namespace NCompress {
8*f6dc9357SAndroid Build Coastguard Worker namespace NDeflate {
9*f6dc9357SAndroid Build Coastguard Worker namespace NDecoder {
10*f6dc9357SAndroid Build Coastguard Worker
CCoder(bool deflate64Mode)11*f6dc9357SAndroid Build Coastguard Worker CCoder::CCoder(bool deflate64Mode):
12*f6dc9357SAndroid Build Coastguard Worker _deflateNSIS(false),
13*f6dc9357SAndroid Build Coastguard Worker _deflate64Mode(deflate64Mode),
14*f6dc9357SAndroid Build Coastguard Worker _keepHistory(false),
15*f6dc9357SAndroid Build Coastguard Worker _needFinishInput(false),
16*f6dc9357SAndroid Build Coastguard Worker _needInitInStream(true),
17*f6dc9357SAndroid Build Coastguard Worker _outSizeDefined(false),
18*f6dc9357SAndroid Build Coastguard Worker _outStartPos(0)
19*f6dc9357SAndroid Build Coastguard Worker {}
20*f6dc9357SAndroid Build Coastguard Worker
ReadBits(unsigned numBits)21*f6dc9357SAndroid Build Coastguard Worker UInt32 CCoder::ReadBits(unsigned numBits)
22*f6dc9357SAndroid Build Coastguard Worker {
23*f6dc9357SAndroid Build Coastguard Worker return m_InBitStream.ReadBits(numBits);
24*f6dc9357SAndroid Build Coastguard Worker }
25*f6dc9357SAndroid Build Coastguard Worker
ReadAlignedByte()26*f6dc9357SAndroid Build Coastguard Worker Byte CCoder::ReadAlignedByte()
27*f6dc9357SAndroid Build Coastguard Worker {
28*f6dc9357SAndroid Build Coastguard Worker return m_InBitStream.ReadAlignedByte();
29*f6dc9357SAndroid Build Coastguard Worker }
30*f6dc9357SAndroid Build Coastguard Worker
DecodeLevels(Byte * levels,unsigned numSymbols)31*f6dc9357SAndroid Build Coastguard Worker bool CCoder::DecodeLevels(Byte *levels, unsigned numSymbols)
32*f6dc9357SAndroid Build Coastguard Worker {
33*f6dc9357SAndroid Build Coastguard Worker unsigned i = 0;
34*f6dc9357SAndroid Build Coastguard Worker
35*f6dc9357SAndroid Build Coastguard Worker do
36*f6dc9357SAndroid Build Coastguard Worker {
37*f6dc9357SAndroid Build Coastguard Worker unsigned sym = m_LevelDecoder.Decode(&m_InBitStream);
38*f6dc9357SAndroid Build Coastguard Worker if (sym < kTableDirectLevels)
39*f6dc9357SAndroid Build Coastguard Worker levels[i++] = (Byte)sym;
40*f6dc9357SAndroid Build Coastguard Worker else
41*f6dc9357SAndroid Build Coastguard Worker {
42*f6dc9357SAndroid Build Coastguard Worker if (sym >= kLevelTableSize)
43*f6dc9357SAndroid Build Coastguard Worker return false;
44*f6dc9357SAndroid Build Coastguard Worker
45*f6dc9357SAndroid Build Coastguard Worker unsigned num;
46*f6dc9357SAndroid Build Coastguard Worker unsigned numBits;
47*f6dc9357SAndroid Build Coastguard Worker Byte symbol;
48*f6dc9357SAndroid Build Coastguard Worker
49*f6dc9357SAndroid Build Coastguard Worker if (sym == kTableLevelRepNumber)
50*f6dc9357SAndroid Build Coastguard Worker {
51*f6dc9357SAndroid Build Coastguard Worker if (i == 0)
52*f6dc9357SAndroid Build Coastguard Worker return false;
53*f6dc9357SAndroid Build Coastguard Worker numBits = 2;
54*f6dc9357SAndroid Build Coastguard Worker num = 0;
55*f6dc9357SAndroid Build Coastguard Worker symbol = levels[(size_t)i - 1];
56*f6dc9357SAndroid Build Coastguard Worker }
57*f6dc9357SAndroid Build Coastguard Worker else
58*f6dc9357SAndroid Build Coastguard Worker {
59*f6dc9357SAndroid Build Coastguard Worker sym -= kTableLevel0Number;
60*f6dc9357SAndroid Build Coastguard Worker sym <<= 2;
61*f6dc9357SAndroid Build Coastguard Worker numBits = 3 + (unsigned)sym;
62*f6dc9357SAndroid Build Coastguard Worker num = ((unsigned)sym << 1);
63*f6dc9357SAndroid Build Coastguard Worker symbol = 0;
64*f6dc9357SAndroid Build Coastguard Worker }
65*f6dc9357SAndroid Build Coastguard Worker
66*f6dc9357SAndroid Build Coastguard Worker num += i + 3 + ReadBits(numBits);
67*f6dc9357SAndroid Build Coastguard Worker if (num > numSymbols)
68*f6dc9357SAndroid Build Coastguard Worker return false;
69*f6dc9357SAndroid Build Coastguard Worker do
70*f6dc9357SAndroid Build Coastguard Worker levels[i++] = symbol;
71*f6dc9357SAndroid Build Coastguard Worker while (i < num);
72*f6dc9357SAndroid Build Coastguard Worker }
73*f6dc9357SAndroid Build Coastguard Worker }
74*f6dc9357SAndroid Build Coastguard Worker while (i < numSymbols);
75*f6dc9357SAndroid Build Coastguard Worker
76*f6dc9357SAndroid Build Coastguard Worker return true;
77*f6dc9357SAndroid Build Coastguard Worker }
78*f6dc9357SAndroid Build Coastguard Worker
79*f6dc9357SAndroid Build Coastguard Worker #define RIF(x) { if (!(x)) return false; }
80*f6dc9357SAndroid Build Coastguard Worker
ReadTables(void)81*f6dc9357SAndroid Build Coastguard Worker bool CCoder::ReadTables(void)
82*f6dc9357SAndroid Build Coastguard Worker {
83*f6dc9357SAndroid Build Coastguard Worker m_FinalBlock = (ReadBits(kFinalBlockFieldSize) == NFinalBlockField::kFinalBlock);
84*f6dc9357SAndroid Build Coastguard Worker if (m_InBitStream.ExtraBitsWereRead())
85*f6dc9357SAndroid Build Coastguard Worker return false;
86*f6dc9357SAndroid Build Coastguard Worker const UInt32 blockType = ReadBits(kBlockTypeFieldSize);
87*f6dc9357SAndroid Build Coastguard Worker if (blockType > NBlockType::kDynamicHuffman)
88*f6dc9357SAndroid Build Coastguard Worker return false;
89*f6dc9357SAndroid Build Coastguard Worker if (m_InBitStream.ExtraBitsWereRead())
90*f6dc9357SAndroid Build Coastguard Worker return false;
91*f6dc9357SAndroid Build Coastguard Worker
92*f6dc9357SAndroid Build Coastguard Worker if (blockType == NBlockType::kStored)
93*f6dc9357SAndroid Build Coastguard Worker {
94*f6dc9357SAndroid Build Coastguard Worker m_StoredMode = true;
95*f6dc9357SAndroid Build Coastguard Worker m_InBitStream.AlignToByte();
96*f6dc9357SAndroid Build Coastguard Worker m_StoredBlockSize = ReadAligned_UInt16(); // ReadBits(kStoredBlockLengthFieldSize)
97*f6dc9357SAndroid Build Coastguard Worker if (_deflateNSIS)
98*f6dc9357SAndroid Build Coastguard Worker return true;
99*f6dc9357SAndroid Build Coastguard Worker return (m_StoredBlockSize == (UInt16)~ReadAligned_UInt16());
100*f6dc9357SAndroid Build Coastguard Worker }
101*f6dc9357SAndroid Build Coastguard Worker
102*f6dc9357SAndroid Build Coastguard Worker m_StoredMode = false;
103*f6dc9357SAndroid Build Coastguard Worker
104*f6dc9357SAndroid Build Coastguard Worker CLevels levels;
105*f6dc9357SAndroid Build Coastguard Worker if (blockType == NBlockType::kFixedHuffman)
106*f6dc9357SAndroid Build Coastguard Worker {
107*f6dc9357SAndroid Build Coastguard Worker levels.SetFixedLevels();
108*f6dc9357SAndroid Build Coastguard Worker _numDistLevels = _deflate64Mode ? kDistTableSize64 : kDistTableSize32;
109*f6dc9357SAndroid Build Coastguard Worker }
110*f6dc9357SAndroid Build Coastguard Worker else
111*f6dc9357SAndroid Build Coastguard Worker {
112*f6dc9357SAndroid Build Coastguard Worker const unsigned numLitLenLevels = ReadBits(kNumLenCodesFieldSize) + kNumLitLenCodesMin;
113*f6dc9357SAndroid Build Coastguard Worker _numDistLevels = (unsigned)ReadBits(kNumDistCodesFieldSize) + kNumDistCodesMin;
114*f6dc9357SAndroid Build Coastguard Worker const unsigned numLevelCodes = ReadBits(kNumLevelCodesFieldSize) + kNumLevelCodesMin;
115*f6dc9357SAndroid Build Coastguard Worker
116*f6dc9357SAndroid Build Coastguard Worker if (!_deflate64Mode)
117*f6dc9357SAndroid Build Coastguard Worker if (_numDistLevels > kDistTableSize32)
118*f6dc9357SAndroid Build Coastguard Worker return false;
119*f6dc9357SAndroid Build Coastguard Worker
120*f6dc9357SAndroid Build Coastguard Worker Byte levelLevels[kLevelTableSize];
121*f6dc9357SAndroid Build Coastguard Worker for (unsigned i = 0; i < kLevelTableSize; i++)
122*f6dc9357SAndroid Build Coastguard Worker {
123*f6dc9357SAndroid Build Coastguard Worker const unsigned position = kCodeLengthAlphabetOrder[i];
124*f6dc9357SAndroid Build Coastguard Worker if (i < numLevelCodes)
125*f6dc9357SAndroid Build Coastguard Worker levelLevels[position] = (Byte)ReadBits(kLevelFieldSize);
126*f6dc9357SAndroid Build Coastguard Worker else
127*f6dc9357SAndroid Build Coastguard Worker levelLevels[position] = 0;
128*f6dc9357SAndroid Build Coastguard Worker }
129*f6dc9357SAndroid Build Coastguard Worker
130*f6dc9357SAndroid Build Coastguard Worker if (m_InBitStream.ExtraBitsWereRead())
131*f6dc9357SAndroid Build Coastguard Worker return false;
132*f6dc9357SAndroid Build Coastguard Worker
133*f6dc9357SAndroid Build Coastguard Worker RIF(m_LevelDecoder.Build(levelLevels, false)) // full
134*f6dc9357SAndroid Build Coastguard Worker
135*f6dc9357SAndroid Build Coastguard Worker Byte tmpLevels[kFixedMainTableSize + kFixedDistTableSize];
136*f6dc9357SAndroid Build Coastguard Worker if (!DecodeLevels(tmpLevels, numLitLenLevels + _numDistLevels))
137*f6dc9357SAndroid Build Coastguard Worker return false;
138*f6dc9357SAndroid Build Coastguard Worker
139*f6dc9357SAndroid Build Coastguard Worker if (m_InBitStream.ExtraBitsWereRead())
140*f6dc9357SAndroid Build Coastguard Worker return false;
141*f6dc9357SAndroid Build Coastguard Worker
142*f6dc9357SAndroid Build Coastguard Worker levels.SubClear();
143*f6dc9357SAndroid Build Coastguard Worker memcpy(levels.litLenLevels, tmpLevels, numLitLenLevels);
144*f6dc9357SAndroid Build Coastguard Worker memcpy(levels.distLevels, tmpLevels + numLitLenLevels, _numDistLevels);
145*f6dc9357SAndroid Build Coastguard Worker }
146*f6dc9357SAndroid Build Coastguard Worker RIF(m_MainDecoder.Build(levels.litLenLevels))
147*f6dc9357SAndroid Build Coastguard Worker return m_DistDecoder.Build(levels.distLevels);
148*f6dc9357SAndroid Build Coastguard Worker }
149*f6dc9357SAndroid Build Coastguard Worker
150*f6dc9357SAndroid Build Coastguard Worker
InitInStream(bool needInit)151*f6dc9357SAndroid Build Coastguard Worker HRESULT CCoder::InitInStream(bool needInit)
152*f6dc9357SAndroid Build Coastguard Worker {
153*f6dc9357SAndroid Build Coastguard Worker if (needInit)
154*f6dc9357SAndroid Build Coastguard Worker {
155*f6dc9357SAndroid Build Coastguard Worker // for HDD-Windows:
156*f6dc9357SAndroid Build Coastguard Worker // (1 << 15) - best for reading only prefetch
157*f6dc9357SAndroid Build Coastguard Worker // (1 << 22) - best for real reading / writing
158*f6dc9357SAndroid Build Coastguard Worker if (!m_InBitStream.Create(1 << 20))
159*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
160*f6dc9357SAndroid Build Coastguard Worker m_InBitStream.Init();
161*f6dc9357SAndroid Build Coastguard Worker _needInitInStream = false;
162*f6dc9357SAndroid Build Coastguard Worker }
163*f6dc9357SAndroid Build Coastguard Worker return S_OK;
164*f6dc9357SAndroid Build Coastguard Worker }
165*f6dc9357SAndroid Build Coastguard Worker
166*f6dc9357SAndroid Build Coastguard Worker
CodeSpec(UInt32 curSize,bool finishInputStream,UInt32 inputProgressLimit)167*f6dc9357SAndroid Build Coastguard Worker HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream, UInt32 inputProgressLimit)
168*f6dc9357SAndroid Build Coastguard Worker {
169*f6dc9357SAndroid Build Coastguard Worker if (_remainLen == kLenIdFinished)
170*f6dc9357SAndroid Build Coastguard Worker return S_OK;
171*f6dc9357SAndroid Build Coastguard Worker
172*f6dc9357SAndroid Build Coastguard Worker if (_remainLen == kLenIdNeedInit)
173*f6dc9357SAndroid Build Coastguard Worker {
174*f6dc9357SAndroid Build Coastguard Worker if (!_keepHistory)
175*f6dc9357SAndroid Build Coastguard Worker if (!m_OutWindowStream.Create(_deflate64Mode ? kHistorySize64: kHistorySize32))
176*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
177*f6dc9357SAndroid Build Coastguard Worker RINOK(InitInStream(_needInitInStream))
178*f6dc9357SAndroid Build Coastguard Worker m_OutWindowStream.Init(_keepHistory);
179*f6dc9357SAndroid Build Coastguard Worker
180*f6dc9357SAndroid Build Coastguard Worker m_FinalBlock = false;
181*f6dc9357SAndroid Build Coastguard Worker _remainLen = 0;
182*f6dc9357SAndroid Build Coastguard Worker _needReadTable = true;
183*f6dc9357SAndroid Build Coastguard Worker }
184*f6dc9357SAndroid Build Coastguard Worker
185*f6dc9357SAndroid Build Coastguard Worker // _remainLen >= 0
186*f6dc9357SAndroid Build Coastguard Worker while (_remainLen && curSize)
187*f6dc9357SAndroid Build Coastguard Worker {
188*f6dc9357SAndroid Build Coastguard Worker _remainLen--;
189*f6dc9357SAndroid Build Coastguard Worker const Byte b = m_OutWindowStream.GetByte(_rep0);
190*f6dc9357SAndroid Build Coastguard Worker m_OutWindowStream.PutByte(b);
191*f6dc9357SAndroid Build Coastguard Worker curSize--;
192*f6dc9357SAndroid Build Coastguard Worker }
193*f6dc9357SAndroid Build Coastguard Worker
194*f6dc9357SAndroid Build Coastguard Worker UInt64 inputStart = 0;
195*f6dc9357SAndroid Build Coastguard Worker if (inputProgressLimit != 0)
196*f6dc9357SAndroid Build Coastguard Worker inputStart = m_InBitStream.GetProcessedSize();
197*f6dc9357SAndroid Build Coastguard Worker
198*f6dc9357SAndroid Build Coastguard Worker while (curSize || finishInputStream)
199*f6dc9357SAndroid Build Coastguard Worker {
200*f6dc9357SAndroid Build Coastguard Worker if (m_InBitStream.ExtraBitsWereRead())
201*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
202*f6dc9357SAndroid Build Coastguard Worker
203*f6dc9357SAndroid Build Coastguard Worker if (_needReadTable)
204*f6dc9357SAndroid Build Coastguard Worker {
205*f6dc9357SAndroid Build Coastguard Worker if (m_FinalBlock)
206*f6dc9357SAndroid Build Coastguard Worker {
207*f6dc9357SAndroid Build Coastguard Worker _remainLen = kLenIdFinished;
208*f6dc9357SAndroid Build Coastguard Worker break;
209*f6dc9357SAndroid Build Coastguard Worker }
210*f6dc9357SAndroid Build Coastguard Worker
211*f6dc9357SAndroid Build Coastguard Worker if (inputProgressLimit != 0)
212*f6dc9357SAndroid Build Coastguard Worker if (m_InBitStream.GetProcessedSize() - inputStart >= inputProgressLimit)
213*f6dc9357SAndroid Build Coastguard Worker return S_OK;
214*f6dc9357SAndroid Build Coastguard Worker
215*f6dc9357SAndroid Build Coastguard Worker if (!ReadTables())
216*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
217*f6dc9357SAndroid Build Coastguard Worker if (m_InBitStream.ExtraBitsWereRead())
218*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
219*f6dc9357SAndroid Build Coastguard Worker _needReadTable = false;
220*f6dc9357SAndroid Build Coastguard Worker }
221*f6dc9357SAndroid Build Coastguard Worker
222*f6dc9357SAndroid Build Coastguard Worker if (m_StoredMode)
223*f6dc9357SAndroid Build Coastguard Worker {
224*f6dc9357SAndroid Build Coastguard Worker if (finishInputStream && curSize == 0 && m_StoredBlockSize != 0)
225*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
226*f6dc9357SAndroid Build Coastguard Worker /* NSIS version contains some bits in bitl bits buffer.
227*f6dc9357SAndroid Build Coastguard Worker So we must read some first bytes via ReadAlignedByte */
228*f6dc9357SAndroid Build Coastguard Worker UInt32 num = m_StoredBlockSize;
229*f6dc9357SAndroid Build Coastguard Worker if (num > curSize)
230*f6dc9357SAndroid Build Coastguard Worker num = curSize;
231*f6dc9357SAndroid Build Coastguard Worker m_StoredBlockSize -= num;
232*f6dc9357SAndroid Build Coastguard Worker curSize -= num;
233*f6dc9357SAndroid Build Coastguard Worker for (; num && m_InBitStream.ThereAreDataInBitsBuffer(); num--)
234*f6dc9357SAndroid Build Coastguard Worker m_OutWindowStream.PutByte(ReadAlignedByte());
235*f6dc9357SAndroid Build Coastguard Worker if (num)
236*f6dc9357SAndroid Build Coastguard Worker {
237*f6dc9357SAndroid Build Coastguard Worker #if 1
238*f6dc9357SAndroid Build Coastguard Worker // fast code
239*f6dc9357SAndroid Build Coastguard Worker do
240*f6dc9357SAndroid Build Coastguard Worker {
241*f6dc9357SAndroid Build Coastguard Worker size_t a;
242*f6dc9357SAndroid Build Coastguard Worker Byte *buf = m_OutWindowStream.GetOutBuffer(a);
243*f6dc9357SAndroid Build Coastguard Worker // a != 0
244*f6dc9357SAndroid Build Coastguard Worker if (a > num)
245*f6dc9357SAndroid Build Coastguard Worker a = num;
246*f6dc9357SAndroid Build Coastguard Worker // a != 0
247*f6dc9357SAndroid Build Coastguard Worker a = m_InBitStream.ReadDirectBytesPart(buf, a);
248*f6dc9357SAndroid Build Coastguard Worker if (a == 0)
249*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
250*f6dc9357SAndroid Build Coastguard Worker m_OutWindowStream.SkipWrittenBytes(a);
251*f6dc9357SAndroid Build Coastguard Worker num -= (UInt32)a;
252*f6dc9357SAndroid Build Coastguard Worker }
253*f6dc9357SAndroid Build Coastguard Worker while (num);
254*f6dc9357SAndroid Build Coastguard Worker #else
255*f6dc9357SAndroid Build Coastguard Worker // slow code:
256*f6dc9357SAndroid Build Coastguard Worker do
257*f6dc9357SAndroid Build Coastguard Worker m_OutWindowStream.PutByte(m_InBitStream.ReadDirectByte());
258*f6dc9357SAndroid Build Coastguard Worker while (--num);
259*f6dc9357SAndroid Build Coastguard Worker #endif
260*f6dc9357SAndroid Build Coastguard Worker }
261*f6dc9357SAndroid Build Coastguard Worker _needReadTable = (m_StoredBlockSize == 0);
262*f6dc9357SAndroid Build Coastguard Worker continue;
263*f6dc9357SAndroid Build Coastguard Worker }
264*f6dc9357SAndroid Build Coastguard Worker
265*f6dc9357SAndroid Build Coastguard Worker while (curSize)
266*f6dc9357SAndroid Build Coastguard Worker {
267*f6dc9357SAndroid Build Coastguard Worker if (m_InBitStream.ExtraBitsWereRead_Fast())
268*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
269*f6dc9357SAndroid Build Coastguard Worker unsigned sym;
270*f6dc9357SAndroid Build Coastguard Worker #if 0
271*f6dc9357SAndroid Build Coastguard Worker sym = m_MainDecoder.Decode(&m_InBitStream);
272*f6dc9357SAndroid Build Coastguard Worker #else
273*f6dc9357SAndroid Build Coastguard Worker Z7_HUFF_DECODE_CHECK(sym, &m_MainDecoder, kNumHuffmanBits, kNumTableBits_Main, &m_InBitStream, { return S_FALSE; })
274*f6dc9357SAndroid Build Coastguard Worker #endif
275*f6dc9357SAndroid Build Coastguard Worker
276*f6dc9357SAndroid Build Coastguard Worker if (sym < 0x100)
277*f6dc9357SAndroid Build Coastguard Worker {
278*f6dc9357SAndroid Build Coastguard Worker m_OutWindowStream.PutByte((Byte)sym);
279*f6dc9357SAndroid Build Coastguard Worker curSize--;
280*f6dc9357SAndroid Build Coastguard Worker continue;
281*f6dc9357SAndroid Build Coastguard Worker }
282*f6dc9357SAndroid Build Coastguard Worker if (sym == kSymbolEndOfBlock)
283*f6dc9357SAndroid Build Coastguard Worker {
284*f6dc9357SAndroid Build Coastguard Worker _needReadTable = true;
285*f6dc9357SAndroid Build Coastguard Worker break;
286*f6dc9357SAndroid Build Coastguard Worker }
287*f6dc9357SAndroid Build Coastguard Worker #if 0
288*f6dc9357SAndroid Build Coastguard Worker if (sym >= kMainTableSize)
289*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
290*f6dc9357SAndroid Build Coastguard Worker #endif
291*f6dc9357SAndroid Build Coastguard Worker {
292*f6dc9357SAndroid Build Coastguard Worker sym -= kSymbolMatch;
293*f6dc9357SAndroid Build Coastguard Worker UInt32 len;
294*f6dc9357SAndroid Build Coastguard Worker {
295*f6dc9357SAndroid Build Coastguard Worker unsigned numBits;
296*f6dc9357SAndroid Build Coastguard Worker if (_deflate64Mode)
297*f6dc9357SAndroid Build Coastguard Worker {
298*f6dc9357SAndroid Build Coastguard Worker len = kLenStart64[sym];
299*f6dc9357SAndroid Build Coastguard Worker numBits = kLenDirectBits64[sym];
300*f6dc9357SAndroid Build Coastguard Worker }
301*f6dc9357SAndroid Build Coastguard Worker else
302*f6dc9357SAndroid Build Coastguard Worker {
303*f6dc9357SAndroid Build Coastguard Worker len = kLenStart32[sym];
304*f6dc9357SAndroid Build Coastguard Worker numBits = kLenDirectBits32[sym];
305*f6dc9357SAndroid Build Coastguard Worker }
306*f6dc9357SAndroid Build Coastguard Worker len += kMatchMinLen + m_InBitStream.ReadBits(numBits);
307*f6dc9357SAndroid Build Coastguard Worker }
308*f6dc9357SAndroid Build Coastguard Worker
309*f6dc9357SAndroid Build Coastguard Worker #if 0
310*f6dc9357SAndroid Build Coastguard Worker sym = m_DistDecoder.Decode(&m_InBitStream);
311*f6dc9357SAndroid Build Coastguard Worker if (sym >= _numDistLevels)
312*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
313*f6dc9357SAndroid Build Coastguard Worker #else
314*f6dc9357SAndroid Build Coastguard Worker Z7_HUFF_DECODE_CHECK(sym, &m_DistDecoder, kNumHuffmanBits, kNumTableBits_Dist, &m_InBitStream, { return S_FALSE; })
315*f6dc9357SAndroid Build Coastguard Worker #endif
316*f6dc9357SAndroid Build Coastguard Worker
317*f6dc9357SAndroid Build Coastguard Worker #if 1
318*f6dc9357SAndroid Build Coastguard Worker sym = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
319*f6dc9357SAndroid Build Coastguard Worker #else
320*f6dc9357SAndroid Build Coastguard Worker if (sym >= 4)
321*f6dc9357SAndroid Build Coastguard Worker {
322*f6dc9357SAndroid Build Coastguard Worker // sym &= 31;
323*f6dc9357SAndroid Build Coastguard Worker const unsigned numDirectBits = (sym - 2) >> 1;
324*f6dc9357SAndroid Build Coastguard Worker sym = (2u | (sym & 1)) << numDirectBits;
325*f6dc9357SAndroid Build Coastguard Worker sym += m_InBitStream.ReadBits(numDirectBits);
326*f6dc9357SAndroid Build Coastguard Worker }
327*f6dc9357SAndroid Build Coastguard Worker #endif
328*f6dc9357SAndroid Build Coastguard Worker UInt32 locLen = len;
329*f6dc9357SAndroid Build Coastguard Worker if (locLen > curSize)
330*f6dc9357SAndroid Build Coastguard Worker locLen = (UInt32)curSize;
331*f6dc9357SAndroid Build Coastguard Worker if (!m_OutWindowStream.CopyBlock(sym, locLen))
332*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
333*f6dc9357SAndroid Build Coastguard Worker curSize -= locLen;
334*f6dc9357SAndroid Build Coastguard Worker len -= locLen;
335*f6dc9357SAndroid Build Coastguard Worker if (len != 0)
336*f6dc9357SAndroid Build Coastguard Worker {
337*f6dc9357SAndroid Build Coastguard Worker _remainLen = (Int32)len;
338*f6dc9357SAndroid Build Coastguard Worker _rep0 = sym;
339*f6dc9357SAndroid Build Coastguard Worker break;
340*f6dc9357SAndroid Build Coastguard Worker }
341*f6dc9357SAndroid Build Coastguard Worker }
342*f6dc9357SAndroid Build Coastguard Worker }
343*f6dc9357SAndroid Build Coastguard Worker
344*f6dc9357SAndroid Build Coastguard Worker if (finishInputStream && curSize == 0)
345*f6dc9357SAndroid Build Coastguard Worker {
346*f6dc9357SAndroid Build Coastguard Worker if (m_MainDecoder.Decode(&m_InBitStream) != kSymbolEndOfBlock)
347*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
348*f6dc9357SAndroid Build Coastguard Worker _needReadTable = true;
349*f6dc9357SAndroid Build Coastguard Worker }
350*f6dc9357SAndroid Build Coastguard Worker }
351*f6dc9357SAndroid Build Coastguard Worker
352*f6dc9357SAndroid Build Coastguard Worker if (m_InBitStream.ExtraBitsWereRead())
353*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
354*f6dc9357SAndroid Build Coastguard Worker
355*f6dc9357SAndroid Build Coastguard Worker return S_OK;
356*f6dc9357SAndroid Build Coastguard Worker }
357*f6dc9357SAndroid Build Coastguard Worker
358*f6dc9357SAndroid Build Coastguard Worker
359*f6dc9357SAndroid Build Coastguard Worker #ifdef Z7_NO_EXCEPTIONS
360*f6dc9357SAndroid Build Coastguard Worker
361*f6dc9357SAndroid Build Coastguard Worker #define DEFLATE_TRY_BEGIN
362*f6dc9357SAndroid Build Coastguard Worker #define DEFLATE_TRY_END(res)
363*f6dc9357SAndroid Build Coastguard Worker
364*f6dc9357SAndroid Build Coastguard Worker #else
365*f6dc9357SAndroid Build Coastguard Worker
366*f6dc9357SAndroid Build Coastguard Worker #define DEFLATE_TRY_BEGIN try {
367*f6dc9357SAndroid Build Coastguard Worker #define DEFLATE_TRY_END(res) } \
368*f6dc9357SAndroid Build Coastguard Worker catch(const CSystemException &e) { res = e.ErrorCode; } \
369*f6dc9357SAndroid Build Coastguard Worker catch(...) { res = S_FALSE; }
370*f6dc9357SAndroid Build Coastguard Worker
371*f6dc9357SAndroid Build Coastguard Worker // catch(const CInBufferException &e) { res = e.ErrorCode; }
372*f6dc9357SAndroid Build Coastguard Worker // catch(const CLzOutWindowException &e) { res = e.ErrorCode; }
373*f6dc9357SAndroid Build Coastguard Worker
374*f6dc9357SAndroid Build Coastguard Worker #endif
375*f6dc9357SAndroid Build Coastguard Worker
376*f6dc9357SAndroid Build Coastguard Worker
CodeReal(ISequentialOutStream * outStream,ICompressProgressInfo * progress)377*f6dc9357SAndroid Build Coastguard Worker HRESULT CCoder::CodeReal(ISequentialOutStream *outStream, ICompressProgressInfo *progress)
378*f6dc9357SAndroid Build Coastguard Worker {
379*f6dc9357SAndroid Build Coastguard Worker HRESULT res;
380*f6dc9357SAndroid Build Coastguard Worker
381*f6dc9357SAndroid Build Coastguard Worker DEFLATE_TRY_BEGIN
382*f6dc9357SAndroid Build Coastguard Worker
383*f6dc9357SAndroid Build Coastguard Worker m_OutWindowStream.SetStream(outStream);
384*f6dc9357SAndroid Build Coastguard Worker CCoderReleaser flusher(this);
385*f6dc9357SAndroid Build Coastguard Worker
386*f6dc9357SAndroid Build Coastguard Worker const UInt64 inStart = _needInitInStream ? 0 : m_InBitStream.GetProcessedSize();
387*f6dc9357SAndroid Build Coastguard Worker
388*f6dc9357SAndroid Build Coastguard Worker for (;;)
389*f6dc9357SAndroid Build Coastguard Worker {
390*f6dc9357SAndroid Build Coastguard Worker const UInt32 kInputProgressLimit = 1 << 21;
391*f6dc9357SAndroid Build Coastguard Worker UInt32 curSize = 1 << 20;
392*f6dc9357SAndroid Build Coastguard Worker bool finishInputStream = false;
393*f6dc9357SAndroid Build Coastguard Worker if (_outSizeDefined)
394*f6dc9357SAndroid Build Coastguard Worker {
395*f6dc9357SAndroid Build Coastguard Worker const UInt64 rem = _outSize - GetOutProcessedCur();
396*f6dc9357SAndroid Build Coastguard Worker if (curSize >= rem)
397*f6dc9357SAndroid Build Coastguard Worker {
398*f6dc9357SAndroid Build Coastguard Worker curSize = (UInt32)rem;
399*f6dc9357SAndroid Build Coastguard Worker if (_needFinishInput)
400*f6dc9357SAndroid Build Coastguard Worker finishInputStream = true;
401*f6dc9357SAndroid Build Coastguard Worker else if (curSize == 0)
402*f6dc9357SAndroid Build Coastguard Worker break;
403*f6dc9357SAndroid Build Coastguard Worker }
404*f6dc9357SAndroid Build Coastguard Worker }
405*f6dc9357SAndroid Build Coastguard Worker
406*f6dc9357SAndroid Build Coastguard Worker RINOK(CodeSpec(curSize, finishInputStream, progress ? kInputProgressLimit : 0))
407*f6dc9357SAndroid Build Coastguard Worker
408*f6dc9357SAndroid Build Coastguard Worker if (_remainLen == kLenIdFinished)
409*f6dc9357SAndroid Build Coastguard Worker break;
410*f6dc9357SAndroid Build Coastguard Worker
411*f6dc9357SAndroid Build Coastguard Worker if (progress)
412*f6dc9357SAndroid Build Coastguard Worker {
413*f6dc9357SAndroid Build Coastguard Worker const UInt64 inSize = m_InBitStream.GetProcessedSize() - inStart;
414*f6dc9357SAndroid Build Coastguard Worker const UInt64 nowPos64 = GetOutProcessedCur();
415*f6dc9357SAndroid Build Coastguard Worker RINOK(progress->SetRatioInfo(&inSize, &nowPos64))
416*f6dc9357SAndroid Build Coastguard Worker }
417*f6dc9357SAndroid Build Coastguard Worker }
418*f6dc9357SAndroid Build Coastguard Worker
419*f6dc9357SAndroid Build Coastguard Worker flusher.NeedFlush = false;
420*f6dc9357SAndroid Build Coastguard Worker res = Flush();
421*f6dc9357SAndroid Build Coastguard Worker if (res == S_OK && _remainLen != kLenIdNeedInit && InputEofError())
422*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
423*f6dc9357SAndroid Build Coastguard Worker
424*f6dc9357SAndroid Build Coastguard Worker DEFLATE_TRY_END(res)
425*f6dc9357SAndroid Build Coastguard Worker
426*f6dc9357SAndroid Build Coastguard Worker return res;
427*f6dc9357SAndroid Build Coastguard Worker }
428*f6dc9357SAndroid Build Coastguard Worker
429*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CCoder::Code (ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 * outSize,ICompressProgressInfo * progress))430*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
431*f6dc9357SAndroid Build Coastguard Worker const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress))
432*f6dc9357SAndroid Build Coastguard Worker {
433*f6dc9357SAndroid Build Coastguard Worker SetInStream(inStream);
434*f6dc9357SAndroid Build Coastguard Worker SetOutStreamSize(outSize);
435*f6dc9357SAndroid Build Coastguard Worker const HRESULT res = CodeReal(outStream, progress);
436*f6dc9357SAndroid Build Coastguard Worker ReleaseInStream();
437*f6dc9357SAndroid Build Coastguard Worker /*
438*f6dc9357SAndroid Build Coastguard Worker if (res == S_OK)
439*f6dc9357SAndroid Build Coastguard Worker if (_needFinishInput && inSize && *inSize != m_InBitStream.GetProcessedSize())
440*f6dc9357SAndroid Build Coastguard Worker res = S_FALSE;
441*f6dc9357SAndroid Build Coastguard Worker */
442*f6dc9357SAndroid Build Coastguard Worker return res;
443*f6dc9357SAndroid Build Coastguard Worker }
444*f6dc9357SAndroid Build Coastguard Worker
445*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CCoder::SetFinishMode (UInt32 finishMode))446*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::SetFinishMode(UInt32 finishMode))
447*f6dc9357SAndroid Build Coastguard Worker {
448*f6dc9357SAndroid Build Coastguard Worker Set_NeedFinishInput(finishMode != 0);
449*f6dc9357SAndroid Build Coastguard Worker return S_OK;
450*f6dc9357SAndroid Build Coastguard Worker }
451*f6dc9357SAndroid Build Coastguard Worker
452*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CCoder::GetInStreamProcessedSize (UInt64 * value))453*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::GetInStreamProcessedSize(UInt64 *value))
454*f6dc9357SAndroid Build Coastguard Worker {
455*f6dc9357SAndroid Build Coastguard Worker *value = m_InBitStream.GetStreamSize();
456*f6dc9357SAndroid Build Coastguard Worker return S_OK;
457*f6dc9357SAndroid Build Coastguard Worker }
458*f6dc9357SAndroid Build Coastguard Worker
459*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CCoder::ReadUnusedFromInBuf (void * data,UInt32 size,UInt32 * processedSize))460*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize))
461*f6dc9357SAndroid Build Coastguard Worker {
462*f6dc9357SAndroid Build Coastguard Worker AlignToByte();
463*f6dc9357SAndroid Build Coastguard Worker UInt32 i = 0;
464*f6dc9357SAndroid Build Coastguard Worker {
465*f6dc9357SAndroid Build Coastguard Worker for (i = 0; i < size; i++)
466*f6dc9357SAndroid Build Coastguard Worker {
467*f6dc9357SAndroid Build Coastguard Worker if (!m_InBitStream.ReadAlignedByte_FromBuf(((Byte *)data)[i]))
468*f6dc9357SAndroid Build Coastguard Worker break;
469*f6dc9357SAndroid Build Coastguard Worker }
470*f6dc9357SAndroid Build Coastguard Worker }
471*f6dc9357SAndroid Build Coastguard Worker if (processedSize)
472*f6dc9357SAndroid Build Coastguard Worker *processedSize = i;
473*f6dc9357SAndroid Build Coastguard Worker return S_OK;
474*f6dc9357SAndroid Build Coastguard Worker }
475*f6dc9357SAndroid Build Coastguard Worker
476*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CCoder::SetInStream (ISequentialInStream * inStream))477*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::SetInStream(ISequentialInStream *inStream))
478*f6dc9357SAndroid Build Coastguard Worker {
479*f6dc9357SAndroid Build Coastguard Worker m_InStreamRef = inStream;
480*f6dc9357SAndroid Build Coastguard Worker m_InBitStream.SetStream(inStream);
481*f6dc9357SAndroid Build Coastguard Worker return S_OK;
482*f6dc9357SAndroid Build Coastguard Worker }
483*f6dc9357SAndroid Build Coastguard Worker
484*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CCoder::ReleaseInStream ())485*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::ReleaseInStream())
486*f6dc9357SAndroid Build Coastguard Worker {
487*f6dc9357SAndroid Build Coastguard Worker m_InStreamRef.Release();
488*f6dc9357SAndroid Build Coastguard Worker m_InBitStream.ClearStreamPtr();
489*f6dc9357SAndroid Build Coastguard Worker return S_OK;
490*f6dc9357SAndroid Build Coastguard Worker }
491*f6dc9357SAndroid Build Coastguard Worker
492*f6dc9357SAndroid Build Coastguard Worker
SetOutStreamSizeResume(const UInt64 * outSize)493*f6dc9357SAndroid Build Coastguard Worker void CCoder::SetOutStreamSizeResume(const UInt64 *outSize)
494*f6dc9357SAndroid Build Coastguard Worker {
495*f6dc9357SAndroid Build Coastguard Worker _outSizeDefined = (outSize != NULL);
496*f6dc9357SAndroid Build Coastguard Worker _outSize = 0;
497*f6dc9357SAndroid Build Coastguard Worker if (_outSizeDefined)
498*f6dc9357SAndroid Build Coastguard Worker _outSize = *outSize;
499*f6dc9357SAndroid Build Coastguard Worker m_OutWindowStream.Init(_keepHistory);
500*f6dc9357SAndroid Build Coastguard Worker _outStartPos = m_OutWindowStream.GetProcessedSize();
501*f6dc9357SAndroid Build Coastguard Worker _remainLen = kLenIdNeedInit;
502*f6dc9357SAndroid Build Coastguard Worker }
503*f6dc9357SAndroid Build Coastguard Worker
504*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CCoder::SetOutStreamSize (const UInt64 * outSize))505*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::SetOutStreamSize(const UInt64 *outSize))
506*f6dc9357SAndroid Build Coastguard Worker {
507*f6dc9357SAndroid Build Coastguard Worker /*
508*f6dc9357SAndroid Build Coastguard Worker 18.06:
509*f6dc9357SAndroid Build Coastguard Worker We want to support GetInputProcessedSize() before CCoder::Read()
510*f6dc9357SAndroid Build Coastguard Worker So we call m_InBitStream.Init() even before buffer allocations
511*f6dc9357SAndroid Build Coastguard Worker m_InBitStream.Init() just sets variables to default values
512*f6dc9357SAndroid Build Coastguard Worker But later we will call m_InBitStream.Init() again with real buffer pointers
513*f6dc9357SAndroid Build Coastguard Worker */
514*f6dc9357SAndroid Build Coastguard Worker m_InBitStream.Init();
515*f6dc9357SAndroid Build Coastguard Worker _needInitInStream = true;
516*f6dc9357SAndroid Build Coastguard Worker SetOutStreamSizeResume(outSize);
517*f6dc9357SAndroid Build Coastguard Worker return S_OK;
518*f6dc9357SAndroid Build Coastguard Worker }
519*f6dc9357SAndroid Build Coastguard Worker
520*f6dc9357SAndroid Build Coastguard Worker
521*f6dc9357SAndroid Build Coastguard Worker #ifndef Z7_NO_READ_FROM_CODER
522*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CCoder::Read (void * data,UInt32 size,UInt32 * processedSize))523*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CCoder::Read(void *data, UInt32 size, UInt32 *processedSize))
524*f6dc9357SAndroid Build Coastguard Worker {
525*f6dc9357SAndroid Build Coastguard Worker if (processedSize)
526*f6dc9357SAndroid Build Coastguard Worker *processedSize = 0;
527*f6dc9357SAndroid Build Coastguard Worker const UInt64 outPos = GetOutProcessedCur();
528*f6dc9357SAndroid Build Coastguard Worker
529*f6dc9357SAndroid Build Coastguard Worker bool finishInputStream = false;
530*f6dc9357SAndroid Build Coastguard Worker if (_outSizeDefined)
531*f6dc9357SAndroid Build Coastguard Worker {
532*f6dc9357SAndroid Build Coastguard Worker const UInt64 rem = _outSize - outPos;
533*f6dc9357SAndroid Build Coastguard Worker if (size >= rem)
534*f6dc9357SAndroid Build Coastguard Worker {
535*f6dc9357SAndroid Build Coastguard Worker size = (UInt32)rem;
536*f6dc9357SAndroid Build Coastguard Worker if (_needFinishInput)
537*f6dc9357SAndroid Build Coastguard Worker finishInputStream = true;
538*f6dc9357SAndroid Build Coastguard Worker }
539*f6dc9357SAndroid Build Coastguard Worker }
540*f6dc9357SAndroid Build Coastguard Worker if (!finishInputStream && size == 0)
541*f6dc9357SAndroid Build Coastguard Worker return S_OK;
542*f6dc9357SAndroid Build Coastguard Worker
543*f6dc9357SAndroid Build Coastguard Worker HRESULT res;
544*f6dc9357SAndroid Build Coastguard Worker DEFLATE_TRY_BEGIN
545*f6dc9357SAndroid Build Coastguard Worker m_OutWindowStream.SetMemStream((Byte *)data);
546*f6dc9357SAndroid Build Coastguard Worker res = CodeSpec(size, finishInputStream);
547*f6dc9357SAndroid Build Coastguard Worker DEFLATE_TRY_END(res)
548*f6dc9357SAndroid Build Coastguard Worker {
549*f6dc9357SAndroid Build Coastguard Worker const HRESULT res2 = Flush();
550*f6dc9357SAndroid Build Coastguard Worker if (res2 != S_OK)
551*f6dc9357SAndroid Build Coastguard Worker res = res2;
552*f6dc9357SAndroid Build Coastguard Worker }
553*f6dc9357SAndroid Build Coastguard Worker if (processedSize)
554*f6dc9357SAndroid Build Coastguard Worker *processedSize = (UInt32)(GetOutProcessedCur() - outPos);
555*f6dc9357SAndroid Build Coastguard Worker m_OutWindowStream.SetMemStream(NULL);
556*f6dc9357SAndroid Build Coastguard Worker return res;
557*f6dc9357SAndroid Build Coastguard Worker }
558*f6dc9357SAndroid Build Coastguard Worker
559*f6dc9357SAndroid Build Coastguard Worker #endif
560*f6dc9357SAndroid Build Coastguard Worker
561*f6dc9357SAndroid Build Coastguard Worker
CodeResume(ISequentialOutStream * outStream,const UInt64 * outSize,ICompressProgressInfo * progress)562*f6dc9357SAndroid Build Coastguard Worker HRESULT CCoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
563*f6dc9357SAndroid Build Coastguard Worker {
564*f6dc9357SAndroid Build Coastguard Worker SetOutStreamSizeResume(outSize);
565*f6dc9357SAndroid Build Coastguard Worker return CodeReal(outStream, progress);
566*f6dc9357SAndroid Build Coastguard Worker }
567*f6dc9357SAndroid Build Coastguard Worker
568*f6dc9357SAndroid Build Coastguard Worker }}}
569