Home | History | Annotate | Download | only in Console
      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 
    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
    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 
    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 
    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 
    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 
    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 
    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 
    202 static inline char GetHex(unsigned val)
    203 {
    204   return (char)((val < 10) ? ('0' + val) : ('A' + (val - 10)));
    205 }
    206 
    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 
    286 static void ThrowException_if_Error(HRESULT res)
    287 {
    288   if (res != S_OK)
    289     throw CSystemException(res);
    290 }
    291 
    292 
    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 
    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 
    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 
    346 static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
    347 
    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 
    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