📄 rar3decoder.cpp
字号:
if (c == PpmEscChar)
{
int nextCh = DecodePpmSymbol();
if (nextCh == 0)
return ReadTables(keepDecompressing);
if (nextCh == 2 || nextCh == -1)
return S_OK;
if (nextCh == 3)
{
if (!ReadVmCodePPM())
return S_FALSE;
continue;
}
if (nextCh == 4 || nextCh == 5)
{
UInt32 distance = 0;
UInt32 length = 4;
if (nextCh == 4)
{
for (int i = 0; i < 3; i++)
{
int c = DecodePpmSymbol();
if (c == -1)
return S_OK;
distance = (distance << 8) + (Byte)c;
}
distance++;
length += 28;
}
int c = DecodePpmSymbol();
if (c == -1)
return S_OK;
length += c;
if (distance >= _lzSize)
return S_FALSE;
CopyBlock(distance, length);
num -= (Int32)length;
continue;
}
}
PutByte((Byte)c);
num--;
}
while (num >= 0);
keepDecompressing = true;
return S_OK;
}
/////////////////////////////////////////////////
// LZ
HRESULT CDecoder::ReadTables(bool &keepDecompressing)
{
keepDecompressing = true;
ReadBits((8 - m_InBitStream.GetBitPosition()) & 7);
if (ReadBits(1) != 0)
{
_lzMode = false;
return InitPPM();
}
_lzMode = true;
PrevAlignBits = 0;
PrevAlignCount = 0;
Byte levelLevels[kLevelTableSize];
Byte newLevels[kTablesSizesSum];
if (ReadBits(1) == 0)
memset(m_LastLevels, 0, kTablesSizesSum);
int i;
for (i = 0; i < kLevelTableSize; i++)
{
UInt32 length = ReadBits(4);
if (length == 15)
{
UInt32 zeroCount = ReadBits(4);
if (zeroCount != 0)
{
zeroCount += 2;
while (zeroCount-- > 0 && i < kLevelTableSize)
levelLevels[i++]=0;
i--;
continue;
}
}
levelLevels[i] = (Byte)length;
}
RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
i = 0;
while (i < kTablesSizesSum)
{
UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
if (number < 16)
{
newLevels[i] = Byte((number + m_LastLevels[i]) & 15);
i++;
}
else if (number > kLevelTableSize)
return S_FALSE;
else
{
int num;
if (((number - 16) & 1) == 0)
num = ReadBits(3) + 3;
else
num = ReadBits(7) + 11;
if (number < 18)
{
if (i == 0)
return S_FALSE;
for (; num > 0 && i < kTablesSizesSum; num--, i++)
newLevels[i] = newLevels[i - 1];
}
else
{
for (; num > 0 && i < kTablesSizesSum; num--)
newLevels[i++] = 0;
}
}
}
TablesRead = true;
// original code has check here:
/*
if (InAddr > ReadTop)
{
keepDecompressing = false;
return true;
}
*/
RIF(m_MainDecoder.SetCodeLengths(&newLevels[0]));
RIF(m_DistDecoder.SetCodeLengths(&newLevels[kMainTableSize]));
RIF(m_AlignDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize]));
RIF(m_LenDecoder.SetCodeLengths(&newLevels[kMainTableSize + kDistTableSize + kAlignTableSize]));
memcpy(m_LastLevels, newLevels, kTablesSizesSum);
return S_OK;
}
class CCoderReleaser
{
CDecoder *m_Coder;
public:
CCoderReleaser(CDecoder *coder): m_Coder(coder) {}
~CCoderReleaser()
{
// m_Coder->m_OutWindowStream.Flush();
m_Coder->ReleaseStreams();
}
};
HRESULT CDecoder::ReadEndOfBlock(bool &keepDecompressing)
{
if (ReadBits(1) != 0)
{
// old file
TablesRead = false;
return ReadTables(keepDecompressing);
}
// new file
keepDecompressing = false;
TablesRead = (ReadBits(1) == 0);
return S_OK;
}
UInt32 kDistStart[kDistTableSize];
class CDistInit
{
public:
CDistInit() { Init(); }
void Init()
{
UInt32 start = 0;
for (UInt32 i = 0; i < kDistTableSize; i++)
{
kDistStart[i] = start;
start += (1 << kDistDirectBits[i]);
}
}
} g_DistInit;
HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
{
UInt32 rep0 = _reps[0];
UInt32 rep1 = _reps[1];
UInt32 rep2 = _reps[2];
UInt32 rep3 = _reps[3];
UInt32 length = _lastLength;
for (;;)
{
if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
{
RINOK(WriteBuf());
if (_writtenFileSize > _unpackSize)
{
keepDecompressing = false;
return S_OK;
}
}
UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
if (number < 256)
{
PutByte(Byte(number));
continue;
}
else if (number == kSymbolReadTable)
{
RINOK(ReadEndOfBlock(keepDecompressing));
break;
}
else if (number == 257)
{
if (!ReadVmCodeLZ())
return S_FALSE;
continue;
}
else if (number == 258)
{
}
else if (number < kSymbolRep + 4)
{
if (number != kSymbolRep)
{
UInt32 distance;
if (number == kSymbolRep + 1)
distance = rep1;
else
{
if (number == kSymbolRep + 2)
distance = rep2;
else
{
distance = rep3;
rep3 = rep2;
}
rep2 = rep1;
}
rep1 = rep0;
rep0 = distance;
}
UInt32 number = m_LenDecoder.DecodeSymbol(&m_InBitStream);
if (number >= kLenTableSize)
return S_FALSE;
length = 2 + kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]);
}
else
{
rep3 = rep2;
rep2 = rep1;
rep1 = rep0;
if (number < 271)
{
number -= 263;
rep0 = kLen2DistStarts[number] + m_InBitStream.ReadBits(kLen2DistDirectBits[number]);
length = 2;
}
else if (number < 299)
{
number -= 271;
length = kNormalMatchMinLen + (UInt32)kLenStart[number] + m_InBitStream.ReadBits(kLenDirectBits[number]);
UInt32 number = m_DistDecoder.DecodeSymbol(&m_InBitStream);
if (number >= kDistTableSize)
return S_FALSE;
rep0 = kDistStart[number];
int numBits = kDistDirectBits[number];
if (number >= (kNumAlignBits * 2) + 2)
{
if (numBits > kNumAlignBits)
rep0 += (m_InBitStream.ReadBits(numBits - kNumAlignBits) << kNumAlignBits);
if (PrevAlignCount > 0)
{
PrevAlignCount--;
rep0 += PrevAlignBits;
}
else
{
UInt32 number = m_AlignDecoder.DecodeSymbol(&m_InBitStream);
if (number < (1 << kNumAlignBits))
{
rep0 += number;
PrevAlignBits = number;
}
else if (number == (1 << kNumAlignBits))
{
PrevAlignCount = kNumAlignReps;
rep0 += PrevAlignBits;
}
else
return S_FALSE;
}
}
else
rep0 += m_InBitStream.ReadBits(numBits);
length += ((kDistLimit4 - rep0) >> 31) + ((kDistLimit3 - rep0) >> 31);
}
else
return S_FALSE;
}
if (rep0 >= _lzSize)
return S_FALSE;
CopyBlock(rep0, length);
}
_reps[0] = rep0;
_reps[1] = rep1;
_reps[2] = rep2;
_reps[3] = rep3;
_lastLength = length;
return S_OK;
}
HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
{
_writtenFileSize = 0;
if (!m_IsSolid)
{
_lzSize = 0;
_winPos = 0;
_wrPtr = 0;
for (int i = 0; i < kNumReps; i++)
_reps[i] = 0;
_lastLength = 0;
memset(m_LastLevels, 0, kTablesSizesSum);
TablesRead = false;
PpmEscChar = 2;
InitFilters();
}
if (!m_IsSolid || !TablesRead)
{
bool keepDecompressing;
RINOK(ReadTables(keepDecompressing));
if (!keepDecompressing)
return S_OK;
}
for(;;)
{
bool keepDecompressing;
if (_lzMode)
{
RINOK(DecodeLZ(keepDecompressing))
}
else
{
RINOK(DecodePPM(1 << 18, keepDecompressing))
}
UInt64 packSize = m_InBitStream.GetProcessedSize();
RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize));
if (!keepDecompressing)
break;
}
RINOK(WriteBuf());
if (_writtenFileSize < _unpackSize)
return S_FALSE;
// return m_OutWindowStream.Flush();
return S_OK;
}
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream,
ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
ICompressProgressInfo *progress)
{
try
{
if (inSize == NULL || outSize == NULL)
return E_INVALIDARG;
if (_vmData == 0)
{
_vmData = (Byte *)::MidAlloc(kVmDataSizeMax + kVmCodeSizeMax);
if (_vmData == 0)
return E_OUTOFMEMORY;
_vmCode = _vmData + kVmDataSizeMax;
}
if (_window == 0)
{
_window = (Byte *)::MidAlloc(kWindowSize);
if (_window == 0)
return E_OUTOFMEMORY;
}
if (!m_InBitStream.Create(1 << 20))
return E_OUTOFMEMORY;
if (!_vm.Create())
return E_OUTOFMEMORY;
m_InBitStream.SetStream(inStream);
m_InBitStream.Init();
_outStream = outStream;
CCoderReleaser coderReleaser(this);
_unpackSize = *outSize;
return CodeReal(progress);
}
catch(const CInBufferException &e) { return e.ErrorCode; }
catch(...) { return S_FALSE; }
// CNewException is possible here. But probably CNewException is caused
// by error in data stream.
}
STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
{
if (size < 1)
return E_INVALIDARG;
m_IsSolid = (data[0] != 0);
return S_OK;
}
}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -