Initialer Commit

This commit is contained in:
Tino Reichardt
2016-06-25 21:15:50 +02:00
commit c3967fe27a
1199 changed files with 290375 additions and 0 deletions

1868
CPP/7zip/UI/Agent/Agent.cpp Normal file
View File

File diff suppressed because it is too large Load Diff

332
CPP/7zip/UI/Agent/Agent.h Normal file
View File

@@ -0,0 +1,332 @@
// Agent/Agent.h
#ifndef __AGENT_AGENT_H
#define __AGENT_AGENT_H
#include "../../../Common/MyCom.h"
#include "../../../Windows/PropVariant.h"
#include "../Common/OpenArchive.h"
#include "../Common/UpdateAction.h"
#ifdef NEW_FOLDER_INTERFACE
#include "../FileManager/IFolder.h"
#include "../Common/LoadCodecs.h"
#endif
#include "AgentProxy.h"
#include "IFolderArchive.h"
extern CCodecs *g_CodecsObj;
HRESULT LoadGlobalCodecs();
void FreeGlobalCodecs();
class CAgentFolder;
DECL_INTERFACE(IArchiveFolderInternal, 0x01, 0xC)
{
STDMETHOD(GetAgentFolder)(CAgentFolder **agentFolder) PURE;
};
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
};
class CAgentFolder:
public IFolderFolder,
public IFolderAltStreams,
public IFolderProperties,
public IArchiveGetRawProps,
public IGetFolderArcProps,
public IFolderCompare,
public IFolderGetItemName,
public IArchiveFolder,
public IArchiveFolderInternal,
public IInArchiveGetStream,
// public IFolderSetReplaceAltStreamCharsMode,
#ifdef NEW_FOLDER_INTERFACE
public IFolderOperations,
public IFolderSetFlatMode,
#endif
public CMyUnknownImp
{
void LoadFolder(unsigned proxyDirIndex);
public:
MY_QUERYINTERFACE_BEGIN2(IFolderFolder)
MY_QUERYINTERFACE_ENTRY(IFolderAltStreams)
MY_QUERYINTERFACE_ENTRY(IFolderProperties)
MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps)
MY_QUERYINTERFACE_ENTRY(IGetFolderArcProps)
MY_QUERYINTERFACE_ENTRY(IFolderCompare)
MY_QUERYINTERFACE_ENTRY(IFolderGetItemName)
MY_QUERYINTERFACE_ENTRY(IArchiveFolder)
MY_QUERYINTERFACE_ENTRY(IArchiveFolderInternal)
MY_QUERYINTERFACE_ENTRY(IInArchiveGetStream)
// MY_QUERYINTERFACE_ENTRY(IFolderSetReplaceAltStreamCharsMode)
#ifdef NEW_FOLDER_INTERFACE
MY_QUERYINTERFACE_ENTRY(IFolderOperations)
MY_QUERYINTERFACE_ENTRY(IFolderSetFlatMode)
#endif
MY_QUERYINTERFACE_END
MY_ADDREF_RELEASE
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;
// INTERFACE_FolderSetReplaceAltStreamCharsMode(;)
INTERFACE_FolderFolder(;)
INTERFACE_FolderAltStreams(;)
INTERFACE_FolderProperties(;)
INTERFACE_IArchiveGetRawProps(;)
INTERFACE_IFolderGetItemName(;)
STDMETHOD(GetFolderArcProps)(IFolderArcProps **object);
STDMETHOD_(Int32, CompareItems)(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw);
int CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw);
// IArchiveFolder
INTERFACE_IArchiveFolder(;)
STDMETHOD(GetAgentFolder)(CAgentFolder **agentFolder);
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
#ifdef NEW_FOLDER_INTERFACE
INTERFACE_FolderOperations(;)
STDMETHOD(SetFlatMode)(Int32 flatMode);
#endif
CAgentFolder():
_proxyDirIndex(0),
_isAltStreamFolder(false),
_flatMode(false),
_loadAltStreams(false) // _loadAltStreams alt streams works in flat mode, but we don't use it now
/* , _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:
const CProxyArc *_proxy;
const CProxyArc2 *_proxy2;
unsigned _proxyDirIndex;
bool _isAltStreamFolder;
// CMyComPtr<IFolderFolder> _parentFolder;
CMyComPtr<IInFolderArchive> _agent;
CAgent *_agentSpec;
CRecordVector<CProxyItem> _items;
bool _flatMode;
bool _loadAltStreams; // in Flat mode
// Int32 _replaceAltStreamCharsMode;
};
class CAgent:
public IInFolderArchive,
public IFolderArcProps,
#ifndef EXTRACT_ONLY
public IOutFolderArchive,
public ISetProperties,
#endif
public CMyUnknownImp
{
public:
MY_QUERYINTERFACE_BEGIN2(IInFolderArchive)
MY_QUERYINTERFACE_ENTRY(IFolderArcProps)
#ifndef EXTRACT_ONLY
MY_QUERYINTERFACE_ENTRY(IOutFolderArchive)
MY_QUERYINTERFACE_ENTRY(ISetProperties)
#endif
MY_QUERYINTERFACE_END
MY_ADDREF_RELEASE
INTERFACE_IInFolderArchive(;)
INTERFACE_IFolderArcProps(;)
#ifndef EXTRACT_ONLY
INTERFACE_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 UpdateOneFile(ISequentialOutStream *outArchiveStream,
const UInt32 *indices, UInt32 numItems, const wchar_t *diskFilePath,
IFolderArchiveUpdateCallback *updateCallback100);
// ISetProperties
STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
#endif
CAgent();
~CAgent();
private:
HRESULT ReadItems();
public:
CProxyArc *_proxy;
CProxyArc2 *_proxy2;
CArchiveLink _archiveLink;
bool ThereIsPathProp;
// bool ThereIsAltStreamProp;
UString ArchiveType;
FStringVector _names;
FString _folderPrefix;
bool _updatePathPrefix_is_AltFolder;
UString _updatePathPrefix;
CAgentFolder *_agentFolder;
UString _archiveFilePath;
bool _isDeviceFile;
#ifndef EXTRACT_ONLY
CObjectVector<UString> m_PropNames;
CObjectVector<NWindows::NCOM::CPropVariant> m_PropValues;
#endif
const CArc &GetArc() const { return _archiveLink.Arcs.Back(); }
IInArchive *GetArchive() const { if ( _archiveLink.Arcs.IsEmpty()) return 0; return GetArc().Archive; }
bool CanUpdate() const;
bool IsThereReadOnlyArc() 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 L"Parser";
return g_CodecsObj->GetFormatNamePtr(arc.FormatIndex);
}
UString GetErrorMessage() const
{
UString s;
for (int i = _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.AddAscii("Warning: The archive is open with offset");
else
{
s2.AddAscii("Can not open the file as [");
s2 += g_CodecsObj->GetFormatNamePtr(arc.ErrorInfo.ErrorFormatIndex);
s2.AddAscii("] archive");
}
}
if (!arc.ErrorInfo.ErrorMessage.IsEmpty())
{
if (!s2.IsEmpty())
s2.Add_LF();
s2.AddAscii("\n[");
s2 += GetTypeOfArc(arc);
s2.AddAscii("]: ");
s2 += arc.ErrorInfo.ErrorMessage;
}
if (!s2.IsEmpty())
{
if (!s.IsEmpty())
s.AddAscii("--------------------\n");
s += arc.Path;
s.Add_LF();
s += s2;
s.Add_LF();
}
}
return s;
}
void KeepModeForNextOpen() { _archiveLink.KeepModeForNextOpen(); }
};
#ifdef NEW_FOLDER_INTERFACE
class CArchiveFolderManager:
public IFolderManager,
public CMyUnknownImp
{
void LoadFormats();
int FindFormat(const UString &type);
public:
MY_UNKNOWN_IMP1(IFolderManager)
INTERFACE_IFolderManager(;)
};
#endif
#endif

View File

@@ -0,0 +1,660 @@
// 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 "Agent.h"
#include "UpdateCallbackAgent.h"
using namespace NWindows;
using namespace NCOM;
STDMETHODIMP CAgent::SetFolder(IFolderFolder *folder)
{
_updatePathPrefix.Empty();
_updatePathPrefix_is_AltFolder = false;
_agentFolder = NULL;
if (!folder)
return S_OK;
{
CMyComPtr<IArchiveFolderInternal> afi;
RINOK(folder->QueryInterface(IID_IArchiveFolderInternal, (void **)&afi));
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;
}
STDMETHODIMP 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().GetItemMTime(arcIndex, ai.MTime, ai.MTimeDefined));
RINOK(agent->GetArc().GetItemSize(arcIndex, ai.Size, ai.SizeDefined));
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().GetItemMTime(dirItem.ArcIndex, ai.MTime, ai.MTimeDefined));
ai.IsDir = true;
ai.SizeDefined = false;
ai.Name = fullName;
ai.Censored = true; // test it
ai.IndexInServer = 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().GetItemMTime(arcIndex, ai.MTime, ai.MTimeDefined));
ai.IsDir = file.IsDir();
ai.SizeDefined = false;
ai.IsAltStream = file.IsAltStream;
if (!ai.IsDir)
{
RINOK(agent->GetArc().GetItemSize(arcIndex, ai.Size, ai.SizeDefined));
ai.IsDir = false;
}
arcItems.Add(ai);
if (file.AltDirIndex >= 0)
{
RINOK(EnumerateArchiveItems2(agent, file.AltDirIndex, ai.Name + L':', arcItems));
}
if (ai.IsDir)
{
RINOK(EnumerateArchiveItems2(agent, file.DirIndex, ai.Name + WCHAR_PATH_SEPARATOR, arcItems));
}
}
return S_OK;
}
struct CAgUpCallbackImp: public IUpdateProduceCallback
{
const CObjectVector<CArcItem> *_arcItems;
IFolderArchiveUpdateCallback *_callback;
CAgUpCallbackImp(const CObjectVector<CArcItem> *a,
IFolderArchiveUpdateCallback *callback): _arcItems(a), _callback(callback) {}
HRESULT ShowDeleteFile(unsigned arcIndex);
};
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;
}
struct CDirItemsCallback_AgentOut: public IDirItemsCallback
{
CMyComPtr<IFolderScanProgress> FolderScanProgress;
IFolderArchiveUpdateCallback *FolderArchiveUpdateCallback;
HRESULT ErrorCode;
CDirItemsCallback_AgentOut(): ErrorCode(S_OK), FolderArchiveUpdateCallback(NULL) {}
HRESULT ScanError(const FString &name, DWORD systemError)
{
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)
{
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;
}
};
STDMETHODIMP 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;
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(formatIndex, outArchive));
#ifdef EXTERNAL_CODECS
{
CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
if (setCompressCodecsInfo)
{
RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs));
}
}
#endif
}
NFileTimeType::EEnum fileTimeType;
UInt32 value;
RINOK(outArchive->GetFileTimeType(&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);
CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec );
updateCallbackSpec->DirItems = &dirItems;
updateCallbackSpec->ArcItems = &arcItems;
updateCallbackSpec->UpdatePairs = &updatePairs2;
SetInArchiveInterfaces(this, updateCallbackSpec);
updateCallbackSpec->Callback = &updateCallbackAgent;
CByteBuffer processedItems;
if (processedPaths)
{
unsigned num = dirItems.Items.Size();
processedItems.Alloc(num);
for (unsigned i = 0; i < num; i++)
processedItems[i] = 0;
updateCallbackSpec->ProcessedItemsStatuses = processedItems;
}
CMyComPtr<ISetProperties> setProperties;
if (outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties) == S_OK)
{
if (m_PropNames.Size() == 0)
{
RINOK(setProperties->SetProperties(0, 0, 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.Front(), propValues, names.Size()));
}
catch(...)
{
delete []propValues;
return E_FAIL;
}
delete []propValues;
}
}
m_PropNames.Clear();
m_PropValues.Clear();
if (sfxModule != NULL)
{
CInFileStream *sfxStreamSpec = new CInFileStream;
CMyComPtr<IInStream> sfxStream(sfxStreamSpec);
if (!sfxStreamSpec->Open(us2fs(sfxModule)))
return E_FAIL;
// throw "Can't open sfx module";
RINOK(NCompress::CopyStream(sfxStream, outArchiveStream, NULL));
}
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 >= 0 && up.NewData)
{
const CDirItem &di = dirItems.Items[up.DirIndex];
if (!di.IsDir() && di.Size == 0)
processedItems[up.DirIndex] = 1;
}
}
}
FOR_VECTOR (i, dirItems.Items)
if (processedItems[i] != 0)
processedPaths->Add(dirItems.GetPhyPath(i));
}
return res;
}
STDMETHODIMP 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);
}
STDMETHODIMP CAgent::DeleteItems(ISequentialOutStream *outArchiveStream,
const UInt32 *indices, UInt32 numItems,
IFolderArchiveUpdateCallback *updateCallback100)
{
if (!CanUpdate())
return E_NOTIMPL;
CRecordVector<CUpdatePair2> updatePairs;
CUpdateCallbackAgent updateCallbackAgent;
updateCallbackAgent.SetCallback(updateCallback100);
CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
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().GetItemPath2(i, deletePath));
RINOK(updateCallback100->DeleteOperation(deletePath));
curIndex++;
continue;
}
CUpdatePair2 up2;
up2.SetAs_NoChangeArcItem(i);
updatePairs.Add(up2);
}
updateCallbackSpec->UpdatePairs = &updatePairs;
SetInArchiveInterfaces(this, updateCallbackSpec);
updateCallbackSpec->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);
CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
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);
updateCallbackSpec->Callback = &updateCallbackAgent;
updateCallbackSpec->DirItems = &dirItems;
updateCallbackSpec->UpdatePairs = &updatePairs;
SetInArchiveInterfaces(this, updateCallbackSpec);
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);
CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
CUIntVector realIndices;
_agentFolder->GetRealIndices(indices, numItems,
true, // includeAltStreams
true, // includeFolderSubItemsInFlatMode
realIndices);
int mainRealIndex = _agentFolder->GetRealIndex(indices[0]);
UString fullPrefix = _agentFolder->GetFullPrefix(indices[0]);
UString oldItemPath = fullPrefix + _agentFolder->GetName(indices[0]);
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().IsItemAnti(i, up2.IsAnti)); // it must work without that line too.
UString oldFullPath;
RINOK(GetArc().GetItemPath2(i, oldFullPath));
if (!IsPath1PrefixedByPath2(oldFullPath, oldItemPath))
return E_INVALIDARG;
up2.NewNameIndex = newNames.Add(newItemPath + oldFullPath.Ptr(oldItemPath.Len()));
up2.IsMainRenameItem = (mainRealIndex == (int)i);
curIndex++;
}
updatePairs.Add(up2);
}
updateCallbackSpec->Callback = &updateCallbackAgent;
updateCallbackSpec->UpdatePairs = &updatePairs;
updateCallbackSpec->NewNames = &newNames;
SetInArchiveInterfaces(this, updateCallbackSpec);
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);
CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
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);
}
updateCallbackSpec->DirItems = &dirItems;
updateCallbackSpec->Callback = &updateCallbackAgent;
updateCallbackSpec->UpdatePairs = &updatePairs;
SetInArchiveInterfaces(this, updateCallbackSpec);
updateCallbackSpec->KeepOriginalItemNames = true;
return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback);
}
STDMETHODIMP 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;
}

View File

@@ -0,0 +1,717 @@
// 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 "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;
}
unsigned mid = (left + right) / 2;
unsigned dirIndex2 = subDirs[mid];
int compare = CompareFileNames(name, Dirs[dirIndex2].Name);
if (compare == 0)
return dirIndex2;
if (compare < 0)
right = mid;
else
left = mid + 1;
}
}
int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name) const
{
unsigned insertPos;
return FindSubDir(dirIndex, name, insertPos);
}
unsigned CProxyArc::AddDir(unsigned dirIndex, int arcIndex, const UString &name)
{
unsigned insertPos;
int subDirIndex = FindSubDir(dirIndex, name, insertPos);
if (subDirIndex >= 0)
{
if (arcIndex >= 0)
{
CProxyDir &item = Dirs[subDirIndex];
if (item.ArcIndex < 0)
item.ArcIndex = arcIndex;
}
return subDirIndex;
}
subDirIndex = Dirs.Size();
Dirs[dirIndex].SubDirs.Insert(insertPos, subDirIndex);
CProxyDir &item = Dirs.AddNew();
item.NameLen = name.Len();
item.Name = new wchar_t[item.NameLen + 1];
MyStringCopy((wchar_t *)item.Name, name);
item.ArcIndex = arcIndex;
item.ParentDir = dirIndex;
return subDirIndex;
}
void CProxyDir::Clear()
{
SubDirs.Clear();
SubFiles.Clear();
}
void CProxyArc::GetDirPathParts(int dirIndex, UStringVector &pathParts) const
{
pathParts.Clear();
while (dirIndex >= 0)
{
const CProxyDir &dir = Dirs[dirIndex];
dirIndex = dir.ParentDir;
if (dirIndex < 0)
break;
pathParts.Insert(0, dir.Name);
}
}
UString CProxyArc::GetDirPath_as_Prefix(int dirIndex) const
{
UString s;
while (dirIndex >= 0)
{
const CProxyDir &dir = Dirs[dirIndex];
dirIndex = dir.ParentDir;
if (dirIndex < 0)
break;
s.InsertAtFront(WCHAR_PATH_SEPARATOR);
s.Insert(0, dir.Name);
}
return s;
}
void CProxyArc::AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const
{
const CProxyDir &dir = Dirs[dirIndex];
if (dir.IsLeaf())
realIndices.Add(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];
unsigned numDirItems = dir.SubDirs.Size();
if (index < numDirItems)
{
const CProxyDir &f = Dirs[dir.SubDirs[index]];
if (f.IsLeaf())
return f.ArcIndex;
return -1;
}
return 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++)
{
UInt32 index = indices[i];
unsigned numDirItems = dir.SubDirs.Size();
if (index < numDirItems)
AddRealIndices(dir.SubDirs[index], realIndices);
else
realIndices.Add(dir.SubFiles[index - numDirItems]);
}
HeapSort(&realIndices.Front(), 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++)
{
UInt32 index = (UInt32)dir.SubFiles[i];
UInt64 size, packSize;
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)
{
UInt64 currentItemIndex = i;
RINOK(progress->SetCompleted(&currentItemIndex));
}
const wchar_t *s = NULL;
unsigned len = 0;
bool isPtrName = false;
#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 (!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.GetDefaultItemPath(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++)
{
wchar_t c = s[j];
if (c == WCHAR_PATH_SEPARATOR || c == L'/')
{
const unsigned kLevelLimit = 1 << 10;
if (numLevels <= kLevelLimit)
{
if (numLevels == kLevelLimit)
name.SetFromAscii("[LONG_PATH]");
else
name.SetFrom(s + namePos, j - namePos);
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 = new wchar_t[f.NameLen + 1];
f.NeedDeleteName = true;
MyStringCopy((wchar_t *)f.Name, s);
}
if (isDir)
{
name = s;
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(int 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[dir.ArcIndex];
if (pathParts.IsEmpty() && dirIndex == file.AltDirIndex)
isAltStreamDir = true;
pathParts.Insert(0, file.Name);
int par = file.Parent;
if (par < 0)
break;
dirIndex = Files[par].DirIndex;
}
}
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[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[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 >= 0)
AddRealIndices_of_Dir(file.DirIndex, includeAltStreams, realIndices);
if (includeAltStreams && file.AltDirIndex >= 0)
AddRealIndices_of_Dir(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.Front(), 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;
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 < 0)
{
dir.NumSubFiles++;
}
else
{
dir.NumSubDirs++;
CProxyDir2 &f = Dirs[subFile.DirIndex];
f.PathPrefix = dir.PathPrefix + subFile.Name + WCHAR_PATH_SEPARATOR;
CalculateSizes(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 < 0)
{
// dir.NumSubFiles++;
}
else
{
// dir.NumSubDirs++;
CProxyDir2 &f = Dirs[subFile.AltDirIndex];
f.PathPrefix = dir.PathPrefix + subFile.Name + L':';
CalculateSizes(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 = L':';
}
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 / sizeof(wchar_t) - 1;
}
else
#endif
if (p && propType == NPropDataType::kUtf8z)
{
tempAString = (const char *)p;
ConvertUTF8ToUnicode(tempAString, tempUString);
file.NameLen = tempUString.Len();
file.Name = new wchar_t[file.NameLen + 1];
file.NeedDeleteName = true;
wmemcpy((wchar_t *)file.Name, tempUString.Ptr(), file.NameLen + 1);
}
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 = new wchar_t[file.NameLen + 1];
file.NeedDeleteName = true;
wmemcpy((wchar_t *)file.Name, s, file.NameLen + 1);
}
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 = Dirs.Size();
CProxyDir2 &dir = Dirs.AddNew();
dir.ArcIndex = 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 < 0)
dirIndex = k_Proxy2_AltRootDirIndex;
else
{
int &folderIndex2 = Files[file.Parent].AltDirIndex;
if (folderIndex2 < 0)
{
folderIndex2 = Dirs.Size();
CProxyDir2 &dir = Dirs.AddNew();
dir.ArcIndex = file.Parent;
}
dirIndex = folderIndex2;
}
}
else
{
if (file.Parent < 0)
dirIndex = k_Proxy2_RootDirIndex;
else
{
dirIndex = Files[file.Parent].DirIndex;
if (dirIndex < 0)
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 < 0)
continue;
if (CompareFileNames(file.Name, name) == 0)
return i;
}
return -1;
}

View File

@@ -0,0 +1,162 @@
// AgentProxy.h
#ifndef __AGENT_PROXY_H
#define __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 *)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 *)Name; }
void Clear();
bool IsLeaf() const { return ArcIndex >= 0; }
};
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(int dirIndex, UStringVector &pathParts) const;
// returns full path of Dirs[dirIndex], including back slash
UString GetDirPath_as_Prefix(int 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 >= 0; }
CProxyFile2():
DirIndex(-1), AltDirIndex(-1), Parent(-1),
Name(NULL), NameLen(0),
NeedDeleteName(false),
Ignore(false),
IsAltStream(false)
{}
~CProxyFile2()
{
if (NeedDeleteName)
delete [](wchar_t *)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(int 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 < 0)
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

View File

@@ -0,0 +1,44 @@
// Agent/ArchiveFolder.cpp
#include "StdAfx.h"
#include "../../../Common/ComTry.h"
#include "../Common/ArchiveExtractCallback.h"
#include "Agent.h"
/*
STDMETHODIMP CAgentFolder::SetReplaceAltStreamCharsMode(Int32 replaceAltStreamCharsMode)
{
_replaceAltStreamCharsMode = replaceAltStreamCharsMode;
return S_OK;
}
*/
STDMETHODIMP 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
}

