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 |