This commit is contained in:
softworkz 2026-04-17 07:52:33 +02:00 committed by GitHub
commit 61048d143e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 530 additions and 34 deletions

View file

@ -896,6 +896,8 @@ $O/DefaultName.o: ../../UI/Common/DefaultName.cpp
$(CXX) $(CXXFLAGS) $<
$O/EnumDirItems.o: ../../UI/Common/EnumDirItems.cpp
$(CXX) $(CXXFLAGS) $<
$O/ChainedExtract.o: ../../UI/Common/ChainedExtract.cpp
$(CXX) $(CXXFLAGS) $<
$O/Extract.o: ../../UI/Common/Extract.cpp
$(CXX) $(CXXFLAGS) $<
$O/ExtractingFilePath.o: ../../UI/Common/ExtractingFilePath.cpp

View file

@ -730,15 +730,18 @@ Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
stream = _stream;
const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
if (allFilesMode && !seqMode)
numItems = _items.Size();
if (_stream && numItems == 0)
return S_OK;
UInt64 totalSize = 0;
UInt32 i;
for (i = 0; i < numItems; i++)
totalSize += _items[allFilesMode ? i : indices[i]].Get_UnpackSize();
RINOK(extractCallback->SetTotal(totalSize))
if (!(seqMode && allFilesMode))
{
for (i = 0; i < numItems; i++)
totalSize += _items[allFilesMode ? i : indices[i]].Get_UnpackSize();
RINOK(extractCallback->SetTotal(totalSize))
}
UInt64 totalPackSize;
totalSize = totalPackSize = 0;

View file

@ -186,6 +186,7 @@ HRESULT CArchive::GetNextItemReal(CItemEx &item)
filled = false;
bool thereAreEmptyRecords = false;
unsigned numEmptyRecords = 0;
for (;;)
{
size_t processedSize = NFileHeader::kRecordSize;
@ -219,6 +220,9 @@ HRESULT CArchive::GetNextItemReal(CItemEx &item)
break;
item.HeaderSize += NFileHeader::kRecordSize;
thereAreEmptyRecords = true;
numEmptyRecords++;
if (!InStream && numEmptyRecords >= 2)
return S_OK;
RINOK(Progress(item, 0))
}
if (thereAreEmptyRecords)

View file

@ -101,6 +101,7 @@ UI_COMMON_OBJS = \
$O/Bench.o \
$O/DefaultName.o \
$O/EnumDirItems.o \
$O/ChainedExtract.o \
$O/Extract.o \
$O/ExtractingFilePath.o \
$O/HashCalc.o \

View file

@ -99,6 +99,7 @@ UI_COMMON_OBJS = \
$O/Bench.o \
$O/DefaultName.o \
$O/EnumDirItems.o \
$O/ChainedExtract.o \
$O/Extract.o \
$O/ExtractingFilePath.o \
$O/HashCalc.o \

View file

@ -48,6 +48,7 @@ UI_COMMON_OBJS = \
$O\CompressCall2.obj \
$O\DefaultName.obj \
$O\EnumDirItems.obj \
$O\ChainedExtract.obj \
$O\Extract.obj \
$O\ExtractingFilePath.obj \
$O\HashCalc.obj \

View file

@ -67,6 +67,7 @@ UI_COMMON_OBJS = \
$O\ArchiveExtractCallback.obj \
$O\ArchiveOpenCallback.obj \
$O\DefaultName.obj \
$O\ChainedExtract.obj \
$O\Extract.obj \
$O\ExtractingFilePath.obj \
$O\LoadCodecs.obj \

View file

@ -129,6 +129,7 @@ UI_COMMON_OBJS = \
$O/ArchiveExtractCallback.o \
$O/ArchiveOpenCallback.o \
$O/DefaultName.o \
$O/ChainedExtract.o \
$O/Extract.o \
$O/ExtractingFilePath.o \
$O/LoadCodecs.o \

View file

