// Extract.cpp #include "StdAfx.h" #include "Extract.h" #include "Windows/Defs.h" #include "Windows/FileDir.h" #include "OpenArchive.h" #include "SetProperties.h" using namespace NWindows; HRESULT DecompressArchive( IInArchive *archive, UInt64 packSize, const UString &defaultName, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &options, IExtractCallbackUI *callback, CArchiveExtractCallback *extractCallbackSpec, UString &errorMessage) { CRecordVector realIndices; UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); for(UInt32 i = 0; i < numItems; i++) { UString filePath; RINOK(GetArchiveItemPath(archive, i, options.DefaultItemName, filePath)); bool isFolder; RINOK(IsArchiveItemFolder(archive, i, isFolder)); if (!wildcardCensor.CheckPath(filePath, !isFolder)) continue; realIndices.Add(i); } if (realIndices.Size() == 0) { callback->ThereAreNoFiles(); return S_OK; } UStringVector removePathParts; UString outDir = options.OutputDir; outDir.Replace(L"*", defaultName); if(!outDir.IsEmpty()) if(!NFile::NDirectory::CreateComplexDirectory(outDir)) { HRESULT res = ::GetLastError(); if (res == S_OK) res = E_FAIL; errorMessage = ((UString)L"Can not create output directory ") + outDir; return res; } extractCallbackSpec->Init( archive, callback, options.StdOutMode, outDir, removePathParts, options.DefaultItemName, options.ArchiveFileInfo.LastWriteTime, options.ArchiveFileInfo.Attributes, packSize); #ifdef COMPRESS_MT RINOK(SetProperties(archive, options.Properties)); #endif HRESULT result = archive->Extract(&realIndices.Front(), realIndices.Size(), options.TestMode? 1: 0, extractCallbackSpec); return callback->ExtractResult(result); } HRESULT DecompressArchives( CCodecs *codecs, UStringVector &archivePaths, UStringVector &archivePathsFull, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &optionsSpec, IOpenCallbackUI *openCallback, IExtractCallbackUI *extractCallback, UString &errorMessage, CDecompressStat &stat) { stat.Clear(); CExtractOptions options = optionsSpec; int i; UInt64 totalPackSize = 0; for (i = 0; i < archivePaths.Size(); i++) { const UString &archivePath = archivePaths[i]; NFile::NFind::CFileInfoW archiveFileInfo; if (!NFile::NFind::FindFile(archivePath, archiveFileInfo)) throw "there is no such archive"; if (archiveFileInfo.IsDirectory()) throw "can't decompress folder"; totalPackSize += archiveFileInfo.Size; } CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; CMyComPtr ec(extractCallbackSpec); bool multi = (archivePaths.Size() > 1); extractCallbackSpec->InitForMulti(multi, options.PathMode, options.OverwriteMode); if (multi) { RINOK(extractCallback->SetTotal(totalPackSize)); } for (i = 0; i < archivePaths.Size(); i++) { const UString &archivePath = archivePaths[i]; NFile::NFind::CFileInfoW archiveFileInfo; if (!NFile::NFind::FindFile(archivePath, archiveFileInfo)) throw "there is no such archive"; if (archiveFileInfo.IsDirectory()) throw "there is no such archive"; options.ArchiveFileInfo = archiveFileInfo; #ifndef _NO_CRYPTO openCallback->ClearPasswordWasAskedFlag(); #endif RINOK(extractCallback->BeforeOpen(archivePath)); CArchiveLink archiveLink; HRESULT result = MyOpenArchive(codecs, archivePath, archiveLink, openCallback); bool crypted = false; #ifndef _NO_CRYPTO crypted = openCallback->WasPasswordAsked(); #endif RINOK(extractCallback->OpenResult(archivePath, result, crypted)); if (result != S_OK) continue; for (int v = 0; v < archiveLink.VolumePaths.Size(); v++) { int index = archivePathsFull.FindInSorted(archiveLink.VolumePaths[v]); if (index >= 0 && index > i) { archivePaths.Delete(index); archivePathsFull.Delete(index); } } #ifndef _NO_CRYPTO UString password; RINOK(openCallback->GetPasswordIfAny(password)); if (!password.IsEmpty()) { RINOK(extractCallback->SetPassword(password)); } #endif options.DefaultItemName = archiveLink.GetDefaultItemName(); RINOK(DecompressArchive( archiveLink.GetArchive(), archiveFileInfo.Size, archiveLink.GetDefaultItemName(), wildcardCensor, options, extractCallback, extractCallbackSpec, errorMessage)); extractCallbackSpec->LocalProgressSpec->InSize += archiveFileInfo.Size + archiveLink.VolumesSize; extractCallbackSpec->LocalProgressSpec->OutSize = extractCallbackSpec->UnpackSize; if (!errorMessage.IsEmpty()) return E_FAIL; } stat.NumFolders = extractCallbackSpec->NumFolders; stat.NumFiles = extractCallbackSpec->NumFiles; stat.UnpackSize = extractCallbackSpec->UnpackSize; stat.NumArchives = archivePaths.Size(); stat.PackSize = extractCallbackSpec->LocalProgressSpec->InSize; return S_OK; }