view 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
line wrap: on
line source
1 // Rar3Decoder.cpp
2 // According to unRAR license, this code may not be used to develop
3 // a program that creates RAR archives
5 #include "StdAfx.h"
7 #include "../Common/StreamUtils.h"
9 #include "Rar3Decoder.h"
11 namespace NCompress {
12 namespace NRar3 {
14 static const UInt32 kNumAlignReps = 15;
16 static const UInt32 kSymbolReadTable = 256;
17 static const UInt32 kSymbolRep = 259;
18 static const UInt32 kSymbolLen2 = kSymbolRep + kNumReps;
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};
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};
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};
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};
33 static const UInt32 kDistLimit3 = 0x2000 - 2;
34 static const UInt32 kDistLimit4 = 0x40000 - 2;
36 static const UInt32 kNormalMatchMinLen = 3;
38 static const UInt32 kVmDataSizeMax = 1 << 16;
39 static const UInt32 kVmCodeSizeMax = 1 << 16;
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 }
53 CDecoder::~CDecoder()
54 {
55 InitFilters();
56 ::MidFree(_vmData);
57 ::MidFree(_window);
58 }
60 HRESULT CDecoder::WriteDataToStream(const Byte *data, UInt32 size)
61 {
62 return WriteStream(_outStream, data, size);
63 }
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 }
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 }
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 }
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 }
165 _wrPtr = _winPos;
166 return WriteArea(writtenBorder, _winPos);
167 }
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 }
181 bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize)
182 {
183 CMemBitDecoder inp;
184 inp.Init(_vmData, codeSize);
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());
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 }
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;
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;
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 }
267 tempFilter->AllocateEmptyFixedGlobal();
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);
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 }
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 }
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 }
345 #define RIF(x) { if (!(x)) return S_FALSE; }
347 UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
349 /////////////////////////////////////////////////
350 // PPM
352 HRESULT CDecoder::InitPPM()
353 {
354 Byte maxOrder = (Byte)ReadBits(7);
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);
386 if (!_ppm.SubAllocator.StartSubAllocator((maxMB + 1) << 20))
387 return E_OUTOFMEMORY;
388 _ppm.MaxOrder = 0;
389 _ppm.StartModelRare(maxOrder);
391 }
392 // return (minContext != NULL);
394 return S_OK;
395 }
397 int CDecoder::DecodePpmSymbol() { return _ppm.DecodeSymbol(&m_InBitStream); }
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 }
468 /////////////////////////////////////////////////
469 // LZ
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 }
481 _lzMode = true;
482 PrevAlignBits = 0;
483 PrevAlignCount = 0;
485 Byte levelLevels[kLevelTableSize];
486 Byte newLevels[kTablesSizesSum];
488 if (ReadBits(1) == 0)
489 memset(m_LastLevels, 0, kTablesSizesSum);
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;
544 // original code has check here:
545 /*
546 if (InAddr > ReadTop)
547 {
548 keepDecompressing = false;
549 return true;
550 }
551 */
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]));
558 memcpy(m_LastLevels, newLevels, kTablesSizesSum);
559 return S_OK;
560 }
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 };
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 }
588 UInt32 kDistStart[kDistTableSize];
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;
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));
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 }
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;
734 return S_OK;
735 }
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 }
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 }
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;
792 if (_vmData == 0)
793 {
794 _vmData = (Byte *)::MidAlloc(kVmDataSizeMax + kVmCodeSizeMax);
795 if (_vmData == 0)
796 return E_OUTOFMEMORY;
797 _vmCode = _vmData + kVmDataSizeMax;
798 }
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;
812 m_InBitStream.SetStream(inStream);
813 m_InBitStream.Init();
814 _outStream = outStream;
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 }
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 }
834 }}