@ -76,6 +76,7 @@ UI_COMMON_OBJS = \
$O\ArchiveExtractCallback.obj \
$O\ArchiveOpenCallback.obj \
$O\DefaultName.obj \
$O\ChainedExtract.obj \
$O\Extract.obj \
$O\ExtractingFilePath.obj \
$O\LoadCodecs.obj \

View file

@ -3,6 +3,7 @@
#ifndef ZIP7_INC_STREAM_BINDER_H
#define ZIP7_INC_STREAM_BINDER_H
#include "../../Common/MyCom.h"
#include "../../Windows/Synchronization.h"
#include "../IStream.h"

View file

@ -187,6 +187,7 @@ enum Enum
kUseSlashMark,
kDisableWildcardParsing,
kElimDup,
kChainedExtract,
kFullPathMode,
kHardLinks,
@ -338,6 +339,7 @@ static const CSwitchForm kSwitchForms[] =
{ "spm", SWFRM_STRING_SINGL(0) },
{ "spd", SWFRM_SIMPLE },
{ "spe", SWFRM_MINUS },
{ "sce", SWFRM_MINUS },
{ "spf", SWFRM_STRING_SINGL(0) },
{ "snh", SWFRM_MINUS },
@ -1358,6 +1360,9 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
options.ExtractOptions.ElimDup.Def = true;
options.ExtractOptions.ElimDup.Val = !parser[NKey::kElimDup].WithMinus;
}
if (parser[NKey::kChainedExtract].ThereIs)
options.ExtractOptions.EnableChainedExtract = !parser[NKey::kChainedExtract].WithMinus;
NWildcard::ECensorPathMode censorPathMode = NWildcard::k_RelatPath;
bool fullPathMode = parser[NKey::kFullPathMode].ThereIs;

View file

