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