| OLD | NEW |
| (Empty) |
| 1 // ArchiveCommandLine.cpp | |
| 2 | |
| 3 #include "StdAfx.h" | |
| 4 | |
| 5 #ifdef _WIN32 | |
| 6 #include <io.h> | |
| 7 #endif | |
| 8 #include <stdio.h> | |
| 9 | |
| 10 #include "Common/ListFileUtils.h" | |
| 11 #include "Common/StringConvert.h" | |
| 12 #include "Common/StringToInt.h" | |
| 13 | |
| 14 #include "Windows/FileName.h" | |
| 15 #include "Windows/FileDir.h" | |
| 16 #ifdef _WIN32 | |
| 17 #include "Windows/FileMapping.h" | |
| 18 #include "Windows/Synchronization.h" | |
| 19 #endif | |
| 20 | |
| 21 #include "ArchiveCommandLine.h" | |
| 22 #include "UpdateAction.h" | |
| 23 #include "Update.h" | |
| 24 #include "SortUtils.h" | |
| 25 #include "EnumDirItems.h" | |
| 26 | |
| 27 extern bool g_CaseSensitive; | |
| 28 | |
| 29 #if _MSC_VER >= 1400 | |
| 30 #define MY_isatty_fileno(x) _isatty(_fileno(x)) | |
| 31 #else | |
| 32 #define MY_isatty_fileno(x) isatty(fileno(x)) | |
| 33 #endif | |
| 34 | |
| 35 #define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0); | |
| 36 | |
| 37 using namespace NCommandLineParser; | |
| 38 using namespace NWindows; | |
| 39 using namespace NFile; | |
| 40 | |
| 41 namespace NKey { | |
| 42 enum Enum | |
| 43 { | |
| 44 kHelp1 = 0, | |
| 45 kHelp2, | |
| 46 kHelp3, | |
| 47 kDisableHeaders, | |
| 48 kDisablePercents, | |
| 49 kArchiveType, | |
| 50 kYes, | |
| 51 #ifndef _NO_CRYPTO | |
| 52 kPassword, | |
| 53 #endif | |
| 54 kProperty, | |
| 55 kOutputDir, | |
| 56 kWorkingDir, | |
| 57 kInclude, | |
| 58 kExclude, | |
| 59 kArInclude, | |
| 60 kArExclude, | |
| 61 kNoArName, | |
| 62 kUpdate, | |
| 63 kVolume, | |
| 64 kRecursed, | |
| 65 kSfx, | |
| 66 kStdIn, | |
| 67 kStdOut, | |
| 68 kOverwrite, | |
| 69 kEmail, | |
| 70 kShowDialog, | |
| 71 kLargePages, | |
| 72 kCharSet, | |
| 73 kTechMode, | |
| 74 kShareForWrite, | |
| 75 kCaseSensitive | |
| 76 }; | |
| 77 | |
| 78 } | |
| 79 | |
| 80 | |
| 81 static const wchar_t kRecursedIDChar = 'R'; | |
| 82 static const wchar_t *kRecursedPostCharSet = L"0-"; | |
| 83 | |
| 84 namespace NRecursedPostCharIndex { | |
| 85 enum EEnum | |
| 86 { | |
| 87 kWildCardRecursionOnly = 0, | |
| 88 kNoRecursion = 1 | |
| 89 }; | |
| 90 } | |
| 91 | |
| 92 static const char kImmediateNameID = '!'; | |
| 93 static const char kMapNameID = '#'; | |
| 94 static const char kFileListID = '@'; | |
| 95 | |
| 96 static const char kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must
be | |
| 97 static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!
><N>ame must be | |
| 98 | |
| 99 static const wchar_t *kOverwritePostCharSet = L"asut"; | |
| 100 | |
| 101 NExtract::NOverwriteMode::EEnum k_OverwriteModes[] = | |
| 102 { | |
| 103 NExtract::NOverwriteMode::kWithoutPrompt, | |
| 104 NExtract::NOverwriteMode::kSkipExisting, | |
| 105 NExtract::NOverwriteMode::kAutoRename, | |
| 106 NExtract::NOverwriteMode::kAutoRenameExisting | |
| 107 }; | |
| 108 | |
| 109 static const CSwitchForm kSwitchForms[] = | |
| 110 { | |
| 111 { L"?", NSwitchType::kSimple, false }, | |
| 112 { L"H", NSwitchType::kSimple, false }, | |
| 113 { L"-HELP", NSwitchType::kSimple, false }, | |
| 114 { L"BA", NSwitchType::kSimple, false }, | |
| 115 { L"BD", NSwitchType::kSimple, false }, | |
| 116 { L"T", NSwitchType::kUnLimitedPostString, false, 1 }, | |
| 117 { L"Y", NSwitchType::kSimple, false }, | |
| 118 #ifndef _NO_CRYPTO | |
| 119 { L"P", NSwitchType::kUnLimitedPostString, false, 0 }, | |
| 120 #endif | |
| 121 { L"M", NSwitchType::kUnLimitedPostString, true, 1 }, | |
| 122 { L"O", NSwitchType::kUnLimitedPostString, false, 1 }, | |
| 123 { L"W", NSwitchType::kUnLimitedPostString, false, 0 }, | |
| 124 { L"I", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSiz
e}, | |
| 125 { L"X", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSiz
e}, | |
| 126 { L"AI", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSiz
e}, | |
| 127 { L"AX", NSwitchType::kUnLimitedPostString, true, kSomeCludePostStringMinSiz
e}, | |
| 128 { L"AN", NSwitchType::kSimple, false }, | |
| 129 { L"U", NSwitchType::kUnLimitedPostString, true, 1}, | |
| 130 { L"V", NSwitchType::kUnLimitedPostString, true, 1}, | |
| 131 { L"R", NSwitchType::kPostChar, false, 0, 0, kRecursedPostCharSet }, | |
| 132 { L"SFX", NSwitchType::kUnLimitedPostString, false, 0 }, | |
| 133 { L"SI", NSwitchType::kUnLimitedPostString, false, 0 }, | |
| 134 { L"SO", NSwitchType::kSimple, false, 0 }, | |
| 135 { L"AO", NSwitchType::kPostChar, false, 1, 1, kOverwritePostCharSet}, | |
| 136 { L"SEML", NSwitchType::kUnLimitedPostString, false, 0}, | |
| 137 { L"AD", NSwitchType::kSimple, false }, | |
| 138 { L"SLP", NSwitchType::kUnLimitedPostString, false, 0}, | |
| 139 { L"SCS", NSwitchType::kUnLimitedPostString, false, 0}, | |
| 140 { L"SLT", NSwitchType::kSimple, false }, | |
| 141 { L"SSW", NSwitchType::kSimple, false }, | |
| 142 { L"SSC", NSwitchType::kPostChar, false, 0, 0, L"-" } | |
| 143 }; | |
| 144 | |
| 145 static const CCommandForm g_CommandForms[] = | |
| 146 { | |
| 147 { L"A", false }, | |
| 148 { L"U", false }, | |
| 149 { L"D", false }, | |
| 150 { L"T", false }, | |
| 151 { L"E", false }, | |
| 152 { L"X", false }, | |
| 153 { L"L", false }, | |
| 154 { L"B", false }, | |
| 155 { L"I", false } | |
| 156 }; | |
| 157 | |
| 158 static const int kNumCommandForms = sizeof(g_CommandForms) / sizeof(g_CommandFo
rms[0]); | |
| 159 | |
| 160 static const wchar_t *kUniversalWildcard = L"*"; | |
| 161 static const int kMinNonSwitchWords = 1; | |
| 162 static const int kCommandIndex = 0; | |
| 163 | |
| 164 // --------------------------- | |
| 165 // exception messages | |
| 166 | |
| 167 static const char *kUserErrorMessage = "Incorrect command line"; | |
| 168 static const char *kIncorrectListFile = "Incorrect item in listfile.\nCheck char
set encoding and -scs switch."; | |
| 169 static const char *kIncorrectWildCardInListFile = "Incorrect wildcard in listfil
e"; | |
| 170 static const char *kIncorrectWildCardInCommandLine = "Incorrect wildcard in com
mand line"; | |
| 171 static const char *kTerminalOutError = "I won't write compressed data to a termi
nal"; | |
| 172 static const char *kSameTerminalError = "I won't write data and program's messag
es to same terminal"; | |
| 173 | |
| 174 static void ThrowException(const char *errorMessage) | |
| 175 { | |
| 176 throw CArchiveCommandLineException(errorMessage); | |
| 177 }; | |
| 178 | |
| 179 static void ThrowUserErrorException() | |
| 180 { | |
| 181 ThrowException(kUserErrorMessage); | |
| 182 }; | |
| 183 | |
| 184 // --------------------------- | |
| 185 | |
| 186 bool CArchiveCommand::IsFromExtractGroup() const | |
| 187 { | |
| 188 switch(CommandType) | |
| 189 { | |
| 190 case NCommandType::kTest: | |
| 191 case NCommandType::kExtract: | |
| 192 case NCommandType::kFullExtract: | |
| 193 return true; | |
| 194 default: | |
| 195 return false; | |
| 196 } | |
| 197 } | |
| 198 | |
| 199 NExtract::NPathMode::EEnum CArchiveCommand::GetPathMode() const | |
| 200 { | |
| 201 switch(CommandType) | |
| 202 { | |
| 203 case NCommandType::kTest: | |
| 204 case NCommandType::kFullExtract: | |
| 205 return NExtract::NPathMode::kFullPathnames; | |
| 206 default: | |
| 207 return NExtract::NPathMode::kNoPathnames; | |
| 208 } | |
| 209 } | |
| 210 | |
| 211 bool CArchiveCommand::IsFromUpdateGroup() const | |
| 212 { | |
| 213 return (CommandType == NCommandType::kAdd || | |
| 214 CommandType == NCommandType::kUpdate || | |
| 215 CommandType == NCommandType::kDelete); | |
| 216 } | |
| 217 | |
| 218 static NRecursedType::EEnum GetRecursedTypeFromIndex(int index) | |
| 219 { | |
| 220 switch (index) | |
| 221 { | |
| 222 case NRecursedPostCharIndex::kWildCardRecursionOnly: | |
| 223 return NRecursedType::kWildCardOnlyRecursed; | |
| 224 case NRecursedPostCharIndex::kNoRecursion: | |
| 225 return NRecursedType::kNonRecursed; | |
| 226 default: | |
| 227 return NRecursedType::kRecursed; | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 static bool ParseArchiveCommand(const UString &commandString, CArchiveCommand &c
ommand) | |
| 232 { | |
| 233 UString commandStringUpper = commandString; | |
| 234 commandStringUpper.MakeUpper(); | |
| 235 UString postString; | |
| 236 int commandIndex = ParseCommand(kNumCommandForms, g_CommandForms, commandStrin
gUpper, | |
| 237 postString) ; | |
| 238 if (commandIndex < 0) | |
| 239 return false; | |
| 240 command.CommandType = (NCommandType::EEnum)commandIndex; | |
| 241 return true; | |
| 242 } | |
| 243 | |
| 244 // ------------------------------------------------------------------ | |
| 245 // filenames functions | |
| 246 | |
| 247 static bool AddNameToCensor(NWildcard::CCensor &wildcardCensor, | |
| 248 const UString &name, bool include, NRecursedType::EEnum type) | |
| 249 { | |
| 250 bool isWildCard = DoesNameContainWildCard(name); | |
| 251 bool recursed = false; | |
| 252 | |
| 253 switch (type) | |
| 254 { | |
| 255 case NRecursedType::kWildCardOnlyRecursed: | |
| 256 recursed = isWildCard; | |
| 257 break; | |
| 258 case NRecursedType::kRecursed: | |
| 259 recursed = true; | |
| 260 break; | |
| 261 case NRecursedType::kNonRecursed: | |
| 262 recursed = false; | |
| 263 break; | |
| 264 } | |
| 265 wildcardCensor.AddItem(include, name, recursed); | |
| 266 return true; | |
| 267 } | |
| 268 | |
| 269 static void AddToCensorFromListFile(NWildcard::CCensor &wildcardCensor, | |
| 270 LPCWSTR fileName, bool include, NRecursedType::EEnum type, UINT codePage) | |
| 271 { | |
| 272 UStringVector names; | |
| 273 if (!ReadNamesFromListFile(fileName, names, codePage)) | |
| 274 throw kIncorrectListFile; | |
| 275 for (int i = 0; i < names.Size(); i++) | |
| 276 if (!AddNameToCensor(wildcardCensor, names[i], include, type)) | |
| 277 throw kIncorrectWildCardInListFile; | |
| 278 } | |
| 279 | |
| 280 static void AddCommandLineWildCardToCensr(NWildcard::CCensor &wildcardCensor, | |
| 281 const UString &name, bool include, NRecursedType::EEnum recursedType) | |
| 282 { | |
| 283 if (!AddNameToCensor(wildcardCensor, name, include, recursedType)) | |
| 284 throw kIncorrectWildCardInCommandLine; | |
| 285 } | |
| 286 | |
| 287 static void AddToCensorFromNonSwitchesStrings( | |
| 288 int startIndex, | |
| 289 NWildcard::CCensor &wildcardCensor, | |
| 290 const UStringVector &nonSwitchStrings, NRecursedType::EEnum type, | |
| 291 bool thereAreSwitchIncludes, UINT codePage) | |
| 292 { | |
| 293 if (nonSwitchStrings.Size() == startIndex && (!thereAreSwitchIncludes)) | |
| 294 AddCommandLineWildCardToCensr(wildcardCensor, kUniversalWildcard, true, type
); | |
| 295 for (int i = startIndex; i < nonSwitchStrings.Size(); i++) | |
| 296 { | |
| 297 const UString &s = nonSwitchStrings[i]; | |
| 298 if (s[0] == kFileListID) | |
| 299 AddToCensorFromListFile(wildcardCensor, s.Mid(1), true, type, codePage); | |
| 300 else | |
| 301 AddCommandLineWildCardToCensr(wildcardCensor, s, true, type); | |
| 302 } | |
| 303 } | |
| 304 | |
| 305 #ifdef _WIN32 | |
| 306 static void ParseMapWithPaths(NWildcard::CCensor &wildcardCensor, | |
| 307 const UString &switchParam, bool include, | |
| 308 NRecursedType::EEnum commonRecursedType) | |
| 309 { | |
| 310 int splitPos = switchParam.Find(L':'); | |
| 311 if (splitPos < 0) | |
| 312 ThrowUserErrorException(); | |
| 313 UString mappingName = switchParam.Left(splitPos); | |
| 314 | |
| 315 UString switchParam2 = switchParam.Mid(splitPos + 1); | |
| 316 splitPos = switchParam2.Find(L':'); | |
| 317 if (splitPos < 0) | |
| 318 ThrowUserErrorException(); | |
| 319 | |
| 320 UString mappingSize = switchParam2.Left(splitPos); | |
| 321 UString eventName = switchParam2.Mid(splitPos + 1); | |
| 322 | |
| 323 UInt64 dataSize64 = ConvertStringToUInt64(mappingSize, NULL); | |
| 324 UInt32 dataSize = (UInt32)dataSize64; | |
| 325 { | |
| 326 CFileMapping fileMapping; | |
| 327 if (!fileMapping.Open(FILE_MAP_READ, false, GetSystemString(mappingName))) | |
| 328 ThrowException("Can not open mapping"); | |
| 329 LPVOID data = fileMapping.MapViewOfFile(FILE_MAP_READ, 0, dataSize); | |
| 330 if (data == NULL) | |
| 331 ThrowException("MapViewOfFile error"); | |
| 332 try | |
| 333 { | |
| 334 const wchar_t *curData = (const wchar_t *)data; | |
| 335 if (*curData != 0) | |
| 336 ThrowException("Incorrect mapping data"); | |
| 337 UInt32 numChars = dataSize / sizeof(wchar_t); | |
| 338 UString name; | |
| 339 for (UInt32 i = 1; i < numChars; i++) | |
| 340 { | |
| 341 wchar_t c = curData[i]; | |
| 342 if (c == L'\0') | |
| 343 { | |
| 344 AddCommandLineWildCardToCensr(wildcardCensor, | |
| 345 name, include, commonRecursedType); | |
| 346 name.Empty(); | |
| 347 } | |
| 348 else | |
| 349 name += c; | |
| 350 } | |
| 351 if (!name.IsEmpty()) | |
| 352 ThrowException("data error"); | |
| 353 } | |
| 354 catch(...) | |
| 355 { | |
| 356 UnmapViewOfFile(data); | |
| 357 throw; | |
| 358 } | |
| 359 UnmapViewOfFile(data); | |
| 360 } | |
| 361 | |
| 362 { | |
| 363 NSynchronization::CManualResetEvent event; | |
| 364 if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(eventName)) == S_O
K) | |
| 365 event.Set(); | |
| 366 } | |
| 367 } | |
| 368 #endif | |
| 369 | |
| 370 static void AddSwitchWildCardsToCensor(NWildcard::CCensor &wildcardCensor, | |
| 371 const UStringVector &strings, bool include, | |
| 372 NRecursedType::EEnum commonRecursedType, UINT codePage) | |
| 373 { | |
| 374 for (int i = 0; i < strings.Size(); i++) | |
| 375 { | |
| 376 const UString &name = strings[i]; | |
| 377 NRecursedType::EEnum recursedType; | |
| 378 int pos = 0; | |
| 379 if (name.Length() < kSomeCludePostStringMinSize) | |
| 380 ThrowUserErrorException(); | |
| 381 if (::MyCharUpper(name[pos]) == kRecursedIDChar) | |
| 382 { | |
| 383 pos++; | |
| 384 int index = UString(kRecursedPostCharSet).Find(name[pos]); | |
| 385 recursedType = GetRecursedTypeFromIndex(index); | |
| 386 if (index >= 0) | |
| 387 pos++; | |
| 388 } | |
| 389 else | |
| 390 recursedType = commonRecursedType; | |
| 391 if (name.Length() < pos + kSomeCludeAfterRecursedPostStringMinSize) | |
| 392 ThrowUserErrorException(); | |
| 393 UString tail = name.Mid(pos + 1); | |
| 394 if (name[pos] == kImmediateNameID) | |
| 395 AddCommandLineWildCardToCensr(wildcardCensor, tail, include, recursedType)
; | |
| 396 else if (name[pos] == kFileListID) | |
| 397 AddToCensorFromListFile(wildcardCensor, tail, include, recursedType, codeP
age); | |
| 398 #ifdef _WIN32 | |
| 399 else if (name[pos] == kMapNameID) | |
| 400 ParseMapWithPaths(wildcardCensor, tail, include, recursedType); | |
| 401 #endif | |
| 402 else | |
| 403 ThrowUserErrorException(); | |
| 404 } | |
| 405 } | |
| 406 | |
| 407 #ifdef _WIN32 | |
| 408 | |
| 409 // This code converts all short file names to long file names. | |
| 410 | |
| 411 static void ConvertToLongName(const UString &prefix, UString &name) | |
| 412 { | |
| 413 if (name.IsEmpty() || DoesNameContainWildCard(name)) | |
| 414 return; | |
| 415 NFind::CFileInfoW fileInfo; | |
| 416 if (NFind::FindFile(prefix + name, fileInfo)) | |
| 417 name = fileInfo.Name; | |
| 418 } | |
| 419 | |
| 420 static void ConvertToLongNames(const UString &prefix, CObjectVector<NWildcard::C
Item> &items) | |
| 421 { | |
| 422 for (int i = 0; i < items.Size(); i++) | |
| 423 { | |
| 424 NWildcard::CItem &item = items[i]; | |
| 425 if (item.Recursive || item.PathParts.Size() != 1) | |
| 426 continue; | |
| 427 ConvertToLongName(prefix, item.PathParts.Front()); | |
| 428 } | |
| 429 } | |
| 430 | |
| 431 static void ConvertToLongNames(const UString &prefix, NWildcard::CCensorNode &no
de) | |
| 432 { | |
| 433 ConvertToLongNames(prefix, node.IncludeItems); | |
| 434 ConvertToLongNames(prefix, node.ExcludeItems); | |
| 435 int i; | |
| 436 for (i = 0; i < node.SubNodes.Size(); i++) | |
| 437 ConvertToLongName(prefix, node.SubNodes[i].Name); | |
| 438 // mix folders with same name | |
| 439 for (i = 0; i < node.SubNodes.Size(); i++) | |
| 440 { | |
| 441 NWildcard::CCensorNode &nextNode1 = node.SubNodes[i]; | |
| 442 for (int j = i + 1; j < node.SubNodes.Size();) | |
| 443 { | |
| 444 const NWildcard::CCensorNode &nextNode2 = node.SubNodes[j]; | |
| 445 if (nextNode1.Name.CompareNoCase(nextNode2.Name) == 0) | |
| 446 { | |
| 447 nextNode1.IncludeItems += nextNode2.IncludeItems; | |
| 448 nextNode1.ExcludeItems += nextNode2.ExcludeItems; | |
| 449 node.SubNodes.Delete(j); | |
| 450 } | |
| 451 else | |
| 452 j++; | |
| 453 } | |
| 454 } | |
| 455 for (i = 0; i < node.SubNodes.Size(); i++) | |
| 456 { | |
| 457 NWildcard::CCensorNode &nextNode = node.SubNodes[i]; | |
| 458 ConvertToLongNames(prefix + nextNode.Name + wchar_t(NFile::NName::kDirDelimi
ter), nextNode); | |
| 459 } | |
| 460 } | |
| 461 | |
| 462 static void ConvertToLongNames(NWildcard::CCensor &censor) | |
| 463 { | |
| 464 for (int i = 0; i < censor.Pairs.Size(); i++) | |
| 465 { | |
| 466 NWildcard::CPair &pair = censor.Pairs[i]; | |
| 467 ConvertToLongNames(pair.Prefix, pair.Head); | |
| 468 } | |
| 469 } | |
| 470 | |
| 471 #endif | |
| 472 | |
| 473 static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i) | |
| 474 { | |
| 475 switch(i) | |
| 476 { | |
| 477 case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairActio
n::kIgnore; | |
| 478 case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction:
:kCopy; | |
| 479 case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAct
ion::kCompress; | |
| 480 case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NP
airAction::kCompressAsAnti; | |
| 481 } | |
| 482 throw 98111603; | |
| 483 } | |
| 484 | |
| 485 const UString kUpdatePairStateIDSet = L"PQRXYZW"; | |
| 486 const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1}; | |
| 487 | |
| 488 const UString kUpdatePairActionIDSet = L"0123"; //Ignore, Copy, Compress, Create
Anti | |
| 489 | |
| 490 const wchar_t *kUpdateIgnoreItselfPostStringID = L"-"; | |
| 491 const wchar_t kUpdateNewArchivePostCharID = '!'; | |
| 492 | |
| 493 | |
| 494 static bool ParseUpdateCommandString2(const UString &command, | |
| 495 NUpdateArchive::CActionSet &actionSet, UString &postString) | |
| 496 { | |
| 497 for (int i = 0; i < command.Length();) | |
| 498 { | |
| 499 wchar_t c = MyCharUpper(command[i]); | |
| 500 int statePos = kUpdatePairStateIDSet.Find(c); | |
| 501 if (statePos < 0) | |
| 502 { | |
| 503 postString = command.Mid(i); | |
| 504 return true; | |
| 505 } | |
| 506 i++; | |
| 507 if (i >= command.Length()) | |
| 508 return false; | |
| 509 int actionPos = kUpdatePairActionIDSet.Find(::MyCharUpper(command[i])); | |
| 510 if (actionPos < 0) | |
| 511 return false; | |
| 512 actionSet.StateActions[statePos] = GetUpdatePairActionType(actionPos); | |
| 513 if (kUpdatePairStateNotSupportedActions[statePos] == actionPos) | |
| 514 return false; | |
| 515 i++; | |
| 516 } | |
| 517 postString.Empty(); | |
| 518 return true; | |
| 519 } | |
| 520 | |
| 521 static void ParseUpdateCommandString(CUpdateOptions &options, | |
| 522 const UStringVector &updatePostStrings, | |
| 523 const NUpdateArchive::CActionSet &defaultActionSet) | |
| 524 { | |
| 525 for (int i = 0; i < updatePostStrings.Size(); i++) | |
| 526 { | |
| 527 const UString &updateString = updatePostStrings[i]; | |
| 528 if (updateString.CompareNoCase(kUpdateIgnoreItselfPostStringID) == 0) | |
| 529 { | |
| 530 if (options.UpdateArchiveItself) | |
| 531 { | |
| 532 options.UpdateArchiveItself = false; | |
| 533 options.Commands.Delete(0); | |
| 534 } | |
| 535 } | |
| 536 else | |
| 537 { | |
| 538 NUpdateArchive::CActionSet actionSet = defaultActionSet; | |
| 539 | |
| 540 UString postString; | |
| 541 if (!ParseUpdateCommandString2(updateString, actionSet, postString)) | |
| 542 ThrowUserErrorException(); | |
| 543 if (postString.IsEmpty()) | |
| 544 { | |
| 545 if (options.UpdateArchiveItself) | |
| 546 options.Commands[0].ActionSet = actionSet; | |
| 547 } | |
| 548 else | |
| 549 { | |
| 550 if (MyCharUpper(postString[0]) != kUpdateNewArchivePostCharID) | |
| 551 ThrowUserErrorException(); | |
| 552 CUpdateArchiveCommand uc; | |
| 553 UString archivePath = postString.Mid(1); | |
| 554 if (archivePath.IsEmpty()) | |
| 555 ThrowUserErrorException(); | |
| 556 uc.UserArchivePath = archivePath; | |
| 557 uc.ActionSet = actionSet; | |
| 558 options.Commands.Add(uc); | |
| 559 } | |
| 560 } | |
| 561 } | |
| 562 } | |
| 563 | |
| 564 static const char kByteSymbol = 'B'; | |
| 565 static const char kKiloSymbol = 'K'; | |
| 566 static const char kMegaSymbol = 'M'; | |
| 567 static const char kGigaSymbol = 'G'; | |
| 568 | |
| 569 static bool ParseComplexSize(const UString &src, UInt64 &result) | |
| 570 { | |
| 571 UString s = src; | |
| 572 s.MakeUpper(); | |
| 573 | |
| 574 const wchar_t *start = s; | |
| 575 const wchar_t *end; | |
| 576 UInt64 number = ConvertStringToUInt64(start, &end); | |
| 577 int numDigits = (int)(end - start); | |
| 578 if (numDigits == 0 || s.Length() > numDigits + 1) | |
| 579 return false; | |
| 580 if (s.Length() == numDigits) | |
| 581 { | |
| 582 result = number; | |
| 583 return true; | |
| 584 } | |
| 585 int numBits; | |
| 586 switch (s[numDigits]) | |
| 587 { | |
| 588 case kByteSymbol: | |
| 589 result = number; | |
| 590 return true; | |
| 591 case kKiloSymbol: | |
| 592 numBits = 10; | |
| 593 break; | |
| 594 case kMegaSymbol: | |
| 595 numBits = 20; | |
| 596 break; | |
| 597 case kGigaSymbol: | |
| 598 numBits = 30; | |
| 599 break; | |
| 600 default: | |
| 601 return false; | |
| 602 } | |
| 603 if (number >= ((UInt64)1 << (64 - numBits))) | |
| 604 return false; | |
| 605 result = number << numBits; | |
| 606 return true; | |
| 607 } | |
| 608 | |
| 609 static void SetAddCommandOptions( | |
| 610 NCommandType::EEnum commandType, | |
| 611 const CParser &parser, | |
| 612 CUpdateOptions &options) | |
| 613 { | |
| 614 NUpdateArchive::CActionSet defaultActionSet; | |
| 615 switch(commandType) | |
| 616 { | |
| 617 case NCommandType::kAdd: | |
| 618 defaultActionSet = NUpdateArchive::kAddActionSet; | |
| 619 break; | |
| 620 case NCommandType::kDelete: | |
| 621 defaultActionSet = NUpdateArchive::kDeleteActionSet; | |
| 622 break; | |
| 623 default: | |
| 624 defaultActionSet = NUpdateArchive::kUpdateActionSet; | |
| 625 } | |
| 626 | |
| 627 options.UpdateArchiveItself = true; | |
| 628 | |
| 629 options.Commands.Clear(); | |
| 630 CUpdateArchiveCommand updateMainCommand; | |
| 631 updateMainCommand.ActionSet = defaultActionSet; | |
| 632 options.Commands.Add(updateMainCommand); | |
| 633 if (parser[NKey::kUpdate].ThereIs) | |
| 634 ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings, | |
| 635 defaultActionSet); | |
| 636 if (parser[NKey::kWorkingDir].ThereIs) | |
| 637 { | |
| 638 const UString &postString = parser[NKey::kWorkingDir].PostStrings[0]; | |
| 639 if (postString.IsEmpty()) | |
| 640 NDirectory::MyGetTempPath(options.WorkingDir); | |
| 641 else | |
| 642 options.WorkingDir = postString; | |
| 643 } | |
| 644 options.SfxMode = parser[NKey::kSfx].ThereIs; | |
| 645 if (options.SfxMode) | |
| 646 options.SfxModule = parser[NKey::kSfx].PostStrings[0]; | |
| 647 | |
| 648 if (parser[NKey::kVolume].ThereIs) | |
| 649 { | |
| 650 const UStringVector &sv = parser[NKey::kVolume].PostStrings; | |
| 651 for (int i = 0; i < sv.Size(); i++) | |
| 652 { | |
| 653 UInt64 size; | |
| 654 if (!ParseComplexSize(sv[i], size)) | |
| 655 ThrowException("Incorrect volume size"); | |
| 656 options.VolumesSizes.Add(size); | |
| 657 } | |
| 658 } | |
| 659 } | |
| 660 | |
| 661 static void SetMethodOptions(const CParser &parser, CObjectVector<CProperty> &pr
operties) | |
| 662 { | |
| 663 if (parser[NKey::kProperty].ThereIs) | |
| 664 { | |
| 665 // options.MethodMode.Properties.Clear(); | |
| 666 for (int i = 0; i < parser[NKey::kProperty].PostStrings.Size(); i++) | |
| 667 { | |
| 668 CProperty property; | |
| 669 const UString &postString = parser[NKey::kProperty].PostStrings[i]; | |
| 670 int index = postString.Find(L'='); | |
| 671 if (index < 0) | |
| 672 property.Name = postString; | |
| 673 else | |
| 674 { | |
| 675 property.Name = postString.Left(index); | |
| 676 property.Value = postString.Mid(index + 1); | |
| 677 } | |
| 678 properties.Add(property); | |
| 679 } | |
| 680 } | |
| 681 } | |
| 682 | |
| 683 CArchiveCommandLineParser::CArchiveCommandLineParser(): | |
| 684 parser(sizeof(kSwitchForms) / sizeof(kSwitchForms[0])) {} | |
| 685 | |
| 686 void CArchiveCommandLineParser::Parse1(const UStringVector &commandStrings, | |
| 687 CArchiveCommandLineOptions &options) | |
| 688 { | |
| 689 try | |
| 690 { | |
| 691 parser.ParseStrings(kSwitchForms, commandStrings); | |
| 692 } | |
| 693 catch(...) | |
| 694 { | |
| 695 ThrowUserErrorException(); | |
| 696 } | |
| 697 | |
| 698 options.IsInTerminal = MY_IS_TERMINAL(stdin); | |
| 699 options.IsStdOutTerminal = MY_IS_TERMINAL(stdout); | |
| 700 options.IsStdErrTerminal = MY_IS_TERMINAL(stderr); | |
| 701 options.StdOutMode = parser[NKey::kStdOut].ThereIs; | |
| 702 options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs; | |
| 703 options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereI
s || parser[NKey::kHelp3].ThereIs; | |
| 704 | |
| 705 #ifdef _WIN32 | |
| 706 options.LargePages = false; | |
| 707 if (parser[NKey::kLargePages].ThereIs) | |
| 708 { | |
| 709 const UString &postString = parser[NKey::kLargePages].PostStrings.Front(); | |
| 710 if (postString.IsEmpty()) | |
| 711 options.LargePages = true; | |
| 712 } | |
| 713 #endif | |
| 714 } | |
| 715 | |
| 716 struct CCodePagePair | |
| 717 { | |
| 718 const wchar_t *Name; | |
| 719 UINT CodePage; | |
| 720 }; | |
| 721 | |
| 722 static CCodePagePair g_CodePagePairs[] = | |
| 723 { | |
| 724 { L"UTF-8", CP_UTF8 }, | |
| 725 { L"WIN", CP_ACP }, | |
| 726 { L"DOS", CP_OEMCP } | |
| 727 }; | |
| 728 | |
| 729 static const int kNumCodePages = sizeof(g_CodePagePairs) / sizeof(g_CodePagePair
s[0]); | |
| 730 | |
| 731 static bool ConvertStringToUInt32(const wchar_t *s, UInt32 &v) | |
| 732 { | |
| 733 const wchar_t *end; | |
| 734 UInt64 number = ConvertStringToUInt64(s, &end); | |
| 735 if (*end != 0) | |
| 736 return false; | |
| 737 if (number > (UInt32)0xFFFFFFFF) | |
| 738 return false; | |
| 739 v = (UInt32)number; | |
| 740 return true; | |
| 741 } | |
| 742 | |
| 743 void CArchiveCommandLineParser::Parse2(CArchiveCommandLineOptions &options) | |
| 744 { | |
| 745 const UStringVector &nonSwitchStrings = parser.NonSwitchStrings; | |
| 746 int numNonSwitchStrings = nonSwitchStrings.Size(); | |
| 747 if (numNonSwitchStrings < kMinNonSwitchWords) | |
| 748 ThrowUserErrorException(); | |
| 749 | |
| 750 if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command)) | |
| 751 ThrowUserErrorException(); | |
| 752 | |
| 753 options.TechMode = parser[NKey::kTechMode].ThereIs; | |
| 754 | |
| 755 if (parser[NKey::kCaseSensitive].ThereIs) | |
| 756 g_CaseSensitive = (parser[NKey::kCaseSensitive].PostCharIndex < 0); | |
| 757 | |
| 758 NRecursedType::EEnum recursedType; | |
| 759 if (parser[NKey::kRecursed].ThereIs) | |
| 760 recursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharInde
x); | |
| 761 else | |
| 762 recursedType = NRecursedType::kNonRecursed; | |
| 763 | |
| 764 UINT codePage = CP_UTF8; | |
| 765 if (parser[NKey::kCharSet].ThereIs) | |
| 766 { | |
| 767 UString name = parser[NKey::kCharSet].PostStrings.Front(); | |
| 768 name.MakeUpper(); | |
| 769 int i; | |
| 770 for (i = 0; i < kNumCodePages; i++) | |
| 771 { | |
| 772 const CCodePagePair &pair = g_CodePagePairs[i]; | |
| 773 if (name.Compare(pair.Name) == 0) | |
| 774 { | |
| 775 codePage = pair.CodePage; | |
| 776 break; | |
| 777 } | |
| 778 } | |
| 779 if (i >= kNumCodePages) | |
| 780 ThrowUserErrorException(); | |
| 781 } | |
| 782 | |
| 783 bool thereAreSwitchIncludes = false; | |
| 784 if (parser[NKey::kInclude].ThereIs) | |
| 785 { | |
| 786 thereAreSwitchIncludes = true; | |
| 787 AddSwitchWildCardsToCensor(options.WildcardCensor, | |
| 788 parser[NKey::kInclude].PostStrings, true, recursedType, codePage); | |
| 789 } | |
| 790 if (parser[NKey::kExclude].ThereIs) | |
| 791 AddSwitchWildCardsToCensor(options.WildcardCensor, | |
| 792 parser[NKey::kExclude].PostStrings, false, recursedType, codePage); | |
| 793 | |
| 794 int curCommandIndex = kCommandIndex + 1; | |
| 795 bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs && | |
| 796 options.Command.CommandType != NCommandType::kBenchmark && | |
| 797 options.Command.CommandType != NCommandType::kInfo; | |
| 798 if (thereIsArchiveName) | |
| 799 { | |
| 800 if (curCommandIndex >= numNonSwitchStrings) | |
| 801 ThrowUserErrorException(); | |
| 802 options.ArchiveName = nonSwitchStrings[curCommandIndex++]; | |
| 803 } | |
| 804 | |
| 805 AddToCensorFromNonSwitchesStrings( | |
| 806 curCommandIndex, options.WildcardCensor, | |
| 807 nonSwitchStrings, recursedType, thereAreSwitchIncludes, codePage); | |
| 808 | |
| 809 options.YesToAll = parser[NKey::kYes].ThereIs; | |
| 810 | |
| 811 bool isExtractGroupCommand = options.Command.IsFromExtractGroup(); | |
| 812 | |
| 813 #ifndef _NO_CRYPTO | |
| 814 options.PasswordEnabled = parser[NKey::kPassword].ThereIs; | |
| 815 if (options.PasswordEnabled) | |
| 816 options.Password = parser[NKey::kPassword].PostStrings[0]; | |
| 817 #endif | |
| 818 | |
| 819 options.StdInMode = parser[NKey::kStdIn].ThereIs; | |
| 820 options.ShowDialog = parser[NKey::kShowDialog].ThereIs; | |
| 821 | |
| 822 if (parser[NKey::kArchiveType].ThereIs) | |
| 823 options.ArcType = parser[NKey::kArchiveType].PostStrings[0]; | |
| 824 | |
| 825 if (isExtractGroupCommand || options.Command.CommandType == NCommandType::kLis
t) | |
| 826 { | |
| 827 if (options.StdInMode) | |
| 828 ThrowException("Reading archives from stdin is not implemented"); | |
| 829 if (!options.WildcardCensor.AllAreRelative()) | |
| 830 ThrowException("Cannot use absolute pathnames for this command"); | |
| 831 | |
| 832 NWildcard::CCensor archiveWildcardCensor; | |
| 833 | |
| 834 if (parser[NKey::kArInclude].ThereIs) | |
| 835 { | |
| 836 AddSwitchWildCardsToCensor(archiveWildcardCensor, | |
| 837 parser[NKey::kArInclude].PostStrings, true, NRecursedType::kNonRecursed,
codePage); | |
| 838 } | |
| 839 if (parser[NKey::kArExclude].ThereIs) | |
| 840 AddSwitchWildCardsToCensor(archiveWildcardCensor, | |
| 841 parser[NKey::kArExclude].PostStrings, false, NRecursedType::kNonRecursed,
codePage); | |
| 842 | |
| 843 if (thereIsArchiveName) | |
| 844 AddCommandLineWildCardToCensr(archiveWildcardCensor, options.ArchiveName,
true, NRecursedType::kNonRecursed); | |
| 845 | |
| 846 #ifdef _WIN32 | |
| 847 ConvertToLongNames(archiveWildcardCensor); | |
| 848 #endif | |
| 849 | |
| 850 archiveWildcardCensor.ExtendExclude(); | |
| 851 | |
| 852 UStringVector archivePaths; | |
| 853 | |
| 854 { | |
| 855 CDirItems dirItems; | |
| 856 { | |
| 857 UStringVector errorPaths; | |
| 858 CRecordVector<DWORD> errorCodes; | |
| 859 HRESULT res = EnumerateItems(archiveWildcardCensor, dirItems, NULL, erro
rPaths, errorCodes); | |
| 860 if (res != S_OK || errorPaths.Size() > 0) | |
| 861 throw "cannot find archive"; | |
| 862 } | |
| 863 for (int i = 0; i < dirItems.Items.Size(); i++) | |
| 864 { | |
| 865 const CDirItem &dirItem = dirItems.Items[i]; | |
| 866 if (!dirItem.IsDir()) | |
| 867 archivePaths.Add(dirItems.GetPhyPath(i)); | |
| 868 } | |
| 869 } | |
| 870 | |
| 871 if (archivePaths.Size() == 0) | |
| 872 throw "there is no such archive"; | |
| 873 | |
| 874 UStringVector archivePathsFull; | |
| 875 | |
| 876 int i; | |
| 877 for (i = 0; i < archivePaths.Size(); i++) | |
| 878 { | |
| 879 UString fullPath; | |
| 880 NFile::NDirectory::MyGetFullPathName(archivePaths[i], fullPath); | |
| 881 archivePathsFull.Add(fullPath); | |
| 882 } | |
| 883 CIntVector indices; | |
| 884 SortFileNames(archivePathsFull, indices); | |
| 885 options.ArchivePathsSorted.Reserve(indices.Size()); | |
| 886 options.ArchivePathsFullSorted.Reserve(indices.Size()); | |
| 887 for (i = 0; i < indices.Size(); i++) | |
| 888 { | |
| 889 options.ArchivePathsSorted.Add(archivePaths[indices[i]]); | |
| 890 options.ArchivePathsFullSorted.Add(archivePathsFull[indices[i]]); | |
| 891 } | |
| 892 | |
| 893 if (isExtractGroupCommand) | |
| 894 { | |
| 895 SetMethodOptions(parser, options.ExtractProperties); | |
| 896 if (options.StdOutMode && options.IsStdOutTerminal && options.IsStdErrTerm
inal) | |
| 897 throw kSameTerminalError; | |
| 898 if (parser[NKey::kOutputDir].ThereIs) | |
| 899 { | |
| 900 options.OutputDir = parser[NKey::kOutputDir].PostStrings[0]; | |
| 901 NFile::NName::NormalizeDirPathPrefix(options.OutputDir); | |
| 902 } | |
| 903 | |
| 904 options.OverwriteMode = NExtract::NOverwriteMode::kAskBefore; | |
| 905 if (parser[NKey::kOverwrite].ThereIs) | |
| 906 options.OverwriteMode = | |
| 907 k_OverwriteModes[parser[NKey::kOverwrite].PostCharIndex]; | |
| 908 else if (options.YesToAll) | |
| 909 options.OverwriteMode = NExtract::NOverwriteMode::kWithoutPrompt; | |
| 910 } | |
| 911 } | |
| 912 else if (options.Command.IsFromUpdateGroup()) | |
| 913 { | |
| 914 CUpdateOptions &updateOptions = options.UpdateOptions; | |
| 915 | |
| 916 SetAddCommandOptions(options.Command.CommandType, parser, updateOptions); | |
| 917 | |
| 918 SetMethodOptions(parser, updateOptions.MethodMode.Properties); | |
| 919 | |
| 920 if (parser[NKey::kShareForWrite].ThereIs) | |
| 921 updateOptions.OpenShareForWrite = true; | |
| 922 | |
| 923 options.EnablePercents = !parser[NKey::kDisablePercents].ThereIs; | |
| 924 | |
| 925 if (options.EnablePercents) | |
| 926 { | |
| 927 if ((options.StdOutMode && !options.IsStdErrTerminal) || | |
| 928 (!options.StdOutMode && !options.IsStdOutTerminal)) | |
| 929 options.EnablePercents = false; | |
| 930 } | |
| 931 | |
| 932 updateOptions.EMailMode = parser[NKey::kEmail].ThereIs; | |
| 933 if (updateOptions.EMailMode) | |
| 934 { | |
| 935 updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front(); | |
| 936 if (updateOptions.EMailAddress.Length() > 0) | |
| 937 if (updateOptions.EMailAddress[0] == L'.') | |
| 938 { | |
| 939 updateOptions.EMailRemoveAfter = true; | |
| 940 updateOptions.EMailAddress.Delete(0); | |
| 941 } | |
| 942 } | |
| 943 | |
| 944 updateOptions.StdOutMode = options.StdOutMode; | |
| 945 updateOptions.StdInMode = options.StdInMode; | |
| 946 | |
| 947 if (updateOptions.StdOutMode && updateOptions.EMailMode) | |
| 948 throw "stdout mode and email mode cannot be combined"; | |
| 949 if (updateOptions.StdOutMode && options.IsStdOutTerminal) | |
| 950 throw kTerminalOutError; | |
| 951 if (updateOptions.StdInMode) | |
| 952 updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front(); | |
| 953 | |
| 954 #ifdef _WIN32 | |
| 955 ConvertToLongNames(options.WildcardCensor); | |
| 956 #endif | |
| 957 } | |
| 958 else if (options.Command.CommandType == NCommandType::kBenchmark) | |
| 959 { | |
| 960 options.NumThreads = (UInt32)-1; | |
| 961 options.DictionarySize = (UInt32)-1; | |
| 962 options.NumIterations = 1; | |
| 963 if (curCommandIndex < numNonSwitchStrings) | |
| 964 { | |
| 965 if (!ConvertStringToUInt32(nonSwitchStrings[curCommandIndex++], options.Nu
mIterations)) | |
| 966 ThrowUserErrorException(); | |
| 967 } | |
| 968 for (int i = 0; i < parser[NKey::kProperty].PostStrings.Size(); i++) | |
| 969 { | |
| 970 UString postString = parser[NKey::kProperty].PostStrings[i]; | |
| 971 postString.MakeUpper(); | |
| 972 if (postString.Length() < 2) | |
| 973 ThrowUserErrorException(); | |
| 974 if (postString[0] == 'D') | |
| 975 { | |
| 976 int pos = 1; | |
| 977 if (postString[pos] == '=') | |
| 978 pos++; | |
| 979 UInt32 logSize; | |
| 980 if (!ConvertStringToUInt32((const wchar_t *)postString + pos, logSize)) | |
| 981 ThrowUserErrorException(); | |
| 982 if (logSize > 31) | |
| 983 ThrowUserErrorException(); | |
| 984 options.DictionarySize = 1 << logSize; | |
| 985 } | |
| 986 else if (postString[0] == 'M' && postString[1] == 'T' ) | |
| 987 { | |
| 988 int pos = 2; | |
| 989 if (postString[pos] == '=') | |
| 990 pos++; | |
| 991 if (postString[pos] != 0) | |
| 992 if (!ConvertStringToUInt32((const wchar_t *)postString + pos, options.
NumThreads)) | |
| 993 ThrowUserErrorException(); | |
| 994 } | |
| 995 else if (postString[0] == 'M' && postString[1] == '=' ) | |
| 996 { | |
| 997 int pos = 2; | |
| 998 if (postString[pos] != 0) | |
| 999 options.Method = postString.Mid(2); | |
| 1000 } | |
| 1001 else | |
| 1002 ThrowUserErrorException(); | |
| 1003 } | |
| 1004 } | |
| 1005 else if (options.Command.CommandType == NCommandType::kInfo) | |
| 1006 { | |
| 1007 } | |
| 1008 else | |
| 1009 ThrowUserErrorException(); | |
| 1010 options.WildcardCensor.ExtendExclude(); | |
| 1011 } | |
| OLD | NEW |