// AgentProxy.cpp #include "StdAfx.h" // #include #ifdef _WIN32 #include #else #include #endif #include "../../../../C/Sort.h" #include "../../../../C/CpuArch.h" #include "../../../Common/UTFConvert.h" #include "../../../Common/Wildcard.h" #include "../../../Windows/PropVariant.h" #include "../../../Windows/PropVariantConv.h" #include "AgentProxy.h" using namespace NWindows; int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &insertPos) const { const CRecordVector &subDirs = Dirs[dirIndex].SubDirs; unsigned left = 0, right = subDirs.Size(); for (;;) { if (left == right) { insertPos = left; return -1; } unsigned mid = (left + right) / 2; unsigned dirIndex2 = subDirs[mid]; int compare = CompareFileNames(name, Dirs[dirIndex2].Name); if (compare == 0) return dirIndex2; if (compare < 0) right = mid; else left = mid + 1; } } int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name) const { unsigned insertPos; return FindSubDir(dirIndex, name, insertPos); } unsigned CProxyArc::AddDir(unsigned dirIndex, int arcIndex, const UString &name) { unsigned insertPos; int subDirIndex = FindSubDir(dirIndex, name, insertPos); if (subDirIndex >= 0) { if (arcIndex >= 0) { CProxyDir &item = Dirs[subDirIndex]; if (item.ArcIndex < 0) item.ArcIndex = arcIndex; } return subDirIndex; } subDirIndex = Dirs.Size(); Dirs[dirIndex].SubDirs.Insert(insertPos, subDirIndex); CProxyDir &item = Dirs.AddNew(); item.NameLen = name.Len(); item.Name = new wchar_t[item.NameLen + 1]; MyStringCopy((wchar_t *)item.Name, name); item.ArcIndex = arcIndex; item.ParentDir = dirIndex; return subDirIndex; } void CProxyDir::Clear() { SubDirs.Clear(); SubFiles.Clear(); } void CProxyArc::GetDirPathParts(int dirIndex, UStringVector &pathParts) const { pathParts.Clear(); while (dirIndex >= 0) { const CProxyDir &dir = Dirs[dirIndex]; dirIndex = dir.ParentDir; if (dirIndex < 0) break; pathParts.Insert(0, dir.Name); } } UString CProxyArc::GetDirPath_as_Prefix(int dirIndex) const { UString s; while (dirIndex >= 0) { const CProxyDir &dir = Dirs[dirIndex]; dirIndex = dir.ParentDir; if (dirIndex < 0) break; s.InsertAtFront(WCHAR_PATH_SEPARATOR); s.Insert(0, dir.Name); } return s; } void CProxyArc::AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const { const CProxyDir &dir = Dirs[dirIndex]; if (dir.IsLeaf()) realIndices.Add(dir.ArcIndex); unsigned i; for (i = 0; i < dir.SubDirs.Size(); i++) AddRealIndices(dir.SubDirs[i], realIndices); for (i = 0; i < dir.SubFiles.Size(); i++) realIndices.Add(dir.SubFiles[i]); } int CProxyArc::GetRealIndex(unsigned dirIndex, unsigned index) const { const CProxyDir &dir = Dirs[dirIndex]; unsigned numDirItems = dir.SubDirs.Size(); if (index < numDirItems) { const CProxyDir &f = Dirs[dir.SubDirs[index]]; if (f.IsLeaf()) return f.ArcIndex; return -1; } return dir.SubFiles[index - numDirItems]; } void CProxyArc::GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, CUIntVector &realIndices) const { const CProxyDir &dir = Dirs[dirIndex]; realIndices.Clear(); for (UInt32 i = 0; i < numItems; i++) { UInt32 index = indices[i]; unsigned numDirItems = dir.SubDirs.Size(); if (index < numDirItems) AddRealIndices(dir.SubDirs[index], realIndices); else realIndices.Add(dir.SubFiles[index - numDirItems]); } HeapSort(&realIndices.Front(), realIndices.Size()); } /////////////////////////////////////////////// // CProxyArc 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 CProxyArc::CalculateSizes(unsigned dirIndex, IInArchive *archive) { CProxyDir &dir = Dirs[dirIndex]; dir.Size = dir.PackSize = 0; dir.NumSubDirs = dir.SubDirs.Size(); dir.NumSubFiles = dir.SubFiles.Size(); dir.CrcIsDefined = true; dir.Crc = 0; unsigned i; for (i = 0; i < dir.SubFiles.Size(); i++) { UInt32 index = (UInt32)dir.SubFiles[i]; UInt64 size, packSize; bool sizeDefined = GetSize(archive, index, kpidSize, size); dir.Size += size; GetSize(archive, index, kpidPackSize, packSize); dir.PackSize += packSize; { NCOM::CPropVariant prop; if (archive->GetProperty(index, kpidCRC, &prop) == S_OK) { if (prop.vt == VT_UI4) dir.Crc += prop.ulVal; else if (prop.vt != VT_EMPTY || size != 0 || !sizeDefined) dir.CrcIsDefined = false; } else dir.CrcIsDefined = false; } } for (i = 0; i < dir.SubDirs.Size(); i++) { unsigned subDirIndex = dir.SubDirs[i]; CalculateSizes(subDirIndex, archive); CProxyDir &f = Dirs[subDirIndex]; dir.Size += f.Size; dir.PackSize += f.PackSize; dir.NumSubFiles += f.NumSubFiles; dir.NumSubDirs += f.NumSubDirs; dir.Crc += f.Crc; if (!f.CrcIsDefined) dir.CrcIsDefined = false; } } HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress) { // DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1; ttt++) { Files.Free(); Dirs.Clear(); Dirs.AddNew(); IInArchive *archive = arc.Archive; UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); if (progress) RINOK(progress->SetTotal(numItems)); Files.Alloc(numItems); UString path; UString name; NCOM::CPropVariant prop; for (UInt32 i = 0; i < numItems; i++) { if (progress && (i & 0xFFFF) == 0) { UInt64 currentItemIndex = i; RINOK(progress->SetCompleted(¤tItemIndex)); } const wchar_t *s = NULL; unsigned len = 0; bool isPtrName = false; #if defined(MY_CPU_LE) && defined(_WIN32) // it works only if (sizeof(wchar_t) == 2) if (arc.GetRawProps) { const void *p; UInt32 size; UInt32 propType; if (arc.GetRawProps->GetRawProp(i, kpidPath, &p, &size, &propType) == S_OK && propType == NPropDataType::kUtf16z && size > 2) { // is (size <= 2), it's empty name, and we call default arc.GetItemPath(); len = size / 2 - 1; s = (const wchar_t *)p; isPtrName = true; } } if (!s) #endif { prop.Clear(); RINOK(arc.Archive->GetProperty(i, kpidPath, &prop)); if (prop.vt == VT_BSTR) { s = prop.bstrVal; len = ::SysStringLen(prop.bstrVal); } else if (prop.vt != VT_EMPTY) return E_FAIL; if (len == 0) { RINOK(arc.GetDefaultItemPath(i, path)); len = path.Len(); s = path; } /* RINOK(arc.GetItemPath(i, path)); len = path.Len(); s = path; */ } unsigned curItem = 0; /* 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]"); } */ unsigned namePos = 0; unsigned numLevels = 0; for (unsigned j = 0; j < len; j++) { wchar_t c = s[j]; if (c == WCHAR_PATH_SEPARATOR || c == L'/') { const unsigned kLevelLimit = 1 << 10; if (numLevels <= kLevelLimit) { if (numLevels == kLevelLimit) name.SetFromAscii("[LONG_PATH]"); else name.SetFrom(s + namePos, j - namePos); curItem = AddDir(curItem, -1, name); } namePos = j + 1; numLevels++; } } /* 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 isDir; RINOK(Archive_IsItem_Dir(archive, i, isDir)); CProxyFile &f = Files[i]; f.NameLen = len - namePos; s += namePos; if (isPtrName) f.Name = s; else { f.Name = new wchar_t[f.NameLen + 1]; f.NeedDeleteName = true; MyStringCopy((wchar_t *)f.Name, s); } if (isDir) { name = s; AddDir(curItem, (int)i, name); } else Dirs[curItem].SubFiles.Add(i); } CalculateSizes(0, archive); // } char s[128]; sprintf(s, "Load archive: %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s); return S_OK; } // ---------- for Tree-mode archive ---------- void CProxyArc2::GetDirPathParts(int dirIndex, UStringVector &pathParts, bool &isAltStreamDir) const { pathParts.Clear(); isAltStreamDir = false; if (dirIndex == k_Proxy2_RootDirIndex) return; if (dirIndex == k_Proxy2_AltRootDirIndex) { isAltStreamDir = true; return; } while (dirIndex >= k_Proxy2_NumRootDirs) { const CProxyDir2 &dir = Dirs[dirIndex]; const CProxyFile2 &file = Files[dir.ArcIndex]; if (pathParts.IsEmpty() && dirIndex == file.AltDirIndex) isAltStreamDir = true; pathParts.Insert(0, file.Name); int par = file.Parent; if (par < 0) break; dirIndex = Files[par].DirIndex; } } bool CProxyArc2::IsAltDir(unsigned dirIndex) const { if (dirIndex == k_Proxy2_RootDirIndex) return false; if (dirIndex == k_Proxy2_AltRootDirIndex) return true; const CProxyDir2 &dir = Dirs[dirIndex]; const CProxyFile2 &file = Files[dir.ArcIndex]; return ((int)dirIndex == file.AltDirIndex); } UString CProxyArc2::GetDirPath_as_Prefix(unsigned dirIndex, bool &isAltStreamDir) const { isAltStreamDir = false; const CProxyDir2 &dir = Dirs[dirIndex]; if (dirIndex == k_Proxy2_AltRootDirIndex) isAltStreamDir = true; else if (dirIndex >= k_Proxy2_NumRootDirs) { const CProxyFile2 &file = Files[dir.ArcIndex]; isAltStreamDir = ((int)dirIndex == file.AltDirIndex); } return dir.PathPrefix; } void CProxyArc2::AddRealIndices_of_ArcItem(unsigned arcIndex, bool includeAltStreams, CUIntVector &realIndices) const { realIndices.Add(arcIndex); const CProxyFile2 &file = Files[arcIndex]; if (file.DirIndex >= 0) AddRealIndices_of_Dir(file.DirIndex, includeAltStreams, realIndices); if (includeAltStreams && file.AltDirIndex >= 0) AddRealIndices_of_Dir(file.AltDirIndex, includeAltStreams, realIndices); } void CProxyArc2::AddRealIndices_of_Dir(unsigned dirIndex, bool includeAltStreams, CUIntVector &realIndices) const { const CRecordVector &subFiles = Dirs[dirIndex].Items; FOR_VECTOR (i, subFiles) { AddRealIndices_of_ArcItem(subFiles[i], includeAltStreams, realIndices); } } unsigned CProxyArc2::GetRealIndex(unsigned dirIndex, unsigned index) const { return Dirs[dirIndex].Items[index]; } void CProxyArc2::GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, bool includeAltStreams, CUIntVector &realIndices) const { const CProxyDir2 &dir = Dirs[dirIndex]; realIndices.Clear(); for (UInt32 i = 0; i < numItems; i++) { AddRealIndices_of_ArcItem(dir.Items[indices[i]], includeAltStreams, realIndices); } HeapSort(&realIndices.Front(), realIndices.Size()); } void CProxyArc2::CalculateSizes(unsigned dirIndex, IInArchive *archive) { CProxyDir2 &dir = Dirs[dirIndex]; dir.Size = dir.PackSize = 0; dir.NumSubDirs = 0; // dir.SubDirs.Size(); dir.NumSubFiles = 0; // dir.Files.Size(); dir.CrcIsDefined = true; dir.Crc = 0; FOR_VECTOR (i, dir.Items) { UInt32 index = dir.Items[i]; UInt64 size, packSize; bool sizeDefined = GetSize(archive, index, kpidSize, size); dir.Size += size; GetSize(archive, index, kpidPackSize, packSize); dir.PackSize += packSize; { NCOM::CPropVariant prop; if (archive->GetProperty(index, kpidCRC, &prop) == S_OK) { if (prop.vt == VT_UI4) dir.Crc += prop.ulVal; else if (prop.vt != VT_EMPTY || size != 0 || !sizeDefined) dir.CrcIsDefined = false; } else dir.CrcIsDefined = false; } const CProxyFile2 &subFile = Files[index]; if (subFile.DirIndex < 0) { dir.NumSubFiles++; } else { dir.NumSubDirs++; CProxyDir2 &f = Dirs[subFile.DirIndex]; f.PathPrefix = dir.PathPrefix + subFile.Name + WCHAR_PATH_SEPARATOR; CalculateSizes(subFile.DirIndex, archive); dir.Size += f.Size; dir.PackSize += f.PackSize; dir.NumSubFiles += f.NumSubFiles; dir.NumSubDirs += f.NumSubDirs; dir.Crc += f.Crc; if (!f.CrcIsDefined) dir.CrcIsDefined = false; } if (subFile.AltDirIndex < 0) { // dir.NumSubFiles++; } else { // dir.NumSubDirs++; CProxyDir2 &f = Dirs[subFile.AltDirIndex]; f.PathPrefix = dir.PathPrefix + subFile.Name + L':'; CalculateSizes(subFile.AltDirIndex, archive); } } } bool CProxyArc2::IsThere_SubDir(unsigned dirIndex, const UString &name) const { const CRecordVector &subFiles = Dirs[dirIndex].Items; FOR_VECTOR (i, subFiles) { const CProxyFile2 &file = Files[subFiles[i]]; if (file.IsDir()) if (CompareFileNames(name, file.Name) == 0) return true; } return false; } HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress) { if (!arc.GetRawProps) return E_FAIL; // DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1; ttt++) { Dirs.Clear(); Files.Free(); IInArchive *archive = arc.Archive; UInt32 numItems; RINOK(archive->GetNumberOfItems(&numItems)); if (progress) RINOK(progress->SetTotal(numItems)); UString fileName; { // Dirs[0] - root dir /* CProxyDir2 &dir = */ Dirs.AddNew(); } { // Dirs[1] - for alt streams of root dir CProxyDir2 &dir = Dirs.AddNew(); dir.PathPrefix = L':'; } Files.Alloc(numItems); UString tempUString; AString tempAString; UInt32 i; for (i = 0; i < numItems; i++) { if (progress && (i & 0xFFFFF) == 0) { UInt64 currentItemIndex = i; RINOK(progress->SetCompleted(¤tItemIndex)); } CProxyFile2 &file = Files[i]; const void *p; UInt32 size; UInt32 propType; RINOK(arc.GetRawProps->GetRawProp(i, kpidName, &p, &size, &propType)); #ifdef MY_CPU_LE if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE) { file.Name = (const wchar_t *)p; file.NameLen = 0; if (size >= sizeof(wchar_t)) file.NameLen = size / sizeof(wchar_t) - 1; } else #endif if (p && propType == NPropDataType::kUtf8z) { tempAString = (const char *)p; ConvertUTF8ToUnicode(tempAString, tempUString); file.NameLen = tempUString.Len(); file.Name = new wchar_t[file.NameLen + 1]; file.NeedDeleteName = true; wmemcpy((wchar_t *)file.Name, tempUString.Ptr(), file.NameLen + 1); } else { 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.NameLen = MyStringLen(s); file.Name = new wchar_t[file.NameLen + 1]; file.NeedDeleteName = true; wmemcpy((wchar_t *)file.Name, s, file.NameLen + 1); } 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 isDir; RINOK(Archive_IsItem_Dir(archive, i, isDir)); if (isDir) { file.DirIndex = Dirs.Size(); CProxyDir2 &dir = Dirs.AddNew(); dir.ArcIndex = i; } if (arc.Ask_AltStream) RINOK(Archive_IsItem_AltStream(archive, i, file.IsAltStream)); } for (i = 0; i < numItems; i++) { CProxyFile2 &file = Files[i]; int dirIndex; if (file.IsAltStream) { if (file.Parent < 0) dirIndex = k_Proxy2_AltRootDirIndex; else { int &folderIndex2 = Files[file.Parent].AltDirIndex; if (folderIndex2 < 0) { folderIndex2 = Dirs.Size(); CProxyDir2 &dir = Dirs.AddNew(); dir.ArcIndex = file.Parent; } dirIndex = folderIndex2; } } else { if (file.Parent < 0) dirIndex = k_Proxy2_RootDirIndex; else { dirIndex = Files[file.Parent].DirIndex; if (dirIndex < 0) return E_FAIL; } } Dirs[dirIndex].Items.Add(i); } for (i = 0; i < k_Proxy2_NumRootDirs; i++) CalculateSizes(i, archive); // } char s[128]; sprintf(s, "Load archive: %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s); return S_OK; } int CProxyArc2::FindItem(unsigned dirIndex, const wchar_t *name, bool foldersOnly) const { const CProxyDir2 &dir = Dirs[dirIndex]; FOR_VECTOR (i, dir.Items) { const CProxyFile2 &file = Files[dir.Items[i]]; if (foldersOnly && file.DirIndex < 0) continue; if (CompareFileNames(file.Name, name) == 0) return i; } return -1; }