1 // Main.cpp
2 
3 #include "StdAfx.h"
4 
5 #include <Psapi.h>
6 
7 #if defined( _WIN32) && defined( _7ZIP_LARGE_PAGES)
8 #include "../../../../C/Alloc.h"
9 #endif
10 
11 #include "../../../Common/MyInitGuid.h"
12 
13 #include "../../../Common/CommandLineParser.h"
14 #include "../../../Common/IntToString.h"
15 #include "../../../Common/MyException.h"
16 #include "../../../Common/StringConvert.h"
17 #include "../../../Common/StringToInt.h"
18 
19 #include "../../../Windows/ErrorMsg.h"
20 #ifdef _WIN32
21 #include "../../../Windows/MemoryLock.h"
22 #endif
23 
24 #ifndef _7ZIP_ST
25 #include "../../../Windows/Synchronization.h"
26 #endif
27 
28 #include "../../../Windows/TimeUtils.h"
29 
30 #include "../Common/ArchiveCommandLine.h"
31 #include "../Common/ExitCode.h"
32 #include "../Common/Extract.h"
33 #ifdef EXTERNAL_CODECS
34 #include "../Common/LoadCodecs.h"
35 #endif
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 extern CStdOutStream *g_StdStream;
60 
61 static const char *kCopyrightString = "\n7-Zip"
62 #ifndef EXTERNAL_CODECS
63 #ifdef PROG_VARIANT_R
64 " (r)"
65 #else
66 " (a)"
67 #endif
68 #endif
69 
70 #ifdef _WIN64
71 " [64]"
72 #endif
73 
74 " " MY_VERSION_COPYRIGHT_DATE "\n";
75 
76 static const char *kHelpString =
77     "\nUsage: 7z"
78 #ifndef EXTERNAL_CODECS
79 #ifdef PROG_VARIANT_R
80     "r"
81 #else
82     "a"
83 #endif
84 #endif
85     " <command> [<switches>...] <archive_name> [<file_names>...]\n"
86     "       [<@listfiles...>]\n"
87     "\n"
88     "<Commands>\n"
89     "  a : Add files to archive\n"
90     "  b : Benchmark\n"
91     "  d : Delete files from archive\n"
92     "  e : Extract files from archive (without using directory names)\n"
93     "  h : Calculate hash values for files\n"
94     "  l : List contents of archive\n"
95 //    "  l[a|t][f] : List contents of archive\n"
96 //    "    a - with Additional fields\n"
97 //    "    t - with all fields\n"
98 //    "    f - with Full pathnames\n"
99     "  rn : Rename files in archive\n"
100     "  t : Test integrity of archive\n"
101     "  u : Update files to archive\n"
102     "  x : eXtract files with full paths\n"
103     "<Switches>\n"
104     "  -- : Stop switches parsing\n"
105     "  -ai[r[-|0]]{@listfile|!wildcard} : Include archives\n"
106     "  -ax[r[-|0]]{@listfile|!wildcard} : eXclude archives\n"
107     "  -bd : Disable percentage indicator\n"
108     "  -i[r[-|0]]{@listfile|!wildcard} : Include filenames\n"
109     "  -m{Parameters} : set compression Method\n"
110     "  -o{Directory} : set Output directory\n"
111     #ifndef _NO_CRYPTO
112     "  -p{Password} : set Password\n"
113     #endif
114     "  -r[-|0] : Recurse subdirectories\n"
115     "  -scs{UTF-8|UTF-16LE|UTF-16BE|WIN|DOS|{id}} : set charset for list files\n"
116     "  -sfx[{name}] : Create SFX archive\n"
117     "  -si[{name}] : read data from stdin\n"
118     "  -slt : show technical information for l (List) command\n"
119     "  -so : write data to stdout\n"
120     "  -ssc[-] : set sensitive case mode\n"
121     "  -ssw : compress shared files\n"
122     "  -t{Type} : Set type of archive\n"
123     "  -u[-][p#][q#][r#][x#][y#][z#][!newArchiveName] : Update options\n"
124     "  -v{Size}[b|k|m|g] : Create volumes\n"
125     "  -w[{path}] : assign Work directory. Empty path means a temporary directory\n"
126     "  -x[r[-|0]]]{@listfile|!wildcard} : eXclude filenames\n"
127     "  -y : assume Yes on all queries\n";
128 
129 // ---------------------------
130 // exception messages
131 
132 static const char *kEverythingIsOk = "Everything is Ok";
133 static const char *kUserErrorMessage = "Incorrect command line";
134 static const char *kNoFormats = "7-Zip cannot find the code that works with archives.";
135 static const char *kUnsupportedArcTypeMessage = "Unsupported archive type";
136 // static const char *kUnsupportedUpdateArcType = "Can't create archive for that type";
137 
138 static CFSTR kDefaultSfxModule = FTEXT("7zCon.sfx");
139 
ShowMessageAndThrowException(CStdOutStream & s,LPCSTR message,NExitCode::EEnum code)140 static void ShowMessageAndThrowException(CStdOutStream &s, LPCSTR message, NExitCode::EEnum code)
141 {
142   s << endl << "Error: " << message << endl;
143   throw code;
144 }
145 
146 #ifndef _WIN32
GetArguments(int numArgs,const char * args[],UStringVector & parts)147 static void GetArguments(int numArgs, const char *args[], UStringVector &parts)
148 {
149   parts.Clear();
150   for (int i = 0; i < numArgs; i++)
151   {
152     UString s = MultiByteToUnicodeString(args[i]);
153     parts.Add(s);
154   }
155 }
156 #endif
157 
ShowCopyrightAndHelp(CStdOutStream & s,bool needHelp)158 static void ShowCopyrightAndHelp(CStdOutStream &s, bool needHelp)
159 {
160   s << kCopyrightString;
161   // s << "# CPUs: " << (UInt64)NWindows::NSystem::GetNumberOfProcessors() << "\n";
162   if (needHelp)
163     s << kHelpString;
164 }
165 
166 #ifdef EXTERNAL_CODECS
167 
PrintString(CStdOutStream & stdStream,const AString & s,int size)168 static void PrintString(CStdOutStream &stdStream, const AString &s, int size)
169 {
170   int len = s.Len();
171   for (int i = len; i < size; i++)
172     stdStream << ' ';
173   stdStream << s;
174 }
175 
PrintUInt32(CStdOutStream & stdStream,UInt32 val,int size)176 static void PrintUInt32(CStdOutStream &stdStream, UInt32 val, int size)
177 {
178   char s[16];
179   ConvertUInt32ToString(val, s);
180   PrintString(stdStream, s, size);
181 }
182 
PrintLibIndex(CStdOutStream & stdStream,int libIndex)183 static void PrintLibIndex(CStdOutStream &stdStream, int libIndex)
184 {
185   if (libIndex >= 0)
186     PrintUInt32(stdStream, libIndex, 2);
187   else
188     stdStream << "  ";
189   stdStream << ' ';
190 }
191 
192 #endif
193 
PrintString(CStdOutStream & stdStream,const UString & s,int size)194 static void PrintString(CStdOutStream &stdStream, const UString &s, int size)
195 {
196   int len = s.Len();
197   stdStream << s;
198   for (int i = len; i < size; i++)
199     stdStream << ' ';
200 }
201 
GetHex(unsigned val)202 static inline char GetHex(unsigned val)
203 {
204   return (char)((val < 10) ? ('0' + val) : ('A' + (val - 10)));
205 }
206 
WarningsCheck(HRESULT result,const CCallbackConsoleBase & callback,const CErrorInfo & errorInfo,CStdOutStream & stdStream)207 static int WarningsCheck(HRESULT result, const CCallbackConsoleBase &callback,
208     const CErrorInfo &errorInfo, CStdOutStream &stdStream)
209 {
210   int exitCode = NExitCode::kSuccess;
211 
212   if (callback.CantFindFiles.Size() > 0)
213   {
214     stdStream << endl;
215     stdStream << "WARNINGS for files:" << endl << endl;
216     unsigned numErrors = callback.CantFindFiles.Size();
217     for (unsigned i = 0; i < numErrors; i++)
218     {
219       stdStream << callback.CantFindFiles[i] << " : ";
220       stdStream << NError::MyFormatMessage(callback.CantFindCodes[i]) << endl;
221     }
222     stdStream << "----------------" << endl;
223     stdStream << "WARNING: Cannot find " << numErrors << " file";
224     if (numErrors > 1)
225       stdStream << "s";
226     stdStream << endl;
227     exitCode = NExitCode::kWarning;
228   }
229 
230   if (result != S_OK)
231   {
232     UString message;
233     if (!errorInfo.Message.IsEmpty())
234     {
235       message += errorInfo.Message;
236       message += L"\n";
237     }
238     if (!errorInfo.FileName.IsEmpty())
239     {
240       message += fs2us(errorInfo.FileName);
241       message += L"\n";
242     }
243     if (!errorInfo.FileName2.IsEmpty())
244     {
245       message += fs2us(errorInfo.FileName2);
246       message += L"\n";
247     }
248     if (errorInfo.SystemError != 0)
249     {
250       message += NError::MyFormatMessage(errorInfo.SystemError);
251       message += L"\n";
252     }
253     if (!message.IsEmpty())
254       stdStream << L"\nError:\n" << message;
255 
256     // we will work with (result) later
257     // throw CSystemException(result);
258     return NExitCode::kFatalError;
259   }
260 
261   unsigned numErrors = callback.FailedFiles.Size();
262   if (numErrors == 0)
263   {
264     if (callback.CantFindFiles.Size() == 0)
265       stdStream << kEverythingIsOk << endl;
266   }
267   else
268   {
269     stdStream << endl;
270     stdStream << "WARNINGS for files:" << endl << endl;
271     for (unsigned i = 0; i < numErrors; i++)
272     {
273       stdStream << callback.FailedFiles[i] << " : ";
274       stdStream << NError::MyFormatMessage(callback.FailedCodes[i]) << endl;
275     }
276     stdStream << "----------------" << endl;
277     stdStream << "WARNING: Cannot open " << numErrors << " file";
278     if (numErrors > 1)
279       stdStream << "s";
280     stdStream << endl;
281     exitCode = NExitCode::kWarning;
282   }
283   return exitCode;
284 }
285 
ThrowException_if_Error(HRESULT res)286 static void ThrowException_if_Error(HRESULT res)
287 {
288   if (res != S_OK)
289     throw CSystemException(res);
290 }
291 
292 
PrintNum(UInt64 val,unsigned numDigits,char c=' ')293 static void PrintNum(UInt64 val, unsigned numDigits, char c = ' ')
294 {
295   char temp[64];
296   char *p = temp + 32;
297   ConvertUInt64ToString(val, p);
298   unsigned len = MyStringLen(p);
299   for (; len < numDigits; len++)
300     *--p = c;
301   *g_StdStream << p;
302 }
303 
PrintTime(const char * s,UInt64 val,UInt64 total)304 static void PrintTime(const char *s, UInt64 val, UInt64 total)
305 {
306   *g_StdStream << endl << s << " Time =";
307   const UInt32 kFreq = 10000000;
308   UInt64 sec = val / kFreq;
309   PrintNum(sec, 6);
310   *g_StdStream << '.';
311   UInt32 ms = (UInt32)(val - (sec * kFreq)) / (kFreq / 1000);
312   PrintNum(ms, 3, '0');
313 
314   while (val > ((UInt64)1 << 56))
315   {
316     val >>= 1;
317     total >>= 1;
318   }
319 
320   UInt64 percent = 0;
321   if (total != 0)
322     percent = val * 100 / total;
323   *g_StdStream << " =";
324   PrintNum(percent, 5);
325   *g_StdStream << '%';
326 }
327 
328 #ifndef UNDER_CE
329 
330 #define SHIFT_SIZE_VALUE(x, num) (((x) + (1 << (num)) - 1) >> (num))
331 
PrintMemUsage(const char * s,UInt64 val)332 static void PrintMemUsage(const char *s, UInt64 val)
333 {
334   *g_StdStream << "    " << s << " Memory =";
335   PrintNum(SHIFT_SIZE_VALUE(val, 20), 7);
336   *g_StdStream << " MB";
337 }
338 
339 EXTERN_C_BEGIN
340 typedef BOOL (WINAPI *Func_GetProcessMemoryInfo)(HANDLE Process,
341     PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb);
342 EXTERN_C_END
343 
344 #endif
345 
GetTime64(const FILETIME & t)346 static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
347 
PrintStat()348 static void PrintStat()
349 {
350   FILETIME creationTimeFT, exitTimeFT, kernelTimeFT, userTimeFT;
351   if (!
352       #ifdef UNDER_CE
353         ::GetThreadTimes(::GetCurrentThread()
354       #else
355         // NT 3.5
356         ::GetProcessTimes(::GetCurrentProcess()
357       #endif
358       , &creationTimeFT, &exitTimeFT, &kernelTimeFT, &userTimeFT))
359     return;
360   FILETIME curTimeFT;
361   NTime::GetCurUtcFileTime(curTimeFT);
362 
363   #ifndef UNDER_CE
364 
365   PROCESS_MEMORY_COUNTERS m;
366   memset(&m, 0, sizeof(m));
367   BOOL memDefined = FALSE;
368   {
369     /* NT 4.0: GetProcessMemoryInfo() in Psapi.dll
370        Win7: new function K32GetProcessMemoryInfo() in kernel32.dll
371        It's faster to call kernel32.dll code than Psapi.dll code
372        GetProcessMemoryInfo() requires Psapi.lib
373        Psapi.lib in SDK7+ can link to K32GetProcessMemoryInfo in kernel32.dll
374        The program with K32GetProcessMemoryInfo will not work on systems before Win7
375        // memDefined = GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m));
376     */
377 
378     Func_GetProcessMemoryInfo my_GetProcessMemoryInfo = (Func_GetProcessMemoryInfo)
379         ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "K32GetProcessMemoryInfo");
380     if (!my_GetProcessMemoryInfo)
381     {
382       HMODULE lib = LoadLibraryW(L"Psapi.dll");
383       if (lib)
384         my_GetProcessMemoryInfo = (Func_GetProcessMemoryInfo)::GetProcAddress(lib, "GetProcessMemoryInfo");
385     }
386     if (my_GetProcessMemoryInfo)
387       memDefined = my_GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m));
388     // FreeLibrary(lib);
389   }
390 
391   #endif
392 
393   UInt64 curTime = GetTime64(curTimeFT);
394   UInt64 creationTime = GetTime64(creationTimeFT);
395   UInt64 kernelTime = GetTime64(kernelTimeFT);
396   UInt64 userTime = GetTime64(userTimeFT);
397 
398   UInt64 totalTime = curTime - creationTime;
399 
400   PrintTime("Kernel ", kernelTime, totalTime);
401   PrintTime("User   ", userTime, totalTime);
402 
403   PrintTime("Process", kernelTime + userTime, totalTime);
404   #ifndef UNDER_CE
405   if (memDefined) PrintMemUsage("Virtual ", m.PeakPagefileUsage);
406   #endif
407 
408   PrintTime("Global ", totalTime, totalTime);
409   #ifndef UNDER_CE
410   if (memDefined) PrintMemUsage("Physical", m.PeakWorkingSetSize);
411   #endif
412 
413   *g_StdStream << endl;
414 }
415 
Main2(int numArgs,const char * args[])416 int Main2(
417   #ifndef _WIN32
418   int numArgs, const char *args[]
419   #endif
420 )
421 {
422   #if defined(_WIN32) && !defined(UNDER_CE)
423   SetFileApisToOEM();
424   #endif
425 
426   UStringVector commandStrings;
427   #ifdef _WIN32
428   NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
429   #else
430   GetArguments(numArgs, args, commandStrings);
431   #endif
432 
433   if (commandStrings.Size() == 1)
434   {
435     ShowCopyrightAndHelp(g_StdOut, true);
436     return 0;
437   }
438 
439   commandStrings.Delete(0);
440 
441   CArcCmdLineOptions options;
442 
443   CArcCmdLineParser parser;
444 
445   parser.Parse1(commandStrings, options);
446 
447   if (options.HelpMode)
448   {
449     ShowCopyrightAndHelp(g_StdOut, true);
450     return 0;
451   }
452 
453   #if defined(_WIN32) && !defined(UNDER_CE)
454   NSecurity::EnablePrivilege_SymLink();
455   #endif
456   #ifdef _7ZIP_LARGE_PAGES
457   if (options.LargePages)
458   {
459     SetLargePageSize();
460     #if defined(_WIN32) && !defined(UNDER_CE)
461     NSecurity::EnablePrivilege_LockMemory();
462     #endif
463   }
464   #endif
465 
466   CStdOutStream &stdStream = options.StdOutMode ? g_StdErr : g_StdOut;
467   g_StdStream = &stdStream;
468 
469   if (options.EnableHeaders)
470     ShowCopyrightAndHelp(stdStream, false);
471 
472   parser.Parse2(options);
473 
474   CCodecs *codecs = new CCodecs;
475   #ifdef EXTERNAL_CODECS
476   CExternalCodecs __externalCodecs;
477   __externalCodecs.GetCodecs = codecs;
478   __externalCodecs.GetHashers = codecs;
479   #else
480   CMyComPtr<IUnknown> compressCodecsInfo = codecs;
481   #endif
482   codecs->CaseSensitiveChange = options.CaseSensitiveChange;
483   codecs->CaseSensitive = options.CaseSensitive;
484   ThrowException_if_Error(codecs->Load());
485 
486   bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
487 
488   if (codecs->Formats.Size() == 0 &&
489         (isExtractGroupCommand
490         || options.Command.CommandType == NCommandType::kList
491         || options.Command.IsFromUpdateGroup()))
492     throw kNoFormats;
493 
494   CObjectVector<COpenType> types;
495   if (!ParseOpenTypes(*codecs, options.ArcType, types))
496     throw kUnsupportedArcTypeMessage;
497 
498   CIntVector excludedFormats;
499   FOR_VECTOR (k, options.ExcludedArcTypes)
500   {
501     CIntVector tempIndices;
502     if (!codecs->FindFormatForArchiveType(options.ExcludedArcTypes[k], tempIndices)
503         || tempIndices.Size() != 1)
504       throw kUnsupportedArcTypeMessage;
505     excludedFormats.AddToUniqueSorted(tempIndices[0]);
506     // excludedFormats.Sort();
507   }
508 
509 
510   #ifdef EXTERNAL_CODECS
511   if (isExtractGroupCommand
512       || options.Command.CommandType == NCommandType::kHash
513       || options.Command.CommandType == NCommandType::kBenchmark)
514     ThrowException_if_Error(__externalCodecs.LoadCodecs());
515   #endif
516 
517   int retCode = NExitCode::kSuccess;
518   HRESULT hresultMain = S_OK;
519 
520   bool showStat = true;
521   if (!options.EnableHeaders ||
522       options.TechMode)
523     showStat = false;
524 
525 
526   if (options.Command.CommandType == NCommandType::kInfo)
527   {
528     unsigned i;
529 
530     #ifdef EXTERNAL_CODECS
531     stdStream << endl << "Libs:" << endl;
532     for (i = 0; i < codecs->Libs.Size(); i++)
533     {
534       PrintLibIndex(stdStream, i);
535       stdStream << ' ' << codecs->Libs[i].Path << endl;
536     }
537     #endif
538 
539     stdStream << endl << "Formats:" << endl;
540 
541     const char *kArcFlags = "KSNFMGOPBELH";
542     const unsigned kNumArcFlags = (unsigned)strlen(kArcFlags);
543 
544     for (i = 0; i < codecs->Formats.Size(); i++)
545     {
546       const CArcInfoEx &arc = codecs->Formats[i];
547       #ifdef EXTERNAL_CODECS
548       PrintLibIndex(stdStream, arc.LibIndex);
549       #else
550       stdStream << "  ";
551       #endif
552       stdStream << (char)(arc.UpdateEnabled ? 'C' : ' ');
553       for (unsigned b = 0; b < kNumArcFlags; b++)
554       {
555         stdStream << (char)
556           ((arc.Flags & ((UInt32)1 << b)) != 0 ? kArcFlags[b] : ' ');
557       }
558 
559       stdStream << ' ';
560       PrintString(stdStream, arc.Name, 8);
561       stdStream << ' ';
562       UString s;
563       FOR_VECTOR (t, arc.Exts)
564       {
565         if (t != 0)
566           s += L' ';
567         const CArcExtInfo &ext = arc.Exts[t];
568         s += ext.Ext;
569         if (!ext.AddExt.IsEmpty())
570         {
571           s += L" (";
572           s += ext.AddExt;
573           s += L')';
574         }
575       }
576       PrintString(stdStream, s, 13);
577       stdStream << ' ';
578       if (arc.SignatureOffset != 0)
579         stdStream << "offset=" << arc.SignatureOffset << ' ';
580 
581       FOR_VECTOR(si, arc.Signatures)
582       {
583         if (si != 0)
584           stdStream << "  ||  ";
585 
586         const CByteBuffer &sig = arc.Signatures[si];
587 
588         for (size_t j = 0; j < sig.Size(); j++)
589         {
590           if (j != 0)
591             stdStream << ' ';
592           Byte b = sig[j];
593           if (b > 0x20 && b < 0x80)
594           {
595             stdStream << (char)b;
596           }
597           else
598           {
599             stdStream << GetHex((b >> 4) & 0xF);
600             stdStream << GetHex(b & 0xF);
601           }
602         }
603       }
604       stdStream << endl;
605     }
606 
607     #ifdef EXTERNAL_CODECS
608 
609     stdStream << endl << "Codecs:" << endl << "Lib         ID  Name" << endl;
610     UInt32 numMethods;
611     if (codecs->GetNumberOfMethods(&numMethods) == S_OK)
612     for (UInt32 j = 0; j < numMethods; j++)
613     {
614       PrintLibIndex(stdStream, codecs->GetCodecLibIndex(j));
615       stdStream << (char)(codecs->GetCodecEncoderIsAssigned(j) ? 'C' : ' ');
616       UInt64 id;
617       stdStream << "  ";
618       HRESULT res = codecs->GetCodecId(j, id);
619       if (res != S_OK)
620         id = (UInt64)(Int64)-1;
621       char s[32];
622       ConvertUInt64ToHex(id, s);
623       PrintString(stdStream, s, 8);
624       stdStream << "  " << codecs->GetCodecName(j) << endl;
625     }
626 
627     stdStream << endl << "Hashers:" << endl << " L Size     ID  Name" << endl;
628     numMethods = codecs->GetNumHashers();
629     for (UInt32 j = 0; j < numMethods; j++)
630     {
631       PrintLibIndex(stdStream, codecs->GetHasherLibIndex(j));
632       PrintUInt32(stdStream, codecs->GetHasherDigestSize(j), 4);
633       stdStream << ' ';
634       char s[32];
635       ConvertUInt64ToHex(codecs->GetHasherId(j), s);
636       PrintString(stdStream, s, 6);
637       stdStream << "  " << codecs->GetHasherName(j) << endl;
638     }
639 
640     #endif
641 
642   }
643   else if (options.Command.CommandType == NCommandType::kBenchmark)
644   {
645     hresultMain = BenchCon(EXTERNAL_CODECS_VARS
646         options.Properties, options.NumIterations, (FILE *)stdStream);
647     if (hresultMain == S_FALSE)
648     {
649       stdStream << "\nDecoding Error\n";
650       retCode = NExitCode::kFatalError;
651       hresultMain = S_OK;
652     }
653   }
654   else if (isExtractGroupCommand || options.Command.CommandType == NCommandType::kList)
655   {
656     if (isExtractGroupCommand)
657     {
658       CExtractCallbackConsole *ecs = new CExtractCallbackConsole;
659       CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
660 
661       ecs->OutStream = &stdStream;
662 
663       #ifndef _NO_CRYPTO
664       ecs->PasswordIsDefined = options.PasswordEnabled;
665       ecs->Password = options.Password;
666       #endif
667 
668       ecs->Init();
669 
670       COpenCallbackConsole openCallback;
671       openCallback.OutStream = &stdStream;
672 
673       #ifndef _NO_CRYPTO
674       openCallback.PasswordIsDefined = options.PasswordEnabled;
675       openCallback.Password = options.Password;
676       #endif
677 
678       CExtractOptions eo;
679       (CExtractOptionsBase &)eo = options.ExtractOptions;
680       eo.StdInMode = options.StdInMode;
681       eo.StdOutMode = options.StdOutMode;
682       eo.YesToAll = options.YesToAll;
683       eo.TestMode = options.Command.IsTestCommand();
684 
685       #ifndef _SFX
686       eo.Properties = options.Properties;
687       #endif
688 
689       UString errorMessage;
690       CDecompressStat stat;
691       CHashBundle hb;
692       IHashCalc *hashCalc = NULL;
693 
694       if (!options.HashMethods.IsEmpty())
695       {
696         hashCalc = &hb;
697         ThrowException_if_Error(hb.SetMethods(EXTERNAL_CODECS_VARS options.HashMethods));
698         hb.Init();
699       }
700       hresultMain = Extract(
701           codecs,
702           types,
703           excludedFormats,
704           options.ArchivePathsSorted,
705           options.ArchivePathsFullSorted,
706           options.Censor.Pairs.Front().Head,
707           eo, &openCallback, ecs, hashCalc, errorMessage, stat);
708       if (!errorMessage.IsEmpty())
709       {
710         stdStream << endl << "Error: " << errorMessage;
711         if (hresultMain == S_OK)
712           hresultMain = E_FAIL;
713       }
714 
715       stdStream << endl;
716 
717       if (ecs->NumTryArcs > 1)
718       {
719         stdStream << "Archives: " << ecs->NumTryArcs << endl;
720         stdStream << "OK archives: " << ecs->NumOkArcs << endl;
721       }
722       bool isError = false;
723       if (ecs->NumCantOpenArcs != 0)
724       {
725         isError = true;
726         stdStream << "Can't open as archive: " << ecs->NumCantOpenArcs << endl;
727       }
728       if (ecs->NumArcsWithError != 0)
729       {
730         isError = true;
731         stdStream << "Archives with Errors: " << ecs->NumArcsWithError << endl;
732       }
733       if (ecs->NumArcsWithWarnings != 0)
734         stdStream << "Archives with Warnings: " << ecs->NumArcsWithWarnings << endl;
735 
736       if (ecs->NumOpenArcWarnings != 0)
737       {
738         stdStream << endl;
739         if (ecs->NumOpenArcWarnings != 0)
740           stdStream << "Warnings: " << ecs->NumOpenArcWarnings << endl;
741       }
742 
743       if (ecs->NumOpenArcErrors != 0)
744       {
745         isError = true;
746         stdStream << endl;
747         if (ecs->NumOpenArcErrors != 0)
748           stdStream << "Open Errors: " << ecs->NumOpenArcErrors << endl;
749       }
750 
751       if (isError)
752         retCode = NExitCode::kFatalError;
753 
754       if (ecs->NumArcsWithError != 0 || ecs->NumFileErrors != 0)
755       {
756         // if (ecs->NumArchives > 1)
757         {
758           stdStream << endl;
759           if (ecs->NumFileErrors != 0)
760             stdStream << "Sub items Errors: " << ecs->NumFileErrors << endl;
761         }
762       }
763       else if (hresultMain == S_OK)
764       {
765 
766       if (stat.NumFolders != 0)
767         stdStream << "Folders: " << stat.NumFolders << endl;
768       if (stat.NumFiles != 1 || stat.NumFolders != 0 || stat.NumAltStreams != 0)
769         stdStream << "Files: " << stat.NumFiles << endl;
770       if (stat.NumAltStreams != 0)
771       {
772         stdStream << "Alternate Streams: " << stat.NumAltStreams << endl;
773         stdStream << "Alternate Streams Size: " << stat.AltStreams_UnpackSize << endl;
774       }
775 
776       stdStream
777            << "Size:       " << stat.UnpackSize << endl
778            << "Compressed: " << stat.PackSize << endl;
779       if (hashCalc)
780         PrintHashStat(stdStream, hb);
781       }
782     }
783     else
784     {
785       UInt64 numErrors = 0;
786       UInt64 numWarnings = 0;
787 
788       // options.ExtractNtOptions.StoreAltStreams = true, if -sns[-] is not definmed
789 
790       hresultMain = ListArchives(
791           codecs,
792           types,
793           excludedFormats,
794           options.StdInMode,
795           options.ArchivePathsSorted,
796           options.ArchivePathsFullSorted,
797           options.ExtractOptions.NtOptions.AltStreams.Val,
798           options.AltStreams.Val, // we don't want to show AltStreams by default
799           options.Censor.Pairs.Front().Head,
800           options.EnableHeaders,
801           options.TechMode,
802           #ifndef _NO_CRYPTO
803           options.PasswordEnabled,
804           options.Password,
805           #endif
806           &options.Properties,
807           numErrors, numWarnings);
808 
809         if (options.EnableHeaders)
810           if (numWarnings > 0)
811             g_StdOut << endl << "Warnings: " << numWarnings << endl;
812       if (numErrors > 0)
813       {
814         if (options.EnableHeaders)
815           g_StdOut << endl << "Errors: " << numErrors << endl;
816         retCode = NExitCode::kFatalError;
817       }
818     }
819   }
820   else if (options.Command.IsFromUpdateGroup())
821   {
822     CUpdateOptions &uo = options.UpdateOptions;
823     if (uo.SfxMode && uo.SfxModule.IsEmpty())
824       uo.SfxModule = kDefaultSfxModule;
825 
826     COpenCallbackConsole openCallback;
827     openCallback.OutStream = &stdStream;
828 
829     #ifndef _NO_CRYPTO
830     bool passwordIsDefined =
831         options.PasswordEnabled && !options.Password.IsEmpty();
832     openCallback.PasswordIsDefined = passwordIsDefined;
833     openCallback.Password = options.Password;
834     #endif
835 
836     CUpdateCallbackConsole callback;
837     callback.EnablePercents = options.EnablePercents;
838 
839     #ifndef _NO_CRYPTO
840     callback.PasswordIsDefined = passwordIsDefined;
841     callback.AskPassword = options.PasswordEnabled && options.Password.IsEmpty();
842     callback.Password = options.Password;
843     #endif
844     callback.StdOutMode = uo.StdOutMode;
845     callback.Init(&stdStream);
846 
847     CUpdateErrorInfo errorInfo;
848 
849     /*
850     if (!uo.Init(codecs, types, options.ArchiveName))
851       throw kUnsupportedUpdateArcType;
852     */
853     hresultMain = UpdateArchive(codecs,
854         types,
855         options.ArchiveName,
856         options.Censor,
857         uo,
858         errorInfo, &openCallback, &callback, true);
859     retCode = WarningsCheck(hresultMain, callback, errorInfo, stdStream);
860   }
861   else if (options.Command.CommandType == NCommandType::kHash)
862   {
863     const CHashOptions &uo = options.HashOptions;
864 
865     CHashCallbackConsole callback;
866     callback.EnablePercents = options.EnablePercents;
867 
868     callback.Init(&stdStream);
869 
870     UString errorInfoString;
871     hresultMain = HashCalc(EXTERNAL_CODECS_VARS
872         options.Censor, uo,
873         errorInfoString, &callback);
874     CErrorInfo errorInfo;
875     errorInfo.Message = errorInfoString;
876     retCode = WarningsCheck(hresultMain, callback, errorInfo, stdStream);
877   }
878   else
879     ShowMessageAndThrowException(stdStream, kUserErrorMessage, NExitCode::kUserError);
880 
881   if (showStat)
882     PrintStat();
883 
884   ThrowException_if_Error(hresultMain);
885 
886   return retCode;
887 }
888