Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Pavlov <ipavlov@users.sourceforge.net>2015-08-16 03:00:00 +0300
committerKornel LesiƄski <kornel@geekhood.net>2016-05-28 02:16:55 +0300
commitcba375916fb18db8b9101aedf4fa079e019311b3 (patch)
tree6275ae5fc2a8dd337ab0327180c871807e6ba5d4 /CPP/7zip/Compress
parent54490d51d5c6b0d794dcbad2d634d4c95fc25b6c (diff)
15.0615.06
Diffstat (limited to 'CPP/7zip/Compress')
-rw-r--r--CPP/7zip/Compress/Codec.def2
-rw-r--r--CPP/7zip/Compress/DeflateEncoder.cpp8
-rw-r--r--CPP/7zip/Compress/HuffmanDecoder.h19
-rw-r--r--CPP/7zip/Compress/Rar1Decoder.cpp2
-rw-r--r--CPP/7zip/Compress/Rar2Decoder.cpp2
-rw-r--r--CPP/7zip/Compress/Rar3Decoder.cpp22
-rw-r--r--CPP/7zip/Compress/Rar3Decoder.h1
-rw-r--r--CPP/7zip/Compress/Rar3Vm.cpp105
-rw-r--r--CPP/7zip/Compress/Rar3Vm.h34
-rw-r--r--CPP/7zip/Compress/Rar5Decoder.cpp960
-rw-r--r--CPP/7zip/Compress/Rar5Decoder.h335
-rw-r--r--CPP/7zip/Compress/RarCodecsRegister.cpp3
12 files changed, 1435 insertions, 58 deletions
diff --git a/CPP/7zip/Compress/Codec.def b/CPP/7zip/Compress/Codec.def
index ebf73a3b..f55b2d57 100644
--- a/CPP/7zip/Compress/Codec.def
+++ b/CPP/7zip/Compress/Codec.def
@@ -2,3 +2,5 @@ EXPORTS
CreateObject PRIVATE
GetNumberOfMethods PRIVATE
GetMethodProperty PRIVATE
+ CreateDecoder PRIVATE
+ CreateEncoder PRIVATE
diff --git a/CPP/7zip/Compress/DeflateEncoder.cpp b/CPP/7zip/Compress/DeflateEncoder.cpp
index eb012e8d..94d0092b 100644
--- a/CPP/7zip/Compress/DeflateEncoder.cpp
+++ b/CPP/7zip/Compress/DeflateEncoder.cpp
@@ -130,14 +130,14 @@ CCoder::CCoder(bool deflate64Mode):
m_Values(0),
m_Tables(0)
{
- {
- CEncProps props;
- SetProps(&props);
- }
m_MatchMaxLen = deflate64Mode ? kMatchMaxLen64 : kMatchMaxLen32;
m_NumLenCombinations = deflate64Mode ? kNumLenSymbols64 : kNumLenSymbols32;
m_LenStart = deflate64Mode ? kLenStart64 : kLenStart32;
m_LenDirectBits = deflate64Mode ? kLenDirectBits64 : kLenDirectBits32;
+ {
+ CEncProps props;
+ SetProps(&props);
+ }
MatchFinder_Construct(&_lzInWindow);
}
diff --git a/CPP/7zip/Compress/HuffmanDecoder.h b/CPP/7zip/Compress/HuffmanDecoder.h
index 6faf8005..65e0f93c 100644
--- a/CPP/7zip/Compress/HuffmanDecoder.h
+++ b/CPP/7zip/Compress/HuffmanDecoder.h
@@ -22,11 +22,13 @@ public:
bool SetCodeLengths(const Byte *lens)
{
- unsigned lenCounts[kNumBitsMax + 1];
+ UInt32 lenCounts[kNumBitsMax + 1];
UInt32 tmpPositions[kNumBitsMax + 1];
+
unsigned i;
for (i = 1; i <= kNumBitsMax; i++)
lenCounts[i] = 0;
+
UInt32 symbol;
for (symbol = 0; symbol < m_NumSymbols; symbol++)
@@ -42,7 +44,7 @@ public:
m_Positions[0] = m_Limits[0] = 0;
UInt32 startPos = 0;
UInt32 index = 0;
- const UInt32 kMaxValue = (1 << kNumBitsMax);
+ const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
for (i = 1; i <= kNumBitsMax; i++)
{
@@ -74,14 +76,15 @@ public:
UInt32 DecodeSymbol(TBitDecoder *bitStream)
{
unsigned numBits;
- UInt32 value = bitStream->GetValue(kNumBitsMax);
- if (value < m_Limits[kNumTableBits])
- numBits = m_Lengths[value >> (kNumBitsMax - kNumTableBits)];
+ UInt32 val = bitStream->GetValue(kNumBitsMax);
+
+ if (val < m_Limits[kNumTableBits])
+ numBits = m_Lengths[val >> (kNumBitsMax - kNumTableBits)];
else
- for (numBits = kNumTableBits + 1; value >= m_Limits[numBits]; numBits++);
+ for (numBits = kNumTableBits + 1; val >= m_Limits[numBits]; numBits++);
+
bitStream->MovePos(numBits);
- UInt32 index = m_Positions[numBits] +
- ((value - m_Limits[numBits - 1]) >> (kNumBitsMax - numBits));
+ UInt32 index = m_Positions[numBits] + ((val - m_Limits[numBits - 1]) >> (kNumBitsMax - numBits));
if (index >= m_NumSymbols)
// throw CDecoderException(); // test it
return 0xFFFFFFFF;
diff --git a/CPP/7zip/Compress/Rar1Decoder.cpp b/CPP/7zip/Compress/Rar1Decoder.cpp
index 12de7e19..1aaedcc1 100644
--- a/CPP/7zip/Compress/Rar1Decoder.cpp
+++ b/CPP/7zip/Compress/Rar1Decoder.cpp
@@ -486,7 +486,7 @@ STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
{
if (size < 1)
return E_INVALIDARG;
- m_IsSolid = (data[0] != 0);
+ m_IsSolid = ((data[0] & 1) != 0);
return S_OK;
}
diff --git a/CPP/7zip/Compress/Rar2Decoder.cpp b/CPP/7zip/Compress/Rar2Decoder.cpp
index 6f42d2e6..5082ded3 100644
--- a/CPP/7zip/Compress/Rar2Decoder.cpp
+++ b/CPP/7zip/Compress/Rar2Decoder.cpp
@@ -394,7 +394,7 @@ STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
{
if (size < 1)
return E_INVALIDARG;
- m_IsSolid = (data[0] != 0);
+ m_IsSolid = ((data[0] & 1) != 0);
return S_OK;
}
diff --git a/CPP/7zip/Compress/Rar3Decoder.cpp b/CPP/7zip/Compress/Rar3Decoder.cpp
index f0553c85..81eb8285 100644
--- a/CPP/7zip/Compress/Rar3Decoder.cpp
+++ b/CPP/7zip/Compress/Rar3Decoder.cpp
@@ -140,6 +140,8 @@ void CDecoder::ExecuteFilter(int tempFilterIndex, NVm::CBlockRef &outBlockRef)
NVm::SetValue32(&tempFilter->GlobalData[0x24], (UInt32)_writtenFileSize);
NVm::SetValue32(&tempFilter->GlobalData[0x28], (UInt32)(_writtenFileSize >> 32));
CFilter *filter = _filters[tempFilter->FilterIndex];
+ if (!filter->IsSupported)
+ _unsupportedFilter = true;
_vm.Execute(filter, tempFilter, outBlockRef, filter->GlobalData);
delete tempFilter;
_tempFilters[tempFilterIndex] = 0;
@@ -226,12 +228,15 @@ void CDecoder::InitFilters()
_filters.Clear();
}
+static const unsigned MAX_UNPACK_FILTERS = 8192;
+
bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize)
{
CMemBitDecoder inp;
inp.Init(_vmData, codeSize);
UInt32 filterIndex;
+
if (firstByte & 0x80)
{
filterIndex = inp.ReadEncodedUInt32();
@@ -242,6 +247,7 @@ bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize)
}
else
filterIndex = _lastFilter;
+
if (filterIndex > (UInt32)_filters.Size())
return false;
_lastFilter = filterIndex;
@@ -251,7 +257,7 @@ bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize)
if (newFilter)
{
// check if too many filters
- if (filterIndex > 1024)
+ if (filterIndex > MAX_UNPACK_FILTERS)
return false;
filter = new CFilter;
_filters.Add(filter);
@@ -301,6 +307,8 @@ bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize)
if (initMask & (1 << i))
tempFilter->InitR[i] = inp.ReadEncodedUInt32();
}
+
+ bool isOK = true;
if (newFilter)
{
UInt32 vmCodeSize = inp.ReadEncodedUInt32();
@@ -308,7 +316,7 @@ bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize)
return false;
for (UInt32 i = 0; i < vmCodeSize; i++)
_vmCode[i] = (Byte)inp.ReadBits(8);
- filter->PrepareProgram(_vmCode, vmCodeSize);
+ isOK = filter->PrepareProgram(_vmCode, vmCodeSize);
}
Byte *globalData = &tempFilter->GlobalData[0];
@@ -331,7 +339,8 @@ bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize)
for (UInt32 i = 0; i < dataSize; i++)
dest[i] = (Byte)inp.ReadBits(8);
}
- return true;
+
+ return isOK;
}
bool CDecoder::ReadVmCodeLZ()
@@ -796,6 +805,7 @@ HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
{
_writtenFileSize = 0;
+ _unsupportedFilter = false;
if (!m_IsSolid)
{
_lzSize = 0;
@@ -843,6 +853,10 @@ HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize));
if (_writtenFileSize < _unpackSize)
return S_FALSE;
+
+ if (_unsupportedFilter)
+ return E_NOTIMPL;
+
return S_OK;
}
@@ -892,7 +906,7 @@ STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
{
if (size < 1)
return E_INVALIDARG;
- m_IsSolid = (data[0] != 0);
+ m_IsSolid = ((data[0] & 1) != 0);
return S_OK;
}
diff --git a/CPP/7zip/Compress/Rar3Decoder.h b/CPP/7zip/Compress/Rar3Decoder.h
index 77379858..d8dfd11a 100644
--- a/CPP/7zip/Compress/Rar3Decoder.h
+++ b/CPP/7zip/Compress/Rar3Decoder.h
@@ -194,6 +194,7 @@ class CDecoder:
bool m_IsSolid;
bool _lzMode;
+ bool _unsupportedFilter;
UInt32 PrevAlignBits;
UInt32 PrevAlignCount;
diff --git a/CPP/7zip/Compress/Rar3Vm.cpp b/CPP/7zip/Compress/Rar3Vm.cpp
index 3cbfb0e1..5dca9eab 100644
--- a/CPP/7zip/Compress/Rar3Vm.cpp
+++ b/CPP/7zip/Compress/Rar3Vm.cpp
@@ -12,6 +12,8 @@ Note:
#include "StdAfx.h"
+#include <stdlib.h>
+
#include "../../../C/7zCrc.h"
#include "../../../C/Alloc.h"
@@ -55,6 +57,8 @@ namespace NVm {
static const UInt32 kStackRegIndex = kNumRegs - 1;
+#ifdef RARVM_VM_ENABLE
+
static const UInt32 FLAG_C = 1;
static const UInt32 FLAG_Z = 2;
static const UInt32 FLAG_S = 0x80000000;
@@ -113,11 +117,14 @@ static const Byte kCmdFlags[]=
/* CMD_PRINT */ CF_OP0
};
+#endif
+
+
CVm::CVm(): Mem(NULL) {}
bool CVm::Create()
{
- if (Mem == NULL)
+ if (!Mem)
Mem = (Byte *)::MyAlloc(kSpaceSize + 4);
return (Mem != NULL);
}
@@ -145,12 +152,14 @@ bool CVm::Execute(CProgram *prg, const CProgramInitState *initState,
memcpy(Mem + kGlobalOffset + globalSize, &prg->StaticData[0], staticSize);
bool res = true;
+
#ifdef RARVM_STANDARD_FILTERS
if (prg->StandardFilterIndex >= 0)
ExecuteStandardFilter(prg->StandardFilterIndex);
else
#endif
{
+ #ifdef RARVM_VM_ENABLE
res = ExecuteCode(prg);
if (!res)
{
@@ -158,7 +167,11 @@ bool CVm::Execute(CProgram *prg, const CProgramInitState *initState,
prg->Commands.Add(CCommand());
prg->Commands.Back().OpCode = CMD_RET;
}
+ #else
+ res = false;
+ #endif
}
+
UInt32 newBlockPos = GetFixedGlobalValue32(NGlobalOffset::kBlockPos) & kSpaceMask;
UInt32 newBlockSize = GetFixedGlobalValue32(NGlobalOffset::kBlockSize) & kSpaceMask;
if (newBlockPos + newBlockSize >= kSpaceSize)
@@ -175,9 +188,11 @@ bool CVm::Execute(CProgram *prg, const CProgramInitState *initState,
outGlobalData.ClearAndSetSize(dataSize);
memcpy(&outGlobalData[0], Mem + kGlobalOffset, dataSize);
}
+
return res;
}
+#ifdef RARVM_VM_ENABLE
#define SET_IP(IP) \
if ((IP) >= numCommands) return true; \
@@ -191,7 +206,7 @@ bool CVm::Execute(CProgram *prg, const CProgramInitState *initState,
UInt32 CVm::GetOperand32(const COperand *op) const
{
- switch(op->Type)
+ switch (op->Type)
{
case OP_TYPE_REG: return R[op->Data];
case OP_TYPE_REGMEM: return GetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask]);
@@ -201,7 +216,7 @@ UInt32 CVm::GetOperand32(const COperand *op) const
void CVm::SetOperand32(const COperand *op, UInt32 val)
{
- switch(op->Type)
+ switch (op->Type)
{
case OP_TYPE_REG: R[op->Data] = val; return;
case OP_TYPE_REGMEM: SetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask], val); return;
@@ -210,7 +225,7 @@ void CVm::SetOperand32(const COperand *op, UInt32 val)
Byte CVm::GetOperand8(const COperand *op) const
{
- switch(op->Type)
+ switch (op->Type)
{
case OP_TYPE_REG: return (Byte)R[op->Data];
case OP_TYPE_REGMEM: return Mem[(op->Base + R[op->Data]) & kSpaceMask];;
@@ -220,7 +235,7 @@ Byte CVm::GetOperand8(const COperand *op) const
void CVm::SetOperand8(const COperand *op, Byte val)
{
- switch(op->Type)
+ switch (op->Type)
{
case OP_TYPE_REG: R[op->Data] = (R[op->Data] & 0xFFFFFF00) | val; return;
case OP_TYPE_REGMEM: Mem[(op->Base + R[op->Data]) & kSpaceMask] = val; return;
@@ -253,10 +268,8 @@ bool CVm::ExecuteCode(const CProgram *prg)
for (;;)
{
- switch(cmd->OpCode)
+ switch (cmd->OpCode)
{
- #ifndef RARVM_NO_VM
-
case CMD_MOV:
SetOperand32(&cmd->Op1, GetOperand32(&cmd->Op2));
break;
@@ -619,8 +632,6 @@ bool CVm::ExecuteCode(const CProgram *prg)
}
break;
- #endif
-
case CMD_RET:
{
if (R[kStackRegIndex] >= kSpaceSize)
@@ -638,7 +649,6 @@ bool CVm::ExecuteCode(const CProgram *prg)
}
}
-
//////////////////////////////////////////////////////
// Read program
@@ -682,25 +692,31 @@ void CProgram::ReadProgram(const Byte *code, UInt32 codeSize)
inp.Init(code, codeSize);
StaticData.Clear();
+
if (inp.ReadBit())
{
UInt32 dataSize = inp.ReadEncodedUInt32() + 1;
for (UInt32 i = 0; inp.Avail() && i < dataSize; i++)
StaticData.Add((Byte)inp.ReadBits(8));
}
+
while (inp.Avail())
{
Commands.Add(CCommand());
CCommand *cmd = &Commands.Back();
+
if (inp.ReadBit() == 0)
cmd->OpCode = (ECommand)inp.ReadBits(3);
else
cmd->OpCode = (ECommand)(8 + inp.ReadBits(5));
+
if (kCmdFlags[(unsigned)cmd->OpCode] & CF_BYTEMODE)
cmd->ByteMode = (inp.ReadBit()) ? true : false;
else
cmd->ByteMode = 0;
+
int opNum = (kCmdFlags[(unsigned)cmd->OpCode] & CF_OPMASK);
+
if (opNum > 0)
{
DecodeArg(inp, cmd->Op1, cmd->ByteMode);
@@ -727,6 +743,7 @@ void CProgram::ReadProgram(const Byte *code, UInt32 codeSize)
}
}
}
+
if (cmd->ByteMode)
{
switch (cmd->OpCode)
@@ -751,6 +768,9 @@ void CProgram::ReadProgram(const Byte *code, UInt32 codeSize)
}
}
+#endif
+
+
#ifdef RARVM_STANDARD_FILTERS
enum EStandardFilter
@@ -760,8 +780,8 @@ enum EStandardFilter
SF_ITANIUM,
SF_RGB,
SF_AUDIO,
- SF_DELTA,
- SF_UPCASE
+ SF_DELTA
+ // SF_UPCASE
};
static const struct CStandardFilterSignature
@@ -777,8 +797,8 @@ kStdFilters[]=
{ 120, 0x3769893f, SF_ITANIUM },
{ 29, 0x0e06077d, SF_DELTA },
{ 149, 0x1c2c5dc8, SF_RGB },
- { 216, 0xbc85e701, SF_AUDIO },
- { 40, 0x46b9c560, SF_UPCASE }
+ { 216, 0xbc85e701, SF_AUDIO }
+ // { 40, 0x46b9c560, SF_UPCASE }
};
static int FindStandardFilter(const Byte *code, UInt32 codeSize)
@@ -795,28 +815,48 @@ static int FindStandardFilter(const Byte *code, UInt32 codeSize)
#endif
-void CProgram::PrepareProgram(const Byte *code, UInt32 codeSize)
+
+bool CProgram::PrepareProgram(const Byte *code, UInt32 codeSize)
{
- Byte xorSum = 0;
- for (UInt32 i = 1; i < codeSize; i++)
- xorSum ^= code[i];
+ IsSupported = false;
+ #ifdef RARVM_VM_ENABLE
Commands.Clear();
+ #endif
+
#ifdef RARVM_STANDARD_FILTERS
StandardFilterIndex = -1;
#endif
- if (xorSum == code[0] && codeSize > 0)
+ bool isOK = false;
+
+ Byte xorSum = 0;
+ for (UInt32 i = 0; i < codeSize; i++)
+ xorSum ^= code[i];
+
+ if (xorSum == 0 && codeSize != 0)
{
+ IsSupported = true;
+ isOK = true;
#ifdef RARVM_STANDARD_FILTERS
StandardFilterIndex = FindStandardFilter(code, codeSize);
if (StandardFilterIndex >= 0)
- return;
+ return true;
#endif
+
+ #ifdef RARVM_VM_ENABLE
ReadProgram(code + 1, codeSize - 1);
+ #else
+ IsSupported = false;
+ #endif
}
+
+ #ifdef RARVM_VM_ENABLE
Commands.Add(CCommand());
Commands.Back().OpCode = CMD_RET;
+ #endif
+
+ return isOK;
}
void CVm::SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize)
@@ -833,12 +873,11 @@ static void E8E9Decode(Byte *data, UInt32 dataSize, UInt32 fileOffset, bool e9)
return;
dataSize -= 4;
const UInt32 kFileSize = 0x1000000;
- Byte cmpByte2 = (Byte)(e9 ? 0xE9 : 0xE8);
+ Byte cmpMask = (Byte)(e9 ? 0xFE : 0xFF);
for (UInt32 curPos = 0; curPos < dataSize;)
{
- Byte curByte = *(data++);
curPos++;
- if (curByte == 0xE8 || curByte == cmpByte2)
+ if (((*data++) & cmpMask) == 0xE8)
{
UInt32 offset = curPos + fileOffset;
UInt32 addr = (Int32)GetValue32(data);
@@ -852,9 +891,9 @@ static void E8E9Decode(Byte *data, UInt32 dataSize, UInt32 fileOffset, bool e9)
}
}
-static inline UInt32 ItaniumGetOpType(const Byte *data, int bitPos)
+static inline UInt32 ItaniumGetOpType(const Byte *data, unsigned bitPos)
{
- return (data[(unsigned int)bitPos >> 3] >> (bitPos & 7)) & 0xF;
+ return (data[bitPos >> 3] >> (bitPos & 7)) & 0xF;
}
static const Byte kCmdMasks[16] = {4,4,6,6,0,0,7,7,4,4,0,0,4,4,0,0};
@@ -870,20 +909,20 @@ static void ItaniumDecode(Byte *data, UInt32 dataSize, UInt32 fileOffset)
{
Byte cmdMask = kCmdMasks[b];
if (cmdMask != 0)
- for (int i = 0; i < 3; i++)
+ for (unsigned i = 0; i < 3; i++)
if (cmdMask & (1 << i))
{
- int startPos = i * 41 + 18;
+ unsigned startPos = i * 41 + 18;
if (ItaniumGetOpType(data, startPos + 24) == 5)
{
const UInt32 kMask = 0xFFFFF;
- Byte *p = data + ((unsigned int)startPos >> 3);
+ Byte *p = data + (startPos >> 3);
UInt32 bitField = ((UInt32)p[0]) | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16);
- int inBit = (startPos & 7);
+ unsigned inBit = (startPos & 7);
UInt32 offset = (bitField >> inBit) & kMask;
UInt32 andMask = ~(kMask << inBit);
bitField = ((offset - fileOffset) & kMask) << inBit;
- for (int j = 0; j < 3; j++)
+ for (unsigned j = 0; j < 3; j++)
{
p[j] &= andMask;
p[j] |= bitField;
@@ -1016,6 +1055,7 @@ static void AudioDecode(Byte *srcData, UInt32 dataSize, UInt32 numChannels)
}
}
+/*
static UInt32 UpCaseDecode(Byte *data, UInt32 dataSize)
{
UInt32 srcPos = 0, destPos = dataSize;
@@ -1028,6 +1068,7 @@ static UInt32 UpCaseDecode(Byte *data, UInt32 dataSize)
}
return destPos - dataSize;
}
+*/
void CVm::ExecuteStandardFilter(unsigned filterIndex)
{
@@ -1068,6 +1109,7 @@ void CVm::ExecuteStandardFilter(unsigned filterIndex)
SetBlockPos(dataSize);
AudioDecode(Mem, dataSize, R[0]);
break;
+ /*
case SF_UPCASE:
if (dataSize >= kGlobalOffset / 2)
break;
@@ -1075,6 +1117,7 @@ void CVm::ExecuteStandardFilter(unsigned filterIndex)
SetBlockSize(destSize);
SetBlockPos(dataSize);
break;
+ */
}
}
diff --git a/CPP/7zip/Compress/Rar3Vm.h b/CPP/7zip/Compress/Rar3Vm.h
index 23f4abab..4272c93e 100644
--- a/CPP/7zip/Compress/Rar3Vm.h
+++ b/CPP/7zip/Compress/Rar3Vm.h
@@ -7,10 +7,10 @@
#include "../../../C/CpuArch.h"
-#include "../../Common/MyTypes.h"
#include "../../Common/MyVector.h"
#define RARVM_STANDARD_FILTERS
+// #define RARVM_VM_ENABLE
namespace NCompress {
namespace NRar3 {
@@ -39,12 +39,12 @@ namespace NVm {
inline UInt32 GetValue32(const void *addr) { return GetUi32(addr); }
inline void SetValue32(void *addr, UInt32 value) { SetUi32(addr, value); }
-const int kNumRegBits = 3;
+const unsigned kNumRegBits = 3;
const UInt32 kNumRegs = 1 << kNumRegBits;
const UInt32 kNumGpRegs = kNumRegs - 1;
const UInt32 kSpaceSize = 0x40000;
-const UInt32 kSpaceMask = kSpaceSize -1;
+const UInt32 kSpaceMask = kSpaceSize - 1;
const UInt32 kGlobalOffset = 0x3C000;
const UInt32 kGlobalSize = 0x2000;
const UInt32 kFixedGlobalSize = 64;
@@ -57,6 +57,9 @@ namespace NGlobalOffset
const UInt32 kGlobalMemOutSize = 0x30;
}
+
+#ifdef RARVM_VM_ENABLE
+
enum ECommand
{
CMD_MOV, CMD_CMP, CMD_ADD, CMD_SUB, CMD_JZ, CMD_JNZ, CMD_INC, CMD_DEC,
@@ -89,27 +92,36 @@ struct CCommand
COperand Op1, Op2;
};
+#endif
+
+
struct CBlockRef
{
UInt32 Offset;
UInt32 Size;
};
+
class CProgram
{
+ #ifdef RARVM_VM_ENABLE
+ void ReadProgram(const Byte *code, UInt32 codeSize);
public:
CRecordVector<CCommand> Commands;
+ #endif
+
+public:
#ifdef RARVM_STANDARD_FILTERS
int StandardFilterIndex;
#endif
+
+ bool IsSupported;
CRecordVector<Byte> StaticData;
-private:
- void ReadProgram(const Byte *code, UInt32 codeSize);
-public:
- void PrepareProgram(const Byte *code, UInt32 codeSize);
+ bool PrepareProgram(const Byte *code, UInt32 codeSize);
};
+
struct CProgramInitState
{
UInt32 InitR[kNumGpRegs];
@@ -122,6 +134,7 @@ struct CProgramInitState
}
};
+
class CVm
{
static UInt32 GetValue(bool byteMode, const void *addr)
@@ -146,15 +159,18 @@ class CVm
void SetBlockPos(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockPos], v); }
public:
static void SetValue(void *addr, UInt32 value) { SetValue(false, addr, value); }
+
private:
+
+ #ifdef RARVM_VM_ENABLE
UInt32 GetOperand32(const COperand *op) const;
void SetOperand32(const COperand *op, UInt32 val);
Byte GetOperand8(const COperand *op) const;
void SetOperand8(const COperand *op, Byte val);
UInt32 GetOperand(bool byteMode, const COperand *op) const;
void SetOperand(bool byteMode, const COperand *op, UInt32 val);
-
bool ExecuteCode(const CProgram *prg);
+ #endif
#ifdef RARVM_STANDARD_FILTERS
void ExecuteStandardFilter(unsigned filterIndex);
@@ -163,6 +179,7 @@ private:
Byte *Mem;
UInt32 R[kNumRegs + 1]; // R[kNumRegs] = 0 always (speed optimization)
UInt32 Flags;
+
public:
CVm();
~CVm();
@@ -171,7 +188,6 @@ public:
bool Execute(CProgram *prg, const CProgramInitState *initState,
CBlockRef &outBlockRef, CRecordVector<Byte> &outGlobalData);
const Byte *GetDataPointer(UInt32 offset) const { return Mem + offset; }
-
};
#endif
diff --git a/CPP/7zip/Compress/Rar5Decoder.cpp b/CPP/7zip/Compress/Rar5Decoder.cpp
new file mode 100644
index 00000000..9e3ff3e4
--- /dev/null
+++ b/CPP/7zip/Compress/Rar5Decoder.cpp
@@ -0,0 +1,960 @@
+// Rar5Decoder.cpp
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../Common/StreamUtils.h"
+
+#include "Rar5Decoder.h"
+
+namespace NCompress {
+namespace NRar5 {
+
+static const size_t kInputBufSize = 1 << 20;
+
+void CBitDecoder::Prepare2() throw()
+{
+ const unsigned kSize = 16;
+ if (_buf > _bufLim)
+ return;
+
+ size_t rem = _bufLim - _buf;
+ if (rem != 0)
+ memcpy(_bufBase, _buf, rem);
+
+ _bufLim = _bufBase + rem;
+ _processedSize += (_buf - _bufBase);
+ _buf = _bufBase;
+
+ if (!_wasFinished)
+ {
+ UInt32 processed = (UInt32)(kInputBufSize - rem);
+ _hres = _stream->Read(_bufLim, (UInt32)processed, &processed);
+ _bufLim += processed;
+ _wasFinished = (processed == 0);
+ if (_hres != S_OK)
+ {
+ _wasFinished = true;
+ // throw CInBufferException(result);
+ }
+ }
+
+ rem = _bufLim - _buf;
+ _bufCheck = _buf;
+ if (rem < kSize)
+ memset(_bufLim, 0xFF, kSize - rem);
+ else
+ _bufCheck = _bufLim - kSize;
+
+ SetCheck2();
+}
+
+
+enum FilterType
+{
+ FILTER_DELTA = 0,
+ FILTER_E8,
+ FILTER_E8E9,
+ FILTER_ARM
+};
+
+static const size_t kWriteStep = (size_t)1 << 22;
+
+CDecoder::CDecoder():
+ _window(NULL),
+ _winPos(0),
+ _winSizeAllocated(0),
+ _lzSize(0),
+ _lzEnd(0),
+ _writtenFileSize(0),
+ _dictSizeLog(0),
+ _isSolid(false),
+ _wasInit(false),
+ _inputBuf(NULL)
+{
+}
+
+CDecoder::~CDecoder()
+{
+ ::MidFree(_window);
+ ::MidFree(_inputBuf);
+}
+
+HRESULT CDecoder::WriteData(const Byte *data, size_t size)
+{
+ HRESULT res = S_OK;
+ if (!_unpackSize_Defined || _writtenFileSize < _unpackSize)
+ {
+ size_t cur = size;
+ if (_unpackSize_Defined)
+ {
+ UInt64 rem = _unpackSize - _writtenFileSize;
+ if (cur > rem)
+ cur = (size_t)rem;
+ }
+ res = WriteStream(_outStream, data, cur);
+ if (res != S_OK)
+ _writeError = true;
+ }
+ _writtenFileSize += size;
+ return res;
+}
+
+HRESULT CDecoder::ExecuteFilter(const CFilter &f)
+{
+ bool useDest = false;
+
+ Byte *data = _filterSrc;
+ UInt32 dataSize = f.Size;
+
+ // printf("\nType = %d offset = %9d size = %5d", f.Type, (unsigned)(f.Start - _lzFileStart), dataSize);
+
+ switch (f.Type)
+ {
+ case FILTER_E8:
+ case FILTER_E8E9:
+ {
+ // printf(" FILTER_E8");
+ if (dataSize > 4)
+ {
+ dataSize -= 4;
+ UInt32 fileOffset = (UInt32)(f.Start - _lzFileStart);
+
+ const UInt32 kFileSize = (UInt32)1 << 24;
+ Byte cmpMask = (Byte)(f.Type == FILTER_E8 ? 0xFF : 0xFE);
+
+ for (UInt32 curPos = 0; curPos < dataSize;)
+ {
+ curPos++;
+ if (((*data++) & cmpMask) == 0xE8)
+ {
+ UInt32 offset = (curPos + fileOffset) & (kFileSize - 1);
+ UInt32 addr = GetUi32(data);
+
+ if (addr < kFileSize)
+ {
+ SetUi32(data, addr - offset);
+ }
+ else if (addr > ((UInt32)0xFFFFFFFF - offset)) // (addr > ~(offset))
+ {
+ SetUi32(data, addr + kFileSize);
+ }
+
+ data += 4;
+ curPos += 4;
+ }
+ }
+ }
+ break;
+ }
+
+ case FILTER_ARM:
+ {
+ if (dataSize >= 4)
+ {
+ dataSize -= 4;
+ UInt32 fileOffset = (UInt32)(f.Start - _lzFileStart);
+
+ for (UInt32 curPos = 0; curPos <= dataSize; curPos += 4)
+ {
+ Byte *d = data + curPos;
+ if (d[3] == 0xEB)
+ {
+ UInt32 offset = d[0] | ((UInt32)d[1] << 8) | ((UInt32)d[2] << 16);
+ offset -= (fileOffset + curPos) >> 2;
+ d[0] = (Byte)offset;
+ d[1] = (Byte)(offset >> 8);
+ d[2] = (Byte)(offset >> 16);
+ }
+ }
+ }
+ break;
+ }
+
+ case FILTER_DELTA:
+ {
+ // printf(" channels = %d", f.Channels);
+ _filterDst.AllocAtLeast(dataSize);
+ if (!_filterDst.IsAllocated())
+ return E_OUTOFMEMORY;
+
+ Byte *dest = _filterDst;
+ UInt32 numChannels = f.Channels;
+
+ for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
+ {
+ Byte prevByte = 0;
+ for (UInt32 destPos = curChannel; destPos < dataSize; destPos += numChannels)
+ dest[destPos] = (prevByte = (Byte)(prevByte - *data++));
+ }
+ useDest = true;
+ break;
+ }
+
+ default:
+ _unsupportedFilter = true;
+ }
+
+ return WriteData(useDest ?
+ (const Byte *)_filterDst :
+ (const Byte *)_filterSrc,
+ f.Size);
+}
+
+
+HRESULT CDecoder::WriteBuf()
+{
+ DeleteUnusedFilters();
+
+ for (unsigned i = 0; i < _filters.Size();)
+ {
+ const CFilter &f = _filters[i];
+
+ UInt64 blockStart = f.Start;
+
+ size_t lzAvail = (size_t)(_lzSize - _lzWritten);
+ if (lzAvail == 0)
+ break;
+
+ if (blockStart > _lzWritten)
+ {
+ UInt64 rem = blockStart - _lzWritten;
+ size_t size = lzAvail;
+ if (size > rem)
+ size = (size_t)rem;
+ if (size != 0)
+ {
+ RINOK(WriteData(_window + _winPos - lzAvail, size));
+ _lzWritten += size;
+ }
+ continue;
+ }
+
+ UInt32 blockSize = f.Size;
+ size_t offset = (size_t)(_lzWritten - blockStart);
+ if (offset == 0)
+ {
+ _filterSrc.AllocAtLeast(blockSize);
+ if (!_filterSrc.IsAllocated())
+ return E_OUTOFMEMORY;
+ }
+
+ size_t blockRem = (size_t)blockSize - offset;
+ size_t size = lzAvail;
+ if (size > blockRem)
+ size = blockRem;
+ memcpy(_filterSrc + offset, _window + _winPos - lzAvail, size);
+ _lzWritten += size;
+ offset += size;
+ if (offset != blockSize)
+ return S_OK;
+
+ _numUnusedFilters = ++i;
+ RINOK(ExecuteFilter(f));
+ }
+
+ DeleteUnusedFilters();
+
+ if (!_filters.IsEmpty())
+ return S_OK;
+
+ size_t lzAvail = (size_t)(_lzSize - _lzWritten);
+ RINOK(WriteData(_window + _winPos - lzAvail, lzAvail));
+ _lzWritten += lzAvail;
+ return S_OK;
+}
+
+
+static UInt32 ReadUInt32(CBitDecoder &bi)
+{
+ unsigned numBytes = bi.ReadBits9fix(2) + 1;
+ UInt32 v = 0;
+ for (unsigned i = 0; i < numBytes; i++)
+ v += ((UInt32)bi.ReadBits9fix(8) << (i * 8));
+ return v;
+}
+
+
+static const unsigned MAX_UNPACK_FILTERS = 8192;
+
+HRESULT CDecoder::AddFilter(CBitDecoder &_bitStream)
+{
+ DeleteUnusedFilters();
+
+ if (_filters.Size() >= MAX_UNPACK_FILTERS)
+ {
+ RINOK(WriteBuf());
+ DeleteUnusedFilters();
+ if (_filters.Size() >= MAX_UNPACK_FILTERS)
+ {
+ _unsupportedFilter = true;
+ InitFilters();
+ }
+ }
+
+ _bitStream.Prepare();
+
+ CFilter f;
+ UInt32 blockStart = ReadUInt32(_bitStream);
+ f.Size = ReadUInt32(_bitStream);
+
+ // if (f.Size > ((UInt32)1 << 16)) _unsupportedFilter = true;
+
+ f.Type = (Byte)_bitStream.ReadBits9fix(3);
+ if (f.Type == FILTER_DELTA)
+ f.Channels = (Byte)(_bitStream.ReadBits9fix(5) + 1);
+ f.Start = _lzSize + blockStart;
+
+ if (f.Start < _filterEnd)
+ _unsupportedFilter = true;
+ else
+ {
+ _filterEnd = f.Start + f.Size;
+ if (f.Size != 0)
+ _filters.Add(f);
+ }
+
+ return S_OK;
+}
+
+
+#define RIF(x) { if (!(x)) return S_FALSE; }
+
+HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream)
+{
+ if (_progress)
+ {
+ UInt64 packSize = _bitStream.GetProcessedSize();
+ RINOK(_progress->SetRatioInfo(&packSize, &_writtenFileSize));
+ }
+
+ _bitStream.AlignToByte();
+ _bitStream.Prepare();
+
+ unsigned flags = _bitStream.ReadByteInAligned();
+ unsigned checkSum = _bitStream.ReadByteInAligned();
+ checkSum ^= flags;
+
+ UInt32 blockSize;
+ {
+ unsigned num = (flags >> 3) & 3;
+ if (num == 3)
+ return S_FALSE;
+ blockSize = _bitStream.ReadByteInAligned();
+ if (num > 0)
+ {
+ blockSize += (UInt32)_bitStream.ReadByteInAligned() << 8;
+ if (num > 1)
+ blockSize += (UInt32)_bitStream.ReadByteInAligned() << 16;
+ }
+ }
+
+ checkSum ^= blockSize ^ (blockSize >> 8) ^ (blockSize >> 16);
+ if ((Byte)checkSum != 0x5A)
+ return S_FALSE;
+
+ unsigned blockSizeBits7 = (flags & 7) + 1;
+
+ if (blockSize == 0 && blockSizeBits7 != 8)
+ return S_FALSE;
+
+ blockSize += (blockSizeBits7 >> 3);
+ blockSize--;
+
+ _bitStream._blockEndBits7 = (Byte)(blockSizeBits7 & 7);
+ _bitStream._blockEnd = _bitStream.GetProcessedSize_Round() + blockSize;
+
+ _bitStream.SetCheck2();
+
+ _isLastBlock = ((flags & 0x40) != 0);
+
+ if ((flags & 0x80) == 0)
+ {
+ if (!_tableWasFilled && blockSize != 0)
+ return S_FALSE;
+ return S_OK;
+ }
+
+ _tableWasFilled = false;
+
+ {
+ Byte lens2[kLevelTableSize];
+
+ for (unsigned i = 0; i < kLevelTableSize;)
+ {
+ _bitStream.Prepare();
+ unsigned len = (unsigned)_bitStream.ReadBits9fix(4);
+ if (len == 15)
+ {
+ unsigned num = (unsigned)_bitStream.ReadBits9fix(4);
+ if (num != 0)
+ {
+ num += 2;
+ num += i;
+ if (num > kLevelTableSize)
+ num = kLevelTableSize;
+ do
+ lens2[i++] = 0;
+ while (i < num);
+ continue;
+ }
+ }
+ lens2[i++] = (Byte)len;
+ }
+
+ if (_bitStream.IsBlockOverRead())
+ return S_FALSE;
+
+ RIF(m_LevelDecoder.SetCodeLengths(lens2));
+ }
+
+ Byte lens[kTablesSizesSum];
+ unsigned i = 0;
+
+ while (i < kTablesSizesSum)
+ {
+ if (_bitStream._buf >= _bitStream._bufCheck2)
+ {
+ if (_bitStream._buf >= _bitStream._bufCheck)
+ _bitStream.Prepare();
+ if (_bitStream.IsBlockOverRead())
+ return S_FALSE;
+ }
+
+ UInt32 sym = m_LevelDecoder.DecodeSymbol(&_bitStream);
+
+ if (sym < 16)
+ lens[i++] = (Byte)sym;
+ else if (sym > kLevelTableSize)
+ return S_FALSE;
+ else
+ {
+ sym -= 16;
+ unsigned sh = ((sym & 1) << 2);
+ unsigned num = (unsigned)_bitStream.ReadBits9(3 + sh) + 3 + (sh << 1);
+
+ num += i;
+ if (num > kTablesSizesSum)
+ num = kTablesSizesSum;
+
+ if (sym < 2)
+ {
+ if (i == 0)
+ {
+ // return S_FALSE;
+ continue; // original unRAR
+ }
+ Byte v = lens[i - 1];
+ do
+ lens[i++] = v;
+ while (i < num);
+ }
+ else
+ {
+ do
+ lens[i++] = 0;
+ while (i < num);
+ }
+ }
+ }
+
+ if (_bitStream.IsBlockOverRead())
+ return S_FALSE;
+ if (_bitStream.InputEofError())
+ return S_FALSE;
+
+ RIF(m_MainDecoder.SetCodeLengths(&lens[0]));
+ RIF(m_DistDecoder.SetCodeLengths(&lens[kMainTableSize]));
+ RIF(m_AlignDecoder.SetCodeLengths(&lens[kMainTableSize + kDistTableSize]));
+ RIF(m_LenDecoder.SetCodeLengths(&lens[kMainTableSize + kDistTableSize + kAlignTableSize]));
+
+ _useAlignBits = false;
+ // _useAlignBits = true;
+ for (i = 0; i < kAlignTableSize; i++)
+ if (lens[kMainTableSize + kDistTableSize + i] != kNumAlignBits)
+ {
+ _useAlignBits = true;
+ break;
+ }
+
+ _tableWasFilled = true;
+ return S_OK;
+}
+
+
+static inline unsigned SlotToLen(CBitDecoder &_bitStream, unsigned slot)
+{
+ if (slot < 8)
+ return slot + 2;
+ unsigned numBits = (slot >> 2) - 1;
+ return 2 + ((4 | (slot & 3)) << numBits) + _bitStream.ReadBits9(numBits);
+}
+
+
+static const UInt32 kSymbolRep = 258;
+// static const unsigned kMaxMatchLen = 0x1001 + 3;
+
+HRESULT CDecoder::DecodeLZ()
+{
+ CBitDecoder _bitStream;
+ _bitStream._stream = _inStream;
+ _bitStream._bufBase = _inputBuf;
+ _bitStream.Init();
+
+ UInt32 rep0 = _reps[0];
+
+ UInt32 remLen = 0;
+
+ size_t limit;
+ {
+ size_t rem = _winSize - _winPos;
+ if (rem > kWriteStep)
+ rem = kWriteStep;
+ limit = _winPos + rem;
+ }
+
+ for (;;)
+ {
+ if (_winPos >= limit)
+ {
+ RINOK(WriteBuf());
+ if (_unpackSize_Defined && _writtenFileSize > _unpackSize)
+ break; // return S_FALSE;
+
+ {
+ size_t rem = _winSize - _winPos;
+
+ if (rem == 0)
+ {
+ _winPos = 0;
+ rem = _winSize;
+ }
+ if (rem > kWriteStep)
+ rem = kWriteStep;
+ limit = _winPos + rem;
+ }
+
+ if (remLen != 0)
+ {
+ size_t winPos = _winPos;
+ size_t winMask = _winMask;
+ size_t pos = (winPos - (size_t)rep0 - 1) & winMask;
+
+ Byte *win = _window;
+ do
+ {
+ if (winPos >= limit)
+ break;
+ win[winPos] = win[pos];
+ winPos++;
+ pos = (pos + 1) & winMask;
+ }
+ while (--remLen != 0);
+
+ _lzSize += winPos - _winPos;
+ _winPos = winPos;
+ continue;
+ }
+ }
+
+ if (_bitStream._buf >= _bitStream._bufCheck2)
+ {
+ if (_bitStream.InputEofError())
+ break; // return S_FALSE;
+ if (_bitStream._buf >= _bitStream._bufCheck)
+ _bitStream.Prepare2();
+
+ UInt64 processed = _bitStream.GetProcessedSize_Round();
+ if (processed >= _bitStream._blockEnd)
+ {
+ if (processed > _bitStream._blockEnd)
+ break; // return S_FALSE;
+ {
+ unsigned bits7 = _bitStream.GetProcessedBits7();
+ if (bits7 > _bitStream._blockEndBits7)
+ break; // return S_FALSE;
+ if (bits7 == _bitStream._blockEndBits7)
+ {
+ if (_isLastBlock)
+ {
+ _reps[0] = rep0;
+
+ if (_bitStream.InputEofError())
+ break;
+
+ /*
+ // packSize can be 15 bytes larger for encrypted archive
+ if (_packSize_Defined && _packSize < _bitStream.GetProcessedSize())
+ break;
+ */
+
+ return _bitStream._hres;
+ // break;
+ }
+ RINOK(ReadTables(_bitStream));
+ continue;
+ }
+ }
+ }
+ }
+
+ UInt32 sym = m_MainDecoder.DecodeSymbol(&_bitStream);
+
+ if (sym < 256)
+ {
+ size_t winPos = _winPos;
+ _window[winPos] = (Byte)sym;
+ _winPos = winPos + 1;
+ _lzSize++;
+ continue;
+ }
+
+ UInt32 len;
+
+ if (sym < kSymbolRep + kNumReps)
+ {
+ if (sym >= kSymbolRep)
+ {
+ if (sym != kSymbolRep)
+ {
+ UInt32 dist;
+ if (sym == kSymbolRep + 1)
+ dist = _reps[1];
+ else
+ {
+ if (sym == kSymbolRep + 2)
+ dist = _reps[2];
+ else
+ {
+ dist = _reps[3];
+ _reps[3] = _reps[2];
+ }
+ _reps[2] = _reps[1];
+ }
+ _reps[1] = rep0;
+ rep0 = dist;
+ }
+
+ UInt32 sym = m_LenDecoder.DecodeSymbol(&_bitStream);
+ if (sym >= kLenTableSize)
+ break; // return S_FALSE;
+ len = SlotToLen(_bitStream, sym);
+ }
+ else
+ {
+ if (sym == 256)
+ {
+ RINOK(AddFilter(_bitStream));
+ continue;
+ }
+ else // if (sym == 257)
+ {
+ len = _lastLen;
+ // if (len = 0), we ignore that symbol, like original unRAR code, but it can mean error in stream.
+ // if (len == 0) return S_FALSE;
+ if (len == 0)
+ continue;
+ }
+ }
+ }
+ else if (sym >= kMainTableSize)
+ break; // return S_FALSE;
+ else
+ {
+ _reps[3] = _reps[2];
+ _reps[2] = _reps[1];
+ _reps[1] = rep0;
+ len = SlotToLen(_bitStream, sym - (kSymbolRep + kNumReps));
+
+ rep0 = m_DistDecoder.DecodeSymbol(&_bitStream);
+
+ if (rep0 >= 4)
+ {
+ if (rep0 >= _numCorrectDistSymbols)
+ break; // return S_FALSE;
+ unsigned numBits = (rep0 >> 1) - 1;
+ rep0 = (2 | (rep0 & 1)) << numBits;
+
+ if (numBits < kNumAlignBits)
+ rep0 += _bitStream.ReadBits9(numBits);
+ else
+ {
+ len += (numBits >= 7);
+ len += (numBits >= 12);
+ len += (numBits >= 17);
+
+ if (_useAlignBits)
+ {
+ // if (numBits > kNumAlignBits)
+ rep0 += (_bitStream.ReadBits32(numBits - kNumAlignBits) << kNumAlignBits);
+ UInt32 a = m_AlignDecoder.DecodeSymbol(&_bitStream);
+ if (a >= kAlignTableSize)
+ break; // return S_FALSE;
+ rep0 += a;
+ }
+ else
+ rep0 += _bitStream.ReadBits32(numBits);
+ }
+ }
+ }
+
+ _lastLen = len;
+
+ if (rep0 >= _lzSize)
+ _lzError = true;
+
+ {
+ UInt32 lenCur = len;
+ size_t winPos = _winPos;
+ size_t pos = (winPos - (size_t)rep0 - 1) & _winMask;
+ {
+ size_t rem = limit - winPos;
+ // size_t rem = _winSize - winPos;
+
+ if (lenCur > rem)
+ {
+ lenCur = (UInt32)rem;
+ remLen = len - lenCur;
+ }
+ }
+
+ Byte *win = _window;
+ _lzSize += lenCur;
+ _winPos = winPos + lenCur;
+ if (_winSize - pos >= lenCur)
+ {
+ const Byte *src = win + pos;
+ Byte *dest = win + winPos;
+ do
+ *dest++ = *src++;
+ while (--lenCur != 0);
+ }
+ else
+ {
+ do
+ {
+ win[winPos] = win[pos];
+ winPos++;
+ pos = (pos + 1) & _winMask;
+ }
+ while (--lenCur != 0);
+ }
+ }
+ }
+
+ if (_bitStream._hres != S_OK)
+ return _bitStream._hres;
+
+ return S_FALSE;
+}
+
+
+HRESULT CDecoder::CodeReal()
+{
+ _unsupportedFilter = false;
+ _lzError = false;
+ _writeError = false;
+
+ if (!_isSolid || !_wasInit)
+ {
+ size_t clearSize = _winSize;
+ if (_lzSize < _winSize)
+ clearSize = (size_t)_lzSize;
+ memset(_window, 0, clearSize);
+
+ _wasInit = true;
+ _lzSize = 0;
+ _lzWritten = 0;
+ _winPos = 0;
+
+ for (unsigned i = 0; i < kNumReps; i++)
+ _reps[i] = (UInt32)0 - 1;
+
+ _lastLen = 0;
+ _tableWasFilled = false;
+ }
+
+ _isLastBlock = false;
+
+ InitFilters();
+
+ _filterEnd = 0;
+ _writtenFileSize = 0;
+
+ _lzFileStart = _lzSize;
+ _lzWritten = _lzSize;
+
+ HRESULT res = DecodeLZ();
+
+ HRESULT res2 = S_OK;
+ if (!_writeError && res != E_OUTOFMEMORY)
+ res2 = WriteBuf();
+
+ /*
+ if (res == S_OK)
+ if (InputEofError())
+ res = S_FALSE;
+ */
+
+ if (res == S_OK)
+ res = res2;
+
+ if (res == S_OK && _unpackSize_Defined && _writtenFileSize != _unpackSize)
+ return S_FALSE;
+ return res;
+}
+
+
+// Original unRAR claims that maximum possible filter block size is (1 << 16) now,
+// and (1 << 17) is minimum win size required to support filter.
+// Original unRAR uses (1 << 18) for "extra safety and possible filter area size expansion"
+// We can use any win size.
+
+static const unsigned kWinSize_Log_Min = 17;
+
+STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try
+ {
+ if (_dictSizeLog >= sizeof(size_t) * 8)
+ return E_NOTIMPL;
+
+ if (!_isSolid)
+ _lzEnd = 0;
+ else
+ {
+ if (_lzSize < _lzEnd)
+ {
+ if (_window)
+ {
+ UInt64 rem = _lzEnd - _lzSize;
+ if (rem >= _winSize)
+ memset(_window, 0, _winSize);
+ else
+ {
+ size_t pos = (size_t)_lzSize & _winSize;
+ size_t rem2 = _winSize - pos;
+ if (rem2 > rem)
+ rem2 = (size_t)rem;
+ memset(_window + pos, 0, rem2);
+ rem -= rem2;
+ memset(_window, 0, (size_t)rem);
+ }
+ }
+ _lzEnd &= ((((UInt64)1) << 33) - 1);
+ _lzSize = _lzEnd;
+ _winPos = (size_t)(_lzSize & _winSize);
+ }
+ _lzEnd = _lzSize;
+ }
+
+ size_t newSize;
+ {
+ unsigned newSizeLog = _dictSizeLog;
+ if (newSizeLog < kWinSize_Log_Min)
+ newSizeLog = kWinSize_Log_Min;
+ newSize = (size_t)1 << newSizeLog;
+ _numCorrectDistSymbols = newSizeLog * 2;
+ }
+
+ if (!_window || _winSize != newSize)
+ {
+ if (!_isSolid && newSize > _winSizeAllocated)
+ {
+ ::MidFree(_window);
+ _window = NULL;
+ _winSizeAllocated = 0;
+ }
+
+ Byte *win = _window;
+ if (!_window || newSize > _winSizeAllocated)
+ {
+ win = (Byte *)::MidAlloc(newSize);
+ if (!win)
+ return E_OUTOFMEMORY;
+ _winSizeAllocated = newSize;
+ memset(win, 0, newSize);
+ }
+
+ if (_isSolid && _window)
+ {
+ // original unRAR claims:
+ // "Archiving code guarantees that win size does not grow in the same solid stream",
+ // but the original unRAR decoder still supports such grow case.
+
+ Byte *winOld = _window;
+ size_t oldSize = _winSize;
+ size_t newMask = newSize - 1;
+ size_t oldMask = _winSize - 1;
+ size_t winPos = _winPos;
+ for (size_t i = 1; i < oldSize; i++) // i < oldSize) ?
+ win[(winPos - i) & newMask] = winOld[(winPos - i) & oldMask];
+ ::MidFree(_window);
+ }
+
+ _window = win;
+ _winSize = newSize;
+ }
+
+ _winMask = _winSize - 1;
+
+ if (!_inputBuf)
+ {
+ _inputBuf = (Byte *)::MidAlloc(kInputBufSize);
+ if (!_inputBuf)
+ return E_OUTOFMEMORY;
+ }
+
+ _inStream = inStream;
+ _outStream = outStream;
+
+ /*
+ _packSize = 0;
+ _packSize_Defined = (inSize != NULL);
+ if (_packSize_Defined)
+ _packSize = *inSize;
+ */
+
+ _unpackSize = 0;
+ _unpackSize_Defined = (outSize != NULL);
+ if (_unpackSize_Defined)
+ _unpackSize = *outSize;
+
+ if ((Int64)_unpackSize >= 0)
+ _lzEnd += _unpackSize;
+ else
+ _lzEnd = 0;
+
+ _progress = progress;
+
+ HRESULT res = CodeReal();
+
+ if (res != S_OK)
+ return res;
+ if (_lzError)
+ return S_FALSE;
+ if (_unsupportedFilter)
+ return E_NOTIMPL;
+ return S_OK;
+ }
+ // catch(const CInBufferException &e) { return e.ErrorCode; }
+ // catch(...) { return S_FALSE; }
+ catch(...) { return E_OUTOFMEMORY; }
+ // CNewException is possible here. But probably CNewException is caused
+ // by error in data stream.
+}
+
+STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ if (size != 2)
+ return E_NOTIMPL;
+ _dictSizeLog = (Byte)((data[0] & 0xF) + 17);
+ _isSolid = ((data[1] & 1) != 0);
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Compress/Rar5Decoder.h b/CPP/7zip/Compress/Rar5Decoder.h
new file mode 100644
index 00000000..b0a4dd12
--- /dev/null
+++ b/CPP/7zip/Compress/Rar5Decoder.h
@@ -0,0 +1,335 @@
+// Rar5Decoder.h
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#ifndef __COMPRESS_RAR5_DECODER_H
+#define __COMPRESS_RAR5_DECODER_H
+
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyCom.h"
+#include "../../Common/MyException.h"
+#include "../../Common/MyVector.h"
+
+#include "../ICoder.h"
+
+#include "HuffmanDecoder.h"
+
+namespace NCompress {
+namespace NRar5 {
+
+class CMidBuffer
+{
+ Byte *_data;
+ size_t _size;
+
+ CLASS_NO_COPY(CMidBuffer)
+
+public:
+ CMidBuffer(): _data(NULL), _size(0) {};
+ ~CMidBuffer() { ::MidFree(_data); }
+
+ bool IsAllocated() const { return _data != NULL; }
+ operator Byte *() { return _data; }
+ operator const Byte *() const { return _data; }
+ size_t Size() const { return _size; }
+
+ void AllocAtLeast(size_t size)
+ {
+ if (size > _size)
+ {
+ const size_t kMinSize = (1 << 16);
+ if (size < kMinSize)
+ size = kMinSize;
+ ::MidFree(_data);
+ _data = (Byte *)::MidAlloc(size);
+ _size = size;
+ }
+ }
+};
+
+/*
+struct CInBufferException: public CSystemException
+{
+ CInBufferException(HRESULT errorCode): CSystemException(errorCode) {}
+};
+*/
+
+class CBitDecoder
+{
+public:
+ const Byte *_buf;
+ unsigned _bitPos;
+ bool _wasFinished;
+ Byte _blockEndBits7;
+ const Byte *_bufCheck2;
+ const Byte *_bufCheck;
+ Byte *_bufLim;
+ Byte *_bufBase;
+
+ UInt64 _processedSize;
+ UInt64 _blockEnd;
+
+ ISequentialInStream *_stream;
+ HRESULT _hres;
+
+ void SetCheck2()
+ {
+ _bufCheck2 = _bufCheck;
+ if (_bufCheck > _buf)
+ {
+ UInt64 processed = GetProcessedSize_Round();
+ if (_blockEnd < processed)
+ _bufCheck2 = _buf;
+ else
+ {
+ UInt64 delta = _blockEnd - processed;
+ if ((size_t)(_bufCheck - _buf) > delta)
+ _bufCheck2 = _buf + (size_t)delta;
+ }
+ }
+ }
+
+ bool IsBlockOverRead() const
+ {
+ UInt64 v = GetProcessedSize_Round();
+ if (v < _blockEnd)
+ return false;
+ if (v > _blockEnd)
+ return true;
+ return _bitPos > _blockEndBits7;
+ }
+
+ /*
+ CBitDecoder() throw():
+ _buf(0),
+ _bufLim(0),
+ _bufBase(0),
+ _stream(0),
+ _processedSize(0),
+ _wasFinished(false)
+ {}
+ */
+
+ void Init() throw()
+ {
+ _blockEnd = 0;
+ _blockEndBits7 = 0;
+
+ _bitPos = 0;
+ _processedSize = 0;
+ _buf = _bufBase;
+ _bufLim = _bufBase;
+ _bufCheck = _buf;
+ _bufCheck2 = _buf;
+ _wasFinished = false;
+ }
+
+ void Prepare2() throw();
+
+ void Prepare() throw()
+ {
+ if (_buf >= _bufCheck)
+ Prepare2();
+ }
+
+ bool ExtraBitsWereRead() const
+ {
+ return _buf >= _bufLim && (_buf > _bufLim || _bitPos != 0);
+ }
+
+ bool InputEofError() const { return ExtraBitsWereRead(); }
+
+ unsigned GetProcessedBits7() const { return _bitPos; }
+ UInt64 GetProcessedSize_Round() const { return _processedSize + (_buf - _bufBase); }
+ UInt64 GetProcessedSize() const { return _processedSize + (_buf - _bufBase) + ((_bitPos + 7) >> 3); }
+
+ void AlignToByte()
+ {
+ _buf += (_bitPos + 7) >> 3;
+ _bitPos = 0;
+ }
+
+ Byte ReadByteInAligned()
+ {
+ return *_buf++;
+ }
+
+ UInt32 GetValue(unsigned numBits)
+ {
+ UInt32 v = ((UInt32)_buf[0] << 16) | ((UInt32)_buf[1] << 8) | (UInt32)_buf[2];
+ v >>= (24 - numBits - _bitPos);
+ return v & ((1 << numBits) - 1);
+ }
+
+ void MovePos(unsigned numBits)
+ {
+ _bitPos += numBits;
+ _buf += (_bitPos >> 3);
+ _bitPos &= 7;
+ }
+
+ UInt32 ReadBits9(unsigned numBits)
+ {
+ const Byte *buf = _buf;
+ UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1];
+ v &= ((UInt32)0xFFFF >> _bitPos);
+ numBits += _bitPos;
+ v >>= (16 - numBits);
+ _buf = buf + (numBits >> 3);
+ _bitPos = numBits & 7;
+ return v;
+ }
+
+ UInt32 ReadBits9fix(unsigned numBits)
+ {
+ const Byte *buf = _buf;
+ UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1];
+ UInt32 mask = ((1 << numBits) - 1);
+ numBits += _bitPos;
+ v >>= (16 - numBits);
+ _buf = buf + (numBits >> 3);
+ _bitPos = numBits & 7;
+ return v & mask;
+ }
+
+ UInt32 ReadBits32(unsigned numBits)
+ {
+ UInt32 mask = ((1 << numBits) - 1);
+ numBits += _bitPos;
+ const Byte *buf = _buf;
+ UInt32 v = GetBe32(buf);
+ if (numBits > 32)
+ {
+ v <<= (numBits - 32);
+ v |= (UInt32)buf[4] >> (40 - numBits);
+ }
+ else
+ v >>= (32 - numBits);
+ _buf = buf + (numBits >> 3);
+ _bitPos = numBits & 7;
+ return v & mask;
+ }
+};
+
+
+struct CFilter
+{
+ Byte Type;
+ Byte Channels;
+ UInt32 Size;
+ UInt64 Start;
+};
+
+
+const unsigned kNumReps = 4;
+const unsigned kLenTableSize = 11 * 4;
+const unsigned kMainTableSize = 256 + 1 + 1 + kNumReps + kLenTableSize;
+const unsigned kDistTableSize = 64;
+const unsigned kNumAlignBits = 4;
+const unsigned kAlignTableSize = (1 << kNumAlignBits);
+const unsigned kLevelTableSize = 20;
+const unsigned kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize + kLenTableSize;
+
+const unsigned kNumHuffmanBits = 15;
+
+class CDecoder:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public CMyUnknownImp
+{
+ bool _useAlignBits;
+ bool _isLastBlock;
+ bool _unpackSize_Defined;
+ // bool _packSize_Defined;
+
+ bool _unsupportedFilter;
+ bool _lzError;
+ bool _writeError;
+
+ // CBitDecoder _bitStream;
+ Byte *_window;
+ size_t _winPos;
+ size_t _winSize;
+ size_t _winMask;
+
+ UInt64 _lzSize;
+
+ unsigned _numCorrectDistSymbols;
+ unsigned _numUnusedFilters;
+
+ UInt64 _lzWritten;
+ UInt64 _lzFileStart;
+ UInt64 _unpackSize;
+ // UInt64 _packSize;
+ UInt64 _lzEnd;
+ UInt64 _writtenFileSize;
+ size_t _winSizeAllocated;
+
+ Byte _dictSizeLog;
+ bool _tableWasFilled;
+ bool _isSolid;
+ bool _wasInit;
+
+ UInt32 _reps[kNumReps];
+ UInt32 _lastLen;
+
+ UInt64 _filterEnd;
+ CMidBuffer _filterSrc;
+ CMidBuffer _filterDst;
+
+ CRecordVector<CFilter> _filters;
+
+ ISequentialInStream *_inStream;
+ ISequentialOutStream *_outStream;
+ ICompressProgressInfo *_progress;
+ Byte *_inputBuf;
+
+ NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kAlignTableSize> m_AlignDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
+
+
+ void InitFilters()
+ {
+ _numUnusedFilters = 0;
+ _filters.Clear();
+ }
+
+ void DeleteUnusedFilters()
+ {
+ if (_numUnusedFilters != 0)
+ {
+ _filters.DeleteFrontal(_numUnusedFilters);
+ _numUnusedFilters = 0;
+ }
+ }
+
+ HRESULT WriteData(const Byte *data, size_t size);
+ HRESULT ExecuteFilter(const CFilter &f);
+ HRESULT WriteBuf();
+ HRESULT AddFilter(CBitDecoder &_bitStream);
+
+ HRESULT ReadTables(CBitDecoder &_bitStream);
+ HRESULT DecodeLZ();
+ HRESULT CodeReal();
+
+public:
+ CDecoder();
+ ~CDecoder();
+
+ MY_UNKNOWN_IMP1(ICompressSetDecoderProperties2)
+
+ STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/RarCodecsRegister.cpp b/CPP/7zip/Compress/RarCodecsRegister.cpp
index 66fcc9a9..2f3a1138 100644
--- a/CPP/7zip/Compress/RarCodecsRegister.cpp
+++ b/CPP/7zip/Compress/RarCodecsRegister.cpp
@@ -7,12 +7,14 @@
#include "Rar1Decoder.h"
#include "Rar2Decoder.h"
#include "Rar3Decoder.h"
+#include "Rar5Decoder.h"
#define CREATE_CODEC(x) REGISTER_CODEC_CREATE(CreateCodec ## x, NCompress::NRar ## x::CDecoder())
CREATE_CODEC(1)
CREATE_CODEC(2)
CREATE_CODEC(3)
+CREATE_CODEC(5)
#define RAR_CODEC(x, name) { CreateCodec ## x, NULL, 0x40300 + x, "Rar" name, 1, false }
@@ -21,6 +23,7 @@ REGISTER_CODECS_VAR
RAR_CODEC(1, "1"),
RAR_CODEC(2, "2"),
RAR_CODEC(3, "3"),
+ RAR_CODEC(5, "5"),
};
REGISTER_CODECS(Rar)