Home | History | Annotate | Download | only in Console
      1 // Main.cpp
      2 
      3 #include "StdAfx.h"
      4 
      5 #if defined( _WIN32) && defined( _7ZIP_LARGE_PAGES)
      6 #include "../../../../C/Alloc.h"
      7 #endif
      8 
      9 #include "Common/MyInitGuid.h"
     10 
     11 #include "Common/CommandLineParser.h"
     12 #include "Common/IntToString.h"
     13 #include "Common/MyException.h"
     14 #include "Common/StdOutStream.h"
     15 #include "Common/StringConvert.h"
     16 #include "Common/StringToInt.h"
     17 
     18 #include "Windows/Error.h"
     19 #ifdef _WIN32
     20 #include "Windows/MemoryLock.h"
     21 #endif
     22 
     23 #include "../Common/ArchiveCommandLine.h"
     24 #include "../Common/ExitCode.h"
     25 #include "../Common/Extract.h"
     26 #ifdef EXTERNAL_CODECS
     27 #include "../Common/LoadCodecs.h"
     28 #endif
     29 
     30 #include "BenchCon.h"
     31 #include "ExtractCallbackConsole.h"
     32 #include "List.h"
     33 #include "OpenCallbackConsole.h"
     34 #include "UpdateCallbackConsole.h"
     35 
     36 #include "../../MyVersion.h"
     37 
     38 using namespace NWindows;
     39 using namespace NFile;
     40 using namespace NCommandLineParser;
     41 
     42 HINSTANCE g_hInstance = 0;
     43 extern CStdOutStream *g_StdStream;
     44 
     45 static const char *kCopyrightString = "\n7-Zip"
     46 #ifndef EXTERNAL_CODECS
     47 " (A)"
     48 #endif
     49 
     50 #ifdef _WIN64
     51 " [64]"
     52 #endif
     53 
     54 " " MY_VERSION_COPYRIGHT_DATE "\n";
     55 
     56 static const char *kHelpString =
     57     "\nUsage: 7z"
     58 #ifdef _NO_CRYPTO
     59     "r"
     60 #else
     61 #ifndef EXTERNAL_CODECS
     62     "a"
     63 #endif
     64 #endif
     65     " <command> [<switches>...] <archive_name> [<file_names>...]\n"
     66     "       [<@listfiles...>]\n"
     67     "\n"
     68     "<Commands>\n"
     69     "  a: Add files to archive\n"
     70     "  b: Benchmark\n"
     71     "  d: Delete files from archive\n"
     72     "  e: Extract files from archive (without using directory names)\n"
     73     "  l: List contents of archive\n"
     74 //    "  l[a|t][f]: List contents of archive\n"
     75 //    "    a - with Additional fields\n"
     76 //    "    t - with all fields\n"
     77 //    "    f - with Full pathnames\n"
     78     "  t: Test integrity of archive\n"
     79     "  u: Update files to archive\n"
     80     "  x: eXtract files with full paths\n"
     81     "<Switches>\n"
     82     "  -ai[r[-|0]]{@listfile|!wildcard}: Include archives\n"
     83     "  -ax[r[-|0]]{@listfile|!wildcard}: eXclude archives\n"
     84     "  -bd: Disable percentage indicator\n"
     85     "  -i[r[-|0]]{@listfile|!wildcard}: Include filenames\n"
     86     "  -m{Parameters}: set compression Method\n"
     87     "  -o{Directory}: set Output directory\n"
     88     #ifndef _NO_CRYPTO
     89     "  -p{Password}: set Password\n"
     90     #endif
     91     "  -r[-|0]: Recurse subdirectories\n"
     92     "  -scs{UTF-8 | WIN | DOS}: set charset for list files\n"
     93     "  -sfx[{name}]: Create SFX archive\n"
     94     "  -si[{name}]: read data from stdin\n"
     95     "  -slt: show technical information for l (List) command\n"
     96     "  -so: write data to stdout\n"
     97     "  -ssc[-]: set sensitive case mode\n"
     98     "  -ssw: compress shared files\n"
     99     "  -t{Type}: Set type of archive\n"
    100     "  -u[-][p#][q#][r#][x#][y#][z#][!newArchiveName]: Update options\n"
    101     "  -v{Size}[b|k|m|g]: Create volumes\n"
    102     "  -w[{path}]: assign Work directory. Empty path means a temporary directory\n"
    103     "  -x[r[-|0]]]{@listfile|!wildcard}: eXclude filenames\n"
    104     "  -y: assume Yes on all queries\n";
    105 
    106 // ---------------------------
    107 // exception messages
    108 
    109 static const char *kEverythingIsOk = "Everything is Ok";
    110 static const char *kUserErrorMessage = "Incorrect command line";
    111 static const char *kNoFormats = "7-Zip cannot find the code that works with archives.";
    112 static const char *kUnsupportedArcTypeMessage = "Unsupported archive type";
    113 
    114 static const wchar_t *kDefaultSfxModule = L"7zCon.sfx";
    115 
    116 static void ShowMessageAndThrowException(CStdOutStream &s, LPCSTR message, NExitCode::EEnum code)
    117 {
    118   s << message << endl;
    119   throw code;
    120 }
    121 
    122 static void PrintHelpAndExit(CStdOutStream &s)
    123 {
    124   s << kHelpString;
    125   ShowMessageAndThrowException(s, kUserErrorMessage, NExitCode::kUserError);
    126 }
    127 
    128 #ifndef _WIN32
    129 static void GetArguments(int numArgs, const char *args[], UStringVector &parts)
    130 {
    131   parts.Clear();
    132   for (int i = 0; i < numArgs; i++)
    133   {
    134     UString s = MultiByteToUnicodeString(args[i]);
    135     parts.Add(s);
    136   }
    137 }
    138 #endif
    139 
    140 static void ShowCopyrightAndHelp(CStdOutStream &s, bool needHelp)
    141 {
    142   s << kCopyrightString;
    143   // s << "# CPUs: " << (UInt64)NWindows::NSystem::GetNumberOfProcessors() << "\n";
    144   if (needHelp)
    145     s << kHelpString;
    146 }
    147 
    148 #ifdef EXTERNAL_CODECS
    149 static void PrintString(CStdOutStream &stdStream, const AString &s, int size)
    150 {
    151   int len = s.Length();
    152   stdStream << s;
    153   for (int i = len; i < size; i++)
    154     stdStream << ' ';
    155 }
    156 #endif
    157 
    158 static void PrintString(CStdOutStream &stdStream, const UString &s, int size)
    159 {
    160   int len = s.Length();
    161   stdStream << s;
    162   for (int i = len; i < size; i++)
    163     stdStream << ' ';
    164 }
    165 
    166 static inline char GetHex(Byte value)
    167 {
    168   return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
    169 }
    170 
    171 int Main2(
    172   #ifndef _WIN32
    173   int numArgs, const char *args[]
    174   #endif
    175 )
    176 {
    177   #if defined(_WIN32) && !defined(UNDER_CE)
    178   SetFileApisToOEM();
    179   #endif
    180 
    181   UStringVector commandStrings;
    182   #ifdef _WIN32
    183   NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
    184   #else
    185   GetArguments(numArgs, args, commandStrings);
    186   #endif
    187 
    188   if (commandStrings.Size() == 1)
    189   {
    190     ShowCopyrightAndHelp(g_StdOut, true);
    191     return 0;
    192   }
    193   commandStrings.Delete(0);
    194 
    195   CArchiveCommandLineOptions options;
    196 
    197   CArchiveCommandLineParser parser;
    198 
    199   parser.Parse1(commandStrings, options);
    200 
    201   if (options.HelpMode)
    202   {
    203     ShowCopyrightAndHelp(g_StdOut, true);
    204     return 0;
    205   }
    206 
    207   #if defined(_WIN32) && defined(_7ZIP_LARGE_PAGES)
    208   if (options.LargePages)
    209   {
    210     SetLargePageSize();
    211     NSecurity::EnableLockMemoryPrivilege();
    212   }
    213   #endif
    214 
    215   CStdOutStream &stdStream = options.StdOutMode ? g_StdErr : g_StdOut;
    216   g_StdStream = &stdStream;
    217 
    218   if (options.EnableHeaders)
    219     ShowCopyrightAndHelp(stdStream, false);
    220 
    221   parser.Parse2(options);
    222 
    223   CCodecs *codecs = new CCodecs;
    224   CMyComPtr<
    225     #ifdef EXTERNAL_CODECS
    226     ICompressCodecsInfo
    227     #else
    228     IUnknown
    229     #endif
    230     > compressCodecsInfo = codecs;
    231   HRESULT result = codecs->Load();
    232   if (result != S_OK)
    233     throw CSystemException(result);
    234 
    235   bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
    236 
    237   if (codecs->Formats.Size() == 0 &&
    238         (isExtractGroupCommand ||
    239         options.Command.CommandType == NCommandType::kList ||
    240         options.Command.IsFromUpdateGroup()))
    241     throw kNoFormats;
    242 
    243   CIntVector formatIndices;
    244   if (!codecs->FindFormatForArchiveType(options.ArcType, formatIndices))
    245     throw kUnsupportedArcTypeMessage;
    246 
    247   if (options.Command.CommandType == NCommandType::kInfo)
    248   {
    249     stdStream << endl << "Formats:" << endl;
    250     int i;
    251     for (i = 0; i < codecs->Formats.Size(); i++)
    252     {
    253       const CArcInfoEx &arc = codecs->Formats[i];
    254       #ifdef EXTERNAL_CODECS
    255       if (arc.LibIndex >= 0)
    256       {
    257         char s[16];
    258         ConvertUInt32ToString(arc.LibIndex, s);
    259         PrintString(stdStream, s, 2);
    260       }
    261       else
    262       #endif
    263         stdStream << "  ";
    264       stdStream << ' ';
    265       stdStream << (char)(arc.UpdateEnabled ? 'C' : ' ');
    266       stdStream << (char)(arc.KeepName ? 'K' : ' ');
    267       stdStream << "  ";
    268       PrintString(stdStream, arc.Name, 6);
    269       stdStream << "  ";
    270       UString s;
    271       for (int t = 0; t < arc.Exts.Size(); t++)
    272       {
    273         const CArcExtInfo &ext = arc.Exts[t];
    274         s += ext.Ext;
    275         if (!ext.AddExt.IsEmpty())
    276         {
    277           s += L" (";
    278           s += ext.AddExt;
    279           s += L')';
    280         }
    281         s += L' ';
    282       }
    283       PrintString(stdStream, s, 14);
    284       stdStream << "  ";
    285       const CByteBuffer &sig = arc.StartSignature;
    286       for (size_t j = 0; j < sig.GetCapacity(); j++)
    287       {
    288         Byte b = sig[j];
    289         if (b > 0x20 && b < 0x80)
    290         {
    291           stdStream << (char)b;
    292         }
    293         else
    294         {
    295           stdStream << GetHex((Byte)((b >> 4) & 0xF));
    296           stdStream << GetHex((Byte)(b & 0xF));
    297         }
    298         stdStream << ' ';
    299       }
    300       stdStream << endl;
    301     }
    302     stdStream << endl << "Codecs:" << endl;
    303 
    304     #ifdef EXTERNAL_CODECS
    305     UInt32 numMethods;
    306     if (codecs->GetNumberOfMethods(&numMethods) == S_OK)
    307     for (UInt32 j = 0; j < numMethods; j++)
    308     {
    309       int libIndex = codecs->GetCodecLibIndex(j);
    310       if (libIndex >= 0)
    311       {
    312         char s[16];
    313         ConvertUInt32ToString(libIndex, s);
    314         PrintString(stdStream, s, 2);
    315       }
    316       else
    317         stdStream << "  ";
    318       stdStream << ' ';
    319       stdStream << (char)(codecs->GetCodecEncoderIsAssigned(j) ? 'C' : ' ');
    320       UInt64 id;
    321       stdStream << "  ";
    322       HRESULT res = codecs->GetCodecId(j, id);
    323       if (res != S_OK)
    324         id = (UInt64)(Int64)-1;
    325       char s[32];
    326       ConvertUInt64ToString(id, s, 16);
    327       PrintString(stdStream, s, 8);
    328       stdStream << "  ";
    329       PrintString(stdStream, codecs->GetCodecName(j), 11);
    330       stdStream << endl;
    331       /*
    332       if (res != S_OK)
    333         throw "incorrect Codec ID";
    334       */
    335     }
    336     #endif
    337     return S_OK;
    338   }
    339   else if (options.Command.CommandType == NCommandType::kBenchmark)
    340   {
    341     if (options.Method.CompareNoCase(L"CRC") == 0)
    342     {
    343       HRESULT res = CrcBenchCon((FILE *)stdStream, options.NumIterations, options.NumThreads, options.DictionarySize);
    344       if (res != S_OK)
    345       {
    346         if (res == S_FALSE)
    347         {
    348           stdStream << "\nCRC Error\n";
    349           return NExitCode::kFatalError;
    350         }
    351         throw CSystemException(res);
    352       }
    353     }
    354     else
    355     {
    356       HRESULT res;
    357       #ifdef EXTERNAL_CODECS
    358       CObjectVector<CCodecInfoEx> externalCodecs;
    359       res = LoadExternalCodecs(compressCodecsInfo, externalCodecs);
    360       if (res != S_OK)
    361         throw CSystemException(res);
    362       #endif
    363       res = LzmaBenchCon(
    364           #ifdef EXTERNAL_CODECS
    365           compressCodecsInfo, &externalCodecs,
    366           #endif
    367         (FILE *)stdStream, options.NumIterations, options.NumThreads, options.DictionarySize);
    368       if (res != S_OK)
    369       {
    370         if (res == S_FALSE)
    371         {
    372           stdStream << "\nDecoding Error\n";
    373           return NExitCode::kFatalError;
    374         }
    375         throw CSystemException(res);
    376       }
    377     }
    378   }
    379   else if (isExtractGroupCommand || options.Command.CommandType == NCommandType::kList)
    380   {
    381     if (isExtractGroupCommand)
    382     {
    383       CExtractCallbackConsole *ecs = new CExtractCallbackConsole;
    384       CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
    385 
    386       ecs->OutStream = &stdStream;
    387 
    388       #ifndef _NO_CRYPTO
    389       ecs->PasswordIsDefined = options.PasswordEnabled;
    390       ecs->Password = options.Password;
    391       #endif
    392 
    393       ecs->Init();
    394 
    395       COpenCallbackConsole openCallback;
    396       openCallback.OutStream = &stdStream;
    397 
    398       #ifndef _NO_CRYPTO
    399       openCallback.PasswordIsDefined = options.PasswordEnabled;
    400       openCallback.Password = options.Password;
    401       #endif
    402 
    403       CExtractOptions eo;
    404       eo.StdInMode = options.StdInMode;
    405       eo.StdOutMode = options.StdOutMode;
    406       eo.PathMode = options.Command.GetPathMode();
    407       eo.TestMode = options.Command.IsTestMode();
    408       eo.OverwriteMode = options.OverwriteMode;
    409       eo.OutputDir = options.OutputDir;
    410       eo.YesToAll = options.YesToAll;
    411       eo.CalcCrc = options.CalcCrc;
    412       #if !defined(_7ZIP_ST) && !defined(_SFX)
    413       eo.Properties = options.ExtractProperties;
    414       #endif
    415       UString errorMessage;
    416       CDecompressStat stat;
    417       HRESULT result = DecompressArchives(
    418           codecs,
    419           formatIndices,
    420           options.ArchivePathsSorted,
    421           options.ArchivePathsFullSorted,
    422           options.WildcardCensor.Pairs.Front().Head,
    423           eo, &openCallback, ecs, errorMessage, stat);
    424       if (!errorMessage.IsEmpty())
    425       {
    426         stdStream << endl << "Error: " << errorMessage;
    427         if (result == S_OK)
    428           result = E_FAIL;
    429       }
    430 
    431       stdStream << endl;
    432       if (ecs->NumArchives > 1)
    433         stdStream << "Archives: " << ecs->NumArchives << endl;
    434       if (ecs->NumArchiveErrors != 0 || ecs->NumFileErrors != 0)
    435       {
    436         if (ecs->NumArchives > 1)
    437         {
    438           stdStream << endl;
    439           if (ecs->NumArchiveErrors != 0)
    440             stdStream << "Archive Errors: " << ecs->NumArchiveErrors << endl;
    441           if (ecs->NumFileErrors != 0)
    442             stdStream << "Sub items Errors: " << ecs->NumFileErrors << endl;
    443         }
    444         if (result != S_OK)
    445           throw CSystemException(result);
    446         return NExitCode::kFatalError;
    447       }
    448       if (result != S_OK)
    449         throw CSystemException(result);
    450       if (stat.NumFolders != 0)
    451         stdStream << "Folders: " << stat.NumFolders << endl;
    452       if (stat.NumFiles != 1 || stat.NumFolders != 0)
    453           stdStream << "Files: " << stat.NumFiles << endl;
    454       stdStream
    455            << "Size:       " << stat.UnpackSize << endl
    456            << "Compressed: " << stat.PackSize << endl;
    457       if (options.CalcCrc)
    458       {
    459         char s[16];
    460         ConvertUInt32ToHexWithZeros(stat.CrcSum, s);
    461         stdStream << "CRC: " << s << endl;
    462       }
    463     }
    464     else
    465     {
    466       UInt64 numErrors = 0;
    467       HRESULT result = ListArchives(
    468           codecs,
    469           formatIndices,
    470           options.StdInMode,
    471           options.ArchivePathsSorted,
    472           options.ArchivePathsFullSorted,
    473           options.WildcardCensor.Pairs.Front().Head,
    474           options.EnableHeaders,
    475           options.TechMode,
    476           #ifndef _NO_CRYPTO
    477           options.PasswordEnabled,
    478           options.Password,
    479           #endif
    480           numErrors);
    481       if (numErrors > 0)
    482       {
    483         g_StdOut << endl << "Errors: " << numErrors;
    484         return NExitCode::kFatalError;
    485       }
    486       if (result != S_OK)
    487         throw CSystemException(result);
    488     }
    489   }
    490   else if (options.Command.IsFromUpdateGroup())
    491   {
    492     CUpdateOptions &uo = options.UpdateOptions;
    493     if (uo.SfxMode && uo.SfxModule.IsEmpty())
    494       uo.SfxModule = kDefaultSfxModule;
    495 
    496     COpenCallbackConsole openCallback;
    497     openCallback.OutStream = &stdStream;
    498 
    499     #ifndef _NO_CRYPTO
    500     bool passwordIsDefined =
    501         options.PasswordEnabled && !options.Password.IsEmpty();
    502     openCallback.PasswordIsDefined = passwordIsDefined;
    503     openCallback.Password = options.Password;
    504     #endif
    505 
    506     CUpdateCallbackConsole callback;
    507     callback.EnablePercents = options.EnablePercents;
    508 
    509     #ifndef _NO_CRYPTO
    510     callback.PasswordIsDefined = passwordIsDefined;
    511     callback.AskPassword = options.PasswordEnabled && options.Password.IsEmpty();
    512     callback.Password = options.Password;
    513     #endif
    514     callback.StdOutMode = uo.StdOutMode;
    515     callback.Init(&stdStream);
    516 
    517     CUpdateErrorInfo errorInfo;
    518 
    519     if (!uo.Init(codecs, formatIndices, options.ArchiveName))
    520       throw kUnsupportedArcTypeMessage;
    521     HRESULT result = UpdateArchive(codecs,
    522         options.WildcardCensor, uo,
    523         errorInfo, &openCallback, &callback);
    524 
    525     int exitCode = NExitCode::kSuccess;
    526     if (callback.CantFindFiles.Size() > 0)
    527     {
    528       stdStream << endl;
    529       stdStream << "WARNINGS for files:" << endl << endl;
    530       int numErrors = callback.CantFindFiles.Size();
    531       for (int i = 0; i < numErrors; i++)
    532       {
    533         stdStream << callback.CantFindFiles[i] << " : ";
    534         stdStream << NError::MyFormatMessageW(callback.CantFindCodes[i]) << endl;
    535       }
    536       stdStream << "----------------" << endl;
    537       stdStream << "WARNING: Cannot find " << numErrors << " file";
    538       if (numErrors > 1)
    539         stdStream << "s";
    540       stdStream << endl;
    541       exitCode = NExitCode::kWarning;
    542     }
    543 
    544     if (result != S_OK)
    545     {
    546       UString message;
    547       if (!errorInfo.Message.IsEmpty())
    548       {
    549         message += errorInfo.Message;
    550         message += L"\n";
    551       }
    552       if (!errorInfo.FileName.IsEmpty())
    553       {
    554         message += errorInfo.FileName;
    555         message += L"\n";
    556       }
    557       if (!errorInfo.FileName2.IsEmpty())
    558       {
    559         message += errorInfo.FileName2;
    560         message += L"\n";
    561       }
    562       if (errorInfo.SystemError != 0)
    563       {
    564         message += NError::MyFormatMessageW(errorInfo.SystemError);
    565         message += L"\n";
    566       }
    567       if (!message.IsEmpty())
    568         stdStream << L"\nError:\n" << message;
    569       throw CSystemException(result);
    570     }
    571     int numErrors = callback.FailedFiles.Size();
    572     if (numErrors == 0)
    573     {
    574       if (callback.CantFindFiles.Size() == 0)
    575         stdStream << kEverythingIsOk << endl;
    576     }
    577     else
    578     {
    579       stdStream << endl;
    580       stdStream << "WARNINGS for files:" << endl << endl;
    581       for (int i = 0; i < numErrors; i++)
    582       {
    583         stdStream << callback.FailedFiles[i] << " : ";
    584         stdStream << NError::MyFormatMessageW(callback.FailedCodes[i]) << endl;
    585       }
    586       stdStream << "----------------" << endl;
    587       stdStream << "WARNING: Cannot open " << numErrors << " file";
    588       if (numErrors > 1)
    589         stdStream << "s";
    590       stdStream << endl;
    591       exitCode = NExitCode::kWarning;
    592     }
    593     return exitCode;
    594   }
    595   else
    596     PrintHelpAndExit(stdStream);
    597   return 0;
    598 }
    599