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