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 #if !defined(EXTERNAL_CODECS) && defined(_NO_CRYPTO)
37 #define IT_IS_REDUCED_VERSION
38 #endif
39 
40 #ifdef IT_IS_REDUCED_VERSION
41 #include "../../../../C/7zVersion.h"
42 #else
43 #include "../../MyVersion.h"
44 #endif
45 
46 using namespace NWindows;
47 using namespace NFile;
48 using namespace NCommandLineParser;
49 
50 #ifdef _WIN32
51 HINSTANCE g_hInstance = 0;
52 #endif
53 extern CStdOutStream *g_StdStream;
54 
55 static const char *kCopyrightString = "\n7-Zip"
56 #ifndef EXTERNAL_CODECS
57 #ifdef IT_IS_REDUCED_VERSION
58 " (r)"
59 #else
60 " (a)"
61 #endif
62 #endif
63 
64 #ifdef _WIN64
65 " [64]"
66 #endif
67 
68 " " MY_VERSION_COPYRIGHT_DATE "\n";
69 
70 static const char *kHelpString =
71     "\nUsage: 7z"
72 #ifndef EXTERNAL_CODECS
73 #ifdef IT_IS_REDUCED_VERSION
74     "r"
75 #else
76     "a"
77 #endif
78 #endif
79     " <command> [<switches>...] <archive_name> [<file_names>...]\n"
80     "       [<@listfiles...>]\n"
81     "\n"
82     "<Commands>\n"
83     "  a: Add files to archive\n"
84     "  b: Benchmark\n"
85     "  d: Delete files from archive\n"
86     "  e: Extract files from archive (without using directory names)\n"
87     "  l: List contents of archive\n"
88 //    "  l[a|t][f]: List contents of archive\n"
89 //    "    a - with Additional fields\n"
90 //    "    t - with all fields\n"
91 //    "    f - with Full pathnames\n"
92     "  t: Test integrity of archive\n"
93     "  u: Update files to archive\n"
94     "  x: eXtract files with full paths\n"
95     "<Switches>\n"
96     "  -ai[r[-|0]]{@listfile|!wildcard}: Include archives\n"
97     "  -ax[r[-|0]]{@listfile|!wildcard}: eXclude archives\n"
98     "  -bd: Disable percentage indicator\n"
99     "  -i[r[-|0]]{@listfile|!wildcard}: Include filenames\n"
100     "  -m{Parameters}: set compression Method\n"
101     "  -o{Directory}: set Output directory\n"
102     #ifndef _NO_CRYPTO
103     "  -p{Password}: set Password\n"
104     #endif
105     "  -r[-|0]: Recurse subdirectories\n"
106     "  -scs{UTF-8 | WIN | DOS}: set charset for list files\n"
107     "  -sfx[{name}]: Create SFX archive\n"
108     "  -si[{name}]: read data from stdin\n"
109     "  -slt: show technical information for l (List) command\n"
110     "  -so: write data to stdout\n"
111     "  -ssc[-]: set sensitive case mode\n"
112     "  -ssw: compress shared files\n"
113     "  -t{Type}: Set type of archive\n"
114     "  -u[-][p#][q#][r#][x#][y#][z#][!newArchiveName]: Update options\n"
115     "  -v{Size}[b|k|m|g]: Create volumes\n"
116     "  -w[{path}]: assign Work directory. Empty path means a temporary directory\n"
117     "  -x[r[-|0]]]{@listfile|!wildcard}: eXclude filenames\n"
118     "  -y: assume Yes on all queries\n";
119 
120 // ---------------------------
121 // exception messages
122 
123 static const char *kEverythingIsOk = "Everything is Ok";
124 static const char *kUserErrorMessage = "Incorrect command line";
125 static const char *kNoFormats = "7-Zip cannot find the code that works with archives.";
126 static const char *kUnsupportedArcTypeMessage = "Unsupported archive type";
127 
128 static CFSTR kDefaultSfxModule = FTEXT("7zCon.sfx");
129 
ShowMessageAndThrowException(CStdOutStream & s,LPCSTR message,NExitCode::EEnum code)130 static void ShowMessageAndThrowException(CStdOutStream &s, LPCSTR message, NExitCode::EEnum code)
131 {
132   s << message << endl;
133   throw code;
134 }
135 
PrintHelpAndExit(CStdOutStream & s)136 static void PrintHelpAndExit(CStdOutStream &s)
137 {
138   s << kHelpString;
139   ShowMessageAndThrowException(s, kUserErrorMessage, NExitCode::kUserError);
140 }
141 
142 #ifndef _WIN32
GetArguments(int numArgs,const char * args[],UStringVector & parts)143 static void GetArguments(int numArgs, const char *args[], UStringVector &parts)
144 {
145   parts.Clear();
146   for (int i = 0; i < numArgs; i++)
147   {
148     UString s = MultiByteToUnicodeString(args[i]);
149     parts.Add(s);
150   }
151 }
152 #endif
153 
ShowCopyrightAndHelp(CStdOutStream & s,bool needHelp)154 static void ShowCopyrightAndHelp(CStdOutStream &s, bool needHelp)
155 {
156   s << kCopyrightString;
157   // s << "# CPUs: " << (UInt64)NWindows::NSystem::GetNumberOfProcessors() << "\n";
158   if (needHelp)
159     s << kHelpString;
160 }
161 
162 #ifdef EXTERNAL_CODECS
PrintString(CStdOutStream & stdStream,const AString & s,int size)163 static void PrintString(CStdOutStream &stdStream, const AString &s, int size)
164 {
165   int len = s.Length();
166   stdStream << s;
167   for (int i = len; i < size; i++)
168     stdStream << ' ';
169 }
170 #endif
171 
PrintString(CStdOutStream & stdStream,const UString & s,int size)172 static void PrintString(CStdOutStream &stdStream, const UString &s, int size)
173 {
174   int len = s.Length();
175   stdStream << s;
176   for (int i = len; i < size; i++)
177     stdStream << ' ';
178 }
179 
GetHex(Byte value)180 static inline char GetHex(Byte value)
181 {
182   return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
183 }
184 
Main2(int numArgs,const char * args[])185 int Main2(
186   #ifndef _WIN32
187   int numArgs, const char *args[]
188   #endif
189 )
190 {
191   #if defined(_WIN32) && !defined(UNDER_CE)
192   SetFileApisToOEM();
193   #endif
194 
195   UStringVector commandStrings;
196   #ifdef _WIN32
197   NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
198   #else
199   GetArguments(numArgs, args, commandStrings);
200   #endif
201 
202   if (commandStrings.Size() == 1)
203   {
204     ShowCopyrightAndHelp(g_StdOut, true);
205     return 0;
206   }
207   commandStrings.Delete(0);
208 
209   CArchiveCommandLineOptions options;
210 
211   CArchiveCommandLineParser parser;
212 
213   parser.Parse1(commandStrings, options);
214 
215   if (options.HelpMode)
216   {
217     ShowCopyrightAndHelp(g_StdOut, true);
218     return 0;
219   }
220 
221   #if defined(_WIN32) && defined(_7ZIP_LARGE_PAGES)
222   if (options.LargePages)
223   {
224     SetLargePageSize();
225     NSecurity::EnableLockMemoryPrivilege();
226   }
227   #endif
228 
229   CStdOutStream &stdStream = options.StdOutMode ? g_StdErr : g_StdOut;
230   g_StdStream = &stdStream;
231 
232   if (options.EnableHeaders)
233     ShowCopyrightAndHelp(stdStream, false);
234 
235   parser.Parse2(options);
236 
237   CCodecs *codecs = new CCodecs;
238   CMyComPtr<
239     #ifdef EXTERNAL_CODECS
240     ICompressCodecsInfo
241     #else
242     IUnknown
243     #endif
244     > compressCodecsInfo = codecs;
245   HRESULT result = codecs->Load();
246   if (result != S_OK)
247     throw CSystemException(result);
248 
249   bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
250 
251   if (codecs->Formats.Size() == 0 &&
252         (isExtractGroupCommand ||
253         options.Command.CommandType == NCommandType::kList ||
254         options.Command.IsFromUpdateGroup()))
255     throw kNoFormats;
256 
257   CIntVector formatIndices;
258   if (!codecs->FindFormatForArchiveType(options.ArcType, formatIndices))
259     throw kUnsupportedArcTypeMessage;
260 
261   if (options.Command.CommandType == NCommandType::kInfo)
262   {
263     stdStream << endl << "Formats:" << endl;
264     int i;
265     for (i = 0; i < codecs->Formats.Size(); i++)
266     {
267       const CArcInfoEx &arc = codecs->Formats[i];
268       #ifdef EXTERNAL_CODECS
269       if (arc.LibIndex >= 0)
270       {
271         char s[16];
272         ConvertUInt32ToString(arc.LibIndex, s);
273         PrintString(stdStream, s, 2);
274       }
275       else
276       #endif
277         stdStream << "  ";
278       stdStream << ' ';
279       stdStream << (char)(arc.UpdateEnabled ? 'C' : ' ');
280       stdStream << (char)(arc.KeepName ? 'K' : ' ');
281       stdStream << "  ";
282       PrintString(stdStream, arc.Name, 6);
283       stdStream << "  ";
284       UString s;
285       for (int t = 0; t < arc.Exts.Size(); t++)
286       {
287         const CArcExtInfo &ext = arc.Exts[t];
288         s += ext.Ext;
289         if (!ext.AddExt.IsEmpty())
290         {
291           s += L" (";
292           s += ext.AddExt;
293           s += L')';
294         }
295         s += L' ';
296       }
297       PrintString(stdStream, s, 14);
298       stdStream << "  ";
299       const CByteBuffer &sig = arc.StartSignature;
300       for (size_t j = 0; j < sig.GetCapacity(); j++)
301       {
302         Byte b = sig[j];
303         if (b > 0x20 && b < 0x80)
304         {
305           stdStream << (char)b;
306         }
307         else
308         {
309           stdStream << GetHex((Byte)((b >> 4) & 0xF));
310           stdStream << GetHex((Byte)(b & 0xF));
311         }
312         stdStream << ' ';
313       }
314       stdStream << endl;
315     }
316     stdStream << endl << "Codecs:" << endl;
317 
318     #ifdef EXTERNAL_CODECS
319     UInt32 numMethods;
320     if (codecs->GetNumberOfMethods(&numMethods) == S_OK)
321     for (UInt32 j = 0; j < numMethods; j++)
322     {
323       int libIndex = codecs->GetCodecLibIndex(j);
324       if (libIndex >= 0)
325       {
326         char s[16];
327         ConvertUInt32ToString(libIndex, s);
328         PrintString(stdStream, s, 2);
329       }
330       else
331         stdStream << "  ";
332       stdStream << ' ';
333       stdStream << (char)(codecs->GetCodecEncoderIsAssigned(j) ? 'C' : ' ');
334       UInt64 id;
335       stdStream << "  ";
336       HRESULT res = codecs->GetCodecId(j, id);
337       if (res != S_OK)
338         id = (UInt64)(Int64)-1;
339       char s[32];
340       ConvertUInt64ToString(id, s, 16);
341       PrintString(stdStream, s, 8);
342       stdStream << "  ";
343       PrintString(stdStream, codecs->GetCodecName(j), 11);
344       stdStream << endl;
345       /*
346       if (res != S_OK)
347         throw "incorrect Codec ID";
348       */
349     }
350     #endif
351     return S_OK;
352   }
353   else if (options.Command.CommandType == NCommandType::kBenchmark)
354   {
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 = BenchCon(
364           #ifdef EXTERNAL_CODECS
365           compressCodecsInfo, &externalCodecs,
366           #endif
367           options.Properties, options.NumIterations, (FILE *)stdStream);
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.Properties;
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 << endl;
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 += fs2us(errorInfo.FileName);
555         message += L"\n";
556       }
557       if (!errorInfo.FileName2.IsEmpty())
558       {
559         message += fs2us(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