1 // Rar5Decoder.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 <stdio.h>
8
9 #include "../Common/StreamUtils.h"
10
11 #include "Rar5Decoder.h"
12
13 namespace NCompress {
14 namespace NRar5 {
15
16 static const size_t kInputBufSize = 1 << 20;
17
Prepare2()18 void CBitDecoder::Prepare2() throw()
19 {
20 const unsigned kSize = 16;
21 if (_buf > _bufLim)
22 return;
23
24 size_t rem = _bufLim - _buf;
25 if (rem != 0)
26 memmove(_bufBase, _buf, rem);
27
28 _bufLim = _bufBase + rem;
29 _processedSize += (_buf - _bufBase);
30 _buf = _bufBase;
31
32 if (!_wasFinished)
33 {
34 UInt32 processed = (UInt32)(kInputBufSize - rem);
35 _hres = _stream->Read(_bufLim, (UInt32)processed, &processed);
36 _bufLim += processed;
37 _wasFinished = (processed == 0);
38 if (_hres != S_OK)
39 {
40 _wasFinished = true;
41 // throw CInBufferException(result);
42 }
43 }
44
45 rem = _bufLim - _buf;
46 _bufCheck = _buf;
47 if (rem < kSize)
48 memset(_bufLim, 0xFF, kSize - rem);
49 else
50 _bufCheck = _bufLim - kSize;
51
52 SetCheck2();
53 }
54
55
56 enum FilterType
57 {
58 FILTER_DELTA = 0,
59 FILTER_E8,
60 FILTER_E8E9,
61 FILTER_ARM
62 };
63
64 static const size_t kWriteStep = (size_t)1 << 22;
65
CDecoder()66 CDecoder::CDecoder():
67 _isSolid(false),
68 _solidAllowed(false),
69 _wasInit(false),
70 _dictSizeLog(0),
71 _window(NULL),
72 _winPos(0),
73 _lzSize(0),
74 _lzEnd(0),
75 _writtenFileSize(0),
76 _winSizeAllocated(0),
77 _inputBuf(NULL)
78 {
79 }
80
~CDecoder()81 CDecoder::~CDecoder()
82 {
83 ::MidFree(_window);
84 ::MidFree(_inputBuf);
85 }
86
WriteData(const Byte * data,size_t size)87 HRESULT CDecoder::WriteData(const Byte *data, size_t size)
88 {
89 HRESULT res = S_OK;
90 if (!_unpackSize_Defined || _writtenFileSize < _unpackSize)
91 {
92 size_t cur = size;
93 if (_unpackSize_Defined)
94 {
95 UInt64 rem = _unpackSize - _writtenFileSize;
96 if (cur > rem)
97 cur = (size_t)rem;
98 }
99 res = WriteStream(_outStream, data, cur);
100 if (res != S_OK)
101 _writeError = true;
102 }
103 _writtenFileSize += size;
104 return res;
105 }
106
ExecuteFilter(const CFilter & f)107 HRESULT CDecoder::ExecuteFilter(const CFilter &f)
108 {
109 bool useDest = false;
110
111 Byte *data = _filterSrc;
112 UInt32 dataSize = f.Size;
113
114 // printf("\nType = %d offset = %9d size = %5d", f.Type, (unsigned)(f.Start - _lzFileStart), dataSize);
115
116 switch (f.Type)
117 {
118 case FILTER_E8:
119 case FILTER_E8E9:
120 {
121 // printf(" FILTER_E8");
122 if (dataSize > 4)
123 {
124 dataSize -= 4;
125 UInt32 fileOffset = (UInt32)(f.Start - _lzFileStart);
126
127 const UInt32 kFileSize = (UInt32)1 << 24;
128 Byte cmpMask = (Byte)(f.Type == FILTER_E8 ? 0xFF : 0xFE);
129
130 for (UInt32 curPos = 0; curPos < dataSize;)
131 {
132 curPos++;
133 if (((*data++) & cmpMask) == 0xE8)
134 {
135 UInt32 offset = (curPos + fileOffset) & (kFileSize - 1);
136 UInt32 addr = GetUi32(data);
137
138 if (addr < kFileSize)
139 {
140 SetUi32(data, addr - offset);
141 }
142 else if (addr > ((UInt32)0xFFFFFFFF - offset)) // (addr > ~(offset))
143 {
144 SetUi32(data, addr + kFileSize);
145 }
146
147 data += 4;
148 curPos += 4;
149 }
150 }
151 }
152 break;
153 }
154
155 case FILTER_ARM:
156 {
157 if (dataSize >= 4)
158 {
159 dataSize -= 4;
160 UInt32 fileOffset = (UInt32)(f.Start - _lzFileStart);
161
162 for (UInt32 curPos = 0; curPos <= dataSize; curPos += 4)
163 {
164 Byte *d = data + curPos;
165 if (d[3] == 0xEB)
166 {
167 UInt32 offset = d[0] | ((UInt32)d[1] << 8) | ((UInt32)d[2] << 16);
168 offset -= (fileOffset + curPos) >> 2;
169 d[0] = (Byte)offset;
170 d[1] = (Byte)(offset >> 8);
171 d[2] = (Byte)(offset >> 16);
172 }
173 }
174 }
175 break;
176 }
177
178 case FILTER_DELTA:
179 {
180 // printf(" channels = %d", f.Channels);
181 _filterDst.AllocAtLeast(dataSize);
182 if (!_filterDst.IsAllocated())
183 return E_OUTOFMEMORY;
184
185 Byte *dest = _filterDst;
186 UInt32 numChannels = f.Channels;
187
188 for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
189 {
190 Byte prevByte = 0;
191 for (UInt32 destPos = curChannel; destPos < dataSize; destPos += numChannels)
192 dest[destPos] = (prevByte = (Byte)(prevByte - *data++));
193 }
194 useDest = true;
195 break;
196 }
197
198 default:
199 _unsupportedFilter = true;
200 memset(_filterSrc, 0, f.Size);
201 // return S_OK; // unrar
202 }
203
204 return WriteData(useDest ?
205 (const Byte *)_filterDst :
206 (const Byte *)_filterSrc,
207 f.Size);
208 }
209
210
WriteBuf()211 HRESULT CDecoder::WriteBuf()
212 {
213 DeleteUnusedFilters();
214
215 for (unsigned i = 0; i < _filters.Size();)
216 {
217 const CFilter &f = _filters[i];
218
219 UInt64 blockStart = f.Start;
220
221 size_t lzAvail = (size_t)(_lzSize - _lzWritten);
222 if (lzAvail == 0)
223 break;
224
225 if (blockStart > _lzWritten)
226 {
227 UInt64 rem = blockStart - _lzWritten;
228 size_t size = lzAvail;
229 if (size > rem)
230 size = (size_t)rem;
231 if (size != 0)
232 {
233 RINOK(WriteData(_window + _winPos - lzAvail, size));
234 _lzWritten += size;
235 }
236 continue;
237 }
238
239 UInt32 blockSize = f.Size;
240 size_t offset = (size_t)(_lzWritten - blockStart);
241 if (offset == 0)
242 {
243 _filterSrc.AllocAtLeast(blockSize);
244 if (!_filterSrc.IsAllocated())
245 return E_OUTOFMEMORY;
246 }
247
248 size_t blockRem = (size_t)blockSize - offset;
249 size_t size = lzAvail;
250 if (size > blockRem)
251 size = blockRem;
252 memcpy(_filterSrc + offset, _window + _winPos - lzAvail, size);
253 _lzWritten += size;
254 offset += size;
255 if (offset != blockSize)
256 return S_OK;
257
258 _numUnusedFilters = ++i;
259 RINOK(ExecuteFilter(f));
260 }
261
262 DeleteUnusedFilters();
263
264 if (!_filters.IsEmpty())
265 return S_OK;
266
267 size_t lzAvail = (size_t)(_lzSize - _lzWritten);
268 RINOK(WriteData(_window + _winPos - lzAvail, lzAvail));
269 _lzWritten += lzAvail;
270 return S_OK;
271 }
272
273
ReadUInt32(CBitDecoder & bi)274 static UInt32 ReadUInt32(CBitDecoder &bi)
275 {
276 unsigned numBytes = bi.ReadBits9fix(2) + 1;
277 UInt32 v = 0;
278 for (unsigned i = 0; i < numBytes; i++)
279 v += ((UInt32)bi.ReadBits9fix(8) << (i * 8));
280 return v;
281 }
282
283
284 static const unsigned MAX_UNPACK_FILTERS = 8192;
285
AddFilter(CBitDecoder & _bitStream)286 HRESULT CDecoder::AddFilter(CBitDecoder &_bitStream)
287 {
288 DeleteUnusedFilters();
289
290 if (_filters.Size() >= MAX_UNPACK_FILTERS)
291 {
292 RINOK(WriteBuf());
293 DeleteUnusedFilters();
294 if (_filters.Size() >= MAX_UNPACK_FILTERS)
295 {
296 _unsupportedFilter = true;
297 InitFilters();
298 }
299 }
300
301 _bitStream.Prepare();
302
303 CFilter f;
304 UInt32 blockStart = ReadUInt32(_bitStream);
305 f.Size = ReadUInt32(_bitStream);
306
307 if (f.Size > ((UInt32)1 << 22))
308 {
309 _unsupportedFilter = true;
310 f.Size = 0; // unrar 5.5.5
311 }
312
313 f.Type = (Byte)_bitStream.ReadBits9fix(3);
314 f.Channels = 0;
315 if (f.Type == FILTER_DELTA)
316 f.Channels = (Byte)(_bitStream.ReadBits9fix(5) + 1);
317 f.Start = _lzSize + blockStart;
318
319 if (f.Start < _filterEnd)
320 _unsupportedFilter = true;
321 else
322 {
323 _filterEnd = f.Start + f.Size;
324 if (f.Size != 0)
325 _filters.Add(f);
326 }
327
328 return S_OK;
329 }
330
331
332 #define RIF(x) { if (!(x)) return S_FALSE; }
333
ReadTables(CBitDecoder & _bitStream)334 HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream)
335 {
336 if (_progress)
337 {
338 const UInt64 packSize = _bitStream.GetProcessedSize();
339 RINOK(_progress->SetRatioInfo(&packSize, &_writtenFileSize));
340 }
341
342 _bitStream.AlignToByte();
343 _bitStream.Prepare();
344
345 {
346 unsigned flags = _bitStream.ReadByteInAligned();
347 unsigned checkSum = _bitStream.ReadByteInAligned();
348 checkSum ^= flags;
349 unsigned num = (flags >> 3) & 3;
350 if (num == 3)
351 return S_FALSE;
352 UInt32 blockSize = _bitStream.ReadByteInAligned();
353 checkSum ^= blockSize;
354
355 if (num != 0)
356 {
357 unsigned b = _bitStream.ReadByteInAligned();
358 checkSum ^= b;
359 blockSize += (UInt32)b << 8;
360 if (num > 1)
361 {
362 b = _bitStream.ReadByteInAligned();
363 checkSum ^= b;
364 blockSize += (UInt32)b << 16;
365 }
366 }
367
368 if (checkSum != 0x5A)
369 return S_FALSE;
370
371 unsigned blockSizeBits7 = (flags & 7) + 1;
372 blockSize += (blockSizeBits7 >> 3);
373 if (blockSize == 0)
374 return S_FALSE;
375 blockSize--;
376 blockSizeBits7 &= 7;
377
378 _bitStream._blockEndBits7 = (Byte)blockSizeBits7;
379 _bitStream._blockEnd = _bitStream.GetProcessedSize_Round() + blockSize;
380
381 _bitStream.SetCheck2();
382
383 _isLastBlock = ((flags & 0x40) != 0);
384
385 if ((flags & 0x80) == 0)
386 {
387 if (!_tableWasFilled)
388 if (blockSize != 0 || blockSizeBits7 != 0)
389 return S_FALSE;
390 return S_OK;
391 }
392
393 _tableWasFilled = false;
394 }
395
396 {
397 Byte lens2[kLevelTableSize];
398
399 for (unsigned i = 0; i < kLevelTableSize;)
400 {
401 _bitStream.Prepare();
402 unsigned len = (unsigned)_bitStream.ReadBits9fix(4);
403 if (len == 15)
404 {
405 unsigned num = (unsigned)_bitStream.ReadBits9fix(4);
406 if (num != 0)
407 {
408 num += 2;
409 num += i;
410 if (num > kLevelTableSize)
411 num = kLevelTableSize;
412 do
413 lens2[i++] = 0;
414 while (i < num);
415 continue;
416 }
417 }
418 lens2[i++] = (Byte)len;
419 }
420
421 if (_bitStream.IsBlockOverRead())
422 return S_FALSE;
423
424 RIF(m_LevelDecoder.Build(lens2));
425 }
426
427 Byte lens[kTablesSizesSum];
428 unsigned i = 0;
429
430 do
431 {
432 if (_bitStream._buf >= _bitStream._bufCheck2)
433 {
434 if (_bitStream._buf >= _bitStream._bufCheck)
435 _bitStream.Prepare();
436 if (_bitStream.IsBlockOverRead())
437 return S_FALSE;
438 }
439
440 UInt32 sym = m_LevelDecoder.Decode(&_bitStream);
441
442 if (sym < 16)
443 lens[i++] = (Byte)sym;
444 else if (sym > kLevelTableSize)
445 return S_FALSE;
446 else
447 {
448 unsigned num = ((sym - 16) & 1) * 4;
449 num += num + 3 + (unsigned)_bitStream.ReadBits9(num + 3);
450 num += i;
451 if (num > kTablesSizesSum)
452 num = kTablesSizesSum;
453 Byte v = 0;
454 if (sym < 16 + 2)
455 {
456 if (i == 0)
457 return S_FALSE;
458 v = lens[(size_t)i - 1];
459 }
460 do
461 lens[i++] = v;
462 while (i < num);
463 }
464 }
465 while (i < kTablesSizesSum);
466
467 if (_bitStream.IsBlockOverRead())
468 return S_FALSE;
469 if (_bitStream.InputEofError())
470 return S_FALSE;
471
472 RIF(m_MainDecoder.Build(&lens[0]));
473 RIF(m_DistDecoder.Build(&lens[kMainTableSize]));
474 RIF(m_AlignDecoder.Build(&lens[kMainTableSize + kDistTableSize]));
475 RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize + kAlignTableSize]));
476
477 _useAlignBits = false;
478 // _useAlignBits = true;
479 for (i = 0; i < kAlignTableSize; i++)
480 if (lens[kMainTableSize + kDistTableSize + (size_t)i] != kNumAlignBits)
481 {
482 _useAlignBits = true;
483 break;
484 }
485
486 _tableWasFilled = true;
487 return S_OK;
488 }
489
490
SlotToLen(CBitDecoder & _bitStream,unsigned slot)491 static inline unsigned SlotToLen(CBitDecoder &_bitStream, unsigned slot)
492 {
493 if (slot < 8)
494 return slot + 2;
495 unsigned numBits = (slot >> 2) - 1;
496 return 2 + ((4 | (slot & 3)) << numBits) + _bitStream.ReadBits9(numBits);
497 }
498
499
500 static const UInt32 kSymbolRep = 258;
501 // static const unsigned kMaxMatchLen = 0x1001 + 3;
502
DecodeLZ()503 HRESULT CDecoder::DecodeLZ()
504 {
505 CBitDecoder _bitStream;
506 _bitStream._stream = _inStream;
507 _bitStream._bufBase = _inputBuf;
508 _bitStream.Init();
509
510 UInt32 rep0 = _reps[0];
511
512 UInt32 remLen = 0;
513
514 size_t limit;
515 {
516 size_t rem = _winSize - _winPos;
517 if (rem > kWriteStep)
518 rem = kWriteStep;
519 limit = _winPos + rem;
520 }
521
522 for (;;)
523 {
524 if (_winPos >= limit)
525 {
526 RINOK(WriteBuf());
527 if (_unpackSize_Defined && _writtenFileSize > _unpackSize)
528 break; // return S_FALSE;
529
530 {
531 size_t rem = _winSize - _winPos;
532
533 if (rem == 0)
534 {
535 _winPos = 0;
536 rem = _winSize;
537 }
538 if (rem > kWriteStep)
539 rem = kWriteStep;
540 limit = _winPos + rem;
541 }
542
543 if (remLen != 0)
544 {
545 size_t winPos = _winPos;
546 size_t winMask = _winMask;
547 size_t pos = (winPos - (size_t)rep0 - 1) & winMask;
548
549 Byte *win = _window;
550 do
551 {
552 if (winPos >= limit)
553 break;
554 win[winPos] = win[pos];
555 winPos++;
556 pos = (pos + 1) & winMask;
557 }
558 while (--remLen != 0);
559
560 _lzSize += winPos - _winPos;
561 _winPos = winPos;
562 continue;
563 }
564 }
565
566 if (_bitStream._buf >= _bitStream._bufCheck2)
567 {
568 if (_bitStream.InputEofError())
569 break; // return S_FALSE;
570 if (_bitStream._buf >= _bitStream._bufCheck)
571 _bitStream.Prepare2();
572
573 UInt64 processed = _bitStream.GetProcessedSize_Round();
574 if (processed >= _bitStream._blockEnd)
575 {
576 if (processed > _bitStream._blockEnd)
577 break; // return S_FALSE;
578 {
579 unsigned bits7 = _bitStream.GetProcessedBits7();
580 if (bits7 > _bitStream._blockEndBits7)
581 break; // return S_FALSE;
582 if (bits7 == _bitStream._blockEndBits7)
583 {
584 if (_isLastBlock)
585 {
586 _reps[0] = rep0;
587
588 if (_bitStream.InputEofError())
589 break;
590
591 /*
592 // packSize can be 15 bytes larger for encrypted archive
593 if (_packSize_Defined && _packSize < _bitStream.GetProcessedSize())
594 break;
595 */
596
597 return _bitStream._hres;
598 // break;
599 }
600 RINOK(ReadTables(_bitStream));
601 continue;
602 }
603 }
604 }
605
606 // that check is not required, but it can help, if there is BUG in another code
607 if (!_tableWasFilled)
608 break; // return S_FALSE;
609 }
610
611 UInt32 sym = m_MainDecoder.Decode(&_bitStream);
612
613 if (sym < 256)
614 {
615 size_t winPos = _winPos;
616 _window[winPos] = (Byte)sym;
617 _winPos = winPos + 1;
618 _lzSize++;
619 continue;
620 }
621
622 UInt32 len;
623
624 if (sym < kSymbolRep + kNumReps)
625 {
626 if (sym >= kSymbolRep)
627 {
628 if (sym != kSymbolRep)
629 {
630 UInt32 dist;
631 if (sym == kSymbolRep + 1)
632 dist = _reps[1];
633 else
634 {
635 if (sym == kSymbolRep + 2)
636 dist = _reps[2];
637 else
638 {
639 dist = _reps[3];
640 _reps[3] = _reps[2];
641 }
642 _reps[2] = _reps[1];
643 }
644 _reps[1] = rep0;
645 rep0 = dist;
646 }
647
648 const UInt32 sym2 = m_LenDecoder.Decode(&_bitStream);
649 if (sym2 >= kLenTableSize)
650 break; // return S_FALSE;
651 len = SlotToLen(_bitStream, sym2);
652 }
653 else
654 {
655 if (sym == 256)
656 {
657 RINOK(AddFilter(_bitStream));
658 continue;
659 }
660 else // if (sym == 257)
661 {
662 len = _lastLen;
663 // if (len = 0), we ignore that symbol, like original unRAR code, but it can mean error in stream.
664 // if (len == 0) return S_FALSE;
665 if (len == 0)
666 continue;
667 }
668 }
669 }
670 else if (sym >= kMainTableSize)
671 break; // return S_FALSE;
672 else
673 {
674 _reps[3] = _reps[2];
675 _reps[2] = _reps[1];
676 _reps[1] = rep0;
677 len = SlotToLen(_bitStream, sym - (kSymbolRep + kNumReps));
678
679 rep0 = m_DistDecoder.Decode(&_bitStream);
680
681 if (rep0 >= 4)
682 {
683 if (rep0 >= _numCorrectDistSymbols)
684 break; // return S_FALSE;
685 unsigned numBits = (rep0 >> 1) - 1;
686 rep0 = (2 | (rep0 & 1)) << numBits;
687
688 if (numBits < kNumAlignBits)
689 rep0 += _bitStream.ReadBits9(numBits);
690 else
691 {
692 len += (numBits >= 7);
693 len += (numBits >= 12);
694 len += (numBits >= 17);
695
696 if (_useAlignBits)
697 {
698 // if (numBits > kNumAlignBits)
699 rep0 += (_bitStream.ReadBits32(numBits - kNumAlignBits) << kNumAlignBits);
700 UInt32 a = m_AlignDecoder.Decode(&_bitStream);
701 if (a >= kAlignTableSize)
702 break; // return S_FALSE;
703 rep0 += a;
704 }
705 else
706 rep0 += _bitStream.ReadBits32(numBits);
707 }
708 }
709 }
710
711 _lastLen = len;
712
713 if (rep0 >= _lzSize)
714 _lzError = true;
715
716 {
717 UInt32 lenCur = len;
718 size_t winPos = _winPos;
719 size_t pos = (winPos - (size_t)rep0 - 1) & _winMask;
720 {
721 size_t rem = limit - winPos;
722 // size_t rem = _winSize - winPos;
723
724 if (lenCur > rem)
725 {
726 lenCur = (UInt32)rem;
727 remLen = len - lenCur;
728 }
729 }
730
731 Byte *win = _window;
732 _lzSize += lenCur;
733 _winPos = winPos + lenCur;
734 if (_winSize - pos >= lenCur)
735 {
736 const Byte *src = win + pos;
737 Byte *dest = win + winPos;
738 do
739 *dest++ = *src++;
740 while (--lenCur != 0);
741 }
742 else
743 {
744 do
745 {
746 win[winPos] = win[pos];
747 winPos++;
748 pos = (pos + 1) & _winMask;
749 }
750 while (--lenCur != 0);
751 }
752 }
753 }
754
755 if (_bitStream._hres != S_OK)
756 return _bitStream._hres;
757
758 return S_FALSE;
759 }
760
761
CodeReal()762 HRESULT CDecoder::CodeReal()
763 {
764 _unsupportedFilter = false;
765 _lzError = false;
766 _writeError = false;
767
768 if (!_isSolid || !_wasInit)
769 {
770 size_t clearSize = _winSize;
771 if (_lzSize < _winSize)
772 clearSize = (size_t)_lzSize;
773 memset(_window, 0, clearSize);
774
775 _wasInit = true;
776 _lzSize = 0;
777 _lzWritten = 0;
778 _winPos = 0;
779
780 for (unsigned i = 0; i < kNumReps; i++)
781 _reps[i] = (UInt32)0 - 1;
782
783 _lastLen = 0;
784 _tableWasFilled = false;
785 }
786
787 _isLastBlock = false;
788
789 InitFilters();
790
791 _filterEnd = 0;
792 _writtenFileSize = 0;
793
794 _lzFileStart = _lzSize;
795 _lzWritten = _lzSize;
796
797 HRESULT res = DecodeLZ();
798
799 HRESULT res2 = S_OK;
800 if (!_writeError && res != E_OUTOFMEMORY)
801 res2 = WriteBuf();
802
803 /*
804 if (res == S_OK)
805 if (InputEofError())
806 res = S_FALSE;
807 */
808
809 if (res == S_OK)
810 {
811 _solidAllowed = true;
812 res = res2;
813 }
814
815 if (res == S_OK && _unpackSize_Defined && _writtenFileSize != _unpackSize)
816 return S_FALSE;
817 return res;
818 }
819
820
821 // Original unRAR claims that maximum possible filter block size is (1 << 16) now,
822 // and (1 << 17) is minimum win size required to support filter.
823 // Original unRAR uses (1 << 18) for "extra safety and possible filter area size expansion"
824 // We can use any win size.
825
826 static const unsigned kWinSize_Log_Min = 17;
827
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 * outSize,ICompressProgressInfo * progress)828 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
829 const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
830 {
831 try
832 {
833 if (_isSolid && !_solidAllowed)
834 return S_FALSE;
835 _solidAllowed = false;
836
837 if (_dictSizeLog >= sizeof(size_t) * 8)
838 return E_NOTIMPL;
839
840 if (!_isSolid)
841 _lzEnd = 0;
842 else
843 {
844 if (_lzSize < _lzEnd)
845 {
846 if (_window)
847 {
848 UInt64 rem = _lzEnd - _lzSize;
849 if (rem >= _winSize)
850 memset(_window, 0, _winSize);
851 else
852 {
853 size_t pos = (size_t)_lzSize & _winSize;
854 size_t rem2 = _winSize - pos;
855 if (rem2 > rem)
856 rem2 = (size_t)rem;
857 memset(_window + pos, 0, rem2);
858 rem -= rem2;
859 memset(_window, 0, (size_t)rem);
860 }
861 }
862 _lzEnd &= ((((UInt64)1) << 33) - 1);
863 _lzSize = _lzEnd;
864 _winPos = (size_t)(_lzSize & _winSize);
865 }
866 _lzEnd = _lzSize;
867 }
868
869 size_t newSize;
870 {
871 unsigned newSizeLog = _dictSizeLog;
872 if (newSizeLog < kWinSize_Log_Min)
873 newSizeLog = kWinSize_Log_Min;
874 newSize = (size_t)1 << newSizeLog;
875 _numCorrectDistSymbols = newSizeLog * 2;
876 }
877
878 // If dictionary was reduced, we use allocated dictionary block
879 // for compatibility with original unRAR decoder.
880
881 if (_window && newSize < _winSizeAllocated)
882 _winSize = _winSizeAllocated;
883 else if (!_window || _winSize != newSize)
884 {
885 if (!_isSolid)
886 {
887 ::MidFree(_window);
888 _window = NULL;
889 _winSizeAllocated = 0;
890 }
891
892 Byte *win;
893
894 {
895 win = (Byte *)::MidAlloc(newSize);
896 if (!win)
897 return E_OUTOFMEMORY;
898 memset(win, 0, newSize);
899 }
900
901 if (_isSolid && _window)
902 {
903 // original unRAR claims:
904 // "Archiving code guarantees that win size does not grow in the same solid stream",
905 // but the original unRAR decoder still supports such grow case.
906
907 Byte *winOld = _window;
908 size_t oldSize = _winSize;
909 size_t newMask = newSize - 1;
910 size_t oldMask = _winSize - 1;
911 size_t winPos = _winPos;
912 for (size_t i = 1; i <= oldSize; i++)
913 win[(winPos - i) & newMask] = winOld[(winPos - i) & oldMask];
914 ::MidFree(_window);
915 }
916
917 _window = win;
918 _winSizeAllocated = newSize;
919 _winSize = newSize;
920 }
921
922 _winMask = _winSize - 1;
923 _winPos &= _winMask;
924
925 if (!_inputBuf)
926 {
927 _inputBuf = (Byte *)::MidAlloc(kInputBufSize);
928 if (!_inputBuf)
929 return E_OUTOFMEMORY;
930 }
931
932 _inStream = inStream;
933 _outStream = outStream;
934
935 /*
936 _packSize = 0;
937 _packSize_Defined = (inSize != NULL);
938 if (_packSize_Defined)
939 _packSize = *inSize;
940 */
941
942 _unpackSize = 0;
943 _unpackSize_Defined = (outSize != NULL);
944 if (_unpackSize_Defined)
945 _unpackSize = *outSize;
946
947 if ((Int64)_unpackSize >= 0)
948 _lzEnd += _unpackSize;
949 else
950 _lzEnd = 0;
951
952 _progress = progress;
953
954 HRESULT res = CodeReal();
955
956 if (res != S_OK)
957 return res;
958 if (_lzError)
959 return S_FALSE;
960 if (_unsupportedFilter)
961 return E_NOTIMPL;
962 return S_OK;
963 }
964 // catch(const CInBufferException &e) { return e.ErrorCode; }
965 // catch(...) { return S_FALSE; }
966 catch(...) { return E_OUTOFMEMORY; }
967 // CNewException is possible here. But probably CNewException is caused
968 // by error in data stream.
969 }
970
SetDecoderProperties2(const Byte * data,UInt32 size)971 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
972 {
973 if (size != 2)
974 return E_NOTIMPL;
975 _dictSizeLog = (Byte)((data[0] & 0xF) + 17);
976 _isSolid = ((data[1] & 1) != 0);
977 return S_OK;
978 }
979
980 }}
981