View File

@@ -0,0 +1,141 @@
// Agent/ArchiveFolderOpen.cpp
#include "StdAfx.h"
#include "../../../Windows/DLL.h"
#include "Agent.h"
void CArchiveFolderManager::LoadFormats()
{
LoadGlobalCodecs();
}
int CArchiveFolderManager::FindFormat(const UString &type)
{
FOR_VECTOR (i, g_CodecsObj->Formats)
if (type.IsEqualTo_NoCase(g_CodecsObj->Formats[i].Name))
return i;
return -1;
}
STDMETHODIMP 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;
RINOK(agent->Open(inStream, filePath, arcFormat, NULL, openArchiveCallback));
return agent->BindToRootFolder(resultFolder);
}
/*
HRESULT CAgent::FolderReOpen(
IArchiveOpenCallback *openArchiveCallback)
{
return ReOpenArchive(_archive, _archiveFilePath);
}
*/
/*
STDMETHODIMP 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;
}
}
STDMETHODIMP CArchiveFolderManager::GetExtensions(BSTR *extensions)
{
LoadFormats();
*extensions = 0;
UString res;
#ifdef EXTERNAL_CODECS
FOR_VECTOR (i, g_CodecsObj->Libs)
AddIconExt(g_CodecsObj->Libs[i], res);
#endif
AddIconExt(g_CodecsObj->InternalIcons, res);
return StringToBstr(res, extensions);
}
STDMETHODIMP CArchiveFolderManager::GetIconPath(const wchar_t *ext, BSTR *iconPath, Int32 *iconIndex)
{
*iconPath = 0;
*iconIndex = 0;
LoadFormats();
#ifdef EXTERNAL_CODECS
FOR_VECTOR (i, g_CodecsObj->Libs)
{
const CCodecLib &lib = g_CodecsObj->Libs[i];
int ii;
if (lib.FindIconIndex(ext, ii))
{
*iconIndex = ii;
return StringToBstr(fs2us(lib.Path), iconPath);
}
}
#endif
int ii;
if (g_CodecsObj->InternalIcons.FindIconIndex(ext, ii))
{
FString path;
if (NWindows::NDLL::MyGetModuleFileName(path))
{
*iconIndex = ii;
return StringToBstr(fs2us(path), iconPath);
}
}
return S_OK;
}
/*
STDMETHODIMP 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);
}
STDMETHODIMP CArchiveFolderManager::CreateFolderFile(const wchar_t * type,
const wchar_t * filePath, IProgress progress)
{
return E_NOTIMPL;
}
*/

