diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2015-08-16 03:00:00 +0300 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:16:55 +0300 |
commit | cba375916fb18db8b9101aedf4fa079e019311b3 (patch) | |
tree | 6275ae5fc2a8dd337ab0327180c871807e6ba5d4 /CPP/7zip/Compress | |
parent | 54490d51d5c6b0d794dcbad2d634d4c95fc25b6c (diff) |
15.0615.06
Diffstat (limited to 'CPP/7zip/Compress')
-rw-r--r-- | CPP/7zip/Compress/Codec.def | 2 | ||||
-rw-r--r-- | CPP/7zip/Compress/DeflateEncoder.cpp | 8 | ||||
-rw-r--r-- | CPP/7zip/Compress/HuffmanDecoder.h | 19 | ||||
-rw-r--r-- | CPP/7zip/Compress/Rar1Decoder.cpp | 2 | ||||
-rw-r--r-- | CPP/7zip/Compress/Rar2Decoder.cpp | 2 | ||||
-rw-r--r-- | CPP/7zip/Compress/Rar3Decoder.cpp | 22 | ||||
-rw-r--r-- | CPP/7zip/Compress/Rar3Decoder.h | 1 | ||||
-rw-r--r-- | CPP/7zip/Compress/Rar3Vm.cpp | 105 | ||||
-rw-r--r-- | CPP/7zip/Compress/Rar3Vm.h | 34 | ||||
-rw-r--r-- | CPP/7zip/Compress/Rar5Decoder.cpp | 960 | ||||
-rw-r--r-- | CPP/7zip/Compress/Rar5Decoder.h | 335 | ||||
-rw-r--r-- | CPP/7zip/Compress/RarCodecsRegister.cpp | 3 |
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) |