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