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