xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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 Z7_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_Path(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.Add_Char(')');
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 Z7_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 
Z7_COM7F_IMF(CExtractCallbackConsole::SetTotal (UInt64 size))238 Z7_COM7F_IMF(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 
Z7_COM7F_IMF(CExtractCallbackConsole::SetCompleted (const UInt64 * completeValue))250 Z7_COM7F_IMF(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(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 
Z7_COM7F_IMF(CExtractCallbackConsole::AskOverwrite (const wchar_t * existName,const FILETIME * existTime,const UInt64 * existSize,const wchar_t * newName,const FILETIME * newTime,const UInt64 * newSize,Int32 * answer))284 Z7_COM7F_IMF(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 ((int)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 
Z7_COM7F_IMF(CExtractCallbackConsole::PrepareOperation (const wchar_t * name,Int32 isFolder,Int32 askExtractMode,const UInt64 * position))328 Z7_COM7F_IMF(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   const 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_Path(_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     // _so->Flush();  // for debug only
377   }
378 
379   if (NeedPercents())
380   {
381     if (PercentsNameLevel >= 1)
382     {
383       _percent.FileName.Empty();
384       _percent.Command.Empty();
385       if (PercentsNameLevel > 1 || !show2)
386       {
387         _percent.Command = s;
388         if (name)
389           _percent.FileName = name;
390       }
391     }
392     _percent.Print();
393   }
394 
395   return CheckBreak2();
396 }
397 
Z7_COM7F_IMF(CExtractCallbackConsole::MessageError (const wchar_t * message))398 Z7_COM7F_IMF(CExtractCallbackConsole::MessageError(const wchar_t *message))
399 {
400   MT_LOCK
401 
402   RINOK(CheckBreak2())
403 
404   NumFileErrors_in_Current++;
405   NumFileErrors++;
406 
407   ClosePercentsAndFlush();
408   if (_se)
409   {
410     *_se << kError << message << endl;
411     _se->Flush();
412   }
413 
414   return CheckBreak2();
415 }
416 
417 void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest);
SetExtractErrorMessage(Int32 opRes,Int32 encrypted,AString & dest)418 void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest)
419 {
420   dest.Empty();
421     const char *s = NULL;
422 
423     switch (opRes)
424     {
425       case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
426         s = kUnsupportedMethod;
427         break;
428       case NArchive::NExtract::NOperationResult::kCRCError:
429         s = (encrypted ? kCrcFailedEncrypted : kCrcFailed);
430         break;
431       case NArchive::NExtract::NOperationResult::kDataError:
432         s = (encrypted ? kDataErrorEncrypted : kDataError);
433         break;
434       case NArchive::NExtract::NOperationResult::kUnavailable:
435         s = kUnavailableData;
436         break;
437       case NArchive::NExtract::NOperationResult::kUnexpectedEnd:
438         s = kUnexpectedEnd;
439         break;
440       case NArchive::NExtract::NOperationResult::kDataAfterEnd:
441         s = kDataAfterEnd;
442         break;
443       case NArchive::NExtract::NOperationResult::kIsNotArc:
444         s = kIsNotArc;
445         break;
446       case NArchive::NExtract::NOperationResult::kHeadersError:
447         s = kHeadersError;
448         break;
449       case NArchive::NExtract::NOperationResult::kWrongPassword:
450         s = kWrongPassword;
451         break;
452       default: break;
453     }
454 
455     dest += kError;
456     if (s)
457       dest += s;
458     else
459     {
460       dest += "Error #";
461       dest.Add_UInt32((UInt32)opRes);
462     }
463 }
464 
Z7_COM7F_IMF(CExtractCallbackConsole::SetOperationResult (Int32 opRes,Int32 encrypted))465 Z7_COM7F_IMF(CExtractCallbackConsole::SetOperationResult(Int32 opRes, Int32 encrypted))
466 {
467   MT_LOCK
468 
469   if (opRes == NArchive::NExtract::NOperationResult::kOK)
470   {
471     if (NeedPercents())
472     {
473       _percent.Command.Empty();
474       _percent.FileName.Empty();
475       _percent.Files++;
476     }
477   }
478   else
479   {
480     NumFileErrors_in_Current++;
481     NumFileErrors++;
482 
483     if (_se)
484     {
485       ClosePercentsAndFlush();
486 
487       AString s;
488       SetExtractErrorMessage(opRes, encrypted, s);
489 
490       *_se << s;
491       if (!_currentName.IsEmpty())
492       {
493         *_se << " : ";
494         _se->NormalizePrint_UString_Path(_currentName);
495       }
496       *_se << endl;
497       _se->Flush();
498     }
499   }
500 
501   return CheckBreak2();
502 }
503 
Z7_COM7F_IMF(CExtractCallbackConsole::ReportExtractResult (Int32 opRes,Int32 encrypted,const wchar_t * name))504 Z7_COM7F_IMF(CExtractCallbackConsole::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name))
505 {
506   if (opRes != NArchive::NExtract::NOperationResult::kOK)
507   {
508     _currentName = name;
509     return SetOperationResult(opRes, encrypted);
510   }
511 
512   return CheckBreak2();
513 }
514 
515 
516 
517 #ifndef Z7_NO_CRYPTO
518 
SetPassword(const UString & password)519 HRESULT CExtractCallbackConsole::SetPassword(const UString &password)
520 {
521   PasswordIsDefined = true;
522   Password = password;
523   return S_OK;
524 }
525 
Z7_COM7F_IMF(CExtractCallbackConsole::CryptoGetTextPassword (BSTR * password))526 Z7_COM7F_IMF(CExtractCallbackConsole::CryptoGetTextPassword(BSTR *password))
527 {
528   COM_TRY_BEGIN
529   MT_LOCK
530   return Open_CryptoGetTextPassword(password);
531   COM_TRY_END
532 }
533 
534 #endif
535 
536 
537 #ifndef Z7_SFX
538 
PrintTo_se_Path_WithTitle(const UString & path,const char * title)539 void CExtractCallbackConsole::PrintTo_se_Path_WithTitle(const UString &path, const char *title)
540 {
541   *_se << title;
542   _se->NormalizePrint_UString_Path(path);
543   *_se << endl;
544 }
545 
Add_ArchiveName_Error()546 void CExtractCallbackConsole::Add_ArchiveName_Error()
547 {
548   if (_needWriteArchivePath)
549   {
550     PrintTo_se_Path_WithTitle(_currentArchivePath, "Archive: ");
551     _needWriteArchivePath = false;
552   }
553 }
554 
555 
Z7_COM7F_IMF(CExtractCallbackConsole::RequestMemoryUse (UInt32 flags,UInt32,UInt32,const wchar_t * path,UInt64 requiredSize,UInt64 * allowedSize,UInt32 * answerFlags))556 Z7_COM7F_IMF(CExtractCallbackConsole::RequestMemoryUse(
557     UInt32 flags, UInt32 /* indexType */, UInt32 /* index */, const wchar_t *path,
558     UInt64 requiredSize, UInt64 *allowedSize, UInt32 *answerFlags))
559 {
560   if ((flags & NRequestMemoryUseFlags::k_IsReport) == 0
561       && requiredSize <= *allowedSize)
562   {
563 #if 0
564     // it's expected, that *answerFlags was set to NRequestMemoryAnswerFlags::k_Allow already,
565     // because it's default answer for (requiredSize <= *allowedSize) case.
566     // optional code:
567     *answerFlags = NRequestMemoryAnswerFlags::k_Allow;
568 #endif
569   }
570   else
571   {
572     if ((flags & NRequestMemoryUseFlags::k_NoErrorMessage) == 0)
573     if (_se)
574     {
575       const UInt64 num_GB_allowed  = (*allowedSize + ((1u << 30) - 1)) >> 30;
576       const UInt64 num_GB_required = (requiredSize + ((1u << 30) - 1)) >> 30;
577       ClosePercentsAndFlush();
578       Add_ArchiveName_Error();
579       if (path)
580         PrintTo_se_Path_WithTitle(path, "File: ");
581       *_se << "The extraction operation requires big amount memory (RAM):" << endl
582         << "  " << num_GB_required  << " GB : required memory usage size" << endl
583         << "  " << num_GB_allowed   << " GB : allowed memory usage limit" << endl
584         << "  Use -smemx{size}g switch to set allowed memory usage limit for extraction." << endl;
585       *_se << "ERROR: Memory usage limit was exceeded." << endl;
586       const char *m = NULL;
587       // if (indexType == NArchive::NEventIndexType::kNoIndex)
588            if ((flags & NRequestMemoryUseFlags::k_SkipArc_IsExpected) ||
589                (flags & NRequestMemoryUseFlags::k_Report_SkipArc))
590           m = "Archive unpacking was skipped.";
591 /*
592       else if ((flags & NRequestMemoryUseFlags::k_SkipBigFiles_IsExpected) ||
593                (flags & NRequestMemoryUseFlags::k_Report_SkipBigFiles))
594           m = "Extraction for some files will be skipped.";
595       else if ((flags & NRequestMemoryUseFlags::k_SkipBigFile_IsExpected) ||
596                (flags & NRequestMemoryUseFlags::k_Report_SkipBigFile))
597           m = "File extraction was skipped.";
598 */
599       if (m)
600         *_se << m;
601       _se->Flush();
602     }
603 
604     if ((flags & NRequestMemoryUseFlags::k_IsReport) == 0)
605     {
606       // default answer can be k_Allow, if limit was not forced,
607       // so we change answer to non-allowed here.
608       *answerFlags = NRequestMemoryAnswerFlags::k_Limit_Exceeded;
609            if (flags & NRequestMemoryUseFlags::k_SkipArc_IsExpected)
610         *answerFlags |= NRequestMemoryAnswerFlags::k_SkipArc;
611 /*
612       else if (flags & NRequestMemoryUseFlags::k_SkipBigFile_IsExpected)
613         *answerFlags |= NRequestMemoryAnswerFlags::k_SkipBigFile;
614       else if (flags & NRequestMemoryUseFlags::k_SkipBigFiles_IsExpected)
615         *answerFlags |= NRequestMemoryAnswerFlags::k_SkipBigFiles;
616 */
617     }
618   }
619   return CheckBreak2();
620 }
621 
622 #endif
623 
624 
BeforeOpen(const wchar_t * name,bool testMode)625 HRESULT CExtractCallbackConsole::BeforeOpen(const wchar_t *name, bool testMode)
626 {
627   _currentArchivePath = name;
628   _needWriteArchivePath = true;
629 
630   RINOK(CheckBreak2())
631 
632   NumTryArcs++;
633   ThereIsError_in_Current = false;
634   ThereIsWarning_in_Current = false;
635   NumFileErrors_in_Current = 0;
636 
637   ClosePercents_for_so();
638   if (_so)
639   {
640     *_so << endl << (testMode ? kTesting : kExtracting);
641     _so->NormalizePrint_wstr_Path(name);
642     *_so << endl;
643   }
644 
645   if (NeedPercents())
646     _percent.Command = "Open";
647   return S_OK;
648 }
649 
650 HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
651 HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
652 
GetOpenArcErrorMessage(UInt32 errorFlags)653 static AString GetOpenArcErrorMessage(UInt32 errorFlags)
654 {
655   AString s;
656 
657   for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_ErrorFlagsMessages); i++)
658   {
659     UInt32 f = (1 << i);
660     if ((errorFlags & f) == 0)
661       continue;
662     const char *m = k_ErrorFlagsMessages[i];
663     if (!s.IsEmpty())
664       s.Add_LF();
665     s += m;
666     errorFlags &= ~f;
667   }
668 
669   if (errorFlags != 0)
670   {
671     char sz[16];
672     sz[0] = '0';
673     sz[1] = 'x';
674     ConvertUInt32ToHex(errorFlags, sz + 2);
675     if (!s.IsEmpty())
676       s.Add_LF();
677     s += sz;
678   }
679 
680   return s;
681 }
682 
683 void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags);
PrintErrorFlags(CStdOutStream & so,const char * s,UInt32 errorFlags)684 void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags)
685 {
686   if (errorFlags == 0)
687     return;
688   so << s << endl << GetOpenArcErrorMessage(errorFlags) << endl;
689 }
690 
Add_Messsage_Pre_ArcType(UString & s,const char * pre,const wchar_t * arcType)691 static void Add_Messsage_Pre_ArcType(UString &s, const char *pre, const wchar_t *arcType)
692 {
693   s.Add_LF();
694   s += pre;
695   s += " as [";
696   s += arcType;
697   s += "] archive";
698 }
699 
700 void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc);
Print_ErrorFormatIndex_Warning(CStdOutStream * _so,const CCodecs * codecs,const CArc & arc)701 void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc)
702 {
703   const CArcErrorInfo &er = arc.ErrorInfo;
704 
705   *_so << "WARNING:\n";
706   _so->NormalizePrint_UString_Path(arc.Path);
707   UString s;
708   if (arc.FormatIndex == er.ErrorFormatIndex)
709   {
710     s.Add_LF();
711     s += "The archive is open with offset";
712   }
713   else
714   {
715     Add_Messsage_Pre_ArcType(s, "Cannot open the file", codecs->GetFormatNamePtr(er.ErrorFormatIndex));
716     Add_Messsage_Pre_ArcType(s, "The file is open", codecs->GetFormatNamePtr(arc.FormatIndex));
717   }
718 
719   *_so << s << endl << endl;
720 }
721 
722 
OpenResult(const CCodecs * codecs,const CArchiveLink & arcLink,const wchar_t * name,HRESULT result)723 HRESULT CExtractCallbackConsole::OpenResult(
724     const CCodecs *codecs, const CArchiveLink &arcLink,
725     const wchar_t *name, HRESULT result)
726 {
727   _currentArchivePath = name;
728   _needWriteArchivePath = true;
729 
730   ClosePercents();
731 
732   if (NeedPercents())
733   {
734     _percent.Files = 0;
735     _percent.Command.Empty();
736     _percent.FileName.Empty();
737   }
738 
739 
740   ClosePercentsAndFlush();
741 
742   FOR_VECTOR (level, arcLink.Arcs)
743   {
744     const CArc &arc = arcLink.Arcs[level];
745     const CArcErrorInfo &er = arc.ErrorInfo;
746 
747     UInt32 errorFlags = er.GetErrorFlags();
748 
749     if (errorFlags != 0 || !er.ErrorMessage.IsEmpty())
750     {
751       if (_se)
752       {
753         *_se << endl;
754         if (level != 0)
755         {
756           _se->NormalizePrint_UString_Path(arc.Path);
757           *_se << endl;
758         }
759       }
760 
761       if (errorFlags != 0)
762       {
763         if (_se)
764           PrintErrorFlags(*_se, "ERRORS:", errorFlags);
765         NumOpenArcErrors++;
766         ThereIsError_in_Current = true;
767       }
768 
769       if (!er.ErrorMessage.IsEmpty())
770       {
771         if (_se)
772           *_se << "ERRORS:" << endl << er.ErrorMessage << endl;
773         NumOpenArcErrors++;
774         ThereIsError_in_Current = true;
775       }
776 
777       if (_se)
778       {
779         *_se << endl;
780         _se->Flush();
781       }
782     }
783 
784     UInt32 warningFlags = er.GetWarningFlags();
785 
786     if (warningFlags != 0 || !er.WarningMessage.IsEmpty())
787     {
788       if (_so)
789       {
790         *_so << endl;
791         if (level != 0)
792         {
793           _so->NormalizePrint_UString_Path(arc.Path);
794           *_so << endl;
795         }
796       }
797 
798       if (warningFlags != 0)
799       {
800         if (_so)
801           PrintErrorFlags(*_so, "WARNINGS:", warningFlags);
802         NumOpenArcWarnings++;
803         ThereIsWarning_in_Current = true;
804       }
805 
806       if (!er.WarningMessage.IsEmpty())
807       {
808         if (_so)
809           *_so << "WARNINGS:" << endl << er.WarningMessage << endl;
810         NumOpenArcWarnings++;
811         ThereIsWarning_in_Current = true;
812       }
813 
814       if (_so)
815       {
816         *_so << endl;
817         if (NeedFlush)
818           _so->Flush();
819       }
820     }
821 
822 
823     if (er.ErrorFormatIndex >= 0)
824     {
825       if (_so)
826       {
827         Print_ErrorFormatIndex_Warning(_so, codecs, arc);
828         if (NeedFlush)
829           _so->Flush();
830       }
831       ThereIsWarning_in_Current = true;
832     }
833   }
834 
835   if (result == S_OK)
836   {
837     if (_so)
838     {
839       RINOK(Print_OpenArchive_Props(*_so, codecs, arcLink))
840       *_so << endl;
841     }
842   }
843   else
844   {
845     NumCantOpenArcs++;
846     if (_so)
847       _so->Flush();
848     if (_se)
849     {
850       *_se << kError;
851       _se->NormalizePrint_wstr_Path(name);
852       *_se << endl;
853       const HRESULT res = Print_OpenArchive_Error(*_se, codecs, arcLink);
854       RINOK(res)
855       if (result == S_FALSE)
856       {
857       }
858       else
859       {
860         if (result == E_OUTOFMEMORY)
861           *_se << "Can't allocate required memory";
862         else
863           *_se << NError::MyFormatMessage(result);
864         *_se << endl;
865       }
866       _se->Flush();
867     }
868   }
869 
870 
871   return CheckBreak2();
872 }
873 
ThereAreNoFiles()874 HRESULT CExtractCallbackConsole::ThereAreNoFiles()
875 {
876   ClosePercents_for_so();
877 
878   if (_so)
879   {
880     *_so << endl << kNoFiles << endl;
881     if (NeedFlush)
882       _so->Flush();
883   }
884   return CheckBreak2();
885 }
886 
ExtractResult(HRESULT result)887 HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result)
888 {
889   MT_LOCK
890 
891   if (NeedPercents())
892   {
893     _percent.ClosePrint(true);
894     _percent.Command.Empty();
895     _percent.FileName.Empty();
896   }
897 
898   if (_so)
899     _so->Flush();
900 
901   if (result == S_OK)
902   {
903     if (NumFileErrors_in_Current == 0 && !ThereIsError_in_Current)
904     {
905       if (ThereIsWarning_in_Current)
906         NumArcsWithWarnings++;
907       else
908         NumOkArcs++;
909       if (_so)
910         *_so << kEverythingIsOk << endl;
911     }
912     else
913     {
914       NumArcsWithError++;
915       if (_so)
916       {
917         *_so << endl;
918         if (NumFileErrors_in_Current != 0)
919           *_so << "Sub items Errors: " << NumFileErrors_in_Current << endl;
920       }
921     }
922     if (_so && NeedFlush)
923       _so->Flush();
924   }
925   else
926   {
927     // we don't update NumArcsWithError, if error is not related to archive data.
928     if (result == E_ABORT
929         || result == HRESULT_FROM_WIN32(ERROR_DISK_FULL))
930       return result;
931     NumArcsWithError++;
932 
933     if (_se)
934     {
935       *_se << endl << kError;
936       if (result == E_OUTOFMEMORY)
937         *_se << kMemoryExceptionMessage;
938       else
939         *_se << NError::MyFormatMessage(result);
940       *_se << endl;
941       _se->Flush();
942     }
943   }
944 
945   return CheckBreak2();
946 }
947