View File

@@ -0,0 +1,366 @@
// 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 DeleteEmptyFolderAndEmptySubFolders(const FString &path)
{
NFind::CFileInfo fileInfo;
FString pathPrefix = path + FCHAR_PATH_SEPARATOR;
{
NFind::CEnumerator enumerator(pathPrefix + FCHAR_ANY_MASK);
while (enumerator.Next(fileInfo))
{
if (fileInfo.IsDir())
if (!DeleteEmptyFolderAndEmptySubFolders(pathPrefix + fileInfo.Name))
return false;
}
}
/*
// we don't need clear readonly for folders
if (!SetFileAttrib(path, 0))
return false;
*/
return RemoveDir(path);
}
HRESULT CAgentFolder::CommonUpdateOperation(
AGENT_OP operation,
bool moveMode,
const wchar_t *newItemName,
const NUpdateArchive::CActionSet *actionSet,
const UInt32 *indices, UInt32 numItems,
IProgress *progress)
{
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 (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_CopyFromFile:
result = _agentSpec->UpdateOneFile(tailStream, indices, numItems, newItemName, updateCallback100);
break;
case AGENT_OP_Uni:
{
Byte actionSetByte[NUpdateArchive::NPairState::kNumValues];
for (int 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();
_agentSpec->Close();
// before 9.26: if there was error for MoveToOriginal archive was closed.
// now: we reopen archive after close
// m_FolderItem = NULL;
HRESULT res = tempFile.MoveToOriginal(true);
// 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))
DeleteEmptyFolderAndEmptySubFolders(fs);
}
}
}
{
CMyComPtr<IArchiveOpenCallback> openCallback;
if (updateCallback100)
updateCallback100->QueryInterface(IID_IArchiveOpenCallback, (void **)&openCallback);
RINOK(_agentSpec->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(_agentSpec->BindToRootFolder(&archiveFolder));
// CAgent::BindToRootFolder() changes _proxy and _proxy2
_proxy = _agentSpec->_proxy;
_proxy2 = _agentSpec->_proxy2;
if (_proxy)
{
FOR_VECTOR (i, pathParts)
{
int next = _proxy->FindSubDir(_proxyDirIndex, pathParts[i]);
if (next < 0)
break;
_proxyDirIndex = next;
}
}
if (_proxy2)
{
if (pathParts.IsEmpty() && isAltStreamFolder)
{
_proxyDirIndex = k_Proxy2_AltRootDirIndex;
}
else FOR_VECTOR (i, pathParts)
{
bool dirOnly = (i + 1 < pathParts.Size() || !isAltStreamFolder);
int index = _proxy2->FindItem(_proxyDirIndex, pathParts[i], dirOnly);
if (index < 0)
break;
const CProxyFile2 &file = _proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]];
if (dirOnly)
_proxyDirIndex = file.DirIndex;
else
{
if (file.AltDirIndex >= 0)
_proxyDirIndex = 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 = L"Error: ";
s2 += s;
RINOK(updateCallback100->UpdateErrorMessage(s2));
return E_FAIL;
}
throw;
}
}
STDMETHODIMP 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
}
STDMETHODIMP CAgentFolder::CopyFromFile(UInt32 destIndex, const wchar_t *itemPath, IProgress *progress)
{
COM_TRY_BEGIN
CUIntVector indices;
indices.Add(destIndex);
{
return CommonUpdateOperation(AGENT_OP_CopyFromFile, false, itemPath,
&NUpdateArchive::k_ActionSet_Add,
&indices.Front(), indices.Size(), progress);
}
COM_TRY_END
}
STDMETHODIMP 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
}
STDMETHODIMP 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) >= 0)
return ERROR_ALREADY_EXISTS;
}
return CommonUpdateOperation(AGENT_OP_CreateFolder, false, name, NULL, NULL, 0, progress);
COM_TRY_END
}
STDMETHODIMP CAgentFolder::Rename(UInt32 index, const wchar_t *newName, IProgress *progress)
{
COM_TRY_BEGIN
CUIntVector indices;
indices.Add(index);
return CommonUpdateOperation(AGENT_OP_Rename, false, newName, NULL,
&indices.Front(), indices.Size(), progress);
COM_TRY_END
}
STDMETHODIMP CAgentFolder::CreateFile(const wchar_t * /* name */, IProgress * /* progress */)
{
return E_NOTIMPL;
}
STDMETHODIMP CAgentFolder::SetProperty(UInt32 /* index */, PROPID /* propID */,
const PROPVARIANT * /* value */, IProgress * /* progress */)
{
return E_NOTIMPL;
}

