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