Home | History | Annotate | Download | only in Common
      1 // OpenArchive.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 // #define SHOW_DEBUG_INFO
      6 
      7 #ifdef SHOW_DEBUG_INFO
      8 #include <stdio.h>
      9 #endif
     10 
     11 #include "../../../../C/CpuArch.h"
     12 
     13 #include "../../../Common/ComTry.h"
     14 #include "../../../Common/IntToString.h"
     15 #include "../../../Common/StringConvert.h"
     16 #include "../../../Common/StringToInt.h"
     17 #include "../../../Common/Wildcard.h"
     18 
     19 #include "../../../Windows/FileDir.h"
     20 
     21 #include "../../Common/FileStreams.h"
     22 #include "../../Common/LimitedStreams.h"
     23 #include "../../Common/ProgressUtils.h"
     24 #include "../../Common/StreamUtils.h"
     25 
     26 #include "../../Compress/CopyCoder.h"
     27 
     28 #include "DefaultName.h"
     29 #include "OpenArchive.h"
     30 
     31 #ifndef _SFX
     32 #include "SetProperties.h"
     33 #endif
     34 
     35 #ifdef SHOW_DEBUG_INFO
     36 #define PRF(x) x
     37 #else
     38 #define PRF(x)
     39 #endif
     40 
     41 // increase it, if you need to support larger SFX stubs
     42 static const UInt64 kMaxCheckStartPosition = 1 << 23;
     43 
     44 /*
     45 Open:
     46   - formatIndex >= 0 (exact Format)
     47        1) Open with main type. Archive handler is allowed to use archive start finder.
     48           Warning, if there is tail.
     49 
     50   - formatIndex = -1 (Parser:0) (default)
     51     - same as #1 but doesn't return Parser
     52 
     53   - formatIndex = -2 (#1)
     54     - file has supported extension (like a.7z)
     55       Open with that main type (only starting from start of file).
     56         - open OK:
     57             - if there is no tail - return OK
     58             - if there is tail:
     59               - archive is not "Self Exe" - return OK with Warning, that there is tail
     60               - archive is "Self Exe"
     61                 ignore "Self Exe" stub, and tries to open tail
     62                   - tail can be open as archive - shows that archive and stub size property.
     63                   - tail can't be open as archive - shows Parser ???
     64         - open FAIL:
     65            Try to open with all other types from offset 0 only.
     66            If some open type is OK and physical archive size is uequal or larger
     67            than file size, then return that archive with warning that can not be open as [extension type].
     68            If extension was EXE, it will try to open as unknown_extension case
     69     - file has unknown extension (like a.hhh)
     70        It tries to open via parser code.
     71          - if there is full archive or tail archive and unknown block or "Self Exe"
     72            at front, it shows tail archive and stub size property.
     73          - in another cases, if there is some archive inside file, it returns parser/
     74          - in another cases, it retuens S_FALSE
     75 
     76 
     77   - formatIndex = -3 (#2)
     78     - same as #1, but
     79     - stub (EXE) + archive is open in Parser
     80 
     81   - formatIndex = -4 (#3)
     82     - returns only Parser. skip full file archive. And show other sub-archives
     83 
     84   - formatIndex = -5 (#4)
     85     - returns only Parser. skip full file archive. And show other sub-archives for each byte pos
     86 
     87 */
     88 
     89 
     90 
     91 
     92 using namespace NWindows;
     93 
     94 /*
     95 #ifdef _SFX
     96 #define OPEN_PROPS_PARAM
     97 #else
     98 #define OPEN_PROPS_PARAM  , props
     99 #endif
    100 */
    101 
    102 /*
    103 CArc::~CArc()
    104 {
    105   GetRawProps.Release();
    106   Archive.Release();
    107   printf("\nCArc::~CArc()\n");
    108 }
    109 */
    110 
    111 #ifndef _SFX
    112 
    113 namespace NArchive {
    114 namespace NParser {
    115 
    116 struct CParseItem
    117 {
    118   UInt64 Offset;
    119   UInt64 Size;
    120   // UInt64 OkSize;
    121   UString Name;
    122   UString Extension;
    123   FILETIME FileTime;
    124   UString Comment;
    125   UString ArcType;
    126 
    127   bool FileTime_Defined;
    128   bool UnpackSize_Defined;
    129   bool NumSubDirs_Defined;
    130   bool NumSubFiles_Defined;
    131 
    132   bool IsSelfExe;
    133   bool IsNotArcType;
    134 
    135   UInt64 UnpackSize;
    136   UInt64 NumSubDirs;
    137   UInt64 NumSubFiles;
    138 
    139   int FormatIndex;
    140 
    141   bool LenIsUnknown;
    142 
    143   CParseItem():
    144       LenIsUnknown(false),
    145       FileTime_Defined(false),
    146       UnpackSize_Defined(false),
    147       NumSubFiles_Defined(false),
    148       NumSubDirs_Defined(false),
    149       IsSelfExe(false),
    150       IsNotArcType(false)
    151       // OkSize(0)
    152     {}
    153 
    154   /*
    155   bool IsEqualTo(const CParseItem &item) const
    156   {
    157     return Offset == item.Offset && Size == item.Size;
    158   }
    159   */
    160 
    161   void NormalizeOffset()
    162   {
    163     if ((Int64)Offset < 0)
    164     {
    165       Size += Offset;
    166       // OkSize += Offset;
    167       Offset = 0;
    168     }
    169   }
    170 };
    171 
    172 class CHandler:
    173   public IInArchive,
    174   public IInArchiveGetStream,
    175   public CMyUnknownImp
    176 {
    177 public:
    178   CObjectVector<CParseItem> _items;
    179   UInt64 _maxEndOffset;
    180   CMyComPtr<IInStream> _stream;
    181 
    182   MY_UNKNOWN_IMP2(
    183     IInArchive,
    184     IInArchiveGetStream)
    185 
    186   INTERFACE_IInArchive(;)
    187   STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
    188 
    189   UInt64 GetLastEnd() const
    190   {
    191     if (_items.IsEmpty())
    192       return 0;
    193     const CParseItem &back = _items.Back();
    194     return back.Offset + back.Size;
    195   }
    196 
    197   void AddUnknownItem(UInt64 next);
    198   int FindInsertPos(const CParseItem &item) const;
    199   void AddItem(const CParseItem &item);
    200 
    201   CHandler(): _maxEndOffset(0) {}
    202 };
    203 
    204 int CHandler::FindInsertPos(const CParseItem &item) const
    205 {
    206   unsigned left = 0, right = _items.Size();
    207   while (left != right)
    208   {
    209     unsigned mid = (left + right) / 2;
    210     const CParseItem & midItem = _items[mid];
    211     if (item.Offset < midItem.Offset)
    212       right = mid;
    213     else if (item.Offset > midItem.Offset)
    214       left = mid + 1;
    215     else if (item.Size < midItem.Size)
    216       right = mid;
    217     else if (item.Size > midItem.Size)
    218       left = mid + 1;
    219     else
    220     {
    221       left = mid + 1;
    222       // return -1;
    223     }
    224   }
    225   return left;
    226 }
    227 
    228 void CHandler::AddUnknownItem(UInt64 next)
    229 {
    230   /*
    231   UInt64 prevEnd = 0;
    232   if (!_items.IsEmpty())
    233   {
    234     const CParseItem &back = _items.Back();
    235     prevEnd = back.Offset + back.Size;
    236   }
    237   */
    238   if (_maxEndOffset < next)
    239   {
    240     CParseItem item2;
    241     item2.Offset = _maxEndOffset;
    242     item2.Size = next - _maxEndOffset;
    243     _maxEndOffset = next;
    244     _items.Add(item2);
    245   }
    246   else if (_maxEndOffset > next && !_items.IsEmpty())
    247   {
    248     CParseItem &back = _items.Back();
    249     if (back.LenIsUnknown)
    250     {
    251       back.Size = next - back.Offset;
    252       _maxEndOffset = next;
    253     }
    254   }
    255 }
    256 
    257 void CHandler::AddItem(const CParseItem &item)
    258 {
    259   AddUnknownItem(item.Offset);
    260   int pos = FindInsertPos(item);
    261   if (pos >= 0)
    262   {
    263     _items.Insert(pos, item);
    264     UInt64 next = item.Offset + item.Size;
    265     if (_maxEndOffset < next)
    266       _maxEndOffset = next;
    267   }
    268 }
    269 
    270 /*
    271 static const CStatProp kProps[] =
    272 {
    273   { NULL, kpidPath, VT_BSTR},
    274   { NULL, kpidSize, VT_UI8},
    275   { NULL, kpidMTime, VT_FILETIME},
    276   { NULL, kpidType, VT_BSTR},
    277   { NULL, kpidComment, VT_BSTR},
    278   { NULL, kpidOffset, VT_UI8},
    279   { NULL, kpidUnpackSize, VT_UI8},
    280 //   { NULL, kpidNumSubDirs, VT_UI8},
    281 };
    282 */
    283 
    284 static const Byte kProps[] =
    285 {
    286   kpidPath,
    287   kpidSize,
    288   kpidMTime,
    289   kpidType,
    290   kpidComment,
    291   kpidOffset,
    292   kpidUnpackSize
    293 };
    294 
    295 IMP_IInArchive_Props
    296 IMP_IInArchive_ArcProps_NO
    297 
    298 STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* openArchiveCallback */)
    299 {
    300   COM_TRY_BEGIN
    301   {
    302     Close();
    303     _stream = stream;
    304   }
    305   return S_OK;
    306   COM_TRY_END
    307 }
    308 
    309 STDMETHODIMP CHandler::Close()
    310 {
    311   _items.Clear();
    312   _stream.Release();
    313   return S_OK;
    314 }
    315 
    316 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
    317 {
    318   *numItems = _items.Size();
    319   return S_OK;
    320 }
    321 
    322 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
    323 {
    324   COM_TRY_BEGIN
    325   NCOM::CPropVariant prop;
    326 
    327   const CParseItem &item = _items[index];
    328 
    329   switch (propID)
    330   {
    331     case kpidPath:
    332     {
    333       wchar_t sz[32];
    334       ConvertUInt32ToString(index + 1, sz);
    335       UString s = sz;
    336       if (!item.Name.IsEmpty())
    337       {
    338         s += L'.';
    339         s += item.Name;
    340       }
    341       if (!item.Extension.IsEmpty())
    342       {
    343         s += L'.';
    344         s += item.Extension;
    345       }
    346       prop = s; break;
    347     }
    348     case kpidSize:
    349     case kpidPackSize: prop = item.Size; break;
    350     case kpidOffset: prop = item.Offset; break;
    351     case kpidUnpackSize: if (item.UnpackSize_Defined) prop = item.UnpackSize; break;
    352     case kpidNumSubFiles: if (item.NumSubFiles_Defined) prop = item.NumSubFiles; break;
    353     case kpidNumSubDirs: if (item.NumSubDirs_Defined) prop = item.NumSubDirs; break;
    354     case kpidMTime: if (item.FileTime_Defined) prop = item.FileTime; break;
    355     case kpidComment: if (!item.Comment.IsEmpty()) prop = item.Comment; break;
    356     case kpidType: if (!item.ArcType.IsEmpty()) prop = item.ArcType; break;
    357   }
    358   prop.Detach(value);
    359   return S_OK;
    360   COM_TRY_END
    361 }
    362 
    363 HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
    364     Int32 testMode, IArchiveExtractCallback *extractCallback)
    365 {
    366   COM_TRY_BEGIN
    367 
    368   bool allFilesMode = (numItems == (UInt32)(Int32)-1);
    369   if (allFilesMode)
    370     numItems = _items.Size();
    371   if (_stream && numItems == 0)
    372     return S_OK;
    373   UInt64 totalSize = 0;
    374   UInt32 i;
    375   for (i = 0; i < numItems; i++)
    376     totalSize += _items[allFilesMode ? i : indices[i]].Size;
    377   extractCallback->SetTotal(totalSize);
    378 
    379   totalSize = 0;
    380 
    381   CLocalProgress *lps = new CLocalProgress;
    382   CMyComPtr<ICompressProgressInfo> progress = lps;
    383   lps->Init(extractCallback, false);
    384 
    385   CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
    386   CMyComPtr<ISequentialInStream> inStream(streamSpec);
    387   streamSpec->SetStream(_stream);
    388 
    389   CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
    390   CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
    391 
    392   NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
    393   CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
    394 
    395   for (i = 0; i < numItems; i++)
    396   {
    397     lps->InSize = totalSize;
    398     lps->OutSize = totalSize;
    399     RINOK(lps->SetCur());
    400     CMyComPtr<ISequentialOutStream> realOutStream;
    401     Int32 askMode = testMode ?
    402         NExtract::NAskMode::kTest :
    403         NExtract::NAskMode::kExtract;
    404     Int32 index = allFilesMode ? i : indices[i];
    405     const CParseItem &item = _items[index];
    406 
    407     RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
    408     UInt64 unpackSize = item.Size;
    409     totalSize += unpackSize;
    410     bool skipMode = false;
    411     if (!testMode && !realOutStream)
    412       continue;
    413     RINOK(extractCallback->PrepareOperation(askMode));
    414 
    415     outStreamSpec->SetStream(realOutStream);
    416     realOutStream.Release();
    417     outStreamSpec->Init(skipMode ? 0 : unpackSize, true);
    418 
    419     Int32 opRes = NExtract::NOperationResult::kOK;
    420     RINOK(_stream->Seek(item.Offset, STREAM_SEEK_SET, NULL));
    421     streamSpec->Init(unpackSize);
    422     RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
    423 
    424     if (outStreamSpec->GetRem() != 0)
    425       opRes = NExtract::NOperationResult::kDataError;
    426     outStreamSpec->ReleaseStream();
    427     RINOK(extractCallback->SetOperationResult(opRes));
    428   }
    429 
    430   return S_OK;
    431 
    432   COM_TRY_END
    433 }
    434 
    435 
    436 STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
    437 {
    438   COM_TRY_BEGIN
    439   const CParseItem &item = _items[index];
    440   return CreateLimitedInStream(_stream, item.Offset, item.Size, stream);
    441   COM_TRY_END
    442 }
    443 
    444 }}
    445 
    446 #endif
    447 
    448 HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw()
    449 {
    450   NCOM::CPropVariant prop;
    451   result = false;
    452   RINOK(arc->GetProperty(index, propID, &prop));
    453   if (prop.vt == VT_BOOL)
    454     result = VARIANT_BOOLToBool(prop.boolVal);
    455   else if (prop.vt != VT_EMPTY)
    456     return E_FAIL;
    457   return S_OK;
    458 }
    459 
    460 HRESULT Archive_IsItem_Dir(IInArchive *arc, UInt32 index, bool &result) throw()
    461 {
    462   return Archive_GetItemBoolProp(arc, index, kpidIsDir, result);
    463 }
    464 
    465 HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw()
    466 {
    467   return Archive_GetItemBoolProp(arc, index, kpidIsAux, result);
    468 }
    469 
    470 HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw()
    471 {
    472   return Archive_GetItemBoolProp(arc, index, kpidIsAltStream, result);
    473 }
    474 
    475 HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &result) throw()
    476 {
    477   return Archive_GetItemBoolProp(arc, index, kpidIsDeleted, result);
    478 }
    479 
    480 static HRESULT Archive_GetArcBoolProp(IInArchive *arc, PROPID propid, bool &result) throw()
    481 {
    482   NCOM::CPropVariant prop;
    483   result = false;
    484   RINOK(arc->GetArchiveProperty(propid, &prop));
    485   if (prop.vt == VT_BOOL)
    486     result = VARIANT_BOOLToBool(prop.boolVal);
    487   else if (prop.vt != VT_EMPTY)
    488     return E_FAIL;
    489   return S_OK;
    490 }
    491 
    492 static HRESULT Archive_GetArcProp_UInt(IInArchive *arc, PROPID propid, UInt64 &result, bool &defined)
    493 {
    494   defined = false;
    495   NCOM::CPropVariant prop;
    496   RINOK(arc->GetArchiveProperty(propid, &prop));
    497   switch (prop.vt)
    498   {
    499     case VT_UI4: result = prop.ulVal; defined = true; break;
    500     case VT_I4: result = (Int64)prop.lVal; defined = true; break;
    501     case VT_UI8: result = (UInt64)prop.uhVal.QuadPart; defined = true; break;
    502     case VT_I8: result = (UInt64)prop.hVal.QuadPart; defined = true; break;
    503     case VT_EMPTY: break;
    504     default: return E_FAIL;
    505   }
    506   return S_OK;
    507 }
    508 
    509 static HRESULT Archive_GetArcProp_Int(IInArchive *arc, PROPID propid, Int64 &result, bool &defined)
    510 {
    511   defined = false;
    512   NCOM::CPropVariant prop;
    513   RINOK(arc->GetArchiveProperty(propid, &prop));
    514   switch (prop.vt)
    515   {
    516     case VT_UI4: result = prop.ulVal; defined = true; break;
    517     case VT_I4: result = prop.lVal; defined = true; break;
    518     case VT_UI8: result = (Int64)prop.uhVal.QuadPart; defined = true; break;
    519     case VT_I8: result = (Int64)prop.hVal.QuadPart; defined = true; break;
    520     case VT_EMPTY: break;
    521     default: return E_FAIL;
    522   }
    523   return S_OK;
    524 }
    525 
    526 #ifndef _SFX
    527 
    528 HRESULT CArc::GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const
    529 {
    530   if (!GetRawProps)
    531     return E_FAIL;
    532   if (index == parent)
    533     return S_OK;
    534   UInt32 curIndex = index;
    535 
    536   UString s;
    537 
    538   bool prevWasAltStream = false;
    539 
    540   for (;;)
    541   {
    542     #ifdef MY_CPU_LE
    543     const void *p;
    544     UInt32 size;
    545     UInt32 propType;
    546     RINOK(GetRawProps->GetRawProp(curIndex, kpidName, &p, &size, &propType));
    547     if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE)
    548       s = (const wchar_t *)p;
    549     else
    550     #endif
    551     {
    552       NCOM::CPropVariant prop;
    553       RINOK(Archive->GetProperty(curIndex, kpidName, &prop));
    554       if (prop.vt == VT_BSTR && prop.bstrVal)
    555         s.SetFromBstr(prop.bstrVal);
    556       else if (prop.vt == VT_EMPTY)
    557         s.Empty();
    558       else
    559         return E_FAIL;
    560     }
    561 
    562     UInt32 curParent = (UInt32)(Int32)-1;
    563     UInt32 parentType = 0;
    564     RINOK(GetRawProps->GetParent(curIndex, &curParent, &parentType));
    565 
    566     if (parentType != NParentType::kAltStream)
    567     {
    568       for (;;)
    569       {
    570         int pos = s.ReverseFind_PathSepar();
    571         if (pos < 0)
    572         {
    573           break;
    574         }
    575         parts.Insert(0, s.Ptr(pos + 1));
    576         s.DeleteFrom(pos);
    577       }
    578     }
    579 
    580     parts.Insert(0, s);
    581 
    582     if (prevWasAltStream)
    583     {
    584       {
    585         UString &s2 = parts[parts.Size() - 2];
    586         s2 += L':';
    587         s2 += parts.Back();
    588       }
    589       parts.DeleteBack();
    590     }
    591 
    592     if (parent == curParent)
    593       return S_OK;
    594 
    595     prevWasAltStream = false;
    596     if (parentType == NParentType::kAltStream)
    597       prevWasAltStream = true;
    598 
    599     if (curParent == (UInt32)(Int32)-1)
    600       return E_FAIL;
    601     curIndex = curParent;
    602   }
    603 }
    604 
    605 #endif
    606 
    607 HRESULT CArc::GetItemPath(UInt32 index, UString &result) const
    608 {
    609   #ifdef MY_CPU_LE
    610   if (GetRawProps)
    611   {
    612     const void *p;
    613     UInt32 size;
    614     UInt32 propType;
    615     if (!IsTree)
    616     {
    617       if (GetRawProps->GetRawProp(index, kpidPath, &p, &size, &propType) == S_OK &&
    618           propType == NPropDataType::kUtf16z)
    619       {
    620         unsigned len = size / 2 - 1;
    621         wchar_t *s = result.GetBuf(len);
    622         for (unsigned i = 0; i < len; i++)
    623         {
    624           wchar_t c = GetUi16(p);
    625           p = (const void *)((const Byte *)p + 2);
    626           #if WCHAR_PATH_SEPARATOR != L'/'
    627           if (c == L'/')
    628             c = WCHAR_PATH_SEPARATOR;
    629           #endif
    630           *s++ = c;
    631         }
    632         *s = 0;
    633         result.ReleaseBuf_SetLen(len);
    634         if (len != 0)
    635           return S_OK;
    636       }
    637     }
    638     /*
    639     else if (GetRawProps->GetRawProp(index, kpidName, &p, &size, &propType) == S_OK &&
    640         p && propType == NPropDataType::kUtf16z)
    641     {
    642       size -= 2;
    643       UInt32 totalSize = size;
    644       bool isOK = false;
    645 
    646       {
    647         UInt32 index2 = index;
    648         for (;;)
    649         {
    650           UInt32 parent = (UInt32)(Int32)-1;
    651           UInt32 parentType = 0;
    652           if (GetRawProps->GetParent(index2, &parent, &parentType) != S_OK)
    653             break;
    654           if (parent == (UInt32)(Int32)-1)
    655           {
    656             if (parentType != 0)
    657               totalSize += 2;
    658             isOK = true;
    659             break;
    660           }
    661           index2 = parent;
    662           UInt32 size2;
    663           const void *p2;
    664           if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK &&
    665               p2 && propType == NPropDataType::kUtf16z)
    666             break;
    667           totalSize += size2;
    668         }
    669       }
    670 
    671       if (isOK)
    672       {
    673         wchar_t *sz = result.GetBuf_SetEnd(totalSize / 2);
    674         UInt32 pos = totalSize - size;
    675         memcpy((Byte *)sz + pos, p, size);
    676         UInt32 index2 = index;
    677         for (;;)
    678         {
    679           UInt32 parent = (UInt32)(Int32)-1;
    680           UInt32 parentType = 0;
    681           if (GetRawProps->GetParent(index2, &parent, &parentType) != S_OK)
    682             break;
    683           if (parent == (UInt32)(Int32)-1)
    684           {
    685             if (parentType != 0)
    686               sz[pos / 2 - 1] = L':';
    687             break;
    688           }
    689           index2 = parent;
    690           UInt32 size2;
    691           const void *p2;
    692           if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK)
    693             break;
    694           pos -= size2;
    695           memcpy((Byte *)sz + pos, p2, size2);
    696           sz[(pos + size2 - 2) / 2] = (parentType == 0) ? WCHAR_PATH_SEPARATOR : L':';
    697         }
    698         #ifdef _WIN32
    699         // result.Replace(L'/', WCHAR_PATH_SEPARATOR);
    700         #endif
    701         return S_OK;
    702       }
    703     }
    704     */
    705   }
    706   #endif
    707 
    708   {
    709     NCOM::CPropVariant prop;
    710     RINOK(Archive->GetProperty(index, kpidPath, &prop));
    711     if (prop.vt == VT_BSTR && prop.bstrVal)
    712       result.SetFromBstr(prop.bstrVal);
    713     else if (prop.vt == VT_EMPTY)
    714       result.Empty();
    715     else
    716       return E_FAIL;
    717   }
    718 
    719   if (result.IsEmpty())
    720     return GetDefaultItemPath(index, result);
    721   return S_OK;
    722 }
    723 
    724 HRESULT CArc::GetDefaultItemPath(UInt32 index, UString &result) const
    725 {
    726   result.Empty();
    727   bool isDir;
    728   RINOK(Archive_IsItem_Dir(Archive, index, isDir));
    729   if (!isDir)
    730   {
    731     result = DefaultName;
    732     NCOM::CPropVariant prop;
    733     RINOK(Archive->GetProperty(index, kpidExtension, &prop));
    734     if (prop.vt == VT_BSTR)
    735     {
    736       result += L'.';
    737       result += prop.bstrVal;
    738     }
    739     else if (prop.vt != VT_EMPTY)
    740       return E_FAIL;
    741   }
    742   return S_OK;
    743 }
    744 
    745 HRESULT CArc::GetItemPath2(UInt32 index, UString &result) const
    746 {
    747   RINOK(GetItemPath(index, result));
    748   if (Ask_Deleted)
    749   {
    750     bool isDeleted = false;
    751     RINOK(Archive_IsItem_Deleted(Archive, index, isDeleted));
    752     if (isDeleted)
    753       result.Insert(0, L"[DELETED]" WSTRING_PATH_SEPARATOR);
    754   }
    755   return S_OK;
    756 }
    757 
    758 #ifdef SUPPORT_ALT_STREAMS
    759 
    760 int FindAltStreamColon_in_Path(const wchar_t *path)
    761 {
    762   unsigned i = 0;
    763   int colonPos = -1;
    764   for (;; i++)
    765   {
    766     wchar_t c = path[i];
    767     if (c == 0)
    768       return colonPos;
    769     if (c == ':')
    770     {
    771       if (colonPos < 0)
    772         colonPos = i;
    773       continue;
    774     }
    775     if (c == WCHAR_PATH_SEPARATOR)
    776       colonPos = -1;
    777   }
    778 }
    779 
    780 #endif
    781 
    782 HRESULT CArc::GetItem(UInt32 index, CReadArcItem &item) const
    783 {
    784   #ifdef SUPPORT_ALT_STREAMS
    785   item.IsAltStream = false;
    786   item.AltStreamName.Empty();
    787   item.MainPath.Empty();
    788   #endif
    789 
    790   item.IsDir = false;
    791   item.Path.Empty();
    792   item.ParentIndex = (UInt32)(Int32)-1;
    793 
    794   item.PathParts.Clear();
    795 
    796   RINOK(Archive_IsItem_Dir(Archive, index, item.IsDir));
    797   item.MainIsDir = item.IsDir;
    798 
    799   RINOK(GetItemPath2(index, item.Path));
    800 
    801   #ifndef _SFX
    802   UInt32 mainIndex = index;
    803   #endif
    804 
    805   #ifdef SUPPORT_ALT_STREAMS
    806 
    807   item.MainPath = item.Path;
    808   if (Ask_AltStream)
    809   {
    810     RINOK(Archive_IsItem_AltStream(Archive, index, item.IsAltStream));
    811   }
    812 
    813   bool needFindAltStream = false;
    814 
    815   if (item.IsAltStream)
    816   {
    817     needFindAltStream = true;
    818     if (GetRawProps)
    819     {
    820       UInt32 parentType = 0;
    821       UInt32 parentIndex;
    822       RINOK(GetRawProps->GetParent(index, &parentIndex, &parentType));
    823       if (parentType == NParentType::kAltStream)
    824       {
    825         NCOM::CPropVariant prop;
    826         RINOK(Archive->GetProperty(index, kpidName, &prop));
    827         if (prop.vt == VT_BSTR && prop.bstrVal)
    828           item.AltStreamName.SetFromBstr(prop.bstrVal);
    829         else if (prop.vt != VT_EMPTY)
    830           return E_FAIL;
    831         else
    832         {
    833           // item.IsAltStream = false;
    834         }
    835         /*
    836         if (item.AltStreamName.IsEmpty())
    837           item.IsAltStream = false;
    838         */
    839 
    840         needFindAltStream = false;
    841         item.ParentIndex = parentIndex;
    842         mainIndex = parentIndex;
    843 
    844         if (parentIndex == (UInt32)(Int32)-1)
    845         {
    846           item.MainPath.Empty();
    847           item.MainIsDir = true;
    848         }
    849         else
    850         {
    851           RINOK(GetItemPath2(parentIndex, item.MainPath));
    852           RINOK(Archive_IsItem_Dir(Archive, parentIndex, item.MainIsDir));
    853         }
    854       }
    855     }
    856   }
    857 
    858   if (item.WriteToAltStreamIfColon || needFindAltStream)
    859   {
    860     /* Good handler must support GetRawProps::GetParent for alt streams./
    861        So the following code currently is not used */
    862     int colon = FindAltStreamColon_in_Path(item.Path);
    863     if (colon >= 0)
    864     {
    865       item.MainPath.DeleteFrom(colon);
    866       item.AltStreamName = item.Path.Ptr(colon + 1);
    867       item.MainIsDir = (colon == 0 || IsPathSepar(item.Path[(unsigned)colon - 1]));
    868       item.IsAltStream = true;
    869     }
    870   }
    871 
    872   #endif
    873 
    874   #ifndef _SFX
    875   if (item._use_baseParentFolder_mode)
    876   {
    877     RINOK(GetItemPathToParent(mainIndex, item._baseParentFolder, item.PathParts));
    878 
    879     #ifdef SUPPORT_ALT_STREAMS
    880     if ((item.WriteToAltStreamIfColon || needFindAltStream) && !item.PathParts.IsEmpty())
    881     {
    882       int colon;
    883       {
    884         UString &s = item.PathParts.Back();
    885         colon = FindAltStreamColon_in_Path(s);
    886         if (colon >= 0)
    887         {
    888           item.AltStreamName = s.Ptr(colon + 1);
    889           item.MainIsDir = (colon == 0 || IsPathSepar(s[(unsigned)colon - 1]));
    890           item.IsAltStream = true;
    891           s.DeleteFrom(colon);
    892         }
    893       }
    894       if (colon == 0)
    895         item.PathParts.DeleteBack();
    896     }
    897     #endif
    898 
    899   }
    900   else
    901   #endif
    902     SplitPathToParts(
    903           #ifdef SUPPORT_ALT_STREAMS
    904             item.MainPath
    905           #else
    906             item.Path
    907           #endif
    908       , item.PathParts);
    909 
    910   return S_OK;
    911 }
    912 
    913 #ifndef _SFX
    914 
    915 static HRESULT Archive_GetItem_Size(IInArchive *archive, UInt32 index, UInt64 &size, bool &defined)
    916 {
    917   NCOM::CPropVariant prop;
    918   defined = false;
    919   size = 0;
    920   RINOK(archive->GetProperty(index, kpidSize, &prop));
    921   switch (prop.vt)
    922   {
    923     case VT_UI1: size = prop.bVal; break;
    924     case VT_UI2: size = prop.uiVal; break;
    925     case VT_UI4: size = prop.ulVal; break;
    926     case VT_UI8: size = (UInt64)prop.uhVal.QuadPart; break;
    927     case VT_EMPTY: return S_OK;
    928     default: return E_FAIL;
    929   }
    930   defined = true;
    931   return S_OK;
    932 }
    933 
    934 #endif
    935 
    936 HRESULT CArc::GetItemSize(UInt32 index, UInt64 &size, bool &defined) const
    937 {
    938   NCOM::CPropVariant prop;
    939   defined = false;
    940   size = 0;
    941   RINOK(Archive->GetProperty(index, kpidSize, &prop));
    942   switch (prop.vt)
    943   {
    944     case VT_UI1: size = prop.bVal; break;
    945     case VT_UI2: size = prop.uiVal; break;
    946     case VT_UI4: size = prop.ulVal; break;
    947     case VT_UI8: size = (UInt64)prop.uhVal.QuadPart; break;
    948     case VT_EMPTY: return S_OK;
    949     default: return E_FAIL;
    950   }
    951   defined = true;
    952   return S_OK;
    953 }
    954 
    955 HRESULT CArc::GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const
    956 {
    957   NCOM::CPropVariant prop;
    958   defined = false;
    959   ft.dwHighDateTime = ft.dwLowDateTime = 0;
    960   RINOK(Archive->GetProperty(index, kpidMTime, &prop));
    961   if (prop.vt == VT_FILETIME)
    962   {
    963     ft = prop.filetime;
    964     defined = true;
    965   }
    966   else if (prop.vt != VT_EMPTY)
    967     return E_FAIL;
    968   else if (MTimeDefined)
    969   {
    970     ft = MTime;
    971     defined = true;
    972   }
    973   return S_OK;
    974 }
    975 
    976 #ifndef _SFX
    977 
    978 static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size)
    979 {
    980   for (size_t i = 0; i < size; i++)
    981     if (p1[i] != p2[i])
    982       return false;
    983   return true;
    984 }
    985 
    986 static void MakeCheckOrder(CCodecs *codecs,
    987     CIntVector &orderIndices, unsigned numTypes, CIntVector &orderIndices2,
    988     const Byte *data, size_t dataSize)
    989 {
    990   for (unsigned i = 0; i < numTypes; i++)
    991   {
    992     int index = orderIndices[i];
    993     if (index < 0)
    994       continue;
    995     const CArcInfoEx &ai = codecs->Formats[index];
    996     if (ai.SignatureOffset != 0)
    997     {
    998       orderIndices2.Add(index);
    999       orderIndices[i] = -1;
   1000       continue;
   1001     }
   1002 
   1003     const CObjectVector<CByteBuffer> &sigs = ai.Signatures;
   1004     FOR_VECTOR (k, sigs)
   1005     {
   1006       const CByteBuffer &sig = sigs[k];
   1007       if (sig.Size() == 0 && dataSize == 0 ||
   1008           sig.Size() != 0 && sig.Size() <= dataSize &&
   1009           TestSignature(data, sig, sig.Size()))
   1010       {
   1011         orderIndices2.Add(index);
   1012         orderIndices[i] = -1;
   1013         break;
   1014       }
   1015     }
   1016   }
   1017 }
   1018 
   1019 #endif
   1020 
   1021 #ifdef UNDER_CE
   1022   static const unsigned kNumHashBytes = 1;
   1023   #define HASH_VAL(buf, pos) ((buf)[pos])
   1024 #else
   1025   static const unsigned kNumHashBytes = 2;
   1026   #define HASH_VAL(buf, pos) ((buf)[pos] | ((UInt32)(buf)[pos + 1] << 8))
   1027 #endif
   1028 
   1029 
   1030 #ifndef _SFX
   1031 
   1032 static bool IsExeExt(const UString &ext)
   1033 {
   1034   return ext.IsEqualTo_Ascii_NoCase("exe");
   1035 }
   1036 
   1037 static const char * const k_PreArcFormats[] =
   1038 {
   1039     "pe"
   1040   , "elf"
   1041   , "macho"
   1042   , "mub"
   1043   , "te"
   1044 };
   1045 
   1046 static bool IsNameFromList(const UString &s, const char * const names[], size_t num)
   1047 {
   1048   for (unsigned i = 0; i < num; i++)
   1049     if (StringsAreEqualNoCase_Ascii(s, names[i]))
   1050       return true;
   1051   return false;
   1052 }
   1053 
   1054 
   1055 static bool IsPreArcFormat(const CArcInfoEx &ai)
   1056 {
   1057   if (ai.Flags_PreArc())
   1058     return true;
   1059   return IsNameFromList(ai.Name, k_PreArcFormats, ARRAY_SIZE(k_PreArcFormats));
   1060 }
   1061 
   1062 static const char * const k_Formats_with_simple_signuature[] =
   1063 {
   1064     "7z"
   1065   , "xz"
   1066   , "rar"
   1067   , "bzip2"
   1068   , "gzip"
   1069   , "cab"
   1070   , "wim"
   1071   , "rpm"
   1072   , "vhd"
   1073   , "xar"
   1074 };
   1075 
   1076 static bool IsNewStyleSignature(const CArcInfoEx &ai)
   1077 {
   1078   // if (ai.Version >= 0x91F)
   1079   if (ai.NewInterface)
   1080     return true;
   1081   return IsNameFromList(ai.Name, k_Formats_with_simple_signuature, ARRAY_SIZE(k_Formats_with_simple_signuature));
   1082 }
   1083 
   1084 class CArchiveOpenCallback_Offset:
   1085   public IArchiveOpenCallback,
   1086   public IArchiveOpenVolumeCallback,
   1087   #ifndef _NO_CRYPTO
   1088   public ICryptoGetTextPassword,
   1089   #endif
   1090   public CMyUnknownImp
   1091 {
   1092 public:
   1093   CMyComPtr<IArchiveOpenCallback> Callback;
   1094   CMyComPtr<IArchiveOpenVolumeCallback> OpenVolumeCallback;
   1095   UInt64 Files;
   1096   UInt64 Offset;
   1097 
   1098   #ifndef _NO_CRYPTO
   1099   CMyComPtr<ICryptoGetTextPassword> GetTextPassword;
   1100   #endif
   1101 
   1102   MY_QUERYINTERFACE_BEGIN2(IArchiveOpenCallback)
   1103   MY_QUERYINTERFACE_ENTRY(IArchiveOpenVolumeCallback)
   1104   #ifndef _NO_CRYPTO
   1105   MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)
   1106   #endif
   1107   MY_QUERYINTERFACE_END
   1108   MY_ADDREF_RELEASE
   1109 
   1110   INTERFACE_IArchiveOpenCallback(;)
   1111   INTERFACE_IArchiveOpenVolumeCallback(;)
   1112   #ifndef _NO_CRYPTO
   1113   STDMETHOD(CryptoGetTextPassword)(BSTR *password);
   1114   #endif
   1115 };
   1116 
   1117 #ifndef _NO_CRYPTO
   1118 STDMETHODIMP CArchiveOpenCallback_Offset::CryptoGetTextPassword(BSTR *password)
   1119 {
   1120   COM_TRY_BEGIN
   1121   if (GetTextPassword)
   1122     return GetTextPassword->CryptoGetTextPassword(password);
   1123   return E_NOTIMPL;
   1124   COM_TRY_END
   1125 }
   1126 #endif
   1127 
   1128 STDMETHODIMP CArchiveOpenCallback_Offset::SetTotal(const UInt64 *, const UInt64 *)
   1129 {
   1130   return S_OK;
   1131 }
   1132 
   1133 STDMETHODIMP CArchiveOpenCallback_Offset::SetCompleted(const UInt64 *, const UInt64 *bytes)
   1134 {
   1135   if (!Callback)
   1136     return S_OK;
   1137   UInt64 value = Offset;
   1138   if (bytes)
   1139     value += *bytes;
   1140   return Callback->SetCompleted(&Files, &value);
   1141 }
   1142 
   1143 STDMETHODIMP CArchiveOpenCallback_Offset::GetProperty(PROPID propID, PROPVARIANT *value)
   1144 {
   1145   if (OpenVolumeCallback)
   1146     return OpenVolumeCallback->GetProperty(propID, value);
   1147   NCOM::PropVariant_Clear(value);
   1148   return S_OK;
   1149   // return E_NOTIMPL;
   1150 }
   1151 
   1152 STDMETHODIMP CArchiveOpenCallback_Offset::GetStream(const wchar_t *name, IInStream **inStream)
   1153 {
   1154   if (OpenVolumeCallback)
   1155     return OpenVolumeCallback->GetStream(name, inStream);
   1156   return S_FALSE;
   1157 }
   1158 
   1159 #endif
   1160 
   1161 
   1162 UInt32 GetOpenArcErrorFlags(const NCOM::CPropVariant &prop, bool *isDefinedProp)
   1163 {
   1164   if (isDefinedProp != NULL)
   1165     *isDefinedProp = false;
   1166 
   1167   switch (prop.vt)
   1168   {
   1169     case VT_UI8: if (isDefinedProp) *isDefinedProp = true; return (UInt32)prop.uhVal.QuadPart;
   1170     case VT_UI4: if (isDefinedProp) *isDefinedProp = true; return prop.ulVal;
   1171     case VT_EMPTY: return 0;
   1172     default: throw 151199;
   1173   }
   1174 }
   1175 
   1176 void CArcErrorInfo::ClearErrors()
   1177 {
   1178   // ErrorFormatIndex = -1; // we don't need to clear ErrorFormatIndex here !!!
   1179 
   1180   ThereIsTail = false;
   1181   UnexpecedEnd = false;
   1182   IgnoreTail = false;
   1183   // NonZerosTail = false;
   1184   ErrorFlags_Defined = false;
   1185   ErrorFlags = 0;
   1186   WarningFlags = 0;
   1187   TailSize = 0;
   1188 
   1189   ErrorMessage.Empty();
   1190   WarningMessage.Empty();
   1191 }
   1192 
   1193 HRESULT CArc::ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes)
   1194 {
   1195   // OkPhySize_Defined = false;
   1196   PhySizeDefined = false;
   1197   PhySize = 0;
   1198   Offset = 0;
   1199   AvailPhySize = FileSize - startPos;
   1200 
   1201   ErrorInfo.ClearErrors();
   1202   {
   1203     NCOM::CPropVariant prop;
   1204     RINOK(archive->GetArchiveProperty(kpidErrorFlags, &prop));
   1205     ErrorInfo.ErrorFlags = GetOpenArcErrorFlags(prop, &ErrorInfo.ErrorFlags_Defined);
   1206   }
   1207   {
   1208     NCOM::CPropVariant prop;
   1209     RINOK(archive->GetArchiveProperty(kpidWarningFlags, &prop));
   1210     ErrorInfo.WarningFlags = GetOpenArcErrorFlags(prop);
   1211   }
   1212 
   1213   {
   1214     NCOM::CPropVariant prop;
   1215     RINOK(archive->GetArchiveProperty(kpidError, &prop));
   1216     if (prop.vt != VT_EMPTY)
   1217       ErrorInfo.ErrorMessage = (prop.vt == VT_BSTR ? prop.bstrVal : L"Unknown error");
   1218   }
   1219 
   1220   {
   1221     NCOM::CPropVariant prop;
   1222     RINOK(archive->GetArchiveProperty(kpidWarning, &prop));
   1223     if (prop.vt != VT_EMPTY)
   1224       ErrorInfo.WarningMessage = (prop.vt == VT_BSTR ? prop.bstrVal : L"Unknown warning");
   1225   }
   1226 
   1227   if (openRes == S_OK || ErrorInfo.IsArc_After_NonOpen())
   1228   {
   1229     RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, PhySize, PhySizeDefined));
   1230     /*
   1231     RINOK(Archive_GetArcProp_UInt(archive, kpidOkPhySize, OkPhySize, OkPhySize_Defined));
   1232     if (!OkPhySize_Defined)
   1233     {
   1234       OkPhySize_Defined = PhySizeDefined;
   1235       OkPhySize = PhySize;
   1236     }
   1237     */
   1238 
   1239     bool offsetDefined;
   1240     RINOK(Archive_GetArcProp_Int(archive, kpidOffset, Offset, offsetDefined));
   1241 
   1242     Int64 globalOffset = startPos + Offset;
   1243     AvailPhySize = FileSize - globalOffset;
   1244     if (PhySizeDefined)
   1245     {
   1246       UInt64 endPos = globalOffset + PhySize;
   1247       if (endPos < FileSize)
   1248       {
   1249         AvailPhySize = PhySize;
   1250         ErrorInfo.ThereIsTail = true;
   1251         ErrorInfo.TailSize = FileSize - endPos;
   1252       }
   1253       else if (endPos > FileSize)
   1254         ErrorInfo.UnexpecedEnd = true;
   1255     }
   1256   }
   1257 
   1258   return S_OK;
   1259 }
   1260 
   1261 /*
   1262 static PrintNumber(const char *s, int n)
   1263 {
   1264   char temp[100];
   1265   sprintf(temp, "%s %d", s, n);
   1266   OutputDebugStringA(temp);
   1267 }
   1268 */
   1269 
   1270 HRESULT CArc::PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr<IInArchive> &archive)
   1271 {
   1272   // OutputDebugStringA("a1");
   1273   // PrintNumber("formatIndex", formatIndex);
   1274 
   1275   RINOK(op.codecs->CreateInArchive(formatIndex, archive));
   1276   // OutputDebugStringA("a2");
   1277   if (!archive)
   1278     return S_OK;
   1279 
   1280   #ifdef EXTERNAL_CODECS
   1281   if (op.codecs->NeedSetLibCodecs)
   1282   {
   1283     const CArcInfoEx &ai = op.codecs->Formats[formatIndex];
   1284     if (ai.LibIndex >= 0 ?
   1285         !op.codecs->Libs[ai.LibIndex].SetCodecs :
   1286         !op.codecs->Libs.IsEmpty())
   1287     {
   1288       CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
   1289       archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
   1290       if (setCompressCodecsInfo)
   1291       {
   1292         RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(op.codecs));
   1293       }
   1294     }
   1295   }
   1296   #endif
   1297 
   1298 
   1299   #ifndef _SFX
   1300 
   1301   const CArcInfoEx &ai = op.codecs->Formats[formatIndex];
   1302 
   1303   // OutputDebugStringW(ai.Name);
   1304   // OutputDebugStringA("a3");
   1305 
   1306   if (ai.Flags_PreArc())
   1307   {
   1308     /* we notify parsers that extract executables, that they don't need
   1309        to open archive, if there is tail after executable (for SFX cases) */
   1310     CMyComPtr<IArchiveAllowTail> allowTail;
   1311     archive.QueryInterface(IID_IArchiveAllowTail, (void **)&allowTail);
   1312     if (allowTail)
   1313       allowTail->AllowTail(BoolToInt(true));
   1314   }
   1315 
   1316   if (op.props)
   1317   {
   1318     /*
   1319     FOR_VECTOR (y, op.props)
   1320     {
   1321       const COptionalOpenProperties &optProps = (*op.props)[y];
   1322       if (optProps.FormatName.IsEmpty() || optProps.FormatName.CompareNoCase(ai.Name) == 0)
   1323       {
   1324         RINOK(SetProperties(archive, optProps.Props));
   1325         break;
   1326       }
   1327     }
   1328     */
   1329     RINOK(SetProperties(archive, *op.props));
   1330   }
   1331 
   1332   #endif
   1333   return S_OK;
   1334 }
   1335 
   1336 #ifndef _SFX
   1337 
   1338 static HRESULT ReadParseItemProps(IInArchive *archive, const CArcInfoEx &ai, NArchive::NParser::CParseItem &pi)
   1339 {
   1340   pi.Extension = ai.GetMainExt();
   1341   pi.FileTime_Defined = false;
   1342   pi.ArcType = ai.Name;
   1343 
   1344   RINOK(Archive_GetArcBoolProp(archive, kpidIsNotArcType, pi.IsNotArcType));
   1345 
   1346   // RINOK(Archive_GetArcBoolProp(archive, kpidIsSelfExe, pi.IsSelfExe));
   1347   pi.IsSelfExe = ai.Flags_PreArc();
   1348 
   1349   {
   1350     NCOM::CPropVariant prop;
   1351     RINOK(archive->GetArchiveProperty(kpidMTime, &prop));
   1352     if (prop.vt == VT_FILETIME)
   1353     {
   1354       pi.FileTime_Defined = true;
   1355       pi.FileTime = prop.filetime;
   1356     }
   1357   }
   1358 
   1359   if (!pi.FileTime_Defined)
   1360   {
   1361     NCOM::CPropVariant prop;
   1362     RINOK(archive->GetArchiveProperty(kpidCTime, &prop));
   1363     if (prop.vt == VT_FILETIME)
   1364     {
   1365       pi.FileTime_Defined = true;
   1366       pi.FileTime = prop.filetime;
   1367     }
   1368   }
   1369 
   1370   {
   1371     NCOM::CPropVariant prop;
   1372     RINOK(archive->GetArchiveProperty(kpidName, &prop));
   1373     if (prop.vt == VT_BSTR)
   1374     {
   1375       pi.Name.SetFromBstr(prop.bstrVal);
   1376       pi.Extension.Empty();
   1377     }
   1378     else
   1379     {
   1380       RINOK(archive->GetArchiveProperty(kpidExtension, &prop));
   1381       if (prop.vt == VT_BSTR)
   1382         pi.Extension.SetFromBstr(prop.bstrVal);
   1383     }
   1384   }
   1385 
   1386   {
   1387     NCOM::CPropVariant prop;
   1388     RINOK(archive->GetArchiveProperty(kpidShortComment, &prop));
   1389     if (prop.vt == VT_BSTR)
   1390       pi.Comment.SetFromBstr(prop.bstrVal);
   1391   }
   1392 
   1393 
   1394   UInt32 numItems;
   1395   RINOK(archive->GetNumberOfItems(&numItems));
   1396 
   1397   // pi.NumSubFiles = numItems;
   1398   // RINOK(Archive_GetArcProp_UInt(archive, kpidUnpackSize, pi.UnpackSize, pi.UnpackSize_Defined));
   1399   // if (!pi.UnpackSize_Defined)
   1400   {
   1401     pi.NumSubFiles = 0;
   1402     pi.NumSubDirs = 0;
   1403     pi.UnpackSize = 0;
   1404     for (UInt32 i = 0; i < numItems; i++)
   1405     {
   1406       UInt64 size = 0;
   1407       bool defined = false;
   1408       Archive_GetItem_Size(archive, i, size, defined);
   1409       if (defined)
   1410       {
   1411         pi.UnpackSize_Defined = true;
   1412         pi.UnpackSize += size;
   1413       }
   1414 
   1415       bool isDir = false;
   1416       Archive_IsItem_Dir(archive, i, isDir);
   1417       if (isDir)
   1418         pi.NumSubDirs++;
   1419       else
   1420         pi.NumSubFiles++;
   1421     }
   1422     if (pi.NumSubDirs != 0)
   1423       pi.NumSubDirs_Defined = true;
   1424     pi.NumSubFiles_Defined = true;
   1425   }
   1426 
   1427   return S_OK;
   1428 }
   1429 
   1430 #endif
   1431 
   1432 HRESULT CArc::CheckZerosTail(const COpenOptions &op, UInt64 offset)
   1433 {
   1434   if (!op.stream)
   1435     return S_OK;
   1436   RINOK(op.stream->Seek(offset, STREAM_SEEK_SET, NULL));
   1437   const UInt32 kBufSize = 1 << 11;
   1438   Byte buf[kBufSize];
   1439 
   1440   for (;;)
   1441   {
   1442     UInt32 processed = 0;
   1443     RINOK(op.stream->Read(buf, kBufSize, &processed));
   1444     if (processed == 0)
   1445     {
   1446       // ErrorInfo.NonZerosTail = false;
   1447       ErrorInfo.IgnoreTail = true;
   1448       return S_OK;
   1449     }
   1450     for (size_t i = 0; i < processed; i++)
   1451     {
   1452       if (buf[i] != 0)
   1453       {
   1454         // ErrorInfo.IgnoreTail = false;
   1455         // ErrorInfo.NonZerosTail = true;
   1456         return S_OK;
   1457       }
   1458     }
   1459   }
   1460 }
   1461 
   1462 #ifndef _SFX
   1463 
   1464 class CExtractCallback_To_OpenCallback:
   1465   public IArchiveExtractCallback,
   1466   public ICompressProgressInfo,
   1467   public CMyUnknownImp
   1468 {
   1469 public:
   1470   CMyComPtr<IArchiveOpenCallback> Callback;
   1471   UInt64 Files;
   1472   UInt64 Offset;
   1473 
   1474   MY_UNKNOWN_IMP2(IArchiveExtractCallback, ICompressProgressInfo)
   1475   INTERFACE_IArchiveExtractCallback(;)
   1476   STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
   1477   void Init(IArchiveOpenCallback *callback)
   1478   {
   1479     Callback = callback;
   1480     Files = 0;
   1481     Offset = 0;
   1482   }
   1483 };
   1484 
   1485 STDMETHODIMP CExtractCallback_To_OpenCallback::SetTotal(UInt64 /* size */)
   1486 {
   1487   return S_OK;
   1488 }
   1489 
   1490 STDMETHODIMP CExtractCallback_To_OpenCallback::SetCompleted(const UInt64 * /* completeValue */)
   1491 {
   1492   return S_OK;
   1493 }
   1494 
   1495 STDMETHODIMP CExtractCallback_To_OpenCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)
   1496 {
   1497   if (Callback)
   1498   {
   1499     UInt64 value = Offset;
   1500     if (inSize)
   1501       value += *inSize;
   1502     return Callback->SetCompleted(&Files, &value);
   1503   }
   1504   return S_OK;
   1505 }
   1506 
   1507 STDMETHODIMP CExtractCallback_To_OpenCallback::GetStream(UInt32 /* index */, ISequentialOutStream **outStream, Int32 /* askExtractMode */)
   1508 {
   1509   *outStream = 0;
   1510   return S_OK;
   1511 }
   1512 
   1513 STDMETHODIMP CExtractCallback_To_OpenCallback::PrepareOperation(Int32 /* askExtractMode */)
   1514 {
   1515   return S_OK;
   1516 }
   1517 
   1518 STDMETHODIMP CExtractCallback_To_OpenCallback::SetOperationResult(Int32 /* operationResult */)
   1519 {
   1520   return S_OK;
   1521 }
   1522 
   1523 static HRESULT OpenArchiveSpec(IInArchive *archive, bool needPhySize,
   1524     IInStream *stream, const UInt64 *maxCheckStartPosition,
   1525     IArchiveOpenCallback *openCallback,
   1526     IArchiveExtractCallback *extractCallback)
   1527 {
   1528   /*
   1529   if (needPhySize)
   1530   {
   1531     CMyComPtr<IArchiveOpen2> open2;
   1532     archive->QueryInterface(IID_IArchiveOpen2, (void **)&open2);
   1533     if (open2)
   1534       return open2->ArcOpen2(stream, kOpenFlags_RealPhySize, openCallback);
   1535   }
   1536   */
   1537   RINOK(archive->Open(stream, maxCheckStartPosition, openCallback));
   1538   if (needPhySize)
   1539   {
   1540     bool phySize_Defined = false;
   1541     UInt64 phySize = 0;
   1542     RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, phySize, phySize_Defined));
   1543     if (phySize_Defined)
   1544       return S_OK;
   1545 
   1546     bool phySizeCantBeDetected = false;;
   1547     RINOK(Archive_GetArcBoolProp(archive, kpidPhySizeCantBeDetected, phySizeCantBeDetected));
   1548 
   1549     if (!phySizeCantBeDetected)
   1550     {
   1551       RINOK(archive->Extract(0, (UInt32)(Int32)-1, BoolToInt(true), extractCallback));
   1552     }
   1553   }
   1554   return S_OK;
   1555 }
   1556 
   1557 static int FindFormatForArchiveType(CCodecs *codecs, CIntVector orderIndices, const char *name)
   1558 {
   1559   FOR_VECTOR (i, orderIndices)
   1560     if (StringsAreEqualNoCase_Ascii(codecs->Formats[orderIndices[i]].Name, name))
   1561       return i;
   1562   return -1;
   1563 }
   1564 
   1565 #endif
   1566 
   1567 HRESULT CArc::OpenStream2(const COpenOptions &op)
   1568 {
   1569   // fprintf(stdout, "\nOpen: %S", Path); fflush(stdout);
   1570 
   1571   Archive.Release();
   1572   GetRawProps.Release();
   1573   GetRootProps.Release();
   1574 
   1575   ErrorInfo.ClearErrors();
   1576   ErrorInfo.ErrorFormatIndex = -1;
   1577 
   1578   IsParseArc = false;
   1579   ArcStreamOffset = 0;
   1580 
   1581   // OutputDebugStringA("1");
   1582   // OutputDebugStringW(Path);
   1583 
   1584   const UString fileName = ExtractFileNameFromPath(Path);
   1585   UString extension;
   1586   {
   1587     int dotPos = fileName.ReverseFind_Dot();
   1588     if (dotPos >= 0)
   1589       extension = fileName.Ptr(dotPos + 1);
   1590   }
   1591 
   1592   CIntVector orderIndices;
   1593 
   1594   bool searchMarkerInHandler = false;
   1595   #ifdef _SFX
   1596     searchMarkerInHandler = true;
   1597   #endif
   1598 
   1599   CBoolArr isMainFormatArr(op.codecs->Formats.Size());
   1600   {
   1601     FOR_VECTOR(i, op.codecs->Formats)
   1602       isMainFormatArr[i] = false;
   1603   }
   1604 
   1605   UInt64 maxStartOffset =
   1606       op.openType.MaxStartOffset_Defined ?
   1607       op.openType.MaxStartOffset :
   1608       kMaxCheckStartPosition;
   1609 
   1610   #ifndef _SFX
   1611   bool isUnknownExt = false;
   1612   #endif
   1613 
   1614   bool isForced = false;
   1615   unsigned numMainTypes = 0;
   1616   int formatIndex = op.openType.FormatIndex;
   1617 
   1618   if (formatIndex >= 0)
   1619   {
   1620     isForced = true;
   1621     orderIndices.Add(formatIndex);
   1622     numMainTypes = 1;
   1623     isMainFormatArr[(unsigned)formatIndex] = true;
   1624 
   1625     searchMarkerInHandler = true;
   1626   }
   1627   else
   1628   {
   1629     unsigned numFinded = 0;
   1630     #ifndef _SFX
   1631     bool isPrearcExt = false;
   1632     #endif
   1633 
   1634     {
   1635       #ifndef _SFX
   1636 
   1637       bool isZip = false;
   1638       bool isRar = false;
   1639 
   1640       const wchar_t c = extension[0];
   1641       if (c == 'z' || c == 'Z' || c == 'r' || c == 'R')
   1642       {
   1643         bool isNumber = false;
   1644         for (unsigned k = 1;; k++)
   1645         {
   1646           const wchar_t d = extension[k];
   1647           if (d == 0)
   1648             break;
   1649           if (d < '0' || d > '9')
   1650           {
   1651             isNumber = false;
   1652             break;
   1653           }
   1654           isNumber = true;
   1655         }
   1656         if (isNumber)
   1657           if (c == 'z' || c == 'Z')
   1658             isZip = true;
   1659           else
   1660             isRar = true;
   1661       }
   1662 
   1663       #endif
   1664 
   1665       FOR_VECTOR (i, op.codecs->Formats)
   1666       {
   1667         const CArcInfoEx &ai = op.codecs->Formats[i];
   1668 
   1669         if (IgnoreSplit || !op.openType.CanReturnArc)
   1670           if (ai.IsSplit())
   1671             continue;
   1672         if (op.excludedFormats->FindInSorted(i) >= 0)
   1673           continue;
   1674 
   1675         #ifndef _SFX
   1676         if (IsPreArcFormat(ai))
   1677           isPrearcExt = true;
   1678         #endif
   1679 
   1680         if (ai.FindExtension(extension) >= 0
   1681             #ifndef _SFX
   1682             || isZip && StringsAreEqualNoCase_Ascii(ai.Name, "zip")
   1683             || isRar && StringsAreEqualNoCase_Ascii(ai.Name, "rar")
   1684             #endif
   1685             )
   1686         {
   1687           // PrintNumber("orderIndices.Insert", i);
   1688           orderIndices.Insert(numFinded++, i);
   1689           isMainFormatArr[i] = true;
   1690         }
   1691         else
   1692           orderIndices.Add(i);
   1693       }
   1694     }
   1695 
   1696     if (!op.stream)
   1697     {
   1698       if (numFinded != 1)
   1699         return E_NOTIMPL;
   1700       orderIndices.DeleteFrom(1);
   1701     }
   1702     // PrintNumber("numFinded", numFinded );
   1703 
   1704     /*
   1705     if (op.openOnlySpecifiedByExtension)
   1706     {
   1707       if (numFinded != 0 && !IsExeExt(extension))
   1708         orderIndices.DeleteFrom(numFinded);
   1709     }
   1710     */
   1711 
   1712     #ifndef _SFX
   1713 
   1714       if (op.stream && orderIndices.Size() >= 2)
   1715       {
   1716         RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
   1717         CByteBuffer byteBuffer;
   1718         CIntVector orderIndices2;
   1719         if (numFinded == 0 || IsExeExt(extension))
   1720         {
   1721           // signature search was here
   1722         }
   1723         else if (extension.IsEqualTo("000") || extension.IsEqualTo("001"))
   1724         {
   1725           int i = FindFormatForArchiveType(op.codecs, orderIndices, "rar");
   1726           if (i >= 0)
   1727           {
   1728             const size_t kBufSize = (1 << 10);
   1729             byteBuffer.Alloc(kBufSize);
   1730             size_t processedSize = kBufSize;
   1731             RINOK(ReadStream(op.stream, byteBuffer, &processedSize));
   1732             if (processedSize >= 16)
   1733             {
   1734               const Byte *buf = byteBuffer;
   1735               const Byte kRarHeader[] = { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 };
   1736               if (TestSignature(buf, kRarHeader, 7) && buf[9] == 0x73 && (buf[10] & 1) != 0)
   1737               {
   1738                 orderIndices2.Add(orderIndices[i]);
   1739                 orderIndices[i] = -1;
   1740                 if (i >= (int)numFinded)
   1741                   numFinded++;
   1742               }
   1743             }
   1744           }
   1745         }
   1746         else
   1747         {
   1748           const size_t kBufSize = (1 << 10);
   1749           byteBuffer.Alloc(kBufSize);
   1750           size_t processedSize = kBufSize;
   1751           RINOK(ReadStream(op.stream, byteBuffer, &processedSize));
   1752           if (processedSize == 0)
   1753             return S_FALSE;
   1754 
   1755           /*
   1756           check type order:
   1757             1) matched extension, no signuature
   1758             2) matched extension, matched signuature
   1759             // 3) no signuature
   1760             // 4) matched signuature
   1761           */
   1762 
   1763           MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, NULL, 0);
   1764           MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, byteBuffer, processedSize);
   1765           // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, NULL, 0);
   1766           // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, byteBuffer, processedSize);
   1767         }
   1768 
   1769         FOR_VECTOR (i, orderIndices)
   1770         {
   1771           int val = orderIndices[i];
   1772           if (val != -1)
   1773             orderIndices2.Add(val);
   1774         }
   1775         orderIndices = orderIndices2;
   1776       }
   1777 
   1778       if (orderIndices.Size() >= 2)
   1779       {
   1780         int iIso = FindFormatForArchiveType(op.codecs, orderIndices, "iso");
   1781         int iUdf = FindFormatForArchiveType(op.codecs, orderIndices, "udf");
   1782         if (iUdf > iIso && iIso >= 0)
   1783         {
   1784           int isoIndex = orderIndices[iIso];
   1785           int udfIndex = orderIndices[iUdf];
   1786           orderIndices[iUdf] = isoIndex;
   1787           orderIndices[iIso] = udfIndex;
   1788         }
   1789       }
   1790 
   1791       numMainTypes = numFinded;
   1792       isUnknownExt = (numMainTypes == 0) || isPrearcExt;
   1793 
   1794     #else // _SFX
   1795 
   1796       numMainTypes = orderIndices.Size();
   1797 
   1798       // we need correct numMainTypes for mutlivolume SFX (if some volume is missing)
   1799       if (numFinded != 0)
   1800         numMainTypes = numFinded;
   1801 
   1802     #endif
   1803   }
   1804 
   1805   UInt64 fileSize = 0;
   1806   if (op.stream)
   1807   {
   1808     RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize));
   1809     RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
   1810   }
   1811   FileSize = fileSize;
   1812 
   1813 
   1814   #ifndef _SFX
   1815 
   1816   CBoolArr skipFrontalFormat(op.codecs->Formats.Size());
   1817   {
   1818     FOR_VECTOR(i, op.codecs->Formats)
   1819       skipFrontalFormat[i] = false;
   1820   }
   1821 
   1822   #endif
   1823 
   1824   const COpenType &mode = op.openType;
   1825 
   1826 
   1827 
   1828 
   1829 
   1830   if (mode.CanReturnArc)
   1831   {
   1832     // ---------- OPEN main type by extenssion ----------
   1833 
   1834     unsigned numCheckTypes = orderIndices.Size();
   1835     if (formatIndex >= 0)
   1836       numCheckTypes = numMainTypes;
   1837 
   1838     for (unsigned i = 0; i < numCheckTypes; i++)
   1839     {
   1840       FormatIndex = orderIndices[i];
   1841 
   1842       bool exactOnly = false;
   1843 
   1844       #ifndef _SFX
   1845 
   1846       const CArcInfoEx &ai = op.codecs->Formats[FormatIndex];
   1847       // OutputDebugStringW(ai.Name);
   1848       if (i >= numMainTypes)
   1849       {
   1850         if (!ai.Flags_BackwardOpen()
   1851             // && !ai.Flags_PureStartOpen()
   1852             )
   1853           continue;
   1854         exactOnly = true;
   1855       }
   1856 
   1857       #endif
   1858 
   1859       // Some handlers do not set total bytes. So we set it here
   1860       if (op.callback)
   1861         RINOK(op.callback->SetTotal(NULL, &fileSize));
   1862 
   1863       if (op.stream)
   1864       {
   1865         RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
   1866       }
   1867 
   1868       CMyComPtr<IInArchive> archive;
   1869 
   1870       RINOK(PrepareToOpen(op, FormatIndex, archive));
   1871       if (!archive)
   1872         continue;
   1873 
   1874       HRESULT result;
   1875       if (op.stream)
   1876       {
   1877         UInt64 searchLimit = (!exactOnly && searchMarkerInHandler) ? maxStartOffset: 0;
   1878         result = archive->Open(op.stream, &searchLimit, op.callback);
   1879       }
   1880       else
   1881       {
   1882         CMyComPtr<IArchiveOpenSeq> openSeq;
   1883         archive.QueryInterface(IID_IArchiveOpenSeq, (void **)&openSeq);
   1884         if (!openSeq)
   1885           return E_NOTIMPL;
   1886         result = openSeq->OpenSeq(op.seqStream);
   1887       }
   1888 
   1889       RINOK(ReadBasicProps(archive, 0, result));
   1890 
   1891       if (result == S_FALSE)
   1892       {
   1893         bool isArc = ErrorInfo.IsArc_After_NonOpen();
   1894 
   1895         #ifndef _SFX
   1896         // if it's archive, we allow another open attempt for parser
   1897         if (!mode.CanReturnParser || !isArc)
   1898           skipFrontalFormat[(unsigned)FormatIndex] = true;
   1899         #endif
   1900 
   1901         if (exactOnly)
   1902           continue;
   1903 
   1904         if (i == 0 && numMainTypes == 1)
   1905         {
   1906           // we set NonOpenErrorInfo, only if there is only one main format (defined by extension).
   1907           ErrorInfo.ErrorFormatIndex = FormatIndex;
   1908           NonOpen_ErrorInfo = ErrorInfo;
   1909 
   1910           if (!mode.CanReturnParser && isArc)
   1911           {
   1912             // if (formatIndex < 0 && !searchMarkerInHandler)
   1913             {
   1914               // if bad archive was detected, we don't need additional open attempts
   1915               #ifndef _SFX
   1916               if (!IsPreArcFormat(ai) /* || !mode.SkipSfxStub */)
   1917               #endif
   1918                 return S_FALSE;
   1919             }
   1920           }
   1921         }
   1922 
   1923         /*
   1924         #ifndef _SFX
   1925         if (IsExeExt(extension) || ai.Flags_PreArc())
   1926         {
   1927         // openOnlyFullArc = false;
   1928         // canReturnTailArc = true;
   1929         // limitSignatureSearch = true;
   1930         }
   1931         #endif
   1932         */
   1933 
   1934         continue;
   1935       }
   1936 
   1937       RINOK(result);
   1938 
   1939       #ifndef _SFX
   1940 
   1941       bool isMainFormat = isMainFormatArr[(unsigned)FormatIndex];
   1942       const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt);
   1943 
   1944       bool thereIsTail = ErrorInfo.ThereIsTail;
   1945       if (thereIsTail && mode.ZerosTailIsAllowed)
   1946       {
   1947         RINOK(CheckZerosTail(op, Offset + PhySize));
   1948         if (ErrorInfo.IgnoreTail)
   1949           thereIsTail = false;
   1950       }
   1951 
   1952       if (Offset > 0)
   1953       {
   1954         if (exactOnly
   1955             || !searchMarkerInHandler
   1956             || !specFlags.CanReturn_NonStart()
   1957             || (mode.MaxStartOffset_Defined && (UInt64)Offset > mode.MaxStartOffset))
   1958           continue;
   1959       }
   1960       if (thereIsTail)
   1961       {
   1962         if (Offset > 0)
   1963         {
   1964           if (!specFlags.CanReturnMid)
   1965             continue;
   1966         }
   1967         else if (!specFlags.CanReturnFrontal)
   1968           continue;
   1969       }
   1970 
   1971       if (Offset > 0 || thereIsTail)
   1972       {
   1973         if (formatIndex < 0)
   1974         {
   1975           if (IsPreArcFormat(ai))
   1976           {
   1977             // openOnlyFullArc = false;
   1978             // canReturnTailArc = true;
   1979             /*
   1980             if (mode.SkipSfxStub)
   1981             limitSignatureSearch = true;
   1982             */
   1983             // if (mode.SkipSfxStub)
   1984             {
   1985               // skipFrontalFormat[FormatIndex] = true;
   1986               continue;
   1987             }
   1988           }
   1989         }
   1990       }
   1991 
   1992       #endif
   1993 
   1994       Archive = archive;
   1995       return S_OK;
   1996     }
   1997   }
   1998 
   1999 
   2000 
   2001   #ifndef _SFX
   2002 
   2003   if (!op.stream)
   2004     return S_FALSE;
   2005 
   2006   if (formatIndex >= 0 && !mode.CanReturnParser)
   2007   {
   2008     if (mode.MaxStartOffset_Defined)
   2009     {
   2010       if (mode.MaxStartOffset == 0)
   2011         return S_FALSE;
   2012     }
   2013     else
   2014     {
   2015       const CArcInfoEx &ai = op.codecs->Formats[formatIndex];
   2016       if (ai.FindExtension(extension) >= 0)
   2017       {
   2018         if (ai.Flags_FindSignature() && searchMarkerInHandler)
   2019           return S_FALSE;
   2020       }
   2021     }
   2022   }
   2023 
   2024   NArchive::NParser::CHandler *handlerSpec = new NArchive::NParser::CHandler;
   2025   CMyComPtr<IInArchive> handler = handlerSpec;
   2026 
   2027   CExtractCallback_To_OpenCallback *extractCallback_To_OpenCallback_Spec = new CExtractCallback_To_OpenCallback;
   2028   CMyComPtr<IArchiveExtractCallback> extractCallback_To_OpenCallback = extractCallback_To_OpenCallback_Spec;
   2029   extractCallback_To_OpenCallback_Spec->Init(op.callback);
   2030 
   2031   {
   2032     // ---------- Check all possible START archives ----------
   2033     // this code is better for full file archives than Parser's code.
   2034 
   2035     CByteBuffer byteBuffer;
   2036     bool endOfFile = false;
   2037     size_t processedSize;
   2038     {
   2039       size_t bufSize = 1 << 20; // it must be larger than max signature offset or IsArcFunc offset ((1 << 19) + x for UDF)
   2040       if (bufSize > fileSize)
   2041       {
   2042         bufSize = (size_t)fileSize;
   2043         endOfFile = true;
   2044       }
   2045       byteBuffer.Alloc(bufSize);
   2046       RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
   2047       processedSize = bufSize;
   2048       RINOK(ReadStream(op.stream, byteBuffer, &processedSize));
   2049       if (processedSize == 0)
   2050         return S_FALSE;
   2051       if (processedSize < bufSize)
   2052         endOfFile = true;
   2053     }
   2054     CUIntVector sortedFormats;
   2055 
   2056     unsigned i;
   2057 
   2058     int splitIndex = -1;
   2059 
   2060     for (i = 0; i < orderIndices.Size(); i++)
   2061     {
   2062       unsigned form = orderIndices[i];
   2063       if (skipFrontalFormat[form])
   2064         continue;
   2065       const CArcInfoEx &ai = op.codecs->Formats[form];
   2066       if (ai.IsSplit())
   2067       {
   2068         splitIndex = form;
   2069         continue;
   2070       }
   2071 
   2072       if (ai.IsArcFunc)
   2073       {
   2074         UInt32 isArcRes = ai.IsArcFunc(byteBuffer, processedSize);
   2075         if (isArcRes == k_IsArc_Res_NO)
   2076           continue;
   2077         if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile)
   2078           continue;
   2079         // if (isArcRes == k_IsArc_Res_YES_LOW_PROB) continue;
   2080         sortedFormats.Insert(0, form);
   2081         continue;
   2082       }
   2083 
   2084       bool isNewStyleSignature = IsNewStyleSignature(ai);
   2085       bool needCheck = !isNewStyleSignature
   2086           || ai.Signatures.IsEmpty()
   2087           || ai.Flags_PureStartOpen()
   2088           || ai.Flags_StartOpen()
   2089           || ai.Flags_BackwardOpen();
   2090 
   2091       if (isNewStyleSignature && !ai.Signatures.IsEmpty())
   2092       {
   2093         unsigned k;
   2094         for (k = 0; k < ai.Signatures.Size(); k++)
   2095         {
   2096           const CByteBuffer &sig = ai.Signatures[k];
   2097           UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size();
   2098           if (processedSize < signatureEnd)
   2099           {
   2100             if (!endOfFile)
   2101               needCheck = true;
   2102           }
   2103           else if (memcmp(sig, byteBuffer + ai.SignatureOffset, sig.Size()) == 0)
   2104             break;
   2105         }
   2106         if (k != ai.Signatures.Size())
   2107         {
   2108           sortedFormats.Insert(0, form);
   2109           continue;
   2110         }
   2111       }
   2112       if (needCheck)
   2113         sortedFormats.Add(form);
   2114     }
   2115 
   2116     if (splitIndex >= 0)
   2117       sortedFormats.Insert(0, splitIndex);
   2118 
   2119     for (i = 0; i < sortedFormats.Size(); i++)
   2120     {
   2121       FormatIndex = sortedFormats[i];
   2122       const CArcInfoEx &ai = op.codecs->Formats[FormatIndex];
   2123 
   2124       if (op.callback)
   2125         RINOK(op.callback->SetTotal(NULL, &fileSize));
   2126 
   2127       RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
   2128 
   2129       CMyComPtr<IInArchive> archive;
   2130       RINOK(PrepareToOpen(op, FormatIndex, archive));
   2131       if (!archive)
   2132         continue;
   2133 
   2134       PRF(printf("\nSorted Open %S", (const wchar_t *)ai.Name));
   2135       HRESULT result;
   2136       {
   2137         UInt64 searchLimit = 0;
   2138         /*
   2139         if (mode.CanReturnArc)
   2140           result = archive->Open(op.stream, &searchLimit, op.callback);
   2141         else
   2142         */
   2143         result = OpenArchiveSpec(archive, !mode.CanReturnArc, op.stream, &searchLimit, op.callback, extractCallback_To_OpenCallback);
   2144       }
   2145 
   2146       if (result == S_FALSE)
   2147       {
   2148         skipFrontalFormat[(unsigned)FormatIndex] = true;
   2149         // FIXME: maybe we must use LenIsUnknown.
   2150         // printf("  OpenForSize Error");
   2151         continue;
   2152       }
   2153       RINOK(result);
   2154 
   2155       RINOK(ReadBasicProps(archive, 0, result));
   2156 
   2157       if (Offset > 0)
   2158       {
   2159         continue; // good handler doesn't return such Offset > 0
   2160         // but there are some cases like false prefixed PK00 archive, when
   2161         // we can support it?
   2162       }
   2163 
   2164       NArchive::NParser::CParseItem pi;
   2165       pi.Offset = Offset;
   2166       pi.Size = AvailPhySize;
   2167 
   2168       // bool needScan = false;
   2169 
   2170       if (!PhySizeDefined)
   2171       {
   2172         // it's for Z format
   2173         pi.LenIsUnknown = true;
   2174         // needScan = true;
   2175         // phySize = arcRem;
   2176         // nextNeedCheckStartOpen = false;
   2177       }
   2178 
   2179       /*
   2180       if (OkPhySize_Defined)
   2181         pi.OkSize = pi.OkPhySize;
   2182       else
   2183         pi.OkSize = pi.Size;
   2184       */
   2185 
   2186       pi.NormalizeOffset();
   2187       // printf("  phySize = %8d", (unsigned)phySize);
   2188 
   2189 
   2190       if (mode.CanReturnArc)
   2191       {
   2192         bool isMainFormat = isMainFormatArr[(unsigned)FormatIndex];
   2193         const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt);
   2194         bool openCur = false;
   2195 
   2196         if (!ErrorInfo.ThereIsTail)
   2197           openCur = true;
   2198         else
   2199         {
   2200           if (mode.ZerosTailIsAllowed)
   2201           {
   2202             RINOK(CheckZerosTail(op, Offset + PhySize));
   2203             if (ErrorInfo.IgnoreTail)
   2204               openCur = true;
   2205           }
   2206           if (!openCur)
   2207           {
   2208             openCur = specFlags.CanReturnFrontal;
   2209             if (formatIndex < 0) // format is not forced
   2210             {
   2211               if (IsPreArcFormat(ai))
   2212               {
   2213                 // if (mode.SkipSfxStub)
   2214                 {
   2215                   openCur = false;
   2216                 }
   2217               }
   2218             }
   2219           }
   2220         }
   2221 
   2222         if (openCur)
   2223         {
   2224           InStream = op.stream;
   2225           Archive = archive;
   2226           return S_OK;
   2227         }
   2228       }
   2229 
   2230       skipFrontalFormat[(unsigned)FormatIndex] = true;
   2231 
   2232 
   2233       // if (!mode.CanReturnArc)
   2234       /*
   2235       if (!ErrorInfo.ThereIsTail)
   2236           continue;
   2237       */
   2238       if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize)
   2239         continue;
   2240 
   2241       // printf("\nAdd offset = %d", (int)pi.Offset);
   2242       RINOK(ReadParseItemProps(archive, ai, pi));
   2243       handlerSpec->AddItem(pi);
   2244     }
   2245   }
   2246 
   2247 
   2248 
   2249 
   2250 
   2251   // ---------- PARSER ----------
   2252 
   2253   CUIntVector arc2sig; // formatIndex to signatureIndex
   2254   CUIntVector sig2arc; // signatureIndex to formatIndex;
   2255   {
   2256     unsigned sum = 0;
   2257     FOR_VECTOR (i, op.codecs->Formats)
   2258     {
   2259       arc2sig.Add(sum);
   2260       const CObjectVector<CByteBuffer> &sigs = op.codecs->Formats[i].Signatures;
   2261       sum += sigs.Size();
   2262       FOR_VECTOR (k, sigs)
   2263         sig2arc.Add(i);
   2264     }
   2265   }
   2266 
   2267   {
   2268     const size_t kBeforeSize = 1 << 16;
   2269     const size_t kAfterSize  = 1 << 20;
   2270     const size_t kBufSize = 1 << 22; // it must be more than kBeforeSize + kAfterSize
   2271 
   2272     const UInt32 kNumVals = (UInt32)1 << (kNumHashBytes * 8);
   2273     CByteArr hashBuffer(kNumVals);
   2274     Byte *hash = hashBuffer;
   2275     memset(hash, 0xFF, kNumVals);
   2276     Byte prevs[256];
   2277     memset(prevs, 0xFF, sizeof(prevs));
   2278     if (sig2arc.Size() >= 0xFF)
   2279       return S_FALSE;
   2280 
   2281     CUIntVector difficultFormats;
   2282     CBoolArr difficultBools(256);
   2283     {
   2284       for (unsigned i = 0; i < 256; i++)
   2285         difficultBools[i] = false;
   2286     }
   2287 
   2288     bool thereAreHandlersForSearch = false;
   2289 
   2290     // UInt32 maxSignatureEnd = 0;
   2291 
   2292     FOR_VECTOR (i, orderIndices)
   2293     {
   2294       int index = orderIndices[i];
   2295       if (index < 0)
   2296         continue;
   2297       const CArcInfoEx &ai = op.codecs->Formats[index];
   2298       bool isDifficult = false;
   2299       // if (ai.Version < 0x91F) // we don't use parser with old DLL (before 9.31)
   2300       if (!ai.NewInterface)
   2301         isDifficult = true;
   2302       else
   2303       {
   2304         if (ai.Flags_StartOpen())
   2305           isDifficult = true;
   2306         FOR_VECTOR (k, ai.Signatures)
   2307         {
   2308           const CByteBuffer &sig = ai.Signatures[k];
   2309           /*
   2310           UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size();
   2311           if (maxSignatureEnd < signatureEnd)
   2312             maxSignatureEnd = signatureEnd;
   2313           */
   2314           if (sig.Size() < kNumHashBytes)
   2315           {
   2316             isDifficult = true;
   2317             continue;
   2318           }
   2319           thereAreHandlersForSearch = true;
   2320           UInt32 v = HASH_VAL(sig, 0);
   2321           unsigned sigIndex = arc2sig[(unsigned)index] + k;
   2322           prevs[sigIndex] = hash[v];
   2323           hash[v] = (Byte)sigIndex;
   2324         }
   2325       }
   2326       if (isDifficult)
   2327       {
   2328         difficultFormats.Add(index);
   2329         difficultBools[index] = true;
   2330       }
   2331     }
   2332 
   2333     if (!thereAreHandlersForSearch)
   2334     {
   2335       // openOnlyFullArc = true;
   2336       // canReturnTailArc = true;
   2337     }
   2338 
   2339     RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
   2340 
   2341     CLimitedCachedInStream *limitedStreamSpec = new CLimitedCachedInStream;
   2342     CMyComPtr<IInStream> limitedStream = limitedStreamSpec;
   2343     limitedStreamSpec->SetStream(op.stream);
   2344 
   2345     CArchiveOpenCallback_Offset *openCallback_Offset_Spec = NULL;
   2346     CMyComPtr<IArchiveOpenCallback> openCallback_Offset;
   2347     if (op.callback)
   2348     {
   2349       openCallback_Offset_Spec = new CArchiveOpenCallback_Offset;
   2350       openCallback_Offset = openCallback_Offset_Spec;
   2351       openCallback_Offset_Spec->Callback = op.callback;
   2352       openCallback_Offset_Spec->Callback.QueryInterface(IID_IArchiveOpenVolumeCallback, &openCallback_Offset_Spec->OpenVolumeCallback);
   2353       #ifndef _NO_CRYPTO
   2354       openCallback_Offset_Spec->Callback.QueryInterface(IID_ICryptoGetTextPassword, &openCallback_Offset_Spec->GetTextPassword);
   2355       #endif
   2356     }
   2357 
   2358     if (op.callback)
   2359       RINOK(op.callback->SetTotal(NULL, &fileSize));
   2360 
   2361     CByteBuffer &byteBuffer = limitedStreamSpec->Buffer;
   2362     byteBuffer.Alloc(kBufSize);
   2363 
   2364     UInt64 callbackPrev = 0;
   2365     bool needCheckStartOpen = true; // = true, if we need to test all archives types for current pos.
   2366 
   2367     bool endOfFile = false;
   2368     UInt64 bufPhyPos = 0;
   2369     size_t bytesInBuf = 0;
   2370     // UInt64 prevPos = 0;
   2371 
   2372     // ---------- Main Scan Loop ----------
   2373 
   2374     UInt64 pos = 0;
   2375 
   2376     if (!mode.EachPos && handlerSpec->_items.Size() == 1)
   2377     {
   2378       NArchive::NParser::CParseItem &pi = handlerSpec->_items[0];
   2379       if (!pi.LenIsUnknown && pi.Offset == 0)
   2380         pos = pi.Size;
   2381     }
   2382 
   2383     for (;;)
   2384     {
   2385       // printf("\nPos = %d", (int)pos);
   2386       UInt64 posInBuf = pos - bufPhyPos;
   2387 
   2388       // if (pos > ((UInt64)1 << 35)) break;
   2389 
   2390       if (!endOfFile)
   2391       {
   2392         if (bytesInBuf < kBufSize)
   2393         {
   2394           size_t processedSize = kBufSize - bytesInBuf;
   2395           // printf("\nRead ask = %d", (unsigned)processedSize);
   2396           UInt64 seekPos = bufPhyPos + bytesInBuf;
   2397           RINOK(op.stream->Seek(bufPhyPos + bytesInBuf, STREAM_SEEK_SET, NULL));
   2398           RINOK(ReadStream(op.stream, byteBuffer + bytesInBuf, &processedSize));
   2399           // printf("   processed = %d", (unsigned)processedSize);
   2400           if (processedSize == 0)
   2401           {
   2402             fileSize = seekPos;
   2403             endOfFile = true;
   2404           }
   2405           else
   2406           {
   2407             bytesInBuf += processedSize;
   2408             limitedStreamSpec->SetCache(processedSize, (size_t)bufPhyPos);
   2409           }
   2410           continue;
   2411         }
   2412 
   2413         if (bytesInBuf < posInBuf)
   2414         {
   2415           UInt64 skipSize = posInBuf - bytesInBuf;
   2416           if (skipSize <= kBeforeSize)
   2417           {
   2418             size_t keepSize = (size_t)(kBeforeSize - skipSize);
   2419             // printf("\nmemmove skip = %d", (int)keepSize);
   2420             memmove(byteBuffer, byteBuffer + bytesInBuf - keepSize, keepSize);
   2421             bytesInBuf = keepSize;
   2422             bufPhyPos = pos - keepSize;
   2423             continue;
   2424           }
   2425           // printf("\nSkip %d", (int)(skipSize - kBeforeSize));
   2426           // RINOK(op.stream->Seek(skipSize - kBeforeSize, STREAM_SEEK_CUR, NULL));
   2427           bytesInBuf = 0;
   2428           bufPhyPos = pos - kBeforeSize;
   2429           continue;
   2430         }
   2431 
   2432         if (bytesInBuf - posInBuf < kAfterSize)
   2433         {
   2434           size_t beg = (size_t)posInBuf - kBeforeSize;
   2435           // printf("\nmemmove for after beg = %d", (int)beg);
   2436           memmove(byteBuffer, byteBuffer + beg, bytesInBuf - beg);
   2437           bufPhyPos += beg;
   2438           bytesInBuf -= beg;
   2439           continue;
   2440         }
   2441       }
   2442 
   2443       bool useOffsetCallback = false;
   2444       if (openCallback_Offset)
   2445       {
   2446         openCallback_Offset_Spec->Files = handlerSpec->_items.Size();
   2447         openCallback_Offset_Spec->Offset = pos;
   2448 
   2449         useOffsetCallback = (!op.openType.CanReturnArc || handlerSpec->_items.Size() > 1);
   2450 
   2451         if (pos >= callbackPrev + (1 << 23))
   2452         {
   2453           RINOK(openCallback_Offset_Spec->SetCompleted(NULL, NULL));
   2454           callbackPrev = pos;
   2455         }
   2456       }
   2457 
   2458       {
   2459         UInt64 endPos = bufPhyPos + bytesInBuf;
   2460         if (fileSize < endPos)
   2461         {
   2462           FileSize = fileSize; // why ????
   2463           fileSize = endPos;
   2464         }
   2465       }
   2466 
   2467       size_t availSize = bytesInBuf - (size_t)posInBuf;
   2468       if (availSize < kNumHashBytes)
   2469         break;
   2470       size_t scanSize = availSize -
   2471           ((availSize >= kAfterSize) ? kAfterSize : kNumHashBytes);
   2472 
   2473       {
   2474         /*
   2475         UInt64 scanLimit = openOnlyFullArc ?
   2476             maxSignatureEnd :
   2477             op.openType.ScanSize + maxSignatureEnd;
   2478         */
   2479         if (!mode.CanReturnParser)
   2480         {
   2481           if (pos > maxStartOffset)
   2482             break;
   2483           UInt64 remScan = maxStartOffset - pos;
   2484           if (scanSize > remScan)
   2485             scanSize = (size_t)remScan;
   2486         }
   2487       }
   2488 
   2489       scanSize++;
   2490 
   2491       const Byte *buf = byteBuffer + (size_t)posInBuf;
   2492       size_t ppp = 0;
   2493 
   2494       if (!needCheckStartOpen)
   2495       {
   2496         for (; ppp < scanSize && hash[HASH_VAL(buf, ppp)] == 0xFF; ppp++);
   2497         pos += ppp;
   2498         if (ppp == scanSize)
   2499           continue;
   2500       }
   2501 
   2502       UInt32 v = HASH_VAL(buf, ppp);
   2503       bool nextNeedCheckStartOpen = true;
   2504       unsigned i = hash[v];
   2505       unsigned indexOfDifficult = 0;
   2506 
   2507       // ---------- Open Loop for Current Pos ----------
   2508       bool wasOpen = false;
   2509 
   2510       for (;;)
   2511       {
   2512         unsigned index;
   2513         bool isDifficult;
   2514         if (needCheckStartOpen && indexOfDifficult < difficultFormats.Size())
   2515         {
   2516           index = difficultFormats[indexOfDifficult++];
   2517           isDifficult = true;
   2518         }
   2519         else
   2520         {
   2521           if (i == 0xFF)
   2522             break;
   2523           index = sig2arc[i];
   2524           unsigned sigIndex = i - arc2sig[index];
   2525           i = prevs[i];
   2526           if (needCheckStartOpen && difficultBools[index])
   2527             continue;
   2528           const CArcInfoEx &ai = op.codecs->Formats[index];
   2529 
   2530           if (pos < ai.SignatureOffset)
   2531             continue;
   2532 
   2533           /*
   2534           if (openOnlyFullArc)
   2535             if (pos != ai.SignatureOffset)
   2536               continue;
   2537           */
   2538 
   2539           const CByteBuffer &sig = ai.Signatures[sigIndex];
   2540 
   2541           if (ppp + sig.Size() > availSize
   2542               || !TestSignature(buf + ppp, sig, sig.Size()))
   2543             continue;
   2544           // printf("\nSignature OK: %10S %8x %5d", (const wchar_t *)ai.Name, (int)pos, (int)(pos - prevPos));
   2545           // prevPos = pos;
   2546           isDifficult = false;
   2547         }
   2548 
   2549         const CArcInfoEx &ai = op.codecs->Formats[index];
   2550 
   2551 
   2552         if ((isDifficult && pos == 0) || ai.SignatureOffset == pos)
   2553         {
   2554           // we don't check same archive second time */
   2555           if (skipFrontalFormat[index])
   2556             continue;
   2557         }
   2558 
   2559         UInt64 startArcPos = pos;
   2560         if (!isDifficult)
   2561         {
   2562           if (pos < ai.SignatureOffset)
   2563             continue;
   2564           startArcPos = pos - ai.SignatureOffset;
   2565           /*
   2566           // we don't need the check for Z files
   2567           if (startArcPos < handlerSpec->GetLastEnd())
   2568             continue;
   2569           */
   2570         }
   2571 
   2572         if (ai.IsArcFunc && startArcPos >= bufPhyPos)
   2573         {
   2574           size_t offsetInBuf = (size_t)(startArcPos - bufPhyPos);
   2575           if (offsetInBuf < bytesInBuf)
   2576           {
   2577             UInt32 isArcRes = ai.IsArcFunc(byteBuffer + offsetInBuf, bytesInBuf - offsetInBuf);
   2578             if (isArcRes == k_IsArc_Res_NO)
   2579               continue;
   2580             if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile)
   2581               continue;
   2582             /*
   2583             if (isArcRes == k_IsArc_Res_YES_LOW_PROB)
   2584             {
   2585               // if (pos != ai.SignatureOffset)
   2586               continue;
   2587             }
   2588             */
   2589           }
   2590           // printf("\nIsArc OK: %S", (const wchar_t *)ai.Name);
   2591         }
   2592 
   2593         /*
   2594         if (pos == 67109888)
   2595           pos = pos;
   2596         */
   2597         PRF(printf("\npos = %9I64d : %S", pos, (const wchar_t *)ai.Name));
   2598 
   2599         bool isMainFormat = isMainFormatArr[index];
   2600         const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt);
   2601 
   2602         CMyComPtr<IInArchive> archive;
   2603         RINOK(PrepareToOpen(op, index, archive));
   2604         if (!archive)
   2605           return E_FAIL;
   2606 
   2607         // OutputDebugStringW(ai.Name);
   2608 
   2609         UInt64 rem = fileSize - startArcPos;
   2610 
   2611         UInt64 arcStreamOffset = 0;
   2612 
   2613         if (ai.Flags_UseGlobalOffset())
   2614         {
   2615           limitedStreamSpec->InitAndSeek(0, fileSize);
   2616           limitedStream->Seek(startArcPos, STREAM_SEEK_SET, NULL);
   2617         }
   2618         else
   2619         {
   2620           limitedStreamSpec->InitAndSeek(startArcPos, rem);
   2621           arcStreamOffset = startArcPos;
   2622         }
   2623 
   2624         UInt64 maxCheckStartPosition = 0;
   2625 
   2626         if (openCallback_Offset)
   2627         {
   2628           openCallback_Offset_Spec->Files = handlerSpec->_items.Size();
   2629           openCallback_Offset_Spec->Offset = startArcPos;
   2630         }
   2631 
   2632         // HRESULT result = archive->Open(limitedStream, &maxCheckStartPosition, openCallback_Offset);
   2633         extractCallback_To_OpenCallback_Spec->Files = 0;
   2634         extractCallback_To_OpenCallback_Spec->Offset = startArcPos;
   2635 
   2636         HRESULT result = OpenArchiveSpec(archive, true, limitedStream, &maxCheckStartPosition,
   2637             useOffsetCallback ? (IArchiveOpenCallback *)openCallback_Offset : (IArchiveOpenCallback *)op.callback,
   2638             extractCallback_To_OpenCallback);
   2639 
   2640         RINOK(ReadBasicProps(archive, ai.Flags_UseGlobalOffset() ? 0 : startArcPos, result));
   2641 
   2642         bool isOpen = false;
   2643         if (result == S_FALSE)
   2644         {
   2645           if (!mode.CanReturnParser)
   2646           {
   2647             if (formatIndex < 0 && ErrorInfo.IsArc_After_NonOpen())
   2648             {
   2649               ErrorInfo.ErrorFormatIndex = index;
   2650               NonOpen_ErrorInfo = ErrorInfo;
   2651               // if archive was detected, we don't need additional open attempts
   2652               return S_FALSE;
   2653             }
   2654             continue;
   2655           }
   2656           if (!ErrorInfo.IsArc_After_NonOpen() || !PhySizeDefined || PhySize == 0)
   2657             continue;
   2658         }
   2659         else
   2660         {
   2661           isOpen = true;
   2662           RINOK(result);
   2663           PRF(printf("  OK "));
   2664         }
   2665 
   2666         // fprintf(stderr, "\n %8X  %S", startArcPos, Path);
   2667         // printf("\nOpen OK: %S", ai.Name);
   2668 
   2669 
   2670         NArchive::NParser::CParseItem pi;
   2671         pi.Offset = startArcPos;
   2672 
   2673         if (ai.Flags_UseGlobalOffset())
   2674           pi.Offset = Offset;
   2675         else if (Offset != 0)
   2676           return E_FAIL;
   2677         UInt64 arcRem = FileSize - pi.Offset;
   2678         UInt64 phySize = arcRem;
   2679         bool phySizeDefined = PhySizeDefined;
   2680         if (phySizeDefined)
   2681         {
   2682           if (pi.Offset + PhySize > FileSize)
   2683           {
   2684             // ErrorInfo.ThereIsTail = true;
   2685             PhySize = FileSize - pi.Offset;
   2686           }
   2687           phySize = PhySize;
   2688         }
   2689         if (phySize == 0 || (UInt64)phySize > ((UInt64)1 << 63))
   2690           return E_FAIL;
   2691 
   2692         /*
   2693         if (!ai.UseGlobalOffset)
   2694         {
   2695           if (phySize > arcRem)
   2696           {
   2697             ThereIsTail = true;
   2698             phySize = arcRem;
   2699           }
   2700         }
   2701         */
   2702 
   2703         bool needScan = false;
   2704 
   2705 
   2706         if (isOpen && !phySizeDefined)
   2707         {
   2708           // it's for Z format
   2709           pi.LenIsUnknown = true;
   2710           needScan = true;
   2711           phySize = arcRem;
   2712           nextNeedCheckStartOpen = false;
   2713         }
   2714 
   2715         pi.Size = phySize;
   2716         /*
   2717         if (OkPhySize_Defined)
   2718           pi.OkSize = OkPhySize;
   2719         */
   2720         pi.NormalizeOffset();
   2721         // printf("  phySize = %8d", (unsigned)phySize);
   2722 
   2723         /*
   2724         if (needSkipFullArc)
   2725           if (pi.Offset == 0 && phySizeDefined && pi.Size >= fileSize)
   2726             continue;
   2727         */
   2728         if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize)
   2729         {
   2730           // it's possible for dmg archives
   2731           if (!mode.CanReturnArc)
   2732             continue;
   2733         }
   2734 
   2735         if (mode.EachPos)
   2736           pos++;
   2737         else if (needScan)
   2738         {
   2739           pos++;
   2740           /*
   2741           if (!OkPhySize_Defined)
   2742             pos++;
   2743           else
   2744             pos = pi.Offset + pi.OkSize;
   2745           */
   2746         }
   2747         else
   2748           pos = pi.Offset + pi.Size;
   2749 
   2750 
   2751         RINOK(ReadParseItemProps(archive, ai, pi));
   2752 
   2753         if (pi.Offset < startArcPos && !mode.EachPos /* && phySizeDefined */)
   2754         {
   2755           /* It's for DMG format.
   2756           This code deletes all previous items that are included to current item */
   2757 
   2758           while (!handlerSpec->_items.IsEmpty())
   2759           {
   2760             {
   2761               const NArchive::NParser::CParseItem &back = handlerSpec->_items.Back();
   2762               if (back.Offset < pi.Offset)
   2763                 break;
   2764               if (back.Offset + back.Size > pi.Offset + pi.Size)
   2765                 break;
   2766             }
   2767             handlerSpec->_items.DeleteBack();
   2768           }
   2769         }
   2770 
   2771 
   2772         if (isOpen && mode.CanReturnArc && phySizeDefined)
   2773         {
   2774           // if (pi.Offset + pi.Size >= fileSize)
   2775           bool openCur = false;
   2776 
   2777           bool thereIsTail = ErrorInfo.ThereIsTail;
   2778           if (thereIsTail && mode.ZerosTailIsAllowed)
   2779           {
   2780             RINOK(CheckZerosTail(op, arcStreamOffset + Offset + PhySize));
   2781             if (ErrorInfo.IgnoreTail)
   2782               thereIsTail = false;
   2783           }
   2784 
   2785           if (pi.Offset != 0)
   2786           {
   2787             if (!pi.IsNotArcType)
   2788               if (thereIsTail)
   2789                 openCur = specFlags.CanReturnMid;
   2790               else
   2791                 openCur = specFlags.CanReturnTail;
   2792           }
   2793           else
   2794           {
   2795             if (!thereIsTail)
   2796               openCur = true;
   2797             else
   2798               openCur = specFlags.CanReturnFrontal;
   2799 
   2800 
   2801             if (formatIndex >= -2)
   2802               openCur = true;
   2803           }
   2804           if (formatIndex < 0 && pi.IsSelfExe /* && mode.SkipSfxStub */)
   2805             openCur = false;
   2806 
   2807           // We open file as SFX, if there is front archive or first archive is "Self Executable"
   2808           if (!openCur && !pi.IsSelfExe && !thereIsTail &&
   2809               (!pi.IsNotArcType || pi.Offset == 0))
   2810           {
   2811             if (handlerSpec->_items.IsEmpty())
   2812             {
   2813               if (specFlags.CanReturnTail)
   2814                 openCur = true;
   2815             }
   2816             else if (handlerSpec->_items.Size() == 1)
   2817             {
   2818               if (handlerSpec->_items[0].IsSelfExe)
   2819               {
   2820                 if (mode.SpecUnknownExt.CanReturnTail)
   2821                   openCur = true;
   2822               }
   2823             }
   2824           }
   2825 
   2826           if (openCur)
   2827           {
   2828             InStream = op.stream;
   2829             Archive = archive;
   2830             FormatIndex = index;
   2831             ArcStreamOffset = arcStreamOffset;
   2832             return S_OK;
   2833           }
   2834         }
   2835 
   2836         /*
   2837         if (openOnlyFullArc)
   2838         {
   2839           ErrorInfo.ClearErrors();
   2840           return S_FALSE;
   2841         }
   2842         */
   2843 
   2844         pi.FormatIndex = index;
   2845 
   2846         // printf("\nAdd offset = %d", (int)pi.Offset);
   2847         handlerSpec->AddItem(pi);
   2848         wasOpen = true;
   2849         break;
   2850       }
   2851       // ---------- End of Open Loop for Current Pos ----------
   2852 
   2853       if (!wasOpen)
   2854         pos++;
   2855       needCheckStartOpen = (nextNeedCheckStartOpen && wasOpen);
   2856     }
   2857     // ---------- End of Main Scan Loop ----------
   2858 
   2859     /*
   2860     if (handlerSpec->_items.Size() == 1)
   2861     {
   2862       const NArchive::NParser::CParseItem &pi = handlerSpec->_items[0];
   2863       if (pi.Size == fileSize && pi.Offset == 0)
   2864       {
   2865         Archive = archive;
   2866         FormatIndex2 = pi.FormatIndex;
   2867         return S_OK;
   2868       }
   2869     }
   2870     */
   2871 
   2872     if (mode.CanReturnParser)
   2873     {
   2874       bool returnParser = (handlerSpec->_items.Size() == 1); // it's possible if fileSize was not correct at start of parsing
   2875       handlerSpec->AddUnknownItem(fileSize);
   2876       if (handlerSpec->_items.Size() == 0)
   2877         return S_FALSE;
   2878       if (returnParser || handlerSpec->_items.Size() != 1)
   2879       {
   2880         // return S_FALSE;
   2881         handlerSpec->_stream = op.stream;
   2882         Archive = handler;
   2883         ErrorInfo.ClearErrors();
   2884         IsParseArc = true;
   2885         FormatIndex = -1; // It's parser
   2886         Offset = 0;
   2887         return S_OK;
   2888       }
   2889     }
   2890   }
   2891 
   2892   #endif
   2893 
   2894   if (!Archive)
   2895     return S_FALSE;
   2896   return S_OK;
   2897 }
   2898 
   2899 HRESULT CArc::OpenStream(const COpenOptions &op)
   2900 {
   2901   RINOK(OpenStream2(op));
   2902   // PrintNumber("op.formatIndex 3", op.formatIndex);
   2903 
   2904   if (Archive)
   2905   {
   2906     GetRawProps.Release();
   2907     GetRootProps.Release();
   2908     Archive->QueryInterface(IID_IArchiveGetRawProps, (void **)&GetRawProps);
   2909     Archive->QueryInterface(IID_IArchiveGetRootProps, (void **)&GetRootProps);
   2910 
   2911     RINOK(Archive_GetArcBoolProp(Archive, kpidIsTree, IsTree));
   2912     RINOK(Archive_GetArcBoolProp(Archive, kpidIsDeleted, Ask_Deleted));
   2913     RINOK(Archive_GetArcBoolProp(Archive, kpidIsAltStream, Ask_AltStream));
   2914     RINOK(Archive_GetArcBoolProp(Archive, kpidIsAux, Ask_Aux));
   2915     RINOK(Archive_GetArcBoolProp(Archive, kpidINode, Ask_INode));
   2916     RINOK(Archive_GetArcBoolProp(Archive, kpidReadOnly, IsReadOnly));
   2917 
   2918     const UString fileName = ExtractFileNameFromPath(Path);
   2919     UString extension;
   2920     {
   2921       int dotPos = fileName.ReverseFind_Dot();
   2922       if (dotPos >= 0)
   2923         extension = fileName.Ptr(dotPos + 1);
   2924     }
   2925 
   2926     DefaultName.Empty();
   2927     if (FormatIndex >= 0)
   2928     {
   2929       const CArcInfoEx &ai = op.codecs->Formats[FormatIndex];
   2930       if (ai.Exts.Size() == 0)
   2931         DefaultName = GetDefaultName2(fileName, UString(), UString());
   2932       else
   2933       {
   2934         int subExtIndex = ai.FindExtension(extension);
   2935         if (subExtIndex < 0)
   2936           subExtIndex = 0;
   2937         const CArcExtInfo &extInfo = ai.Exts[subExtIndex];
   2938         DefaultName = GetDefaultName2(fileName, extInfo.Ext, extInfo.AddExt);
   2939       }
   2940     }
   2941   }
   2942 
   2943   return S_OK;
   2944 }
   2945 
   2946 #ifdef _SFX
   2947 
   2948 #ifdef _WIN32
   2949   static const char *k_ExeExt = ".exe";
   2950   static const unsigned k_ExeExt_Len = 4;
   2951 #else
   2952   static const char *k_ExeExt = "";
   2953   static const unsigned k_ExeExt_Len = 0;
   2954 #endif
   2955 
   2956 #endif
   2957 
   2958 HRESULT CArc::OpenStreamOrFile(COpenOptions &op)
   2959 {
   2960   CMyComPtr<IInStream> fileStream;
   2961   CMyComPtr<ISequentialInStream> seqStream;
   2962   CInFileStream *fileStreamSpec = NULL;
   2963 
   2964   if (op.stdInMode)
   2965   {
   2966     seqStream = new CStdInFileStream;
   2967     op.seqStream = seqStream;
   2968   }
   2969   else if (!op.stream)
   2970   {
   2971     fileStreamSpec = new CInFileStream;
   2972     fileStream = fileStreamSpec;
   2973     Path = filePath;
   2974     if (!fileStreamSpec->Open(us2fs(Path)))
   2975     {
   2976       return GetLastError();
   2977     }
   2978     op.stream = fileStream;
   2979     #ifdef _SFX
   2980     IgnoreSplit = true;
   2981     #endif
   2982   }
   2983 
   2984   /*
   2985   if (callback)
   2986   {
   2987     UInt64 fileSize;
   2988     RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize));
   2989     RINOK(op.callback->SetTotal(NULL, &fileSize))
   2990   }
   2991   */
   2992 
   2993   HRESULT res = OpenStream(op);
   2994   IgnoreSplit = false;
   2995 
   2996   #ifdef _SFX
   2997 
   2998   if (res != S_FALSE
   2999       || !fileStreamSpec
   3000       || !op.callbackSpec
   3001       || NonOpen_ErrorInfo.IsArc_After_NonOpen())
   3002     return res;
   3003 
   3004   {
   3005     if (filePath.Len() > k_ExeExt_Len
   3006         && StringsAreEqualNoCase_Ascii(filePath.RightPtr(k_ExeExt_Len), k_ExeExt))
   3007     {
   3008       const UString path2 = filePath.Left(filePath.Len() - k_ExeExt_Len);
   3009       FOR_VECTOR (i, op.codecs->Formats)
   3010       {
   3011         const CArcInfoEx &ai = op.codecs->Formats[i];
   3012         if (ai.IsSplit())
   3013           continue;
   3014         UString path3 = path2;
   3015         path3 += L'.';
   3016         path3 += ai.GetMainExt(); // "7z"  for SFX.
   3017         Path = path3;
   3018         Path.AddAscii(".001");
   3019         bool isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path));
   3020         if (!isOk)
   3021         {
   3022           Path = path3;
   3023           isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path));
   3024         }
   3025         if (isOk)
   3026         {
   3027           if (fileStreamSpec->Open(us2fs(Path)))
   3028           {
   3029             op.stream = fileStream;
   3030             NonOpen_ErrorInfo.ClearErrors_Full();
   3031             if (OpenStream(op) == S_OK)
   3032               return S_OK;
   3033           }
   3034         }
   3035       }
   3036     }
   3037   }
   3038 
   3039   #endif
   3040 
   3041   return res;
   3042 }
   3043 
   3044 void CArchiveLink::KeepModeForNextOpen()
   3045 {
   3046   for (unsigned i = Arcs.Size(); i != 0;)
   3047   {
   3048     i--;
   3049     CMyComPtr<IArchiveKeepModeForNextOpen> keep;
   3050     Arcs[i].Archive->QueryInterface(IID_IArchiveKeepModeForNextOpen, (void **)&keep);
   3051     if (keep)
   3052       keep->KeepModeForNextOpen();
   3053   }
   3054 }
   3055 
   3056 HRESULT CArchiveLink::Close()
   3057 {
   3058   for (unsigned i = Arcs.Size(); i != 0;)
   3059   {
   3060     i--;
   3061     RINOK(Arcs[i].Close());
   3062   }
   3063   IsOpen = false;
   3064   // ErrorsText.Empty();
   3065   return S_OK;
   3066 }
   3067 
   3068 void CArchiveLink::Release()
   3069 {
   3070   // NonOpenErrorFormatIndex = -1;
   3071   NonOpen_ErrorInfo.ClearErrors();
   3072   NonOpen_ArcPath.Empty();
   3073   while (!Arcs.IsEmpty())
   3074     Arcs.DeleteBack();
   3075 }
   3076 
   3077 /*
   3078 void CArchiveLink::Set_ErrorsText()
   3079 {
   3080   FOR_VECTOR(i, Arcs)
   3081   {
   3082     const CArc &arc = Arcs[i];
   3083     if (!arc.ErrorFlagsText.IsEmpty())
   3084     {
   3085       if (!ErrorsText.IsEmpty())
   3086         ErrorsText.Add_LF();
   3087       ErrorsText += GetUnicodeString(arc.ErrorFlagsText);
   3088     }
   3089     if (!arc.ErrorMessage.IsEmpty())
   3090     {
   3091       if (!ErrorsText.IsEmpty())
   3092         ErrorsText.Add_LF();
   3093       ErrorsText += arc.ErrorMessage;
   3094     }
   3095 
   3096     if (!arc.WarningMessage.IsEmpty())
   3097     {
   3098       if (!ErrorsText.IsEmpty())
   3099         ErrorsText.Add_LF();
   3100       ErrorsText += arc.WarningMessage;
   3101     }
   3102   }
   3103 }
   3104 */
   3105 
   3106 HRESULT CArchiveLink::Open(COpenOptions &op)
   3107 {
   3108   Release();
   3109   if (op.types->Size() >= 32)
   3110     return E_NOTIMPL;
   3111 
   3112   HRESULT resSpec;
   3113 
   3114   for (;;)
   3115   {
   3116     resSpec = S_OK;
   3117 
   3118     op.openType = COpenType();
   3119     if (op.types->Size() >= 1)
   3120     {
   3121       COpenType latest;
   3122       if (Arcs.Size() < op.types->Size())
   3123         latest = (*op.types)[op.types->Size() - Arcs.Size() - 1];
   3124       else
   3125       {
   3126         latest = (*op.types)[0];
   3127         if (!latest.Recursive)
   3128           break;
   3129       }
   3130       op.openType = latest;
   3131     }
   3132     else if (Arcs.Size() >= 32)
   3133       break;
   3134 
   3135     /*
   3136     op.formatIndex = -1;
   3137     if (op.types->Size() >= 1)
   3138     {
   3139       int latest;
   3140       if (Arcs.Size() < op.types->Size())
   3141         latest = (*op.types)[op.types->Size() - Arcs.Size() - 1];
   3142       else
   3143       {
   3144         latest = (*op.types)[0];
   3145         if (latest != -2 && latest != -3)
   3146           break;
   3147       }
   3148       if (latest >= 0)
   3149         op.formatIndex = latest;
   3150       else if (latest == -1 || latest == -2)
   3151       {
   3152         // default
   3153       }
   3154       else if (latest == -3)
   3155         op.formatIndex = -2;
   3156       else
   3157         op.formatIndex = latest + 2;
   3158     }
   3159     else if (Arcs.Size() >= 32)
   3160       break;
   3161     */
   3162 
   3163     if (Arcs.IsEmpty())
   3164     {
   3165       CArc arc;
   3166       arc.filePath = op.filePath;
   3167       arc.Path = op.filePath;
   3168       arc.SubfileIndex = (UInt32)(Int32)-1;
   3169       HRESULT result = arc.OpenStreamOrFile(op);
   3170       if (result != S_OK)
   3171       {
   3172         if (result == S_FALSE)
   3173         {
   3174           NonOpen_ErrorInfo = arc.NonOpen_ErrorInfo;
   3175           // NonOpenErrorFormatIndex = arc.ErrorFormatIndex;
   3176           NonOpen_ArcPath = arc.Path;
   3177         }
   3178         return result;
   3179       }
   3180       Arcs.Add(arc);
   3181       continue;
   3182     }
   3183 
   3184     // PrintNumber("op.formatIndex 11", op.formatIndex);
   3185 
   3186     const CArc &arc = Arcs.Back();
   3187 
   3188     if (op.types->Size() > Arcs.Size())
   3189       resSpec = E_NOTIMPL;
   3190 
   3191     UInt32 mainSubfile;
   3192     {
   3193       NCOM::CPropVariant prop;
   3194       RINOK(arc.Archive->GetArchiveProperty(kpidMainSubfile, &prop));
   3195       if (prop.vt == VT_UI4)
   3196         mainSubfile = prop.ulVal;
   3197       else
   3198         break;
   3199       UInt32 numItems;
   3200       RINOK(arc.Archive->GetNumberOfItems(&numItems));
   3201       if (mainSubfile >= numItems)
   3202         break;
   3203     }
   3204 
   3205 
   3206     CMyComPtr<IInArchiveGetStream> getStream;
   3207     if (arc.Archive->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream) != S_OK || !getStream)
   3208       break;
   3209 
   3210     CMyComPtr<ISequentialInStream> subSeqStream;
   3211     if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK || !subSeqStream)
   3212       break;
   3213 
   3214     CMyComPtr<IInStream> subStream;
   3215     if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK || !subStream)
   3216       break;
   3217 
   3218     CArc arc2;
   3219     RINOK(arc.GetItemPath(mainSubfile, arc2.Path));
   3220 
   3221     bool zerosTailIsAllowed;
   3222     RINOK(Archive_GetItemBoolProp(arc.Archive, mainSubfile, kpidZerosTailIsAllowed, zerosTailIsAllowed));
   3223 
   3224 
   3225     if (op.callback)
   3226     {
   3227       CMyComPtr<IArchiveOpenSetSubArchiveName> setSubArchiveName;
   3228       op.callback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName);
   3229       if (setSubArchiveName)
   3230         setSubArchiveName->SetSubArchiveName(arc2.Path);
   3231     }
   3232 
   3233     arc2.SubfileIndex = mainSubfile;
   3234 
   3235     // CIntVector incl;
   3236     CIntVector excl;
   3237 
   3238     COpenOptions op2;
   3239     #ifndef _SFX
   3240     op2.props = op.props;
   3241     #endif
   3242     op2.codecs = op.codecs;
   3243     // op2.types = &incl;
   3244     op2.openType = op.openType;
   3245     op2.openType.ZerosTailIsAllowed = zerosTailIsAllowed;
   3246     op2.excludedFormats = &excl;
   3247     op2.stdInMode = false;
   3248     op2.stream = subStream;
   3249     op2.filePath = arc2.Path;
   3250     op2.callback = op.callback;
   3251     op2.callbackSpec = op.callbackSpec;
   3252 
   3253 
   3254     HRESULT result = arc2.OpenStream(op2);
   3255     resSpec = (op.types->Size() == 0 ? S_OK : S_FALSE);
   3256     if (result == S_FALSE)
   3257     {
   3258       NonOpen_ErrorInfo = arc2.ErrorInfo;
   3259       NonOpen_ArcPath = arc2.Path;
   3260       break;
   3261     }
   3262     RINOK(result);
   3263     RINOK(arc.GetItemMTime(mainSubfile, arc2.MTime, arc2.MTimeDefined));
   3264     Arcs.Add(arc2);
   3265   }
   3266   IsOpen = !Arcs.IsEmpty();
   3267   return resSpec;
   3268 }
   3269 
   3270 HRESULT CArchiveLink::Open2(COpenOptions &op, IOpenCallbackUI *callbackUI)
   3271 {
   3272   VolumesSize = 0;
   3273   COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
   3274   CMyComPtr<IArchiveOpenCallback> callback = openCallbackSpec;
   3275   openCallbackSpec->Callback = callbackUI;
   3276 
   3277   FString prefix, name;
   3278 
   3279   if (!op.stream && !op.stdInMode)
   3280   {
   3281     NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), prefix, name);
   3282     openCallbackSpec->Init(prefix, name);
   3283   }
   3284   else
   3285   {
   3286     openCallbackSpec->SetSubArchiveName(op.filePath);
   3287   }
   3288 
   3289   op.callback = callback;
   3290   op.callbackSpec = openCallbackSpec;
   3291 
   3292   HRESULT res = Open(op);
   3293 
   3294   PasswordWasAsked = openCallbackSpec->PasswordWasAsked;
   3295   // Password = openCallbackSpec->Password;
   3296 
   3297   RINOK(res);
   3298   // VolumePaths.Add(fs2us(prefix + name));
   3299 
   3300   FOR_VECTOR (i, openCallbackSpec->FileNames_WasUsed)
   3301   {
   3302     if (openCallbackSpec->FileNames_WasUsed[i])
   3303     {
   3304       VolumePaths.Add(fs2us(prefix) + openCallbackSpec->FileNames[i]);
   3305       VolumesSize += openCallbackSpec->FileSizes[i];
   3306     }
   3307   }
   3308   // VolumesSize = openCallbackSpec->TotalSize;
   3309   return S_OK;
   3310 }
   3311 
   3312 HRESULT CArc::ReOpen(const COpenOptions &op)
   3313 {
   3314   ErrorInfo.ClearErrors();
   3315   ErrorInfo.ErrorFormatIndex = -1;
   3316 
   3317   UInt64 fileSize = 0;
   3318   if (op.stream)
   3319   {
   3320     RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize));
   3321     RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
   3322   }
   3323   FileSize = fileSize;
   3324 
   3325   CMyComPtr<IInStream> stream2;
   3326   Int64 globalOffset = GetGlobalOffset();
   3327   if (globalOffset <= 0)
   3328     stream2 = op.stream;
   3329   else
   3330   {
   3331     CTailInStream *tailStreamSpec = new CTailInStream;
   3332     stream2 = tailStreamSpec;
   3333     tailStreamSpec->Stream = op.stream;
   3334     tailStreamSpec->Offset = globalOffset;
   3335     tailStreamSpec->Init();
   3336     RINOK(tailStreamSpec->SeekToStart());
   3337   }
   3338 
   3339   // There are archives with embedded STUBs (like ZIP), so we must support signature scanning
   3340   // But for another archives we can use 0 here. So the code can be fixed !!!
   3341   UInt64 maxStartPosition = kMaxCheckStartPosition;
   3342   HRESULT res = Archive->Open(stream2, &maxStartPosition, op.callback);
   3343 
   3344   if (res == S_OK)
   3345   {
   3346     RINOK(ReadBasicProps(Archive, globalOffset, res));
   3347     ArcStreamOffset = globalOffset;
   3348     if (ArcStreamOffset != 0)
   3349       InStream = op.stream;
   3350   }
   3351   return res;
   3352 }
   3353 
   3354 HRESULT CArchiveLink::Open3(COpenOptions &op, IOpenCallbackUI *callbackUI)
   3355 {
   3356   HRESULT res = Open2(op, callbackUI);
   3357   if (callbackUI)
   3358   {
   3359     RINOK(callbackUI->Open_Finished());
   3360   }
   3361   return res;
   3362 }
   3363 
   3364 HRESULT CArchiveLink::ReOpen(COpenOptions &op)
   3365 {
   3366   if (Arcs.Size() > 1)
   3367     return E_NOTIMPL;
   3368 
   3369   CObjectVector<COpenType> inc;
   3370   CIntVector excl;
   3371 
   3372   op.types = &inc;
   3373   op.excludedFormats = &excl;
   3374   op.stdInMode = false;
   3375   op.stream = NULL;
   3376   if (Arcs.Size() == 0) // ???
   3377     return Open2(op, NULL);
   3378 
   3379   COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
   3380   CMyComPtr<IArchiveOpenCallback> openCallbackNew = openCallbackSpec;
   3381 
   3382   openCallbackSpec->Callback = NULL;
   3383   openCallbackSpec->ReOpenCallback = op.callback;
   3384   {
   3385     FString dirPrefix, fileName;
   3386     NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), dirPrefix, fileName);
   3387     openCallbackSpec->Init(dirPrefix, fileName);
   3388   }
   3389 
   3390 
   3391   CInFileStream *fileStreamSpec = new CInFileStream;
   3392   CMyComPtr<IInStream> stream(fileStreamSpec);
   3393   if (!fileStreamSpec->Open(us2fs(op.filePath)))
   3394     return GetLastError();
   3395   op.stream = stream;
   3396 
   3397   CArc &arc = Arcs[0];
   3398   HRESULT res = arc.ReOpen(op);
   3399 
   3400   PasswordWasAsked = openCallbackSpec->PasswordWasAsked;
   3401   // Password = openCallbackSpec->Password;
   3402 
   3403   IsOpen = (res == S_OK);
   3404   return res;
   3405 }
   3406 
   3407 #ifndef _SFX
   3408 
   3409 bool ParseComplexSize(const wchar_t *s, UInt64 &result)
   3410 {
   3411   result = 0;
   3412   const wchar_t *end;
   3413   UInt64 number = ConvertStringToUInt64(s, &end);
   3414   if (end == s)
   3415     return false;
   3416   if (*end == 0)
   3417   {
   3418     result = number;
   3419     return true;
   3420   }
   3421   if (end[1] != 0)
   3422     return false;
   3423   unsigned numBits;
   3424   switch (MyCharLower_Ascii(*end))
   3425   {
   3426     case 'b': result = number; return true;
   3427     case 'k': numBits = 10; break;
   3428     case 'm': numBits = 20; break;
   3429     case 'g': numBits = 30; break;
   3430     case 't': numBits = 40; break;
   3431     default: return false;
   3432   }
   3433   if (number >= ((UInt64)1 << (64 - numBits)))
   3434     return false;
   3435   result = number << numBits;
   3436   return true;
   3437 }
   3438 
   3439 static bool ParseTypeParams(const UString &s, COpenType &type)
   3440 {
   3441   if (s[0] == 0)
   3442     return true;
   3443   if (s[1] == 0)
   3444   {
   3445     switch ((unsigned)(Byte)s[0])
   3446     {
   3447       case 'e': type.EachPos = true; return true;
   3448       case 'a': type.CanReturnArc = true; return true;
   3449       case 'r': type.Recursive = true; return true;
   3450     }
   3451     return false;
   3452   }
   3453   if (s[0] == 's')
   3454   {
   3455     UInt64 result;
   3456     if (!ParseComplexSize(s.Ptr(1), result))
   3457       return false;
   3458     type.MaxStartOffset = result;
   3459     type.MaxStartOffset_Defined = true;
   3460     return true;
   3461   }
   3462 
   3463   return false;
   3464 }
   3465 
   3466 bool ParseType(CCodecs &codecs, const UString &s, COpenType &type)
   3467 {
   3468   int pos2 = s.Find(L':');
   3469 
   3470   {
   3471   UString name;
   3472   if (pos2 < 0)
   3473   {
   3474     name = s;
   3475     pos2 = s.Len();
   3476   }
   3477   else
   3478   {
   3479     name = s.Left(pos2);
   3480     pos2++;
   3481   }
   3482 
   3483   int index = codecs.FindFormatForArchiveType(name);
   3484   type.Recursive = false;
   3485 
   3486   if (index < 0)
   3487   {
   3488     if (name[0] == '*')
   3489     {
   3490       if (name[1] != 0)
   3491         return false;
   3492     }
   3493     else if (name[0] == '#')
   3494     {
   3495       if (name[1] != 0)
   3496         return false;
   3497       type.CanReturnArc = false;
   3498       type.CanReturnParser = true;
   3499     }
   3500     else
   3501       return false;
   3502   }
   3503 
   3504   type.FormatIndex = index;
   3505 
   3506   }
   3507 
   3508   for (unsigned i = pos2; i < s.Len();)
   3509   {
   3510     int next = s.Find(L':', i);
   3511     if (next < 0)
   3512       next = s.Len();
   3513     const UString name = s.Mid(i, next - i);
   3514     if (name.IsEmpty())
   3515       return false;
   3516     if (!ParseTypeParams(name, type))
   3517       return false;
   3518     i = next + 1;
   3519   }
   3520 
   3521   return true;
   3522 }
   3523 
   3524 bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> &types)
   3525 {
   3526   types.Clear();
   3527   for (unsigned pos = 0; pos < s.Len();)
   3528   {
   3529     int pos2 = s.Find(L'.', pos);
   3530     if (pos2 < 0)
   3531       pos2 = s.Len();
   3532     UString name = s.Mid(pos, pos2 - pos);
   3533     if (name.IsEmpty())
   3534       return false;
   3535     COpenType type;
   3536     if (!ParseType(codecs, name, type))
   3537       return false;
   3538     types.Add(type);
   3539     pos = pos2 + 1;
   3540   }
   3541   return true;
   3542 }
   3543 
   3544 #endif
   3545