View File

@@ -0,0 +1,119 @@
// IFolderArchive.h
#ifndef __IFOLDER_ARCHIVE_H
#define __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"
#define FOLDER_ARCHIVE_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 0x01, x)
#define FOLDER_ARCHIVE_INTERFACE(i, x) FOLDER_ARCHIVE_INTERFACE_SUB(i, IUnknown, x)
/* ---------- 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 INTERFACE_IArchiveFolder(x) \
STDMETHOD(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) x; \
FOLDER_ARCHIVE_INTERFACE(IArchiveFolder, 0x0D)
{
INTERFACE_IArchiveFolder(PURE)
};
/* ---------- IInFolderArchive ----------
IInFolderArchive is implemented by CAgent (Agent/Agent.h)
IInFolderArchive Is used by FAR/Plugin
*/
#define INTERFACE_IInFolderArchive(x) \
STDMETHOD(Open)(IInStream *inStream, const wchar_t *filePath, const wchar_t *arcFormat, BSTR *archiveTypeRes, IArchiveOpenCallback *openArchiveCallback) x; \
STDMETHOD(ReOpen)(IArchiveOpenCallback *openArchiveCallback) x; \
STDMETHOD(Close)() x; \
STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties) x; \
STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) x; \
STDMETHOD(BindToRootFolder)(IFolderFolder **resultFolder) x; \
STDMETHOD(Extract)(NExtract::NPathMode::EEnum pathMode, \
NExtract::NOverwriteMode::EEnum overwriteMode, const wchar_t *path, \
Int32 testMode, IFolderArchiveExtractCallback *extractCallback2) x; \
FOLDER_ARCHIVE_INTERFACE(IInFolderArchive, 0x0E)
{
INTERFACE_IInFolderArchive(PURE)
};
#define INTERFACE_IFolderArchiveUpdateCallback(x) \
STDMETHOD(CompressOperation)(const wchar_t *name) x; \
STDMETHOD(DeleteOperation)(const wchar_t *name) x; \
STDMETHOD(OperationResult)(Int32 opRes) x; \
STDMETHOD(UpdateErrorMessage)(const wchar_t *message) x; \
STDMETHOD(SetNumFiles)(UInt64 numFiles) x; \
FOLDER_ARCHIVE_INTERFACE_SUB(IFolderArchiveUpdateCallback, IProgress, 0x0B)
{
INTERFACE_IFolderArchiveUpdateCallback(PURE)
};
#define INTERFACE_IOutFolderArchive(x) \
STDMETHOD(SetFolder)(IFolderFolder *folder) x; \
STDMETHOD(SetFiles)(const wchar_t *folderPrefix, const wchar_t * const *names, UInt32 numNames) x; \
STDMETHOD(DeleteItems)(ISequentialOutStream *outArchiveStream, \
const UInt32 *indices, UInt32 numItems, IFolderArchiveUpdateCallback *updateCallback) x; \
STDMETHOD(DoOperation)( \
FStringVector *requestedPaths, \
FStringVector *processedPaths, \
CCodecs *codecs, int index, \
ISequentialOutStream *outArchiveStream, const Byte *stateActions, const wchar_t *sfxModule, \
IFolderArchiveUpdateCallback *updateCallback) x; \
STDMETHOD(DoOperation2)( \
FStringVector *requestedPaths, \
FStringVector *processedPaths, \
ISequentialOutStream *outArchiveStream, const Byte *stateActions, const wchar_t *sfxModule, \
IFolderArchiveUpdateCallback *updateCallback) x; \
FOLDER_ARCHIVE_INTERFACE(IOutFolderArchive, 0x0F)
{
INTERFACE_IOutFolderArchive(PURE)
};
#define INTERFACE_IFolderArchiveUpdateCallback2(x) \
STDMETHOD(OpenFileError)(const wchar_t *path, HRESULT errorCode) x; \
STDMETHOD(ReadingFileError)(const wchar_t *path, HRESULT errorCode) x; \
STDMETHOD(ReportExtractResult)(Int32 opRes, Int32 isEncrypted, const wchar_t *path) x; \
STDMETHOD(ReportUpdateOperation)(UInt32 notifyOp, const wchar_t *path, Int32 isDir) x; \
FOLDER_ARCHIVE_INTERFACE(IFolderArchiveUpdateCallback2, 0x10)
{
INTERFACE_IFolderArchiveUpdateCallback2(PURE)
};
#define INTERFACE_IFolderScanProgress(x) \
STDMETHOD(ScanError)(const wchar_t *path, HRESULT errorCode) x; \
STDMETHOD(ScanProgress)(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, Int32 isDir) x; \
FOLDER_ARCHIVE_INTERFACE(IFolderScanProgress, 0x11)
{
INTERFACE_IFolderScanProgress(PURE)
};
#endif

