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