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 = !
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 = !
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