xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/Agent/Agent.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // Agent.cpp
2 
3 #include "StdAfx.h"
4 
5 #include <wchar.h>
6 
7 #include "../../../../C/Sort.h"
8 
9 #include "../../../Common/ComTry.h"
10 
11 #include "../../../Windows/FileDir.h"
12 #include "../../../Windows/FileName.h"
13 #include "../../../Windows/PropVariantConv.h"
14 
15 #ifndef Z7_ST
16 #include "../../../Windows/Synchronization.h"
17 #endif
18 
19 #include "../Common/ArchiveExtractCallback.h"
20 #include "../FileManager/RegistryUtils.h"
21 
22 #include "Agent.h"
23 
24 using namespace NWindows;
25 
26 CCodecs *g_CodecsObj;
27 
28 static const bool k_keepEmptyDirPrefixes =
29     false; // 22.00
30     // true; // 21.07
31 
32 #ifdef Z7_EXTERNAL_CODECS
33   extern
34   CExternalCodecs g_ExternalCodecs;
35   CExternalCodecs g_ExternalCodecs;
36   extern
37   const CExternalCodecs *g_ExternalCodecs_Ptr;
38   const CExternalCodecs *g_ExternalCodecs_Ptr;
39   static CCodecs::CReleaser g_CodecsReleaser;
40 #else
41   extern
42   CMyComPtr<IUnknown> g_CodecsRef;
43   CMyComPtr<IUnknown> g_CodecsRef;
44 #endif
45 
46 #ifndef Z7_ST
47 static NSynchronization::CCriticalSection g_CriticalSection;
48 #define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
49 #else
50 #define MT_LOCK
51 #endif
52 
FreeGlobalCodecs()53 void FreeGlobalCodecs()
54 {
55   MT_LOCK
56 
57   #ifdef Z7_EXTERNAL_CODECS
58   if (g_CodecsObj)
59   {
60     g_CodecsObj->CloseLibs();
61   }
62   g_CodecsReleaser.Set(NULL);
63   g_CodecsObj = NULL;
64   g_ExternalCodecs.ClearAndRelease();
65   g_ExternalCodecs_Ptr = NULL;
66   #else
67   g_CodecsRef.Release();
68   #endif
69 }
70 
LoadGlobalCodecs()71 HRESULT LoadGlobalCodecs()
72 {
73   MT_LOCK
74 
75   if (g_CodecsObj)
76     return S_OK;
77 
78   g_CodecsObj = new CCodecs;
79 
80   #ifdef Z7_EXTERNAL_CODECS
81   g_ExternalCodecs.GetCodecs = g_CodecsObj;
82   g_ExternalCodecs.GetHashers = g_CodecsObj;
83   g_CodecsReleaser.Set(g_CodecsObj);
84   #else
85   g_CodecsRef.Release();
86   g_CodecsRef = g_CodecsObj;
87   #endif
88 
89   RINOK(g_CodecsObj->Load())
90   if (g_CodecsObj->Formats.IsEmpty())
91   {
92     FreeGlobalCodecs();
93     return E_NOTIMPL;
94   }
95 
96   Codecs_AddHashArcHandler(g_CodecsObj);
97 
98   #ifdef Z7_EXTERNAL_CODECS
99   RINOK(g_ExternalCodecs.Load())
100   g_ExternalCodecs_Ptr = &g_ExternalCodecs;
101   #endif
102 
103   return S_OK;
104 }
105 
Z7_COM7F_IMF(CAgentFolder::GetAgentFolder (CAgentFolder ** agentFolder))106 Z7_COM7F_IMF(CAgentFolder::GetAgentFolder(CAgentFolder **agentFolder))
107 {
108   *agentFolder = this;
109   return S_OK;
110 }
111 
LoadFolder(unsigned proxyDirIndex)112 void CAgentFolder::LoadFolder(unsigned proxyDirIndex)
113 {
114   CProxyItem item;
115   item.DirIndex = proxyDirIndex;
116 
117   if (_proxy2)
118   {
119     const CProxyDir2 &dir = _proxy2->Dirs[proxyDirIndex];
120     FOR_VECTOR (i, dir.Items)
121     {
122       item.Index = i;
123       _items.Add(item);
124       const CProxyFile2 &file = _proxy2->Files[dir.Items[i]];
125       if (file.DirIndex != -1)
126         LoadFolder((unsigned)file.DirIndex);
127       if (_loadAltStreams && file.AltDirIndex != -1)
128         LoadFolder((unsigned)file.AltDirIndex);
129     }
130     return;
131   }
132 
133   const CProxyDir &dir = _proxy->Dirs[proxyDirIndex];
134   unsigned i;
135   for (i = 0; i < dir.SubDirs.Size(); i++)
136   {
137     item.Index = i;
138     _items.Add(item);
139     LoadFolder(dir.SubDirs[i]);
140   }
141 
142   unsigned start = dir.SubDirs.Size();
143   for (i = 0; i < dir.SubFiles.Size(); i++)
144   {
145     item.Index = start + i;
146     _items.Add(item);
147   }
148 }
149 
Z7_COM7F_IMF(CAgentFolder::LoadItems ())150 Z7_COM7F_IMF(CAgentFolder::LoadItems())
151 {
152   if (!_agentSpec->_archiveLink.IsOpen)
153     return E_FAIL;
154   _items.Clear();
155   if (_flatMode)
156   {
157     LoadFolder(_proxyDirIndex);
158     if (_proxy2 && _loadAltStreams)
159     {
160       if (_proxyDirIndex == k_Proxy2_RootDirIndex)
161         LoadFolder(k_Proxy2_AltRootDirIndex);
162     }
163   }
164   return S_OK;
165 }
166 
Z7_COM7F_IMF(CAgentFolder::GetNumberOfItems (UInt32 * numItems))167 Z7_COM7F_IMF(CAgentFolder::GetNumberOfItems(UInt32 *numItems))
168 {
169   if (_flatMode)
170     *numItems = _items.Size();
171   else if (_proxy2)
172     *numItems = _proxy2->Dirs[_proxyDirIndex].Items.Size();
173   else
174   {
175     const CProxyDir *dir = &_proxy->Dirs[_proxyDirIndex];
176     *numItems = dir->SubDirs.Size() + dir->SubFiles.Size();
177   }
178   return S_OK;
179 }
180 
181 #define SET_realIndex_AND_dir \
182   unsigned realIndex; const CProxyDir *dir; \
183   if (_flatMode) { const CProxyItem &item = _items[index]; dir = &_proxy->Dirs[item.DirIndex]; realIndex = item.Index; } \
184   else { dir = &_proxy->Dirs[_proxyDirIndex]; realIndex = index; }
185 
186 #define SET_realIndex_AND_dir_2 \
187   unsigned realIndex; const CProxyDir2 *dir; \
188   if (_flatMode) { const CProxyItem &item = _items[index]; dir = &_proxy2->Dirs[item.DirIndex]; realIndex = item.Index; } \
189   else { dir = &_proxy2->Dirs[_proxyDirIndex]; realIndex = index; }
190 
GetName(UInt32 index) const191 UString CAgentFolder::GetName(UInt32 index) const
192 {
193   if (_proxy2)
194   {
195     SET_realIndex_AND_dir_2
196     return _proxy2->Files[dir->Items[realIndex]].Name;
197   }
198   SET_realIndex_AND_dir
199   if (realIndex < dir->SubDirs.Size())
200     return _proxy->Dirs[dir->SubDirs[realIndex]].Name;
201   return _proxy->Files[dir->SubFiles[realIndex - dir->SubDirs.Size()]].Name;
202 }
203 
GetPrefix(UInt32 index,UString & prefix) const204 void CAgentFolder::GetPrefix(UInt32 index, UString &prefix) const
205 {
206   if (!_flatMode)
207   {
208     prefix.Empty();
209     return;
210   }
211 
212   const CProxyItem &item = _items[index];
213   unsigned proxyIndex = item.DirIndex;
214 
215   if (_proxy2)
216   {
217     // that code is unused. 7-Zip gets prefix via GetItemPrefix() .
218 
219     unsigned len = 0;
220     while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs)
221     {
222       const CProxyFile2 &file = _proxy2->Files[(unsigned)_proxy2->Dirs[proxyIndex].ArcIndex];
223       len += file.NameLen + 1;
224       proxyIndex = (file.Parent == -1) ? 0 : (unsigned)_proxy2->Files[(unsigned)file.Parent].GetDirIndex(file.IsAltStream);
225     }
226 
227     wchar_t *p = prefix.GetBuf_SetEnd(len) + len;
228     proxyIndex = item.DirIndex;
229     while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs)
230     {
231       const CProxyFile2 &file = _proxy2->Files[(unsigned)_proxy2->Dirs[proxyIndex].ArcIndex];
232       p--;
233       *p = WCHAR_PATH_SEPARATOR;
234       p -= file.NameLen;
235       wmemcpy(p, file.Name, file.NameLen);
236       proxyIndex = (file.Parent == -1) ? 0 : (unsigned)_proxy2->Files[(unsigned)file.Parent].GetDirIndex(file.IsAltStream);
237     }
238   }
239   else
240   {
241     unsigned len = 0;
242     while (proxyIndex != _proxyDirIndex)
243     {
244       const CProxyDir *dir = &_proxy->Dirs[proxyIndex];
245       len += dir->NameLen + 1;
246       proxyIndex = (unsigned)dir->ParentDir;
247     }
248 
249     wchar_t *p = prefix.GetBuf_SetEnd(len) + len;
250     proxyIndex = item.DirIndex;
251     while (proxyIndex != _proxyDirIndex)
252     {
253       const CProxyDir *dir = &_proxy->Dirs[proxyIndex];
254       p--;
255       *p = WCHAR_PATH_SEPARATOR;
256       p -= dir->NameLen;
257       wmemcpy(p, dir->Name, dir->NameLen);
258       proxyIndex = (unsigned)dir->ParentDir;
259     }
260   }
261 }
262 
GetFullPrefix(UInt32 index) const263 UString CAgentFolder::GetFullPrefix(UInt32 index) const
264 {
265   unsigned foldIndex = _proxyDirIndex;
266 
267   if (_flatMode)
268     foldIndex = _items[index].DirIndex;
269 
270   if (_proxy2)
271     return _proxy2->Dirs[foldIndex].PathPrefix;
272   else
273     return _proxy->GetDirPath_as_Prefix(foldIndex);
274 }
275 
Z7_COM7F_IMF2(UInt64,CAgentFolder::GetItemSize (UInt32 index))276 Z7_COM7F_IMF2(UInt64, CAgentFolder::GetItemSize(UInt32 index))
277 {
278   unsigned arcIndex;
279   if (_proxy2)
280   {
281     SET_realIndex_AND_dir_2
282     arcIndex = dir->Items[realIndex];
283     const CProxyFile2 &item = _proxy2->Files[arcIndex];
284     if (item.IsDir())
285     {
286       const CProxyDir2 &itemFolder = _proxy2->Dirs[item.DirIndex];
287       if (!_flatMode)
288         return itemFolder.Size;
289     }
290   }
291   else
292   {
293     SET_realIndex_AND_dir
294     if (realIndex < dir->SubDirs.Size())
295     {
296       const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]];
297       if (!_flatMode)
298         return item.Size;
299       if (!item.IsLeaf())
300         return 0;
301       arcIndex = (unsigned)item.ArcIndex;
302     }
303     else
304     {
305       arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()];
306     }
307   }
308   NCOM::CPropVariant prop;
309   _agentSpec->GetArchive()->GetProperty(arcIndex, kpidSize, &prop);
310   if (prop.vt == VT_UI8)
311     return prop.uhVal.QuadPart;
312   else
313     return 0;
314 }
315 
Z7_COM7F_IMF(CAgentFolder::GetProperty (UInt32 index,PROPID propID,PROPVARIANT * value))316 Z7_COM7F_IMF(CAgentFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
317 {
318   COM_TRY_BEGIN
319   NCOM::CPropVariant prop;
320 
321   if (propID == kpidPrefix)
322   {
323     if (_flatMode)
324     {
325       UString prefix;
326       GetPrefix(index, prefix);
327       prop = prefix;
328     }
329   }
330   else if (_proxy2)
331   {
332     SET_realIndex_AND_dir_2
333     unsigned arcIndex = dir->Items[realIndex];
334     const CProxyFile2 &item = _proxy2->Files[arcIndex];
335     /*
336     if (propID == kpidNumAltStreams)
337     {
338       if (item.AltDirIndex != -1)
339         prop = _proxy2->Dirs[item.AltDirIndex].Items.Size();
340     }
341     else
342     */
343     if (!item.IsDir())
344     {
345       switch (propID)
346       {
347         case kpidIsDir: prop = false; break;
348         case kpidName: prop = item.Name; break;
349         default: return _agentSpec->GetArchive()->GetProperty(arcIndex, propID, value);
350       }
351     }
352     else
353     {
354       const CProxyDir2 &itemFolder = _proxy2->Dirs[item.DirIndex];
355       if (!_flatMode && propID == kpidSize)
356         prop = itemFolder.Size;
357       else if (!_flatMode && propID == kpidPackSize)
358         prop = itemFolder.PackSize;
359       else switch (propID)
360       {
361         case kpidIsDir: prop = true; break;
362         case kpidNumSubDirs: prop = itemFolder.NumSubDirs; break;
363         case kpidNumSubFiles: prop = itemFolder.NumSubFiles; break;
364         case kpidName: prop = item.Name; break;
365         case kpidCRC:
366         {
367           // if (itemFolder.IsLeaf)
368           if (!item.Ignore)
369           {
370             RINOK(_agentSpec->GetArchive()->GetProperty(arcIndex, propID, value))
371           }
372           if (itemFolder.CrcIsDefined && value->vt == VT_EMPTY)
373             prop = itemFolder.Crc;
374           break;
375         }
376         default:
377           // if (itemFolder.IsLeaf)
378           if (!item.Ignore)
379             return _agentSpec->GetArchive()->GetProperty(arcIndex, propID, value);
380       }
381     }
382   }
383   else
384   {
385   SET_realIndex_AND_dir
386   if (realIndex < dir->SubDirs.Size())
387   {
388     const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]];
389     if (!_flatMode && propID == kpidSize)
390       prop = item.Size;
391     else if (!_flatMode && propID == kpidPackSize)
392       prop = item.PackSize;
393     else
394     switch (propID)
395     {
396       case kpidIsDir: prop = true; break;
397       case kpidNumSubDirs: prop = item.NumSubDirs; break;
398       case kpidNumSubFiles: prop = item.NumSubFiles; break;
399       case kpidName: prop = item.Name; break;
400       case kpidCRC:
401       {
402         if (item.IsLeaf())
403         {
404           RINOK(_agentSpec->GetArchive()->GetProperty((unsigned)item.ArcIndex, propID, value))
405         }
406         if (item.CrcIsDefined && value->vt == VT_EMPTY)
407           prop = item.Crc;
408         break;
409       }
410       default:
411         if (item.IsLeaf())
412           return _agentSpec->GetArchive()->GetProperty((unsigned)item.ArcIndex, propID, value);
413     }
414   }
415   else
416   {
417     unsigned arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()];
418     switch (propID)
419     {
420       case kpidIsDir: prop = false; break;
421       case kpidName: prop = _proxy->Files[arcIndex].Name; break;
422       default:
423         return _agentSpec->GetArchive()->GetProperty(arcIndex, propID, value);
424     }
425   }
426   }
427   prop.Detach(value);
428   return S_OK;
429   COM_TRY_END
430 }
431 
GetUInt64Prop(IInArchive * archive,UInt32 index,PROPID propID)432 static UInt64 GetUInt64Prop(IInArchive *archive, UInt32 index, PROPID propID)
433 {
434   NCOM::CPropVariant prop;
435   if (archive->GetProperty(index, propID, &prop) != S_OK)
436     throw 111233443;
437   UInt64 v = 0;
438   if (ConvertPropVariantToUInt64(prop, v))
439     return v;
440   return 0;
441 }
442 
Z7_COM7F_IMF(CAgentFolder::GetItemName (UInt32 index,const wchar_t ** name,unsigned * len))443 Z7_COM7F_IMF(CAgentFolder::GetItemName(UInt32 index, const wchar_t **name, unsigned *len))
444 {
445   if (_proxy2)
446   {
447     SET_realIndex_AND_dir_2
448     unsigned arcIndex = dir->Items[realIndex];
449     const CProxyFile2 &item = _proxy2->Files[arcIndex];
450     *name = item.Name;
451     *len = item.NameLen;
452     return S_OK;
453   }
454   else
455   {
456     SET_realIndex_AND_dir
457     if (realIndex < dir->SubDirs.Size())
458     {
459       const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]];
460       *name = item.Name;
461       *len = item.NameLen;
462       return S_OK;
463     }
464     else
465     {
466       const CProxyFile &item = _proxy->Files[dir->SubFiles[realIndex - dir->SubDirs.Size()]];
467       *name = item.Name;
468       *len = item.NameLen;
469       return S_OK;
470     }
471   }
472 }
473 
Z7_COM7F_IMF(CAgentFolder::GetItemPrefix (UInt32 index,const wchar_t ** name,unsigned * len))474 Z7_COM7F_IMF(CAgentFolder::GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len))
475 {
476   *name = NULL;
477   *len = 0;
478   if (!_flatMode)
479     return S_OK;
480 
481   if (_proxy2)
482   {
483     const CProxyItem &item = _items[index];
484     const UString &s = _proxy2->Dirs[item.DirIndex].PathPrefix;
485     unsigned baseLen = _proxy2->Dirs[_proxyDirIndex].PathPrefix.Len();
486     if (baseLen <= s.Len())
487     {
488       *name = (const wchar_t *)s + baseLen;
489       *len = s.Len() - baseLen;
490     }
491     else
492     {
493       return E_FAIL;
494       // throw 111l;
495     }
496   }
497   return S_OK;
498 }
499 
CompareRawProps(IArchiveGetRawProps * rawProps,unsigned arcIndex1,unsigned arcIndex2,PROPID propID)500 static int CompareRawProps(IArchiveGetRawProps *rawProps, unsigned arcIndex1, unsigned arcIndex2, PROPID propID)
501 {
502   // if (propID == kpidSha1)
503   if (rawProps)
504   {
505     const void *p1, *p2;
506     UInt32 size1, size2;
507     UInt32 propType1, propType2;
508     const HRESULT res1 = rawProps->GetRawProp(arcIndex1, propID, &p1, &size1, &propType1);
509     const HRESULT res2 = rawProps->GetRawProp(arcIndex2, propID, &p2, &size2, &propType2);
510     if (res1 == S_OK && res2 == S_OK)
511     {
512       for (UInt32 i = 0; i < size1 && i < size2; i++)
513       {
514         const Byte b1 = ((const Byte *)p1)[i];
515         const Byte b2 = ((const Byte *)p2)[i];
516         if (b1 < b2) return -1;
517         if (b1 > b2) return 1;
518       }
519       if (size1 < size2) return -1;
520       if (size1 > size2) return 1;
521       return 0;
522     }
523   }
524   return 0;
525 }
526 
527 // returns pointer to extension including '.'
528 
GetExtension(const wchar_t * name)529 static const wchar_t *GetExtension(const wchar_t *name)
530 {
531   for (const wchar_t *dotPtr = NULL;; name++)
532   {
533     wchar_t c = *name;
534     if (c == 0)
535       return dotPtr ? dotPtr : name;
536     if (c == '.')
537       dotPtr = name;
538   }
539 }
540 
541 
CompareItems3(UInt32 index1,UInt32 index2,PROPID propID)542 int CAgentFolder::CompareItems3(UInt32 index1, UInt32 index2, PROPID propID)
543 {
544   NCOM::CPropVariant prop1, prop2;
545   // Name must be first property
546   GetProperty(index1, propID, &prop1);
547   GetProperty(index2, propID, &prop2);
548   if (prop1.vt != prop2.vt)
549     return MyCompare(prop1.vt, prop2.vt);
550   if (prop1.vt == VT_BSTR)
551     return MyStringCompareNoCase(prop1.bstrVal, prop2.bstrVal);
552   return prop1.Compare(prop2);
553 }
554 
555 
CompareItems2(UInt32 index1,UInt32 index2,PROPID propID,Int32 propIsRaw)556 int CAgentFolder::CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw)
557 {
558   unsigned realIndex1, realIndex2;
559   const CProxyDir2 *dir1, *dir2;
560 
561   if (_flatMode)
562   {
563     const CProxyItem &item1 = _items[index1];
564     const CProxyItem &item2 = _items[index2];
565     dir1 = &_proxy2->Dirs[item1.DirIndex];
566     dir2 = &_proxy2->Dirs[item2.DirIndex];
567     realIndex1 = item1.Index;
568     realIndex2 = item2.Index;
569   }
570   else
571   {
572     dir2 = dir1 = &_proxy2->Dirs[_proxyDirIndex];
573     realIndex1 = index1;
574     realIndex2 = index2;
575   }
576 
577   UInt32 arcIndex1;
578   UInt32 arcIndex2;
579   bool isDir1, isDir2;
580   arcIndex1 = dir1->Items[realIndex1];
581   arcIndex2 = dir2->Items[realIndex2];
582   const CProxyFile2 &prox1 = _proxy2->Files[arcIndex1];
583   const CProxyFile2 &prox2 = _proxy2->Files[arcIndex2];
584 
585   if (propID == kpidName)
586   {
587     return CompareFileNames_ForFolderList(prox1.Name, prox2.Name);
588   }
589 
590   if (propID == kpidPrefix)
591   {
592     if (!_flatMode)
593       return 0;
594     return CompareFileNames_ForFolderList(
595         _proxy2->Dirs[_items[index1].DirIndex].PathPrefix,
596         _proxy2->Dirs[_items[index2].DirIndex].PathPrefix);
597   }
598 
599   if (propID == kpidExtension)
600   {
601      return CompareFileNames_ForFolderList(
602          GetExtension(prox1.Name),
603          GetExtension(prox2.Name));
604   }
605 
606   isDir1 = prox1.IsDir();
607   isDir2 = prox2.IsDir();
608 
609   if (propID == kpidIsDir)
610   {
611     if (isDir1 == isDir2)
612       return 0;
613     return isDir1 ? -1 : 1;
614   }
615 
616   const CProxyDir2 *proxFolder1 = NULL;
617   const CProxyDir2 *proxFolder2 = NULL;
618   if (isDir1) proxFolder1 = &_proxy2->Dirs[prox1.DirIndex];
619   if (isDir2) proxFolder2 = &_proxy2->Dirs[prox2.DirIndex];
620 
621   if (propID == kpidNumSubDirs)
622   {
623     UInt32 n1 = 0;
624     UInt32 n2 = 0;
625     if (isDir1) n1 = proxFolder1->NumSubDirs;
626     if (isDir2) n2 = proxFolder2->NumSubDirs;
627     return MyCompare(n1, n2);
628   }
629 
630   if (propID == kpidNumSubFiles)
631   {
632     UInt32 n1 = 0;
633     UInt32 n2 = 0;
634     if (isDir1) n1 = proxFolder1->NumSubFiles;
635     if (isDir2) n2 = proxFolder2->NumSubFiles;
636     return MyCompare(n1, n2);
637   }
638 
639   if (propID == kpidSize)
640   {
641     UInt64 n1, n2;
642     if (isDir1)
643       n1 = _flatMode ? 0 : proxFolder1->Size;
644     else
645       n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidSize);
646     if (isDir2)
647       n2 = _flatMode ? 0 : proxFolder2->Size;
648     else
649       n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidSize);
650     return MyCompare(n1, n2);
651   }
652 
653   if (propID == kpidPackSize)
654   {
655     UInt64 n1, n2;
656     if (isDir1)
657       n1 = _flatMode ? 0 : proxFolder1->PackSize;
658     else
659       n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidPackSize);
660     if (isDir2)
661       n2 = _flatMode ? 0 : proxFolder2->PackSize;
662     else
663       n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidPackSize);
664     return MyCompare(n1, n2);
665   }
666 
667   if (propID == kpidCRC)
668   {
669     UInt64 n1, n2;
670     if (!isDir1 || !prox1.Ignore)
671       n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidCRC);
672     else
673       n1 = proxFolder1->Crc;
674     if (!isDir2 || !prox2.Ignore)
675       n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidCRC);
676     else
677       n2 = proxFolder2->Crc;
678     return MyCompare(n1, n2);
679   }
680 
681   if (propIsRaw)
682     return CompareRawProps(_agentSpec->_archiveLink.GetArchiveGetRawProps(), arcIndex1, arcIndex2, propID);
683 
684   return CompareItems3(index1, index2, propID);
685 }
686 
687 
Z7_COM7F_IMF2(Int32,CAgentFolder::CompareItems (UInt32 index1,UInt32 index2,PROPID propID,Int32 propIsRaw))688 Z7_COM7F_IMF2(Int32, CAgentFolder::CompareItems(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw))
689 {
690   try {
691   if (_proxy2)
692     return CompareItems2(index1, index2, propID, propIsRaw);
693 
694   unsigned realIndex1, realIndex2;
695   const CProxyDir *dir1, *dir2;
696 
697   if (_flatMode)
698   {
699     const CProxyItem &item1 = _items[index1];
700     const CProxyItem &item2 = _items[index2];
701     dir1 = &_proxy->Dirs[item1.DirIndex];
702     dir2 = &_proxy->Dirs[item2.DirIndex];
703     realIndex1 = item1.Index;
704     realIndex2 = item2.Index;
705   }
706   else
707   {
708     dir2 = dir1 = &_proxy->Dirs[_proxyDirIndex];
709     realIndex1 = index1;
710     realIndex2 = index2;
711   }
712 
713   if (propID == kpidPrefix)
714   {
715     if (!_flatMode)
716       return 0;
717     UString prefix1, prefix2;
718     GetPrefix(index1, prefix1);
719     GetPrefix(index2, prefix2);
720     return CompareFileNames_ForFolderList(prefix1, prefix2);
721   }
722 
723   UInt32 arcIndex1;
724   UInt32 arcIndex2;
725 
726   const CProxyDir *proxFolder1 = NULL;
727   const CProxyDir *proxFolder2 = NULL;
728 
729   if (realIndex1 < dir1->SubDirs.Size())
730   {
731     proxFolder1 = &_proxy->Dirs[dir1->SubDirs[realIndex1]];
732     arcIndex1 = (unsigned)proxFolder1->ArcIndex;
733   }
734   else
735     arcIndex1 = dir1->SubFiles[realIndex1 - dir1->SubDirs.Size()];
736 
737   if (realIndex2 < dir2->SubDirs.Size())
738   {
739     proxFolder2 = &_proxy->Dirs[dir2->SubDirs[realIndex2]];
740     arcIndex2 = (unsigned)proxFolder2->ArcIndex;
741   }
742   else
743     arcIndex2 = dir2->SubFiles[realIndex2 - dir2->SubDirs.Size()];
744 
745   if (propID == kpidName)
746     return CompareFileNames_ForFolderList(
747         proxFolder1 ? proxFolder1->Name : _proxy->Files[arcIndex1].Name,
748         proxFolder2 ? proxFolder2->Name : _proxy->Files[arcIndex2].Name);
749 
750   if (propID == kpidExtension)
751     return CompareFileNames_ForFolderList(
752        GetExtension(proxFolder1 ? proxFolder1->Name : _proxy->Files[arcIndex1].Name),
753        GetExtension(proxFolder2 ? proxFolder2->Name : _proxy->Files[arcIndex2].Name));
754 
755   if (propID == kpidIsDir)
756   {
757     if (proxFolder1)
758       return proxFolder2 ? 0 : -1;
759     return proxFolder2 ? 1 : 0;
760   }
761 
762   if (propID == kpidNumSubDirs)
763   {
764     UInt32 n1 = 0;
765     UInt32 n2 = 0;
766     if (proxFolder1) n1 = proxFolder1->NumSubDirs;
767     if (proxFolder2) n2 = proxFolder2->NumSubDirs;
768     return MyCompare(n1, n2);
769   }
770 
771   if (propID == kpidNumSubFiles)
772   {
773     UInt32 n1 = 0;
774     UInt32 n2 = 0;
775     if (proxFolder1) n1 = proxFolder1->NumSubFiles;
776     if (proxFolder2) n2 = proxFolder2->NumSubFiles;
777     return MyCompare(n1, n2);
778   }
779 
780   if (propID == kpidSize)
781   {
782     UInt64 n1, n2;
783     if (proxFolder1)
784       n1 = _flatMode ? 0 : proxFolder1->Size;
785     else
786       n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidSize);
787     if (proxFolder2)
788       n2 = _flatMode ? 0 : proxFolder2->Size;
789     else
790       n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidSize);
791     return MyCompare(n1, n2);
792   }
793 
794   if (propID == kpidPackSize)
795   {
796     UInt64 n1, n2;
797     if (proxFolder1)
798       n1 = _flatMode ? 0 : proxFolder1->PackSize;
799     else
800       n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidPackSize);
801     if (proxFolder2)
802       n2 = _flatMode ? 0 : proxFolder2->PackSize;
803     else
804       n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidPackSize);
805     return MyCompare(n1, n2);
806   }
807 
808   if (propID == kpidCRC)
809   {
810     UInt64 n1, n2;
811     if (proxFolder1 && !proxFolder1->IsLeaf())
812       n1 = proxFolder1->Crc;
813     else
814       n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidCRC);
815     if (proxFolder2 && !proxFolder2->IsLeaf())
816       n2 = proxFolder2->Crc;
817     else
818       n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidCRC);
819     return MyCompare(n1, n2);
820   }
821 
822   if (propIsRaw)
823   {
824     bool isVirt1 = (proxFolder1 && !proxFolder1->IsLeaf());
825     bool isVirt2 = (proxFolder2 && !proxFolder2->IsLeaf());
826     if (isVirt1)
827       return isVirt2 ? 0 : -1;
828     if (isVirt2)
829       return 1;
830     return CompareRawProps(_agentSpec->_archiveLink.GetArchiveGetRawProps(), arcIndex1, arcIndex2, propID);
831   }
832 
833   return CompareItems3(index1, index2, propID);
834 
835   } catch(...) { return 0; }
836 }
837 
838 
BindToFolder_Internal(unsigned proxyDirIndex,IFolderFolder ** resultFolder)839 HRESULT CAgentFolder::BindToFolder_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder)
840 {
841   /*
842   CMyComPtr<IFolderFolder> parentFolder;
843 
844   if (_proxy2)
845   {
846     const CProxyDir2 &dir = _proxy2->Dirs[proxyDirIndex];
847     int par = _proxy2->GetParentFolderOfFile(dir.ArcIndex);
848     if (par != (int)_proxyDirIndex)
849     {
850       RINOK(BindToFolder_Internal(par, &parentFolder));
851     }
852     else
853       parentFolder = this;
854   }
855   else
856   {
857     const CProxyDir &dir = _proxy->Dirs[proxyDirIndex];
858     if (dir.Parent != (int)_proxyDirIndex)
859     {
860       RINOK(BindToFolder_Internal(dir.Parent, &parentFolder));
861     }
862     else
863       parentFolder = this;
864   }
865   */
866   CAgentFolder *folderSpec = new CAgentFolder;
867   CMyComPtr<IFolderFolder> agentFolder = folderSpec;
868   folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec);
869   *resultFolder = agentFolder.Detach();
870   return S_OK;
871 }
872 
Z7_COM7F_IMF(CAgentFolder::BindToFolder (UInt32 index,IFolderFolder ** resultFolder))873 Z7_COM7F_IMF(CAgentFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder))
874 {
875   COM_TRY_BEGIN
876   if (_proxy2)
877   {
878     SET_realIndex_AND_dir_2
879     const unsigned arcIndex = dir->Items[realIndex];
880     const CProxyFile2 &item = _proxy2->Files[arcIndex];
881     if (!item.IsDir())
882       return E_INVALIDARG;
883     return BindToFolder_Internal((unsigned)item.DirIndex, resultFolder);
884   }
885   SET_realIndex_AND_dir
886   if (realIndex >= (UInt32)dir->SubDirs.Size())
887     return E_INVALIDARG;
888   return BindToFolder_Internal(dir->SubDirs[realIndex], resultFolder);
889   COM_TRY_END
890 }
891 
Z7_COM7F_IMF(CAgentFolder::BindToFolder (const wchar_t * name,IFolderFolder ** resultFolder))892 Z7_COM7F_IMF(CAgentFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder))
893 {
894   COM_TRY_BEGIN
895   if (_proxy2)
896   {
897     const int index = _proxy2->FindItem(_proxyDirIndex, name, true);
898     if (index == -1)
899       return E_INVALIDARG;
900     return BindToFolder_Internal((unsigned)_proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]].DirIndex, resultFolder);
901   }
902   const int index = _proxy->FindSubDir(_proxyDirIndex, name);
903   if (index == -1)
904     return E_INVALIDARG;
905   return BindToFolder_Internal((unsigned)index, resultFolder);
906   COM_TRY_END
907 }
908 
909 
910 
911 // ---------- IFolderAltStreams ----------
912 
BindToAltStreams_Internal(unsigned proxyDirIndex,IFolderFolder ** resultFolder)913 HRESULT CAgentFolder::BindToAltStreams_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder)
914 {
915   *resultFolder = NULL;
916   if (!_proxy2)
917     return S_OK;
918 
919   /*
920   CMyComPtr<IFolderFolder> parentFolder;
921 
922   int par = _proxy2->GetParentFolderOfFile(_proxy2->Dirs[proxyDirIndex].ArcIndex);
923   if (par != (int)_proxyDirIndex)
924   {
925     RINOK(BindToFolder_Internal(par, &parentFolder));
926     if (!parentFolder)
927       return S_OK;
928   }
929   else
930     parentFolder = this;
931   */
932 
933   CAgentFolder *folderSpec = new CAgentFolder;
934   CMyComPtr<IFolderFolder> agentFolder = folderSpec;
935   folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec);
936   *resultFolder = agentFolder.Detach();
937   return S_OK;
938 }
939 
Z7_COM7F_IMF(CAgentFolder::BindToAltStreams (UInt32 index,IFolderFolder ** resultFolder))940 Z7_COM7F_IMF(CAgentFolder::BindToAltStreams(UInt32 index, IFolderFolder **resultFolder))
941 {
942   COM_TRY_BEGIN
943 
944   *resultFolder = NULL;
945 
946   if (!_proxy2)
947     return S_OK;
948 
949   if (_proxy2->IsAltDir(_proxyDirIndex))
950     return S_OK;
951 
952   {
953     if (index == (UInt32)(Int32)-1)
954     {
955       unsigned altDirIndex;
956       // IFolderFolder *parentFolder;
957 
958       if (_proxyDirIndex == k_Proxy2_RootDirIndex)
959       {
960         altDirIndex = k_Proxy2_AltRootDirIndex;
961         // parentFolder = this; // we want to use Root dir as parent for alt root
962       }
963       else
964       {
965         const unsigned arcIndex = (unsigned)_proxy2->Dirs[_proxyDirIndex].ArcIndex;
966         const CProxyFile2 &item = _proxy2->Files[arcIndex];
967         if (item.AltDirIndex == -1)
968           return S_OK;
969         altDirIndex = (unsigned)item.AltDirIndex;
970         // parentFolder = _parentFolder;
971       }
972 
973       CAgentFolder *folderSpec = new CAgentFolder;
974       CMyComPtr<IFolderFolder> agentFolder = folderSpec;
975       folderSpec->Init(_proxy, _proxy2, altDirIndex, /* parentFolder, */ _agentSpec);
976       *resultFolder = agentFolder.Detach();
977       return S_OK;
978     }
979 
980     SET_realIndex_AND_dir_2
981     const unsigned arcIndex = dir->Items[realIndex];
982     const CProxyFile2 &item = _proxy2->Files[arcIndex];
983     if (item.AltDirIndex == -1)
984       return S_OK;
985     return BindToAltStreams_Internal((unsigned)item.AltDirIndex, resultFolder);
986   }
987 
988   COM_TRY_END
989 }
990 
Z7_COM7F_IMF(CAgentFolder::BindToAltStreams (const wchar_t * name,IFolderFolder ** resultFolder))991 Z7_COM7F_IMF(CAgentFolder::BindToAltStreams(const wchar_t *name, IFolderFolder **resultFolder))
992 {
993   COM_TRY_BEGIN
994 
995   *resultFolder = NULL;
996 
997   if (!_proxy2)
998     return S_OK;
999 
1000   if (_proxy2->IsAltDir(_proxyDirIndex))
1001     return S_OK;
1002 
1003   if (name[0] == 0)
1004     return BindToAltStreams((UInt32)(Int32)-1, resultFolder);
1005 
1006   {
1007     const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex];
1008     FOR_VECTOR (i, dir.Items)
1009     {
1010       const CProxyFile2 &file = _proxy2->Files[dir.Items[i]];
1011       if (file.AltDirIndex != -1)
1012         if (CompareFileNames(file.Name, name) == 0)
1013           return BindToAltStreams_Internal((unsigned)file.AltDirIndex, resultFolder);
1014     }
1015     return E_INVALIDARG;
1016   }
1017   COM_TRY_END
1018 }
1019 
Z7_COM7F_IMF(CAgentFolder::AreAltStreamsSupported (UInt32 index,Int32 * isSupported))1020 Z7_COM7F_IMF(CAgentFolder::AreAltStreamsSupported(UInt32 index, Int32 *isSupported))
1021 {
1022   *isSupported = BoolToInt(false);
1023 
1024   if (!_proxy2)
1025     return S_OK;
1026 
1027   if (_proxy2->IsAltDir(_proxyDirIndex))
1028     return S_OK;
1029 
1030   unsigned arcIndex;
1031 
1032   if (index == (UInt32)(Int32)-1)
1033   {
1034     if (_proxyDirIndex == k_Proxy2_RootDirIndex)
1035     {
1036       *isSupported = BoolToInt(true);
1037       return S_OK;
1038     }
1039     arcIndex = (unsigned)_proxy2->Dirs[_proxyDirIndex].ArcIndex;
1040   }
1041   else
1042   {
1043     SET_realIndex_AND_dir_2
1044     arcIndex = dir->Items[realIndex];
1045   }
1046 
1047   if (_proxy2->Files[arcIndex].AltDirIndex != -1)
1048     *isSupported = BoolToInt(true);
1049   return S_OK;
1050 }
1051 
1052 
Z7_COM7F_IMF(CAgentFolder::BindToParentFolder (IFolderFolder ** resultFolder))1053 Z7_COM7F_IMF(CAgentFolder::BindToParentFolder(IFolderFolder **resultFolder))
1054 {
1055   COM_TRY_BEGIN
1056   /*
1057   CMyComPtr<IFolderFolder> parentFolder = _parentFolder;
1058   *resultFolder = parentFolder.Detach();
1059   */
1060   *resultFolder = NULL;
1061 
1062   unsigned proxyDirIndex;
1063 
1064   if (_proxy2)
1065   {
1066     if (_proxyDirIndex == k_Proxy2_RootDirIndex)
1067       return S_OK;
1068     if (_proxyDirIndex == k_Proxy2_AltRootDirIndex)
1069       proxyDirIndex = k_Proxy2_RootDirIndex;
1070     else
1071     {
1072       const CProxyDir2 &fold = _proxy2->Dirs[_proxyDirIndex];
1073       const CProxyFile2 &file = _proxy2->Files[(unsigned)fold.ArcIndex];
1074       const int parentIndex = file.Parent;
1075       if (parentIndex == -1)
1076         proxyDirIndex = k_Proxy2_RootDirIndex;
1077       else
1078         proxyDirIndex = (unsigned)_proxy2->Files[(unsigned)parentIndex].DirIndex;
1079     }
1080   }
1081   else
1082   {
1083     const int parent = _proxy->Dirs[_proxyDirIndex].ParentDir;
1084     if (parent == -1)
1085       return S_OK;
1086     proxyDirIndex = (unsigned)parent;
1087   }
1088 
1089   CAgentFolder *folderSpec = new CAgentFolder;
1090   CMyComPtr<IFolderFolder> agentFolder = folderSpec;
1091   folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec);
1092   *resultFolder = agentFolder.Detach();
1093 
1094   return S_OK;
1095   COM_TRY_END
1096 }
1097 
Z7_COM7F_IMF(CAgentFolder::GetStream (UInt32 index,ISequentialInStream ** stream))1098 Z7_COM7F_IMF(CAgentFolder::GetStream(UInt32 index, ISequentialInStream **stream))
1099 {
1100   Z7_DECL_CMyComPtr_QI_FROM(
1101       IInArchiveGetStream,
1102       getStream, _agentSpec->GetArchive())
1103   if (!getStream)
1104     return S_OK;
1105 
1106   UInt32 arcIndex;
1107   if (_proxy2)
1108   {
1109     SET_realIndex_AND_dir_2
1110     arcIndex = dir->Items[realIndex];
1111   }
1112   else
1113   {
1114     SET_realIndex_AND_dir
1115 
1116     if (realIndex < dir->SubDirs.Size())
1117     {
1118       const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]];
1119       if (!item.IsLeaf())
1120         return S_OK;
1121       arcIndex = (unsigned)item.ArcIndex;
1122     }
1123     else
1124       arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()];
1125   }
1126   return getStream->GetStream(arcIndex, stream);
1127 }
1128 
1129 // static const unsigned k_FirstOptionalProp = 2;
1130 
1131 static const PROPID kProps[] =
1132 {
1133   kpidNumSubDirs,
1134   kpidNumSubFiles,
1135 
1136   // kpidNumAltStreams,
1137   kpidPrefix
1138 };
1139 
1140 struct CArchiveItemPropertyTemp
1141 {
1142   UString Name;
1143   PROPID ID;
1144   VARTYPE Type;
1145 };
1146 
Z7_COM7F_IMF(CAgentFolder::GetNumberOfProperties (UInt32 * numProps))1147 Z7_COM7F_IMF(CAgentFolder::GetNumberOfProperties(UInt32 *numProps))
1148 {
1149   COM_TRY_BEGIN
1150   RINOK(_agentSpec->GetArchive()->GetNumberOfProperties(numProps))
1151   *numProps += Z7_ARRAY_SIZE(kProps);
1152   if (!_flatMode)
1153     (*numProps)--;
1154   /*
1155   if (!_agentSpec->ThereIsAltStreamProp)
1156     (*numProps)--;
1157   */
1158   /*
1159   bool thereIsPathProp = _proxy2 ?
1160     _agentSpec->_proxy2->ThereIsPathProp :
1161     _agentSpec->_proxy->ThereIsPathProp;
1162   */
1163 
1164   // if there is kpidPath, we change kpidPath to kpidName
1165   // if there is no kpidPath, we add kpidName.
1166   if (!_agentSpec->ThereIsPathProp)
1167     (*numProps)++;
1168   return S_OK;
1169   COM_TRY_END
1170 }
1171 
Z7_COM7F_IMF(CAgentFolder::GetPropertyInfo (UInt32 index,BSTR * name,PROPID * propID,VARTYPE * varType))1172 Z7_COM7F_IMF(CAgentFolder::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType))
1173 {
1174   COM_TRY_BEGIN
1175   UInt32 numProps;
1176   _agentSpec->GetArchive()->GetNumberOfProperties(&numProps);
1177 
1178   /*
1179   bool thereIsPathProp = _proxy2 ?
1180     _agentSpec->_proxy2->ThereIsPathProp :
1181     _agentSpec->_proxy->ThereIsPathProp;
1182   */
1183 
1184   if (!_agentSpec->ThereIsPathProp)
1185   {
1186     if (index == 0)
1187     {
1188       *propID = kpidName;
1189       *varType = VT_BSTR;
1190       *name = NULL;
1191       return S_OK;
1192     }
1193     index--;
1194   }
1195 
1196   if (index < numProps)
1197   {
1198     RINOK(_agentSpec->GetArchive()->GetPropertyInfo(index, name, propID, varType))
1199     if (*propID == kpidPath)
1200       *propID = kpidName;
1201   }
1202   else
1203   {
1204     index -= numProps;
1205     /*
1206     if (index >= k_FirstOptionalProp)
1207     {
1208       if (!_agentSpec->ThereIsAltStreamProp)
1209         index++;
1210     }
1211     */
1212     *propID = kProps[index];
1213     *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID];
1214     *name = NULL;
1215   }
1216   return S_OK;
1217   COM_TRY_END
1218 }
1219 
1220 static const PROPID kFolderProps[] =
1221 {
1222   kpidSize,
1223   kpidPackSize,
1224   kpidNumSubDirs,
1225   kpidNumSubFiles,
1226   kpidCRC
1227 };
1228 
Z7_COM7F_IMF(CAgentFolder::GetFolderProperty (PROPID propID,PROPVARIANT * value))1229 Z7_COM7F_IMF(CAgentFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value))
1230 {
1231   COM_TRY_BEGIN
1232 
1233   NWindows::NCOM::CPropVariant prop;
1234 
1235   if (propID == kpidReadOnly)
1236   {
1237     if (_agentSpec->Is_Attrib_ReadOnly())
1238       prop = true;
1239     else
1240       prop = _agentSpec->IsThere_ReadOnlyArc();
1241   }
1242   else if (propID == kpidIsHash)
1243   {
1244     prop = _agentSpec->_isHashHandler;
1245   }
1246   else if (_proxy2)
1247   {
1248     const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex];
1249     if (propID == kpidName)
1250     {
1251       if (dir.ArcIndex != -1)
1252         prop = _proxy2->Files[(unsigned)dir.ArcIndex].Name;
1253     }
1254     else if (propID == kpidPath)
1255     {
1256       bool isAltStreamFolder = false;
1257       prop = _proxy2->GetDirPath_as_Prefix(_proxyDirIndex, isAltStreamFolder);
1258     }
1259     else switch (propID)
1260     {
1261       case kpidSize:         prop = dir.Size; break;
1262       case kpidPackSize:     prop = dir.PackSize; break;
1263       case kpidNumSubDirs:   prop = dir.NumSubDirs; break;
1264       case kpidNumSubFiles:  prop = dir.NumSubFiles; break;
1265         // case kpidName:         prop = dir.Name; break;
1266       // case kpidPath:         prop = _proxy2->GetFullPathPrefix(_proxyDirIndex); break;
1267       case kpidType: prop = UString("7-Zip.") + _agentSpec->ArchiveType; break;
1268       case kpidCRC: if (dir.CrcIsDefined) { prop = dir.Crc; } break;
1269     }
1270 
1271   }
1272   else
1273   {
1274   const CProxyDir &dir = _proxy->Dirs[_proxyDirIndex];
1275   switch (propID)
1276   {
1277     case kpidSize:         prop = dir.Size; break;
1278     case kpidPackSize:     prop = dir.PackSize; break;
1279     case kpidNumSubDirs:   prop = dir.NumSubDirs; break;
1280     case kpidNumSubFiles:  prop = dir.NumSubFiles; break;
1281     case kpidName:         prop = dir.Name; break;
1282     case kpidPath:         prop = _proxy->GetDirPath_as_Prefix(_proxyDirIndex); break;
1283     case kpidType: prop = UString("7-Zip.") + _agentSpec->ArchiveType; break;
1284     case kpidCRC: if (dir.CrcIsDefined) prop = dir.Crc; break;
1285   }
1286   }
1287   prop.Detach(value);
1288   return S_OK;
1289   COM_TRY_END
1290 }
1291 
Z7_COM7F_IMF(CAgentFolder::GetNumberOfFolderProperties (UInt32 * numProps))1292 Z7_COM7F_IMF(CAgentFolder::GetNumberOfFolderProperties(UInt32 *numProps))
1293 {
1294   *numProps = Z7_ARRAY_SIZE(kFolderProps);
1295   return S_OK;
1296 }
1297 
IMP_IFolderFolder_GetProp(CAgentFolder::GetFolderPropertyInfo,kFolderProps)1298 IMP_IFolderFolder_GetProp(
1299   CAgentFolder::GetFolderPropertyInfo,
1300   kFolderProps)
1301 
1302 Z7_COM7F_IMF(CAgentFolder::GetParent(UInt32 /* index */, UInt32 * /* parent */, UInt32 * /* parentType */))
1303 {
1304   return E_FAIL;
1305 }
1306 
1307 
Z7_COM7F_IMF(CAgentFolder::GetNumRawProps (UInt32 * numProps))1308 Z7_COM7F_IMF(CAgentFolder::GetNumRawProps(UInt32 *numProps))
1309 {
1310   IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps();
1311   if (rawProps)
1312     return rawProps->GetNumRawProps(numProps);
1313   *numProps = 0;
1314   return S_OK;
1315 }
1316 
Z7_COM7F_IMF(CAgentFolder::GetRawPropInfo (UInt32 index,BSTR * name,PROPID * propID))1317 Z7_COM7F_IMF(CAgentFolder::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID))
1318 {
1319   IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps();
1320   if (rawProps)
1321     return rawProps->GetRawPropInfo(index, name, propID);
1322   return E_FAIL;
1323 }
1324 
Z7_COM7F_IMF(CAgentFolder::GetRawProp (UInt32 index,PROPID propID,const void ** data,UInt32 * dataSize,UInt32 * propType))1325 Z7_COM7F_IMF(CAgentFolder::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
1326 {
1327   IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps();
1328   if (rawProps)
1329   {
1330     unsigned arcIndex;
1331     if (_proxy2)
1332     {
1333       SET_realIndex_AND_dir_2
1334       arcIndex = dir->Items[realIndex];
1335     }
1336     else
1337     {
1338       SET_realIndex_AND_dir
1339       if (realIndex < dir->SubDirs.Size())
1340       {
1341         const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]];
1342         if (!item.IsLeaf())
1343         {
1344           *data = NULL;
1345           *dataSize = 0;
1346           *propType = 0;
1347           return S_OK;
1348         }
1349         arcIndex = (unsigned)item.ArcIndex;
1350       }
1351       else
1352         arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()];
1353     }
1354     return rawProps->GetRawProp(arcIndex, propID, data, dataSize, propType);
1355   }
1356   *data = NULL;
1357   *dataSize = 0;
1358   *propType = 0;
1359   return S_OK;
1360 }
1361 
Z7_COM7F_IMF(CAgentFolder::GetFolderArcProps (IFolderArcProps ** object))1362 Z7_COM7F_IMF(CAgentFolder::GetFolderArcProps(IFolderArcProps **object))
1363 {
1364   CMyComPtr<IFolderArcProps> temp = _agentSpec;
1365   *object = temp.Detach();
1366   return S_OK;
1367 }
1368 
1369 
Z7_COM7F_IMF(CAgentFolder::SetFlatMode (Int32 flatMode))1370 Z7_COM7F_IMF(CAgentFolder::SetFlatMode(Int32 flatMode))
1371 {
1372   _flatMode = IntToBool(flatMode);
1373   return S_OK;
1374 }
1375 
1376 
GetRealIndex(unsigned index) const1377 int CAgentFolder::GetRealIndex(unsigned index) const
1378 {
1379   if (!_flatMode)
1380   {
1381     if (_proxy2)
1382       return (int)_proxy2->GetRealIndex(_proxyDirIndex, index);
1383     else
1384       return _proxy->GetRealIndex(_proxyDirIndex, index);
1385   }
1386   {
1387     const CProxyItem &item = _items[index];
1388     if (_proxy2)
1389     {
1390       const CProxyDir2 *dir = &_proxy2->Dirs[item.DirIndex];
1391       return (int)dir->Items[item.Index];
1392     }
1393     else
1394     {
1395       const CProxyDir *dir = &_proxy->Dirs[item.DirIndex];
1396       const unsigned realIndex = item.Index;
1397       if (realIndex < dir->SubDirs.Size())
1398       {
1399         const CProxyDir &f = _proxy->Dirs[dir->SubDirs[realIndex]];
1400         if (!f.IsLeaf())
1401           return -1;
1402         return f.ArcIndex;
1403       }
1404       return (int)dir->SubFiles[realIndex - dir->SubDirs.Size()];
1405     }
1406   }
1407 }
1408 
GetRealIndices(const UInt32 * indices,UInt32 numItems,bool includeAltStreams,bool includeFolderSubItemsInFlatMode,CUIntVector & realIndices) const1409 void CAgentFolder::GetRealIndices(const UInt32 *indices, UInt32 numItems, bool includeAltStreams, bool includeFolderSubItemsInFlatMode, CUIntVector &realIndices) const
1410 {
1411   if (!_flatMode)
1412   {
1413     if (_proxy2)
1414       _proxy2->GetRealIndices(_proxyDirIndex, indices, numItems, includeAltStreams, realIndices);
1415     else
1416       _proxy->GetRealIndices(_proxyDirIndex, indices, numItems, realIndices);
1417     return;
1418   }
1419 
1420   realIndices.Clear();
1421 
1422   for (UInt32 i = 0; i < numItems; i++)
1423   {
1424     const CProxyItem &item = _items[indices[i]];
1425     if (_proxy2)
1426     {
1427       const CProxyDir2 *dir = &_proxy2->Dirs[item.DirIndex];
1428       _proxy2->AddRealIndices_of_ArcItem(dir->Items[item.Index], includeAltStreams, realIndices);
1429       continue;
1430     }
1431     UInt32 arcIndex;
1432     {
1433       const CProxyDir *dir = &_proxy->Dirs[item.DirIndex];
1434       unsigned realIndex = item.Index;
1435       if (realIndex < dir->SubDirs.Size())
1436       {
1437         if (includeFolderSubItemsInFlatMode)
1438         {
1439           _proxy->AddRealIndices(dir->SubDirs[realIndex], realIndices);
1440           continue;
1441         }
1442         const CProxyDir &f = _proxy->Dirs[dir->SubDirs[realIndex]];
1443         if (!f.IsLeaf())
1444           continue;
1445         arcIndex = (unsigned)f.ArcIndex;
1446       }
1447       else
1448         arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()];
1449     }
1450     realIndices.Add(arcIndex);
1451   }
1452 
1453   HeapSort(realIndices.NonConstData(), realIndices.Size());
1454 }
1455 
Z7_COM7F_IMF(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))1456 Z7_COM7F_IMF(CAgentFolder::Extract(const UInt32 *indices,
1457     UInt32 numItems,
1458     Int32 includeAltStreams,
1459     Int32 replaceAltStreamColon,
1460     NExtract::NPathMode::EEnum pathMode,
1461     NExtract::NOverwriteMode::EEnum overwriteMode,
1462     const wchar_t *path,
1463     Int32 testMode,
1464     IFolderArchiveExtractCallback *extractCallback2))
1465 {
1466   COM_TRY_BEGIN
1467 
1468   if (!testMode && _agentSpec->_isHashHandler)
1469     return E_NOTIMPL;
1470 
1471   CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
1472   CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
1473   UStringVector pathParts;
1474   bool isAltStreamFolder = false;
1475   if (_proxy2)
1476     _proxy2->GetDirPathParts(_proxyDirIndex, pathParts, isAltStreamFolder);
1477   else
1478     _proxy->GetDirPathParts(_proxyDirIndex, pathParts);
1479 
1480   /*
1481   if (_flatMode)
1482     pathMode = NExtract::NPathMode::kNoPathnames;
1483   */
1484 
1485   extractCallbackSpec->InitForMulti(
1486       false, // multiArchives
1487       pathMode,
1488       overwriteMode,
1489       _zoneMode,
1490       k_keepEmptyDirPrefixes);
1491 
1492   if (extractCallback2)
1493     extractCallback2->SetTotal(_agentSpec->GetArc().GetEstmatedPhySize());
1494 
1495   FString pathU;
1496   if (path)
1497   {
1498     pathU = us2fs(path);
1499     if (!pathU.IsEmpty()
1500       && !NFile::NName::IsAltStreamPrefixWithColon(path))
1501     {
1502       NFile::NName::NormalizeDirPathPrefix(pathU);
1503       NFile::NDir::CreateComplexDir(pathU);
1504     }
1505   }
1506 
1507   CExtractNtOptions extractNtOptions;
1508   extractNtOptions.AltStreams.Val = IntToBool(includeAltStreams); // change it!!!
1509   extractNtOptions.AltStreams.Def = true;
1510 
1511   extractNtOptions.ReplaceColonForAltStream = IntToBool(replaceAltStreamColon);
1512 
1513   extractCallbackSpec->InitBeforeNewArchive();
1514 
1515   #if defined(_WIN32) && !defined(UNDER_CE)
1516     if (_zoneMode != NExtract::NZoneIdMode::kNone)
1517     {
1518       ReadZoneFile_Of_BaseFile(us2fs(_agentSpec->_archiveFilePath), extractCallbackSpec->ZoneBuf);
1519       if (_zoneBuf.Size() != 0)
1520         extractCallbackSpec->ZoneBuf = _zoneBuf;
1521     }
1522   #endif
1523 
1524   extractCallbackSpec->Init(
1525       extractNtOptions,
1526       NULL, &_agentSpec->GetArc(),
1527       extractCallback2,
1528       false, // stdOutMode
1529       IntToBool(testMode),
1530       pathU,
1531       pathParts, isAltStreamFolder,
1532       (UInt64)(Int64)-1);
1533 
1534   if (_proxy2)
1535     extractCallbackSpec->SetBaseParentFolderIndex((unsigned)_proxy2->Dirs[_proxyDirIndex].ArcIndex);
1536 
1537   // do we need another base folder for subfolders ?
1538   extractCallbackSpec->DirPathPrefix_for_HashFiles = _agentSpec->_hashBaseFolderPrefix;
1539 
1540   CUIntVector realIndices;
1541   GetRealIndices(indices, numItems, IntToBool(includeAltStreams),
1542       false, // includeFolderSubItemsInFlatMode
1543       realIndices); //
1544 
1545   #ifdef SUPPORT_LINKS
1546 
1547   if (!testMode)
1548   {
1549     RINOK(extractCallbackSpec->PrepareHardLinks(&realIndices))
1550   }
1551 
1552   #endif
1553 
1554   {
1555     CArchiveExtractCallback_Closer ecsCloser(extractCallbackSpec);
1556 
1557     HRESULT res = _agentSpec->GetArchive()->Extract(realIndices.ConstData(),
1558         realIndices.Size(), testMode, extractCallback);
1559 
1560     const HRESULT res2 = ecsCloser.Close();
1561     if (res == S_OK)
1562       res = res2;
1563     return res;
1564   }
1565 
1566   COM_TRY_END
1567 }
1568 
1569 /////////////////////////////////////////
1570 // CAgent
1571 
CAgent()1572 CAgent::CAgent():
1573     _proxy(NULL),
1574     _proxy2(NULL),
1575     _updatePathPrefix_is_AltFolder(false),
1576     _isDeviceFile(false),
1577     _isHashHandler(false)
1578 {
1579 }
1580 
~CAgent()1581 CAgent::~CAgent()
1582 {
1583   if (_proxy)
1584     delete _proxy;
1585   if (_proxy2)
1586     delete _proxy2;
1587 }
1588 
CanUpdate() const1589 bool CAgent::CanUpdate() const
1590 {
1591   // FAR plugin uses empty agent to create new archive !!!
1592   if (_archiveLink.Arcs.Size() == 0)
1593     return true;
1594   if (_isDeviceFile)
1595     return false;
1596   if (_archiveLink.Arcs.Size() != 1)
1597     return false;
1598   if (_archiveLink.Arcs[0].ErrorInfo.ThereIsTail)
1599     return false;
1600   return true;
1601 }
1602 
Z7_COM7F_IMF(CAgent::Open (IInStream * inStream,const wchar_t * filePath,const wchar_t * arcFormat,BSTR * archiveType,IArchiveOpenCallback * openArchiveCallback))1603 Z7_COM7F_IMF(CAgent::Open(
1604     IInStream *inStream,
1605     const wchar_t *filePath,
1606     const wchar_t *arcFormat,
1607     BSTR *archiveType,
1608     IArchiveOpenCallback *openArchiveCallback))
1609 {
1610   COM_TRY_BEGIN
1611   _archiveFilePath = filePath;
1612   _hashBaseFolderPrefix.Empty();
1613   _attrib = 0;
1614   _isDeviceFile = false;
1615   _isHashHandler = false;
1616   NFile::NFind::CFileInfo fi;
1617   if (!inStream)
1618   {
1619     if (!fi.Find(us2fs(_archiveFilePath)))
1620       return GetLastError_noZero_HRESULT();
1621     if (fi.IsDir())
1622       return E_FAIL;
1623     _attrib = fi.Attrib;
1624     _isDeviceFile = fi.IsDevice;
1625     FString dirPrefix, fileName;
1626     if (NFile::NDir::GetFullPathAndSplit(us2fs(_archiveFilePath), dirPrefix, fileName))
1627     {
1628       NFile::NName::NormalizeDirPathPrefix(dirPrefix);
1629       _hashBaseFolderPrefix = dirPrefix;
1630     }
1631   }
1632   CArcInfoEx archiverInfo0, archiverInfo1;
1633 
1634   RINOK(LoadGlobalCodecs())
1635 
1636   CObjectVector<COpenType> types;
1637   if (!ParseOpenTypes(*g_CodecsObj, arcFormat, types))
1638     return S_FALSE;
1639 
1640   /*
1641   CObjectVector<COptionalOpenProperties> optProps;
1642   if (Read_ShowDeleted())
1643   {
1644     COptionalOpenProperties &optPair = optProps.AddNew();
1645     optPair.FormatName = "ntfs";
1646     // optPair.Props.AddNew().Name = "LS";
1647     optPair.Props.AddNew().Name = "LD";
1648   }
1649   */
1650 
1651   COpenOptions options;
1652   options.props = NULL;
1653   options.codecs = g_CodecsObj;
1654   options.types = &types;
1655   CIntVector exl;
1656   options.excludedFormats = &exl;
1657   options.stdInMode = false;
1658   options.stream = inStream;
1659   options.filePath = _archiveFilePath;
1660   options.callback = openArchiveCallback;
1661 
1662   HRESULT res = _archiveLink.Open(options);
1663 
1664   if (!_archiveLink.Arcs.IsEmpty())
1665   {
1666     CArc &arc = _archiveLink.Arcs.Back();
1667     if (!inStream)
1668     {
1669       arc.MTime.Set_From_FiTime(fi.MTime);
1670       arc.MTime.Def = !fi.IsDevice;
1671     }
1672 
1673     ArchiveType = GetTypeOfArc(arc);
1674     if (archiveType)
1675     {
1676       RINOK(StringToBstr(ArchiveType, archiveType))
1677     }
1678 
1679     if (arc.IsHashHandler(options))
1680       _isHashHandler = true;
1681   }
1682 
1683   return res;
1684 
1685   COM_TRY_END
1686 }
1687 
1688 
Z7_COM7F_IMF(CAgent::ReOpen (IArchiveOpenCallback * openArchiveCallback))1689 Z7_COM7F_IMF(CAgent::ReOpen(IArchiveOpenCallback *openArchiveCallback))
1690 {
1691   COM_TRY_BEGIN
1692   if (_proxy2)
1693   {
1694     delete _proxy2;
1695     _proxy2 = NULL;
1696   }
1697   if (_proxy)
1698   {
1699     delete _proxy;
1700     _proxy = NULL;
1701   }
1702 
1703   CObjectVector<COpenType> incl;
1704   CIntVector exl;
1705 
1706   COpenOptions options;
1707   options.props = NULL;
1708   options.codecs = g_CodecsObj;
1709   options.types = &incl;
1710   options.excludedFormats = &exl;
1711   options.stdInMode = false;
1712   options.filePath = _archiveFilePath;
1713   options.callback = openArchiveCallback;
1714 
1715   RINOK(_archiveLink.ReOpen(options))
1716   return ReadItems();
1717   COM_TRY_END
1718 }
1719 
Z7_COM7F_IMF(CAgent::Close ())1720 Z7_COM7F_IMF(CAgent::Close())
1721 {
1722   COM_TRY_BEGIN
1723   return _archiveLink.Close();
1724   COM_TRY_END
1725 }
1726 
1727 /*
1728 Z7_COM7F_IMF(CAgent::EnumProperties(IEnumSTATPROPSTG **EnumProperties)
1729 {
1730   return _archive->EnumProperties(EnumProperties);
1731 }
1732 */
1733 
ReadItems()1734 HRESULT CAgent::ReadItems()
1735 {
1736   if (_proxy || _proxy2)
1737     return S_OK;
1738 
1739   const CArc &arc = GetArc();
1740   bool useProxy2 = (arc.GetRawProps && arc.IsTree);
1741 
1742   // useProxy2 = false;
1743 
1744   if (useProxy2)
1745     _proxy2 = new CProxyArc2();
1746   else
1747     _proxy = new CProxyArc();
1748 
1749   {
1750     ThereIsPathProp = false;
1751     // ThereIsAltStreamProp = false;
1752     UInt32 numProps;
1753     arc.Archive->GetNumberOfProperties(&numProps);
1754     for (UInt32 i = 0; i < numProps; i++)
1755     {
1756       CMyComBSTR name;
1757       PROPID propID;
1758       VARTYPE varType;
1759       RINOK(arc.Archive->GetPropertyInfo(i, &name, &propID, &varType))
1760       if (propID == kpidPath)
1761         ThereIsPathProp = true;
1762       /*
1763       if (propID == kpidIsAltStream)
1764         ThereIsAltStreamProp = true;
1765       */
1766     }
1767   }
1768 
1769   if (_proxy2)
1770     return _proxy2->Load(GetArc(), NULL);
1771   return _proxy->Load(GetArc(), NULL);
1772 }
1773 
Z7_COM7F_IMF(CAgent::BindToRootFolder (IFolderFolder ** resultFolder))1774 Z7_COM7F_IMF(CAgent::BindToRootFolder(IFolderFolder **resultFolder))
1775 {
1776   COM_TRY_BEGIN
1777   if (!_archiveLink.Arcs.IsEmpty())
1778   {
1779     RINOK(ReadItems())
1780   }
1781   CAgentFolder *folderSpec = new CAgentFolder;
1782   CMyComPtr<IFolderFolder> rootFolder = folderSpec;
1783   folderSpec->Init(_proxy, _proxy2, k_Proxy_RootDirIndex, /* NULL, */ this);
1784   *resultFolder = rootFolder.Detach();
1785   return S_OK;
1786   COM_TRY_END
1787 }
1788 
Z7_COM7F_IMF(CAgent::Extract (NExtract::NPathMode::EEnum pathMode,NExtract::NOverwriteMode::EEnum overwriteMode,const wchar_t * path,Int32 testMode,IFolderArchiveExtractCallback * extractCallback2))1789 Z7_COM7F_IMF(CAgent::Extract(
1790     NExtract::NPathMode::EEnum pathMode,
1791     NExtract::NOverwriteMode::EEnum overwriteMode,
1792     const wchar_t *path,
1793     Int32 testMode,
1794     IFolderArchiveExtractCallback *extractCallback2))
1795 {
1796   COM_TRY_BEGIN
1797 
1798   if (!testMode && _isHashHandler)
1799     return E_NOTIMPL;
1800 
1801   CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
1802   CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
1803   extractCallbackSpec->InitForMulti(
1804       false, // multiArchives
1805       pathMode,
1806       overwriteMode,
1807       NExtract::NZoneIdMode::kNone,
1808       k_keepEmptyDirPrefixes);
1809 
1810   CExtractNtOptions extractNtOptions;
1811   extractNtOptions.AltStreams.Val = true; // change it!!!
1812   extractNtOptions.AltStreams.Def = true; // change it!!!
1813   extractNtOptions.ReplaceColonForAltStream = false; // change it!!!
1814 
1815   extractCallbackSpec->Init(
1816       extractNtOptions,
1817       NULL, &GetArc(),
1818       extractCallback2,
1819       false, // stdOutMode
1820       IntToBool(testMode),
1821       us2fs(path),
1822       UStringVector(), false,
1823       (UInt64)(Int64)-1);
1824 
1825   extractCallbackSpec->DirPathPrefix_for_HashFiles = _hashBaseFolderPrefix;
1826 
1827   #ifdef SUPPORT_LINKS
1828 
1829   if (!testMode)
1830   {
1831     RINOK(extractCallbackSpec->PrepareHardLinks(NULL)) // NULL means all items
1832   }
1833 
1834   #endif
1835 
1836   return GetArchive()->Extract(NULL, (UInt32)(Int32)-1, testMode, extractCallback);
1837   COM_TRY_END
1838 }
1839 
Z7_COM7F_IMF(CAgent::GetNumberOfProperties (UInt32 * numProps))1840 Z7_COM7F_IMF(CAgent::GetNumberOfProperties(UInt32 *numProps))
1841 {
1842   COM_TRY_BEGIN
1843   return GetArchive()->GetNumberOfProperties(numProps);
1844   COM_TRY_END
1845 }
1846 
Z7_COM7F_IMF(CAgent::GetPropertyInfo (UInt32 index,BSTR * name,PROPID * propID,VARTYPE * varType))1847 Z7_COM7F_IMF(CAgent::GetPropertyInfo(UInt32 index,
1848       BSTR *name, PROPID *propID, VARTYPE *varType))
1849 {
1850   COM_TRY_BEGIN
1851   RINOK(GetArchive()->GetPropertyInfo(index, name, propID, varType))
1852   if (*propID == kpidPath)
1853     *propID = kpidName;
1854   return S_OK;
1855   COM_TRY_END
1856 }
1857 
Z7_COM7F_IMF(CAgent::GetArcNumLevels (UInt32 * numLevels))1858 Z7_COM7F_IMF(CAgent::GetArcNumLevels(UInt32 *numLevels))
1859 {
1860   *numLevels = _archiveLink.Arcs.Size();
1861   return S_OK;
1862 }
1863 
Z7_COM7F_IMF(CAgent::GetArcProp (UInt32 level,PROPID propID,PROPVARIANT * value))1864 Z7_COM7F_IMF(CAgent::GetArcProp(UInt32 level, PROPID propID, PROPVARIANT *value))
1865 {
1866   COM_TRY_BEGIN
1867   NWindows::NCOM::CPropVariant prop;
1868   if (level > (UInt32)_archiveLink.Arcs.Size())
1869     return E_INVALIDARG;
1870   if (level == (UInt32)_archiveLink.Arcs.Size())
1871   {
1872     switch (propID)
1873     {
1874       case kpidPath:
1875         if (!_archiveLink.NonOpen_ArcPath.IsEmpty())
1876           prop = _archiveLink.NonOpen_ArcPath;
1877         break;
1878       case kpidErrorType:
1879         if (_archiveLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
1880           prop = g_CodecsObj->Formats[_archiveLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name;
1881         break;
1882       case kpidErrorFlags:
1883       {
1884         UInt32 flags = _archiveLink.NonOpen_ErrorInfo.GetErrorFlags();
1885         if (flags != 0)
1886           prop = flags;
1887         break;
1888       }
1889       case kpidWarningFlags:
1890       {
1891         UInt32 flags = _archiveLink.NonOpen_ErrorInfo.GetWarningFlags();
1892         if (flags != 0)
1893           prop = flags;
1894         break;
1895       }
1896     }
1897   }
1898   else
1899   {
1900     const CArc &arc = _archiveLink.Arcs[level];
1901     switch (propID)
1902     {
1903       case kpidType: prop = GetTypeOfArc(arc); break;
1904       case kpidPath: prop = arc.Path; break;
1905       case kpidErrorType:
1906         if (arc.ErrorInfo.ErrorFormatIndex >= 0)
1907           prop = g_CodecsObj->Formats[arc.ErrorInfo.ErrorFormatIndex].Name;
1908         break;
1909       case kpidErrorFlags:
1910       {
1911         const UInt32 flags = arc.ErrorInfo.GetErrorFlags();
1912         if (flags != 0)
1913           prop = flags;
1914         break;
1915       }
1916       case kpidWarningFlags:
1917       {
1918         const UInt32 flags = arc.ErrorInfo.GetWarningFlags();
1919         if (flags != 0)
1920           prop = flags;
1921         break;
1922       }
1923       case kpidOffset:
1924       {
1925         const Int64 v = arc.GetGlobalOffset();
1926         if (v != 0)
1927           prop.Set_Int64(v);
1928         break;
1929       }
1930       case kpidTailSize:
1931       {
1932         if (arc.ErrorInfo.TailSize != 0)
1933           prop = arc.ErrorInfo.TailSize;
1934         break;
1935       }
1936       default: return arc.Archive->GetArchiveProperty(propID, value);
1937     }
1938   }
1939   prop.Detach(value);
1940   return S_OK;
1941   COM_TRY_END
1942 }
1943 
Z7_COM7F_IMF(CAgent::GetArcNumProps (UInt32 level,UInt32 * numProps))1944 Z7_COM7F_IMF(CAgent::GetArcNumProps(UInt32 level, UInt32 *numProps))
1945 {
1946   return _archiveLink.Arcs[level].Archive->GetNumberOfArchiveProperties(numProps);
1947 }
1948 
Z7_COM7F_IMF(CAgent::GetArcPropInfo (UInt32 level,UInt32 index,BSTR * name,PROPID * propID,VARTYPE * varType))1949 Z7_COM7F_IMF(CAgent::GetArcPropInfo(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType))
1950 {
1951   return _archiveLink.Arcs[level].Archive->GetArchivePropertyInfo(index, name, propID, varType);
1952 }
1953 
1954 // MainItemProperty
Z7_COM7F_IMF(CAgent::GetArcProp2 (UInt32 level,PROPID propID,PROPVARIANT * value))1955 Z7_COM7F_IMF(CAgent::GetArcProp2(UInt32 level, PROPID propID, PROPVARIANT *value))
1956 {
1957   return _archiveLink.Arcs[level - 1].Archive->GetProperty(_archiveLink.Arcs[level].SubfileIndex, propID, value);
1958 }
1959 
Z7_COM7F_IMF(CAgent::GetArcNumProps2 (UInt32 level,UInt32 * numProps))1960 Z7_COM7F_IMF(CAgent::GetArcNumProps2(UInt32 level, UInt32 *numProps))
1961 {
1962   return _archiveLink.Arcs[level - 1].Archive->GetNumberOfProperties(numProps);
1963 }
1964 
Z7_COM7F_IMF(CAgent::GetArcPropInfo2 (UInt32 level,UInt32 index,BSTR * name,PROPID * propID,VARTYPE * varType))1965 Z7_COM7F_IMF(CAgent::GetArcPropInfo2(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType))
1966 {
1967   return _archiveLink.Arcs[level - 1].Archive->GetPropertyInfo(index, name, propID, varType);
1968 }
1969