diff options
Diffstat (limited to '3rdparty/lzma/CPP/7zip/UI/Common/Extract.cpp')
-rw-r--r-- | 3rdparty/lzma/CPP/7zip/UI/Common/Extract.cpp | 416 |
1 files changed, 315 insertions, 101 deletions
diff --git a/3rdparty/lzma/CPP/7zip/UI/Common/Extract.cpp b/3rdparty/lzma/CPP/7zip/UI/Common/Extract.cpp index 81186772a62..14aa74072bc 100644 --- a/3rdparty/lzma/CPP/7zip/UI/Common/Extract.cpp +++ b/3rdparty/lzma/CPP/7zip/UI/Common/Extract.cpp @@ -2,11 +2,13 @@ #include "StdAfx.h" -#include <stdio.h> +#include "../../../../C/Sort.h" -#include "Windows/FileDir.h" -#include "Windows/PropVariant.h" -#include "Windows/PropVariantConversions.h" +#include "../../../Common/StringConvert.h" + +#include "../../../Windows/FileDir.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantConv.h" #include "../Common/ExtractingFilePath.h" @@ -14,111 +16,249 @@ #include "SetProperties.h" using namespace NWindows; +using namespace NFile; +using namespace NDir; static HRESULT DecompressArchive( - const CArc &arc, + CCodecs *codecs, + const CArchiveLink &arcLink, UInt64 packSize, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &options, + bool calcCrc, IExtractCallbackUI *callback, - CArchiveExtractCallback *extractCallbackSpec, + CArchiveExtractCallback *ecs, UString &errorMessage, UInt64 &stdInProcessed) { + const CArc &arc = arcLink.Arcs.Back(); stdInProcessed = 0; IInArchive *archive = arc.Archive; CRecordVector<UInt32> realIndices; + + UStringVector removePathParts; + + FString outDir = options.OutputDir; + UString replaceName = arc.DefaultName; + + if (arcLink.Arcs.Size() > 1) + { + // Most "pe" archives have same name of archive subfile "[0]" or ".rsrc_1". + // So it extracts different archives to one folder. + // We will use top level archive name + const CArc &arc0 = arcLink.Arcs[0]; + if (StringsAreEqualNoCase_Ascii(codecs->Formats[arc0.FormatIndex].Name, "pe")) + replaceName = arc0.DefaultName; + } + + outDir.Replace(FSTRING_ANY_MASK, us2fs(Get_Correct_FsFile_Name(replaceName))); + + bool elimIsPossible = false; + UString elimPrefix; // only pure name without dir delimiter + FString outDirReduced = outDir; + + if (options.ElimDup.Val && options.PathMode != NExtract::NPathMode::kAbsPaths) + { + UString dirPrefix; + SplitPathToParts_Smart(fs2us(outDir), dirPrefix, elimPrefix); + if (!elimPrefix.IsEmpty()) + { + if (IsPathSepar(elimPrefix.Back())) + elimPrefix.DeleteBack(); + if (!elimPrefix.IsEmpty()) + { + outDirReduced = us2fs(dirPrefix); + elimIsPossible = true; + } + } + } + + bool allFilesAreAllowed = wildcardCensor.AreAllAllowed(); + if (!options.StdInMode) { UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); + CReadArcItem item; + 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)) + if (elimIsPossible || !allFilesAreAllowed) + { + RINOK(arc.GetItem(i, item)); + } + else + { + #ifdef SUPPORT_ALT_STREAMS + item.IsAltStream = false; + if (!options.NtOptions.AltStreams.Val && arc.Ask_AltStream) + { + RINOK(Archive_IsItem_AltStream(arc.Archive, i, item.IsAltStream)); + } + #endif + } + + #ifdef SUPPORT_ALT_STREAMS + if (!options.NtOptions.AltStreams.Val && item.IsAltStream) continue; + #endif + + if (elimIsPossible) + { + const UString &s = + #ifdef SUPPORT_ALT_STREAMS + item.MainPath; + #else + item.Path; + #endif + if (!IsPath1PrefixedByPath2(s, elimPrefix)) + elimIsPossible = false; + else + { + wchar_t c = s[elimPrefix.Len()]; + if (c == 0) + { + if (!item.MainIsDir) + elimIsPossible = false; + } + else if (!IsPathSepar(c)) + elimIsPossible = false; + } + } + + if (!allFilesAreAllowed) + { + if (!CensorNode_CheckPath(wildcardCensor, item)) + continue; + } + realIndices.Add(i); } + if (realIndices.Size() == 0) { callback->ThereAreNoFiles(); - return S_OK; + return callback->ExtractResult(S_OK); } } - UStringVector removePathParts; + if (elimIsPossible) + { + removePathParts.Add(elimPrefix); + // outDir = outDirReduced; + } - FString outDir = options.OutputDir; - outDir.Replace(FSTRING_ANY_MASK, us2fs(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 ") + fs2us(outDir); - return res; - } + if (outDir.IsEmpty()) + outDir = FTEXT(".") FSTRING_PATH_SEPARATOR; + /* + #ifdef _WIN32 + else if (NName::IsAltPathPrefix(outDir)) {} + #endif + */ + else if (!CreateComplexDir(outDir)) + { + HRESULT res = ::GetLastError(); + if (res == S_OK) + res = E_FAIL; + errorMessage.SetFromAscii("Can not create output directory: "); + errorMessage += fs2us(outDir); + return res; + } - extractCallbackSpec->Init( + ecs->Init( + options.NtOptions, options.StdInMode ? &wildcardCensor : NULL, &arc, callback, - options.StdOutMode, options.TestMode, options.CalcCrc, + options.StdOutMode, options.TestMode, outDir, - removePathParts, + removePathParts, false, packSize); - #if !defined(_7ZIP_ST) && !defined(_SFX) - RINOK(SetProperties(archive, options.Properties)); + + #ifdef SUPPORT_LINKS + + if (!options.StdInMode && + !options.TestMode && + options.NtOptions.HardLinks.Val) + { + RINOK(ecs->PrepareHardLinks(&realIndices)); + } + #endif + HRESULT result; - Int32 testMode = (options.TestMode && !options.CalcCrc) ? 1: 0; + Int32 testMode = (options.TestMode && !calcCrc) ? 1: 0; if (options.StdInMode) { - result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, extractCallbackSpec); + result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, ecs); NCOM::CPropVariant prop; if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK) - if (prop.vt == VT_UI8 || prop.vt == VT_UI4) - stdInProcessed = ConvertPropVariantToUInt64(prop); + ConvertPropVariantToUInt64(prop, stdInProcessed); } else - result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, extractCallbackSpec); - + result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, ecs); + if (result == S_OK && !options.StdInMode) + result = ecs->SetDirsTimes(); return callback->ExtractResult(result); } -HRESULT DecompressArchives( - CCodecs *codecs, const CIntVector &formatIndices, +/* v9.31: BUG was fixed: + Sorted list for file paths was sorted with case insensitive compare function. + But FindInSorted function did binary search via case sensitive compare function */ + +int Find_FileName_InSortedVector(const UStringVector &fileName, const UString &name) +{ + unsigned left = 0, right = fileName.Size(); + while (left != right) + { + unsigned mid = (left + right) / 2; + const UString &midValue = fileName[mid]; + int compare = CompareFileNames(name, midValue); + if (compare == 0) + return mid; + if (compare < 0) + right = mid; + else + left = mid + 1; + } + return -1; +} + +HRESULT Extract( + CCodecs *codecs, + const CObjectVector<COpenType> &types, + const CIntVector &excludedFormats, UStringVector &arcPaths, UStringVector &arcPathsFull, const NWildcard::CCensorNode &wildcardCensor, const CExtractOptions &options, IOpenCallbackUI *openCallback, IExtractCallbackUI *extractCallback, + #ifndef _SFX + IHashCalc *hash, + #endif UString &errorMessage, - CDecompressStat &stat) + CDecompressStat &st) { - stat.Clear(); - int i; + st.Clear(); UInt64 totalPackSize = 0; - CRecordVector<UInt64> archiveSizes; + CRecordVector<UInt64> arcSizes; - int numArcs = options.StdInMode ? 1 : arcPaths.Size(); + unsigned numArcs = options.StdInMode ? 1 : arcPaths.Size(); + unsigned i; + for (i = 0; i < numArcs; i++) { - NFile::NFind::CFileInfo fi; + NFind::CFileInfo fi; fi.Size = 0; if (!options.StdInMode) { @@ -128,21 +268,37 @@ HRESULT DecompressArchives( if (fi.IsDir()) throw "can't decompress folder"; } - archiveSizes.Add(fi.Size); + arcSizes.Add(fi.Size); totalPackSize += fi.Size; } - CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback; - CMyComPtr<IArchiveExtractCallback> ec(extractCallbackSpec); + + CBoolArr skipArcs(numArcs); + for (i = 0; i < numArcs; i++) + skipArcs[i] = false; + + CArchiveExtractCallback *ecs = new CArchiveExtractCallback; + CMyComPtr<IArchiveExtractCallback> ec(ecs); bool multi = (numArcs > 1); - extractCallbackSpec->InitForMulti(multi, options.PathMode, options.OverwriteMode); + ecs->InitForMulti(multi, options.PathMode, options.OverwriteMode); + #ifndef _SFX + ecs->SetHashMethods(hash); + #endif + if (multi) { RINOK(extractCallback->SetTotal(totalPackSize)); } + + UInt64 totalPackProcessed = 0; + bool thereAreNotOpenArcs = false; + for (i = 0; i < numArcs; i++) { + if (skipArcs[i]) + continue; + const UString &arcPath = arcPaths[i]; - NFile::NFind::CFileInfo fi; + NFind::CFileInfo fi; if (options.StdInMode) { fi.Size = 0; @@ -154,21 +310,24 @@ HRESULT DecompressArchives( throw "there is no such archive"; } + /* #ifndef _NO_CRYPTO - openCallback->Open_ClearPasswordWasAskedFlag(); + openCallback->Open_Clear_PasswordWasAsked_Flag(); #endif + */ - RINOK(extractCallback->BeforeOpen(arcPath)); - CArchiveLink archiveLink; + RINOK(extractCallback->BeforeOpen(arcPath, options.TestMode)); + CArchiveLink arcLink; - CIntVector formatIndices2 = formatIndices; + CObjectVector<COpenType> types2 = types; + /* #ifndef _SFX - if (formatIndices.IsEmpty()) + if (types.IsEmpty()) { int pos = arcPath.ReverseFind(L'.'); if (pos >= 0) { - UString s = arcPath.Mid(pos + 1); + UString s = arcPath.Ptr(pos + 1); int index = codecs->FindFormatForExtension(s); if (index >= 0 && s == L"001") { @@ -176,88 +335,143 @@ HRESULT DecompressArchives( pos = s.ReverseFind(L'.'); if (pos >= 0) { - int index2 = codecs->FindFormatForExtension(s.Mid(pos + 1)); - if (index2 >= 0 && s.CompareNoCase(L"rar") != 0) + int index2 = codecs->FindFormatForExtension(s.Ptr(pos + 1)); + if (index2 >= 0) // && s.CompareNoCase(L"rar") != 0 { - formatIndices2.Add(index2); - formatIndices2.Add(index); + types2.Add(index2); + types2.Add(index); } } } } } #endif - HRESULT result = archiveLink.Open2(codecs, formatIndices2, options.StdInMode, NULL, arcPath, openCallback); + */ + + COpenOptions op; + #ifndef _SFX + op.props = &options.Properties; + #endif + op.codecs = codecs; + op.types = &types2; + op.excludedFormats = &excludedFormats; + op.stdInMode = options.StdInMode; + op.stream = NULL; + op.filePath = arcPath; + + HRESULT result = arcLink.Open3(op, openCallback); + if (result == E_ABORT) return result; - bool crypted = false; - #ifndef _NO_CRYPTO - crypted = openCallback->Open_WasPasswordAsked(); - #endif + if (result == S_OK && arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) + result = S_FALSE; + + // arcLink.Set_ErrorsText(); + RINOK(extractCallback->OpenResult(codecs, arcLink, arcPath, result)); - RINOK(extractCallback->OpenResult(arcPath, result, crypted)); if (result != S_OK) + { + thereAreNotOpenArcs = true; + if (!options.StdInMode) + { + NFind::CFileInfo fi; + if (fi.Find(us2fs(arcPath))) + if (!fi.IsDir()) + totalPackProcessed += fi.Size; + } 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) + // numVolumes += arcLink.VolumePaths.Size(); + // arcLink.VolumesSize; + + // totalPackSize -= DeleteUsedFileNamesFromList(arcLink, i + 1, arcPaths, arcPathsFull, &arcSizes); + // numArcs = arcPaths.Size(); + if (arcLink.VolumePaths.Size() != 0) { - arcPaths.Delete(index); - arcPathsFull.Delete(index); - totalPackSize -= archiveSizes[index]; - archiveSizes.Delete(index); - numArcs = arcPaths.Size(); + Int64 correctionSize = arcLink.VolumesSize; + FOR_VECTOR (v, arcLink.VolumePaths) + { + int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]); + if (index >= 0) + { + if ((unsigned)index > i) + { + skipArcs[(unsigned)index] = true; + correctionSize -= arcSizes[(unsigned)index]; + } + } + } + if (correctionSize != 0) + { + Int64 newPackSize = (Int64)totalPackSize + correctionSize; + if (newPackSize < 0) + newPackSize = 0; + totalPackSize = newPackSize; + RINOK(extractCallback->SetTotal(totalPackSize)); + } } } - if (archiveLink.VolumePaths.Size() != 0) - { - totalPackSize += archiveLink.VolumesSize; - RINOK(extractCallback->SetTotal(totalPackSize)); - } + + /* + // Now openCallback and extractCallback use same object. So we don't need to send password. #ifndef _NO_CRYPTO + bool passwordIsDefined; UString password; - RINOK(openCallback->Open_GetPasswordIfAny(password)); - if (!password.IsEmpty()) + RINOK(openCallback->Open_GetPasswordIfAny(passwordIsDefined, password)); + if (passwordIsDefined) { 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(); + CArc &arc = arcLink.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)); + bool calcCrc = + #ifndef _SFX + (hash != NULL); + #else + false; + #endif + + RINOK(DecompressArchive( + codecs, + arcLink, + fi.Size + arcLink.VolumesSize, + wildcardCensor, + options, + calcCrc, + extractCallback, ecs, errorMessage, packProcessed)); + if (!options.StdInMode) - packProcessed = fi.Size + archiveLink.VolumesSize; - extractCallbackSpec->LocalProgressSpec->InSize += packProcessed; - extractCallbackSpec->LocalProgressSpec->OutSize = extractCallbackSpec->UnpackSize; + packProcessed = fi.Size + arcLink.VolumesSize; + totalPackProcessed += packProcessed; + ecs->LocalProgressSpec->InSize += packProcessed; + ecs->LocalProgressSpec->OutSize = ecs->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; + if (multi || thereAreNotOpenArcs) + { + RINOK(extractCallback->SetTotal(totalPackSize)); + RINOK(extractCallback->SetCompleted(&totalPackProcessed)); + } + + st.NumFolders = ecs->NumFolders; + st.NumFiles = ecs->NumFiles; + st.NumAltStreams = ecs->NumAltStreams; + st.UnpackSize = ecs->UnpackSize; + st.AltStreams_UnpackSize = ecs->AltStreams_UnpackSize; + st.NumArchives = arcPaths.Size(); + st.PackSize = ecs->LocalProgressSpec->InSize; return S_OK; } |