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 10 #ifdef _WIN32 11 #include "../../../Windows/DLL.h" 12 #include "../../../Windows/FileDir.h" 13 #endif 14 #include "../../../Windows/FileName.h" 15 16 #include "../../UI/Common/ExitCode.h" 17 #include "../../UI/Common/Extract.h" 18 19 #include "../../UI/Console/ExtractCallbackConsole.h" 20 #include "../../UI/Console/List.h" 21 #include "../../UI/Console/OpenCallbackConsole.h" 22 23 #include "../../MyVersion.h" 24 25 using namespace NWindows; 26 using namespace NFile; 27 using namespace NDir; 28 using namespace NCommandLineParser; 29 30 #ifdef _WIN32 31 HINSTANCE g_hInstance = 0; 32 #endif 33 int g_CodePage = -1; 34 extern CStdOutStream *g_StdStream; 35 36 static const char *kCopyrightString = 37 "\n7-Zip SFX " MY_VERSION_COPYRIGHT_DATE "\n"; 38 39 static const int kNumSwitches = 6; 40 41 namespace NKey { 42 enum Enum 43 { 44 kHelp1 = 0, 45 kHelp2, 46 kDisablePercents, 47 kYes, 48 kPassword, 49 kOutputDir 50 }; 51 52 } 53 54 namespace NRecursedType { 55 enum EEnum 56 { 57 kRecursed, 58 kWildcardOnlyRecursed, 59 kNonRecursed 60 }; 61 } 62 /* 63 static const char kRecursedIDChar = 'R'; 64 static const wchar_t *kRecursedPostCharSet = L"0-"; 65 66 namespace NRecursedPostCharIndex { 67 enum EEnum 68 { 69 kWildcardRecursionOnly = 0, 70 kNoRecursion = 1 71 }; 72 } 73 74 static const char kFileListID = '@'; 75 static const char kImmediateNameID = '!'; 76 77 static const char kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be 78 static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be 79 */ 80 static const CSwitchForm kSwitchForms[kNumSwitches] = 81 { 82 { "?", NSwitchType::kSimple }, 83 { "H", NSwitchType::kSimple }, 84 { "BD", NSwitchType::kSimple }, 85 { "Y", NSwitchType::kSimple }, 86 { "P", NSwitchType::kString, false, 1 }, 87 { "O", NSwitchType::kString, false, 1 }, 88 }; 89 90 static const int kNumCommandForms = 3; 91 92 static const NRecursedType::EEnum kCommandRecursedDefault[kNumCommandForms] = 93 { 94 NRecursedType::kRecursed 95 }; 96 97 // static const bool kTestExtractRecursedDefault = true; 98 // static const bool kAddRecursedDefault = false; 99 100 static const wchar_t *kUniversalWildcard = L"*"; 101 static const int kCommandIndex = 0; 102 103 static const char *kHelpString = 104 "\nUsage: 7zSFX [<command>] [<switches>...]\n" 105 "\n" 106 "<Commands>\n" 107 " l: List contents of archive\n" 108 " t: Test integrity of archive\n" 109 " x: eXtract files with full pathname (default)\n" 110 "<Switches>\n" 111 // " -bd Disable percentage indicator\n" 112 " -o{Directory}: set Output directory\n" 113 " -p{Password}: set Password\n" 114 " -y: assume Yes on all queries\n"; 115 116 117 // --------------------------- 118 // exception messages 119 120 static const char *kUserErrorMessage = "Incorrect command line"; // NExitCode::kUserError 121 // static const char *kIncorrectListFile = "Incorrect wildcard in listfile"; 122 static const char *kIncorrectWildcardInCommandLine = "Incorrect wildcard in command line"; 123 124 // static const CSysString kFileIsNotArchiveMessageBefore = "File \""; 125 // static const CSysString kFileIsNotArchiveMessageAfter = "\" is not archive"; 126 127 // static const char *kProcessArchiveMessage = " archive: "; 128 129 static const char *kCantFindSFX = " cannot find sfx"; 130 131 namespace NCommandType 132 { 133 enum EEnum 134 { 135 kTest = 0, 136 kFullExtract, 137 kList 138 }; 139 } 140 141 static const char *g_Commands = "txl"; 142 143 struct CArchiveCommand 144 { 145 NCommandType::EEnum CommandType; 146 147 NRecursedType::EEnum DefaultRecursedType() const; 148 }; 149 150 bool ParseArchiveCommand(const UString &commandString, CArchiveCommand &command) 151 { 152 UString s = commandString; 153 s.MakeLower_Ascii(); 154 if (s.Len() != 1) 155 return false; 156 if (s[0] >= 0x80) 157 return false; 158 int index = FindCharPosInString(g_Commands, (char)s[0]); 159 if (index < 0) 160 return false; 161 command.CommandType = (NCommandType::EEnum)index; 162 return true; 163 } 164 165 NRecursedType::EEnum CArchiveCommand::DefaultRecursedType() const 166 { 167 return kCommandRecursedDefault[CommandType]; 168 } 169 170 void PrintHelp(void) 171 { 172 g_StdOut << kHelpString; 173 } 174 175 static void ShowMessageAndThrowException(const char *message, NExitCode::EEnum code) 176 { 177 g_StdOut << message << endl; 178 throw code; 179 } 180 181 static void PrintHelpAndExit() // yyy 182 { 183 PrintHelp(); 184 ShowMessageAndThrowException(kUserErrorMessage, NExitCode::kUserError); 185 } 186 187 // ------------------------------------------------------------------ 188 // filenames functions 189 190 static bool AddNameToCensor(NWildcard::CCensor &wildcardCensor, 191 const UString &name, bool include, NRecursedType::EEnum type) 192 { 193 /* 194 if (!IsWildcardFilePathLegal(name)) 195 return false; 196 */ 197 bool isWildcard = DoesNameContainWildcard(name); 198 bool recursed = false; 199 200 switch (type) 201 { 202 case NRecursedType::kWildcardOnlyRecursed: 203 recursed = isWildcard; 204 break; 205 case NRecursedType::kRecursed: 206 recursed = true; 207 break; 208 case NRecursedType::kNonRecursed: 209 recursed = false; 210 break; 211 } 212 wildcardCensor.AddPreItem(include, name, recursed, true); 213 return true; 214 } 215 216 void AddCommandLineWildcardToCensor(NWildcard::CCensor &wildcardCensor, 217 const UString &name, bool include, NRecursedType::EEnum type) 218 { 219 if (!AddNameToCensor(wildcardCensor, name, include, type)) 220 ShowMessageAndThrowException(kIncorrectWildcardInCommandLine, NExitCode::kUserError); 221 } 222 223 void AddToCensorFromNonSwitchesStrings(NWildcard::CCensor &wildcardCensor, 224 const UStringVector & /* nonSwitchStrings */, NRecursedType::EEnum type, 225 bool /* thereAreSwitchIncludeWildcards */) 226 { 227 AddCommandLineWildcardToCensor(wildcardCensor, kUniversalWildcard, true, type); 228 } 229 230 231 #ifndef _WIN32 232 static void GetArguments(int numArgs, const char *args[], UStringVector &parts) 233 { 234 parts.Clear(); 235 for (int i = 0; i < numArgs; i++) 236 { 237 UString s = MultiByteToUnicodeString(args[i]); 238 parts.Add(s); 239 } 240 } 241 #endif 242 243 int Main2( 244 #ifndef _WIN32 245 int numArgs, const char *args[] 246 #endif 247 ) 248 { 249 #if defined(_WIN32) && !defined(UNDER_CE) 250 SetFileApisToOEM(); 251 #endif 252 253 g_StdOut << kCopyrightString; 254 255 UStringVector commandStrings; 256 #ifdef _WIN32 257 NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings); 258 #else 259 GetArguments(numArgs, args, commandStrings); 260 #endif 261 262 #ifdef _WIN32 263 264 FString arcPath; 265 { 266 FString path; 267 NDLL::MyGetModuleFileName(path); 268 if (!MyGetFullPathName(path, arcPath)) 269 { 270 g_StdOut << "GetFullPathName Error"; 271 return NExitCode::kFatalError; 272 } 273 } 274 275 #else 276 277 UString arcPath = commandStrings.Front(); 278 279 #endif 280 281 commandStrings.Delete(0); 282 283 NCommandLineParser::CParser parser(kNumSwitches); 284 try 285 { 286 parser.ParseStrings(kSwitchForms, commandStrings); 287 } 288 catch(...) 289 { 290 PrintHelpAndExit(); 291 } 292 293 if (parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs) 294 { 295 PrintHelp(); 296 return 0; 297 } 298 const UStringVector &nonSwitchStrings = parser.NonSwitchStrings; 299 300 int numNonSwitchStrings = nonSwitchStrings.Size(); 301 302 CArchiveCommand command; 303 if (numNonSwitchStrings == 0) 304 command.CommandType = NCommandType::kFullExtract; 305 else 306 { 307 if (numNonSwitchStrings > 1) 308 PrintHelpAndExit(); 309 if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], command)) 310 PrintHelpAndExit(); 311 } 312 313 314 NRecursedType::EEnum recursedType; 315 recursedType = command.DefaultRecursedType(); 316 317 NWildcard::CCensor wildcardCensor; 318 319 bool thereAreSwitchIncludeWildcards; 320 thereAreSwitchIncludeWildcards = false; 321 322 AddToCensorFromNonSwitchesStrings(wildcardCensor, nonSwitchStrings, recursedType, 323 thereAreSwitchIncludeWildcards); 324 325 bool yesToAll = parser[NKey::kYes].ThereIs; 326 327 // NExtractMode::EEnum extractMode; 328 // bool isExtractGroupCommand = command.IsFromExtractGroup(extractMode); 329 330 bool passwordEnabled = parser[NKey::kPassword].ThereIs; 331 332 UString password; 333 if (passwordEnabled) 334 password = parser[NKey::kPassword].PostStrings[0]; 335 336 if (!NFind::DoesFileExist(arcPath)) 337 throw kCantFindSFX; 338 339 FString outputDir; 340 if (parser[NKey::kOutputDir].ThereIs) 341 { 342 outputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]); 343 NName::NormalizeDirPathPrefix(outputDir); 344 } 345 346 347 wildcardCensor.AddPathsToCensor(NWildcard::k_RelatPath); 348 349 { 350 UStringVector v1, v2; 351 v1.Add(fs2us(arcPath)); 352 v2.Add(fs2us(arcPath)); 353 const NWildcard::CCensorNode &wildcardCensorHead = 354 wildcardCensor.Pairs.Front().Head; 355 356 CCodecs *codecs = new CCodecs; 357 CMyComPtr< 358 #ifdef EXTERNAL_CODECS 359 ICompressCodecsInfo 360 #else 361 IUnknown 362 #endif 363 > compressCodecsInfo = codecs; 364 HRESULT result = codecs->Load(); 365 if (result != S_OK) 366 throw CSystemException(result); 367 368 if (command.CommandType != NCommandType::kList) 369 { 370 CExtractCallbackConsole *ecs = new CExtractCallbackConsole; 371 CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs; 372 ecs->OutStream = g_StdStream; 373 374 #ifndef _NO_CRYPTO 375 ecs->PasswordIsDefined = passwordEnabled; 376 ecs->Password = password; 377 #endif 378 379 ecs->Init(); 380 381 COpenCallbackConsole openCallback; 382 openCallback.OutStream = g_StdStream; 383 384 #ifndef _NO_CRYPTO 385 openCallback.PasswordIsDefined = passwordEnabled; 386 openCallback.Password = password; 387 #endif 388 389 CExtractOptions eo; 390 eo.StdOutMode = false; 391 eo.YesToAll = yesToAll; 392 eo.TestMode = command.CommandType == NCommandType::kTest; 393 eo.PathMode = NExtract::NPathMode::kFullPaths; 394 eo.OverwriteMode = yesToAll ? 395 NExtract::NOverwriteMode::kOverwrite : 396 NExtract::NOverwriteMode::kAsk; 397 eo.OutputDir = outputDir; 398 399 UString errorMessage; 400 CDecompressStat stat; 401 HRESULT result = Extract( 402 codecs, CObjectVector<COpenType>(), CIntVector(), 403 v1, v2, 404 wildcardCensorHead, 405 eo, &openCallback, ecs, 406 // NULL, // hash 407 errorMessage, stat); 408 if (!errorMessage.IsEmpty()) 409 { 410 (*g_StdStream) << endl << "Error: " << errorMessage;; 411 if (result == S_OK) 412 result = E_FAIL; 413 } 414 415 if (ecs->NumArcsWithError != 0 || ecs->NumFileErrors != 0) 416 { 417 if (ecs->NumArcsWithError != 0) 418 (*g_StdStream) << endl << "Archive Errors" << endl; 419 if (ecs->NumFileErrors != 0) 420 (*g_StdStream) << endl << "Sub items Errors: " << ecs->NumFileErrors << endl; 421 return NExitCode::kFatalError; 422 } 423 if (result != S_OK) 424 throw CSystemException(result); 425 } 426 else 427 { 428 UInt64 numErrors = 0; 429 UInt64 numWarnings = 0; 430 HRESULT result = ListArchives( 431 codecs, CObjectVector<COpenType>(), CIntVector(), 432 false, // stdInMode 433 v1, v2, 434 true, // processAltStreams 435 false, // showAltStreams 436 wildcardCensorHead, 437 true, // enableHeaders 438 false, // techMode 439 #ifndef _NO_CRYPTO 440 passwordEnabled, password, 441 #endif 442 numErrors, numWarnings); 443 if (numErrors > 0) 444 { 445 g_StdOut << endl << "Errors: " << numErrors; 446 return NExitCode::kFatalError; 447 } 448 if (result != S_OK) 449 throw CSystemException(result); 450 } 451 } 452 return 0; 453 } 454