summaryrefslogtreecommitdiffstats
path: root/src/libs/7zip/unix/CPP/7zip/Compress/Rar1Decoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/7zip/unix/CPP/7zip/Compress/Rar1Decoder.cpp')
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/Rar1Decoder.cpp480
1 files changed, 480 insertions, 0 deletions
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/Rar1Decoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/Rar1Decoder.cpp
new file mode 100644
index 000000000..eadca7b3d
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/Rar1Decoder.cpp
@@ -0,0 +1,480 @@
+// 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 UInt32 PosL1[]={0,0,0,2,3,5,7,11,16,20,24,32,32, 256};
+static UInt32 PosL2[]={0,0,0,0,5,7,9,13,18,22,26,34,36, 256};
+static UInt32 PosHf0[]={0,0,0,0,0,8,16,24,33,33,33,33,33, 257};
+static UInt32 PosHf1[]={0,0,0,0,0,0,4,44,60,76,80,80,127, 257};
+static UInt32 PosHf2[]={0,0,0,0,0,0,2,7,53,117,233, 257,0};
+static UInt32 PosHf3[]={0,0,0,0,0,0,0,2,16,218,251, 257,0};
+static UInt32 PosHf4[]={0,0,0,0,0,0,0,0,0,255, 257,0,0};
+
+static const UInt32 kHistorySize = (1 << 16);
+
+class CCoderReleaser
+{
+ CDecoder *m_Coder;
+public:
+ CCoderReleaser(CDecoder *coder): m_Coder(coder) {}
+ ~CCoderReleaser() { m_Coder->ReleaseStreams(); }
+};
+
+CDecoder::CDecoder(): m_IsSolid(false) { }
+
+void CDecoder::InitStructures()
+{
+ for(int i = 0; i < kNumRepDists; i++)
+ m_RepDists[i] = 0;
+ m_RepDistPtr = 0;
+ LastLength = 0;
+ LastDist = 0;
+}
+
+UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
+
+HRESULT CDecoder::CopyBlock(UInt32 distance, UInt32 len)
+{
+ if (len == 0)
+ return S_FALSE;
+ m_UnpackSize -= len;
+ return m_OutWindowStream.CopyBlock(distance, len) ? S_OK : S_FALSE;
+}
+
+
+UInt32 CDecoder::DecodeNum(const UInt32 *posTab)
+{
+ UInt32 startPos = 2;
+ UInt32 num = m_InBitStream.GetValue(12);
+ for (;;)
+ {
+ UInt32 cur = (posTab[startPos + 1] - posTab[startPos]) << (12 - startPos);
+ if (num < cur)
+ break;
+ startPos++;
+ num -= cur;
+ }
+ m_InBitStream.MovePos(startPos);
+ return((num >> (12 - startPos)) + posTab[startPos]);
+}
+
+static Byte kShortLen1[] = {1,3,4,4,5,6,7,8,8,4,4,5,6,6 };
+static Byte kShortLen1a[] = {1,4,4,4,5,6,7,8,8,4,4,5,6,6,4 };
+static Byte kShortLen2[] = {2,3,3,3,4,4,5,6,6,4,4,5,6,6 };
+static Byte kShortLen2a[] = {2,3,3,4,4,4,5,6,6,4,4,5,6,6,4 };
+static UInt32 kShortXor1[] = {0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0};
+static UInt32 kShortXor2[] = {0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0};
+
+HRESULT CDecoder::ShortLZ()
+{
+ UInt32 len, saveLen, dist;
+ int distancePlace;
+ Byte *kShortLen;
+ const UInt32 *kShortXor;
+ NumHuf = 0;
+
+ if (LCount == 2)
+ {
+ if (ReadBits(1))
+ return CopyBlock(LastDist, LastLength);
+ LCount = 0;
+ }
+
+ UInt32 bitField = m_InBitStream.GetValue(8);
+
+ if (AvrLn1 < 37)
+ {
+ kShortLen = Buf60 ? kShortLen1a : kShortLen1;
+ kShortXor = kShortXor1;
+ }
+ else
+ {
+ kShortLen = Buf60 ? kShortLen2a : kShortLen2;
+ kShortXor = kShortXor2;
+ }
+
+ for (len = 0; ((bitField ^ kShortXor[len]) & (~(0xff >> kShortLen[len]))) != 0; len++);
+ m_InBitStream.MovePos(kShortLen[len]);
+
+ if (len >= 9)
+ {
+ if (len == 9)
+ {
+ LCount++;
+ return CopyBlock(LastDist, LastLength);
+ }
+ if (len == 14)
+ {
+ LCount = 0;
+ len = DecodeNum(PosL2) + 5;
+ dist = 0x8000 + ReadBits(15) - 1;
+ LastLength = len;
+ LastDist = dist;
+ return CopyBlock(dist, len);
+ }
+
+ LCount = 0;
+ saveLen = len;
+ dist = m_RepDists[(m_RepDistPtr - (len - 9)) & 3];
+ len = DecodeNum(PosL1) + 2;
+ if (len == 0x101 && saveLen == 10)
+ {
+ Buf60 ^= 1;
+ return S_OK;
+ }
+ if (dist >= 256)
+ len++;
+ if (dist >= MaxDist3 - 1)
+ len++;
+ }
+ else
+ {
+ LCount = 0;
+ AvrLn1 += len;
+ AvrLn1 -= AvrLn1 >> 4;
+
+ distancePlace = DecodeNum(PosHf2) & 0xff;
+ dist = ChSetA[distancePlace];
+ if (--distancePlace != -1)
+ {
+ PlaceA[dist]--;
+ UInt32 lastDistance = ChSetA[distancePlace];
+ PlaceA[lastDistance]++;
+ ChSetA[distancePlace + 1] = lastDistance;
+ ChSetA[distancePlace] = dist;
+ }
+ len += 2;
+ }
+ m_RepDists[m_RepDistPtr++] = dist;
+ m_RepDistPtr &= 3;
+ 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 >= 122)
+ len = DecodeNum(PosL2);
+ else if (AvrLn2 >= 64)
+ len = DecodeNum(PosL1);
+ 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;
+
+ if (AvrPlcB > 0x28ff)
+ distancePlace = DecodeNum(PosHf2);
+ else if (AvrPlcB > 0x6ff)
+ distancePlace = DecodeNum(PosHf1);
+ else
+ distancePlace = DecodeNum(PosHf0);
+
+ AvrPlcB += distancePlace;
+ AvrPlcB -= AvrPlcB >> 8;
+ for (;;)
+ {
+ dist = ChSetB[distancePlace & 0xff];
+ newDistancePlace = NToPlB[dist++ & 0xff]++;
+ if (!(dist & 0xff))
+ CorrHuff(ChSetB,NToPlB);
+ else
+ break;
+ }
+
+ 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;
+ int bytePlace;
+
+ if (AvrPlc > 0x75ff) bytePlace = DecodeNum(PosHf4);
+ else if (AvrPlc > 0x5dff) bytePlace = DecodeNum(PosHf3);
+ else if (AvrPlc > 0x35ff) bytePlace = DecodeNum(PosHf2);
+ else if (AvrPlc > 0x0dff) bytePlace = DecodeNum(PosHf1);
+ else bytePlace = DecodeNum(PosHf0);
+ if (StMode)
+ {
+ if (--bytePlace == -1)
+ {
+ if (ReadBits(1))
+ {
+ NumHuf = StMode = 0;
+ return S_OK;
+ }
+ else
+ {
+ len = (ReadBits(1)) ? 4 : 3;
+ dist = DecodeNum(PosHf2);
+ dist = (dist << 5) | ReadBits(5);
+ return CopyBlock(dist - 1, len);
+ }
+ }
+ }
+ else if (NumHuf++ >= 16 && FlagsCnt == 0)
+ StMode = 1;
+ 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)
+ CorrHuff(ChSet, NToPl);
+ else
+ break;
+ }
+
+ ChSet[bytePlace] = ChSet[newBytePlace];
+ ChSet[newBytePlace] = curByte;
+ return S_OK;
+}
+
+
+void CDecoder::GetFlagsBuf()
+{
+ UInt32 flags, newFlagsPlace;
+ UInt32 flagsPlace = DecodeNum(PosHf2);
+
+ 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::InitData()
+{
+ if (!m_IsSolid)
+ {
+ AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0;
+ AvrPlc = 0x3500;
+ MaxDist3 = 0x2001;
+ Nhfb = Nlzb = 0x80;
+ }
+ FlagsCnt = 0;
+ FlagBuf = 0;
+ StMode = 0;
+ LCount = 0;
+}
+
+void CDecoder::CorrHuff(UInt32 *CharSet,UInt32 *NumToPlace)
+{
+ int i;
+ for (i = 7; i >= 0; i--)
+ for (int j = 0; j < 32; j++, CharSet++)
+ *CharSet = (*CharSet & ~0xff) | i;
+ memset(NumToPlace, 0, sizeof(NToPl));
+ for (i = 6; i >= 0; i--)
+ NumToPlace[i] = (7 - i) * 32;
+}
+
+void CDecoder::InitHuff()
+{
+ for (UInt32 i = 0; i < 256; i++)
+ {
+ Place[i] = PlaceA[i] = PlaceB[i] = i;
+ PlaceC[i] = (~i + 1) & 0xff;
+ ChSet[i] = ChSetB[i] = i << 8;
+ ChSetA[i] = i;
+ ChSetC[i] = ((~i + 1) & 0xff) << 8;
+ }
+ memset(NToPl, 0, sizeof(NToPl));
+ memset(NToPlB, 0, sizeof(NToPlB));
+ memset(NToPlC, 0, sizeof(NToPlC));
+ CorrHuff(ChSetB, NToPlB);
+}
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo * /* progress */)
+{
+ if (inSize == NULL || outSize == NULL)
+ return E_INVALIDARG;
+
+ if (!m_OutWindowStream.Create(kHistorySize))
+ return E_OUTOFMEMORY;
+ if (!m_InBitStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+
+ m_UnpackSize = (Int64)*outSize;
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(m_IsSolid);
+ m_InBitStream.SetStream(inStream);
+ m_InBitStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+ InitData();
+ if (!m_IsSolid)
+ {
+ InitStructures();
+ InitHuff();
+ }
+ if (m_UnpackSize > 0)
+ {
+ GetFlagsBuf();
+ FlagsCnt = 8;
+ }
+
+ while (m_UnpackSize > 0)
+ {
+ if (StMode)
+ {
+ RINOK(HuffDecode());
+ continue;
+ }
+
+ if (--FlagsCnt < 0)
+ {
+ GetFlagsBuf();
+ FlagsCnt=7;
+ }
+
+ if (FlagBuf & 0x80)
+ {
+ FlagBuf <<= 1;
+ if (Nlzb > Nhfb)
+ {
+ RINOK(LongLZ());
+ }
+ else
+ {
+ RINOK(HuffDecode());
+ }
+ }
+ else
+ {
+ FlagBuf <<= 1;
+ if (--FlagsCnt < 0)
+ {
+ GetFlagsBuf();
+ FlagsCnt = 7;
+ }
+ if (FlagBuf & 0x80)
+ {
+ FlagBuf <<= 1;
+ if (Nlzb > Nhfb)
+ {
+ RINOK(HuffDecode());
+ }
+ else
+ {
+ RINOK(LongLZ());
+ }
+ }
+ else
+ {
+ FlagBuf <<= 1;
+ RINOK(ShortLZ());
+ }
+ }
+ }
+ if (m_UnpackSize < 0)
+ return S_FALSE;
+ return m_OutWindowStream.Flush();
+}
+
+STDMETHODIMP 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; }
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ if (size < 1)
+ return E_INVALIDARG;
+ m_IsSolid = (data[0] != 0);
+ return S_OK;
+}
+
+}}