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