chore: initial commit (extracted from Launchers monorepo)

Plugin: ns7zip v2.0.0
Architectures: x86-ansi, x86-unicode, amd64-unicode
License: LGPL-2.1-or-later
This commit is contained in:
Simone
2026-04-29 14:07:51 +02:00
commit d074cc7c07
3848 changed files with 1076682 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+358
View File
@@ -0,0 +1,358 @@
// Agent/Agent.h
#ifndef ZIP7_INC_AGENT_AGENT_H
#define ZIP7_INC_AGENT_AGENT_H
#include "../../../Common/MyCom.h"
#include "../../../Windows/PropVariant.h"
#include "../Common/LoadCodecs.h"
#include "../Common/OpenArchive.h"
#include "../Common/UpdateAction.h"
#include "../FileManager/IFolder.h"
#include "AgentProxy.h"
#include "IFolderArchive.h"
extern CCodecs *g_CodecsObj;
HRESULT LoadGlobalCodecs();
void FreeGlobalCodecs();
class CAgentFolder;
Z7_PURE_INTERFACES_BEGIN
#define Z7_IFACEM_IArchiveFolderInternal(x) \
x(GetAgentFolder(CAgentFolder **agentFolder))
Z7_IFACE_CONSTR_FOLDERARC(IArchiveFolderInternal, 0xC)
Z7_PURE_INTERFACES_END
struct CProxyItem
{
unsigned DirIndex;
unsigned Index;
};
class CAgent;
enum AGENT_OP
{
AGENT_OP_Uni,
AGENT_OP_Delete,
AGENT_OP_CreateFolder,
AGENT_OP_Rename,
AGENT_OP_CopyFromFile,
AGENT_OP_Comment
};
class CAgentFolder Z7_final:
public IFolderFolder,
public IFolderAltStreams,
public IFolderProperties,
public IArchiveGetRawProps,
public IGetFolderArcProps,
public IFolderCompare,
public IFolderGetItemName,
public IArchiveFolder,
public IArchiveFolderInternal,
public IInArchiveGetStream,
public IFolderSetZoneIdMode,
public IFolderSetZoneIdFile,
public IFolderOperations,
public IFolderSetFlatMode,
public CMyUnknownImp
{
Z7_COM_QI_BEGIN2(IFolderFolder)
Z7_COM_QI_ENTRY(IFolderAltStreams)
Z7_COM_QI_ENTRY(IFolderProperties)
Z7_COM_QI_ENTRY(IArchiveGetRawProps)
Z7_COM_QI_ENTRY(IGetFolderArcProps)
Z7_COM_QI_ENTRY(IFolderCompare)
Z7_COM_QI_ENTRY(IFolderGetItemName)
Z7_COM_QI_ENTRY(IArchiveFolder)
Z7_COM_QI_ENTRY(IArchiveFolderInternal)
Z7_COM_QI_ENTRY(IInArchiveGetStream)
Z7_COM_QI_ENTRY(IFolderSetZoneIdMode)
Z7_COM_QI_ENTRY(IFolderSetZoneIdFile)
Z7_COM_QI_ENTRY(IFolderOperations)
Z7_COM_QI_ENTRY(IFolderSetFlatMode)
Z7_COM_QI_END
Z7_COM_ADDREF_RELEASE
Z7_IFACE_COM7_IMP(IFolderFolder)
Z7_IFACE_COM7_IMP(IFolderAltStreams)
Z7_IFACE_COM7_IMP(IFolderProperties)
Z7_IFACE_COM7_IMP(IArchiveGetRawProps)
Z7_IFACE_COM7_IMP(IGetFolderArcProps)
Z7_IFACE_COM7_IMP(IFolderCompare)
Z7_IFACE_COM7_IMP(IFolderGetItemName)
Z7_IFACE_COM7_IMP(IArchiveFolder)
Z7_IFACE_COM7_IMP(IArchiveFolderInternal)
Z7_IFACE_COM7_IMP(IInArchiveGetStream)
Z7_IFACE_COM7_IMP(IFolderSetZoneIdMode)
Z7_IFACE_COM7_IMP(IFolderSetZoneIdFile)
Z7_IFACE_COM7_IMP(IFolderOperations)
Z7_IFACE_COM7_IMP(IFolderSetFlatMode)
void LoadFolder(unsigned proxyDirIndex);
public:
HRESULT BindToFolder_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder);
HRESULT BindToAltStreams_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder);
int GetRealIndex(unsigned index) const;
void GetRealIndices(const UInt32 *indices, UInt32 numItems,
bool includeAltStreams, bool includeFolderSubItemsInFlatMode, CUIntVector &realIndices) const;
int CompareItems3(UInt32 index1, UInt32 index2, PROPID propID);
int CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw);
CAgentFolder():
_isAltStreamFolder(false),
_flatMode(false),
_loadAltStreams(false), // _loadAltStreams alt streams works in flat mode, but we don't use it now
_proxyDirIndex(0),
_zoneMode(NExtract::NZoneIdMode::kNone)
/* , _replaceAltStreamCharsMode(0) */
{}
void Init(const CProxyArc *proxy, const CProxyArc2 *proxy2,
unsigned proxyDirIndex,
/* IFolderFolder *parentFolder, */
CAgent *agent)
{
_proxy = proxy;
_proxy2 = proxy2;
_proxyDirIndex = proxyDirIndex;
_isAltStreamFolder = false;
if (_proxy2)
_isAltStreamFolder = _proxy2->IsAltDir(proxyDirIndex);
// _parentFolder = parentFolder;
_agent = (IInFolderArchive *)agent;
_agentSpec = agent;
}
void GetPathParts(UStringVector &pathParts, bool &isAltStreamFolder);
HRESULT CommonUpdateOperation(
AGENT_OP operation,
bool moveMode,
const wchar_t *newItemName,
const NUpdateArchive::CActionSet *actionSet,
const UInt32 *indices, UInt32 numItems,
IProgress *progress);
void GetPrefix(UInt32 index, UString &prefix) const;
UString GetName(UInt32 index) const;
UString GetFullPrefix(UInt32 index) const; // relative too root folder of archive
public:
bool _isAltStreamFolder;
bool _flatMode;
bool _loadAltStreams; // in Flat mode
const CProxyArc *_proxy;
const CProxyArc2 *_proxy2;
unsigned _proxyDirIndex;
NExtract::NZoneIdMode::EEnum _zoneMode;
CByteBuffer _zoneBuf;
// Int32 _replaceAltStreamCharsMode;
// CMyComPtr<IFolderFolder> _parentFolder;
CMyComPtr<IInFolderArchive> _agent;
CAgent *_agentSpec;
CRecordVector<CProxyItem> _items;
};
class CAgent Z7_final:
public IInFolderArchive,
public IFolderArcProps,
#ifndef Z7_EXTRACT_ONLY
public IOutFolderArchive,
public ISetProperties,
#endif
public CMyUnknownImp
{
Z7_COM_QI_BEGIN2(IInFolderArchive)
Z7_COM_QI_ENTRY(IFolderArcProps)
#ifndef Z7_EXTRACT_ONLY
Z7_COM_QI_ENTRY(IOutFolderArchive)
Z7_COM_QI_ENTRY(ISetProperties)
#endif
Z7_COM_QI_END
Z7_COM_ADDREF_RELEASE
Z7_IFACE_COM7_IMP(IInFolderArchive)
Z7_IFACE_COM7_IMP(IFolderArcProps)
#ifndef Z7_EXTRACT_ONLY
Z7_IFACE_COM7_IMP(ISetProperties)
public:
Z7_IFACE_COM7_IMP(IOutFolderArchive)
HRESULT CommonUpdate(ISequentialOutStream *outArchiveStream,
unsigned numUpdateItems, IArchiveUpdateCallback *updateCallback);
HRESULT CreateFolder(ISequentialOutStream *outArchiveStream,
const wchar_t *folderName, IFolderArchiveUpdateCallback *updateCallback100);
HRESULT RenameItem(ISequentialOutStream *outArchiveStream,
const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName,
IFolderArchiveUpdateCallback *updateCallback100);
HRESULT CommentItem(ISequentialOutStream *outArchiveStream,
const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName,
IFolderArchiveUpdateCallback *updateCallback100);
HRESULT UpdateOneFile(ISequentialOutStream *outArchiveStream,
const UInt32 *indices, UInt32 numItems, const wchar_t *diskFilePath,
IFolderArchiveUpdateCallback *updateCallback100);
#endif
private:
HRESULT ReadItems();
public:
CProxyArc *_proxy;
CProxyArc2 *_proxy2;
CArchiveLink _archiveLink;
UString ArchiveType;
FStringVector _names;
FString _folderPrefix; // for new files from disk
UString _updatePathPrefix;
CAgentFolder *_agentFolder;
UString _archiveFilePath; // it can be path of non-existing file if file is virtual
DWORD _attrib;
bool _updatePathPrefix_is_AltFolder;
bool ThereIsPathProp;
bool _isDeviceFile;
bool _isHashHandler;
FString _hashBaseFolderPrefix;
#ifndef Z7_EXTRACT_ONLY
CObjectVector<UString> m_PropNames;
CObjectVector<NWindows::NCOM::CPropVariant> m_PropValues;
#endif
CAgent();
~CAgent();
const CArc &GetArc() const { return _archiveLink.Arcs.Back(); }
IInArchive *GetArchive() const { if ( _archiveLink.Arcs.IsEmpty()) return NULL; return GetArc().Archive; }
bool CanUpdate() const;
bool Is_Attrib_ReadOnly() const
{
return _attrib != INVALID_FILE_ATTRIBUTES && (_attrib & FILE_ATTRIBUTE_READONLY);
}
bool IsThere_ReadOnlyArc() const
{
FOR_VECTOR (i, _archiveLink.Arcs)
{
const CArc &arc = _archiveLink.Arcs[i];
if (arc.FormatIndex < 0
|| arc.IsReadOnly
|| !g_CodecsObj->Formats[arc.FormatIndex].UpdateEnabled)
return true;
}
return false;
}
UString GetTypeOfArc(const CArc &arc) const
{
if (arc.FormatIndex < 0)
return UString("Parser");
return g_CodecsObj->GetFormatNamePtr(arc.FormatIndex);
}
UString GetErrorMessage() const
{
UString s;
for (int i = (int)_archiveLink.Arcs.Size() - 1; i >= 0; i--)
{
const CArc &arc = _archiveLink.Arcs[i];
UString s2;
if (arc.ErrorInfo.ErrorFormatIndex >= 0)
{
if (arc.ErrorInfo.ErrorFormatIndex == arc.FormatIndex)
s2 += "Warning: The archive is open with offset";
else
{
s2 += "Cannot open the file as [";
s2 += g_CodecsObj->GetFormatNamePtr(arc.ErrorInfo.ErrorFormatIndex);
s2 += "] archive";
}
}
if (!arc.ErrorInfo.ErrorMessage.IsEmpty())
{
if (!s2.IsEmpty())
s2.Add_LF();
s2 += "\n[";
s2 += GetTypeOfArc(arc);
s2 += "]: ";
s2 += arc.ErrorInfo.ErrorMessage;
}
if (!s2.IsEmpty())
{
if (!s.IsEmpty())
s += "--------------------\n";
s += arc.Path;
s.Add_LF();
s += s2;
s.Add_LF();
}
}
return s;
}
void KeepModeForNextOpen() { _archiveLink.KeepModeForNextOpen(); }
};
// #ifdef NEW_FOLDER_INTERFACE
struct CCodecIcons
{
struct CIconPair
{
UString Ext;
int IconIndex;
};
CObjectVector<CIconPair> IconPairs;
// void Clear() { IconPairs.Clear(); }
void LoadIcons(HMODULE m);
bool FindIconIndex(const UString &ext, int &iconIndex) const;
};
Z7_CLASS_IMP_COM_1(
CArchiveFolderManager
, IFolderManager
)
CObjectVector<CCodecIcons> CodecIconsVector;
CCodecIcons InternalIcons;
bool WasLoaded;
void LoadFormats();
// int FindFormat(const UString &type);
public:
CArchiveFolderManager():
WasLoaded(false)
{}
};
// #endif
#endif
@@ -0,0 +1,718 @@
// AgentOut.cpp
#include "StdAfx.h"
#include "../../../Common/Wildcard.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/FileName.h"
#include "../../../Windows/TimeUtils.h"
#include "../../Compress/CopyCoder.h"
#include "../../Common/FileStreams.h"
#include "../../Archive/Common/ItemNameUtils.h"
#include "Agent.h"
#include "UpdateCallbackAgent.h"
using namespace NWindows;
using namespace NCOM;
Z7_COM7F_IMF(CAgent::SetFolder(IFolderFolder *folder))
{
_updatePathPrefix.Empty();
_updatePathPrefix_is_AltFolder = false;
_agentFolder = NULL;
if (!folder)
return S_OK;
{
Z7_DECL_CMyComPtr_QI_FROM(
IArchiveFolderInternal,
afi, folder)
if (afi)
{
RINOK(afi->GetAgentFolder(&_agentFolder))
}
if (!_agentFolder)
return E_FAIL;
}
if (_proxy2)
_updatePathPrefix = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex, _updatePathPrefix_is_AltFolder);
else
_updatePathPrefix = _proxy->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex);
return S_OK;
}
Z7_COM7F_IMF(CAgent::SetFiles(const wchar_t *folderPrefix,
const wchar_t * const *names, UInt32 numNames))
{
_folderPrefix = us2fs(folderPrefix);
_names.ClearAndReserve(numNames);
for (UInt32 i = 0; i < numNames; i++)
_names.AddInReserved(us2fs(names[i]));
return S_OK;
}
static HRESULT EnumerateArchiveItems(CAgent *agent,
const CProxyDir &item,
const UString &prefix,
CObjectVector<CArcItem> &arcItems)
{
unsigned i;
for (i = 0; i < item.SubFiles.Size(); i++)
{
unsigned arcIndex = item.SubFiles[i];
const CProxyFile &fileItem = agent->_proxy->Files[arcIndex];
CArcItem ai;
RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime))
RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined))
ai.IsDir = false;
ai.Name = prefix + fileItem.Name;
ai.Censored = true; // test it
ai.IndexInServer = arcIndex;
arcItems.Add(ai);
}
for (i = 0; i < item.SubDirs.Size(); i++)
{
const CProxyDir &dirItem = agent->_proxy->Dirs[item.SubDirs[i]];
UString fullName = prefix + dirItem.Name;
if (dirItem.IsLeaf())
{
CArcItem ai;
RINOK(agent->GetArc().GetItem_MTime((unsigned)dirItem.ArcIndex, ai.MTime))
ai.IsDir = true;
ai.Size_Defined = false;
ai.Name = fullName;
ai.Censored = true; // test it
ai.IndexInServer = (unsigned)dirItem.ArcIndex;
arcItems.Add(ai);
}
RINOK(EnumerateArchiveItems(agent, dirItem, fullName + WCHAR_PATH_SEPARATOR, arcItems))
}
return S_OK;
}
static HRESULT EnumerateArchiveItems2(const CAgent *agent,
unsigned dirIndex,
const UString &prefix,
CObjectVector<CArcItem> &arcItems)
{
const CProxyDir2 &dir = agent->_proxy2->Dirs[dirIndex];
FOR_VECTOR (i, dir.Items)
{
unsigned arcIndex = dir.Items[i];
const CProxyFile2 &file = agent->_proxy2->Files[arcIndex];
CArcItem ai;
ai.IndexInServer = arcIndex;
ai.Name = prefix + file.Name;
ai.Censored = true; // test it
RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime))
ai.IsDir = file.IsDir();
ai.Size_Defined = false;
ai.IsAltStream = file.IsAltStream;
if (!ai.IsDir)
{
RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined))
ai.IsDir = false;
}
arcItems.Add(ai);
if (file.AltDirIndex != -1)
{
RINOK(EnumerateArchiveItems2(agent, (unsigned)file.AltDirIndex, ai.Name + L':', arcItems))
}
if (ai.IsDir)
{
RINOK(EnumerateArchiveItems2(agent, (unsigned)file.DirIndex, ai.Name + WCHAR_PATH_SEPARATOR, arcItems))
}
}
return S_OK;
}
struct CAgUpCallbackImp Z7_final: public IUpdateProduceCallback
{
const CObjectVector<CArcItem> *_arcItems;
IFolderArchiveUpdateCallback *_callback;
CAgUpCallbackImp(const CObjectVector<CArcItem> *a,
IFolderArchiveUpdateCallback *callback): _arcItems(a), _callback(callback) {}
HRESULT ShowDeleteFile(unsigned arcIndex) Z7_override;
};
HRESULT CAgUpCallbackImp::ShowDeleteFile(unsigned arcIndex)
{
return _callback->DeleteOperation((*_arcItems)[arcIndex].Name);
}
static void SetInArchiveInterfaces(CAgent *agent, CArchiveUpdateCallback *upd)
{
if (agent->_archiveLink.Arcs.IsEmpty())
return;
const CArc &arc = agent->GetArc();
upd->Arc = &arc;
upd->Archive = arc.Archive;
upd->ArcFileName = ExtractFileNameFromPath(arc.Path);
}
struct CDirItemsCallback_AgentOut Z7_final: public IDirItemsCallback
{
CMyComPtr<IFolderScanProgress> FolderScanProgress;
IFolderArchiveUpdateCallback *FolderArchiveUpdateCallback;
HRESULT ErrorCode;
CDirItemsCallback_AgentOut(): FolderArchiveUpdateCallback(NULL), ErrorCode(S_OK) {}
HRESULT ScanError(const FString &name, DWORD systemError) Z7_override
{
const HRESULT hres = HRESULT_FROM_WIN32(systemError);
if (FolderArchiveUpdateCallback)
return FolderScanProgress->ScanError(fs2us(name), hres);
ErrorCode = hres;
return ErrorCode;
}
HRESULT ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) Z7_override
{
if (FolderScanProgress)
return FolderScanProgress->ScanProgress(st.NumDirs, st.NumFiles + st.NumAltStreams,
st.GetTotalBytes(), fs2us(path), BoolToInt(isDir));
if (FolderArchiveUpdateCallback)
return FolderArchiveUpdateCallback->SetNumFiles(st.NumFiles);
return S_OK;
}
};
Z7_COM7F_IMF(CAgent::DoOperation(
FStringVector *requestedPaths,
FStringVector *processedPaths,
CCodecs *codecs,
int formatIndex,
ISequentialOutStream *outArchiveStream,
const Byte *stateActions,
const wchar_t *sfxModule,
IFolderArchiveUpdateCallback *updateCallback100))
{
if (!CanUpdate())
return E_NOTIMPL;
NUpdateArchive::CActionSet actionSet;
{
for (unsigned i = 0; i < NUpdateArchive::NPairState::kNumValues; i++)
actionSet.StateActions[i] = (NUpdateArchive::NPairAction::EEnum)stateActions[i];
}
CDirItemsCallback_AgentOut enumCallback;
if (updateCallback100)
{
enumCallback.FolderArchiveUpdateCallback = updateCallback100;
updateCallback100->QueryInterface(IID_IFolderScanProgress, (void **)&enumCallback.FolderScanProgress);
}
CDirItems dirItems;
dirItems.Callback = &enumCallback;
{
FString folderPrefix = _folderPrefix;
if (!NFile::NName::IsAltStreamPrefixWithColon(fs2us(folderPrefix)))
NFile::NName::NormalizeDirPathPrefix(folderPrefix);
RINOK(dirItems.EnumerateItems2(folderPrefix, _updatePathPrefix, _names, requestedPaths))
if (_updatePathPrefix_is_AltFolder)
{
FOR_VECTOR(i, dirItems.Items)
{
CDirItem &item = dirItems.Items[i];
if (item.IsDir())
return E_NOTIMPL;
item.IsAltStream = true;
}
}
}
CMyComPtr<IOutArchive> outArchive;
if (GetArchive())
{
RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive))
}
else
{
if (formatIndex < 0)
return E_FAIL;
RINOK(codecs->CreateOutArchive((unsigned)formatIndex, outArchive))
#ifdef Z7_EXTERNAL_CODECS
{
CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
if (setCompressCodecsInfo)
{
RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs))
}
}
#endif
}
NFileTimeType::EEnum fileTimeType = NFileTimeType::kNotDefined;
UInt32 value;
RINOK(outArchive->GetFileTimeType(&value))
// we support any future fileType here.
// 22.00:
fileTimeType = (NFileTimeType::EEnum)value;
/*
switch (value)
{
case NFileTimeType::kWindows:
case NFileTimeType::kDOS:
case NFileTimeType::kUnix:
fileTimeType = NFileTimeType::EEnum(value);
break;
default:
{
return E_FAIL;
}
}
*/
CObjectVector<CArcItem> arcItems;
if (GetArchive())
{
RINOK(ReadItems())
if (_proxy2)
{
RINOK(EnumerateArchiveItems2(this, k_Proxy2_RootDirIndex, L"", arcItems))
RINOK(EnumerateArchiveItems2(this, k_Proxy2_AltRootDirIndex, L":", arcItems))
}
else
{
RINOK(EnumerateArchiveItems(this, _proxy->Dirs[0], L"", arcItems))
}
}
CRecordVector<CUpdatePair2> updatePairs2;
{
CRecordVector<CUpdatePair> updatePairs;
GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs);
CAgUpCallbackImp upCallback(&arcItems, updateCallback100);
UpdateProduce(updatePairs, actionSet, updatePairs2, &upCallback);
}
UInt32 numFiles = 0;
{
FOR_VECTOR (i, updatePairs2)
if (updatePairs2[i].NewData)
numFiles++;
}
if (updateCallback100)
{
RINOK(updateCallback100->SetNumFiles(numFiles))
}
CUpdateCallbackAgent updateCallbackAgent;
updateCallbackAgent.SetCallback(updateCallback100);
CMyComPtr2_Create<IArchiveUpdateCallback, CArchiveUpdateCallback> updateCallback;
updateCallback->DirItems = &dirItems;
updateCallback->ArcItems = &arcItems;
updateCallback->UpdatePairs = &updatePairs2;
SetInArchiveInterfaces(this, updateCallback.ClsPtr());
updateCallback->Callback = &updateCallbackAgent;
CByteBuffer processedItems;
if (processedPaths)
{
unsigned num = dirItems.Items.Size();
processedItems.Alloc(num);
for (unsigned i = 0; i < num; i++)
processedItems[i] = 0;
updateCallback->ProcessedItemsStatuses = processedItems;
}
Z7_DECL_CMyComPtr_QI_FROM(
ISetProperties,
setProperties, outArchive)
if (setProperties)
{
if (m_PropNames.Size() == 0)
{
RINOK(setProperties->SetProperties(NULL, NULL, 0))
}
else
{
CRecordVector<const wchar_t *> names;
FOR_VECTOR (i, m_PropNames)
names.Add((const wchar_t *)m_PropNames[i]);
CPropVariant *propValues = new CPropVariant[m_PropValues.Size()];
try
{
FOR_VECTOR (i, m_PropValues)
propValues[i] = m_PropValues[i];
RINOK(setProperties->SetProperties(names.ConstData(), propValues, names.Size()))
}
catch(...)
{
delete []propValues;
return E_FAIL;
}
delete []propValues;
}
}
m_PropNames.Clear();
m_PropValues.Clear();
if (sfxModule != NULL)
{
CMyComPtr2_Create<IInStream, CInFileStream> sfxStream;
if (!sfxStream->Open(us2fs(sfxModule)))
return E_FAIL;
// throw "Can't open sfx module";
RINOK(NCompress::CopyStream(sfxStream, outArchiveStream, NULL))
}
const HRESULT res = outArchive->UpdateItems(outArchiveStream, updatePairs2.Size(), updateCallback);
if (res == S_OK && processedPaths)
{
{
/* OutHandler for 7z archives doesn't report compression operation for empty files.
So we must include these files manually */
FOR_VECTOR(i, updatePairs2)
{
const CUpdatePair2 &up = updatePairs2[i];
if (up.DirIndex != -1 && up.NewData)
{
const CDirItem &di = dirItems.Items[(unsigned)up.DirIndex];
if (!di.IsDir() && di.Size == 0)
processedItems[(unsigned)up.DirIndex] = 1;
}
}
}
FOR_VECTOR (i, dirItems.Items)
if (processedItems[i] != 0)
processedPaths->Add(dirItems.GetPhyPath(i));
}
return res;
}
Z7_COM7F_IMF(CAgent::DoOperation2(
FStringVector *requestedPaths,
FStringVector *processedPaths,
ISequentialOutStream *outArchiveStream,
const Byte *stateActions, const wchar_t *sfxModule, IFolderArchiveUpdateCallback *updateCallback100))
{
return DoOperation(requestedPaths, processedPaths, g_CodecsObj, -1, outArchiveStream, stateActions, sfxModule, updateCallback100);
}
HRESULT CAgent::CommonUpdate(ISequentialOutStream *outArchiveStream,
unsigned numUpdateItems, IArchiveUpdateCallback *updateCallback)
{
if (!CanUpdate())
return E_NOTIMPL;
CMyComPtr<IOutArchive> outArchive;
RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive))
return outArchive->UpdateItems(outArchiveStream, numUpdateItems, updateCallback);
}
Z7_COM7F_IMF(CAgent::DeleteItems(ISequentialOutStream *outArchiveStream,
const UInt32 *indices, UInt32 numItems,
IFolderArchiveUpdateCallback *updateCallback100))
{
if (!CanUpdate())
return E_NOTIMPL;
CRecordVector<CUpdatePair2> updatePairs;
CUpdateCallbackAgent updateCallbackAgent;
updateCallbackAgent.SetCallback(updateCallback100);
CMyComPtr2_Create<IArchiveUpdateCallback, CArchiveUpdateCallback> updateCallback;
CUIntVector realIndices;
_agentFolder->GetRealIndices(indices, numItems,
true, // includeAltStreams
false, // includeFolderSubItemsInFlatMode, we don't want to delete subItems in Flat Mode
realIndices);
unsigned curIndex = 0;
UInt32 numItemsInArchive;
RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive))
UString deletePath;
for (UInt32 i = 0; i < numItemsInArchive; i++)
{
if (curIndex < realIndices.Size())
if (realIndices[curIndex] == i)
{
RINOK(GetArc().GetItem_Path2(i, deletePath))
RINOK(updateCallback100->DeleteOperation(deletePath))
curIndex++;
continue;
}
CUpdatePair2 up2;
up2.SetAs_NoChangeArcItem(i);
updatePairs.Add(up2);
}
updateCallback->UpdatePairs = &updatePairs;
SetInArchiveInterfaces(this, updateCallback.ClsPtr());
updateCallback->Callback = &updateCallbackAgent;
return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback);
}
HRESULT CAgent::CreateFolder(ISequentialOutStream *outArchiveStream,
const wchar_t *folderName, IFolderArchiveUpdateCallback *updateCallback100)
{
if (!CanUpdate())
return E_NOTIMPL;
CRecordVector<CUpdatePair2> updatePairs;
CDirItems dirItems;
CUpdateCallbackAgent updateCallbackAgent;
updateCallbackAgent.SetCallback(updateCallback100);
CMyComPtr2_Create<IArchiveUpdateCallback, CArchiveUpdateCallback> updateCallback;
UInt32 numItemsInArchive;
RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive))
for (UInt32 i = 0; i < numItemsInArchive; i++)
{
CUpdatePair2 up2;
up2.SetAs_NoChangeArcItem(i);
updatePairs.Add(up2);
}
CUpdatePair2 up2;
up2.NewData = up2.NewProps = true;
up2.UseArcProps = false;
up2.DirIndex = 0;
updatePairs.Add(up2);
updatePairs.ReserveDown();
CDirItem di;
di.Attrib = FILE_ATTRIBUTE_DIRECTORY;
di.Size = 0;
bool isAltStreamFolder = false;
if (_proxy2)
di.Name = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex, isAltStreamFolder);
else
di.Name = _proxy->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex);
di.Name += folderName;
FILETIME ft;
NTime::GetCurUtcFileTime(ft);
di.CTime = di.ATime = di.MTime = ft;
dirItems.Items.Add(di);
updateCallback->Callback = &updateCallbackAgent;
updateCallback->DirItems = &dirItems;
updateCallback->UpdatePairs = &updatePairs;
SetInArchiveInterfaces(this, updateCallback.ClsPtr());
return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback);
}
HRESULT CAgent::RenameItem(ISequentialOutStream *outArchiveStream,
const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName,
IFolderArchiveUpdateCallback *updateCallback100)
{
if (!CanUpdate())
return E_NOTIMPL;
if (numItems != 1)
return E_INVALIDARG;
if (!_archiveLink.IsOpen)
return E_FAIL;
CRecordVector<CUpdatePair2> updatePairs;
CUpdateCallbackAgent updateCallbackAgent;
updateCallbackAgent.SetCallback(updateCallback100);
CMyComPtr2_Create<IArchiveUpdateCallback, CArchiveUpdateCallback> updateCallback;
CUIntVector realIndices;
_agentFolder->GetRealIndices(indices, numItems,
true, // includeAltStreams
true, // includeFolderSubItemsInFlatMode
realIndices);
const UInt32 ind0 = indices[0];
const int mainRealIndex = _agentFolder->GetRealIndex(ind0);
const UString fullPrefix = _agentFolder->GetFullPrefix(ind0);
UString name = _agentFolder->GetName(ind0);
// 22.00 : we normalize name
NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name);
const UString oldItemPath = fullPrefix + name;
const UString newItemPath = fullPrefix + newItemName;
UStringVector newNames;
unsigned curIndex = 0;
UInt32 numItemsInArchive;
RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive))
for (UInt32 i = 0; i < numItemsInArchive; i++)
{
CUpdatePair2 up2;
up2.SetAs_NoChangeArcItem(i);
if (curIndex < realIndices.Size())
if (realIndices[curIndex] == i)
{
up2.NewProps = true;
RINOK(GetArc().IsItem_Anti(i, up2.IsAnti)) // it must work without that line too.
UString oldFullPath;
RINOK(GetArc().GetItem_Path2(i, oldFullPath))
if (!IsPath1PrefixedByPath2(oldFullPath, oldItemPath))
return E_INVALIDARG;
up2.NewNameIndex = (int)newNames.Add(newItemPath + oldFullPath.Ptr(oldItemPath.Len()));
up2.IsMainRenameItem = (mainRealIndex == (int)i);
curIndex++;
}
updatePairs.Add(up2);
}
updateCallback->Callback = &updateCallbackAgent;
updateCallback->UpdatePairs = &updatePairs;
updateCallback->NewNames = &newNames;
SetInArchiveInterfaces(this, updateCallback.ClsPtr());
return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback);
}
HRESULT CAgent::CommentItem(ISequentialOutStream *outArchiveStream,
const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName,
IFolderArchiveUpdateCallback *updateCallback100)
{
if (!CanUpdate())
return E_NOTIMPL;
if (numItems != 1)
return E_INVALIDARG;
if (!_archiveLink.IsOpen)
return E_FAIL;
CRecordVector<CUpdatePair2> updatePairs;
CUpdateCallbackAgent updateCallbackAgent;
updateCallbackAgent.SetCallback(updateCallback100);
CMyComPtr2_Create<IArchiveUpdateCallback, CArchiveUpdateCallback> updateCallback;
const int mainRealIndex = _agentFolder->GetRealIndex(indices[0]);
if (mainRealIndex < 0)
return E_NOTIMPL;
UInt32 numItemsInArchive;
RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive))
UString newName = newItemName;
for (UInt32 i = 0; i < numItemsInArchive; i++)
{
CUpdatePair2 up2;
up2.SetAs_NoChangeArcItem(i);
if ((int)i == mainRealIndex)
up2.NewProps = true;
updatePairs.Add(up2);
}
updateCallback->Callback = &updateCallbackAgent;
updateCallback->UpdatePairs = &updatePairs;
updateCallback->CommentIndex = mainRealIndex;
updateCallback->Comment = &newName;
SetInArchiveInterfaces(this, updateCallback.ClsPtr());
return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback);
}
HRESULT CAgent::UpdateOneFile(ISequentialOutStream *outArchiveStream,
const UInt32 *indices, UInt32 numItems, const wchar_t *diskFilePath,
IFolderArchiveUpdateCallback *updateCallback100)
{
if (!CanUpdate())
return E_NOTIMPL;
CRecordVector<CUpdatePair2> updatePairs;
CDirItems dirItems;
CUpdateCallbackAgent updateCallbackAgent;
updateCallbackAgent.SetCallback(updateCallback100);
CMyComPtr2_Create<IArchiveUpdateCallback, CArchiveUpdateCallback> updateCallback;
UInt32 realIndex;
{
CUIntVector realIndices;
_agentFolder->GetRealIndices(indices, numItems,
false, // includeAltStreams // we update only main stream of file
false, // includeFolderSubItemsInFlatMode
realIndices);
if (realIndices.Size() != 1)
return E_FAIL;
realIndex = realIndices[0];
}
{
FStringVector filePaths;
filePaths.Add(us2fs(diskFilePath));
dirItems.EnumerateItems2(FString(), UString(), filePaths, NULL);
if (dirItems.Items.Size() != 1)
return E_FAIL;
}
UInt32 numItemsInArchive;
RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive))
for (UInt32 i = 0; i < numItemsInArchive; i++)
{
CUpdatePair2 up2;
up2.SetAs_NoChangeArcItem(i);
if (realIndex == i)
{
up2.DirIndex = 0;
up2.NewData = true;
up2.NewProps = true;
up2.UseArcProps = false;
}
updatePairs.Add(up2);
}
updateCallback->DirItems = &dirItems;
updateCallback->Callback = &updateCallbackAgent;
updateCallback->UpdatePairs = &updatePairs;
SetInArchiveInterfaces(this, updateCallback.ClsPtr());
updateCallback->KeepOriginalItemNames = true;
return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback);
}
Z7_COM7F_IMF(CAgent::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
{
m_PropNames.Clear();
m_PropValues.Clear();
for (UInt32 i = 0; i < numProps; i++)
{
m_PropNames.Add(names[i]);
m_PropValues.Add(values[i]);
}
return S_OK;
}
@@ -0,0 +1,752 @@
// AgentProxy.cpp
#include "StdAfx.h"
// #include <stdio.h>
#ifdef _WIN32
#include <wchar.h>
#else
#include <ctype.h>
#endif
#include "../../../../C/Sort.h"
#include "../../../../C/CpuArch.h"
#include "../../../Common/UTFConvert.h"
#include "../../../Common/Wildcard.h"
#include "../../../Windows/PropVariant.h"
#include "../../../Windows/PropVariantConv.h"
#include "../../Archive/Common/ItemNameUtils.h"
#include "AgentProxy.h"
using namespace NWindows;
int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &insertPos) const
{
const CRecordVector<unsigned> &subDirs = Dirs[dirIndex].SubDirs;
unsigned left = 0, right = subDirs.Size();
for (;;)
{
if (left == right)
{
insertPos = left;
return -1;
}
const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
const unsigned dirIndex2 = subDirs[mid];
const int comp = CompareFileNames(name, Dirs[dirIndex2].Name);
if (comp == 0)
return (int)dirIndex2;
if (comp < 0)
right = mid;
else
left = mid + 1;
}
}
int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name) const
{
unsigned insertPos;
return FindSubDir(dirIndex, name, insertPos);
}
static const wchar_t *AllocStringAndCopy(const wchar_t *s, size_t len)
{
wchar_t *p = new wchar_t[len + 1];
MyStringCopy(p, s);
return p;
}
static const wchar_t *AllocStringAndCopy(const UString &s)
{
return AllocStringAndCopy(s, s.Len());
}
unsigned CProxyArc::AddDir(unsigned dirIndex, int arcIndex, const UString &name)
{
unsigned insertPos;
int subDirIndex = FindSubDir(dirIndex, name, insertPos);
if (subDirIndex != -1)
{
if (arcIndex != -1)
{
CProxyDir &item = Dirs[(unsigned)subDirIndex];
if (item.ArcIndex == -1)
item.ArcIndex = arcIndex;
}
return (unsigned)subDirIndex;
}
subDirIndex = (int)Dirs.Size();
Dirs[dirIndex].SubDirs.Insert(insertPos, (unsigned)subDirIndex);
CProxyDir &item = Dirs.AddNew();
item.NameLen = name.Len();
item.Name = AllocStringAndCopy(name);
item.ArcIndex = arcIndex;
item.ParentDir = (int)dirIndex;
return (unsigned)subDirIndex;
}
void CProxyDir::Clear()
{
SubDirs.Clear();
SubFiles.Clear();
}
void CProxyArc::GetDirPathParts(unsigned dirIndex, UStringVector &pathParts) const
{
pathParts.Clear();
// while (dirIndex != -1)
for (;;)
{
const CProxyDir &dir = Dirs[dirIndex];
dirIndex = (unsigned)dir.ParentDir;
if (dir.ParentDir == -1)
break;
pathParts.Insert(0, dir.Name);
// 22.00: we normalize name
NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(pathParts[0]);
}
}
UString CProxyArc::GetDirPath_as_Prefix(unsigned dirIndex) const
{
UString s;
// while (dirIndex != -1)
for (;;)
{
const CProxyDir &dir = Dirs[dirIndex];
dirIndex = (unsigned)dir.ParentDir;
if (dir.ParentDir == -1)
break;
s.InsertAtFront(WCHAR_PATH_SEPARATOR);
s.Insert(0, dir.Name);
// 22.00: we normalize name
NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(s.GetBuf(), MyStringLen(dir.Name));
}
return s;
}
void CProxyArc::AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const
{
const CProxyDir &dir = Dirs[dirIndex];
if (dir.IsLeaf())
realIndices.Add((unsigned)dir.ArcIndex);
unsigned i;
for (i = 0; i < dir.SubDirs.Size(); i++)
AddRealIndices(dir.SubDirs[i], realIndices);
for (i = 0; i < dir.SubFiles.Size(); i++)
realIndices.Add(dir.SubFiles[i]);
}
int CProxyArc::GetRealIndex(unsigned dirIndex, unsigned index) const
{
const CProxyDir &dir = Dirs[dirIndex];
const unsigned numDirItems = dir.SubDirs.Size();
if (index < numDirItems)
{
const CProxyDir &f = Dirs[dir.SubDirs[index]];
if (f.IsLeaf())
return f.ArcIndex;
return -1;
}
return (int)dir.SubFiles[index - numDirItems];
}
void CProxyArc::GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, CUIntVector &realIndices) const
{
const CProxyDir &dir = Dirs[dirIndex];
realIndices.Clear();
for (UInt32 i = 0; i < numItems; i++)
{
const UInt32 index = indices[i];
const unsigned numDirItems = dir.SubDirs.Size();
if (index < numDirItems)
AddRealIndices(dir.SubDirs[index], realIndices);
else
realIndices.Add(dir.SubFiles[index - numDirItems]);
}
HeapSort(realIndices.NonConstData(), realIndices.Size());
}
///////////////////////////////////////////////
// CProxyArc
static bool GetSize(IInArchive *archive, UInt32 index, PROPID propID, UInt64 &size)
{
size = 0;
NCOM::CPropVariant prop;
if (archive->GetProperty(index, propID, &prop) != S_OK)
throw 20120228;
return ConvertPropVariantToUInt64(prop, size);
}
void CProxyArc::CalculateSizes(unsigned dirIndex, IInArchive *archive)
{
CProxyDir &dir = Dirs[dirIndex];
dir.Size = dir.PackSize = 0;
dir.NumSubDirs = dir.SubDirs.Size();
dir.NumSubFiles = dir.SubFiles.Size();
dir.CrcIsDefined = true;
dir.Crc = 0;
unsigned i;
for (i = 0; i < dir.SubFiles.Size(); i++)
{
const UInt32 index = (UInt32)dir.SubFiles[i];
UInt64 size, packSize;
const bool sizeDefined = GetSize(archive, index, kpidSize, size);
dir.Size += size;
GetSize(archive, index, kpidPackSize, packSize);
dir.PackSize += packSize;
{
NCOM::CPropVariant prop;
if (archive->GetProperty(index, kpidCRC, &prop) == S_OK)
{
if (prop.vt == VT_UI4)
dir.Crc += prop.ulVal;
else if (prop.vt != VT_EMPTY || size != 0 || !sizeDefined)
dir.CrcIsDefined = false;
}
else
dir.CrcIsDefined = false;
}
}
for (i = 0; i < dir.SubDirs.Size(); i++)
{
unsigned subDirIndex = dir.SubDirs[i];
CalculateSizes(subDirIndex, archive);
CProxyDir &f = Dirs[subDirIndex];
dir.Size += f.Size;
dir.PackSize += f.PackSize;
dir.NumSubFiles += f.NumSubFiles;
dir.NumSubDirs += f.NumSubDirs;
dir.Crc += f.Crc;
if (!f.CrcIsDefined)
dir.CrcIsDefined = false;
}
}
HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
{
// DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1; ttt++) {
Files.Free();
Dirs.Clear();
Dirs.AddNew();
IInArchive *archive = arc.Archive;
UInt32 numItems;
RINOK(archive->GetNumberOfItems(&numItems))
if (progress)
RINOK(progress->SetTotal(numItems))
Files.Alloc(numItems);
UString path;
UString name;
NCOM::CPropVariant prop;
for (UInt32 i = 0; i < numItems; i++)
{
if (progress && (i & 0xFFFF) == 0)
{
const UInt64 currentItemIndex = i;
RINOK(progress->SetCompleted(&currentItemIndex))
}
const wchar_t *s = NULL;
unsigned len = 0;
bool isPtrName = false;
#if WCHAR_PATH_SEPARATOR != L'/'
wchar_t separatorChar = WCHAR_PATH_SEPARATOR;
#endif
#if defined(MY_CPU_LE) && defined(_WIN32)
// it works only if (sizeof(wchar_t) == 2)
if (arc.GetRawProps)
{
const void *p;
UInt32 size;
UInt32 propType;
if (arc.GetRawProps->GetRawProp(i, kpidPath, &p, &size, &propType) == S_OK
&& propType == NPropDataType::kUtf16z
&& size > 2)
{
// is (size <= 2), it's empty name, and we call default arc.GetItemPath();
len = size / 2 - 1;
s = (const wchar_t *)p;
isPtrName = true;
#if WCHAR_PATH_SEPARATOR != L'/'
separatorChar = L'/'; // 0
#endif
}
}
if (!s)
#endif
{
prop.Clear();
RINOK(arc.Archive->GetProperty(i, kpidPath, &prop))
if (prop.vt == VT_BSTR)
{
s = prop.bstrVal;
len = ::SysStringLen(prop.bstrVal);
}
else if (prop.vt != VT_EMPTY)
return E_FAIL;
if (len == 0)
{
RINOK(arc.GetItem_DefaultPath(i, path))
len = path.Len();
s = path;
}
/*
RINOK(arc.GetItemPath(i, path));
len = path.Len();
s = path;
*/
}
unsigned curItem = 0;
/*
if (arc.Ask_Deleted)
{
bool isDeleted = false;
RINOK(Archive_IsItem_Deleted(archive, i, isDeleted));
if (isDeleted)
curItem = AddDirSubItem(curItem, (UInt32)(Int32)-1, false, L"[DELETED]");
}
*/
unsigned namePos = 0;
unsigned numLevels = 0;
for (unsigned j = 0; j < len; j++)
{
const wchar_t c = s[j];
if (c == L'/'
#if WCHAR_PATH_SEPARATOR != L'/'
|| (c == separatorChar)
#endif
)
{
const unsigned kLevelLimit = 1 << 10;
if (numLevels <= kLevelLimit)
{
if (numLevels == kLevelLimit)
name = "[LONG_PATH]";
else
name.SetFrom(s + namePos, j - namePos);
// 22.00: we can normalize dir here
// NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name);
curItem = AddDir(curItem, -1, name);
}
namePos = j + 1;
numLevels++;
}
}
/*
that code must be implemeted to hide alt streams in list.
if (arc.Ask_AltStreams)
{
bool isAltStream;
RINOK(Archive_IsItem_AltStream(archive, i, isAltStream));
if (isAltStream)
{
}
}
*/
bool isDir;
RINOK(Archive_IsItem_Dir(archive, i, isDir))
CProxyFile &f = Files[i];
f.NameLen = len - namePos;
s += namePos;
if (isPtrName)
f.Name = s;
else
{
f.Name = AllocStringAndCopy(s, f.NameLen);
f.NeedDeleteName = true;
}
if (isDir)
{
name = s;
// 22.00: we can normalize dir here
// NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name);
AddDir(curItem, (int)i, name);
}
else
Dirs[curItem].SubFiles.Add(i);
}
CalculateSizes(0, archive);
// } char s[128]; sprintf(s, "Load archive: %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s);
return S_OK;
}
// ---------- for Tree-mode archive ----------
void CProxyArc2::GetDirPathParts(unsigned dirIndex, UStringVector &pathParts, bool &isAltStreamDir) const
{
pathParts.Clear();
isAltStreamDir = false;
if (dirIndex == k_Proxy2_RootDirIndex)
return;
if (dirIndex == k_Proxy2_AltRootDirIndex)
{
isAltStreamDir = true;
return;
}
while (dirIndex >= k_Proxy2_NumRootDirs)
{
const CProxyDir2 &dir = Dirs[dirIndex];
const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex];
if (pathParts.IsEmpty() && (int)dirIndex == file.AltDirIndex)
isAltStreamDir = true;
pathParts.Insert(0, file.Name);
const int par = file.Parent;
if (par == -1)
break;
dirIndex = (unsigned)Files[(unsigned)par].DirIndex;
// if ((int)dirIndex == -1) break;
}
}
bool CProxyArc2::IsAltDir(unsigned dirIndex) const
{
if (dirIndex == k_Proxy2_RootDirIndex)
return false;
if (dirIndex == k_Proxy2_AltRootDirIndex)
return true;
const CProxyDir2 &dir = Dirs[dirIndex];
const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex];
return ((int)dirIndex == file.AltDirIndex);
}
UString CProxyArc2::GetDirPath_as_Prefix(unsigned dirIndex, bool &isAltStreamDir) const
{
isAltStreamDir = false;
const CProxyDir2 &dir = Dirs[dirIndex];
if (dirIndex == k_Proxy2_AltRootDirIndex)
isAltStreamDir = true;
else if (dirIndex >= k_Proxy2_NumRootDirs)
{
const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex];
isAltStreamDir = ((int)dirIndex == file.AltDirIndex);
}
return dir.PathPrefix;
}
void CProxyArc2::AddRealIndices_of_ArcItem(unsigned arcIndex, bool includeAltStreams, CUIntVector &realIndices) const
{
realIndices.Add(arcIndex);
const CProxyFile2 &file = Files[arcIndex];
if (file.DirIndex != -1)
AddRealIndices_of_Dir((unsigned)file.DirIndex, includeAltStreams, realIndices);
if (includeAltStreams && file.AltDirIndex != -1)
AddRealIndices_of_Dir((unsigned)file.AltDirIndex, includeAltStreams, realIndices);
}
void CProxyArc2::AddRealIndices_of_Dir(unsigned dirIndex, bool includeAltStreams, CUIntVector &realIndices) const
{
const CRecordVector<unsigned> &subFiles = Dirs[dirIndex].Items;
FOR_VECTOR (i, subFiles)
{
AddRealIndices_of_ArcItem(subFiles[i], includeAltStreams, realIndices);
}
}
unsigned CProxyArc2::GetRealIndex(unsigned dirIndex, unsigned index) const
{
return Dirs[dirIndex].Items[index];
}
void CProxyArc2::GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, bool includeAltStreams, CUIntVector &realIndices) const
{
const CProxyDir2 &dir = Dirs[dirIndex];
realIndices.Clear();
for (UInt32 i = 0; i < numItems; i++)
{
AddRealIndices_of_ArcItem(dir.Items[indices[i]], includeAltStreams, realIndices);
}
HeapSort(realIndices.NonConstData(), realIndices.Size());
}
void CProxyArc2::CalculateSizes(unsigned dirIndex, IInArchive *archive)
{
CProxyDir2 &dir = Dirs[dirIndex];
dir.Size = dir.PackSize = 0;
dir.NumSubDirs = 0; // dir.SubDirs.Size();
dir.NumSubFiles = 0; // dir.Files.Size();
dir.CrcIsDefined = true;
dir.Crc = 0;
FOR_VECTOR (i, dir.Items)
{
UInt32 index = dir.Items[i];
UInt64 size, packSize;
const bool sizeDefined = GetSize(archive, index, kpidSize, size);
dir.Size += size;
GetSize(archive, index, kpidPackSize, packSize);
dir.PackSize += packSize;
{
NCOM::CPropVariant prop;
if (archive->GetProperty(index, kpidCRC, &prop) == S_OK)
{
if (prop.vt == VT_UI4)
dir.Crc += prop.ulVal;
else if (prop.vt != VT_EMPTY || size != 0 || !sizeDefined)
dir.CrcIsDefined = false;
}
else
dir.CrcIsDefined = false;
}
const CProxyFile2 &subFile = Files[index];
if (subFile.DirIndex == -1)
{
dir.NumSubFiles++;
}
else
{
// 22.00: we normalize name
UString s = subFile.Name;
NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(s);
dir.NumSubDirs++;
CProxyDir2 &f = Dirs[subFile.DirIndex];
f.PathPrefix = dir.PathPrefix + s + WCHAR_PATH_SEPARATOR;
CalculateSizes((unsigned)subFile.DirIndex, archive);
dir.Size += f.Size;
dir.PackSize += f.PackSize;
dir.NumSubFiles += f.NumSubFiles;
dir.NumSubDirs += f.NumSubDirs;
dir.Crc += f.Crc;
if (!f.CrcIsDefined)
dir.CrcIsDefined = false;
}
if (subFile.AltDirIndex == -1)
{
// dir.NumSubFiles++;
}
else
{
// dir.NumSubDirs++;
CProxyDir2 &f = Dirs[subFile.AltDirIndex];
f.PathPrefix = dir.PathPrefix + subFile.Name + L':';
CalculateSizes((unsigned)subFile.AltDirIndex, archive);
}
}
}
bool CProxyArc2::IsThere_SubDir(unsigned dirIndex, const UString &name) const
{
const CRecordVector<unsigned> &subFiles = Dirs[dirIndex].Items;
FOR_VECTOR (i, subFiles)
{
const CProxyFile2 &file = Files[subFiles[i]];
if (file.IsDir())
if (CompareFileNames(name, file.Name) == 0)
return true;
}
return false;
}
HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress)
{
if (!arc.GetRawProps)
return E_FAIL;
// DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1; ttt++) {
Dirs.Clear();
Files.Free();
IInArchive *archive = arc.Archive;
UInt32 numItems;
RINOK(archive->GetNumberOfItems(&numItems))
if (progress)
RINOK(progress->SetTotal(numItems))
UString fileName;
{
// Dirs[0] - root dir
/* CProxyDir2 &dir = */ Dirs.AddNew();
}
{
// Dirs[1] - for alt streams of root dir
CProxyDir2 &dir = Dirs.AddNew();
dir.PathPrefix = ':';
}
Files.Alloc(numItems);
UString tempUString;
AString tempAString;
UInt32 i;
for (i = 0; i < numItems; i++)
{
if (progress && (i & 0xFFFFF) == 0)
{
UInt64 currentItemIndex = i;
RINOK(progress->SetCompleted(&currentItemIndex))
}
CProxyFile2 &file = Files[i];
const void *p;
UInt32 size;
UInt32 propType;
RINOK(arc.GetRawProps->GetRawProp(i, kpidName, &p, &size, &propType))
#ifdef MY_CPU_LE
if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE)
{
file.Name = (const wchar_t *)p;
file.NameLen = 0;
if (size >= sizeof(wchar_t))
file.NameLen = size / (unsigned)sizeof(wchar_t) - 1;
}
else
#endif
if (p && propType == NPropDataType::kUtf8z)
{
tempAString = (const char *)p;
ConvertUTF8ToUnicode(tempAString, tempUString);
file.NameLen = tempUString.Len();
file.Name = AllocStringAndCopy(tempUString);
file.NeedDeleteName = true;
}
else
{
NCOM::CPropVariant prop;
RINOK(arc.Archive->GetProperty(i, kpidName, &prop))
const wchar_t *s;
if (prop.vt == VT_BSTR)
s = prop.bstrVal;
else if (prop.vt == VT_EMPTY)
s = L"[Content]";
else
return E_FAIL;
file.NameLen = MyStringLen(s);
file.Name = AllocStringAndCopy(s, file.NameLen);
file.NeedDeleteName = true;
}
UInt32 parent = (UInt32)(Int32)-1;
UInt32 parentType = 0;
RINOK(arc.GetRawProps->GetParent(i, &parent, &parentType))
file.Parent = (Int32)parent;
if (arc.Ask_Deleted)
{
bool isDeleted = false;
RINOK(Archive_IsItem_Deleted(archive, i, isDeleted))
if (isDeleted)
{
// continue;
// curItem = AddDirSubItem(curItem, (UInt32)(Int32)-1, false, L"[DELETED]");
}
}
bool isDir;
RINOK(Archive_IsItem_Dir(archive, i, isDir))
if (isDir)
{
file.DirIndex = (int)Dirs.Size();
CProxyDir2 &dir = Dirs.AddNew();
dir.ArcIndex = (int)i;
}
if (arc.Ask_AltStream)
RINOK(Archive_IsItem_AltStream(archive, i, file.IsAltStream))
}
for (i = 0; i < numItems; i++)
{
CProxyFile2 &file = Files[i];
int dirIndex;
if (file.IsAltStream)
{
if (file.Parent == -1)
dirIndex = k_Proxy2_AltRootDirIndex;
else
{
int &folderIndex2 = Files[(unsigned)file.Parent].AltDirIndex;
if (folderIndex2 == -1)
{
folderIndex2 = (int)Dirs.Size();
CProxyDir2 &dir = Dirs.AddNew();
dir.ArcIndex = file.Parent;
}
dirIndex = folderIndex2;
}
}
else
{
if (file.Parent == -1)
dirIndex = k_Proxy2_RootDirIndex;
else
{
dirIndex = Files[(unsigned)file.Parent].DirIndex;
if (dirIndex == -1)
return E_FAIL;
}
}
Dirs[dirIndex].Items.Add(i);
}
for (i = 0; i < k_Proxy2_NumRootDirs; i++)
CalculateSizes(i, archive);
// } char s[128]; sprintf(s, "Load archive: %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s);
return S_OK;
}
int CProxyArc2::FindItem(unsigned dirIndex, const wchar_t *name, bool foldersOnly) const
{
const CProxyDir2 &dir = Dirs[dirIndex];
FOR_VECTOR (i, dir.Items)
{
const CProxyFile2 &file = Files[dir.Items[i]];
if (foldersOnly && file.DirIndex == -1)
continue;
if (CompareFileNames(file.Name, name) == 0)
return (int)i;
}
return -1;
}
@@ -0,0 +1,162 @@
// AgentProxy.h
#ifndef ZIP7_INC_AGENT_PROXY_H
#define ZIP7_INC_AGENT_PROXY_H
#include "../Common/OpenArchive.h"
struct CProxyFile
{
const wchar_t *Name;
unsigned NameLen;
bool NeedDeleteName;
CProxyFile(): Name(NULL), NameLen(0), NeedDeleteName(false) {}
~CProxyFile() { if (NeedDeleteName) delete [](wchar_t *)(void *)Name; } // delete [](wchar_t *)Name;
};
const unsigned k_Proxy_RootDirIndex = 0;
struct CProxyDir
{
const wchar_t *Name;
unsigned NameLen;
int ArcIndex; // index in proxy->Files[] ; -1 if there is no item for that folder
int ParentDir; // index in proxy->Dirs[] ; -1 for root folder; ;
CRecordVector<unsigned> SubDirs;
CRecordVector<unsigned> SubFiles;
UInt64 Size;
UInt64 PackSize;
UInt32 Crc;
UInt32 NumSubDirs;
UInt32 NumSubFiles;
bool CrcIsDefined;
CProxyDir(): Name(NULL), NameLen(0), ParentDir(-1) {}
~CProxyDir() { delete [](wchar_t *)(void *)Name; }
void Clear();
bool IsLeaf() const { return ArcIndex != -1; }
};
class CProxyArc
{
int FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &insertPos) const;
void CalculateSizes(unsigned dirIndex, IInArchive *archive);
unsigned AddDir(unsigned dirIndex, int arcIndex, const UString &name);
public:
CObjectVector<CProxyDir> Dirs; // Dirs[0] - root
CObjArray<CProxyFile> Files; // all items from archive in same order
// returns index in Dirs[], or -1,
int FindSubDir(unsigned dirIndex, const wchar_t *name) const;
void GetDirPathParts(unsigned dirIndex, UStringVector &pathParts) const;
// returns full path of Dirs[dirIndex], including back slash
UString GetDirPath_as_Prefix(unsigned dirIndex) const;
// AddRealIndices DOES ADD also item represented by dirIndex (if it's Leaf)
void AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const;
int GetRealIndex(unsigned dirIndex, unsigned index) const;
void GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, CUIntVector &realIndices) const;
HRESULT Load(const CArc &arc, IProgress *progress);
};
// ---------- for Tree-mode archive ----------
struct CProxyFile2
{
int DirIndex; // >= 0 for dir. (index in ProxyArchive2->Dirs)
int AltDirIndex; // >= 0 if there are alt streams. (index in ProxyArchive2->Dirs)
int Parent; // >= 0 if there is parent. (index in archive and in ProxyArchive2->Files)
const wchar_t *Name;
unsigned NameLen;
bool NeedDeleteName;
bool Ignore;
bool IsAltStream;
int GetDirIndex(bool forAltStreams) const { return forAltStreams ? AltDirIndex : DirIndex; }
bool IsDir() const { return DirIndex != -1; }
CProxyFile2():
DirIndex(-1), AltDirIndex(-1), Parent(-1),
Name(NULL), NameLen(0),
NeedDeleteName(false),
Ignore(false),
IsAltStream(false)
{}
~CProxyFile2()
{
if (NeedDeleteName)
delete [](wchar_t *)(void *)Name;
}
};
struct CProxyDir2
{
int ArcIndex; // = -1 for root folders, index in proxy->Files[]
CRecordVector<unsigned> Items;
UString PathPrefix;
UInt64 Size;
UInt64 PackSize;
bool CrcIsDefined;
UInt32 Crc;
UInt32 NumSubDirs;
UInt32 NumSubFiles;
CProxyDir2(): ArcIndex(-1) {}
void AddFileSubItem(UInt32 index, const UString &name);
void Clear();
};
const unsigned k_Proxy2_RootDirIndex = k_Proxy_RootDirIndex;
const unsigned k_Proxy2_AltRootDirIndex = 1;
const unsigned k_Proxy2_NumRootDirs = 2;
class CProxyArc2
{
void CalculateSizes(unsigned dirIndex, IInArchive *archive);
// AddRealIndices_of_Dir DOES NOT ADD item itself represented by dirIndex
void AddRealIndices_of_Dir(unsigned dirIndex, bool includeAltStreams, CUIntVector &realIndices) const;
public:
CObjectVector<CProxyDir2> Dirs; // Dirs[0] - root folder
// Dirs[1] - for alt streams of root dir
CObjArray<CProxyFile2> Files; // all items from archive in same order
bool IsThere_SubDir(unsigned dirIndex, const UString &name) const;
void GetDirPathParts(unsigned dirIndex, UStringVector &pathParts, bool &isAltStreamDir) const;
UString GetDirPath_as_Prefix(unsigned dirIndex, bool &isAltStreamDir) const;
bool IsAltDir(unsigned dirIndex) const;
// AddRealIndices_of_ArcItem DOES ADD item and subItems
void AddRealIndices_of_ArcItem(unsigned arcIndex, bool includeAltStreams, CUIntVector &realIndices) const;
unsigned GetRealIndex(unsigned dirIndex, unsigned index) const;
void GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, bool includeAltStreams, CUIntVector &realIndices) const;
HRESULT Load(const CArc &arc, IProgress *progress);
int GetParentDirOfFile(UInt32 arcIndex) const
{
const CProxyFile2 &file = Files[arcIndex];
if (file.Parent == -1)
return file.IsAltStream ?
k_Proxy2_AltRootDirIndex :
k_Proxy2_RootDirIndex;
const CProxyFile2 &parentFile = Files[file.Parent];
return file.IsAltStream ?
parentFile.AltDirIndex :
parentFile.DirIndex;
}
int FindItem(unsigned dirIndex, const wchar_t *name, bool foldersOnly) const;
};
#endif
@@ -0,0 +1,57 @@
// Agent/ArchiveFolder.cpp
#include "StdAfx.h"
#include "../../../Common/ComTry.h"
#include "../Common/ArchiveExtractCallback.h"
#include "Agent.h"
/*
Z7_COM7F_IMF(CAgentFolder::SetReplaceAltStreamCharsMode(Int32 replaceAltStreamCharsMode))
{
_replaceAltStreamCharsMode = replaceAltStreamCharsMode;
return S_OK;
}
*/
Z7_COM7F_IMF(CAgentFolder::SetZoneIdMode(NExtract::NZoneIdMode::EEnum zoneMode))
{
_zoneMode = zoneMode;
return S_OK;
}
Z7_COM7F_IMF(CAgentFolder::SetZoneIdFile(const Byte *data, UInt32 size))
{
_zoneBuf.CopyFrom(data, size);
return S_OK;
}
Z7_COM7F_IMF(CAgentFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems,
Int32 includeAltStreams, Int32 replaceAltStreamCharsMode,
const wchar_t *path, IFolderOperationsExtractCallback *callback))
{
if (moveMode)
return E_NOTIMPL;
COM_TRY_BEGIN
CMyComPtr<IFolderArchiveExtractCallback> extractCallback2;
{
CMyComPtr<IFolderOperationsExtractCallback> callbackWrap = callback;
RINOK(callbackWrap.QueryInterface(IID_IFolderArchiveExtractCallback, &extractCallback2))
}
NExtract::NPathMode::EEnum pathMode;
if (!_flatMode)
pathMode = NExtract::NPathMode::kCurPaths;
else
pathMode = (_proxy2 && _loadAltStreams) ?
NExtract::NPathMode::kNoPathsAlt :
NExtract::NPathMode::kNoPaths;
return Extract(indices, numItems,
includeAltStreams, replaceAltStreamCharsMode,
pathMode, NExtract::NOverwriteMode::kAsk,
path, BoolToInt(false), extractCallback2);
COM_TRY_END
}
@@ -0,0 +1,231 @@
// Agent/ArchiveFolderOpen.cpp
#include "StdAfx.h"
// #ifdef NEW_FOLDER_INTERFACE
#include "../../../Common/StringToInt.h"
#include "../../../Windows/DLL.h"
#include "../../../Windows/ResourceString.h"
#include "Agent.h"
extern HINSTANCE g_hInstance;
static const UINT kIconTypesResId = 100;
void CCodecIcons::LoadIcons(HMODULE m)
{
IconPairs.Clear();
UString iconTypes;
NWindows::MyLoadString(m, kIconTypesResId, iconTypes);
UStringVector pairs;
SplitString(iconTypes, pairs);
FOR_VECTOR (i, pairs)
{
const UString &s = pairs[i];
int pos = s.Find(L':');
CIconPair iconPair;
iconPair.IconIndex = -1;
if (pos < 0)
pos = (int)s.Len();
else
{
const UString num = s.Ptr((unsigned)pos + 1);
if (!num.IsEmpty())
{
const wchar_t *end;
iconPair.IconIndex = (int)ConvertStringToUInt32(num, &end);
if (*end != 0)
continue;
}
}
iconPair.Ext = s.Left((unsigned)pos);
IconPairs.Add(iconPair);
}
}
bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const
{
iconIndex = -1;
FOR_VECTOR (i, IconPairs)
{
const CIconPair &pair = IconPairs[i];
if (ext.IsEqualTo_NoCase(pair.Ext))
{
iconIndex = pair.IconIndex;
return true;
}
}
return false;
}
void CArchiveFolderManager::LoadFormats()
{
if (WasLoaded)
return;
LoadGlobalCodecs();
#ifdef Z7_EXTERNAL_CODECS
CodecIconsVector.Clear();
FOR_VECTOR (i, g_CodecsObj->Libs)
{
CCodecIcons &ci = CodecIconsVector.AddNew();
ci.LoadIcons(g_CodecsObj->Libs[i].Lib.Get_HMODULE());
}
#endif
InternalIcons.LoadIcons(g_hInstance);
WasLoaded = true;
}
/*
int CArchiveFolderManager::FindFormat(const UString &type)
{
FOR_VECTOR (i, g_CodecsObj->Formats)
if (type.IsEqualTo_NoCase(g_CodecsObj->Formats[i].Name))
return (int)i;
return -1;
}
*/
Z7_COM7F_IMF(CArchiveFolderManager::OpenFolderFile(IInStream *inStream,
const wchar_t *filePath, const wchar_t *arcFormat,
IFolderFolder **resultFolder, IProgress *progress))
{
CMyComPtr<IArchiveOpenCallback> openArchiveCallback;
if (progress)
{
CMyComPtr<IProgress> progressWrapper = progress;
progressWrapper.QueryInterface(IID_IArchiveOpenCallback, &openArchiveCallback);
}
CAgent *agent = new CAgent();
CMyComPtr<IInFolderArchive> archive = agent;
const HRESULT res = archive->Open(inStream, filePath, arcFormat, NULL, openArchiveCallback);
if (res != S_OK)
{
if (res != S_FALSE)
return res;
/* 20.01: we create folder even for Non-Open cases, if there is NonOpen_ErrorInfo information.
So we can get error information from that IFolderFolder later. */
if (!agent->_archiveLink.NonOpen_ErrorInfo.IsThereErrorOrWarning())
return res;
}
RINOK(archive->BindToRootFolder(resultFolder))
return res;
}
/*
HRESULT CAgent::FolderReOpen(
IArchiveOpenCallback *openArchiveCallback)
{
return ReOpenArchive(_archive, _archiveFilePath);
}
*/
/*
Z7_COM7F_IMF(CArchiveFolderManager::GetExtensions(const wchar_t *type, BSTR *extensions))
{
*extensions = 0;
int formatIndex = FindFormat(type);
if (formatIndex < 0)
return E_INVALIDARG;
// Exts[0].Ext;
return StringToBstr(g_CodecsObj.Formats[formatIndex].GetAllExtensions(), extensions);
}
*/
static void AddIconExt(const CCodecIcons &lib, UString &dest)
{
FOR_VECTOR (i, lib.IconPairs)
{
dest.Add_Space_if_NotEmpty();
dest += lib.IconPairs[i].Ext;
}
}
Z7_COM7F_IMF(CArchiveFolderManager::GetExtensions(BSTR *extensions))
{
*extensions = NULL;
LoadFormats();
UString res;
#ifdef Z7_EXTERNAL_CODECS
/*
FOR_VECTOR (i, g_CodecsObj->Libs)
AddIconExt(g_CodecsObj->Libs[i].CodecIcons, res);
*/
FOR_VECTOR (i, CodecIconsVector)
AddIconExt(CodecIconsVector[i], res);
#endif
AddIconExt(
// g_CodecsObj->
InternalIcons, res);
return StringToBstr(res, extensions);
}
Z7_COM7F_IMF(CArchiveFolderManager::GetIconPath(const wchar_t *ext, BSTR *iconPath, Int32 *iconIndex))
{
*iconPath = NULL;
*iconIndex = 0;
LoadFormats();
#ifdef Z7_EXTERNAL_CODECS
// FOR_VECTOR (i, g_CodecsObj->Libs)
FOR_VECTOR (i, CodecIconsVector)
{
int ii;
if (CodecIconsVector[i].FindIconIndex(ext, ii))
{
const CCodecLib &lib = g_CodecsObj->Libs[i];
*iconIndex = ii;
return StringToBstr(fs2us(lib.Path), iconPath);
}
}
#endif
int ii;
if (InternalIcons.FindIconIndex(ext, ii))
{
FString path;
if (NWindows::NDLL::MyGetModuleFileName(path))
{
*iconIndex = ii;
return StringToBstr(fs2us(path), iconPath);
}
}
return S_OK;
}
/*
Z7_COM7F_IMF(CArchiveFolderManager::GetTypes(BSTR *types))
{
LoadFormats();
UString typesStrings;
FOR_VECTOR(i, g_CodecsObj.Formats)
{
const CArcInfoEx &ai = g_CodecsObj.Formats[i];
if (ai.AssociateExts.Size() == 0)
continue;
if (i != 0)
typesStrings.Add_Space();
typesStrings += ai.Name;
}
return StringToBstr(typesStrings, types);
}
Z7_COM7F_IMF(CArchiveFolderManager::CreateFolderFile(const wchar_t * type,
const wchar_t * filePath, IProgress progress))
{
return E_NOTIMPL;
}
*/
// #endif
@@ -0,0 +1,456 @@
// ArchiveFolderOut.cpp
#include "StdAfx.h"
#include "../../../Common/ComTry.h"
#include "../../../Windows/FileDir.h"
#include "../../Common/FileStreams.h"
#include "../../Common/LimitedStreams.h"
#include "../../Compress/CopyCoder.h"
#include "../Common/WorkDir.h"
#include "Agent.h"
using namespace NWindows;
using namespace NFile;
using namespace NDir;
void CAgentFolder::GetPathParts(UStringVector &pathParts, bool &isAltStreamFolder)
{
if (_proxy2)
_proxy2->GetDirPathParts(_proxyDirIndex, pathParts, isAltStreamFolder);
else
_proxy->GetDirPathParts(_proxyDirIndex, pathParts);
}
static bool Delete_EmptyFolder_And_EmptySubFolders(const FString &path)
{
{
const FString pathPrefix = path + FCHAR_PATH_SEPARATOR;
CObjectVector<FString> names;
{
NFind::CDirEntry fileInfo;
NFind::CEnumerator enumerator;
enumerator.SetDirPrefix(pathPrefix);
for (;;)
{
bool found;
if (!enumerator.Next(fileInfo, found))
return false;
if (!found)
break;
if (fileInfo.IsDir())
names.Add(fileInfo.Name);
}
}
bool res = true;
FOR_VECTOR (i, names)
{
if (!Delete_EmptyFolder_And_EmptySubFolders(pathPrefix + names[i]))
res = false;
}
if (!res)
return false;
}
// we clear read-only attrib to remove read-only dir
if (!SetFileAttrib(path, 0))
return false;
return RemoveDir(path);
}
struct C_CopyFileProgress_to_FolderCallback_MoveArc Z7_final:
public ICopyFileProgress
{
IFolderArchiveUpdateCallback_MoveArc *Callback;
HRESULT CallbackResult;
virtual DWORD CopyFileProgress(UInt64 total, UInt64 current) Z7_override
{
HRESULT res = Callback->MoveArc_Progress(total, current);
CallbackResult = res;
// we can ignore E_ABORT here, because we update archive,
// and we want to get correct archive after updating
if (res == E_ABORT)
res = S_OK;
return res == S_OK ? PROGRESS_CONTINUE : PROGRESS_CANCEL;
}
C_CopyFileProgress_to_FolderCallback_MoveArc(
IFolderArchiveUpdateCallback_MoveArc *callback) :
Callback(callback),
CallbackResult(S_OK)
{}
};
HRESULT CAgentFolder::CommonUpdateOperation(
AGENT_OP operation,
bool moveMode,
const wchar_t *newItemName,
const NUpdateArchive::CActionSet *actionSet,
const UInt32 *indices, UInt32 numItems,
IProgress *progress)
{
if (moveMode && _agentSpec->_isHashHandler)
return E_NOTIMPL;
if (!_agentSpec->CanUpdate())
return E_NOTIMPL;
CMyComPtr<IFolderArchiveUpdateCallback> updateCallback100;
if (progress)
progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&updateCallback100);
try
{
RINOK(_agentSpec->SetFolder(this))
// ---------- Save FolderItem ----------
UStringVector pathParts;
bool isAltStreamFolder = false;
GetPathParts(pathParts, isAltStreamFolder);
FStringVector requestedPaths;
FStringVector processedPaths;
CWorkDirTempFile tempFile;
RINOK(tempFile.CreateTempFile(us2fs(_agentSpec->_archiveFilePath)))
{
CMyComPtr<IOutStream> tailStream;
const CArc &arc = *_agentSpec->_archiveLink.GetArc();
if (arc.ArcStreamOffset == 0)
tailStream = tempFile.OutStream;
else
{
if (arc.Offset < 0)
return E_NOTIMPL;
RINOK(arc.InStream->Seek(0, STREAM_SEEK_SET, NULL))
RINOK(NCompress::CopyStream_ExactSize(arc.InStream, tempFile.OutStream, arc.ArcStreamOffset, NULL))
CTailOutStream *tailStreamSpec = new CTailOutStream;
tailStream = tailStreamSpec;
tailStreamSpec->Stream = tempFile.OutStream;
tailStreamSpec->Offset = arc.ArcStreamOffset;
tailStreamSpec->Init();
}
HRESULT result;
switch ((int)operation)
{
case AGENT_OP_Delete:
result = _agentSpec->DeleteItems(tailStream, indices, numItems, updateCallback100);
break;
case AGENT_OP_CreateFolder:
result = _agentSpec->CreateFolder(tailStream, newItemName, updateCallback100);
break;
case AGENT_OP_Rename:
result = _agentSpec->RenameItem(tailStream, indices, numItems, newItemName, updateCallback100);
break;
case AGENT_OP_Comment:
result = _agentSpec->CommentItem(tailStream, indices, numItems, newItemName, updateCallback100);
break;
case AGENT_OP_CopyFromFile:
result = _agentSpec->UpdateOneFile(tailStream, indices, numItems, newItemName, updateCallback100);
break;
case AGENT_OP_Uni:
{
Byte actionSetByte[NUpdateArchive::NPairState::kNumValues];
for (unsigned i = 0; i < NUpdateArchive::NPairState::kNumValues; i++)
actionSetByte[i] = (Byte)actionSet->StateActions[i];
result = _agentSpec->DoOperation2(
moveMode ? &requestedPaths : NULL,
moveMode ? &processedPaths : NULL,
tailStream, actionSetByte, NULL, updateCallback100);
break;
}
default:
return E_FAIL;
}
RINOK(result)
}
_agentSpec->KeepModeForNextOpen();
_agent->Close();
// before 9.26: if there was error for MoveToOriginal archive was closed.
// now: we reopen archive after close
// m_FolderItem = NULL;
_items.Clear();
_proxyDirIndex = k_Proxy_RootDirIndex;
CMyComPtr<IFolderArchiveUpdateCallback_MoveArc> updateCallback_MoveArc;
if (progress)
progress->QueryInterface(IID_IFolderArchiveUpdateCallback_MoveArc, (void **)&updateCallback_MoveArc);
HRESULT res;
if (updateCallback_MoveArc)
{
const FString &tempFilePath = tempFile.Get_TempFilePath();
UInt64 totalSize = 0;
{
NFind::CFileInfo fi;
if (fi.Find(tempFilePath))
totalSize = fi.Size;
}
RINOK(updateCallback_MoveArc->MoveArc_Start(
fs2us(tempFilePath),
fs2us(tempFile.Get_OriginalFilePath()),
totalSize,
1)) // updateMode
C_CopyFileProgress_to_FolderCallback_MoveArc prox(updateCallback_MoveArc);
res = tempFile.MoveToOriginal(
true, // deleteOriginal
&prox);
if (res == S_OK)
{
res = updateCallback_MoveArc->MoveArc_Finish();
// we don't return after E_ABORT here, because
// we want to reopen new archive still.
}
else if (prox.CallbackResult != S_OK)
res = prox.CallbackResult;
// if updating callback returned E_ABORT,
// then openCallback still can return E_ABORT also.
// So ReOpen() will return with E_ABORT.
// But we want to open archive still.
// And Before_ArcReopen() call will clear user break status in that case.
RINOK(updateCallback_MoveArc->Before_ArcReopen())
}
else
res = tempFile.MoveToOriginal(true); // deleteOriginal
// RINOK(res);
if (res == S_OK)
{
if (moveMode)
{
unsigned i;
for (i = 0; i < processedPaths.Size(); i++)
{
DeleteFileAlways(processedPaths[i]);
}
for (i = 0; i < requestedPaths.Size(); i++)
{
const FString &fs = requestedPaths[i];
if (NFind::DoesDirExist(fs))
Delete_EmptyFolder_And_EmptySubFolders(fs);
}
}
}
{
CMyComPtr<IArchiveOpenCallback> openCallback;
if (updateCallback100)
updateCallback100->QueryInterface(IID_IArchiveOpenCallback, (void **)&openCallback);
RINOK(_agent->ReOpen(openCallback))
}
// CAgent::ReOpen() deletes _proxy and _proxy2
// _items.Clear();
_proxy = NULL;
_proxy2 = NULL;
// _proxyDirIndex = k_Proxy_RootDirIndex;
_isAltStreamFolder = false;
// ---------- Restore FolderItem ----------
CMyComPtr<IFolderFolder> archiveFolder;
RINOK(_agent->BindToRootFolder(&archiveFolder))
// CAgent::BindToRootFolder() changes _proxy and _proxy2
_proxy = _agentSpec->_proxy;
_proxy2 = _agentSpec->_proxy2;
if (_proxy)
{
FOR_VECTOR (i, pathParts)
{
const int next = _proxy->FindSubDir(_proxyDirIndex, pathParts[i]);
if (next == -1)
break;
_proxyDirIndex = (unsigned)next;
}
}
if (_proxy2)
{
if (pathParts.IsEmpty() && isAltStreamFolder)
{
_proxyDirIndex = k_Proxy2_AltRootDirIndex;
}
else FOR_VECTOR (i, pathParts)
{
const bool dirOnly = (i + 1 < pathParts.Size() || !isAltStreamFolder);
const int index = _proxy2->FindItem(_proxyDirIndex, pathParts[i], dirOnly);
if (index == -1)
break;
const CProxyFile2 &file = _proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]];
if (dirOnly)
_proxyDirIndex = (unsigned)file.DirIndex;
else
{
if (file.AltDirIndex != -1)
_proxyDirIndex = (unsigned)file.AltDirIndex;
break;
}
}
}
/*
if (pathParts.IsEmpty() && isAltStreamFolder)
{
CMyComPtr<IFolderAltStreams> folderAltStreams;
archiveFolder.QueryInterface(IID_IFolderAltStreams, &folderAltStreams);
if (folderAltStreams)
{
CMyComPtr<IFolderFolder> newFolder;
folderAltStreams->BindToAltStreams((UInt32)(Int32)-1, &newFolder);
if (newFolder)
archiveFolder = newFolder;
}
}
FOR_VECTOR (i, pathParts)
{
CMyComPtr<IFolderFolder> newFolder;
if (isAltStreamFolder && i == pathParts.Size() - 1)
{
CMyComPtr<IFolderAltStreams> folderAltStreams;
archiveFolder.QueryInterface(IID_IFolderAltStreams, &folderAltStreams);
if (folderAltStreams)
folderAltStreams->BindToAltStreams(pathParts[i], &newFolder);
}
else
archiveFolder->BindToFolder(pathParts[i], &newFolder);
if (!newFolder)
break;
archiveFolder = newFolder;
}
CMyComPtr<IArchiveFolderInternal> archiveFolderInternal;
RINOK(archiveFolder.QueryInterface(IID_IArchiveFolderInternal, &archiveFolderInternal));
CAgentFolder *agentFolder;
RINOK(archiveFolderInternal->GetAgentFolder(&agentFolder));
_proxyDirIndex = agentFolder->_proxyDirIndex;
// _parentFolder = agentFolder->_parentFolder;
*/
if (_proxy2)
_isAltStreamFolder = _proxy2->IsAltDir(_proxyDirIndex);
return res;
}
catch(const UString &s)
{
if (updateCallback100)
{
UString s2 ("Error: ");
s2 += s;
RINOK(updateCallback100->UpdateErrorMessage(s2))
return E_FAIL;
}
throw;
}
}
Z7_COM7F_IMF(CAgentFolder::CopyFrom(Int32 moveMode,
const wchar_t *fromFolderPath, /* test it */
const wchar_t * const *itemsPaths,
UInt32 numItems,
IProgress *progress))
{
COM_TRY_BEGIN
{
RINOK(_agentSpec->SetFiles(fromFolderPath, itemsPaths, numItems))
return CommonUpdateOperation(AGENT_OP_Uni, (moveMode != 0), NULL,
&NUpdateArchive::k_ActionSet_Add,
NULL, 0, progress);
}
COM_TRY_END
}
Z7_COM7F_IMF(CAgentFolder::CopyFromFile(UInt32 destIndex, const wchar_t *itemPath, IProgress *progress))
{
COM_TRY_BEGIN
return CommonUpdateOperation(AGENT_OP_CopyFromFile, false, itemPath,
&NUpdateArchive::k_ActionSet_Add,
&destIndex, 1, progress);
COM_TRY_END
}
Z7_COM7F_IMF(CAgentFolder::Delete(const UInt32 *indices, UInt32 numItems, IProgress *progress))
{
COM_TRY_BEGIN
return CommonUpdateOperation(AGENT_OP_Delete, false, NULL,
&NUpdateArchive::k_ActionSet_Delete, indices, numItems, progress);
COM_TRY_END
}
Z7_COM7F_IMF(CAgentFolder::CreateFolder(const wchar_t *name, IProgress *progress))
{
COM_TRY_BEGIN
if (_isAltStreamFolder)
return E_NOTIMPL;
if (_proxy2)
{
if (_proxy2->IsThere_SubDir(_proxyDirIndex, name))
return ERROR_ALREADY_EXISTS;
}
else
{
if (_proxy->FindSubDir(_proxyDirIndex, name) != -1)
return ERROR_ALREADY_EXISTS;
}
return CommonUpdateOperation(AGENT_OP_CreateFolder, false, name, NULL, NULL, 0, progress);
COM_TRY_END
}
Z7_COM7F_IMF(CAgentFolder::Rename(UInt32 index, const wchar_t *newName, IProgress *progress))
{
COM_TRY_BEGIN
return CommonUpdateOperation(AGENT_OP_Rename, false, newName, NULL,
&index, 1, progress);
COM_TRY_END
}
Z7_COM7F_IMF(CAgentFolder::CreateFile(const wchar_t * /* name */, IProgress * /* progress */))
{
return E_NOTIMPL;
}
Z7_COM7F_IMF(CAgentFolder::SetProperty(UInt32 index, PROPID propID,
const PROPVARIANT *value, IProgress *progress))
{
COM_TRY_BEGIN
if (propID != kpidComment || value->vt != VT_BSTR)
return E_NOTIMPL;
if (!_agentSpec || !_agentSpec->GetTypeOfArc(_agentSpec->GetArc()).IsEqualTo_Ascii_NoCase("zip"))
return E_NOTIMPL;
return CommonUpdateOperation(AGENT_OP_Comment, false, value->bstrVal, NULL,
&index, 1, progress);
COM_TRY_END
}
@@ -0,0 +1,123 @@
// IFolderArchive.h
#ifndef ZIP7_INC_IFOLDER_ARCHIVE_H
#define ZIP7_INC_IFOLDER_ARCHIVE_H
#include "../../../Common/MyString.h"
#include "../../Archive/IArchive.h"
#include "../../UI/Common/LoadCodecs.h"
#include "../../UI/FileManager/IFolder.h"
#include "../Common/ExtractMode.h"
#include "../Common/IFileExtractCallback.h"
Z7_PURE_INTERFACES_BEGIN
/* ---------- IArchiveFolder ----------
IArchiveFolder is implemented by CAgentFolder (Agent/Agent.h)
IArchiveFolder is used by:
- FileManager/PanelCopy.cpp
CPanel::CopyTo(), if (options->testMode)
- FAR/PluginRead.cpp
CPlugin::ExtractFiles
*/
#define Z7_IFACEM_IArchiveFolder(x) \
x(Extract(const UInt32 *indices, UInt32 numItems, \
Int32 includeAltStreams, \
Int32 replaceAltStreamCharsMode, \
NExtract::NPathMode::EEnum pathMode, \
NExtract::NOverwriteMode::EEnum overwriteMode, \
const wchar_t *path, Int32 testMode, \
IFolderArchiveExtractCallback *extractCallback2)) \
Z7_IFACE_CONSTR_FOLDERARC(IArchiveFolder, 0x0D)
/* ---------- IInFolderArchive ----------
IInFolderArchive is implemented by CAgent (Agent/Agent.h)
IInFolderArchive Is used by FAR/Plugin
*/
#define Z7_IFACEM_IInFolderArchive(x) \
x(Open(IInStream *inStream, const wchar_t *filePath, const wchar_t *arcFormat, BSTR *archiveTypeRes, IArchiveOpenCallback *openArchiveCallback)) \
x(ReOpen(IArchiveOpenCallback *openArchiveCallback)) \
x(Close()) \
x(GetNumberOfProperties(UInt32 *numProperties)) \
x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \
x(BindToRootFolder(IFolderFolder **resultFolder)) \
x(Extract(NExtract::NPathMode::EEnum pathMode, \
NExtract::NOverwriteMode::EEnum overwriteMode, const wchar_t *path, \
Int32 testMode, IFolderArchiveExtractCallback *extractCallback2)) \
Z7_IFACE_CONSTR_FOLDERARC(IInFolderArchive, 0x0E)
#define Z7_IFACEM_IFolderArchiveUpdateCallback(x) \
x(CompressOperation(const wchar_t *name)) \
x(DeleteOperation(const wchar_t *name)) \
x(OperationResult(Int32 opRes)) \
x(UpdateErrorMessage(const wchar_t *message)) \
x(SetNumFiles(UInt64 numFiles)) \
Z7_IFACE_CONSTR_FOLDERARC_SUB(IFolderArchiveUpdateCallback, IProgress, 0x0B)
#define Z7_IFACEM_IOutFolderArchive(x) \
x(SetFolder(IFolderFolder *folder)) \
x(SetFiles(const wchar_t *folderPrefix, const wchar_t * const *names, UInt32 numNames)) \
x(DeleteItems(ISequentialOutStream *outArchiveStream, \
const UInt32 *indices, UInt32 numItems, IFolderArchiveUpdateCallback *updateCallback)) \
x(DoOperation( \
FStringVector *requestedPaths, \
FStringVector *processedPaths, \
CCodecs *codecs, int index, \
ISequentialOutStream *outArchiveStream, const Byte *stateActions, const wchar_t *sfxModule, \
IFolderArchiveUpdateCallback *updateCallback)) \
x(DoOperation2( \
FStringVector *requestedPaths, \
FStringVector *processedPaths, \
ISequentialOutStream *outArchiveStream, const Byte *stateActions, const wchar_t *sfxModule, \
IFolderArchiveUpdateCallback *updateCallback)) \
Z7_IFACE_CONSTR_FOLDERARC(IOutFolderArchive, 0x0F)
#define Z7_IFACEM_IFolderArchiveUpdateCallback2(x) \
x(OpenFileError(const wchar_t *path, HRESULT errorCode)) \
x(ReadingFileError(const wchar_t *path, HRESULT errorCode)) \
x(ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *path)) \
x(ReportUpdateOperation(UInt32 notifyOp, const wchar_t *path, Int32 isDir)) \
Z7_IFACE_CONSTR_FOLDERARC(IFolderArchiveUpdateCallback2, 0x10)
#define Z7_IFACEM_IFolderScanProgress(x) \
x(ScanError(const wchar_t *path, HRESULT errorCode)) \
x(ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, Int32 isDir)) \
Z7_IFACE_CONSTR_FOLDERARC(IFolderScanProgress, 0x11)
#define Z7_IFACEM_IFolderSetZoneIdMode(x) \
x(SetZoneIdMode(NExtract::NZoneIdMode::EEnum zoneMode)) \
Z7_IFACE_CONSTR_FOLDERARC(IFolderSetZoneIdMode, 0x12)
#define Z7_IFACEM_IFolderSetZoneIdFile(x) \
x(SetZoneIdFile(const Byte *data, UInt32 size)) \
Z7_IFACE_CONSTR_FOLDERARC(IFolderSetZoneIdFile, 0x13)
// if the caller calls Before_ArcReopen(), the callee must
// clear user break status, because the caller want to open archive still.
#define Z7_IFACEM_IFolderArchiveUpdateCallback_MoveArc(x) \
x(MoveArc_Start(const wchar_t *srcTempPath, const wchar_t *destFinalPath, UInt64 size, Int32 updateMode)) \
x(MoveArc_Progress(UInt64 totalSize, UInt64 currentSize)) \
x(MoveArc_Finish()) \
x(Before_ArcReopen()) \
Z7_IFACE_CONSTR_FOLDERARC(IFolderArchiveUpdateCallback_MoveArc, 0x14)
Z7_PURE_INTERFACES_END
#endif
+11
View File
@@ -0,0 +1,11 @@
// StdAfx.h
#ifndef ZIP7_INC_STDAFX_H
#define ZIP7_INC_STDAFX_H
#if defined(_MSC_VER) && _MSC_VER >= 1800
#pragma warning(disable : 4464) // relative include path contains '..'
#endif
#include "../../../Common/Common.h"
#endif
@@ -0,0 +1,208 @@
// UpdateCallbackAgent.h
#include "StdAfx.h"
#include "../../../Common/IntToString.h"
#include "../../../Windows/ErrorMsg.h"
#include "UpdateCallbackAgent.h"
using namespace NWindows;
void CUpdateCallbackAgent::SetCallback(IFolderArchiveUpdateCallback *callback)
{
Callback = callback;
_compressProgress.Release();
Callback2.Release();
if (Callback)
{
Callback.QueryInterface(IID_ICompressProgressInfo, &_compressProgress);
Callback.QueryInterface(IID_IFolderArchiveUpdateCallback2, &Callback2);
}
}
HRESULT CUpdateCallbackAgent::SetNumItems(const CArcToDoStat &stat)
{
if (Callback)
return Callback->SetNumFiles(stat.Get_NumDataItems_Total());
return S_OK;
}
HRESULT CUpdateCallbackAgent::WriteSfx(const wchar_t * /* name */, UInt64 /* size */)
{
return S_OK;
}
HRESULT CUpdateCallbackAgent::SetTotal(UINT64 size)
{
if (Callback)
return Callback->SetTotal(size);
return S_OK;
}
HRESULT CUpdateCallbackAgent::SetCompleted(const UINT64 *completeValue)
{
if (Callback)
return Callback->SetCompleted(completeValue);
return S_OK;
}
HRESULT CUpdateCallbackAgent::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
{
if (_compressProgress)
return _compressProgress->SetRatioInfo(inSize, outSize);
return S_OK;
}
HRESULT CUpdateCallbackAgent::CheckBreak()
{
return S_OK;
}
/*
HRESULT CUpdateCallbackAgent::Finalize()
{
return S_OK;
}
*/
HRESULT CUpdateCallbackAgent::OpenFileError(const FString &path, DWORD systemError)
{
const HRESULT hres = HRESULT_FROM_WIN32(systemError);
// if (systemError == ERROR_SHARING_VIOLATION)
{
if (Callback2)
{
RINOK(Callback2->OpenFileError(fs2us(path), hres))
return S_FALSE;
}
if (Callback)
{
UString s ("WARNING: ");
s += NError::MyFormatMessage(systemError);
s += ": ";
s += fs2us(path);
RINOK(Callback->UpdateErrorMessage(s))
return S_FALSE;
}
}
// FailedFiles.Add(name);
return hres;
}
HRESULT CUpdateCallbackAgent::ReadingFileError(const FString &path, DWORD systemError)
{
const HRESULT hres = HRESULT_FROM_WIN32(systemError);
// if (systemError == ERROR_SHARING_VIOLATION)
{
if (Callback2)
{
RINOK(Callback2->ReadingFileError(fs2us(path), hres))
}
else if (Callback)
{
UString s ("ERROR: ");
s += NError::MyFormatMessage(systemError);
s += ": ";
s += fs2us(path);
RINOK(Callback->UpdateErrorMessage(s))
}
}
// FailedFiles.Add(name);
return hres;
}
HRESULT CUpdateCallbackAgent::GetStream(const wchar_t *name, bool isDir, bool /* isAnti */, UInt32 mode)
{
if (Callback2)
return Callback2->ReportUpdateOperation(mode, name, BoolToInt(isDir));
if (Callback)
return Callback->CompressOperation(name);
return S_OK;
}
HRESULT CUpdateCallbackAgent::SetOperationResult(Int32 operationResult)
{
if (Callback)
return Callback->OperationResult(operationResult);
return S_OK;
}
void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s);
HRESULT CUpdateCallbackAgent::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name)
{
if (Callback2)
{
return Callback2->ReportExtractResult(opRes, isEncrypted, name);
}
/*
if (mode != NArchive::NExtract::NOperationResult::kOK)
{
Int32 encrypted = 0;
UString s;
SetExtractErrorMessage(mode, encrypted, name, s);
// ProgressDialog->Sync.AddError_Message(s);
}
*/
return S_OK;
}
HRESULT CUpdateCallbackAgent::ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir)
{
if (Callback2)
{
return Callback2->ReportUpdateOperation(op, name, BoolToInt(isDir));
}
return S_OK;
}
/*
HRESULT CUpdateCallbackAgent::SetPassword(const UString &
#ifndef Z7_NO_CRYPTO
password
#endif
)
{
#ifndef Z7_NO_CRYPTO
PasswordIsDefined = true;
Password = password;
#endif
return S_OK;
}
*/
HRESULT CUpdateCallbackAgent::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
{
*password = NULL;
*passwordIsDefined = BoolToInt(false);
if (!_cryptoGetTextPassword)
{
if (!Callback)
return S_OK;
Callback.QueryInterface(IID_ICryptoGetTextPassword2, &_cryptoGetTextPassword);
if (!_cryptoGetTextPassword)
return S_OK;
}
return _cryptoGetTextPassword->CryptoGetTextPassword2(passwordIsDefined, password);
}
HRESULT CUpdateCallbackAgent::CryptoGetTextPassword(BSTR *password)
{
*password = NULL;
CMyComPtr<ICryptoGetTextPassword> getTextPassword;
Callback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
if (!getTextPassword)
return E_NOTIMPL;
return getTextPassword->CryptoGetTextPassword(password);
}
HRESULT CUpdateCallbackAgent::ShowDeleteFile(const wchar_t *name, bool /* isDir */)
{
return Callback->DeleteOperation(name);
}
@@ -0,0 +1,22 @@
// UpdateCallbackAgent.h
#ifndef ZIP7_INC_UPDATE_CALLBACK_AGENT_H
#define ZIP7_INC_UPDATE_CALLBACK_AGENT_H
#include "../Common/UpdateCallback.h"
#include "IFolderArchive.h"
class CUpdateCallbackAgent Z7_final: public IUpdateCallbackUI
{
Z7_IFACE_IMP(IUpdateCallbackUI)
CMyComPtr<ICryptoGetTextPassword2> _cryptoGetTextPassword;
CMyComPtr<IFolderArchiveUpdateCallback> Callback;
CMyComPtr<IFolderArchiveUpdateCallback2> Callback2;
CMyComPtr<ICompressProgressInfo> _compressProgress;
public:
void SetCallback(IFolderArchiveUpdateCallback *callback);
};
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,331 @@
# Microsoft Developer Studio Project File - Name="Client7z" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
CFG=Client7z - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "Client7z.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "Client7z.mak" CFG="Client7z - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "Client7z - Win32 Release" (based on "Win32 (x86) Console Application")
!MESSAGE "Client7z - Win32 Debug" (based on "Win32 (x86) Console Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "Client7z - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /MD /W4 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
# ADD BASE RSC /l 0x419 /d "NDEBUG"
# ADD RSC /l 0x419 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"Release/7zcl.exe"
!ELSEIF "$(CFG)" == "Client7z - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
# ADD CPP /nologo /MDd /W4 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
# ADD BASE RSC /l 0x419 /d "_DEBUG"
# ADD RSC /l 0x419 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/7zcl.exe" /pdbtype:sept
!ENDIF
# Begin Target
# Name "Client7z - Win32 Release"
# Name "Client7z - Win32 Debug"
# Begin Group "Spec"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\resource.rc
# End Source File
# Begin Source File
SOURCE=.\StdAfx.cpp
# ADD CPP /Yc"stdafx.h"
# End Source File
# Begin Source File
SOURCE=.\StdAfx.h
# End Source File
# End Group
# Begin Group "Windows"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\..\Windows\Defs.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\DLL.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\DLL.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\FileDir.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\FileDir.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\FileFind.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\FileFind.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\FileIO.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\FileIO.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\FileName.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\FileName.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\NtCheck.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\PropVariant.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\PropVariant.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\PropVariantConv.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\PropVariantConv.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\TimeUtils.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Windows\TimeUtils.h
# End Source File
# End Group
# Begin Group "Common"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\..\Common\Common.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\Defs.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\IntToString.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\IntToString.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\MyBuffer.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\MyCom.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\MyInitGuid.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\MyLinux.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\MyString.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\MyString.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\MyTypes.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\MyVector.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\MyVector.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\MyWindows.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\NewHandler.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\NewHandler.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\StringConvert.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\StringConvert.h
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\Wildcard.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\Common\Wildcard.h
# End Source File
# End Group
# Begin Group "7zip Common"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\Common\FileStreams.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Common\FileStreams.h
# End Source File
# Begin Source File
SOURCE=..\..\Common\UniqBlocks.h
# End Source File
# End Group
# Begin Group "C"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\..\..\C\7zTypes.h
# End Source File
# Begin Source File
SOURCE=..\..\..\..\C\7zVersion.h
# End Source File
# Begin Source File
SOURCE=..\..\..\..\C\7zWindows.h
# End Source File
# Begin Source File
SOURCE=..\..\..\..\C\Compiler.h
# End Source File
# Begin Source File
SOURCE=..\..\..\..\C\CpuArch.h
# End Source File
# End Group
# Begin Group "7zip"
# PROP Default_Filter ""
# Begin Source File
SOURCE=..\..\IDecl.h
# End Source File
# Begin Source File
SOURCE=..\..\IPassword.h
# End Source File
# Begin Source File
SOURCE=..\..\IProgress.h
# End Source File
# Begin Source File
SOURCE=..\..\PropID.h
# End Source File
# End Group
# Begin Source File
SOURCE=.\Client7z.cpp
# End Source File
# Begin Source File
SOURCE=..\..\Archive\IArchive.h
# End Source File
# End Target
# End Project
@@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "Client7z"=.\Client7z.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################
@@ -0,0 +1,3 @@
// StdAfx.cpp
#include "StdAfx.h"
@@ -0,0 +1,11 @@
// StdAfx.h
#ifndef ZIP7_INC_STDAFX_H
#define ZIP7_INC_STDAFX_H
#if defined(_MSC_VER) && _MSC_VER >= 1800
#pragma warning(disable : 4464) // relative include path contains '..'
#endif
#include "../../../Common/Common.h"
#endif
@@ -0,0 +1,29 @@
PROG = 7zcl.exe
MY_CONSOLE = 1
CURRENT_OBJS = \
$O\Client7z.obj \
COMMON_OBJS = \
$O\IntToString.obj \
$O\NewHandler.obj \
$O\MyString.obj \
$O\MyVector.obj \
$O\StringConvert.obj \
$O\StringToInt.obj \
$O\Wildcard.obj \
WIN_OBJS = \
$O\DLL.obj \
$O\FileDir.obj \
$O\FileFind.obj \
$O\FileIO.obj \
$O\FileName.obj \
$O\PropVariant.obj \
$O\PropVariantConv.obj \
$O\TimeUtils.obj \
7ZIP_COMMON_OBJS = \
$O\FileStreams.obj \
!include "../../7zip.mak"
@@ -0,0 +1,72 @@
PROG = 7zcl
IS_NOT_STANDALONE = 1
# IS_X64 = 1
ifdef SystemDrive
IS_MINGW = 1
else
ifdef SYSTEMDRIVE
# ifdef OS
IS_MINGW = 1
endif
endif
ifdef IS_MINGW
SYS_OBJS = \
$O/resource.o \
else
SYS_OBJS = \
$O/MyWindows.o \
endif
LOCAL_FLAGS = \
CURRENT_OBJS = \
$O/Client7z.o \
COMMON_OBJS = \
$O/IntToString.o \
$O/MyString.o \
$O/MyVector.o \
$O/NewHandler.o \
$O/StringConvert.o \
$O/StringToInt.o \
$O/UTFConvert.o \
$O/Wildcard.o \
WIN_OBJS = \
$O/DLL.o \
$O/FileDir.o \
$O/FileFind.o \
$O/FileIO.o \
$O/FileName.o \
$O/PropVariant.o \
$O/PropVariantConv.o \
$O/TimeUtils.o \
7ZIP_COMMON_OBJS = \
$O/FileStreams.o \
C_OBJS = \
$O/Alloc.o \
OBJS = \
$(C_OBJS) \
$(COMMON_OBJS) \
$(WIN_OBJS) \
$(SYS_OBJS) \
$(7ZIP_COMMON_OBJS) \
$(CURRENT_OBJS) \
include ../../7zip_gcc.mak
@@ -0,0 +1,3 @@
#include "../../MyVersionInfo.rc"
MY_VERSION_INFO_APP("7-Zip client" , "7zcl")
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,170 @@
// ArchiveCommandLine.h
#ifndef ZIP7_INC_ARCHIVE_COMMAND_LINE_H
#define ZIP7_INC_ARCHIVE_COMMAND_LINE_H
#include "../../../Common/CommandLineParser.h"
#include "../../../Common/Wildcard.h"
#include "EnumDirItems.h"
#include "Extract.h"
#include "HashCalc.h"
#include "Update.h"
typedef CMessagePathException CArcCmdLineException;
namespace NCommandType { enum EEnum
{
kAdd = 0,
kUpdate,
kDelete,
kTest,
kExtract,
kExtractFull,
kList,
kBenchmark,
kInfo,
kHash,
kRename
};}
struct CArcCommand
{
NCommandType::EEnum CommandType;
bool IsFromExtractGroup() const;
bool IsFromUpdateGroup() const;
bool IsTestCommand() const { return CommandType == NCommandType::kTest; }
NExtract::NPathMode::EEnum GetPathMode() const;
};
enum
{
k_OutStream_disabled = 0,
k_OutStream_stdout = 1,
k_OutStream_stderr = 2
};
struct CArcCmdLineOptions
{
bool HelpMode;
// bool LargePages;
bool CaseSensitive_Change;
bool CaseSensitive;
bool IsInTerminal;
bool IsStdOutTerminal;
bool IsStdErrTerminal;
bool StdInMode;
bool StdOutMode;
bool EnableHeaders;
bool DisablePercents;
bool YesToAll;
bool ShowDialog;
bool TechMode;
bool ShowTime;
CBoolPair ListPathSeparatorSlash;
CBoolPair NtSecurity;
CBoolPair AltStreams;
CBoolPair HardLinks;
CBoolPair SymLinks;
CBoolPair StoreOwnerId;
CBoolPair StoreOwnerName;
AString ListFields;
int ConsoleCodePage;
NWildcard::CCensor Censor;
CArcCommand Command;
UString ArchiveName;
#ifndef Z7_NO_CRYPTO
bool PasswordEnabled;
UString Password;
#endif
UStringVector HashMethods;
// UString HashFilePath;
// bool AppendName;
// UStringVector ArchivePathsSorted;
// UStringVector ArchivePathsFullSorted;
NWildcard::CCensor arcCensor;
UString ArcName_for_StdInMode;
CObjectVector<CProperty> Properties;
CExtractOptionsBase ExtractOptions;
CUpdateOptions UpdateOptions;
CHashOptions HashOptions;
UString ArcType;
UStringVector ExcludedArcTypes;
unsigned Number_for_Out;
unsigned Number_for_Errors;
unsigned Number_for_Percents;
unsigned LogLevel;
// bool IsOutAllowed() const { return Number_for_Out != k_OutStream_disabled; }
// Benchmark
UInt32 NumIterations;
bool NumIterations_Defined;
CArcCmdLineOptions():
HelpMode(false),
// LargePages(false),
CaseSensitive_Change(false),
CaseSensitive(false),
IsInTerminal(false),
IsStdOutTerminal(false),
IsStdErrTerminal(false),
StdInMode(false),
StdOutMode(false),
EnableHeaders(false),
DisablePercents(false),
YesToAll(false),
ShowDialog(false),
TechMode(false),
ShowTime(false),
ConsoleCodePage(-1),
Number_for_Out(k_OutStream_stdout),
Number_for_Errors(k_OutStream_stderr),
Number_for_Percents(k_OutStream_stdout),
LogLevel(0)
{
ListPathSeparatorSlash.Val =
#ifdef _WIN32
false;
#else
true;
#endif
}
};
class CArcCmdLineParser
{
NCommandLineParser::CParser parser;
public:
UString Parse1Log;
void Parse1(const UStringVector &commandStrings, CArcCmdLineOptions &options);
void Parse2(CArcCmdLineOptions &options);
};
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,641 @@
// ArchiveExtractCallback.h
#ifndef ZIP7_INC_ARCHIVE_EXTRACT_CALLBACK_H
#define ZIP7_INC_ARCHIVE_EXTRACT_CALLBACK_H
#include "../../../Common/MyCom.h"
#include "../../../Common/MyLinux.h"
#include "../../../Common/Wildcard.h"
#include "../../IPassword.h"
#include "../../Common/FileStreams.h"
#include "../../Common/ProgressUtils.h"
#include "../../Common/StreamObjects.h"
#include "../../Archive/IArchive.h"
#include "ExtractMode.h"
#include "IFileExtractCallback.h"
#include "OpenArchive.h"
#include "HashCalc.h"
#ifndef Z7_SFX
Z7_CLASS_IMP_NOQIB_1(
COutStreamWithHash
, ISequentialOutStream
)
bool _calculate;
CMyComPtr<ISequentialOutStream> _stream;
UInt64 _size;
public:
IHashCalc *_hash;
void SetStream(ISequentialOutStream *stream) { _stream = stream; }
void ReleaseStream() { _stream.Release(); }
void Init(bool calculate = true)
{
InitCRC();
_size = 0;
_calculate = calculate;
}
void EnableCalc(bool calculate) { _calculate = calculate; }
void InitCRC() { _hash->InitForNewFile(); }
UInt64 GetSize() const { return _size; }
};
#endif
struct CExtractNtOptions
{
CBoolPair NtSecurity;
CBoolPair SymLinks;
CBoolPair HardLinks;
CBoolPair AltStreams;
bool ReplaceColonForAltStream;
bool WriteToAltStreamIfColon;
bool ExtractOwner;
bool PreAllocateOutFile;
// used for hash arcs only, when we open external files
bool PreserveATime;
bool OpenShareForWrite;
unsigned SymLinks_DangerousLevel;
UInt64 MemLimit;
CExtractNtOptions():
ReplaceColonForAltStream(false),
WriteToAltStreamIfColon(false),
ExtractOwner(false),
PreserveATime(false),
OpenShareForWrite(false),
SymLinks_DangerousLevel(5),
MemLimit((UInt64)(Int64)-1)
{
SymLinks.Val = true;
HardLinks.Val = true;
AltStreams.Val = true;
PreAllocateOutFile =
#ifdef _WIN32
true;
#else
false;
#endif
}
};
#ifndef Z7_SFX
#ifndef UNDER_CE
#define SUPPORT_LINKS
#endif
#endif
#ifdef SUPPORT_LINKS
struct CHardLinkNode
{
UInt64 StreamId;
UInt64 INode;
int Compare(const CHardLinkNode &a) const;
};
class CHardLinks
{
public:
CRecordVector<CHardLinkNode> IDs;
CObjectVector<FString> Links;
void Clear()
{
IDs.Clear();
Links.Clear();
}
void PrepareLinks()
{
while (Links.Size() < IDs.Size())
Links.AddNew();
}
};
#endif
#ifdef SUPPORT_ALT_STREAMS
struct CIndexToPathPair
{
UInt32 Index;
FString Path;
CIndexToPathPair(UInt32 index): Index(index) {}
CIndexToPathPair(UInt32 index, const FString &path): Index(index), Path(path) {}
int Compare(const CIndexToPathPair &pair) const
{
return MyCompare(Index, pair.Index);
}
};
#endif
struct CFiTimesCAM
{
CFiTime CTime;
CFiTime ATime;
CFiTime MTime;
bool CTime_Defined;
bool ATime_Defined;
bool MTime_Defined;
bool IsSomeTimeDefined() const
{
return
CTime_Defined |
ATime_Defined |
MTime_Defined;
}
bool SetDirTime_to_FS(CFSTR path) const;
#ifdef SUPPORT_LINKS
bool SetLinkFileTime_to_FS(CFSTR path) const;
#endif
};
struct CDirPathTime: public CFiTimesCAM
{
FString Path;
bool SetDirTime_to_FS_2() const { return SetDirTime_to_FS(Path); }
};
#ifdef SUPPORT_LINKS
enum ELinkType
{
k_LinkType_HardLink,
k_LinkType_PureSymLink,
k_LinkType_Junction,
k_LinkType_WSL
// , k_LinkType_CopyLink;
};
struct CLinkInfo
{
ELinkType LinkType;
bool isRelative;
// if (isRelative == false), then (LinkPath) is relative to root folder of archive
// if (isRelative == true ), then (LinkPath) is relative to current item
bool isWindowsPath;
UString LinkPath;
bool Is_HardLink() const { return LinkType == k_LinkType_HardLink; }
bool Is_AnySymLink() const { return LinkType != k_LinkType_HardLink; }
bool Is_WSL() const { return LinkType == k_LinkType_WSL; }
CLinkInfo():
LinkType(k_LinkType_PureSymLink),
isRelative(false),
isWindowsPath(false)
{}
void Clear()
{
LinkType = k_LinkType_PureSymLink;
isRelative = false;
isWindowsPath = false;
LinkPath.Empty();
}
bool Parse_from_WindowsReparseData(const Byte *data, size_t dataSize);
bool Parse_from_LinuxData(const Byte *data, size_t dataSize);
void Normalize_to_RelativeSafe(UStringVector &removePathParts);
private:
void Remove_AbsPathPrefixes();
};
#endif // SUPPORT_LINKS
struct CProcessedFileInfo
{
CArcTime CTime;
CArcTime ATime;
CArcTime MTime;
UInt32 Attrib;
bool Attrib_Defined;
#ifndef _WIN32
struct COwnerInfo
{
bool Id_Defined;
UInt32 Id;
AString Name;
void Clear()
{
Id_Defined = false;
Id = 0;
Name.Empty();
}
};
COwnerInfo Owner;
COwnerInfo Group;
#endif
void Clear()
{
#ifndef _WIN32
Attrib_Defined = false;
Owner.Clear();
#endif
}
bool IsReparse() const
{
return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0);
}
bool IsLinuxSymLink() const
{
return (Attrib_Defined && MY_LIN_S_ISLNK(Attrib >> 16));
}
void SetFromPosixAttrib(UInt32 a)
{
// here we set only part of combined attribute required by SetFileAttrib() call
#ifdef _WIN32
// Windows sets FILE_ATTRIBUTE_NORMAL, if we try to set 0 as attribute.
Attrib = MY_LIN_S_ISDIR(a) ?
FILE_ATTRIBUTE_DIRECTORY :
FILE_ATTRIBUTE_ARCHIVE;
if ((a & 0222) == 0) // (& S_IWUSR) in p7zip
Attrib |= FILE_ATTRIBUTE_READONLY;
// 22.00 : we need type bits for (MY_LIN_S_IFLNK) for IsLinuxSymLink()
a &= MY_LIN_S_IFMT;
if (a == MY_LIN_S_IFLNK)
Attrib |= (a << 16);
#else
Attrib = (a << 16) | FILE_ATTRIBUTE_UNIX_EXTENSION;
#endif
Attrib_Defined = true;
}
};
#ifdef SUPPORT_LINKS
struct CPostLink
{
UInt32 Index_in_Arc;
bool item_IsDir; // _item.IsDir
UString item_Path; // _item.Path;
UStringVector item_PathParts; // _item.PathParts;
CProcessedFileInfo item_FileInfo; // _fi
FString fullProcessedPath_from; // full file path in FS
CLinkInfo LinkInfo;
};
/*
struct CPostLinks
{
void Clear()
{
Links.Clear();
}
};
*/
#endif // SUPPORT_LINKS
class CArchiveExtractCallback Z7_final:
public IArchiveExtractCallback,
public IArchiveExtractCallbackMessage2,
public ICryptoGetTextPassword,
public ICompressProgressInfo,
#ifndef Z7_SFX
public IArchiveUpdateCallbackFile,
public IArchiveGetDiskProperty,
public IArchiveRequestMemoryUseCallback,
#endif
public CMyUnknownImp
{
/* IArchiveExtractCallback, */
Z7_COM_QI_BEGIN2(IArchiveExtractCallbackMessage2)
Z7_COM_QI_ENTRY(ICryptoGetTextPassword)
Z7_COM_QI_ENTRY(ICompressProgressInfo)
#ifndef Z7_SFX
Z7_COM_QI_ENTRY(IArchiveUpdateCallbackFile)
Z7_COM_QI_ENTRY(IArchiveGetDiskProperty)
Z7_COM_QI_ENTRY(IArchiveRequestMemoryUseCallback)
#endif
Z7_COM_QI_END
Z7_COM_ADDREF_RELEASE
Z7_IFACE_COM7_IMP(IProgress)
Z7_IFACE_COM7_IMP(IArchiveExtractCallback)
Z7_IFACE_COM7_IMP(IArchiveExtractCallbackMessage2)
Z7_IFACE_COM7_IMP(ICryptoGetTextPassword)
Z7_IFACE_COM7_IMP(ICompressProgressInfo)
#ifndef Z7_SFX
Z7_IFACE_COM7_IMP(IArchiveUpdateCallbackFile)
Z7_IFACE_COM7_IMP(IArchiveGetDiskProperty)
Z7_IFACE_COM7_IMP(IArchiveRequestMemoryUseCallback)
#endif
// bool Write_CTime;
// bool Write_ATime;
// bool Write_MTime;
bool _stdOutMode;
bool _testMode;
bool _removePartsForAltStreams;
public:
bool Is_elimPrefix_Mode;
private:
const CArc *_arc;
public:
CExtractNtOptions _ntOptions;
private:
bool _encrypted;
bool _isSplit;
bool _curSize_Defined;
bool _fileLength_WasSet;
bool _isRenamed;
bool _extractMode;
bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX.
// _is_SymLink_in_Data_Linux is detected from Windows/Linux part of attributes of file.
bool _needSetAttrib;
bool _isSymLinkCreated;
bool _itemFailure;
bool _some_pathParts_wereRemoved;
bool _multiArchives;
bool _keepAndReplaceEmptyDirPrefixes; // replace them to "_";
#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
bool _saclEnabled;
#endif
NExtract::NPathMode::EEnum _pathMode;
NExtract::NOverwriteMode::EEnum _overwriteMode;
CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2;
const NWildcard::CCensorNode *_wildcardCensor; // we need wildcard for single pass mode (stdin)
// CMyComPtr<ICompressProgressInfo> _compressProgress;
// CMyComPtr<IArchiveExtractCallbackMessage2> _callbackMessage;
CMyComPtr<IFolderArchiveExtractCallback2> _folderArchiveExtractCallback2;
CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;
FString _dirPathPrefix;
public:
FString _dirPathPrefix_Full;
private:
#ifndef Z7_SFX
CMyComPtr<IFolderExtractToStreamCallback> ExtractToStreamCallback;
CMyComPtr<IArchiveRequestMemoryUseCallback> _requestMemoryUseCallback;
#endif
CReadArcItem _item;
FString _diskFilePath;
CProcessedFileInfo _fi;
UInt64 _position;
UInt64 _curSize;
UInt64 _fileLength_that_WasSet;
UInt32 _index;
// #ifdef SUPPORT_ALT_STREAMS
#if defined(_WIN32) && !defined(UNDER_CE)
DWORD _altStream_NeedRestore_AttribVal;
FString _altStream_NeedRestore_Attrib_for_parentFsPath;
#endif
// #endif
COutFileStream *_outFileStreamSpec;
CMyComPtr<ISequentialOutStream> _outFileStream;
CByteBuffer _outMemBuf;
CBufPtrSeqOutStream *_bufPtrSeqOutStream_Spec;
CMyComPtr<ISequentialOutStream> _bufPtrSeqOutStream;
#ifndef Z7_SFX
COutStreamWithHash *_hashStreamSpec;
CMyComPtr<ISequentialOutStream> _hashStream;
bool _hashStreamWasUsed;
bool _use_baseParentFolder_mode;
UInt32 _baseParentFolder;
#endif
UStringVector _removePathParts;
UInt64 _packTotal;
UInt64 _progressTotal;
// bool _progressTotal_Defined;
CObjectVector<CDirPathTime> _extractedFolders;
#ifndef _WIN32
// CObjectVector<NWindows::NFile::NDir::CDelayedSymLink> _delayedSymLinks;
#endif
void CreateComplexDirectory(
const UStringVector &dirPathParts, bool isFinal, FString &fullPath);
HRESULT GetTime(UInt32 index, PROPID propID, CArcTime &ft);
HRESULT GetUnpackSize();
FString Hash_GetFullFilePath();
void SetAttrib() const;
public:
HRESULT SendMessageError(const char *message, const FString &path) const;
HRESULT SendMessageError_with_Error(HRESULT errorCode, const char *message, const FString &path) const;
HRESULT SendMessageError_with_LastError(const char *message, const FString &path) const;
HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2) const;
HRESULT SendMessageError2_with_LastError(const char *message, const FString &path1, const FString &path2) const;
#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
NExtract::NZoneIdMode::EEnum ZoneMode;
CByteBuffer ZoneBuf;
#endif
CMyComPtr2_Create<ICompressProgressInfo, CLocalProgress> LocalProgressSpec;
UInt64 NumFolders;
UInt64 NumFiles;
UInt64 NumAltStreams;
UInt64 UnpackSize;
UInt64 AltStreams_UnpackSize;
FString DirPathPrefix_for_HashFiles;
CArchiveExtractCallback();
void InitForMulti(bool multiArchives,
NExtract::NPathMode::EEnum pathMode,
NExtract::NOverwriteMode::EEnum overwriteMode,
NExtract::NZoneIdMode::EEnum zoneMode,
bool keepAndReplaceEmptyDirPrefixes)
{
_multiArchives = multiArchives;
_pathMode = pathMode;
_overwriteMode = overwriteMode;
#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
ZoneMode = zoneMode;
#else
UNUSED_VAR(zoneMode)
#endif
_keepAndReplaceEmptyDirPrefixes = keepAndReplaceEmptyDirPrefixes;
NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0;
}
#ifndef Z7_SFX
void SetHashMethods(IHashCalc *hash)
{
if (!hash)
return;
_hashStreamSpec = new COutStreamWithHash;
_hashStream = _hashStreamSpec;
_hashStreamSpec->_hash = hash;
}
#endif
void InitBeforeNewArchive();
void Init(
const CExtractNtOptions &ntOptions,
const NWildcard::CCensorNode *wildcardCensor,
const CArc *arc,
IFolderArchiveExtractCallback *extractCallback2,
bool stdOutMode, bool testMode,
const FString &directoryPath,
const UStringVector &removePathParts, bool removePartsForAltStreams,
UInt64 packSize);
#ifdef SUPPORT_LINKS
private:
CHardLinks _hardLinks;
CObjectVector<CPostLink> _postLinks;
CLinkInfo _link;
// const void *NtReparse_Data;
// UInt32 NtReparse_Size;
// FString _copyFile_Path;
// HRESULT MyCopyFile(ISequentialOutStream *outStream);
HRESULT ReadLink();
HRESULT SetLink(
const FString &fullProcessedPath_from,
const CLinkInfo &linkInfo,
bool &linkWasSet);
HRESULT SetPostLinks() const;
public:
HRESULT CreateHardLink2(const FString &newFilePath,
const FString &existFilePath, bool &link_was_Created) const;
HRESULT DeleteLinkFileAlways_or_RemoveEmptyDir(const FString &path, bool checkThatFileIsEmpty) const;
HRESULT PrepareHardLinks(const CRecordVector<UInt32> *realIndices); // NULL means all items
#endif
private:
#ifdef SUPPORT_ALT_STREAMS
CObjectVector<CIndexToPathPair> _renamedFiles;
#endif
// call it after Init()
public:
#ifndef Z7_SFX
void SetBaseParentFolderIndex(UInt32 indexInArc)
{
_baseParentFolder = indexInArc;
_use_baseParentFolder_mode = true;
}
#endif
HRESULT CloseArc();
private:
void ClearExtractedDirsInfo()
{
_extractedFolders.Clear();
#ifndef _WIN32
// _delayedSymLinks.Clear();
#endif
}
HRESULT Read_fi_Props();
void CorrectPathParts();
void CreateFolders();
HRESULT CheckExistFile(FString &fullProcessedPath, bool &needExit);
HRESULT GetExtractStream(CMyComPtr<ISequentialOutStream> &outStreamLoc, bool &needExit);
HRESULT GetItem(UInt32 index);
HRESULT CloseFile();
HRESULT CloseReparseAndFile();
HRESULT SetDirsTimes();
HRESULT SetSecurityInfo(UInt32 indexInArc, const FString &path) const;
};
struct CArchiveExtractCallback_Closer
{
CArchiveExtractCallback *_ref;
CArchiveExtractCallback_Closer(CArchiveExtractCallback *ref): _ref(ref) {}
HRESULT Close()
{
HRESULT res = S_OK;
if (_ref)
{
res = _ref->CloseArc();
_ref = NULL;
}
return res;
}
~CArchiveExtractCallback_Closer()
{
Close();
}
};
bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item);
bool Is_ZoneId_StreamName(const wchar_t *s);
void ReadZoneFile_Of_BaseFile(CFSTR fileName, CByteBuffer &buf);
bool WriteZoneFile_To_BaseFile(CFSTR fileName, const CByteBuffer &buf);
#endif
@@ -0,0 +1,176 @@
// ArchiveName.cpp
#include "StdAfx.h"
#include "../../../../C/Sort.h"
#include "../../../Common/Wildcard.h"
#include "../../../Common/StringToInt.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/FileName.h"
#include "ArchiveName.h"
#include "ExtractingFilePath.h"
using namespace NWindows;
using namespace NFile;
static const char * const g_ArcExts =
"7z"
"\0" "zip"
"\0" "tar"
"\0" "wim"
"\0";
static const char * const g_HashExts =
"sha256"
"\0";
UString CreateArchiveName(
const UStringVector &paths,
bool isHash,
const NFind::CFileInfo *fi,
UString &baseName)
{
bool keepName = isHash;
/*
if (paths.Size() == 1)
{
const UString &name = paths[0];
if (name.Len() > 4)
if (CompareFileNames(name.RightPtr(4), L".tar") == 0)
keepName = true;
}
*/
UString name ("Archive");
NFind::CFileInfo fi3;
if (paths.Size() > 1)
fi = NULL;
if (!fi && paths.Size() != 0)
{
const UString &path = paths.Front();
if (paths.Size() == 1)
{
if (fi3.Find(us2fs(path)))
fi = &fi3;
}
else
{
// we try to use name of parent folder
FString dirPrefix;
if (NDir::GetOnlyDirPrefix(us2fs(path), dirPrefix))
{
if (!dirPrefix.IsEmpty() && IsPathSepar(dirPrefix.Back()))
{
#if defined(_WIN32) && !defined(UNDER_CE)
if (NName::IsDriveRootPath_SuperAllowed(dirPrefix))
{
if (path != fs2us(dirPrefix))
name = dirPrefix[dirPrefix.Len() - 3]; // only letter
}
else
#endif
{
dirPrefix.DeleteBack();
if (!dirPrefix.IsEmpty())
{
const int slash = dirPrefix.ReverseFind_PathSepar();
if (slash >= 0 && slash != (int)dirPrefix.Len() - 1)
name = dirPrefix.Ptr(slash + 1);
else if (fi3.Find(dirPrefix))
name = fs2us(fi3.Name);
}
}
}
}
}
}
if (fi)
{
name = fs2us(fi->Name);
if (!fi->IsDir() && !keepName)
{
const int dotPos = name.Find(L'.');
if (dotPos > 0 && name.Find(L'.', (unsigned)dotPos + 1) < 0)
name.DeleteFrom((unsigned)dotPos);
}
}
name = Get_Correct_FsFile_Name(name);
CRecordVector<UInt32> ids;
bool simple_IsAllowed = true;
// for (int y = 0; y < 10000; y++) // for debug
{
// ids.Clear();
UString n;
FOR_VECTOR (i, paths)
{
const UString &a = paths[i];
const int slash = a.ReverseFind_PathSepar();
// if (name.Len() >= a.Len() - slash + 1) continue;
const wchar_t *s = a.Ptr(slash + 1);
if (!IsPath1PrefixedByPath2(s, name))
continue;
s += name.Len();
const char *exts = isHash ? g_HashExts : g_ArcExts;
for (;;)
{
const char *ext = exts;
const unsigned len = MyStringLen(ext);
if (len == 0)
break;
exts += len + 1;
n = s;
if (n.Len() <= len)
continue;
if (!StringsAreEqualNoCase_Ascii(n.RightPtr(len), ext))
continue;
n.DeleteFrom(n.Len() - len);
if (n.Back() != '.')
continue;
n.DeleteBack();
if (n.IsEmpty())
{
simple_IsAllowed = false;
break;
}
if (n.Len() < 2)
continue;
if (n[0] != '_')
continue;
const wchar_t *end;
const UInt32 v = ConvertStringToUInt32(n.Ptr(1), &end);
if (*end != 0)
continue;
ids.Add(v);
break;
}
}
}
baseName = name;
if (!simple_IsAllowed)
{
HeapSort(ids.NonConstData(), ids.Size());
UInt32 v = 2;
const unsigned num = ids.Size();
for (unsigned i = 0; i < num; i++)
{
const UInt32 id = ids[i];
if (id > v)
break;
if (id == v)
v = id + 1;
}
name.Add_Char('_');
name.Add_UInt32(v);
}
return name;
}
@@ -0,0 +1,16 @@
// ArchiveName.h
#ifndef ZIP7_INC_ARCHIVE_NAME_H
#define ZIP7_INC_ARCHIVE_NAME_H
#include "../../../Windows/FileFind.h"
/* (fi != NULL) only if (paths.Size() == 1) */
UString CreateArchiveName(
const UStringVector &paths,
bool isHash,
const NWindows::NFile::NFind::CFileInfo *fi,
UString &baseName);
#endif
@@ -0,0 +1,398 @@
// ArchiveOpenCallback.cpp
#include "StdAfx.h"
#include "../../../Common/ComTry.h"
#include "../../../Windows/FileName.h"
#include "../../../Windows/PropVariant.h"
#include "../../../Windows/System.h"
#include "../../Common/StreamUtils.h"
#include "ArchiveOpenCallback.h"
// #define DEBUG_VOLUMES
#ifdef DEBUG_VOLUMES
#include <stdio.h>
#endif
#ifdef DEBUG_VOLUMES
#define PRF(x) x
#else
#define PRF(x)
#endif
using namespace NWindows;
HRESULT COpenCallbackImp::Init2(const FString &folderPrefix, const FString &fileName)
{
Volumes.Init();
FileNames.Clear();
FileNames_WasUsed.Clear();
FileSizes.Clear();
_subArchiveMode = false;
// TotalSize = 0;
PasswordWasAsked = false;
_folderPrefix = folderPrefix;
if (!_fileInfo.Find_FollowLink(_folderPrefix + fileName))
{
// throw 20121118;
return GetLastError_noZero_HRESULT();
}
return S_OK;
}
Z7_COM7F_IMF(COpenCallbackImp::SetSubArchiveName(const wchar_t *name))
{
_subArchiveMode = true;
_subArchiveName = name;
// TotalSize = 0;
return S_OK;
}
Z7_COM7F_IMF(COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes))
{
COM_TRY_BEGIN
if (ReOpenCallback)
return ReOpenCallback->SetTotal(files, bytes);
if (!Callback)
return S_OK;
return Callback->Open_SetTotal(files, bytes);
COM_TRY_END
}
Z7_COM7F_IMF(COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes))
{
COM_TRY_BEGIN
if (ReOpenCallback)
return ReOpenCallback->SetCompleted(files, bytes);
if (!Callback)
return S_OK;
return Callback->Open_SetCompleted(files, bytes);
COM_TRY_END
}
Z7_COM7F_IMF(COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value))
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
if (_subArchiveMode)
switch (propID)
{
case kpidName: prop = _subArchiveName; break;
// case kpidSize: prop = _subArchiveSize; break; // we don't use it now
default: break;
}
else
switch (propID)
{
case kpidName: prop = fs2us(_fileInfo.Name); break;
case kpidIsDir: prop = _fileInfo.IsDir(); break;
case kpidSize: prop = _fileInfo.Size; break;
case kpidAttrib: prop = (UInt32)_fileInfo.GetWinAttrib(); break;
case kpidPosixAttrib: prop = (UInt32)_fileInfo.GetPosixAttrib(); break;
case kpidCTime: PropVariant_SetFrom_FiTime(prop, _fileInfo.CTime); break;
case kpidATime: PropVariant_SetFrom_FiTime(prop, _fileInfo.ATime); break;
case kpidMTime: PropVariant_SetFrom_FiTime(prop, _fileInfo.MTime); break;
default: break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
// ---------- CInFileStreamVol ----------
Z7_class_final(CInFileStreamVol):
public IInStream
, public IStreamGetSize
, public CMyUnknownImp
{
Z7_IFACES_IMP_UNK_3(
IInStream,
ISequentialInStream,
IStreamGetSize)
public:
unsigned FileIndex;
COpenCallbackImp *OpenCallbackImp;
CMyComPtr<IArchiveOpenCallback> OpenCallbackRef;
HRESULT EnsureOpen()
{
return OpenCallbackImp->Volumes.EnsureOpen(FileIndex);
}
~CInFileStreamVol()
{
if (OpenCallbackRef)
OpenCallbackImp->AtCloseFile(FileIndex);
}
};
void CMultiStreams::InsertToList(unsigned index)
{
{
CSubStream &s = Streams[index];
s.Next = Head;
s.Prev = -1;
}
if (Head != -1)
Streams[(unsigned)Head].Prev = (int)index;
else
{
// if (Tail != -1) throw 1;
Tail = (int)index;
}
Head = (int)index;
NumListItems++;
}
// s must bee in List
void CMultiStreams::RemoveFromList(CSubStream &s)
{
if (s.Next != -1) Streams[(unsigned)s.Next].Prev = s.Prev; else Tail = s.Prev;
if (s.Prev != -1) Streams[(unsigned)s.Prev].Next = s.Next; else Head = s.Next;
s.Next = -1; // optional
s.Prev = -1; // optional
NumListItems--;
}
void CMultiStreams::CloseFile(unsigned index)
{
CSubStream &s = Streams[index];
if (s.Stream)
{
s.Stream.Release();
RemoveFromList(s);
// s.InFile->Close();
// s.IsOpen = false;
#ifdef DEBUG_VOLUMES
static int numClosing = 0;
numClosing++;
printf("\nCloseFile %u, total_closes = %u, num_open_files = %u\n", index, numClosing, NumListItems);
#endif
}
}
void CMultiStreams::Init()
{
Head = -1;
Tail = -1;
NumListItems = 0;
Streams.Clear();
}
CMultiStreams::CMultiStreams():
Head(-1),
Tail(-1),
NumListItems(0)
{
NumOpenFiles_AllowedMax = NSystem::Get_File_OPEN_MAX_Reduced_for_3_tasks();
PRF(printf("\nNumOpenFiles_Limit = %u\n", NumOpenFiles_AllowedMax));
}
HRESULT CMultiStreams::PrepareToOpenNew()
{
if (NumListItems < NumOpenFiles_AllowedMax)
return S_OK;
if (Tail == -1)
return E_FAIL;
CMultiStreams::CSubStream &tailStream = Streams[(unsigned)Tail];
RINOK(InStream_GetPos(tailStream.Stream, tailStream.LocalPos))
CloseFile((unsigned)Tail);
return S_OK;
}
HRESULT CMultiStreams::EnsureOpen(unsigned index)
{
CMultiStreams::CSubStream &s = Streams[index];
if (s.Stream)
{
if ((int)index != Head)
{
RemoveFromList(s);
InsertToList(index);
}
}
else
{
RINOK(PrepareToOpenNew())
{
CInFileStream *inFile = new CInFileStream;
CMyComPtr<IInStream> inStreamTemp = inFile;
if (!inFile->Open(s.Path))
return GetLastError_noZero_HRESULT();
s.FileSpec = inFile;
s.Stream = s.FileSpec;
InsertToList(index);
}
// s.IsOpen = true;
if (s.LocalPos != 0)
{
RINOK(s.Stream->Seek((Int64)s.LocalPos, STREAM_SEEK_SET, &s.LocalPos))
}
#ifdef DEBUG_VOLUMES
static int numOpens = 0;
numOpens++;
printf("\n-- %u, ReOpen, total_reopens = %u, num_open_files = %u\n", index, numOpens, NumListItems);
#endif
}
return S_OK;
}
Z7_COM7F_IMF(CInFileStreamVol::Read(void *data, UInt32 size, UInt32 *processedSize))
{
if (processedSize)
*processedSize = 0;
if (size == 0)
return S_OK;
RINOK(EnsureOpen())
CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex];
PRF(printf("\n== %u, Read =%u \n", FileIndex, size));
return s.Stream->Read(data, size, processedSize);
}
Z7_COM7F_IMF(CInFileStreamVol::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
{
// if (seekOrigin >= 3) return STG_E_INVALIDFUNCTION;
RINOK(EnsureOpen())
CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex];
PRF(printf("\n-- %u, Seek seekOrigin=%u Seek =%u\n", FileIndex, seekOrigin, (unsigned)offset));
return s.Stream->Seek(offset, seekOrigin, newPosition);
}
Z7_COM7F_IMF(CInFileStreamVol::GetSize(UInt64 *size))
{
RINOK(EnsureOpen())
CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex];
return s.FileSpec->GetSize(size);
}
// from ArchiveExtractCallback.cpp
bool IsSafePath(const UString &path);
Z7_COM7F_IMF(COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream))
{
COM_TRY_BEGIN
*inStream = NULL;
if (_subArchiveMode)
return S_FALSE;
if (Callback)
{
RINOK(Callback->Open_CheckBreak())
}
UString name2 = name;
#ifndef Z7_SFX
#ifdef _WIN32
name2.Replace(L'/', WCHAR_PATH_SEPARATOR);
#endif
// if (!allowAbsVolPaths)
if (!IsSafePath(name2))
return S_FALSE;
#ifdef _WIN32
/* WIN32 allows wildcards in Find() function
and doesn't allow wildcard in File.Open()
so we can work without the following wildcard check here */
if (name2.Find(L'*') >= 0)
return S_FALSE;
{
unsigned startPos = 0;
if (name2.IsPrefixedBy_Ascii_NoCase("\\\\?\\"))
startPos = 3;
if (name2.Find(L'?', startPos) >= 0)
return S_FALSE;
}
#endif
#endif
FString fullPath;
if (!NFile::NName::GetFullPath(_folderPrefix, us2fs(name2), fullPath))
return S_FALSE;
if (!_fileInfo.Find_FollowLink(fullPath))
return S_FALSE;
if (_fileInfo.IsDir())
return S_FALSE;
CMultiStreams::CSubStream s;
{
CInFileStream *inFile = new CInFileStream;
CMyComPtr<IInStream> inStreamTemp = inFile;
if (!inFile->Open(fullPath))
return GetLastError_noZero_HRESULT();
RINOK(Volumes.PrepareToOpenNew())
s.FileSpec = inFile;
s.Stream = s.FileSpec;
s.Path = fullPath;
// s.Size = _fileInfo.Size;
// s.IsOpen = true;
}
const unsigned fileIndex = Volumes.Streams.Add(s);
Volumes.InsertToList(fileIndex);
FileSizes.Add(_fileInfo.Size);
FileNames.Add(name2);
FileNames_WasUsed.Add(true);
CInFileStreamVol *inFile = new CInFileStreamVol;
CMyComPtr<IInStream> inStreamTemp = inFile;
inFile->FileIndex = fileIndex;
inFile->OpenCallbackImp = this;
inFile->OpenCallbackRef = this;
// TotalSize += _fileInfo.Size;
*inStream = inStreamTemp.Detach();
return S_OK;
COM_TRY_END
}
#ifndef Z7_NO_CRYPTO
Z7_COM7F_IMF(COpenCallbackImp::CryptoGetTextPassword(BSTR *password))
{
COM_TRY_BEGIN
if (ReOpenCallback)
{
Z7_DECL_CMyComPtr_QI_FROM(
ICryptoGetTextPassword,
getTextPassword, ReOpenCallback)
if (getTextPassword)
return getTextPassword->CryptoGetTextPassword(password);
}
if (!Callback)
return E_NOTIMPL;
PasswordWasAsked = true;
return Callback->Open_CryptoGetTextPassword(password);
COM_TRY_END
}
#endif
// IProgress
Z7_COM7F_IMF(COpenCallbackImp::SetTotal(const UInt64 /* total */))
{
return S_OK;
}
Z7_COM7F_IMF(COpenCallbackImp::SetCompleted(const UInt64 * /* completed */))
{
return S_OK;
}
@@ -0,0 +1,182 @@
// ArchiveOpenCallback.h
#ifndef ZIP7_INC_ARCHIVE_OPEN_CALLBACK_H
#define ZIP7_INC_ARCHIVE_OPEN_CALLBACK_H
#include "../../../Common/MyCom.h"
#include "../../../Windows/FileFind.h"
#include "../../Common/FileStreams.h"
#ifndef Z7_NO_CRYPTO
#include "../../IPassword.h"
#endif
#include "../../Archive/IArchive.h"
Z7_PURE_INTERFACES_BEGIN
#ifdef Z7_NO_CRYPTO
#define Z7_IFACEM_IOpenCallbackUI_Crypto(x)
#else
#define Z7_IFACEM_IOpenCallbackUI_Crypto(x) \
virtual HRESULT Open_CryptoGetTextPassword(BSTR *password) x \
/* virtual HRESULT Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password) x */ \
/* virtual bool Open_WasPasswordAsked() x */ \
/* virtual void Open_Clear_PasswordWasAsked_Flag() x */ \
#endif
#define Z7_IFACEN_IOpenCallbackUI(x) \
virtual HRESULT Open_CheckBreak() x \
virtual HRESULT Open_SetTotal(const UInt64 *files, const UInt64 *bytes) x \
virtual HRESULT Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) x \
virtual HRESULT Open_Finished() x \
Z7_IFACEM_IOpenCallbackUI_Crypto(x)
Z7_IFACE_DECL_PURE(IOpenCallbackUI)
Z7_PURE_INTERFACES_END
class CMultiStreams Z7_final
{
public:
struct CSubStream
{
CMyComPtr<IInStream> Stream;
CInFileStream *FileSpec;
FString Path;
// UInt64 Size;
UInt64 LocalPos;
int Next; // next older
int Prev; // prev newer
// bool IsOpen;
CSubStream():
FileSpec(NULL),
// Size(0),
LocalPos(0),
Next(-1),
Prev(-1)
// IsOpen(false)
{}
};
CObjectVector<CSubStream> Streams;
private:
// we must use critical section here, if we want to access from different volumnes simultaneously
int Head; // newest
int Tail; // oldest
unsigned NumListItems;
unsigned NumOpenFiles_AllowedMax;
public:
CMultiStreams();
void Init();
HRESULT PrepareToOpenNew();
void InsertToList(unsigned index);
void RemoveFromList(CSubStream &s);
void CloseFile(unsigned index);
HRESULT EnsureOpen(unsigned index);
};
/*
We need COpenCallbackImp class for multivolume processing.
Also we use it as proxy from COM interfaces (IArchiveOpenCallback) to internal (IOpenCallbackUI) interfaces.
If archive is multivolume:
COpenCallbackImp object will exist after Open stage.
COpenCallbackImp object will be deleted when last reference
from each volume object (CInFileStreamVol) will be closed (when archive will be closed).
*/
class COpenCallbackImp Z7_final:
public IArchiveOpenCallback,
public IArchiveOpenVolumeCallback,
public IArchiveOpenSetSubArchiveName,
#ifndef Z7_NO_CRYPTO
public ICryptoGetTextPassword,
#endif
public IProgress, // IProgress is used for 7zFM
public CMyUnknownImp
{
Z7_COM_QI_BEGIN2(IArchiveOpenCallback)
Z7_COM_QI_ENTRY(IArchiveOpenVolumeCallback)
Z7_COM_QI_ENTRY(IArchiveOpenSetSubArchiveName)
#ifndef Z7_NO_CRYPTO
Z7_COM_QI_ENTRY(ICryptoGetTextPassword)
#endif
// Z7_COM_QI_ENTRY(IProgress) // the code doesn't require it
Z7_COM_QI_END
Z7_COM_ADDREF_RELEASE
Z7_IFACE_COM7_IMP(IArchiveOpenCallback)
Z7_IFACE_COM7_IMP(IArchiveOpenVolumeCallback)
Z7_IFACE_COM7_IMP(IProgress)
public:
Z7_IFACE_COM7_IMP(IArchiveOpenSetSubArchiveName)
private:
#ifndef Z7_NO_CRYPTO
Z7_IFACE_COM7_IMP(ICryptoGetTextPassword)
#endif
bool _subArchiveMode;
public:
bool PasswordWasAsked;
UStringVector FileNames;
CBoolVector FileNames_WasUsed;
CRecordVector<UInt64> FileSizes;
void AtCloseFile(unsigned fileIndex)
{
FileNames_WasUsed[fileIndex] = false;
Volumes.CloseFile(fileIndex);
}
/* we have two ways to Callback from this object
1) IArchiveOpenCallback * ReOpenCallback - for ReOpen function, when IOpenCallbackUI is not available
2) IOpenCallbackUI *Callback - for usual callback
we can't transfer IOpenCallbackUI pointer via internal interface,
so we use ReOpenCallback to callback without IOpenCallbackUI.
*/
/* we use Callback/ReOpenCallback only at Open stage.
So the CMyComPtr reference counter is not required,
and we don't want additional reference to unused object,
if COpenCallbackImp is not closed
*/
IArchiveOpenCallback *ReOpenCallback;
// CMyComPtr<IArchiveOpenCallback> ReOpenCallback;
IOpenCallbackUI *Callback;
// CMyComPtr<IUnknown> Callback_Ref;
private:
FString _folderPrefix;
UString _subArchiveName;
NWindows::NFile::NFind::CFileInfo _fileInfo;
public:
CMultiStreams Volumes;
// UInt64 TotalSize;
COpenCallbackImp():
_subArchiveMode(false),
PasswordWasAsked(false),
ReOpenCallback(NULL),
Callback(NULL) {}
HRESULT Init2(const FString &folderPrefix, const FString &fileName);
bool SetSecondFileInfo(CFSTR newName)
{
return _fileInfo.Find_FollowLink(newName) && !_fileInfo.IsDir();
}
};
#endif
File diff suppressed because it is too large Load Diff
+121
View File
@@ -0,0 +1,121 @@
// Bench.h
#ifndef ZIP7_INC_7ZIP_BENCH_H
#define ZIP7_INC_7ZIP_BENCH_H
#include "../../../Windows/System.h"
#include "../../Common/CreateCoder.h"
#include "../../UI/Common/Property.h"
UInt64 Benchmark_GetUsage_Percents(UInt64 usage);
struct CBenchInfo
{
UInt64 GlobalTime;
UInt64 GlobalFreq;
UInt64 UserTime;
UInt64 UserFreq;
UInt64 UnpackSize;
UInt64 PackSize;
UInt64 NumIterations;
/*
during Code(): we track benchInfo only from one thread (theads with index[0])
NumIterations means number of threads
UnpackSize and PackSize are total sizes of all iterations of current thread
after Code():
NumIterations means the number of Iterations
UnpackSize and PackSize are total sizes of all threads
*/
CBenchInfo(): NumIterations(0) {}
UInt64 GetUsage() const;
UInt64 GetRatingPerUsage(UInt64 rating) const;
UInt64 GetSpeed(UInt64 numUnits) const;
UInt64 GetUnpackSizeSpeed() const { return GetSpeed(UnpackSize * NumIterations); }
UInt64 Get_UnpackSize_Full() const { return UnpackSize * NumIterations; }
UInt64 GetRating_LzmaEnc(UInt64 dictSize) const;
UInt64 GetRating_LzmaDec() const;
};
struct CTotalBenchRes
{
// UInt64 NumIterations1; // for Usage
UInt64 NumIterations2; // for Rating / RPU
UInt64 Rating;
UInt64 Usage;
UInt64 RPU;
UInt64 Speed;
void Init() { /* NumIterations1 = 0; */ NumIterations2 = 0; Rating = 0; Usage = 0; RPU = 0; Speed = 0; }
void SetSum(const CTotalBenchRes &r1, const CTotalBenchRes &r2)
{
Rating = (r1.Rating + r2.Rating);
Usage = (r1.Usage + r2.Usage);
RPU = (r1.RPU + r2.RPU);
Speed = (r1.Speed + r2.Speed);
// NumIterations1 = (r1.NumIterations1 + r2.NumIterations1);
NumIterations2 = (r1.NumIterations2 + r2.NumIterations2);
}
void Generate_From_BenchInfo(const CBenchInfo &info);
void Mult_For_Weight(unsigned weight);
void Update_With_Res(const CTotalBenchRes &r);
};
const unsigned kBenchMinDicLogSize = 18;
UInt64 GetBenchMemoryUsage(UInt32 numThreads, int level, UInt64 dictionary, bool totalBench);
Z7_PURE_INTERFACES_BEGIN
DECLARE_INTERFACE(IBenchCallback)
{
// virtual HRESULT SetFreq(bool showFreq, UInt64 cpuFreq) = 0;
virtual HRESULT SetEncodeResult(const CBenchInfo &info, bool final) = 0;
virtual HRESULT SetDecodeResult(const CBenchInfo &info, bool final) = 0;
};
DECLARE_INTERFACE(IBenchPrintCallback)
{
virtual void Print(const char *s) = 0;
virtual void NewLine() = 0;
virtual HRESULT CheckBreak() = 0;
};
DECLARE_INTERFACE(IBenchFreqCallback)
{
virtual HRESULT AddCpuFreq(unsigned numThreads, UInt64 freq, UInt64 usage) = 0;
virtual HRESULT FreqsFinished(unsigned numThreads) = 0;
};
Z7_PURE_INTERFACES_END
HRESULT Bench(
DECL_EXTERNAL_CODECS_LOC_VARS
IBenchPrintCallback *printCallback,
IBenchCallback *benchCallback,
const CObjectVector<CProperty> &props,
UInt32 numIterations,
bool multiDict,
IBenchFreqCallback *freqCallback = NULL);
AString GetProcessThreadsInfo(const NWindows::NSystem::CProcessAffinity &ti);
void GetSysInfo(AString &s1, AString &s2);
void GetCpuName(AString &s);
void AddCpuFeatures(AString &s);
#ifdef Z7_LARGE_PAGES
void Add_LargePages_String(AString &s);
#else
// #define Add_LargePages_String
#endif
#endif
@@ -0,0 +1,343 @@
// CompressCall.cpp
#include "StdAfx.h"
#include <wchar.h>
#include "../../../Common/IntToString.h"
#include "../../../Common/MyCom.h"
#include "../../../Common/Random.h"
#include "../../../Common/StringConvert.h"
#include "../../../Windows/DLL.h"
#include "../../../Windows/ErrorMsg.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/FileMapping.h"
#include "../../../Windows/MemoryLock.h"
#include "../../../Windows/ProcessUtils.h"
#include "../../../Windows/Synchronization.h"
#include "../FileManager/RegistryUtils.h"
#include "CompressCall.h"
using namespace NWindows;
#define MY_TRY_BEGIN try {
#define MY_TRY_FINISH } \
catch(...) { ErrorMessageHRESULT(E_FAIL); return E_FAIL; }
#define MY_TRY_FINISH_VOID } \
catch(...) { ErrorMessageHRESULT(E_FAIL); }
#define k7zGui "7zG.exe"
// 21.07 : we can disable wildcard
// #define ISWITCH_NO_WILDCARD_POSTFIX "w-"
#define ISWITCH_NO_WILDCARD_POSTFIX
#define kShowDialogSwitch " -ad"
#define kEmailSwitch " -seml."
#define kArchiveTypeSwitch " -t"
#define kIncludeSwitch " -i" ISWITCH_NO_WILDCARD_POSTFIX
#define kArcIncludeSwitches " -an -ai" ISWITCH_NO_WILDCARD_POSTFIX
#define kHashIncludeSwitches kIncludeSwitch
#define kStopSwitchParsing " --"
extern HWND g_HWND;
UString GetQuotedString(const UString &s)
{
UString s2 ('\"');
s2 += s;
s2.Add_Char('\"');
return s2;
}
static void ErrorMessage(LPCWSTR message)
{
MessageBoxW(g_HWND, message, L"7-Zip", MB_ICONERROR | MB_OK);
}
static void ErrorMessageHRESULT(HRESULT res, LPCWSTR s = NULL)
{
UString s2 = NError::MyFormatMessage(res);
if (s)
{
s2.Add_LF();
s2 += s;
}
ErrorMessage(s2);
}
static HRESULT Call7zGui(const UString &params,
// LPCWSTR curDir,
bool waitFinish,
NSynchronization::CBaseEvent *event)
{
UString imageName = fs2us(NWindows::NDLL::GetModuleDirPrefix());
imageName += k7zGui;
CProcess process;
const WRes wres = process.Create(imageName, params, NULL); // curDir);
if (wres != 0)
{
const HRESULT hres = HRESULT_FROM_WIN32(wres);
ErrorMessageHRESULT(hres, imageName);
return hres;
}
if (waitFinish)
process.Wait();
else if (event != NULL)
{
HANDLE handles[] = { process, *event };
::WaitForMultipleObjects(Z7_ARRAY_SIZE(handles), handles, FALSE, INFINITE);
}
return S_OK;
}
static void AddLagePagesSwitch(UString &params)
{
if (ReadLockMemoryEnable())
#ifndef UNDER_CE
if (NSecurity::Get_LargePages_RiskLevel() == 0)
#endif
params += " -slp";
}
class CRandNameGenerator
{
CRandom _random;
public:
CRandNameGenerator() { _random.Init(); }
void GenerateName(UString &s, const char *prefix)
{
s += prefix;
s.Add_UInt32((UInt32)(unsigned)_random.Generate());
}
};
static HRESULT CreateMap(const UStringVector &names,
CFileMapping &fileMapping, NSynchronization::CManualResetEvent &event,
UString &params)
{
size_t totalSize = 1;
{
FOR_VECTOR (i, names)
totalSize += (names[i].Len() + 1);
}
totalSize *= sizeof(wchar_t);
CRandNameGenerator random;
UString mappingName;
for (;;)
{
random.GenerateName(mappingName, "7zMap");
const WRes wres = fileMapping.Create(PAGE_READWRITE, totalSize, GetSystemString(mappingName));
if (fileMapping.IsCreated() && wres == 0)
break;
if (wres != ERROR_ALREADY_EXISTS)
return HRESULT_FROM_WIN32(wres);
fileMapping.Close();
}
UString eventName;
for (;;)
{
random.GenerateName(eventName, "7zEvent");
const WRes wres = event.CreateWithName(false, GetSystemString(eventName));
if (event.IsCreated() && wres == 0)
break;
if (wres != ERROR_ALREADY_EXISTS)
return HRESULT_FROM_WIN32(wres);
event.Close();
}
params.Add_Char('#');
params += mappingName;
params.Add_Colon();
char temp[32];
ConvertUInt64ToString(totalSize, temp);
params += temp;
params.Add_Colon();
params += eventName;
LPVOID data = fileMapping.Map(FILE_MAP_WRITE, 0, totalSize);
if (!data)
return E_FAIL;
CFileUnmapper unmapper(data);
{
wchar_t *cur = (wchar_t *)data;
*cur++ = 0; // it means wchar_t strings (UTF-16 in WIN32)
FOR_VECTOR (i, names)
{
const UString &s = names[i];
const unsigned len = s.Len() + 1;
wmemcpy(cur, (const wchar_t *)s, len);
cur += len;
}
}
return S_OK;
}
HRESULT CompressFiles(
const UString &arcPathPrefix,
const UString &arcName,
const UString &arcType,
bool addExtension,
const UStringVector &names,
bool email, bool showDialog, bool waitFinish)
{
MY_TRY_BEGIN
UString params ('a');
CFileMapping fileMapping;
NSynchronization::CManualResetEvent event;
params += kIncludeSwitch;
RINOK(CreateMap(names, fileMapping, event, params))
if (!arcType.IsEmpty())
{
params += kArchiveTypeSwitch;
params += arcType;
}
if (email)
params += kEmailSwitch;
if (showDialog)
params += kShowDialogSwitch;
AddLagePagesSwitch(params);
if (arcName.IsEmpty())
params += " -an";
if (addExtension)
params += " -saa";
else
params += " -sae";
params += kStopSwitchParsing;
params.Add_Space();
if (!arcName.IsEmpty())
{
params += GetQuotedString(
// #ifdef UNDER_CE
arcPathPrefix +
// #endif
arcName);
}
return Call7zGui(params,
// (arcPathPrefix.IsEmpty()? 0: (LPCWSTR)arcPathPrefix),
waitFinish, &event);
MY_TRY_FINISH
}
static void ExtractGroupCommand(const UStringVector &arcPaths, UString &params, bool isHash)
{
AddLagePagesSwitch(params);
params += (isHash ? kHashIncludeSwitches : kArcIncludeSwitches);
CFileMapping fileMapping;
NSynchronization::CManualResetEvent event;
HRESULT result = CreateMap(arcPaths, fileMapping, event, params);
if (result == S_OK)
result = Call7zGui(params, false, &event);
if (result != S_OK)
ErrorMessageHRESULT(result);
}
void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup, UInt32 writeZone)
{
MY_TRY_BEGIN
UString params ('x');
if (!outFolder.IsEmpty())
{
params += " -o";
params += GetQuotedString(outFolder);
}
if (elimDup)
params += " -spe";
if (writeZone != (UInt32)(Int32)-1)
{
params += " -snz";
params.Add_UInt32(writeZone);
}
if (showDialog)
params += kShowDialogSwitch;
ExtractGroupCommand(arcPaths, params, false);
MY_TRY_FINISH_VOID
}
void TestArchives(const UStringVector &arcPaths, bool hashMode)
{
MY_TRY_BEGIN
UString params ('t');
if (hashMode)
{
params += kArchiveTypeSwitch;
params += "hash";
}
ExtractGroupCommand(arcPaths, params, false);
MY_TRY_FINISH_VOID
}
void CalcChecksum(const UStringVector &paths,
const UString &methodName,
const UString &arcPathPrefix,
const UString &arcFileName)
{
MY_TRY_BEGIN
if (!arcFileName.IsEmpty())
{
CompressFiles(
arcPathPrefix,
arcFileName,
UString("hash"),
false, // addExtension,
paths,
false, // email,
false, // showDialog,
false // waitFinish
);
return;
}
UString params ('h');
if (!methodName.IsEmpty())
{
params += " -scrc";
params += methodName;
/*
if (!arcFileName.IsEmpty())
{
// not used alternate method of generating file
params += " -scrf=";
params += GetQuotedString(arcPathPrefix + arcFileName);
}
*/
}
ExtractGroupCommand(paths, params, true);
MY_TRY_FINISH_VOID
}
void Benchmark(bool totalMode)
{
MY_TRY_BEGIN
UString params ('b');
if (totalMode)
params += " -mm=*";
AddLagePagesSwitch(params);
const HRESULT result = Call7zGui(params, false, NULL);
if (result != S_OK)
ErrorMessageHRESULT(result);
MY_TRY_FINISH_VOID
}
@@ -0,0 +1,28 @@
// CompressCall.h
#ifndef ZIP7_INC_COMPRESS_CALL_H
#define ZIP7_INC_COMPRESS_CALL_H
#include "../../../Common/MyString.h"
UString GetQuotedString(const UString &s);
HRESULT CompressFiles(
const UString &arcPathPrefix,
const UString &arcName,
const UString &arcType,
bool addExtension,
const UStringVector &names,
bool email, bool showDialog, bool waitFinish);
void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup, UInt32 writeZone);
void TestArchives(const UStringVector &arcPaths, bool hashMode = false);
void CalcChecksum(const UStringVector &paths,
const UString &methodName,
const UString &arcPathPrefix,
const UString &arcFileName);
void Benchmark(bool totalMode);
#endif
@@ -0,0 +1,327 @@
// CompressCall2.cpp
#include "StdAfx.h"
#ifndef Z7_EXTERNAL_CODECS
#include "../../../Common/MyException.h"
#include "../../UI/Common/EnumDirItems.h"
#include "../../UI/FileManager/LangUtils.h"
#include "../../UI/GUI/BenchmarkDialog.h"
#include "../../UI/GUI/ExtractGUI.h"
#include "../../UI/GUI/UpdateGUI.h"
#include "../../UI/GUI/HashGUI.h"
#include "../../UI/GUI/ExtractRes.h"
#include "CompressCall.h"
extern HWND g_HWND;
#define MY_TRY_BEGIN HRESULT result; try {
#define MY_TRY_FINISH } \
catch(CSystemException &e) { result = e.ErrorCode; } \
catch(UString &s) { ErrorMessage(s); result = E_FAIL; } \
catch(...) { result = E_FAIL; } \
if (result != S_OK && result != E_ABORT) \
ErrorMessageHRESULT(result);
static void ThrowException_if_Error(HRESULT res)
{
if (res != S_OK)
throw CSystemException(res);
}
#ifdef Z7_EXTERNAL_CODECS
#define CREATE_CODECS \
CCodecs *codecs = new CCodecs; \
CMyComPtr<ICompressCodecsInfo> compressCodecsInfo = codecs; \
ThrowException_if_Error(codecs->Load()); \
Codecs_AddHashArcHandler(codecs);
#define LOAD_EXTERNAL_CODECS \
CExternalCodecs _externalCodecs; \
_externalCodecs.GetCodecs = codecs; \
_externalCodecs.GetHashers = codecs; \
ThrowException_if_Error(_externalCodecs.Load());
#else
#define CREATE_CODECS \
CCodecs *codecs = new CCodecs; \
CMyComPtr<IUnknown> compressCodecsInfo = codecs; \
ThrowException_if_Error(codecs->Load()); \
Codecs_AddHashArcHandler(codecs);
#define LOAD_EXTERNAL_CODECS
#endif
UString GetQuotedString(const UString &s)
{
UString s2 ('\"');
s2 += s;
s2.Add_Char('\"');
return s2;
}
static void ErrorMessage(LPCWSTR message)
{
MessageBoxW(g_HWND, message, L"7-Zip", MB_ICONERROR);
}
static void ErrorMessageHRESULT(HRESULT res)
{
ErrorMessage(HResultToMessage(res));
}
static void ErrorLangMessage(UINT resourceID)
{
ErrorMessage(LangString(resourceID));
}
HRESULT CompressFiles(
const UString &arcPathPrefix,
const UString &arcName,
const UString &arcType,
bool addExtension,
const UStringVector &names,
bool email, bool showDialog, bool /* waitFinish */)
{
MY_TRY_BEGIN
CREATE_CODECS
CUpdateCallbackGUI callback;
callback.Init();
CUpdateOptions uo;
uo.EMailMode = email;
uo.SetActionCommand_Add();
uo.ArcNameMode = (addExtension ? k_ArcNameMode_Add : k_ArcNameMode_Exact);
CObjectVector<COpenType> formatIndices;
if (!ParseOpenTypes(*codecs, arcType, formatIndices))
{
ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE);
return E_FAIL;
}
const UString arcPath = arcPathPrefix + arcName;
if (!uo.InitFormatIndex(codecs, formatIndices, arcPath) ||
!uo.SetArcPath(codecs, arcPath))
{
ErrorLangMessage(IDS_UPDATE_NOT_SUPPORTED);
return E_FAIL;
}
NWildcard::CCensor censor;
FOR_VECTOR (i, names)
{
censor.AddPreItem_NoWildcard(names[i]);
}
bool messageWasDisplayed = false;
result = UpdateGUI(codecs,
formatIndices, arcPath,
censor, uo, showDialog, messageWasDisplayed, &callback, g_HWND);
if (result != S_OK)
{
if (result != E_ABORT && messageWasDisplayed)
return E_FAIL;
throw CSystemException(result);
}
if (callback.FailedFiles.Size() > 0)
{
if (!messageWasDisplayed)
throw CSystemException(E_FAIL);
return E_FAIL;
}
MY_TRY_FINISH
return S_OK;
}
static HRESULT ExtractGroupCommand(const UStringVector &arcPaths,
bool showDialog, CExtractOptions &eo, const char *kType = NULL)
{
MY_TRY_BEGIN
CREATE_CODECS
CExtractCallbackImp *ecs = new CExtractCallbackImp;
CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
ecs->Init();
// eo.CalcCrc = options.CalcCrc;
UStringVector arcPathsSorted;
UStringVector arcFullPathsSorted;
{
NWildcard::CCensor arcCensor;
FOR_VECTOR (i, arcPaths)
{
arcCensor.AddPreItem_NoWildcard(arcPaths[i]);
}
arcCensor.AddPathsToCensor(NWildcard::k_RelatPath);
CDirItemsStat st;
EnumerateDirItemsAndSort(arcCensor, NWildcard::k_RelatPath, UString(),
arcPathsSorted, arcFullPathsSorted,
st,
NULL // &scan: change it!!!!
);
}
CObjectVector<COpenType> formatIndices;
if (kType)
{
if (!ParseOpenTypes(*codecs, UString(kType), formatIndices))
{
throw CSystemException(E_INVALIDARG);
// ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE);
// return E_INVALIDARG;
}
}
NWildcard::CCensor censor;
{
censor.AddPreItem_Wildcard();
}
censor.AddPathsToCensor(NWildcard::k_RelatPath);
bool messageWasDisplayed = false;
ecs->MultiArcMode = (arcPathsSorted.Size() > 1);
result = ExtractGUI(codecs,
formatIndices, CIntVector(),
arcPathsSorted, arcFullPathsSorted,
censor.Pairs.Front().Head, eo, NULL, showDialog, messageWasDisplayed, ecs, g_HWND);
if (result != S_OK)
{
if (result != E_ABORT && messageWasDisplayed)
return E_FAIL;
throw CSystemException(result);
}
return ecs->IsOK() ? S_OK : E_FAIL;
MY_TRY_FINISH
return result;
}
void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder,
bool showDialog, bool elimDup, UInt32 writeZone)
{
CExtractOptions eo;
eo.OutputDir = us2fs(outFolder);
eo.TestMode = false;
eo.ElimDup.Val = elimDup;
eo.ElimDup.Def = elimDup;
if (writeZone != (UInt32)(Int32)-1)
eo.ZoneMode = (NExtract::NZoneIdMode::EEnum)writeZone;
ExtractGroupCommand(arcPaths, showDialog, eo);
}
void TestArchives(const UStringVector &arcPaths, bool hashMode)
{
CExtractOptions eo;
eo.TestMode = true;
ExtractGroupCommand(arcPaths,
true, // showDialog
eo,
hashMode ? "hash" : NULL);
}
void CalcChecksum(const UStringVector &paths,
const UString &methodName,
const UString &arcPathPrefix,
const UString &arcFileName)
{
MY_TRY_BEGIN
if (!arcFileName.IsEmpty())
{
CompressFiles(
arcPathPrefix,
arcFileName,
UString("hash"),
false, // addExtension,
paths,
false, // email,
false, // showDialog,
false // waitFinish
);
return;
}
CREATE_CODECS
LOAD_EXTERNAL_CODECS
NWildcard::CCensor censor;
FOR_VECTOR (i, paths)
{
censor.AddPreItem_NoWildcard(paths[i]);
}
censor.AddPathsToCensor(NWildcard::k_RelatPath);
bool messageWasDisplayed = false;
CHashOptions options;
options.Methods.Add(methodName);
/*
if (!arcFileName.IsEmpty())
options.HashFilePath = arcPathPrefix + arcFileName;
*/
result = HashCalcGUI(EXTERNAL_CODECS_VARS_L censor, options, messageWasDisplayed);
if (result != S_OK)
{
if (result != E_ABORT && messageWasDisplayed)
return; // E_FAIL;
throw CSystemException(result);
}
MY_TRY_FINISH
return; // result;
}
void Benchmark(bool totalMode)
{
MY_TRY_BEGIN
CREATE_CODECS
LOAD_EXTERNAL_CODECS
CObjectVector<CProperty> props;
if (totalMode)
{
CProperty prop;
prop.Name = "m";
prop.Value = "*";
props.Add(prop);
}
result = Benchmark(
EXTERNAL_CODECS_VARS_L
props,
k_NumBenchIterations_Default,
g_HWND);
MY_TRY_FINISH
}
#endif
@@ -0,0 +1,37 @@
// DefaultName.cpp
#include "StdAfx.h"
#include "DefaultName.h"
static UString GetDefaultName3(const UString &fileName,
const UString &extension, const UString &addSubExtension)
{
const unsigned extLen = extension.Len();
const unsigned fileNameLen = fileName.Len();
if (fileNameLen > extLen + 1)
{
const unsigned dotPos = fileNameLen - (extLen + 1);
if (fileName[dotPos] == '.')
if (extension.IsEqualTo_NoCase(fileName.Ptr(dotPos + 1)))
return fileName.Left(dotPos) + addSubExtension;
}
int dotPos = fileName.ReverseFind_Dot();
if (dotPos > 0)
return fileName.Left((unsigned)dotPos) + addSubExtension;
if (addSubExtension.IsEmpty())
return fileName + L'~';
else
return fileName + addSubExtension;
}
UString GetDefaultName2(const UString &fileName,
const UString &extension, const UString &addSubExtension)
{
UString name = GetDefaultName3(fileName, extension, addSubExtension);
name.TrimRight();
return name;
}
@@ -0,0 +1,11 @@
// DefaultName.h
#ifndef ZIP7_INC_DEFAULT_NAME_H
#define ZIP7_INC_DEFAULT_NAME_H
#include "../../../Common/MyString.h"
UString GetDefaultName2(const UString &fileName,
const UString &extension, const UString &addSubExtension);
#endif
+407
View File
@@ -0,0 +1,407 @@
// DirItem.h
#ifndef ZIP7_INC_DIR_ITEM_H
#define ZIP7_INC_DIR_ITEM_H
#ifdef _WIN32
#include "../../../Common/MyLinux.h"
#endif
#include "../../../Common/MyString.h"
#include "../../../Windows/FileFind.h"
#include "../../../Windows/PropVariant.h"
#include "../../../Windows/TimeUtils.h"
#include "../../Common/UniqBlocks.h"
#include "../../Archive/IArchive.h"
struct CDirItemsStat
{
UInt64 NumDirs;
UInt64 NumFiles;
UInt64 NumAltStreams;
UInt64 FilesSize;
UInt64 AltStreamsSize;
UInt64 NumErrors;
// UInt64 Get_NumItems() const { return NumDirs + NumFiles + NumAltStreams; }
UInt64 Get_NumDataItems() const { return NumFiles + NumAltStreams; }
UInt64 GetTotalBytes() const { return FilesSize + AltStreamsSize; }
bool IsEmpty() const { return
0 == NumDirs
&& 0 == NumFiles
&& 0 == NumAltStreams
&& 0 == FilesSize
&& 0 == AltStreamsSize
&& 0 == NumErrors; }
CDirItemsStat():
NumDirs(0),
NumFiles(0),
NumAltStreams(0),
FilesSize(0),
AltStreamsSize(0),
NumErrors(0)
{}
};
struct CDirItemsStat2: public CDirItemsStat
{
UInt64 Anti_NumDirs;
UInt64 Anti_NumFiles;
UInt64 Anti_NumAltStreams;
// UInt64 Get_NumItems() const { return Anti_NumDirs + Anti_NumFiles + Anti_NumAltStreams + CDirItemsStat::Get_NumItems(); }
UInt64 Get_NumDataItems2() const { return Anti_NumFiles + Anti_NumAltStreams + CDirItemsStat::Get_NumDataItems(); }
bool IsEmpty() const { return CDirItemsStat::IsEmpty()
&& 0 == Anti_NumDirs
&& 0 == Anti_NumFiles
&& 0 == Anti_NumAltStreams; }
CDirItemsStat2():
Anti_NumDirs(0),
Anti_NumFiles(0),
Anti_NumAltStreams(0)
{}
};
Z7_PURE_INTERFACES_BEGIN
#define Z7_IFACEN_IDirItemsCallback(x) \
virtual HRESULT ScanError(const FString &path, DWORD systemError) x \
virtual HRESULT ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) x \
Z7_IFACE_DECL_PURE(IDirItemsCallback)
Z7_PURE_INTERFACES_END
struct CArcTime
{
FILETIME FT;
UInt16 Prec;
Byte Ns100;
bool Def;
CArcTime()
{
Clear();
}
void Clear()
{
FT.dwHighDateTime = FT.dwLowDateTime = 0;
Prec = 0;
Ns100 = 0;
Def = false;
}
bool IsZero() const
{
return FT.dwLowDateTime == 0 && FT.dwHighDateTime == 0 && Ns100 == 0;
}
int CompareWith(const CArcTime &a) const
{
const int res = CompareFileTime(&FT, &a.FT);
if (res != 0)
return res;
if (Ns100 < a.Ns100) return -1;
if (Ns100 > a.Ns100) return 1;
return 0;
}
UInt64 Get_FILETIME_as_UInt64() const
{
return (((UInt64)FT.dwHighDateTime) << 32) + FT.dwLowDateTime;
}
UInt32 Get_DosTime() const
{
FILETIME ft2 = FT;
if ((Prec == k_PropVar_TimePrec_Base + 8 ||
Prec == k_PropVar_TimePrec_Base + 9)
&& Ns100 != 0)
{
UInt64 u64 = Get_FILETIME_as_UInt64();
// we round up even small (ns < 100ns) as FileTimeToDosTime()
if (u64 % 20000000 == 0)
{
u64++;
ft2.dwHighDateTime = (DWORD)(u64 >> 32);
ft2.dwHighDateTime = (DWORD)u64;
}
}
// FileTimeToDosTime() is expected to round up in Windows
UInt32 dosTime;
// we use simplified code with utctime->dos.
// do we need local time instead here?
NWindows::NTime::FileTime_To_DosTime(ft2, dosTime);
return dosTime;
}
int GetNumDigits() const
{
if (Prec == k_PropVar_TimePrec_Unix ||
Prec == k_PropVar_TimePrec_DOS)
return 0;
if (Prec == k_PropVar_TimePrec_HighPrec)
return 9;
if (Prec == k_PropVar_TimePrec_0)
return 7;
int digits = (int)Prec - (int)k_PropVar_TimePrec_Base;
if (digits < 0)
digits = 0;
return digits;
}
void Write_To_FiTime(CFiTime &dest) const
{
#ifdef _WIN32
dest = FT;
#else
if (FILETIME_To_timespec(FT, dest))
if ((Prec == k_PropVar_TimePrec_Base + 8 ||
Prec == k_PropVar_TimePrec_Base + 9)
&& Ns100 != 0)
{
dest.tv_nsec += Ns100;
}
#endif
}
// (Def) is not set
void Set_From_FILETIME(const FILETIME &ft)
{
FT = ft;
// Prec = k_PropVar_TimePrec_CompatNTFS;
Prec = k_PropVar_TimePrec_Base + 7;
Ns100 = 0;
}
// (Def) is not set
// it set full form precision: k_PropVar_TimePrec_Base + numDigits
void Set_From_FiTime(const CFiTime &ts)
{
#ifdef _WIN32
FT = ts;
Prec = k_PropVar_TimePrec_Base + 7;
// Prec = k_PropVar_TimePrec_Base; // for debug
// Prec = 0; // for debug
Ns100 = 0;
#else
unsigned ns100;
FiTime_To_FILETIME_ns100(ts, FT, ns100);
Ns100 = (Byte)ns100;
Prec = k_PropVar_TimePrec_Base + 9;
#endif
}
void Set_From_Prop(const PROPVARIANT &prop)
{
FT = prop.filetime;
unsigned prec = 0;
unsigned ns100 = 0;
const unsigned prec_Temp = prop.wReserved1;
if (prec_Temp != 0
&& prec_Temp <= k_PropVar_TimePrec_1ns
&& prop.wReserved3 == 0)
{
const unsigned ns100_Temp = prop.wReserved2;
if (ns100_Temp < 100)
{
ns100 = ns100_Temp;
prec = prec_Temp;
}
}
Prec = (UInt16)prec;
Ns100 = (Byte)ns100;
Def = true;
}
};
struct CDirItem: public NWindows::NFile::NFind::CFileInfoBase
{
UString Name;
#ifndef UNDER_CE
CByteBuffer ReparseData;
#ifdef _WIN32
// UString ShortName;
CByteBuffer ReparseData2; // fixed (reduced) absolute links for WIM format
bool AreReparseData() const { return ReparseData.Size() != 0 || ReparseData2.Size() != 0; }
#else
bool AreReparseData() const { return ReparseData.Size() != 0; }
#endif // _WIN32
#endif // !UNDER_CE
void Copy_From_FileInfoBase(const NWindows::NFile::NFind::CFileInfoBase &fi)
{
(NWindows::NFile::NFind::CFileInfoBase &)*this = fi;
}
int PhyParent;
int LogParent;
int SecureIndex;
#ifdef _WIN32
#else
int OwnerNameIndex;
int OwnerGroupIndex;
#endif
// bool Attrib_IsDefined;
CDirItem():
PhyParent(-1)
, LogParent(-1)
, SecureIndex(-1)
#ifdef _WIN32
#else
, OwnerNameIndex(-1)
, OwnerGroupIndex(-1)
#endif
// , Attrib_IsDefined(true)
{
}
CDirItem(const NWindows::NFile::NFind::CFileInfo &fi,
int phyParent, int logParent, int secureIndex):
CFileInfoBase(fi)
, Name(fs2us(fi.Name))
#if defined(_WIN32) && !defined(UNDER_CE)
// , ShortName(fs2us(fi.ShortName))
#endif
, PhyParent(phyParent)
, LogParent(logParent)
, SecureIndex(secureIndex)
#ifdef _WIN32
#else
, OwnerNameIndex(-1)
, OwnerGroupIndex(-1)
#endif
{}
};
class CDirItems
{
UStringVector Prefixes;
CIntVector PhyParents;
CIntVector LogParents;
UString GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const;
HRESULT EnumerateDir(int phyParent, int logParent, const FString &phyPrefix);
public:
CObjectVector<CDirItem> Items;
bool SymLinks;
bool ScanAltStreams;
bool ExcludeDirItems;
bool ExcludeFileItems;
bool ShareForWrite;
/* it must be called after anotrher checks */
bool CanIncludeItem(bool isDir) const
{
return isDir ? !ExcludeDirItems : !ExcludeFileItems;
}
CDirItemsStat Stat;
#if !defined(UNDER_CE)
HRESULT SetLinkInfo(CDirItem &dirItem, const NWindows::NFile::NFind::CFileInfo &fi,
const FString &phyPrefix);
#endif
#if defined(_WIN32) && !defined(UNDER_CE)
CUniqBlocks SecureBlocks;
CByteBuffer TempSecureBuf;
bool _saclEnabled;
bool ReadSecure;
HRESULT AddSecurityItem(const FString &path, int &secureIndex);
HRESULT FillFixedReparse();
#endif
#ifndef _WIN32
C_UInt32_UString_Map OwnerNameMap;
C_UInt32_UString_Map OwnerGroupMap;
bool StoreOwnerName;
HRESULT FillDeviceSizes();
#endif
IDirItemsCallback *Callback;
CDirItems();
void AddDirFileInfo(int phyParent, int logParent, int secureIndex,
const NWindows::NFile::NFind::CFileInfo &fi);
HRESULT AddError(const FString &path, DWORD errorCode);
HRESULT AddError(const FString &path);
HRESULT ScanProgress(const FString &path);
// unsigned GetNumFolders() const { return Prefixes.Size(); }
FString GetPhyPath(unsigned index) const;
UString GetLogPath(unsigned index) const;
unsigned AddPrefix(int phyParent, int logParent, const UString &prefix);
void DeleteLastPrefix();
// HRESULT EnumerateOneDir(const FString &phyPrefix, CObjectVector<NWindows::NFile::NFind::CDirEntry> &files);
HRESULT EnumerateOneDir(const FString &phyPrefix, CObjectVector<NWindows::NFile::NFind::CFileInfo> &files);
HRESULT EnumerateItems2(
const FString &phyPrefix,
const UString &logPrefix,
const FStringVector &filePaths,
FStringVector *requestedPaths);
void ReserveDown();
};
struct CArcItem
{
UInt64 Size;
UString Name;
CArcTime MTime; // it can be mtime of archive file, if MTime is not defined for item in archive
bool IsDir;
bool IsAltStream;
bool Size_Defined;
bool Censored;
UInt32 IndexInServer;
CArcItem():
IsDir(false),
IsAltStream(false),
Size_Defined(false),
Censored(false)
{}
};
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,38 @@
// EnumDirItems.h
#ifndef ZIP7_INC_ENUM_DIR_ITEMS_H
#define ZIP7_INC_ENUM_DIR_ITEMS_H
#include "../../../Common/Wildcard.h"
#include "DirItem.h"
HRESULT EnumerateItems(
const NWildcard::CCensor &censor,
NWildcard::ECensorPathMode pathMode,
const UString &addPathPrefix,
CDirItems &dirItems);
struct CMessagePathException: public UString
{
CMessagePathException(const char *a, const wchar_t *u = NULL);
CMessagePathException(const wchar_t *a, const wchar_t *u = NULL);
};
HRESULT EnumerateDirItemsAndSort(
NWildcard::CCensor &censor,
NWildcard::ECensorPathMode pathMode,
const UString &addPathPrefix,
UStringVector &sortedPaths,
UStringVector &sortedFullPaths,
CDirItemsStat &st,
IDirItemsCallback *callback);
#ifdef _WIN32
void ConvertToLongNames(NWildcard::CCensor &censor);
#endif
#endif
@@ -0,0 +1,27 @@
// ExitCode.h
#ifndef ZIP7_INC_EXIT_CODE_H
#define ZIP7_INC_EXIT_CODE_H
namespace NExitCode {
enum EEnum {
kSuccess = 0, // Successful operation
kWarning = 1, // Non fatal error(s) occurred
kFatalError = 2, // A fatal error occurred
// kCRCError = 3, // A CRC error occurred when unpacking
// kLockedArchive = 4, // Attempt to modify an archive previously locked
// kWriteError = 5, // Write to disk error
// kOpenError = 6, // Open file error
kUserError = 7, // Command line option error
kMemoryError = 8, // Not enough memory for operation
// kCreateFileError = 9, // Create file error
kUserBreak = 255 // User stopped the process
};
}
#endif
@@ -0,0 +1,575 @@
// Extract.cpp
#include "StdAfx.h"
#include "../../../Common/StringConvert.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/FileName.h"
#include "../../../Windows/ErrorMsg.h"
#include "../../../Windows/PropVariant.h"
#include "../../../Windows/PropVariantConv.h"
#include "../Common/ExtractingFilePath.h"
#include "../Common/HashCalc.h"
#include "Extract.h"
#include "SetProperties.h"
using namespace NWindows;
using namespace NFile;
using namespace NDir;
static void SetErrorMessage(const char *message,
const FString &path, HRESULT errorCode,
UString &s)
{
s = message;
s += " : ";
s += NError::MyFormatMessage(errorCode);
s += " : ";
s += fs2us(path);
}
static 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)
{
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 (arc0.FormatIndex >= 0 && StringsAreEqualNoCase_Ascii(codecs->Formats[(unsigned)arc0.FormatIndex].Name, "pe"))
replaceName = arc0.DefaultName;
}
outDir.Replace(FString("*"), 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;
}
}
}
const bool allFilesAreAllowed = wildcardCensor.AreAllAllowed();
if (!options.StdInMode)
{
UInt32 numItems;
RINOK(archive->GetNumberOfItems(&numItems))
CReadArcItem item;
for (UInt32 i = 0; i < numItems; i++)
{
if (elimIsPossible
|| !allFilesAreAllowed
|| options.ExcludeDirItems
|| options.ExcludeFileItems)
{
RINOK(arc.GetItem(i, item))
if (item.IsDir ? options.ExcludeDirItems : options.ExcludeFileItems)
continue;
}
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 callback->ExtractResult(S_OK);
}
}
if (elimIsPossible)
{
removePathParts.Add(elimPrefix);
// outDir = outDirReduced;
}
#ifdef _WIN32
// GetCorrectFullFsPath doesn't like "..".
// outDir.TrimRight();
// outDir = GetCorrectFullFsPath(outDir);
#endif
if (outDir.IsEmpty())
outDir = "." STRING_PATH_SEPARATOR;
/*
#ifdef _WIN32
else if (NName::IsAltPathPrefix(outDir)) {}
#endif
*/
else if (!CreateComplexDir(outDir))
{
const HRESULT res = GetLastError_noZero_HRESULT();
SetErrorMessage("Cannot create output directory", outDir, res, errorMessage);
return res;
}
ecs->Init(
options.NtOptions,
options.StdInMode ? &wildcardCensor : NULL,
&arc,
callbackFAE,
options.StdOutMode, options.TestMode,
outDir,
removePathParts, false,
packSize);
ecs->Is_elimPrefix_Mode = elimIsPossible;
#ifdef SUPPORT_LINKS
if (!options.StdInMode &&
!options.TestMode &&
options.NtOptions.HardLinks.Val)
{
RINOK(ecs->PrepareHardLinks(&realIndices))
}
#endif
HRESULT result;
const Int32 testMode = (options.TestMode && !calcCrc) ? 1: 0;
CArchiveExtractCallback_Closer ecsCloser(ecs);
if (options.StdInMode)
{
result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, ecs);
NCOM::CPropVariant prop;
if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK)
ConvertPropVariantToUInt64(prop, stdInProcessed);
}
else
{
// v23.02: we reset completed value that could be set by Open() operation
IArchiveExtractCallback *aec = ecs;
const UInt64 val = 0;
RINOK(aec->SetCompleted(&val))
result = archive->Extract(realIndices.ConstData(), realIndices.Size(), testMode, aec);
}
const HRESULT res2 = ecsCloser.Close();
if (result == S_OK)
result = res2;
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 */
int Find_FileName_InSortedVector(const UStringVector &fileNames, const UString &name);
int Find_FileName_InSortedVector(const UStringVector &fileNames, const UString &name)
{
unsigned left = 0, right = fileNames.Size();
while (left != right)
{
const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
const UString &midVal = fileNames[mid];
const int comp = CompareFileNames(name, midVal);
if (comp == 0)
return (int)mid;
if (comp < 0)
right = mid;
else
left = mid + 1;
}
return -1;
}
HRESULT Extract(
// DECL_EXTERNAL_CODECS_LOC_VARS
CCodecs *codecs,
const CObjectVector<COpenType> &types,
const CIntVector &excludedFormats,
UStringVector &arcPaths, UStringVector &arcPathsFull,
const NWildcard::CCensorNode &wildcardCensor,
const CExtractOptions &options,
IOpenCallbackUI *openCallback,
IExtractCallbackUI *extractCallback,
IFolderArchiveExtractCallback *faeCallback,
#ifndef Z7_SFX
IHashCalc *hash,
#endif
UString &errorMessage,
CDecompressStat &st)
{
st.Clear();
UInt64 totalPackSize = 0;
CRecordVector<UInt64> arcSizes;
unsigned numArcs = options.StdInMode ? 1 : arcPaths.Size();
unsigned i;
for (i = 0; i < numArcs; i++)
{
NFind::CFileInfo fi;
fi.Size = 0;
if (!options.StdInMode)
{
const FString arcPath = us2fs(arcPaths[i]);
if (!fi.Find_FollowLink(arcPath))
{
const HRESULT errorCode = GetLastError_noZero_HRESULT();
SetErrorMessage("Cannot find archive file", arcPath, errorCode, errorMessage);
return errorCode;
}
if (fi.IsDir())
{
HRESULT errorCode = E_FAIL;
SetErrorMessage("The item is a directory", arcPath, errorCode, errorMessage);
return errorCode;
}
}
arcSizes.Add(fi.Size);
totalPackSize += fi.Size;
}
CBoolArr skipArcs(numArcs);
for (i = 0; i < numArcs; i++)
skipArcs[i] = false;
CArchiveExtractCallback *ecs = new CArchiveExtractCallback;
CMyComPtr<IArchiveExtractCallback> ec(ecs);
const bool multi = (numArcs > 1);
ecs->InitForMulti(multi,
options.PathMode,
options.OverwriteMode,
options.ZoneMode,
false // keepEmptyDirParts
);
#ifndef Z7_SFX
ecs->SetHashMethods(hash);
#endif
if (multi)
{
RINOK(faeCallback->SetTotal(totalPackSize))
}
UInt64 totalPackProcessed = 0;
bool thereAreNotOpenArcs = false;
for (i = 0; i < numArcs; i++)
{
if (skipArcs[i])
continue;
ecs->InitBeforeNewArchive();
const UString &arcPath = arcPaths[i];
NFind::CFileInfo fi;
if (options.StdInMode)
{
// do we need ctime and mtime?
// fi.ClearBase();
// fi.Size = 0; // (UInt64)(Int64)-1;
if (!fi.SetAs_StdInFile())
return GetLastError_noZero_HRESULT();
}
else
{
if (!fi.Find_FollowLink(us2fs(arcPath)) || fi.IsDir())
{
const HRESULT errorCode = GetLastError_noZero_HRESULT();
SetErrorMessage("Cannot find archive file", us2fs(arcPath), errorCode, errorMessage);
return errorCode;
}
}
/*
#ifndef Z7_NO_CRYPTO
openCallback->Open_Clear_PasswordWasAsked_Flag();
#endif
*/
RINOK(extractCallback->BeforeOpen(arcPath, options.TestMode))
CArchiveLink arcLink;
CObjectVector<COpenType> types2 = types;
/*
#ifndef Z7_SFX
if (types.IsEmpty())
{
int pos = arcPath.ReverseFind(L'.');
if (pos >= 0)
{
UString s = arcPath.Ptr(pos + 1);
int index = codecs->FindFormatForExtension(s);
if (index >= 0 && s.IsEqualTo("001"))
{
s = arcPath.Left(pos);
pos = s.ReverseFind(L'.');
if (pos >= 0)
{
int index2 = codecs->FindFormatForExtension(s.Ptr(pos + 1));
if (index2 >= 0) // && s.CompareNoCase(L"rar") != 0
{
types2.Add(index2);
types2.Add(index);
}
}
}
}
}
#endif
*/
COpenOptions op;
#ifndef Z7_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.Open_Strict(op, openCallback);
if (result == E_ABORT)
return result;
// arcLink.Set_ErrorsText();
RINOK(extractCallback->OpenResult(codecs, arcLink, arcPath, result))
if (result != S_OK)
{
thereAreNotOpenArcs = true;
if (!options.StdInMode)
totalPackProcessed += fi.Size;
continue;
}
#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
if (options.ZoneMode != NExtract::NZoneIdMode::kNone
&& !options.StdInMode)
{
ReadZoneFile_Of_BaseFile(us2fs(arcPath), ecs->ZoneBuf);
}
#endif
if (arcLink.Arcs.Size() != 0)
{
if (arcLink.GetArc()->IsHashHandler(op))
{
if (!options.TestMode)
{
/* real Extracting to files is possible.
But user can think that hash archive contains real files.
So we block extracting here. */
// v23.00 : we don't break process.
RINOK(extractCallback->OpenResult(codecs, arcLink, arcPath, E_NOTIMPL))
thereAreNotOpenArcs = true;
if (!options.StdInMode)
totalPackProcessed += fi.Size;
continue;
// return E_NOTIMPL; // before v23
}
FString dirPrefix = us2fs(options.HashDir);
if (dirPrefix.IsEmpty())
{
if (!NFile::NDir::GetOnlyDirPrefix(us2fs(arcPath), dirPrefix))
{
// return GetLastError_noZero_HRESULT();
}
}
if (!dirPrefix.IsEmpty())
NName::NormalizeDirPathPrefix(dirPrefix);
ecs->DirPathPrefix_for_HashFiles = dirPrefix;
}
}
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 = (Int64)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 = (UInt64)newPackSize;
RINOK(faeCallback->SetTotal(totalPackSize))
}
}
}
/*
// Now openCallback and extractCallback use same object. So we don't need to send password.
#ifndef Z7_NO_CRYPTO
bool passwordIsDefined;
UString password;
RINOK(openCallback->Open_GetPasswordIfAny(passwordIsDefined, password))
if (passwordIsDefined)
{
RINOK(extractCallback->SetPassword(password))
}
#endif
*/
CArc &arc = arcLink.Arcs.Back();
arc.MTime.Def = !options.StdInMode
#ifdef _WIN32
&& !fi.IsDevice
#endif
;
if (arc.MTime.Def)
arc.MTime.Set_From_FiTime(fi.MTime);
UInt64 packProcessed;
const bool calcCrc =
#ifndef Z7_SFX
(hash != NULL);
#else
false;
#endif
RINOK(DecompressArchive(
codecs,
arcLink,
fi.Size + arcLink.VolumesSize,
wildcardCensor,
options,
calcCrc,
extractCallback, faeCallback, ecs,
errorMessage, packProcessed))
if (!options.StdInMode)
packProcessed = fi.Size + arcLink.VolumesSize;
totalPackProcessed += packProcessed;
ecs->LocalProgressSpec->InSize += packProcessed;
ecs->LocalProgressSpec->OutSize = ecs->UnpackSize;
if (!errorMessage.IsEmpty())
return E_FAIL;
}
if (multi || thereAreNotOpenArcs)
{
RINOK(faeCallback->SetTotal(totalPackSize))
RINOK(faeCallback->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;
}
+107
View File
@@ -0,0 +1,107 @@
// Extract.h
#ifndef ZIP7_INC_EXTRACT_H
#define ZIP7_INC_EXTRACT_H
#include "../../../Windows/FileFind.h"
#include "../../Archive/IArchive.h"
#include "ArchiveExtractCallback.h"
#include "ArchiveOpenCallback.h"
#include "ExtractMode.h"
#include "Property.h"
#include "../Common/LoadCodecs.h"
struct CExtractOptionsBase
{
CBoolPair ElimDup;
bool ExcludeDirItems;
bool ExcludeFileItems;
bool PathMode_Force;
bool OverwriteMode_Force;
NExtract::NPathMode::EEnum PathMode;
NExtract::NOverwriteMode::EEnum OverwriteMode;
NExtract::NZoneIdMode::EEnum ZoneMode;
CExtractNtOptions NtOptions;
FString OutputDir;
UString HashDir;
CExtractOptionsBase():
ExcludeDirItems(false),
ExcludeFileItems(false),
PathMode_Force(false),
OverwriteMode_Force(false),
PathMode(NExtract::NPathMode::kFullPaths),
OverwriteMode(NExtract::NOverwriteMode::kAsk),
ZoneMode(NExtract::NZoneIdMode::kNone)
{}
};
struct CExtractOptions: public CExtractOptionsBase
{
bool StdInMode;
bool StdOutMode;
bool YesToAll;
bool TestMode;
// bool ShowDialog;
// bool PasswordEnabled;
// UString Password;
#ifndef Z7_SFX
CObjectVector<CProperty> Properties;
#endif
/*
#ifdef Z7_EXTERNAL_CODECS
CCodecs *Codecs;
#endif
*/
CExtractOptions():
StdInMode(false),
StdOutMode(false),
YesToAll(false),
TestMode(false)
{}
};
struct CDecompressStat
{
UInt64 NumArchives;
UInt64 UnpackSize;
UInt64 AltStreams_UnpackSize;
UInt64 PackSize;
UInt64 NumFolders;
UInt64 NumFiles;
UInt64 NumAltStreams;
void Clear()
{
NumArchives = UnpackSize = AltStreams_UnpackSize = PackSize = NumFolders = NumFiles = NumAltStreams = 0;
}
};
HRESULT Extract(
// DECL_EXTERNAL_CODECS_LOC_VARS
CCodecs *codecs,
const CObjectVector<COpenType> &types,
const CIntVector &excludedFormats,
UStringVector &archivePaths, UStringVector &archivePathsFull,
const NWildcard::CCensorNode &wildcardCensor,
const CExtractOptions &options,
IOpenCallbackUI *openCallback,
IExtractCallbackUI *extractCallback,
IFolderArchiveExtractCallback *faeCallback,
#ifndef Z7_SFX
IHashCalc *hash,
#endif
UString &errorMessage,
CDecompressStat &st);
#endif
@@ -0,0 +1,44 @@
// ExtractMode.h
#ifndef ZIP7_INC_EXTRACT_MODE_H
#define ZIP7_INC_EXTRACT_MODE_H
namespace NExtract {
namespace NPathMode
{
enum EEnum
{
kFullPaths,
kCurPaths,
kNoPaths,
kAbsPaths,
kNoPathsAlt // alt streams must be extracted without name of base file
};
}
namespace NOverwriteMode
{
enum EEnum
{
kAsk,
kOverwrite,
kSkip,
kRename,
kRenameExisting
};
}
namespace NZoneIdMode
{
enum EEnum
{
kNone,
kAll,
kOffice
};
}
}
#endif
@@ -0,0 +1,296 @@
// ExtractingFilePath.cpp
#include "StdAfx.h"
#include "../../../Common/Wildcard.h"
#include "../../../Windows/FileName.h"
#include "ExtractingFilePath.h"
extern
bool g_PathTrailReplaceMode;
bool g_PathTrailReplaceMode =
#ifdef _WIN32
true
#else
false
#endif
;
#ifdef _WIN32
static void ReplaceIncorrectChars(UString &s)
{
{
for (unsigned i = 0; i < s.Len(); i++)
{
wchar_t c = s[i];
if (
#ifdef _WIN32
c == ':' || c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"'
|| c == '/'
// || c == 0x202E // RLO
||
#endif
c == WCHAR_PATH_SEPARATOR)
{
#if WCHAR_PATH_SEPARATOR != L'/'
// 22.00 : WSL replacement for backslash
if (c == WCHAR_PATH_SEPARATOR)
c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT;
else
#endif
c = '_';
s.ReplaceOneCharAtPos(i,
c
// (wchar_t)(0xf000 + c) // 21.02 debug: WSL encoding for unsupported characters
);
}
}
}
if (g_PathTrailReplaceMode)
{
/*
// if (g_PathTrailReplaceMode == 1)
{
if (!s.IsEmpty())
{
wchar_t c = s.Back();
if (c == '.' || c == ' ')
{
// s += (wchar_t)(0x9c); // STRING TERMINATOR
s += (wchar_t)'_';
}
}
}
else
*/
{
unsigned i;
for (i = s.Len(); i != 0;)
{
wchar_t c = s[i - 1];
if (c != '.' && c != ' ')
break;
i--;
s.ReplaceOneCharAtPos(i, '_');
// s.ReplaceOneCharAtPos(i, (c == ' ' ? (wchar_t)(0x2423) : (wchar_t)0x00B7));
}
/*
if (g_PathTrailReplaceMode > 1 && i != s.Len())
{
s.DeleteFrom(i);
}
*/
}
}
}
#endif
/* WinXP-64 doesn't support ':', '\\' and '/' symbols in name of alt stream.
But colon in postfix ":$DATA" is allowed.
WIN32 functions don't allow empty alt stream name "name:" */
void Correct_AltStream_Name(UString &s)
{
unsigned len = s.Len();
const unsigned kPostfixSize = 6;
if (s.Len() >= kPostfixSize
&& StringsAreEqualNoCase_Ascii(s.RightPtr(kPostfixSize), ":$DATA"))
len -= kPostfixSize;
for (unsigned i = 0; i < len; i++)
{
wchar_t c = s[i];
if (c == ':' || c == '\\' || c == '/'
|| c == 0x202E // RLO
)
s.ReplaceOneCharAtPos(i, '_');
}
if (s.IsEmpty())
s = '_';
}
#ifdef _WIN32
static const unsigned g_ReservedWithNum_Index = 4;
static const char * const g_ReservedNames[] =
{
"CON", "PRN", "AUX", "NUL",
"COM", "LPT"
};
static bool IsSupportedName(const UString &name)
{
for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ReservedNames); i++)
{
const char *reservedName = g_ReservedNames[i];
unsigned len = MyStringLen(reservedName);
if (name.Len() < len)
continue;
if (!name.IsPrefixedBy_Ascii_NoCase(reservedName))
continue;
if (i >= g_ReservedWithNum_Index)
{
wchar_t c = name[len];
if (c < L'0' || c > L'9')
continue;
len++;
}
for (;;)
{
wchar_t c = name[len++];
if (c == 0 || c == '.')
return false;
if (c != ' ')
break;
}
}
return true;
}
static void CorrectUnsupportedName(UString &name)
{
if (!IsSupportedName(name))
name.InsertAtFront(L'_');
}
#endif
static void Correct_PathPart(UString &s)
{
// "." and ".."
if (s.IsEmpty())
return;
if (s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0)))
s.Empty();
#ifdef _WIN32
else
ReplaceIncorrectChars(s);
#endif
}
// static const char * const k_EmptyReplaceName = "[]";
static const char k_EmptyReplaceName = '_';
UString Get_Correct_FsFile_Name(const UString &name)
{
UString res = name;
Correct_PathPart(res);
#ifdef _WIN32
CorrectUnsupportedName(res);
#endif
if (res.IsEmpty())
res = k_EmptyReplaceName;
return res;
}
void Correct_FsPath(bool absIsAllowed, bool keepAndReplaceEmptyPrefixes, UStringVector &parts, bool isDir)
{
unsigned i = 0;
if (absIsAllowed)
{
#if defined(_WIN32) && !defined(UNDER_CE)
bool isDrive = false;
#endif
if (parts[0].IsEmpty())
{
i = 1;
#if defined(_WIN32) && !defined(UNDER_CE)
if (parts.Size() > 1 && parts[1].IsEmpty())
{
i = 2;
if (parts.Size() > 2 && parts[2].IsEqualTo("?"))
{
i = 3;
if (parts.Size() > 3 && NWindows::NFile::NName::IsDrivePath2(parts[3]))
{
isDrive = true;
i = 4;
}
}
}
#endif
}
#if defined(_WIN32) && !defined(UNDER_CE)
else if (NWindows::NFile::NName::IsDrivePath2(parts[0]))
{
isDrive = true;
i = 1;
}
if (isDrive)
{
// we convert "c:name" to "c:\name", if absIsAllowed path.
UString &ds = parts[i - 1];
if (ds.Len() > 2)
{
parts.Insert(i, ds.Ptr(2));
ds.DeleteFrom(2);
}
}
#endif
}
if (i != 0)
keepAndReplaceEmptyPrefixes = false;
for (; i < parts.Size();)
{
UString &s = parts[i];
Correct_PathPart(s);
if (s.IsEmpty())
{
if (!keepAndReplaceEmptyPrefixes)
if (isDir || i != parts.Size() - 1)
{
parts.Delete(i);
continue;
}
s = k_EmptyReplaceName;
}
else
{
keepAndReplaceEmptyPrefixes = false;
#ifdef _WIN32
CorrectUnsupportedName(s);
#endif
}
i++;
}
if (!isDir)
{
if (parts.IsEmpty())
parts.Add((UString)k_EmptyReplaceName);
else
{
UString &s = parts.Back();
if (s.IsEmpty())
s = k_EmptyReplaceName;
}
}
}
UString MakePathFromParts(const UStringVector &parts)
{
UString s;
FOR_VECTOR (i, parts)
{
if (i != 0)
s.Add_PathSepar();
s += parts[i];
}
return s;
}
@@ -0,0 +1,31 @@
// ExtractingFilePath.h
#ifndef ZIP7_INC_EXTRACTING_FILE_PATH_H
#define ZIP7_INC_EXTRACTING_FILE_PATH_H
#include "../../../Common/MyString.h"
// #ifdef _WIN32
void Correct_AltStream_Name(UString &s);
// #endif
// replaces unsuported characters, and replaces "." , ".." and "" to "[]"
UString Get_Correct_FsFile_Name(const UString &name);
/*
Correct_FsPath() corrects path parts to prepare it for File System operations.
It also corrects empty path parts like "\\\\":
- frontal empty path parts : it removes them or changes them to "_"
- another empty path parts : it removes them
if (absIsAllowed && path is absolute) : it removes empty path parts after start absolute path prefix marker
else
{
if (!keepAndReplaceEmptyPrefixes) : it removes empty path parts
if ( keepAndReplaceEmptyPrefixes) : it changes each empty frontal path part to "_"
}
*/
void Correct_FsPath(bool absIsAllowed, bool keepAndReplaceEmptyPrefixes, UStringVector &parts, bool isDir);
UString MakePathFromParts(const UStringVector &parts);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,322 @@
// HashCalc.h
#ifndef ZIP7_INC_HASH_CALC_H
#define ZIP7_INC_HASH_CALC_H
#include "../../../Common/UTFConvert.h"
#include "../../../Common/Wildcard.h"
#include "../../Common/CreateCoder.h"
#include "../../Common/MethodProps.h"
#include "DirItem.h"
#include "IFileExtractCallback.h"
const unsigned k_HashCalc_DigestSize_Max = 64;
const unsigned k_HashCalc_ExtraSize = 8;
const unsigned k_HashCalc_NumGroups = 4;
/*
if (size <= 8) : upper case : reversed byte order : it shows 32-bit/64-bit number, if data contains little-endian number
if (size > 8) : lower case : original byte order (as big-endian byte sequence)
*/
void HashHexToString(char *dest, const Byte *data, size_t size);
enum
{
k_HashCalc_Index_Current,
k_HashCalc_Index_DataSum,
k_HashCalc_Index_NamesSum,
k_HashCalc_Index_StreamsSum
};
struct CHasherState
{
CMyComPtr<IHasher> Hasher;
AString Name;
UInt32 DigestSize;
UInt64 NumSums[k_HashCalc_NumGroups];
Byte Digests[k_HashCalc_NumGroups][k_HashCalc_DigestSize_Max + k_HashCalc_ExtraSize];
void InitDigestGroup(unsigned groupIndex)
{
NumSums[groupIndex] = 0;
memset(Digests[groupIndex], 0, sizeof(Digests[groupIndex]));
}
const Byte *GetExtraData_for_Group(unsigned groupIndex) const
{
return Digests[groupIndex] + k_HashCalc_DigestSize_Max;
}
unsigned GetNumExtraBytes_for_Group(unsigned groupIndex) const
{
const Byte *p = GetExtraData_for_Group(groupIndex);
// we use little-endian to read extra bytes
for (unsigned i = k_HashCalc_ExtraSize; i != 0; i--)
if (p[i - 1] != 0)
return i;
return 0;
}
void AddDigest(unsigned groupIndex, const Byte *data);
void WriteToString(unsigned digestIndex, char *s) const;
};
Z7_PURE_INTERFACES_BEGIN
DECLARE_INTERFACE(IHashCalc)
{
virtual void InitForNewFile() = 0;
virtual void Update(const void *data, UInt32 size) = 0;
virtual void SetSize(UInt64 size) = 0;
virtual void Final(bool isDir, bool isAltStream, const UString &path) = 0;
};
Z7_PURE_INTERFACES_END
struct CHashBundle Z7_final: public IHashCalc
{
CObjectVector<CHasherState> Hashers;
UInt64 NumDirs;
UInt64 NumFiles;
UInt64 NumAltStreams;
UInt64 FilesSize;
UInt64 AltStreamsSize;
UInt64 NumErrors;
UInt64 CurSize;
UString MainName;
UString FirstFileName;
HRESULT SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &methods);
// void Init() {}
CHashBundle()
{
NumDirs = NumFiles = NumAltStreams = FilesSize = AltStreamsSize = NumErrors = 0;
}
void InitForNewFile() Z7_override;
void Update(const void *data, UInt32 size) Z7_override;
void SetSize(UInt64 size) Z7_override;
void Final(bool isDir, bool isAltStream, const UString &path) Z7_override;
};
Z7_PURE_INTERFACES_BEGIN
// INTERFACE_IDirItemsCallback(x)
#define Z7_IFACEN_IHashCallbackUI(x) \
virtual HRESULT StartScanning() x \
virtual HRESULT FinishScanning(const CDirItemsStat &st) x \
virtual HRESULT SetNumFiles(UInt64 numFiles) x \
virtual HRESULT SetTotal(UInt64 size) x \
virtual HRESULT SetCompleted(const UInt64 *completeValue) x \
virtual HRESULT CheckBreak() x \
virtual HRESULT BeforeFirstFile(const CHashBundle &hb) x \
virtual HRESULT GetStream(const wchar_t *name, bool isFolder) x \
virtual HRESULT OpenFileError(const FString &path, DWORD systemError) x \
virtual HRESULT SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash) x \
virtual HRESULT AfterLastFile(CHashBundle &hb) x \
Z7_IFACE_DECL_PURE_(IHashCallbackUI, IDirItemsCallback)
Z7_PURE_INTERFACES_END
struct CHashOptionsLocal
{
CBoolPair HashMode_Zero;
CBoolPair HashMode_Tag;
CBoolPair HashMode_Dirs;
CBoolPair HashMode_OnlyHash;
void Init_HashOptionsLocal()
{
HashMode_Zero.Init();
HashMode_Tag.Init();
HashMode_Dirs.Init();
HashMode_OnlyHash.Init();
// HashMode_Dirs = true; // for debug
}
CHashOptionsLocal()
{
Init_HashOptionsLocal();
}
bool ParseFlagCharOption(wchar_t c, bool val)
{
c = MyCharLower_Ascii(c);
if (c == 'z') HashMode_Zero.SetVal_as_Defined(val);
else if (c == 't') HashMode_Tag.SetVal_as_Defined(val);
else if (c == 'd') HashMode_Dirs.SetVal_as_Defined(val);
else if (c == 'h') HashMode_OnlyHash.SetVal_as_Defined(val);
else return false;
return true;
}
bool ParseString(const UString &s)
{
for (unsigned i = 0; i < s.Len();)
{
const wchar_t c = s[i++];
bool val = true;
if (i < s.Len())
{
const wchar_t next = s[i];
if (next == '-')
{
val = false;
i++;
}
}
if (!ParseFlagCharOption(c, val))
return false;
}
return true;
}
};
struct CHashOptions
// : public CHashOptionsLocal
{
UStringVector Methods;
// UString HashFilePath;
bool PreserveATime;
bool OpenShareForWrite;
bool StdInMode;
bool AltStreamsMode;
CBoolPair SymLinks;
NWildcard::ECensorPathMode PathMode;
CHashOptions():
PreserveATime(false),
OpenShareForWrite(false),
StdInMode(false),
AltStreamsMode(false),
PathMode(NWildcard::k_RelatPath) {}
};
HRESULT HashCalc(
DECL_EXTERNAL_CODECS_LOC_VARS
const NWildcard::CCensor &censor,
const CHashOptions &options,
AString &errorInfo,
IHashCallbackUI *callback);
#ifndef Z7_SFX
namespace NHash {
struct CHashPair
{
CByteBuffer Hash;
char Mode;
bool IsBSD;
bool Escape;
bool Size_from_Arc_Defined;
bool Size_from_Disk_Defined;
AString Method;
AString Name;
AString FullLine;
AString HashString;
// unsigned HashLengthInBits;
// AString MethodName;
UInt64 Size_from_Arc;
UInt64 Size_from_Disk;
bool IsDir() const;
void Get_UString_Path(UString &path) const
{
path.Empty();
if (!ConvertUTF8ToUnicode(Name, path))
return;
}
bool ParseCksum(const char *s);
bool Parse(const char *s);
bool IsSupportedMode() const
{
return Mode != 'U' && Mode != '^';
}
CHashPair():
Mode(0)
, IsBSD(false)
, Escape(false)
, Size_from_Arc_Defined(false)
, Size_from_Disk_Defined(false)
// , HashLengthInBits(0)
, Size_from_Arc(0)
, Size_from_Disk(0)
{}
};
Z7_CLASS_IMP_CHandler_IInArchive_3(
IArchiveGetRawProps,
/* public IGetArchiveHashHandler, */
IOutArchive,
ISetProperties
)
bool _isArc;
bool _supportWindowsBackslash;
bool _crcSize_WasSet;
bool _is_CksumMode;
bool _is_PgpMethod;
bool _is_ZeroMode;
bool _are_there_Tags;
bool _are_there_Dirs;
bool _is_KnownMethod_in_FileName;
bool _hashSize_Defined;
unsigned _hashSize;
UInt32 _crcSize;
UInt64 _phySize;
CObjectVector<CHashPair> HashPairs;
UStringVector _methods;
AString _method_from_FileName;
AString _pgpMethod;
AString _method_for_Extraction;
CHashOptionsLocal _options;
void ClearVars();
void InitProps();
bool CanUpdate() const
{
if (!_isArc || _is_PgpMethod || _is_CksumMode)
return false;
return true;
}
HRESULT SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value);
public:
CHandler();
};
}
void Codecs_AddHashArcHandler(CCodecs *codecs);
#endif
#endif
@@ -0,0 +1,112 @@
// IFileExtractCallback.h
#ifndef ZIP7_INC_I_FILE_EXTRACT_CALLBACK_H
#define ZIP7_INC_I_FILE_EXTRACT_CALLBACK_H
#include "../../../Common/MyString.h"
#include "../../IDecl.h"
#include "LoadCodecs.h"
#include "OpenArchive.h"
Z7_PURE_INTERFACES_BEGIN
#define Z7_IFACE_CONSTR_FOLDERARC_SUB(i, base, n) \
Z7_DECL_IFACE_7ZIP_SUB(i, base, 1, n) \
{ Z7_IFACE_COM7_PURE(i) };
#define Z7_IFACE_CONSTR_FOLDERARC(i, n) \
Z7_IFACE_CONSTR_FOLDERARC_SUB(i, IUnknown, n)
namespace NOverwriteAnswer
{
enum EEnum
{
kYes,
kYesToAll,
kNo,
kNoToAll,
kAutoRename,
kCancel
};
}
/* ---------- IFolderArchiveExtractCallback ----------
is implemented by
Console/ExtractCallbackConsole.h CExtractCallbackConsole
FileManager/ExtractCallback.h CExtractCallbackImp
FAR/ExtractEngine.cpp CExtractCallBackImp: (QueryInterface is not supported)
IID_IFolderArchiveExtractCallback is requested by:
- Agent/ArchiveFolder.cpp
CAgentFolder::CopyTo(..., IFolderOperationsExtractCallback *callback)
is sent to IArchiveFolder::Extract()
- FileManager/PanelCopy.cpp
CPanel::CopyTo(), if (options->testMode)
is sent to IArchiveFolder::Extract()
IFolderArchiveExtractCallback is used by Common/ArchiveExtractCallback.cpp
*/
#define Z7_IFACEM_IFolderArchiveExtractCallback(x) \
x(AskOverwrite( \
const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, \
const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, \
Int32 *answer)) \
x(PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 *position)) \
x(MessageError(const wchar_t *message)) \
x(SetOperationResult(Int32 opRes, Int32 encrypted)) \
Z7_IFACE_CONSTR_FOLDERARC_SUB(IFolderArchiveExtractCallback, IProgress, 0x07)
#define Z7_IFACEM_IFolderArchiveExtractCallback2(x) \
x(ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)) \
Z7_IFACE_CONSTR_FOLDERARC(IFolderArchiveExtractCallback2, 0x08)
/* ---------- IExtractCallbackUI ----------
is implemented by
Console/ExtractCallbackConsole.h CExtractCallbackConsole
FileManager/ExtractCallback.h CExtractCallbackImp
*/
#ifdef Z7_NO_CRYPTO
#define Z7_IFACEM_IExtractCallbackUI_Crypto(px)
#else
#define Z7_IFACEM_IExtractCallbackUI_Crypto(px) \
virtual HRESULT SetPassword(const UString &password) px
#endif
#define Z7_IFACEN_IExtractCallbackUI(px) \
virtual HRESULT BeforeOpen(const wchar_t *name, bool testMode) px \
virtual HRESULT OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) px \
virtual HRESULT ThereAreNoFiles() px \
virtual HRESULT ExtractResult(HRESULT result) px \
Z7_IFACEM_IExtractCallbackUI_Crypto(px)
// IExtractCallbackUI - is non-COM interface
// IFolderArchiveExtractCallback - is COM interface
// Z7_IFACE_DECL_PURE_(IExtractCallbackUI, IFolderArchiveExtractCallback)
Z7_IFACE_DECL_PURE(IExtractCallbackUI)
#define Z7_IFACEM_IGetProp(x) \
x(GetProp(PROPID propID, PROPVARIANT *value)) \
Z7_IFACE_CONSTR_FOLDERARC(IGetProp, 0x20)
#define Z7_IFACEM_IFolderExtractToStreamCallback(x) \
x(UseExtractToStream(Int32 *res)) \
x(GetStream7(const wchar_t *name, Int32 isDir, ISequentialOutStream **outStream, Int32 askExtractMode, IGetProp *getProp)) \
x(PrepareOperation7(Int32 askExtractMode)) \
x(SetOperationResult8(Int32 resultEOperationResult, Int32 encrypted, UInt64 size)) \
Z7_IFACE_CONSTR_FOLDERARC(IFolderExtractToStreamCallback, 0x31)
Z7_PURE_INTERFACES_END
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,482 @@
// LoadCodecs.h
#ifndef ZIP7_INC_LOAD_CODECS_H
#define ZIP7_INC_LOAD_CODECS_H
/*
Client application uses LoadCodecs.* to load plugins to
CCodecs object, that contains 3 lists of plugins:
1) Formats - internal and external archive handlers
2) Codecs - external codecs
3) Hashers - external hashers
Z7_EXTERNAL_CODECS
---------------
if Z7_EXTERNAL_CODECS is defined, then the code tries to load external
plugins from DLL files (shared libraries).
There are two types of executables in 7-Zip:
1) Executable that uses external plugins must be compiled
with Z7_EXTERNAL_CODECS defined:
- 7z.exe, 7zG.exe, 7zFM.exe
Note: Z7_EXTERNAL_CODECS is used also in CPP/7zip/Common/CreateCoder.h
that code is used in plugin module (7z.dll).
2) Standalone modules are compiled without Z7_EXTERNAL_CODECS:
- SFX modules: 7z.sfx, 7zCon.sfx
- standalone versions of console 7-Zip: 7za.exe, 7zr.exe
if Z7_EXTERNAL_CODECS is defined, CCodecs class implements interfaces:
- ICompressCodecsInfo : for Codecs
- IHashers : for Hashers
The client application can send CCodecs object to each plugin module.
And plugin module can use ICompressCodecsInfo or IHashers interface to access
another plugins.
There are 2 ways to send (ICompressCodecsInfo * compressCodecsInfo) to plugin
1) for old versions:
a) request ISetCompressCodecsInfo from created archive handler.
b) call ISetCompressCodecsInfo::SetCompressCodecsInfo(compressCodecsInfo)
2) for new versions:
a) request "SetCodecs" function from DLL file
b) call SetCodecs(compressCodecsInfo) function from DLL file
*/
#include "../../../Common/MyBuffer.h"
#include "../../../Common/MyCom.h"
#include "../../../Common/MyString.h"
#include "../../../Common/ComTry.h"
#ifdef Z7_EXTERNAL_CODECS
#include "../../../Windows/DLL.h"
#endif
#include "../../ICoder.h"
#include "../../Archive/IArchive.h"
#ifdef Z7_EXTERNAL_CODECS
struct CDllCodecInfo
{
unsigned LibIndex;
UInt32 CodecIndex;
bool EncoderIsAssigned;
bool DecoderIsAssigned;
bool IsFilter;
bool IsFilter_Assigned;
CLSID Encoder;
CLSID Decoder;
};
struct CDllHasherInfo
{
unsigned LibIndex;
UInt32 HasherIndex;
};
#endif
struct CArcExtInfo
{
UString Ext;
UString AddExt;
CArcExtInfo() {}
CArcExtInfo(const UString &ext): Ext(ext) {}
CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {}
};
struct CArcInfoEx
{
UInt32 Flags;
UInt32 TimeFlags;
Func_CreateInArchive CreateInArchive;
Func_IsArc IsArcFunc;
UString Name;
CObjectVector<CArcExtInfo> Exts;
#ifndef Z7_SFX
Func_CreateOutArchive CreateOutArchive;
bool UpdateEnabled;
bool NewInterface;
// UInt32 Version;
UInt32 SignatureOffset;
CObjectVector<CByteBuffer> Signatures;
/*
#ifdef NEW_FOLDER_INTERFACE
UStringVector AssociateExts;
#endif
*/
#endif
#ifdef Z7_EXTERNAL_CODECS
int LibIndex;
UInt32 FormatIndex;
CLSID ClassID;
#endif
int Compare(const CArcInfoEx &a) const
{
const int res = Name.Compare(a.Name);
if (res != 0)
return res;
#ifdef Z7_EXTERNAL_CODECS
return MyCompare(LibIndex, a.LibIndex);
#else
return 0;
#endif
/*
if (LibIndex < a.LibIndex) return -1;
if (LibIndex > a.LibIndex) return 1;
return 0;
*/
}
bool Flags_KeepName() const { return (Flags & NArcInfoFlags::kKeepName) != 0; }
bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; }
bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; }
bool Flags_NtSecurity() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; }
bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; }
bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; }
bool Flags_UseGlobalOffset() const { return (Flags & NArcInfoFlags::kUseGlobalOffset) != 0; }
bool Flags_StartOpen() const { return (Flags & NArcInfoFlags::kStartOpen) != 0; }
bool Flags_BackwardOpen() const { return (Flags & NArcInfoFlags::kBackwardOpen) != 0; }
bool Flags_PreArc() const { return (Flags & NArcInfoFlags::kPreArc) != 0; }
bool Flags_PureStartOpen() const { return (Flags & NArcInfoFlags::kPureStartOpen) != 0; }
bool Flags_ByExtOnlyOpen() const { return (Flags & NArcInfoFlags::kByExtOnlyOpen) != 0; }
bool Flags_HashHandler() const { return (Flags & NArcInfoFlags::kHashHandler) != 0; }
bool Flags_CTime() const { return (Flags & NArcInfoFlags::kCTime) != 0; }
bool Flags_ATime() const { return (Flags & NArcInfoFlags::kATime) != 0; }
bool Flags_MTime() const { return (Flags & NArcInfoFlags::kMTime) != 0; }
bool Flags_CTime_Default() const { return (Flags & NArcInfoFlags::kCTime_Default) != 0; }
bool Flags_ATime_Default() const { return (Flags & NArcInfoFlags::kATime_Default) != 0; }
bool Flags_MTime_Default() const { return (Flags & NArcInfoFlags::kMTime_Default) != 0; }
UInt32 Get_TimePrecFlags() const
{
return (TimeFlags >> NArcInfoTimeFlags::kTime_Prec_Mask_bit_index) &
(((UInt32)1 << NArcInfoTimeFlags::kTime_Prec_Mask_num_bits) - 1);
}
UInt32 Get_DefaultTimePrec() const
{
return (TimeFlags >> NArcInfoTimeFlags::kTime_Prec_Default_bit_index) &
(((UInt32)1 << NArcInfoTimeFlags::kTime_Prec_Default_num_bits) - 1);
}
UString GetMainExt() const
{
if (Exts.IsEmpty())
return UString();
return Exts[0].Ext;
}
int FindExtension(const UString &ext) const;
bool Is_7z() const { return Name.IsEqualTo_Ascii_NoCase("7z"); }
bool Is_Split() const { return Name.IsEqualTo_Ascii_NoCase("Split"); }
bool Is_Xz() const { return Name.IsEqualTo_Ascii_NoCase("xz"); }
bool Is_BZip2() const { return Name.IsEqualTo_Ascii_NoCase("bzip2"); }
bool Is_GZip() const { return Name.IsEqualTo_Ascii_NoCase("gzip"); }
bool Is_Tar() const { return Name.IsEqualTo_Ascii_NoCase("tar"); }
bool Is_Zip() const { return Name.IsEqualTo_Ascii_NoCase("zip"); }
bool Is_Rar() const { return Name.IsEqualTo_Ascii_NoCase("rar"); }
bool Is_Zstd() const { return Name.IsEqualTo_Ascii_NoCase("zstd"); }
/*
UString GetAllExtensions() const
{
UString s;
for (int i = 0; i < Exts.Size(); i++)
{
if (i > 0)
s.Add_Space();
s += Exts[i].Ext;
}
return s;
}
*/
void AddExts(const UString &ext, const UString &addExt);
CArcInfoEx():
Flags(0),
TimeFlags(0),
CreateInArchive(NULL),
IsArcFunc(NULL)
#ifndef Z7_SFX
, CreateOutArchive(NULL)
, UpdateEnabled(false)
, NewInterface(false)
// , Version(0)
, SignatureOffset(0)
#endif
#ifdef Z7_EXTERNAL_CODECS
, LibIndex(-1)
#endif
{}
};
#ifdef Z7_EXTERNAL_CODECS
struct CCodecLib
{
NWindows::NDLL::CLibrary Lib;
FString Path;
Func_CreateObject CreateObject;
Func_GetMethodProperty GetMethodProperty;
Func_CreateDecoder CreateDecoder;
Func_CreateEncoder CreateEncoder;
Func_SetCodecs SetCodecs;
CMyComPtr<IHashers> ComHashers;
UInt32 Version;
/*
#ifdef NEW_FOLDER_INTERFACE
CCodecIcons CodecIcons;
void LoadIcons() { CodecIcons.LoadIcons((HMODULE)Lib); }
#endif
*/
CCodecLib():
CreateObject(NULL),
GetMethodProperty(NULL),
CreateDecoder(NULL),
CreateEncoder(NULL),
SetCodecs(NULL),
Version(0)
{}
};
#endif
struct CCodecError
{
FString Path;
HRESULT ErrorCode;
AString Message;
CCodecError(): ErrorCode(0) {}
};
struct CCodecInfoUser
{
// unsigned LibIndex;
// UInt32 CodecIndex;
// UInt64 id;
bool EncoderIsAssigned;
bool DecoderIsAssigned;
bool IsFilter;
bool IsFilter_Assigned;
UInt32 NumStreams;
AString Name;
};
class CCodecs Z7_final:
#ifdef Z7_EXTERNAL_CODECS
public ICompressCodecsInfo,
public IHashers,
#else
public IUnknown,
#endif
public CMyUnknownImp
{
#ifdef Z7_EXTERNAL_CODECS
Z7_IFACES_IMP_UNK_2(ICompressCodecsInfo, IHashers)
#else
Z7_COM_UNKNOWN_IMP_0
#endif // Z7_EXTERNAL_CODECS
Z7_CLASS_NO_COPY(CCodecs)
public:
#ifdef Z7_EXTERNAL_CODECS
CObjectVector<CCodecLib> Libs;
FString MainDll_ErrorPath;
CObjectVector<CCodecError> Errors;
void AddLastError(const FString &path);
void CloseLibs();
class CReleaser
{
Z7_CLASS_NO_COPY(CReleaser)
/* CCodecsReleaser object releases CCodecs links.
1) CCodecs is COM object that is deleted when all links to that object will be released/
2) CCodecs::Libs[i] can hold (ICompressCodecsInfo *) link to CCodecs object itself.
To break that reference loop, we must close all CCodecs::Libs in CCodecsReleaser desttructor. */
CCodecs *_codecs;
public:
CReleaser(): _codecs(NULL) {}
void Set(CCodecs *codecs) { _codecs = codecs; }
~CReleaser() { if (_codecs) _codecs->CloseLibs(); }
};
bool NeedSetLibCodecs; // = false, if we don't need to set codecs for archive handler via ISetCompressCodecsInfo
HRESULT LoadCodecs();
HRESULT LoadFormats();
HRESULT LoadDll(const FString &path, bool needCheckDll, bool *loadedOK = NULL);
HRESULT LoadDllsFromFolder(const FString &folderPrefix);
HRESULT CreateArchiveHandler(const CArcInfoEx &ai, bool outHandler, void **archive) const
{
return Libs[(unsigned)ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive);
}
#endif
/*
#ifdef NEW_FOLDER_INTERFACE
CCodecIcons InternalIcons;
#endif
*/
CObjectVector<CArcInfoEx> Formats;
#ifdef Z7_EXTERNAL_CODECS
CRecordVector<CDllCodecInfo> Codecs;
CRecordVector<CDllHasherInfo> Hashers;
#endif
bool CaseSensitive_Change;
bool CaseSensitive;
CCodecs():
#ifdef Z7_EXTERNAL_CODECS
NeedSetLibCodecs(true),
#endif
CaseSensitive_Change(false),
CaseSensitive(false)
{}
~CCodecs()
{
// OutputDebugStringA("~CCodecs");
}
const wchar_t *GetFormatNamePtr(int formatIndex) const
{
return formatIndex < 0 ? L"#" : (const wchar_t *)Formats[(unsigned)formatIndex].Name;
}
HRESULT Load();
#ifndef Z7_SFX
int FindFormatForArchiveName(const UString &arcPath) const;
int FindFormatForExtension(const UString &ext) const;
int FindFormatForArchiveType(const UString &arcType) const;
bool FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const;
#endif
#ifdef Z7_EXTERNAL_CODECS
int GetCodec_LibIndex(UInt32 index) const;
bool GetCodec_DecoderIsAssigned(UInt32 index) const;
bool GetCodec_EncoderIsAssigned(UInt32 index) const;
bool GetCodec_IsFilter(UInt32 index, bool &isAssigned) const;
UInt32 GetCodec_NumStreams(UInt32 index);
HRESULT GetCodec_Id(UInt32 index, UInt64 &id);
AString GetCodec_Name(UInt32 index);
int GetHasherLibIndex(UInt32 index);
UInt64 GetHasherId(UInt32 index);
AString GetHasherName(UInt32 index);
UInt32 GetHasherDigestSize(UInt32 index);
void GetCodecsErrorMessage(UString &s);
#endif
HRESULT CreateInArchive(unsigned formatIndex, CMyComPtr<IInArchive> &archive) const
{
const CArcInfoEx &ai = Formats[formatIndex];
#ifdef Z7_EXTERNAL_CODECS
if (ai.LibIndex < 0)
#endif
{
COM_TRY_BEGIN
archive = ai.CreateInArchive();
return S_OK;
COM_TRY_END
}
#ifdef Z7_EXTERNAL_CODECS
return CreateArchiveHandler(ai, false, (void **)&archive);
#endif
}
#ifndef Z7_SFX
HRESULT CreateOutArchive(unsigned formatIndex, CMyComPtr<IOutArchive> &archive) const
{
const CArcInfoEx &ai = Formats[formatIndex];
#ifdef Z7_EXTERNAL_CODECS
if (ai.LibIndex < 0)
#endif
{
COM_TRY_BEGIN
archive = ai.CreateOutArchive();
return S_OK;
COM_TRY_END
}
#ifdef Z7_EXTERNAL_CODECS
return CreateArchiveHandler(ai, true, (void **)&archive);
#endif
}
int FindOutFormatFromName(const UString &name) const
{
FOR_VECTOR (i, Formats)
{
const CArcInfoEx &arc = Formats[i];
if (!arc.UpdateEnabled)
continue;
if (arc.Name.IsEqualTo_NoCase(name))
return (int)i;
}
return -1;
}
void Get_CodecsInfoUser_Vector(CObjectVector<CCodecInfoUser> &v);
#endif // Z7_SFX
};
#ifdef Z7_EXTERNAL_CODECS
#define CREATE_CODECS_OBJECT \
CCodecs *codecs = new CCodecs; \
CExternalCodecs _externalCodecs; \
_externalCodecs.GetCodecs = codecs; \
_externalCodecs.GetHashers = codecs; \
CCodecs::CReleaser codecsReleaser; \
codecsReleaser.Set(codecs);
#else
#define CREATE_CODECS_OBJECT \
CCodecs *codecs = new CCodecs; \
CMyComPtr<IUnknown> _codecsRef = codecs;
#endif
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,469 @@
// OpenArchive.h
#ifndef ZIP7_INC_OPEN_ARCHIVE_H
#define ZIP7_INC_OPEN_ARCHIVE_H
#include "../../../Windows/PropVariant.h"
#include "ArchiveOpenCallback.h"
#include "LoadCodecs.h"
#include "Property.h"
#include "DirItem.h"
#ifndef Z7_SFX
#define SUPPORT_ALT_STREAMS
#endif
HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw();
HRESULT Archive_IsItem_Dir(IInArchive *arc, UInt32 index, bool &result) throw();
HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw();
HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw();
HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &deleted) throw();
#ifdef SUPPORT_ALT_STREAMS
int FindAltStreamColon_in_Path(const wchar_t *path);
#endif
/*
struct COptionalOpenProperties
{
UString FormatName;
CObjectVector<CProperty> Props;
};
*/
#ifdef Z7_SFX
#define OPEN_PROPS_DECL
#else
#define OPEN_PROPS_DECL const CObjectVector<CProperty> *props;
// #define OPEN_PROPS_DECL , const CObjectVector<COptionalOpenProperties> *props
#endif
struct COpenSpecFlags
{
// bool CanReturnFull;
bool CanReturnFrontal;
bool CanReturnTail;
bool CanReturnMid;
bool CanReturn_NonStart() const { return CanReturnTail || CanReturnMid; }
COpenSpecFlags():
// CanReturnFull(true),
CanReturnFrontal(false),
CanReturnTail(false),
CanReturnMid(false)
{}
};
struct COpenType
{
int FormatIndex;
COpenSpecFlags SpecForcedType;
COpenSpecFlags SpecMainType;
COpenSpecFlags SpecWrongExt;
COpenSpecFlags SpecUnknownExt;
bool Recursive;
bool CanReturnArc;
bool CanReturnParser;
bool IsHashType;
bool EachPos;
// bool SkipSfxStub;
// bool ExeAsUnknown;
bool ZerosTailIsAllowed;
bool MaxStartOffset_Defined;
UInt64 MaxStartOffset;
const COpenSpecFlags &GetSpec(bool isForced, bool isMain, bool isUnknown) const
{
return isForced ? SpecForcedType : (isMain ? SpecMainType : (isUnknown ? SpecUnknownExt : SpecWrongExt));
}
COpenType():
FormatIndex(-1),
Recursive(true),
CanReturnArc(true),
CanReturnParser(false),
IsHashType(false),
EachPos(false),
// SkipSfxStub(true),
// ExeAsUnknown(true),
ZerosTailIsAllowed(false),
MaxStartOffset_Defined(false),
MaxStartOffset(0)
{
SpecForcedType.CanReturnFrontal = true;
SpecForcedType.CanReturnTail = true;
SpecForcedType.CanReturnMid = true;
SpecMainType.CanReturnFrontal = true;
SpecUnknownExt.CanReturnTail = true; // for sfx
SpecUnknownExt.CanReturnMid = true;
SpecUnknownExt.CanReturnFrontal = true; // for alt streams of sfx with pad
// ZerosTailIsAllowed = true;
}
};
struct COpenOptions
{
CCodecs *codecs;
COpenType openType;
const CObjectVector<COpenType> *types;
const CIntVector *excludedFormats;
IInStream *stream;
ISequentialInStream *seqStream;
IArchiveOpenCallback *callback;
COpenCallbackImp *callbackSpec; // it's used for SFX only
OPEN_PROPS_DECL
// bool openOnlySpecifiedByExtension,
bool stdInMode;
UString filePath;
COpenOptions():
codecs(NULL),
types(NULL),
excludedFormats(NULL),
stream(NULL),
seqStream(NULL),
callback(NULL),
callbackSpec(NULL),
stdInMode(false)
{}
};
UInt32 GetOpenArcErrorFlags(const NWindows::NCOM::CPropVariant &prop, bool *isDefinedProp = NULL);
struct CArcErrorInfo
{
bool ThereIsTail;
bool UnexpecedEnd;
bool IgnoreTail; // all are zeros
// bool NonZerosTail;
bool ErrorFlags_Defined;
UInt32 ErrorFlags;
UInt32 WarningFlags;
int ErrorFormatIndex; // - 1 means no Error.
// if FormatIndex == ErrorFormatIndex, the archive is open with offset
UInt64 TailSize;
/* if CArc is Open OK with some format:
- ErrorFormatIndex shows error format index, if extension is incorrect
- other variables show message and warnings of archive that is open */
UString ErrorMessage;
UString WarningMessage;
// call IsArc_After_NonOpen only if Open returns S_FALSE
bool IsArc_After_NonOpen() const
{
return (ErrorFlags_Defined && (ErrorFlags & kpv_ErrorFlags_IsNotArc) == 0);
}
CArcErrorInfo():
ThereIsTail(false),
UnexpecedEnd(false),
IgnoreTail(false),
// NonZerosTail(false),
ErrorFlags_Defined(false),
ErrorFlags(0),
WarningFlags(0),
ErrorFormatIndex(-1),
TailSize(0)
{}
void ClearErrors();
void ClearErrors_Full()
{
ErrorFormatIndex = -1;
ClearErrors();
}
bool IsThereErrorOrWarning() const
{
return ErrorFlags != 0
|| WarningFlags != 0
|| NeedTailWarning()
|| UnexpecedEnd
|| !ErrorMessage.IsEmpty()
|| !WarningMessage.IsEmpty();
}
bool AreThereErrors() const { return ErrorFlags != 0 || UnexpecedEnd; }
bool AreThereWarnings() const { return WarningFlags != 0 || NeedTailWarning(); }
bool NeedTailWarning() const { return !IgnoreTail && ThereIsTail; }
UInt32 GetWarningFlags() const
{
UInt32 a = WarningFlags;
if (NeedTailWarning() && (ErrorFlags & kpv_ErrorFlags_DataAfterEnd) == 0)
a |= kpv_ErrorFlags_DataAfterEnd;
return a;
}
UInt32 GetErrorFlags() const
{
UInt32 a = ErrorFlags;
if (UnexpecedEnd)
a |= kpv_ErrorFlags_UnexpectedEnd;
return a;
}
};
struct CReadArcItem
{
UString Path; // Path from root (including alt stream name, if alt stream)
UStringVector PathParts; // without altStream name, path from root or from _baseParentFolder, if _use_baseParentFolder_mode
#ifdef SUPPORT_ALT_STREAMS
UString MainPath;
/* MainPath = Path for non-AltStream,
MainPath = Path of parent, if there is parent for AltStream. */
UString AltStreamName;
bool IsAltStream;
bool WriteToAltStreamIfColon;
#endif
bool IsDir;
bool MainIsDir;
UInt32 ParentIndex; // use it, if IsAltStream
#ifndef Z7_SFX
bool _use_baseParentFolder_mode;
int _baseParentFolder;
#endif
CReadArcItem()
{
#ifdef SUPPORT_ALT_STREAMS
WriteToAltStreamIfColon = false;
#endif
#ifndef Z7_SFX
_use_baseParentFolder_mode = false;
_baseParentFolder = -1;
#endif
}
};
class CArc
{
HRESULT PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr<IInArchive> &archive);
HRESULT CheckZerosTail(const COpenOptions &op, UInt64 offset);
HRESULT OpenStream2(const COpenOptions &options);
#ifndef Z7_SFX
// parts.Back() can contain alt stream name "nams:AltName"
HRESULT GetItem_PathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const;
#endif
public:
CMyComPtr<IInArchive> Archive;
CMyComPtr<IInStream> InStream;
// we use InStream in 2 cases (ArcStreamOffset != 0):
// 1) if we use additional cache stream
// 2) we reopen sfx archive with CTailInStream
CMyComPtr<IArchiveGetRawProps> GetRawProps;
CMyComPtr<IArchiveGetRootProps> GetRootProps;
bool IsParseArc;
bool IsTree;
bool IsReadOnly;
bool Ask_Deleted;
bool Ask_AltStream;
bool Ask_Aux;
bool Ask_INode;
bool IgnoreSplit; // don't try split handler
UString Path;
UString filePath;
UString DefaultName;
int FormatIndex; // -1 means Parser
UInt32 SubfileIndex; // (UInt32)(Int32)-1; means no subfile
// CFiTime MTime;
// bool MTime_Defined;
CArcTime MTime;
Int64 Offset; // it's offset of start of archive inside stream that is open by Archive Handler
UInt64 PhySize;
// UInt64 OkPhySize;
bool PhySize_Defined;
// bool OkPhySize_Defined;
UInt64 FileSize;
UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file
CArcErrorInfo ErrorInfo; // for OK archives
CArcErrorInfo NonOpen_ErrorInfo; // ErrorInfo for mainArchive (false OPEN)
UInt64 GetEstmatedPhySize() const { return PhySize_Defined ? PhySize : FileSize; }
UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler
Int64 GetGlobalOffset() const { return (Int64)ArcStreamOffset + Offset; } // it's global offset of archive
// AString ErrorFlagsText;
// void Set_ErrorFlagsText();
CArc():
// MTime_Defined(false),
IsTree(false),
IsReadOnly(false),
Ask_Deleted(false),
Ask_AltStream(false),
Ask_Aux(false),
Ask_INode(false),
IgnoreSplit(false)
{}
HRESULT ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes);
HRESULT Close()
{
InStream.Release();
return Archive->Close();
}
HRESULT GetItem_Path(UInt32 index, UString &result) const;
HRESULT GetItem_DefaultPath(UInt32 index, UString &result) const;
// GetItemPath2 adds [DELETED] dir prefix for deleted items.
HRESULT GetItem_Path2(UInt32 index, UString &result) const;
HRESULT GetItem(UInt32 index, CReadArcItem &item) const;
HRESULT GetItem_Size(UInt32 index, UInt64 &size, bool &defined) const;
/* if (GetProperty() returns vt==VT_EMPTY), this function sets
timestamp from archive file timestamp (MTime).
So (at) will be set in most cases (at.Def == true)
if (at.Prec == 0)
{
it means that (Prec == 0) was returned for (kpidMTime),
and no value was returned for (kpidTimeType).
it can mean Windows precision or unknown precision.
}
*/
HRESULT GetItem_MTime(UInt32 index, CArcTime &at) const;
HRESULT IsItem_Anti(UInt32 index, bool &result) const
{ return Archive_GetItemBoolProp(Archive, index, kpidIsAnti, result); }
HRESULT OpenStream(const COpenOptions &options);
HRESULT OpenStreamOrFile(COpenOptions &options);
HRESULT ReOpen(const COpenOptions &options, IArchiveOpenCallback *openCallback_Additional);
HRESULT CreateNewTailStream(CMyComPtr<IInStream> &stream);
bool IsHashHandler(const COpenOptions &options) const
{
if (FormatIndex < 0)
return false;
return options.codecs->Formats[(unsigned)FormatIndex].Flags_HashHandler();
}
};
struct CArchiveLink
{
CObjectVector<CArc> Arcs;
UStringVector VolumePaths;
UInt64 VolumesSize;
bool IsOpen;
bool PasswordWasAsked;
// UString Password;
// int NonOpenErrorFormatIndex; // - 1 means no Error.
UString NonOpen_ArcPath;
CArcErrorInfo NonOpen_ErrorInfo;
// UString ErrorsText;
// void Set_ErrorsText();
CArchiveLink():
VolumesSize(0),
IsOpen(false),
PasswordWasAsked(false)
{}
void KeepModeForNextOpen();
HRESULT Close();
void Release();
~CArchiveLink() { Release(); }
const CArc *GetArc() const { return &Arcs.Back(); }
IInArchive *GetArchive() const { return Arcs.Back().Archive; }
IArchiveGetRawProps *GetArchiveGetRawProps() const { return Arcs.Back().GetRawProps; }
IArchiveGetRootProps *GetArchiveGetRootProps() const { return Arcs.Back().GetRootProps; }
/*
Open() opens archive and COpenOptions::callback
Open2() uses COpenCallbackImp that implements Volumes and password callback
Open3() calls Open2() and callbackUI->Open_Finished();
Open_Strict() returns S_FALSE also in case, if there is non-open expected nested archive.
*/
HRESULT Open(COpenOptions &options);
HRESULT Open2(COpenOptions &options, IOpenCallbackUI *callbackUI);
HRESULT Open3(COpenOptions &options, IOpenCallbackUI *callbackUI);
HRESULT Open_Strict(COpenOptions &options, IOpenCallbackUI *callbackUI)
{
HRESULT result = Open3(options, callbackUI);
if (result == S_OK && NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
result = S_FALSE;
return result;
}
HRESULT ReOpen(COpenOptions &options);
};
bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> &types);
// bool IsHashType(const CObjectVector<COpenType> &types);
struct CDirPathSortPair
{
unsigned Len;
unsigned Index;
void SetNumSlashes(const FChar *s);
int Compare(const CDirPathSortPair &a) const
{
// We need sorting order where parent items will be after child items
if (Len < a.Len) return 1;
if (Len > a.Len) return -1;
if (Index < a.Index) return -1;
if (Index > a.Index) return 1;
return 0;
}
};
#endif
@@ -0,0 +1,745 @@
// PropIDUtils.cpp
#include "StdAfx.h"
#include "../../../../C/CpuArch.h"
#include "../../../Common/IntToString.h"
#include "../../../Common/StringConvert.h"
#include "../../../Windows/FileIO.h"
#include "../../../Windows/PropVariantConv.h"
#include "../../PropID.h"
#include "PropIDUtils.h"
#ifndef Z7_SFX
#define Get16(x) GetUi16(x)
#define Get32(x) GetUi32(x)
#endif
using namespace NWindows;
static const unsigned kNumWinAtrribFlags = 30;
static const char g_WinAttribChars[kNumWinAtrribFlags + 1] = "RHS8DAdNTsLCOIEVvX.PU.M......B";
/*
FILE_ATTRIBUTE_
0 READONLY
1 HIDDEN
2 SYSTEM
3 (Volume label - obsolete)
4 DIRECTORY
5 ARCHIVE
6 DEVICE
7 NORMAL
8 TEMPORARY
9 SPARSE_FILE
10 REPARSE_POINT
11 COMPRESSED
12 OFFLINE
13 NOT_CONTENT_INDEXED (I - Win10 attrib/Explorer)
14 ENCRYPTED
15 INTEGRITY_STREAM (V - ReFS Win8/Win2012)
16 VIRTUAL (reserved)
17 NO_SCRUB_DATA (X - ReFS Win8/Win2012 attrib)
18 RECALL_ON_OPEN or EA
19 PINNED
20 UNPINNED
21 STRICTLY_SEQUENTIAL (10.0.16267)
22 RECALL_ON_DATA_ACCESS
29 STRICTLY_SEQUENTIAL (10.0.17134+) (SMR Blob)
*/
static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' };
#define MY_ATTR_CHAR(a, n, c) (((a) & (1 << (n))) ? c : '-')
static void ConvertPosixAttribToString(char *s, UInt32 a) throw()
{
s[0] = kPosixTypes[(a >> 12) & 0xF];
for (int i = 6; i >= 0; i -= 3)
{
s[7 - i] = MY_ATTR_CHAR(a, i + 2, 'r');
s[8 - i] = MY_ATTR_CHAR(a, i + 1, 'w');
s[9 - i] = MY_ATTR_CHAR(a, i + 0, 'x');
}
if ((a & 0x800) != 0) s[3] = ((a & (1 << 6)) ? 's' : 'S'); // S_ISUID
if ((a & 0x400) != 0) s[6] = ((a & (1 << 3)) ? 's' : 'S'); // S_ISGID
if ((a & 0x200) != 0) s[9] = ((a & (1 << 0)) ? 't' : 'T'); // S_ISVTX
s[10] = 0;
a &= ~(UInt32)0xFFFF;
if (a != 0)
{
s[10] = ' ';
ConvertUInt32ToHex8Digits(a, s + 11);
}
}
void ConvertWinAttribToString(char *s, UInt32 wa) throw()
{
/*
some programs store posix attributes in high 16 bits.
p7zip - stores additional 0x8000 flag marker.
macos - stores additional 0x4000 flag marker.
info-zip - no additional marker.
But this code works with Attrib from internal 7zip code.
So we expect that 0x8000 marker is set, if there are posix attributes.
(DT_UNKNOWN == 0) type in high bits is possible in some case for linux files.
0x8000 flag is possible also in ReFS (Windows)?
*/
const bool isPosix = (
(wa & 0x8000) != 0 // FILE_ATTRIBUTE_UNIX_EXTENSION;
// && (wa & 0xFFFF0000u) != 0
);
UInt32 posix = 0;
if (isPosix)
{
posix = wa >> 16;
if ((wa & 0xF0000000u) != 0)
wa &= (UInt32)0x3FFF;
}
for (unsigned i = 0; i < kNumWinAtrribFlags; i++)
{
const UInt32 flag = (UInt32)1 << i;
if (wa & flag)
{
const char c = g_WinAttribChars[i];
if (c != '.')
{
wa &= ~flag;
// if (i != 7) // we can disable N (NORMAL) printing
*s++ = c;
}
}
}
if (wa != 0)
{
*s++ = ' ';
ConvertUInt32ToHex8Digits(wa, s);
s += strlen(s);
}
*s = 0;
if (isPosix)
{
*s++ = ' ';
ConvertPosixAttribToString(s, posix);
}
}
void ConvertPropertyToShortString2(char *dest, const PROPVARIANT &prop, PROPID propID, int level) throw()
{
*dest = 0;
if (prop.vt == VT_FILETIME)
{
const FILETIME &ft = prop.filetime;
unsigned ns100 = 0;
int numDigits = kTimestampPrintLevel_NTFS;
const unsigned prec = prop.wReserved1;
const unsigned ns100_Temp = prop.wReserved2;
if (prec != 0
&& prec <= k_PropVar_TimePrec_1ns
&& ns100_Temp < 100
&& prop.wReserved3 == 0)
{
ns100 = ns100_Temp;
if (prec == k_PropVar_TimePrec_Unix ||
prec == k_PropVar_TimePrec_DOS)
numDigits = 0;
else if (prec == k_PropVar_TimePrec_HighPrec)
numDigits = 9;
else
{
numDigits = (int)prec - (int)k_PropVar_TimePrec_Base;
if (
// numDigits < kTimestampPrintLevel_DAY // for debuf
numDigits < kTimestampPrintLevel_SEC
)
numDigits = kTimestampPrintLevel_NTFS;
}
}
if (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0 && ns100 == 0)
return;
if (level > numDigits)
level = numDigits;
ConvertUtcFileTimeToString2(ft, ns100, dest, level);
return;
}
switch (propID)
{
case kpidCRC:
{
if (prop.vt != VT_UI4)
break;
ConvertUInt32ToHex8Digits(prop.ulVal, dest);
return;
}
case kpidAttrib:
{
if (prop.vt != VT_UI4)
break;
const UInt32 a = prop.ulVal;
/*
if ((a & 0x8000) && (a & 0x7FFF) == 0)
ConvertPosixAttribToString(dest, a >> 16);
else
*/
ConvertWinAttribToString(dest, a);
return;
}
case kpidPosixAttrib:
{
if (prop.vt != VT_UI4)
break;
ConvertPosixAttribToString(dest, prop.ulVal);
return;
}
case kpidINode:
{
if (prop.vt != VT_UI8)
break;
ConvertUInt32ToString((UInt32)(prop.uhVal.QuadPart >> 48), dest);
dest += strlen(dest);
*dest++ = '-';
const UInt64 low = prop.uhVal.QuadPart & (((UInt64)1 << 48) - 1);
ConvertUInt64ToString(low, dest);
return;
}
case kpidVa:
{
UInt64 v = 0;
if (prop.vt == VT_UI4)
v = prop.ulVal;
else if (prop.vt == VT_UI8)
v = (UInt64)prop.uhVal.QuadPart;
else
break;
dest[0] = '0';
dest[1] = 'x';
ConvertUInt64ToHex(v, dest + 2);
return;
}
/*
case kpidDevice:
{
UInt64 v = 0;
if (prop.vt == VT_UI4)
v = prop.ulVal;
else if (prop.vt == VT_UI8)
v = (UInt64)prop.uhVal.QuadPart;
else
break;
ConvertUInt32ToString(MY_dev_major(v), dest);
dest += strlen(dest);
*dest++ = ',';
ConvertUInt32ToString(MY_dev_minor(v), dest);
return;
}
*/
default: break;
}
ConvertPropVariantToShortString(prop, dest);
}
void ConvertPropertyToString2(UString &dest, const PROPVARIANT &prop, PROPID propID, int level)
{
if (prop.vt == VT_BSTR)
{
dest.SetFromBstr(prop.bstrVal);
return;
}
char temp[64];
ConvertPropertyToShortString2(temp, prop, propID, level);
dest = temp;
}
#ifndef Z7_SFX
static inline void AddHexToString(AString &res, unsigned v)
{
res.Add_Char((char)GET_HEX_CHAR_UPPER(v >> 4));
res.Add_Char((char)GET_HEX_CHAR_UPPER(v & 15));
}
/*
static AString Data_To_Hex(const Byte *data, size_t size)
{
AString s;
for (size_t i = 0; i < size; i++)
AddHexToString(s, data[i]);
return s;
}
*/
static const char * const sidNames[] =
{
"0"
, "Dialup"
, "Network"
, "Batch"
, "Interactive"
, "Logon" // S-1-5-5-X-Y
, "Service"
, "Anonymous"
, "Proxy"
, "EnterpriseDC"
, "Self"
, "AuthenticatedUsers"
, "RestrictedCode"
, "TerminalServer"
, "RemoteInteractiveLogon"
, "ThisOrganization"
, "16"
, "IUserIIS"
, "LocalSystem"
, "LocalService"
, "NetworkService"
, "Domains"
};
struct CSecID2Name
{
UInt32 n;
const char *sz;
};
static int FindPairIndex(const CSecID2Name * pairs, unsigned num, UInt32 id)
{
for (unsigned i = 0; i < num; i++)
if (pairs[i].n == id)
return (int)i;
return -1;
}
static const CSecID2Name sid_32_Names[] =
{
{ 544, "Administrators" },
{ 545, "Users" },
{ 546, "Guests" },
{ 547, "PowerUsers" },
{ 548, "AccountOperators" },
{ 549, "ServerOperators" },
{ 550, "PrintOperators" },
{ 551, "BackupOperators" },
{ 552, "Replicators" },
{ 553, "Backup Operators" },
{ 554, "PreWindows2000CompatibleAccess" },
{ 555, "RemoteDesktopUsers" },
{ 556, "NetworkConfigurationOperators" },
{ 557, "IncomingForestTrustBuilders" },
{ 558, "PerformanceMonitorUsers" },
{ 559, "PerformanceLogUsers" },
{ 560, "WindowsAuthorizationAccessGroup" },
{ 561, "TerminalServerLicenseServers" },
{ 562, "DistributedCOMUsers" },
{ 569, "CryptographicOperators" },
{ 573, "EventLogReaders" },
{ 574, "CertificateServiceDCOMAccess" }
};
static const CSecID2Name sid_21_Names[] =
{
{ 500, "Administrator" },
{ 501, "Guest" },
{ 502, "KRBTGT" },
{ 512, "DomainAdmins" },
{ 513, "DomainUsers" },
{ 515, "DomainComputers" },
{ 516, "DomainControllers" },
{ 517, "CertPublishers" },
{ 518, "SchemaAdmins" },
{ 519, "EnterpriseAdmins" },
{ 520, "GroupPolicyCreatorOwners" },
{ 553, "RASandIASServers" },
{ 553, "RASandIASServers" },
{ 571, "AllowedRODCPasswordReplicationGroup" },
{ 572, "DeniedRODCPasswordReplicationGroup" }
};
struct CServicesToName
{
UInt32 n[5];
const char *sz;
};
static const CServicesToName services_to_name[] =
{
{ { 0x38FB89B5, 0xCBC28419, 0x6D236C5C, 0x6E770057, 0x876402C0 } , "TrustedInstaller" }
};
static void ParseSid(AString &s, const Byte *p, size_t lim /* , unsigned &sidSize */)
{
// sidSize = 0;
if (lim < 8)
{
s += "ERROR";
return;
}
if (p[0] != 1) // rev
{
s += "UNSUPPORTED";
return;
}
const unsigned num = p[1];
const unsigned sidSize_Loc = 8 + num * 4;
if (sidSize_Loc > lim)
{
s += "ERROR";
return;
}
// sidSize = sidSize_Loc;
const UInt32 authority = GetBe32(p + 4);
if (p[2] == 0 && p[3] == 0 && authority == 5 && num >= 1)
{
const UInt32 v0 = Get32(p + 8);
if (v0 < Z7_ARRAY_SIZE(sidNames))
{
s += sidNames[v0];
return;
}
if (v0 == 32 && num == 2)
{
const UInt32 v1 = Get32(p + 12);
const int index = FindPairIndex(sid_32_Names, Z7_ARRAY_SIZE(sid_32_Names), v1);
if (index >= 0)
{
s += sid_32_Names[(unsigned)index].sz;
return;
}
}
if (v0 == 21 && num == 5)
{
UInt32 v4 = Get32(p + 8 + 4 * 4);
const int index = FindPairIndex(sid_21_Names, Z7_ARRAY_SIZE(sid_21_Names), v4);
if (index >= 0)
{
s += sid_21_Names[(unsigned)index].sz;
return;
}
}
if (v0 == 80 && num == 6)
{
for (unsigned i = 0; i < Z7_ARRAY_SIZE(services_to_name); i++)
{
const CServicesToName &sn = services_to_name[i];
int j;
for (j = 0; j < 5 && sn.n[j] == Get32(p + 8 + 4 + j * 4); j++);
if (j == 5)
{
s += sn.sz;
return;
}
}
}
}
s += "S-1-";
if (p[2] == 0 && p[3] == 0)
s.Add_UInt32(authority);
else
{
s += "0x";
for (int i = 2; i < 8; i++)
AddHexToString(s, p[i]);
}
for (UInt32 i = 0; i < num; i++)
{
s.Add_Minus();
s.Add_UInt32(Get32(p + 8 + i * 4));
}
}
static void ParseOwner(AString &s, const Byte *p, size_t size, UInt32 pos)
{
if (pos > size)
{
s += "ERROR";
return;
}
// unsigned sidSize = 0;
ParseSid(s, p + pos, size - pos /* , sidSize */);
}
static void ParseAcl(AString &s, const Byte *p, size_t size, const char *strName, UInt32 flags, UInt32 offset)
{
const unsigned control = Get16(p + 2);
if ((flags & control) == 0)
return;
const UInt32 pos = Get32(p + offset);
s.Add_Space();
s += strName;
if (pos >= size)
return;
p += pos;
size -= (size_t)pos;
if (size < 8)
return;
if (Get16(p) != 2) // revision
return;
const UInt32 num = Get32(p + 4);
s.Add_UInt32(num);
/*
UInt32 aclSize = Get16(p + 2);
if (num >= (1 << 16))
return;
if (aclSize > size)
return;
size = aclSize;
size -= 8;
p += 8;
for (UInt32 i = 0 ; i < num; i++)
{
if (size <= 8)
return;
// Byte type = p[0];
// Byte flags = p[1];
// UInt32 aceSize = Get16(p + 2);
// UInt32 mask = Get32(p + 4);
p += 8;
size -= 8;
UInt32 sidSize = 0;
s.Add_Space();
ParseSid(s, p, size, sidSize);
if (sidSize == 0)
return;
p += sidSize;
size -= sidSize;
}
// the tail can contain zeros. So (size != 0) is not ERROR
// if (size != 0) s += " ERROR";
*/
}
/*
#define MY_SE_OWNER_DEFAULTED (0x0001)
#define MY_SE_GROUP_DEFAULTED (0x0002)
*/
#define MY_SE_DACL_PRESENT (0x0004)
/*
#define MY_SE_DACL_DEFAULTED (0x0008)
*/
#define MY_SE_SACL_PRESENT (0x0010)
/*
#define MY_SE_SACL_DEFAULTED (0x0020)
#define MY_SE_DACL_AUTO_INHERIT_REQ (0x0100)
#define MY_SE_SACL_AUTO_INHERIT_REQ (0x0200)
#define MY_SE_DACL_AUTO_INHERITED (0x0400)
#define MY_SE_SACL_AUTO_INHERITED (0x0800)
#define MY_SE_DACL_PROTECTED (0x1000)
#define MY_SE_SACL_PROTECTED (0x2000)
#define MY_SE_RM_CONTROL_VALID (0x4000)
#define MY_SE_SELF_RELATIVE (0x8000)
*/
void ConvertNtSecureToString(const Byte *data, size_t size, AString &s)
{
s.Empty();
if (size < 20 || size > (1 << 18))
{
s += "ERROR";
return;
}
if (Get16(data) != 1) // revision
{
s += "UNSUPPORTED";
return;
}
ParseOwner(s, data, size, Get32(data + 4));
s.Add_Space();
ParseOwner(s, data, size, Get32(data + 8));
ParseAcl(s, data, size, "s:", MY_SE_SACL_PRESENT, 12);
ParseAcl(s, data, size, "d:", MY_SE_DACL_PRESENT, 16);
s.Add_Space();
s.Add_UInt32((UInt32)size);
// s.Add_LF();
// s += Data_To_Hex(data, size);
}
#ifdef _WIN32
static bool CheckSid(const Byte *data, size_t size, UInt32 pos) throw()
{
if (pos >= size)
return false;
size -= pos;
if (size < 8)
return false;
if (data[pos] != 1) // rev
return false;
const unsigned num = data[pos + 1];
return (8 + num * 4 <= size);
}
static bool CheckAcl(const Byte *p, size_t size, UInt32 flags, size_t offset) throw()
{
const unsigned control = Get16(p + 2);
if ((flags & control) == 0)
return true;
const UInt32 pos = Get32(p + offset);
if (pos >= size)
return false;
p += pos;
size -= pos;
if (size < 8)
return false;
const unsigned aclSize = Get16(p + 2);
return (aclSize <= size);
}
bool CheckNtSecure(const Byte *data, size_t size) throw()
{
if (size < 20)
return false;
if (Get16(data) != 1) // revision
return true; // windows function can handle such error, so we allow it
if (size > (1 << 18))
return false;
if (!CheckSid(data, size, Get32(data + 4))) return false;
if (!CheckSid(data, size, Get32(data + 8))) return false;
if (!CheckAcl(data, size, MY_SE_SACL_PRESENT, 12)) return false;
if (!CheckAcl(data, size, MY_SE_DACL_PRESENT, 16)) return false;
return true;
}
#endif
// IO_REPARSE_TAG_*
static const CSecID2Name k_ReparseTags[] =
{
{ 0xA0000003, "MOUNT_POINT" },
{ 0xC0000004, "HSM" },
{ 0x80000005, "DRIVE_EXTENDER" },
{ 0x80000006, "HSM2" },
{ 0x80000007, "SIS" },
{ 0x80000008, "WIM" },
{ 0x80000009, "CSV" },
{ 0x8000000A, "DFS" },
{ 0x8000000B, "FILTER_MANAGER" },
{ 0xA000000C, "SYMLINK" },
{ 0xA0000010, "IIS_CACHE" },
{ 0x80000012, "DFSR" },
{ 0x80000013, "DEDUP" },
{ 0xC0000014, "APPXSTRM" },
{ 0x80000014, "NFS" },
{ 0x80000015, "FILE_PLACEHOLDER" },
{ 0x80000016, "DFM" },
{ 0x80000017, "WOF" },
{ 0x80000018, "WCI" },
{ 0x8000001B, "APPEXECLINK" },
{ 0xA000001D, "LX_SYMLINK" },
{ 0x80000023, "AF_UNIX" },
{ 0x80000024, "LX_FIFO" },
{ 0x80000025, "LX_CHR" },
{ 0x80000026, "LX_BLK" }
};
bool ConvertNtReparseToString(const Byte *data, size_t size, UString &s)
{
s.Empty();
NFile::CReparseAttr attr;
if (attr.Parse(data, size))
{
if (attr.IsSymLink_WSL())
{
s += "WSL: ";
s += attr.GetPath();
}
else
{
if (!attr.IsSymLink_Win())
s += "Junction: ";
s += attr.GetPath();
if (s.IsEmpty())
s += "Link: ";
if (!attr.IsOkNamePair())
{
s += " : ";
s += attr.PrintName;
}
}
if (attr.MinorError)
s += " : MINOR_ERROR";
return true;
// s.Add_Space(); // for debug
}
if (size < 8)
return false;
const UInt32 tag = Get32(data);
const UInt32 len = Get16(data + 4);
if (len + 8 > size)
return false;
if (Get16(data + 6) != 0) // padding
return false;
/*
#define my_IO_REPARSE_TAG_DEDUP (0x80000013L)
if (tag == my_IO_REPARSE_TAG_DEDUP)
{
}
*/
{
const int index = FindPairIndex(k_ReparseTags, Z7_ARRAY_SIZE(k_ReparseTags), tag);
if (index >= 0)
s += k_ReparseTags[(unsigned)index].sz;
else
{
s += "REPARSE:";
char hex[16];
ConvertUInt32ToHex8Digits(tag, hex);
s += hex;
}
}
s.Add_Colon();
s.Add_UInt32(len);
if (len != 0)
{
s.Add_Space();
data += 8;
for (UInt32 i = 0; i < len; i++)
{
if (i >= 16)
{
s += "...";
break;
}
const unsigned b = data[i];
s.Add_Char((char)GET_HEX_CHAR_UPPER(b >> 4));
s.Add_Char((char)GET_HEX_CHAR_UPPER(b & 15));
}
}
return true;
}
#endif
@@ -0,0 +1,18 @@
// PropIDUtils.h
#ifndef ZIP7_INC_PROPID_UTILS_H
#define ZIP7_INC_PROPID_UTILS_H
#include "../../../Common/MyString.h"
// provide at least 64 bytes for buffer including zero-end
void ConvertPropertyToShortString2(char *dest, const PROPVARIANT &propVariant, PROPID propID, int level = 0) throw();
void ConvertPropertyToString2(UString &dest, const PROPVARIANT &propVariant, PROPID propID, int level = 0);
bool ConvertNtReparseToString(const Byte *data, size_t size, UString &s);
void ConvertNtSecureToString(const Byte *data, size_t size, AString &s);
bool CheckNtSecure(const Byte *data, size_t size) throw();
void ConvertWinAttribToString(char *s, UInt32 wa) throw();
#endif
@@ -0,0 +1,14 @@
// Property.h
#ifndef ZIP7_INC_7Z_PROPERTY_H
#define ZIP7_INC_7Z_PROPERTY_H
#include "../../../Common/MyString.h"
struct CProperty
{
UString Name;
UString Value;
};
#endif
@@ -0,0 +1,88 @@
// SetProperties.cpp
#include "StdAfx.h"
#include "../../../Common/MyCom.h"
#include "../../../Common/MyString.h"
#include "../../../Common/StringToInt.h"
#include "../../../Windows/PropVariant.h"
#include "../../Archive/IArchive.h"
#include "SetProperties.h"
using namespace NWindows;
using namespace NCOM;
static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
{
const wchar_t *end;
const UInt64 result = ConvertStringToUInt64(s, &end);
if (*end != 0 || s.IsEmpty())
prop = s;
else if (result <= (UInt32)0xFFFFFFFF)
prop = (UInt32)result;
else
prop = result;
}
struct CPropPropetiesVector
{
CPropVariant *values;
CPropPropetiesVector(unsigned num)
{
values = new CPropVariant[num];
}
~CPropPropetiesVector()
{
delete []values;
}
};
HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties)
{
if (properties.IsEmpty())
return S_OK;
Z7_DECL_CMyComPtr_QI_FROM(
ISetProperties,
setProperties, unknown)
if (!setProperties)
return S_OK;
UStringVector realNames;
CPropPropetiesVector values(properties.Size());
{
unsigned i;
for (i = 0; i < properties.Size(); i++)
{
const CProperty &property = properties[i];
NCOM::CPropVariant propVariant;
UString name = property.Name;
if (property.Value.IsEmpty())
{
if (!name.IsEmpty())
{
const wchar_t c = name.Back();
if (c == L'-')
propVariant = false;
else if (c == L'+')
propVariant = true;
if (propVariant.vt != VT_EMPTY)
name.DeleteBack();
}
}
else
ParseNumberString(property.Value, propVariant);
realNames.Add(name);
values.values[i] = propVariant;
}
CRecordVector<const wchar_t *> names;
for (i = 0; i < realNames.Size(); i++)
names.Add((const wchar_t *)realNames[i]);
return setProperties->SetProperties(names.ConstData(), values.values, names.Size());
}
}
@@ -0,0 +1,10 @@
// SetProperties.h
#ifndef ZIP7_INC_SETPROPERTIES_H
#define ZIP7_INC_SETPROPERTIES_H
#include "Property.h"
HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties);
#endif
@@ -0,0 +1,25 @@
// SortUtils.cpp
#include "StdAfx.h"
#include "../../../Common/Wildcard.h"
#include "SortUtils.h"
static int CompareStrings(const unsigned *p1, const unsigned *p2, void *param)
{
const UStringVector &strings = *(const UStringVector *)param;
return CompareFileNames(strings[*p1], strings[*p2]);
}
void SortFileNames(const UStringVector &strings, CUIntVector &indices)
{
const unsigned numItems = strings.Size();
indices.ClearAndSetSize(numItems);
if (numItems == 0)
return;
unsigned *vals = &indices[0];
for (unsigned i = 0; i < numItems; i++)
vals[i] = i;
indices.Sort(CompareStrings, (void *)&strings);
}
@@ -0,0 +1,10 @@
// SortUtils.h
#ifndef ZIP7_INC_SORT_UTLS_H
#define ZIP7_INC_SORT_UTLS_H
#include "../../../Common/MyString.h"
void SortFileNames(const UStringVector &strings, CUIntVector &indices);
#endif
@@ -0,0 +1,11 @@
// StdAfx.h
#ifndef ZIP7_INC_STDAFX_H
#define ZIP7_INC_STDAFX_H
#if defined(_MSC_VER) && _MSC_VER >= 1800
#pragma warning(disable : 4464) // relative include path contains '..'
#endif
#include "../../../Common/Common.h"
#endif
@@ -0,0 +1,20 @@
// TempFiles.cpp
#include "StdAfx.h"
#include "../../../Windows/FileDir.h"
#include "TempFiles.h"
using namespace NWindows;
using namespace NFile;
void CTempFiles::Clear()
{
while (!Paths.IsEmpty())
{
if (NeedDeleteFiles)
NDir::DeleteFileAlways(Paths.Back());
Paths.DeleteBack();
}
}
@@ -0,0 +1,19 @@
// TempFiles.h
#ifndef ZIP7_INC_TEMP_FILES_H
#define ZIP7_INC_TEMP_FILES_H
#include "../../../Common/MyString.h"
class CTempFiles
{
void Clear();
public:
FStringVector Paths;
bool NeedDeleteFiles;
CTempFiles(): NeedDeleteFiles(true) {}
~CTempFiles() { Clear(); }
};
#endif
File diff suppressed because it is too large Load Diff
+221
View File
@@ -0,0 +1,221 @@
// Update.h
#ifndef ZIP7_INC_COMMON_UPDATE_H
#define ZIP7_INC_COMMON_UPDATE_H
#include "../../../Common/Wildcard.h"
#include "ArchiveOpenCallback.h"
#include "LoadCodecs.h"
#include "OpenArchive.h"
#include "Property.h"
#include "UpdateAction.h"
#include "UpdateCallback.h"
enum EArcNameMode
{
k_ArcNameMode_Smart,
k_ArcNameMode_Exact,
k_ArcNameMode_Add
};
struct CArchivePath
{
UString OriginalPath;
UString Prefix; // path(folder) prefix including slash
UString Name; // base name
UString BaseExtension; // archive type extension or "exe" extension
UString VolExtension; // archive type extension for volumes
bool Temp;
FString TempPrefix; // path(folder) for temp location
FString TempPostfix;
CArchivePath(): Temp(false) {}
void ParseFromPath(const UString &path, EArcNameMode mode);
UString GetPathWithoutExt() const { return Prefix + Name; }
UString GetFinalPath() const;
UString GetFinalVolPath() const;
FString GetTempPath() const;
};
struct CUpdateArchiveCommand
{
UString UserArchivePath;
CArchivePath ArchivePath;
NUpdateArchive::CActionSet ActionSet;
};
struct CCompressionMethodMode
{
bool Type_Defined;
COpenType Type;
CObjectVector<CProperty> Properties;
CCompressionMethodMode(): Type_Defined(false) {}
};
namespace NRecursedType { enum EEnum
{
kRecursed,
kWildcardOnlyRecursed,
kNonRecursed
};}
struct CRenamePair
{
UString OldName;
UString NewName;
bool WildcardParsing;
NRecursedType::EEnum RecursedType;
CRenamePair(): WildcardParsing(true), RecursedType(NRecursedType::kNonRecursed) {}
bool Prepare();
bool GetNewPath(bool isFolder, const UString &src, UString &dest) const;
};
struct CUpdateOptions
{
bool UpdateArchiveItself;
bool SfxMode;
bool PreserveATime;
bool OpenShareForWrite;
bool StopAfterOpenError;
bool StdInMode;
bool StdOutMode;
bool EMailMode;
bool EMailRemoveAfter;
bool DeleteAfterCompressing;
bool SetArcMTime;
bool RenameMode;
CBoolPair NtSecurity;
CBoolPair AltStreams;
CBoolPair HardLinks;
CBoolPair SymLinks;
CBoolPair StoreOwnerId;
CBoolPair StoreOwnerName;
EArcNameMode ArcNameMode;
NWildcard::ECensorPathMode PathMode;
CCompressionMethodMode MethodMode;
CObjectVector<CUpdateArchiveCommand> Commands;
CArchivePath ArchivePath;
FString SfxModule;
UString StdInFileName;
UString EMailAddress;
FString WorkingDir;
// UString AddPathPrefix;
CObjectVector<CRenamePair> RenamePairs;
CRecordVector<UInt64> VolumesSizes;
bool InitFormatIndex(const CCodecs *codecs, const CObjectVector<COpenType> &types, const UString &arcPath);
bool SetArcPath(const CCodecs *codecs, const UString &arcPath);
CUpdateOptions():
UpdateArchiveItself(true),
SfxMode(false),
PreserveATime(false),
OpenShareForWrite(false),
StopAfterOpenError(false),
StdInMode(false),
StdOutMode(false),
EMailMode(false),
EMailRemoveAfter(false),
DeleteAfterCompressing(false),
SetArcMTime(false),
RenameMode(false),
ArcNameMode(k_ArcNameMode_Smart),
PathMode(NWildcard::k_RelatPath)
{}
void SetActionCommand_Add()
{
Commands.Clear();
CUpdateArchiveCommand c;
c.ActionSet = NUpdateArchive::k_ActionSet_Add;
Commands.Add(c);
}
};
struct CUpdateErrorInfo
{
DWORD SystemError; // it's DWORD (WRes) only;
AString Message;
FStringVector FileNames;
bool ThereIsError() const { return SystemError != 0 || !Message.IsEmpty() || !FileNames.IsEmpty(); }
HRESULT Get_HRESULT_Error() const { return SystemError == 0 ? E_FAIL : HRESULT_FROM_WIN32(SystemError); }
void SetFromLastError(const char *message);
HRESULT SetFromLastError(const char *message, const FString &fileName);
HRESULT SetFromError_DWORD(const char *message, const FString &fileName, DWORD error);
CUpdateErrorInfo(): SystemError(0) {}
};
struct CFinishArchiveStat
{
UInt64 OutArcFileSize;
unsigned NumVolumes;
bool IsMultiVolMode;
CFinishArchiveStat(): OutArcFileSize(0), NumVolumes(0), IsMultiVolMode(false) {}
};
Z7_PURE_INTERFACES_BEGIN
// INTERFACE_IUpdateCallbackUI(x)
// INTERFACE_IDirItemsCallback(x)
#define Z7_IFACEN_IUpdateCallbackUI2(x) \
virtual HRESULT OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) x \
virtual HRESULT StartScanning() x \
virtual HRESULT FinishScanning(const CDirItemsStat &st) x \
virtual HRESULT StartOpenArchive(const wchar_t *name) x \
virtual HRESULT StartArchive(const wchar_t *name, bool updating) x \
virtual HRESULT FinishArchive(const CFinishArchiveStat &st) x \
virtual HRESULT DeletingAfterArchiving(const FString &path, bool isDir) x \
virtual HRESULT FinishDeletingAfterArchiving() x \
virtual HRESULT MoveArc_Start(const wchar_t *srcTempPath, const wchar_t *destFinalPath, UInt64 size, Int32 updateMode) x \
virtual HRESULT MoveArc_Progress(UInt64 total, UInt64 current) x \
virtual HRESULT MoveArc_Finish() x \
DECLARE_INTERFACE(IUpdateCallbackUI2):
public IUpdateCallbackUI,
public IDirItemsCallback
{
Z7_IFACE_PURE(IUpdateCallbackUI2)
};
Z7_PURE_INTERFACES_END
HRESULT UpdateArchive(
CCodecs *codecs,
const CObjectVector<COpenType> &types,
const UString &cmdArcPath2,
NWildcard::CCensor &censor,
CUpdateOptions &options,
CUpdateErrorInfo &errorInfo,
IOpenCallbackUI *openCallback,
IUpdateCallbackUI2 *callback,
bool needSetPath);
#endif
@@ -0,0 +1,64 @@
// UpdateAction.cpp
#include "StdAfx.h"
#include "UpdateAction.h"
namespace NUpdateArchive {
const CActionSet k_ActionSet_Add =
{{
NPairAction::kCopy,
NPairAction::kCopy,
NPairAction::kCompress,
NPairAction::kCompress,
NPairAction::kCompress,
NPairAction::kCompress,
NPairAction::kCompress
}};
const CActionSet k_ActionSet_Update =
{{
NPairAction::kCopy,
NPairAction::kCopy,
NPairAction::kCompress,
NPairAction::kCopy,
NPairAction::kCompress,
NPairAction::kCopy,
NPairAction::kCompress
}};
const CActionSet k_ActionSet_Fresh =
{{
NPairAction::kCopy,
NPairAction::kCopy,
NPairAction::kIgnore,
NPairAction::kCopy,
NPairAction::kCompress,
NPairAction::kCopy,
NPairAction::kCompress
}};
const CActionSet k_ActionSet_Sync =
{{
NPairAction::kCopy,
NPairAction::kIgnore,
NPairAction::kCompress,
NPairAction::kCopy,
NPairAction::kCompress,
NPairAction::kCopy,
NPairAction::kCompress,
}};
const CActionSet k_ActionSet_Delete =
{{
NPairAction::kCopy,
NPairAction::kIgnore,
NPairAction::kIgnore,
NPairAction::kIgnore,
NPairAction::kIgnore,
NPairAction::kIgnore,
NPairAction::kIgnore
}};
}
@@ -0,0 +1,66 @@
// UpdateAction.h
#ifndef ZIP7_INC_UPDATE_ACTION_H
#define ZIP7_INC_UPDATE_ACTION_H
namespace NUpdateArchive {
namespace NPairState
{
const unsigned kNumValues = 7;
enum EEnum
{
kNotMasked = 0,
kOnlyInArchive,
kOnlyOnDisk,
kNewInArchive,
kOldInArchive,
kSameFiles,
kUnknowNewerFiles
};
}
namespace NPairAction
{
enum EEnum
{
kIgnore = 0,
kCopy,
kCompress,
kCompressAsAnti
};
}
struct CActionSet
{
NPairAction::EEnum StateActions[NPairState::kNumValues];
bool IsEqualTo(const CActionSet &a) const
{
for (unsigned i = 0; i < NPairState::kNumValues; i++)
if (StateActions[i] != a.StateActions[i])
return false;
return true;
}
bool NeedScanning() const
{
unsigned i;
for (i = 0; i < NPairState::kNumValues; i++)
if (StateActions[i] == NPairAction::kCompress)
return true;
for (i = 1; i < NPairState::kNumValues; i++)
if (StateActions[i] != NPairAction::kIgnore)
return true;
return false;
}
};
extern const CActionSet k_ActionSet_Add;
extern const CActionSet k_ActionSet_Update;
extern const CActionSet k_ActionSet_Fresh;
extern const CActionSet k_ActionSet_Sync;
extern const CActionSet k_ActionSet_Delete;
}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,197 @@
// UpdateCallback.h
#ifndef ZIP7_INC_UPDATE_CALLBACK_H
#define ZIP7_INC_UPDATE_CALLBACK_H
#include "../../../Common/MyCom.h"
#include "../../Common/FileStreams.h"
#include "../../IPassword.h"
#include "../../ICoder.h"
#include "../Common/UpdatePair.h"
#include "../Common/UpdateProduce.h"
#include "OpenArchive.h"
struct CArcToDoStat
{
CDirItemsStat2 NewData;
CDirItemsStat2 OldData;
CDirItemsStat2 DeleteData;
UInt64 Get_NumDataItems_Total() const
{
return NewData.Get_NumDataItems2() + OldData.Get_NumDataItems2();
}
};
Z7_PURE_INTERFACES_BEGIN
#define Z7_IFACEN_IUpdateCallbackUI(x) \
virtual HRESULT WriteSfx(const wchar_t *name, UInt64 size) x \
virtual HRESULT SetTotal(UInt64 size) x \
virtual HRESULT SetCompleted(const UInt64 *completeValue) x \
virtual HRESULT SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) x \
virtual HRESULT CheckBreak() x \
/* virtual HRESULT Finalize() x */ \
virtual HRESULT SetNumItems(const CArcToDoStat &stat) x \
virtual HRESULT GetStream(const wchar_t *name, bool isDir, bool isAnti, UInt32 mode) x \
virtual HRESULT OpenFileError(const FString &path, DWORD systemError) x \
virtual HRESULT ReadingFileError(const FString &path, DWORD systemError) x \
virtual HRESULT SetOperationResult(Int32 opRes) x \
virtual HRESULT ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name) x \
virtual HRESULT ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir) x \
/* virtual HRESULT SetPassword(const UString &password) x */ \
virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x \
virtual HRESULT CryptoGetTextPassword(BSTR *password) x \
virtual HRESULT ShowDeleteFile(const wchar_t *name, bool isDir) x \
/*
virtual HRESULT ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value) x \
virtual HRESULT ReportRawProp(UInt32 indexType, UInt32 index, PROPID propID, const void *data, UInt32 dataSize, UInt32 propType) x \
virtual HRESULT ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes) x \
*/
/* virtual HRESULT CloseProgress() { return S_OK; } */
Z7_IFACE_DECL_PURE(IUpdateCallbackUI)
Z7_PURE_INTERFACES_END
struct CKeyKeyValPair
{
UInt64 Key1;
UInt64 Key2;
unsigned Value;
int Compare(const CKeyKeyValPair &a) const
{
if (Key1 < a.Key1) return -1;
if (Key1 > a.Key1) return 1;
return MyCompare(Key2, a.Key2);
}
};
class CArchiveUpdateCallback Z7_final:
public IArchiveUpdateCallback2,
public IArchiveUpdateCallbackFile,
// public IArchiveUpdateCallbackArcProp,
public IArchiveExtractCallbackMessage2,
public IArchiveGetRawProps,
public IArchiveGetRootProps,
public ICryptoGetTextPassword2,
public ICryptoGetTextPassword,
public ICompressProgressInfo,
public IInFileStream_Callback,
public CMyUnknownImp
{
Z7_COM_QI_BEGIN2(IArchiveUpdateCallback2)
Z7_COM_QI_ENTRY(IArchiveUpdateCallbackFile)
// Z7_COM_QI_ENTRY(IArchiveUpdateCallbackArcProp)
Z7_COM_QI_ENTRY(IArchiveExtractCallbackMessage2)
Z7_COM_QI_ENTRY(IArchiveGetRawProps)
Z7_COM_QI_ENTRY(IArchiveGetRootProps)
Z7_COM_QI_ENTRY(ICryptoGetTextPassword2)
Z7_COM_QI_ENTRY(ICryptoGetTextPassword)
Z7_COM_QI_ENTRY(ICompressProgressInfo)
Z7_COM_QI_END
Z7_COM_ADDREF_RELEASE
Z7_IFACE_COM7_IMP(ICompressProgressInfo)
Z7_IFACE_COM7_IMP(IProgress)
Z7_IFACE_COM7_IMP(IArchiveUpdateCallback)
Z7_IFACE_COM7_IMP(IArchiveUpdateCallback2)
Z7_IFACE_COM7_IMP(IArchiveUpdateCallbackFile)
// Z7_IFACE_COM7_IMP(IArchiveUpdateCallbackArcProp)
Z7_IFACE_COM7_IMP(IArchiveExtractCallbackMessage2)
Z7_IFACE_COM7_IMP(IArchiveGetRawProps)
Z7_IFACE_COM7_IMP(IArchiveGetRootProps)
Z7_IFACE_COM7_IMP(ICryptoGetTextPassword2)
Z7_IFACE_COM7_IMP(ICryptoGetTextPassword)
void UpdateProcessedItemStatus(unsigned dirIndex);
public:
bool PreserveATime;
bool ShareForWrite;
bool StopAfterOpenError;
bool StdInMode;
bool KeepOriginalItemNames;
bool StoreNtSecurity;
bool StoreHardLinks;
bool StoreSymLinks;
bool StoreOwnerId;
bool StoreOwnerName;
bool Need_LatestMTime;
bool LatestMTime_Defined;
/*
bool Need_ArcMTime_Report;
bool ArcMTime_WasReported;
*/
CRecordVector<UInt32> _openFiles_Indexes;
FStringVector _openFiles_Paths;
// CRecordVector< CInFileStream* > _openFiles_Streams;
bool AreAllFilesClosed() const { return _openFiles_Indexes.IsEmpty(); }
virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error) Z7_override;
virtual void InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val) Z7_override;
IUpdateCallbackUI *Callback;
const CDirItems *DirItems;
const CDirItem *ParentDirItem;
const CArc *Arc;
CMyComPtr<IInArchive> Archive;
const CObjectVector<CArcItem> *ArcItems;
const CRecordVector<CUpdatePair2> *UpdatePairs;
CRecordVector<UInt64> VolumesSizes;
FString VolName;
FString VolExt;
UString ArcFileName; // without path prefix
const UStringVector *NewNames;
const UString *Comment;
int CommentIndex;
/*
CArcTime Reported_ArcMTime;
*/
CFiTime LatestMTime;
Byte *ProcessedItemsStatuses;
CArchiveUpdateCallback();
bool IsDir(const CUpdatePair2 &up) const
{
if (up.DirIndex >= 0)
return DirItems->Items[(unsigned)up.DirIndex].IsDir();
else if (up.ArcIndex >= 0)
return (*ArcItems)[(unsigned)up.ArcIndex].IsDir;
return false;
}
private:
#if defined(_WIN32) && !defined(UNDER_CE)
bool _saclEnabled;
#endif
CRecordVector<CKeyKeyValPair> _map;
UInt32 _hardIndex_From;
UInt32 _hardIndex_To;
};
#endif
@@ -0,0 +1,302 @@
// UpdatePair.cpp
#include "StdAfx.h"
#include <time.h>
// #include <stdio.h>
#include "../../../Common/Wildcard.h"
#include "../../../Windows/TimeUtils.h"
#include "SortUtils.h"
#include "UpdatePair.h"
using namespace NWindows;
using namespace NTime;
/*
a2.Prec =
{
0 (k_PropVar_TimePrec_0):
if GetProperty(kpidMTime) returned 0 and
GetProperty(kpidTimeType) did not returned VT_UI4.
7z, wim, tar in 7-Zip before v21)
in that case we use
(prec) that is set by IOutArchive::GetFileTimeType()
}
*/
static int MyCompareTime(unsigned prec, const CFiTime &f1, const CArcTime &a2)
{
// except of precision, we also have limitation, when timestamp is out of range
/* if (Prec) in archive item is defined, then use global (prec) */
if (a2.Prec != k_PropVar_TimePrec_0)
prec = a2.Prec;
CArcTime a1;
a1.Set_From_FiTime(f1);
/* Set_From_FiTime() must set full form precision:
k_PropVar_TimePrec_Base + numDigits
windows: 7 digits, non-windows: 9 digits */
if (prec == k_PropVar_TimePrec_DOS)
{
const UInt32 dosTime1 = a1.Get_DosTime();
const UInt32 dosTime2 = a2.Get_DosTime();
return MyCompare(dosTime1, dosTime2);
}
if (prec == k_PropVar_TimePrec_Unix)
{
const Int64 u2 = FileTime_To_UnixTime64(a2.FT);
if (u2 == 0 || u2 == (UInt32)0xFFFFFFFF)
{
// timestamp probably was saturated in archive to 32-bit
// so we use saturated 32-bit value for disk file too.
UInt32 u1;
FileTime_To_UnixTime(a1.FT, u1);
const UInt32 u2_32 = (UInt32)u2;
return MyCompare(u1, u2_32);
}
const Int64 u1 = FileTime_To_UnixTime64(a1.FT);
return MyCompare(u1, u2);
// prec = k_PropVar_TimePrec_Base; // for debug
}
if (prec == k_PropVar_TimePrec_0)
prec = k_PropVar_TimePrec_Base + 7;
else if (prec == k_PropVar_TimePrec_HighPrec)
prec = k_PropVar_TimePrec_Base + 9;
else if (prec < k_PropVar_TimePrec_Base)
prec = k_PropVar_TimePrec_Base;
else if (prec > k_PropVar_TimePrec_Base + 9)
prec = k_PropVar_TimePrec_Base + 7;
// prec now is full form: k_PropVar_TimePrec_Base + numDigits;
if (prec > a1.Prec && a1.Prec >= k_PropVar_TimePrec_Base)
prec = a1.Prec;
const unsigned numDigits = prec - k_PropVar_TimePrec_Base;
if (numDigits >= 7)
{
const int comp = CompareFileTime(&a1.FT, &a2.FT);
if (comp != 0 || numDigits == 7)
return comp;
return MyCompare(a1.Ns100, a2.Ns100);
}
UInt32 d = 1;
for (unsigned k = numDigits; k < 7; k++)
d *= 10;
const UInt64 v1 = a1.Get_FILETIME_as_UInt64() / d * d;
const UInt64 v2 = a2.Get_FILETIME_as_UInt64() / d * d;
// printf("\ndelta=%d numDigits=%d\n", (unsigned)(v1- v2), numDigits);
return MyCompare(v1, v2);
}
static const char * const k_Duplicate_inArc_Message = "Duplicate filename in archive:";
static const char * const k_Duplicate_inDir_Message = "Duplicate filename on disk:";
static const char * const k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):";
Z7_ATTR_NORETURN
static
void ThrowError(const char *message, const UString &s1, const UString &s2)
{
UString m (message);
m.Add_LF(); m += s1;
m.Add_LF(); m += s2;
throw m;
}
static int CompareArcItemsBase(const CArcItem &ai1, const CArcItem &ai2)
{
const int res = CompareFileNames(ai1.Name, ai2.Name);
if (res != 0)
return res;
if (ai1.IsDir != ai2.IsDir)
return ai1.IsDir ? -1 : 1;
return 0;
}
static int CompareArcItems(const unsigned *p1, const unsigned *p2, void *param)
{
const unsigned i1 = *p1;
const unsigned i2 = *p2;
const CObjectVector<CArcItem> &arcItems = *(const CObjectVector<CArcItem> *)param;
const int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]);
if (res != 0)
return res;
return MyCompare(i1, i2);
}
void GetUpdatePairInfoList(
const CDirItems &dirItems,
const CObjectVector<CArcItem> &arcItems,
NFileTimeType::EEnum fileTimeType,
CRecordVector<CUpdatePair> &updatePairs)
{
CUIntVector dirIndices, arcIndices;
const unsigned numDirItems = dirItems.Items.Size();
const unsigned numArcItems = arcItems.Size();
CIntArr duplicatedArcItem(numArcItems);
{
int *vals = &duplicatedArcItem[0];
for (unsigned i = 0; i < numArcItems; i++)
vals[i] = 0;
}
{
arcIndices.ClearAndSetSize(numArcItems);
if (numArcItems != 0)
{
unsigned *vals = &arcIndices[0];
for (unsigned i = 0; i < numArcItems; i++)
vals[i] = i;
}
arcIndices.Sort(CompareArcItems, (void *)&arcItems);
for (unsigned i = 0; i + 1 < numArcItems; i++)
if (CompareArcItemsBase(
arcItems[arcIndices[i]],
arcItems[arcIndices[i + 1]]) == 0)
{
duplicatedArcItem[i] = 1;
duplicatedArcItem[i + 1] = -1;
}
}
UStringVector dirNames;
{
dirNames.ClearAndReserve(numDirItems);
unsigned i;
for (i = 0; i < numDirItems; i++)
dirNames.AddInReserved(dirItems.GetLogPath(i));
SortFileNames(dirNames, dirIndices);
for (i = 0; i + 1 < numDirItems; i++)
{
const UString &s1 = dirNames[dirIndices[i]];
const UString &s2 = dirNames[dirIndices[i + 1]];
if (CompareFileNames(s1, s2) == 0)
ThrowError(k_Duplicate_inDir_Message, s1, s2);
}
}
unsigned dirIndex = 0;
unsigned arcIndex = 0;
int prevHostFile = -1;
const UString *prevHostName = NULL;
while (dirIndex < numDirItems || arcIndex < numArcItems)
{
CUpdatePair pair;
int dirIndex2 = -1;
int arcIndex2 = -1;
const CDirItem *di = NULL;
const CArcItem *ai = NULL;
int compareResult = -1;
const UString *name = NULL;
if (dirIndex < numDirItems)
{
dirIndex2 = (int)dirIndices[dirIndex];
di = &dirItems.Items[(unsigned)dirIndex2];
}
if (arcIndex < numArcItems)
{
arcIndex2 = (int)arcIndices[arcIndex];
ai = &arcItems[(unsigned)arcIndex2];
compareResult = 1;
if (dirIndex < numDirItems)
{
compareResult = CompareFileNames(dirNames[(unsigned)dirIndex2], ai->Name);
if (compareResult == 0)
{
if (di->IsDir() != ai->IsDir)
compareResult = (ai->IsDir ? 1 : -1);
}
}
}
if (compareResult < 0)
{
name = &dirNames[(unsigned)dirIndex2];
pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
pair.DirIndex = dirIndex2;
dirIndex++;
}
else if (compareResult > 0)
{
name = &ai->Name;
pair.State = ai->Censored ?
NUpdateArchive::NPairState::kOnlyInArchive:
NUpdateArchive::NPairState::kNotMasked;
pair.ArcIndex = arcIndex2;
arcIndex++;
}
else
{
const int dupl = duplicatedArcItem[arcIndex];
if (dupl != 0)
ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[(unsigned)((int)arcIndex + dupl)]].Name);
name = &dirNames[(unsigned)dirIndex2];
if (!ai->Censored)
ThrowError(k_NotCensoredCollision_Message, *name, ai->Name);
pair.DirIndex = dirIndex2;
pair.ArcIndex = arcIndex2;
int compResult = 0;
if (ai->MTime.Def)
{
compResult = MyCompareTime((unsigned)fileTimeType, di->MTime, ai->MTime);
}
switch (compResult)
{
case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break;
case 1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break;
default:
pair.State = (ai->Size_Defined && di->Size == ai->Size) ?
NUpdateArchive::NPairState::kSameFiles :
NUpdateArchive::NPairState::kUnknowNewerFiles;
}
dirIndex++;
arcIndex++;
}
if (
#ifdef _WIN32
(di && di->IsAltStream) ||
#endif
(ai && ai->IsAltStream))
{
if (prevHostName)
{
const unsigned hostLen = prevHostName->Len();
if (name->Len() > hostLen)
if ((*name)[hostLen] == ':' && CompareFileNames(*prevHostName, name->Left(hostLen)) == 0)
pair.HostIndex = prevHostFile;
}
}
else
{
prevHostFile = (int)updatePairs.Size();
prevHostName = name;
}
updatePairs.Add(pair);
}
updatePairs.ReserveDown();
}
@@ -0,0 +1,27 @@
// UpdatePair.h
#ifndef ZIP7_INC_UPDATE_PAIR_H
#define ZIP7_INC_UPDATE_PAIR_H
#include "DirItem.h"
#include "UpdateAction.h"
#include "../../Archive/IArchive.h"
struct CUpdatePair
{
NUpdateArchive::NPairState::EEnum State;
int ArcIndex;
int DirIndex;
int HostIndex; // >= 0 for alt streams only, contains index of host pair
CUpdatePair(): ArcIndex(-1), DirIndex(-1), HostIndex(-1) {}
};
void GetUpdatePairInfoList(
const CDirItems &dirItems,
const CObjectVector<CArcItem> &arcItems,
NFileTimeType::EEnum fileTimeType,
CRecordVector<CUpdatePair> &updatePairs);
#endif
@@ -0,0 +1,74 @@
// UpdateProduce.cpp
#include "StdAfx.h"
#include "UpdateProduce.h"
using namespace NUpdateArchive;
static const char * const kUpdateActionSetCollision = "Internal collision in update action set";
void UpdateProduce(
const CRecordVector<CUpdatePair> &updatePairs,
const CActionSet &actionSet,
CRecordVector<CUpdatePair2> &operationChain,
IUpdateProduceCallback *callback)
{
FOR_VECTOR (i, updatePairs)
{
const CUpdatePair &pair = updatePairs[i];
CUpdatePair2 up2;
up2.DirIndex = pair.DirIndex;
up2.ArcIndex = pair.ArcIndex;
up2.NewData = up2.NewProps = true;
up2.UseArcProps = false;
switch ((int)actionSet.StateActions[(unsigned)pair.State])
{
case NPairAction::kIgnore:
if (pair.ArcIndex >= 0 && callback)
callback->ShowDeleteFile((unsigned)pair.ArcIndex);
continue;
case NPairAction::kCopy:
if (pair.State == NPairState::kOnlyOnDisk)
throw kUpdateActionSetCollision;
if (pair.State == NPairState::kOnlyInArchive)
{
if (pair.HostIndex >= 0)
{
/*
ignore alt stream if
1) no such alt stream in Disk
2) there is Host file in disk
*/
if (updatePairs[(unsigned)pair.HostIndex].DirIndex >= 0)
continue;
}
}
up2.NewData = up2.NewProps = false;
up2.UseArcProps = true;
break;
case NPairAction::kCompress:
if (pair.State == NPairState::kOnlyInArchive ||
pair.State == NPairState::kNotMasked)
throw kUpdateActionSetCollision;
break;
case NPairAction::kCompressAsAnti:
up2.IsAnti = true;
up2.UseArcProps = (pair.ArcIndex >= 0);
break;
default: throw 123; // break; // is unexpected case
}
up2.IsSameTime = ((unsigned)pair.State == NUpdateArchive::NPairState::kSameFiles);
operationChain.Add(up2);
}
operationChain.ReserveDown();
}
@@ -0,0 +1,60 @@
// UpdateProduce.h
#ifndef ZIP7_INC_UPDATE_PRODUCE_H
#define ZIP7_INC_UPDATE_PRODUCE_H
#include "UpdatePair.h"
struct CUpdatePair2
{
bool NewData;
bool NewProps;
bool UseArcProps; // if (UseArcProps && NewProps), we want to change only some properties.
bool IsAnti; // if (!IsAnti) we use other ways to detect Anti status
int DirIndex;
int ArcIndex;
int NewNameIndex;
bool IsMainRenameItem;
bool IsSameTime;
void SetAs_NoChangeArcItem(unsigned arcIndex) // int
{
NewData = NewProps = false;
UseArcProps = true;
IsAnti = false;
ArcIndex = (int)arcIndex;
}
bool ExistOnDisk() const { return DirIndex != -1; }
bool ExistInArchive() const { return ArcIndex != -1; }
CUpdatePair2():
NewData(false),
NewProps(false),
UseArcProps(false),
IsAnti(false),
DirIndex(-1),
ArcIndex(-1),
NewNameIndex(-1),
IsMainRenameItem(false),
IsSameTime(false)
{}
};
Z7_PURE_INTERFACES_BEGIN
DECLARE_INTERFACE(IUpdateProduceCallback)
{
virtual HRESULT ShowDeleteFile(unsigned arcIndex) = 0;
};
Z7_PURE_INTERFACES_END
void UpdateProduce(
const CRecordVector<CUpdatePair> &updatePairs,
const NUpdateArchive::CActionSet &actionSet,
CRecordVector<CUpdatePair2> &operationChain,
IUpdateProduceCallback *callback);
#endif
@@ -0,0 +1,84 @@
// WorkDir.cpp
#include "StdAfx.h"
#include "../../../Windows/FileName.h"
#include "../../../Windows/FileSystem.h"
#include "WorkDir.h"
using namespace NWindows;
using namespace NFile;
using namespace NDir;
FString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const FString &path, FString &fileName)
{
NWorkDir::NMode::EEnum mode = workDirInfo.Mode;
#if defined(_WIN32) && !defined(UNDER_CE)
if (workDirInfo.ForRemovableOnly)
{
mode = NWorkDir::NMode::kCurrent;
const FString prefix = path.Left(3);
if (NName::IsDrivePath(prefix))
{
const UINT driveType = NSystem::MyGetDriveType(prefix);
if (driveType == DRIVE_CDROM || driveType == DRIVE_REMOVABLE)
mode = workDirInfo.Mode;
}
/*
CParsedPath parsedPath;
parsedPath.ParsePath(archiveName);
UINT driveType = GetDriveType(parsedPath.Prefix);
if ((driveType != DRIVE_CDROM) && (driveType != DRIVE_REMOVABLE))
mode = NZipSettings::NWorkDir::NMode::kCurrent;
*/
}
#endif
const int pos = path.ReverseFind_PathSepar() + 1;
fileName = path.Ptr((unsigned)pos);
FString tempDir;
switch ((int)mode)
{
case NWorkDir::NMode::kCurrent:
tempDir = path.Left((unsigned)pos);
break;
case NWorkDir::NMode::kSpecified:
tempDir = workDirInfo.Path;
break;
// case NWorkDir::NMode::kSystem:
default:
if (!MyGetTempPath(tempDir))
throw 141717;
break;
}
NName::NormalizeDirPathPrefix(tempDir);
return tempDir;
}
HRESULT CWorkDirTempFile::CreateTempFile(const FString &originalPath)
{
NWorkDir::CInfo workDirInfo;
workDirInfo.Load();
FString namePart;
FString path = GetWorkDir(workDirInfo, originalPath, namePart);
CreateComplexDir(path);
path += namePart;
_outStreamSpec = new COutFileStream;
OutStream = _outStreamSpec;
if (!_tempFile.Create(path, &_outStreamSpec->File))
return GetLastError_noZero_HRESULT();
_originalPath = originalPath;
return S_OK;
}
HRESULT CWorkDirTempFile::MoveToOriginal(bool deleteOriginal,
NWindows::NFile::NDir::ICopyFileProgress *progress)
{
OutStream.Release();
if (!_tempFile.MoveTo(_originalPath, deleteOriginal, progress))
return GetLastError_noZero_HRESULT();
return S_OK;
}
@@ -0,0 +1,30 @@
// WorkDir.h
#ifndef ZIP7_INC_WORK_DIR_H
#define ZIP7_INC_WORK_DIR_H
#include "../../../Windows/FileDir.h"
#include "../../Common/FileStreams.h"
#include "ZipRegistry.h"
FString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const FString &path, FString &fileName);
class CWorkDirTempFile MY_UNCOPYABLE
{
FString _originalPath;
NWindows::NFile::NDir::CTempFile _tempFile;
COutFileStream *_outStreamSpec;
public:
CMyComPtr<IOutStream> OutStream;
const FString &Get_OriginalFilePath() const { return _originalPath; }
const FString &Get_TempFilePath() const { return _tempFile.GetPath(); }
HRESULT CreateTempFile(const FString &originalPath);
HRESULT MoveToOriginal(bool deleteOriginal,
NWindows::NFile::NDir::ICopyFileProgress *progress = NULL);
};
#endif
@@ -0,0 +1,599 @@
// ZipRegistry.cpp
#include "StdAfx.h"
#include "../../../../C/CpuArch.h"
#include "../../../Common/IntToString.h"
#include "../../../Common/StringToInt.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/Registry.h"
#include "../../../Windows/Synchronization.h"
// #include "../Explorer/ContextMenuFlags.h"
#include "ZipRegistry.h"
using namespace NWindows;
using namespace NRegistry;
static NSynchronization::CCriticalSection g_CS;
#define CS_LOCK NSynchronization::CCriticalSectionLock lock(g_CS);
static LPCTSTR const kCuPrefix = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-Zip") TEXT(STRING_PATH_SEPARATOR);
static CSysString GetKeyPath(LPCTSTR path) { return kCuPrefix + (CSysString)path; }
static LONG OpenMainKey(CKey &key, LPCTSTR keyName)
{
return key.Open(HKEY_CURRENT_USER, GetKeyPath(keyName), KEY_READ);
}
static LONG CreateMainKey(CKey &key, LPCTSTR keyName)
{
return key.Create(HKEY_CURRENT_USER, GetKeyPath(keyName));
}
static void Key_Set_UInt32(CKey &key, LPCTSTR name, UInt32 value)
{
if (value == (UInt32)(Int32)-1)
key.DeleteValue(name);
else
key.SetValue(name, value);
}
static void Key_Get_UInt32(CKey &key, LPCTSTR name, UInt32 &value)
{
value = (UInt32)(Int32)-1;
key.GetValue_UInt32_IfOk(name, value);
}
static void Key_Set_BoolPair(CKey &key, LPCTSTR name, const CBoolPair &b)
{
if (b.Def)
key.SetValue(name, b.Val);
}
static void Key_Set_bool_if_Changed(CKey &key, LPCTSTR name, bool val)
{
bool oldVal = false;
if (key.GetValue_bool_IfOk(name, oldVal) == ERROR_SUCCESS)
if (val == oldVal)
return;
key.SetValue(name, val);
}
static void Key_Set_BoolPair_Delete_IfNotDef(CKey &key, LPCTSTR name, const CBoolPair &b)
{
if (b.Def)
Key_Set_bool_if_Changed(key, name, b.Val);
else
key.DeleteValue(name);
}
static void Key_Get_BoolPair(CKey &key, LPCTSTR name, CBoolPair &b)
{
b.Val = false;
b.Def = (key.GetValue_bool_IfOk(name, b.Val) == ERROR_SUCCESS);
}
static void Key_Get_BoolPair_true(CKey &key, LPCTSTR name, CBoolPair &b)
{
b.Val = true;
b.Def = (key.GetValue_bool_IfOk(name, b.Val) == ERROR_SUCCESS);
}
namespace NExtract
{
static LPCTSTR const kKeyName = TEXT("Extraction");
static LPCTSTR const kExtractMode = TEXT("ExtractMode");
static LPCTSTR const kOverwriteMode = TEXT("OverwriteMode");
static LPCTSTR const kShowPassword = TEXT("ShowPassword");
static LPCTSTR const kPathHistory = TEXT("PathHistory");
static LPCTSTR const kSplitDest = TEXT("SplitDest");
static LPCTSTR const kElimDup = TEXT("ElimDup");
// static LPCTSTR const kAltStreams = TEXT("AltStreams");
static LPCTSTR const kNtSecur = TEXT("Security");
static LPCTSTR const kMemLimit = TEXT("MemLimit");
void CInfo::Save() const
{
CS_LOCK
CKey key;
CreateMainKey(key, kKeyName);
if (PathMode_Force)
key.SetValue(kExtractMode, (UInt32)PathMode);
if (OverwriteMode_Force)
key.SetValue(kOverwriteMode, (UInt32)OverwriteMode);
Key_Set_BoolPair(key, kSplitDest, SplitDest);
Key_Set_BoolPair(key, kElimDup, ElimDup);
// Key_Set_BoolPair(key, kAltStreams, AltStreams);
Key_Set_BoolPair(key, kNtSecur, NtSecurity);
Key_Set_BoolPair(key, kShowPassword, ShowPassword);
key.RecurseDeleteKey(kPathHistory);
key.SetValue_Strings(kPathHistory, Paths);
}
void Save_ShowPassword(bool showPassword)
{
CS_LOCK
CKey key;
CreateMainKey(key, kKeyName);
key.SetValue(kShowPassword, showPassword);
}
void Save_LimitGB(UInt32 limit_GB)
{
CS_LOCK
CKey key;
CreateMainKey(key, kKeyName);
Key_Set_UInt32(key, kMemLimit, limit_GB);
}
void CInfo::Load()
{
PathMode = NPathMode::kCurPaths;
PathMode_Force = false;
OverwriteMode = NOverwriteMode::kAsk;
OverwriteMode_Force = false;
SplitDest.Val = true;
Paths.Clear();
CS_LOCK
CKey key;
if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
return;
key.GetValue_Strings(kPathHistory, Paths);
UInt32 v;
if (key.GetValue_UInt32_IfOk(kExtractMode, v) == ERROR_SUCCESS && v <= NPathMode::kAbsPaths)
{
PathMode = (NPathMode::EEnum)v;
PathMode_Force = true;
}
if (key.GetValue_UInt32_IfOk(kOverwriteMode, v) == ERROR_SUCCESS && v <= NOverwriteMode::kRenameExisting)
{
OverwriteMode = (NOverwriteMode::EEnum)v;
OverwriteMode_Force = true;
}
Key_Get_BoolPair_true(key, kSplitDest, SplitDest);
Key_Get_BoolPair(key, kElimDup, ElimDup);
// Key_Get_BoolPair(key, kAltStreams, AltStreams);
Key_Get_BoolPair(key, kNtSecur, NtSecurity);
Key_Get_BoolPair(key, kShowPassword, ShowPassword);
}
bool Read_ShowPassword()
{
CS_LOCK
CKey key;
bool showPassword = false;
if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
return showPassword;
key.GetValue_bool_IfOk(kShowPassword, showPassword);
return showPassword;
}
UInt32 Read_LimitGB()
{
CS_LOCK
CKey key;
UInt32 v = (UInt32)(Int32)-1;
if (OpenMainKey(key, kKeyName) == ERROR_SUCCESS)
key.GetValue_UInt32_IfOk(kMemLimit, v);
return v;
}
}
namespace NCompression
{
static LPCTSTR const kKeyName = TEXT("Compression");
static LPCTSTR const kArcHistory = TEXT("ArcHistory");
static LPCWSTR const kArchiver = L"Archiver";
static LPCTSTR const kShowPassword = TEXT("ShowPassword");
static LPCTSTR const kEncryptHeaders = TEXT("EncryptHeaders");
static LPCTSTR const kOptionsKeyName = TEXT("Options");
static LPCTSTR const kLevel = TEXT("Level");
static LPCTSTR const kDictionary = TEXT("Dictionary");
// static LPCTSTR const kDictionaryChain = TEXT("DictionaryChain");
static LPCTSTR const kOrder = TEXT("Order");
static LPCTSTR const kBlockSize = TEXT("BlockSize");
static LPCTSTR const kNumThreads = TEXT("NumThreads");
static LPCWSTR const kMethod = L"Method";
static LPCWSTR const kOptions = L"Options";
static LPCWSTR const kEncryptionMethod = L"EncryptionMethod";
static LPCTSTR const kNtSecur = TEXT("Security");
static LPCTSTR const kAltStreams = TEXT("AltStreams");
static LPCTSTR const kHardLinks = TEXT("HardLinks");
static LPCTSTR const kSymLinks = TEXT("SymLinks");
static LPCTSTR const kPreserveATime = TEXT("PreserveATime");
static LPCTSTR const kTimePrec = TEXT("TimePrec");
static LPCTSTR const kMTime = TEXT("MTime");
static LPCTSTR const kATime = TEXT("ATime");
static LPCTSTR const kCTime = TEXT("CTime");
static LPCTSTR const kSetArcMTime = TEXT("SetArcMTime");
static void SetRegString(CKey &key, LPCWSTR name, const UString &value)
{
if (value.IsEmpty())
key.DeleteValue(name);
else
key.SetValue(name, value);
}
static void GetRegString(CKey &key, LPCWSTR name, UString &value)
{
if (key.QueryValue(name, value) != ERROR_SUCCESS)
value.Empty();
}
static LPCWSTR const kMemUse = L"MemUse"
#if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4)
L"32";
#else
L"64";
#endif
void CInfo::Save() const
{
CS_LOCK
CKey key;
CreateMainKey(key, kKeyName);
Key_Set_BoolPair_Delete_IfNotDef (key, kNtSecur, NtSecurity);
Key_Set_BoolPair_Delete_IfNotDef (key, kAltStreams, AltStreams);
Key_Set_BoolPair_Delete_IfNotDef (key, kHardLinks, HardLinks);
Key_Set_BoolPair_Delete_IfNotDef (key, kSymLinks, SymLinks);
Key_Set_BoolPair_Delete_IfNotDef (key, kPreserveATime, PreserveATime);
key.SetValue(kShowPassword, ShowPassword);
key.SetValue(kLevel, (UInt32)Level);
key.SetValue(kArchiver, ArcType);
key.SetValue(kShowPassword, ShowPassword);
key.SetValue(kEncryptHeaders, EncryptHeaders);
key.RecurseDeleteKey(kArcHistory);
key.SetValue_Strings(kArcHistory, ArcPaths);
key.RecurseDeleteKey(kOptionsKeyName);
{
CKey optionsKey;
optionsKey.Create(key, kOptionsKeyName);
FOR_VECTOR (i, Formats)
{
const CFormatOptions &fo = Formats[i];
CKey fk;
fk.Create(optionsKey, fo.FormatID);
SetRegString(fk, kMethod, fo.Method);
SetRegString(fk, kOptions, fo.Options);
SetRegString(fk, kEncryptionMethod, fo.EncryptionMethod);
SetRegString(fk, kMemUse, fo.MemUse);
Key_Set_UInt32(fk, kLevel, fo.Level);
Key_Set_UInt32(fk, kDictionary, fo.Dictionary);
// Key_Set_UInt32(fk, kDictionaryChain, fo.DictionaryChain);
Key_Set_UInt32(fk, kOrder, fo.Order);
Key_Set_UInt32(fk, kBlockSize, fo.BlockLogSize);
Key_Set_UInt32(fk, kNumThreads, fo.NumThreads);
Key_Set_UInt32(fk, kTimePrec, fo.TimePrec);
Key_Set_BoolPair_Delete_IfNotDef (fk, kMTime, fo.MTime);
Key_Set_BoolPair_Delete_IfNotDef (fk, kATime, fo.ATime);
Key_Set_BoolPair_Delete_IfNotDef (fk, kCTime, fo.CTime);
Key_Set_BoolPair_Delete_IfNotDef (fk, kSetArcMTime, fo.SetArcMTime);
}
}
}
void CInfo::Load()
{
ArcPaths.Clear();
Formats.Clear();
Level = 5;
ArcType = L"7z";
ShowPassword = false;
EncryptHeaders = false;
CS_LOCK
CKey key;
if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
return;
Key_Get_BoolPair(key, kNtSecur, NtSecurity);
Key_Get_BoolPair(key, kAltStreams, AltStreams);
Key_Get_BoolPair(key, kHardLinks, HardLinks);
Key_Get_BoolPair(key, kSymLinks, SymLinks);
Key_Get_BoolPair(key, kPreserveATime, PreserveATime);
key.GetValue_Strings(kArcHistory, ArcPaths);
{
CKey optionsKey;
if (optionsKey.Open(key, kOptionsKeyName, KEY_READ) == ERROR_SUCCESS)
{
CSysStringVector formatIDs;
optionsKey.EnumKeys(formatIDs);
FOR_VECTOR (i, formatIDs)
{
CKey fk;
CFormatOptions fo;
fo.FormatID = formatIDs[i];
if (fk.Open(optionsKey, fo.FormatID, KEY_READ) == ERROR_SUCCESS)
{
GetRegString(fk, kMethod, fo.Method);
GetRegString(fk, kOptions, fo.Options);
GetRegString(fk, kEncryptionMethod, fo.EncryptionMethod);
GetRegString(fk, kMemUse, fo.MemUse);
Key_Get_UInt32(fk, kLevel, fo.Level);
Key_Get_UInt32(fk, kDictionary, fo.Dictionary);
// Key_Get_UInt32(fk, kDictionaryChain, fo.DictionaryChain);
Key_Get_UInt32(fk, kOrder, fo.Order);
Key_Get_UInt32(fk, kBlockSize, fo.BlockLogSize);
Key_Get_UInt32(fk, kNumThreads, fo.NumThreads);
Key_Get_UInt32(fk, kTimePrec, fo.TimePrec);
Key_Get_BoolPair(fk, kMTime, fo.MTime);
Key_Get_BoolPair(fk, kATime, fo.ATime);
Key_Get_BoolPair(fk, kCTime, fo.CTime);
Key_Get_BoolPair(fk, kSetArcMTime, fo.SetArcMTime);
Formats.Add(fo);
}
}
}
}
UString a;
if (key.QueryValue(kArchiver, a) == ERROR_SUCCESS)
ArcType = a;
key.GetValue_UInt32_IfOk(kLevel, Level);
key.GetValue_bool_IfOk(kShowPassword, ShowPassword);
key.GetValue_bool_IfOk(kEncryptHeaders, EncryptHeaders);
}
static bool ParseMemUse(const wchar_t *s, CMemUse &mu)
{
mu.Clear();
bool percentMode = false;
{
const wchar_t c = *s;
if (MyCharLower_Ascii(c) == 'p')
{
percentMode = true;
s++;
}
}
const wchar_t *end;
UInt64 number = ConvertStringToUInt64(s, &end);
if (end == s)
return false;
wchar_t c = *end;
if (percentMode)
{
if (c != 0)
return false;
mu.IsPercent = true;
mu.Val = number;
return true;
}
if (c == 0)
{
mu.Val = number;
return true;
}
c = MyCharLower_Ascii(c);
const wchar_t c1 = end[1];
if (c == '%')
{
if (c1 != 0)
return false;
mu.IsPercent = true;
mu.Val = number;
return true;
}
if (c == 'b')
{
if (c1 != 0)
return false;
mu.Val = number;
return true;
}
if (c1 != 0)
if (MyCharLower_Ascii(c1) != 'b' || end[2] != 0)
return false;
unsigned numBits;
switch (c)
{
case 'k': numBits = 10; break;
case 'm': numBits = 20; break;
case 'g': numBits = 30; break;
case 't': numBits = 40; break;
default: return false;
}
if (number >= ((UInt64)1 << (64 - numBits)))
return false;
mu.Val = number << numBits;
return true;
}
void CMemUse::Parse(const UString &s)
{
IsDefined = ParseMemUse(s, *this);
}
/*
void MemLimit_Save(const UString &s)
{
CS_LOCK
CKey key;
CreateMainKey(key, kKeyName);
SetRegString(key, kMemUse, s);
}
bool MemLimit_Load(NCompression::CMemUse &mu)
{
mu.Clear();
UString a;
{
CS_LOCK
CKey key;
if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
return false;
if (key.QueryValue(kMemUse, a) != ERROR_SUCCESS)
return false;
}
if (a.IsEmpty())
return false;
mu.Parse(a);
return mu.IsDefined;
}
*/
}
static LPCTSTR const kOptionsInfoKeyName = TEXT("Options");
namespace NWorkDir
{
static LPCTSTR const kWorkDirType = TEXT("WorkDirType");
static LPCWSTR const kWorkDirPath = L"WorkDirPath";
static LPCTSTR const kTempRemovableOnly = TEXT("TempRemovableOnly");
void CInfo::Save()const
{
CS_LOCK
CKey key;
CreateMainKey(key, kOptionsInfoKeyName);
key.SetValue(kWorkDirType, (UInt32)Mode);
key.SetValue(kWorkDirPath, fs2us(Path));
key.SetValue(kTempRemovableOnly, ForRemovableOnly);
}
void CInfo::Load()
{
SetDefault();
CS_LOCK
CKey key;
if (OpenMainKey(key, kOptionsInfoKeyName) != ERROR_SUCCESS)
return;
UInt32 dirType;
if (key.GetValue_UInt32_IfOk(kWorkDirType, dirType) != ERROR_SUCCESS)
return;
switch (dirType)
{
case NMode::kSystem:
case NMode::kCurrent:
case NMode::kSpecified:
Mode = (NMode::EEnum)dirType;
}
UString pathU;
if (key.QueryValue(kWorkDirPath, pathU) == ERROR_SUCCESS)
Path = us2fs(pathU);
else
{
Path.Empty();
if (Mode == NMode::kSpecified)
Mode = NMode::kSystem;
}
key.GetValue_bool_IfOk(kTempRemovableOnly, ForRemovableOnly);
}
}
static LPCTSTR const kCascadedMenu = TEXT("CascadedMenu");
static LPCTSTR const kContextMenu = TEXT("ContextMenu");
static LPCTSTR const kMenuIcons = TEXT("MenuIcons");
static LPCTSTR const kElimDup = TEXT("ElimDupExtract");
static LPCTSTR const kWriteZoneId = TEXT("WriteZoneIdExtract");
void CContextMenuInfo::Save() const
{
CS_LOCK
CKey key;
CreateMainKey(key, kOptionsInfoKeyName);
Key_Set_BoolPair(key, kCascadedMenu, Cascaded);
Key_Set_BoolPair(key, kMenuIcons, MenuIcons);
Key_Set_BoolPair(key, kElimDup, ElimDup);
Key_Set_UInt32(key, kWriteZoneId, WriteZone);
if (Flags_Def)
key.SetValue(kContextMenu, Flags);
}
void CContextMenuInfo::Load()
{
Cascaded.Val = true;
Cascaded.Def = false;
MenuIcons.Val = false;
MenuIcons.Def = false;
ElimDup.Val = true;
ElimDup.Def = false;
WriteZone = (UInt32)(Int32)-1;
/* we can disable email items by default,
because email code doesn't work in some systems */
Flags = (UInt32)(Int32)-1
/*
& ~NContextMenuFlags::kCompressEmail
& ~NContextMenuFlags::kCompressTo7zEmail
& ~NContextMenuFlags::kCompressToZipEmail
*/
;
Flags_Def = false;
CS_LOCK
CKey key;
if (OpenMainKey(key, kOptionsInfoKeyName) != ERROR_SUCCESS)
return;
Key_Get_BoolPair_true(key, kCascadedMenu, Cascaded);
Key_Get_BoolPair_true(key, kElimDup, ElimDup);
Key_Get_BoolPair(key, kMenuIcons, MenuIcons);
Key_Get_UInt32(key, kWriteZoneId, WriteZone);
Flags_Def = (key.GetValue_UInt32_IfOk(kContextMenu, Flags) == ERROR_SUCCESS);
}
@@ -0,0 +1,212 @@
// ZipRegistry.h
#ifndef ZIP7_INC_ZIP_REGISTRY_H
#define ZIP7_INC_ZIP_REGISTRY_H
#include "../../../Common/MyTypes.h"
#include "../../../Common/MyString.h"
#include "../../Common/MethodProps.h"
#include "ExtractMode.h"
/*
CBoolPair::Def in writing functions means:
if ( CBoolPair::Def ), we write CBoolPair::Val
if ( !CBoolPair::Def )
{
in NCompression functions we delete registry value
in another functions we do nothing
}
*/
namespace NExtract
{
struct CInfo
{
NPathMode::EEnum PathMode;
NOverwriteMode::EEnum OverwriteMode;
bool PathMode_Force;
bool OverwriteMode_Force;
CBoolPair SplitDest;
CBoolPair ElimDup;
// CBoolPair AltStreams;
CBoolPair NtSecurity;
CBoolPair ShowPassword;
UStringVector Paths;
void Save() const;
void Load();
};
void Save_ShowPassword(bool showPassword);
bool Read_ShowPassword();
void Save_LimitGB(UInt32 limit_GB);
UInt32 Read_LimitGB();
}
namespace NCompression
{
struct CMemUse
{
// UString Str;
bool IsDefined;
bool IsPercent;
UInt64 Val;
CMemUse():
IsDefined(false),
IsPercent(false),
Val(0)
{}
void Clear()
{
// Str.Empty();
IsDefined = false;
IsPercent = false;
Val = 0;
}
UInt64 GetBytes(UInt64 ramSize) const
{
if (!IsPercent)
return Val;
return Calc_From_Val_Percents(ramSize, Val);
}
void Parse(const UString &s);
};
struct CFormatOptions
{
UInt32 Level;
UInt32 Dictionary;
// UInt32 DictionaryChain;
UInt32 Order;
UInt32 BlockLogSize;
UInt32 NumThreads;
UInt32 TimePrec;
CBoolPair MTime;
CBoolPair ATime;
CBoolPair CTime;
CBoolPair SetArcMTime;
CSysString FormatID;
UString Method;
UString Options;
UString EncryptionMethod;
UString MemUse;
void Reset_TimePrec()
{
TimePrec = (UInt32)(Int32)-1;
}
bool IsSet_TimePrec() const
{
return TimePrec != (UInt32)(Int32)-1;
}
void Reset_BlockLogSize()
{
BlockLogSize = (UInt32)(Int32)-1;
}
void ResetForLevelChange()
{
BlockLogSize = NumThreads = Level = Dictionary = Order = (UInt32)(Int32)-1;
// DictionaryChain = (UInt32)(Int32)-1;
Method.Empty();
// Options.Empty();
// EncryptionMethod.Empty();
}
CFormatOptions()
{
// TimePrec = 0;
Reset_TimePrec();
ResetForLevelChange();
}
};
struct CInfo
{
UInt32 Level;
bool ShowPassword;
bool EncryptHeaders;
CBoolPair NtSecurity;
CBoolPair AltStreams;
CBoolPair HardLinks;
CBoolPair SymLinks;
CBoolPair PreserveATime;
UString ArcType;
UStringVector ArcPaths;
CObjectVector<CFormatOptions> Formats;
void Save() const;
void Load();
};
}
namespace NWorkDir
{
namespace NMode
{
enum EEnum
{
kSystem,
kCurrent,
kSpecified
};
}
struct CInfo
{
NMode::EEnum Mode;
bool ForRemovableOnly;
FString Path;
void SetForRemovableOnlyDefault() { ForRemovableOnly = true; }
void SetDefault()
{
Mode = NMode::kSystem;
Path.Empty();
SetForRemovableOnlyDefault();
}
void Save() const;
void Load();
};
}
struct CContextMenuInfo
{
CBoolPair Cascaded;
CBoolPair MenuIcons;
CBoolPair ElimDup;
bool Flags_Def;
UInt32 Flags;
UInt32 WriteZone;
/*
CContextMenuInfo():
Flags_Def(0),
WriteZone((UInt32)(Int32)-1),
Flags((UInt32)(Int32)-1)
{}
*/
void Save() const;
void Load();
};
#endif
@@ -0,0 +1,41 @@
// BenchCon.cpp
#include "StdAfx.h"
#include "../Common/Bench.h"
#include "BenchCon.h"
#include "ConsoleClose.h"
struct CPrintBenchCallback Z7_final: public IBenchPrintCallback
{
FILE *_file;
void Print(const char *s) Z7_override;
void NewLine() Z7_override;
HRESULT CheckBreak() Z7_override;
};
void CPrintBenchCallback::Print(const char *s)
{
fputs(s, _file);
}
void CPrintBenchCallback::NewLine()
{
fputc('\n', _file);
}
HRESULT CPrintBenchCallback::CheckBreak()
{
return NConsoleClose::TestBreakSignal() ? E_ABORT: S_OK;
}
HRESULT BenchCon(DECL_EXTERNAL_CODECS_LOC_VARS
const CObjectVector<CProperty> &props, UInt32 numIterations, FILE *f)
{
CPrintBenchCallback callback;
callback._file = f;
return Bench(EXTERNAL_CODECS_LOC_VARS
&callback, NULL, props, numIterations, true);
}
@@ -0,0 +1,14 @@
// BenchCon.h
#ifndef ZIP7_INC_BENCH_CON_H
#define ZIP7_INC_BENCH_CON_H
#include <stdio.h>
#include "../../Common/CreateCoder.h"
#include "../../UI/Common/Property.h"
HRESULT BenchCon(DECL_EXTERNAL_CODECS_LOC_VARS
const CObjectVector<CProperty> &props, UInt32 numIterations, FILE *f);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "Console"=".\Console.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################
@@ -0,0 +1,46 @@
MY_CONSOLE = 1
!IFNDEF UNDER_CE
CFLAGS = $(CFLAGS) -DZ7_DEVICE_FILE
# -DZ7_LONG_PATH -DZ7_LARGE_PAGES
!ENDIF
CONSOLE_OBJS = \
$O\BenchCon.obj \
$O\ConsoleClose.obj \
$O\ExtractCallbackConsole.obj \
$O\HashCon.obj \
$O\List.obj \
$O\Main.obj \
$O\MainAr.obj \
$O\OpenCallbackConsole.obj \
$O\PercentPrinter.obj \
$O\UpdateCallbackConsole.obj \
$O\UserInputUtils.obj \
UI_COMMON_OBJS = \
$O\ArchiveCommandLine.obj \
$O\ArchiveExtractCallback.obj \
$O\ArchiveOpenCallback.obj \
$O\Bench.obj \
$O\DefaultName.obj \
$O\EnumDirItems.obj \
$O\Extract.obj \
$O\ExtractingFilePath.obj \
$O\HashCalc.obj \
$O\LoadCodecs.obj \
$O\OpenArchive.obj \
$O\PropIDUtils.obj \
$O\SetProperties.obj \
$O\SortUtils.obj \
$O\TempFiles.obj \
$O\Update.obj \
$O\UpdateAction.obj \
$O\UpdateCallback.obj \
$O\UpdatePair.obj \
$O\UpdateProduce.obj \
C_OBJS = $(C_OBJS) \
$O\DllSecur.obj \
# we need empty line after last line above
@@ -0,0 +1,16 @@
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7z" type="win32"></assemblyIdentity>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security><requestedPrivileges><requestedExecutionLevel level="asInvoker" uiAccess="false">
</requestedExecutionLevel></requestedPrivileges></security></trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application>
<!-- Vista --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
<!-- Win 7 --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<!-- Win 8 --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<!-- Win 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<!-- Win 10 --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application></compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
<ws2:longPathAware>true</ws2:longPathAware></windowsSettings></application>
</assembly>
@@ -0,0 +1,98 @@
// ConsoleClose.cpp
#include "StdAfx.h"
#include "ConsoleClose.h"
#ifndef UNDER_CE
#ifdef _WIN32
#include "../../../Common/MyWindows.h"
#else
#include <stdlib.h>
#include <signal.h>
#endif
namespace NConsoleClose {
unsigned g_BreakCounter = 0;
static const unsigned kBreakAbortThreshold = 3;
#ifdef _WIN32
static BOOL WINAPI HandlerRoutine(DWORD ctrlType)
{
if (ctrlType == CTRL_LOGOFF_EVENT)
{
// printf("\nCTRL_LOGOFF_EVENT\n");
return TRUE;
}
if (++g_BreakCounter < kBreakAbortThreshold)
return TRUE;
return FALSE;
/*
switch (ctrlType)
{
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
if (g_BreakCounter < kBreakAbortThreshold)
return TRUE;
}
return FALSE;
*/
}
CCtrlHandlerSetter::CCtrlHandlerSetter()
{
if (!SetConsoleCtrlHandler(HandlerRoutine, TRUE))
throw 1019; // "SetConsoleCtrlHandler fails";
}
CCtrlHandlerSetter::~CCtrlHandlerSetter()
{
if (!SetConsoleCtrlHandler(HandlerRoutine, FALSE))
{
// warning for throw in destructor.
// throw "SetConsoleCtrlHandler fails";
}
}
#else // _WIN32
static void HandlerRoutine(int)
{
if (++g_BreakCounter < kBreakAbortThreshold)
return;
exit(EXIT_FAILURE);
}
CCtrlHandlerSetter::CCtrlHandlerSetter()
{
memo_sig_int = signal(SIGINT, HandlerRoutine); // CTRL-C
if (memo_sig_int == SIG_ERR)
throw "SetConsoleCtrlHandler fails (SIGINT)";
memo_sig_term = signal(SIGTERM, HandlerRoutine); // for kill -15 (before "kill -9")
if (memo_sig_term == SIG_ERR)
throw "SetConsoleCtrlHandler fails (SIGTERM)";
}
CCtrlHandlerSetter::~CCtrlHandlerSetter()
{
signal(SIGINT, memo_sig_int); // CTRL-C
signal(SIGTERM, memo_sig_term); // kill {pid}
}
#endif // _WIN32
/*
void CheckCtrlBreak()
{
if (TestBreakSignal())
throw CCtrlBreakException();
}
*/
}
#endif
@@ -0,0 +1,39 @@
// ConsoleClose.h
#ifndef ZIP7_INC_CONSOLE_CLOSE_H
#define ZIP7_INC_CONSOLE_CLOSE_H
namespace NConsoleClose {
// class CCtrlBreakException {};
#ifdef UNDER_CE
inline bool TestBreakSignal() { return false; }
struct CCtrlHandlerSetter {};
#else
extern unsigned g_BreakCounter;
inline bool TestBreakSignal()
{
return (g_BreakCounter != 0);
}
class CCtrlHandlerSetter Z7_final
{
#ifndef _WIN32
void (*memo_sig_int)(int);
void (*memo_sig_term)(int);
#endif
public:
CCtrlHandlerSetter();
~CCtrlHandlerSetter();
};
#endif
}
#endif
@@ -0,0 +1,946 @@
// ExtractCallbackConsole.cpp
#include "StdAfx.h"
#include "../../../Common/IntToString.h"
#include "../../../Common/Wildcard.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/FileFind.h"
#include "../../../Windows/TimeUtils.h"
#include "../../../Windows/ErrorMsg.h"
#include "../../../Windows/PropVariantConv.h"
#ifndef Z7_ST
#include "../../../Windows/Synchronization.h"
#endif
#include "../../Common/FilePathAutoRename.h"
#include "../Common/ExtractingFilePath.h"
#include "ConsoleClose.h"
#include "ExtractCallbackConsole.h"
#include "UserInputUtils.h"
using namespace NWindows;
using namespace NFile;
using namespace NDir;
static HRESULT CheckBreak2()
{
return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
}
static const char * const kError = "ERROR: ";
void CExtractScanConsole::StartScanning()
{
if (NeedPercents())
_percent.Command = "Scan";
}
HRESULT CExtractScanConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */)
{
if (NeedPercents())
{
_percent.Files = st.NumDirs + st.NumFiles;
_percent.Completed = st.GetTotalBytes();
_percent.FileName = fs2us(path);
_percent.Print();
}
return CheckBreak2();
}
HRESULT CExtractScanConsole::ScanError(const FString &path, DWORD systemError)
{
// 22.00:
// ScanErrors.AddError(path, systemError);
ClosePercentsAndFlush();
if (_se)
{
*_se << endl << kError << NError::MyFormatMessage(systemError) << endl;
_se->NormalizePrint_UString_Path(fs2us(path));
*_se << endl << endl;
_se->Flush();
}
return HRESULT_FROM_WIN32(systemError);
// 22.00: commented
// CommonError(path, systemError, true);
// return S_OK;
}
void Print_UInt64_and_String(AString &s, UInt64 val, const char *name);
void Print_UInt64_and_String(AString &s, UInt64 val, const char *name)
{
char temp[32];
ConvertUInt64ToString(val, temp);
s += temp;
s.Add_Space();
s += name;
}
void PrintSize_bytes_Smart(AString &s, UInt64 val);
void PrintSize_bytes_Smart(AString &s, UInt64 val)
{
Print_UInt64_and_String(s, val, "bytes");
if (val == 0)
return;
unsigned numBits = 10;
char c = 'K';
char temp[4] = { 'K', 'i', 'B', 0 };
if (val >= ((UInt64)10 << 30)) { numBits = 30; c = 'G'; }
else if (val >= ((UInt64)10 << 20)) { numBits = 20; c = 'M'; }
temp[0] = c;
s += " (";
Print_UInt64_and_String(s, ((val + ((UInt64)1 << numBits) - 1) >> numBits), temp);
s.Add_Char(')');
}
static void PrintSize_bytes_Smart_comma(AString &s, UInt64 val)
{
if (val == (UInt64)(Int64)-1)
return;
s += ", ";
PrintSize_bytes_Smart(s, val);
}
void Print_DirItemsStat(AString &s, const CDirItemsStat &st);
void Print_DirItemsStat(AString &s, const CDirItemsStat &st)
{
if (st.NumDirs != 0)
{
Print_UInt64_and_String(s, st.NumDirs, st.NumDirs == 1 ? "folder" : "folders");
s += ", ";
}
Print_UInt64_and_String(s, st.NumFiles, st.NumFiles == 1 ? "file" : "files");
PrintSize_bytes_Smart_comma(s, st.FilesSize);
if (st.NumAltStreams != 0)
{
s.Add_LF();
Print_UInt64_and_String(s, st.NumAltStreams, "alternate streams");
PrintSize_bytes_Smart_comma(s, st.AltStreamsSize);
}
}
void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st);
void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st)
{
Print_DirItemsStat(s, (CDirItemsStat &)st);
bool needLF = true;
if (st.Anti_NumDirs != 0)
{
if (needLF)
s.Add_LF();
needLF = false;
Print_UInt64_and_String(s, st.Anti_NumDirs, st.Anti_NumDirs == 1 ? "anti-folder" : "anti-folders");
}
if (st.Anti_NumFiles != 0)
{
if (needLF)
s.Add_LF();
else
s += ", ";
needLF = false;
Print_UInt64_and_String(s, st.Anti_NumFiles, st.Anti_NumFiles == 1 ? "anti-file" : "anti-files");
}
if (st.Anti_NumAltStreams != 0)
{
if (needLF)
s.Add_LF();
else
s += ", ";
needLF = false;
Print_UInt64_and_String(s, st.Anti_NumAltStreams, "anti-alternate-streams");
}
}
void CExtractScanConsole::PrintStat(const CDirItemsStat &st)
{
if (_so)
{
AString s;
Print_DirItemsStat(s, st);
*_so << s << endl;
}
}
#ifndef Z7_ST
static NSynchronization::CCriticalSection g_CriticalSection;
#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
#else
#define MT_LOCK
#endif
static const char * const kTestString = "T";
static const char * const kExtractString = "-";
static const char * const kSkipString = ".";
static const char * const kReadString = "H";
// static const char * const kCantAutoRename = "cannot create file with auto name\n";
// static const char * const kCantRenameFile = "cannot rename existing file\n";
// static const char * const kCantDeleteOutputFile = "cannot delete output file ";
static const char * const kMemoryExceptionMessage = "Can't allocate required memory!";
static const char * const kExtracting = "Extracting archive: ";
static const char * const kTesting = "Testing archive: ";
static const char * const kEverythingIsOk = "Everything is Ok";
static const char * const kNoFiles = "No files to process";
static const char * const kUnsupportedMethod = "Unsupported Method";
static const char * const kCrcFailed = "CRC Failed";
static const char * const kCrcFailedEncrypted = "CRC Failed in encrypted file. Wrong password?";
static const char * const kDataError = "Data Error";
static const char * const kDataErrorEncrypted = "Data Error in encrypted file. Wrong password?";
static const char * const kUnavailableData = "Unavailable data";
static const char * const kUnexpectedEnd = "Unexpected end of data";
static const char * const kDataAfterEnd = "There are some data after the end of the payload data";
static const char * const kIsNotArc = "Is not archive";
static const char * const kHeadersError = "Headers Error";
static const char * const kWrongPassword = "Wrong password";
static const char * const k_ErrorFlagsMessages[] =
{
"Is not archive"
, "Headers Error"
, "Headers Error in encrypted archive. Wrong password?"
, "Unavailable start of archive"
, "Unconfirmed start of archive"
, "Unexpected end of archive"
, "There are data after the end of archive"
, "Unsupported method"
, "Unsupported feature"
, "Data Error"
, "CRC Error"
};
Z7_COM7F_IMF(CExtractCallbackConsole::SetTotal(UInt64 size))
{
MT_LOCK
if (NeedPercents())
{
_percent.Total = size;
_percent.Print();
}
return CheckBreak2();
}
Z7_COM7F_IMF(CExtractCallbackConsole::SetCompleted(const UInt64 *completeValue))
{
MT_LOCK
if (NeedPercents())
{
if (completeValue)
_percent.Completed = *completeValue;
_percent.Print();
}
return CheckBreak2();
}
static const char * const kTab = " ";
static void PrintFileInfo(CStdOutStream *_so, const wchar_t *path, const FILETIME *ft, const UInt64 *size)
{
*_so << kTab << "Path: ";
_so->NormalizePrint_wstr_Path(path);
*_so << endl;
if (size && *size != (UInt64)(Int64)-1)
{
AString s;
PrintSize_bytes_Smart(s, *size);
*_so << kTab << "Size: " << s << endl;
}
if (ft)
{
char temp[64];
if (ConvertUtcFileTimeToString(*ft, temp, kTimestampPrintLevel_SEC))
*_so << kTab << "Modified: " << temp << endl;
}
}
Z7_COM7F_IMF(CExtractCallbackConsole::AskOverwrite(
const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
Int32 *answer))
{
MT_LOCK
RINOK(CheckBreak2())
ClosePercentsAndFlush();
if (_so)
{
*_so << endl << "Would you like to replace the existing file:\n";
PrintFileInfo(_so, existName, existTime, existSize);
*_so << "with the file from archive:\n";
PrintFileInfo(_so, newName, newTime, newSize);
}
NUserAnswerMode::EEnum overwriteAnswer = ScanUserYesNoAllQuit(_so);
switch ((int)overwriteAnswer)
{
case NUserAnswerMode::kQuit: return E_ABORT;
case NUserAnswerMode::kNo: *answer = NOverwriteAnswer::kNo; break;
case NUserAnswerMode::kNoAll: *answer = NOverwriteAnswer::kNoToAll; break;
case NUserAnswerMode::kYesAll: *answer = NOverwriteAnswer::kYesToAll; break;
case NUserAnswerMode::kYes: *answer = NOverwriteAnswer::kYes; break;
case NUserAnswerMode::kAutoRenameAll: *answer = NOverwriteAnswer::kAutoRename; break;
case NUserAnswerMode::kEof: return E_ABORT;
case NUserAnswerMode::kError: return E_FAIL;
default: return E_FAIL;
}
if (_so)
{
*_so << endl;
if (NeedFlush)
_so->Flush();
}
return CheckBreak2();
}
Z7_COM7F_IMF(CExtractCallbackConsole::PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 *position))
{
MT_LOCK
_currentName = name;
const char *s;
unsigned requiredLevel = 1;
switch (askExtractMode)
{
case NArchive::NExtract::NAskMode::kExtract: s = kExtractString; break;
case NArchive::NExtract::NAskMode::kTest: s = kTestString; break;
case NArchive::NExtract::NAskMode::kSkip: s = kSkipString; requiredLevel = 2; break;
case NArchive::NExtract::NAskMode::kReadExternal: s = kReadString; requiredLevel = 0; break;
default: s = "???"; requiredLevel = 2;
}
const bool show2 = (LogLevel >= requiredLevel && _so);
if (show2)
{
ClosePercents_for_so();
_tempA = s;
if (name)
_tempA.Add_Space();
*_so << _tempA;
_tempU.Empty();
if (name)
{
_tempU = name;
_so->Normalize_UString_Path(_tempU);
// 21.04
if (isFolder)
{
if (!_tempU.IsEmpty() && _tempU.Back() != WCHAR_PATH_SEPARATOR)
_tempU.Add_PathSepar();
}
}
_so->PrintUString(_tempU, _tempA);
if (position)
*_so << " <" << *position << ">";
*_so << endl;
if (NeedFlush)
_so->Flush();
// _so->Flush(); // for debug only
}
if (NeedPercents())
{
if (PercentsNameLevel >= 1)
{
_percent.FileName.Empty();
_percent.Command.Empty();
if (PercentsNameLevel > 1 || !show2)
{
_percent.Command = s;
if (name)
_percent.FileName = name;
}
}
_percent.Print();
}
return CheckBreak2();
}
Z7_COM7F_IMF(CExtractCallbackConsole::MessageError(const wchar_t *message))
{
MT_LOCK
RINOK(CheckBreak2())
NumFileErrors_in_Current++;
NumFileErrors++;
ClosePercentsAndFlush();
if (_se)
{
*_se << kError << message << endl;
_se->Flush();
}
return CheckBreak2();
}
void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest);
void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest)
{
dest.Empty();
const char *s = NULL;
switch (opRes)
{
case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
s = kUnsupportedMethod;
break;
case NArchive::NExtract::NOperationResult::kCRCError:
s = (encrypted ? kCrcFailedEncrypted : kCrcFailed);
break;
case NArchive::NExtract::NOperationResult::kDataError:
s = (encrypted ? kDataErrorEncrypted : kDataError);
break;
case NArchive::NExtract::NOperationResult::kUnavailable:
s = kUnavailableData;
break;
case NArchive::NExtract::NOperationResult::kUnexpectedEnd:
s = kUnexpectedEnd;
break;
case NArchive::NExtract::NOperationResult::kDataAfterEnd:
s = kDataAfterEnd;
break;
case NArchive::NExtract::NOperationResult::kIsNotArc:
s = kIsNotArc;
break;
case NArchive::NExtract::NOperationResult::kHeadersError:
s = kHeadersError;
break;
case NArchive::NExtract::NOperationResult::kWrongPassword:
s = kWrongPassword;
break;
default: break;
}
dest += kError;
if (s)
dest += s;
else
{
dest += "Error #";
dest.Add_UInt32((UInt32)opRes);
}
}
Z7_COM7F_IMF(CExtractCallbackConsole::SetOperationResult(Int32 opRes, Int32 encrypted))
{
MT_LOCK
if (opRes == NArchive::NExtract::NOperationResult::kOK)
{
if (NeedPercents())
{
_percent.Command.Empty();
_percent.FileName.Empty();
_percent.Files++;
}
}
else
{
NumFileErrors_in_Current++;
NumFileErrors++;
if (_se)
{
ClosePercentsAndFlush();
AString s;
SetExtractErrorMessage(opRes, encrypted, s);
*_se << s;
if (!_currentName.IsEmpty())
{
*_se << " : ";
_se->NormalizePrint_UString_Path(_currentName);
}
*_se << endl;
_se->Flush();
}
}
return CheckBreak2();
}
Z7_COM7F_IMF(CExtractCallbackConsole::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name))
{
if (opRes != NArchive::NExtract::NOperationResult::kOK)
{
_currentName = name;
return SetOperationResult(opRes, encrypted);
}
return CheckBreak2();
}
#ifndef Z7_NO_CRYPTO
HRESULT CExtractCallbackConsole::SetPassword(const UString &password)
{
PasswordIsDefined = true;
Password = password;
return S_OK;
}
Z7_COM7F_IMF(CExtractCallbackConsole::CryptoGetTextPassword(BSTR *password))
{
COM_TRY_BEGIN
MT_LOCK
return Open_CryptoGetTextPassword(password);
COM_TRY_END
}
#endif
#ifndef Z7_SFX
void CExtractCallbackConsole::PrintTo_se_Path_WithTitle(const UString &path, const char *title)
{
*_se << title;
_se->NormalizePrint_UString_Path(path);
*_se << endl;
}
void CExtractCallbackConsole::Add_ArchiveName_Error()
{
if (_needWriteArchivePath)
{
PrintTo_se_Path_WithTitle(_currentArchivePath, "Archive: ");
_needWriteArchivePath = false;
}
}
Z7_COM7F_IMF(CExtractCallbackConsole::RequestMemoryUse(
UInt32 flags, UInt32 /* indexType */, UInt32 /* index */, const wchar_t *path,
UInt64 requiredSize, UInt64 *allowedSize, UInt32 *answerFlags))
{
if ((flags & NRequestMemoryUseFlags::k_IsReport) == 0
&& requiredSize <= *allowedSize)
{
#if 0
// it's expected, that *answerFlags was set to NRequestMemoryAnswerFlags::k_Allow already,
// because it's default answer for (requiredSize <= *allowedSize) case.
// optional code:
*answerFlags = NRequestMemoryAnswerFlags::k_Allow;
#endif
}
else
{
if ((flags & NRequestMemoryUseFlags::k_NoErrorMessage) == 0)
if (_se)
{
const UInt64 num_GB_allowed = (*allowedSize + ((1u << 30) - 1)) >> 30;
const UInt64 num_GB_required = (requiredSize + ((1u << 30) - 1)) >> 30;
ClosePercentsAndFlush();
Add_ArchiveName_Error();
if (path)
PrintTo_se_Path_WithTitle(path, "File: ");
*_se << "The extraction operation requires big amount memory (RAM):" << endl
<< " " << num_GB_required << " GB : required memory usage size" << endl
<< " " << num_GB_allowed << " GB : allowed memory usage limit" << endl
<< " Use -smemx{size}g switch to set allowed memory usage limit for extraction." << endl;
*_se << "ERROR: Memory usage limit was exceeded." << endl;
const char *m = NULL;
// if (indexType == NArchive::NEventIndexType::kNoIndex)
if ((flags & NRequestMemoryUseFlags::k_SkipArc_IsExpected) ||
(flags & NRequestMemoryUseFlags::k_Report_SkipArc))
m = "Archive unpacking was skipped.";
/*
else if ((flags & NRequestMemoryUseFlags::k_SkipBigFiles_IsExpected) ||
(flags & NRequestMemoryUseFlags::k_Report_SkipBigFiles))
m = "Extraction for some files will be skipped.";
else if ((flags & NRequestMemoryUseFlags::k_SkipBigFile_IsExpected) ||
(flags & NRequestMemoryUseFlags::k_Report_SkipBigFile))
m = "File extraction was skipped.";
*/
if (m)
*_se << m;
_se->Flush();
}
if ((flags & NRequestMemoryUseFlags::k_IsReport) == 0)
{
// default answer can be k_Allow, if limit was not forced,
// so we change answer to non-allowed here.
*answerFlags = NRequestMemoryAnswerFlags::k_Limit_Exceeded;
if (flags & NRequestMemoryUseFlags::k_SkipArc_IsExpected)
*answerFlags |= NRequestMemoryAnswerFlags::k_SkipArc;
/*
else if (flags & NRequestMemoryUseFlags::k_SkipBigFile_IsExpected)
*answerFlags |= NRequestMemoryAnswerFlags::k_SkipBigFile;
else if (flags & NRequestMemoryUseFlags::k_SkipBigFiles_IsExpected)
*answerFlags |= NRequestMemoryAnswerFlags::k_SkipBigFiles;
*/
}
}
return CheckBreak2();
}
#endif
HRESULT CExtractCallbackConsole::BeforeOpen(const wchar_t *name, bool testMode)
{
_currentArchivePath = name;
_needWriteArchivePath = true;
RINOK(CheckBreak2())
NumTryArcs++;
ThereIsError_in_Current = false;
ThereIsWarning_in_Current = false;
NumFileErrors_in_Current = 0;
ClosePercents_for_so();
if (_so)
{
*_so << endl << (testMode ? kTesting : kExtracting);
_so->NormalizePrint_wstr_Path(name);
*_so << endl;
}
if (NeedPercents())
_percent.Command = "Open";
return S_OK;
}
HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
static AString GetOpenArcErrorMessage(UInt32 errorFlags)
{
AString s;
for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_ErrorFlagsMessages); i++)
{
UInt32 f = (1 << i);
if ((errorFlags & f) == 0)
continue;
const char *m = k_ErrorFlagsMessages[i];
if (!s.IsEmpty())
s.Add_LF();
s += m;
errorFlags &= ~f;
}
if (errorFlags != 0)
{
char sz[16];
sz[0] = '0';
sz[1] = 'x';
ConvertUInt32ToHex(errorFlags, sz + 2);
if (!s.IsEmpty())
s.Add_LF();
s += sz;
}
return s;
}
void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags);
void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags)
{
if (errorFlags == 0)
return;
so << s << endl << GetOpenArcErrorMessage(errorFlags) << endl;
}
static void Add_Messsage_Pre_ArcType(UString &s, const char *pre, const wchar_t *arcType)
{
s.Add_LF();
s += pre;
s += " as [";
s += arcType;
s += "] archive";
}
void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc);
void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc)
{
const CArcErrorInfo &er = arc.ErrorInfo;
*_so << "WARNING:\n";
_so->NormalizePrint_UString_Path(arc.Path);
UString s;
if (arc.FormatIndex == er.ErrorFormatIndex)
{
s.Add_LF();
s += "The archive is open with offset";
}
else
{
Add_Messsage_Pre_ArcType(s, "Cannot open the file", codecs->GetFormatNamePtr(er.ErrorFormatIndex));
Add_Messsage_Pre_ArcType(s, "The file is open", codecs->GetFormatNamePtr(arc.FormatIndex));
}
*_so << s << endl << endl;
}
HRESULT CExtractCallbackConsole::OpenResult(
const CCodecs *codecs, const CArchiveLink &arcLink,
const wchar_t *name, HRESULT result)
{
_currentArchivePath = name;
_needWriteArchivePath = true;
ClosePercents();
if (NeedPercents())
{
_percent.Files = 0;
_percent.Command.Empty();
_percent.FileName.Empty();
}
ClosePercentsAndFlush();
FOR_VECTOR (level, arcLink.Arcs)
{
const CArc &arc = arcLink.Arcs[level];
const CArcErrorInfo &er = arc.ErrorInfo;
UInt32 errorFlags = er.GetErrorFlags();
if (errorFlags != 0 || !er.ErrorMessage.IsEmpty())
{
if (_se)
{
*_se << endl;
if (level != 0)
{
_se->NormalizePrint_UString_Path(arc.Path);
*_se << endl;
}
}
if (errorFlags != 0)
{
if (_se)
PrintErrorFlags(*_se, "ERRORS:", errorFlags);
NumOpenArcErrors++;
ThereIsError_in_Current = true;
}
if (!er.ErrorMessage.IsEmpty())
{
if (_se)
*_se << "ERRORS:" << endl << er.ErrorMessage << endl;
NumOpenArcErrors++;
ThereIsError_in_Current = true;
}
if (_se)
{
*_se << endl;
_se->Flush();
}
}
UInt32 warningFlags = er.GetWarningFlags();
if (warningFlags != 0 || !er.WarningMessage.IsEmpty())
{
if (_so)
{
*_so << endl;
if (level != 0)
{
_so->NormalizePrint_UString_Path(arc.Path);
*_so << endl;
}
}
if (warningFlags != 0)
{
if (_so)
PrintErrorFlags(*_so, "WARNINGS:", warningFlags);
NumOpenArcWarnings++;
ThereIsWarning_in_Current = true;
}
if (!er.WarningMessage.IsEmpty())
{
if (_so)
*_so << "WARNINGS:" << endl << er.WarningMessage << endl;
NumOpenArcWarnings++;
ThereIsWarning_in_Current = true;
}
if (_so)
{
*_so << endl;
if (NeedFlush)
_so->Flush();
}
}
if (er.ErrorFormatIndex >= 0)
{
if (_so)
{
Print_ErrorFormatIndex_Warning(_so, codecs, arc);
if (NeedFlush)
_so->Flush();
}
ThereIsWarning_in_Current = true;
}
}
if (result == S_OK)
{
if (_so)
{
RINOK(Print_OpenArchive_Props(*_so, codecs, arcLink))
*_so << endl;
}
}
else
{
NumCantOpenArcs++;
if (_so)
_so->Flush();
if (_se)
{
*_se << kError;
_se->NormalizePrint_wstr_Path(name);
*_se << endl;
const HRESULT res = Print_OpenArchive_Error(*_se, codecs, arcLink);
RINOK(res)
if (result == S_FALSE)
{
}
else
{
if (result == E_OUTOFMEMORY)
*_se << "Can't allocate required memory";
else
*_se << NError::MyFormatMessage(result);
*_se << endl;
}
_se->Flush();
}
}
return CheckBreak2();
}
HRESULT CExtractCallbackConsole::ThereAreNoFiles()
{
ClosePercents_for_so();
if (_so)
{
*_so << endl << kNoFiles << endl;
if (NeedFlush)
_so->Flush();
}
return CheckBreak2();
}
HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result)
{
MT_LOCK
if (NeedPercents())
{
_percent.ClosePrint(true);
_percent.Command.Empty();
_percent.FileName.Empty();
}
if (_so)
_so->Flush();
if (result == S_OK)
{
if (NumFileErrors_in_Current == 0 && !ThereIsError_in_Current)
{
if (ThereIsWarning_in_Current)
NumArcsWithWarnings++;
else
NumOkArcs++;
if (_so)
*_so << kEverythingIsOk << endl;
}
else
{
NumArcsWithError++;
if (_so)
{
*_so << endl;
if (NumFileErrors_in_Current != 0)
*_so << "Sub items Errors: " << NumFileErrors_in_Current << endl;
}
}
if (_so && NeedFlush)
_so->Flush();
}
else
{
// we don't update NumArcsWithError, if error is not related to archive data.
if (result == E_ABORT
|| result == HRESULT_FROM_WIN32(ERROR_DISK_FULL))
return result;
NumArcsWithError++;
if (_se)
{
*_se << endl << kError;
if (result == E_OUTOFMEMORY)
*_se << kMemoryExceptionMessage;
else
*_se << NError::MyFormatMessage(result);
*_se << endl;
_se->Flush();
}
}
return CheckBreak2();
}
@@ -0,0 +1,211 @@
// ExtractCallbackConsole.h
#ifndef ZIP7_INC_EXTRACT_CALLBACK_CONSOLE_H
#define ZIP7_INC_EXTRACT_CALLBACK_CONSOLE_H
#include "../../../Common/StdOutStream.h"
#include "../../IPassword.h"
#include "../../Archive/IArchive.h"
#include "../Common/ArchiveExtractCallback.h"
#include "PercentPrinter.h"
#include "OpenCallbackConsole.h"
/*
struct CErrorPathCodes2
{
FStringVector Paths;
CRecordVector<DWORD> Codes;
void AddError(const FString &path, DWORD systemError)
{
Paths.Add(path);
Codes.Add(systemError);
}
void Clear()
{
Paths.Clear();
Codes.Clear();
}
};
*/
class CExtractScanConsole Z7_final: public IDirItemsCallback
{
Z7_IFACE_IMP(IDirItemsCallback)
CStdOutStream *_so;
CStdOutStream *_se;
CPercentPrinter _percent;
// CErrorPathCodes2 ScanErrors;
bool NeedPercents() const { return _percent._so && !_percent.DisablePrint; }
void ClosePercentsAndFlush()
{
if (NeedPercents())
_percent.ClosePrint(true);
if (_so)
_so->Flush();
}
public:
void Init(
CStdOutStream *outStream,
CStdOutStream *errorStream,
CStdOutStream *percentStream,
bool disablePercents)
{
_so = outStream;
_se = errorStream;
_percent._so = percentStream;
_percent.DisablePrint = disablePercents;
}
void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; }
void StartScanning();
void CloseScanning()
{
if (NeedPercents())
_percent.ClosePrint(true);
}
void PrintStat(const CDirItemsStat &st);
};
class CExtractCallbackConsole Z7_final:
public IFolderArchiveExtractCallback,
public IExtractCallbackUI,
// public IArchiveExtractCallbackMessage,
public IFolderArchiveExtractCallback2,
#ifndef Z7_NO_CRYPTO
public ICryptoGetTextPassword,
#endif
#ifndef Z7_SFX
public IArchiveRequestMemoryUseCallback,
#endif
public COpenCallbackConsole,
public CMyUnknownImp
{
Z7_COM_QI_BEGIN2(IFolderArchiveExtractCallback)
// Z7_COM_QI_ENTRY(IArchiveExtractCallbackMessage)
Z7_COM_QI_ENTRY(IFolderArchiveExtractCallback2)
#ifndef Z7_NO_CRYPTO
Z7_COM_QI_ENTRY(ICryptoGetTextPassword)
#endif
#ifndef Z7_SFX
Z7_COM_QI_ENTRY(IArchiveRequestMemoryUseCallback)
#endif
Z7_COM_QI_END
Z7_COM_ADDREF_RELEASE
Z7_IFACE_COM7_IMP(IProgress)
Z7_IFACE_COM7_IMP(IFolderArchiveExtractCallback)
Z7_IFACE_IMP(IExtractCallbackUI)
// Z7_IFACE_COM7_IMP(IArchiveExtractCallbackMessage)
Z7_IFACE_COM7_IMP(IFolderArchiveExtractCallback2)
#ifndef Z7_NO_CRYPTO
Z7_IFACE_COM7_IMP(ICryptoGetTextPassword)
#endif
#ifndef Z7_SFX
Z7_IFACE_COM7_IMP(IArchiveRequestMemoryUseCallback)
#endif
bool _needWriteArchivePath;
public:
bool ThereIsError_in_Current;
bool ThereIsWarning_in_Current;
bool NeedFlush;
private:
AString _tempA;
UString _tempU;
UString _currentArchivePath;
UString _currentName;
#ifndef Z7_SFX
void PrintTo_se_Path_WithTitle(const UString &path, const char *title);
void Add_ArchiveName_Error();
#endif
void ClosePercents_for_so()
{
if (NeedPercents() && _so == _percent._so)
_percent.ClosePrint(false);
}
void ClosePercentsAndFlush()
{
if (NeedPercents())
_percent.ClosePrint(true);
if (_so)
_so->Flush();
}
public:
UInt64 NumTryArcs;
UInt64 NumOkArcs;
UInt64 NumCantOpenArcs;
UInt64 NumArcsWithError;
UInt64 NumArcsWithWarnings;
UInt64 NumOpenArcErrors;
UInt64 NumOpenArcWarnings;
UInt64 NumFileErrors;
UInt64 NumFileErrors_in_Current;
unsigned PercentsNameLevel;
unsigned LogLevel;
CExtractCallbackConsole():
_needWriteArchivePath(true),
NeedFlush(false),
PercentsNameLevel(1),
LogLevel(0)
{}
void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; }
void Init(
CStdOutStream *outStream,
CStdOutStream *errorStream,
CStdOutStream *percentStream,
bool disablePercents)
{
COpenCallbackConsole::Init(outStream, errorStream, percentStream, disablePercents);
NumTryArcs = 0;
ThereIsError_in_Current = false;
ThereIsWarning_in_Current = false;
NumOkArcs = 0;
NumCantOpenArcs = 0;
NumArcsWithError = 0;
NumArcsWithWarnings = 0;
NumOpenArcErrors = 0;
NumOpenArcWarnings = 0;
NumFileErrors = 0;
NumFileErrors_in_Current = 0;
}
};
#endif
@@ -0,0 +1,426 @@
// HashCon.cpp
#include "StdAfx.h"
#include "../../../Common/IntToString.h"
#include "../../../Windows/FileName.h"
#include "ConsoleClose.h"
#include "HashCon.h"
static const char * const kEmptyFileAlias = "[Content]";
static const char * const kScanningMessage = "Scanning";
static HRESULT CheckBreak2()
{
return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
}
HRESULT CHashCallbackConsole::CheckBreak()
{
return CheckBreak2();
}
HRESULT CHashCallbackConsole::StartScanning()
{
if (PrintHeaders && _so)
*_so << kScanningMessage << endl;
if (NeedPercents())
{
_percent.ClearCurState();
_percent.Command = "Scan";
}
return CheckBreak2();
}
HRESULT CHashCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir)
{
if (NeedPercents())
{
_percent.Files = st.NumDirs + st.NumFiles + st.NumAltStreams;
_percent.Completed = st.GetTotalBytes();
_percent.FileName = fs2us(path);
if (isDir)
NWindows::NFile::NName::NormalizeDirPathPrefix(_percent.FileName);
_percent.Print();
}
return CheckBreak2();
}
HRESULT CHashCallbackConsole::ScanError(const FString &path, DWORD systemError)
{
return ScanError_Base(path, systemError);
}
void Print_DirItemsStat(AString &s, const CDirItemsStat &st);
HRESULT CHashCallbackConsole::FinishScanning(const CDirItemsStat &st)
{
if (NeedPercents())
{
_percent.ClosePrint(true);
_percent.ClearCurState();
}
if (PrintHeaders && _so)
{
Print_DirItemsStat(_s, st);
*_so << _s << endl << endl;
}
return CheckBreak2();
}
HRESULT CHashCallbackConsole::SetNumFiles(UInt64 /* numFiles */)
{
return CheckBreak2();
}
HRESULT CHashCallbackConsole::SetTotal(UInt64 size)
{
if (NeedPercents())
{
_percent.Total = size;
_percent.Print();
}
return CheckBreak2();
}
HRESULT CHashCallbackConsole::SetCompleted(const UInt64 *completeValue)
{
if (completeValue && NeedPercents())
{
_percent.Completed = *completeValue;
_percent.Print();
}
return CheckBreak2();
}
static void AddMinuses(AString &s, unsigned num)
{
for (unsigned i = 0; i < num; i++)
s.Add_Minus();
}
static void AddSpaces_if_Positive(AString &s, int num)
{
for (int i = 0; i < num; i++)
s.Add_Space();
}
static void SetSpacesAndNul(char *s, unsigned num)
{
for (unsigned i = 0; i < num; i++)
s[i] = ' ';
s[num] = 0;
}
static void SetSpacesAndNul_if_Positive(char *s, int num)
{
if (num < 0)
return;
for (int i = 0; i < num; i++)
s[i] = ' ';
s[num] = 0;
}
static const unsigned kSizeField_Len = 13;
static const unsigned kNameField_Len = 12;
static const unsigned kHashColumnWidth_Min = 4 * 2;
static unsigned GetColumnWidth(unsigned digestSize)
{
unsigned width = digestSize * 2;
return width < kHashColumnWidth_Min ? kHashColumnWidth_Min: width;
}
AString CHashCallbackConsole::GetFields() const
{
AString s (PrintFields);
if (s.IsEmpty())
s = "hsn";
s.MakeLower_Ascii();
return s;
}
void CHashCallbackConsole::PrintSeparatorLine(const CObjectVector<CHasherState> &hashers)
{
_s.Empty();
const AString fields = GetFields();
for (unsigned pos = 0; pos < fields.Len(); pos++)
{
const char c = fields[pos];
if (c == 'h')
{
for (unsigned i = 0; i < hashers.Size(); i++)
{
AddSpace();
const CHasherState &h = hashers[i];
AddMinuses(_s, GetColumnWidth(h.DigestSize));
}
}
else if (c == 's')
{
AddSpace();
AddMinuses(_s, kSizeField_Len);
}
else if (c == 'n')
{
AddSpacesBeforeName();
AddMinuses(_s, kNameField_Len);
}
}
*_so << _s << endl;
}
HRESULT CHashCallbackConsole::BeforeFirstFile(const CHashBundle &hb)
{
if (PrintHeaders && _so)
{
_s.Empty();
ClosePercents_for_so();
const AString fields = GetFields();
for (unsigned pos = 0; pos < fields.Len(); pos++)
{
const char c = fields[pos];
if (c == 'h')
{
FOR_VECTOR (i, hb.Hashers)
{
AddSpace();
const CHasherState &h = hb.Hashers[i];
_s += h.Name;
AddSpaces_if_Positive(_s, (int)GetColumnWidth(h.DigestSize) - (int)h.Name.Len());
}
}
else if (c == 's')
{
AddSpace();
const AString s2 ("Size");
AddSpaces_if_Positive(_s, (int)kSizeField_Len - (int)s2.Len());
_s += s2;
}
else if (c == 'n')
{
AddSpacesBeforeName();
_s += "Name";
}
}
*_so << _s << endl;
PrintSeparatorLine(hb.Hashers);
}
return CheckBreak2();
}
HRESULT CHashCallbackConsole::OpenFileError(const FString &path, DWORD systemError)
{
return OpenFileError_Base(path, systemError);
}
HRESULT CHashCallbackConsole::GetStream(const wchar_t *name, bool isDir)
{
_fileName = name;
if (isDir)
NWindows::NFile::NName::NormalizeDirPathPrefix(_fileName);
if (NeedPercents())
{
if (PrintNameInPercents)
{
_percent.FileName.Empty();
if (name)
_percent.FileName = name;
}
_percent.Print();
}
return CheckBreak2();
}
static const unsigned k_DigestStringSize = k_HashCalc_DigestSize_Max * 2 + k_HashCalc_ExtraSize * 2 + 16;
void CHashCallbackConsole::PrintResultLine(UInt64 fileSize,
const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash,
const AString &path)
{
ClosePercents_for_so();
_s.Empty();
const AString fields = GetFields();
for (unsigned pos = 0; pos < fields.Len(); pos++)
{
const char c = fields[pos];
if (c == 'h')
{
FOR_VECTOR (i, hashers)
{
AddSpace();
const CHasherState &h = hashers[i];
char s[k_DigestStringSize];
s[0] = 0;
if (showHash)
h.WriteToString(digestIndex, s);
const unsigned len = (unsigned)strlen(s);
SetSpacesAndNul_if_Positive(s + len, (int)GetColumnWidth(h.DigestSize) - (int)len);
_s += s;
}
}
else if (c == 's')
{
AddSpace();
char s[kSizeField_Len + 32];
char *p = s;
SetSpacesAndNul(s, kSizeField_Len);
if (showHash)
{
p = s + kSizeField_Len;
ConvertUInt64ToString(fileSize, p);
const int numSpaces = (int)kSizeField_Len - (int)strlen(p);
if (numSpaces > 0)
p -= (unsigned)numSpaces;
}
_s += p;
}
else if (c == 'n')
{
AddSpacesBeforeName();
_s += path;
}
}
*_so << _s;
}
HRESULT CHashCallbackConsole::SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash)
{
if (_so)
{
AString s;
if (_fileName.IsEmpty())
s = kEmptyFileAlias;
else
{
UString temp (_fileName);
_so->Normalize_UString_Path(temp);
_so->Convert_UString_to_AString(temp, s);
}
PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash, s);
/*
PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash);
if (PrintName)
{
if (_fileName.IsEmpty())
*_so << kEmptyFileAlias;
else
_so->NormalizePrint_UString(_fileName);
}
*/
// if (PrintNewLine)
*_so << endl;
}
if (NeedPercents())
{
_percent.Files++;
_percent.Print();
}
return CheckBreak2();
}
static const char * const k_DigestTitles[] =
{
" : "
, " for data: "
, " for data and names: "
, " for streams and names: "
};
static void PrintSum(CStdOutStream &so, const CHasherState &h, unsigned digestIndex)
{
so << h.Name;
{
AString temp;
AddSpaces_if_Positive(temp, 6 - (int)h.Name.Len());
so << temp;
}
so << k_DigestTitles[digestIndex];
char s[k_DigestStringSize];
// s[0] = 0;
h.WriteToString(digestIndex, s);
so << s << endl;
}
void PrintHashStat(CStdOutStream &so, const CHashBundle &hb)
{
FOR_VECTOR (i, hb.Hashers)
{
const CHasherState &h = hb.Hashers[i];
PrintSum(so, h, k_HashCalc_Index_DataSum);
if (hb.NumFiles != 1 || hb.NumDirs != 0)
PrintSum(so, h, k_HashCalc_Index_NamesSum);
if (hb.NumAltStreams != 0)
PrintSum(so, h, k_HashCalc_Index_StreamsSum);
so << endl;
}
}
void CHashCallbackConsole::PrintProperty(const char *name, UInt64 value)
{
char s[32];
s[0] = ':';
s[1] = ' ';
ConvertUInt64ToString(value, s + 2);
*_so << name << s << endl;
}
HRESULT CHashCallbackConsole::AfterLastFile(CHashBundle &hb)
{
ClosePercents2();
if (PrintHeaders && _so)
{
PrintSeparatorLine(hb.Hashers);
PrintResultLine(hb.FilesSize, hb.Hashers, k_HashCalc_Index_DataSum, true, AString());
*_so << endl << endl;
if (hb.NumFiles != 1 || hb.NumDirs != 0)
{
if (hb.NumDirs != 0)
PrintProperty("Folders", hb.NumDirs);
PrintProperty("Files", hb.NumFiles);
}
PrintProperty("Size", hb.FilesSize);
if (hb.NumAltStreams != 0)
{
PrintProperty("Alternate streams", hb.NumAltStreams);
PrintProperty("Alternate streams size", hb.AltStreamsSize);
}
*_so << endl;
PrintHashStat(*_so, hb);
}
return S_OK;
}
@@ -0,0 +1,58 @@
// HashCon.h
#ifndef ZIP7_INC_HASH_CON_H
#define ZIP7_INC_HASH_CON_H
#include "../Common/HashCalc.h"
#include "UpdateCallbackConsole.h"
class CHashCallbackConsole Z7_final:
public IHashCallbackUI,
public CCallbackConsoleBase
{
Z7_IFACE_IMP(IDirItemsCallback)
Z7_IFACE_IMP(IHashCallbackUI)
UString _fileName;
AString _s;
void AddSpace()
{
_s.Add_Space_if_NotEmpty();
}
void AddSpacesBeforeName()
{
if (!_s.IsEmpty())
{
_s.Add_Space();
_s.Add_Space();
}
}
void PrintSeparatorLine(const CObjectVector<CHasherState> &hashers);
void PrintResultLine(UInt64 fileSize,
const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash, const AString &path);
void PrintProperty(const char *name, UInt64 value);
public:
bool PrintNameInPercents;
bool PrintHeaders;
// bool PrintSize;
// bool PrintNewLine; // set it too (false), if you need only hash for single file without LF char.
AString PrintFields;
AString GetFields() const;
CHashCallbackConsole():
PrintNameInPercents(true),
PrintHeaders(false)
// , PrintSize(true),
// , PrintNewLine(true)
{}
};
void PrintHashStat(CStdOutStream &so, const CHashBundle &hb);
#endif
File diff suppressed because it is too large Load Diff
+42
View File
@@ -0,0 +1,42 @@
// List.h
#ifndef ZIP7_INC_LIST_H
#define ZIP7_INC_LIST_H
#include "../../../Common/Wildcard.h"
#include "../Common/LoadCodecs.h"
struct CListOptions
{
bool ExcludeDirItems;
bool ExcludeFileItems;
bool DisablePercents;
CListOptions():
ExcludeDirItems(false),
ExcludeFileItems(false),
DisablePercents(false)
{}
};
HRESULT ListArchives(
const CListOptions &listOptions,
CCodecs *codecs,
const CObjectVector<COpenType> &types,
const CIntVector &excludedFormats,
bool stdInMode,
UStringVector &archivePaths, UStringVector &archivePathsFull,
bool processAltStreams, bool showAltStreams,
const NWildcard::CCensorNode &wildcardCensor,
bool enableHeaders, bool techMode,
#ifndef Z7_NO_CRYPTO
bool &passwordEnabled, UString &password,
#endif
#ifndef Z7_SFX
const CObjectVector<CProperty> *props,
#endif
UInt64 &errors,
UInt64 &numWarnings);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,235 @@
// MainAr.cpp
#include "StdAfx.h"
#ifdef _WIN32
#include "../../../../C/DllSecur.h"
#endif
#include "../../../../C/CpuArch.h"
#include "../../../Common/MyException.h"
#include "../../../Common/StdOutStream.h"
#include "../../../Windows/ErrorMsg.h"
#include "../../../Windows/NtCheck.h"
#include "../Common/ArchiveCommandLine.h"
#include "../Common/ExitCode.h"
#include "ConsoleClose.h"
using namespace NWindows;
extern
CStdOutStream *g_StdStream;
CStdOutStream *g_StdStream = NULL;
extern
CStdOutStream *g_ErrStream;
CStdOutStream *g_ErrStream = NULL;
extern int Main2(
#ifndef _WIN32
int numArgs, char *args[]
#endif
);
static const char * const kException_CmdLine_Error_Message = "Command Line Error:";
static const char * const kExceptionErrorMessage = "ERROR:";
static const char * const kUserBreakMessage = "Break signaled";
static const char * const kMemoryExceptionMessage = "ERROR: Can't allocate required memory!";
static const char * const kUnknownExceptionMessage = "Unknown Error";
static const char * const kInternalExceptionMessage = "\n\nInternal Error #";
static void FlushStreams()
{
if (g_StdStream)
g_StdStream->Flush();
}
static void PrintError(const char *message)
{
FlushStreams();
if (g_ErrStream)
*g_ErrStream << "\n\n" << message << endl;
}
#if defined(_WIN32) && defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
#define NT_CHECK_FAIL_ACTION *g_StdStream << "Unsupported Windows version"; return NExitCode::kFatalError;
#endif
static inline bool CheckIsa()
{
// __try
{
// some compilers (e2k) support SSE/AVX, but cpuid() can be unavailable or return lower isa support
#ifdef MY_CPU_X86_OR_AMD64
#if 0 && (defined(__AVX512F__) && defined(__AVX512VL__))
if (!CPU_IsSupported_AVX512F_AVX512VL())
return false;
#elif defined(__AVX2__)
if (!CPU_IsSupported_AVX2())
return false;
#elif defined(__AVX__)
if (!CPU_IsSupported_AVX())
return false;
#elif defined(__SSE2__) && !defined(MY_CPU_AMD64) || defined(_M_IX86_FP) && (_M_IX86_FP >= 2)
if (!CPU_IsSupported_SSE2())
return false;
#elif defined(__SSE__) && !defined(MY_CPU_AMD64) || defined(_M_IX86_FP) && (_M_IX86_FP >= 1)
if (!CPU_IsSupported_SSE() ||
!CPU_IsSupported_CMOV())
return false;
#endif
#endif
/*
__asm
{
_emit 0fH
_emit 038H
_emit 0cbH
_emit (0c0H + 0 * 8 + 0)
}
*/
return true;
}
/*
__except (EXCEPTION_EXECUTE_HANDLER)
{
return false;
}
*/
}
int Z7_CDECL main
(
#ifndef _WIN32
int numArgs, char *args[]
#endif
)
{
g_ErrStream = &g_StdErr;
g_StdStream = &g_StdOut;
// #if (defined(_MSC_VER) && defined(_M_IX86))
if (!CheckIsa())
{
PrintError("ERROR: processor doesn't support required ISA extension");
return NExitCode::kFatalError;
}
// #endif
NT_CHECK
NConsoleClose::CCtrlHandlerSetter ctrlHandlerSetter;
int res = 0;
try
{
#ifdef _WIN32
My_SetDefaultDllDirectories();
#endif
res = Main2(
#ifndef _WIN32
numArgs, args
#endif
);
}
catch(const CNewException &)
{
PrintError(kMemoryExceptionMessage);
return (NExitCode::kMemoryError);
}
/*
catch(const NConsoleClose::CCtrlBreakException &)
{
PrintError(kUserBreakMessage);
return (NExitCode::kUserBreak);
}
*/
catch(const CMessagePathException &e)
{
PrintError(kException_CmdLine_Error_Message);
if (g_ErrStream)
*g_ErrStream << e << endl;
return (NExitCode::kUserError);
}
catch(const CSystemException &systemError)
{
if (systemError.ErrorCode == E_OUTOFMEMORY)
{
PrintError(kMemoryExceptionMessage);
return (NExitCode::kMemoryError);
}
if (systemError.ErrorCode == E_ABORT)
{
PrintError(kUserBreakMessage);
return (NExitCode::kUserBreak);
}
if (g_ErrStream)
{
PrintError("System ERROR:");
*g_ErrStream << NError::MyFormatMessage(systemError.ErrorCode) << endl;
}
return (NExitCode::kFatalError);
}
catch(NExitCode::EEnum exitCode)
{
FlushStreams();
if (g_ErrStream)
*g_ErrStream << kInternalExceptionMessage << exitCode << endl;
return (exitCode);
}
catch(const UString &s)
{
if (g_ErrStream)
{
PrintError(kExceptionErrorMessage);
*g_ErrStream << s << endl;
}
return (NExitCode::kFatalError);
}
catch(const AString &s)
{
if (g_ErrStream)
{
PrintError(kExceptionErrorMessage);
*g_ErrStream << s << endl;
}
return (NExitCode::kFatalError);
}
catch(const char *s)
{
if (g_ErrStream)
{
PrintError(kExceptionErrorMessage);
*g_ErrStream << s << endl;
}
return (NExitCode::kFatalError);
}
catch(const wchar_t *s)
{
if (g_ErrStream)
{
PrintError(kExceptionErrorMessage);
*g_ErrStream << s << endl;
}
return (NExitCode::kFatalError);
}
catch(int t)
{
if (g_ErrStream)
{
FlushStreams();
*g_ErrStream << kInternalExceptionMessage << t << endl;
return (NExitCode::kFatalError);
}
}
catch(...)
{
PrintError(kUnknownExceptionMessage);
return (NExitCode::kFatalError);
}
return res;
}
@@ -0,0 +1,115 @@
// OpenCallbackConsole.cpp
#include "StdAfx.h"
#include "OpenCallbackConsole.h"
#include "ConsoleClose.h"
#include "UserInputUtils.h"
static HRESULT CheckBreak2()
{
return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
}
HRESULT COpenCallbackConsole::Open_CheckBreak()
{
return CheckBreak2();
}
HRESULT COpenCallbackConsole::Open_SetTotal(const UInt64 *files, const UInt64 *bytes)
{
if (!MultiArcMode && NeedPercents())
{
if (files)
{
_totalFilesDefined = true;
// _totalFiles = *files;
_percent.Total = *files;
}
else
_totalFilesDefined = false;
if (bytes)
{
// _totalBytesDefined = true;
_totalBytes = *bytes;
if (!files)
_percent.Total = *bytes;
}
else
{
// _totalBytesDefined = false;
if (!files)
_percent.Total = _totalBytes;
}
}
return CheckBreak2();
}
HRESULT COpenCallbackConsole::Open_SetCompleted(const UInt64 *files, const UInt64 *bytes)
{
if (!MultiArcMode && NeedPercents())
{
if (files)
{
_percent.Files = *files;
if (_totalFilesDefined)
_percent.Completed = *files;
}
if (bytes)
{
if (!_totalFilesDefined)
_percent.Completed = *bytes;
}
_percent.Print();
}
return CheckBreak2();
}
HRESULT COpenCallbackConsole::Open_Finished()
{
ClosePercents();
return S_OK;
}
#ifndef Z7_NO_CRYPTO
HRESULT COpenCallbackConsole::Open_CryptoGetTextPassword(BSTR *password)
{
*password = NULL;
RINOK(CheckBreak2())
if (!PasswordIsDefined)
{
ClosePercents();
RINOK(GetPassword_HRESULT(_so, Password))
PasswordIsDefined = true;
}
return StringToBstr(Password, password);
}
/*
HRESULT COpenCallbackConsole::Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password)
{
passwordIsDefined = PasswordIsDefined;
password = Password;
return S_OK;
}
bool COpenCallbackConsole::Open_WasPasswordAsked()
{
return PasswordWasAsked;
}
void COpenCallbackConsole::Open_Clear_PasswordWasAsked_Flag ()
{
PasswordWasAsked = false;
}
*/
#endif
@@ -0,0 +1,73 @@
// OpenCallbackConsole.h
#ifndef ZIP7_INC_OPEN_CALLBACK_CONSOLE_H
#define ZIP7_INC_OPEN_CALLBACK_CONSOLE_H
#include "../../../Common/StdOutStream.h"
#include "../Common/ArchiveOpenCallback.h"
#include "PercentPrinter.h"
class COpenCallbackConsole: public IOpenCallbackUI
{
protected:
CPercentPrinter _percent;
CStdOutStream *_so;
CStdOutStream *_se;
// UInt64 _totalFiles;
UInt64 _totalBytes;
bool _totalFilesDefined;
// bool _totalBytesDefined;
bool NeedPercents() const { return _percent._so && !_percent.DisablePrint; }
public:
bool MultiArcMode;
void ClosePercents()
{
if (NeedPercents())
_percent.ClosePrint(true);
}
COpenCallbackConsole():
_totalBytes(0),
_totalFilesDefined(false),
// _totalBytesDefined(false),
MultiArcMode(false)
#ifndef Z7_NO_CRYPTO
, PasswordIsDefined(false)
// , PasswordWasAsked(false)
#endif
{}
virtual ~COpenCallbackConsole() {}
void Init(
CStdOutStream *outStream,
CStdOutStream *errorStream,
CStdOutStream *percentStream,
bool disablePercents)
{
_so = outStream;
_se = errorStream;
_percent._so = percentStream;
_percent.DisablePrint = disablePercents;
}
Z7_IFACE_IMP(IOpenCallbackUI)
#ifndef Z7_NO_CRYPTO
bool PasswordIsDefined;
// bool PasswordWasAsked;
UString Password;
#endif
};
#endif
@@ -0,0 +1,186 @@
// PercentPrinter.cpp
#include "StdAfx.h"
#include "../../../Common/IntToString.h"
#include "PercentPrinter.h"
static const unsigned kPercentsSize = 4;
CPercentPrinter::~CPercentPrinter()
{
ClosePrint(false);
}
void CPercentPrinterState::ClearCurState()
{
Completed = 0;
Total = ((UInt64)(Int64)-1);
Files = 0;
Command.Empty();
FileName.Empty();
}
void CPercentPrinter::ClosePrint(bool needFlush)
{
unsigned num = _printedString.Len();
if (num != 0)
{
unsigned i;
/* '\r' in old MAC OS means "new line".
So we can't use '\r' in some systems */
#ifdef _WIN32
char *start = _temp.GetBuf(num + 2);
char *p = start;
*p++ = '\r';
for (i = 0; i < num; i++) *p++ = ' ';
*p++ = '\r';
#else
char *start = _temp.GetBuf(num * 3);
char *p = start;
for (i = 0; i < num; i++) *p++ = '\b';
for (i = 0; i < num; i++) *p++ = ' ';
for (i = 0; i < num; i++) *p++ = '\b';
#endif
*p = 0;
_temp.ReleaseBuf_SetLen((unsigned)(p - start));
*_so << _temp;
}
if (needFlush)
_so->Flush();
_printedString.Empty();
}
void CPercentPrinter::GetPercents()
{
char s[32];
unsigned size;
{
char c = '%';
UInt64 val = 0;
if (Total == (UInt64)(Int64)-1 ||
(Total == 0 && Completed != 0))
{
val = Completed >> 20;
c = 'M';
}
else if (Total != 0)
val = Completed * 100 / Total;
ConvertUInt64ToString(val, s);
size = (unsigned)strlen(s);
s[size++] = c;
s[size] = 0;
}
while (size < kPercentsSize)
{
_s.Add_Space();
size++;
}
_s += s;
}
void CPercentPrinter::Print()
{
if (DisablePrint)
return;
DWORD tick = 0;
if (_tickStep != 0)
tick = GetTickCount();
bool onlyPercentsChanged = false;
if (!_printedString.IsEmpty())
{
if (_tickStep != 0 && (UInt32)(tick - _prevTick) < _tickStep)
return;
CPercentPrinterState &st = *this;
if (_printedState.Command == st.Command
&& _printedState.FileName == st.FileName
&& _printedState.Files == st.Files)
{
if (_printedState.Total == st.Total
&& _printedState.Completed == st.Completed)
return;
onlyPercentsChanged = true;
}
}
_s.Empty();
GetPercents();
if (onlyPercentsChanged && _s == _printedPercents)
return;
_printedPercents = _s;
if (Files != 0)
{
char s[32];
ConvertUInt64ToString(Files, s);
// unsigned size = (unsigned)strlen(s);
// for (; size < 3; size++) _s.Add_Space();
_s.Add_Space();
_s += s;
// _s += "f";
}
if (!Command.IsEmpty())
{
_s.Add_Space();
_s += Command;
}
if (!FileName.IsEmpty() && _s.Len() < MaxLen)
{
_s.Add_Space();
_tempU = FileName;
_so->Normalize_UString_Path(_tempU);
_so->Convert_UString_to_AString(_tempU, _temp);
if (_s.Len() + _temp.Len() > MaxLen)
{
unsigned len = FileName.Len();
for (; len != 0;)
{
unsigned delta = len / 8;
if (delta == 0)
delta = 1;
len -= delta;
_tempU = FileName;
_tempU.Delete(len / 2, _tempU.Len() - len);
_tempU.Insert(len / 2, L" . ");
_so->Normalize_UString_Path(_tempU);
_so->Convert_UString_to_AString(_tempU, _temp);
if (_s.Len() + _temp.Len() <= MaxLen)
break;
}
if (len == 0)
_temp.Empty();
}
_s += _temp;
}
if (_printedString != _s)
{
ClosePrint(false);
*_so << _s;
if (NeedFlush)
_so->Flush();
_printedString = _s;
}
_printedState = *this;
if (_tickStep != 0)
_prevTick = tick;
}
@@ -0,0 +1,66 @@
// PercentPrinter.h
#ifndef ZIP7_INC_PERCENT_PRINTER_H
#define ZIP7_INC_PERCENT_PRINTER_H
#include "../../../Common/StdOutStream.h"
struct CPercentPrinterState
{
UInt64 Completed;
UInt64 Total;
UInt64 Files;
AString Command;
UString FileName;
void ClearCurState();
CPercentPrinterState():
Completed(0),
Total((UInt64)(Int64)-1),
Files(0)
{}
};
class CPercentPrinter: public CPercentPrinterState
{
public:
CStdOutStream *_so;
bool DisablePrint;
bool NeedFlush;
unsigned MaxLen;
private:
UInt32 _tickStep;
DWORD _prevTick;
AString _s;
AString _printedString;
AString _temp;
UString _tempU;
CPercentPrinterState _printedState;
AString _printedPercents;
void GetPercents();
public:
CPercentPrinter(UInt32 tickStep = 200):
DisablePrint(false),
NeedFlush(true),
MaxLen(80 - 1),
_tickStep(tickStep),
_prevTick(0)
{}
~CPercentPrinter();
void ClosePrint(bool needFlush);
void Print();
};
#endif
@@ -0,0 +1,3 @@
// StdAfx.cpp
#include "StdAfx.h"
@@ -0,0 +1,11 @@
// StdAfx.h
#ifndef ZIP7_INC_STDAFX_H
#define ZIP7_INC_STDAFX_H
#if defined(_MSC_VER) && _MSC_VER >= 1800
#pragma warning(disable : 4464) // relative include path contains '..'
#endif
#include "../../../Common/Common.h"
#endif
@@ -0,0 +1,998 @@
// UpdateCallbackConsole.cpp
#include "StdAfx.h"
#include "../../../Common/IntToString.h"
#include "../../../Windows/ErrorMsg.h"
#include "../../../Windows/FileName.h"
#ifndef Z7_ST
#include "../../../Windows/Synchronization.h"
#endif
// #include "../Common/PropIDUtils.h"
#include "ConsoleClose.h"
#include "UserInputUtils.h"
#include "UpdateCallbackConsole.h"
using namespace NWindows;
#ifndef Z7_ST
static NSynchronization::CCriticalSection g_CriticalSection;
#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
#else
#define MT_LOCK
#endif
static const wchar_t * const kEmptyFileAlias = L"[Content]";
static const char * const kOpenArchiveMessage = "Open archive: ";
static const char * const kCreatingArchiveMessage = "Creating archive: ";
static const char * const kUpdatingArchiveMessage = "Updating archive: ";
static const char * const kScanningMessage = "Scanning the drive:";
static const char * const kError = "ERROR: ";
static const char * const kWarning = "WARNING: ";
static HRESULT CheckBreak2()
{
return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
}
HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags);
void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc);
HRESULT CUpdateCallbackConsole::OpenResult(
const CCodecs *codecs, const CArchiveLink &arcLink,
const wchar_t *name, HRESULT result)
{
ClosePercents2();
FOR_VECTOR (level, arcLink.Arcs)
{
const CArc &arc = arcLink.Arcs[level];
const CArcErrorInfo &er = arc.ErrorInfo;
UInt32 errorFlags = er.GetErrorFlags();
if (errorFlags != 0 || !er.ErrorMessage.IsEmpty())
{
if (_se)
{
*_se << endl;
if (level != 0)
*_se << arc.Path << endl;
}
if (errorFlags != 0)
{
if (_se)
PrintErrorFlags(*_se, "ERRORS:", errorFlags);
}
if (!er.ErrorMessage.IsEmpty())
{
if (_se)
*_se << "ERRORS:" << endl << er.ErrorMessage << endl;
}
if (_se)
{
*_se << endl;
_se->Flush();
}
}
UInt32 warningFlags = er.GetWarningFlags();
if (warningFlags != 0 || !er.WarningMessage.IsEmpty())
{
if (_so)
{
*_so << endl;
if (level != 0)
*_so << arc.Path << endl;
}
if (warningFlags != 0)
{
if (_so)
PrintErrorFlags(*_so, "WARNINGS:", warningFlags);
}
if (!er.WarningMessage.IsEmpty())
{
if (_so)
*_so << "WARNINGS:" << endl << er.WarningMessage << endl;
}
if (_so)
{
*_so << endl;
if (NeedFlush)
_so->Flush();
}
}
if (er.ErrorFormatIndex >= 0)
{
if (_so)
{
Print_ErrorFormatIndex_Warning(_so, codecs, arc);
if (NeedFlush)
_so->Flush();
}
}
}
if (result == S_OK)
{
if (_so)
{
RINOK(Print_OpenArchive_Props(*_so, codecs, arcLink))
*_so << endl;
}
}
else
{
if (_so)
_so->Flush();
if (_se)
{
*_se << kError;
_se->NormalizePrint_wstr_Path(name);
*_se << endl;
HRESULT res = Print_OpenArchive_Error(*_se, codecs, arcLink);
RINOK(res)
_se->Flush();
}
}
return S_OK;
}
HRESULT CUpdateCallbackConsole::StartScanning()
{
if (_so)
*_so << kScanningMessage << endl;
_percent.Command = "Scan ";
return S_OK;
}
HRESULT CUpdateCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */)
{
if (NeedPercents())
{
_percent.Files = st.NumDirs + st.NumFiles + st.NumAltStreams;
_percent.Completed = st.GetTotalBytes();
_percent.FileName = fs2us(path);
_percent.Print();
}
return CheckBreak();
}
void CCallbackConsoleBase::CommonError(const FString &path, DWORD systemError, bool isWarning)
{
ClosePercents2();
if (_se)
{
if (_so)
_so->Flush();
*_se << endl << (isWarning ? kWarning : kError)
<< NError::MyFormatMessage(systemError)
<< endl;
_se->NormalizePrint_UString_Path(fs2us(path));
*_se << endl << endl;
_se->Flush();
}
}
/*
void CCallbackConsoleBase::CommonError(const char *message)
{
ClosePercents2();
if (_se)
{
if (_so)
_so->Flush();
*_se << endl << kError << message << endl;
_se->Flush();
}
}
*/
HRESULT CCallbackConsoleBase::ScanError_Base(const FString &path, DWORD systemError)
{
MT_LOCK
ScanErrors.AddError(path, systemError);
CommonError(path, systemError, true);
return S_OK;
}
HRESULT CCallbackConsoleBase::OpenFileError_Base(const FString &path, DWORD systemError)
{
MT_LOCK
FailedFiles.AddError(path, systemError);
NumNonOpenFiles++;
/*
if (systemError == ERROR_SHARING_VIOLATION)
{
*/
CommonError(path, systemError, true);
return S_FALSE;
/*
}
return systemError;
*/
}
HRESULT CCallbackConsoleBase::ReadingFileError_Base(const FString &path, DWORD systemError)
{
MT_LOCK
CommonError(path, systemError, false);
return HRESULT_FROM_WIN32(systemError);
}
HRESULT CUpdateCallbackConsole::ScanError(const FString &path, DWORD systemError)
{
return ScanError_Base(path, systemError);
}
static void PrintPropPair(AString &s, const char *name, UInt64 val)
{
char temp[32];
ConvertUInt64ToString(val, temp);
s += name;
s += ": ";
s += temp;
}
void PrintSize_bytes_Smart(AString &s, UInt64 val);
void Print_DirItemsStat(AString &s, const CDirItemsStat &st);
void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st);
HRESULT CUpdateCallbackConsole::FinishScanning(const CDirItemsStat &st)
{
if (NeedPercents())
{
_percent.ClosePrint(true);
_percent.ClearCurState();
}
if (_so)
{
AString s;
Print_DirItemsStat(s, st);
*_so << s << endl << endl;
}
return S_OK;
}
static const char * const k_StdOut_ArcName = "StdOut";
HRESULT CUpdateCallbackConsole::StartOpenArchive(const wchar_t *name)
{
if (_so)
{
*_so << kOpenArchiveMessage;
if (name)
*_so << name;
else
*_so << k_StdOut_ArcName;
*_so << endl;
}
return S_OK;
}
HRESULT CUpdateCallbackConsole::StartArchive(const wchar_t *name, bool updating)
{
if (NeedPercents())
_percent.ClosePrint(true);
_percent.ClearCurState();
NumNonOpenFiles = 0;
if (_so)
{
*_so << (updating ? kUpdatingArchiveMessage : kCreatingArchiveMessage);
if (name)
_so->NormalizePrint_wstr_Path(name);
else
*_so << k_StdOut_ArcName;
*_so << endl << endl;
}
return S_OK;
}
HRESULT CUpdateCallbackConsole::FinishArchive(const CFinishArchiveStat &st)
{
ClosePercents2();
if (_so)
{
AString s;
// Print_UInt64_and_String(s, _percent.Files == 1 ? "file" : "files", _percent.Files);
PrintPropPair(s, "Files read from disk", _percent.Files - NumNonOpenFiles);
s.Add_LF();
s += "Archive size: ";
PrintSize_bytes_Smart(s, st.OutArcFileSize);
s.Add_LF();
if (st.IsMultiVolMode)
{
s += "Volumes: ";
s.Add_UInt32(st.NumVolumes);
s.Add_LF();
}
*_so << endl;
*_so << s;
// *_so << endl;
}
return S_OK;
}
HRESULT CUpdateCallbackConsole::WriteSfx(const wchar_t *name, UInt64 size)
{
if (_so)
{
*_so << "Write SFX: ";
*_so << name;
AString s (" : ");
PrintSize_bytes_Smart(s, size);
*_so << s << endl;
}
return S_OK;
}
HRESULT CUpdateCallbackConsole::MoveArc_UpdateStatus()
{
if (NeedPercents())
{
AString &s = _percent.Command;
s = " : ";
s.Add_UInt64(_arcMoving_percents);
s.Add_Char('%');
const bool totalDefined = (_arcMoving_total != 0 && _arcMoving_total != (UInt64)(Int64)-1);
if (_arcMoving_current != 0 || totalDefined)
{
s += " : ";
s.Add_UInt64(_arcMoving_current >> 20);
s += " MiB";
}
if (totalDefined)
{
s += " / ";
s.Add_UInt64((_arcMoving_total + ((1 << 20) - 1)) >> 20);
s += " MiB";
}
s += " : temporary archive moving ...";
_percent.Print();
}
// we ignore single Ctrl-C, if (_arcMoving_updateMode) mode
// because we want to get good final archive instead of temp archive.
if (NConsoleClose::g_BreakCounter == 1 && _arcMoving_updateMode)
return S_OK;
return CheckBreak();
}
HRESULT CUpdateCallbackConsole::MoveArc_Start(
const wchar_t *srcTempPath, const wchar_t *destFinalPath,
UInt64 size, Int32 updateMode)
{
#if 0 // 1 : for debug
if (LogLevel > 0 && _so)
{
ClosePercents_for_so();
*_so << "Temporary archive moving:" << endl;
_tempU = srcTempPath;
_so->Normalize_UString_Path(_tempU);
_so->PrintUString(_tempU, _tempA);
*_so << endl;
_tempU = destFinalPath;
_so->Normalize_UString_Path(_tempU);
_so->PrintUString(_tempU, _tempA);
*_so << endl;
}
#else
UNUSED_VAR(srcTempPath)
UNUSED_VAR(destFinalPath)
#endif
_arcMoving_updateMode = updateMode;
_arcMoving_total = size;
_arcMoving_current = 0;
_arcMoving_percents = 0;
return MoveArc_UpdateStatus();
}
HRESULT CUpdateCallbackConsole::MoveArc_Progress(UInt64 totalSize, UInt64 currentSize)
{
#if 0 // 1 : for debug
if (_so)
{
ClosePercents_for_so();
*_so << totalSize << " : " << currentSize << endl;
}
#endif
UInt64 percents = 0;
if (totalSize != 0)
{
if (totalSize < ((UInt64)1 << 57))
percents = currentSize * 100 / totalSize;
else
percents = currentSize / (totalSize / 100);
}
#ifdef _WIN32
// Sleep(300); // for debug
#endif
// totalSize = (UInt64)(Int64)-1; // for debug
if (percents == _arcMoving_percents)
return CheckBreak();
_arcMoving_current = currentSize;
_arcMoving_total = totalSize;
_arcMoving_percents = percents;
return MoveArc_UpdateStatus();
}
HRESULT CUpdateCallbackConsole::MoveArc_Finish()
{
// _arcMoving_percents = 0;
if (NeedPercents())
{
_percent.Command.Empty();
_percent.Print();
}
// it can return delayed user break (E_ABORT) status,
// if it ignored single CTRL+C in MoveArc_Progress().
return CheckBreak();
}
HRESULT CUpdateCallbackConsole::DeletingAfterArchiving(const FString &path, bool /* isDir */)
{
if (LogLevel > 0 && _so)
{
ClosePercents_for_so();
if (!DeleteMessageWasShown)
{
if (_so)
*_so << endl << ": Removing files after including to archive" << endl;
}
{
{
_tempA = "Removing";
_tempA.Add_Space();
*_so << _tempA;
_tempU = fs2us(path);
_so->Normalize_UString_Path(_tempU);
_so->PrintUString(_tempU, _tempA);
*_so << endl;
if (NeedFlush)
_so->Flush();
}
}
}
if (!DeleteMessageWasShown)
{
if (NeedPercents())
{
_percent.ClearCurState();
}
DeleteMessageWasShown = true;
}
else
{
_percent.Files++;
}
if (NeedPercents())
{
// if (!FullLog)
{
_percent.Command = "Removing";
_percent.FileName = fs2us(path);
}
_percent.Print();
}
return S_OK;
}
HRESULT CUpdateCallbackConsole::FinishDeletingAfterArchiving()
{
ClosePercents2();
if (_so && DeleteMessageWasShown)
*_so << endl;
return S_OK;
}
HRESULT CUpdateCallbackConsole::CheckBreak()
{
return CheckBreak2();
}
/*
HRESULT CUpdateCallbackConsole::Finalize()
{
// MT_LOCK
return S_OK;
}
*/
void static PrintToDoStat(CStdOutStream *_so, const CDirItemsStat2 &stat, const char *name)
{
AString s;
Print_DirItemsStat2(s, stat);
*_so << name << ": " << s << endl;
}
HRESULT CUpdateCallbackConsole::SetNumItems(const CArcToDoStat &stat)
{
if (_so)
{
ClosePercents_for_so();
if (!stat.DeleteData.IsEmpty())
{
*_so << endl;
PrintToDoStat(_so, stat.DeleteData, "Delete data from archive");
}
if (!stat.OldData.IsEmpty())
PrintToDoStat(_so, stat.OldData, "Keep old data in archive");
// if (!stat.NewData.IsEmpty())
{
PrintToDoStat(_so, stat.NewData, "Add new data to archive");
}
*_so << endl;
}
return S_OK;
}
HRESULT CUpdateCallbackConsole::SetTotal(UInt64 size)
{
MT_LOCK
if (NeedPercents())
{
_percent.Total = size;
_percent.Print();
}
return S_OK;
}
HRESULT CUpdateCallbackConsole::SetCompleted(const UInt64 *completeValue)
{
MT_LOCK
if (completeValue)
{
if (NeedPercents())
{
_percent.Completed = *completeValue;
_percent.Print();
}
}
return CheckBreak2();
}
HRESULT CUpdateCallbackConsole::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 * /* outSize */)
{
return CheckBreak2();
}
HRESULT CCallbackConsoleBase::PrintProgress(const wchar_t *name, bool isDir, const char *command, bool showInLog)
{
MT_LOCK
bool show2 = (showInLog && _so);
if (show2)
{
ClosePercents_for_so();
_tempA = command;
if (name)
_tempA.Add_Space();
*_so << _tempA;
_tempU.Empty();
if (name)
{
_tempU = name;
if (isDir)
NWindows::NFile::NName::NormalizeDirPathPrefix(_tempU);
_so->Normalize_UString_Path(_tempU);
}
_so->PrintUString(_tempU, _tempA);
*_so << endl;
if (NeedFlush)
_so->Flush();
}
if (NeedPercents())
{
if (PercentsNameLevel >= 1)
{
_percent.FileName.Empty();
_percent.Command.Empty();
if (PercentsNameLevel > 1 || !show2)
{
_percent.Command = command;
if (name)
_percent.FileName = name;
}
}
_percent.Print();
}
return CheckBreak2();
}
/*
void CCallbackConsoleBase::PrintInfoLine(const UString &s)
{
if (LogLevel < 1000)
return;
MT_LOCK
const bool show2 = (_so != NULL);
if (show2)
{
ClosePercents_for_so();
_so->PrintUString(s, _tempA);
*_so << endl;
if (NeedFlush)
_so->Flush();
}
}
*/
HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool isDir, bool isAnti, UInt32 mode)
{
if (StdOutMode)
return S_OK;
if (!name || name[0] == 0)
name = kEmptyFileAlias;
unsigned requiredLevel = 1;
const char *s;
if (mode == NUpdateNotifyOp::kAdd ||
mode == NUpdateNotifyOp::kUpdate)
{
if (isAnti)
s = "Anti";
else if (mode == NUpdateNotifyOp::kAdd)
s = "+";
else
s = "U";
}
else
{
requiredLevel = 3;
if (mode == NUpdateNotifyOp::kAnalyze)
s = "A";
else
s = "Reading";
}
return PrintProgress(name, isDir, s, LogLevel >= requiredLevel);
}
HRESULT CUpdateCallbackConsole::OpenFileError(const FString &path, DWORD systemError)
{
return OpenFileError_Base(path, systemError);
}
HRESULT CUpdateCallbackConsole::ReadingFileError(const FString &path, DWORD systemError)
{
return ReadingFileError_Base(path, systemError);
}
HRESULT CUpdateCallbackConsole::SetOperationResult(Int32 /* opRes */)
{
MT_LOCK
_percent.Files++;
/*
if (opRes != NArchive::NUpdate::NOperationResult::kOK)
{
if (opRes == NArchive::NUpdate::NOperationResult::kError_FileChanged)
{
CommonError("Input file changed");
}
}
*/
return S_OK;
}
void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest);
HRESULT CUpdateCallbackConsole::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name)
{
// if (StdOutMode) return S_OK;
if (opRes != NArchive::NExtract::NOperationResult::kOK)
{
ClosePercents2();
if (_se)
{
if (_so)
_so->Flush();
AString s;
SetExtractErrorMessage(opRes, isEncrypted, s);
*_se << s << " : " << endl;
_se->NormalizePrint_wstr_Path(name);
*_se << endl << endl;
_se->Flush();
}
return S_OK;
}
return S_OK;
}
HRESULT CUpdateCallbackConsole::ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir)
{
// if (StdOutMode) return S_OK;
char temp[16];
const char *s;
unsigned requiredLevel = 1;
switch (op)
{
case NUpdateNotifyOp::kAdd: s = "+"; break;
case NUpdateNotifyOp::kUpdate: s = "U"; break;
case NUpdateNotifyOp::kAnalyze: s = "A"; requiredLevel = 3; break;
case NUpdateNotifyOp::kReplicate: s = "="; requiredLevel = 3; break;
case NUpdateNotifyOp::kRepack: s = "R"; requiredLevel = 2; break;
case NUpdateNotifyOp::kSkip: s = "."; requiredLevel = 2; break;
case NUpdateNotifyOp::kDelete: s = "D"; requiredLevel = 3; break;
case NUpdateNotifyOp::kHeader: s = "Header creation"; requiredLevel = 100; break;
case NUpdateNotifyOp::kInFileChanged: s = "Size of input file was changed:"; requiredLevel = 10; break;
// case NUpdateNotifyOp::kOpFinished: s = "Finished"; requiredLevel = 100; break;
default:
{
temp[0] = 'o';
temp[1] = 'p';
ConvertUInt64ToString(op, temp + 2);
s = temp;
}
}
return PrintProgress(name, isDir, s, LogLevel >= requiredLevel);
}
/*
HRESULT CUpdateCallbackConsole::SetPassword(const UString &
#ifndef Z7_NO_CRYPTO
password
#endif
)
{
#ifndef Z7_NO_CRYPTO
PasswordIsDefined = true;
Password = password;
#endif
return S_OK;
}
*/
HRESULT CUpdateCallbackConsole::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
{
COM_TRY_BEGIN
*password = NULL;
#ifdef Z7_NO_CRYPTO
*passwordIsDefined = false;
return S_OK;
#else
if (!PasswordIsDefined)
{
if (AskPassword)
{
RINOK(GetPassword_HRESULT(_so, Password))
PasswordIsDefined = true;
}
}
*passwordIsDefined = BoolToInt(PasswordIsDefined);
return StringToBstr(Password, password);
#endif
COM_TRY_END
}
HRESULT CUpdateCallbackConsole::CryptoGetTextPassword(BSTR *password)
{
COM_TRY_BEGIN
*password = NULL;
#ifdef Z7_NO_CRYPTO
return E_NOTIMPL;
#else
if (!PasswordIsDefined)
{
{
RINOK(GetPassword_HRESULT(_so, Password))
PasswordIsDefined = true;
}
}
return StringToBstr(Password, password);
#endif
COM_TRY_END
}
HRESULT CUpdateCallbackConsole::ShowDeleteFile(const wchar_t *name, bool isDir)
{
if (StdOutMode)
return S_OK;
if (LogLevel > 7)
{
if (!name || name[0] == 0)
name = kEmptyFileAlias;
return PrintProgress(name, isDir, "D", true);
}
return S_OK;
}
/*
void GetPropName(PROPID propID, const wchar_t *name, AString &nameA, UString &nameU);
static void GetPropName(PROPID propID, UString &nameU)
{
AString nameA;
GetPropName(propID, NULL, nameA, nameU);
// if (!nameA.IsEmpty())
nameU = nameA;
}
static void AddPropNamePrefix(UString &s, PROPID propID)
{
UString name;
GetPropName(propID, name);
s += name;
s += " = ";
}
void CCallbackConsoleBase::PrintPropInfo(UString &s, PROPID propID, const PROPVARIANT *value)
{
AddPropNamePrefix(s, propID);
{
UString dest;
const int level = 9; // we show up to ns precision level
ConvertPropertyToString2(dest, *value, propID, level);
s += dest;
}
PrintInfoLine(s);
}
static void Add_IndexType_Index(UString &s, UInt32 indexType, UInt32 index)
{
if (indexType == NArchive::NEventIndexType::kArcProp)
{
}
else
{
if (indexType == NArchive::NEventIndexType::kBlockIndex)
{
s += "#";
}
else if (indexType == NArchive::NEventIndexType::kOutArcIndex)
{
}
else
{
s += "indexType_";
s.Add_UInt32(indexType);
s.Add_Space();
}
s.Add_UInt32(index);
}
s += ": ";
}
HRESULT CUpdateCallbackConsole::ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value)
{
UString s;
Add_IndexType_Index(s, indexType, index);
PrintPropInfo(s, propID, value);
return S_OK;
}
static inline char GetHex(Byte value)
{
return (char)((value < 10) ? ('0' + value) : ('a' + (value - 10)));
}
static void AddHexToString(UString &dest, const Byte *data, UInt32 size)
{
for (UInt32 i = 0; i < size; i++)
{
Byte b = data[i];
dest += GetHex((Byte)((b >> 4) & 0xF));
dest += GetHex((Byte)(b & 0xF));
}
}
void HashHexToString(char *dest, const Byte *data, UInt32 size);
HRESULT CUpdateCallbackConsole::ReportRawProp(UInt32 indexType, UInt32 index,
PROPID propID, const void *data, UInt32 dataSize, UInt32 propType)
{
UString s;
propType = propType;
Add_IndexType_Index(s, indexType, index);
AddPropNamePrefix(s, propID);
if (propID == kpidChecksum)
{
char temp[k_HashCalc_DigestSize_Max + 8];
HashHexToString(temp, (const Byte *)data, dataSize);
s += temp;
}
else
AddHexToString(s, (const Byte *)data, dataSize);
PrintInfoLine(s);
return S_OK;
}
HRESULT CUpdateCallbackConsole::ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes)
{
UString s;
Add_IndexType_Index(s, indexType, index);
s += "finished";
if (opRes != NArchive::NUpdate::NOperationResult::kOK)
{
s += ": ";
s.Add_UInt32(opRes);
}
PrintInfoLine(s);
return S_OK;
}
*/
@@ -0,0 +1,148 @@
// UpdateCallbackConsole.h
#ifndef ZIP7_INC_UPDATE_CALLBACK_CONSOLE_H
#define ZIP7_INC_UPDATE_CALLBACK_CONSOLE_H
#include "../../../Common/StdOutStream.h"
#include "../Common/Update.h"
#include "PercentPrinter.h"
struct CErrorPathCodes
{
FStringVector Paths;
CRecordVector<DWORD> Codes;
void AddError(const FString &path, DWORD systemError)
{
Paths.Add(path);
Codes.Add(systemError);
}
void Clear()
{
Paths.Clear();
Codes.Clear();
}
};
class CCallbackConsoleBase
{
void CommonError(const FString &path, DWORD systemError, bool isWarning);
protected:
CStdOutStream *_so;
CStdOutStream *_se;
HRESULT ScanError_Base(const FString &path, DWORD systemError);
HRESULT OpenFileError_Base(const FString &name, DWORD systemError);
HRESULT ReadingFileError_Base(const FString &name, DWORD systemError);
public:
bool StdOutMode;
bool NeedFlush;
unsigned PercentsNameLevel;
unsigned LogLevel;
protected:
AString _tempA;
UString _tempU;
CPercentPrinter _percent;
public:
CErrorPathCodes FailedFiles;
CErrorPathCodes ScanErrors;
UInt64 NumNonOpenFiles;
CCallbackConsoleBase():
StdOutMode(false),
NeedFlush(false),
PercentsNameLevel(1),
LogLevel(0),
NumNonOpenFiles(0)
{}
bool NeedPercents() const { return _percent._so != NULL; }
void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; }
void Init(
CStdOutStream *outStream,
CStdOutStream *errorStream,
CStdOutStream *percentStream,
bool disablePercents)
{
FailedFiles.Clear();
_so = outStream;
_se = errorStream;
_percent._so = percentStream;
_percent.DisablePrint = disablePercents;
}
void ClosePercents2()
{
if (NeedPercents())
_percent.ClosePrint(true);
}
void ClosePercents_for_so()
{
if (NeedPercents() && _so == _percent._so)
_percent.ClosePrint(false);
}
HRESULT PrintProgress(const wchar_t *name, bool isDir, const char *command, bool showInLog);
// void PrintInfoLine(const UString &s);
// void PrintPropInfo(UString &s, PROPID propID, const PROPVARIANT *value);
};
class CUpdateCallbackConsole Z7_final:
public IUpdateCallbackUI2,
public CCallbackConsoleBase
{
// void PrintPropPair(const char *name, const wchar_t *val);
Z7_IFACE_IMP(IUpdateCallbackUI)
Z7_IFACE_IMP(IDirItemsCallback)
Z7_IFACE_IMP(IUpdateCallbackUI2)
HRESULT MoveArc_UpdateStatus();
UInt64 _arcMoving_total;
UInt64 _arcMoving_current;
UInt64 _arcMoving_percents;
Int32 _arcMoving_updateMode;
public:
bool DeleteMessageWasShown;
#ifndef Z7_NO_CRYPTO
bool PasswordIsDefined;
bool AskPassword;
UString Password;
#endif
CUpdateCallbackConsole():
_arcMoving_total(0)
, _arcMoving_current(0)
, _arcMoving_percents(0)
, _arcMoving_updateMode(0)
, DeleteMessageWasShown(false)
#ifndef Z7_NO_CRYPTO
, PasswordIsDefined(false)
, AskPassword(false)
#endif
{}
/*
void Init(CStdOutStream *outStream)
{
CCallbackConsoleBase::Init(outStream);
}
*/
// ~CUpdateCallbackConsole() { if (NeedPercents()) _percent.ClosePrint(); }
};
#endif
@@ -0,0 +1,118 @@
// UserInputUtils.cpp
#include "StdAfx.h"
#include "../../../Common/StdInStream.h"
#include "../../../Common/StringConvert.h"
#include "UserInputUtils.h"
static const char kYes = 'y';
static const char kNo = 'n';
static const char kYesAll = 'a';
static const char kNoAll = 's';
static const char kAutoRenameAll = 'u';
static const char kQuit = 'q';
static const char * const kFirstQuestionMessage = "? ";
static const char * const kHelpQuestionMessage =
"(Y)es / (N)o / (A)lways / (S)kip all / A(u)to rename all / (Q)uit? ";
// return true if pressed Quite;
NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream)
{
if (outStream)
*outStream << kFirstQuestionMessage;
for (;;)
{
if (outStream)
{
*outStream << kHelpQuestionMessage;
outStream->Flush();
}
AString scannedString;
if (!g_StdIn.ScanAStringUntilNewLine(scannedString))
return NUserAnswerMode::kError;
if (g_StdIn.Error())
return NUserAnswerMode::kError;
scannedString.Trim();
if (scannedString.IsEmpty() && g_StdIn.Eof())
return NUserAnswerMode::kEof;
if (scannedString.Len() == 1)
switch (::MyCharLower_Ascii(scannedString[0]))
{
case kYes: return NUserAnswerMode::kYes;
case kNo: return NUserAnswerMode::kNo;
case kYesAll: return NUserAnswerMode::kYesAll;
case kNoAll: return NUserAnswerMode::kNoAll;
case kAutoRenameAll: return NUserAnswerMode::kAutoRenameAll;
case kQuit: return NUserAnswerMode::kQuit;
default: break;
}
}
}
#ifdef _WIN32
#ifndef UNDER_CE
#define MY_DISABLE_ECHO
#endif
#endif
static bool GetPassword(CStdOutStream *outStream, UString &psw)
{
if (outStream)
{
*outStream << "\nEnter password"
#ifdef MY_DISABLE_ECHO
" (will not be echoed)"
#endif
":";
outStream->Flush();
}
#ifdef MY_DISABLE_ECHO
const HANDLE console = GetStdHandle(STD_INPUT_HANDLE);
/*
GetStdHandle() returns
INVALID_HANDLE_VALUE: If the function fails.
NULL : If an application does not have associated standard handles,
such as a service running on an interactive desktop,
and has not redirected them. */
bool wasChanged = false;
DWORD mode = 0;
if (console != INVALID_HANDLE_VALUE && console != NULL)
if (GetConsoleMode(console, &mode))
wasChanged = (SetConsoleMode(console, mode & ~(DWORD)ENABLE_ECHO_INPUT) != 0);
const bool res = g_StdIn.ScanUStringUntilNewLine(psw);
if (wasChanged)
SetConsoleMode(console, mode);
#else
const bool res = g_StdIn.ScanUStringUntilNewLine(psw);
#endif
if (outStream)
{
*outStream << endl;
outStream->Flush();
}
return res;
}
HRESULT GetPassword_HRESULT(CStdOutStream *outStream, UString &psw)
{
if (!GetPassword(outStream, psw))
return E_INVALIDARG;
if (g_StdIn.Error())
return E_FAIL;
if (g_StdIn.Eof() && psw.IsEmpty())
return E_ABORT;
return S_OK;
}

Some files were not shown because too many files have changed in this diff Show More