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