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