Files
nsis-plugin-ns7zip/versions/26.00/CPP/7zip/Compress/Rar2Decoder.cpp
T
Simone d074cc7c07 chore: initial commit (extracted from Launchers monorepo)
Plugin: ns7zip v2.0.0
Architectures: x86-ansi, x86-unicode, amd64-unicode
License: LGPL-2.1-or-later
2026-04-29 14:07:51 +02:00

473 lines
12 KiB
C++

// Rar2Decoder.cpp
// According to unRAR license, this code may not be used to develop
// a program that creates RAR archives
#include "StdAfx.h"
#include <stdlib.h>
#include "Rar2Decoder.h"
namespace NCompress {
namespace NRar2 {
namespace NMultimedia {
#define my_abs(x) (unsigned)abs(x)
Byte CFilter::Decode(int &channelDelta, Byte deltaByte)
{
D4 = D3;
D3 = D2;
D2 = LastDelta - D1;
D1 = LastDelta;
const int predictedValue = ((8 * LastChar + K1 * D1 + K2 * D2 + K3 * D3 + K4 * D4 + K5 * channelDelta) >> 3);
const Byte realValue = (Byte)(predictedValue - deltaByte);
{
const int i = ((int)(signed char)deltaByte) << 3;
Dif[0] += my_abs(i);
Dif[1] += my_abs(i - D1);
Dif[2] += my_abs(i + D1);
Dif[3] += my_abs(i - D2);
Dif[4] += my_abs(i + D2);
Dif[5] += my_abs(i - D3);
Dif[6] += my_abs(i + D3);
Dif[7] += my_abs(i - D4);
Dif[8] += my_abs(i + D4);
Dif[9] += my_abs(i - channelDelta);
Dif[10] += my_abs(i + channelDelta);
}
channelDelta = LastDelta = (signed char)(realValue - LastChar);
LastChar = realValue;
if (((++ByteCount) & 0x1F) == 0)
{
UInt32 minDif = Dif[0];
UInt32 numMinDif = 0;
Dif[0] = 0;
for (unsigned i = 1; i < Z7_ARRAY_SIZE(Dif); i++)
{
if (Dif[i] < minDif)
{
minDif = Dif[i];
numMinDif = i;
}
Dif[i] = 0;
}
switch (numMinDif)
{
case 1: if (K1 >= -16) K1--; break;
case 2: if (K1 < 16) K1++; break;
case 3: if (K2 >= -16) K2--; break;
case 4: if (K2 < 16) K2++; break;
case 5: if (K3 >= -16) K3--; break;
case 6: if (K3 < 16) K3++; break;
case 7: if (K4 >= -16) K4--; break;
case 8: if (K4 < 16) K4++; break;
case 9: if (K5 >= -16) K5--; break;
case 10:if (K5 < 16) K5++; break;
}
}
return realValue;
}
}
static const UInt32 kHistorySize = 1 << 20;
// static const UInt32 kWindowReservSize = (1 << 22) + 256;
CDecoder::CDecoder():
_isSolid(false),
_solidAllowed(false),
m_TablesOK(false)
{
}
void CDecoder::InitStructures()
{
m_MmFilter.Init();
for (unsigned i = 0; i < kNumReps; i++)
m_RepDists[i] = 0;
m_RepDistPtr = 0;
m_LastLength = 0;
memset(m_LastLevels, 0, kMaxTableSize);
}
UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); }
#define RIF(x) { if (!(x)) return false; }
static const unsigned kRepBothNumber = 256;
static const unsigned kRepNumber = kRepBothNumber + 1;
static const unsigned kLen2Number = kRepNumber + kNumReps;
static const unsigned kReadTableNumber = kLen2Number + kNumLen2Symbols;
static const unsigned kMatchNumber = kReadTableNumber + 1;
// static const unsigned kDistTableStart = kMainTableSize;
// static const unsigned kLenTableStart = kDistTableStart + kDistTableSize;
static const UInt32 kDistStart [kDistTableSize] = {0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040};
static const Byte kDistDirectBits[kDistTableSize] = {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, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16};
static const Byte kLen2DistStarts [kNumLen2Symbols]={0,4,8,16,32,64,128,192};
static const Byte kLen2DistDirectBits[kNumLen2Symbols]={2,2,3, 4, 5, 6, 6, 6};
static const UInt32 kDistLimit2 = 0x101 - 1;
static const UInt32 kDistLimit3 = 0x2000 - 1;
static const UInt32 kDistLimit4 = 0x40000 - 1;
// static const UInt32 kMatchMaxLen = 255 + 2;
// static const UInt32 kMatchMaxLenMax = 255 + 5;
bool CDecoder::ReadTables(void)
{
m_TablesOK = false;
const unsigned kLevelTableSize = 19;
Byte levelLevels[kLevelTableSize];
Byte lens[kMaxTableSize];
m_AudioMode = (ReadBits(1) == 1);
if (ReadBits(1) == 0)
memset(m_LastLevels, 0, kMaxTableSize);
unsigned numLevels;
if (m_AudioMode)
{
m_NumChannels = ReadBits(2) + 1;
if (m_MmFilter.CurrentChannel >= m_NumChannels)
m_MmFilter.CurrentChannel = 0;
numLevels = m_NumChannels * k_MM_TableSize;
}
else
numLevels = kHeapTablesSizesSum;
unsigned i;
for (i = 0; i < kLevelTableSize; i++)
levelLevels[i] = (Byte)ReadBits(4);
NHuffman::CDecoder256<kNumHufBits, kLevelTableSize, 6> m_LevelDecoder;
RIF(m_LevelDecoder.Build(levelLevels, NHuffman::k_BuildMode_Full))
i = 0;
do
{
const unsigned sym = m_LevelDecoder.DecodeFull(&m_InBitStream);
if (sym < 16)
{
lens[i] = (Byte)((sym + m_LastLevels[i]) & 15);
i++;
}
#if 0
else if (sym >= kLevelTableSize)
return false;
#endif
else
{
unsigned num;
Byte v;
if (sym == 16)
{
if (i == 0)
return false;
num = ReadBits(2) + 3;
v = lens[(size_t)i - 1];
}
else
{
num = (sym - 17) * 4;
num += num + 3 + ReadBits(3 + num);
v = 0;
}
num += i;
if (num > numLevels)
{
// return false;
num = numLevels; // original unRAR
}
do
lens[i++] = v;
while (i < num);
}
}
while (i < numLevels);
if (m_InBitStream.ExtraBitsWereRead())
return false;
if (m_AudioMode)
for (i = 0; i < m_NumChannels; i++)
{
RIF(m_MMDecoders[i].Build(&lens[(size_t)i * k_MM_TableSize]))
}
else
{
RIF(m_MainDecoder.Build(&lens[0]))
RIF(m_DistDecoder.Build(&lens[kMainTableSize]))
RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize]))
}
memcpy(m_LastLevels, lens, kMaxTableSize);
m_TablesOK = true;
return true;
}
bool CDecoder::ReadLastTables()
{
// it differs a little from pure RAR sources;
// UInt64 ttt = m_InBitStream.GetProcessedSize() + 2;
// + 2 works for: return 0xFF; in CInBuffer::ReadByte.
if (m_InBitStream.GetProcessedSize() + 7 <= m_PackSize) // test it: probably incorrect;
// if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect;
{
if (m_AudioMode)
{
const unsigned symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream);
if (symbol == 256)
return ReadTables();
if (symbol >= k_MM_TableSize)
return false;
}
else
{
const unsigned sym = m_MainDecoder.Decode(&m_InBitStream);
if (sym == kReadTableNumber)
return ReadTables();
if (sym >= kMainTableSize)
return false;
}
}
return true;
}
bool CDecoder::DecodeMm(UInt32 pos)
{
while (pos-- != 0)
{
const unsigned symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream);
if (m_InBitStream.ExtraBitsWereRead())
return false;
if (symbol >= 256)
return symbol == 256;
/*
Byte byPredict = m_Predictor.Predict();
Byte byReal = (Byte)(byPredict - (Byte)symbol);
m_Predictor.Update(byReal, byPredict);
*/
const Byte byReal = m_MmFilter.Decode((Byte)symbol);
m_OutWindowStream.PutByte(byReal);
if (++m_MmFilter.CurrentChannel == m_NumChannels)
m_MmFilter.CurrentChannel = 0;
}
return true;
}
typedef unsigned CLenType;
static inline CLenType SlotToLen(CBitDecoder &_bitStream, CLenType slot)
{
const unsigned numBits = ((unsigned)slot >> 2) - 1;
return ((4 | (slot & 3)) << numBits) + (CLenType)_bitStream.ReadBits(numBits);
}
bool CDecoder::DecodeLz(Int32 pos)
{
while (pos > 0)
{
unsigned sym = m_MainDecoder.Decode(&m_InBitStream);
if (m_InBitStream.ExtraBitsWereRead())
return false;
UInt32 len, distance;
if (sym < 256)
{
m_OutWindowStream.PutByte(Byte(sym));
pos--;
continue;
}
else if (sym >= kMatchNumber)
{
if (sym >= kMainTableSize)
return false;
len = sym - kMatchNumber;
if (len >= 8)
len = SlotToLen(m_InBitStream, len);
len += 3;
sym = m_DistDecoder.Decode(&m_InBitStream);
if (sym >= kDistTableSize)
return false;
distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
if (distance >= kDistLimit3)
{
len += 2 - ((distance - kDistLimit4) >> 31);
// len++;
// if (distance >= kDistLimit4)
// len++;
}
}
else if (sym == kRepBothNumber)
{
len = m_LastLength;
if (len == 0)
return false;
distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3];
}
else if (sym < kLen2Number)
{
distance = m_RepDists[(m_RepDistPtr - (sym - kRepNumber + 1)) & 3];
len = m_LenDecoder.Decode(&m_InBitStream);
if (len >= kLenTableSize)
return false;
if (len >= 8)
len = SlotToLen(m_InBitStream, len);
len += 2;
if (distance >= kDistLimit2)
{
len++;
if (distance >= kDistLimit3)
{
len += 2 - ((distance - kDistLimit4) >> 31);
// len++;
// if (distance >= kDistLimit4)
// len++;
}
}
}
else if (sym < kReadTableNumber)
{
sym -= kLen2Number;
distance = kLen2DistStarts[sym] +
m_InBitStream.ReadBits(kLen2DistDirectBits[sym]);
len = 2;
}
else // (sym == kReadTableNumber)
return true;
m_RepDists[m_RepDistPtr++ & 3] = distance;
m_LastLength = len;
if (!m_OutWindowStream.CopyBlock(distance, len))
return false;
pos -= len;
}
return true;
}
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_PackSize = *inSize;
UInt64 pos = 0, unPackSize = *outSize;
m_OutWindowStream.SetStream(outStream);
m_OutWindowStream.Init(_isSolid);
m_InBitStream.SetStream(inStream);
m_InBitStream.Init();
// CCoderReleaser coderReleaser(this);
if (!_isSolid)
{
InitStructures();
if (unPackSize == 0)
{
if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect;
if (!ReadTables())
return S_FALSE;
_solidAllowed = true;
return S_OK;
}
ReadTables();
}
if (!m_TablesOK)
return S_FALSE;
const UInt64 startPos = m_OutWindowStream.GetProcessedSize();
while (pos < unPackSize)
{
UInt32 blockSize = 1 << 20;
if (blockSize > unPackSize - pos)
blockSize = (UInt32)(unPackSize - pos);
UInt64 blockStartPos = m_OutWindowStream.GetProcessedSize();
if (m_AudioMode)
{
if (!DecodeMm(blockSize))
return S_FALSE;
}
else
{
if (!DecodeLz((Int32)blockSize))
return S_FALSE;
}
if (m_InBitStream.ExtraBitsWereRead())
return S_FALSE;
const UInt64 globalPos = m_OutWindowStream.GetProcessedSize();
pos = globalPos - blockStartPos;
if (pos < blockSize)
if (!ReadTables())
return S_FALSE;
pos = globalPos - startPos;
if (progress)
{
const UInt64 packSize = m_InBitStream.GetProcessedSize();
RINOK(progress->SetRatioInfo(&packSize, &pos))
}
}
if (pos > unPackSize)
return S_FALSE;
if (!ReadLastTables())
return S_FALSE;
_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;
}
}}