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