mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 15:14:59 -06:00
1572 lines
41 KiB
C++
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);
|
|
}
|