// 7zExtract.cpp #include "StdAfx.h" #include "7zHandler.h" #include "7zFolderOutStream.h" #include "7zDecode.h" // #include "7z1Decode.h" #include "../../../Common/ComTry.h" #include "../../Common/StreamObjects.h" #include "../../Common/ProgressUtils.h" #include "../../Common/LimitedStreams.h" namespace NArchive { namespace N7z { struct CExtractFolderInfo { #ifdef _7Z_VOL int VolumeIndex; #endif CNum FileIndex; CNum FolderIndex; CBoolVector ExtractStatuses; UInt64 UnPackSize; CExtractFolderInfo( #ifdef _7Z_VOL int volumeIndex, #endif CNum fileIndex, CNum folderIndex): #ifdef _7Z_VOL VolumeIndex(volumeIndex), #endif FileIndex(fileIndex), FolderIndex(folderIndex), UnPackSize(0) { if (fileIndex != kNumNoIndex) { ExtractStatuses.Reserve(1); ExtractStatuses.Add(true); } }; }; STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems, Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec) { COM_TRY_BEGIN bool testMode = (testModeSpec != 0); CMyComPtr extractCallback = extractCallbackSpec; UInt64 importantTotalUnPacked = 0; bool allFilesMode = (numItems == UInt32(-1)); if (allFilesMode) numItems = #ifdef _7Z_VOL _refs.Size(); #else _database.Files.Size(); #endif if(numItems == 0) return S_OK; /* if(_volumes.Size() != 1) return E_FAIL; const CVolume &volume = _volumes.Front(); const CArchiveDatabaseEx &_database = volume.Database; IInStream *_inStream = volume.Stream; */ CObjectVector extractFolderInfoVector; for(UInt32 ii = 0; ii < numItems; ii++) { // UInt32 fileIndex = allFilesMode ? indexIndex : indices[indexIndex]; UInt32 ref2Index = allFilesMode ? ii : indices[ii]; // const CRef2 &ref2 = _refs[ref2Index]; // for(UInt32 ri = 0; ri < ref2.Refs.Size(); ri++) { #ifdef _7Z_VOL // const CRef &ref = ref2.Refs[ri]; const CRef &ref = _refs[ref2Index]; int volumeIndex = ref.VolumeIndex; const CVolume &volume = _volumes[volumeIndex]; const CArchiveDatabaseEx &database = volume.Database; UInt32 fileIndex = ref.ItemIndex; #else const CArchiveDatabaseEx &database = _database; UInt32 fileIndex = ref2Index; #endif CNum folderIndex = database.FileIndexToFolderIndexMap[fileIndex]; if (folderIndex == kNumNoIndex) { extractFolderInfoVector.Add(CExtractFolderInfo( #ifdef _7Z_VOL volumeIndex, #endif fileIndex, kNumNoIndex)); continue; } if (extractFolderInfoVector.IsEmpty() || folderIndex != extractFolderInfoVector.Back().FolderIndex #ifdef _7Z_VOL || volumeIndex != extractFolderInfoVector.Back().VolumeIndex #endif ) { extractFolderInfoVector.Add(CExtractFolderInfo( #ifdef _7Z_VOL volumeIndex, #endif kNumNoIndex, folderIndex)); const CFolder &folderInfo = database.Folders[folderIndex]; UInt64 unPackSize = folderInfo.GetUnPackSize(); importantTotalUnPacked += unPackSize; extractFolderInfoVector.Back().UnPackSize = unPackSize; } CExtractFolderInfo &efi = extractFolderInfoVector.Back(); // const CFolderInfo &folderInfo = m_dam_Folders[folderIndex]; CNum startIndex = database.FolderStartFileIndex[folderIndex]; for (CNum index = efi.ExtractStatuses.Size(); index <= fileIndex - startIndex; index++) { // UInt64 unPackSize = _database.Files[startIndex + index].UnPackSize; // Count partial_folder_size // efi.UnPackSize += unPackSize; // importantTotalUnPacked += unPackSize; efi.ExtractStatuses.Add(index == fileIndex - startIndex); } } } extractCallback->SetTotal(importantTotalUnPacked); CDecoder decoder( #ifdef _ST_MODE false #else true #endif ); // CDecoder1 decoder; UInt64 currentTotalPacked = 0; UInt64 currentTotalUnPacked = 0; UInt64 totalFolderUnPacked; UInt64 totalFolderPacked; CLocalProgress *lps = new CLocalProgress; CMyComPtr progress = lps; lps->Init(extractCallback, false); for(int i = 0; i < extractFolderInfoVector.Size(); i++, currentTotalUnPacked += totalFolderUnPacked, currentTotalPacked += totalFolderPacked) { lps->OutSize = currentTotalUnPacked; lps->InSize = currentTotalPacked; RINOK(lps->SetCur()); const CExtractFolderInfo &efi = extractFolderInfoVector[i]; totalFolderUnPacked = efi.UnPackSize; totalFolderPacked = 0; CFolderOutStream *folderOutStream = new CFolderOutStream; CMyComPtr outStream(folderOutStream); #ifdef _7Z_VOL const CVolume &volume = _volumes[efi.VolumeIndex]; const CArchiveDatabaseEx &database = volume.Database; #else const CArchiveDatabaseEx &database = _database; #endif CNum startIndex; if (efi.FileIndex != kNumNoIndex) startIndex = efi.FileIndex; else startIndex = database.FolderStartFileIndex[efi.FolderIndex]; HRESULT result = folderOutStream->Init(&database, #ifdef _7Z_VOL volume.StartRef2Index, #else 0, #endif startIndex, &efi.ExtractStatuses, extractCallback, testMode, _crcSize != 0); RINOK(result); if (efi.FileIndex != kNumNoIndex) continue; CNum folderIndex = efi.FolderIndex; const CFolder &folderInfo = database.Folders[folderIndex]; totalFolderPacked = _database.GetFolderFullPackSize(folderIndex); CNum packStreamIndex = database.FolderStartPackStreamIndex[folderIndex]; UInt64 folderStartPackPos = database.GetFolderStreamPos(folderIndex, 0); #ifndef _NO_CRYPTO CMyComPtr getTextPassword; if (extractCallback) extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); #endif try { HRESULT result = decoder.Decode( EXTERNAL_CODECS_VARS #ifdef _7Z_VOL volume.Stream, #else _inStream, #endif folderStartPackPos, &database.PackSizes[packStreamIndex], folderInfo, outStream, progress #ifndef _NO_CRYPTO , getTextPassword #endif #ifdef COMPRESS_MT , true, _numThreads #endif ); if (result == S_FALSE) { RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError)); continue; } if (result == E_NOTIMPL) { RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kUnSupportedMethod)); continue; } if (result != S_OK) return result; if (folderOutStream->WasWritingFinished() != S_OK) { RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError)); continue; } } catch(...) { RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError)); continue; } } return S_OK; COM_TRY_END } }}