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 116 static void ShowMessageAndThrowException(CStdOutStream &s, LPCSTR message, NExitCode::EEnum code) 117 { 118 s << message << endl; 119 throw code; 120 } 121 122 static void PrintHelpAndExit(CStdOutStream &s) 123 { 124 s << kHelpString; 125 ShowMessageAndThrowException(s, kUserErrorMessage, NExitCode::kUserError); 126 } 127 128 #ifndef _WIN32 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 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 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 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 166 static inline char GetHex(Byte value) 167 { 168 return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10))); 169 } 170 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