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