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