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 
ShowMessageAndThrowException(CStdOutStream & s,LPCSTR message,NExitCode::EEnum code)116 static void ShowMessageAndThrowException(CStdOutStream &s, LPCSTR message, NExitCode::EEnum code)
117 {
118   s << message << endl;
119   throw code;
120 }
121 
PrintHelpAndExit(CStdOutStream & s)122 static void PrintHelpAndExit(CStdOutStream &s)
123 {
124   s << kHelpString;
125   ShowMessageAndThrowException(s, kUserErrorMessage, NExitCode::kUserError);
126 }
127 
128 #ifndef _WIN32
GetArguments(int numArgs,const char * args[],UStringVector & parts)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 
ShowCopyrightAndHelp(CStdOutStream & s,bool needHelp)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
PrintString(CStdOutStream & stdStream,const AString & s,int size)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 
PrintString(CStdOutStream & stdStream,const UString & s,int size)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 
GetHex(Byte value)166 static inline char GetHex(Byte value)
167 {
168   return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
169 }
170 
Main2(int numArgs,const char * args[])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