rlm@1
|
1 // Rar3Decoder.cpp
|
rlm@1
|
2 // According to unRAR license, this code may not be used to develop
|
rlm@1
|
3 // a program that creates RAR archives
|
rlm@1
|
4
|
rlm@1
|
5 #include "StdAfx.h"
|
rlm@1
|
6
|
rlm@1
|
7 #include "../Common/StreamUtils.h"
|
rlm@1
|
8
|
rlm@1
|
9 #include "Rar3Decoder.h"
|
rlm@1
|
10
|
rlm@1
|
11 namespace NCompress {
|
rlm@1
|
12 namespace NRar3 {
|
rlm@1
|
13
|
rlm@1
|
14 static const UInt32 kNumAlignReps = 15;
|
rlm@1
|
15
|
rlm@1
|
16 static const UInt32 kSymbolReadTable = 256;
|
rlm@1
|
17 static const UInt32 kSymbolRep = 259;
|
rlm@1
|
18 static const UInt32 kSymbolLen2 = kSymbolRep + kNumReps;
|
rlm@1
|
19
|
rlm@1
|
20 static const Byte kLenStart[kLenTableSize] = {0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224};
|
rlm@1
|
21 static const Byte kLenDirectBits[kLenTableSize] = {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5};
|
rlm@1
|
22
|
rlm@1
|
23 static const Byte kDistDirectBits[kDistTableSize] =
|
rlm@1
|
24 {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,
|
rlm@1
|
25 16,16,16,16,16,16,16,16,16,16,16,16,16,16,
|
rlm@1
|
26 18,18,18,18,18,18,18,18,18,18,18,18};
|
rlm@1
|
27
|
rlm@1
|
28 static const Byte kLevelDirectBits[kLevelTableSize] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
|
rlm@1
|
29
|
rlm@1
|
30 static const Byte kLen2DistStarts[kNumLen2Symbols]={0,4,8,16,32,64,128,192};
|
rlm@1
|
31 static const Byte kLen2DistDirectBits[kNumLen2Symbols]={2,2,3, 4, 5, 6, 6, 6};
|
rlm@1
|
32
|
rlm@1
|
33 static const UInt32 kDistLimit3 = 0x2000 - 2;
|
rlm@1
|
34 static const UInt32 kDistLimit4 = 0x40000 - 2;
|
rlm@1
|
35
|
rlm@1
|
36 static const UInt32 kNormalMatchMinLen = 3;
|
rlm@1
|
37
|
rlm@1
|
38 static const UInt32 kVmDataSizeMax = 1 << 16;
|
rlm@1
|
39 static const UInt32 kVmCodeSizeMax = 1 << 16;
|
rlm@1
|
40
|
rlm@1
|
41 CDecoder::CDecoder():
|
rlm@1
|
42 _window(0),
|
rlm@1
|
43 _winPos(0),
|
rlm@1
|
44 _wrPtr(0),
|
rlm@1
|
45 _lzSize(0),
|
rlm@1
|
46 _writtenFileSize(0),
|
rlm@1
|
47 _vmData(0),
|
rlm@1
|
48 _vmCode(0),
|
rlm@1
|
49 m_IsSolid(false)
|
rlm@1
|
50 {
|
rlm@1
|
51 }
|
rlm@1
|
52
|
rlm@1
|
53 CDecoder::~CDecoder()
|
rlm@1
|
54 {
|
rlm@1
|
55 InitFilters();
|
rlm@1
|
56 ::MidFree(_vmData);
|
rlm@1
|
57 ::MidFree(_window);
|
rlm@1
|
58 }
|
rlm@1
|
59
|
rlm@1
|
60 HRESULT CDecoder::WriteDataToStream(const Byte *data, UInt32 size)
|
rlm@1
|
61 {
|
rlm@1
|
62 return WriteStream(_outStream, data, size);
|
rlm@1
|
63 }
|
rlm@1
|
64
|
rlm@1
|
65 HRESULT CDecoder::WriteData(const Byte *data, UInt32 size)
|
rlm@1
|
66 {
|
rlm@1
|
67 HRESULT res = S_OK;
|
rlm@1
|
68 if (_writtenFileSize < _unpackSize)
|
rlm@1
|
69 {
|
rlm@1
|
70 UInt32 curSize = size;
|
rlm@1
|
71 UInt64 remain = _unpackSize - _writtenFileSize;
|
rlm@1
|
72 if (remain < curSize)
|
rlm@1
|
73 curSize = (UInt32)remain;
|
rlm@1
|
74 res = WriteDataToStream(data, curSize);
|
rlm@1
|
75 }
|
rlm@1
|
76 _writtenFileSize += size;
|
rlm@1
|
77 return res;
|
rlm@1
|
78 }
|
rlm@1
|
79
|
rlm@1
|
80 HRESULT CDecoder::WriteArea(UInt32 startPtr, UInt32 endPtr)
|
rlm@1
|
81 {
|
rlm@1
|
82 if (startPtr <= endPtr)
|
rlm@1
|
83 return WriteData(_window + startPtr, endPtr - startPtr);
|
rlm@1
|
84 RINOK(WriteData(_window + startPtr, kWindowSize - startPtr));
|
rlm@1
|
85 return WriteData(_window, endPtr);
|
rlm@1
|
86 }
|
rlm@1
|
87
|
rlm@1
|
88 void CDecoder::ExecuteFilter(int tempFilterIndex, NVm::CBlockRef &outBlockRef)
|
rlm@1
|
89 {
|
rlm@1
|
90 CTempFilter *tempFilter = _tempFilters[tempFilterIndex];
|
rlm@1
|
91 tempFilter->InitR[6] = (UInt32)_writtenFileSize;
|
rlm@1
|
92 NVm::SetValue32(&tempFilter->GlobalData[0x24], (UInt32)_writtenFileSize);
|
rlm@1
|
93 NVm::SetValue32(&tempFilter->GlobalData[0x28], (UInt32)(_writtenFileSize >> 32));
|
rlm@1
|
94 CFilter *filter = _filters[tempFilter->FilterIndex];
|
rlm@1
|
95 _vm.Execute(filter, tempFilter, outBlockRef, filter->GlobalData);
|
rlm@1
|
96 delete tempFilter;
|
rlm@1
|
97 _tempFilters[tempFilterIndex] = 0;
|
rlm@1
|
98 }
|
rlm@1
|
99
|
rlm@1
|
100 HRESULT CDecoder::WriteBuf()
|
rlm@1
|
101 {
|
rlm@1
|
102 UInt32 writtenBorder = _wrPtr;
|
rlm@1
|
103 UInt32 writeSize = (_winPos - writtenBorder) & kWindowMask;
|
rlm@1
|
104 for (int i = 0; i < _tempFilters.Size(); i++)
|
rlm@1
|
105 {
|
rlm@1
|
106 CTempFilter *filter = _tempFilters[i];
|
rlm@1
|
107 if (filter == NULL)
|
rlm@1
|
108 continue;
|
rlm@1
|
109 if (filter->NextWindow)
|
rlm@1
|
110 {
|
rlm@1
|
111 filter->NextWindow = false;
|
rlm@1
|
112 continue;
|
rlm@1
|
113 }
|
rlm@1
|
114 UInt32 blockStart = filter->BlockStart;
|
rlm@1
|
115 UInt32 blockSize = filter->BlockSize;
|
rlm@1
|
116 if (((blockStart - writtenBorder) & kWindowMask) < writeSize)
|
rlm@1
|
117 {
|
rlm@1
|
118 if (writtenBorder != blockStart)
|
rlm@1
|
119 {
|
rlm@1
|
120 RINOK(WriteArea(writtenBorder, blockStart));
|
rlm@1
|
121 writtenBorder = blockStart;
|
rlm@1
|
122 writeSize = (_winPos - writtenBorder) & kWindowMask;
|
rlm@1
|
123 }
|
rlm@1
|
124 if (blockSize <= writeSize)
|
rlm@1
|
125 {
|
rlm@1
|
126 UInt32 blockEnd = (blockStart + blockSize) & kWindowMask;
|
rlm@1
|
127 if (blockStart < blockEnd || blockEnd == 0)
|
rlm@1
|
128 _vm.SetMemory(0, _window + blockStart, blockSize);
|
rlm@1
|
129 else
|
rlm@1
|
130 {
|
rlm@1
|
131 UInt32 tailSize = kWindowSize - blockStart;
|
rlm@1
|
132 _vm.SetMemory(0, _window + blockStart, tailSize);
|
rlm@1
|
133 _vm.SetMemory(tailSize, _window, blockEnd);
|
rlm@1
|
134 }
|
rlm@1
|
135 NVm::CBlockRef outBlockRef;
|
rlm@1
|
136 ExecuteFilter(i, outBlockRef);
|
rlm@1
|
137 while (i + 1 < _tempFilters.Size())
|
rlm@1
|
138 {
|
rlm@1
|
139 CTempFilter *nextFilter = _tempFilters[i + 1];
|
rlm@1
|
140 if (nextFilter == NULL || nextFilter->BlockStart != blockStart ||
|
rlm@1
|
141 nextFilter->BlockSize != outBlockRef.Size || nextFilter->NextWindow)
|
rlm@1
|
142 break;
|
rlm@1
|
143 _vm.SetMemory(0, _vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size);
|
rlm@1
|
144 ExecuteFilter(++i, outBlockRef);
|
rlm@1
|
145 }
|
rlm@1
|
146 WriteDataToStream(_vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size);
|
rlm@1
|
147 _writtenFileSize += outBlockRef.Size;
|
rlm@1
|
148 writtenBorder = blockEnd;
|
rlm@1
|
149 writeSize = (_winPos - writtenBorder) & kWindowMask;
|
rlm@1
|
150 }
|
rlm@1
|
151 else
|
rlm@1
|
152 {
|
rlm@1
|
153 for (int j = i; j < _tempFilters.Size(); j++)
|
rlm@1
|
154 {
|
rlm@1
|
155 CTempFilter *filter = _tempFilters[j];
|
rlm@1
|
156 if (filter != NULL && filter->NextWindow)
|
rlm@1
|
157 filter->NextWindow = false;
|
rlm@1
|
158 }
|
rlm@1
|
159 _wrPtr = writtenBorder;
|
rlm@1
|
160 return S_OK; // check it
|
rlm@1
|
161 }
|
rlm@1
|
162 }
|
rlm@1
|
163 }
|
rlm@1
|
164
|
rlm@1
|
165 _wrPtr = _winPos;
|
rlm@1
|
166 return WriteArea(writtenBorder, _winPos);
|
rlm@1
|
167 }
|
rlm@1
|
168
|
rlm@1
|
169 void CDecoder::InitFilters()
|
rlm@1
|
170 {
|
rlm@1
|
171 _lastFilter = 0;
|
rlm@1
|
172 int i;
|
rlm@1
|
173 for (i = 0; i < _tempFilters.Size(); i++)
|
rlm@1
|
174 delete _tempFilters[i];
|
rlm@1
|
175 _tempFilters.Clear();
|
rlm@1
|
176 for (i = 0; i < _filters.Size(); i++)
|
rlm@1
|
177 delete _filters[i];
|
rlm@1
|
178 _filters.Clear();
|
rlm@1
|
179 }
|
rlm@1
|
180
|
rlm@1
|
181 bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize)
|
rlm@1
|
182 {
|
rlm@1
|
183 CMemBitDecoder inp;
|
rlm@1
|
184 inp.Init(_vmData, codeSize);
|
rlm@1
|
185
|
rlm@1
|
186 UInt32 filterIndex;
|
rlm@1
|
187 if (firstByte & 0x80)
|
rlm@1
|
188 {
|
rlm@1
|
189 filterIndex = NVm::ReadEncodedUInt32(inp);
|
rlm@1
|
190 if (filterIndex == 0)
|
rlm@1
|
191 InitFilters();
|
rlm@1
|
192 else
|
rlm@1
|
193 filterIndex--;
|
rlm@1
|
194 }
|
rlm@1
|
195 else
|
rlm@1
|
196 filterIndex = _lastFilter;
|
rlm@1
|
197 if (filterIndex > (UInt32)_filters.Size())
|
rlm@1
|
198 return false;
|
rlm@1
|
199 _lastFilter = filterIndex;
|
rlm@1
|
200 bool newFilter = (filterIndex == (UInt32)_filters.Size());
|
rlm@1
|
201
|
rlm@1
|
202 CFilter *filter;
|
rlm@1
|
203 if (newFilter)
|
rlm@1
|
204 {
|
rlm@1
|
205 // check if too many filters
|
rlm@1
|
206 if (filterIndex > 1024)
|
rlm@1
|
207 return false;
|
rlm@1
|
208 filter = new CFilter;
|
rlm@1
|
209 _filters.Add(filter);
|
rlm@1
|
210 }
|
rlm@1
|
211 else
|
rlm@1
|
212 {
|
rlm@1
|
213 filter = _filters[filterIndex];
|
rlm@1
|
214 filter->ExecCount++;
|
rlm@1
|
215 }
|
rlm@1
|
216
|
rlm@1
|
217 int numEmptyItems = 0;
|
rlm@1
|
218 int i;
|
rlm@1
|
219 for (i = 0; i < _tempFilters.Size(); i++)
|
rlm@1
|
220 {
|
rlm@1
|
221 _tempFilters[i - numEmptyItems] = _tempFilters[i];
|
rlm@1
|
222 if (_tempFilters[i] == NULL)
|
rlm@1
|
223 numEmptyItems++;
|
rlm@1
|
224 if (numEmptyItems > 0)
|
rlm@1
|
225 _tempFilters[i] = NULL;
|
rlm@1
|
226 }
|
rlm@1
|
227 if (numEmptyItems == 0)
|
rlm@1
|
228 {
|
rlm@1
|
229 _tempFilters.Add(NULL);
|
rlm@1
|
230 numEmptyItems = 1;
|
rlm@1
|
231 }
|
rlm@1
|
232 CTempFilter *tempFilter = new CTempFilter;
|
rlm@1
|
233 _tempFilters[_tempFilters.Size() - numEmptyItems] = tempFilter;
|
rlm@1
|
234 tempFilter->FilterIndex = filterIndex;
|
rlm@1
|
235 tempFilter->ExecCount = filter->ExecCount;
|
rlm@1
|
236
|
rlm@1
|
237 UInt32 blockStart = NVm::ReadEncodedUInt32(inp);
|
rlm@1
|
238 if (firstByte & 0x40)
|
rlm@1
|
239 blockStart += 258;
|
rlm@1
|
240 tempFilter->BlockStart = (blockStart + _winPos) & kWindowMask;
|
rlm@1
|
241 if (firstByte & 0x20)
|
rlm@1
|
242 filter->BlockSize = NVm::ReadEncodedUInt32(inp);
|
rlm@1
|
243 tempFilter->BlockSize = filter->BlockSize;
|
rlm@1
|
244 tempFilter->NextWindow = _wrPtr != _winPos && ((_wrPtr - _winPos) & kWindowMask) <= blockStart;
|
rlm@1
|
245
|
rlm@1
|
246 memset(tempFilter->InitR, 0, sizeof(tempFilter->InitR));
|
rlm@1
|
247 tempFilter->InitR[3] = NVm::kGlobalOffset;
|
rlm@1
|
248 tempFilter->InitR[4] = tempFilter->BlockSize;
|
rlm@1
|
249 tempFilter->InitR[5] = tempFilter->ExecCount;
|
rlm@1
|
250 if (firstByte & 0x10)
|
rlm@1
|
251 {
|
rlm@1
|
252 UInt32 initMask = inp.ReadBits(NVm::kNumGpRegs);
|
rlm@1
|
253 for (int i = 0; i < NVm::kNumGpRegs; i++)
|
rlm@1
|
254 if (initMask & (1 << i))
|
rlm@1
|
255 tempFilter->InitR[i] = NVm::ReadEncodedUInt32(inp);
|
rlm@1
|
256 }
|
rlm@1
|
257 if (newFilter)
|
rlm@1
|
258 {
|
rlm@1
|
259 UInt32 vmCodeSize = NVm::ReadEncodedUInt32(inp);
|
rlm@1
|
260 if (vmCodeSize >= kVmCodeSizeMax || vmCodeSize == 0)
|
rlm@1
|
261 return false;
|
rlm@1
|
262 for (UInt32 i = 0; i < vmCodeSize; i++)
|
rlm@1
|
263 _vmCode[i] = (Byte)inp.ReadBits(8);
|
rlm@1
|
264 _vm.PrepareProgram(_vmCode, vmCodeSize, filter);
|
rlm@1
|
265 }
|
rlm@1
|
266
|
rlm@1
|
267 tempFilter->AllocateEmptyFixedGlobal();
|
rlm@1
|
268
|
rlm@1
|
269 Byte *globalData = &tempFilter->GlobalData[0];
|
rlm@1
|
270 for (i = 0; i < NVm::kNumGpRegs; i++)
|
rlm@1
|
271 NVm::SetValue32(&globalData[i * 4], tempFilter->InitR[i]);
|
rlm@1
|
272 NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockSize], tempFilter->BlockSize);
|
rlm@1
|
273 NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockPos], 0); // It was commented. why?
|
rlm@1
|
274 NVm::SetValue32(&globalData[NVm::NGlobalOffset::kExecCount], tempFilter->ExecCount);
|
rlm@1
|
275
|
rlm@1
|
276 if (firstByte & 8)
|
rlm@1
|
277 {
|
rlm@1
|
278 UInt32 dataSize = NVm::ReadEncodedUInt32(inp);
|
rlm@1
|
279 if (dataSize > NVm::kGlobalSize - NVm::kFixedGlobalSize)
|
rlm@1
|
280 return false;
|
rlm@1
|
281 CRecordVector<Byte> &globalData = tempFilter->GlobalData;
|
rlm@1
|
282 int requredSize = (int)(dataSize + NVm::kFixedGlobalSize);
|
rlm@1
|
283 if (globalData.Size() < requredSize)
|
rlm@1
|
284 {
|
rlm@1
|
285 globalData.Reserve(requredSize);
|
rlm@1
|
286 for (; globalData.Size() < requredSize; i++)
|
rlm@1
|
287 globalData.Add(0);
|
rlm@1
|
288 }
|
rlm@1
|
289 for (UInt32 i = 0; i < dataSize; i++)
|
rlm@1
|
290 globalData[NVm::kFixedGlobalSize + i] = (Byte)inp.ReadBits(8);
|
rlm@1
|
291 }
|
rlm@1
|
292 return true;
|
rlm@1
|
293 }
|
rlm@1
|
294
|
rlm@1
|
295 bool CDecoder::ReadVmCodeLZ()
|
rlm@1
|
296 {
|
rlm@1
|
297 UInt32 firstByte = m_InBitStream.ReadBits(8);
|
rlm@1
|
298 UInt32 length = (firstByte & 7) + 1;
|
rlm@1
|
299 if (length == 7)
|
rlm@1
|
300 length = m_InBitStream.ReadBits(8) + 7;
|
rlm@1
|
301 else if (length == 8)
|
rlm@1
|
302 length = m_InBitStream.ReadBits(16);
|
rlm@1
|
303 if (length > kVmDataSizeMax)
|
rlm@1
|
304 return false;
|
rlm@1
|
305 for (UInt32 i = 0; i < length; i++)
|
rlm@1
|
306 _vmData[i] = (Byte)m_InBitStream.ReadBits(8);
|
rlm@1
|
307 return AddVmCode(firstByte, length);
|
rlm@1
|
308 }
|
rlm@1
|
309
|
rlm@1
|
310 bool CDecoder::ReadVmCodePPM()
|
rlm@1
|
311 {
|
rlm@1
|
312 int firstByte = DecodePpmSymbol();
|
rlm@1
|
313 if (firstByte == -1)
|
rlm@1
|
314 return false;
|
rlm@1
|
315 UInt32 length = (firstByte & 7) + 1;
|
rlm@1
|
316 if (length == 7)
|
rlm@1
|
317 {
|
rlm@1
|
318 int b1 = DecodePpmSymbol();
|
rlm@1
|
319 if (b1 == -1)
|
rlm@1
|
320 return false;
|
rlm@1
|
321 length = b1 + 7;
|
rlm@1
|
322 }
|
rlm@1
|
323 else if (length == 8)
|
rlm@1
|
324 {
|
rlm@1
|
325 int b1 = DecodePpmSymbol();
|
rlm@1
|
326 if (b1 == -1)
|
rlm@1
|
327 return false;
|
rlm@1
|
328 int b2 = DecodePpmSymbol();
|
rlm@1
|
329 if (b2 == -1)
|
rlm@1
|
330 return false;
|
rlm@1
|
331 length = b1 * 256 + b2;
|
rlm@1
|
332 }
|
rlm@1
|
333 if (length > kVmDataSizeMax)
|
rlm@1
|
334 return false;
|
rlm@1
|
335 for (UInt32 i = 0; i < length; i++)
|
rlm@1
|
336 {
|
rlm@1
|
337 int b = DecodePpmSymbol();
|
rlm@1
|
338 if (b == -1)
|
rlm@1
|
339 return false;
|
rlm@1
|
340 _vmData[i] = (Byte)b;
|
rlm@1
|
341 }
|
rlm@1
|
342 return AddVmCode(firstByte, length);
|
rlm@1
|
343 }
|
rlm@1
|
344
|
rlm@1
|
345 #define RIF(x) { if (!(x)) return S_FALSE; }
|
rlm@1
|
346
|
rlm@1
|
347 UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
|
rlm@1
|
348
|
rlm@1
|
349 /////////////////////////////////////////////////
|
rlm@1
|
350 // PPM
|
rlm@1
|
351
|
rlm@1
|
352 HRESULT CDecoder::InitPPM()
|
rlm@1
|
353 {
|
rlm@1
|
354 Byte maxOrder = (Byte)ReadBits(7);
|
rlm@1
|
355
|
rlm@1
|
356 bool reset = ((maxOrder & 0x20) != 0);
|
rlm@1
|
357 int maxMB = 0;
|
rlm@1
|
358 if (reset)
|
rlm@1
|
359 maxMB = (Byte)ReadBits(8);
|
rlm@1
|
360 else
|
rlm@1
|
361 {
|
rlm@1
|
362 if (_ppm.SubAllocator.GetSubAllocatorSize()== 0)
|
rlm@1
|
363 return S_FALSE;
|
rlm@1
|
364 }
|
rlm@1
|
365 if (maxOrder & 0x40)
|
rlm@1
|
366 PpmEscChar = (Byte)ReadBits(8);
|
rlm@1
|
367 m_InBitStream.InitRangeCoder();
|
rlm@1
|
368 /*
|
rlm@1
|
369 if (m_InBitStream.m_BitPos != 0)
|
rlm@1
|
370 return S_FALSE;
|
rlm@1
|
371 */
|
rlm@1
|
372 if (reset)
|
rlm@1
|
373 {
|
rlm@1
|
374 maxOrder = (maxOrder & 0x1F) + 1;
|
rlm@1
|
375 if (maxOrder > 16)
|
rlm@1
|
376 maxOrder = 16 + (maxOrder - 16) * 3;
|
rlm@1
|
377 if (maxOrder == 1)
|
rlm@1
|
378 {
|
rlm@1
|
379 // SubAlloc.StopSubAllocator();
|
rlm@1
|
380 _ppm.SubAllocator.StopSubAllocator();
|
rlm@1
|
381 return S_FALSE;
|
rlm@1
|
382 }
|
rlm@1
|
383 // SubAlloc.StartSubAllocator(MaxMB+1);
|
rlm@1
|
384 // StartModelRare(maxOrder);
|
rlm@1
|
385
|
rlm@1
|
386 if (!_ppm.SubAllocator.StartSubAllocator((maxMB + 1) << 20))
|
rlm@1
|
387 return E_OUTOFMEMORY;
|
rlm@1
|
388 _ppm.MaxOrder = 0;
|
rlm@1
|
389 _ppm.StartModelRare(maxOrder);
|
rlm@1
|
390
|
rlm@1
|
391 }
|
rlm@1
|
392 // return (minContext != NULL);
|
rlm@1
|
393
|
rlm@1
|
394 return S_OK;
|
rlm@1
|
395 }
|
rlm@1
|
396
|
rlm@1
|
397 int CDecoder::DecodePpmSymbol() { return _ppm.DecodeSymbol(&m_InBitStream); }
|
rlm@1
|
398
|
rlm@1
|
399 HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing)
|
rlm@1
|
400 {
|
rlm@1
|
401 keepDecompressing = false;
|
rlm@1
|
402 do
|
rlm@1
|
403 {
|
rlm@1
|
404 if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
|
rlm@1
|
405 {
|
rlm@1
|
406 RINOK(WriteBuf());
|
rlm@1
|
407 if (_writtenFileSize > _unpackSize)
|
rlm@1
|
408 {
|
rlm@1
|
409 keepDecompressing = false;
|
rlm@1
|
410 return S_OK;
|
rlm@1
|
411 }
|
rlm@1
|
412 }
|
rlm@1
|
413 int c = DecodePpmSymbol();
|
rlm@1
|
414 if (c == -1)
|
rlm@1
|
415 {
|
rlm@1
|
416 // Original code sets PPMError=true here and then it returns S_OK. Why ???
|
rlm@1
|
417 // return S_OK;
|
rlm@1
|
418 return S_FALSE;
|
rlm@1
|
419 }
|
rlm@1
|
420 if (c == PpmEscChar)
|
rlm@1
|
421 {
|
rlm@1
|
422 int nextCh = DecodePpmSymbol();
|
rlm@1
|
423 if (nextCh == 0)
|
rlm@1
|
424 return ReadTables(keepDecompressing);
|
rlm@1
|
425 if (nextCh == 2 || nextCh == -1)
|
rlm@1
|
426 return S_OK;
|
rlm@1
|
427 if (nextCh == 3)
|
rlm@1
|
428 {
|
rlm@1
|
429 if (!ReadVmCodePPM())
|
rlm@1
|
430 return S_FALSE;
|
rlm@1
|
431 continue;
|
rlm@1
|
432 }
|
rlm@1
|
433 if (nextCh == 4 || nextCh == 5)
|
rlm@1
|
434 {
|
rlm@1
|
435 UInt32 distance = 0;
|
rlm@1
|
436 UInt32 length = 4;
|
rlm@1
|
437 if (nextCh == 4)
|
rlm@1
|
438 {
|
rlm@1
|
439 for (int i = 0; i < 3; i++)
|
rlm@1
|
440 {
|
rlm@1
|
441 int c = DecodePpmSymbol();
|
rlm@1
|
442 if (c == -1)
|
rlm@1
|
443 return S_OK;
|
rlm@1
|
444 distance = (distance << 8) + (Byte)c;
|
rlm@1
|
445 }
|
rlm@1
|
446 distance++;
|
rlm@1
|
447 length += 28;
|
rlm@1
|
448 }
|
rlm@1
|
449 int c = DecodePpmSymbol();
|
rlm@1
|
450 if (c == -1)
|
rlm@1
|
451 return S_OK;
|
rlm@1
|
452 length += c;
|
rlm@1
|
453 if (distance >= _lzSize)
|
rlm@1
|
454 return S_FALSE;
|
rlm@1
|
455 CopyBlock(distance, length);
|
rlm@1
|
456 num -= (Int32)length;
|
rlm@1
|
457 continue;
|
rlm@1
|
458 }
|
rlm@1
|
459 }
|
rlm@1
|
460 PutByte((Byte)c);
|
rlm@1
|
461 num--;
|
rlm@1
|
462 }
|
rlm@1
|
463 while (num >= 0);
|
rlm@1
|
464 keepDecompressing = true;
|
rlm@1
|
465 return S_OK;
|
rlm@1
|
466 }
|
rlm@1
|
467
|
rlm@1
|
468 /////////////////////////////////////////////////
|
rlm@1
|
469 // LZ
|
rlm@1
|
470
|
rlm@1
|
471 HRESULT CDecoder::ReadTables(bool &keepDecompressing)
|
rlm@1
|
472 {
|
rlm@1
|
473 keepDecompressing = true;
|
rlm@1
|
474 ReadBits((8 - m_InBitStream.GetBitPosition()) & 7);
|
rlm@1
|
475 if (ReadBits(1) != 0)
|
rlm@1
|
476 {
|
rlm@1
|
477 _lzMode = false;
|
rlm@1
|
478 return InitPPM();
|
rlm@1
|
479 }
|
rlm@1
|
480
|
rlm@1
|
481 _lzMode = true;
|
rlm@1
|
482 PrevAlignBits = 0;
|
rlm@1
|
483 PrevAlignCount = 0;
|
rlm@1
|
484
|
rlm@1
|
485 Byte levelLevels[kLevelTableSize];
|
rlm@1
|
486 Byte newLevels[kTablesSizesSum];
|
rlm@1
|
487
|
rlm@1
|
488 if (ReadBits(1) == 0)
|
rlm@1
|
489 memset(m_LastLevels, 0, kTablesSizesSum);
|
rlm@1
|
490
|
rlm@1
|
491 int i;
|
rlm@1
|
492 for (i = 0; i < kLevelTableSize; i++)
|
rlm@1
|
493 {
|
rlm@1
|
494 UInt32 length = ReadBits(4);
|
rlm@1
|
495 if (length == 15)
|
rlm@1
|
496 {
|
rlm@1
|
497 UInt32 zeroCount = ReadBits(4);
|
rlm@1
|
498 if (zeroCount != 0)
|
rlm@1
|
499 {
|
rlm@1
|
500 zeroCount += 2;
|
rlm@1
|
501 while (zeroCount-- > 0 && i < kLevelTableSize)
|
rlm@1
|
502 levelLevels[i++]=0;
|
rlm@1
|
503 i--;
|
rlm@1
|
504 continue;
|
rlm@1
|
505 }
|
rlm@1
|
506 }
|
rlm@1
|
507 levelLevels[i] = (Byte)length;
|
rlm@1
|
508 }
|
rlm@1
|
509 RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
|
rlm@1
|
510 i = 0;
|
rlm@1
|
511 while (i < kTablesSizesSum)
|
rlm@1
|
512 {
|
rlm@1
|
513 UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
|
rlm@1
|
514 if (number < 16)
|
rlm@1
|
515 {
|
rlm@1
|
516 newLevels[i] = Byte((number + m_LastLevels[i]) & 15);
|
rlm@1
|
517 i++;
|
rlm@1
|
518 }
|
rlm@1
|
519 else if (number > kLevelTableSize)
|
rlm@1
|
520 return S_FALSE;
|
rlm@1
|
521 else
|
rlm@1
|
522 {
|
rlm@1
|
523 int num;
|
rlm@1
|
524 if (((number - 16) & 1) == 0)
|
rlm@1
|
525 num = ReadBits(3) + 3;
|
rlm@1
|
526 else
|
rlm@1
|
527 num = ReadBits(7) + 11;
|
rlm@1
|
528 if (number < 18)
|
rlm@1
|
529 {
|
rlm@1
|
530 if (i == 0)
|
rlm@1
|
531 return S_FALSE;
|
rlm@1
|
532 for (; num > 0 && i < kTablesSizesSum; num--, i++)
|
rlm@1
|
533 newLevels[i] = newLevels[i - 1];
|
rlm@1
|
534 }
|
rlm@1
|
535 else
|
rlm@1
|
536 {
|
rlm@1
|
537 for (; num > 0 && i < kTablesSizesSum; num--)
|
rlm@1
|
538 newLevels[i++] = 0;
|
rlm@1
|
539 }
|
rlm@1
|
540 }
|
rlm@1
|
541 }
|
rlm@1
|
542 TablesRead = true;
|
rlm@1
|
543
|
rlm@1
|
544 // original code has check here:
|
rlm@1
|
545 /*
|
rlm@1
|
546 if (InAddr > ReadTop)
|
rlm@1
|
547 {
|
rlm@1
|
548 keepDecompressing = false;
|
rlm@1
|
549 return true;
|
rlm@1
|
550 }
|
rlm@1
|
551 */
|
rlm@1
|
552
|
rlm@1
|
553 RIF(m_MainDecoder.SetCodeLengths(&newLevels[0]));
|
rlm@1
|
554 RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize]));
|
rlm@1
|
555 RIF(m_AlignDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize]));
|
rlm@1
|
556 RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize + kAlignTableSize]));
|
rlm@1
|
557
|
rlm@1
|
558 memcpy(m_LastLevels, newLevels, kTablesSizesSum);
|
rlm@1
|
559 return S_OK;
|
rlm@1
|
560 }
|
rlm@1
|
561
|
rlm@1
|
562 class CCoderReleaser
|
rlm@1
|
563 {
|
rlm@1
|
564 CDecoder *m_Coder;
|
rlm@1
|
565 public:
|
rlm@1
|
566 CCoderReleaser(CDecoder *coder): m_Coder(coder) {}
|
rlm@1
|
567 ~CCoderReleaser()
|
rlm@1
|
568 {
|
rlm@1
|
569 // m_Coder->m_OutWindowStream.Flush();
|
rlm@1
|
570 m_Coder->ReleaseStreams();
|
rlm@1
|
571 }
|
rlm@1
|
572 };
|
rlm@1
|
573
|
rlm@1
|
574 HRESULT CDecoder::ReadEndOfBlock(bool &keepDecompressing)
|
rlm@1
|
575 {
|
rlm@1
|
576 if (ReadBits(1) != 0)
|
rlm@1
|
577 {
|
rlm@1
|
578 // old file
|
rlm@1
|
579 TablesRead = false;
|
rlm@1
|
580 return ReadTables(keepDecompressing);
|
rlm@1
|
581 }
|
rlm@1
|
582 // new file
|
rlm@1
|
583 keepDecompressing = false;
|
rlm@1
|
584 TablesRead = (ReadBits(1) == 0);
|
rlm@1
|
585 return S_OK;
|
rlm@1
|
586 }
|
rlm@1
|
587
|
rlm@1
|
588 UInt32 kDistStart[kDistTableSize];
|
rlm@1
|
589
|
rlm@1
|
590 class CDistInit
|
rlm@1
|
591 {
|
rlm@1
|
592 public:
|
rlm@1
|
593 CDistInit() { Init(); }
|
rlm@1
|
594 void Init()
|
rlm@1
|
595 {
|
rlm@1
|
596 UInt32 start = 0;
|
rlm@1
|
597 for (UInt32 i = 0; i < kDistTableSize; i++)
|
rlm@1
|
598 {
|
rlm@1
|
599 kDistStart[i] = start;
|
rlm@1
|
600 start += (1 << kDistDirectBits[i]);
|
rlm@1
|
601 }
|
rlm@1
|
602 }
|
rlm@1
|
603 } g_DistInit;
|
rlm@1
|
604
|
rlm@1
|
605 HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
|
rlm@1
|
606 {
|
rlm@1
|
607 UInt32 rep0 = _reps[0];
|
rlm@1
|
608 UInt32 rep1 = _reps[1];
|
rlm@1
|
609 UInt32 rep2 = _reps[2];
|
rlm@1
|
610 UInt32 rep3 = _reps[3];
|
rlm@1
|
611 UInt32 length = _lastLength;
|
rlm@1
|
612 for (;;)
|
rlm@1
|
613 {
|
rlm@1
|
614 if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
|
rlm@1
|
615 {
|
rlm@1
|
616 RINOK(WriteBuf());
|
rlm@1
|
617 if (_writtenFileSize > _unpackSize)
|
rlm@1
|
618 {
|
rlm@1
|
619 keepDecompressing = false;
|
rlm@1
|
620 return S_OK;
|
rlm@1
|
621 }
|
rlm@1
|
622 }
|
rlm@1
|
623 UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
|
rlm@1
|
624 if (number < 256)
|
rlm@1
|
625 {
|
rlm@1
|
626 PutByte(Byte(number));
|
rlm@1
|
627
|
rlm@1
|
628 continue;
|
rlm@1
|
629 }
|
rlm@1
|
630 else if (number == kSymbolReadTable)
|
rlm@1
|
631 {
|
rlm@1
|
632 RINOK(ReadEndOfBlock(keepDecompressing));
|
rlm@1
|
633 break;
|
rlm@1
|
634 }
|
rlm@1
|
635 else if (number == 257)
|
rlm@1
|
636 {
|
rlm@1
|
637 if (!ReadVmCodeLZ())
|
rlm@1
|
638 return S_FALSE;
|
rlm@1
|
639 continue;
|
rlm@1
|
640 }
|
rlm@1
|
641 else if (number == 258)
|
rlm@1
|
642 {
|
rlm@1
|
643 }
|
rlm@1
|
644 else if (number < kSymbolRep + 4)
|
rlm@1
|
645 {
|
rlm@1
|
646 if (number != kSymbolRep)
|
rlm@1
|
647 {
|
rlm@1
|
648 UInt32 distance;
|
rlm@1
|
649 if (number == kSymbolRep + 1)
|
rlm@1
|
650 distance = rep1;
|
rlm@1
|
651 else
|
rlm@1
|
652 {
|
rlm@1
|
653 if (number == kSymbolRep + 2)
|
rlm@1
|
654 distance = rep2;
|
rlm@1
|
655 else
|
rlm@1
|
656 {
|
rlm@1
|
657 distance = rep3;
|
rlm@1
|
658 rep3 = rep2;
|
rlm@1
|
659 }
|
rlm@1
|
660 rep2 = rep1;
|
rlm@1
|
661 }
|
rlm@1
|
662 rep1 = rep0;
|
rlm@1
|
663 rep0 = distance;
|
rlm@1
|
664 }
|
rlm@1
|
665
|
rlm@1
|
666 UInt32 number = m_LenDecoder.DecodeSymbol(&m_InBitStream);
|
rlm@1
|
667 if (number >= kLenTableSize)
|
rlm@1
|
668 return S_FALSE;
|
rlm@1
|
669 length = 2 + kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]);
|
rlm@1
|
670 }
|
rlm@1
|
671 else
|
rlm@1
|
672 {
|
rlm@1
|
673 rep3 = rep2;
|
rlm@1
|
674 rep2 = rep1;
|
rlm@1
|
675 rep1 = rep0;
|
rlm@1
|
676 if (number < 271)
|
rlm@1
|
677 {
|
rlm@1
|
678 number -= 263;
|
rlm@1
|
679 rep0 = kLen2DistStarts[number] + m_InBitStream.ReadBits(kLen2DistDirectBits[number]);
|
rlm@1
|
680 length = 2;
|
rlm@1
|
681 }
|
rlm@1
|
682 else if (number < 299)
|
rlm@1
|
683 {
|
rlm@1
|
684 number -= 271;
|
rlm@1
|
685 length = kNormalMatchMinLen + (UInt32)kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]);
|
rlm@1
|
686 UInt32 number = m_DistDecoder.DecodeSymbol(&m_InBitStream);
|
rlm@1
|
687 if (number >= kDistTableSize)
|
rlm@1
|
688 return S_FALSE;
|
rlm@1
|
689 rep0 = kDistStart[number];
|
rlm@1
|
690 int numBits = kDistDirectBits[number];
|
rlm@1
|
691 if (number >= (kNumAlignBits * 2) + 2)
|
rlm@1
|
692 {
|
rlm@1
|
693 if (numBits > kNumAlignBits)
|
rlm@1
|
694 rep0 += (m_InBitStream.ReadBits(numBits - kNumAlignBits) << kNumAlignBits);
|
rlm@1
|
695 if (PrevAlignCount > 0)
|
rlm@1
|
696 {
|
rlm@1
|
697 PrevAlignCount--;
|
rlm@1
|
698 rep0 += PrevAlignBits;
|
rlm@1
|
699 }
|
rlm@1
|
700 else
|
rlm@1
|
701 {
|
rlm@1
|
702 UInt32 number = m_AlignDecoder.DecodeSymbol(&m_InBitStream);
|
rlm@1
|
703 if (number < (1 << kNumAlignBits))
|
rlm@1
|
704 {
|
rlm@1
|
705 rep0 += number;
|
rlm@1
|
706 PrevAlignBits = number;
|
rlm@1
|
707 }
|
rlm@1
|
708 else if (number == (1 << kNumAlignBits))
|
rlm@1
|
709 {
|
rlm@1
|
710 PrevAlignCount = kNumAlignReps;
|
rlm@1
|
711 rep0 += PrevAlignBits;
|
rlm@1
|
712 }
|
rlm@1
|
713 else
|
rlm@1
|
714 return S_FALSE;
|
rlm@1
|
715 }
|
rlm@1
|
716 }
|
rlm@1
|
717 else
|
rlm@1
|
718 rep0 += m_InBitStream.ReadBits(numBits);
|
rlm@1
|
719 length += ((kDistLimit4 - rep0) >> 31) + ((kDistLimit3 - rep0) >> 31);
|
rlm@1
|
720 }
|
rlm@1
|
721 else
|
rlm@1
|
722 return S_FALSE;
|
rlm@1
|
723 }
|
rlm@1
|
724 if (rep0 >= _lzSize)
|
rlm@1
|
725 return S_FALSE;
|
rlm@1
|
726 CopyBlock(rep0, length);
|
rlm@1
|
727 }
|
rlm@1
|
728 _reps[0] = rep0;
|
rlm@1
|
729 _reps[1] = rep1;
|
rlm@1
|
730 _reps[2] = rep2;
|
rlm@1
|
731 _reps[3] = rep3;
|
rlm@1
|
732 _lastLength = length;
|
rlm@1
|
733
|
rlm@1
|
734 return S_OK;
|
rlm@1
|
735 }
|
rlm@1
|
736
|
rlm@1
|
737 HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
|
rlm@1
|
738 {
|
rlm@1
|
739 _writtenFileSize = 0;
|
rlm@1
|
740 if (!m_IsSolid)
|
rlm@1
|
741 {
|
rlm@1
|
742 _lzSize = 0;
|
rlm@1
|
743 _winPos = 0;
|
rlm@1
|
744 _wrPtr = 0;
|
rlm@1
|
745 for (int i = 0; i < kNumReps; i++)
|
rlm@1
|
746 _reps[i] = 0;
|
rlm@1
|
747 _lastLength = 0;
|
rlm@1
|
748 memset(m_LastLevels, 0, kTablesSizesSum);
|
rlm@1
|
749 TablesRead = false;
|
rlm@1
|
750 PpmEscChar = 2;
|
rlm@1
|
751 InitFilters();
|
rlm@1
|
752 }
|
rlm@1
|
753 if (!m_IsSolid || !TablesRead)
|
rlm@1
|
754 {
|
rlm@1
|
755 bool keepDecompressing;
|
rlm@1
|
756 RINOK(ReadTables(keepDecompressing));
|
rlm@1
|
757 if (!keepDecompressing)
|
rlm@1
|
758 return S_OK;
|
rlm@1
|
759 }
|
rlm@1
|
760
|
rlm@1
|
761 for(;;)
|
rlm@1
|
762 {
|
rlm@1
|
763 bool keepDecompressing;
|
rlm@1
|
764 if (_lzMode)
|
rlm@1
|
765 {
|
rlm@1
|
766 RINOK(DecodeLZ(keepDecompressing))
|
rlm@1
|
767 }
|
rlm@1
|
768 else
|
rlm@1
|
769 {
|
rlm@1
|
770 RINOK(DecodePPM(1 << 18, keepDecompressing))
|
rlm@1
|
771 }
|
rlm@1
|
772 UInt64 packSize = m_InBitStream.GetProcessedSize();
|
rlm@1
|
773 RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize));
|
rlm@1
|
774 if (!keepDecompressing)
|
rlm@1
|
775 break;
|
rlm@1
|
776 }
|
rlm@1
|
777 RINOK(WriteBuf());
|
rlm@1
|
778 if (_writtenFileSize < _unpackSize)
|
rlm@1
|
779 return S_FALSE;
|
rlm@1
|
780 // return m_OutWindowStream.Flush();
|
rlm@1
|
781 return S_OK;
|
rlm@1
|
782 }
|
rlm@1
|
783
|
rlm@1
|
784 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
rlm@1
|
785 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
rlm@1
|
786 {
|
rlm@1
|
787 try
|
rlm@1
|
788 {
|
rlm@1
|
789 if (inSize == NULL || outSize == NULL)
|
rlm@1
|
790 return E_INVALIDARG;
|
rlm@1
|
791
|
rlm@1
|
792 if (_vmData == 0)
|
rlm@1
|
793 {
|
rlm@1
|
794 _vmData = (Byte *)::MidAlloc(kVmDataSizeMax + kVmCodeSizeMax);
|
rlm@1
|
795 if (_vmData == 0)
|
rlm@1
|
796 return E_OUTOFMEMORY;
|
rlm@1
|
797 _vmCode = _vmData + kVmDataSizeMax;
|
rlm@1
|
798 }
|
rlm@1
|
799
|
rlm@1
|
800 if (_window == 0)
|
rlm@1
|
801 {
|
rlm@1
|
802 _window = (Byte *)::MidAlloc(kWindowSize);
|
rlm@1
|
803 if (_window == 0)
|
rlm@1
|
804 return E_OUTOFMEMORY;
|
rlm@1
|
805 }
|
rlm@1
|
806 if (!m_InBitStream.Create(1 << 20))
|
rlm@1
|
807 return E_OUTOFMEMORY;
|
rlm@1
|
808 if (!_vm.Create())
|
rlm@1
|
809 return E_OUTOFMEMORY;
|
rlm@1
|
810
|
rlm@1
|
811
|
rlm@1
|
812 m_InBitStream.SetStream(inStream);
|
rlm@1
|
813 m_InBitStream.Init();
|
rlm@1
|
814 _outStream = outStream;
|
rlm@1
|
815
|
rlm@1
|
816 CCoderReleaser coderReleaser(this);
|
rlm@1
|
817 _unpackSize = *outSize;
|
rlm@1
|
818 return CodeReal(progress);
|
rlm@1
|
819 }
|
rlm@1
|
820 catch(const CInBufferException &e) { return e.ErrorCode; }
|
rlm@1
|
821 catch(...) { return S_FALSE; }
|
rlm@1
|
822 // CNewException is possible here. But probably CNewException is caused
|
rlm@1
|
823 // by error in data stream.
|
rlm@1
|
824 }
|
rlm@1
|
825
|
rlm@1
|
826 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
|
rlm@1
|
827 {
|
rlm@1
|
828 if (size < 1)
|
rlm@1
|
829 return E_INVALIDARG;
|
rlm@1
|
830 m_IsSolid = (data[0] != 0);
|
rlm@1
|
831 return S_OK;
|
rlm@1
|
832 }
|
rlm@1
|
833
|
rlm@1
|
834 }}
|