// Rar1Decoder.cpp // According to unRAR license, this code may not be used to develop // a program that creates RAR archives #include "StdAfx.h" #include "Rar1Decoder.h" namespace NCompress { namespace NRar1 { static const unsigned kNumBits = 12; static const Byte kShortLen1[16 * 3] = { 0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0,0, 1,3,4,4,5,6,7,8,8,4,4,5,6,6,0,0, 1,4,4,4,5,6,7,8,8,4,4,5,6,6,4,0 }; static const Byte kShortLen2[16 * 3] = { 0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0,0, 2,3,3,3,4,4,5,6,6,4,4,5,6,6,0,0, 2,3,3,4,4,4,5,6,6,4,4,5,6,6,4,0 }; static const Byte PosL1[kNumBits + 1] = { 0,0,2,1,2,2,4,5,4,4,8,0,224 }; static const Byte PosL2[kNumBits + 1] = { 0,0,0,5,2,2,4,5,4,4,8,2,220 }; static const Byte PosHf0[kNumBits + 1] = { 0,0,0,0,8,8,8,9,0,0,0,0,224 }; static const Byte PosHf1[kNumBits + 1] = { 0,0,0,0,0,4,40,16,16,4,0,47,130 }; static const Byte PosHf2[kNumBits + 1] = { 0,0,0,0,0,2,5,46,64,116,24,0,0 }; static const Byte PosHf3[kNumBits + 1] = { 0,0,0,0,0,0,2,14,202,33,6,0,0 }; static const Byte PosHf4[kNumBits + 1] = { 0,0,0,0,0,0,0,0,255,2,0,0,0 }; static const UInt32 kHistorySize = (1 << 16); CDecoder::CDecoder(): _isSolid(false), _solidAllowed(false) {} UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); } HRESULT CDecoder::CopyBlock(UInt32 distance, UInt32 len) { if (len == 0) return S_FALSE; if (m_UnpackSize < len) return S_FALSE; m_UnpackSize -= len; return m_OutWindowStream.CopyBlock(distance, len) ? S_OK : S_FALSE; } UInt32 CDecoder::DecodeNum(const Byte *numTab) { /* { // we can check that tables are correct UInt32 sum = 0; for (unsigned i = 0; i <= kNumBits; i++) sum += ((UInt32)numTab[i] << (kNumBits - i)); if (sum != (1 << kNumBits)) throw 111; } */ UInt32 val = m_InBitStream.GetValue(kNumBits); UInt32 sum = 0; unsigned i = 2; for (;;) { const UInt32 num = numTab[i]; const UInt32 cur = num << (kNumBits - i); if (val < cur) break; i++; val -= cur; sum += num; } m_InBitStream.MovePos(i); return ((val >> (kNumBits - i)) + sum); } HRESULT CDecoder::ShortLZ() { NumHuf = 0; if (LCount == 2) { if (ReadBits(1)) return CopyBlock(LastDist, LastLength); LCount = 0; } UInt32 bitField = m_InBitStream.GetValue(8); UInt32 len, dist; { const Byte *xors = (AvrLn1 < 37) ? kShortLen1 : kShortLen2; const Byte *lens = xors + 16 + Buf60; for (len = 0; ((bitField ^ xors[len]) >> (8 - lens[len])) != 0; len++); m_InBitStream.MovePos(lens[len]); } if (len >= 9) { if (len == 9) { LCount++; return CopyBlock(LastDist, LastLength); } LCount = 0; if (len == 14) { len = DecodeNum(PosL2) + 5; dist = 0x8000 + ReadBits(15) - 1; LastLength = len; LastDist = dist; return CopyBlock(dist, len); } const UInt32 saveLen = len; dist = m_RepDists[(m_RepDistPtr - (len - 9)) & 3]; len = DecodeNum(PosL1); if (len == 0xff && saveLen == 10) { Buf60 ^= 16; return S_OK; } if (dist >= 256) { len++; if (dist >= MaxDist3 - 1) len++; } } else { LCount = 0; AvrLn1 += len; AvrLn1 -= AvrLn1 >> 4; unsigned distancePlace = DecodeNum(PosHf2) & 0xff; dist = ChSetA[distancePlace]; if (distancePlace != 0) { PlaceA[dist]--; UInt32 lastDistance = ChSetA[(size_t)distancePlace - 1]; PlaceA[lastDistance]++; ChSetA[distancePlace] = lastDistance; ChSetA[(size_t)distancePlace - 1] = dist; } } m_RepDists[m_RepDistPtr++] = dist; m_RepDistPtr &= 3; len += 2; LastLength = len; LastDist = dist; return CopyBlock(dist, len); } HRESULT CDecoder::LongLZ() { UInt32 len; UInt32 dist; UInt32 distancePlace, newDistancePlace; UInt32 oldAvr2, oldAvr3; NumHuf = 0; Nlzb += 16; if (Nlzb > 0xff) { Nlzb = 0x90; Nhfb >>= 1; } oldAvr2 = AvrLn2; if (AvrLn2 >= 64) len = DecodeNum(AvrLn2 < 122 ? PosL1 : PosL2); else { UInt32 bitField = m_InBitStream.GetValue(16); if (bitField < 0x100) { len = bitField; m_InBitStream.MovePos(16); } else { for (len = 0; ((bitField << len) & 0x8000) == 0; len++); m_InBitStream.MovePos(len + 1); } } AvrLn2 += len; AvrLn2 -= AvrLn2 >> 5; { const Byte *tab; if (AvrPlcB >= 0x2900) tab = PosHf2; else if (AvrPlcB >= 0x0700) tab = PosHf1; else tab = PosHf0; distancePlace = DecodeNum(tab); // [0, 256] } AvrPlcB += distancePlace; AvrPlcB -= AvrPlcB >> 8; distancePlace &= 0xff; for (;;) { dist = ChSetB[distancePlace]; newDistancePlace = NToPlB[dist++ & 0xff]++; if (dist & 0xff) break; CorrHuff(ChSetB,NToPlB); } ChSetB[distancePlace] = ChSetB[newDistancePlace]; ChSetB[newDistancePlace] = dist; dist = ((dist & 0xff00) >> 1) | ReadBits(7); oldAvr3 = AvrLn3; if (len != 1 && len != 4) { if (len == 0 && dist <= MaxDist3) { AvrLn3++; AvrLn3 -= AvrLn3 >> 8; } else if (AvrLn3 > 0) AvrLn3--; } len += 3; if (dist >= MaxDist3) len++; if (dist <= 256) len += 8; if (oldAvr3 > 0xb0 || (AvrPlc >= 0x2a00 && oldAvr2 < 0x40)) MaxDist3 = 0x7f00; else MaxDist3 = 0x2001; m_RepDists[m_RepDistPtr++] = --dist; m_RepDistPtr &= 3; LastLength = len; LastDist = dist; return CopyBlock(dist, len); } HRESULT CDecoder::HuffDecode() { UInt32 curByte, newBytePlace; UInt32 len; UInt32 dist; unsigned bytePlace; { const Byte *tab; if (AvrPlc >= 0x7600) tab = PosHf4; else if (AvrPlc >= 0x5e00) tab = PosHf3; else if (AvrPlc >= 0x3600) tab = PosHf2; else if (AvrPlc >= 0x0e00) tab = PosHf1; else tab = PosHf0; bytePlace = DecodeNum(tab); // [0, 256] } if (StMode) { if (bytePlace == 0) { if (ReadBits(1)) { NumHuf = 0; StMode = false; return S_OK; } len = ReadBits(1) + 3; dist = DecodeNum(PosHf2); dist = (dist << 5) | ReadBits(5); if (dist == 0) return S_FALSE; return CopyBlock(dist - 1, len); } bytePlace--; // bytePlace is [0, 255] } else if (NumHuf++ >= 16 && FlagsCnt == 0) StMode = true; bytePlace &= 0xff; AvrPlc += bytePlace; AvrPlc -= AvrPlc >> 8; Nhfb += 16; if (Nhfb > 0xff) { Nhfb = 0x90; Nlzb >>= 1; } m_UnpackSize--; m_OutWindowStream.PutByte((Byte)(ChSet[bytePlace] >> 8)); for (;;) { curByte = ChSet[bytePlace]; newBytePlace = NToPl[curByte++ & 0xff]++; if ((curByte & 0xff) <= 0xa1) break; CorrHuff(ChSet, NToPl); } ChSet[bytePlace] = ChSet[newBytePlace]; ChSet[newBytePlace] = curByte; return S_OK; } void CDecoder::GetFlagsBuf() { UInt32 flags, newFlagsPlace; const UInt32 flagsPlace = DecodeNum(PosHf2); // [0, 256] if (flagsPlace >= Z7_ARRAY_SIZE(ChSetC)) return; for (;;) { flags = ChSetC[flagsPlace]; FlagBuf = flags >> 8; newFlagsPlace = NToPlC[flags++ & 0xff]++; if ((flags & 0xff) != 0) break; CorrHuff(ChSetC, NToPlC); } ChSetC[flagsPlace] = ChSetC[newFlagsPlace]; ChSetC[newFlagsPlace] = flags; } void CDecoder::CorrHuff(UInt32 *CharSet, UInt32 *NumToPlace) { int i; for (i = 7; i >= 0; i--) for (unsigned j = 0; j < 32; j++, CharSet++) *CharSet = (*CharSet & ~(UInt32)0xff) | (unsigned)i; memset(NumToPlace, 0, sizeof(NToPl)); for (i = 6; i >= 0; i--) NumToPlace[i] = (7 - (unsigned)i) * 32; } HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo * /* progress */) { if (!inSize || !outSize) return E_INVALIDARG; if (_isSolid && !_solidAllowed) return S_FALSE; _solidAllowed = false; if (!m_OutWindowStream.Create(kHistorySize)) return E_OUTOFMEMORY; if (!m_InBitStream.Create(1 << 20)) return E_OUTOFMEMORY; m_UnpackSize = *outSize; m_OutWindowStream.SetStream(outStream); m_OutWindowStream.Init(_isSolid); m_InBitStream.SetStream(inStream); m_InBitStream.Init(); // InitData FlagsCnt = 0; FlagBuf = 0; StMode = false; LCount = 0; if (!_isSolid) { AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0; AvrPlc = 0x3500; MaxDist3 = 0x2001; Nhfb = Nlzb = 0x80; { // InitStructures for (unsigned i = 0; i < kNumRepDists; i++) m_RepDists[i] = 0; m_RepDistPtr = 0; LastLength = 0; LastDist = 0; } // InitHuff for (UInt32 i = 0; i < 256; i++) { Place[i] = PlaceA[i] = PlaceB[i] = i; UInt32 c = (~i + 1) & 0xff; PlaceC[i] = c; ChSet[i] = ChSetB[i] = i << 8; ChSetA[i] = i; ChSetC[i] = c << 8; } memset(NToPl, 0, sizeof(NToPl)); memset(NToPlB, 0, sizeof(NToPlB)); memset(NToPlC, 0, sizeof(NToPlC)); CorrHuff(ChSetB, NToPlB); } if (m_UnpackSize > 0) { GetFlagsBuf(); FlagsCnt = 8; } while (m_UnpackSize != 0) { if (!StMode) { if (--FlagsCnt < 0) { GetFlagsBuf(); FlagsCnt = 7; } if (FlagBuf & 0x80) { FlagBuf <<= 1; if (Nlzb > Nhfb) { RINOK(LongLZ()) continue; } } else { FlagBuf <<= 1; if (--FlagsCnt < 0) { GetFlagsBuf(); FlagsCnt = 7; } if ((FlagBuf & 0x80) == 0) { FlagBuf <<= 1; RINOK(ShortLZ()) continue; } FlagBuf <<= 1; if (Nlzb <= Nhfb) { RINOK(LongLZ()) continue; } } } RINOK(HuffDecode()) } _solidAllowed = true; return m_OutWindowStream.Flush(); } Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)) { try { return CodeReal(inStream, outStream, inSize, outSize, progress); } catch(const CInBufferException &e) { return e.ErrorCode; } catch(const CLzOutWindowException &e) { return e.ErrorCode; } catch(...) { return S_FALSE; } } Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)) { if (size < 1) return E_INVALIDARG; _isSolid = ((data[0] & 1) != 0); return S_OK; } }}