Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/UI/Agent/AgentOut.cpp')
-rwxr-xr-xCPP/7zip/UI/Agent/AgentOut.cpp518
1 files changed, 518 insertions, 0 deletions
diff --git a/CPP/7zip/UI/Agent/AgentOut.cpp b/CPP/7zip/UI/Agent/AgentOut.cpp
new file mode 100755
index 00000000..25d65bb2
--- /dev/null
+++ b/CPP/7zip/UI/Agent/AgentOut.cpp
@@ -0,0 +1,518 @@
+// AgentOut.cpp
+
+#include "StdAfx.h"
+
+#include "Common/StringConvert.h"
+#include "Common/IntToString.h"
+
+#include "Windows/Defs.h"
+#include "Windows/PropVariant.h"
+#include "Windows/PropVariantConversions.h"
+#include "Windows/FileDir.h"
+
+#include "../../Compress/Copy/CopyCoder.h"
+#include "../../Common/FileStreams.h"
+
+#include "../Common/UpdatePair.h"
+#include "../Common/EnumDirItems.h"
+#include "../Common/HandlerLoader.h"
+#include "../Common/UpdateCallback.h"
+#include "../Common/OpenArchive.h"
+
+#include "Agent.h"
+#include "UpdateCallbackAgent.h"
+
+using namespace NWindows;
+using namespace NCOM;
+
+static HRESULT CopyBlock(ISequentialInStream *inStream, ISequentialOutStream *outStream)
+{
+ CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
+ return copyCoder->Code(inStream, outStream, NULL, NULL, NULL);
+}
+
+STDMETHODIMP CAgent::SetFolder(IFolderFolder *folder)
+{
+ _archiveNamePrefix.Empty();
+ if (folder == NULL)
+ {
+ _agentFolder = NULL;
+ return S_OK;
+ }
+ else
+ {
+ CMyComPtr<IFolderFolder> archiveFolder = folder;
+ CMyComPtr<IArchiveFolderInternal> archiveFolderInternal;
+ RINOK(archiveFolder.QueryInterface(IID_IArchiveFolderInternal, &archiveFolderInternal));
+ RINOK(archiveFolderInternal->GetAgentFolder(&_agentFolder));
+ }
+
+ UStringVector pathParts;
+ pathParts.Clear();
+ CMyComPtr<IFolderFolder> folderItem = folder;
+ if (folderItem != NULL)
+ for (;;)
+ {
+ CMyComPtr<IFolderFolder> newFolder;
+ folderItem->BindToParentFolder(&newFolder);
+ if (newFolder == NULL)
+ break;
+ CMyComBSTR name;
+ folderItem->GetName(&name);
+ pathParts.Insert(0, (const wchar_t *)name);
+ folderItem = newFolder;
+ }
+
+ for(int i = 0; i < pathParts.Size(); i++)
+ {
+ _archiveNamePrefix += pathParts[i];
+ _archiveNamePrefix += L'\\';
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CAgent::SetFiles(const wchar_t *folderPrefix,
+ const wchar_t **names, UINT32 numNames)
+{
+ _folderPrefix = folderPrefix;
+ _names.Clear();
+ _names.Reserve(numNames);
+ for (UINT32 i = 0; i < numNames; i++)
+ _names.Add(names[i]);
+ return S_OK;
+}
+
+
+static HRESULT GetFileTime(CAgent *agent, UINT32 itemIndex, FILETIME &fileTime)
+{
+ CPropVariant property;
+ RINOK(agent->GetArchive()->GetProperty(itemIndex, kpidLastWriteTime, &property));
+ if (property.vt == VT_FILETIME)
+ fileTime = property.filetime;
+ else if (property.vt == VT_EMPTY)
+ fileTime = agent->DefaultTime;
+ else
+ throw 4190407;
+ return S_OK;
+}
+
+static HRESULT EnumerateArchiveItems(CAgent *agent,
+ const CProxyFolder &item,
+ const UString &prefix,
+ CObjectVector<CArchiveItem> &archiveItems)
+{
+ int i;
+ for(i = 0; i < item.Files.Size(); i++)
+ {
+ const CProxyFile &fileItem = item.Files[i];
+ CArchiveItem archiveItem;
+
+ RINOK(::GetFileTime(agent, fileItem.Index, archiveItem.LastWriteTime));
+
+ CPropVariant property;
+ agent->GetArchive()->GetProperty(fileItem.Index, kpidSize, &property);
+ archiveItem.SizeIsDefined = (property.vt != VT_EMPTY);
+ if (archiveItem.SizeIsDefined)
+ archiveItem.Size = ConvertPropVariantToUInt64(property);
+ archiveItem.IsDirectory = false;
+ archiveItem.Name = prefix + fileItem.Name;
+ archiveItem.Censored = true; // test it
+ archiveItem.IndexInServer = fileItem.Index;
+ archiveItems.Add(archiveItem);
+ }
+ for(i = 0; i < item.Folders.Size(); i++)
+ {
+ const CProxyFolder &dirItem = item.Folders[i];
+ UString fullName = prefix + dirItem.Name;
+ if(dirItem.IsLeaf)
+ {
+ CArchiveItem archiveItem;
+ RINOK(::GetFileTime(agent, dirItem.Index, archiveItem.LastWriteTime));
+ archiveItem.IsDirectory = true;
+ archiveItem.SizeIsDefined = false;
+ archiveItem.Name = fullName;
+ archiveItem.Censored = true; // test it
+ archiveItem.IndexInServer = dirItem.Index;
+ archiveItems.Add(archiveItem);
+ }
+ RINOK(EnumerateArchiveItems(agent, dirItem, fullName + UString(L'\\'), archiveItems));
+ }
+ return S_OK;
+}
+
+STDMETHODIMP CAgent::DoOperation(
+ const wchar_t *filePath,
+ const CLSID *clsID,
+ const wchar_t *newArchiveName,
+ const Byte *stateActions,
+ const wchar_t *sfxModule,
+ IFolderArchiveUpdateCallback *updateCallback100)
+{
+ if (!CanUpdate())
+ return E_NOTIMPL;
+ NUpdateArchive::CActionSet actionSet;
+ int i;
+ for (i = 0; i < NUpdateArchive::NPairState::kNumValues; i++)
+ actionSet.StateActions[i] = (NUpdateArchive::NPairAction::EEnum)stateActions[i];
+
+ CObjectVector<CDirItem> dirItems;
+
+ UString folderPrefix = _folderPrefix;
+ NFile::NName::NormalizeDirPathPrefix(folderPrefix);
+ UStringVector errorPaths;
+ CRecordVector<DWORD> errorCodes;
+ ::EnumerateDirItems(folderPrefix, _names, _archiveNamePrefix, dirItems, errorPaths, errorCodes);
+ if (errorCodes.Size() > 0)
+ {
+ return errorCodes.Front();
+ }
+
+ NWindows::NDLL::CLibrary library;
+
+ CMyComPtr<IOutArchive> outArchive;
+ if (GetArchive())
+ {
+ RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive));
+ }
+ else
+ {
+ CHandlerLoader loader;
+ RINOK(loader.CreateHandler(filePath, *clsID, (void **)&outArchive, true));
+ library.Attach(loader.Detach());
+ }
+
+ 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<CUpdatePair> updatePairs;
+
+ CObjectVector<CArchiveItem> archiveItems;
+ if (GetArchive())
+ {
+ RINOK(ReadItems());
+ EnumerateArchiveItems(this, _proxyArchive->RootFolder, L"", archiveItems);
+ }
+
+ GetUpdatePairInfoList(dirItems, archiveItems, fileTimeType, updatePairs);
+
+ CObjectVector<CUpdatePair2> updatePairs2;
+ UpdateProduce(updatePairs, actionSet, updatePairs2);
+
+ CUpdateCallbackAgent updateCallbackAgent;
+ updateCallbackAgent.Callback = updateCallback100;
+ CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+ CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec );
+
+ updateCallbackSpec->DirPrefix = folderPrefix;
+ updateCallbackSpec->DirItems = &dirItems;
+ updateCallbackSpec->ArchiveItems = &archiveItems;
+ updateCallbackSpec->UpdatePairs = &updatePairs2;
+ updateCallbackSpec->Archive = GetArchive();
+ updateCallbackSpec->Callback = &updateCallbackAgent;
+
+ COutFileStream *outStreamSpec = new COutFileStream;
+ CMyComPtr<IOutStream> outStream(outStreamSpec);
+ UString archiveName = newArchiveName;
+ {
+ UString resultPath;
+ int pos;
+ if(!NFile::NDirectory::MyGetFullPathName(archiveName, resultPath, pos))
+ throw 141716;
+ NFile::NDirectory::CreateComplexDirectory(resultPath.Left(pos));
+ }
+ if (!outStreamSpec->Create(archiveName, true))
+ {
+ // ShowLastErrorMessage();
+ return E_FAIL;
+ }
+
+ 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(i = 0; i < m_PropNames.Size(); i++)
+ names.Add((const wchar_t *)m_PropNames[i]);
+
+ NWindows::NCOM::CPropVariant *propValues = new NWindows::NCOM::CPropVariant[m_PropValues.Size()];
+ try
+ {
+ for (int i = 0; i < m_PropValues.Size(); i++)
+ propValues[i] = m_PropValues[i];
+ RINOK(setProperties->SetProperties(&names.Front(), propValues, names.Size()));
+ }
+ catch(...)
+ {
+ delete []propValues;
+ throw;
+ }
+ delete []propValues;
+ }
+ }
+ m_PropNames.Clear();
+ m_PropValues.Clear();
+
+ if (sfxModule != NULL)
+ {
+ CInFileStream *sfxStreamSpec = new CInFileStream;
+ CMyComPtr<IInStream> sfxStream(sfxStreamSpec);
+ if (!sfxStreamSpec->Open(sfxModule))
+ throw "Can't open sfx module";
+ RINOK(CopyBlock(sfxStream, outStream));
+ }
+
+ return outArchive->UpdateItems(outStream, updatePairs2.Size(),updateCallback);
+}
+
+
+HRESULT CAgent::CommonUpdate(
+ const wchar_t *newArchiveName,
+ int numUpdateItems,
+ IArchiveUpdateCallback *updateCallback)
+{
+ if (!CanUpdate())
+ return E_NOTIMPL;
+ CMyComPtr<IOutArchive> outArchive;
+ RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive));
+
+ COutFileStream *outStreamSpec = new COutFileStream;
+ CMyComPtr<IOutStream> outStream(outStreamSpec);
+
+ UString archiveName = newArchiveName;
+ {
+ UString resultPath;
+ int pos;
+ if(!NFile::NDirectory::MyGetFullPathName(archiveName, resultPath, pos))
+ throw 141716;
+ NFile::NDirectory::CreateComplexDirectory(resultPath.Left(pos));
+ }
+
+ /*
+ bool isOK = false;
+ for (int i = 0; i < (1 << 16); i++)
+ {
+ resultName = newArchiveName;
+ if (i > 0)
+ {
+ wchar_t s[32];
+ ConvertUInt64ToString(i, s);
+ resultName += s;
+ }
+ if (outStreamSpec->Open(realPath))
+ {
+ isOK = true;
+ break;
+ }
+ if (::GetLastError() != ERROR_FILE_EXISTS)
+ return ::GetLastError();
+ }
+ if (!isOK)
+ return ::GetLastError();
+ */
+ if (!outStreamSpec->Create(archiveName, true))
+ {
+ // ShowLastErrorMessage();
+ return E_FAIL;
+ }
+
+ return outArchive->UpdateItems(outStream, numUpdateItems, updateCallback);
+}
+
+
+STDMETHODIMP CAgent::DeleteItems(
+ const wchar_t *newArchiveName,
+ const UINT32 *indices, UINT32 numItems,
+ IFolderArchiveUpdateCallback *updateCallback100)
+{
+ if (!CanUpdate())
+ return E_NOTIMPL;
+ CUpdateCallbackAgent updateCallbackAgent;
+ updateCallbackAgent.Callback = updateCallback100;
+ CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+ CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+
+ CUIntVector realIndices;
+ _agentFolder->GetRealIndices(indices, numItems, realIndices);
+ CObjectVector<CUpdatePair2> updatePairs;
+ int curIndex = 0;
+ UInt32 numItemsInArchive;
+ RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive));
+ for (UInt32 i = 0; i < numItemsInArchive; i++)
+ {
+ if (curIndex < realIndices.Size())
+ if (realIndices[curIndex] == i)
+ {
+ curIndex++;
+ continue;
+ }
+ CUpdatePair2 updatePair;
+ updatePair.NewData = updatePair.NewProperties = false;
+ updatePair.ExistInArchive = true;
+ updatePair.ExistOnDisk = false;
+ updatePair.IsAnti = false; // check it. Maybe it can be undefined
+ updatePair.ArchiveItemIndex = i;
+ updatePairs.Add(updatePair);
+ }
+ updateCallbackSpec->UpdatePairs = &updatePairs;
+ updateCallbackSpec->Archive = GetArchive();
+ updateCallbackSpec->Callback = &updateCallbackAgent;
+ return CommonUpdate(newArchiveName, updatePairs.Size(), updateCallback);
+}
+
+HRESULT CAgent::CreateFolder(
+ const wchar_t *newArchiveName,
+ const wchar_t *folderName,
+ IFolderArchiveUpdateCallback *updateCallback100)
+{
+ if (!CanUpdate())
+ return E_NOTIMPL;
+ CUpdateCallbackAgent updateCallbackAgent;
+ updateCallbackAgent.Callback = updateCallback100;
+ CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+ CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+
+ CObjectVector<CUpdatePair2> updatePairs;
+ UINT32 numItemsInArchive;
+ RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive));
+ for (UInt32 i = 0; i < numItemsInArchive; i++)
+ {
+ CUpdatePair2 updatePair;
+ updatePair.NewData = updatePair.NewProperties = false;
+ updatePair.ExistInArchive = true;
+ updatePair.ExistOnDisk = false;
+ updatePair.IsAnti = false; // check it.
+ updatePair.ArchiveItemIndex = i;
+ updatePairs.Add(updatePair);
+ }
+ CUpdatePair2 updatePair;
+ updatePair.NewData = updatePair.NewProperties = true;
+ updatePair.ExistInArchive = false;
+ updatePair.ExistOnDisk = true;
+ updatePair.IsAnti = false;
+ updatePair.ArchiveItemIndex = -1;
+ updatePair.DirItemIndex = 0;
+
+ updatePairs.Add(updatePair);
+
+ CObjectVector<CDirItem> dirItems;
+ CDirItem dirItem;
+
+ dirItem.Attributes = FILE_ATTRIBUTE_DIRECTORY;
+ dirItem.Size = 0;
+ dirItem.Name = _agentFolder->_proxyFolderItem->GetFullPathPrefix() + folderName;
+
+ SYSTEMTIME systemTime;
+ FILETIME fileTime;
+ ::GetSystemTime(&systemTime);
+ ::SystemTimeToFileTime(&systemTime, &fileTime);
+ dirItem.LastAccessTime = dirItem.LastWriteTime =
+ dirItem.CreationTime = fileTime;
+
+ dirItems.Add(dirItem);
+
+ updateCallbackSpec->Callback = &updateCallbackAgent;
+ updateCallbackSpec->DirItems = &dirItems;
+ updateCallbackSpec->UpdatePairs = &updatePairs;
+ updateCallbackSpec->Archive = GetArchive();
+ return CommonUpdate(newArchiveName, updatePairs.Size(), updateCallback);
+}
+
+
+HRESULT CAgent::RenameItem(
+ const wchar_t *newArchiveName,
+ const UINT32 *indices, UINT32 numItems,
+ const wchar_t *newItemName,
+ IFolderArchiveUpdateCallback *updateCallback100)
+{
+ if (!CanUpdate())
+ return E_NOTIMPL;
+ if (numItems != 1)
+ return E_INVALIDARG;
+ CUpdateCallbackAgent updateCallbackAgent;
+ updateCallbackAgent.Callback = updateCallback100;
+ CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+ CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+
+ CUIntVector realIndices;
+ _agentFolder->GetRealIndices(indices, numItems, realIndices);
+
+ UString fullPrefix = _agentFolder->GetFullPathPrefixPlusPrefix(indices[0]);
+ UString oldItemPath = fullPrefix + _agentFolder->GetName(indices[0]);
+ UString newItemPath = fullPrefix + newItemName;
+
+ CObjectVector<CUpdatePair2> updatePairs;
+ int curIndex = 0;
+ UINT32 numItemsInArchive;
+ RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive));
+ for (UInt32 i = 0; i < numItemsInArchive; i++)
+ {
+ if (curIndex < realIndices.Size())
+ if (realIndices[curIndex] == i)
+ {
+ CUpdatePair2 updatePair;
+ updatePair.NewData = false;
+ updatePair.NewProperties = true;
+ updatePair.ExistInArchive = true;
+ updatePair.ExistOnDisk = false;
+ RINOK(IsArchiveItemAnti(GetArchive(), i, updatePair.IsAnti));
+ updatePair.ArchiveItemIndex = i;
+ updatePair.NewNameIsDefined = true;
+
+ updatePair.NewName = newItemName;
+
+ UString oldFullPath;
+ RINOK(GetArchiveItemPath(GetArchive(), i, DefaultName, oldFullPath));
+
+ if (oldItemPath.CompareNoCase(oldFullPath.Left(oldItemPath.Length())) != 0)
+ return E_INVALIDARG;
+
+ updatePair.NewName = newItemPath + oldFullPath.Mid(oldItemPath.Length());
+ updatePairs.Add(updatePair);
+ curIndex++;
+ continue;
+ }
+ CUpdatePair2 updatePair;
+ updatePair.NewData = updatePair.NewProperties = false;
+ updatePair.ExistInArchive = true;
+ updatePair.ExistOnDisk = false;
+ updatePair.IsAnti = false;
+ updatePair.ArchiveItemIndex = i;
+ updatePairs.Add(updatePair);
+ }
+ updateCallbackSpec->Callback = &updateCallbackAgent;
+ updateCallbackSpec->UpdatePairs = &updatePairs;
+ updateCallbackSpec->Archive = GetArchive();
+ return CommonUpdate(newArchiveName, updatePairs.Size(), updateCallback);
+}
+
+STDMETHODIMP CAgent::SetProperties(const wchar_t **names,
+ const PROPVARIANT *values, INT32 numProperties)
+{
+ m_PropNames.Clear();
+ m_PropValues.Clear();
+ for (int i = 0; i < numProperties; i++)
+ {
+ m_PropNames.Add(names[i]);
+ m_PropValues.Add(values[i]);
+ }
+ return S_OK;
+}
+
+