• 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   // 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 
79 void Print_UInt64_and_String(AString &s, UInt64 val, const char *name);
Print_UInt64_and_String(AString & s,UInt64 val,const char * name)80 void 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 
89 void PrintSize_bytes_Smart(AString &s, UInt64 val);
PrintSize_bytes_Smart(AString & s,UInt64 val)90 void 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 
PrintSize_bytes_Smart_comma(AString & s,UInt64 val)108 static 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 
118 void Print_DirItemsStat(AString &s, const CDirItemsStat &st);
Print_DirItemsStat(AString & s,const CDirItemsStat & st)119 void 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 
137 void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st);
Print_DirItemsStat2(AString & s,const CDirItemsStat2 & st)138 void 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 
PrintStat(const CDirItemsStat & st)170 void 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 _7ZIP_ST
187 static NSynchronization::CCriticalSection g_CriticalSection;
188 #define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
189 #else
190 #define MT_LOCK
191 #endif
192 
193 
194 static const char * const kTestString    =  "T";
195 static const char * const kExtractString =  "-";
196 static const char * const kSkipString    =  ".";
197 static 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 
203 static const char * const kMemoryExceptionMessage = "Can't allocate required memory!";
204 
205 static const char * const kExtracting = "Extracting archive: ";
206 static const char * const kTesting = "Testing archive: ";
207 
208 static const char * const kEverythingIsOk = "Everything is Ok";
209 static const char * const kNoFiles = "No files to process";
210 
211 static const char * const kUnsupportedMethod = "Unsupported Method";
212 static const char * const kCrcFailed = "CRC Failed";
213 static const char * const kCrcFailedEncrypted = "CRC Failed in encrypted file. Wrong password?";
214 static const char * const kDataError = "Data Error";
215 static const char * const kDataErrorEncrypted = "Data Error in encrypted file. Wrong password?";
216 static const char * const kUnavailableData = "Unavailable data";
217 static const char * const kUnexpectedEnd = "Unexpected end of data";
218 static const char * const kDataAfterEnd = "There are some data after the end of the payload data";
219 static const char * const kIsNotArc = "Is not archive";
220 static const char * const kHeadersError = "Headers Error";
221 static const char * const kWrongPassword = "Wrong password";
222 
223 static 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 
SetTotal(UInt64 size)238 STDMETHODIMP 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 
SetCompleted(const UInt64 * completeValue)250 STDMETHODIMP 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 
263 static const char * const kTab = "  ";
264 
PrintFileInfo(CStdOutStream * _so,const wchar_t * path,const FILETIME * ft,const UInt64 * size)265 static 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 
AskOverwrite(const wchar_t * existName,const FILETIME * existTime,const UInt64 * existSize,const wchar_t * newName,const FILETIME * newTime,const UInt64 * newSize,Int32 * answer)284 STDMETHODIMP 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 (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 
PrepareOperation(const wchar_t * name,Int32 isFolder,Int32 askExtractMode,const UInt64 * position)328 STDMETHODIMP 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 
MessageError(const wchar_t * message)397 STDMETHODIMP 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 
416 void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest);
SetExtractErrorMessage(Int32 opRes,Int32 encrypted,AString & dest)417 void 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 
SetOperationResult(Int32 opRes,Int32 encrypted)463 STDMETHODIMP 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 
ReportExtractResult(Int32 opRes,Int32 encrypted,const wchar_t * name)502 STDMETHODIMP 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 _NO_CRYPTO
516 
SetPassword(const UString & password)517 HRESULT CExtractCallbackConsole::SetPassword(const UString &password)
518 {
519   PasswordIsDefined = true;
520   Password = password;
521   return S_OK;
522 }
523 
CryptoGetTextPassword(BSTR * password)524 STDMETHODIMP 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 
BeforeOpen(const wchar_t * name,bool testMode)534 HRESULT 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 
556 HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
557 HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
558 
GetOpenArcErrorMessage(UInt32 errorFlags)559 static AString GetOpenArcErrorMessage(UInt32 errorFlags)
560 {
561   AString s;
562 
563   for (unsigned i = 0; i < 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 
589 void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags);
PrintErrorFlags(CStdOutStream & so,const char * s,UInt32 errorFlags)590 void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags)
591 {
592   if (errorFlags == 0)
593     return;
594   so << s << endl << GetOpenArcErrorMessage(errorFlags) << endl;
595 }
596 
Add_Messsage_Pre_ArcType(UString & s,const char * pre,const wchar_t * arcType)597 static 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 
606 void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc);
Print_ErrorFormatIndex_Warning(CStdOutStream * _so,const CCodecs * codecs,const CArc & arc)607 void 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 
OpenResult(const CCodecs * codecs,const CArchiveLink & arcLink,const wchar_t * name,HRESULT result)629 HRESULT 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       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 
ThereAreNoFiles()777 HRESULT 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 
ExtractResult(HRESULT result)790 HRESULT 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