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