| // 7zExtract.cpp | |
| #include "StdAfx.h" | |
| #include "../../../Common/ComTry.h" | |
| #include "../../Common/ProgressUtils.h" | |
| #include "7zDecode.h" | |
| // #include "7z1Decode.h" | |
| #include "7zFolderOutStream.h" | |
| #include "7zHandler.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.ClearAndSetSize(1); | |
| ExtractStatuses[0] = true; | |
| } | |
| }; | |
| }; | |
| STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, | |
| Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec) | |
| { | |
| COM_TRY_BEGIN | |
| bool testMode = (testModeSpec != 0); | |
| CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec; | |
| UInt64 importantTotalUnpacked = 0; | |
| bool allFilesMode = (numItems == (UInt32)(Int32)-1); | |
| if (allFilesMode) | |
| numItems = | |
| #ifdef _7Z_VOL | |
| _refs.Size(); | |
| #else | |
| _db.Files.Size(); | |
| #endif | |
| if(numItems == 0) | |
| return S_OK; | |
| /* | |
| if(_volumes.Size() != 1) | |
| return E_FAIL; | |
| const CVolume &volume = _volumes.Front(); | |
| const CDbEx &_db = volume.Database; | |
| IInStream *_inStream = volume.Stream; | |
| */ | |
| CObjectVector<CExtractFolderInfo> 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 CDbEx &db = volume.Database; | |
| UInt32 fileIndex = ref.ItemIndex; | |
| #else | |
| const CDbEx &db = _db; | |
| UInt32 fileIndex = ref2Index; | |
| #endif | |
| CNum folderIndex = db.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)); | |
| UInt64 unpackSize = db.GetFolderUnpackSize(folderIndex); | |
| importantTotalUnpacked += unpackSize; | |
| extractFolderInfoVector.Back().UnpackSize = unpackSize; | |
| } | |
| CExtractFolderInfo &efi = extractFolderInfoVector.Back(); | |
| // const CFolderInfo &folderInfo = m_dam_Folders[folderIndex]; | |
| CNum startIndex = db.FolderStartFileIndex[folderIndex]; | |
| for (CNum index = efi.ExtractStatuses.Size(); | |
| index <= fileIndex - startIndex; index++) | |
| { | |
| // UInt64 unpackSize = _db.Files[startIndex + index].UnpackSize; | |
| // Count partial_folder_size | |
| // efi.UnpackSize += unpackSize; | |
| // importantTotalUnpacked += unpackSize; | |
| efi.ExtractStatuses.Add(index == fileIndex - startIndex); | |
| } | |
| } | |
| } | |
| RINOK(extractCallback->SetTotal(importantTotalUnpacked)); | |
| CDecoder decoder( | |
| #ifdef _ST_MODE | |
| false | |
| #else | |
| true | |
| #endif | |
| ); | |
| // CDecoder1 decoder; | |
| UInt64 totalPacked = 0; | |
| UInt64 totalUnpacked = 0; | |
| UInt64 curPacked, curUnpacked; | |
| CLocalProgress *lps = new CLocalProgress; | |
| CMyComPtr<ICompressProgressInfo> progress = lps; | |
| lps->Init(extractCallback, false); | |
| for (unsigned i = 0;; i++, totalUnpacked += curUnpacked, totalPacked += curPacked) | |
| { | |
| lps->OutSize = totalUnpacked; | |
| lps->InSize = totalPacked; | |
| RINOK(lps->SetCur()); | |
| if (i >= extractFolderInfoVector.Size()) | |
| break; | |
| const CExtractFolderInfo &efi = extractFolderInfoVector[i]; | |
| curUnpacked = efi.UnpackSize; | |
| curPacked = 0; | |
| CFolderOutStream *folderOutStream = new CFolderOutStream; | |
| CMyComPtr<ISequentialOutStream> outStream(folderOutStream); | |
| #ifdef _7Z_VOL | |
| const CVolume &volume = _volumes[efi.VolumeIndex]; | |
| const CDbEx &db = volume.Database; | |
| #else | |
| const CDbEx &db = _db; | |
| #endif | |
| CNum startIndex; | |
| if (efi.FileIndex != kNumNoIndex) | |
| startIndex = efi.FileIndex; | |
| else | |
| startIndex = db.FolderStartFileIndex[efi.FolderIndex]; | |
| HRESULT result = folderOutStream->Init(&db, | |
| #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; | |
| curPacked = _db.GetFolderFullPackSize(folderIndex); | |
| #ifndef _NO_CRYPTO | |
| CMyComPtr<ICryptoGetTextPassword> getTextPassword; | |
| if (extractCallback) | |
| extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); | |
| #endif | |
| try | |
| { | |
| #ifndef _NO_CRYPTO | |
| bool isEncrypted = false; | |
| bool passwordIsDefined = false; | |
| #endif | |
| HRESULT result = decoder.Decode( | |
| EXTERNAL_CODECS_VARS | |
| #ifdef _7Z_VOL | |
| volume.Stream, | |
| #else | |
| _inStream, | |
| #endif | |
| db.ArcInfo.DataStartPosition, | |
| db, folderIndex, | |
| outStream, | |
| progress | |
| _7Z_DECODER_CRYPRO_VARS | |
| #if !defined(_7ZIP_ST) && !defined(_SFX) | |
| , true, _numThreads | |
| #endif | |
| ); | |
| if (result == S_FALSE) | |
| { | |
| RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)); | |
| continue; | |
| } | |
| if (result == E_NOTIMPL) | |
| { | |
| RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kUnsupportedMethod)); | |
| continue; | |
| } | |
| if (result != S_OK) | |
| return result; | |
| if (folderOutStream->WasWritingFinished() != S_OK) | |
| { | |
| RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)); | |
| continue; | |
| } | |
| } | |
| catch(...) | |
| { | |
| RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError)); | |
| continue; | |
| } | |
| } | |
| return S_OK; | |
| COM_TRY_END | |
| } | |
| }} |