Files
easy7zip/CPP/7zip/UI/Agent/Agent.cpp
Igor Pavlov 0dc16c691d 9.35
2016-05-28 00:16:53 +01:00

1572 lines
41 KiB
C++

// Agent.cpp
#include "StdAfx.h"
#include "../../../../C/Sort.h"
#include "../../../Common/ComTry.h"
#include "../../../Windows/PropVariantConv.h"
#include "../Common/ArchiveExtractCallback.h"
#include "../FileManager/RegistryUtils.h"
#include "Agent.h"
using namespace NWindows;
STDMETHODIMP CAgentFolder::GetAgentFolder(CAgentFolder **agentFolder)
{
*agentFolder = this;
return S_OK;
}
void CAgentFolder::LoadFolder(unsigned proxyFolderIndex)
{
unsigned i;
CProxyItem item;
item.ProxyFolderIndex = proxyFolderIndex;
if (_proxyArchive2)
{
const CProxyFolder2 &folder = _proxyArchive2->Folders[proxyFolderIndex];
for (i = 0; i < folder.SubFiles.Size(); i++)
{
item.Index = i;
_items.Add(item);
const CProxyFile2 &file = _proxyArchive2->Files[folder.SubFiles[i]];
int subFolderIndex = file.FolderIndex;
if (subFolderIndex >= 0)
LoadFolder(subFolderIndex);
subFolderIndex = file.AltStreamsFolderIndex;
if (subFolderIndex >= 0)
LoadFolder(subFolderIndex);
}
return;
}
const CProxyFolder &folder = _proxyArchive->Folders[proxyFolderIndex];
for (i = 0; i < folder.Folders.Size(); i++)
{
item.Index = i;
_items.Add(item);
LoadFolder(folder.Folders[i]);
}
unsigned start = folder.Folders.Size();
for (i = 0; i < folder.Files.Size(); i++)
{
item.Index = start + i;
_items.Add(item);
}
}
STDMETHODIMP CAgentFolder::LoadItems()
{
if (!_agentSpec->_archiveLink.IsOpen)
return E_FAIL;
_items.Clear();
if (_flatMode)
LoadFolder(_proxyFolderItem);
return S_OK;
}
STDMETHODIMP CAgentFolder::GetNumberOfItems(UInt32 *numItems)
{
if (_flatMode)
*numItems = _items.Size();
else if (_proxyArchive2)
*numItems = _proxyArchive2->Folders[_proxyFolderItem].SubFiles.Size();
else
{
const CProxyFolder *folder = &_proxyArchive->Folders[_proxyFolderItem];
*numItems = folder->Folders.Size() + folder ->Files.Size();
}
return S_OK;
}
#define SET_realIndex_AND_folder \
UInt32 realIndex; const CProxyFolder *folder; \
if (_flatMode) { const CProxyItem &item = _items[index]; folder = &_proxyArchive->Folders[item.ProxyFolderIndex]; realIndex = item.Index; } \
else { folder = &_proxyArchive->Folders[_proxyFolderItem]; realIndex = index; }
#define SET_realIndex_AND_folder_2 \
UInt32 realIndex; const CProxyFolder2 *folder; \
if (_flatMode) { const CProxyItem &item = _items[index]; folder = &_proxyArchive2->Folders[item.ProxyFolderIndex]; realIndex = item.Index; } \
else { folder = &_proxyArchive2->Folders[_proxyFolderItem]; realIndex = index; }
UString CAgentFolder::GetName(UInt32 index) const
{
if (_proxyArchive2)
{
SET_realIndex_AND_folder_2
return _proxyArchive2->Files[folder->SubFiles[realIndex]].Name;
}
SET_realIndex_AND_folder
if (realIndex < (UInt32)folder->Folders.Size())
return _proxyArchive->Folders[folder->Folders[realIndex]].Name;
return folder->Files[realIndex - folder->Folders.Size()].Name;
}
void CAgentFolder::GetPrefix(UInt32 index, UString &prefix) const
{
if (!_flatMode)
{
prefix.Empty();
return;
}
const CProxyItem &item = _items[index];
unsigned proxyIndex = item.ProxyFolderIndex;
unsigned totalLen;
if (_proxyArchive2)
{
unsigned len = 0;
while (proxyIndex != _proxyFolderItem)
{
const CProxyFile2 &file = _proxyArchive2->Files[_proxyArchive2->Folders[proxyIndex].ArcIndex];
len += file.NameSize + 1;
proxyIndex = (file.Parent < 0) ? 0 : _proxyArchive2->Files[file.Parent].GetFolderIndex(file.IsAltStream);
}
totalLen = len;
wchar_t *p = prefix.GetBuffer(len);
proxyIndex = item.ProxyFolderIndex;
while (proxyIndex != _proxyFolderItem)
{
const CProxyFile2 &file = _proxyArchive2->Files[_proxyArchive2->Folders[proxyIndex].ArcIndex];
MyStringCopy(p + len - file.NameSize - 1, file.Name);
p[--len] = WCHAR_PATH_SEPARATOR;
len -= file.NameSize;
proxyIndex = (file.Parent < 0) ? 0 : _proxyArchive2->Files[file.Parent].GetFolderIndex(file.IsAltStream);
}
}
else
{
unsigned len = 0;
while (proxyIndex != _proxyFolderItem)
{
const CProxyFolder *folder = &_proxyArchive->Folders[proxyIndex];
len += folder->Name.Len() + 1;
proxyIndex = folder->Parent;
}
totalLen = len;
wchar_t *p = prefix.GetBuffer(len);
proxyIndex = item.ProxyFolderIndex;
while (proxyIndex != _proxyFolderItem)
{
const CProxyFolder *folder = &_proxyArchive->Folders[proxyIndex];
MyStringCopy(p + len - folder->Name.Len() - 1, (const wchar_t *)folder->Name);
p[--len] = WCHAR_PATH_SEPARATOR;
len -= folder->Name.Len();
proxyIndex = folder->Parent;
}
}
prefix.ReleaseBuffer(totalLen);
}
UString CAgentFolder::GetFullPathPrefixPlusPrefix(UInt32 index) const
{
UString prefix;
GetPrefix(index, prefix);
if (_proxyArchive2)
return _proxyArchive2->GetFullPathPrefix(_proxyFolderItem) + prefix;
else
return _proxyArchive->GetFullPathPrefix(_proxyFolderItem) + prefix;
}
STDMETHODIMP_(UInt64) CAgentFolder::GetItemSize(UInt32 index)
{
unsigned arcIndex;
if (_proxyArchive2)
{
SET_realIndex_AND_folder_2
arcIndex = folder->SubFiles[realIndex];
const CProxyFile2 &item = _proxyArchive2->Files[arcIndex];
if (item.IsDir())
{
const CProxyFolder2 &itemFolder = _proxyArchive2->Folders[item.FolderIndex];
if (!_flatMode)
return itemFolder.Size;
}
}
else
{
SET_realIndex_AND_folder
if (realIndex < (UInt32)folder->Folders.Size())
{
const CProxyFolder &item = _proxyArchive->Folders[folder->Folders[realIndex]];
if (!_flatMode)
return item.Size;
if (!item.IsLeaf)
return 0;
arcIndex = item.Index;
}
else
{
const CProxyFile &item = folder->Files[realIndex - folder->Folders.Size()];
arcIndex = item.Index;
}
}
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 (_proxyArchive2)
{
SET_realIndex_AND_folder_2
unsigned arcIndex = folder->SubFiles[realIndex];
const CProxyFile2 &item = _proxyArchive2->Files[arcIndex];
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 CProxyFolder2 &itemFolder = _proxyArchive2->Folders[item.FolderIndex];
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.NumSubFolders; 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_folder
if (realIndex < (UInt32)folder->Folders.Size())
{
const CProxyFolder &item = _proxyArchive->Folders[folder->Folders[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.NumSubFolders; break;
case kpidNumSubFiles: prop = item.NumSubFiles; break;
case kpidName: prop = item.Name; break;
case kpidCRC:
{
if (item.IsLeaf)
{
RINOK(_agentSpec->GetArchive()->GetProperty(item.Index, propID, value));
}
if (item.CrcIsDefined && value->vt == VT_EMPTY)
prop = item.Crc;
break;
}
default:
if (item.IsLeaf)
return _agentSpec->GetArchive()->GetProperty(item.Index, propID, value);
}
}
else
{
const CProxyFile &item = folder->Files[realIndex - folder->Folders.Size()];
switch (propID)
{
case kpidIsDir: prop = false; break;
case kpidName: prop = item.Name; break;
default:
return _agentSpec->GetArchive()->GetProperty(item.Index, 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 (_proxyArchive2)
{
SET_realIndex_AND_folder_2
unsigned arcIndex = folder->SubFiles[realIndex];
const CProxyFile2 &item = _proxyArchive2->Files[arcIndex];
*name = item.Name;
*len = item.NameSize;
return S_OK;
}
else
{
SET_realIndex_AND_folder
if (realIndex < (UInt32)folder->Folders.Size())
{
const CProxyFolder &item = _proxyArchive->Folders[folder->Folders[realIndex]];
*name = item.Name;
*len = item.Name.Len();
return S_OK;
}
else
{
const CProxyFile &item = folder->Files[realIndex - folder->Folders.Size()];
*name = item.Name;
*len = item.Name.Len();
return S_OK;
}
}
}
STDMETHODIMP CAgentFolder::GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len)
{
*name = 0;
*len = 0;
if (!_flatMode)
return S_OK;
if (_proxyArchive2)
{
SET_realIndex_AND_folder_2
unsigned arcIndex = folder->SubFiles[realIndex];
const CProxyFile2 &item = _proxyArchive2->Files[arcIndex];
if (item.Parent >= 0)
{
const CProxyFile2 &item2 = _proxyArchive2->Files[item.Parent];
int foldInd = item2.GetFolderIndex(item.IsAltStream);
if (foldInd >= 0)
{
const UString &s = _proxyArchive2->Folders[foldInd].PathPrefix;
unsigned baseLen = _proxyArchive2->Folders[_proxyFolderItem].PathPrefix.Len();
if (baseLen <= s.Len())
{
*name = (const wchar_t *)s + baseLen;
*len = s.Len() - baseLen;
}
}
}
}
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)
{
UInt32 realIndex1, realIndex2;
const CProxyFolder2 *folder1, *folder2;
if (_flatMode)
{
const CProxyItem &item1 = _items[index1];
const CProxyItem &item2 = _items[index2];
folder1 = &_proxyArchive2->Folders[item1.ProxyFolderIndex];
folder2 = &_proxyArchive2->Folders[item2.ProxyFolderIndex];
realIndex1 = item1.Index;
realIndex2 = item2.Index;
}
else
{
folder2 = folder1 = &_proxyArchive2->Folders[_proxyFolderItem];
realIndex1 = index1;
realIndex2 = index2;
}
UInt32 arcIndex1;
UInt32 arcIndex2;
bool isDir1, isDir2;
arcIndex1 = folder1->SubFiles[realIndex1];
arcIndex2 = folder2->SubFiles[realIndex2];
const CProxyFile2 &prox1 = _proxyArchive2->Files[arcIndex1];
const CProxyFile2 &prox2 = _proxyArchive2->Files[arcIndex2];
if (propID == kpidName)
{
return CompareFileNames_ForFolderList(prox1.Name, prox2.Name);
}
if (propID == kpidPrefix)
{
if (!_flatMode)
return 0;
if (prox1.Parent < 0) return prox2.Parent < 0 ? 0 : -1;
if (prox2.Parent < 0) return 1;
const CProxyFile2 &proxPar1 = _proxyArchive2->Files[prox1.Parent];
const CProxyFile2 &proxPar2 = _proxyArchive2->Files[prox2.Parent];
return CompareFileNames_ForFolderList(
_proxyArchive2->Folders[proxPar1.GetFolderIndex(prox1.IsAltStream)].PathPrefix,
_proxyArchive2->Folders[proxPar2.GetFolderIndex(prox2.IsAltStream)].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 CProxyFolder2 *proxFolder1 = NULL;
const CProxyFolder2 *proxFolder2 = NULL;
if (isDir1) proxFolder1 = &_proxyArchive2->Folders[prox1.FolderIndex];
if (isDir2) proxFolder2 = &_proxyArchive2->Folders[prox2.FolderIndex];
if (propID == kpidNumSubDirs)
{
UInt32 n1 = 0;
UInt32 n2 = 0;
if (isDir1) n1 = proxFolder1->NumSubFolders;
if (isDir2) n2 = proxFolder2->NumSubFolders;
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)
{
COM_TRY_BEGIN
if (_proxyArchive2)
return CompareItems2(index1, index2, propID, propIsRaw);
UInt32 realIndex1, realIndex2;
const CProxyFolder *folder1, *folder2;
if (_flatMode)
{
const CProxyItem &item1 = _items[index1];
const CProxyItem &item2 = _items[index2];
folder1 = &_proxyArchive->Folders[item1.ProxyFolderIndex];
folder2 = &_proxyArchive->Folders[item2.ProxyFolderIndex];
realIndex1 = item1.Index;
realIndex2 = item2.Index;
}
else
{
folder2 = folder1 = &_proxyArchive->Folders[_proxyFolderItem];
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);
}
const CProxyFile *prox1;
const CProxyFile *prox2;
const CProxyFolder *proxFolder1 = NULL;
const CProxyFolder *proxFolder2 = NULL;
bool isDir1, isDir2;
if (realIndex1 < (UInt32)folder1->Folders.Size())
{
isDir1 = true;
prox1 = proxFolder1 = &_proxyArchive->Folders[folder1->Folders[realIndex1]];
}
else
{
isDir1 = false;
prox1 = &folder1->Files[realIndex1 - folder1->Folders.Size()];
}
if (realIndex2 < (UInt32)folder2->Folders.Size())
{
isDir2 = true;
prox2 = proxFolder2 = &_proxyArchive->Folders[folder2->Folders[realIndex2]];
}
else
{
isDir2 = false;
prox2 = &folder2->Files[realIndex2 - folder2->Folders.Size()];
}
if (propID == kpidName)
{
return CompareFileNames_ForFolderList(prox1->Name, prox2->Name);
}
if (propID == kpidExtension)
{
return CompareFileNames_ForFolderList(
GetExtension(prox1->Name),
GetExtension(prox2->Name));
}
if (propID == kpidIsDir)
{
if (isDir1 == isDir2)
return 0;
return isDir1 ? -1 : 1;
}
if (propID == kpidNumSubDirs)
{
UInt32 n1 = 0;
UInt32 n2 = 0;
if (isDir1) n1 = proxFolder1->NumSubFolders;
if (isDir2) n2 = proxFolder2->NumSubFolders;
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(), prox1->Index, kpidSize);
if (isDir2)
n2 = _flatMode ? 0 : proxFolder2->Size;
else
n2 = GetUInt64Prop(_agentSpec->GetArchive(), prox2->Index, kpidSize);
return MyCompare(n1, n2);
}
if (propID == kpidPackSize)
{
UInt64 n1, n2;
if (isDir1)
n1 = _flatMode ? 0 : proxFolder1->PackSize;
else
n1 = GetUInt64Prop(_agentSpec->GetArchive(), prox1->Index, kpidPackSize);
if (isDir2)
n2 = _flatMode ? 0 : proxFolder2->PackSize;
else
n2 = GetUInt64Prop(_agentSpec->GetArchive(), prox2->Index, kpidPackSize);
return MyCompare(n1, n2);
}
if (propID == kpidCRC)
{
UInt64 n1, n2;
if (!isDir1 || proxFolder1->IsLeaf)
n1 = GetUInt64Prop(_agentSpec->GetArchive(), prox1->Index, kpidCRC);
else
n1 = proxFolder1->Crc;
if (!isDir2 || proxFolder2->IsLeaf)
n2 = GetUInt64Prop(_agentSpec->GetArchive(), prox2->Index, kpidCRC);
else
n2 = proxFolder2->Crc;
return MyCompare(n1, n2);
}
if (propIsRaw)
return CompareRawProps(_agentSpec->_archiveLink.GetArchiveGetRawProps(), prox1->Index, prox2->Index, 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);
COM_TRY_END
}
HRESULT CAgentFolder::BindToFolder_Internal(unsigned proxyFolderIndex, IFolderFolder **resultFolder)
{
CMyComPtr<IFolderFolder> parentFolder;
if (_proxyArchive2)
{
parentFolder = NULL; // Change it;
const CProxyFolder2 &folder = _proxyArchive2->Folders[proxyFolderIndex];
int par = _proxyArchive2->GetParentFolderOfFile(folder.ArcIndex);
if (par != (int)_proxyFolderItem)
{
// return E_FAIL;
RINOK(BindToFolder_Internal(par, &parentFolder));
}
else
parentFolder = this;
}
else
{
const CProxyFolder &folder = _proxyArchive->Folders[proxyFolderIndex];
if (folder.Parent != (int)_proxyFolderItem)
{
RINOK(BindToFolder_Internal(folder.Parent, &parentFolder));
}
else
parentFolder = this;
}
CAgentFolder *folderSpec = new CAgentFolder;
CMyComPtr<IFolderFolder> agentFolder = folderSpec;
folderSpec->Init(_proxyArchive, _proxyArchive2, proxyFolderIndex, parentFolder, _agentSpec);
*resultFolder = agentFolder.Detach();
return S_OK;
}
STDMETHODIMP CAgentFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder)
{
COM_TRY_BEGIN
if (_proxyArchive2)
{
SET_realIndex_AND_folder_2
unsigned arcIndex = folder->SubFiles[realIndex];
const CProxyFile2 &item = _proxyArchive2->Files[arcIndex];
if (!item.IsDir())
return E_INVALIDARG;
return BindToFolder_Internal(item.FolderIndex, resultFolder);
}
SET_realIndex_AND_folder
if (realIndex >= (UInt32)folder->Folders.Size())
return E_INVALIDARG;
return BindToFolder_Internal(folder->Folders[realIndex], resultFolder);
COM_TRY_END
}
STDMETHODIMP CAgentFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder)
{
COM_TRY_BEGIN
if (_proxyArchive2)
{
const CProxyFolder2 &folder = _proxyArchive2->Folders[_proxyFolderItem];
FOR_VECTOR (i, folder.SubFiles)
{
const CProxyFile2 &file = _proxyArchive2->Files[folder.SubFiles[i]];
if (file.FolderIndex >= 0)
if (StringsAreEqualNoCase(file.Name, name))
return BindToFolder_Internal(file.FolderIndex, resultFolder);
}
return E_INVALIDARG;
}
int index = _proxyArchive->FindDirSubItemIndex(_proxyFolderItem, name);
if (index < 0)
return E_INVALIDARG;
return BindToFolder_Internal(index, resultFolder);
COM_TRY_END
}
STDMETHODIMP CAgentFolder::BindToParentFolder(IFolderFolder **resultFolder)
{
// COM_TRY_BEGIN
CMyComPtr<IFolderFolder> parentFolder = _parentFolder;
*resultFolder = parentFolder.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 indexInArchive;
if (_proxyArchive2)
{
SET_realIndex_AND_folder_2
indexInArchive = folder->SubFiles[realIndex];
}
else
{
SET_realIndex_AND_folder
if (realIndex < (UInt32)folder->Folders.Size())
{
const CProxyFolder &item = _proxyArchive->Folders[folder->Folders[realIndex]];
if (!item.IsLeaf)
return S_OK;
indexInArchive = item.Index;
}
else
indexInArchive = folder->Files[realIndex - folder->Folders.Size()].Index;
}
return getStream->GetStream(indexInArchive, stream);
}
static const PROPID kProps[] =
{
kpidNumSubDirs,
kpidNumSubFiles,
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)--;
/*
bool thereIsPathProp = _proxyArchive2 ?
_agentSpec->_proxyArchive2->ThereIsPathProp :
_agentSpec->_proxyArchive->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 = _proxyArchive2 ?
_agentSpec->_proxyArchive2->ThereIsPathProp :
_agentSpec->_proxyArchive->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
{
*propID = kProps[index - numProps];
*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 (_proxyArchive2)
{
const CProxyFolder2 &folder = _proxyArchive2->Folders[_proxyFolderItem];
if (propID == kpidName)
{
if (folder.ArcIndex >= 0)
prop = _proxyArchive2->Files[folder.ArcIndex].Name;
}
else if (propID == kpidPath)
{
prop = _proxyArchive2->GetFullPathPrefix(_proxyFolderItem);
}
else switch (propID)
{
case kpidSize: prop = folder.Size; break;
case kpidPackSize: prop = folder.PackSize; break;
case kpidNumSubDirs: prop = folder.NumSubFolders; break;
case kpidNumSubFiles: prop = folder.NumSubFiles; break;
// case kpidName: prop = folder.Name; break;
// case kpidPath: prop = _proxyArchive2->GetFullPathPrefix(_proxyFolderItem); break;
case kpidType: prop = UString(L"7-Zip.") + _agentSpec->ArchiveType; break;
case kpidCRC: if (folder.CrcIsDefined) prop = folder.Crc; break;
}
}
else
{
const CProxyFolder &folder = _proxyArchive->Folders[_proxyFolderItem];
switch (propID)
{
case kpidSize: prop = folder.Size; break;
case kpidPackSize: prop = folder.PackSize; break;
case kpidNumSubDirs: prop = folder.NumSubFolders; break;
case kpidNumSubFiles: prop = folder.NumSubFiles; break;
case kpidName: prop = folder.Name; break;
case kpidPath: prop = _proxyArchive->GetFullPathPrefix(_proxyFolderItem); break;
case kpidType: prop = UString(L"7-Zip.") + _agentSpec->ArchiveType; break;
case kpidCRC: if (folder.CrcIsDefined) prop = folder.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 (_proxyArchive2)
{
SET_realIndex_AND_folder_2
arcIndex = folder->SubFiles[realIndex];
}
else
{
SET_realIndex_AND_folder
if (realIndex < (UInt32)folder->Folders.Size())
{
const CProxyFolder &item = _proxyArchive->Folders[folder->Folders[realIndex]];
if (!item.IsLeaf)
{
*data = NULL;
*dataSize = 0;
*propType = 0;
return S_OK;
}
arcIndex = item.Index;
}
else
{
const CProxyFile &item = folder->Files[realIndex - folder->Folders.Size()];
arcIndex = item.Index;
}
}
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 (_proxyArchive2)
return _proxyArchive2->GetRealIndex(_proxyFolderItem, index);
else
return _proxyArchive->GetRealIndex(_proxyFolderItem, index);
}
{
const CProxyItem &item = _items[index];
if (_proxyArchive2)
{
const CProxyFolder2 *folder = &_proxyArchive2->Folders[item.ProxyFolderIndex];
return folder->SubFiles[item.Index];
}
else
{
const CProxyFolder *folder = &_proxyArchive->Folders[item.ProxyFolderIndex];
unsigned realIndex = item.Index;
if (realIndex < folder->Folders.Size())
{
const CProxyFolder &f = _proxyArchive->Folders[folder->Folders[realIndex]];
if (!f.IsLeaf)
return -1;
return f.Index;
}
return folder->Files[realIndex - folder->Folders.Size()].Index;
}
}
}
void CAgentFolder::GetRealIndices(const UInt32 *indices, UInt32 numItems, bool includeAltStreams, bool includeFolderSubItemsInFlatMode, CUIntVector &realIndices) const
{
if (!_flatMode)
{
if (_proxyArchive2)
_proxyArchive2->GetRealIndices(_proxyFolderItem, indices, numItems, includeAltStreams, realIndices);
else
_proxyArchive->GetRealIndices(_proxyFolderItem, indices, numItems, realIndices);
return;
}
realIndices.Clear();
for (UInt32 i = 0; i < numItems; i++)
{
const CProxyItem &item = _items[indices[i]];
if (_proxyArchive2)
{
const CProxyFolder2 *folder = &_proxyArchive2->Folders[item.ProxyFolderIndex];
_proxyArchive2->AddRealIndices_of_ArcItem(folder->SubFiles[item.Index], includeAltStreams, realIndices);
continue;
}
UInt32 arcIndex;
{
const CProxyFolder *folder = &_proxyArchive->Folders[item.ProxyFolderIndex];
unsigned realIndex = item.Index;
if (realIndex < folder->Folders.Size())
{
if (includeFolderSubItemsInFlatMode)
{
_proxyArchive->AddRealIndices(folder->Folders[realIndex], realIndices);
continue;
}
const CProxyFolder &f = _proxyArchive->Folders[folder->Folders[realIndex]];
if (!f.IsLeaf)
continue;
arcIndex = f.Index;
}
else
arcIndex = folder->Files[realIndex - folder->Folders.Size()].Index;
}
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;
if (_proxyArchive2)
_proxyArchive2->GetPathParts(_proxyFolderItem, pathParts);
else
_proxyArchive->GetPathParts(_proxyFolderItem, pathParts);
/*
if (_flatMode)
pathMode = NExtract::NPathMode::kNoPathnames;
*/
extractCallbackSpec->InitForMulti(false, pathMode, overwriteMode);
FString pathU;
if (path)
pathU = us2fs(path);
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),
path ? pathU : FTEXT(""),
pathParts,
(UInt64)(Int64)-1);
if (_proxyArchive2)
extractCallbackSpec->SetBaseParentFolderIndex(_proxyArchive2->Folders[_proxyFolderItem].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():
_proxyArchive(NULL),
_proxyArchive2(NULL),
_isDeviceFile(false),
_codecs(0)
{
}
CAgent::~CAgent()
{
if (_proxyArchive)
delete _proxyArchive;
if (_proxyArchive2)
delete _proxyArchive2;
}
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;
_compressCodecsInfo.Release();
_codecs = new CCodecs;
_compressCodecsInfo = _codecs;
RINOK(_codecs->Load());
CObjectVector<COpenType> types;
if (!ParseOpenTypes(*_codecs, 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 = _codecs;
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 (_proxyArchive2)
{
delete _proxyArchive2;
_proxyArchive2 = NULL;
}
if (_proxyArchive)
{
delete _proxyArchive;
_proxyArchive = NULL;
}
CObjectVector<COpenType> incl;
CIntVector exl;
COpenOptions options;
options.props = NULL;
options.codecs = _codecs;
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 (_proxyArchive || _proxyArchive2)
return S_OK;
const CArc &arc = GetArc();
bool useProxy2 = (arc.GetRawProps && arc.IsTree);
// useProxy2 = false;
if (useProxy2)
_proxyArchive2 = new CProxyArchive2();
else
_proxyArchive = new CProxyArchive();
{
ThereIsPathProp = 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;
break;
}
}
}
if (_proxyArchive2)
return _proxyArchive2->Load(GetArc(), NULL);
return _proxyArchive->Load(GetArc(), NULL);
}
STDMETHODIMP CAgent::BindToRootFolder(IFolderFolder **resultFolder)
{
COM_TRY_BEGIN
RINOK(ReadItems());
CAgentFolder *folderSpec = new CAgentFolder;
CMyComPtr<IFolderFolder> rootFolder = folderSpec;
folderSpec->Init(_proxyArchive, _proxyArchive2, 0, 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(),
(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 = _codecs->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 = _codecs->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);
}