// Extract.cpp #include "StdAfx.h" #include #include "Windows/FileDir.h" #include "Windows/PropVariant.h" #include "Windows/PropVariantConversions.h" #include "../Common/ExtractingFilePath.h" #include "Extract.h" #include "SetProperties.h" using namespace NWindows; static HRESULT DecompressArchive( const CArc &arc, UInt64 packSize, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &options, IExtractCallbackUI *callback, CArchiveExtractCallback *extractCallbackSpec, UString &errorMessage, UInt64 &stdInProcessed) { stdInProcessed = 0; IInArchive *archive = arc.Archive; CRecordVector realIndices; if (!options.StdInMode) { UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); for (UInt32 i = 0; i < numItems; i++) { UString filePath; RINOK(arc.GetItemPath(i, 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"*", GetCorrectFsPath(arc.DefaultName)); #ifdef _WIN32 // GetCorrectFullFsPath doesn't like "..". // outDir.TrimRight(); // outDir = GetCorrectFullFsPath(outDir); #endif 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( options.StdInMode ? &wildcardCensor : NULL, &arc, callback, options.StdOutMode, options.TestMode, options.CalcCrc, outDir, removePathParts, packSize); #if !defined(_7ZIP_ST) && !defined(_SFX) RINOK(SetProperties(archive, options.Properties)); #endif HRESULT result; Int32 testMode = (options.TestMode && !options.CalcCrc) ? 1: 0; if (options.StdInMode) { result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, extractCallbackSpec); NCOM::CPropVariant prop; if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK) if (prop.vt == VT_UI8 || prop.vt == VT_UI4) stdInProcessed = ConvertPropVariantToUInt64(prop); } else result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, extractCallbackSpec); return callback->ExtractResult(result); } HRESULT DecompressArchives( CCodecs *codecs, const CIntVector &formatIndices, UStringVector &arcPaths, UStringVector &arcPathsFull, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &options, IOpenCallbackUI *openCallback, IExtractCallbackUI *extractCallback, UString &errorMessage, CDecompressStat &stat) { stat.Clear(); int i; UInt64 totalPackSize = 0; CRecordVector archiveSizes; int numArcs = options.StdInMode ? 1 : arcPaths.Size(); for (i = 0; i < numArcs; i++) { NFile::NFind::CFileInfoW fi; fi.Size = 0; if (!options.StdInMode) { const UString &arcPath = arcPaths[i]; if (!fi.Find(arcPath)) throw "there is no such archive"; if (fi.IsDir()) throw "can't decompress folder"; } archiveSizes.Add(fi.Size); totalPackSize += fi.Size; } CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; CMyComPtr ec(extractCallbackSpec); bool multi = (numArcs > 1); extractCallbackSpec->InitForMulti(multi, options.PathMode, options.OverwriteMode); if (multi) { RINOK(extractCallback->SetTotal(totalPackSize)); } for (i = 0; i < numArcs; i++) { const UString &arcPath = arcPaths[i]; NFile::NFind::CFileInfoW fi; if (options.StdInMode) { fi.Size = 0; fi.Attrib = 0; } else { if (!fi.Find(arcPath) || fi.IsDir()) throw "there is no such archive"; } #ifndef _NO_CRYPTO openCallback->Open_ClearPasswordWasAskedFlag(); #endif RINOK(extractCallback->BeforeOpen(arcPath)); CArchiveLink archiveLink; CIntVector formatIndices2 = formatIndices; #ifndef _SFX if (formatIndices.IsEmpty()) { int pos = arcPath.ReverseFind(L'.'); if (pos >= 0) { UString s = arcPath.Mid(pos + 1); int index = codecs->FindFormatForExtension(s); if (index >= 0 && s == L"001") { s = arcPath.Left(pos); pos = s.ReverseFind(L'.'); if (pos >= 0) { int index2 = codecs->FindFormatForExtension(s.Mid(pos + 1)); if (index2 >= 0 && s.CompareNoCase(L"rar") != 0) { formatIndices2.Add(index2); formatIndices2.Add(index); } } } } } #endif HRESULT result = archiveLink.Open2(codecs, formatIndices2, options.StdInMode, NULL, arcPath, openCallback); if (result == E_ABORT) return result; bool crypted = false; #ifndef _NO_CRYPTO crypted = openCallback->Open_WasPasswordAsked(); #endif RINOK(extractCallback->OpenResult(arcPath, result, crypted)); if (result != S_OK) continue; if (!options.StdInMode) for (int v = 0; v < archiveLink.VolumePaths.Size(); v++) { int index = arcPathsFull.FindInSorted(archiveLink.VolumePaths[v]); if (index >= 0 && index > i) { arcPaths.Delete(index); arcPathsFull.Delete(index); totalPackSize -= archiveSizes[index]; archiveSizes.Delete(index); numArcs = arcPaths.Size(); } } if (archiveLink.VolumePaths.Size() != 0) { totalPackSize += archiveLink.VolumesSize; RINOK(extractCallback->SetTotal(totalPackSize)); } #ifndef _NO_CRYPTO UString password; RINOK(openCallback->Open_GetPasswordIfAny(password)); if (!password.IsEmpty()) { RINOK(extractCallback->SetPassword(password)); } #endif for (int v = 0; v < archiveLink.Arcs.Size(); v++) { const UString &s = archiveLink.Arcs[v].ErrorMessage; if (!s.IsEmpty()) { RINOK(extractCallback->MessageError(s)); } } CArc &arc = archiveLink.Arcs.Back(); arc.MTimeDefined = (!options.StdInMode && !fi.IsDevice); arc.MTime = fi.MTime; UInt64 packProcessed; RINOK(DecompressArchive(arc, fi.Size + archiveLink.VolumesSize, wildcardCensor, options, extractCallback, extractCallbackSpec, errorMessage, packProcessed)); if (!options.StdInMode) packProcessed = fi.Size + archiveLink.VolumesSize; extractCallbackSpec->LocalProgressSpec->InSize += packProcessed; extractCallbackSpec->LocalProgressSpec->OutSize = extractCallbackSpec->UnpackSize; if (!errorMessage.IsEmpty()) return E_FAIL; } stat.NumFolders = extractCallbackSpec->NumFolders; stat.NumFiles = extractCallbackSpec->NumFiles; stat.UnpackSize = extractCallbackSpec->UnpackSize; stat.CrcSum = extractCallbackSpec->CrcSum; stat.NumArchives = arcPaths.Size(); stat.PackSize = extractCallbackSpec->LocalProgressSpec->InSize; return S_OK; }