diff options
Diffstat (limited to 'src/libs/3rdparty/7zip/unix/CPP/7zip/Archive/7z/7zDecode.cpp')
-rw-r--r-- | src/libs/3rdparty/7zip/unix/CPP/7zip/Archive/7z/7zDecode.cpp | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/src/libs/3rdparty/7zip/unix/CPP/7zip/Archive/7z/7zDecode.cpp b/src/libs/3rdparty/7zip/unix/CPP/7zip/Archive/7z/7zDecode.cpp new file mode 100644 index 000000000..973966bd3 --- /dev/null +++ b/src/libs/3rdparty/7zip/unix/CPP/7zip/Archive/7z/7zDecode.cpp @@ -0,0 +1,343 @@ +// 7zDecode.cpp + +#include "StdAfx.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/LockedStream.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamObjects.h" + +#include "7zDecode.h" + +namespace NArchive { +namespace N7z { + +static void ConvertFolderItemInfoToBindInfo(const CFolder &folder, + CBindInfoEx &bindInfo) +{ + bindInfo.Clear(); + bindInfo.BindPairs.ClearAndSetSize(folder.BindPairs.Size()); + unsigned i; + for (i = 0; i < folder.BindPairs.Size(); i++) + { + NCoderMixer::CBindPair &bindPair = bindInfo.BindPairs[i]; + bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex; + bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex; + } + + bindInfo.Coders.ClearAndSetSize(folder.Coders.Size()); + bindInfo.CoderMethodIDs.ClearAndSetSize(folder.Coders.Size()); + + UInt32 outStreamIndex = 0; + for (i = 0; i < folder.Coders.Size(); i++) + { + NCoderMixer::CCoderStreamsInfo &coderStreamsInfo = bindInfo.Coders[i]; + const CCoderInfo &coderInfo = folder.Coders[i]; + coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams; + coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams; + bindInfo.CoderMethodIDs[i] = coderInfo.MethodID; + for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++) + if (folder.FindBindPairForOutStream(outStreamIndex) < 0) + bindInfo.OutStreams.Add(outStreamIndex); + } + bindInfo.InStreams.ClearAndSetSize(folder.PackStreams.Size()); + for (i = 0; i < folder.PackStreams.Size(); i++) + bindInfo.InStreams[i] = (UInt32)folder.PackStreams[i]; +} + +static bool AreCodersEqual(const NCoderMixer::CCoderStreamsInfo &a1, + const NCoderMixer::CCoderStreamsInfo &a2) +{ + return (a1.NumInStreams == a2.NumInStreams) && + (a1.NumOutStreams == a2.NumOutStreams); +} + +static bool AreBindPairsEqual(const NCoderMixer::CBindPair &a1, const NCoderMixer::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; + unsigned 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; +} + +HRESULT CDecoder::Decode( + DECL_EXTERNAL_CODECS_LOC_VARS + IInStream *inStream, + UInt64 startPos, + const CFolders &folders, int folderIndex, + ISequentialOutStream *outStream, + ICompressProgressInfo *compressProgress + _7Z_DECODER_CRYPRO_VARS_DECL + #if !defined(_7ZIP_ST) && !defined(_SFX) + , bool mtMode, UInt32 numThreads + #endif + ) +{ + const UInt64 *packPositions = &folders.PackPositions[folders.FoStartPackStreamIndex[folderIndex]]; + CFolder folderInfo; + folders.ParseFolderInfo(folderIndex, folderInfo); + + if (!folderInfo.CheckStructure(folders.GetNumFolderUnpackSizes(folderIndex))) + return E_NOTIMPL; + + /* + We don't need to init isEncrypted and passwordIsDefined + We must upgrade them only + #ifndef _NO_CRYPTO + isEncrypted = false; + passwordIsDefined = false; + #endif + */ + + CObjectVector< CMyComPtr<ISequentialInStream> > inStreams; + + CLockedInStream lockedInStream; + lockedInStream.Init(inStream); + + for (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++) + { + CLockedSequentialInStreamImp *lockedStreamImpSpec = new CLockedSequentialInStreamImp; + CMyComPtr<ISequentialInStream> lockedStreamImp = lockedStreamImpSpec; + lockedStreamImpSpec->Init(&lockedInStream, startPos + packPositions[j]); + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + CMyComPtr<ISequentialInStream> inStream = streamSpec; + streamSpec->SetStream(lockedStreamImp); + streamSpec->Init(packPositions[j + 1] - packPositions[j]); + inStreams.Add(inStream); + } + + unsigned numCoders = folderInfo.Coders.Size(); + + CBindInfoEx bindInfo; + ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo); + bool createNewCoders; + if (!_bindInfoExPrevIsDefined) + createNewCoders = true; + else + createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev); + if (createNewCoders) + { + unsigned i; + _decoders.Clear(); + // _decoders2.Clear(); + + _mixerCoder.Release(); + + if (_multiThread) + { + _mixerCoderMTSpec = new NCoderMixer::CCoderMixer2MT; + _mixerCoder = _mixerCoderMTSpec; + _mixerCoderCommon = _mixerCoderMTSpec; + } + else + { + #ifdef _ST_MODE + _mixerCoderSTSpec = new NCoderMixer::CCoderMixer2ST; + _mixerCoder = _mixerCoderSTSpec; + _mixerCoderCommon = _mixerCoderSTSpec; + #endif + } + RINOK(_mixerCoderCommon->SetBindInfo(bindInfo)); + + for (i = 0; i < numCoders; i++) + { + const CCoderInfo &coderInfo = folderInfo.Coders[i]; + + + CMyComPtr<ICompressCoder> decoder; + CMyComPtr<ICompressCoder2> decoder2; + RINOK(CreateCoder( + EXTERNAL_CODECS_LOC_VARS + coderInfo.MethodID, decoder, decoder2, false)); + CMyComPtr<IUnknown> decoderUnknown; + if (coderInfo.IsSimpleCoder()) + { + if (decoder == 0) + return E_NOTIMPL; + + decoderUnknown = (IUnknown *)decoder; + + if (_multiThread) + _mixerCoderMTSpec->AddCoder(decoder); + #ifdef _ST_MODE + else + _mixerCoderSTSpec->AddCoder(decoder, false); + #endif + } + else + { + if (decoder2 == 0) + return E_NOTIMPL; + decoderUnknown = (IUnknown *)decoder2; + if (_multiThread) + _mixerCoderMTSpec->AddCoder2(decoder2); + #ifdef _ST_MODE + else + _mixerCoderSTSpec->AddCoder2(decoder2, false); + #endif + } + _decoders.Add(decoderUnknown); + #ifdef EXTERNAL_CODECS + CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo; + decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); + if (setCompressCodecsInfo) + { + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs)); + } + #endif + } + _bindInfoExPrev = bindInfo; + _bindInfoExPrevIsDefined = true; + } + unsigned i; + _mixerCoderCommon->ReInit(); + + UInt32 packStreamIndex = 0; + UInt32 unpackStreamIndexStart = folders.FoToCoderUnpackSizes[folderIndex]; + UInt32 unpackStreamIndex = unpackStreamIndexStart; + UInt32 coderIndex = 0; + // UInt32 coder2Index = 0; + + for (i = 0; i < numCoders; i++) + { + const CCoderInfo &coderInfo = folderInfo.Coders[i]; + CMyComPtr<IUnknown> &decoder = _decoders[coderIndex]; + + { + CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties; + decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties); + if (setDecoderProperties) + { + const CByteBuffer &props = coderInfo.Props; + size_t size = props.Size(); + if (size > 0xFFFFFFFF) + return E_NOTIMPL; + // if (size > 0) + { + RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size)); + } + } + } + + #if !defined(_7ZIP_ST) && !defined(_SFX) + 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) + { + isEncrypted = true; + if (!getTextPassword) + return E_NOTIMPL; + CMyComBSTR passwordBSTR; + RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR)); + passwordIsDefined = true; + size_t len = 0; + if (passwordBSTR) + len = MyStringLen((BSTR)passwordBSTR); + CByteBuffer buffer(len * 2); + for (size_t i = 0; i < len; i++) + { + wchar_t c = passwordBSTR[i]; + ((Byte *)buffer)[i * 2] = (Byte)c; + ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); + } + RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size())); + } + } + #endif + + coderIndex++; + + UInt32 numInStreams = (UInt32)coderInfo.NumInStreams; + UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams; + CObjArray<UInt64> packSizes(numInStreams); + CObjArray<const UInt64 *> packSizesPointers(numInStreams); + CObjArray<const UInt64 *> unpackSizesPointers(numOutStreams); + UInt32 j; + + for (j = 0; j < numOutStreams; j++, unpackStreamIndex++) + unpackSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndex]; + + for (j = 0; j < numInStreams; j++, packStreamIndex++) + { + int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex); + if (bindPairIndex >= 0) + packSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndexStart + (UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]; + else + { + int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex); + if (index < 0) + return S_FALSE; // check it + packSizes[j] = packPositions[index + 1] - packPositions[index]; + packSizesPointers[j] = &packSizes[j]; + } + } + + _mixerCoderCommon->SetCoderInfo(i, packSizesPointers, unpackSizesPointers); + } + UInt32 mainCoder, temp; + bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp); + + if (_multiThread) + _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder); + /* + else + _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);; + */ + + if (numCoders == 0) + return 0; + unsigned num = inStreams.Size(); + CObjArray<ISequentialInStream *> inStreamPointers(num); + for (i = 0; i < num; i++) + inStreamPointers[i] = inStreams[i]; + ISequentialOutStream *outStreamPointer = outStream; + return _mixerCoder->Code( + inStreamPointers, NULL, num, + &outStreamPointer, NULL, 1, + compressProgress); +} + +}} |