1// ExtractCallbackConsole.cpp 2 3#include "StdAfx.h" 4 5#include "../../../Common/IntToString.h" 6#include "../../../Common/Wildcard.h" 7 8#include "../../../Windows/FileDir.h" 9#include "../../../Windows/FileFind.h" 10#include "../../../Windows/TimeUtils.h" 11#include "../../../Windows/ErrorMsg.h" 12#include "../../../Windows/PropVariantConv.h" 13 14#ifndef Z7_ST 15#include "../../../Windows/Synchronization.h" 16#endif 17 18#include "../../Common/FilePathAutoRename.h" 19 20#include "../Common/ExtractingFilePath.h" 21 22#include "ConsoleClose.h" 23#include "ExtractCallbackConsole.h" 24#include "UserInputUtils.h" 25 26using namespace NWindows; 27using namespace NFile; 28using namespace NDir; 29 30static HRESULT CheckBreak2() 31{ 32 return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK; 33} 34 35static const char * const kError = "ERROR: "; 36 37 38void CExtractScanConsole::StartScanning() 39{ 40 if (NeedPercents()) 41 _percent.Command = "Scan"; 42} 43 44HRESULT CExtractScanConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */) 45{ 46 if (NeedPercents()) 47 { 48 _percent.Files = st.NumDirs + st.NumFiles; 49 _percent.Completed = st.GetTotalBytes(); 50 _percent.FileName = fs2us(path); 51 _percent.Print(); 52 } 53 54 return CheckBreak2(); 55} 56 57HRESULT CExtractScanConsole::ScanError(const FString &path, DWORD systemError) 58{ 59 // 22.00: 60 // ScanErrors.AddError(path, systemError); 61 62 ClosePercentsAndFlush(); 63 64 if (_se) 65 { 66 *_se << endl << kError << NError::MyFormatMessage(systemError) << endl; 67 _se->NormalizePrint_UString(fs2us(path)); 68 *_se << endl << endl; 69 _se->Flush(); 70 } 71 return HRESULT_FROM_WIN32(systemError); 72 73 // 22.00: commented 74 // CommonError(path, systemError, true); 75 // return S_OK; 76} 77 78 79void Print_UInt64_and_String(AString &s, UInt64 val, const char *name); 80void Print_UInt64_and_String(AString &s, UInt64 val, const char *name) 81{ 82 char temp[32]; 83 ConvertUInt64ToString(val, temp); 84 s += temp; 85 s.Add_Space(); 86 s += name; 87} 88 89void PrintSize_bytes_Smart(AString &s, UInt64 val); 90void PrintSize_bytes_Smart(AString &s, UInt64 val) 91{ 92 Print_UInt64_and_String(s, val, "bytes"); 93 94 if (val == 0) 95 return; 96 97 unsigned numBits = 10; 98 char c = 'K'; 99 char temp[4] = { 'K', 'i', 'B', 0 }; 100 if (val >= ((UInt64)10 << 30)) { numBits = 30; c = 'G'; } 101 else if (val >= ((UInt64)10 << 20)) { numBits = 20; c = 'M'; } 102 temp[0] = c; 103 s += " ("; 104 Print_UInt64_and_String(s, ((val + ((UInt64)1 << numBits) - 1) >> numBits), temp); 105 s += ')'; 106} 107 108static void PrintSize_bytes_Smart_comma(AString &s, UInt64 val) 109{ 110 if (val == (UInt64)(Int64)-1) 111 return; 112 s += ", "; 113 PrintSize_bytes_Smart(s, val); 114} 115 116 117 118void Print_DirItemsStat(AString &s, const CDirItemsStat &st); 119void Print_DirItemsStat(AString &s, const CDirItemsStat &st) 120{ 121 if (st.NumDirs != 0) 122 { 123 Print_UInt64_and_String(s, st.NumDirs, st.NumDirs == 1 ? "folder" : "folders"); 124 s += ", "; 125 } 126 Print_UInt64_and_String(s, st.NumFiles, st.NumFiles == 1 ? "file" : "files"); 127 PrintSize_bytes_Smart_comma(s, st.FilesSize); 128 if (st.NumAltStreams != 0) 129 { 130 s.Add_LF(); 131 Print_UInt64_and_String(s, st.NumAltStreams, "alternate streams"); 132 PrintSize_bytes_Smart_comma(s, st.AltStreamsSize); 133 } 134} 135 136 137void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st); 138void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st) 139{ 140 Print_DirItemsStat(s, (CDirItemsStat &)st); 141 bool needLF = true; 142 if (st.Anti_NumDirs != 0) 143 { 144 if (needLF) 145 s.Add_LF(); 146 needLF = false; 147 Print_UInt64_and_String(s, st.Anti_NumDirs, st.Anti_NumDirs == 1 ? "anti-folder" : "anti-folders"); 148 } 149 if (st.Anti_NumFiles != 0) 150 { 151 if (needLF) 152 s.Add_LF(); 153 else 154 s += ", "; 155 needLF = false; 156 Print_UInt64_and_String(s, st.Anti_NumFiles, st.Anti_NumFiles == 1 ? "anti-file" : "anti-files"); 157 } 158 if (st.Anti_NumAltStreams != 0) 159 { 160 if (needLF) 161 s.Add_LF(); 162 else 163 s += ", "; 164 needLF = false; 165 Print_UInt64_and_String(s, st.Anti_NumAltStreams, "anti-alternate-streams"); 166 } 167} 168 169 170void CExtractScanConsole::PrintStat(const CDirItemsStat &st) 171{ 172 if (_so) 173 { 174 AString s; 175 Print_DirItemsStat(s, st); 176 *_so << s << endl; 177 } 178} 179 180 181 182 183 184 185 186#ifndef Z7_ST 187static NSynchronization::CCriticalSection g_CriticalSection; 188#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); 189#else 190#define MT_LOCK 191#endif 192 193 194static const char * const kTestString = "T"; 195static const char * const kExtractString = "-"; 196static const char * const kSkipString = "."; 197static const char * const kReadString = "H"; 198 199// static const char * const kCantAutoRename = "cannot create file with auto name\n"; 200// static const char * const kCantRenameFile = "cannot rename existing file\n"; 201// static const char * const kCantDeleteOutputFile = "cannot delete output file "; 202 203static const char * const kMemoryExceptionMessage = "Can't allocate required memory!"; 204 205static const char * const kExtracting = "Extracting archive: "; 206static const char * const kTesting = "Testing archive: "; 207 208static const char * const kEverythingIsOk = "Everything is Ok"; 209static const char * const kNoFiles = "No files to process"; 210 211static const char * const kUnsupportedMethod = "Unsupported Method"; 212static const char * const kCrcFailed = "CRC Failed"; 213static const char * const kCrcFailedEncrypted = "CRC Failed in encrypted file. Wrong password?"; 214static const char * const kDataError = "Data Error"; 215static const char * const kDataErrorEncrypted = "Data Error in encrypted file. Wrong password?"; 216static const char * const kUnavailableData = "Unavailable data"; 217static const char * const kUnexpectedEnd = "Unexpected end of data"; 218static const char * const kDataAfterEnd = "There are some data after the end of the payload data"; 219static const char * const kIsNotArc = "Is not archive"; 220static const char * const kHeadersError = "Headers Error"; 221static const char * const kWrongPassword = "Wrong password"; 222 223static const char * const k_ErrorFlagsMessages[] = 224{ 225 "Is not archive" 226 , "Headers Error" 227 , "Headers Error in encrypted archive. Wrong password?" 228 , "Unavailable start of archive" 229 , "Unconfirmed start of archive" 230 , "Unexpected end of archive" 231 , "There are data after the end of archive" 232 , "Unsupported method" 233 , "Unsupported feature" 234 , "Data Error" 235 , "CRC Error" 236}; 237 238Z7_COM7F_IMF(CExtractCallbackConsole::SetTotal(UInt64 size)) 239{ 240 MT_LOCK 241 242 if (NeedPercents()) 243 { 244 _percent.Total = size; 245 _percent.Print(); 246 } 247 return CheckBreak2(); 248} 249 250Z7_COM7F_IMF(CExtractCallbackConsole::SetCompleted(const UInt64 *completeValue)) 251{ 252 MT_LOCK 253 254 if (NeedPercents()) 255 { 256 if (completeValue) 257 _percent.Completed = *completeValue; 258 _percent.Print(); 259 } 260 return CheckBreak2(); 261} 262 263static const char * const kTab = " "; 264 265static void PrintFileInfo(CStdOutStream *_so, const wchar_t *path, const FILETIME *ft, const UInt64 *size) 266{ 267 *_so << kTab << "Path: "; 268 _so->NormalizePrint_wstr(path); 269 *_so << endl; 270 if (size && *size != (UInt64)(Int64)-1) 271 { 272 AString s; 273 PrintSize_bytes_Smart(s, *size); 274 *_so << kTab << "Size: " << s << endl; 275 } 276 if (ft) 277 { 278 char temp[64]; 279 if (ConvertUtcFileTimeToString(*ft, temp, kTimestampPrintLevel_SEC)) 280 *_so << kTab << "Modified: " << temp << endl; 281 } 282} 283 284Z7_COM7F_IMF(CExtractCallbackConsole::AskOverwrite( 285 const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, 286 const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, 287 Int32 *answer)) 288{ 289 MT_LOCK 290 291 RINOK(CheckBreak2()) 292 293 ClosePercentsAndFlush(); 294 295 if (_so) 296 { 297 *_so << endl << "Would you like to replace the existing file:\n"; 298 PrintFileInfo(_so, existName, existTime, existSize); 299 *_so << "with the file from archive:\n"; 300 PrintFileInfo(_so, newName, newTime, newSize); 301 } 302 303 NUserAnswerMode::EEnum overwriteAnswer = ScanUserYesNoAllQuit(_so); 304 305 switch ((int)overwriteAnswer) 306 { 307 case NUserAnswerMode::kQuit: return E_ABORT; 308 case NUserAnswerMode::kNo: *answer = NOverwriteAnswer::kNo; break; 309 case NUserAnswerMode::kNoAll: *answer = NOverwriteAnswer::kNoToAll; break; 310 case NUserAnswerMode::kYesAll: *answer = NOverwriteAnswer::kYesToAll; break; 311 case NUserAnswerMode::kYes: *answer = NOverwriteAnswer::kYes; break; 312 case NUserAnswerMode::kAutoRenameAll: *answer = NOverwriteAnswer::kAutoRename; break; 313 case NUserAnswerMode::kEof: return E_ABORT; 314 case NUserAnswerMode::kError: return E_FAIL; 315 default: return E_FAIL; 316 } 317 318 if (_so) 319 { 320 *_so << endl; 321 if (NeedFlush) 322 _so->Flush(); 323 } 324 325 return CheckBreak2(); 326} 327 328Z7_COM7F_IMF(CExtractCallbackConsole::PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 *position)) 329{ 330 MT_LOCK 331 332 _currentName = name; 333 334 const char *s; 335 unsigned requiredLevel = 1; 336 337 switch (askExtractMode) 338 { 339 case NArchive::NExtract::NAskMode::kExtract: s = kExtractString; break; 340 case NArchive::NExtract::NAskMode::kTest: s = kTestString; break; 341 case NArchive::NExtract::NAskMode::kSkip: s = kSkipString; requiredLevel = 2; break; 342 case NArchive::NExtract::NAskMode::kReadExternal: s = kReadString; requiredLevel = 0; break; 343 default: s = "???"; requiredLevel = 2; 344 } 345 346 bool show2 = (LogLevel >= requiredLevel && _so); 347 348 if (show2) 349 { 350 ClosePercents_for_so(); 351 352 _tempA = s; 353 if (name) 354 _tempA.Add_Space(); 355 *_so << _tempA; 356 357 _tempU.Empty(); 358 if (name) 359 { 360 _tempU = name; 361 _so->Normalize_UString(_tempU); 362 // 21.04 363 if (isFolder) 364 { 365 if (!_tempU.IsEmpty() && _tempU.Back() != WCHAR_PATH_SEPARATOR) 366 _tempU.Add_PathSepar(); 367 } 368 } 369 _so->PrintUString(_tempU, _tempA); 370 if (position) 371 *_so << " <" << *position << ">"; 372 *_so << endl; 373 374 if (NeedFlush) 375 _so->Flush(); 376 } 377 378 if (NeedPercents()) 379 { 380 if (PercentsNameLevel >= 1) 381 { 382 _percent.FileName.Empty(); 383 _percent.Command.Empty(); 384 if (PercentsNameLevel > 1 || !show2) 385 { 386 _percent.Command = s; 387 if (name) 388 _percent.FileName = name; 389 } 390 } 391 _percent.Print(); 392 } 393 394 return CheckBreak2(); 395} 396 397Z7_COM7F_IMF(CExtractCallbackConsole::MessageError(const wchar_t *message)) 398{ 399 MT_LOCK 400 401 RINOK(CheckBreak2()) 402 403 NumFileErrors_in_Current++; 404 NumFileErrors++; 405 406 ClosePercentsAndFlush(); 407 if (_se) 408 { 409 *_se << kError << message << endl; 410 _se->Flush(); 411 } 412 413 return CheckBreak2(); 414} 415 416void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest); 417void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest) 418{ 419 dest.Empty(); 420 const char *s = NULL; 421 422 switch (opRes) 423 { 424 case NArchive::NExtract::NOperationResult::kUnsupportedMethod: 425 s = kUnsupportedMethod; 426 break; 427 case NArchive::NExtract::NOperationResult::kCRCError: 428 s = (encrypted ? kCrcFailedEncrypted : kCrcFailed); 429 break; 430 case NArchive::NExtract::NOperationResult::kDataError: 431 s = (encrypted ? kDataErrorEncrypted : kDataError); 432 break; 433 case NArchive::NExtract::NOperationResult::kUnavailable: 434 s = kUnavailableData; 435 break; 436 case NArchive::NExtract::NOperationResult::kUnexpectedEnd: 437 s = kUnexpectedEnd; 438 break; 439 case NArchive::NExtract::NOperationResult::kDataAfterEnd: 440 s = kDataAfterEnd; 441 break; 442 case NArchive::NExtract::NOperationResult::kIsNotArc: 443 s = kIsNotArc; 444 break; 445 case NArchive::NExtract::NOperationResult::kHeadersError: 446 s = kHeadersError; 447 break; 448 case NArchive::NExtract::NOperationResult::kWrongPassword: 449 s = kWrongPassword; 450 break; 451 } 452 453 dest += kError; 454 if (s) 455 dest += s; 456 else 457 { 458 dest += "Error #"; 459 dest.Add_UInt32((UInt32)opRes); 460 } 461} 462 463Z7_COM7F_IMF(CExtractCallbackConsole::SetOperationResult(Int32 opRes, Int32 encrypted)) 464{ 465 MT_LOCK 466 467 if (opRes == NArchive::NExtract::NOperationResult::kOK) 468 { 469 if (NeedPercents()) 470 { 471 _percent.Command.Empty(); 472 _percent.FileName.Empty(); 473 _percent.Files++; 474 } 475 } 476 else 477 { 478 NumFileErrors_in_Current++; 479 NumFileErrors++; 480 481 if (_se) 482 { 483 ClosePercentsAndFlush(); 484 485 AString s; 486 SetExtractErrorMessage(opRes, encrypted, s); 487 488 *_se << s; 489 if (!_currentName.IsEmpty()) 490 { 491 *_se << " : "; 492 _se->NormalizePrint_UString(_currentName); 493 } 494 *_se << endl; 495 _se->Flush(); 496 } 497 } 498 499 return CheckBreak2(); 500} 501 502Z7_COM7F_IMF(CExtractCallbackConsole::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)) 503{ 504 if (opRes != NArchive::NExtract::NOperationResult::kOK) 505 { 506 _currentName = name; 507 return SetOperationResult(opRes, encrypted); 508 } 509 510 return CheckBreak2(); 511} 512 513 514 515#ifndef Z7_NO_CRYPTO 516 517HRESULT CExtractCallbackConsole::SetPassword(const UString &password) 518{ 519 PasswordIsDefined = true; 520 Password = password; 521 return S_OK; 522} 523 524Z7_COM7F_IMF(CExtractCallbackConsole::CryptoGetTextPassword(BSTR *password)) 525{ 526 COM_TRY_BEGIN 527 MT_LOCK 528 return Open_CryptoGetTextPassword(password); 529 COM_TRY_END 530} 531 532#endif 533 534HRESULT CExtractCallbackConsole::BeforeOpen(const wchar_t *name, bool testMode) 535{ 536 RINOK(CheckBreak2()) 537 538 NumTryArcs++; 539 ThereIsError_in_Current = false; 540 ThereIsWarning_in_Current = false; 541 NumFileErrors_in_Current = 0; 542 543 ClosePercents_for_so(); 544 if (_so) 545 { 546 *_so << endl << (testMode ? kTesting : kExtracting); 547 _so->NormalizePrint_wstr(name); 548 *_so << endl; 549 } 550 551 if (NeedPercents()) 552 _percent.Command = "Open"; 553 return S_OK; 554} 555 556HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); 557HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); 558 559static AString GetOpenArcErrorMessage(UInt32 errorFlags) 560{ 561 AString s; 562 563 for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_ErrorFlagsMessages); i++) 564 { 565 UInt32 f = (1 << i); 566 if ((errorFlags & f) == 0) 567 continue; 568 const char *m = k_ErrorFlagsMessages[i]; 569 if (!s.IsEmpty()) 570 s.Add_LF(); 571 s += m; 572 errorFlags &= ~f; 573 } 574 575 if (errorFlags != 0) 576 { 577 char sz[16]; 578 sz[0] = '0'; 579 sz[1] = 'x'; 580 ConvertUInt32ToHex(errorFlags, sz + 2); 581 if (!s.IsEmpty()) 582 s.Add_LF(); 583 s += sz; 584 } 585 586 return s; 587} 588 589void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags); 590void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags) 591{ 592 if (errorFlags == 0) 593 return; 594 so << s << endl << GetOpenArcErrorMessage(errorFlags) << endl; 595} 596 597static void Add_Messsage_Pre_ArcType(UString &s, const char *pre, const wchar_t *arcType) 598{ 599 s.Add_LF(); 600 s += pre; 601 s += " as ["; 602 s += arcType; 603 s += "] archive"; 604} 605 606void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc); 607void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc) 608{ 609 const CArcErrorInfo &er = arc.ErrorInfo; 610 611 *_so << "WARNING:\n"; 612 _so->NormalizePrint_UString(arc.Path); 613 UString s; 614 if (arc.FormatIndex == er.ErrorFormatIndex) 615 { 616 s.Add_LF(); 617 s += "The archive is open with offset"; 618 } 619 else 620 { 621 Add_Messsage_Pre_ArcType(s, "Cannot open the file", codecs->GetFormatNamePtr(er.ErrorFormatIndex)); 622 Add_Messsage_Pre_ArcType(s, "The file is open", codecs->GetFormatNamePtr(arc.FormatIndex)); 623 } 624 625 *_so << s << endl << endl; 626} 627 628 629HRESULT CExtractCallbackConsole::OpenResult( 630 const CCodecs *codecs, const CArchiveLink &arcLink, 631 const wchar_t *name, HRESULT result) 632{ 633 ClosePercents(); 634 635 if (NeedPercents()) 636 { 637 _percent.Files = 0; 638 _percent.Command.Empty(); 639 _percent.FileName.Empty(); 640 } 641 642 643 ClosePercentsAndFlush(); 644 645 FOR_VECTOR (level, arcLink.Arcs) 646 { 647 const CArc &arc = arcLink.Arcs[level]; 648 const CArcErrorInfo &er = arc.ErrorInfo; 649 650 UInt32 errorFlags = er.GetErrorFlags(); 651 652 if (errorFlags != 0 || !er.ErrorMessage.IsEmpty()) 653 { 654 if (_se) 655 { 656 *_se << endl; 657 if (level != 0) 658 { 659 _se->NormalizePrint_UString(arc.Path); 660 *_se << endl; 661 } 662 } 663 664 if (errorFlags != 0) 665 { 666 if (_se) 667 PrintErrorFlags(*_se, "ERRORS:", errorFlags); 668 NumOpenArcErrors++; 669 ThereIsError_in_Current = true; 670 } 671 672 if (!er.ErrorMessage.IsEmpty()) 673 { 674 if (_se) 675 *_se << "ERRORS:" << endl << er.ErrorMessage << endl; 676 NumOpenArcErrors++; 677 ThereIsError_in_Current = true; 678 } 679 680 if (_se) 681 { 682 *_se << endl; 683 _se->Flush(); 684 } 685 } 686 687 UInt32 warningFlags = er.GetWarningFlags(); 688 689 if (warningFlags != 0 || !er.WarningMessage.IsEmpty()) 690 { 691 if (_so) 692 { 693 *_so << endl; 694 if (level != 0) 695 { 696 _so->NormalizePrint_UString(arc.Path); 697 *_so << endl; 698 } 699 } 700 701 if (warningFlags != 0) 702 { 703 if (_so) 704 PrintErrorFlags(*_so, "WARNINGS:", warningFlags); 705 NumOpenArcWarnings++; 706 ThereIsWarning_in_Current = true; 707 } 708 709 if (!er.WarningMessage.IsEmpty()) 710 { 711 if (_so) 712 *_so << "WARNINGS:" << endl << er.WarningMessage << endl; 713 NumOpenArcWarnings++; 714 ThereIsWarning_in_Current = true; 715 } 716 717 if (_so) 718 { 719 *_so << endl; 720 if (NeedFlush) 721 _so->Flush(); 722 } 723 } 724 725 726 if (er.ErrorFormatIndex >= 0) 727 { 728 if (_so) 729 { 730 Print_ErrorFormatIndex_Warning(_so, codecs, arc); 731 if (NeedFlush) 732 _so->Flush(); 733 } 734 ThereIsWarning_in_Current = true; 735 } 736 } 737 738 if (result == S_OK) 739 { 740 if (_so) 741 { 742 RINOK(Print_OpenArchive_Props(*_so, codecs, arcLink)) 743 *_so << endl; 744 } 745 } 746 else 747 { 748 NumCantOpenArcs++; 749 if (_so) 750 _so->Flush(); 751 if (_se) 752 { 753 *_se << kError; 754 _se->NormalizePrint_wstr(name); 755 *_se << endl; 756 const HRESULT res = Print_OpenArchive_Error(*_se, codecs, arcLink); 757 RINOK(res) 758 if (result == S_FALSE) 759 { 760 } 761 else 762 { 763 if (result == E_OUTOFMEMORY) 764 *_se << "Can't allocate required memory"; 765 else 766 *_se << NError::MyFormatMessage(result); 767 *_se << endl; 768 } 769 _se->Flush(); 770 } 771 } 772 773 774 return CheckBreak2(); 775} 776 777HRESULT CExtractCallbackConsole::ThereAreNoFiles() 778{ 779 ClosePercents_for_so(); 780 781 if (_so) 782 { 783 *_so << endl << kNoFiles << endl; 784 if (NeedFlush) 785 _so->Flush(); 786 } 787 return CheckBreak2(); 788} 789 790HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result) 791{ 792 MT_LOCK 793 794 if (NeedPercents()) 795 { 796 _percent.ClosePrint(true); 797 _percent.Command.Empty(); 798 _percent.FileName.Empty(); 799 } 800 801 if (_so) 802 _so->Flush(); 803 804 if (result == S_OK) 805 { 806 if (NumFileErrors_in_Current == 0 && !ThereIsError_in_Current) 807 { 808 if (ThereIsWarning_in_Current) 809 NumArcsWithWarnings++; 810 else 811 NumOkArcs++; 812 if (_so) 813 *_so << kEverythingIsOk << endl; 814 } 815 else 816 { 817 NumArcsWithError++; 818 if (_so) 819 { 820 *_so << endl; 821 if (NumFileErrors_in_Current != 0) 822 *_so << "Sub items Errors: " << NumFileErrors_in_Current << endl; 823 } 824 } 825 if (_so && NeedFlush) 826 _so->Flush(); 827 } 828 else 829 { 830 NumArcsWithError++; 831 if (result == E_ABORT 832 || result == HRESULT_FROM_WIN32(ERROR_DISK_FULL) 833 ) 834 return result; 835 836 if (_se) 837 { 838 *_se << endl << kError; 839 if (result == E_OUTOFMEMORY) 840 *_se << kMemoryExceptionMessage; 841 else 842 *_se << NError::MyFormatMessage(result); 843 *_se << endl; 844 _se->Flush(); 845 } 846 } 847 848 return CheckBreak2(); 849} 850