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