View File

@@ -0,0 +1,8 @@
// StdAfx.h
#ifndef __STDAFX_H
#define __STDAFX_H
#include "../../../Common/Common.h"
#endif

View File

@@ -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(UInt64 numItems)
{
if (Callback)
return Callback->SetNumFiles(numItems);
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)
{
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 = L"WARNING: ";
s += NError::MyFormatMessage(systemError);
s += L": ";
s += fs2us(path);
RINOK(Callback->UpdateErrorMessage(s));
return S_FALSE;
}
}
// FailedFiles.Add(name);
return hres;
}
HRESULT CUpdateCallbackAgent::ReadingFileError(const FString &path, DWORD systemError)
{
HRESULT hres = HRESULT_FROM_WIN32(systemError);
// if (systemError == ERROR_SHARING_VIOLATION)
{
if (Callback2)
{
RINOK(Callback2->ReadingFileError(fs2us(path), hres));
}
else if (Callback)
{
UString s = L"ERROR: ";
s += NError::MyFormatMessage(systemError);
s += L": ";
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::ReportUpdateOpeartion(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 _NO_CRYPTO
password
#endif
)
{
#ifndef _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);
}

View File

@@ -0,0 +1,22 @@
// UpdateCallbackAgent.h
#ifndef __UPDATE_CALLBACK_AGENT_H
#define __UPDATE_CALLBACK_AGENT_H
#include "../Common/UpdateCallback.h"
#include "IFolderArchive.h"
class CUpdateCallbackAgent: public IUpdateCallbackUI
{
INTERFACE_IUpdateCallbackUI(;)
CMyComPtr<ICryptoGetTextPassword2> _cryptoGetTextPassword;
CMyComPtr<IFolderArchiveUpdateCallback> Callback;
CMyComPtr<IFolderArchiveUpdateCallback2> Callback2;
CMyComPtr<ICompressProgressInfo> _compressProgress;
public:
void SetCallback(IFolderArchiveUpdateCallback *callback);
};
#endif