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