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