@ -301,7 +301,8 @@ CArchiveExtractCallback::CArchiveExtractCallback():
// Write_MTime(true),
Is_elimPrefix_Mode(false),
_arc(NULL),
_multiArchives(false)
_multiArchives(false),
_disableProgress(false)
{
#ifdef Z7_USE_SECURITY_CODE
_saclEnabled = InitLocalPrivileges();
@ -311,6 +312,7 @@ CArchiveExtractCallback::CArchiveExtractCallback():
void CArchiveExtractCallback::InitBeforeNewArchive()
{
_disableProgress = false;
#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
ZoneBuf.Free();
#endif
@ -403,6 +405,8 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetTotal(UInt64 size))
COM_TRY_BEGIN
_progressTotal = size;
// _progressTotal_Defined = true;
if (_disableProgress)
return S_OK;
if (!_multiArchives && _extractCallback2)
return _extractCallback2->SetTotal(size);
return S_OK;
@ -438,6 +442,9 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue))
if (!_extractCallback2)
return S_OK;
if (_disableProgress)
return S_OK;
UInt64 packCur;
if (_multiArchives)
{
@ -455,6 +462,8 @@ Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue))
Z7_COM7F_IMF(CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
{
COM_TRY_BEGIN
if (_disableProgress)
return S_OK;
return LocalProgressSpec.Interface()->SetRatioInfo(inSize, outSize);
COM_TRY_END
}

View file

@ -391,6 +391,7 @@ private:
bool _some_pathParts_wereRemoved;
bool _multiArchives;
bool _disableProgress;
bool _keepAndReplaceEmptyDirPrefixes; // replace them to "_";
#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
bool _saclEnabled;
@ -529,6 +530,11 @@ public:
void InitBeforeNewArchive();
void DisableProgress()
{
_disableProgress = true;
}
void Init(
const CExtractNtOptions &ntOptions,
const NWildcard::CCensorNode *wildcardCensor,

View file

@ -0,0 +1,294 @@
// ChainedExtract.cpp
#include "StdAfx.h"
#include "../../Common/StreamBinder.h"
#include "../../Common/VirtThread.h"
#include "ChainedExtract.h"
static void SetExtractOpResMessage(Int32 opRes, UString &message)
{
message.Empty();
switch (opRes)
{
case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
message = "Unsupported Method";
break;
case NArchive::NExtract::NOperationResult::kDataError:
message = "Data Error";
break;
case NArchive::NExtract::NOperationResult::kCRCError:
message = "CRC Failed";
break;
case NArchive::NExtract::NOperationResult::kUnavailable:
message = "Unavailable data";
break;
case NArchive::NExtract::NOperationResult::kUnexpectedEnd:
message = "Unexpected end of data";
break;
case NArchive::NExtract::NOperationResult::kDataAfterEnd:
message = "There are some data after the end of the payload data";
break;
case NArchive::NExtract::NOperationResult::kIsNotArc:
message = "Is not archive";
break;
case NArchive::NExtract::NOperationResult::kHeadersError:
message = "Headers Error";
break;
case NArchive::NExtract::NOperationResult::kWrongPassword:
message = "Wrong password";
break;
}
}
static HRESULT CheckOuterStreamResult(Int32 opRes, UString &errorMessage)
{
if (opRes == NArchive::NExtract::NOperationResult::kOK)
return S_OK;
SetExtractOpResMessage(opRes, errorMessage);
if (errorMessage.IsEmpty())
errorMessage = "Error";
errorMessage = UString("Outer stream: ") + errorMessage;
return E_FAIL;
}
static HRESULT DrainChainedStream(ISequentialInStream *stream)
{
Byte buf[1 << 15];
for (;;)
{
UInt32 processed = 0;
RINOK(stream->Read(buf, (UInt32)sizeof(buf), &processed))
if (processed == 0)
return S_OK;
}
}
Z7_CLASS_IMP_COM_1(
CChainedStreamExtractCallback
, IArchiveExtractCallback
)
Z7_IFACE_COM7_IMP(IProgress)
public:
CMyComPtr<IFolderArchiveExtractCallback> Progress;
CMyComPtr<ISequentialOutStream> Stream;
Int32 OperationResult;
bool MultiMode;
UInt64 CompletedBeforeArc;
void Init(IFolderArchiveExtractCallback *progress, ISequentialOutStream *stream,
bool multiMode, UInt64 completedBeforeArc)
{
Progress = progress;
Stream = stream;
OperationResult = NArchive::NExtract::NOperationResult::kOK;
MultiMode = multiMode;
CompletedBeforeArc = completedBeforeArc;
}
};
Z7_COM7F_IMF(CChainedStreamExtractCallback::SetTotal(UInt64 size))
{
if (MultiMode)
return S_OK;
return Progress ? Progress->SetTotal(size) : S_OK;
}
Z7_COM7F_IMF(CChainedStreamExtractCallback::SetCompleted(const UInt64 *completeValue))
{
if (MultiMode)
{
if (!Progress || !completeValue)
return S_OK;
const UInt64 completed = CompletedBeforeArc + *completeValue;
return Progress->SetCompleted(&completed);
}
return Progress ? Progress->SetCompleted(completeValue) : S_OK;
}
Z7_COM7F_IMF(CChainedStreamExtractCallback::GetStream(
UInt32 index, ISequentialOutStream **outStream, Int32 /* askExtractMode */))
{
*outStream = NULL;
if (index != 0 || !Stream)
return E_FAIL;
*outStream = Stream.Detach();
return S_OK;
}
Z7_COM7F_IMF(CChainedStreamExtractCallback::PrepareOperation(Int32 /* askExtractMode */))
{
return S_OK;
}
Z7_COM7F_IMF(CChainedStreamExtractCallback::SetOperationResult(Int32 opRes))
{
OperationResult = opRes;
return S_OK;
}
struct CChainedStreamExtractThread Z7_final:
public CVirtThread
{
const CArc *Arc;
CMyComPtr<IArchiveExtractCallback> Callback;
HRESULT Result;
CChainedStreamExtractThread():
Arc(NULL),
Result(S_OK)
{}
void Execute() Z7_override
{
Result = Arc->Archive->Extract(NULL, (UInt32)(Int32)-1, 0, Callback);
}
};
static int FindChainedFormatIndex(
const CCodecs *codecs,
const CArc &arc,
const CExtractOptions &options)
{
if (!options.EnableChainedExtract)
return -1;
if (options.StdInMode || options.StdOutMode)
return -1;
if (arc.FormatIndex < 0)
return -1;
const CArcInfoEx &ai = codecs->Formats[(unsigned)arc.FormatIndex];
const UString wrappedExt = ai.GetWrappedExt();
if (wrappedExt.IsEmpty())
return -1;
UInt32 numItems = 0;
if (arc.Archive->GetNumberOfItems(&numItems) != S_OK || numItems != 1)
return -1;
UString ext(wrappedExt);
if (ext.IsPrefixedBy(L"."))
ext.DeleteFrontal(1);
const int dotPos = arc.DefaultName.ReverseFind_Dot();
if (dotPos < 0)
return -1;
if (!ext.IsEqualTo_NoCase(arc.DefaultName.Ptr((unsigned)(dotPos + 1))))
return -1;
FOR_VECTOR (i, codecs->Formats)
if (codecs->Formats[i].FindExtension(ext) >= 0)
return (int)i;
return -1;
}
HRESULT TryChainedExtract(
CCodecs *codecs,
const CArchiveLink &arcLink,
UInt64 packSize,
UInt64 completedBeforeArc,
bool multi,
const NWildcard::CCensorNode &wildcardCensor,
const CExtractOptions &options,
bool calcCrc,
IExtractCallbackUI *callback,
IFolderArchiveExtractCallback *callbackFAE,
CArchiveExtractCallback *ecs,
UString &errorMessage)
{
const CArc &arc = arcLink.Arcs.Back();
const int innerFormatIndex = FindChainedFormatIndex(codecs, arc, options);
if (innerFormatIndex < 0)
return S_FALSE;
CStreamBinder binder;
RINOK(binder.Create_ReInit())
CMyComPtr<ISequentialInStream> binderInStream;
CMyComPtr<ISequentialOutStream> binderOutStream;
binder.CreateStreams2(binderInStream, binderOutStream);
CMyComPtr2_Create<IArchiveExtractCallback, CChainedStreamExtractCallback> outerExtractCallback;
outerExtractCallback->Init(callbackFAE, binderOutStream, multi, completedBeforeArc);
binderOutStream.Release();
CChainedStreamExtractThread outerExtractThread;
outerExtractThread.Arc = &arc;
outerExtractThread.Callback = outerExtractCallback;
RINOK(HRESULT_FROM_WIN32(outerExtractThread.Create()))
RINOK(HRESULT_FROM_WIN32(outerExtractThread.Start()))
HRESULT result = S_OK;
{
CArchiveLink innerArcLink;
CObjectVector<COpenType> innerTypes;
COpenType innerType;
innerType.FormatIndex = innerFormatIndex;
innerTypes.Add(innerType);
CIntVector excludedFormats;
COpenOptions op;
#ifndef Z7_SFX
op.props = &options.Properties;
#endif
op.codecs = codecs;
op.types = &innerTypes;
op.excludedFormats = &excludedFormats;
op.seqStream = binderInStream;
op.filePath = arc.DefaultName;
result = innerArcLink.Open(op);
if (result == S_OK)
{
UInt64 innerProcessed = 0;
ecs->DisableProgress();
result = DecompressArchive(
codecs,
innerArcLink,
packSize,
wildcardCensor,
options,
calcCrc,
callback,
callbackFAE,
ecs,
errorMessage,
innerProcessed,
true);
}
innerArcLink.Release();
}
if (result == S_OK)
{
const HRESULT drainResult = DrainChainedStream(binderInStream);
if (drainResult != S_OK)
result = drainResult;
}
binderInStream.Release();
RINOK(HRESULT_FROM_WIN32(outerExtractThread.WaitExecuteFinish()))
const HRESULT outerResult = outerExtractThread.Result;
if (outerResult != S_OK && outerResult != k_My_HRESULT_WritingWasCut)
return outerResult;
if (result != S_OK)
return result;
return CheckOuterStreamResult(outerExtractCallback->OperationResult, errorMessage);
}

View file

@ -0,0 +1,22 @@
// ChainedExtract.h
#ifndef ZIP7_INC_CHAINED_EXTRACT_H
#define ZIP7_INC_CHAINED_EXTRACT_H
#include "Extract.h"
HRESULT TryChainedExtract(
CCodecs *codecs,
const CArchiveLink &arcLink,
UInt64 packSize,
UInt64 completedBeforeArc,
bool multi,
const NWildcard::CCensorNode &wildcardCensor,
const CExtractOptions &options,
bool calcCrc,
IExtractCallbackUI *callback,
IFolderArchiveExtractCallback *callbackFAE,
CArchiveExtractCallback *ecs,
UString &errorMessage);
#endif

View file

@ -44,6 +44,7 @@ using namespace NWindows;
#define kArcIncludeSwitches " -an -ai" ISWITCH_NO_WILDCARD_POSTFIX
#define kHashIncludeSwitches kIncludeSwitch
#define kStopSwitchParsing " --"
#define kChainedExtractSwitch " -sce"
extern HWND g_HWND;
@ -252,7 +253,7 @@ static void ExtractGroupCommand(const UStringVector &arcPaths, UString &params,
ErrorMessageHRESULT(result);
}
void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup, UInt32 writeZone)
void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup, UInt32 writeZone, bool enableChainedExtract)
{
MY_TRY_BEGIN
UString params ('x');
@ -268,6 +269,8 @@ void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bo
params += " -snz";
params.Add_UInt32(writeZone);
}
if (enableChainedExtract)
params += kChainedExtractSwitch;
if (showDialog)
params += kShowDialogSwitch;
ExtractGroupCommand(arcPaths, params, false);

