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