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