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