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