View file

@ -15,7 +15,7 @@ HRESULT CompressFiles(
const UStringVector &names,
bool email, bool showDialog, bool waitFinish);
void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup, UInt32 writeZone);
void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup, UInt32 writeZone, bool enableChainedExtract);
void TestArchives(const UStringVector &arcPaths, bool hashMode = false);
void CalcChecksum(const UStringVector &paths,

View file

@ -224,11 +224,12 @@ static HRESULT ExtractGroupCommand(const UStringVector &arcPaths,
}
void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder,
bool showDialog, bool elimDup, UInt32 writeZone)
bool showDialog, bool elimDup, UInt32 writeZone, bool enableChainedExtract)
{
CExtractOptions eo;
eo.OutputDir = us2fs(outFolder);
eo.TestMode = false;
eo.EnableChainedExtract = enableChainedExtract;
eo.ElimDup.Val = elimDup;
eo.ElimDup.Def = elimDup;
if (writeZone != (UInt32)(Int32)-1)

View file

@ -13,6 +13,7 @@
#include "../Common/ExtractingFilePath.h"
#include "../Common/HashCalc.h"
#include "ChainedExtract.h"
#include "Extract.h"
#include "SetProperties.h"
@ -33,7 +34,7 @@ static void SetErrorMessage(const char *message,
}
static HRESULT DecompressArchive(
HRESULT DecompressArchive(
CCodecs *codecs,
const CArchiveLink &arcLink,
UInt64 packSize,
@ -44,12 +45,14 @@ static HRESULT DecompressArchive(
IFolderArchiveExtractCallback *callbackFAE,
CArchiveExtractCallback *ecs,
UString &errorMessage,
UInt64 &stdInProcessed)
UInt64 &stdInProcessed,
bool chainedMode)
{
const CArc &arc = arcLink.Arcs.Back();
stdInProcessed = 0;
IInArchive *archive = arc.Archive;
CRecordVector<UInt32> realIndices;
const bool singlePassMode = (options.StdInMode || chainedMode);
UStringVector removePathParts;
@ -90,7 +93,7 @@ static HRESULT DecompressArchive(
const bool allFilesAreAllowed = wildcardCensor.AreAllAllowed();
if (!options.StdInMode)
if (!singlePassMode)
{
UInt32 numItems;
RINOK(archive->GetNumberOfItems(&numItems))
@ -163,7 +166,7 @@ static HRESULT DecompressArchive(
}
}
if (elimIsPossible)
if (elimIsPossible && !singlePassMode)
{
removePathParts.Add(elimPrefix);
// outDir = outDirReduced;
@ -191,7 +194,7 @@ static HRESULT DecompressArchive(
ecs->Init(
options.NtOptions,
options.StdInMode ? &wildcardCensor : NULL,
singlePassMode ? &wildcardCensor : NULL,
&arc,
callbackFAE,
options.StdOutMode, options.TestMode,
@ -199,12 +202,12 @@ static HRESULT DecompressArchive(
removePathParts, false,
packSize);
ecs->Is_elimPrefix_Mode = elimIsPossible;
ecs->Is_elimPrefix_Mode = (elimIsPossible && !singlePassMode);
#ifdef SUPPORT_LINKS
if (!options.StdInMode &&
if (!singlePassMode &&
!options.TestMode &&
options.NtOptions.HardLinks.Val)
{
@ -219,12 +222,15 @@ static HRESULT DecompressArchive(
CArchiveExtractCallback_Closer ecsCloser(ecs);
if (options.StdInMode)
if (singlePassMode)
{
result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, ecs);
NCOM::CPropVariant prop;
if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK)
ConvertPropVariantToUInt64(prop, stdInProcessed);
if (options.StdInMode)
{
NCOM::CPropVariant prop;
if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK)
ConvertPropVariantToUInt64(prop, stdInProcessed);
}
}
else
{
@ -242,6 +248,7 @@ static HRESULT DecompressArchive(
return callback->ExtractResult(result);
}
/* 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 */
@ -539,15 +546,41 @@ HRESULT Extract(
false;
#endif
RINOK(DecompressArchive(
codecs,
arcLink,
fi.Size + arcLink.VolumesSize,
wildcardCensor,
options,
calcCrc,
extractCallback, faeCallback, ecs,
errorMessage, packProcessed))
HRESULT chainRes = S_FALSE;
chainRes = TryChainedExtract(
codecs,
arcLink,
fi.Size + arcLink.VolumesSize,
totalPackProcessed,
multi,
wildcardCensor,
options,
calcCrc,
extractCallback,
faeCallback,
ecs,
errorMessage);
if (chainRes != S_FALSE)
{
RINOK(chainRes)
packProcessed = fi.Size + arcLink.VolumesSize;
}
else
RINOK(DecompressArchive(
codecs,
arcLink,
fi.Size + arcLink.VolumesSize,
wildcardCensor,
options,
calcCrc,
extractCallback,
faeCallback,
ecs,
errorMessage,
packProcessed,
false))
if (!options.StdInMode)
packProcessed = fi.Size + arcLink.VolumesSize;

View file

@ -17,6 +17,7 @@
struct CExtractOptionsBase
{
CBoolPair ElimDup;
bool EnableChainedExtract;
bool ExcludeDirItems;
bool ExcludeFileItems;
@ -33,6 +34,7 @@ struct CExtractOptionsBase
UString HashDir;
CExtractOptionsBase():
EnableChainedExtract(false),
ExcludeDirItems(false),
ExcludeFileItems(false),
PathMode_Force(false),
@ -87,6 +89,20 @@ struct CDecompressStat
}
};
HRESULT DecompressArchive(
CCodecs *codecs,
const CArchiveLink &arcLink,
UInt64 packSize,
const NWildcard::CCensorNode &wildcardCensor,
const CExtractOptions &options,
bool calcCrc,
IExtractCallbackUI *callback,
IFolderArchiveExtractCallback *callbackFAE,
CArchiveExtractCallback *ecs,
UString &errorMessage,
UInt64 &stdInProcessed,
bool chainedMode);
HRESULT Extract(
// DECL_EXTERNAL_CODECS_LOC_VARS
CCodecs *codecs,

View file

@ -184,6 +184,16 @@ struct CArcInfoEx
return UString();
return Exts[0].Ext;
}
UString GetWrappedExt() const
{
if (Flags_KeepName())
FOR_VECTOR (i, Exts)
if (!Exts[i].AddExt.IsEmpty())
return Exts[i].AddExt;
return UString();
}
int FindExtension(const UString &ext) const;
bool Is_7z() const { return Name.IsEqualTo_Ascii_NoCase("7z"); }

View file

@ -3094,11 +3094,10 @@ HRESULT CArc::OpenStreamOrFile(COpenOptions &op)
#endif
op.seqStream = seqStream;
}
else if (!op.stream)
else if (!op.stream && !op.seqStream)
{
fileStreamSpec = new CInFileStream;
fileStream = fileStreamSpec;
Path = filePath;
if (!fileStreamSpec->Open(us2fs(Path)))
return GetLastError_noZero_HRESULT();
op.stream = fileStream;

View file

@ -25,6 +25,7 @@ UI_COMMON_OBJS = \
$O\Bench.obj \
$O\DefaultName.obj \
$O\EnumDirItems.obj \
$O\ChainedExtract.obj \
$O\Extract.obj \
$O\ExtractingFilePath.obj \
$O\HashCalc.obj \

View file

@ -165,6 +165,7 @@ static const char * const kHelpString =
" -p{Password} : set Password\n"
#endif
" -r[-|0] : Recurse subdirectories for name search\n"
" -sce : chained extract archives with tar wrapper in a single operation\n"
" -sa{a|e|s} : set Archive name mode\n"
" -scc{UTF-8|WIN|DOS} : set charset for console input/output\n"
" -scs{UTF-8|UTF-16LE|UTF-16BE|WIN|DOS|{id}} : set charset for list files\n"

View file

@ -45,9 +45,11 @@ WIN_OBJS = \
$O\MultiOutStream.obj \
$O\ProgressUtils.obj \
$O\PropId.obj \
$O\StreamBinder.obj \
$O\StreamObjects.obj \
$O\StreamUtils.obj \
$O\UniqBlocks.obj \
$O\VirtThread.obj \
AR_COMMON_OBJS = \
$O\ItemNameUtils.obj \

View file

@ -444,6 +444,56 @@ static bool IsItArcExt(const UString &ext)
return false;
}
static bool IsTarCompoundExtension(const UString &ext)
{
return ext.IsEqualTo_Ascii_NoCase("gz")
|| ext.IsEqualTo_Ascii_NoCase("gzip")
|| ext.IsEqualTo_Ascii_NoCase("bz2")
|| ext.IsEqualTo_Ascii_NoCase("bzip2")
|| ext.IsEqualTo_Ascii_NoCase("xz")
|| ext.IsEqualTo_Ascii_NoCase("zst")
|| ext.IsEqualTo_Ascii_NoCase("zstd")
|| ext.IsEqualTo_Ascii_NoCase("z");
}
static bool GetChainedExtractFolderName(const UString &arcName, UString &folderName)
{
int dotPos = arcName.ReverseFind_Dot();
if (dotPos < 0)
return false;
const UString ext = arcName.Ptr(dotPos + 1);
UString base = arcName.Left(dotPos);
if (ext.IsEqualTo_Ascii_NoCase("tgz")
|| ext.IsEqualTo_Ascii_NoCase("tpz")
|| ext.IsEqualTo_Ascii_NoCase("tbz")
|| ext.IsEqualTo_Ascii_NoCase("tbz2")
|| ext.IsEqualTo_Ascii_NoCase("txz")
|| ext.IsEqualTo_Ascii_NoCase("tzst")
|| ext.IsEqualTo_Ascii_NoCase("taz"))
{
base.TrimRight();
folderName = Get_Correct_FsFile_Name(base);
return true;
}
if (!IsTarCompoundExtension(ext))
return false;
dotPos = base.ReverseFind_Dot();
if (dotPos < 0)
return false;
if (!StringsAreEqualNoCase_Ascii(base.Ptr((unsigned)(dotPos + 1)), "tar"))
return false;
base.DeleteFrom((unsigned)dotPos);
base.TrimRight();
folderName = Get_Correct_FsFile_Name(base);
return true;
}
UString GetSubFolderNameForExtract(const UString &arcName);
UString GetSubFolderNameForExtract(const UString &arcName)
{
@ -831,9 +881,14 @@ Z7_COMWF_B CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu,
if (_dropMode)
baseFolder = _dropPath;
UString specFolder ('*');
UString specFolderName ('*');
if (_fileNames.Size() == 1)
specFolder = GetSubFolderNameForExtract(fs2us(fi0.Name));
{
const UString arcName = fs2us(fi0.Name);
if (!GetChainedExtractFolderName(arcName, specFolderName))
specFolderName = GetSubFolderNameForExtract(arcName);
}
UString specFolder = specFolderName;
specFolder.Add_PathSepar();
if ((contextMenuFlags & NContextMenuFlags::kExtract) != 0)
@ -861,7 +916,7 @@ Z7_COMWF_B CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu,
UString s;
cmi.Folder = baseFolder + specFolder;
AddCommand(kExtractTo, s, cmi);
MyFormatNew_ReducedName(s, specFolder);
MyFormatNew_ReducedName(s, specFolderName);
Set_UserString_in_LastCommand(s);
MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap);
}
@ -1285,7 +1340,8 @@ HRESULT CZipContextMenu::InvokeCommandCommon(const CCommandMapItem &cmi)
ExtractArchives(_fileNames, cmi.Folder,
(cmdID == kExtract), // showDialog
(cmdID == kExtractTo) && _elimDup.Val, // elimDup
_writeZone
_writeZone,
true
);
break;
}

View file

@ -1035,6 +1035,7 @@ void CPanel::ExtractArchives()
, true // showDialog
, false // elimDup
, ci.WriteZone
, false // enableChainedExtract
);
}

View file

@ -282,6 +282,12 @@ static int Main2()
}
#endif
if (options.StdInMode)
{
ArchivePathsSorted.Add(options.ArcName_for_StdInMode);
ArchivePathsFullSorted.Add(options.ArcName_for_StdInMode);
}
else
{
CDirItemsStat st;
HRESULT hresultMain = EnumerateDirItemsAndSort(

View file

@ -693,6 +693,10 @@ SOURCE=..\..\Common\PropId.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Common\StreamBinder.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Common\StreamObjects.cpp
# End Source File
# Begin Source File
@ -715,6 +719,14 @@ SOURCE=..\..\Common\UniqBlocks.cpp
SOURCE=..\..\Common\UniqBlocks.h
# End Source File
# Begin Source File
SOURCE=..\..\Common\VirtThread.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Common\VirtThread.h
# End Source File
# End Group
# Begin Group "Compress"

View file

@ -76,9 +76,11 @@ WIN_CTRL_OBJS = \
$O\MultiOutStream.obj \
$O\ProgressUtils.obj \
$O\PropId.obj \
$O\StreamBinder.obj \
$O\StreamObjects.obj \
$O\StreamUtils.obj \
$O\UniqBlocks.obj \
$O\VirtThread.obj \
UI_COMMON_OBJS = \
$O\ArchiveCommandLine.obj \
@ -87,6 +89,7 @@ UI_COMMON_OBJS = \
$O\Bench.obj \
$O\DefaultName.obj \
$O\EnumDirItems.obj \
$O\ChainedExtract.obj \
$O\Extract.obj \
$O\ExtractingFilePath.obj \
$O\HashCalc.obj \