// Agent.cpp #include "StdAfx.h" #include #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 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 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 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 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 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 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 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 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 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 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 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 types; if (!ParseOpenTypes(*g_CodecsObj, arcFormat, types)) return S_FALSE; /* CObjectVector 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 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 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 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); }