1 // Main.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../Common/MyWindows.h"
6 
7 #ifdef _WIN32
8 #include <Psapi.h>
9 #endif
10 
11 #include "../../../../C/CpuArch.h"
12 
13 #if defined( _7ZIP_LARGE_PAGES)
14 #include "../../../../C/Alloc.h"
15 #endif
16 
17 #include "../../../Common/MyInitGuid.h"
18 
19 #include "../../../Common/CommandLineParser.h"
20 #include "../../../Common/IntToString.h"
21 #include "../../../Common/MyException.h"
22 #include "../../../Common/StringConvert.h"
23 #include "../../../Common/StringToInt.h"
24 #include "../../../Common/UTFConvert.h"
25 
26 #include "../../../Windows/ErrorMsg.h"
27 
28 #ifdef _WIN32
29 #include "../../../Windows/MemoryLock.h"
30 #endif
31 
32 #include "../../../Windows/TimeUtils.h"
33 
34 #include "../Common/ArchiveCommandLine.h"
35 #include "../Common/ExitCode.h"
36 #include "../Common/Extract.h"
37 
38 #ifdef EXTERNAL_CODECS
39 #include "../Common/LoadCodecs.h"
40 #endif
41 
42 #include "../../Common/RegisterCodec.h"
43 
44 #include "BenchCon.h"
45 #include "ConsoleClose.h"
46 #include "ExtractCallbackConsole.h"
47 #include "List.h"
48 #include "OpenCallbackConsole.h"
49 #include "UpdateCallbackConsole.h"
50 
51 #include "HashCon.h"
52 
53 #ifdef PROG_VARIANT_R
54 #include "../../../../C/7zVersion.h"
55 #else
56 #include "../../MyVersion.h"
57 #endif
58 
59 using namespace NWindows;
60 using namespace NFile;
61 using namespace NCommandLineParser;
62 
63 #ifdef _WIN32
64 HINSTANCE g_hInstance = 0;
65 #endif
66 
67 extern CStdOutStream *g_StdStream;
68 extern CStdOutStream *g_ErrStream;
69 
70 extern unsigned g_NumCodecs;
71 extern const CCodecInfo *g_Codecs[];
72 
73 extern unsigned g_NumHashers;
74 extern const CHasherInfo *g_Hashers[];
75 
76 static const char *kCopyrightString = "\n7-Zip"
77 #ifndef EXTERNAL_CODECS
78 #ifdef PROG_VARIANT_R
79 " (r)"
80 #else
81 " (a)"
82 #endif
83 #endif
84 
85 #ifdef MY_CPU_64BIT
86 " [64]"
87 #elif defined MY_CPU_32BIT
88 " [32]"
89 #endif
90 
91 " " MY_VERSION_COPYRIGHT_DATE "\n\n";
92 
93 static const char *kHelpString =
94     "Usage: 7z"
95 #ifndef EXTERNAL_CODECS
96 #ifdef PROG_VARIANT_R
97     "r"
98 #else
99     "a"
100 #endif
101 #endif
102     " <command> [<switches>...] <archive_name> [<file_names>...]\n"
103     "       [<@listfiles...>]\n"
104     "\n"
105     "<Commands>\n"
106     "  a : Add files to archive\n"
107     "  b : Benchmark\n"
108     "  d : Delete files from archive\n"
109     "  e : Extract files from archive (without using directory names)\n"
110     "  h : Calculate hash values for files\n"
111     "  i : Show information about supported formats\n"
112     "  l : List contents of archive\n"
113     "  rn : Rename files in archive\n"
114     "  t : Test integrity of archive\n"
115     "  u : Update files to archive\n"
116     "  x : eXtract files with full paths\n"
117     "\n"
118     "<Switches>\n"
119     "  -- : Stop switches parsing\n"
120     "  -ai[r[-|0]]{@listfile|!wildcard} : Include archives\n"
121     "  -ax[r[-|0]]{@listfile|!wildcard} : eXclude archives\n"
122     "  -ao{a|s|t|u} : set Overwrite mode\n"
123     "  -an : disable archive_name field\n"
124     "  -bb[0-3] : set output log level\n"
125     "  -bd : disable progress indicator\n"
126     "  -bs{o|e|p}{0|1|2} : set output stream for output/error/progress line\n"
127     "  -bt : show execution time statistics\n"
128     "  -i[r[-|0]]{@listfile|!wildcard} : Include filenames\n"
129     "  -m{Parameters} : set compression Method\n"
130     "    -mmt[N] : set number of CPU threads\n"
131     "  -o{Directory} : set Output directory\n"
132     #ifndef _NO_CRYPTO
133     "  -p{Password} : set Password\n"
134     #endif
135     "  -r[-|0] : Recurse subdirectories\n"
136     "  -sa{a|e|s} : set Archive name mode\n"
137     "  -scc{UTF-8|WIN|DOS} : set charset for for console input/output\n"
138     "  -scs{UTF-8|UTF-16LE|UTF-16BE|WIN|DOS|{id}} : set charset for list files\n"
139     "  -scrc[CRC32|CRC64|SHA1|SHA256|*] : set hash function for x, e, h commands\n"
140     "  -sdel : delete files after compression\n"
141     "  -seml[.] : send archive by email\n"
142     "  -sfx[{name}] : Create SFX archive\n"
143     "  -si[{name}] : read data from stdin\n"
144     "  -slp : set Large Pages mode\n"
145     "  -slt : show technical information for l (List) command\n"
146     "  -snh : store hard links as links\n"
147     "  -snl : store symbolic links as links\n"
148     "  -sni : store NT security information\n"
149     "  -sns[-] : store NTFS alternate streams\n"
150     "  -so : write data to stdout\n"
151     "  -spd : disable wildcard matching for file names\n"
152     "  -spe : eliminate duplication of root folder for extract command\n"
153     "  -spf : use fully qualified file paths\n"
154     "  -ssc[-] : set sensitive case mode\n"
155     "  -ssw : compress shared files\n"
156     "  -stl : set archive timestamp from the most recently modified file\n"
157     "  -stm{HexMask} : set CPU thread affinity mask (hexadecimal number)\n"
158     "  -stx{Type} : exclude archive type\n"
159     "  -t{Type} : Set type of archive\n"
160     "  -u[-][p#][q#][r#][x#][y#][z#][!newArchiveName] : Update options\n"
161     "  -v{Size}[b|k|m|g] : Create volumes\n"
162     "  -w[{path}] : assign Work directory. Empty path means a temporary directory\n"
163     "  -x[r[-|0]]{@listfile|!wildcard} : eXclude filenames\n"
164     "  -y : assume Yes on all queries\n";
165 
166 // ---------------------------
167 // exception messages
168 
169 static const char *kEverythingIsOk = "Everything is Ok";
170 static const char *kUserErrorMessage = "Incorrect command line";
171 static const char *kNoFormats = "7-Zip cannot find the code that works with archives.";
172 static const char *kUnsupportedArcTypeMessage = "Unsupported archive type";
173 // static const char *kUnsupportedUpdateArcType = "Can't create archive for that type";
174 
175 static CFSTR kDefaultSfxModule = FTEXT("7zCon.sfx");
176 
ShowMessageAndThrowException(LPCSTR message,NExitCode::EEnum code)177 static void ShowMessageAndThrowException(LPCSTR message, NExitCode::EEnum code)
178 {
179   if (g_ErrStream)
180     *g_ErrStream << endl << "ERROR: " << message << endl;
181   throw code;
182 }
183 
184 #ifndef _WIN32
GetArguments(int numArgs,const char * args[],UStringVector & parts)185 static void GetArguments(int numArgs, const char *args[], UStringVector &parts)
186 {
187   parts.Clear();
188   for (int i = 0; i < numArgs; i++)
189   {
190     UString s = MultiByteToUnicodeString(args[i]);
191     parts.Add(s);
192   }
193 }
194 #endif
195 
ShowCopyrightAndHelp(CStdOutStream * so,bool needHelp)196 static void ShowCopyrightAndHelp(CStdOutStream *so, bool needHelp)
197 {
198   if (!so)
199     return;
200   *so << kCopyrightString;
201   // *so << "# CPUs: " << (UInt64)NWindows::NSystem::GetNumberOfProcessors() << endl;
202   if (needHelp)
203     *so << kHelpString;
204 }
205 
206 
PrintStringRight(CStdOutStream & so,const AString & s,unsigned size)207 static void PrintStringRight(CStdOutStream &so, const AString &s, unsigned size)
208 {
209   unsigned len = s.Len();
210   for (unsigned i = len; i < size; i++)
211     so << ' ';
212   so << s;
213 }
214 
PrintUInt32(CStdOutStream & so,UInt32 val,unsigned size)215 static void PrintUInt32(CStdOutStream &so, UInt32 val, unsigned size)
216 {
217   char s[16];
218   ConvertUInt32ToString(val, s);
219   PrintStringRight(so, s, size);
220 }
221 
PrintLibIndex(CStdOutStream & so,int libIndex)222 static void PrintLibIndex(CStdOutStream &so, int libIndex)
223 {
224   if (libIndex >= 0)
225     PrintUInt32(so, libIndex, 2);
226   else
227     so << "  ";
228   so << ' ';
229 }
230 
PrintString(CStdOutStream & so,const UString & s,unsigned size)231 static void PrintString(CStdOutStream &so, const UString &s, unsigned size)
232 {
233   unsigned len = s.Len();
234   so << s;
235   for (unsigned i = len; i < size; i++)
236     so << ' ';
237 }
238 
GetHex(unsigned val)239 static inline char GetHex(unsigned val)
240 {
241   return (char)((val < 10) ? ('0' + val) : ('A' + (val - 10)));
242 }
243 
PrintWarningsPaths(const CErrorPathCodes & pc,CStdOutStream & so)244 static void PrintWarningsPaths(const CErrorPathCodes &pc, CStdOutStream &so)
245 {
246   FOR_VECTOR(i, pc.Paths)
247   {
248     so << pc.Paths[i] << " : ";
249     so << NError::MyFormatMessage(pc.Codes[i]) << endl;
250   }
251   so << "----------------" << endl;
252 }
253 
WarningsCheck(HRESULT result,const CCallbackConsoleBase & callback,const CUpdateErrorInfo & errorInfo,CStdOutStream * so,CStdOutStream * se,bool showHeaders)254 static int WarningsCheck(HRESULT result, const CCallbackConsoleBase &callback,
255     const CUpdateErrorInfo &errorInfo,
256     CStdOutStream *so,
257     CStdOutStream *se,
258     bool showHeaders)
259 {
260   int exitCode = NExitCode::kSuccess;
261 
262   if (callback.ScanErrors.Paths.Size() != 0)
263   {
264     if (se)
265     {
266       *se << endl;
267       *se << "Scan WARNINGS for files and folders:" << endl << endl;
268       PrintWarningsPaths(callback.ScanErrors, *se);
269       *se << "Scan WARNINGS: " << callback.ScanErrors.Paths.Size();
270       *se << endl;
271     }
272     exitCode = NExitCode::kWarning;
273   }
274 
275   if (result != S_OK || errorInfo.ThereIsError())
276   {
277     if (se)
278     {
279       UString message;
280       if (!errorInfo.Message.IsEmpty())
281       {
282         message.AddAscii(errorInfo.Message);
283         message.Add_LF();
284       }
285       {
286         FOR_VECTOR(i, errorInfo.FileNames)
287         {
288           message += fs2us(errorInfo.FileNames[i]);
289           message.Add_LF();
290         }
291       }
292       if (errorInfo.SystemError != 0)
293       {
294         message += NError::MyFormatMessage(errorInfo.SystemError);
295         message.Add_LF();
296       }
297       if (!message.IsEmpty())
298         *se << L"\nError:\n" << message;
299     }
300 
301     // we will work with (result) later
302     // throw CSystemException(result);
303     return NExitCode::kFatalError;
304   }
305 
306   unsigned numErrors = callback.FailedFiles.Paths.Size();
307   if (numErrors == 0)
308   {
309     if (showHeaders)
310       if (callback.ScanErrors.Paths.Size() == 0)
311         if (so)
312         {
313           if (se)
314             se->Flush();
315           *so << kEverythingIsOk << endl;
316         }
317   }
318   else
319   {
320     if (se)
321     {
322       *se << endl;
323       *se << "WARNINGS for files:" << endl << endl;
324       PrintWarningsPaths(callback.FailedFiles, *se);
325       *se << "WARNING: Cannot open " << numErrors << " file";
326       if (numErrors > 1)
327         *se << 's';
328       *se << endl;
329     }
330     exitCode = NExitCode::kWarning;
331   }
332 
333   return exitCode;
334 }
335 
ThrowException_if_Error(HRESULT res)336 static void ThrowException_if_Error(HRESULT res)
337 {
338   if (res != S_OK)
339     throw CSystemException(res);
340 }
341 
342 
PrintNum(UInt64 val,unsigned numDigits,char c=' ')343 static void PrintNum(UInt64 val, unsigned numDigits, char c = ' ')
344 {
345   char temp[64];
346   char *p = temp + 32;
347   ConvertUInt64ToString(val, p);
348   unsigned len = MyStringLen(p);
349   for (; len < numDigits; len++)
350     *--p = c;
351   *g_StdStream << p;
352 }
353 
PrintTime(const char * s,UInt64 val,UInt64 total)354 static void PrintTime(const char *s, UInt64 val, UInt64 total)
355 {
356   *g_StdStream << endl << s << " Time =";
357   const UInt32 kFreq = 10000000;
358   UInt64 sec = val / kFreq;
359   PrintNum(sec, 6);
360   *g_StdStream << '.';
361   UInt32 ms = (UInt32)(val - (sec * kFreq)) / (kFreq / 1000);
362   PrintNum(ms, 3, '0');
363 
364   while (val > ((UInt64)1 << 56))
365   {
366     val >>= 1;
367     total >>= 1;
368   }
369 
370   UInt64 percent = 0;
371   if (total != 0)
372     percent = val * 100 / total;
373   *g_StdStream << " =";
374   PrintNum(percent, 5);
375   *g_StdStream << '%';
376 }
377 
378 #ifndef UNDER_CE
379 
380 #define SHIFT_SIZE_VALUE(x, num) (((x) + (1 << (num)) - 1) >> (num))
381 
PrintMemUsage(const char * s,UInt64 val)382 static void PrintMemUsage(const char *s, UInt64 val)
383 {
384   *g_StdStream << "    " << s << " Memory =";
385   PrintNum(SHIFT_SIZE_VALUE(val, 20), 7);
386   *g_StdStream << " MB";
387 }
388 
389 EXTERN_C_BEGIN
390 typedef BOOL (WINAPI *Func_GetProcessMemoryInfo)(HANDLE Process,
391     PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb);
392 EXTERN_C_END
393 
394 #endif
395 
GetTime64(const FILETIME & t)396 static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
397 
PrintStat()398 static void PrintStat()
399 {
400   FILETIME creationTimeFT, exitTimeFT, kernelTimeFT, userTimeFT;
401   if (!
402       #ifdef UNDER_CE
403         ::GetThreadTimes(::GetCurrentThread()
404       #else
405         // NT 3.5
406         ::GetProcessTimes(::GetCurrentProcess()
407       #endif
408       , &creationTimeFT, &exitTimeFT, &kernelTimeFT, &userTimeFT))
409     return;
410   FILETIME curTimeFT;
411   NTime::GetCurUtcFileTime(curTimeFT);
412 
413   #ifndef UNDER_CE
414 
415   PROCESS_MEMORY_COUNTERS m;
416   memset(&m, 0, sizeof(m));
417   BOOL memDefined = FALSE;
418   {
419     /* NT 4.0: GetProcessMemoryInfo() in Psapi.dll
420        Win7: new function K32GetProcessMemoryInfo() in kernel32.dll
421        It's faster to call kernel32.dll code than Psapi.dll code
422        GetProcessMemoryInfo() requires Psapi.lib
423        Psapi.lib in SDK7+ can link to K32GetProcessMemoryInfo in kernel32.dll
424        The program with K32GetProcessMemoryInfo will not work on systems before Win7
425        // memDefined = GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m));
426     */
427 
428     Func_GetProcessMemoryInfo my_GetProcessMemoryInfo = (Func_GetProcessMemoryInfo)
429         ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "K32GetProcessMemoryInfo");
430     if (!my_GetProcessMemoryInfo)
431     {
432       HMODULE lib = LoadLibraryW(L"Psapi.dll");
433       if (lib)
434         my_GetProcessMemoryInfo = (Func_GetProcessMemoryInfo)::GetProcAddress(lib, "GetProcessMemoryInfo");
435     }
436     if (my_GetProcessMemoryInfo)
437       memDefined = my_GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m));
438     // FreeLibrary(lib);
439   }
440 
441   #endif
442 
443   UInt64 curTime = GetTime64(curTimeFT);
444   UInt64 creationTime = GetTime64(creationTimeFT);
445   UInt64 kernelTime = GetTime64(kernelTimeFT);
446   UInt64 userTime = GetTime64(userTimeFT);
447 
448   UInt64 totalTime = curTime - creationTime;
449 
450   PrintTime("Kernel ", kernelTime, totalTime);
451   PrintTime("User   ", userTime, totalTime);
452 
453   PrintTime("Process", kernelTime + userTime, totalTime);
454   #ifndef UNDER_CE
455   if (memDefined) PrintMemUsage("Virtual ", m.PeakPagefileUsage);
456   #endif
457 
458   PrintTime("Global ", totalTime, totalTime);
459   #ifndef UNDER_CE
460   if (memDefined) PrintMemUsage("Physical", m.PeakWorkingSetSize);
461   #endif
462 
463   *g_StdStream << endl;
464 }
465 
PrintHexId(CStdOutStream & so,UInt64 id)466 static void PrintHexId(CStdOutStream &so, UInt64 id)
467 {
468   char s[32];
469   ConvertUInt64ToHex(id, s);
470   PrintStringRight(so, s, 8);
471 }
472 
Main2(int numArgs,char * args[])473 int Main2(
474   #ifndef _WIN32
475   int numArgs, char *args[]
476   #endif
477 )
478 {
479   #if defined(_WIN32) && !defined(UNDER_CE)
480   SetFileApisToOEM();
481   #endif
482 
483   UStringVector commandStrings;
484 
485   #ifdef _WIN32
486   NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
487   #else
488   GetArguments(numArgs, args, commandStrings);
489   #endif
490 
491   if (commandStrings.Size() == 1)
492   {
493     ShowCopyrightAndHelp(g_StdStream, true);
494     return 0;
495   }
496 
497   commandStrings.Delete(0);
498 
499   CArcCmdLineOptions options;
500 
501   CArcCmdLineParser parser;
502 
503   parser.Parse1(commandStrings, options);
504 
505 
506   if (options.Number_for_Out != k_OutStream_stdout)
507     g_StdStream = (options.Number_for_Out == k_OutStream_stderr ? &g_StdErr : NULL);
508 
509   if (options.Number_for_Errors != k_OutStream_stderr)
510     g_ErrStream = (options.Number_for_Errors == k_OutStream_stdout ? &g_StdOut : NULL);
511 
512   CStdOutStream *percentsStream = NULL;
513   if (options.Number_for_Percents != k_OutStream_disabled)
514     percentsStream = (options.Number_for_Percents == k_OutStream_stderr) ? &g_StdErr : &g_StdOut;;
515 
516   if (options.HelpMode)
517   {
518     ShowCopyrightAndHelp(g_StdStream, true);
519     return 0;
520   }
521 
522   #if defined(_WIN32) && !defined(UNDER_CE)
523   NSecurity::EnablePrivilege_SymLink();
524   #endif
525 
526   #ifdef _7ZIP_LARGE_PAGES
527   if (options.LargePages)
528   {
529     SetLargePageSize();
530     #if defined(_WIN32) && !defined(UNDER_CE)
531     NSecurity::EnablePrivilege_LockMemory();
532     #endif
533   }
534   #endif
535 
536   if (options.EnableHeaders)
537     ShowCopyrightAndHelp(g_StdStream, false);
538 
539   parser.Parse2(options);
540 
541   unsigned percentsNameLevel = 1;
542   if (options.LogLevel == 0 || options.Number_for_Percents != options.Number_for_Out)
543     percentsNameLevel = 2;
544 
545   unsigned consoleWidth = 80;
546 
547   if (percentsStream)
548   {
549     #ifdef _WIN32
550 
551     #if !defined(UNDER_CE)
552     CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
553     if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo))
554       consoleWidth = consoleInfo.dwSize.X;
555     #endif
556 
557     #else
558 
559     struct winsize w;
560     if (ioctl(0, TIOCGWINSZ, &w) == )
561       consoleWidth = w.ws_col;
562 
563     #endif
564   }
565 
566   CREATE_CODECS_OBJECT
567 
568   codecs->CaseSensitiveChange = options.CaseSensitiveChange;
569   codecs->CaseSensitive = options.CaseSensitive;
570   ThrowException_if_Error(codecs->Load());
571 
572   bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
573 
574   if (codecs->Formats.Size() == 0 &&
575         (isExtractGroupCommand
576         || options.Command.CommandType == NCommandType::kList
577         || options.Command.IsFromUpdateGroup()))
578   {
579     #ifdef EXTERNAL_CODECS
580     if (!codecs->MainDll_ErrorPath.IsEmpty())
581     {
582       UString s = L"Can't load module ";
583       s += fs2us(codecs->MainDll_ErrorPath);
584       throw s;
585     }
586     #endif
587 
588     throw kNoFormats;
589   }
590 
591   CObjectVector<COpenType> types;
592   if (!ParseOpenTypes(*codecs, options.ArcType, types))
593     throw kUnsupportedArcTypeMessage;
594 
595   CIntVector excludedFormats;
596   FOR_VECTOR (k, options.ExcludedArcTypes)
597   {
598     CIntVector tempIndices;
599     if (!codecs->FindFormatForArchiveType(options.ExcludedArcTypes[k], tempIndices)
600         || tempIndices.Size() != 1)
601       throw kUnsupportedArcTypeMessage;
602     excludedFormats.AddToUniqueSorted(tempIndices[0]);
603     // excludedFormats.Sort();
604   }
605 
606 
607   #ifdef EXTERNAL_CODECS
608   if (isExtractGroupCommand
609       || options.Command.CommandType == NCommandType::kHash
610       || options.Command.CommandType == NCommandType::kBenchmark)
611     ThrowException_if_Error(__externalCodecs.Load());
612   #endif
613 
614   int retCode = NExitCode::kSuccess;
615   HRESULT hresultMain = S_OK;
616 
617   // bool showStat = options.ShowTime;
618 
619   /*
620   if (!options.EnableHeaders ||
621       options.TechMode)
622     showStat = false;
623   */
624 
625 
626   if (options.Command.CommandType == NCommandType::kInfo)
627   {
628     CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut);
629     unsigned i;
630 
631     #ifdef EXTERNAL_CODECS
632     so << endl << "Libs:" << endl;
633     for (i = 0; i < codecs->Libs.Size(); i++)
634     {
635       PrintLibIndex(so, i);
636       so << ' ' << codecs->Libs[i].Path << endl;
637     }
638     #endif
639 
640     so << endl << "Formats:" << endl;
641 
642     const char *kArcFlags = "KSNFMGOPBELH";
643     const unsigned kNumArcFlags = (unsigned)strlen(kArcFlags);
644 
645     for (i = 0; i < codecs->Formats.Size(); i++)
646     {
647       const CArcInfoEx &arc = codecs->Formats[i];
648 
649       #ifdef EXTERNAL_CODECS
650       PrintLibIndex(so, arc.LibIndex);
651       #else
652       so << "  ";
653       #endif
654 
655       so << (char)(arc.UpdateEnabled ? 'C' : ' ');
656 
657       for (unsigned b = 0; b < kNumArcFlags; b++)
658       {
659         so << (char)
660           ((arc.Flags & ((UInt32)1 << b)) != 0 ? kArcFlags[b] : ' ');
661       }
662 
663       so << ' ';
664       PrintString(so, arc.Name, 8);
665       so << ' ';
666       UString s;
667 
668       FOR_VECTOR (t, arc.Exts)
669       {
670         if (t != 0)
671           s.Add_Space();
672         const CArcExtInfo &ext = arc.Exts[t];
673         s += ext.Ext;
674         if (!ext.AddExt.IsEmpty())
675         {
676           s += L" (";
677           s += ext.AddExt;
678           s += L')';
679         }
680       }
681 
682       PrintString(so, s, 13);
683       so << ' ';
684 
685       if (arc.SignatureOffset != 0)
686         so << "offset=" << arc.SignatureOffset << ' ';
687 
688       FOR_VECTOR(si, arc.Signatures)
689       {
690         if (si != 0)
691           so << "  ||  ";
692 
693         const CByteBuffer &sig = arc.Signatures[si];
694 
695         for (size_t j = 0; j < sig.Size(); j++)
696         {
697           if (j != 0)
698             so << ' ';
699           Byte b = sig[j];
700           if (b > 0x20 && b < 0x80)
701           {
702             so << (char)b;
703           }
704           else
705           {
706             so << GetHex((b >> 4) & 0xF);
707             so << GetHex(b & 0xF);
708           }
709         }
710       }
711       so << endl;
712     }
713 
714     so << endl << "Codecs:" << endl; //  << "Lib          ID Name" << endl;
715 
716     for (i = 0; i < g_NumCodecs; i++)
717     {
718       const CCodecInfo &cod = *g_Codecs[i];
719 
720       PrintLibIndex(so, -1);
721 
722       if (cod.NumStreams == 1)
723         so << ' ';
724       else
725         so << cod.NumStreams;
726 
727       so << (char)(cod.CreateEncoder ? 'E' : ' ');
728       so << (char)(cod.CreateDecoder ? 'D' : ' ');
729 
730       so << ' ';
731       PrintHexId(so, cod.Id);
732       so << ' ' << cod.Name << endl;
733     }
734 
735 
736     #ifdef EXTERNAL_CODECS
737 
738     UInt32 numMethods;
739     if (codecs->GetNumMethods(&numMethods) == S_OK)
740     for (UInt32 j = 0; j < numMethods; j++)
741     {
742       PrintLibIndex(so, codecs->GetCodec_LibIndex(j));
743 
744       UInt32 numStreams = codecs->GetCodec_NumStreams(j);
745       if (numStreams == 1)
746         so << ' ';
747       else
748         so << numStreams;
749 
750       so << (char)(codecs->GetCodec_EncoderIsAssigned(j) ? 'E' : ' ');
751       so << (char)(codecs->GetCodec_DecoderIsAssigned(j) ? 'D' : ' ');
752 
753       so << ' ';
754       UInt64 id;
755       HRESULT res = codecs->GetCodec_Id(j, id);
756       if (res != S_OK)
757         id = (UInt64)(Int64)-1;
758       PrintHexId(so, id);
759       so << ' ' << codecs->GetCodec_Name(j) << endl;
760     }
761 
762     #endif
763 
764 
765     so << endl << "Hashers:" << endl; //  << " L Size       ID Name" << endl;
766 
767     for (i = 0; i < g_NumHashers; i++)
768     {
769       const CHasherInfo &codec = *g_Hashers[i];
770       PrintLibIndex(so, -1);
771       PrintUInt32(so, codec.DigestSize, 4);
772       so << ' ';
773       PrintHexId(so, codec.Id);
774       so << ' ' << codec.Name << endl;
775     }
776 
777     #ifdef EXTERNAL_CODECS
778 
779     numMethods = codecs->GetNumHashers();
780     for (UInt32 j = 0; j < numMethods; j++)
781     {
782       PrintLibIndex(so, codecs->GetHasherLibIndex(j));
783       PrintUInt32(so, codecs->GetHasherDigestSize(j), 4);
784       so << ' ';
785       PrintHexId(so, codecs->GetHasherId(j));
786       so << ' ' << codecs->GetHasherName(j) << endl;
787     }
788 
789     #endif
790 
791   }
792   else if (options.Command.CommandType == NCommandType::kBenchmark)
793   {
794     CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut);
795     hresultMain = BenchCon(EXTERNAL_CODECS_VARS_L
796         options.Properties, options.NumIterations, (FILE *)so);
797     if (hresultMain == S_FALSE)
798     {
799       if (g_ErrStream)
800         *g_ErrStream << "\nDecoding ERROR\n";
801       retCode = NExitCode::kFatalError;
802       hresultMain = S_OK;
803     }
804   }
805   else if (isExtractGroupCommand || options.Command.CommandType == NCommandType::kList)
806   {
807     UStringVector ArchivePathsSorted;
808     UStringVector ArchivePathsFullSorted;
809 
810     if (options.StdInMode)
811     {
812       ArchivePathsSorted.Add(options.ArcName_for_StdInMode);
813       ArchivePathsFullSorted.Add(options.ArcName_for_StdInMode);
814     }
815     else
816     {
817       CExtractScanConsole scan;
818 
819       scan.Init(options.EnableHeaders ? g_StdStream : NULL, g_ErrStream, percentsStream);
820       scan.SetWindowWidth(consoleWidth);
821 
822       if (g_StdStream && options.EnableHeaders)
823         *g_StdStream << "Scanning the drive for archives:" << endl;
824 
825       CDirItemsStat st;
826 
827       scan.StartScanning();
828 
829       hresultMain = EnumerateDirItemsAndSort(
830           options.arcCensor,
831           NWildcard::k_RelatPath,
832           UString(), // addPathPrefix
833           ArchivePathsSorted,
834           ArchivePathsFullSorted,
835           st,
836           &scan);
837 
838       scan.CloseScanning();
839 
840       if (hresultMain == S_OK)
841       {
842         if (options.EnableHeaders)
843           scan.PrintStat(st);
844       }
845       else
846       {
847         /*
848         if (res != E_ABORT)
849         {
850           throw CSystemException(res);
851           // errorInfo.Message = "Scanning error";
852         }
853         return res;
854         */
855       }
856     }
857 
858     if (hresultMain == S_OK)
859     if (isExtractGroupCommand)
860     {
861       CExtractCallbackConsole *ecs = new CExtractCallbackConsole;
862       CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
863 
864       #ifndef _NO_CRYPTO
865       ecs->PasswordIsDefined = options.PasswordEnabled;
866       ecs->Password = options.Password;
867       #endif
868 
869       ecs->Init(g_StdStream, g_ErrStream, percentsStream);
870       ecs->MultiArcMode = (ArchivePathsSorted.Size() > 1);
871 
872       ecs->LogLevel = options.LogLevel;
873       ecs->PercentsNameLevel = percentsNameLevel;
874 
875       if (percentsStream)
876         ecs->SetWindowWidth(consoleWidth);
877 
878       /*
879       COpenCallbackConsole openCallback;
880       openCallback.Init(g_StdStream, g_ErrStream);
881 
882       #ifndef _NO_CRYPTO
883       openCallback.PasswordIsDefined = options.PasswordEnabled;
884       openCallback.Password = options.Password;
885       #endif
886       */
887 
888       CExtractOptions eo;
889       (CExtractOptionsBase &)eo = options.ExtractOptions;
890 
891       eo.StdInMode = options.StdInMode;
892       eo.StdOutMode = options.StdOutMode;
893       eo.YesToAll = options.YesToAll;
894       eo.TestMode = options.Command.IsTestCommand();
895 
896       #ifndef _SFX
897       eo.Properties = options.Properties;
898       #endif
899 
900       UString errorMessage;
901       CDecompressStat stat;
902       CHashBundle hb;
903       IHashCalc *hashCalc = NULL;
904 
905       if (!options.HashMethods.IsEmpty())
906       {
907         hashCalc = &hb;
908         ThrowException_if_Error(hb.SetMethods(EXTERNAL_CODECS_VARS_L options.HashMethods));
909         hb.Init();
910       }
911 
912       hresultMain = Extract(
913           codecs,
914           types,
915           excludedFormats,
916           ArchivePathsSorted,
917           ArchivePathsFullSorted,
918           options.Censor.Pairs.Front().Head,
919           eo, ecs, ecs, hashCalc, errorMessage, stat);
920 
921       ecs->ClosePercents();
922 
923       if (!errorMessage.IsEmpty())
924       {
925         if (g_ErrStream)
926           *g_ErrStream << endl << "ERROR:" << endl << errorMessage << endl;
927         if (hresultMain == S_OK)
928           hresultMain = E_FAIL;
929       }
930 
931       CStdOutStream *so = g_StdStream;
932 
933       bool isError = false;
934 
935       if (so)
936       {
937         *so << endl;
938 
939         if (ecs->NumTryArcs > 1)
940         {
941           *so << "Archives: " << ecs->NumTryArcs << endl;
942           *so << "OK archives: " << ecs->NumOkArcs << endl;
943         }
944       }
945 
946       if (ecs->NumCantOpenArcs != 0)
947       {
948         isError = true;
949         if (so)
950           *so << "Can't open as archive: " << ecs->NumCantOpenArcs << endl;
951       }
952 
953       if (ecs->NumArcsWithError != 0)
954       {
955         isError = true;
956         if (so)
957           *so << "Archives with Errors: " << ecs->NumArcsWithError << endl;
958       }
959 
960       if (so)
961       {
962         if (ecs->NumArcsWithWarnings != 0)
963           *so << "Archives with Warnings: " << ecs->NumArcsWithWarnings << endl;
964 
965         if (ecs->NumOpenArcWarnings != 0)
966         {
967           *so << endl;
968           if (ecs->NumOpenArcWarnings != 0)
969             *so << "Warnings: " << ecs->NumOpenArcWarnings << endl;
970         }
971       }
972 
973       if (ecs->NumOpenArcErrors != 0)
974       {
975         isError = true;
976         if (so)
977         {
978           *so << endl;
979           if (ecs->NumOpenArcErrors != 0)
980             *so << "Open Errors: " << ecs->NumOpenArcErrors << endl;
981         }
982       }
983 
984       if (isError)
985         retCode = NExitCode::kFatalError;
986 
987       if (so)
988       if (ecs->NumArcsWithError != 0 || ecs->NumFileErrors != 0)
989       {
990         // if (ecs->NumArchives > 1)
991         {
992           *so << endl;
993           if (ecs->NumFileErrors != 0)
994             *so << "Sub items Errors: " << ecs->NumFileErrors << endl;
995         }
996       }
997       else if (hresultMain == S_OK)
998       {
999         if (stat.NumFolders != 0)
1000           *so << "Folders: " << stat.NumFolders << endl;
1001         if (stat.NumFiles != 1 || stat.NumFolders != 0 || stat.NumAltStreams != 0)
1002           *so << "Files: " << stat.NumFiles << endl;
1003         if (stat.NumAltStreams != 0)
1004         {
1005           *so << "Alternate Streams: " << stat.NumAltStreams << endl;
1006           *so << "Alternate Streams Size: " << stat.AltStreams_UnpackSize << endl;
1007         }
1008 
1009         *so
1010           << "Size:       " << stat.UnpackSize << endl
1011           << "Compressed: " << stat.PackSize << endl;
1012         if (hashCalc)
1013         {
1014           *so << endl;
1015           PrintHashStat(*so, hb);
1016         }
1017       }
1018     }
1019     else
1020     {
1021       UInt64 numErrors = 0;
1022       UInt64 numWarnings = 0;
1023 
1024       // options.ExtractNtOptions.StoreAltStreams = true, if -sns[-] is not definmed
1025 
1026       hresultMain = ListArchives(
1027           codecs,
1028           types,
1029           excludedFormats,
1030           options.StdInMode,
1031           ArchivePathsSorted,
1032           ArchivePathsFullSorted,
1033           options.ExtractOptions.NtOptions.AltStreams.Val,
1034           options.AltStreams.Val, // we don't want to show AltStreams by default
1035           options.Censor.Pairs.Front().Head,
1036           options.EnableHeaders,
1037           options.TechMode,
1038           #ifndef _NO_CRYPTO
1039           options.PasswordEnabled,
1040           options.Password,
1041           #endif
1042           &options.Properties,
1043           numErrors, numWarnings);
1044 
1045       if (options.EnableHeaders)
1046         if (numWarnings > 0)
1047           g_StdOut << endl << "Warnings: " << numWarnings << endl;
1048 
1049       if (numErrors > 0)
1050       {
1051         if (options.EnableHeaders)
1052           g_StdOut << endl << "Errors: " << numErrors << endl;
1053         retCode = NExitCode::kFatalError;
1054       }
1055     }
1056   }
1057   else if (options.Command.IsFromUpdateGroup())
1058   {
1059     CUpdateOptions &uo = options.UpdateOptions;
1060     if (uo.SfxMode && uo.SfxModule.IsEmpty())
1061       uo.SfxModule = kDefaultSfxModule;
1062 
1063     COpenCallbackConsole openCallback;
1064     openCallback.Init(g_StdStream, g_ErrStream, percentsStream);
1065 
1066     #ifndef _NO_CRYPTO
1067     bool passwordIsDefined =
1068         (options.PasswordEnabled && !options.Password.IsEmpty());
1069     openCallback.PasswordIsDefined = passwordIsDefined;
1070     openCallback.Password = options.Password;
1071     #endif
1072 
1073     CUpdateCallbackConsole callback;
1074     callback.LogLevel = options.LogLevel;
1075     callback.PercentsNameLevel = percentsNameLevel;
1076 
1077     if (percentsStream)
1078       callback.SetWindowWidth(consoleWidth);
1079 
1080     #ifndef _NO_CRYPTO
1081     callback.PasswordIsDefined = passwordIsDefined;
1082     callback.AskPassword = (options.PasswordEnabled && options.Password.IsEmpty());
1083     callback.Password = options.Password;
1084     #endif
1085 
1086     callback.StdOutMode = uo.StdOutMode;
1087     callback.Init(
1088       // NULL,
1089       g_StdStream, g_ErrStream, percentsStream);
1090 
1091     CUpdateErrorInfo errorInfo;
1092 
1093     /*
1094     if (!uo.Init(codecs, types, options.ArchiveName))
1095       throw kUnsupportedUpdateArcType;
1096     */
1097     hresultMain = UpdateArchive(codecs,
1098         types,
1099         options.ArchiveName,
1100         options.Censor,
1101         uo,
1102         errorInfo, &openCallback, &callback, true);
1103 
1104     callback.ClosePercents2();
1105 
1106     CStdOutStream *se = g_StdStream;
1107     if (!se)
1108       se = g_ErrStream;
1109 
1110     retCode = WarningsCheck(hresultMain, callback, errorInfo,
1111         g_StdStream, se,
1112         true // options.EnableHeaders
1113         );
1114   }
1115   else if (options.Command.CommandType == NCommandType::kHash)
1116   {
1117     const CHashOptions &uo = options.HashOptions;
1118 
1119     CHashCallbackConsole callback;
1120     if (percentsStream)
1121       callback.SetWindowWidth(consoleWidth);
1122 
1123     callback.Init(g_StdStream, g_ErrStream, percentsStream);
1124     callback.PrintHeaders = options.EnableHeaders;
1125 
1126     AString errorInfoString;
1127     hresultMain = HashCalc(EXTERNAL_CODECS_VARS_L
1128         options.Censor, uo,
1129         errorInfoString, &callback);
1130     CUpdateErrorInfo errorInfo;
1131     errorInfo.Message = errorInfoString;
1132     CStdOutStream *se = g_StdStream;
1133     if (!se)
1134       se = g_ErrStream;
1135     retCode = WarningsCheck(hresultMain, callback, errorInfo, g_StdStream, se, options.EnableHeaders);
1136   }
1137   else
1138     ShowMessageAndThrowException(kUserErrorMessage, NExitCode::kUserError);
1139 
1140   if (options.ShowTime && g_StdStream)
1141     PrintStat();
1142 
1143   ThrowException_if_Error(hresultMain);
1144 
1145   return retCode;
1146 }
1147