tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

OpenArchive.cpp (93545B)


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