xref: /third_party/lzma/CPP/7zip/UI/Console/Main.cpp (revision 370b324c)
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
19typedef 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;
31typedef 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
84using namespace NWindows;
85using namespace NFile;
86using namespace NCommandLineParser;
87
88#ifdef _WIN32
89extern
90HINSTANCE g_hInstance;
91HINSTANCE g_hInstance = NULL;
92#endif
93
94extern CStdOutStream *g_StdStream;
95extern CStdOutStream *g_ErrStream;
96
97extern unsigned g_NumCodecs;
98extern const CCodecInfo *g_Codecs[];
99
100extern unsigned g_NumHashers;
101extern const CHasherInfo *g_Hashers[];
102
103#ifdef Z7_EXTERNAL_CODECS
104extern
105const CExternalCodecs *g_ExternalCodecs_Ptr;
106const CExternalCodecs *g_ExternalCodecs_Ptr;
107#endif
108
109DECLARE_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
126static const char * const kCopyrightString = "\n7-Zip"
127  PROG_POSTFIX_2
128  " " MY_VERSION_CPU
129  " : " MY_COPYRIGHT_DATE "\n";
130
131static 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
203static const char * const kEverythingIsOk = "Everything is Ok";
204static const char * const kUserErrorMessage = "Incorrect command line";
205static const char * const kNoFormats = "7-Zip cannot find the code that works with archives.";
206static 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
211Z7_ATTR_NORETURN
212static 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
223static 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
327static 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
340static 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
348static 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
356static 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
366static 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
375static 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
383static inline char GetHex(unsigned val)
384{
385  return (char)((val < 10) ? ('0' + val) : ('A' + (val - 10)));
386}
387
388static 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
399static 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
481static void ThrowException_if_Error(HRESULT res)
482{
483  if (res != S_OK)
484    throw CSystemException(res);
485}
486
487static 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
500static 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
528static 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
546EXTERN_C_BEGIN
547typedef BOOL (WINAPI *Func_GetProcessMemoryInfo)(HANDLE Process,
548    PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb);
549typedef BOOL (WINAPI *Func_QueryProcessCycleTime)(HANDLE Process, PULONG64 CycleTime);
550EXTERN_C_END
551
552#endif
553
554static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
555
556static 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
663static 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
671static 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
729static 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
748static 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
756void Set_ModuleDirPrefix_From_ProgArg0(const char *s);
757#endif
758
759int Main2(
760  #ifndef _WIN32
761  int numArgs, char *args[]
762  #endif
763);
764int 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