// 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 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 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 parentFolder = _parentFolder; *resultFolder = parentFolder.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 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 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 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 types; if (!ParseOpenTypes(*_codecs, 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 = _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 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 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 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); }