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