OpenArchive.cpp (93545B)
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 char sz[32]; 334 ConvertUInt32ToString(index + 1, sz); 335 UString s(sz); 336 if (!item.Name.IsEmpty()) 337 { 338 s += '.'; 339 s += item.Name; 340 } 341 if (!item.Extension.IsEmpty()) 342 { 343 s += '.'; 344 s += item.Extension; 345 } 346 prop = s; break; 347 } 348 case kpidSize: 349 case kpidPackSize: prop = item.Size; break; 350 case kpidOffset: prop = item.Offset; break; 351 case kpidUnpackSize: if (item.UnpackSize_Defined) prop = item.UnpackSize; break; 352 case kpidNumSubFiles: if (item.NumSubFiles_Defined) prop = item.NumSubFiles; break; 353 case kpidNumSubDirs: if (item.NumSubDirs_Defined) prop = item.NumSubDirs; break; 354 case kpidMTime: if (item.FileTime_Defined) prop = item.FileTime; break; 355 case kpidComment: if (!item.Comment.IsEmpty()) prop = item.Comment; break; 356 case kpidType: if (!item.ArcType.IsEmpty()) prop = item.ArcType; break; 357 } 358 prop.Detach(value); 359 return S_OK; 360 COM_TRY_END 361 } 362 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 += ':'; 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 += '.'; 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[(unsigned)index]; 996 if (ai.SignatureOffset != 0) 997 { 998 orderIndices2.Add(index); 999 orderIndices[i] = -1; 1000 continue; 1001 } 1002 1003 const CObjectVector<CByteBuffer> &sigs = ai.Signatures; 1004 FOR_VECTOR (k, sigs) 1005 { 1006 const CByteBuffer &sig = sigs[k]; 1007 if (sig.Size() == 0 && dataSize == 0 || 1008 sig.Size() != 0 && sig.Size() <= dataSize && 1009 TestSignature(data, sig, sig.Size())) 1010 { 1011 orderIndices2.Add(index); 1012 orderIndices[i] = -1; 1013 break; 1014 } 1015 } 1016 } 1017 } 1018 1019 #endif 1020 1021 #ifdef UNDER_CE 1022 static const unsigned kNumHashBytes = 1; 1023 #define HASH_VAL(buf) ((buf)[0]) 1024 #else 1025 static const unsigned kNumHashBytes = 2; 1026 // #define HASH_VAL(buf) ((buf)[0] | ((UInt32)(buf)[1] << 8)) 1027 #define HASH_VAL(buf) GetUi16(buf) 1028 #endif 1029 1030 1031 #ifndef _SFX 1032 1033 static bool IsExeExt(const UString &ext) 1034 { 1035 return ext.IsEqualTo_Ascii_NoCase("exe"); 1036 } 1037 1038 static const char * const k_PreArcFormats[] = 1039 { 1040 "pe" 1041 , "elf" 1042 , "macho" 1043 , "mub" 1044 , "te" 1045 }; 1046 1047 static bool IsNameFromList(const UString &s, const char * const names[], size_t num) 1048 { 1049 for (unsigned i = 0; i < num; i++) 1050 if (StringsAreEqualNoCase_Ascii(s, names[i])) 1051 return true; 1052 return false; 1053 } 1054 1055 1056 static bool IsPreArcFormat(const CArcInfoEx &ai) 1057 { 1058 if (ai.Flags_PreArc()) 1059 return true; 1060 return IsNameFromList(ai.Name, k_PreArcFormats, ARRAY_SIZE(k_PreArcFormats)); 1061 } 1062 1063 static const char * const k_Formats_with_simple_signuature[] = 1064 { 1065 "7z" 1066 , "xz" 1067 , "rar" 1068 , "bzip2" 1069 , "gzip" 1070 , "cab" 1071 , "wim" 1072 , "rpm" 1073 , "vhd" 1074 , "xar" 1075 }; 1076 1077 static bool IsNewStyleSignature(const CArcInfoEx &ai) 1078 { 1079 // if (ai.Version >= 0x91F) 1080 if (ai.NewInterface) 1081 return true; 1082 return IsNameFromList(ai.Name, k_Formats_with_simple_signuature, ARRAY_SIZE(k_Formats_with_simple_signuature)); 1083 } 1084 1085 class CArchiveOpenCallback_Offset: 1086 public IArchiveOpenCallback, 1087 public IArchiveOpenVolumeCallback, 1088 #ifndef _NO_CRYPTO 1089 public ICryptoGetTextPassword, 1090 #endif 1091 public CMyUnknownImp 1092 { 1093 public: 1094 CMyComPtr<IArchiveOpenCallback> Callback; 1095 CMyComPtr<IArchiveOpenVolumeCallback> OpenVolumeCallback; 1096 UInt64 Files; 1097 UInt64 Offset; 1098 1099 #ifndef _NO_CRYPTO 1100 CMyComPtr<ICryptoGetTextPassword> GetTextPassword; 1101 #endif 1102 1103 MY_QUERYINTERFACE_BEGIN2(IArchiveOpenCallback) 1104 MY_QUERYINTERFACE_ENTRY(IArchiveOpenVolumeCallback) 1105 #ifndef _NO_CRYPTO 1106 MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword) 1107 #endif 1108 MY_QUERYINTERFACE_END 1109 MY_ADDREF_RELEASE 1110 1111 INTERFACE_IArchiveOpenCallback(;) 1112 INTERFACE_IArchiveOpenVolumeCallback(;) 1113 #ifndef _NO_CRYPTO 1114 STDMETHOD(CryptoGetTextPassword)(BSTR *password); 1115 #endif 1116 }; 1117 1118 #ifndef _NO_CRYPTO 1119 STDMETHODIMP CArchiveOpenCallback_Offset::CryptoGetTextPassword(BSTR *password) 1120 { 1121 COM_TRY_BEGIN 1122 if (GetTextPassword) 1123 return GetTextPassword->CryptoGetTextPassword(password); 1124 return E_NOTIMPL; 1125 COM_TRY_END 1126 } 1127 #endif 1128 1129 STDMETHODIMP CArchiveOpenCallback_Offset::SetTotal(const UInt64 *, const UInt64 *) 1130 { 1131 return S_OK; 1132 } 1133 1134 STDMETHODIMP CArchiveOpenCallback_Offset::SetCompleted(const UInt64 *, const UInt64 *bytes) 1135 { 1136 if (!Callback) 1137 return S_OK; 1138 UInt64 value = Offset; 1139 if (bytes) 1140 value += *bytes; 1141 return Callback->SetCompleted(&Files, &value); 1142 } 1143 1144 STDMETHODIMP CArchiveOpenCallback_Offset::GetProperty(PROPID propID, PROPVARIANT *value) 1145 { 1146 if (OpenVolumeCallback) 1147 return OpenVolumeCallback->GetProperty(propID, value); 1148 NCOM::PropVariant_Clear(value); 1149 return S_OK; 1150 // return E_NOTIMPL; 1151 } 1152 1153 STDMETHODIMP CArchiveOpenCallback_Offset::GetStream(const wchar_t *name, IInStream **inStream) 1154 { 1155 if (OpenVolumeCallback) 1156 return OpenVolumeCallback->GetStream(name, inStream); 1157 return S_FALSE; 1158 } 1159 1160 #endif 1161 1162 1163 UInt32 GetOpenArcErrorFlags(const NCOM::CPropVariant &prop, bool *isDefinedProp) 1164 { 1165 if (isDefinedProp != NULL) 1166 *isDefinedProp = false; 1167 1168 switch (prop.vt) 1169 { 1170 case VT_UI8: if (isDefinedProp) *isDefinedProp = true; return (UInt32)prop.uhVal.QuadPart; 1171 case VT_UI4: if (isDefinedProp) *isDefinedProp = true; return prop.ulVal; 1172 case VT_EMPTY: return 0; 1173 default: throw 151199; 1174 } 1175 } 1176 1177 void CArcErrorInfo::ClearErrors() 1178 { 1179 // ErrorFormatIndex = -1; // we don't need to clear ErrorFormatIndex here !!! 1180 1181 ThereIsTail = false; 1182 UnexpecedEnd = false; 1183 IgnoreTail = false; 1184 // NonZerosTail = false; 1185 ErrorFlags_Defined = false; 1186 ErrorFlags = 0; 1187 WarningFlags = 0; 1188 TailSize = 0; 1189 1190 ErrorMessage.Empty(); 1191 WarningMessage.Empty(); 1192 } 1193 1194 HRESULT CArc::ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes) 1195 { 1196 // OkPhySize_Defined = false; 1197 PhySizeDefined = false; 1198 PhySize = 0; 1199 Offset = 0; 1200 AvailPhySize = FileSize - startPos; 1201 1202 ErrorInfo.ClearErrors(); 1203 { 1204 NCOM::CPropVariant prop; 1205 RINOK(archive->GetArchiveProperty(kpidErrorFlags, &prop)); 1206 ErrorInfo.ErrorFlags = GetOpenArcErrorFlags(prop, &ErrorInfo.ErrorFlags_Defined); 1207 } 1208 { 1209 NCOM::CPropVariant prop; 1210 RINOK(archive->GetArchiveProperty(kpidWarningFlags, &prop)); 1211 ErrorInfo.WarningFlags = GetOpenArcErrorFlags(prop); 1212 } 1213 1214 { 1215 NCOM::CPropVariant prop; 1216 RINOK(archive->GetArchiveProperty(kpidError, &prop)); 1217 if (prop.vt != VT_EMPTY) 1218 ErrorInfo.ErrorMessage = (prop.vt == VT_BSTR ? prop.bstrVal : L"Unknown error"); 1219 } 1220 1221 { 1222 NCOM::CPropVariant prop; 1223 RINOK(archive->GetArchiveProperty(kpidWarning, &prop)); 1224 if (prop.vt != VT_EMPTY) 1225 ErrorInfo.WarningMessage = (prop.vt == VT_BSTR ? prop.bstrVal : L"Unknown warning"); 1226 } 1227 1228 if (openRes == S_OK || ErrorInfo.IsArc_After_NonOpen()) 1229 { 1230 RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, PhySize, PhySizeDefined)); 1231 /* 1232 RINOK(Archive_GetArcProp_UInt(archive, kpidOkPhySize, OkPhySize, OkPhySize_Defined)); 1233 if (!OkPhySize_Defined) 1234 { 1235 OkPhySize_Defined = PhySizeDefined; 1236 OkPhySize = PhySize; 1237 } 1238 */ 1239 1240 bool offsetDefined; 1241 RINOK(Archive_GetArcProp_Int(archive, kpidOffset, Offset, offsetDefined)); 1242 1243 Int64 globalOffset = startPos + Offset; 1244 AvailPhySize = FileSize - globalOffset; 1245 if (PhySizeDefined) 1246 { 1247 UInt64 endPos = globalOffset + PhySize; 1248 if (endPos < FileSize) 1249 { 1250 AvailPhySize = PhySize; 1251 ErrorInfo.ThereIsTail = true; 1252 ErrorInfo.TailSize = FileSize - endPos; 1253 } 1254 else if (endPos > FileSize) 1255 ErrorInfo.UnexpecedEnd = true; 1256 } 1257 } 1258 1259 return S_OK; 1260 } 1261 1262 /* 1263 static PrintNumber(const char *s, int n) 1264 { 1265 char temp[100]; 1266 sprintf(temp, "%s %d", s, n); 1267 OutputDebugStringA(temp); 1268 } 1269 */ 1270 1271 HRESULT CArc::PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr<IInArchive> &archive) 1272 { 1273 // OutputDebugStringA("a1"); 1274 // PrintNumber("formatIndex", formatIndex); 1275 1276 RINOK(op.codecs->CreateInArchive(formatIndex, archive)); 1277 // OutputDebugStringA("a2"); 1278 if (!archive) 1279 return S_OK; 1280 1281 #ifdef EXTERNAL_CODECS 1282 if (op.codecs->NeedSetLibCodecs) 1283 { 1284 const CArcInfoEx &ai = op.codecs->Formats[formatIndex]; 1285 if (ai.LibIndex >= 0 ? 1286 !op.codecs->Libs[ai.LibIndex].SetCodecs : 1287 !op.codecs->Libs.IsEmpty()) 1288 { 1289 CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo; 1290 archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); 1291 if (setCompressCodecsInfo) 1292 { 1293 RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(op.codecs)); 1294 } 1295 } 1296 } 1297 #endif 1298 1299 1300 #ifndef _SFX 1301 1302 const CArcInfoEx &ai = op.codecs->Formats[formatIndex]; 1303 1304 // OutputDebugStringW(ai.Name); 1305 // OutputDebugStringA("a3"); 1306 1307 if (ai.Flags_PreArc()) 1308 { 1309 /* we notify parsers that extract executables, that they don't need 1310 to open archive, if there is tail after executable (for SFX cases) */ 1311 CMyComPtr<IArchiveAllowTail> allowTail; 1312 archive.QueryInterface(IID_IArchiveAllowTail, (void **)&allowTail); 1313 if (allowTail) 1314 allowTail->AllowTail(BoolToInt(true)); 1315 } 1316 1317 if (op.props) 1318 { 1319 /* 1320 FOR_VECTOR (y, op.props) 1321 { 1322 const COptionalOpenProperties &optProps = (*op.props)[y]; 1323 if (optProps.FormatName.IsEmpty() || optProps.FormatName.CompareNoCase(ai.Name) == 0) 1324 { 1325 RINOK(SetProperties(archive, optProps.Props)); 1326 break; 1327 } 1328 } 1329 */ 1330 RINOK(SetProperties(archive, *op.props)); 1331 } 1332 1333 #endif 1334 return S_OK; 1335 } 1336 1337 #ifndef _SFX 1338 1339 static HRESULT ReadParseItemProps(IInArchive *archive, const CArcInfoEx &ai, NArchive::NParser::CParseItem &pi) 1340 { 1341 pi.Extension = ai.GetMainExt(); 1342 pi.FileTime_Defined = false; 1343 pi.ArcType = ai.Name; 1344 1345 RINOK(Archive_GetArcBoolProp(archive, kpidIsNotArcType, pi.IsNotArcType)); 1346 1347 // RINOK(Archive_GetArcBoolProp(archive, kpidIsSelfExe, pi.IsSelfExe)); 1348 pi.IsSelfExe = ai.Flags_PreArc(); 1349 1350 { 1351 NCOM::CPropVariant prop; 1352 RINOK(archive->GetArchiveProperty(kpidMTime, &prop)); 1353 if (prop.vt == VT_FILETIME) 1354 { 1355 pi.FileTime_Defined = true; 1356 pi.FileTime = prop.filetime; 1357 } 1358 } 1359 1360 if (!pi.FileTime_Defined) 1361 { 1362 NCOM::CPropVariant prop; 1363 RINOK(archive->GetArchiveProperty(kpidCTime, &prop)); 1364 if (prop.vt == VT_FILETIME) 1365 { 1366 pi.FileTime_Defined = true; 1367 pi.FileTime = prop.filetime; 1368 } 1369 } 1370 1371 { 1372 NCOM::CPropVariant prop; 1373 RINOK(archive->GetArchiveProperty(kpidName, &prop)); 1374 if (prop.vt == VT_BSTR) 1375 { 1376 pi.Name.SetFromBstr(prop.bstrVal); 1377 pi.Extension.Empty(); 1378 } 1379 else 1380 { 1381 RINOK(archive->GetArchiveProperty(kpidExtension, &prop)); 1382 if (prop.vt == VT_BSTR) 1383 pi.Extension.SetFromBstr(prop.bstrVal); 1384 } 1385 } 1386 1387 { 1388 NCOM::CPropVariant prop; 1389 RINOK(archive->GetArchiveProperty(kpidShortComment, &prop)); 1390 if (prop.vt == VT_BSTR) 1391 pi.Comment.SetFromBstr(prop.bstrVal); 1392 } 1393 1394 1395 UInt32 numItems; 1396 RINOK(archive->GetNumberOfItems(&numItems)); 1397 1398 // pi.NumSubFiles = numItems; 1399 // RINOK(Archive_GetArcProp_UInt(archive, kpidUnpackSize, pi.UnpackSize, pi.UnpackSize_Defined)); 1400 // if (!pi.UnpackSize_Defined) 1401 { 1402 pi.NumSubFiles = 0; 1403 pi.NumSubDirs = 0; 1404 pi.UnpackSize = 0; 1405 for (UInt32 i = 0; i < numItems; i++) 1406 { 1407 UInt64 size = 0; 1408 bool defined = false; 1409 Archive_GetItem_Size(archive, i, size, defined); 1410 if (defined) 1411 { 1412 pi.UnpackSize_Defined = true; 1413 pi.UnpackSize += size; 1414 } 1415 1416 bool isDir = false; 1417 Archive_IsItem_Dir(archive, i, isDir); 1418 if (isDir) 1419 pi.NumSubDirs++; 1420 else 1421 pi.NumSubFiles++; 1422 } 1423 if (pi.NumSubDirs != 0) 1424 pi.NumSubDirs_Defined = true; 1425 pi.NumSubFiles_Defined = true; 1426 } 1427 1428 return S_OK; 1429 } 1430 1431 #endif 1432 1433 HRESULT CArc::CheckZerosTail(const COpenOptions &op, UInt64 offset) 1434 { 1435 if (!op.stream) 1436 return S_OK; 1437 RINOK(op.stream->Seek(offset, STREAM_SEEK_SET, NULL)); 1438 const UInt32 kBufSize = 1 << 11; 1439 Byte buf[kBufSize]; 1440 1441 for (;;) 1442 { 1443 UInt32 processed = 0; 1444 RINOK(op.stream->Read(buf, kBufSize, &processed)); 1445 if (processed == 0) 1446 { 1447 // ErrorInfo.NonZerosTail = false; 1448 ErrorInfo.IgnoreTail = true; 1449 return S_OK; 1450 } 1451 for (size_t i = 0; i < processed; i++) 1452 { 1453 if (buf[i] != 0) 1454 { 1455 // ErrorInfo.IgnoreTail = false; 1456 // ErrorInfo.NonZerosTail = true; 1457 return S_OK; 1458 } 1459 } 1460 } 1461 } 1462 1463 #ifndef _SFX 1464 1465 class CExtractCallback_To_OpenCallback: 1466 public IArchiveExtractCallback, 1467 public ICompressProgressInfo, 1468 public CMyUnknownImp 1469 { 1470 public: 1471 CMyComPtr<IArchiveOpenCallback> Callback; 1472 UInt64 Files; 1473 UInt64 Offset; 1474 1475 MY_UNKNOWN_IMP2(IArchiveExtractCallback, ICompressProgressInfo) 1476 INTERFACE_IArchiveExtractCallback(;) 1477 STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); 1478 void Init(IArchiveOpenCallback *callback) 1479 { 1480 Callback = callback; 1481 Files = 0; 1482 Offset = 0; 1483 } 1484 }; 1485 1486 STDMETHODIMP CExtractCallback_To_OpenCallback::SetTotal(UInt64 /* size */) 1487 { 1488 return S_OK; 1489 } 1490 1491 STDMETHODIMP CExtractCallback_To_OpenCallback::SetCompleted(const UInt64 * /* completeValue */) 1492 { 1493 return S_OK; 1494 } 1495 1496 STDMETHODIMP CExtractCallback_To_OpenCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */) 1497 { 1498 if (Callback) 1499 { 1500 UInt64 value = Offset; 1501 if (inSize) 1502 value += *inSize; 1503 return Callback->SetCompleted(&Files, &value); 1504 } 1505 return S_OK; 1506 } 1507 1508 STDMETHODIMP CExtractCallback_To_OpenCallback::GetStream(UInt32 /* index */, ISequentialOutStream **outStream, Int32 /* askExtractMode */) 1509 { 1510 *outStream = 0; 1511 return S_OK; 1512 } 1513 1514 STDMETHODIMP CExtractCallback_To_OpenCallback::PrepareOperation(Int32 /* askExtractMode */) 1515 { 1516 return S_OK; 1517 } 1518 1519 STDMETHODIMP CExtractCallback_To_OpenCallback::SetOperationResult(Int32 /* operationResult */) 1520 { 1521 return S_OK; 1522 } 1523 1524 static HRESULT OpenArchiveSpec(IInArchive *archive, bool needPhySize, 1525 IInStream *stream, const UInt64 *maxCheckStartPosition, 1526 IArchiveOpenCallback *openCallback, 1527 IArchiveExtractCallback *extractCallback) 1528 { 1529 /* 1530 if (needPhySize) 1531 { 1532 CMyComPtr<IArchiveOpen2> open2; 1533 archive->QueryInterface(IID_IArchiveOpen2, (void **)&open2); 1534 if (open2) 1535 return open2->ArcOpen2(stream, kOpenFlags_RealPhySize, openCallback); 1536 } 1537 */ 1538 RINOK(archive->Open(stream, maxCheckStartPosition, openCallback)); 1539 if (needPhySize) 1540 { 1541 bool phySize_Defined = false; 1542 UInt64 phySize = 0; 1543 RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, phySize, phySize_Defined)); 1544 if (phySize_Defined) 1545 return S_OK; 1546 1547 bool phySizeCantBeDetected = false;; 1548 RINOK(Archive_GetArcBoolProp(archive, kpidPhySizeCantBeDetected, phySizeCantBeDetected)); 1549 1550 if (!phySizeCantBeDetected) 1551 { 1552 RINOK(archive->Extract(0, (UInt32)(Int32)-1, BoolToInt(true), extractCallback)); 1553 } 1554 } 1555 return S_OK; 1556 } 1557 1558 static int FindFormatForArchiveType(CCodecs *codecs, CIntVector orderIndices, const char *name) 1559 { 1560 FOR_VECTOR (i, orderIndices) 1561 if (StringsAreEqualNoCase_Ascii(codecs->Formats[orderIndices[i]].Name, name)) 1562 return i; 1563 return -1; 1564 } 1565 1566 #endif 1567 1568 HRESULT CArc::OpenStream2(const COpenOptions &op) 1569 { 1570 // fprintf(stdout, "\nOpen: %S", Path); fflush(stdout); 1571 1572 Archive.Release(); 1573 GetRawProps.Release(); 1574 GetRootProps.Release(); 1575 1576 ErrorInfo.ClearErrors(); 1577 ErrorInfo.ErrorFormatIndex = -1; 1578 1579 IsParseArc = false; 1580 ArcStreamOffset = 0; 1581 1582 // OutputDebugStringA("1"); 1583 // OutputDebugStringW(Path); 1584 1585 const UString fileName = ExtractFileNameFromPath(Path); 1586 UString extension; 1587 { 1588 int dotPos = fileName.ReverseFind_Dot(); 1589 if (dotPos >= 0) 1590 extension = fileName.Ptr(dotPos + 1); 1591 } 1592 1593 CIntVector orderIndices; 1594 1595 bool searchMarkerInHandler = false; 1596 #ifdef _SFX 1597 searchMarkerInHandler = true; 1598 #endif 1599 1600 CBoolArr isMainFormatArr(op.codecs->Formats.Size()); 1601 { 1602 FOR_VECTOR(i, op.codecs->Formats) 1603 isMainFormatArr[i] = false; 1604 } 1605 1606 UInt64 maxStartOffset = 1607 op.openType.MaxStartOffset_Defined ? 1608 op.openType.MaxStartOffset : 1609 kMaxCheckStartPosition; 1610 1611 #ifndef _SFX 1612 bool isUnknownExt = false; 1613 #endif 1614 1615 bool isForced = false; 1616 unsigned numMainTypes = 0; 1617 int formatIndex = op.openType.FormatIndex; 1618 1619 if (formatIndex >= 0) 1620 { 1621 isForced = true; 1622 orderIndices.Add(formatIndex); 1623 numMainTypes = 1; 1624 isMainFormatArr[(unsigned)formatIndex] = true; 1625 1626 searchMarkerInHandler = true; 1627 } 1628 else 1629 { 1630 unsigned numFinded = 0; 1631 #ifndef _SFX 1632 bool isPrearcExt = false; 1633 #endif 1634 1635 { 1636 #ifndef _SFX 1637 1638 bool isZip = false; 1639 bool isRar = false; 1640 1641 const wchar_t c = extension[0]; 1642 if (c == 'z' || c == 'Z' || c == 'r' || c == 'R') 1643 { 1644 bool isNumber = false; 1645 for (unsigned k = 1;; k++) 1646 { 1647 const wchar_t d = extension[k]; 1648 if (d == 0) 1649 break; 1650 if (d < '0' || d > '9') 1651 { 1652 isNumber = false; 1653 break; 1654 } 1655 isNumber = true; 1656 } 1657 if (isNumber) 1658 if (c == 'z' || c == 'Z') 1659 isZip = true; 1660 else 1661 isRar = true; 1662 } 1663 1664 #endif 1665 1666 FOR_VECTOR (i, op.codecs->Formats) 1667 { 1668 const CArcInfoEx &ai = op.codecs->Formats[i]; 1669 1670 if (IgnoreSplit || !op.openType.CanReturnArc) 1671 if (ai.IsSplit()) 1672 continue; 1673 if (op.excludedFormats->FindInSorted(i) >= 0) 1674 continue; 1675 1676 #ifndef _SFX 1677 if (IsPreArcFormat(ai)) 1678 isPrearcExt = true; 1679 #endif 1680 1681 if (ai.FindExtension(extension) >= 0 1682 #ifndef _SFX 1683 || isZip && StringsAreEqualNoCase_Ascii(ai.Name, "zip") 1684 || isRar && StringsAreEqualNoCase_Ascii(ai.Name, "rar") 1685 #endif 1686 ) 1687 { 1688 // PrintNumber("orderIndices.Insert", i); 1689 orderIndices.Insert(numFinded++, i); 1690 isMainFormatArr[i] = true; 1691 } 1692 else 1693 orderIndices.Add(i); 1694 } 1695 } 1696 1697 if (!op.stream) 1698 { 1699 if (numFinded != 1) 1700 return E_NOTIMPL; 1701 orderIndices.DeleteFrom(1); 1702 } 1703 // PrintNumber("numFinded", numFinded ); 1704 1705 /* 1706 if (op.openOnlySpecifiedByExtension) 1707 { 1708 if (numFinded != 0 && !IsExeExt(extension)) 1709 orderIndices.DeleteFrom(numFinded); 1710 } 1711 */ 1712 1713 #ifndef _SFX 1714 1715 if (op.stream && orderIndices.Size() >= 2) 1716 { 1717 RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); 1718 CByteBuffer byteBuffer; 1719 CIntVector orderIndices2; 1720 if (numFinded == 0 || IsExeExt(extension)) 1721 { 1722 // signature search was here 1723 } 1724 else if (extension.IsEqualTo("000") || extension.IsEqualTo("001")) 1725 { 1726 int i = FindFormatForArchiveType(op.codecs, orderIndices, "rar"); 1727 if (i >= 0) 1728 { 1729 const size_t kBufSize = (1 << 10); 1730 byteBuffer.Alloc(kBufSize); 1731 size_t processedSize = kBufSize; 1732 RINOK(ReadStream(op.stream, byteBuffer, &processedSize)); 1733 if (processedSize >= 16) 1734 { 1735 const Byte *buf = byteBuffer; 1736 const Byte kRarHeader[] = { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 }; 1737 if (TestSignature(buf, kRarHeader, 7) && buf[9] == 0x73 && (buf[10] & 1) != 0) 1738 { 1739 orderIndices2.Add(orderIndices[i]); 1740 orderIndices[i] = -1; 1741 if (i >= (int)numFinded) 1742 numFinded++; 1743 } 1744 } 1745 } 1746 } 1747 else 1748 { 1749 const size_t kBufSize = (1 << 10); 1750 byteBuffer.Alloc(kBufSize); 1751 size_t processedSize = kBufSize; 1752 RINOK(ReadStream(op.stream, byteBuffer, &processedSize)); 1753 if (processedSize == 0) 1754 return S_FALSE; 1755 1756 /* 1757 check type order: 1758 1) matched extension, no signuature 1759 2) matched extension, matched signuature 1760 // 3) no signuature 1761 // 4) matched signuature 1762 */ 1763 1764 MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, NULL, 0); 1765 MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, byteBuffer, processedSize); 1766 // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, NULL, 0); 1767 // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, byteBuffer, processedSize); 1768 } 1769 1770 FOR_VECTOR (i, orderIndices) 1771 { 1772 int val = orderIndices[i]; 1773 if (val != -1) 1774 orderIndices2.Add(val); 1775 } 1776 orderIndices = orderIndices2; 1777 } 1778 1779 if (orderIndices.Size() >= 2) 1780 { 1781 int iIso = FindFormatForArchiveType(op.codecs, orderIndices, "iso"); 1782 int iUdf = FindFormatForArchiveType(op.codecs, orderIndices, "udf"); 1783 if (iUdf > iIso && iIso >= 0) 1784 { 1785 int isoIndex = orderIndices[iIso]; 1786 int udfIndex = orderIndices[iUdf]; 1787 orderIndices[iUdf] = isoIndex; 1788 orderIndices[iIso] = udfIndex; 1789 } 1790 } 1791 1792 numMainTypes = numFinded; 1793 isUnknownExt = (numMainTypes == 0) || isPrearcExt; 1794 1795 #else // _SFX 1796 1797 numMainTypes = orderIndices.Size(); 1798 1799 // we need correct numMainTypes for mutlivolume SFX (if some volume is missing) 1800 if (numFinded != 0) 1801 numMainTypes = numFinded; 1802 1803 #endif 1804 } 1805 1806 UInt64 fileSize = 0; 1807 if (op.stream) 1808 { 1809 RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize)); 1810 RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); 1811 } 1812 FileSize = fileSize; 1813 1814 1815 #ifndef _SFX 1816 1817 CBoolArr skipFrontalFormat(op.codecs->Formats.Size()); 1818 { 1819 FOR_VECTOR(i, op.codecs->Formats) 1820 skipFrontalFormat[i] = false; 1821 } 1822 1823 #endif 1824 1825 const COpenType &mode = op.openType; 1826 1827 1828 1829 1830 1831 if (mode.CanReturnArc) 1832 { 1833 // ---------- OPEN main type by extenssion ---------- 1834 1835 unsigned numCheckTypes = orderIndices.Size(); 1836 if (formatIndex >= 0) 1837 numCheckTypes = numMainTypes; 1838 1839 for (unsigned i = 0; i < numCheckTypes; i++) 1840 { 1841 FormatIndex = orderIndices[i]; 1842 1843 bool exactOnly = false; 1844 1845 #ifndef _SFX 1846 1847 const CArcInfoEx &ai = op.codecs->Formats[FormatIndex]; 1848 // OutputDebugStringW(ai.Name); 1849 if (i >= numMainTypes) 1850 { 1851 if (!ai.Flags_BackwardOpen() 1852 // && !ai.Flags_PureStartOpen() 1853 ) 1854 continue; 1855 exactOnly = true; 1856 } 1857 1858 #endif 1859 1860 // Some handlers do not set total bytes. So we set it here 1861 if (op.callback) 1862 RINOK(op.callback->SetTotal(NULL, &fileSize)); 1863 1864 if (op.stream) 1865 { 1866 RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); 1867 } 1868 1869 CMyComPtr<IInArchive> archive; 1870 1871 RINOK(PrepareToOpen(op, FormatIndex, archive)); 1872 if (!archive) 1873 continue; 1874 1875 HRESULT result; 1876 if (op.stream) 1877 { 1878 UInt64 searchLimit = (!exactOnly && searchMarkerInHandler) ? maxStartOffset: 0; 1879 result = archive->Open(op.stream, &searchLimit, op.callback); 1880 } 1881 else 1882 { 1883 CMyComPtr<IArchiveOpenSeq> openSeq; 1884 archive.QueryInterface(IID_IArchiveOpenSeq, (void **)&openSeq); 1885 if (!openSeq) 1886 return E_NOTIMPL; 1887 result = openSeq->OpenSeq(op.seqStream); 1888 } 1889 1890 RINOK(ReadBasicProps(archive, 0, result)); 1891 1892 if (result == S_FALSE) 1893 { 1894 bool isArc = ErrorInfo.IsArc_After_NonOpen(); 1895 1896 #ifndef _SFX 1897 // if it's archive, we allow another open attempt for parser 1898 if (!mode.CanReturnParser || !isArc) 1899 skipFrontalFormat[(unsigned)FormatIndex] = true; 1900 #endif 1901 1902 if (exactOnly) 1903 continue; 1904 1905 if (i == 0 && numMainTypes == 1) 1906 { 1907 // we set NonOpenErrorInfo, only if there is only one main format (defined by extension). 1908 ErrorInfo.ErrorFormatIndex = FormatIndex; 1909 NonOpen_ErrorInfo = ErrorInfo; 1910 1911 if (!mode.CanReturnParser && isArc) 1912 { 1913 // if (formatIndex < 0 && !searchMarkerInHandler) 1914 { 1915 // if bad archive was detected, we don't need additional open attempts 1916 #ifndef _SFX 1917 if (!IsPreArcFormat(ai) /* || !mode.SkipSfxStub */) 1918 #endif 1919 return S_FALSE; 1920 } 1921 } 1922 } 1923 1924 /* 1925 #ifndef _SFX 1926 if (IsExeExt(extension) || ai.Flags_PreArc()) 1927 { 1928 // openOnlyFullArc = false; 1929 // canReturnTailArc = true; 1930 // limitSignatureSearch = true; 1931 } 1932 #endif 1933 */ 1934 1935 continue; 1936 } 1937 1938 RINOK(result); 1939 1940 #ifndef _SFX 1941 1942 bool isMainFormat = isMainFormatArr[(unsigned)FormatIndex]; 1943 const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); 1944 1945 bool thereIsTail = ErrorInfo.ThereIsTail; 1946 if (thereIsTail && mode.ZerosTailIsAllowed) 1947 { 1948 RINOK(CheckZerosTail(op, Offset + PhySize)); 1949 if (ErrorInfo.IgnoreTail) 1950 thereIsTail = false; 1951 } 1952 1953 if (Offset > 0) 1954 { 1955 if (exactOnly 1956 || !searchMarkerInHandler 1957 || !specFlags.CanReturn_NonStart() 1958 || (mode.MaxStartOffset_Defined && (UInt64)Offset > mode.MaxStartOffset)) 1959 continue; 1960 } 1961 if (thereIsTail) 1962 { 1963 if (Offset > 0) 1964 { 1965 if (!specFlags.CanReturnMid) 1966 continue; 1967 } 1968 else if (!specFlags.CanReturnFrontal) 1969 continue; 1970 } 1971 1972 if (Offset > 0 || thereIsTail) 1973 { 1974 if (formatIndex < 0) 1975 { 1976 if (IsPreArcFormat(ai)) 1977 { 1978 // openOnlyFullArc = false; 1979 // canReturnTailArc = true; 1980 /* 1981 if (mode.SkipSfxStub) 1982 limitSignatureSearch = true; 1983 */ 1984 // if (mode.SkipSfxStub) 1985 { 1986 // skipFrontalFormat[FormatIndex] = true; 1987 continue; 1988 } 1989 } 1990 } 1991 } 1992 1993 #endif 1994 1995 Archive = archive; 1996 return S_OK; 1997 } 1998 } 1999 2000 2001 2002 #ifndef _SFX 2003 2004 if (!op.stream) 2005 return S_FALSE; 2006 2007 if (formatIndex >= 0 && !mode.CanReturnParser) 2008 { 2009 if (mode.MaxStartOffset_Defined) 2010 { 2011 if (mode.MaxStartOffset == 0) 2012 return S_FALSE; 2013 } 2014 else 2015 { 2016 const CArcInfoEx &ai = op.codecs->Formats[formatIndex]; 2017 if (ai.FindExtension(extension) >= 0) 2018 { 2019 if (ai.Flags_FindSignature() && searchMarkerInHandler) 2020 return S_FALSE; 2021 } 2022 } 2023 } 2024 2025 NArchive::NParser::CHandler *handlerSpec = new NArchive::NParser::CHandler; 2026 CMyComPtr<IInArchive> handler = handlerSpec; 2027 2028 CExtractCallback_To_OpenCallback *extractCallback_To_OpenCallback_Spec = new CExtractCallback_To_OpenCallback; 2029 CMyComPtr<IArchiveExtractCallback> extractCallback_To_OpenCallback = extractCallback_To_OpenCallback_Spec; 2030 extractCallback_To_OpenCallback_Spec->Init(op.callback); 2031 2032 { 2033 // ---------- Check all possible START archives ---------- 2034 // this code is better for full file archives than Parser's code. 2035 2036 CByteBuffer byteBuffer; 2037 bool endOfFile = false; 2038 size_t processedSize; 2039 { 2040 size_t bufSize = 1 << 20; // it must be larger than max signature offset or IsArcFunc offset ((1 << 19) + x for UDF) 2041 if (bufSize > fileSize) 2042 { 2043 bufSize = (size_t)fileSize; 2044 endOfFile = true; 2045 } 2046 byteBuffer.Alloc(bufSize); 2047 RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); 2048 processedSize = bufSize; 2049 RINOK(ReadStream(op.stream, byteBuffer, &processedSize)); 2050 if (processedSize == 0) 2051 return S_FALSE; 2052 if (processedSize < bufSize) 2053 endOfFile = true; 2054 } 2055 CUIntVector sortedFormats; 2056 2057 unsigned i; 2058 2059 int splitIndex = -1; 2060 2061 for (i = 0; i < orderIndices.Size(); i++) 2062 { 2063 unsigned form = orderIndices[i]; 2064 if (skipFrontalFormat[form]) 2065 continue; 2066 const CArcInfoEx &ai = op.codecs->Formats[form]; 2067 if (ai.IsSplit()) 2068 { 2069 splitIndex = form; 2070 continue; 2071 } 2072 2073 if (ai.IsArcFunc) 2074 { 2075 UInt32 isArcRes = ai.IsArcFunc(byteBuffer, processedSize); 2076 if (isArcRes == k_IsArc_Res_NO) 2077 continue; 2078 if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile) 2079 continue; 2080 // if (isArcRes == k_IsArc_Res_YES_LOW_PROB) continue; 2081 sortedFormats.Insert(0, form); 2082 continue; 2083 } 2084 2085 bool isNewStyleSignature = IsNewStyleSignature(ai); 2086 bool needCheck = !isNewStyleSignature 2087 || ai.Signatures.IsEmpty() 2088 || ai.Flags_PureStartOpen() 2089 || ai.Flags_StartOpen() 2090 || ai.Flags_BackwardOpen(); 2091 2092 if (isNewStyleSignature && !ai.Signatures.IsEmpty()) 2093 { 2094 unsigned k; 2095 for (k = 0; k < ai.Signatures.Size(); k++) 2096 { 2097 const CByteBuffer &sig = ai.Signatures[k]; 2098 UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size(); 2099 if (processedSize < signatureEnd) 2100 { 2101 if (!endOfFile) 2102 needCheck = true; 2103 } 2104 else if (memcmp(sig, byteBuffer + ai.SignatureOffset, sig.Size()) == 0) 2105 break; 2106 } 2107 if (k != ai.Signatures.Size()) 2108 { 2109 sortedFormats.Insert(0, form); 2110 continue; 2111 } 2112 } 2113 if (needCheck) 2114 sortedFormats.Add(form); 2115 } 2116 2117 if (splitIndex >= 0) 2118 sortedFormats.Insert(0, splitIndex); 2119 2120 for (i = 0; i < sortedFormats.Size(); i++) 2121 { 2122 FormatIndex = sortedFormats[i]; 2123 const CArcInfoEx &ai = op.codecs->Formats[FormatIndex]; 2124 2125 if (op.callback) 2126 RINOK(op.callback->SetTotal(NULL, &fileSize)); 2127 2128 RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); 2129 2130 CMyComPtr<IInArchive> archive; 2131 RINOK(PrepareToOpen(op, FormatIndex, archive)); 2132 if (!archive) 2133 continue; 2134 2135 PRF(printf("\nSorted Open %S", (const wchar_t *)ai.Name)); 2136 HRESULT result; 2137 { 2138 UInt64 searchLimit = 0; 2139 /* 2140 if (mode.CanReturnArc) 2141 result = archive->Open(op.stream, &searchLimit, op.callback); 2142 else 2143 */ 2144 result = OpenArchiveSpec(archive, !mode.CanReturnArc, op.stream, &searchLimit, op.callback, extractCallback_To_OpenCallback); 2145 } 2146 2147 if (result == S_FALSE) 2148 { 2149 skipFrontalFormat[(unsigned)FormatIndex] = true; 2150 // FIXME: maybe we must use LenIsUnknown. 2151 // printf(" OpenForSize Error"); 2152 continue; 2153 } 2154 RINOK(result); 2155 2156 RINOK(ReadBasicProps(archive, 0, result)); 2157 2158 if (Offset > 0) 2159 { 2160 continue; // good handler doesn't return such Offset > 0 2161 // but there are some cases like false prefixed PK00 archive, when 2162 // we can support it? 2163 } 2164 2165 NArchive::NParser::CParseItem pi; 2166 pi.Offset = Offset; 2167 pi.Size = AvailPhySize; 2168 2169 // bool needScan = false; 2170 2171 if (!PhySizeDefined) 2172 { 2173 // it's for Z format 2174 pi.LenIsUnknown = true; 2175 // needScan = true; 2176 // phySize = arcRem; 2177 // nextNeedCheckStartOpen = false; 2178 } 2179 2180 /* 2181 if (OkPhySize_Defined) 2182 pi.OkSize = pi.OkPhySize; 2183 else 2184 pi.OkSize = pi.Size; 2185 */ 2186 2187 pi.NormalizeOffset(); 2188 // printf(" phySize = %8d", (unsigned)phySize); 2189 2190 2191 if (mode.CanReturnArc) 2192 { 2193 bool isMainFormat = isMainFormatArr[(unsigned)FormatIndex]; 2194 const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); 2195 bool openCur = false; 2196 2197 if (!ErrorInfo.ThereIsTail) 2198 openCur = true; 2199 else 2200 { 2201 if (mode.ZerosTailIsAllowed) 2202 { 2203 RINOK(CheckZerosTail(op, Offset + PhySize)); 2204 if (ErrorInfo.IgnoreTail) 2205 openCur = true; 2206 } 2207 if (!openCur) 2208 { 2209 openCur = specFlags.CanReturnFrontal; 2210 if (formatIndex < 0) // format is not forced 2211 { 2212 if (IsPreArcFormat(ai)) 2213 { 2214 // if (mode.SkipSfxStub) 2215 { 2216 openCur = false; 2217 } 2218 } 2219 } 2220 } 2221 } 2222 2223 if (openCur) 2224 { 2225 InStream = op.stream; 2226 Archive = archive; 2227 return S_OK; 2228 } 2229 } 2230 2231 skipFrontalFormat[(unsigned)FormatIndex] = true; 2232 2233 2234 // if (!mode.CanReturnArc) 2235 /* 2236 if (!ErrorInfo.ThereIsTail) 2237 continue; 2238 */ 2239 if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize) 2240 continue; 2241 2242 // printf("\nAdd offset = %d", (int)pi.Offset); 2243 RINOK(ReadParseItemProps(archive, ai, pi)); 2244 handlerSpec->AddItem(pi); 2245 } 2246 } 2247 2248 2249 2250 2251 2252 // ---------- PARSER ---------- 2253 2254 CUIntVector arc2sig; // formatIndex to signatureIndex 2255 CUIntVector sig2arc; // signatureIndex to formatIndex; 2256 { 2257 unsigned sum = 0; 2258 FOR_VECTOR (i, op.codecs->Formats) 2259 { 2260 arc2sig.Add(sum); 2261 const CObjectVector<CByteBuffer> &sigs = op.codecs->Formats[i].Signatures; 2262 sum += sigs.Size(); 2263 FOR_VECTOR (k, sigs) 2264 sig2arc.Add(i); 2265 } 2266 } 2267 2268 { 2269 const size_t kBeforeSize = 1 << 16; 2270 const size_t kAfterSize = 1 << 20; 2271 const size_t kBufSize = 1 << 22; // it must be more than kBeforeSize + kAfterSize 2272 2273 const UInt32 kNumVals = (UInt32)1 << (kNumHashBytes * 8); 2274 CByteArr hashBuffer(kNumVals); 2275 Byte *hash = hashBuffer; 2276 memset(hash, 0xFF, kNumVals); 2277 Byte prevs[256]; 2278 memset(prevs, 0xFF, sizeof(prevs)); 2279 if (sig2arc.Size() >= 0xFF) 2280 return S_FALSE; 2281 2282 CUIntVector difficultFormats; 2283 CBoolArr difficultBools(256); 2284 { 2285 for (unsigned i = 0; i < 256; i++) 2286 difficultBools[i] = false; 2287 } 2288 2289 bool thereAreHandlersForSearch = false; 2290 2291 // UInt32 maxSignatureEnd = 0; 2292 2293 FOR_VECTOR (i, orderIndices) 2294 { 2295 int index = orderIndices[i]; 2296 if (index < 0) 2297 continue; 2298 const CArcInfoEx &ai = op.codecs->Formats[(unsigned)index]; 2299 bool isDifficult = false; 2300 // if (ai.Version < 0x91F) // we don't use parser with old DLL (before 9.31) 2301 if (!ai.NewInterface) 2302 isDifficult = true; 2303 else 2304 { 2305 if (ai.Flags_StartOpen()) 2306 isDifficult = true; 2307 FOR_VECTOR (k, ai.Signatures) 2308 { 2309 const CByteBuffer &sig = ai.Signatures[k]; 2310 /* 2311 UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size(); 2312 if (maxSignatureEnd < signatureEnd) 2313 maxSignatureEnd = signatureEnd; 2314 */ 2315 if (sig.Size() < kNumHashBytes) 2316 { 2317 isDifficult = true; 2318 continue; 2319 } 2320 thereAreHandlersForSearch = true; 2321 UInt32 v = HASH_VAL(sig); 2322 unsigned sigIndex = arc2sig[(unsigned)index] + k; 2323 prevs[sigIndex] = hash[v]; 2324 hash[v] = (Byte)sigIndex; 2325 } 2326 } 2327 if (isDifficult) 2328 { 2329 difficultFormats.Add(index); 2330 difficultBools[(unsigned)index] = true; 2331 } 2332 } 2333 2334 if (!thereAreHandlersForSearch) 2335 { 2336 // openOnlyFullArc = true; 2337 // canReturnTailArc = true; 2338 } 2339 2340 RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); 2341 2342 CLimitedCachedInStream *limitedStreamSpec = new CLimitedCachedInStream; 2343 CMyComPtr<IInStream> limitedStream = limitedStreamSpec; 2344 limitedStreamSpec->SetStream(op.stream); 2345 2346 CArchiveOpenCallback_Offset *openCallback_Offset_Spec = NULL; 2347 CMyComPtr<IArchiveOpenCallback> openCallback_Offset; 2348 if (op.callback) 2349 { 2350 openCallback_Offset_Spec = new CArchiveOpenCallback_Offset; 2351 openCallback_Offset = openCallback_Offset_Spec; 2352 openCallback_Offset_Spec->Callback = op.callback; 2353 openCallback_Offset_Spec->Callback.QueryInterface(IID_IArchiveOpenVolumeCallback, &openCallback_Offset_Spec->OpenVolumeCallback); 2354 #ifndef _NO_CRYPTO 2355 openCallback_Offset_Spec->Callback.QueryInterface(IID_ICryptoGetTextPassword, &openCallback_Offset_Spec->GetTextPassword); 2356 #endif 2357 } 2358 2359 if (op.callback) 2360 RINOK(op.callback->SetTotal(NULL, &fileSize)); 2361 2362 CByteBuffer &byteBuffer = limitedStreamSpec->Buffer; 2363 byteBuffer.Alloc(kBufSize); 2364 2365 UInt64 callbackPrev = 0; 2366 bool needCheckStartOpen = true; // = true, if we need to test all archives types for current pos. 2367 2368 bool endOfFile = false; 2369 UInt64 bufPhyPos = 0; 2370 size_t bytesInBuf = 0; 2371 // UInt64 prevPos = 0; 2372 2373 // ---------- Main Scan Loop ---------- 2374 2375 UInt64 pos = 0; 2376 2377 if (!mode.EachPos && handlerSpec->_items.Size() == 1) 2378 { 2379 NArchive::NParser::CParseItem &pi = handlerSpec->_items[0]; 2380 if (!pi.LenIsUnknown && pi.Offset == 0) 2381 pos = pi.Size; 2382 } 2383 2384 for (;;) 2385 { 2386 // printf("\nPos = %d", (int)pos); 2387 UInt64 posInBuf = pos - bufPhyPos; 2388 2389 // if (pos > ((UInt64)1 << 35)) break; 2390 2391 if (!endOfFile) 2392 { 2393 if (bytesInBuf < kBufSize) 2394 { 2395 size_t processedSize = kBufSize - bytesInBuf; 2396 // printf("\nRead ask = %d", (unsigned)processedSize); 2397 UInt64 seekPos = bufPhyPos + bytesInBuf; 2398 RINOK(op.stream->Seek(bufPhyPos + bytesInBuf, STREAM_SEEK_SET, NULL)); 2399 RINOK(ReadStream(op.stream, byteBuffer + bytesInBuf, &processedSize)); 2400 // printf(" processed = %d", (unsigned)processedSize); 2401 if (processedSize == 0) 2402 { 2403 fileSize = seekPos; 2404 endOfFile = true; 2405 } 2406 else 2407 { 2408 bytesInBuf += processedSize; 2409 limitedStreamSpec->SetCache(processedSize, (size_t)bufPhyPos); 2410 } 2411 continue; 2412 } 2413 2414 if (bytesInBuf < posInBuf) 2415 { 2416 UInt64 skipSize = posInBuf - bytesInBuf; 2417 if (skipSize <= kBeforeSize) 2418 { 2419 size_t keepSize = (size_t)(kBeforeSize - skipSize); 2420 // printf("\nmemmove skip = %d", (int)keepSize); 2421 memmove(byteBuffer, byteBuffer + bytesInBuf - keepSize, keepSize); 2422 bytesInBuf = keepSize; 2423 bufPhyPos = pos - keepSize; 2424 continue; 2425 } 2426 // printf("\nSkip %d", (int)(skipSize - kBeforeSize)); 2427 // RINOK(op.stream->Seek(skipSize - kBeforeSize, STREAM_SEEK_CUR, NULL)); 2428 bytesInBuf = 0; 2429 bufPhyPos = pos - kBeforeSize; 2430 continue; 2431 } 2432 2433 if (bytesInBuf - posInBuf < kAfterSize) 2434 { 2435 size_t beg = (size_t)posInBuf - kBeforeSize; 2436 // printf("\nmemmove for after beg = %d", (int)beg); 2437 memmove(byteBuffer, byteBuffer + beg, bytesInBuf - beg); 2438 bufPhyPos += beg; 2439 bytesInBuf -= beg; 2440 continue; 2441 } 2442 } 2443 2444 if (bytesInBuf <= (size_t)posInBuf) 2445 break; 2446 2447 bool useOffsetCallback = false; 2448 if (openCallback_Offset) 2449 { 2450 openCallback_Offset_Spec->Files = handlerSpec->_items.Size(); 2451 openCallback_Offset_Spec->Offset = pos; 2452 2453 useOffsetCallback = (!op.openType.CanReturnArc || handlerSpec->_items.Size() > 1); 2454 2455 if (pos >= callbackPrev + (1 << 23)) 2456 { 2457 RINOK(openCallback_Offset_Spec->SetCompleted(NULL, NULL)); 2458 callbackPrev = pos; 2459 } 2460 } 2461 2462 { 2463 UInt64 endPos = bufPhyPos + bytesInBuf; 2464 if (fileSize < endPos) 2465 { 2466 FileSize = fileSize; // why ???? 2467 fileSize = endPos; 2468 } 2469 } 2470 2471 size_t availSize = bytesInBuf - (size_t)posInBuf; 2472 if (availSize < kNumHashBytes) 2473 break; 2474 size_t scanSize = availSize - 2475 ((availSize >= kAfterSize) ? kAfterSize : kNumHashBytes); 2476 2477 { 2478 /* 2479 UInt64 scanLimit = openOnlyFullArc ? 2480 maxSignatureEnd : 2481 op.openType.ScanSize + maxSignatureEnd; 2482 */ 2483 if (!mode.CanReturnParser) 2484 { 2485 if (pos > maxStartOffset) 2486 break; 2487 UInt64 remScan = maxStartOffset - pos; 2488 if (scanSize > remScan) 2489 scanSize = (size_t)remScan; 2490 } 2491 } 2492 2493 scanSize++; 2494 2495 const Byte *buf = byteBuffer + (size_t)posInBuf; 2496 const Byte *bufLimit = buf + scanSize; 2497 size_t ppp = 0; 2498 2499 if (!needCheckStartOpen) 2500 { 2501 for (; buf < bufLimit && hash[HASH_VAL(buf)] == 0xFF; buf++); 2502 ppp = buf - (byteBuffer + (size_t)posInBuf); 2503 pos += ppp; 2504 if (buf == bufLimit) 2505 continue; 2506 } 2507 2508 UInt32 v = HASH_VAL(buf); 2509 bool nextNeedCheckStartOpen = true; 2510 unsigned i = hash[v]; 2511 unsigned indexOfDifficult = 0; 2512 2513 // ---------- Open Loop for Current Pos ---------- 2514 bool wasOpen = false; 2515 2516 for (;;) 2517 { 2518 unsigned index; 2519 bool isDifficult; 2520 if (needCheckStartOpen && indexOfDifficult < difficultFormats.Size()) 2521 { 2522 index = difficultFormats[indexOfDifficult++]; 2523 isDifficult = true; 2524 } 2525 else 2526 { 2527 if (i == 0xFF) 2528 break; 2529 index = sig2arc[i]; 2530 unsigned sigIndex = i - arc2sig[index]; 2531 i = prevs[i]; 2532 if (needCheckStartOpen && difficultBools[index]) 2533 continue; 2534 const CArcInfoEx &ai = op.codecs->Formats[index]; 2535 2536 if (pos < ai.SignatureOffset) 2537 continue; 2538 2539 /* 2540 if (openOnlyFullArc) 2541 if (pos != ai.SignatureOffset) 2542 continue; 2543 */ 2544 2545 const CByteBuffer &sig = ai.Signatures[sigIndex]; 2546 2547 if (ppp + sig.Size() > availSize 2548 || !TestSignature(buf, sig, sig.Size())) 2549 continue; 2550 // printf("\nSignature OK: %10S %8x %5d", (const wchar_t *)ai.Name, (int)pos, (int)(pos - prevPos)); 2551 // prevPos = pos; 2552 isDifficult = false; 2553 } 2554 2555 const CArcInfoEx &ai = op.codecs->Formats[index]; 2556 2557 2558 if ((isDifficult && pos == 0) || ai.SignatureOffset == pos) 2559 { 2560 // we don't check same archive second time */ 2561 if (skipFrontalFormat[index]) 2562 continue; 2563 } 2564 2565 UInt64 startArcPos = pos; 2566 if (!isDifficult) 2567 { 2568 if (pos < ai.SignatureOffset) 2569 continue; 2570 startArcPos = pos - ai.SignatureOffset; 2571 /* 2572 // we don't need the check for Z files 2573 if (startArcPos < handlerSpec->GetLastEnd()) 2574 continue; 2575 */ 2576 } 2577 2578 if (ai.IsArcFunc && startArcPos >= bufPhyPos) 2579 { 2580 size_t offsetInBuf = (size_t)(startArcPos - bufPhyPos); 2581 if (offsetInBuf < bytesInBuf) 2582 { 2583 UInt32 isArcRes = ai.IsArcFunc(byteBuffer + offsetInBuf, bytesInBuf - offsetInBuf); 2584 if (isArcRes == k_IsArc_Res_NO) 2585 continue; 2586 if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile) 2587 continue; 2588 /* 2589 if (isArcRes == k_IsArc_Res_YES_LOW_PROB) 2590 { 2591 // if (pos != ai.SignatureOffset) 2592 continue; 2593 } 2594 */ 2595 } 2596 // printf("\nIsArc OK: %S", (const wchar_t *)ai.Name); 2597 } 2598 2599 /* 2600 if (pos == 67109888) 2601 pos = pos; 2602 */ 2603 PRF(printf("\npos = %9I64d : %S", pos, (const wchar_t *)ai.Name)); 2604 2605 bool isMainFormat = isMainFormatArr[index]; 2606 const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt); 2607 2608 CMyComPtr<IInArchive> archive; 2609 RINOK(PrepareToOpen(op, index, archive)); 2610 if (!archive) 2611 return E_FAIL; 2612 2613 // OutputDebugStringW(ai.Name); 2614 2615 UInt64 rem = fileSize - startArcPos; 2616 2617 UInt64 arcStreamOffset = 0; 2618 2619 if (ai.Flags_UseGlobalOffset()) 2620 { 2621 limitedStreamSpec->InitAndSeek(0, fileSize); 2622 limitedStream->Seek(startArcPos, STREAM_SEEK_SET, NULL); 2623 } 2624 else 2625 { 2626 limitedStreamSpec->InitAndSeek(startArcPos, rem); 2627 arcStreamOffset = startArcPos; 2628 } 2629 2630 UInt64 maxCheckStartPosition = 0; 2631 2632 if (openCallback_Offset) 2633 { 2634 openCallback_Offset_Spec->Files = handlerSpec->_items.Size(); 2635 openCallback_Offset_Spec->Offset = startArcPos; 2636 } 2637 2638 // HRESULT result = archive->Open(limitedStream, &maxCheckStartPosition, openCallback_Offset); 2639 extractCallback_To_OpenCallback_Spec->Files = 0; 2640 extractCallback_To_OpenCallback_Spec->Offset = startArcPos; 2641 2642 HRESULT result = OpenArchiveSpec(archive, true, limitedStream, &maxCheckStartPosition, 2643 useOffsetCallback ? (IArchiveOpenCallback *)openCallback_Offset : (IArchiveOpenCallback *)op.callback, 2644 extractCallback_To_OpenCallback); 2645 2646 RINOK(ReadBasicProps(archive, ai.Flags_UseGlobalOffset() ? 0 : startArcPos, result)); 2647 2648 bool isOpen = false; 2649 if (result == S_FALSE) 2650 { 2651 if (!mode.CanReturnParser) 2652 { 2653 if (formatIndex < 0 && ErrorInfo.IsArc_After_NonOpen()) 2654 { 2655 ErrorInfo.ErrorFormatIndex = index; 2656 NonOpen_ErrorInfo = ErrorInfo; 2657 // if archive was detected, we don't need additional open attempts 2658 return S_FALSE; 2659 } 2660 continue; 2661 } 2662 if (!ErrorInfo.IsArc_After_NonOpen() || !PhySizeDefined || PhySize == 0) 2663 continue; 2664 } 2665 else 2666 { 2667 isOpen = true; 2668 RINOK(result); 2669 PRF(printf(" OK ")); 2670 } 2671 2672 // fprintf(stderr, "\n %8X %S", startArcPos, Path); 2673 // printf("\nOpen OK: %S", ai.Name); 2674 2675 2676 NArchive::NParser::CParseItem pi; 2677 pi.Offset = startArcPos; 2678 2679 if (ai.Flags_UseGlobalOffset()) 2680 pi.Offset = Offset; 2681 else if (Offset != 0) 2682 return E_FAIL; 2683 UInt64 arcRem = FileSize - pi.Offset; 2684 UInt64 phySize = arcRem; 2685 bool phySizeDefined = PhySizeDefined; 2686 if (phySizeDefined) 2687 { 2688 if (pi.Offset + PhySize > FileSize) 2689 { 2690 // ErrorInfo.ThereIsTail = true; 2691 PhySize = FileSize - pi.Offset; 2692 } 2693 phySize = PhySize; 2694 } 2695 if (phySize == 0 || (UInt64)phySize > ((UInt64)1 << 63)) 2696 return E_FAIL; 2697 2698 /* 2699 if (!ai.UseGlobalOffset) 2700 { 2701 if (phySize > arcRem) 2702 { 2703 ThereIsTail = true; 2704 phySize = arcRem; 2705 } 2706 } 2707 */ 2708 2709 bool needScan = false; 2710 2711 2712 if (isOpen && !phySizeDefined) 2713 { 2714 // it's for Z format 2715 pi.LenIsUnknown = true; 2716 needScan = true; 2717 phySize = arcRem; 2718 nextNeedCheckStartOpen = false; 2719 } 2720 2721 pi.Size = phySize; 2722 /* 2723 if (OkPhySize_Defined) 2724 pi.OkSize = OkPhySize; 2725 */ 2726 pi.NormalizeOffset(); 2727 // printf(" phySize = %8d", (unsigned)phySize); 2728 2729 /* 2730 if (needSkipFullArc) 2731 if (pi.Offset == 0 && phySizeDefined && pi.Size >= fileSize) 2732 continue; 2733 */ 2734 if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize) 2735 { 2736 // it's possible for dmg archives 2737 if (!mode.CanReturnArc) 2738 continue; 2739 } 2740 2741 if (mode.EachPos) 2742 pos++; 2743 else if (needScan) 2744 { 2745 pos++; 2746 /* 2747 if (!OkPhySize_Defined) 2748 pos++; 2749 else 2750 pos = pi.Offset + pi.OkSize; 2751 */ 2752 } 2753 else 2754 pos = pi.Offset + pi.Size; 2755 2756 2757 RINOK(ReadParseItemProps(archive, ai, pi)); 2758 2759 if (pi.Offset < startArcPos && !mode.EachPos /* && phySizeDefined */) 2760 { 2761 /* It's for DMG format. 2762 This code deletes all previous items that are included to current item */ 2763 2764 while (!handlerSpec->_items.IsEmpty()) 2765 { 2766 { 2767 const NArchive::NParser::CParseItem &back = handlerSpec->_items.Back(); 2768 if (back.Offset < pi.Offset) 2769 break; 2770 if (back.Offset + back.Size > pi.Offset + pi.Size) 2771 break; 2772 } 2773 handlerSpec->_items.DeleteBack(); 2774 } 2775 } 2776 2777 2778 if (isOpen && mode.CanReturnArc && phySizeDefined) 2779 { 2780 // if (pi.Offset + pi.Size >= fileSize) 2781 bool openCur = false; 2782 2783 bool thereIsTail = ErrorInfo.ThereIsTail; 2784 if (thereIsTail && mode.ZerosTailIsAllowed) 2785 { 2786 RINOK(CheckZerosTail(op, arcStreamOffset + Offset + PhySize)); 2787 if (ErrorInfo.IgnoreTail) 2788 thereIsTail = false; 2789 } 2790 2791 if (pi.Offset != 0) 2792 { 2793 if (!pi.IsNotArcType) 2794 if (thereIsTail) 2795 openCur = specFlags.CanReturnMid; 2796 else 2797 openCur = specFlags.CanReturnTail; 2798 } 2799 else 2800 { 2801 if (!thereIsTail) 2802 openCur = true; 2803 else 2804 openCur = specFlags.CanReturnFrontal; 2805 2806 2807 if (formatIndex >= -2) 2808 openCur = true; 2809 } 2810 if (formatIndex < 0 && pi.IsSelfExe /* && mode.SkipSfxStub */) 2811 openCur = false; 2812 2813 // We open file as SFX, if there is front archive or first archive is "Self Executable" 2814 if (!openCur && !pi.IsSelfExe && !thereIsTail && 2815 (!pi.IsNotArcType || pi.Offset == 0)) 2816 { 2817 if (handlerSpec->_items.IsEmpty()) 2818 { 2819 if (specFlags.CanReturnTail) 2820 openCur = true; 2821 } 2822 else if (handlerSpec->_items.Size() == 1) 2823 { 2824 if (handlerSpec->_items[0].IsSelfExe) 2825 { 2826 if (mode.SpecUnknownExt.CanReturnTail) 2827 openCur = true; 2828 } 2829 } 2830 } 2831 2832 if (openCur) 2833 { 2834 InStream = op.stream; 2835 Archive = archive; 2836 FormatIndex = index; 2837 ArcStreamOffset = arcStreamOffset; 2838 return S_OK; 2839 } 2840 } 2841 2842 /* 2843 if (openOnlyFullArc) 2844 { 2845 ErrorInfo.ClearErrors(); 2846 return S_FALSE; 2847 } 2848 */ 2849 2850 pi.FormatIndex = index; 2851 2852 // printf("\nAdd offset = %d", (int)pi.Offset); 2853 handlerSpec->AddItem(pi); 2854 wasOpen = true; 2855 break; 2856 } 2857 // ---------- End of Open Loop for Current Pos ---------- 2858 2859 if (!wasOpen) 2860 pos++; 2861 needCheckStartOpen = (nextNeedCheckStartOpen && wasOpen); 2862 } 2863 // ---------- End of Main Scan Loop ---------- 2864 2865 /* 2866 if (handlerSpec->_items.Size() == 1) 2867 { 2868 const NArchive::NParser::CParseItem &pi = handlerSpec->_items[0]; 2869 if (pi.Size == fileSize && pi.Offset == 0) 2870 { 2871 Archive = archive; 2872 FormatIndex2 = pi.FormatIndex; 2873 return S_OK; 2874 } 2875 } 2876 */ 2877 2878 if (mode.CanReturnParser) 2879 { 2880 bool returnParser = (handlerSpec->_items.Size() == 1); // it's possible if fileSize was not correct at start of parsing 2881 handlerSpec->AddUnknownItem(fileSize); 2882 if (handlerSpec->_items.Size() == 0) 2883 return S_FALSE; 2884 if (returnParser || handlerSpec->_items.Size() != 1) 2885 { 2886 // return S_FALSE; 2887 handlerSpec->_stream = op.stream; 2888 Archive = handler; 2889 ErrorInfo.ClearErrors(); 2890 IsParseArc = true; 2891 FormatIndex = -1; // It's parser 2892 Offset = 0; 2893 return S_OK; 2894 } 2895 } 2896 } 2897 2898 #endif 2899 2900 if (!Archive) 2901 return S_FALSE; 2902 return S_OK; 2903 } 2904 2905 HRESULT CArc::OpenStream(const COpenOptions &op) 2906 { 2907 RINOK(OpenStream2(op)); 2908 // PrintNumber("op.formatIndex 3", op.formatIndex); 2909 2910 if (Archive) 2911 { 2912 GetRawProps.Release(); 2913 GetRootProps.Release(); 2914 Archive->QueryInterface(IID_IArchiveGetRawProps, (void **)&GetRawProps); 2915 Archive->QueryInterface(IID_IArchiveGetRootProps, (void **)&GetRootProps); 2916 2917 RINOK(Archive_GetArcBoolProp(Archive, kpidIsTree, IsTree)); 2918 RINOK(Archive_GetArcBoolProp(Archive, kpidIsDeleted, Ask_Deleted)); 2919 RINOK(Archive_GetArcBoolProp(Archive, kpidIsAltStream, Ask_AltStream)); 2920 RINOK(Archive_GetArcBoolProp(Archive, kpidIsAux, Ask_Aux)); 2921 RINOK(Archive_GetArcBoolProp(Archive, kpidINode, Ask_INode)); 2922 RINOK(Archive_GetArcBoolProp(Archive, kpidReadOnly, IsReadOnly)); 2923 2924 const UString fileName = ExtractFileNameFromPath(Path); 2925 UString extension; 2926 { 2927 int dotPos = fileName.ReverseFind_Dot(); 2928 if (dotPos >= 0) 2929 extension = fileName.Ptr(dotPos + 1); 2930 } 2931 2932 DefaultName.Empty(); 2933 if (FormatIndex >= 0) 2934 { 2935 const CArcInfoEx &ai = op.codecs->Formats[FormatIndex]; 2936 if (ai.Exts.Size() == 0) 2937 DefaultName = GetDefaultName2(fileName, UString(), UString()); 2938 else 2939 { 2940 int subExtIndex = ai.FindExtension(extension); 2941 if (subExtIndex < 0) 2942 subExtIndex = 0; 2943 const CArcExtInfo &extInfo = ai.Exts[subExtIndex]; 2944 DefaultName = GetDefaultName2(fileName, extInfo.Ext, extInfo.AddExt); 2945 } 2946 } 2947 } 2948 2949 return S_OK; 2950 } 2951 2952 #ifdef _SFX 2953 2954 #ifdef _WIN32 2955 #define k_ExeExt ".exe" 2956 static const unsigned k_ExeExt_Len = 4; 2957 #else 2958 #define k_ExeExt "" 2959 static const unsigned k_ExeExt_Len = 0; 2960 #endif 2961 2962 #endif 2963 2964 HRESULT CArc::OpenStreamOrFile(COpenOptions &op) 2965 { 2966 CMyComPtr<IInStream> fileStream; 2967 CMyComPtr<ISequentialInStream> seqStream; 2968 CInFileStream *fileStreamSpec = NULL; 2969 2970 if (op.stdInMode) 2971 { 2972 seqStream = new CStdInFileStream; 2973 op.seqStream = seqStream; 2974 } 2975 else if (!op.stream) 2976 { 2977 fileStreamSpec = new CInFileStream; 2978 fileStream = fileStreamSpec; 2979 Path = filePath; 2980 if (!fileStreamSpec->Open(us2fs(Path))) 2981 { 2982 return GetLastError(); 2983 } 2984 op.stream = fileStream; 2985 #ifdef _SFX 2986 IgnoreSplit = true; 2987 #endif 2988 } 2989 2990 /* 2991 if (callback) 2992 { 2993 UInt64 fileSize; 2994 RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize)); 2995 RINOK(op.callback->SetTotal(NULL, &fileSize)) 2996 } 2997 */ 2998 2999 HRESULT res = OpenStream(op); 3000 IgnoreSplit = false; 3001 3002 #ifdef _SFX 3003 3004 if (res != S_FALSE 3005 || !fileStreamSpec 3006 || !op.callbackSpec 3007 || NonOpen_ErrorInfo.IsArc_After_NonOpen()) 3008 return res; 3009 3010 { 3011 if (filePath.Len() > k_ExeExt_Len 3012 && StringsAreEqualNoCase_Ascii(filePath.RightPtr(k_ExeExt_Len), k_ExeExt)) 3013 { 3014 const UString path2 = filePath.Left(filePath.Len() - k_ExeExt_Len); 3015 FOR_VECTOR (i, op.codecs->Formats) 3016 { 3017 const CArcInfoEx &ai = op.codecs->Formats[i]; 3018 if (ai.IsSplit()) 3019 continue; 3020 UString path3 = path2; 3021 path3 += '.'; 3022 path3 += ai.GetMainExt(); // "7z" for SFX. 3023 Path = path3; 3024 Path += ".001"; 3025 bool isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path)); 3026 if (!isOk) 3027 { 3028 Path = path3; 3029 isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path)); 3030 } 3031 if (isOk) 3032 { 3033 if (fileStreamSpec->Open(us2fs(Path))) 3034 { 3035 op.stream = fileStream; 3036 NonOpen_ErrorInfo.ClearErrors_Full(); 3037 if (OpenStream(op) == S_OK) 3038 return S_OK; 3039 } 3040 } 3041 } 3042 } 3043 } 3044 3045 #endif 3046 3047 return res; 3048 } 3049 3050 void CArchiveLink::KeepModeForNextOpen() 3051 { 3052 for (unsigned i = Arcs.Size(); i != 0;) 3053 { 3054 i--; 3055 CMyComPtr<IArchiveKeepModeForNextOpen> keep; 3056 Arcs[i].Archive->QueryInterface(IID_IArchiveKeepModeForNextOpen, (void **)&keep); 3057 if (keep) 3058 keep->KeepModeForNextOpen(); 3059 } 3060 } 3061 3062 HRESULT CArchiveLink::Close() 3063 { 3064 for (unsigned i = Arcs.Size(); i != 0;) 3065 { 3066 i--; 3067 RINOK(Arcs[i].Close()); 3068 } 3069 IsOpen = false; 3070 // ErrorsText.Empty(); 3071 return S_OK; 3072 } 3073 3074 void CArchiveLink::Release() 3075 { 3076 // NonOpenErrorFormatIndex = -1; 3077 NonOpen_ErrorInfo.ClearErrors(); 3078 NonOpen_ArcPath.Empty(); 3079 while (!Arcs.IsEmpty()) 3080 Arcs.DeleteBack(); 3081 } 3082 3083 /* 3084 void CArchiveLink::Set_ErrorsText() 3085 { 3086 FOR_VECTOR(i, Arcs) 3087 { 3088 const CArc &arc = Arcs[i]; 3089 if (!arc.ErrorFlagsText.IsEmpty()) 3090 { 3091 if (!ErrorsText.IsEmpty()) 3092 ErrorsText.Add_LF(); 3093 ErrorsText += GetUnicodeString(arc.ErrorFlagsText); 3094 } 3095 if (!arc.ErrorMessage.IsEmpty()) 3096 { 3097 if (!ErrorsText.IsEmpty()) 3098 ErrorsText.Add_LF(); 3099 ErrorsText += arc.ErrorMessage; 3100 } 3101 3102 if (!arc.WarningMessage.IsEmpty()) 3103 { 3104 if (!ErrorsText.IsEmpty()) 3105 ErrorsText.Add_LF(); 3106 ErrorsText += arc.WarningMessage; 3107 } 3108 } 3109 } 3110 */ 3111 3112 HRESULT CArchiveLink::Open(COpenOptions &op) 3113 { 3114 Release(); 3115 if (op.types->Size() >= 32) 3116 return E_NOTIMPL; 3117 3118 HRESULT resSpec; 3119 3120 for (;;) 3121 { 3122 resSpec = S_OK; 3123 3124 op.openType = COpenType(); 3125 if (op.types->Size() >= 1) 3126 { 3127 COpenType latest; 3128 if (Arcs.Size() < op.types->Size()) 3129 latest = (*op.types)[op.types->Size() - Arcs.Size() - 1]; 3130 else 3131 { 3132 latest = (*op.types)[0]; 3133 if (!latest.Recursive) 3134 break; 3135 } 3136 op.openType = latest; 3137 } 3138 else if (Arcs.Size() >= 32) 3139 break; 3140 3141 /* 3142 op.formatIndex = -1; 3143 if (op.types->Size() >= 1) 3144 { 3145 int latest; 3146 if (Arcs.Size() < op.types->Size()) 3147 latest = (*op.types)[op.types->Size() - Arcs.Size() - 1]; 3148 else 3149 { 3150 latest = (*op.types)[0]; 3151 if (latest != -2 && latest != -3) 3152 break; 3153 } 3154 if (latest >= 0) 3155 op.formatIndex = latest; 3156 else if (latest == -1 || latest == -2) 3157 { 3158 // default 3159 } 3160 else if (latest == -3) 3161 op.formatIndex = -2; 3162 else 3163 op.formatIndex = latest + 2; 3164 } 3165 else if (Arcs.Size() >= 32) 3166 break; 3167 */ 3168 3169 if (Arcs.IsEmpty()) 3170 { 3171 CArc arc; 3172 arc.filePath = op.filePath; 3173 arc.Path = op.filePath; 3174 arc.SubfileIndex = (UInt32)(Int32)-1; 3175 HRESULT result = arc.OpenStreamOrFile(op); 3176 if (result != S_OK) 3177 { 3178 if (result == S_FALSE) 3179 { 3180 NonOpen_ErrorInfo = arc.NonOpen_ErrorInfo; 3181 // NonOpenErrorFormatIndex = arc.ErrorFormatIndex; 3182 NonOpen_ArcPath = arc.Path; 3183 } 3184 return result; 3185 } 3186 Arcs.Add(arc); 3187 continue; 3188 } 3189 3190 // PrintNumber("op.formatIndex 11", op.formatIndex); 3191 3192 const CArc &arc = Arcs.Back(); 3193 3194 if (op.types->Size() > Arcs.Size()) 3195 resSpec = E_NOTIMPL; 3196 3197 UInt32 mainSubfile; 3198 { 3199 NCOM::CPropVariant prop; 3200 RINOK(arc.Archive->GetArchiveProperty(kpidMainSubfile, &prop)); 3201 if (prop.vt == VT_UI4) 3202 mainSubfile = prop.ulVal; 3203 else 3204 break; 3205 UInt32 numItems; 3206 RINOK(arc.Archive->GetNumberOfItems(&numItems)); 3207 if (mainSubfile >= numItems) 3208 break; 3209 } 3210 3211 3212 CMyComPtr<IInArchiveGetStream> getStream; 3213 if (arc.Archive->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream) != S_OK || !getStream) 3214 break; 3215 3216 CMyComPtr<ISequentialInStream> subSeqStream; 3217 if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK || !subSeqStream) 3218 break; 3219 3220 CMyComPtr<IInStream> subStream; 3221 if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK || !subStream) 3222 break; 3223 3224 CArc arc2; 3225 RINOK(arc.GetItemPath(mainSubfile, arc2.Path)); 3226 3227 bool zerosTailIsAllowed; 3228 RINOK(Archive_GetItemBoolProp(arc.Archive, mainSubfile, kpidZerosTailIsAllowed, zerosTailIsAllowed)); 3229 3230 3231 if (op.callback) 3232 { 3233 CMyComPtr<IArchiveOpenSetSubArchiveName> setSubArchiveName; 3234 op.callback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName); 3235 if (setSubArchiveName) 3236 setSubArchiveName->SetSubArchiveName(arc2.Path); 3237 } 3238 3239 arc2.SubfileIndex = mainSubfile; 3240 3241 // CIntVector incl; 3242 CIntVector excl; 3243 3244 COpenOptions op2; 3245 #ifndef _SFX 3246 op2.props = op.props; 3247 #endif 3248 op2.codecs = op.codecs; 3249 // op2.types = &incl; 3250 op2.openType = op.openType; 3251 op2.openType.ZerosTailIsAllowed = zerosTailIsAllowed; 3252 op2.excludedFormats = ! 3253 op2.stdInMode = false; 3254 op2.stream = subStream; 3255 op2.filePath = arc2.Path; 3256 op2.callback = op.callback; 3257 op2.callbackSpec = op.callbackSpec; 3258 3259 3260 HRESULT result = arc2.OpenStream(op2); 3261 resSpec = (op.types->Size() == 0 ? S_OK : S_FALSE); 3262 if (result == S_FALSE) 3263 { 3264 NonOpen_ErrorInfo = arc2.ErrorInfo; 3265 NonOpen_ArcPath = arc2.Path; 3266 break; 3267 } 3268 RINOK(result); 3269 RINOK(arc.GetItemMTime(mainSubfile, arc2.MTime, arc2.MTimeDefined)); 3270 Arcs.Add(arc2); 3271 } 3272 IsOpen = !Arcs.IsEmpty(); 3273 return resSpec; 3274 } 3275 3276 HRESULT CArchiveLink::Open2(COpenOptions &op, IOpenCallbackUI *callbackUI) 3277 { 3278 VolumesSize = 0; 3279 COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; 3280 CMyComPtr<IArchiveOpenCallback> callback = openCallbackSpec; 3281 openCallbackSpec->Callback = callbackUI; 3282 3283 FString prefix, name; 3284 3285 if (!op.stream && !op.stdInMode) 3286 { 3287 NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), prefix, name); 3288 openCallbackSpec->Init(prefix, name); 3289 } 3290 else 3291 { 3292 openCallbackSpec->SetSubArchiveName(op.filePath); 3293 } 3294 3295 op.callback = callback; 3296 op.callbackSpec = openCallbackSpec; 3297 3298 HRESULT res = Open(op); 3299 3300 PasswordWasAsked = openCallbackSpec->PasswordWasAsked; 3301 // Password = openCallbackSpec->Password; 3302 3303 RINOK(res); 3304 // VolumePaths.Add(fs2us(prefix + name)); 3305 3306 FOR_VECTOR (i, openCallbackSpec->FileNames_WasUsed) 3307 { 3308 if (openCallbackSpec->FileNames_WasUsed[i]) 3309 { 3310 VolumePaths.Add(fs2us(prefix) + openCallbackSpec->FileNames[i]); 3311 VolumesSize += openCallbackSpec->FileSizes[i]; 3312 } 3313 } 3314 // VolumesSize = openCallbackSpec->TotalSize; 3315 return S_OK; 3316 } 3317 3318 HRESULT CArc::ReOpen(const COpenOptions &op) 3319 { 3320 ErrorInfo.ClearErrors(); 3321 ErrorInfo.ErrorFormatIndex = -1; 3322 3323 UInt64 fileSize = 0; 3324 if (op.stream) 3325 { 3326 RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize)); 3327 RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL)); 3328 } 3329 FileSize = fileSize; 3330 3331 CMyComPtr<IInStream> stream2; 3332 Int64 globalOffset = GetGlobalOffset(); 3333 if (globalOffset <= 0) 3334 stream2 = op.stream; 3335 else 3336 { 3337 CTailInStream *tailStreamSpec = new CTailInStream; 3338 stream2 = tailStreamSpec; 3339 tailStreamSpec->Stream = op.stream; 3340 tailStreamSpec->Offset = globalOffset; 3341 tailStreamSpec->Init(); 3342 RINOK(tailStreamSpec->SeekToStart()); 3343 } 3344 3345 // There are archives with embedded STUBs (like ZIP), so we must support signature scanning 3346 // But for another archives we can use 0 here. So the code can be fixed !!! 3347 UInt64 maxStartPosition = kMaxCheckStartPosition; 3348 HRESULT res = Archive->Open(stream2, &maxStartPosition, op.callback); 3349 3350 if (res == S_OK) 3351 { 3352 RINOK(ReadBasicProps(Archive, globalOffset, res)); 3353 ArcStreamOffset = globalOffset; 3354 if (ArcStreamOffset != 0) 3355 InStream = op.stream; 3356 } 3357 return res; 3358 } 3359 3360 HRESULT CArchiveLink::Open3(COpenOptions &op, IOpenCallbackUI *callbackUI) 3361 { 3362 HRESULT res = Open2(op, callbackUI); 3363 if (callbackUI) 3364 { 3365 RINOK(callbackUI->Open_Finished()); 3366 } 3367 return res; 3368 } 3369 3370 HRESULT CArchiveLink::ReOpen(COpenOptions &op) 3371 { 3372 if (Arcs.Size() > 1) 3373 return E_NOTIMPL; 3374 3375 CObjectVector<COpenType> inc; 3376 CIntVector excl; 3377 3378 op.types = &inc; 3379 op.excludedFormats = ! 3380 op.stdInMode = false; 3381 op.stream = NULL; 3382 if (Arcs.Size() == 0) // ??? 3383 return Open2(op, NULL); 3384 3385 COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; 3386 CMyComPtr<IArchiveOpenCallback> openCallbackNew = openCallbackSpec; 3387 3388 openCallbackSpec->Callback = NULL; 3389 openCallbackSpec->ReOpenCallback = op.callback; 3390 { 3391 FString dirPrefix, fileName; 3392 NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), dirPrefix, fileName); 3393 openCallbackSpec->Init(dirPrefix, fileName); 3394 } 3395 3396 3397 CInFileStream *fileStreamSpec = new CInFileStream; 3398 CMyComPtr<IInStream> stream(fileStreamSpec); 3399 if (!fileStreamSpec->Open(us2fs(op.filePath))) 3400 return GetLastError(); 3401 op.stream = stream; 3402 3403 CArc &arc = Arcs[0]; 3404 HRESULT res = arc.ReOpen(op); 3405 3406 PasswordWasAsked = openCallbackSpec->PasswordWasAsked; 3407 // Password = openCallbackSpec->Password; 3408 3409 IsOpen = (res == S_OK); 3410 return res; 3411 } 3412 3413 #ifndef _SFX 3414 3415 bool ParseComplexSize(const wchar_t *s, UInt64 &result) 3416 { 3417 result = 0; 3418 const wchar_t *end; 3419 UInt64 number = ConvertStringToUInt64(s, &end); 3420 if (end == s) 3421 return false; 3422 if (*end == 0) 3423 { 3424 result = number; 3425 return true; 3426 } 3427 if (end[1] != 0) 3428 return false; 3429 unsigned numBits; 3430 switch (MyCharLower_Ascii(*end)) 3431 { 3432 case 'b': result = number; return true; 3433 case 'k': numBits = 10; break; 3434 case 'm': numBits = 20; break; 3435 case 'g': numBits = 30; break; 3436 case 't': numBits = 40; break; 3437 default: return false; 3438 } 3439 if (number >= ((UInt64)1 << (64 - numBits))) 3440 return false; 3441 result = number << numBits; 3442 return true; 3443 } 3444 3445 static bool ParseTypeParams(const UString &s, COpenType &type) 3446 { 3447 if (s[0] == 0) 3448 return true; 3449 if (s[1] == 0) 3450 { 3451 switch ((unsigned)(Byte)s[0]) 3452 { 3453 case 'e': type.EachPos = true; return true; 3454 case 'a': type.CanReturnArc = true; return true; 3455 case 'r': type.Recursive = true; return true; 3456 } 3457 return false; 3458 } 3459 if (s[0] == 's') 3460 { 3461 UInt64 result; 3462 if (!ParseComplexSize(s.Ptr(1), result)) 3463 return false; 3464 type.MaxStartOffset = result; 3465 type.MaxStartOffset_Defined = true; 3466 return true; 3467 } 3468 3469 return false; 3470 } 3471 3472 bool ParseType(CCodecs &codecs, const UString &s, COpenType &type) 3473 { 3474 int pos2 = s.Find(L':'); 3475 3476 { 3477 UString name; 3478 if (pos2 < 0) 3479 { 3480 name = s; 3481 pos2 = s.Len(); 3482 } 3483 else 3484 { 3485 name = s.Left(pos2); 3486 pos2++; 3487 } 3488 3489 int index = codecs.FindFormatForArchiveType(name); 3490 type.Recursive = false; 3491 3492 if (index < 0) 3493 { 3494 if (name[0] == '*') 3495 { 3496 if (name[1] != 0) 3497 return false; 3498 } 3499 else if (name[0] == '#') 3500 { 3501 if (name[1] != 0) 3502 return false; 3503 type.CanReturnArc = false; 3504 type.CanReturnParser = true; 3505 } 3506 else 3507 return false; 3508 } 3509 3510 type.FormatIndex = index; 3511 3512 } 3513 3514 for (unsigned i = pos2; i < s.Len();) 3515 { 3516 int next = s.Find(L':', i); 3517 if (next < 0) 3518 next = s.Len(); 3519 const UString name = s.Mid(i, next - i); 3520 if (name.IsEmpty()) 3521 return false; 3522 if (!ParseTypeParams(name, type)) 3523 return false; 3524 i = next + 1; 3525 } 3526 3527 return true; 3528 } 3529 3530 bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> &types) 3531 { 3532 types.Clear(); 3533 for (unsigned pos = 0; pos < s.Len();) 3534 { 3535 int pos2 = s.Find(L'.', pos); 3536 if (pos2 < 0) 3537 pos2 = s.Len(); 3538 UString name = s.Mid(pos, pos2 - pos); 3539 if (name.IsEmpty()) 3540 return false; 3541 COpenType type; 3542 if (!ParseType(codecs, name, type)) 3543 return false; 3544 types.Add(type); 3545 pos = pos2 + 1; 3546 } 3547 return true; 3548 } 3549 3550 #endif