"Fossies" - the Fresh Open Source Software Archive

Member "p7zip_16.02/CPP/7zip/UI/Agent/Agent.cpp" (20 May 2016, 47061 Bytes) of package /linux/misc/p7zip_16.02_src_all.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "Agent.cpp": 15.14.1_src_all_vs_16.02_src_all.

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