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