From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../7zstub/src/CPP/7zip/Archive/7z/7zDecode.cpp | 567 +++++++++++++++++++++ 1 file changed, 567 insertions(+) create mode 100644 other-licenses/7zstub/src/CPP/7zip/Archive/7z/7zDecode.cpp (limited to 'other-licenses/7zstub/src/CPP/7zip/Archive/7z/7zDecode.cpp') diff --git a/other-licenses/7zstub/src/CPP/7zip/Archive/7z/7zDecode.cpp b/other-licenses/7zstub/src/CPP/7zip/Archive/7z/7zDecode.cpp new file mode 100644 index 0000000000..2705ecb9ae --- /dev/null +++ b/other-licenses/7zstub/src/CPP/7zip/Archive/7z/7zDecode.cpp @@ -0,0 +1,567 @@ +// 7zDecode.cpp + +#include "StdAfx.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/StreamObjects.h" + +#include "7zDecode.h" + +namespace NArchive { +namespace N7z { + +class CDecProgress: + public ICompressProgressInfo, + public CMyUnknownImp +{ + CMyComPtr _progress; +public: + CDecProgress(ICompressProgressInfo *progress): _progress(progress) {} + + MY_UNKNOWN_IMP1(ICompressProgressInfo) + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); +}; + +STDMETHODIMP CDecProgress::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 *outSize) +{ + return _progress->SetRatioInfo(NULL, outSize); +} + +static void Convert_FolderInfo_to_BindInfo(const CFolderEx &folder, CBindInfoEx &bi) +{ + bi.Clear(); + + bi.Bonds.ClearAndSetSize(folder.Bonds.Size()); + unsigned i; + for (i = 0; i < folder.Bonds.Size(); i++) + { + NCoderMixer2::CBond &bond = bi.Bonds[i]; + const N7z::CBond &folderBond = folder.Bonds[i]; + bond.PackIndex = folderBond.PackIndex; + bond.UnpackIndex = folderBond.UnpackIndex; + } + + bi.Coders.ClearAndSetSize(folder.Coders.Size()); + bi.CoderMethodIDs.ClearAndSetSize(folder.Coders.Size()); + for (i = 0; i < folder.Coders.Size(); i++) + { + const CCoderInfo &coderInfo = folder.Coders[i]; + bi.Coders[i].NumStreams = coderInfo.NumStreams; + bi.CoderMethodIDs[i] = coderInfo.MethodID; + } + + /* + if (!bi.SetUnpackCoder()) + throw 1112; + */ + bi.UnpackCoder = folder.UnpackCoder; + bi.PackStreams.ClearAndSetSize(folder.PackStreams.Size()); + for (i = 0; i < folder.PackStreams.Size(); i++) + bi.PackStreams[i] = folder.PackStreams[i]; +} + +static inline bool AreCodersEqual( + const NCoderMixer2::CCoderStreamsInfo &a1, + const NCoderMixer2::CCoderStreamsInfo &a2) +{ + return (a1.NumStreams == a2.NumStreams); +} + +static inline bool AreBondsEqual( + const NCoderMixer2::CBond &a1, + const NCoderMixer2::CBond &a2) +{ + return + (a1.PackIndex == a2.PackIndex) && + (a1.UnpackIndex == a2.UnpackIndex); +} + +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.Bonds.Size() != a2.Bonds.Size()) + return false; + for (i = 0; i < a1.Bonds.Size(); i++) + if (!AreBondsEqual(a1.Bonds[i], a2.Bonds[i])) + return false; + + for (i = 0; i < a1.CoderMethodIDs.Size(); i++) + if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i]) + return false; + + if (a1.PackStreams.Size() != a2.PackStreams.Size()) + return false; + for (i = 0; i < a1.PackStreams.Size(); i++) + if (a1.PackStreams[i] != a2.PackStreams[i]) + return false; + + /* + if (a1.UnpackCoder != a2.UnpackCoder) + return false; + */ + return true; +} + +CDecoder::CDecoder(bool useMixerMT): + _bindInfoPrev_Defined(false), + _useMixerMT(useMixerMT) +{} + + +struct CLockedInStream: + public IUnknown, + public CMyUnknownImp +{ + CMyComPtr Stream; + UInt64 Pos; + + MY_UNKNOWN_IMP + + #ifdef USE_MIXER_MT + NWindows::NSynchronization::CCriticalSection CriticalSection; + #endif +}; + + +#ifdef USE_MIXER_MT + +class CLockedSequentialInStreamMT: + public ISequentialInStream, + public CMyUnknownImp +{ + CLockedInStream *_glob; + UInt64 _pos; + CMyComPtr _globRef; +public: + void Init(CLockedInStream *lockedInStream, UInt64 startPos) + { + _globRef = lockedInStream; + _glob = lockedInStream; + _pos = startPos; + } + + MY_UNKNOWN_IMP1(ISequentialInStream) + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP CLockedSequentialInStreamMT::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + NWindows::NSynchronization::CCriticalSectionLock lock(_glob->CriticalSection); + + if (_pos != _glob->Pos) + { + RINOK(_glob->Stream->Seek(_pos, STREAM_SEEK_SET, NULL)); + _glob->Pos = _pos; + } + + UInt32 realProcessedSize = 0; + HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize); + _pos += realProcessedSize; + _glob->Pos = _pos; + if (processedSize) + *processedSize = realProcessedSize; + return res; +} + +#endif + + +#ifdef USE_MIXER_ST + +class CLockedSequentialInStreamST: + public ISequentialInStream, + public CMyUnknownImp +{ + CLockedInStream *_glob; + UInt64 _pos; + CMyComPtr _globRef; +public: + void Init(CLockedInStream *lockedInStream, UInt64 startPos) + { + _globRef = lockedInStream; + _glob = lockedInStream; + _pos = startPos; + } + + MY_UNKNOWN_IMP1(ISequentialInStream) + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP CLockedSequentialInStreamST::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (_pos != _glob->Pos) + { + RINOK(_glob->Stream->Seek(_pos, STREAM_SEEK_SET, NULL)); + _glob->Pos = _pos; + } + + UInt32 realProcessedSize = 0; + HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize); + _pos += realProcessedSize; + _glob->Pos = _pos; + if (processedSize) + *processedSize = realProcessedSize; + return res; +} + +#endif + + + +HRESULT CDecoder::Decode( + DECL_EXTERNAL_CODECS_LOC_VARS + IInStream *inStream, + UInt64 startPos, + const CFolders &folders, unsigned folderIndex, + const UInt64 *unpackSize + + , ISequentialOutStream *outStream + , ICompressProgressInfo *compressProgress + + , ISequentialInStream ** + #ifdef USE_MIXER_ST + inStreamMainRes + #endif + + , bool &dataAfterEnd_Error + + _7Z_DECODER_CRYPRO_VARS_DECL + + #if !defined(_7ZIP_ST) + , bool mtMode, UInt32 numThreads, UInt64 memUsage + #endif + ) +{ + dataAfterEnd_Error = false; + + const UInt64 *packPositions = &folders.PackPositions[folders.FoStartPackStreamIndex[folderIndex]]; + CFolderEx folderInfo; + folders.ParseFolderEx(folderIndex, folderInfo); + + if (!folderInfo.IsDecodingSupported()) + return E_NOTIMPL; + + CBindInfoEx bindInfo; + Convert_FolderInfo_to_BindInfo(folderInfo, bindInfo); + if (!bindInfo.CalcMapsAndCheck()) + return E_NOTIMPL; + + UInt64 folderUnpackSize = folders.GetFolderUnpackSize(folderIndex); + bool fullUnpack = true; + if (unpackSize) + { + if (*unpackSize > folderUnpackSize) + return E_FAIL; + fullUnpack = (*unpackSize == folderUnpackSize); + } + + /* + We don't need to init isEncrypted and passwordIsDefined + We must upgrade them only + + #ifndef _NO_CRYPTO + isEncrypted = false; + passwordIsDefined = false; + #endif + */ + + if (!_bindInfoPrev_Defined || !AreBindInfoExEqual(bindInfo, _bindInfoPrev)) + { + _mixerRef.Release(); + + #ifdef USE_MIXER_MT + #ifdef USE_MIXER_ST + if (_useMixerMT) + #endif + { + _mixerMT = new NCoderMixer2::CMixerMT(false); + _mixerRef = _mixerMT; + _mixer = _mixerMT; + } + #ifdef USE_MIXER_ST + else + #endif + #endif + { + #ifdef USE_MIXER_ST + _mixerST = new NCoderMixer2::CMixerST(false); + _mixerRef = _mixerST; + _mixer = _mixerST; + #endif + } + + RINOK(_mixer->SetBindInfo(bindInfo)); + + FOR_VECTOR(i, folderInfo.Coders) + { + const CCoderInfo &coderInfo = folderInfo.Coders[i]; + + #ifndef _SFX + // we don't support RAR codecs here + if ((coderInfo.MethodID >> 8) == 0x403) + return E_NOTIMPL; + #endif + + CCreatedCoder cod; + RINOK(CreateCoder_Id( + EXTERNAL_CODECS_LOC_VARS + coderInfo.MethodID, false, cod)); + + if (coderInfo.IsSimpleCoder()) + { + if (!cod.Coder) + return E_NOTIMPL; + // CMethodId m = coderInfo.MethodID; + // isFilter = (IsFilterMethod(m) || m == k_AES); + } + else + { + if (!cod.Coder2 || cod.NumStreams != coderInfo.NumStreams) + return E_NOTIMPL; + } + _mixer->AddCoder(cod); + + // now there is no codec that uses another external codec + /* + #ifdef EXTERNAL_CODECS + CMyComPtr setCompressCodecsInfo; + decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); + if (setCompressCodecsInfo) + { + // we must use g_ExternalCodecs also + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs)); + } + #endif + */ + } + + _bindInfoPrev = bindInfo; + _bindInfoPrev_Defined = true; + } + + _mixer->ReInit(); + + UInt32 packStreamIndex = 0; + UInt32 unpackStreamIndexStart = folders.FoToCoderUnpackSizes[folderIndex]; + + unsigned i; + + bool mt_wasUsed = false; + + for (i = 0; i < folderInfo.Coders.Size(); i++) + { + const CCoderInfo &coderInfo = folderInfo.Coders[i]; + IUnknown *decoder = _mixer->GetCoder(i).GetUnknown(); + + #if !defined(_7ZIP_ST) + if (!mt_wasUsed) + { + if (mtMode) + { + CMyComPtr setCoderMt; + decoder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt); + if (setCoderMt) + { + mt_wasUsed = true; + RINOK(setCoderMt->SetNumberOfThreads(numThreads)); + } + } + // if (memUsage != 0) + { + CMyComPtr setMemLimit; + decoder->QueryInterface(IID_ICompressSetMemLimit, (void **)&setMemLimit); + if (setMemLimit) + { + mt_wasUsed = true; + RINOK(setMemLimit->SetMemLimit(memUsage)); + } + } + } + #endif + + { + CMyComPtr setDecoderProperties; + decoder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties); + if (setDecoderProperties) + { + const CByteBuffer &props = coderInfo.Props; + size_t size = props.Size(); + if (size > 0xFFFFFFFF) + return E_NOTIMPL; + HRESULT res = setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size); + if (res == E_INVALIDARG) + res = E_NOTIMPL; + RINOK(res); + } + } + + #ifndef _NO_CRYPTO + { + CMyComPtr cryptoSetPassword; + decoder->QueryInterface(IID_ICryptoSetPassword, (void **)&cryptoSetPassword); + if (cryptoSetPassword) + { + isEncrypted = true; + if (!getTextPassword) + return E_NOTIMPL; + CMyComBSTR passwordBSTR; + RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR)); + passwordIsDefined = true; + password.Empty(); + size_t len = 0; + if (passwordBSTR) + { + password = passwordBSTR; + len = password.Len(); + } + CByteBuffer buffer(len * 2); + for (size_t k = 0; k < len; k++) + { + wchar_t c = passwordBSTR[k]; + ((Byte *)buffer)[k * 2] = (Byte)c; + ((Byte *)buffer)[k * 2 + 1] = (Byte)(c >> 8); + } + RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size())); + } + } + #endif + + bool finishMode = false; + { + CMyComPtr setFinishMode; + decoder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode); + if (setFinishMode) + { + finishMode = fullUnpack; + RINOK(setFinishMode->SetFinishMode(BoolToInt(finishMode))); + } + } + + UInt32 numStreams = (UInt32)coderInfo.NumStreams; + + CObjArray packSizes(numStreams); + CObjArray packSizesPointers(numStreams); + + for (UInt32 j = 0; j < numStreams; j++, packStreamIndex++) + { + int bond = folderInfo.FindBond_for_PackStream(packStreamIndex); + + if (bond >= 0) + packSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndexStart + folderInfo.Bonds[(unsigned)bond].UnpackIndex]; + else + { + int index = folderInfo.Find_in_PackStreams(packStreamIndex); + if (index < 0) + return E_NOTIMPL; + packSizes[j] = packPositions[(unsigned)index + 1] - packPositions[(unsigned)index]; + packSizesPointers[j] = &packSizes[j]; + } + } + + const UInt64 *unpackSizesPointer = + (unpackSize && i == bindInfo.UnpackCoder) ? + unpackSize : + &folders.CoderUnpackSizes[unpackStreamIndexStart + i]; + + _mixer->SetCoderInfo(i, unpackSizesPointer, packSizesPointers, finishMode); + } + + if (outStream) + { + _mixer->SelectMainCoder(!fullUnpack); + } + + CObjectVector< CMyComPtr > inStreams; + + CLockedInStream *lockedInStreamSpec = new CLockedInStream; + CMyComPtr lockedInStream = lockedInStreamSpec; + + bool needMtLock = false; + + if (folderInfo.PackStreams.Size() > 1) + { + // lockedInStream.Pos = (UInt64)(Int64)-1; + // RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &lockedInStream.Pos)); + RINOK(inStream->Seek(startPos + packPositions[0], STREAM_SEEK_SET, &lockedInStreamSpec->Pos)); + lockedInStreamSpec->Stream = inStream; + + #ifdef USE_MIXER_ST + if (_mixer->IsThere_ExternalCoder_in_PackTree(_mixer->MainCoderIndex)) + #endif + needMtLock = true; + } + + for (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++) + { + CMyComPtr packStream; + UInt64 packPos = startPos + packPositions[j]; + + if (folderInfo.PackStreams.Size() == 1) + { + RINOK(inStream->Seek(packPos, STREAM_SEEK_SET, NULL)); + packStream = inStream; + } + else + { + #ifdef USE_MIXER_MT + #ifdef USE_MIXER_ST + if (_useMixerMT || needMtLock) + #endif + { + CLockedSequentialInStreamMT *lockedStreamImpSpec = new CLockedSequentialInStreamMT; + packStream = lockedStreamImpSpec; + lockedStreamImpSpec->Init(lockedInStreamSpec, packPos); + } + #ifdef USE_MIXER_ST + else + #endif + #endif + { + #ifdef USE_MIXER_ST + CLockedSequentialInStreamST *lockedStreamImpSpec = new CLockedSequentialInStreamST; + packStream = lockedStreamImpSpec; + lockedStreamImpSpec->Init(lockedInStreamSpec, packPos); + #endif + } + } + + CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream; + inStreams.AddNew() = streamSpec; + streamSpec->SetStream(packStream); + streamSpec->Init(packPositions[j + 1] - packPositions[j]); + } + + unsigned num = inStreams.Size(); + CObjArray inStreamPointers(num); + for (i = 0; i < num; i++) + inStreamPointers[i] = inStreams[i]; + + if (outStream) + { + CMyComPtr progress2; + if (compressProgress && !_mixer->Is_PackSize_Correct_for_Coder(_mixer->MainCoderIndex)) + progress2 = new CDecProgress(compressProgress); + + ISequentialOutStream *outStreamPointer = outStream; + return _mixer->Code(inStreamPointers, &outStreamPointer, + progress2 ? (ICompressProgressInfo *)progress2 : compressProgress, + dataAfterEnd_Error); + } + + #ifdef USE_MIXER_ST + return _mixerST->GetMainUnpackStream(inStreamPointers, inStreamMainRes); + #else + return E_FAIL; + #endif +} + +}} -- cgit v1.2.3