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