1// ExtractCallback.cpp 2 3#include "StdAfx.h" 4 5 6#include "../../../Common/ComTry.h" 7#include "../../../Common/IntToString.h" 8#include "../../../Common/Lang.h" 9#include "../../../Common/StringConvert.h" 10 11#include "../../../Windows/ErrorMsg.h" 12#include "../../../Windows/FileDir.h" 13#include "../../../Windows/FileFind.h" 14#include "../../../Windows/PropVariantConv.h" 15 16#include "../../Common/FilePathAutoRename.h" 17#include "../../Common/StreamUtils.h" 18#include "../Common/ExtractingFilePath.h" 19 20#ifndef Z7_SFX 21#include "../Common/ZipRegistry.h" 22#endif 23 24#include "../GUI/ExtractRes.h" 25#include "resourceGui.h" 26 27#include "ExtractCallback.h" 28#include "FormatUtils.h" 29#include "LangUtils.h" 30#include "OverwriteDialog.h" 31#ifndef Z7_NO_CRYPTO 32#include "PasswordDialog.h" 33#endif 34#include "PropertyName.h" 35 36using namespace NWindows; 37using namespace NFile; 38using namespace NFind; 39 40CExtractCallbackImp::~CExtractCallbackImp() {} 41 42void CExtractCallbackImp::Init() 43{ 44 _lang_Extracting = LangString(IDS_PROGRESS_EXTRACTING); 45 _lang_Testing = LangString(IDS_PROGRESS_TESTING); 46 _lang_Skipping = LangString(IDS_PROGRESS_SKIPPING); 47 _lang_Reading = "Reading"; 48 49 NumArchiveErrors = 0; 50 ThereAreMessageErrors = false; 51 #ifndef Z7_SFX 52 NumFolders = NumFiles = 0; 53 NeedAddFile = false; 54 #endif 55} 56 57void CExtractCallbackImp::AddError_Message(LPCWSTR s) 58{ 59 ThereAreMessageErrors = true; 60 ProgressDialog->Sync.AddError_Message(s); 61} 62 63#ifndef Z7_SFX 64 65Z7_COM7F_IMF(CExtractCallbackImp::SetNumFiles(UInt64 numFiles)) 66{ 67 #ifdef Z7_SFX 68 UNUSED_VAR(numFiles) 69 #else 70 ProgressDialog->Sync.Set_NumFilesTotal(numFiles); 71 #endif 72 return S_OK; 73} 74 75#endif 76 77Z7_COM7F_IMF(CExtractCallbackImp::SetTotal(UInt64 total)) 78{ 79 ProgressDialog->Sync.Set_NumBytesTotal(total); 80 return S_OK; 81} 82 83Z7_COM7F_IMF(CExtractCallbackImp::SetCompleted(const UInt64 *value)) 84{ 85 return ProgressDialog->Sync.Set_NumBytesCur(value); 86} 87 88HRESULT CExtractCallbackImp::Open_CheckBreak() 89{ 90 return ProgressDialog->Sync.CheckStop(); 91} 92 93HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 *files, const UInt64 *bytes) 94{ 95 HRESULT res = S_OK; 96 if (!MultiArcMode) 97 { 98 if (files) 99 { 100 _totalFilesDefined = true; 101 // res = ProgressDialog->Sync.Set_NumFilesTotal(*files); 102 } 103 else 104 _totalFilesDefined = false; 105 106 if (bytes) 107 { 108 _totalBytesDefined = true; 109 ProgressDialog->Sync.Set_NumBytesTotal(*bytes); 110 } 111 else 112 _totalBytesDefined = false; 113 } 114 115 return res; 116} 117 118HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) 119{ 120 if (!MultiArcMode) 121 { 122 if (files) 123 { 124 ProgressDialog->Sync.Set_NumFilesCur(*files); 125 } 126 127 if (bytes) 128 { 129 } 130 } 131 132 return ProgressDialog->Sync.CheckStop(); 133} 134 135HRESULT CExtractCallbackImp::Open_Finished() 136{ 137 return ProgressDialog->Sync.CheckStop(); 138} 139 140#ifndef Z7_NO_CRYPTO 141 142HRESULT CExtractCallbackImp::Open_CryptoGetTextPassword(BSTR *password) 143{ 144 return CryptoGetTextPassword(password); 145} 146 147/* 148HRESULT CExtractCallbackImp::Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password) 149{ 150 passwordIsDefined = PasswordIsDefined; 151 password = Password; 152 return S_OK; 153} 154 155bool CExtractCallbackImp::Open_WasPasswordAsked() 156{ 157 return PasswordWasAsked; 158} 159 160void CExtractCallbackImp::Open_Clear_PasswordWasAsked_Flag() 161{ 162 PasswordWasAsked = false; 163} 164*/ 165 166#endif 167 168 169#ifndef Z7_SFX 170Z7_COM7F_IMF(CExtractCallbackImp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) 171{ 172 ProgressDialog->Sync.Set_Ratio(inSize, outSize); 173 return S_OK; 174} 175#endif 176 177/* 178Z7_COM7F_IMF(CExtractCallbackImp::SetTotalFiles(UInt64 total) 179{ 180 ProgressDialog->Sync.SetNumFilesTotal(total); 181 return S_OK; 182} 183 184Z7_COM7F_IMF(CExtractCallbackImp::SetCompletedFiles(const UInt64 *value) 185{ 186 if (value != NULL) 187 ProgressDialog->Sync.SetNumFilesCur(*value); 188 return S_OK; 189} 190*/ 191 192Z7_COM7F_IMF(CExtractCallbackImp::AskOverwrite( 193 const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, 194 const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, 195 Int32 *answer)) 196{ 197 COverwriteDialog dialog; 198 199 dialog.OldFileInfo.SetTime(existTime); 200 dialog.OldFileInfo.SetSize(existSize); 201 dialog.OldFileInfo.Name = existName; 202 203 dialog.NewFileInfo.SetTime(newTime); 204 dialog.NewFileInfo.SetSize(newSize); 205 dialog.NewFileInfo.Name = newName; 206 207 ProgressDialog->WaitCreating(); 208 INT_PTR writeAnswer = dialog.Create(*ProgressDialog); 209 210 switch (writeAnswer) 211 { 212 case IDCANCEL: *answer = NOverwriteAnswer::kCancel; return E_ABORT; 213 case IDYES: *answer = NOverwriteAnswer::kYes; break; 214 case IDNO: *answer = NOverwriteAnswer::kNo; break; 215 case IDB_YES_TO_ALL: *answer = NOverwriteAnswer::kYesToAll; break; 216 case IDB_NO_TO_ALL: *answer = NOverwriteAnswer::kNoToAll; break; 217 case IDB_AUTO_RENAME: *answer = NOverwriteAnswer::kAutoRename; break; 218 default: return E_FAIL; 219 } 220 return S_OK; 221} 222 223 224Z7_COM7F_IMF(CExtractCallbackImp::PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 * /* position */)) 225{ 226 _isFolder = IntToBool(isFolder); 227 _currentFilePath = name; 228 229 const UString *msg = &_lang_Empty; 230 switch (askExtractMode) 231 { 232 case NArchive::NExtract::NAskMode::kExtract: msg = &_lang_Extracting; break; 233 case NArchive::NExtract::NAskMode::kTest: msg = &_lang_Testing; break; 234 case NArchive::NExtract::NAskMode::kSkip: msg = &_lang_Skipping; break; 235 case NArchive::NExtract::NAskMode::kReadExternal: msg = &_lang_Reading; break; 236 // default: s = "Unknown operation"; 237 } 238 239 return ProgressDialog->Sync.Set_Status2(*msg, name, IntToBool(isFolder)); 240} 241 242Z7_COM7F_IMF(CExtractCallbackImp::MessageError(const wchar_t *s)) 243{ 244 AddError_Message(s); 245 return S_OK; 246} 247 248HRESULT CExtractCallbackImp::MessageError(const char *message, const FString &path) 249{ 250 ThereAreMessageErrors = true; 251 ProgressDialog->Sync.AddError_Message_Name(GetUnicodeString(message), fs2us(path)); 252 return S_OK; 253} 254 255#ifndef Z7_SFX 256 257Z7_COM7F_IMF(CExtractCallbackImp::ShowMessage(const wchar_t *s)) 258{ 259 AddError_Message(s); 260 return S_OK; 261} 262 263#endif 264 265void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s); 266void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s) 267{ 268 s.Empty(); 269 270 if (opRes == NArchive::NExtract::NOperationResult::kOK) 271 return; 272 273 #ifndef Z7_SFX 274 UINT messageID = 0; 275 #endif 276 UINT id = 0; 277 278 switch (opRes) 279 { 280 case NArchive::NExtract::NOperationResult::kUnsupportedMethod: 281 #ifndef Z7_SFX 282 messageID = IDS_EXTRACT_MESSAGE_UNSUPPORTED_METHOD; 283 #endif 284 id = IDS_EXTRACT_MSG_UNSUPPORTED_METHOD; 285 break; 286 case NArchive::NExtract::NOperationResult::kDataError: 287 #ifndef Z7_SFX 288 messageID = encrypted ? 289 IDS_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED: 290 IDS_EXTRACT_MESSAGE_DATA_ERROR; 291 #endif 292 id = IDS_EXTRACT_MSG_DATA_ERROR; 293 break; 294 case NArchive::NExtract::NOperationResult::kCRCError: 295 #ifndef Z7_SFX 296 messageID = encrypted ? 297 IDS_EXTRACT_MESSAGE_CRC_ERROR_ENCRYPTED: 298 IDS_EXTRACT_MESSAGE_CRC_ERROR; 299 #endif 300 id = IDS_EXTRACT_MSG_CRC_ERROR; 301 break; 302 case NArchive::NExtract::NOperationResult::kUnavailable: 303 id = IDS_EXTRACT_MSG_UNAVAILABLE_DATA; 304 break; 305 case NArchive::NExtract::NOperationResult::kUnexpectedEnd: 306 id = IDS_EXTRACT_MSG_UEXPECTED_END; 307 break; 308 case NArchive::NExtract::NOperationResult::kDataAfterEnd: 309 id = IDS_EXTRACT_MSG_DATA_AFTER_END; 310 break; 311 case NArchive::NExtract::NOperationResult::kIsNotArc: 312 id = IDS_EXTRACT_MSG_IS_NOT_ARC; 313 break; 314 case NArchive::NExtract::NOperationResult::kHeadersError: 315 id = IDS_EXTRACT_MSG_HEADERS_ERROR; 316 break; 317 case NArchive::NExtract::NOperationResult::kWrongPassword: 318 id = IDS_EXTRACT_MSG_WRONG_PSW_CLAIM; 319 break; 320 /* 321 default: 322 messageID = IDS_EXTRACT_MESSAGE_UNKNOWN_ERROR; 323 break; 324 */ 325 } 326 327 UString msg; 328 329 #ifndef Z7_SFX 330 UString msgOld; 331 #ifdef Z7_LANG 332 if (id != 0) 333 LangString_OnlyFromLangFile(id, msg); 334 if (messageID != 0 && msg.IsEmpty()) 335 LangString_OnlyFromLangFile(messageID, msgOld); 336 #endif 337 if (msg.IsEmpty() && !msgOld.IsEmpty()) 338 s = MyFormatNew(msgOld, fileName); 339 else 340 #endif 341 { 342 if (msg.IsEmpty() && id != 0) 343 LangString(id, msg); 344 if (!msg.IsEmpty()) 345 s += msg; 346 else 347 { 348 s += "Error #"; 349 s.Add_UInt32((UInt32)opRes); 350 } 351 352 if (encrypted && opRes != NArchive::NExtract::NOperationResult::kWrongPassword) 353 { 354 // s += " : "; 355 // AddLangString(s, IDS_EXTRACT_MSG_ENCRYPTED); 356 s += " : "; 357 AddLangString(s, IDS_EXTRACT_MSG_WRONG_PSW_GUESS); 358 } 359 s += " : "; 360 s += fileName; 361 } 362} 363 364Z7_COM7F_IMF(CExtractCallbackImp::SetOperationResult(Int32 opRes, Int32 encrypted)) 365{ 366 switch (opRes) 367 { 368 case NArchive::NExtract::NOperationResult::kOK: 369 break; 370 default: 371 { 372 UString s; 373 SetExtractErrorMessage(opRes, encrypted, _currentFilePath, s); 374 Add_ArchiveName_Error(); 375 AddError_Message(s); 376 } 377 } 378 379 #ifndef Z7_SFX 380 if (_isFolder) 381 NumFolders++; 382 else 383 NumFiles++; 384 ProgressDialog->Sync.Set_NumFilesCur(NumFiles); 385 #endif 386 387 return S_OK; 388} 389 390Z7_COM7F_IMF(CExtractCallbackImp::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)) 391{ 392 if (opRes != NArchive::NExtract::NOperationResult::kOK) 393 { 394 UString s; 395 SetExtractErrorMessage(opRes, encrypted, name, s); 396 Add_ArchiveName_Error(); 397 AddError_Message(s); 398 } 399 return S_OK; 400} 401 402//////////////////////////////////////// 403// IExtractCallbackUI 404 405HRESULT CExtractCallbackImp::BeforeOpen(const wchar_t *name, bool /* testMode */) 406{ 407 #ifndef Z7_SFX 408 RINOK(ProgressDialog->Sync.CheckStop()) 409 ProgressDialog->Sync.Set_TitleFileName(name); 410 #endif 411 _currentArchivePath = name; 412 return S_OK; 413} 414 415HRESULT CExtractCallbackImp::SetCurrentFilePath2(const wchar_t *path) 416{ 417 _currentFilePath = path; 418 #ifndef Z7_SFX 419 ProgressDialog->Sync.Set_FilePath(path); 420 #endif 421 return S_OK; 422} 423 424#ifndef Z7_SFX 425 426Z7_COM7F_IMF(CExtractCallbackImp::SetCurrentFilePath(const wchar_t *path)) 427{ 428 #ifndef Z7_SFX 429 if (NeedAddFile) 430 NumFiles++; 431 NeedAddFile = true; 432 ProgressDialog->Sync.Set_NumFilesCur(NumFiles); 433 #endif 434 return SetCurrentFilePath2(path); 435} 436 437#endif 438 439UString HResultToMessage(HRESULT errorCode); 440 441static const UInt32 k_ErrorFlagsIds[] = 442{ 443 IDS_EXTRACT_MSG_IS_NOT_ARC, 444 IDS_EXTRACT_MSG_HEADERS_ERROR, 445 IDS_EXTRACT_MSG_HEADERS_ERROR, 446 IDS_OPEN_MSG_UNAVAILABLE_START, 447 IDS_OPEN_MSG_UNCONFIRMED_START, 448 IDS_EXTRACT_MSG_UEXPECTED_END, 449 IDS_EXTRACT_MSG_DATA_AFTER_END, 450 IDS_EXTRACT_MSG_UNSUPPORTED_METHOD, 451 IDS_OPEN_MSG_UNSUPPORTED_FEATURE, 452 IDS_EXTRACT_MSG_DATA_ERROR, 453 IDS_EXTRACT_MSG_CRC_ERROR 454}; 455 456static void AddNewLineString(UString &s, const UString &m) 457{ 458 s += m; 459 s.Add_LF(); 460} 461 462UString GetOpenArcErrorMessage(UInt32 errorFlags); 463UString GetOpenArcErrorMessage(UInt32 errorFlags) 464{ 465 UString s; 466 467 for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_ErrorFlagsIds); i++) 468 { 469 UInt32 f = ((UInt32)1 << i); 470 if ((errorFlags & f) == 0) 471 continue; 472 UInt32 id = k_ErrorFlagsIds[i]; 473 UString m = LangString(id); 474 if (m.IsEmpty()) 475 continue; 476 if (f == kpv_ErrorFlags_EncryptedHeadersError) 477 { 478 m += " : "; 479 AddLangString(m, IDS_EXTRACT_MSG_WRONG_PSW_GUESS); 480 } 481 if (!s.IsEmpty()) 482 s.Add_LF(); 483 s += m; 484 errorFlags &= ~f; 485 } 486 487 if (errorFlags != 0) 488 { 489 char sz[16]; 490 sz[0] = '0'; 491 sz[1] = 'x'; 492 ConvertUInt32ToHex(errorFlags, sz + 2); 493 if (!s.IsEmpty()) 494 s.Add_LF(); 495 s += sz; 496 } 497 498 return s; 499} 500 501static void ErrorInfo_Print(UString &s, const CArcErrorInfo &er) 502{ 503 UInt32 errorFlags = er.GetErrorFlags(); 504 UInt32 warningFlags = er.GetWarningFlags(); 505 506 if (errorFlags != 0) 507 AddNewLineString(s, GetOpenArcErrorMessage(errorFlags)); 508 509 if (!er.ErrorMessage.IsEmpty()) 510 AddNewLineString(s, er.ErrorMessage); 511 512 if (warningFlags != 0) 513 { 514 s += GetNameOfProperty(kpidWarningFlags, L"Warnings"); 515 s += ":"; 516 s.Add_LF(); 517 AddNewLineString(s, GetOpenArcErrorMessage(warningFlags)); 518 } 519 520 if (!er.WarningMessage.IsEmpty()) 521 { 522 s += GetNameOfProperty(kpidWarning, L"Warning"); 523 s += ": "; 524 s += er.WarningMessage; 525 s.Add_LF(); 526 } 527} 528 529static UString GetBracedType(const wchar_t *type) 530{ 531 UString s ('['); 532 s += type; 533 s += ']'; 534 return s; 535} 536 537void OpenResult_GUI(UString &s, const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result); 538void OpenResult_GUI(UString &s, const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) 539{ 540 FOR_VECTOR (level, arcLink.Arcs) 541 { 542 const CArc &arc = arcLink.Arcs[level]; 543 const CArcErrorInfo &er = arc.ErrorInfo; 544 545 if (!er.IsThereErrorOrWarning() && er.ErrorFormatIndex < 0) 546 continue; 547 548 if (s.IsEmpty()) 549 { 550 s += name; 551 s.Add_LF(); 552 } 553 554 if (level != 0) 555 { 556 AddNewLineString(s, arc.Path); 557 } 558 559 ErrorInfo_Print(s, er); 560 561 if (er.ErrorFormatIndex >= 0) 562 { 563 AddNewLineString(s, GetNameOfProperty(kpidWarning, L"Warning")); 564 if (arc.FormatIndex == er.ErrorFormatIndex) 565 { 566 AddNewLineString(s, LangString(IDS_IS_OPEN_WITH_OFFSET)); 567 } 568 else 569 { 570 AddNewLineString(s, MyFormatNew(IDS_CANT_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(er.ErrorFormatIndex)))); 571 AddNewLineString(s, MyFormatNew(IDS_IS_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(arc.FormatIndex)))); 572 } 573 } 574 } 575 576 if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result != S_OK) 577 { 578 s += name; 579 s.Add_LF(); 580 if (!arcLink.Arcs.IsEmpty()) 581 AddNewLineString(s, arcLink.NonOpen_ArcPath); 582 583 if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result == S_FALSE) 584 { 585 UINT id = IDS_CANT_OPEN_ARCHIVE; 586 UString param; 587 if (arcLink.PasswordWasAsked) 588 id = IDS_CANT_OPEN_ENCRYPTED_ARCHIVE; 589 else if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) 590 { 591 id = IDS_CANT_OPEN_AS_TYPE; 592 param = GetBracedType(codecs->GetFormatNamePtr(arcLink.NonOpen_ErrorInfo.ErrorFormatIndex)); 593 } 594 UString s2 = MyFormatNew(id, param); 595 s2.Replace(L" ''", L""); 596 s2.Replace(L"''", L""); 597 s += s2; 598 } 599 else 600 s += HResultToMessage(result); 601 602 s.Add_LF(); 603 ErrorInfo_Print(s, arcLink.NonOpen_ErrorInfo); 604 } 605 606 if (!s.IsEmpty() && s.Back() == '\n') 607 s.DeleteBack(); 608} 609 610HRESULT CExtractCallbackImp::OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) 611{ 612 _currentArchivePath = name; 613 _needWriteArchivePath = true; 614 615 UString s; 616 OpenResult_GUI(s, codecs, arcLink, name, result); 617 if (!s.IsEmpty()) 618 { 619 NumArchiveErrors++; 620 AddError_Message(s); 621 _needWriteArchivePath = false; 622 } 623 624 return S_OK; 625} 626 627HRESULT CExtractCallbackImp::ThereAreNoFiles() 628{ 629 return S_OK; 630} 631 632void CExtractCallbackImp::Add_ArchiveName_Error() 633{ 634 if (_needWriteArchivePath) 635 { 636 if (!_currentArchivePath.IsEmpty()) 637 AddError_Message(_currentArchivePath); 638 _needWriteArchivePath = false; 639 } 640} 641 642HRESULT CExtractCallbackImp::ExtractResult(HRESULT result) 643{ 644 if (result == S_OK) 645 return result; 646 NumArchiveErrors++; 647 if (result == E_ABORT 648 || result == HRESULT_FROM_WIN32(ERROR_DISK_FULL) 649 ) 650 return result; 651 652 Add_ArchiveName_Error(); 653 if (!_currentFilePath.IsEmpty()) 654 MessageError(_currentFilePath); 655 MessageError(NError::MyFormatMessage(result)); 656 return S_OK; 657} 658 659#ifndef Z7_NO_CRYPTO 660 661HRESULT CExtractCallbackImp::SetPassword(const UString &password) 662{ 663 PasswordIsDefined = true; 664 Password = password; 665 return S_OK; 666} 667 668Z7_COM7F_IMF(CExtractCallbackImp::CryptoGetTextPassword(BSTR *password)) 669{ 670 PasswordWasAsked = true; 671 if (!PasswordIsDefined) 672 { 673 CPasswordDialog dialog; 674 #ifndef Z7_SFX 675 const bool showPassword = NExtract::Read_ShowPassword(); 676 dialog.ShowPassword = showPassword; 677 #endif 678 ProgressDialog->WaitCreating(); 679 if (dialog.Create(*ProgressDialog) != IDOK) 680 return E_ABORT; 681 Password = dialog.Password; 682 PasswordIsDefined = true; 683 #ifndef Z7_SFX 684 if (dialog.ShowPassword != showPassword) 685 NExtract::Save_ShowPassword(dialog.ShowPassword); 686 #endif 687 } 688 return StringToBstr(Password, password); 689} 690 691#endif 692 693#ifndef Z7_SFX 694 695Z7_COM7F_IMF(CExtractCallbackImp::AskWrite( 696 const wchar_t *srcPath, Int32 srcIsFolder, 697 const FILETIME *srcTime, const UInt64 *srcSize, 698 const wchar_t *destPath, 699 BSTR *destPathResult, 700 Int32 *writeAnswer)) 701{ 702 UString destPathResultTemp = destPath; 703 704 // RINOK(StringToBstr(destPath, destPathResult)); 705 706 *destPathResult = NULL; 707 *writeAnswer = BoolToInt(false); 708 709 FString destPathSys = us2fs(destPath); 710 const bool srcIsFolderSpec = IntToBool(srcIsFolder); 711 CFileInfo destFileInfo; 712 713 if (destFileInfo.Find(destPathSys)) 714 { 715 if (srcIsFolderSpec) 716 { 717 if (!destFileInfo.IsDir()) 718 { 719 RINOK(MessageError("Cannot replace file with folder with same name", destPathSys)) 720 return E_ABORT; 721 } 722 *writeAnswer = BoolToInt(false); 723 return S_OK; 724 } 725 726 if (destFileInfo.IsDir()) 727 { 728 RINOK(MessageError("Cannot replace folder with file with same name", destPathSys)) 729 *writeAnswer = BoolToInt(false); 730 return S_OK; 731 } 732 733 switch ((int)OverwriteMode) 734 { 735 case NExtract::NOverwriteMode::kSkip: 736 return S_OK; 737 case NExtract::NOverwriteMode::kAsk: 738 { 739 Int32 overwriteResult; 740 UString destPathSpec = destPath; 741 const int slashPos = destPathSpec.ReverseFind_PathSepar(); 742 destPathSpec.DeleteFrom((unsigned)(slashPos + 1)); 743 destPathSpec += fs2us(destFileInfo.Name); 744 745 RINOK(AskOverwrite( 746 destPathSpec, 747 &destFileInfo.MTime, &destFileInfo.Size, 748 srcPath, 749 srcTime, srcSize, 750 &overwriteResult)) 751 752 switch (overwriteResult) 753 { 754 case NOverwriteAnswer::kCancel: return E_ABORT; 755 case NOverwriteAnswer::kNo: return S_OK; 756 case NOverwriteAnswer::kNoToAll: OverwriteMode = NExtract::NOverwriteMode::kSkip; return S_OK; 757 case NOverwriteAnswer::kYes: break; 758 case NOverwriteAnswer::kYesToAll: OverwriteMode = NExtract::NOverwriteMode::kOverwrite; break; 759 case NOverwriteAnswer::kAutoRename: OverwriteMode = NExtract::NOverwriteMode::kRename; break; 760 default: 761 return E_FAIL; 762 } 763 break; 764 } 765 default: 766 break; 767 } 768 769 if (OverwriteMode == NExtract::NOverwriteMode::kRename) 770 { 771 if (!AutoRenamePath(destPathSys)) 772 { 773 RINOK(MessageError("Cannot create name for file", destPathSys)) 774 return E_ABORT; 775 } 776 destPathResultTemp = fs2us(destPathSys); 777 } 778 else 779 { 780 if (NFind::DoesFileExist_Raw(destPathSys)) 781 if (!NDir::DeleteFileAlways(destPathSys)) 782 if (GetLastError() != ERROR_FILE_NOT_FOUND) 783 { 784 RINOK(MessageError("Cannot delete output file", destPathSys)) 785 return E_ABORT; 786 } 787 } 788 } 789 *writeAnswer = BoolToInt(true); 790 return StringToBstr(destPathResultTemp, destPathResult); 791} 792 793 794Z7_COM7F_IMF(CExtractCallbackImp::UseExtractToStream(Int32 *res)) 795{ 796 *res = BoolToInt(StreamMode); 797 return S_OK; 798} 799 800static HRESULT GetTime(IGetProp *getProp, PROPID propID, FILETIME &ft, bool &ftDefined) 801{ 802 ftDefined = false; 803 NCOM::CPropVariant prop; 804 RINOK(getProp->GetProp(propID, &prop)) 805 if (prop.vt == VT_FILETIME) 806 { 807 ft = prop.filetime; 808 ftDefined = (ft.dwHighDateTime != 0 || ft.dwLowDateTime != 0); 809 } 810 else if (prop.vt != VT_EMPTY) 811 return E_FAIL; 812 return S_OK; 813} 814 815 816static HRESULT GetItemBoolProp(IGetProp *getProp, PROPID propID, bool &result) 817{ 818 NCOM::CPropVariant prop; 819 result = false; 820 RINOK(getProp->GetProp(propID, &prop)) 821 if (prop.vt == VT_BOOL) 822 result = VARIANT_BOOLToBool(prop.boolVal); 823 else if (prop.vt != VT_EMPTY) 824 return E_FAIL; 825 return S_OK; 826} 827 828 829Z7_COM7F_IMF(CExtractCallbackImp::GetStream7(const wchar_t *name, 830 Int32 isDir, 831 ISequentialOutStream **outStream, Int32 askExtractMode, 832 IGetProp *getProp)) 833{ 834 COM_TRY_BEGIN 835 *outStream = NULL; 836 _newVirtFileWasAdded = false; 837 _hashStreamWasUsed = false; 838 _needUpdateStat = false; 839 840 if (_hashStream) 841 _hashStreamSpec->ReleaseStream(); 842 843 GetItemBoolProp(getProp, kpidIsAltStream, _isAltStream); 844 845 if (!ProcessAltStreams && _isAltStream) 846 return S_OK; 847 848 _filePath = name; 849 _isFolder = IntToBool(isDir); 850 _curSize = 0; 851 _curSize_Defined = false; 852 853 UInt64 size = 0; 854 bool sizeDefined; 855 { 856 NCOM::CPropVariant prop; 857 RINOK(getProp->GetProp(kpidSize, &prop)) 858 sizeDefined = ConvertPropVariantToUInt64(prop, size); 859 } 860 861 if (sizeDefined) 862 { 863 _curSize = size; 864 _curSize_Defined = true; 865 } 866 867 if (askExtractMode != NArchive::NExtract::NAskMode::kExtract && 868 askExtractMode != NArchive::NExtract::NAskMode::kTest) 869 return S_OK; 870 871 _needUpdateStat = true; 872 873 CMyComPtr<ISequentialOutStream> outStreamLoc; 874 875 if (VirtFileSystem && askExtractMode == NArchive::NExtract::NAskMode::kExtract) 876 { 877 CVirtFile &file = VirtFileSystemSpec->AddNewFile(); 878 _newVirtFileWasAdded = true; 879 file.Name = name; 880 file.IsDir = IntToBool(isDir); 881 file.IsAltStream = _isAltStream; 882 file.Size = 0; 883 884 RINOK(GetTime(getProp, kpidCTime, file.CTime, file.CTimeDefined)) 885 RINOK(GetTime(getProp, kpidATime, file.ATime, file.ATimeDefined)) 886 RINOK(GetTime(getProp, kpidMTime, file.MTime, file.MTimeDefined)) 887 888 NCOM::CPropVariant prop; 889 RINOK(getProp->GetProp(kpidAttrib, &prop)) 890 if (prop.vt == VT_UI4) 891 { 892 file.Attrib = prop.ulVal; 893 file.AttribDefined = true; 894 } 895 // else if (isDir) file.Attrib = FILE_ATTRIBUTE_DIRECTORY; 896 897 file.ExpectedSize = 0; 898 if (sizeDefined) 899 file.ExpectedSize = size; 900 outStreamLoc = VirtFileSystem; 901 } 902 903 if (_hashStream) 904 { 905 { 906 _hashStreamSpec->SetStream(outStreamLoc); 907 outStreamLoc = _hashStream; 908 _hashStreamSpec->Init(true); 909 _hashStreamWasUsed = true; 910 } 911 } 912 913 if (outStreamLoc) 914 *outStream = outStreamLoc.Detach(); 915 return S_OK; 916 COM_TRY_END 917} 918 919Z7_COM7F_IMF(CExtractCallbackImp::PrepareOperation7(Int32 askExtractMode)) 920{ 921 COM_TRY_BEGIN 922 _needUpdateStat = ( 923 askExtractMode == NArchive::NExtract::NAskMode::kExtract 924 || askExtractMode == NArchive::NExtract::NAskMode::kTest 925 || askExtractMode == NArchive::NExtract::NAskMode::kReadExternal 926 ); 927 928 /* 929 _extractMode = false; 930 switch (askExtractMode) 931 { 932 case NArchive::NExtract::NAskMode::kExtract: 933 if (_testMode) 934 askExtractMode = NArchive::NExtract::NAskMode::kTest; 935 else 936 _extractMode = true; 937 break; 938 }; 939 */ 940 return SetCurrentFilePath2(_filePath); 941 COM_TRY_END 942} 943 944Z7_COM7F_IMF(CExtractCallbackImp::SetOperationResult8(Int32 opRes, Int32 encrypted, UInt64 size)) 945{ 946 COM_TRY_BEGIN 947 if (VirtFileSystem && _newVirtFileWasAdded) 948 { 949 // FIXME: probably we must request file size from VirtFileSystem 950 // _curSize = VirtFileSystem->GetLastFileSize() 951 // _curSize_Defined = true; 952 RINOK(VirtFileSystemSpec->CloseMemFile()) 953 } 954 if (_hashStream && _hashStreamWasUsed) 955 { 956 _hashStreamSpec->_hash->Final(_isFolder, _isAltStream, _filePath); 957 _curSize = _hashStreamSpec->GetSize(); 958 _curSize_Defined = true; 959 _hashStreamSpec->ReleaseStream(); 960 _hashStreamWasUsed = false; 961 } 962 else if (_hashCalc && _needUpdateStat) 963 { 964 _hashCalc->SetSize(size); // (_curSize) before 21.04 965 _hashCalc->Final(_isFolder, _isAltStream, _filePath); 966 } 967 return SetOperationResult(opRes, encrypted); 968 COM_TRY_END 969} 970 971 972 973// static const UInt32 kBlockSize = ((UInt32)1 << 31); 974 975Z7_COM7F_IMF(CVirtFileSystem::Write(const void *data, UInt32 size, UInt32 *processedSize)) 976{ 977 if (processedSize) 978 *processedSize = 0; 979 if (size == 0) 980 return S_OK; 981 if (!_fileMode) 982 { 983 CVirtFile &file = Files.Back(); 984 size_t rem = file.Data.Size() - (size_t)file.Size; 985 bool useMem = true; 986 if (rem < size) 987 { 988 UInt64 b = 0; 989 if (file.Data.Size() == 0) 990 b = file.ExpectedSize; 991 UInt64 a = file.Size + size; 992 if (b < a) 993 b = a; 994 a = (UInt64)file.Data.Size() * 2; 995 if (b < a) 996 b = a; 997 useMem = false; 998 const size_t b_sizet = (size_t)b; 999 if (b == b_sizet && b <= MaxTotalAllocSize) 1000 useMem = file.Data.ReAlloc_KeepData(b_sizet, (size_t)file.Size); 1001 } 1002 if (useMem) 1003 { 1004 memcpy(file.Data + file.Size, data, size); 1005 file.Size += size; 1006 if (processedSize) 1007 *processedSize = (UInt32)size; 1008 return S_OK; 1009 } 1010 _fileMode = true; 1011 } 1012 RINOK(FlushToDisk(false)) 1013 return _outFileStream->Write(data, size, processedSize); 1014} 1015 1016HRESULT CVirtFileSystem::FlushToDisk(bool closeLast) 1017{ 1018 if (!_outFileStream) 1019 { 1020 _outFileStreamSpec = new COutFileStream; 1021 _outFileStream = _outFileStreamSpec; 1022 } 1023 while (_numFlushed < Files.Size()) 1024 { 1025 const CVirtFile &file = Files[_numFlushed]; 1026 const FString path = DirPrefix + us2fs(Get_Correct_FsFile_Name(file.Name)); 1027 if (!_fileIsOpen) 1028 { 1029 if (!_outFileStreamSpec->Create(path, false)) 1030 { 1031 _outFileStream.Release(); 1032 return E_FAIL; 1033 // MessageBoxMyError(UString("Can't create file ") + fs2us(tempFilePath)); 1034 } 1035 _fileIsOpen = true; 1036 RINOK(WriteStream(_outFileStream, file.Data, (size_t)file.Size)) 1037 } 1038 if (_numFlushed == Files.Size() - 1 && !closeLast) 1039 break; 1040 if (file.CTimeDefined || 1041 file.ATimeDefined || 1042 file.MTimeDefined) 1043 _outFileStreamSpec->SetTime( 1044 file.CTimeDefined ? &file.CTime : NULL, 1045 file.ATimeDefined ? &file.ATime : NULL, 1046 file.MTimeDefined ? &file.MTime : NULL); 1047 _outFileStreamSpec->Close(); 1048 _numFlushed++; 1049 _fileIsOpen = false; 1050 if (file.AttribDefined) 1051 NDir::SetFileAttrib_PosixHighDetect(path, file.Attrib); 1052 } 1053 return S_OK; 1054} 1055 1056#endif 1057