mirror of
https://github.com/Xevion/easy7zip.git
synced 2026-02-01 10:24:11 -06:00
9.34
This commit is contained in:
committed by
Kornel Lesiński
parent
83f8ddcc5b
commit
f08f4dcc3c
Executable → Regular
+289
-77
@@ -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,54 +16,117 @@
|
||||
#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(GetCorrectFsPath(replaceName)));
|
||||
|
||||
bool elimIsPossible = false;
|
||||
UString elimPrefix; // only pure name without dir delimiter
|
||||
FString outDirReduced = outDir;
|
||||
|
||||
if (options.ElimDup.Val)
|
||||
{
|
||||
UString dirPrefix;
|
||||
SplitPathToParts_Smart(fs2us(outDir), dirPrefix, elimPrefix);
|
||||
if (!elimPrefix.IsEmpty())
|
||||
{
|
||||
if (IsCharDirLimiter(elimPrefix.Back()))
|
||||
elimPrefix.DeleteBack();
|
||||
if (!elimPrefix.IsEmpty())
|
||||
{
|
||||
outDirReduced = us2fs(dirPrefix);
|
||||
elimIsPossible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.StdInMode)
|
||||
{
|
||||
UInt32 numItems;
|
||||
RINOK(archive->GetNumberOfItems(&numItems));
|
||||
|
||||
UString filePath;
|
||||
|
||||
for (UInt32 i = 0; i < numItems; i++)
|
||||
{
|
||||
UString filePath;
|
||||
RINOK(arc.GetItemPath(i, filePath));
|
||||
|
||||
if (elimIsPossible && options.ElimDup.Val)
|
||||
{
|
||||
if (!IsPath1PrefixedByPath2(filePath, elimPrefix))
|
||||
elimIsPossible = false;
|
||||
else
|
||||
{
|
||||
wchar_t c = filePath[elimPrefix.Len()];
|
||||
if (c != 0 && !IsCharDirLimiter(c))
|
||||
elimIsPossible = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool isFolder;
|
||||
RINOK(IsArchiveItemFolder(archive, i, isFolder));
|
||||
if (!wildcardCensor.CheckPath(filePath, !isFolder))
|
||||
RINOK(Archive_IsItem_Folder(archive, i, isFolder));
|
||||
bool isAltStream;
|
||||
RINOK(Archive_IsItem_AltStream(archive, i, isAltStream));
|
||||
if (!options.NtOptions.AltStreams.Val && isAltStream)
|
||||
continue;
|
||||
if (!wildcardCensor.CheckPath(isAltStream, filePath, !isFolder))
|
||||
continue;
|
||||
realIndices.Add(i);
|
||||
}
|
||||
|
||||
if (realIndices.Size() == 0)
|
||||
{
|
||||
callback->ThereAreNoFiles();
|
||||
return S_OK;
|
||||
return callback->ExtractResult(S_OK);
|
||||
}
|
||||
}
|
||||
|
||||
UStringVector removePathParts;
|
||||
if (elimIsPossible)
|
||||
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))
|
||||
if (outDir.IsEmpty())
|
||||
outDir = FString(FTEXT(".")) + FString(FSTRING_PATH_SEPARATOR);
|
||||
else
|
||||
if (!CreateComplexDir(outDir))
|
||||
{
|
||||
HRESULT res = ::GetLastError();
|
||||
if (res == S_OK)
|
||||
@@ -70,55 +135,92 @@ static HRESULT DecompressArchive(
|
||||
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,
|
||||
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)
|
||||
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)
|
||||
{
|
||||
stat.Clear();
|
||||
int i;
|
||||
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 +230,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;
|
||||
@@ -159,16 +277,17 @@ HRESULT DecompressArchives(
|
||||
#endif
|
||||
|
||||
RINOK(extractCallback->BeforeOpen(arcPath));
|
||||
CArchiveLink archiveLink;
|
||||
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,18 +295,31 @@ 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.Open2(op, openCallback);
|
||||
|
||||
if (result == E_ABORT)
|
||||
return result;
|
||||
|
||||
@@ -196,68 +328,148 @@ HRESULT DecompressArchives(
|
||||
crypted = openCallback->Open_WasPasswordAsked();
|
||||
#endif
|
||||
|
||||
RINOK(extractCallback->OpenResult(arcPath, result, crypted));
|
||||
if (result != S_OK)
|
||||
continue;
|
||||
if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
|
||||
result = S_FALSE;
|
||||
|
||||
// arcLink.Set_ErrorsText();
|
||||
RINOK(extractCallback->OpenResult(arcPath, result, crypted));
|
||||
|
||||
|
||||
if (!options.StdInMode)
|
||||
for (int v = 0; v < archiveLink.VolumePaths.Size(); v++)
|
||||
{
|
||||
int index = arcPathsFull.FindInSorted(archiveLink.VolumePaths[v]);
|
||||
if (index >= 0 && index > i)
|
||||
FOR_VECTOR (r, arcLink.Arcs)
|
||||
{
|
||||
arcPaths.Delete(index);
|
||||
arcPathsFull.Delete(index);
|
||||
totalPackSize -= archiveSizes[index];
|
||||
archiveSizes.Delete(index);
|
||||
numArcs = arcPaths.Size();
|
||||
const CArc &arc = arcLink.Arcs[r];
|
||||
const CArcErrorInfo &er = arc.ErrorInfo;
|
||||
if (er.IsThereErrorOrWarning())
|
||||
{
|
||||
RINOK(extractCallback->SetError(r, arc.Path,
|
||||
er.GetErrorFlags(), er.ErrorMessage,
|
||||
er.GetWarningFlags(), er.WarningMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (archiveLink.VolumePaths.Size() != 0)
|
||||
|
||||
if (result != S_OK)
|
||||
{
|
||||
totalPackSize += archiveLink.VolumesSize;
|
||||
RINOK(extractCallback->SetTotal(totalPackSize));
|
||||
thereAreNotOpenArcs = true;
|
||||
if (!options.StdInMode)
|
||||
{
|
||||
NFind::CFileInfo fi;
|
||||
if (fi.Find(us2fs(arcPath)))
|
||||
if (!fi.IsDir())
|
||||
totalPackProcessed += fi.Size;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!options.StdInMode)
|
||||
{
|
||||
// numVolumes += arcLink.VolumePaths.Size();
|
||||
// arcLink.VolumesSize;
|
||||
|
||||
// totalPackSize -= DeleteUsedFileNamesFromList(arcLink, i + 1, arcPaths, arcPathsFull, &arcSizes);
|
||||
// numArcs = arcPaths.Size();
|
||||
if (arcLink.VolumePaths.Size() != 0)
|
||||
{
|
||||
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[index] = true;
|
||||
correctionSize -= arcSizes[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (correctionSize != 0)
|
||||
{
|
||||
Int64 newPackSize = (Int64)totalPackSize + correctionSize;
|
||||
if (newPackSize < 0)
|
||||
newPackSize = 0;
|
||||
totalPackSize = newPackSize;
|
||||
RINOK(extractCallback->SetTotal(totalPackSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#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++)
|
||||
FOR_VECTOR (k, arcLink.Arcs)
|
||||
{
|
||||
const UString &s = archiveLink.Arcs[v].ErrorMessage;
|
||||
if (!s.IsEmpty())
|
||||
const CArc &arc = arcLink.Arcs[k];
|
||||
const CArcErrorInfo &er = arc.ErrorInfo;
|
||||
|
||||
if (er.ErrorFormatIndex >= 0)
|
||||
{
|
||||
RINOK(extractCallback->OpenTypeWarning(arc.Path,
|
||||
codecs->GetFormatNamePtr(arc.FormatIndex),
|
||||
codecs->GetFormatNamePtr(er.ErrorFormatIndex)))
|
||||
/*
|
||||
UString s = L"Can not open the file as [" + codecs->Formats[arc.ErrorFormatIndex].Name + L"] archive\n";
|
||||
s += L"The file is open as [" + codecs->Formats[arc.FormatIndex].Name + L"] archive";
|
||||
RINOK(extractCallback->MessageError(s));
|
||||
*/
|
||||
}
|
||||
{
|
||||
const UString &s = er.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;
|
||||
|
||||
if (multi || thereAreNotOpenArcs)
|
||||
{
|
||||
RINOK(extractCallback->SetTotal(totalPackSize));
|
||||
RINOK(extractCallback->SetCompleted(&totalPackProcessed));
|
||||
}
|
||||
stat.NumFolders = ecs->NumFolders;
|
||||
stat.NumFiles = ecs->NumFiles;
|
||||
stat.NumAltStreams = ecs->NumAltStreams;
|
||||
stat.UnpackSize = ecs->UnpackSize;
|
||||
stat.AltStreams_UnpackSize = ecs->AltStreams_UnpackSize;
|
||||
stat.NumArchives = arcPaths.Size();
|
||||
stat.PackSize = extractCallbackSpec->LocalProgressSpec->InSize;
|
||||
stat.PackSize = ecs->LocalProgressSpec->InSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user