// Extract.cpp #include "StdAfx.h" #include "Extract.h" #include "Windows/Defs.h" #include "Windows/FileDir.h" #include "OpenArchive.h" #include "SetProperties.h" #ifndef EXCLUDE_COM #include "Windows/DLL.h" #endif using namespace NWindows; HRESULT DecompressArchive( IInArchive *archive, const UString &defaultName, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &options, IExtractCallbackUI *callback, 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; } CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; CMyComPtr extractCallback(extractCallbackSpec); 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, options.PathMode, options.OverwriteMode, removePathParts, options.DefaultItemName, options.ArchiveFileInfo.LastWriteTime, options.ArchiveFileInfo.Attributes); #ifdef COMPRESS_MT RINOK(SetProperties(archive, options.Properties)); #endif HRESULT result = archive->Extract(&realIndices.Front(), realIndices.Size(), options.TestMode? 1: 0, extractCallback); return callback->ExtractResult(result); } HRESULT DecompressArchives( UStringVector &archivePaths, UStringVector &archivePathsFull, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &optionsSpec, IOpenCallbackUI *openCallback, IExtractCallbackUI *extractCallback, UString &errorMessage) { CExtractOptions options = optionsSpec; for (int 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(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(), archiveLink.GetDefaultItemName(), wildcardCensor, options, extractCallback, errorMessage)); if (!errorMessage.IsEmpty()) return E_FAIL; } return S_OK; }