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
38using namespace NWindows;
39using namespace NFile;
40using namespace NCommandLineParser;
41
42HINSTANCE g_hInstance = 0;
43extern CStdOutStream *g_StdStream;
44
45static 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
56static 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
109static const char *kEverythingIsOk = "Everything is Ok";
110static const char *kUserErrorMessage = "Incorrect command line";
111static const char *kNoFormats = "7-Zip cannot find the code that works with archives.";
112static const char *kUnsupportedArcTypeMessage = "Unsupported archive type";
113
114static const wchar_t *kDefaultSfxModule = L"7zCon.sfx";
115
116static void ShowMessageAndThrowException(CStdOutStream &s, LPCSTR message, NExitCode::EEnum code)
117{
118  s << message << endl;
119  throw code;
120}
121
122static void PrintHelpAndExit(CStdOutStream &s)
123{
124  s << kHelpString;
125  ShowMessageAndThrowException(s, kUserErrorMessage, NExitCode::kUserError);
126}
127
128#ifndef _WIN32
129static 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
140static 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
149static 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
158static 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
166static inline char GetHex(Byte value)
167{
168  return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
169}
170
171int 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