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