michael@0: // 7zDecode.cpp michael@0: michael@0: #include "StdAfx.h" michael@0: michael@0: #include "7zDecode.h" michael@0: michael@0: #include "../../IPassword.h" michael@0: #include "../../Common/LockedStream.h" michael@0: #include "../../Common/StreamObjects.h" michael@0: #include "../../Common/ProgressUtils.h" michael@0: #include "../../Common/LimitedStreams.h" michael@0: #include "../Common/FilterCoder.h" michael@0: michael@0: #include "7zMethods.h" michael@0: michael@0: #ifdef COMPRESS_LZMA michael@0: #include "../../Compress/LZMA/LZMADecoder.h" michael@0: static NArchive::N7z::CMethodID k_LZMA = { { 0x3, 0x1, 0x1 }, 3 }; michael@0: #endif michael@0: michael@0: #ifdef COMPRESS_PPMD michael@0: #include "../../Compress/PPMD/PPMDDecoder.h" michael@0: static NArchive::N7z::CMethodID k_PPMD = { { 0x3, 0x4, 0x1 }, 3 }; michael@0: #endif michael@0: michael@0: #ifdef COMPRESS_BCJ_X86 michael@0: #include "../../Compress/Branch/x86.h" michael@0: static NArchive::N7z::CMethodID k_BCJ_X86 = { { 0x3, 0x3, 0x1, 0x3 }, 4 }; michael@0: #endif michael@0: michael@0: #ifdef COMPRESS_BCJ2 michael@0: #include "../../Compress/Branch/x86_2.h" michael@0: static NArchive::N7z::CMethodID k_BCJ2 = { { 0x3, 0x3, 0x1, 0x1B }, 4 }; michael@0: #endif michael@0: michael@0: #ifdef COMPRESS_DEFLATE michael@0: #ifndef COMPRESS_DEFLATE_DECODER michael@0: #define COMPRESS_DEFLATE_DECODER michael@0: #endif michael@0: #endif michael@0: michael@0: #ifdef COMPRESS_DEFLATE_DECODER michael@0: #include "../../Compress/Deflate/DeflateDecoder.h" michael@0: static NArchive::N7z::CMethodID k_Deflate = { { 0x4, 0x1, 0x8 }, 3 }; michael@0: #endif michael@0: michael@0: #ifdef COMPRESS_BZIP2 michael@0: #ifndef COMPRESS_BZIP2_DECODER michael@0: #define COMPRESS_BZIP2_DECODER michael@0: #endif michael@0: #endif michael@0: michael@0: #ifdef COMPRESS_BZIP2_DECODER michael@0: #include "../../Compress/BZip2/BZip2Decoder.h" michael@0: static NArchive::N7z::CMethodID k_BZip2 = { { 0x4, 0x2, 0x2 }, 3 }; michael@0: #endif michael@0: michael@0: #ifdef COMPRESS_COPY michael@0: #include "../../Compress/Copy/CopyCoder.h" michael@0: static NArchive::N7z::CMethodID k_Copy = { { 0x0 }, 1 }; michael@0: #endif michael@0: michael@0: #ifdef CRYPTO_7ZAES michael@0: #include "../../Crypto/7zAES/7zAES.h" michael@0: static NArchive::N7z::CMethodID k_7zAES = { { 0x6, 0xF1, 0x07, 0x01 }, 4 }; michael@0: #endif michael@0: michael@0: namespace NArchive { michael@0: namespace N7z { michael@0: michael@0: static void ConvertFolderItemInfoToBindInfo(const CFolder &folder, michael@0: CBindInfoEx &bindInfo) michael@0: { michael@0: bindInfo.Clear(); michael@0: int i; michael@0: for (i = 0; i < folder.BindPairs.Size(); i++) michael@0: { michael@0: NCoderMixer2::CBindPair bindPair; michael@0: bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex; michael@0: bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex; michael@0: bindInfo.BindPairs.Add(bindPair); michael@0: } michael@0: UInt32 outStreamIndex = 0; michael@0: for (i = 0; i < folder.Coders.Size(); i++) michael@0: { michael@0: NCoderMixer2::CCoderStreamsInfo coderStreamsInfo; michael@0: const CCoderInfo &coderInfo = folder.Coders[i]; michael@0: coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams; michael@0: coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams; michael@0: bindInfo.Coders.Add(coderStreamsInfo); michael@0: const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders.Front(); michael@0: bindInfo.CoderMethodIDs.Add(altCoderInfo.MethodID); michael@0: for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++) michael@0: if (folder.FindBindPairForOutStream(outStreamIndex) < 0) michael@0: bindInfo.OutStreams.Add(outStreamIndex); michael@0: } michael@0: for (i = 0; i < folder.PackStreams.Size(); i++) michael@0: bindInfo.InStreams.Add((UInt32)folder.PackStreams[i]); michael@0: } michael@0: michael@0: static bool AreCodersEqual(const NCoderMixer2::CCoderStreamsInfo &a1, michael@0: const NCoderMixer2::CCoderStreamsInfo &a2) michael@0: { michael@0: return (a1.NumInStreams == a2.NumInStreams) && michael@0: (a1.NumOutStreams == a2.NumOutStreams); michael@0: } michael@0: michael@0: static bool AreBindPairsEqual(const NCoderMixer2::CBindPair &a1, const NCoderMixer2::CBindPair &a2) michael@0: { michael@0: return (a1.InIndex == a2.InIndex) && michael@0: (a1.OutIndex == a2.OutIndex); michael@0: } michael@0: michael@0: static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2) michael@0: { michael@0: if (a1.Coders.Size() != a2.Coders.Size()) michael@0: return false; michael@0: int i; michael@0: for (i = 0; i < a1.Coders.Size(); i++) michael@0: if (!AreCodersEqual(a1.Coders[i], a2.Coders[i])) michael@0: return false; michael@0: if (a1.BindPairs.Size() != a2.BindPairs.Size()) michael@0: return false; michael@0: for (i = 0; i < a1.BindPairs.Size(); i++) michael@0: if (!AreBindPairsEqual(a1.BindPairs[i], a2.BindPairs[i])) michael@0: return false; michael@0: for (i = 0; i < a1.CoderMethodIDs.Size(); i++) michael@0: if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i]) michael@0: return false; michael@0: if (a1.InStreams.Size() != a2.InStreams.Size()) michael@0: return false; michael@0: if (a1.OutStreams.Size() != a2.OutStreams.Size()) michael@0: return false; michael@0: return true; michael@0: } michael@0: michael@0: CDecoder::CDecoder(bool multiThread) michael@0: { michael@0: #ifndef _ST_MODE michael@0: multiThread = true; michael@0: #endif michael@0: _multiThread = multiThread; michael@0: _bindInfoExPrevIsDefinded = false; michael@0: #ifndef EXCLUDE_COM michael@0: LoadMethodMap(); michael@0: #endif michael@0: } michael@0: michael@0: HRESULT CDecoder::Decode(IInStream *inStream, michael@0: UInt64 startPos, michael@0: const UInt64 *packSizes, michael@0: const CFolder &folderInfo, michael@0: ISequentialOutStream *outStream, michael@0: ICompressProgressInfo *compressProgress michael@0: #ifndef _NO_CRYPTO michael@0: , ICryptoGetTextPassword *getTextPassword michael@0: #endif michael@0: #ifdef COMPRESS_MT michael@0: , bool mtMode, UInt32 numThreads michael@0: #endif michael@0: ) michael@0: { michael@0: CObjectVector< CMyComPtr > inStreams; michael@0: michael@0: CLockedInStream lockedInStream; michael@0: lockedInStream.Init(inStream); michael@0: michael@0: for (int j = 0; j < folderInfo.PackStreams.Size(); j++) michael@0: { michael@0: CLockedSequentialInStreamImp *lockedStreamImpSpec = new michael@0: CLockedSequentialInStreamImp; michael@0: CMyComPtr lockedStreamImp = lockedStreamImpSpec; michael@0: lockedStreamImpSpec->Init(&lockedInStream, startPos); michael@0: startPos += packSizes[j]; michael@0: michael@0: CLimitedSequentialInStream *streamSpec = new michael@0: CLimitedSequentialInStream; michael@0: CMyComPtr inStream = streamSpec; michael@0: streamSpec->Init(lockedStreamImp, packSizes[j]); michael@0: inStreams.Add(inStream); michael@0: } michael@0: michael@0: int numCoders = folderInfo.Coders.Size(); michael@0: michael@0: CBindInfoEx bindInfo; michael@0: ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo); michael@0: bool createNewCoders; michael@0: if (!_bindInfoExPrevIsDefinded) michael@0: createNewCoders = true; michael@0: else michael@0: createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev); michael@0: if (createNewCoders) michael@0: { michael@0: int i; michael@0: _decoders.Clear(); michael@0: // _decoders2.Clear(); michael@0: michael@0: _mixerCoder.Release(); michael@0: michael@0: if (_multiThread) michael@0: { michael@0: _mixerCoderMTSpec = new NCoderMixer2::CCoderMixer2MT; michael@0: _mixerCoder = _mixerCoderMTSpec; michael@0: _mixerCoderCommon = _mixerCoderMTSpec; michael@0: } michael@0: else michael@0: { michael@0: #ifdef _ST_MODE michael@0: _mixerCoderSTSpec = new NCoderMixer2::CCoderMixer2ST; michael@0: _mixerCoder = _mixerCoderSTSpec; michael@0: _mixerCoderCommon = _mixerCoderSTSpec; michael@0: #endif michael@0: } michael@0: _mixerCoderCommon->SetBindInfo(bindInfo); michael@0: michael@0: for (i = 0; i < numCoders; i++) michael@0: { michael@0: const CCoderInfo &coderInfo = folderInfo.Coders[i]; michael@0: const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders.Front(); michael@0: #ifndef EXCLUDE_COM michael@0: CMethodInfo methodInfo; michael@0: if (!GetMethodInfo(altCoderInfo.MethodID, methodInfo)) michael@0: return E_NOTIMPL; michael@0: #endif michael@0: michael@0: if (coderInfo.IsSimpleCoder()) michael@0: { michael@0: CMyComPtr decoder; michael@0: CMyComPtr filter; michael@0: michael@0: #ifdef COMPRESS_LZMA michael@0: if (altCoderInfo.MethodID == k_LZMA) michael@0: decoder = new NCompress::NLZMA::CDecoder; michael@0: #endif michael@0: michael@0: #ifdef COMPRESS_PPMD michael@0: if (altCoderInfo.MethodID == k_PPMD) michael@0: decoder = new NCompress::NPPMD::CDecoder; michael@0: #endif michael@0: michael@0: #ifdef COMPRESS_BCJ_X86 michael@0: if (altCoderInfo.MethodID == k_BCJ_X86) michael@0: filter = new CBCJ_x86_Decoder; michael@0: #endif michael@0: michael@0: #ifdef COMPRESS_DEFLATE_DECODER michael@0: if (altCoderInfo.MethodID == k_Deflate) michael@0: decoder = new NCompress::NDeflate::NDecoder::CCOMCoder; michael@0: #endif michael@0: michael@0: #ifdef COMPRESS_BZIP2_DECODER michael@0: if (altCoderInfo.MethodID == k_BZip2) michael@0: decoder = new NCompress::NBZip2::CDecoder; michael@0: #endif michael@0: michael@0: #ifdef COMPRESS_COPY michael@0: if (altCoderInfo.MethodID == k_Copy) michael@0: decoder = new NCompress::CCopyCoder; michael@0: #endif michael@0: michael@0: #ifdef CRYPTO_7ZAES michael@0: if (altCoderInfo.MethodID == k_7zAES) michael@0: filter = new NCrypto::NSevenZ::CDecoder; michael@0: #endif michael@0: michael@0: if (filter) michael@0: { michael@0: CFilterCoder *coderSpec = new CFilterCoder; michael@0: decoder = coderSpec; michael@0: coderSpec->Filter = filter; michael@0: } michael@0: #ifndef EXCLUDE_COM michael@0: if (decoder == 0) michael@0: { michael@0: RINOK(_libraries.CreateCoderSpec(methodInfo.FilePath, michael@0: methodInfo.Decoder, &decoder)); michael@0: } michael@0: #endif michael@0: michael@0: if (decoder == 0) michael@0: return E_NOTIMPL; michael@0: michael@0: _decoders.Add((IUnknown *)decoder); michael@0: michael@0: if (_multiThread) michael@0: _mixerCoderMTSpec->AddCoder(decoder); michael@0: #ifdef _ST_MODE michael@0: else michael@0: _mixerCoderSTSpec->AddCoder(decoder, false); michael@0: #endif michael@0: } michael@0: else michael@0: { michael@0: CMyComPtr decoder; michael@0: michael@0: #ifdef COMPRESS_BCJ2 michael@0: if (altCoderInfo.MethodID == k_BCJ2) michael@0: decoder = new CBCJ2_x86_Decoder; michael@0: #endif michael@0: michael@0: #ifndef EXCLUDE_COM michael@0: if (decoder == 0) michael@0: { michael@0: RINOK(_libraries.CreateCoder2(methodInfo.FilePath, michael@0: methodInfo.Decoder, &decoder)); michael@0: } michael@0: #endif michael@0: michael@0: if (decoder == 0) michael@0: return E_NOTIMPL; michael@0: michael@0: _decoders.Add((IUnknown *)decoder); michael@0: if (_multiThread) michael@0: _mixerCoderMTSpec->AddCoder2(decoder); michael@0: #ifdef _ST_MODE michael@0: else michael@0: _mixerCoderSTSpec->AddCoder2(decoder, false); michael@0: #endif michael@0: } michael@0: } michael@0: _bindInfoExPrev = bindInfo; michael@0: _bindInfoExPrevIsDefinded = true; michael@0: } michael@0: int i; michael@0: _mixerCoderCommon->ReInit(); michael@0: michael@0: UInt32 packStreamIndex = 0, unPackStreamIndex = 0; michael@0: UInt32 coderIndex = 0; michael@0: // UInt32 coder2Index = 0; michael@0: michael@0: for (i = 0; i < numCoders; i++) michael@0: { michael@0: const CCoderInfo &coderInfo = folderInfo.Coders[i]; michael@0: const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders.Front(); michael@0: CMyComPtr &decoder = _decoders[coderIndex]; michael@0: michael@0: { michael@0: CMyComPtr setDecoderProperties; michael@0: HRESULT result = decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties); michael@0: if (setDecoderProperties) michael@0: { michael@0: const CByteBuffer &properties = altCoderInfo.Properties; michael@0: size_t size = properties.GetCapacity(); michael@0: if (size > 0xFFFFFFFF) michael@0: return E_NOTIMPL; michael@0: if (size > 0) michael@0: { michael@0: RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)properties, (UInt32)size)); michael@0: } michael@0: } michael@0: } michael@0: michael@0: #ifdef COMPRESS_MT michael@0: if (mtMode) michael@0: { michael@0: CMyComPtr setCoderMt; michael@0: decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); michael@0: if (setCoderMt) michael@0: { michael@0: RINOK(setCoderMt->SetNumberOfThreads(numThreads)); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: #ifndef _NO_CRYPTO michael@0: { michael@0: CMyComPtr cryptoSetPassword; michael@0: HRESULT result = decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); michael@0: if (cryptoSetPassword) michael@0: { michael@0: if (getTextPassword == 0) michael@0: return E_FAIL; michael@0: CMyComBSTR password; michael@0: RINOK(getTextPassword->CryptoGetTextPassword(&password)); michael@0: CByteBuffer buffer; michael@0: UString unicodePassword(password); michael@0: const UInt32 sizeInBytes = unicodePassword.Length() * 2; michael@0: buffer.SetCapacity(sizeInBytes); michael@0: for (int i = 0; i < unicodePassword.Length(); i++) michael@0: { michael@0: wchar_t c = unicodePassword[i]; michael@0: ((Byte *)buffer)[i * 2] = (Byte)c; michael@0: ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); michael@0: } michael@0: RINOK(cryptoSetPassword->CryptoSetPassword( michael@0: (const Byte *)buffer, sizeInBytes)); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: coderIndex++; michael@0: michael@0: UInt32 numInStreams = (UInt32)coderInfo.NumInStreams; michael@0: UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams; michael@0: CRecordVector packSizesPointers; michael@0: CRecordVector unPackSizesPointers; michael@0: packSizesPointers.Reserve(numInStreams); michael@0: unPackSizesPointers.Reserve(numOutStreams); michael@0: UInt32 j; michael@0: for (j = 0; j < numOutStreams; j++, unPackStreamIndex++) michael@0: unPackSizesPointers.Add(&folderInfo.UnPackSizes[unPackStreamIndex]); michael@0: michael@0: for (j = 0; j < numInStreams; j++, packStreamIndex++) michael@0: { michael@0: int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex); michael@0: if (bindPairIndex >= 0) michael@0: packSizesPointers.Add( michael@0: &folderInfo.UnPackSizes[(UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]); michael@0: else michael@0: { michael@0: int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex); michael@0: if (index < 0) michael@0: return E_FAIL; michael@0: packSizesPointers.Add(&packSizes[index]); michael@0: } michael@0: } michael@0: michael@0: _mixerCoderCommon->SetCoderInfo(i, michael@0: &packSizesPointers.Front(), michael@0: &unPackSizesPointers.Front()); michael@0: } michael@0: UInt32 mainCoder, temp; michael@0: bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp); michael@0: michael@0: if (_multiThread) michael@0: _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder); michael@0: /* michael@0: else michael@0: _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);; michael@0: */ michael@0: michael@0: if (numCoders == 0) michael@0: return 0; michael@0: CRecordVector inStreamPointers; michael@0: inStreamPointers.Reserve(inStreams.Size()); michael@0: for (i = 0; i < inStreams.Size(); i++) michael@0: inStreamPointers.Add(inStreams[i]); michael@0: ISequentialOutStream *outStreamPointer = outStream; michael@0: return _mixerCoder->Code(&inStreamPointers.Front(), NULL, michael@0: inStreams.Size(), &outStreamPointer, NULL, 1, compressProgress); michael@0: } michael@0: michael@0: }}