1 // Main.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../Common/MyWindows.h"
6 
7 #ifdef _WIN32
8 
9 #ifndef Z7_OLD_WIN_SDK
10 
11 #if defined(__MINGW32__) || defined(__MINGW64__)
12 #include <psapi.h>
13 #else
14 #include <Psapi.h>
15 #endif
16 
17 #else // Z7_OLD_WIN_SDK
18 
19 typedef struct _PROCESS_MEMORY_COUNTERS {
20     DWORD cb;
21     DWORD PageFaultCount;
22     SIZE_T PeakWorkingSetSize;
23     SIZE_T WorkingSetSize;
24     SIZE_T QuotaPeakPagedPoolUsage;
25     SIZE_T QuotaPagedPoolUsage;
26     SIZE_T QuotaPeakNonPagedPoolUsage;
27     SIZE_T QuotaNonPagedPoolUsage;
28     SIZE_T PagefileUsage;
29     SIZE_T PeakPagefileUsage;
30 } PROCESS_MEMORY_COUNTERS;
31 typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS;
32 
33 #endif // Z7_OLD_WIN_SDK
34 
35 #else // _WIN32
36 #include <unistd.h>
37 #include <sys/ioctl.h>
38 #include <sys/time.h>
39 #include <sys/times.h>
40 #endif // _WIN32
41 
42 #include "../../../../C/CpuArch.h"
43 
44 #include "../../../Common/MyInitGuid.h"
45 
46 #include "../../../Common/CommandLineParser.h"
47 #include "../../../Common/IntToString.h"
48 #include "../../../Common/MyException.h"
49 #include "../../../Common/StdInStream.h"
50 #include "../../../Common/StdOutStream.h"
51 #include "../../../Common/StringConvert.h"
52 #include "../../../Common/StringToInt.h"
53 #include "../../../Common/UTFConvert.h"
54 
55 #include "../../../Windows/ErrorMsg.h"
56 #include "../../../Windows/TimeUtils.h"
57 #include "../../../Windows/FileDir.h"
58 
59 #include "../Common/ArchiveCommandLine.h"
60 #include "../Common/Bench.h"
61 #include "../Common/ExitCode.h"
62 #include "../Common/Extract.h"
63 
64 #ifdef Z7_EXTERNAL_CODECS
65 #include "../Common/LoadCodecs.h"
66 #endif
67 
68 #include "../../Common/RegisterCodec.h"
69 
70 #include "BenchCon.h"
71 #include "ConsoleClose.h"
72 #include "ExtractCallbackConsole.h"
73 #include "HashCon.h"
74 #include "List.h"
75 #include "OpenCallbackConsole.h"
76 #include "UpdateCallbackConsole.h"
77 
78 #ifdef Z7_PROG_VARIANT_R
79 #include "../../../../C/7zVersion.h"
80 #else
81 #include "../../MyVersion.h"
82 #endif
83 
84 using namespace NWindows;
85 using namespace NFile;
86 using namespace NCommandLineParser;
87 
88 #ifdef _WIN32
89 extern
90 HINSTANCE g_hInstance;
91 HINSTANCE g_hInstance = NULL;
92 #endif
93 
94 extern CStdOutStream *g_StdStream;
95 extern CStdOutStream *g_ErrStream;
96 
97 extern unsigned g_NumCodecs;
98 extern const CCodecInfo *g_Codecs[];
99 
100 extern unsigned g_NumHashers;
101 extern const CHasherInfo *g_Hashers[];
102 
103 #ifdef Z7_EXTERNAL_CODECS
104 extern
105 const CExternalCodecs *g_ExternalCodecs_Ptr;
106 const CExternalCodecs *g_ExternalCodecs_Ptr;
107 #endif
108 
109 DECLARE_AND_SET_CLIENT_VERSION_VAR
110 
111 #if defined(Z7_PROG_VARIANT_Z)
112   #define PROG_POSTFIX      "z"
113   #define PROG_POSTFIX_2  " (z)"
114 #elif defined(Z7_PROG_VARIANT_R)
115   #define PROG_POSTFIX      "r"
116   #define PROG_POSTFIX_2  " (r)"
117 #elif !defined(Z7_EXTERNAL_CODECS)
118   #define PROG_POSTFIX      "a"
119   #define PROG_POSTFIX_2  " (a)"
120 #else
121   #define PROG_POSTFIX    ""
122   #define PROG_POSTFIX_2  ""
123 #endif
124 
125 
126 static const char * const kCopyrightString = "\n7-Zip"
127   PROG_POSTFIX_2
128   " " MY_VERSION_CPU
129   " : " MY_COPYRIGHT_DATE "\n";
130 
131 static const char * const kHelpString =
132     "Usage: 7z"
133     PROG_POSTFIX
134     " <command> [<switches>...] <archive_name> [<file_names>...] [@listfile]\n"
135     "\n"
136     "<Commands>\n"
137     "  a : Add files to archive\n"
138     "  b : Benchmark\n"
139     "  d : Delete files from archive\n"
140     "  e : Extract files from archive (without using directory names)\n"
141     "  h : Calculate hash values for files\n"
142     "  i : Show information about supported formats\n"
143     "  l : List contents of archive\n"
144     "  rn : Rename files in archive\n"
145     "  t : Test integrity of archive\n"
146     "  u : Update files to archive\n"
147     "  x : eXtract files with full paths\n"
148     "\n"
149     "<Switches>\n"
150     "  -- : Stop switches and @listfile parsing\n"
151     "  -ai[r[-|0]]{@listfile|!wildcard} : Include archives\n"
152     "  -ax[r[-|0]]{@listfile|!wildcard} : eXclude archives\n"
153     "  -ao{a|s|t|u} : set Overwrite mode\n"
154     "  -an : disable archive_name field\n"
155     "  -bb[0-3] : set output log level\n"
156     "  -bd : disable progress indicator\n"
157     "  -bs{o|e|p}{0|1|2} : set output stream for output/error/progress line\n"
158     "  -bt : show execution time statistics\n"
159     "  -i[r[-|0]]{@listfile|!wildcard} : Include filenames\n"
160     "  -m{Parameters} : set compression Method\n"
161     "    -mmt[N] : set number of CPU threads\n"
162     "    -mx[N] : set compression level: -mx1 (fastest) ... -mx9 (ultra)\n"
163     "  -o{Directory} : set Output directory\n"
164     #ifndef Z7_NO_CRYPTO
165     "  -p{Password} : set Password\n"
166     #endif
167     "  -r[-|0] : Recurse subdirectories for name search\n"
168     "  -sa{a|e|s} : set Archive name mode\n"
169     "  -scc{UTF-8|WIN|DOS} : set charset for console input/output\n"
170     "  -scs{UTF-8|UTF-16LE|UTF-16BE|WIN|DOS|{id}} : set charset for list files\n"
171     "  -scrc[CRC32|CRC64|SHA1|SHA256|*] : set hash function for x, e, h commands\n"
172     "  -sdel : delete files after compression\n"
173     "  -seml[.] : send archive by email\n"
174     "  -sfx[{name}] : Create SFX archive\n"
175     "  -si[{name}] : read data from stdin\n"
176     "  -slp : set Large Pages mode\n"
177     "  -slt : show technical information for l (List) command\n"
178     "  -snh : store hard links as links\n"
179     "  -snl : store symbolic links as links\n"
180     "  -sni : store NT security information\n"
181     "  -sns[-] : store NTFS alternate streams\n"
182     "  -so : write data to stdout\n"
183     "  -spd : disable wildcard matching for file names\n"
184     "  -spe : eliminate duplication of root folder for extract command\n"
185     "  -spf[2] : use fully qualified file paths\n"
186     "  -ssc[-] : set sensitive case mode\n"
187     "  -sse : stop archive creating, if it can't open some input file\n"
188     "  -ssp : do not change Last Access Time of source files while archiving\n"
189     "  -ssw : compress shared files\n"
190     "  -stl : set archive timestamp from the most recently modified file\n"
191     "  -stm{HexMask} : set CPU thread affinity mask (hexadecimal number)\n"
192     "  -stx{Type} : exclude archive type\n"
193     "  -t{Type} : Set type of archive\n"
194     "  -u[-][p#][q#][r#][x#][y#][z#][!newArchiveName] : Update options\n"
195     "  -v{Size}[b|k|m|g] : Create volumes\n"
196     "  -w[{path}] : assign Work directory. Empty path means a temporary directory\n"
197     "  -x[r[-|0]]{@listfile|!wildcard} : eXclude filenames\n"
198     "  -y : assume Yes on all queries\n";
199 
200 // ---------------------------
201 // exception messages
202 
203 static const char * const kEverythingIsOk = "Everything is Ok";
204 static const char * const kUserErrorMessage = "Incorrect command line";
205 static const char * const kNoFormats = "7-Zip cannot find the code that works with archives.";
206 static const char * const kUnsupportedArcTypeMessage = "Unsupported archive type";
207 // static const char * const kUnsupportedUpdateArcType = "Can't create archive for that type";
208 
209 #define kDefaultSfxModule "7zCon.sfx"
210 
211 Z7_ATTR_NORETURN
ShowMessageAndThrowException(LPCSTR message, NExitCode::EEnum code)212 static void ShowMessageAndThrowException(LPCSTR message, NExitCode::EEnum code)
213 {
214   if (g_ErrStream)
215     *g_ErrStream << endl << "ERROR: " << message << endl;
216   throw code;
217 }
218 
219 
220 #ifdef _WIN32
221 #define ShowProgInfo(so)
222 #else
ShowProgInfo(CStdOutStream *so)223 static void ShowProgInfo(CStdOutStream *so)
224 {
225   if (!so)
226     return;
227 
228   *so
229 
230   /*
231   #ifdef __DATE__
232       << " " << __DATE__
233   #endif
234   #ifdef __TIME__
235       << " " << __TIME__
236   #endif
237   */
238 
239   << " " << (unsigned)(sizeof(void *)) * 8 << "-bit"
240 
241   #ifdef __ILP32__
242     << " ILP32"
243   #endif
244 
245   #ifdef __ARM_ARCH
246   << " arm_v:" << __ARM_ARCH
247   #ifdef __ARM_ARCH_ISA_THUMB
248   << " thumb:" << __ARM_ARCH_ISA_THUMB
249   #endif
250   #endif
251   ;
252 
253 
254 
255   #ifdef ENV_HAVE_LOCALE
256     *so << " locale=" << GetLocale();
257   #endif
258   #ifndef _WIN32
259   {
260     const bool is_IsNativeUTF8 = IsNativeUTF8();
261     if (!is_IsNativeUTF8)
262       *so << " UTF8=" << (is_IsNativeUTF8 ? "+" : "-");
263   }
264   if (!g_ForceToUTF8)
265     *so << " use-UTF8=" << (g_ForceToUTF8 ? "+" : "-");
266   {
267     const unsigned wchar_t_size = (unsigned)sizeof(wchar_t);
268     if (wchar_t_size != 4)
269       *so << " wchar_t=" << wchar_t_size * 8 << "-bit";
270   }
271   {
272     const unsigned off_t_size = (unsigned)sizeof(off_t);
273     if (off_t_size != 8)
274       *so << " Files=" << off_t_size * 8 << "-bit";
275   }
276   #endif
277 
278   {
279     const UInt32 numCpus = NWindows::NSystem::GetNumberOfProcessors();
280     *so << " Threads:" << numCpus;
281     const UInt64 openMAX= NWindows::NSystem::Get_File_OPEN_MAX();
282     *so << " OPEN_MAX:" << openMAX;
283     {
284       FString temp;
285       NDir::MyGetTempPath(temp);
286       if (!temp.IsEqualTo(STRING_PATH_SEPARATOR "tmp" STRING_PATH_SEPARATOR))
287         *so << " temp_path:" << temp;
288     }
289   }
290 
291   #ifdef Z7_7ZIP_ASM
292   *so << ", ASM";
293   #endif
294 
295   /*
296   {
297     AString s;
298     GetCpuName(s);
299     s.Trim();
300     *so << ", " << s;
301   }
302 
303   #ifdef __ARM_FEATURE_CRC32
304      << " CRC32"
305   #endif
306 
307 
308   #if (defined MY_CPU_X86_OR_AMD64 || defined(MY_CPU_ARM_OR_ARM64))
309   if (CPU_IsSupported_AES()) *so << ",AES";
310   #endif
311 
312   #ifdef MY_CPU_ARM_OR_ARM64
313   if (CPU_IsSupported_CRC32()) *so << ",CRC32";
314   #if defined(_WIN32)
315   if (CPU_IsSupported_CRYPTO()) *so << ",CRYPTO";
316   #else
317   if (CPU_IsSupported_SHA1()) *so << ",SHA1";
318   if (CPU_IsSupported_SHA2()) *so << ",SHA2";
319   #endif
320   #endif
321   */
322 
323   *so << endl;
324 }
325 #endif
326 
ShowCopyrightAndHelp(CStdOutStream *so, bool needHelp)327 static void ShowCopyrightAndHelp(CStdOutStream *so, bool needHelp)
328 {
329   if (!so)
330     return;
331   *so << kCopyrightString;
332   // *so << "# CPUs: " << (UInt64)NWindows::NSystem::GetNumberOfProcessors() << endl;
333   ShowProgInfo(so);
334   *so << endl;
335   if (needHelp)
336     *so << kHelpString;
337 }
338 
339 
PrintStringRight(CStdOutStream &so, const char *s, unsigned size)340 static void PrintStringRight(CStdOutStream &so, const char *s, unsigned size)
341 {
342   unsigned len = MyStringLen(s);
343   for (unsigned i = len; i < size; i++)
344     so << ' ';
345   so << s;
346 }
347 
PrintUInt32(CStdOutStream &so, UInt32 val, unsigned size)348 static void PrintUInt32(CStdOutStream &so, UInt32 val, unsigned size)
349 {
350   char s[16];
351   ConvertUInt32ToString(val, s);
352   PrintStringRight(so, s, size);
353 }
354 
355 #ifdef Z7_EXTERNAL_CODECS
PrintNumber(CStdOutStream &so, UInt32 val, unsigned numDigits)356 static void PrintNumber(CStdOutStream &so, UInt32 val, unsigned numDigits)
357 {
358   AString s;
359   s.Add_UInt32(val);
360   while (s.Len() < numDigits)
361     s.InsertAtFront('0');
362   so << s;
363 }
364 #endif
365 
PrintLibIndex(CStdOutStream &so, int libIndex)366 static void PrintLibIndex(CStdOutStream &so, int libIndex)
367 {
368   if (libIndex >= 0)
369     PrintUInt32(so, (UInt32)libIndex, 2);
370   else
371     so << "  ";
372   so << ' ';
373 }
374 
PrintString(CStdOutStream &so, const UString &s, unsigned size)375 static void PrintString(CStdOutStream &so, const UString &s, unsigned size)
376 {
377   unsigned len = s.Len();
378   so << s;
379   for (unsigned i = len; i < size; i++)
380     so << ' ';
381 }
382 
GetHex(unsigned val)383 static inline char GetHex(unsigned val)
384 {
385   return (char)((val < 10) ? ('0' + val) : ('A' + (val - 10)));
386 }
387 
PrintWarningsPaths(const CErrorPathCodes &pc, CStdOutStream &so)388 static void PrintWarningsPaths(const CErrorPathCodes &pc, CStdOutStream &so)
389 {
390   FOR_VECTOR(i, pc.Paths)
391   {
392     so.NormalizePrint_UString(fs2us(pc.Paths[i]));
393     so << " : ";
394     so << NError::MyFormatMessage(pc.Codes[i]) << endl;
395   }
396   so << "----------------" << endl;
397 }
398 
WarningsCheck(HRESULT result, const CCallbackConsoleBase &callback, const CUpdateErrorInfo &errorInfo, CStdOutStream *so, CStdOutStream *se, bool showHeaders)399 static int WarningsCheck(HRESULT result, const CCallbackConsoleBase &callback,
400     const CUpdateErrorInfo &errorInfo,
401     CStdOutStream *so,
402     CStdOutStream *se,
403     bool showHeaders)
404 {
405   int exitCode = NExitCode::kSuccess;
406 
407   if (callback.ScanErrors.Paths.Size() != 0)
408   {
409     if (se)
410     {
411       *se << endl;
412       *se << "Scan WARNINGS for files and folders:" << endl << endl;
413       PrintWarningsPaths(callback.ScanErrors, *se);
414       *se << "Scan WARNINGS: " << callback.ScanErrors.Paths.Size();
415       *se << endl;
416     }
417     exitCode = NExitCode::kWarning;
418   }
419 
420   if (result != S_OK || errorInfo.ThereIsError())
421   {
422     if (se)
423     {
424       UString message;
425       if (!errorInfo.Message.IsEmpty())
426       {
427         message += errorInfo.Message.Ptr();
428         message.Add_LF();
429       }
430       {
431         FOR_VECTOR(i, errorInfo.FileNames)
432         {
433           message += fs2us(errorInfo.FileNames[i]);
434           message.Add_LF();
435         }
436       }
437       if (errorInfo.SystemError != 0)
438       {
439         message += NError::MyFormatMessage(errorInfo.SystemError);
440         message.Add_LF();
441       }
442       if (!message.IsEmpty())
443         *se << L"\nError:\n" << message;
444     }
445 
446     // we will work with (result) later
447     // throw CSystemException(result);
448     return NExitCode::kFatalError;
449   }
450 
451   unsigned numErrors = callback.FailedFiles.Paths.Size();
452   if (numErrors == 0)
453   {
454     if (showHeaders)
455       if (callback.ScanErrors.Paths.Size() == 0)
456         if (so)
457         {
458           if (se)
459             se->Flush();
460           *so << kEverythingIsOk << endl;
461         }
462   }
463   else
464   {
465     if (se)
466     {
467       *se << endl;
468       *se << "WARNINGS for files:" << endl << endl;
469       PrintWarningsPaths(callback.FailedFiles, *se);
470       *se << "WARNING: Cannot open " << numErrors << " file";
471       if (numErrors > 1)
472         *se << 's';
473       *se << endl;
474     }
475     exitCode = NExitCode::kWarning;
476   }
477 
478   return exitCode;
479 }
480 
ThrowException_if_Error(HRESULT res)481 static void ThrowException_if_Error(HRESULT res)
482 {
483   if (res != S_OK)
484     throw CSystemException(res);
485 }
486 
PrintNum(UInt64 val, unsigned numDigits, char c = �)487 static void PrintNum(UInt64 val, unsigned numDigits, char c = ' ')
488 {
489   char temp[64];
490   char *p = temp + 32;
491   ConvertUInt64ToString(val, p);
492   unsigned len = MyStringLen(p);
493   for (; len < numDigits; len++)
494     *--p = c;
495   *g_StdStream << p;
496 }
497 
498 #ifdef _WIN32
499 
PrintTime(const char *s, UInt64 val, UInt64 total)500 static void PrintTime(const char *s, UInt64 val, UInt64 total)
501 {
502   *g_StdStream << endl << s << " Time =";
503   const UInt32 kFreq = 10000000;
504   UInt64 sec = val / kFreq;
505   PrintNum(sec, 6);
506   *g_StdStream << '.';
507   UInt32 ms = (UInt32)(val - (sec * kFreq)) / (kFreq / 1000);
508   PrintNum(ms, 3, '0');
509 
510   while (val > ((UInt64)1 << 56))
511   {
512     val >>= 1;
513     total >>= 1;
514   }
515 
516   UInt64 percent = 0;
517   if (total != 0)
518     percent = val * 100 / total;
519   *g_StdStream << " =";
520   PrintNum(percent, 5);
521   *g_StdStream << '%';
522 }
523 
524 #ifndef UNDER_CE
525 
526 #define SHIFT_SIZE_VALUE(x, num) (((x) + (1 << (num)) - 1) >> (num))
527 
PrintMemUsage(const char *s, UInt64 val)528 static void PrintMemUsage(const char *s, UInt64 val)
529 {
530   *g_StdStream << "    " << s << " Memory =";
531   PrintNum(SHIFT_SIZE_VALUE(val, 20), 7);
532   *g_StdStream << " MB";
533   /*
534   *g_StdStream << " =";
535   PrintNum(SHIFT_SIZE_VALUE(val, 10), 9);
536   *g_StdStream << " KB";
537   */
538   #ifdef Z7_LARGE_PAGES
539   AString lp;
540   Add_LargePages_String(lp);
541   if (!lp.IsEmpty())
542     *g_StdStream << lp;
543   #endif
544 }
545 
546 EXTERN_C_BEGIN
547 typedef BOOL (WINAPI *Func_GetProcessMemoryInfo)(HANDLE Process,
548     PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb);
549 typedef BOOL (WINAPI *Func_QueryProcessCycleTime)(HANDLE Process, PULONG64 CycleTime);
550 EXTERN_C_END
551 
552 #endif
553 
GetTime64(const FILETIME &t)554 static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
555 
PrintStat()556 static void PrintStat()
557 {
558   FILETIME creationTimeFT, exitTimeFT, kernelTimeFT, userTimeFT;
559   if (!
560       #ifdef UNDER_CE
561         ::GetThreadTimes(::GetCurrentThread()
562       #else
563         // NT 3.5
564         ::GetProcessTimes(::GetCurrentProcess()
565       #endif
566       , &creationTimeFT, &exitTimeFT, &kernelTimeFT, &userTimeFT))
567     return;
568   FILETIME curTimeFT;
569   NTime::GetCurUtc_FiTime(curTimeFT);
570 
571   #ifndef UNDER_CE
572 
573   PROCESS_MEMORY_COUNTERS m;
574   memset(&m, 0, sizeof(m));
575   BOOL memDefined = FALSE;
576   BOOL cycleDefined = FALSE;
577   ULONG64 cycleTime = 0;
578   {
579     /* NT 4.0: GetProcessMemoryInfo() in Psapi.dll
580        Win7: new function K32GetProcessMemoryInfo() in kernel32.dll
581        It's faster to call kernel32.dll code than Psapi.dll code
582        GetProcessMemoryInfo() requires Psapi.lib
583        Psapi.lib in SDK7+ can link to K32GetProcessMemoryInfo in kernel32.dll
584        The program with K32GetProcessMemoryInfo will not work on systems before Win7
585        // memDefined = GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m));
586     */
587     const HMODULE kern = ::GetModuleHandleW(L"kernel32.dll");
588     Func_GetProcessMemoryInfo
589       my_GetProcessMemoryInfo = Z7_GET_PROC_ADDRESS(
590     Func_GetProcessMemoryInfo, kern,
591      "K32GetProcessMemoryInfo");
592     if (!my_GetProcessMemoryInfo)
593     {
594       const HMODULE lib = LoadLibraryW(L"Psapi.dll");
595       if (lib)
596           my_GetProcessMemoryInfo = Z7_GET_PROC_ADDRESS(
597         Func_GetProcessMemoryInfo, lib,
598             "GetProcessMemoryInfo");
599     }
600     if (my_GetProcessMemoryInfo)
601       memDefined = my_GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m));
602     // FreeLibrary(lib);
603     const
604     Func_QueryProcessCycleTime
605       my_QueryProcessCycleTime = Z7_GET_PROC_ADDRESS(
606     Func_QueryProcessCycleTime, kern,
607         "QueryProcessCycleTime");
608     if (my_QueryProcessCycleTime)
609       cycleDefined = my_QueryProcessCycleTime(GetCurrentProcess(), &cycleTime);
610   }
611 
612   #endif
613 
614   UInt64 curTime = GetTime64(curTimeFT);
615   UInt64 creationTime = GetTime64(creationTimeFT);
616   UInt64 kernelTime = GetTime64(kernelTimeFT);
617   UInt64 userTime = GetTime64(userTimeFT);
618 
619   UInt64 totalTime = curTime - creationTime;
620 
621   PrintTime("Kernel ", kernelTime, totalTime);
622 
623   const UInt64 processTime = kernelTime + userTime;
624 
625   #ifndef UNDER_CE
626   if (cycleDefined)
627   {
628     *g_StdStream << "    Cnt:";
629     PrintNum(cycleTime / 1000000, 15);
630     *g_StdStream << " MCycles";
631   }
632   #endif
633 
634   PrintTime("User   ", userTime, totalTime);
635 
636   #ifndef UNDER_CE
637   if (cycleDefined)
638   {
639     *g_StdStream << "    Freq (cnt/ptime):";
640     UInt64 us = processTime / 10;
641     if (us == 0)
642       us = 1;
643     PrintNum(cycleTime / us, 6);
644     *g_StdStream << " MHz";
645   }
646   #endif
647 
648   PrintTime("Process", processTime, totalTime);
649   #ifndef UNDER_CE
650   if (memDefined) PrintMemUsage("Virtual ", m.PeakPagefileUsage);
651   #endif
652 
653   PrintTime("Global ", totalTime, totalTime);
654   #ifndef UNDER_CE
655   if (memDefined) PrintMemUsage("Physical", m.PeakWorkingSetSize);
656   #endif
657   *g_StdStream << endl;
658 }
659 
660 
661 #else  // ! _WIN32
662 
663 static UInt64 Get_timeofday_us()
664 {
665   struct timeval now;
666   if (gettimeofday(&now, NULL) == 0)
667     return (UInt64)now.tv_sec * 1000000 + (UInt64)now.tv_usec;
668   return 0;
669 }
670 
671 static void PrintTime(const char *s, UInt64 val, UInt64 total_us, UInt64 kFreq)
672 {
673   *g_StdStream << endl << s << " Time =";
674 
675   {
676     UInt64 sec, ms;
677 
678     if (kFreq == 0)
679     {
680       sec = val / 1000000;
681       ms  = val % 1000000 / 1000;
682     }
683     else
684     {
685       sec = val / kFreq;
686       ms = (UInt32)((val - (sec * kFreq)) * 1000 / kFreq);
687     }
688 
689     PrintNum(sec, 6);
690     *g_StdStream << '.';
691     PrintNum(ms, 3, '0');
692   }
693 
694   if (total_us == 0)
695     return;
696 
697   UInt64 percent = 0;
698   if (kFreq == 0)
699     percent = val * 100 / total_us;
700   else
701   {
702     const UInt64 kMaxVal = (UInt64)(Int64)-1;
703     UInt32 m = 100000000;
704     for (;;)
705     {
706       if (m == 0 || kFreq == 0)
707         break;
708       if (kMaxVal / m > val &&
709         kMaxVal / kFreq > total_us)
710         break;
711       if (val > m)
712         val >>= 1;
713       else
714         m >>= 1;
715       if (kFreq > total_us)
716         kFreq >>= 1;
717       else
718         total_us >>= 1;
719     }
720     const UInt64 total = kFreq * total_us;
721     if (total != 0)
722       percent = val * m / total;
723   }
724   *g_StdStream << " =";
725   PrintNum(percent, 5);
726   *g_StdStream << '%';
727 }
728 
729 static void PrintStat(const UInt64 startTime)
730 {
731   tms t;
732   /* clock_t res = */ times(&t);
733   const UInt64 totalTime = Get_timeofday_us() - startTime;
734   const UInt64 kFreq = (UInt64)sysconf(_SC_CLK_TCK);
735   PrintTime("Kernel ", (UInt64)t.tms_stime, totalTime, kFreq);
736   PrintTime("User   ", (UInt64)t.tms_utime, totalTime, kFreq);
737   PrintTime("Process", (UInt64)t.tms_utime + (UInt64)t.tms_stime, totalTime, kFreq);
738   PrintTime("Global ", totalTime, totalTime, 0);
739   *g_StdStream << endl;
740 }
741 
742 #endif // ! _WIN32
743 
744 
745 
746 
747 
748 static void PrintHexId(CStdOutStream &so, UInt64 id)
749 {
750   char s[32];
751   ConvertUInt64ToHex(id, s);
752   PrintStringRight(so, s, 8);
753 }
754 
755 #ifndef _WIN32
756 void Set_ModuleDirPrefix_From_ProgArg0(const char *s);
757 #endif
758 
759 int Main2(
760   #ifndef _WIN32
761   int numArgs, char *args[]
762   #endif
763 );
764 int Main2(
765   #ifndef _WIN32
766   int numArgs, char *args[]
767   #endif
768 )
769 {
770   #if defined(MY_CPU_SIZEOF_POINTER)
771     { unsigned k = sizeof(void *); if (k != MY_CPU_SIZEOF_POINTER) throw "incorrect MY_CPU_PTR_SIZE"; }
772   #endif
773 
774   #if defined(_WIN32) && !defined(UNDER_CE)
775   SetFileApisToOEM();
776   #endif
777 
778   #ifdef ENV_HAVE_LOCALE
779   // printf("\nBefore SetLocale() : %s\n", IsNativeUtf8() ? "NATIVE UTF-8" : "IS NOT NATIVE UTF-8");
780   MY_SetLocale();
781   // printf("\nAfter  SetLocale() : %s\n", IsNativeUtf8() ? "NATIVE UTF-8" : "IS NOT NATIVE UTF-8");
782   #endif
783 
784   #ifndef _WIN32
785   const UInt64 startTime = Get_timeofday_us();
786   #endif
787 
788   /*
789   {
790     g_StdOut << "DWORD:" << (unsigned)sizeof(DWORD);
791     g_StdOut << " LONG:" << (unsigned)sizeof(LONG);
792     g_StdOut << " long:" << (unsigned)sizeof(long);
793     #ifdef _WIN64
794     // g_StdOut << " long long:" << (unsigned)sizeof(long long);
795     #endif
796     g_StdOut << " int:" << (unsigned)sizeof(int);
797     g_StdOut << " void*:"  << (unsigned)sizeof(void *);
798     g_StdOut << endl;
799   }
800   */
801 
802   UStringVector commandStrings;
803 
804   #ifdef _WIN32
805   NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
806   #else
807   {
808     if (numArgs > 0)
809       Set_ModuleDirPrefix_From_ProgArg0(args[0]);
810 
811     for (int i = 0; i < numArgs; i++)
812     {
813       AString a (args[i]);
814       /*
815       printf("\n%d %s :", i, a.Ptr());
816       for (unsigned k = 0; k < a.Len(); k++)
817         printf(" %2x", (unsigned)(Byte)a[k]);
818       */
819       const UString s = MultiByteToUnicodeString(a);
820       commandStrings.Add(s);
821     }
822     // printf("\n");
823   }
824 
825   #endif
826 
827   #ifndef UNDER_CE
828   if (commandStrings.Size() > 0)
829     commandStrings.Delete(0);
830   #endif
831 
832   if (commandStrings.Size() == 0)
833   {
834     ShowCopyrightAndHelp(g_StdStream, true);
835     return 0;
836   }
837 
838   CArcCmdLineOptions options;
839 
840   CArcCmdLineParser parser;
841 
842   parser.Parse1(commandStrings, options);
843 
844   g_StdOut.IsTerminalMode = options.IsStdOutTerminal;
845   g_StdErr.IsTerminalMode = options.IsStdErrTerminal;
846 
847   if (options.Number_for_Out != k_OutStream_stdout)
848     g_StdStream = (options.Number_for_Out == k_OutStream_stderr ? &g_StdErr : NULL);
849 
850   if (options.Number_for_Errors != k_OutStream_stderr)
851     g_ErrStream = (options.Number_for_Errors == k_OutStream_stdout ? &g_StdOut : NULL);
852 
853   CStdOutStream *percentsStream = NULL;
854   if (options.Number_for_Percents != k_OutStream_disabled)
855     percentsStream = (options.Number_for_Percents == k_OutStream_stderr) ? &g_StdErr : &g_StdOut;
856 
857   if (options.HelpMode)
858   {
859     ShowCopyrightAndHelp(g_StdStream, true);
860     return 0;
861   }
862 
863   if (options.EnableHeaders)
864   {
865     ShowCopyrightAndHelp(g_StdStream, false);
866     if (!parser.Parse1Log.IsEmpty())
867       *g_StdStream << parser.Parse1Log;
868   }
869 
870   parser.Parse2(options);
871 
872   {
873     int cp = options.ConsoleCodePage;
874 
875     int stdout_cp = cp;
876     int stderr_cp = cp;
877     int stdin_cp = cp;
878 
879     /*
880     // these cases are complicated.
881     // maybe we must use CRT functions instead of console WIN32.
882     // different Windows/CRT versions also can work different ways.
883     // so the following code was not enabled:
884     if (cp == -1)
885     {
886       // we set CodePage only if stream is attached to terminal
887       // maybe we should set CodePage even if is not terminal?
888       #ifdef _WIN32
889       {
890         UINT ccp = GetConsoleOutputCP();
891         if (ccp != 0)
892         {
893           if (options.IsStdOutTerminal) stdout_cp = ccp;
894           if (options.IsStdErrTerminal) stderr_cp = ccp;
895         }
896       }
897       if (options.IsInTerminal)
898       {
899         UINT ccp = GetConsoleCP();
900         if (ccp != 0) stdin_cp = ccp;
901       }
902       #endif
903     }
904     */
905 
906     if (stdout_cp != -1) g_StdOut.CodePage = stdout_cp;
907     if (stderr_cp != -1) g_StdErr.CodePage = stderr_cp;
908     if (stdin_cp != -1) g_StdIn.CodePage = stdin_cp;
909   }
910 
911   unsigned percentsNameLevel = 1;
912   if (options.LogLevel == 0 || options.Number_for_Percents != options.Number_for_Out)
913     percentsNameLevel = 2;
914 
915   unsigned consoleWidth = 80;
916 
917   if (percentsStream)
918   {
919     #ifdef _WIN32
920 
921     #if !defined(UNDER_CE)
922     CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
923     if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo))
924       consoleWidth = (unsigned)(unsigned short)consoleInfo.dwSize.X;
925     #endif
926 
927     #else
928 
929     struct winsize w;
930     if (ioctl(0, TIOCGWINSZ, &w) == 0)
931       consoleWidth = w.ws_col;
932 
933     #endif
934   }
935 
936   CREATE_CODECS_OBJECT
937 
938   codecs->CaseSensitive_Change = options.CaseSensitive_Change;
939   codecs->CaseSensitive = options.CaseSensitive;
940   ThrowException_if_Error(codecs->Load());
941   Codecs_AddHashArcHandler(codecs);
942 
943   #ifdef Z7_EXTERNAL_CODECS
944   {
945     g_ExternalCodecs_Ptr = &_externalCodecs;
946     UString s;
947     codecs->GetCodecsErrorMessage(s);
948     if (!s.IsEmpty())
949     {
950       CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut);
951       so << endl << s << endl;
952     }
953   }
954   #endif
955 
956   const bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
957 
958   if (codecs->Formats.Size() == 0 &&
959         (isExtractGroupCommand
960         || options.Command.CommandType == NCommandType::kList
961         || options.Command.IsFromUpdateGroup()))
962   {
963     #ifdef Z7_EXTERNAL_CODECS
964     if (!codecs->MainDll_ErrorPath.IsEmpty())
965     {
966       UString s ("Can't load module: ");
967       s += fs2us(codecs->MainDll_ErrorPath);
968       throw s;
969     }
970     #endif
971     throw kNoFormats;
972   }
973 
974   CObjectVector<COpenType> types;
975   if (!ParseOpenTypes(*codecs, options.ArcType, types))
976   {
977     throw kUnsupportedArcTypeMessage;
978   }
979 
980 
981   CIntVector excludedFormats;
982   FOR_VECTOR (k, options.ExcludedArcTypes)
983   {
984     CIntVector tempIndices;
985     if (!codecs->FindFormatForArchiveType(options.ExcludedArcTypes[k], tempIndices)
986         || tempIndices.Size() != 1)
987       throw kUnsupportedArcTypeMessage;
988 
989 
990 
991     excludedFormats.AddToUniqueSorted(tempIndices[0]);
992     // excludedFormats.Sort();
993   }
994 
995   #ifdef Z7_EXTERNAL_CODECS
996   if (isExtractGroupCommand
997       || options.Command.IsFromUpdateGroup()
998       || options.Command.CommandType == NCommandType::kHash
999       || options.Command.CommandType == NCommandType::kBenchmark)
1000     ThrowException_if_Error(_externalCodecs.Load());
1001   #endif
1002 
1003   int retCode = NExitCode::kSuccess;
1004   HRESULT hresultMain = S_OK;
1005 
1006   // bool showStat = options.ShowTime;
1007 
1008   /*
1009   if (!options.EnableHeaders ||
1010       options.TechMode)
1011     showStat = false;
1012   */
1013 
1014 
1015   if (options.Command.CommandType == NCommandType::kInfo)
1016   {
1017     CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut);
1018     unsigned i;
1019 
1020     #ifdef Z7_EXTERNAL_CODECS
1021     so << endl << "Libs:" << endl;
1022     for (i = 0; i < codecs->Libs.Size(); i++)
1023     {
1024       PrintLibIndex(so, (int)i);
1025       const CCodecLib &lib = codecs->Libs[i];
1026       // if (lib.Version != 0)
1027       so << ": " << (lib.Version >> 16) << ".";
1028       PrintNumber(so, lib.Version & 0xffff, 2);
1029       so << " : " << lib.Path << endl;
1030     }
1031     #endif
1032 
1033     so << endl << "Formats:" << endl;
1034 
1035     const char * const kArcFlags = "KSNFMGOPBELHXCc+a+m+r+";
1036     const char * const kArcTimeFlags = "wudn";
1037     const unsigned kNumArcFlags = (unsigned)strlen(kArcFlags);
1038     const unsigned kNumArcTimeFlags = (unsigned)strlen(kArcTimeFlags);
1039 
1040     for (i = 0; i < codecs->Formats.Size(); i++)
1041     {
1042       const CArcInfoEx &arc = codecs->Formats[i];
1043 
1044       #ifdef Z7_EXTERNAL_CODECS
1045       PrintLibIndex(so, arc.LibIndex);
1046       #else
1047       so << "   ";
1048       #endif
1049 
1050       so << (char)(arc.UpdateEnabled ? 'C' : ' ');
1051 
1052       {
1053         unsigned b;
1054         for (b = 0; b < kNumArcFlags; b++)
1055           so << (char)((arc.Flags & ((UInt32)1 << b)) != 0 ? kArcFlags[b] : '.');
1056         so << ' ';
1057       }
1058 
1059       if (arc.TimeFlags != 0)
1060       {
1061         unsigned b;
1062         for (b = 0; b < kNumArcTimeFlags; b++)
1063           so << (char)((arc.TimeFlags & ((UInt32)1 << b)) != 0 ? kArcTimeFlags[b] : '.');
1064         so << arc.Get_DefaultTimePrec();
1065         so << ' ';
1066       }
1067 
1068       so << ' ';
1069       PrintString(so, arc.Name, 8);
1070       so << ' ';
1071       UString s;
1072 
1073       FOR_VECTOR (t, arc.Exts)
1074       {
1075         if (t != 0)
1076           s.Add_Space();
1077         const CArcExtInfo &ext = arc.Exts[t];
1078         s += ext.Ext;
1079         if (!ext.AddExt.IsEmpty())
1080         {
1081           s += " (";
1082           s += ext.AddExt;
1083           s += ')';
1084         }
1085       }
1086 
1087       PrintString(so, s, 13);
1088       so << ' ';
1089 
1090       if (arc.SignatureOffset != 0)
1091         so << "offset=" << arc.SignatureOffset << ' ';
1092 
1093       // so << "numSignatures = " << arc.Signatures.Size() << " ";
1094 
1095       FOR_VECTOR(si, arc.Signatures)
1096       {
1097         if (si != 0)
1098           so << "  ||  ";
1099 
1100         const CByteBuffer &sig = arc.Signatures[si];
1101 
1102         for (size_t j = 0; j < sig.Size(); j++)
1103         {
1104           if (j != 0)
1105             so << ' ';
1106           Byte b = sig[j];
1107           if (b > 0x20 && b < 0x80)
1108           {
1109             so << (char)b;
1110           }
1111           else
1112           {
1113             so << GetHex((b >> 4) & 0xF);
1114             so << GetHex(b & 0xF);
1115           }
1116         }
1117       }
1118       so << endl;
1119     }
1120 
1121     so << endl << "Codecs:" << endl; //  << "Lib          ID Name" << endl;
1122 
1123     for (i = 0; i < g_NumCodecs; i++)
1124     {
1125       const CCodecInfo &cod = *g_Codecs[i];
1126 
1127       PrintLibIndex(so, -1);
1128 
1129       if (cod.NumStreams == 1)
1130         so << ' ';
1131       else
1132         so << cod.NumStreams;
1133 
1134       so << (char)(cod.CreateEncoder ? 'E' : ' ');
1135       so << (char)(cod.CreateDecoder ? 'D' : ' ');
1136       so << (char)(cod.IsFilter      ? 'F' : ' ');
1137 
1138       so << ' ';
1139       PrintHexId(so, cod.Id);
1140       so << ' ' << cod.Name << endl;
1141     }
1142 
1143 
1144     #ifdef Z7_EXTERNAL_CODECS
1145 
1146     UInt32 numMethods;
1147     if (_externalCodecs.GetCodecs->GetNumMethods(&numMethods) == S_OK)
1148     for (UInt32 j = 0; j < numMethods; j++)
1149     {
1150       PrintLibIndex(so, codecs->GetCodec_LibIndex(j));
1151 
1152       UInt32 numStreams = codecs->GetCodec_NumStreams(j);
1153       if (numStreams == 1)
1154         so << ' ';
1155       else
1156         so << numStreams;
1157 
1158       so << (char)(codecs->GetCodec_EncoderIsAssigned(j) ? 'E' : ' ');
1159       so << (char)(codecs->GetCodec_DecoderIsAssigned(j) ? 'D' : ' ');
1160       {
1161         bool isFilter_Assigned;
1162         const bool isFilter = codecs->GetCodec_IsFilter(j, isFilter_Assigned);
1163         so << (char)(isFilter ? 'F' : isFilter_Assigned ? ' ' : '*');
1164       }
1165 
1166 
1167       so << ' ';
1168       UInt64 id;
1169       HRESULT res = codecs->GetCodec_Id(j, id);
1170       if (res != S_OK)
1171         id = (UInt64)(Int64)-1;
1172       PrintHexId(so, id);
1173       so << ' ' << codecs->GetCodec_Name(j) << endl;
1174     }
1175 
1176     #endif
1177 
1178 
1179     so << endl << "Hashers:" << endl; //  << " L Size       ID Name" << endl;
1180 
1181     for (i = 0; i < g_NumHashers; i++)
1182     {
1183       const CHasherInfo &codec = *g_Hashers[i];
1184       PrintLibIndex(so, -1);
1185       PrintUInt32(so, codec.DigestSize, 4);
1186       so << ' ';
1187       PrintHexId(so, codec.Id);
1188       so << ' ' << codec.Name << endl;
1189     }
1190 
1191     #ifdef Z7_EXTERNAL_CODECS
1192 
1193     numMethods = _externalCodecs.GetHashers->GetNumHashers();
1194     for (UInt32 j = 0; j < numMethods; j++)
1195     {
1196       PrintLibIndex(so, codecs->GetHasherLibIndex(j));
1197       PrintUInt32(so, codecs->GetHasherDigestSize(j), 4);
1198       so << ' ';
1199       PrintHexId(so, codecs->GetHasherId(j));
1200       so << ' ' << codecs->GetHasherName(j) << endl;
1201     }
1202 
1203     #endif
1204 
1205   }
1206   else if (options.Command.CommandType == NCommandType::kBenchmark)
1207   {
1208     CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut);
1209     hresultMain = BenchCon(EXTERNAL_CODECS_VARS_L
1210         options.Properties, options.NumIterations, (FILE *)so);
1211     if (hresultMain == S_FALSE)
1212     {
1213       so << endl;
1214       if (g_ErrStream)
1215         *g_ErrStream << "\nDecoding ERROR\n";
1216       retCode = NExitCode::kFatalError;
1217       hresultMain = S_OK;
1218     }
1219   }
1220   else if (isExtractGroupCommand || options.Command.CommandType == NCommandType::kList)
1221   {
1222     UStringVector ArchivePathsSorted;
1223     UStringVector ArchivePathsFullSorted;
1224 
1225     if (options.StdInMode)
1226     {
1227       ArchivePathsSorted.Add(options.ArcName_for_StdInMode);
1228       ArchivePathsFullSorted.Add(options.ArcName_for_StdInMode);
1229     }
1230     else
1231     {
1232       CExtractScanConsole scan;
1233 
1234       scan.Init(options.EnableHeaders ? g_StdStream : NULL, g_ErrStream, percentsStream);
1235       scan.SetWindowWidth(consoleWidth);
1236 
1237       if (g_StdStream && options.EnableHeaders)
1238         *g_StdStream << "Scanning the drive for archives:" << endl;
1239 
1240       CDirItemsStat st;
1241 
1242       scan.StartScanning();
1243 
1244       hresultMain = EnumerateDirItemsAndSort(
1245           options.arcCensor,
1246           NWildcard::k_RelatPath,
1247           UString(), // addPathPrefix
1248           ArchivePathsSorted,
1249           ArchivePathsFullSorted,
1250           st,
1251           &scan);
1252 
1253       scan.CloseScanning();
1254 
1255       if (hresultMain == S_OK)
1256       {
1257         if (options.EnableHeaders)
1258           scan.PrintStat(st);
1259       }
1260       else
1261       {
1262         /*
1263         if (res != E_ABORT)
1264         {
1265           throw CSystemException(res);
1266           // errorInfo.Message = "Scanning error";
1267         }
1268         return res;
1269         */
1270       }
1271     }
1272 
1273     if (hresultMain == S_OK) {
1274     if (isExtractGroupCommand)
1275     {
1276       CExtractCallbackConsole *ecs = new CExtractCallbackConsole;
1277       CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
1278 
1279       #ifndef Z7_NO_CRYPTO
1280       ecs->PasswordIsDefined = options.PasswordEnabled;
1281       ecs->Password = options.Password;
1282       #endif
1283 
1284       ecs->Init(g_StdStream, g_ErrStream, percentsStream);
1285       ecs->MultiArcMode = (ArchivePathsSorted.Size() > 1);
1286 
1287       ecs->LogLevel = options.LogLevel;
1288       ecs->PercentsNameLevel = percentsNameLevel;
1289 
1290       if (percentsStream)
1291         ecs->SetWindowWidth(consoleWidth);
1292 
1293       /*
1294       COpenCallbackConsole openCallback;
1295       openCallback.Init(g_StdStream, g_ErrStream);
1296 
1297       #ifndef Z7_NO_CRYPTO
1298       openCallback.PasswordIsDefined = options.PasswordEnabled;
1299       openCallback.Password = options.Password;
1300       #endif
1301       */
1302 
1303       CExtractOptions eo;
1304       (CExtractOptionsBase &)eo = options.ExtractOptions;
1305 
1306       eo.StdInMode = options.StdInMode;
1307       eo.StdOutMode = options.StdOutMode;
1308       eo.YesToAll = options.YesToAll;
1309       eo.TestMode = options.Command.IsTestCommand();
1310 
1311       #ifndef Z7_SFX
1312       eo.Properties = options.Properties;
1313       #endif
1314 
1315       UString errorMessage;
1316       CDecompressStat stat;
1317       CHashBundle hb;
1318       IHashCalc *hashCalc = NULL;
1319 
1320       if (!options.HashMethods.IsEmpty())
1321       {
1322         hashCalc = &hb;
1323         ThrowException_if_Error(hb.SetMethods(EXTERNAL_CODECS_VARS_L options.HashMethods));
1324         // hb.Init();
1325       }
1326 
1327       hresultMain = Extract(
1328           // EXTERNAL_CODECS_VARS_L
1329           codecs,
1330           types,
1331           excludedFormats,
1332           ArchivePathsSorted,
1333           ArchivePathsFullSorted,
1334           options.Censor.Pairs.Front().Head,
1335           eo,
1336           ecs, ecs, ecs,
1337           hashCalc, errorMessage, stat);
1338 
1339       ecs->ClosePercents();
1340 
1341       if (!errorMessage.IsEmpty())
1342       {
1343         if (g_ErrStream)
1344           *g_ErrStream << endl << "ERROR:" << endl << errorMessage << endl;
1345         if (hresultMain == S_OK)
1346           hresultMain = E_FAIL;
1347       }
1348 
1349       CStdOutStream *so = g_StdStream;
1350 
1351       bool isError = false;
1352 
1353       if (so)
1354       {
1355         *so << endl;
1356 
1357         if (ecs->NumTryArcs > 1)
1358         {
1359           *so << "Archives: " << ecs->NumTryArcs << endl;
1360           *so << "OK archives: " << ecs->NumOkArcs << endl;
1361         }
1362       }
1363 
1364       if (ecs->NumCantOpenArcs != 0)
1365       {
1366         isError = true;
1367         if (so)
1368           *so << "Can't open as archive: " << ecs->NumCantOpenArcs << endl;
1369       }
1370 
1371       if (ecs->NumArcsWithError != 0)
1372       {
1373         isError = true;
1374         if (so)
1375           *so << "Archives with Errors: " << ecs->NumArcsWithError << endl;
1376       }
1377 
1378       if (so)
1379       {
1380         if (ecs->NumArcsWithWarnings != 0)
1381           *so << "Archives with Warnings: " << ecs->NumArcsWithWarnings << endl;
1382 
1383         if (ecs->NumOpenArcWarnings != 0)
1384         {
1385           *so << endl;
1386           if (ecs->NumOpenArcWarnings != 0)
1387             *so << "Warnings: " << ecs->NumOpenArcWarnings << endl;
1388         }
1389       }
1390 
1391       if (ecs->NumOpenArcErrors != 0)
1392       {
1393         isError = true;
1394         if (so)
1395         {
1396           *so << endl;
1397           if (ecs->NumOpenArcErrors != 0)
1398             *so << "Open Errors: " << ecs->NumOpenArcErrors << endl;
1399         }
1400       }
1401 
1402       if (isError)
1403         retCode = NExitCode::kFatalError;
1404 
1405       if (so) {
1406       if (ecs->NumArcsWithError != 0 || ecs->NumFileErrors != 0)
1407       {
1408         // if (ecs->NumArchives > 1)
1409         {
1410           *so << endl;
1411           if (ecs->NumFileErrors != 0)
1412             *so << "Sub items Errors: " << ecs->NumFileErrors << endl;
1413         }
1414       }
1415       else if (hresultMain == S_OK)
1416       {
1417         if (stat.NumFolders != 0)
1418           *so << "Folders: " << stat.NumFolders << endl;
1419         if (stat.NumFiles != 1 || stat.NumFolders != 0 || stat.NumAltStreams != 0)
1420           *so << "Files: " << stat.NumFiles << endl;
1421         if (stat.NumAltStreams != 0)
1422         {
1423           *so << "Alternate Streams: " << stat.NumAltStreams << endl;
1424           *so << "Alternate Streams Size: " << stat.AltStreams_UnpackSize << endl;
1425         }
1426 
1427         *so
1428           << "Size:       " << stat.UnpackSize << endl
1429           << "Compressed: " << stat.PackSize << endl;
1430         if (hashCalc)
1431         {
1432           *so << endl;
1433           PrintHashStat(*so, hb);
1434         }
1435       }
1436       } // if (so)
1437     }
1438     else // if_(!isExtractGroupCommand)
1439     {
1440       UInt64 numErrors = 0;
1441       UInt64 numWarnings = 0;
1442 
1443       // options.ExtractNtOptions.StoreAltStreams = true, if -sns[-] is not definmed
1444 
1445       CListOptions lo;
1446       lo.ExcludeDirItems = options.Censor.ExcludeDirItems;
1447       lo.ExcludeFileItems = options.Censor.ExcludeFileItems;
1448 
1449       hresultMain = ListArchives(
1450           lo,
1451           codecs,
1452           types,
1453           excludedFormats,
1454           options.StdInMode,
1455           ArchivePathsSorted,
1456           ArchivePathsFullSorted,
1457           options.ExtractOptions.NtOptions.AltStreams.Val,
1458           options.AltStreams.Val, // we don't want to show AltStreams by default
1459           options.Censor.Pairs.Front().Head,
1460           options.EnableHeaders,
1461           options.TechMode,
1462           #ifndef Z7_NO_CRYPTO
1463           options.PasswordEnabled,
1464           options.Password,
1465           #endif
1466           &options.Properties,
1467           numErrors, numWarnings);
1468 
1469       if (options.EnableHeaders)
1470         if (numWarnings > 0)
1471           g_StdOut << endl << "Warnings: " << numWarnings << endl;
1472 
1473       if (numErrors > 0)
1474       {
1475         if (options.EnableHeaders)
1476           g_StdOut << endl << "Errors: " << numErrors << endl;
1477         retCode = NExitCode::kFatalError;
1478       }
1479     } // if_(isExtractGroupCommand)
1480     } // if_(hresultMain == S_OK)
1481   }
1482   else if (options.Command.IsFromUpdateGroup())
1483   {
1484     CUpdateOptions &uo = options.UpdateOptions;
1485     if (uo.SfxMode && uo.SfxModule.IsEmpty())
1486       uo.SfxModule = kDefaultSfxModule;
1487 
1488     COpenCallbackConsole openCallback;
1489     openCallback.Init(g_StdStream, g_ErrStream, percentsStream);
1490 
1491     #ifndef Z7_NO_CRYPTO
1492     bool passwordIsDefined =
1493         (options.PasswordEnabled && !options.Password.IsEmpty());
1494     openCallback.PasswordIsDefined = passwordIsDefined;
1495     openCallback.Password = options.Password;
1496     #endif
1497 
1498     CUpdateCallbackConsole callback;
1499     callback.LogLevel = options.LogLevel;
1500     callback.PercentsNameLevel = percentsNameLevel;
1501 
1502     if (percentsStream)
1503       callback.SetWindowWidth(consoleWidth);
1504 
1505     #ifndef Z7_NO_CRYPTO
1506     callback.PasswordIsDefined = passwordIsDefined;
1507     callback.AskPassword = (options.PasswordEnabled && options.Password.IsEmpty());
1508     callback.Password = options.Password;
1509     #endif
1510 
1511     callback.StdOutMode = uo.StdOutMode;
1512     callback.Init(
1513       // NULL,
1514       g_StdStream, g_ErrStream, percentsStream);
1515 
1516     CUpdateErrorInfo errorInfo;
1517 
1518     /*
1519     if (!uo.Init(codecs, types, options.ArchiveName))
1520       throw kUnsupportedUpdateArcType;
1521     */
1522     hresultMain = UpdateArchive(codecs,
1523         types,
1524         options.ArchiveName,
1525         options.Censor,
1526         uo,
1527         errorInfo, &openCallback, &callback, true);
1528 
1529     callback.ClosePercents2();
1530 
1531     CStdOutStream *se = g_StdStream;
1532     if (!se)
1533       se = g_ErrStream;
1534 
1535     retCode = WarningsCheck(hresultMain, callback, errorInfo,
1536         g_StdStream, se,
1537         true // options.EnableHeaders
1538         );
1539   }
1540   else if (options.Command.CommandType == NCommandType::kHash)
1541   {
1542     const CHashOptions &uo = options.HashOptions;
1543 
1544     CHashCallbackConsole callback;
1545     if (percentsStream)
1546       callback.SetWindowWidth(consoleWidth);
1547 
1548     callback.Init(g_StdStream, g_ErrStream, percentsStream);
1549     callback.PrintHeaders = options.EnableHeaders;
1550     callback.PrintFields = options.ListFields;
1551 
1552     AString errorInfoString;
1553     hresultMain = HashCalc(EXTERNAL_CODECS_VARS_L
1554         options.Censor, uo,
1555         errorInfoString, &callback);
1556     CUpdateErrorInfo errorInfo;
1557     errorInfo.Message = errorInfoString;
1558     CStdOutStream *se = g_StdStream;
1559     if (!se)
1560       se = g_ErrStream;
1561     retCode = WarningsCheck(hresultMain, callback, errorInfo, g_StdStream, se, options.EnableHeaders);
1562   }
1563   else
1564     ShowMessageAndThrowException(kUserErrorMessage, NExitCode::kUserError);
1565 
1566   if (options.ShowTime && g_StdStream)
1567     PrintStat(
1568       #ifndef _WIN32
1569         startTime
1570       #endif
1571     );
1572 
1573   ThrowException_if_Error(hresultMain);
1574 
1575   return retCode;
1576 }
1577