1// UpdateCallbackConsole.cpp 2 3#include "StdAfx.h" 4 5#include "../../../Common/IntToString.h" 6 7#include "../../../Windows/ErrorMsg.h" 8#include "../../../Windows/FileName.h" 9 10#ifndef Z7_ST 11#include "../../../Windows/Synchronization.h" 12#endif 13 14// #include "../Common/PropIDUtils.h" 15 16#include "ConsoleClose.h" 17#include "UserInputUtils.h" 18#include "UpdateCallbackConsole.h" 19 20using namespace NWindows; 21 22#ifndef Z7_ST 23static NSynchronization::CCriticalSection g_CriticalSection; 24#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); 25#else 26#define MT_LOCK 27#endif 28 29static const wchar_t * const kEmptyFileAlias = L"[Content]"; 30 31static const char * const kOpenArchiveMessage = "Open archive: "; 32static const char * const kCreatingArchiveMessage = "Creating archive: "; 33static const char * const kUpdatingArchiveMessage = "Updating archive: "; 34static const char * const kScanningMessage = "Scanning the drive:"; 35 36static const char * const kError = "ERROR: "; 37static const char * const kWarning = "WARNING: "; 38 39static HRESULT CheckBreak2() 40{ 41 return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK; 42} 43 44HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); 45HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); 46 47void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags); 48 49void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc); 50 51HRESULT CUpdateCallbackConsole::OpenResult( 52 const CCodecs *codecs, const CArchiveLink &arcLink, 53 const wchar_t *name, HRESULT result) 54{ 55 ClosePercents2(); 56 57 FOR_VECTOR (level, arcLink.Arcs) 58 { 59 const CArc &arc = arcLink.Arcs[level]; 60 const CArcErrorInfo &er = arc.ErrorInfo; 61 62 UInt32 errorFlags = er.GetErrorFlags(); 63 64 if (errorFlags != 0 || !er.ErrorMessage.IsEmpty()) 65 { 66 if (_se) 67 { 68 *_se << endl; 69 if (level != 0) 70 *_se << arc.Path << endl; 71 } 72 73 if (errorFlags != 0) 74 { 75 if (_se) 76 PrintErrorFlags(*_se, "ERRORS:", errorFlags); 77 } 78 79 if (!er.ErrorMessage.IsEmpty()) 80 { 81 if (_se) 82 *_se << "ERRORS:" << endl << er.ErrorMessage << endl; 83 } 84 85 if (_se) 86 { 87 *_se << endl; 88 _se->Flush(); 89 } 90 } 91 92 UInt32 warningFlags = er.GetWarningFlags(); 93 94 if (warningFlags != 0 || !er.WarningMessage.IsEmpty()) 95 { 96 if (_so) 97 { 98 *_so << endl; 99 if (level != 0) 100 *_so << arc.Path << endl; 101 } 102 103 if (warningFlags != 0) 104 { 105 if (_so) 106 PrintErrorFlags(*_so, "WARNINGS:", warningFlags); 107 } 108 109 if (!er.WarningMessage.IsEmpty()) 110 { 111 if (_so) 112 *_so << "WARNINGS:" << endl << er.WarningMessage << endl; 113 } 114 115 if (_so) 116 { 117 *_so << endl; 118 if (NeedFlush) 119 _so->Flush(); 120 } 121 } 122 123 124 if (er.ErrorFormatIndex >= 0) 125 { 126 if (_so) 127 { 128 Print_ErrorFormatIndex_Warning(_so, codecs, arc); 129 if (NeedFlush) 130 _so->Flush(); 131 } 132 } 133 } 134 135 if (result == S_OK) 136 { 137 if (_so) 138 { 139 RINOK(Print_OpenArchive_Props(*_so, codecs, arcLink)) 140 *_so << endl; 141 } 142 } 143 else 144 { 145 if (_so) 146 _so->Flush(); 147 if (_se) 148 { 149 *_se << kError; 150 _se->NormalizePrint_wstr(name); 151 *_se << endl; 152 HRESULT res = Print_OpenArchive_Error(*_se, codecs, arcLink); 153 RINOK(res) 154 _se->Flush(); 155 } 156 } 157 158 return S_OK; 159} 160 161HRESULT CUpdateCallbackConsole::StartScanning() 162{ 163 if (_so) 164 *_so << kScanningMessage << endl; 165 _percent.Command = "Scan "; 166 return S_OK; 167} 168 169HRESULT CUpdateCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */) 170{ 171 if (NeedPercents()) 172 { 173 _percent.Files = st.NumDirs + st.NumFiles + st.NumAltStreams; 174 _percent.Completed = st.GetTotalBytes(); 175 _percent.FileName = fs2us(path); 176 _percent.Print(); 177 } 178 179 return CheckBreak(); 180} 181 182void CCallbackConsoleBase::CommonError(const FString &path, DWORD systemError, bool isWarning) 183{ 184 ClosePercents2(); 185 186 if (_se) 187 { 188 if (_so) 189 _so->Flush(); 190 191 *_se << endl << (isWarning ? kWarning : kError) 192 << NError::MyFormatMessage(systemError) 193 << endl; 194 _se->NormalizePrint_UString(fs2us(path)); 195 *_se << endl << endl; 196 _se->Flush(); 197 } 198} 199 200/* 201void CCallbackConsoleBase::CommonError(const char *message) 202{ 203 ClosePercents2(); 204 205 if (_se) 206 { 207 if (_so) 208 _so->Flush(); 209 210 *_se << endl << kError << message << endl; 211 _se->Flush(); 212 } 213} 214*/ 215 216 217HRESULT CCallbackConsoleBase::ScanError_Base(const FString &path, DWORD systemError) 218{ 219 MT_LOCK 220 221 ScanErrors.AddError(path, systemError); 222 CommonError(path, systemError, true); 223 224 return S_OK; 225} 226 227HRESULT CCallbackConsoleBase::OpenFileError_Base(const FString &path, DWORD systemError) 228{ 229 MT_LOCK 230 FailedFiles.AddError(path, systemError); 231 NumNonOpenFiles++; 232 /* 233 if (systemError == ERROR_SHARING_VIOLATION) 234 { 235 */ 236 CommonError(path, systemError, true); 237 return S_FALSE; 238 /* 239 } 240 return systemError; 241 */ 242} 243 244HRESULT CCallbackConsoleBase::ReadingFileError_Base(const FString &path, DWORD systemError) 245{ 246 MT_LOCK 247 CommonError(path, systemError, false); 248 return HRESULT_FROM_WIN32(systemError); 249} 250 251HRESULT CUpdateCallbackConsole::ScanError(const FString &path, DWORD systemError) 252{ 253 return ScanError_Base(path, systemError); 254} 255 256 257static void PrintPropPair(AString &s, const char *name, UInt64 val) 258{ 259 char temp[32]; 260 ConvertUInt64ToString(val, temp); 261 s += name; 262 s += ": "; 263 s += temp; 264} 265 266void PrintSize_bytes_Smart(AString &s, UInt64 val); 267void Print_DirItemsStat(AString &s, const CDirItemsStat &st); 268void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st); 269 270HRESULT CUpdateCallbackConsole::FinishScanning(const CDirItemsStat &st) 271{ 272 if (NeedPercents()) 273 { 274 _percent.ClosePrint(true); 275 _percent.ClearCurState(); 276 } 277 278 if (_so) 279 { 280 AString s; 281 Print_DirItemsStat(s, st); 282 *_so << s << endl << endl; 283 } 284 return S_OK; 285} 286 287static const char * const k_StdOut_ArcName = "StdOut"; 288 289HRESULT CUpdateCallbackConsole::StartOpenArchive(const wchar_t *name) 290{ 291 if (_so) 292 { 293 *_so << kOpenArchiveMessage; 294 if (name) 295 *_so << name; 296 else 297 *_so << k_StdOut_ArcName; 298 *_so << endl; 299 } 300 return S_OK; 301} 302 303HRESULT CUpdateCallbackConsole::StartArchive(const wchar_t *name, bool updating) 304{ 305 if (NeedPercents()) 306 _percent.ClosePrint(true); 307 308 _percent.ClearCurState(); 309 NumNonOpenFiles = 0; 310 311 if (_so) 312 { 313 *_so << (updating ? kUpdatingArchiveMessage : kCreatingArchiveMessage); 314 if (name) 315 _so->NormalizePrint_wstr(name); 316 else 317 *_so << k_StdOut_ArcName; 318 *_so << endl << endl; 319 } 320 return S_OK; 321} 322 323HRESULT CUpdateCallbackConsole::FinishArchive(const CFinishArchiveStat &st) 324{ 325 ClosePercents2(); 326 327 if (_so) 328 { 329 AString s; 330 // Print_UInt64_and_String(s, _percent.Files == 1 ? "file" : "files", _percent.Files); 331 PrintPropPair(s, "Files read from disk", _percent.Files - NumNonOpenFiles); 332 s.Add_LF(); 333 s += "Archive size: "; 334 PrintSize_bytes_Smart(s, st.OutArcFileSize); 335 s.Add_LF(); 336 if (st.IsMultiVolMode) 337 { 338 s += "Volumes: "; 339 s.Add_UInt32(st.NumVolumes); 340 s.Add_LF(); 341 } 342 *_so << endl; 343 *_so << s; 344 // *_so << endl; 345 } 346 347 return S_OK; 348} 349 350HRESULT CUpdateCallbackConsole::WriteSfx(const wchar_t *name, UInt64 size) 351{ 352 if (_so) 353 { 354 *_so << "Write SFX: "; 355 *_so << name; 356 AString s (" : "); 357 PrintSize_bytes_Smart(s, size); 358 *_so << s << endl; 359 } 360 return S_OK; 361} 362 363 364HRESULT CUpdateCallbackConsole::DeletingAfterArchiving(const FString &path, bool /* isDir */) 365{ 366 if (LogLevel > 0 && _so) 367 { 368 ClosePercents_for_so(); 369 370 if (!DeleteMessageWasShown) 371 { 372 if (_so) 373 *_so << endl << ": Removing files after including to archive" << endl; 374 } 375 376 { 377 { 378 _tempA = "Removing"; 379 _tempA.Add_Space(); 380 *_so << _tempA; 381 _tempU = fs2us(path); 382 _so->Normalize_UString(_tempU); 383 _so->PrintUString(_tempU, _tempA); 384 *_so << endl; 385 if (NeedFlush) 386 _so->Flush(); 387 } 388 } 389 } 390 391 if (!DeleteMessageWasShown) 392 { 393 if (NeedPercents()) 394 { 395 _percent.ClearCurState(); 396 } 397 DeleteMessageWasShown = true; 398 } 399 else 400 { 401 _percent.Files++; 402 } 403 404 if (NeedPercents()) 405 { 406 // if (!FullLog) 407 { 408 _percent.Command = "Removing"; 409 _percent.FileName = fs2us(path); 410 } 411 _percent.Print(); 412 } 413 414 return S_OK; 415} 416 417 418HRESULT CUpdateCallbackConsole::FinishDeletingAfterArchiving() 419{ 420 ClosePercents2(); 421 if (_so && DeleteMessageWasShown) 422 *_so << endl; 423 return S_OK; 424} 425 426HRESULT CUpdateCallbackConsole::CheckBreak() 427{ 428 return CheckBreak2(); 429} 430 431/* 432HRESULT CUpdateCallbackConsole::Finalize() 433{ 434 // MT_LOCK 435 return S_OK; 436} 437*/ 438 439 440void static PrintToDoStat(CStdOutStream *_so, const CDirItemsStat2 &stat, const char *name) 441{ 442 AString s; 443 Print_DirItemsStat2(s, stat); 444 *_so << name << ": " << s << endl; 445} 446 447HRESULT CUpdateCallbackConsole::SetNumItems(const CArcToDoStat &stat) 448{ 449 if (_so) 450 { 451 ClosePercents_for_so(); 452 if (!stat.DeleteData.IsEmpty()) 453 { 454 *_so << endl; 455 PrintToDoStat(_so, stat.DeleteData, "Delete data from archive"); 456 } 457 if (!stat.OldData.IsEmpty()) 458 PrintToDoStat(_so, stat.OldData, "Keep old data in archive"); 459 // if (!stat.NewData.IsEmpty()) 460 { 461 PrintToDoStat(_so, stat.NewData, "Add new data to archive"); 462 } 463 *_so << endl; 464 } 465 return S_OK; 466} 467 468HRESULT CUpdateCallbackConsole::SetTotal(UInt64 size) 469{ 470 MT_LOCK 471 if (NeedPercents()) 472 { 473 _percent.Total = size; 474 _percent.Print(); 475 } 476 return S_OK; 477} 478 479HRESULT CUpdateCallbackConsole::SetCompleted(const UInt64 *completeValue) 480{ 481 MT_LOCK 482 if (completeValue) 483 { 484 if (NeedPercents()) 485 { 486 _percent.Completed = *completeValue; 487 _percent.Print(); 488 } 489 } 490 return CheckBreak2(); 491} 492 493HRESULT CUpdateCallbackConsole::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 * /* outSize */) 494{ 495 return CheckBreak2(); 496} 497 498HRESULT CCallbackConsoleBase::PrintProgress(const wchar_t *name, bool isDir, const char *command, bool showInLog) 499{ 500 MT_LOCK 501 502 bool show2 = (showInLog && _so); 503 504 if (show2) 505 { 506 ClosePercents_for_so(); 507 508 _tempA = command; 509 if (name) 510 _tempA.Add_Space(); 511 *_so << _tempA; 512 513 _tempU.Empty(); 514 if (name) 515 { 516 _tempU = name; 517 if (isDir) 518 NWindows::NFile::NName::NormalizeDirPathPrefix(_tempU); 519 _so->Normalize_UString(_tempU); 520 } 521 _so->PrintUString(_tempU, _tempA); 522 *_so << endl; 523 if (NeedFlush) 524 _so->Flush(); 525 } 526 527 if (NeedPercents()) 528 { 529 if (PercentsNameLevel >= 1) 530 { 531 _percent.FileName.Empty(); 532 _percent.Command.Empty(); 533 if (PercentsNameLevel > 1 || !show2) 534 { 535 _percent.Command = command; 536 if (name) 537 _percent.FileName = name; 538 } 539 } 540 _percent.Print(); 541 } 542 543 return CheckBreak2(); 544} 545 546 547/* 548void CCallbackConsoleBase::PrintInfoLine(const UString &s) 549{ 550 if (LogLevel < 1000) 551 return; 552 553 MT_LOCK 554 555 const bool show2 = (_so != NULL); 556 557 if (show2) 558 { 559 ClosePercents_for_so(); 560 _so->PrintUString(s, _tempA); 561 *_so << endl; 562 if (NeedFlush) 563 _so->Flush(); 564 } 565} 566*/ 567 568HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool isDir, bool isAnti, UInt32 mode) 569{ 570 if (StdOutMode) 571 return S_OK; 572 573 if (!name || name[0] == 0) 574 name = kEmptyFileAlias; 575 576 unsigned requiredLevel = 1; 577 578 const char *s; 579 if (mode == NUpdateNotifyOp::kAdd || 580 mode == NUpdateNotifyOp::kUpdate) 581 { 582 if (isAnti) 583 s = "Anti"; 584 else if (mode == NUpdateNotifyOp::kAdd) 585 s = "+"; 586 else 587 s = "U"; 588 } 589 else 590 { 591 requiredLevel = 3; 592 if (mode == NUpdateNotifyOp::kAnalyze) 593 s = "A"; 594 else 595 s = "Reading"; 596 } 597 598 return PrintProgress(name, isDir, s, LogLevel >= requiredLevel); 599} 600 601HRESULT CUpdateCallbackConsole::OpenFileError(const FString &path, DWORD systemError) 602{ 603 return OpenFileError_Base(path, systemError); 604} 605 606HRESULT CUpdateCallbackConsole::ReadingFileError(const FString &path, DWORD systemError) 607{ 608 return ReadingFileError_Base(path, systemError); 609} 610 611HRESULT CUpdateCallbackConsole::SetOperationResult(Int32 /* opRes */) 612{ 613 MT_LOCK 614 _percent.Files++; 615 /* 616 if (opRes != NArchive::NUpdate::NOperationResult::kOK) 617 { 618 if (opRes == NArchive::NUpdate::NOperationResult::kError_FileChanged) 619 { 620 CommonError("Input file changed"); 621 } 622 } 623 */ 624 return S_OK; 625} 626 627void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest); 628 629HRESULT CUpdateCallbackConsole::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name) 630{ 631 // if (StdOutMode) return S_OK; 632 633 if (opRes != NArchive::NExtract::NOperationResult::kOK) 634 { 635 ClosePercents2(); 636 637 if (_se) 638 { 639 if (_so) 640 _so->Flush(); 641 642 AString s; 643 SetExtractErrorMessage(opRes, isEncrypted, s); 644 *_se << s << " : " << endl; 645 _se->NormalizePrint_wstr(name); 646 *_se << endl << endl; 647 _se->Flush(); 648 } 649 return S_OK; 650 } 651 return S_OK; 652} 653 654 655HRESULT CUpdateCallbackConsole::ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir) 656{ 657 // if (StdOutMode) return S_OK; 658 659 char temp[16]; 660 const char *s; 661 662 unsigned requiredLevel = 1; 663 664 switch (op) 665 { 666 case NUpdateNotifyOp::kAdd: s = "+"; break; 667 case NUpdateNotifyOp::kUpdate: s = "U"; break; 668 case NUpdateNotifyOp::kAnalyze: s = "A"; requiredLevel = 3; break; 669 case NUpdateNotifyOp::kReplicate: s = "="; requiredLevel = 3; break; 670 case NUpdateNotifyOp::kRepack: s = "R"; requiredLevel = 2; break; 671 case NUpdateNotifyOp::kSkip: s = "."; requiredLevel = 2; break; 672 case NUpdateNotifyOp::kDelete: s = "D"; requiredLevel = 3; break; 673 case NUpdateNotifyOp::kHeader: s = "Header creation"; requiredLevel = 100; break; 674 case NUpdateNotifyOp::kInFileChanged: s = "Size of input file was changed:"; requiredLevel = 10; break; 675 // case NUpdateNotifyOp::kOpFinished: s = "Finished"; requiredLevel = 100; break; 676 default: 677 { 678 temp[0] = 'o'; 679 temp[1] = 'p'; 680 ConvertUInt64ToString(op, temp + 2); 681 s = temp; 682 } 683 } 684 685 return PrintProgress(name, isDir, s, LogLevel >= requiredLevel); 686} 687 688/* 689HRESULT CUpdateCallbackConsole::SetPassword(const UString & 690 #ifndef Z7_NO_CRYPTO 691 password 692 #endif 693 ) 694{ 695 #ifndef Z7_NO_CRYPTO 696 PasswordIsDefined = true; 697 Password = password; 698 #endif 699 return S_OK; 700} 701*/ 702 703HRESULT CUpdateCallbackConsole::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) 704{ 705 COM_TRY_BEGIN 706 707 *password = NULL; 708 709 #ifdef Z7_NO_CRYPTO 710 711 *passwordIsDefined = false; 712 return S_OK; 713 714 #else 715 716 if (!PasswordIsDefined) 717 { 718 if (AskPassword) 719 { 720 RINOK(GetPassword_HRESULT(_so, Password)) 721 PasswordIsDefined = true; 722 } 723 } 724 *passwordIsDefined = BoolToInt(PasswordIsDefined); 725 return StringToBstr(Password, password); 726 727 #endif 728 729 COM_TRY_END 730} 731 732HRESULT CUpdateCallbackConsole::CryptoGetTextPassword(BSTR *password) 733{ 734 COM_TRY_BEGIN 735 736 *password = NULL; 737 738 #ifdef Z7_NO_CRYPTO 739 740 return E_NOTIMPL; 741 742 #else 743 744 if (!PasswordIsDefined) 745 { 746 { 747 RINOK(GetPassword_HRESULT(_so, Password)) 748 PasswordIsDefined = true; 749 } 750 } 751 return StringToBstr(Password, password); 752 753 #endif 754 COM_TRY_END 755} 756 757HRESULT CUpdateCallbackConsole::ShowDeleteFile(const wchar_t *name, bool isDir) 758{ 759 if (StdOutMode) 760 return S_OK; 761 762 if (LogLevel > 7) 763 { 764 if (!name || name[0] == 0) 765 name = kEmptyFileAlias; 766 return PrintProgress(name, isDir, "D", true); 767 } 768 return S_OK; 769} 770 771/* 772void GetPropName(PROPID propID, const wchar_t *name, AString &nameA, UString &nameU); 773 774static void GetPropName(PROPID propID, UString &nameU) 775{ 776 AString nameA; 777 GetPropName(propID, NULL, nameA, nameU); 778 // if (!nameA.IsEmpty()) 779 nameU = nameA; 780} 781 782 783static void AddPropNamePrefix(UString &s, PROPID propID) 784{ 785 UString name; 786 GetPropName(propID, name); 787 s += name; 788 s += " = "; 789} 790 791void CCallbackConsoleBase::PrintPropInfo(UString &s, PROPID propID, const PROPVARIANT *value) 792{ 793 AddPropNamePrefix(s, propID); 794 { 795 UString dest; 796 const int level = 9; // we show up to ns precision level 797 ConvertPropertyToString2(dest, *value, propID, level); 798 s += dest; 799 } 800 PrintInfoLine(s); 801} 802 803static void Add_IndexType_Index(UString &s, UInt32 indexType, UInt32 index) 804{ 805 if (indexType == NArchive::NEventIndexType::kArcProp) 806 { 807 } 808 else 809 { 810 if (indexType == NArchive::NEventIndexType::kBlockIndex) 811 { 812 s += "#"; 813 } 814 else if (indexType == NArchive::NEventIndexType::kOutArcIndex) 815 { 816 } 817 else 818 { 819 s += "indexType_"; 820 s.Add_UInt32(indexType); 821 s.Add_Space(); 822 } 823 s.Add_UInt32(index); 824 } 825 s += ": "; 826} 827 828HRESULT CUpdateCallbackConsole::ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value) 829{ 830 UString s; 831 Add_IndexType_Index(s, indexType, index); 832 PrintPropInfo(s, propID, value); 833 return S_OK; 834} 835 836static inline char GetHex(Byte value) 837{ 838 return (char)((value < 10) ? ('0' + value) : ('a' + (value - 10))); 839} 840 841static void AddHexToString(UString &dest, const Byte *data, UInt32 size) 842{ 843 for (UInt32 i = 0; i < size; i++) 844 { 845 Byte b = data[i]; 846 dest += GetHex((Byte)((b >> 4) & 0xF)); 847 dest += GetHex((Byte)(b & 0xF)); 848 } 849} 850 851void HashHexToString(char *dest, const Byte *data, UInt32 size); 852 853HRESULT CUpdateCallbackConsole::ReportRawProp(UInt32 indexType, UInt32 index, 854 PROPID propID, const void *data, UInt32 dataSize, UInt32 propType) 855{ 856 UString s; 857 propType = propType; 858 Add_IndexType_Index(s, indexType, index); 859 AddPropNamePrefix(s, propID); 860 if (propID == kpidChecksum) 861 { 862 char temp[k_HashCalc_DigestSize_Max + 8]; 863 HashHexToString(temp, (const Byte *)data, dataSize); 864 s += temp; 865 } 866 else 867 AddHexToString(s, (const Byte *)data, dataSize); 868 PrintInfoLine(s); 869 return S_OK; 870} 871 872HRESULT CUpdateCallbackConsole::ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes) 873{ 874 UString s; 875 Add_IndexType_Index(s, indexType, index); 876 s += "finished"; 877 if (opRes != NArchive::NUpdate::NOperationResult::kOK) 878 { 879 s += ": "; 880 s.Add_UInt32(opRes); 881 } 882 PrintInfoLine(s); 883 return S_OK; 884} 885*/ 886