summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/lzma/CPP/7zip/UI/Common/Extract.cpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/lzma/CPP/7zip/UI/Common/Extract.cpp')
-rw-r--r--3rdparty/lzma/CPP/7zip/UI/Common/Extract.cpp416
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;
}