// AgentProxy.cpp #include "StdAfx.h" #include "../../../../C/Sort.h" #include "../../../../C/CpuArch.h" #include "../../../Common/Wildcard.h" #include "../../../Windows/PropVariant.h" #include "../../../Windows/PropVariantConv.h" #include "AgentProxy.h" using namespace NWindows; int CProxyArchive::FindDirSubItemIndex(unsigned folderIndex, const UString &name, unsigned &insertPos) const { const CRecordVector &subFolders = Folders[folderIndex].Folders; unsigned left = 0, right = subFolders.Size(); for (;;) { if (left == right) { insertPos = left; return -1; } unsigned mid = (left + right) / 2; unsigned folderIndex = subFolders[mid]; int compare = CompareFileNames(name, Folders[folderIndex].Name); if (compare == 0) return folderIndex; if (compare < 0) right = mid; else left = mid + 1; } } int CProxyArchive::FindDirSubItemIndex(unsigned folderIndex, const UString &name) const { unsigned insertPos; return FindDirSubItemIndex(folderIndex, name, insertPos); } void CProxyFolder::AddFileSubItem(UInt32 index, const UString &name) { CProxyFile &f = Files.AddNew(); f.Index = index; f.Name = name; } unsigned CProxyArchive::AddDirSubItem(unsigned folderIndex, UInt32 index, bool leaf, const UString &name) { unsigned insertPos; int subFolderIndex = FindDirSubItemIndex(folderIndex, name, insertPos); if (subFolderIndex >= 0) { CProxyFolder &item = Folders[subFolderIndex]; if (leaf) { item.Index = index; item.IsLeaf = true; } return subFolderIndex; } subFolderIndex = Folders.Size(); Folders[folderIndex].Folders.Insert(insertPos, subFolderIndex); CProxyFolder &item = Folders.AddNew(); item.Name = name; item.Index = index; item.Parent = folderIndex; item.IsLeaf = leaf; return subFolderIndex; } void CProxyFolder::Clear() { Folders.Clear(); Files.Clear(); } void CProxyArchive::GetPathParts(int folderIndex, UStringVector &pathParts) const { pathParts.Clear(); while (folderIndex >= 0) { const CProxyFolder &folder = Folders[folderIndex]; folderIndex = folder.Parent; if (folderIndex < 0) break; pathParts.Insert(0, folder.Name); } } UString CProxyArchive::GetFullPathPrefix(int folderIndex) const { UString result; while (folderIndex >= 0) { const CProxyFolder &folder = Folders[folderIndex]; folderIndex = folder.Parent; if (folderIndex < 0) break; result = folder.Name + UString(WCHAR_PATH_SEPARATOR) + result; } return result; } void CProxyArchive::AddRealIndices(unsigned folderIndex, CUIntVector &realIndices) const { const CProxyFolder &folder = Folders[folderIndex]; if (folder.IsLeaf) realIndices.Add(folder.Index); unsigned i; for (i = 0; i < folder.Folders.Size(); i++) AddRealIndices(folder.Folders[i], realIndices); for (i = 0; i < folder.Files.Size(); i++) realIndices.Add(folder.Files[i].Index); } int CProxyArchive::GetRealIndex(unsigned folderIndex, unsigned index) const { const CProxyFolder &folder = Folders[folderIndex]; unsigned numDirItems = folder.Folders.Size(); if (index < numDirItems) { const CProxyFolder &f = Folders[folder.Folders[index]]; if (f.IsLeaf) return f.Index; return -1; } return folder.Files[index - numDirItems].Index; } void CProxyArchive::GetRealIndices(unsigned folderIndex, const UInt32 *indices, UInt32 numItems, CUIntVector &realIndices) const { const CProxyFolder &folder = Folders[folderIndex]; realIndices.Clear(); for (UInt32 i = 0; i < numItems; i++) { UInt32 index = indices[i]; unsigned numDirItems = folder.Folders.Size(); if (index < numDirItems) AddRealIndices(folder.Folders[index], realIndices); else realIndices.Add(folder.Files[index - numDirItems].Index); } HeapSort(&realIndices.Front(), realIndices.Size()); } /////////////////////////////////////////////// // CProxyArchive static bool GetSize(IInArchive *archive, UInt32 index, PROPID propID, UInt64 &size) { size = 0; NCOM::CPropVariant prop; if (archive->GetProperty(index, propID, &prop) != S_OK) throw 20120228; return ConvertPropVariantToUInt64(prop, size); } void CProxyArchive::CalculateSizes(unsigned folderIndex, IInArchive *archive) { CProxyFolder &folder = Folders[folderIndex]; folder.Size = folder.PackSize = 0; folder.NumSubFolders = folder.Folders.Size(); folder.NumSubFiles = folder.Files.Size(); folder.CrcIsDefined = true; folder.Crc = 0; unsigned i; for (i = 0; i < folder.Files.Size(); i++) { UInt32 index = folder.Files[i].Index; UInt64 size, packSize; bool sizeDefined = GetSize(archive, index, kpidSize, size); folder.Size += size; GetSize(archive, index, kpidPackSize, packSize); folder.PackSize += packSize; { NCOM::CPropVariant prop; if (archive->GetProperty(index, kpidCRC, &prop) == S_OK) { if (prop.vt == VT_UI4) folder.Crc += prop.ulVal; else if (prop.vt != VT_EMPTY || size != 0 || !sizeDefined) folder.CrcIsDefined = false; } else folder.CrcIsDefined = false; } } for (i = 0; i < folder.Folders.Size(); i++) { unsigned subFolderIndex = folder.Folders[i]; CProxyFolder &f = Folders[subFolderIndex]; CalculateSizes(subFolderIndex, archive); folder.Size += f.Size; folder.PackSize += f.PackSize; folder.NumSubFiles += f.NumSubFiles; folder.NumSubFolders += f.NumSubFolders; folder.Crc += f.Crc; if (!f.CrcIsDefined) folder.CrcIsDefined = false; } } HRESULT CProxyArchive::Load(const CArc &arc, IProgress *progress) { /* DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1000; ttt++) { */ Folders.Clear(); Folders.AddNew(); IInArchive *archive = arc.Archive; UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); if (progress) RINOK(progress->SetTotal(numItems)); UString filePath; UString fileName; for (UInt32 i = 0; i < numItems; i++) { if (progress && (i & 0xFFFFF) == 0) { UInt64 currentItemIndex = i; RINOK(progress->SetCompleted(¤tItemIndex)); } RINOK(arc.GetItemPath(i, filePath)); unsigned curItem = 0; unsigned len = filePath.Len(); fileName.Empty(); /* if (arc.Ask_Deleted) { bool isDeleted = false; RINOK(Archive_IsItem_Deleted(archive, i, isDeleted)); if (isDeleted) curItem = AddDirSubItem(curItem, (UInt32)(Int32)-1, false, L"[DELETED]"); } */ for (unsigned j = 0; j < len; j++) { wchar_t c = filePath[j]; if (c == WCHAR_PATH_SEPARATOR || c == L'/') { curItem = AddDirSubItem(curItem, (UInt32)(Int32)-1, false, fileName); fileName.Empty(); } else fileName += c; } /* that code must be implemeted to hide alt streams in list. if (arc.Ask_AltStreams) { bool isAltStream; RINOK(Archive_IsItem_AltStream(archive, i, isAltStream)); if (isAltStream) { } } */ bool isFolder; RINOK(Archive_IsItem_Folder(archive, i, isFolder)); if (isFolder) AddDirSubItem(curItem, i, true, fileName); else Folders[curItem].AddFileSubItem(i, fileName); } CalculateSizes(0, archive); /* } char s[128]; sprintf(s, "load archive %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s); */ return S_OK; } // ---------- for Tree-mode archive ---------- void CProxyArchive2::GetPathParts(int folderIndex, UStringVector &pathParts) const { pathParts.Clear(); while (folderIndex > 0) { const CProxyFolder2 &folder = Folders[folderIndex]; const CProxyFile2 &file = Files[folder.ArcIndex]; pathParts.Insert(0, file.Name); int par = file.Parent; if (par < 0) break; folderIndex = Files[par].FolderIndex; } } UString CProxyArchive2::GetFullPathPrefix(unsigned folderIndex) const { return Folders[folderIndex].PathPrefix; /* UString result; while (folderIndex > 0) { const CProxyFile2 &file = Files[Folders[folderIndex].ArcIndex]; result = (UString)(file.Name) + (UString)WCHAR_PATH_SEPARATOR + result; if (file.Parent < 0) break; folderIndex = Files[file.Parent].FolderIndex; } return result; */ } void CProxyArchive2::AddRealIndices_of_ArcItem(unsigned arcIndex, bool includeAltStreams, CUIntVector &realIndices) const { realIndices.Add(arcIndex); const CProxyFile2 &file = Files[arcIndex]; if (file.FolderIndex >= 0) AddRealIndices_of_Folder(file.FolderIndex, includeAltStreams, realIndices); if (includeAltStreams && file.AltStreamsFolderIndex >= 0) AddRealIndices_of_Folder(file.AltStreamsFolderIndex, includeAltStreams, realIndices); } void CProxyArchive2::AddRealIndices_of_Folder(unsigned folderIndex, bool includeAltStreams, CUIntVector &realIndices) const { const CRecordVector &subFiles = Folders[folderIndex].SubFiles; FOR_VECTOR (i, subFiles) { AddRealIndices_of_ArcItem(subFiles[i], includeAltStreams, realIndices); } } unsigned CProxyArchive2::GetRealIndex(unsigned folderIndex, unsigned index) const { return Folders[folderIndex].SubFiles[index]; } void CProxyArchive2::GetRealIndices(unsigned folderIndex, const UInt32 *indices, UInt32 numItems, bool includeAltStreams, CUIntVector &realIndices) const { const CProxyFolder2 &folder = Folders[folderIndex]; realIndices.Clear(); for (UInt32 i = 0; i < numItems; i++) { AddRealIndices_of_ArcItem(folder.SubFiles[indices[i]], includeAltStreams, realIndices); } HeapSort(&realIndices.Front(), realIndices.Size()); } void CProxyArchive2::CalculateSizes(unsigned folderIndex, IInArchive *archive) { CProxyFolder2 &folder = Folders[folderIndex]; folder.Size = folder.PackSize = 0; folder.NumSubFolders = 0; // folder.Folders.Size(); folder.NumSubFiles = 0; // folder.Files.Size(); folder.CrcIsDefined = true; folder.Crc = 0; FOR_VECTOR (i, folder.SubFiles) { UInt32 index = folder.SubFiles[i]; UInt64 size, packSize; bool sizeDefined = GetSize(archive, index, kpidSize, size); folder.Size += size; GetSize(archive, index, kpidPackSize, packSize); folder.PackSize += packSize; { NCOM::CPropVariant prop; if (archive->GetProperty(index, kpidCRC, &prop) == S_OK) { if (prop.vt == VT_UI4) folder.Crc += prop.ulVal; else if (prop.vt != VT_EMPTY || size != 0 || !sizeDefined) folder.CrcIsDefined = false; } else folder.CrcIsDefined = false; } const CProxyFile2 &subFile = Files[index]; if (subFile.FolderIndex < 0) { folder.NumSubFiles++; } else { folder.NumSubFolders++; CProxyFolder2 &f = Folders[subFile.FolderIndex]; f.PathPrefix = folder.PathPrefix + subFile.Name + WCHAR_PATH_SEPARATOR; CalculateSizes(subFile.FolderIndex, archive); folder.Size += f.Size; folder.PackSize += f.PackSize; folder.NumSubFiles += f.NumSubFiles; folder.NumSubFolders += f.NumSubFolders; folder.Crc += f.Crc; if (!f.CrcIsDefined) folder.CrcIsDefined = false; } if (subFile.AltStreamsFolderIndex < 0) { // folder.NumSubFiles++; } else { // folder.NumSubFolders++; CProxyFolder2 &f = Folders[subFile.AltStreamsFolderIndex]; f.PathPrefix = folder.PathPrefix + subFile.Name + L":"; CalculateSizes(subFile.AltStreamsFolderIndex, archive); /* folder.Size += f.Size; folder.PackSize += f.PackSize; folder.NumSubFiles += f.NumSubFiles; folder.NumSubFolders += f.NumSubFolders; folder.Crc += f.Crc; if (!f.CrcIsDefined) folder.CrcIsDefined = false; */ } } } bool CProxyArchive2::IsThere_SubDir(unsigned folderIndex, const UString &name) const { const CRecordVector &subFiles = Folders[folderIndex].SubFiles; FOR_VECTOR (i, subFiles) { const CProxyFile2 &file = Files[subFiles[i]]; if (file.IsDir()) if (CompareFileNames(name, file.Name) == 0) return true; } return false; } HRESULT CProxyArchive2::Load(const CArc &arc, IProgress *progress) { if (!arc.GetRawProps) return E_FAIL; // DWORD tickCount = GetTickCount(); Folders.Clear(); IInArchive *archive = arc.Archive; UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); if (progress) RINOK(progress->SetTotal(numItems)); UString fileName; { CProxyFolder2 &folder = Folders.AddNew(); folder.ArcIndex = -1; } Files.Alloc(numItems); UInt32 i; for (i = 0; i < numItems; i++) { if (progress && (i & 0xFFFFF) == 0) { UInt64 currentItemIndex = i; RINOK(progress->SetCompleted(¤tItemIndex)); } CProxyFile2 &file = Files[i]; #ifdef MY_CPU_LE const void *p; UInt32 size; UInt32 propType; RINOK(arc.GetRawProps->GetRawProp(i, kpidName, &p, &size, &propType)); if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE) { file.Name = (const wchar_t *)p; file.NameSize = 0; if (size >= 2) file.NameSize = size / 2 - 1; } else #endif { NCOM::CPropVariant prop; RINOK(arc.Archive->GetProperty(i, kpidName, &prop)); const wchar_t *s; if (prop.vt == VT_BSTR) s = prop.bstrVal; else if (prop.vt == VT_EMPTY) s = L"[Content]"; else return E_FAIL; file.NameSize = MyStringLen(s); file.Name = new wchar_t[file.NameSize + 1]; file.NeedDeleteName = true; MyStringCopy((wchar_t *)file.Name, s); } UInt32 parent = (UInt32)(Int32)-1; UInt32 parentType = 0; RINOK(arc.GetRawProps->GetParent(i, &parent, &parentType)); file.Parent = (Int32)parent; if (arc.Ask_Deleted) { bool isDeleted = false; RINOK(Archive_IsItem_Deleted(archive, i, isDeleted)); if (isDeleted) { // continue; // curItem = AddDirSubItem(curItem, (UInt32)(Int32)-1, false, L"[DELETED]"); } } bool isFolder; RINOK(Archive_IsItem_Folder(archive, i, isFolder)); if (isFolder) { file.FolderIndex = Folders.Size(); CProxyFolder2 &folder = Folders.AddNew(); folder.ArcIndex = i; } if (arc.Ask_AltStream) RINOK(Archive_IsItem_AltStream(archive, i, file.IsAltStream)); } for (i = 0; i < numItems; i++) { CProxyFile2 &file = Files[i]; if (file.IsAltStream) { if (file.Parent >= 0) { int &folderIndex = Files[file.Parent].AltStreamsFolderIndex; if (folderIndex < 0) { folderIndex = Folders.Size(); CProxyFolder2 &folder = Folders.AddNew(); folder.ArcIndex = file.Parent; // do we need it ??? } Folders[folderIndex].SubFiles.Add(i); } } else { int folderIndex = GetParentFolderOfFile(i); if (folderIndex < 0) return E_FAIL; Folders[folderIndex].SubFiles.Add(i); } } CalculateSizes(0, archive); /* char s[128]; sprintf(s, "load archive %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s); */ return S_OK; }