p7zip-rar/CPP/7zip/UI/Agent/Agent.cpp

1869 lines
46 KiB
C++
Raw Normal View History

2017-10-11 12:40:22 +02:00
// Agent.cpp
#include "StdAfx.h"
#include <wchar.h>
#include "../../../../C/Sort.h"
#include "../../../Common/ComTry.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/FileName.h"
#include "../../../Windows/PropVariantConv.h"
#ifndef _7ZIP_ST
#include "../../../Windows/Synchronization.h"
#endif
#include "../Common/ArchiveExtractCallback.h"
#include "../FileManager/RegistryUtils.h"
#include "Agent.h"
using namespace NWindows;
CCodecs *g_CodecsObj;
#ifdef EXTERNAL_CODECS
CExternalCodecs g_ExternalCodecs;
CCodecs::CReleaser g_CodecsReleaser;
#else
CMyComPtr<IUnknown> g_CodecsRef;
#endif
#ifndef _7ZIP_ST
static NSynchronization::CCriticalSection g_CriticalSection;
#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
#else
#define MT_LOCK
#endif
void FreeGlobalCodecs()
{
MT_LOCK
#ifdef EXTERNAL_CODECS
if (g_CodecsObj)
{
g_CodecsObj->CloseLibs();
}
g_CodecsReleaser.Set(NULL);
g_CodecsObj = NULL;
g_ExternalCodecs.ClearAndRelease();
#else
g_CodecsRef.Release();
#endif
}
HRESULT LoadGlobalCodecs()
{
MT_LOCK
if (g_CodecsObj)
return S_OK;
g_CodecsObj = new CCodecs;
#ifdef EXTERNAL_CODECS
g_ExternalCodecs.GetCodecs = g_CodecsObj;
g_ExternalCodecs.GetHashers = g_CodecsObj;
g_CodecsReleaser.Set(g_CodecsObj);
#else
g_CodecsRef.Release();
g_CodecsRef = g_CodecsObj;
#endif
RINOK(g_CodecsObj->Load());
if (g_CodecsObj->Formats.IsEmpty())
{
FreeGlobalCodecs();
return E_NOTIMPL;
}
#ifdef EXTERNAL_CODECS
RINOK(g_ExternalCodecs.Load());
#endif
return S_OK;
}
STDMETHODIMP CAgentFolder::GetAgentFolder(CAgentFolder **agentFolder)
{
*agentFolder = this;
return S_OK;
}
void CAgentFolder::LoadFolder(unsigned proxyDirIndex)
{
CProxyItem item;
item.DirIndex = proxyDirIndex;
if (_proxy2)
{
const CProxyDir2 &dir = _proxy2->Dirs[proxyDirIndex];
FOR_VECTOR (i, dir.Items)
{
item.Index = i;
_items.Add(item);
const CProxyFile2 &file = _proxy2->Files[dir.Items[i]];
if (file.DirIndex >= 0)
LoadFolder(file.DirIndex);
if (_loadAltStreams && file.AltDirIndex >= 0)
LoadFolder(file.AltDirIndex);
}
return;
}
const CProxyDir &dir = _proxy->Dirs[proxyDirIndex];
unsigned i;
for (i = 0; i < dir.SubDirs.Size(); i++)
{
item.Index = i;
_items.Add(item);
LoadFolder(dir.SubDirs[i]);
}
unsigned start = dir.SubDirs.Size();
for (i = 0; i < dir.SubFiles.Size(); i++)
{
item.Index = start + i;
_items.Add(item);
}
}
STDMETHODIMP CAgentFolder::LoadItems()
{
if (!_agentSpec->_archiveLink.IsOpen)
return E_FAIL;
_items.Clear();
if (_flatMode)
{
LoadFolder(_proxyDirIndex);
if (_proxy2 && _loadAltStreams)
{
if (_proxyDirIndex == k_Proxy2_RootDirIndex)
LoadFolder(k_Proxy2_AltRootDirIndex);
}
}
return S_OK;
}
STDMETHODIMP CAgentFolder::GetNumberOfItems(UInt32 *numItems)
{
if (_flatMode)
*numItems = _items.Size();
else if (_proxy2)
*numItems = _proxy2->Dirs[_proxyDirIndex].Items.Size();
else
{
const CProxyDir *dir = &_proxy->Dirs[_proxyDirIndex];
*numItems = dir->SubDirs.Size() + dir->SubFiles.Size();
}
return S_OK;
}
#define SET_realIndex_AND_dir \
unsigned realIndex; const CProxyDir *dir; \
if (_flatMode) { const CProxyItem &item = _items[index]; dir = &_proxy->Dirs[item.DirIndex]; realIndex = item.Index; } \
else { dir = &_proxy->Dirs[_proxyDirIndex]; realIndex = index; }
#define SET_realIndex_AND_dir_2 \
unsigned realIndex; const CProxyDir2 *dir; \
if (_flatMode) { const CProxyItem &item = _items[index]; dir = &_proxy2->Dirs[item.DirIndex]; realIndex = item.Index; } \
else { dir = &_proxy2->Dirs[_proxyDirIndex]; realIndex = index; }
UString CAgentFolder::GetName(UInt32 index) const
{
if (_proxy2)
{
SET_realIndex_AND_dir_2
return _proxy2->Files[dir->Items[realIndex]].Name;
}
SET_realIndex_AND_dir
if (realIndex < dir->SubDirs.Size())
return _proxy->Dirs[dir->SubDirs[realIndex]].Name;
return _proxy->Files[dir->SubFiles[realIndex - dir->SubDirs.Size()]].Name;
}
void CAgentFolder::GetPrefix(UInt32 index, UString &prefix) const
{
if (!_flatMode)
{
prefix.Empty();
return;
}
const CProxyItem &item = _items[index];
unsigned proxyIndex = item.DirIndex;
if (_proxy2)
{
// that code is unused. 7-Zip gets prefix via GetItemPrefix() .
unsigned len = 0;
while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs)
{
const CProxyFile2 &file = _proxy2->Files[_proxy2->Dirs[proxyIndex].ArcIndex];
len += file.NameLen + 1;
proxyIndex = (file.Parent < 0) ? 0 : _proxy2->Files[file.Parent].GetDirIndex(file.IsAltStream);
}
wchar_t *p = prefix.GetBuf_SetEnd(len) + len;
proxyIndex = item.DirIndex;
while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs)
{
const CProxyFile2 &file = _proxy2->Files[_proxy2->Dirs[proxyIndex].ArcIndex];
p--;
*p = WCHAR_PATH_SEPARATOR;
p -= file.NameLen;
wmemcpy(p, file.Name, file.NameLen);
proxyIndex = (file.Parent < 0) ? 0 : _proxy2->Files[file.Parent].GetDirIndex(file.IsAltStream);
}
}
else
{
unsigned len = 0;
while (proxyIndex != _proxyDirIndex)
{
const CProxyDir *dir = &_proxy->Dirs[proxyIndex];
len += dir->NameLen + 1;
proxyIndex = dir->ParentDir;
}
wchar_t *p = prefix.GetBuf_SetEnd(len) + len;
proxyIndex = item.DirIndex;
while (proxyIndex != _proxyDirIndex)
{
const CProxyDir *dir = &_proxy->Dirs[proxyIndex];
p--;
*p = WCHAR_PATH_SEPARATOR;
p -= dir->NameLen;
wmemcpy(p, dir->Name, dir->NameLen);
proxyIndex = dir->ParentDir;
}
}
}
UString CAgentFolder::GetFullPrefix(UInt32 index) const
{
int foldIndex = _proxyDirIndex;
if (_flatMode)
foldIndex = _items[index].DirIndex;
if (_proxy2)
return _proxy2->Dirs[foldIndex].PathPrefix;
else
return _proxy->GetDirPath_as_Prefix(foldIndex);
}
STDMETHODIMP_(UInt64) CAgentFolder::GetItemSize(UInt32 index)
{
unsigned arcIndex;
if (_proxy2)
{
SET_realIndex_AND_dir_2
arcIndex = dir->Items[realIndex];
const CProxyFile2 &item = _proxy2->Files[arcIndex];
if (item.IsDir())
{
const CProxyDir2 &itemFolder = _proxy2->Dirs[item.DirIndex];
if (!_flatMode)
return itemFolder.Size;
}
}
else
{
SET_realIndex_AND_dir
if (realIndex < dir->SubDirs.Size())
{
const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]];
if (!_flatMode)
return item.Size;
if (!item.IsLeaf())
return 0;
arcIndex = item.ArcIndex;
}
else
{
arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()];
}
}
NCOM::CPropVariant prop;
_agentSpec->GetArchive()->GetProperty(arcIndex, kpidSize, &prop);
if (prop.vt == VT_UI8)
return prop.uhVal.QuadPart;
else
return 0;
}
STDMETHODIMP CAgentFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
if (propID == kpidPrefix)
{
if (_flatMode)
{
UString prefix;
GetPrefix(index, prefix);
prop = prefix;
}
}
else if (_proxy2)
{
SET_realIndex_AND_dir_2
unsigned arcIndex = dir->Items[realIndex];
const CProxyFile2 &item = _proxy2->Files[arcIndex];
/*
if (propID == kpidNumAltStreams)
{
if (item.AltDirIndex >= 0)
prop = _proxy2->Dirs[item.AltDirIndex].Items.Size();
}
else
*/
if (!item.IsDir())
{
switch (propID)
{
case kpidIsDir: prop = false; break;
case kpidName: prop = item.Name; break;
default: return _agentSpec->GetArchive()->GetProperty(arcIndex, propID, value);
}
}
else
{
const CProxyDir2 &itemFolder = _proxy2->Dirs[item.DirIndex];
if (!_flatMode && propID == kpidSize)
prop = itemFolder.Size;
else if (!_flatMode && propID == kpidPackSize)
prop = itemFolder.PackSize;
else switch (propID)
{
case kpidIsDir: prop = true; break;
case kpidNumSubDirs: prop = itemFolder.NumSubDirs; break;
case kpidNumSubFiles: prop = itemFolder.NumSubFiles; break;
case kpidName: prop = item.Name; break;
case kpidCRC:
{
// if (itemFolder.IsLeaf)
if (!item.Ignore)
{
RINOK(_agentSpec->GetArchive()->GetProperty(arcIndex, propID, value));
}
if (itemFolder.CrcIsDefined && value->vt == VT_EMPTY)
prop = itemFolder.Crc;
break;
}
default:
// if (itemFolder.IsLeaf)
if (!item.Ignore)
return _agentSpec->GetArchive()->GetProperty(arcIndex, propID, value);
}
}
}
else
{
SET_realIndex_AND_dir
if (realIndex < dir->SubDirs.Size())
{
const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]];
if (!_flatMode && propID == kpidSize)
prop = item.Size;
else if (!_flatMode && propID == kpidPackSize)
prop = item.PackSize;
else
switch (propID)
{
case kpidIsDir: prop = true; break;
case kpidNumSubDirs: prop = item.NumSubDirs; break;
case kpidNumSubFiles: prop = item.NumSubFiles; break;
case kpidName: prop = item.Name; break;
case kpidCRC:
{
if (item.IsLeaf())
{
RINOK(_agentSpec->GetArchive()->GetProperty(item.ArcIndex, propID, value));
}
if (item.CrcIsDefined && value->vt == VT_EMPTY)
prop = item.Crc;
break;
}
default:
if (item.IsLeaf())
return _agentSpec->GetArchive()->GetProperty(item.ArcIndex, propID, value);
}
}
else
{
unsigned arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()];
switch (propID)
{
case kpidIsDir: prop = false; break;
case kpidName: prop = _proxy->Files[arcIndex].Name; break;
default:
return _agentSpec->GetArchive()->GetProperty(arcIndex, propID, value);
}
}
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
static UInt64 GetUInt64Prop(IInArchive *archive, UInt32 index, PROPID propID)
{
NCOM::CPropVariant prop;
if (archive->GetProperty(index, propID, &prop) != S_OK)
throw 111233443;
UInt64 v = 0;
if (ConvertPropVariantToUInt64(prop, v))
return v;
return 0;
}
STDMETHODIMP CAgentFolder::GetItemName(UInt32 index, const wchar_t **name, unsigned *len)
{
if (_proxy2)
{
SET_realIndex_AND_dir_2
unsigned arcIndex = dir->Items[realIndex];
const CProxyFile2 &item = _proxy2->Files[arcIndex];
*name = item.Name;
*len = item.NameLen;
return S_OK;
}
else
{
SET_realIndex_AND_dir
if (realIndex < dir->SubDirs.Size())
{
const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]];
*name = item.Name;
*len = item.NameLen;
return S_OK;
}
else
{
const CProxyFile &item = _proxy->Files[dir->SubFiles[realIndex - dir->SubDirs.Size()]];
*name = item.Name;
*len = item.NameLen;
return S_OK;
}
}
}
STDMETHODIMP CAgentFolder::GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len)
{
*name = 0;
*len = 0;
if (!_flatMode)
return S_OK;
if (_proxy2)
{
const CProxyItem &item = _items[index];
const UString &s = _proxy2->Dirs[item.DirIndex].PathPrefix;
unsigned baseLen = _proxy2->Dirs[_proxyDirIndex].PathPrefix.Len();
if (baseLen <= s.Len())
{
*name = (const wchar_t *)s + baseLen;
*len = s.Len() - baseLen;
}
else
{
return E_FAIL;
// throw 111l;
}
}
return S_OK;
}
static int CompareRawProps(IArchiveGetRawProps *rawProps, int arcIndex1, int arcIndex2, PROPID propID)
{
// if (propID == kpidSha1)
if (rawProps)
{
const void *p1, *p2;
UInt32 size1, size2;
UInt32 propType1, propType2;
HRESULT res1 = rawProps->GetRawProp(arcIndex1, propID, &p1, &size1, &propType1);
HRESULT res2 = rawProps->GetRawProp(arcIndex2, propID, &p2, &size2, &propType2);
if (res1 == S_OK && res2 == S_OK)
{
for (UInt32 i = 0; i < size1 && i < size2; i++)
{
Byte b1 = ((const Byte *)p1)[i];
Byte b2 = ((const Byte *)p2)[i];
if (b1 < b2) return -1;
if (b1 > b2) return 1;
}
if (size1 < size2) return -1;
if (size1 > size2) return 1;
return 0;
}
}
return 0;
}
// returns pointer to extension including '.'
static const wchar_t *GetExtension(const wchar_t *name)
{
for (const wchar_t *dotPtr = NULL;; name++)
{
wchar_t c = *name;
if (c == 0)
return dotPtr ? dotPtr : name;
if (c == '.')
dotPtr = name;
}
}
int CAgentFolder::CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw)
{
unsigned realIndex1, realIndex2;
const CProxyDir2 *dir1, *dir2;
if (_flatMode)
{
const CProxyItem &item1 = _items[index1];
const CProxyItem &item2 = _items[index2];
dir1 = &_proxy2->Dirs[item1.DirIndex];
dir2 = &_proxy2->Dirs[item2.DirIndex];
realIndex1 = item1.Index;
realIndex2 = item2.Index;
}
else
{
dir2 = dir1 = &_proxy2->Dirs[_proxyDirIndex];
realIndex1 = index1;
realIndex2 = index2;
}
UInt32 arcIndex1;
UInt32 arcIndex2;
bool isDir1, isDir2;
arcIndex1 = dir1->Items[realIndex1];
arcIndex2 = dir2->Items[realIndex2];
const CProxyFile2 &prox1 = _proxy2->Files[arcIndex1];
const CProxyFile2 &prox2 = _proxy2->Files[arcIndex2];
if (propID == kpidName)
{
return CompareFileNames_ForFolderList(prox1.Name, prox2.Name);
}
if (propID == kpidPrefix)
{
if (!_flatMode)
return 0;
return CompareFileNames_ForFolderList(
_proxy2->Dirs[_items[index1].DirIndex].PathPrefix,
_proxy2->Dirs[_items[index2].DirIndex].PathPrefix);
}
if (propID == kpidExtension)
{
return CompareFileNames_ForFolderList(
GetExtension(prox1.Name),
GetExtension(prox2.Name));
}
isDir1 = prox1.IsDir();
isDir2 = prox2.IsDir();
if (propID == kpidIsDir)
{
if (isDir1 == isDir2)
return 0;
return isDir1 ? -1 : 1;
}
const CProxyDir2 *proxFolder1 = NULL;
const CProxyDir2 *proxFolder2 = NULL;
if (isDir1) proxFolder1 = &_proxy2->Dirs[prox1.DirIndex];
if (isDir2) proxFolder2 = &_proxy2->Dirs[prox2.DirIndex];
if (propID == kpidNumSubDirs)
{
UInt32 n1 = 0;
UInt32 n2 = 0;
if (isDir1) n1 = proxFolder1->NumSubDirs;
if (isDir2) n2 = proxFolder2->NumSubDirs;
return MyCompare(n1, n2);
}
if (propID == kpidNumSubFiles)
{
UInt32 n1 = 0;
UInt32 n2 = 0;
if (isDir1) n1 = proxFolder1->NumSubFiles;
if (isDir2) n2 = proxFolder2->NumSubFiles;
return MyCompare(n1, n2);
}
if (propID == kpidSize)
{
UInt64 n1, n2;
if (isDir1)
n1 = _flatMode ? 0 : proxFolder1->Size;
else
n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidSize);
if (isDir2)
n2 = _flatMode ? 0 : proxFolder2->Size;
else
n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidSize);
return MyCompare(n1, n2);
}
if (propID == kpidPackSize)
{
UInt64 n1, n2;
if (isDir1)
n1 = _flatMode ? 0 : proxFolder1->PackSize;
else
n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidPackSize);
if (isDir2)
n2 = _flatMode ? 0 : proxFolder2->PackSize;
else
n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidPackSize);
return MyCompare(n1, n2);
}
if (propID == kpidCRC)
{
UInt64 n1, n2;
if (!isDir1 || !prox1.Ignore)
n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidCRC);
else
n1 = proxFolder1->Crc;
if (!isDir2 || !prox2.Ignore)
n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidCRC);
else
n2 = proxFolder2->Crc;
return MyCompare(n1, n2);
}
if (propIsRaw)
return CompareRawProps(_agentSpec->_archiveLink.GetArchiveGetRawProps(), arcIndex1, arcIndex2, propID);
NCOM::CPropVariant prop1, prop2;
// Name must be first property
GetProperty(index1, propID, &prop1);
GetProperty(index2, propID, &prop2);
if (prop1.vt != prop2.vt)
{
return MyCompare(prop1.vt, prop2.vt);
}
if (prop1.vt == VT_BSTR)
{
return _wcsicmp(prop1.bstrVal, prop2.bstrVal);
}
return prop1.Compare(prop2);
}
STDMETHODIMP_(Int32) CAgentFolder::CompareItems(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw)
{
try {
if (_proxy2)
return CompareItems2(index1, index2, propID, propIsRaw);
unsigned realIndex1, realIndex2;
const CProxyDir *dir1, *dir2;
if (_flatMode)
{
const CProxyItem &item1 = _items[index1];
const CProxyItem &item2 = _items[index2];
dir1 = &_proxy->Dirs[item1.DirIndex];
dir2 = &_proxy->Dirs[item2.DirIndex];
realIndex1 = item1.Index;
realIndex2 = item2.Index;
}
else
{
dir2 = dir1 = &_proxy->Dirs[_proxyDirIndex];
realIndex1 = index1;
realIndex2 = index2;
}
if (propID == kpidPrefix)
{
if (!_flatMode)
return 0;
UString prefix1, prefix2;
GetPrefix(index1, prefix1);
GetPrefix(index2, prefix2);
return CompareFileNames_ForFolderList(prefix1, prefix2);
}
UInt32 arcIndex1;
UInt32 arcIndex2;
const CProxyDir *proxFolder1 = NULL;
const CProxyDir *proxFolder2 = NULL;
if (realIndex1 < dir1->SubDirs.Size())
{
proxFolder1 = &_proxy->Dirs[dir1->SubDirs[realIndex1]];
arcIndex1 = proxFolder1->ArcIndex;
}
else
arcIndex1 = dir1->SubFiles[realIndex1 - dir1->SubDirs.Size()];
if (realIndex2 < dir2->SubDirs.Size())
{
proxFolder2 = &_proxy->Dirs[dir2->SubDirs[realIndex2]];
arcIndex2 = proxFolder2->ArcIndex;
}
else
arcIndex2 = dir2->SubFiles[realIndex2 - dir2->SubDirs.Size()];
if (propID == kpidName)
return CompareFileNames_ForFolderList(
proxFolder1 ? proxFolder1->Name : _proxy->Files[arcIndex1].Name,
proxFolder2 ? proxFolder2->Name : _proxy->Files[arcIndex2].Name);
if (propID == kpidExtension)
return CompareFileNames_ForFolderList(
GetExtension(proxFolder1 ? proxFolder1->Name : _proxy->Files[arcIndex1].Name),
GetExtension(proxFolder2 ? proxFolder2->Name : _proxy->Files[arcIndex2].Name));
if (propID == kpidIsDir)
{
if (proxFolder1)
return proxFolder2 ? 0 : -1;
return proxFolder2 ? 1 : 0;
}
if (propID == kpidNumSubDirs)
{
UInt32 n1 = 0;
UInt32 n2 = 0;
if (proxFolder1) n1 = proxFolder1->NumSubDirs;
if (proxFolder2) n2 = proxFolder2->NumSubDirs;
return MyCompare(n1, n2);
}
if (propID == kpidNumSubFiles)
{
UInt32 n1 = 0;
UInt32 n2 = 0;
if (proxFolder1) n1 = proxFolder1->NumSubFiles;
if (proxFolder2) n2 = proxFolder2->NumSubFiles;
return MyCompare(n1, n2);
}
if (propID == kpidSize)
{
UInt64 n1, n2;
if (proxFolder1)
n1 = _flatMode ? 0 : proxFolder1->Size;
else
n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidSize);
if (proxFolder2)
n2 = _flatMode ? 0 : proxFolder2->Size;
else
n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidSize);
return MyCompare(n1, n2);
}
if (propID == kpidPackSize)
{
UInt64 n1, n2;
if (proxFolder1)
n1 = _flatMode ? 0 : proxFolder1->PackSize;
else
n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidPackSize);
if (proxFolder2)
n2 = _flatMode ? 0 : proxFolder2->PackSize;
else
n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidPackSize);
return MyCompare(n1, n2);
}
if (propID == kpidCRC)
{
UInt64 n1, n2;
if (proxFolder1 && !proxFolder1->IsLeaf())
n1 = proxFolder1->Crc;
else
n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidCRC);
if (proxFolder2 && !proxFolder2->IsLeaf())
n2 = proxFolder2->Crc;
else
n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidCRC);
return MyCompare(n1, n2);
}
if (propIsRaw)
{
bool isVirt1 = (proxFolder1 && !proxFolder1->IsLeaf());
bool isVirt2 = (proxFolder2 && !proxFolder2->IsLeaf());
if (isVirt1)
return isVirt2 ? 0 : -1;
if (isVirt2)
return 1;
return CompareRawProps(_agentSpec->_archiveLink.GetArchiveGetRawProps(), arcIndex1, arcIndex2, propID);
}
NCOM::CPropVariant prop1, prop2;
// Name must be first property
GetProperty(index1, propID, &prop1);
GetProperty(index2, propID, &prop2);
if (prop1.vt != prop2.vt)
{
return MyCompare(prop1.vt, prop2.vt);
}
if (prop1.vt == VT_BSTR)
{
return _wcsicmp(prop1.bstrVal, prop2.bstrVal);
}
return prop1.Compare(prop2);
} catch(...) { return 0; }
}
HRESULT CAgentFolder::BindToFolder_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder)
{
/*
CMyComPtr<IFolderFolder> parentFolder;
if (_proxy2)
{
const CProxyDir2 &dir = _proxy2->Dirs[proxyDirIndex];
int par = _proxy2->GetParentFolderOfFile(dir.ArcIndex);
if (par != (int)_proxyDirIndex)
{
RINOK(BindToFolder_Internal(par, &parentFolder));
}
else
parentFolder = this;
}
else
{
const CProxyDir &dir = _proxy->Dirs[proxyDirIndex];
if (dir.Parent != (int)_proxyDirIndex)
{
RINOK(BindToFolder_Internal(dir.Parent, &parentFolder));
}
else
parentFolder = this;
}
*/
CAgentFolder *folderSpec = new CAgentFolder;
CMyComPtr<IFolderFolder> agentFolder = folderSpec;
folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec);
*resultFolder = agentFolder.Detach();
return S_OK;
}
STDMETHODIMP CAgentFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder)
{
COM_TRY_BEGIN
if (_proxy2)
{
SET_realIndex_AND_dir_2
unsigned arcIndex = dir->Items[realIndex];
const CProxyFile2 &item = _proxy2->Files[arcIndex];
if (!item.IsDir())
return E_INVALIDARG;
return BindToFolder_Internal(item.DirIndex, resultFolder);
}
SET_realIndex_AND_dir
if (realIndex >= (UInt32)dir->SubDirs.Size())
return E_INVALIDARG;
return BindToFolder_Internal(dir->SubDirs[realIndex], resultFolder);
COM_TRY_END
}
STDMETHODIMP CAgentFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder)
{
COM_TRY_BEGIN
if (_proxy2)
{
int index = _proxy2->FindItem(_proxyDirIndex, name, true);
if (index < 0)
return E_INVALIDARG;
return BindToFolder_Internal(_proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]].DirIndex, resultFolder);
}
int index = _proxy->FindSubDir(_proxyDirIndex, name);
if (index < 0)
return E_INVALIDARG;
return BindToFolder_Internal(index, resultFolder);
COM_TRY_END
}
// ---------- IFolderAltStreams ----------
HRESULT CAgentFolder::BindToAltStreams_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder)
{
*resultFolder = NULL;
if (!_proxy2)
return S_OK;
/*
CMyComPtr<IFolderFolder> parentFolder;
int par = _proxy2->GetParentFolderOfFile(_proxy2->Dirs[proxyDirIndex].ArcIndex);
if (par != (int)_proxyDirIndex)
{
RINOK(BindToFolder_Internal(par, &parentFolder));
if (!parentFolder)
return S_OK;
}
else
parentFolder = this;
*/
CAgentFolder *folderSpec = new CAgentFolder;
CMyComPtr<IFolderFolder> agentFolder = folderSpec;
folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec);
*resultFolder = agentFolder.Detach();
return S_OK;
}
STDMETHODIMP CAgentFolder::BindToAltStreams(UInt32 index, IFolderFolder **resultFolder)
{
COM_TRY_BEGIN
*resultFolder = NULL;
if (!_proxy2)
return S_OK;
if (_proxy2->IsAltDir(_proxyDirIndex))
return S_OK;
{
if (index == (UInt32)(Int32)-1)
{
unsigned altDirIndex;
// IFolderFolder *parentFolder;
if (_proxyDirIndex == k_Proxy2_RootDirIndex)
{
altDirIndex = k_Proxy2_AltRootDirIndex;
// parentFolder = this; // we want to use Root dir as parent for alt root
}
else
{
unsigned arcIndex = _proxy2->Dirs[_proxyDirIndex].ArcIndex;
const CProxyFile2 &item = _proxy2->Files[arcIndex];
if (item.AltDirIndex < 0)
return S_OK;
altDirIndex = item.AltDirIndex;
// parentFolder = _parentFolder;
}
CAgentFolder *folderSpec = new CAgentFolder;
CMyComPtr<IFolderFolder> agentFolder = folderSpec;
folderSpec->Init(_proxy, _proxy2, altDirIndex, /* parentFolder, */ _agentSpec);
*resultFolder = agentFolder.Detach();
return S_OK;
}
SET_realIndex_AND_dir_2
unsigned arcIndex = dir->Items[realIndex];
const CProxyFile2 &item = _proxy2->Files[arcIndex];
if (item.AltDirIndex < 0)
return S_OK;
return BindToAltStreams_Internal(item.AltDirIndex, resultFolder);
}
COM_TRY_END
}
STDMETHODIMP CAgentFolder::BindToAltStreams(const wchar_t *name, IFolderFolder **resultFolder)
{
COM_TRY_BEGIN
*resultFolder = NULL;
if (!_proxy2)
return S_OK;
if (_proxy2->IsAltDir(_proxyDirIndex))
return S_OK;
if (name[0] == 0)
return BindToAltStreams((UInt32)(Int32)-1, resultFolder);
{
const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex];
FOR_VECTOR (i, dir.Items)
{
const CProxyFile2 &file = _proxy2->Files[dir.Items[i]];
if (file.AltDirIndex >= 0)
if (CompareFileNames(file.Name, name) == 0)
return BindToAltStreams_Internal(file.AltDirIndex, resultFolder);
}
return E_INVALIDARG;
}
COM_TRY_END
}
STDMETHODIMP CAgentFolder::AreAltStreamsSupported(UInt32 index, Int32 *isSupported)
{
*isSupported = BoolToInt(false);
if (!_proxy2)
return S_OK;
if (_proxy2->IsAltDir(_proxyDirIndex))
return S_OK;
unsigned arcIndex;
if (index == (UInt32)(Int32)-1)
{
if (_proxyDirIndex == k_Proxy2_RootDirIndex)
{
*isSupported = BoolToInt(true);
return S_OK;
}
arcIndex = _proxy2->Dirs[_proxyDirIndex].ArcIndex;
}
else
{
SET_realIndex_AND_dir_2
arcIndex = dir->Items[realIndex];
}
if (_proxy2->Files[arcIndex].AltDirIndex >= 0)
*isSupported = BoolToInt(true);
return S_OK;
}
STDMETHODIMP CAgentFolder::BindToParentFolder(IFolderFolder **resultFolder)
{
COM_TRY_BEGIN
/*
CMyComPtr<IFolderFolder> parentFolder = _parentFolder;
*resultFolder = parentFolder.Detach();
*/
*resultFolder = NULL;
unsigned proxyDirIndex;
if (_proxy2)
{
if (_proxyDirIndex == k_Proxy2_RootDirIndex)
return S_OK;
if (_proxyDirIndex == k_Proxy2_AltRootDirIndex)
proxyDirIndex = k_Proxy2_RootDirIndex;
else
{
const CProxyDir2 &fold = _proxy2->Dirs[_proxyDirIndex];
const CProxyFile2 &file = _proxy2->Files[fold.ArcIndex];
int parentIndex = file.Parent;
if (parentIndex < 0)
proxyDirIndex = k_Proxy2_RootDirIndex;
else
proxyDirIndex = _proxy2->Files[parentIndex].DirIndex;
}
}
else
{
int parent = _proxy->Dirs[_proxyDirIndex].ParentDir;
if (parent < 0)
return S_OK;
proxyDirIndex = parent;
}
CAgentFolder *folderSpec = new CAgentFolder;
CMyComPtr<IFolderFolder> agentFolder = folderSpec;
folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec);
*resultFolder = agentFolder.Detach();
return S_OK;
COM_TRY_END
}
STDMETHODIMP CAgentFolder::GetStream(UInt32 index, ISequentialInStream **stream)
{
CMyComPtr<IInArchiveGetStream> getStream;
_agentSpec->GetArchive()->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream);
if (!getStream)
return S_OK;
UInt32 arcIndex;
if (_proxy2)
{
SET_realIndex_AND_dir_2
arcIndex = dir->Items[realIndex];
}
else
{
SET_realIndex_AND_dir
if (realIndex < dir->SubDirs.Size())
{
const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]];
if (!item.IsLeaf())
return S_OK;
arcIndex = item.ArcIndex;
}
else
arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()];
}
return getStream->GetStream(arcIndex, stream);
}
// static const unsigned k_FirstOptionalProp = 2;
static const PROPID kProps[] =
{
kpidNumSubDirs,
kpidNumSubFiles,
// kpidNumAltStreams,
kpidPrefix
};
struct CArchiveItemPropertyTemp
{
UString Name;
PROPID ID;
VARTYPE Type;
};
STDMETHODIMP CAgentFolder::GetNumberOfProperties(UInt32 *numProps)
{
COM_TRY_BEGIN
RINOK(_agentSpec->GetArchive()->GetNumberOfProperties(numProps));
*numProps += ARRAY_SIZE(kProps);
if (!_flatMode)
(*numProps)--;
/*
if (!_agentSpec->ThereIsAltStreamProp)
(*numProps)--;
*/
/*
bool thereIsPathProp = _proxy2 ?
_agentSpec->_proxy2->ThereIsPathProp :
_agentSpec->_proxy->ThereIsPathProp;
*/
// if there is kpidPath, we change kpidPath to kpidName
// if there is no kpidPath, we add kpidName.
if (!_agentSpec->ThereIsPathProp)
(*numProps)++;
return S_OK;
COM_TRY_END
}
STDMETHODIMP CAgentFolder::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)
{
COM_TRY_BEGIN
UInt32 numProps;
_agentSpec->GetArchive()->GetNumberOfProperties(&numProps);
/*
bool thereIsPathProp = _proxy2 ?
_agentSpec->_proxy2->ThereIsPathProp :
_agentSpec->_proxy->ThereIsPathProp;
*/
if (!_agentSpec->ThereIsPathProp)
{
if (index == 0)
{
*propID = kpidName;
*varType = VT_BSTR;
*name = 0;
return S_OK;
}
index--;
}
if (index < numProps)
{
RINOK(_agentSpec->GetArchive()->GetPropertyInfo(index, name, propID, varType));
if (*propID == kpidPath)
*propID = kpidName;
}
else
{
index -= numProps;
/*
if (index >= k_FirstOptionalProp)
{
if (!_agentSpec->ThereIsAltStreamProp)
index++;
}
*/
*propID = kProps[index];
*varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID];
*name = 0;
}
return S_OK;
COM_TRY_END
}
static const PROPID kFolderProps[] =
{
kpidSize,
kpidPackSize,
kpidNumSubDirs,
kpidNumSubFiles,
kpidCRC
};
STDMETHODIMP CAgentFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
if (propID == kpidReadOnly)
prop = _agentSpec->IsThereReadOnlyArc();
else if (_proxy2)
{
const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex];
if (propID == kpidName)
{
if (dir.ArcIndex >= 0)
prop = _proxy2->Files[dir.ArcIndex].Name;
}
else if (propID == kpidPath)
{
bool isAltStreamFolder = false;
prop = _proxy2->GetDirPath_as_Prefix(_proxyDirIndex, isAltStreamFolder);
}
else switch (propID)
{
case kpidSize: prop = dir.Size; break;
case kpidPackSize: prop = dir.PackSize; break;
case kpidNumSubDirs: prop = dir.NumSubDirs; break;
case kpidNumSubFiles: prop = dir.NumSubFiles; break;
// case kpidName: prop = dir.Name; break;
// case kpidPath: prop = _proxy2->GetFullPathPrefix(_proxyDirIndex); break;
case kpidType: prop = UString(L"7-Zip.") + _agentSpec->ArchiveType; break;
case kpidCRC: if (dir.CrcIsDefined) prop = dir.Crc; break;
}
}
else
{
const CProxyDir &dir = _proxy->Dirs[_proxyDirIndex];
switch (propID)
{
case kpidSize: prop = dir.Size; break;
case kpidPackSize: prop = dir.PackSize; break;
case kpidNumSubDirs: prop = dir.NumSubDirs; break;
case kpidNumSubFiles: prop = dir.NumSubFiles; break;
case kpidName: prop = dir.Name; break;
case kpidPath: prop = _proxy->GetDirPath_as_Prefix(_proxyDirIndex); break;
case kpidType: prop = UString(L"7-Zip.") + _agentSpec->ArchiveType; break;
case kpidCRC: if (dir.CrcIsDefined) prop = dir.Crc; break;
}
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
STDMETHODIMP CAgentFolder::GetNumberOfFolderProperties(UInt32 *numProps)
{
*numProps = ARRAY_SIZE(kFolderProps);
return S_OK;
}
STDMETHODIMP CAgentFolder::GetFolderPropertyInfo IMP_IFolderFolder_GetProp(kFolderProps)
STDMETHODIMP CAgentFolder::GetParent(UInt32 /* index */, UInt32 * /* parent */, UInt32 * /* parentType */)
{
return E_FAIL;
}
STDMETHODIMP CAgentFolder::GetNumRawProps(UInt32 *numProps)
{
IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps();
if (rawProps)
return rawProps->GetNumRawProps(numProps);
*numProps = 0;
return S_OK;
}
STDMETHODIMP CAgentFolder::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)
{
IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps();
if (rawProps)
return rawProps->GetRawPropInfo(index, name, propID);
return E_FAIL;
}
STDMETHODIMP CAgentFolder::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)
{
IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps();
if (rawProps)
{
unsigned arcIndex;
if (_proxy2)
{
SET_realIndex_AND_dir_2
arcIndex = dir->Items[realIndex];
}
else
{
SET_realIndex_AND_dir
if (realIndex < dir->SubDirs.Size())
{
const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]];
if (!item.IsLeaf())
{
*data = NULL;
*dataSize = 0;
*propType = 0;
return S_OK;
}
arcIndex = item.ArcIndex;
}
else
arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()];
}
return rawProps->GetRawProp(arcIndex, propID, data, dataSize, propType);
}
*data = NULL;
*dataSize = 0;
*propType = 0;
return S_OK;
}
STDMETHODIMP CAgentFolder::GetFolderArcProps(IFolderArcProps **object)
{
CMyComPtr<IFolderArcProps> temp = _agentSpec;
*object = temp.Detach();
return S_OK;
}
#ifdef NEW_FOLDER_INTERFACE
STDMETHODIMP CAgentFolder::SetFlatMode(Int32 flatMode)
{
_flatMode = IntToBool(flatMode);
return S_OK;
}
#endif
int CAgentFolder::GetRealIndex(unsigned index) const
{
if (!_flatMode)
{
if (_proxy2)
return _proxy2->GetRealIndex(_proxyDirIndex, index);
else
return _proxy->GetRealIndex(_proxyDirIndex, index);
}
{
const CProxyItem &item = _items[index];
if (_proxy2)
{
const CProxyDir2 *dir = &_proxy2->Dirs[item.DirIndex];
return dir->Items[item.Index];
}
else
{
const CProxyDir *dir = &_proxy->Dirs[item.DirIndex];
unsigned realIndex = item.Index;
if (realIndex < dir->SubDirs.Size())
{
const CProxyDir &f = _proxy->Dirs[dir->SubDirs[realIndex]];
if (!f.IsLeaf())
return -1;
return f.ArcIndex;
}
return dir->SubFiles[realIndex - dir->SubDirs.Size()];
}
}
}
void CAgentFolder::GetRealIndices(const UInt32 *indices, UInt32 numItems, bool includeAltStreams, bool includeFolderSubItemsInFlatMode, CUIntVector &realIndices) const
{
if (!_flatMode)
{
if (_proxy2)
_proxy2->GetRealIndices(_proxyDirIndex, indices, numItems, includeAltStreams, realIndices);
else
_proxy->GetRealIndices(_proxyDirIndex, indices, numItems, realIndices);
return;
}
realIndices.Clear();
for (UInt32 i = 0; i < numItems; i++)
{
const CProxyItem &item = _items[indices[i]];
if (_proxy2)
{
const CProxyDir2 *dir = &_proxy2->Dirs[item.DirIndex];
_proxy2->AddRealIndices_of_ArcItem(dir->Items[item.Index], includeAltStreams, realIndices);
continue;
}
UInt32 arcIndex;
{
const CProxyDir *dir = &_proxy->Dirs[item.DirIndex];
unsigned realIndex = item.Index;
if (realIndex < dir->SubDirs.Size())
{
if (includeFolderSubItemsInFlatMode)
{
_proxy->AddRealIndices(dir->SubDirs[realIndex], realIndices);
continue;
}
const CProxyDir &f = _proxy->Dirs[dir->SubDirs[realIndex]];
if (!f.IsLeaf())
continue;
arcIndex = f.ArcIndex;
}
else
arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()];
}
realIndices.Add(arcIndex);
}
HeapSort(&realIndices.Front(), realIndices.Size());
}
STDMETHODIMP CAgentFolder::Extract(const UInt32 *indices,
UInt32 numItems,
Int32 includeAltStreams,
Int32 replaceAltStreamColon,
NExtract::NPathMode::EEnum pathMode,
NExtract::NOverwriteMode::EEnum overwriteMode,
const wchar_t *path,
Int32 testMode,
IFolderArchiveExtractCallback *extractCallback2)
{
COM_TRY_BEGIN
CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
UStringVector pathParts;
bool isAltStreamFolder = false;
if (_proxy2)
_proxy2->GetDirPathParts(_proxyDirIndex, pathParts, isAltStreamFolder);
else
_proxy->GetDirPathParts(_proxyDirIndex, pathParts);
/*
if (_flatMode)
pathMode = NExtract::NPathMode::kNoPathnames;
*/
extractCallbackSpec->InitForMulti(false, pathMode, overwriteMode);
if (extractCallback2)
extractCallback2->SetTotal(_agentSpec->GetArc().GetEstmatedPhySize());
FString pathU;
if (path)
{
pathU = us2fs(path);
if (!pathU.IsEmpty())
{
NFile::NName::NormalizeDirPathPrefix(pathU);
NFile::NDir::CreateComplexDir(pathU);
}
}
CExtractNtOptions extractNtOptions;
extractNtOptions.AltStreams.Val = IntToBool(includeAltStreams); // change it!!!
extractNtOptions.AltStreams.Def = true;
extractNtOptions.ReplaceColonForAltStream = IntToBool(replaceAltStreamColon);
extractCallbackSpec->Init(
extractNtOptions,
NULL, &_agentSpec->GetArc(),
extractCallback2,
false, // stdOutMode
IntToBool(testMode),
pathU,
pathParts, isAltStreamFolder,
(UInt64)(Int64)-1);
if (_proxy2)
extractCallbackSpec->SetBaseParentFolderIndex(_proxy2->Dirs[_proxyDirIndex].ArcIndex);
CUIntVector realIndices;
GetRealIndices(indices, numItems, IntToBool(includeAltStreams),
false, // includeFolderSubItemsInFlatMode
realIndices); //
#ifdef SUPPORT_LINKS
if (!testMode)
{
RINOK(extractCallbackSpec->PrepareHardLinks(&realIndices));
}
#endif
HRESULT result = _agentSpec->GetArchive()->Extract(&realIndices.Front(),
realIndices.Size(), testMode, extractCallback);
if (result == S_OK)
result = extractCallbackSpec->SetDirsTimes();
return result;
COM_TRY_END
}
/////////////////////////////////////////
// CAgent
CAgent::CAgent():
_proxy(NULL),
_proxy2(NULL),
_isDeviceFile(false),
_updatePathPrefix_is_AltFolder(false)
{
}
CAgent::~CAgent()
{
if (_proxy)
delete _proxy;
if (_proxy2)
delete _proxy2;
}
bool CAgent::CanUpdate() const
{
// FAR plugin uses empty agent to create new archive !!!
if (_archiveLink.Arcs.Size() == 0)
return true;
if (_isDeviceFile)
return false;
if (_archiveLink.Arcs.Size() != 1)
return false;
if (_archiveLink.Arcs[0].ErrorInfo.ThereIsTail)
return false;
return true;
}
STDMETHODIMP CAgent::Open(
IInStream *inStream,
const wchar_t *filePath,
const wchar_t *arcFormat,
BSTR *archiveType,
IArchiveOpenCallback *openArchiveCallback)
{
COM_TRY_BEGIN
_archiveFilePath = filePath;
NFile::NFind::CFileInfo fi;
_isDeviceFile = false;
if (!inStream)
{
if (!fi.Find(us2fs(_archiveFilePath)))
return ::GetLastError();
if (fi.IsDir())
return E_FAIL;
_isDeviceFile = fi.IsDevice;
}
CArcInfoEx archiverInfo0, archiverInfo1;
RINOK(LoadGlobalCodecs());
CObjectVector<COpenType> types;
if (!ParseOpenTypes(*g_CodecsObj, arcFormat, types))
return S_FALSE;
/*
CObjectVector<COptionalOpenProperties> optProps;
if (Read_ShowDeleted())
{
COptionalOpenProperties &optPair = optProps.AddNew();
optPair.FormatName = L"ntfs";
// optPair.Props.AddNew().Name = L"LS";
optPair.Props.AddNew().Name = L"LD";
}
*/
COpenOptions options;
options.props = NULL;
options.codecs = g_CodecsObj;
options.types = &types;
CIntVector exl;
options.excludedFormats = &exl;
options.stdInMode = false;
options.stream = inStream;
options.filePath = _archiveFilePath;
options.callback = openArchiveCallback;
RINOK(_archiveLink.Open(options));
CArc &arc = _archiveLink.Arcs.Back();
if (!inStream)
{
arc.MTimeDefined = !fi.IsDevice;
arc.MTime = fi.MTime;
}
ArchiveType = GetTypeOfArc(arc);
if (archiveType)
{
RINOK(StringToBstr(ArchiveType, archiveType));
}
return S_OK;
COM_TRY_END
}
STDMETHODIMP CAgent::ReOpen(IArchiveOpenCallback *openArchiveCallback)
{
COM_TRY_BEGIN
if (_proxy2)
{
delete _proxy2;
_proxy2 = NULL;
}
if (_proxy)
{
delete _proxy;
_proxy = NULL;
}
CObjectVector<COpenType> incl;
CIntVector exl;
COpenOptions options;
options.props = NULL;
options.codecs = g_CodecsObj;
options.types = &incl;
options.excludedFormats = &exl;
options.stdInMode = false;
options.filePath = _archiveFilePath;
options.callback = openArchiveCallback;
RINOK(_archiveLink.ReOpen(options));
return ReadItems();
COM_TRY_END
}
STDMETHODIMP CAgent::Close()
{
COM_TRY_BEGIN
return _archiveLink.Close();
COM_TRY_END
}
/*
STDMETHODIMP CAgent::EnumProperties(IEnumSTATPROPSTG **EnumProperties)
{
return _archive->EnumProperties(EnumProperties);
}
*/
HRESULT CAgent::ReadItems()
{
if (_proxy || _proxy2)
return S_OK;
const CArc &arc = GetArc();
bool useProxy2 = (arc.GetRawProps && arc.IsTree);
// useProxy2 = false;
if (useProxy2)
_proxy2 = new CProxyArc2();
else
_proxy = new CProxyArc();
{
ThereIsPathProp = false;
// ThereIsAltStreamProp = false;
UInt32 numProps;
arc.Archive->GetNumberOfProperties(&numProps);
for (UInt32 i = 0; i < numProps; i++)
{
CMyComBSTR name;
PROPID propID;
VARTYPE varType;
RINOK(arc.Archive->GetPropertyInfo(i, &name, &propID, &varType));
if (propID == kpidPath)
ThereIsPathProp = true;
/*
if (propID == kpidIsAltStream)
ThereIsAltStreamProp = true;
*/
}
}
if (_proxy2)
return _proxy2->Load(GetArc(), NULL);
return _proxy->Load(GetArc(), NULL);
}
STDMETHODIMP CAgent::BindToRootFolder(IFolderFolder **resultFolder)
{
COM_TRY_BEGIN
RINOK(ReadItems());
CAgentFolder *folderSpec = new CAgentFolder;
CMyComPtr<IFolderFolder> rootFolder = folderSpec;
folderSpec->Init(_proxy, _proxy2, k_Proxy_RootDirIndex, /* NULL, */ this);
*resultFolder = rootFolder.Detach();
return S_OK;
COM_TRY_END
}
STDMETHODIMP CAgent::Extract(
NExtract::NPathMode::EEnum pathMode,
NExtract::NOverwriteMode::EEnum overwriteMode,
const wchar_t *path,
Int32 testMode,
IFolderArchiveExtractCallback *extractCallback2)
{
COM_TRY_BEGIN
CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
extractCallbackSpec->InitForMulti(false, pathMode, overwriteMode);
CExtractNtOptions extractNtOptions;
extractNtOptions.AltStreams.Val = true; // change it!!!
extractNtOptions.AltStreams.Def = true; // change it!!!
extractNtOptions.ReplaceColonForAltStream = false; // change it!!!
extractCallbackSpec->Init(
extractNtOptions,
NULL, &GetArc(),
extractCallback2,
false, // stdOutMode
IntToBool(testMode),
us2fs(path),
UStringVector(), false,
(UInt64)(Int64)-1);
#ifdef SUPPORT_LINKS
if (!testMode)
{
RINOK(extractCallbackSpec->PrepareHardLinks(NULL)); // NULL means all items
}
#endif
return GetArchive()->Extract(0, (UInt32)(Int32)-1, testMode, extractCallback);
COM_TRY_END
}
STDMETHODIMP CAgent::GetNumberOfProperties(UInt32 *numProps)
{
COM_TRY_BEGIN
return GetArchive()->GetNumberOfProperties(numProps);
COM_TRY_END
}
STDMETHODIMP CAgent::GetPropertyInfo(UInt32 index,
BSTR *name, PROPID *propID, VARTYPE *varType)
{
COM_TRY_BEGIN
RINOK(GetArchive()->GetPropertyInfo(index, name, propID, varType));
if (*propID == kpidPath)
*propID = kpidName;
return S_OK;
COM_TRY_END
}
STDMETHODIMP CAgent::GetArcNumLevels(UInt32 *numLevels)
{
*numLevels = _archiveLink.Arcs.Size();
return S_OK;
}
STDMETHODIMP CAgent::GetArcProp(UInt32 level, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
if (level > (UInt32)_archiveLink.Arcs.Size())
return E_INVALIDARG;
if (level == (UInt32)_archiveLink.Arcs.Size())
{
switch (propID)
{
case kpidPath:
if (!_archiveLink.NonOpen_ArcPath.IsEmpty())
prop = _archiveLink.NonOpen_ArcPath;
break;
case kpidErrorType:
if (_archiveLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
prop = g_CodecsObj->Formats[_archiveLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name;
break;
}
}
else
{
const CArc &arc = _archiveLink.Arcs[level];
switch (propID)
{
case kpidType: prop = GetTypeOfArc(arc); break;
case kpidPath: prop = arc.Path; break;
case kpidErrorType: if (arc.ErrorInfo.ErrorFormatIndex >= 0) prop = g_CodecsObj->Formats[arc.ErrorInfo.ErrorFormatIndex].Name; break;
case kpidErrorFlags:
{
UInt32 flags = arc.ErrorInfo.GetErrorFlags();
if (flags != 0)
prop = flags;
break;
}
case kpidWarningFlags:
{
UInt32 flags = arc.ErrorInfo.GetWarningFlags();
if (flags != 0)
prop = flags;
break;
}
case kpidOffset:
{
Int64 v = arc.GetGlobalOffset();
if (v != 0)
prop = v;
break;
}
case kpidTailSize:
{
if (arc.ErrorInfo.TailSize != 0)
prop = arc.ErrorInfo.TailSize;
break;
}
default: return arc.Archive->GetArchiveProperty(propID, value);
}
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
STDMETHODIMP CAgent::GetArcNumProps(UInt32 level, UInt32 *numProps)
{
return _archiveLink.Arcs[level].Archive->GetNumberOfArchiveProperties(numProps);
}
STDMETHODIMP CAgent::GetArcPropInfo(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)
{
return _archiveLink.Arcs[level].Archive->GetArchivePropertyInfo(index, name, propID, varType);
}
// MainItemProperty
STDMETHODIMP CAgent::GetArcProp2(UInt32 level, PROPID propID, PROPVARIANT *value)
{
return _archiveLink.Arcs[level - 1].Archive->GetProperty(_archiveLink.Arcs[level].SubfileIndex, propID, value);
}
STDMETHODIMP CAgent::GetArcNumProps2(UInt32 level, UInt32 *numProps)
{
return _archiveLink.Arcs[level - 1].Archive->GetNumberOfProperties(numProps);
}
STDMETHODIMP CAgent::GetArcPropInfo2(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)
{
return _archiveLink.Arcs[level - 1].Archive->GetPropertyInfo(index, name, propID, varType);
}