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