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