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