• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // ArchiveCommandLine.cpp
2 
3 #include "StdAfx.h"
4 #undef printf
5 #undef sprintf
6 
7 #ifdef _WIN32
8 #ifndef UNDER_CE
9 #include <io.h>
10 #endif
11 #else
12 // for isatty()
13 #include <unistd.h>
14 #endif
15 
16 #include <stdio.h>
17 
18 #ifdef _7ZIP_LARGE_PAGES
19 #include "../../../../C/Alloc.h"
20 #endif
21 
22 #include "../../../Common/IntToString.h"
23 #include "../../../Common/ListFileUtils.h"
24 #include "../../../Common/StringConvert.h"
25 #include "../../../Common/StringToInt.h"
26 
27 #include "../../../Windows/ErrorMsg.h"
28 #include "../../../Windows/FileDir.h"
29 #include "../../../Windows/FileName.h"
30 #include "../../../Windows/System.h"
31 #ifdef _WIN32
32 #include "../../../Windows/FileMapping.h"
33 #include "../../../Windows/MemoryLock.h"
34 #include "../../../Windows/Synchronization.h"
35 #endif
36 
37 #include "ArchiveCommandLine.h"
38 #include "EnumDirItems.h"
39 #include "Update.h"
40 #include "UpdateAction.h"
41 
42 extern bool g_CaseSensitive;
43 extern bool g_PathTrailReplaceMode;
44 
45 #ifdef _7ZIP_LARGE_PAGES
46 extern
47 bool g_LargePagesMode;
48 bool g_LargePagesMode = false;
49 #endif
50 
51 /*
52 #ifdef ENV_HAVE_LSTAT
53 EXTERN_C_BEGIN
54 extern int global_use_lstat;
55 EXTERN_C_END
56 #endif
57 */
58 
59 #ifdef UNDER_CE
60 
61 #define MY_IS_TERMINAL(x) false;
62 
63 #else
64 
65 // #define MY_isatty_fileno(x) (isatty(fileno(x)))
66 // #define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0);
MY_IS_TERMINAL(FILE * x)67 static inline bool MY_IS_TERMINAL(FILE *x)
68 {
69   return (
70     #if defined(_MSC_VER) && (_MSC_VER >= 1400)
71       _isatty(_fileno(x))
72     #else
73       isatty(fileno(x))
74     #endif
75       != 0);
76 }
77 
78 #endif
79 
80 using namespace NCommandLineParser;
81 using namespace NWindows;
82 using namespace NFile;
83 
StringToUInt32(const wchar_t * s,UInt32 & v)84 static bool StringToUInt32(const wchar_t *s, UInt32 &v)
85 {
86   if (*s == 0)
87     return false;
88   const wchar_t *end;
89   v = ConvertStringToUInt32(s, &end);
90   return *end == 0;
91 }
92 
93 
94 namespace NKey {
95 enum Enum
96 {
97   kHelp1 = 0,
98   kHelp2,
99   kHelp3,
100 
101   kDisableHeaders,
102   kDisablePercents,
103   kShowTime,
104   kLogLevel,
105 
106   kOutStream,
107   kErrStream,
108   kPercentStream,
109 
110   kYes,
111 
112   kShowDialog,
113   kOverwrite,
114 
115   kArchiveType,
116   kExcludedArcType,
117 
118   kProperty,
119   kOutputDir,
120   kWorkingDir,
121 
122   kInclude,
123   kExclude,
124   kArInclude,
125   kArExclude,
126   kNoArName,
127 
128   kUpdate,
129   kVolume,
130   kRecursed,
131 
132   kAffinity,
133   kSfx,
134   kEmail,
135   kHash,
136   // kHashGenFile,
137   kHashDir,
138 
139   kStdIn,
140   kStdOut,
141 
142   kLargePages,
143   kListfileCharSet,
144   kConsoleCharSet,
145   kTechMode,
146   kListFields,
147 
148   kPreserveATime,
149   kShareForWrite,
150   kStopAfterOpenError,
151   kCaseSensitive,
152   kArcNameMode,
153 
154   kUseSlashMark,
155   kDisableWildcardParsing,
156   kElimDup,
157   kFullPathMode,
158 
159   kHardLinks,
160   kSymLinks_AllowDangerous,
161   kSymLinks,
162   kNtSecurity,
163 
164   kStoreOwnerId,
165   kStoreOwnerName,
166 
167   kZoneFile,
168   kAltStreams,
169   kReplaceColonForAltStream,
170   kWriteToAltStreamIfColon,
171 
172   kNameTrailReplace,
173 
174   kDeleteAfterCompressing,
175   kSetArcMTime
176 
177   #ifndef _NO_CRYPTO
178   , kPassword
179   #endif
180 };
181 
182 }
183 
184 
185 static const wchar_t kRecursedIDChar = 'r';
186 static const char * const kRecursedPostCharSet = "0-";
187 
188 static const char * const k_ArcNameMode_PostCharSet = "sea";
189 
190 static const char * const k_Stream_PostCharSet = "012";
191 
ParseArcNameMode(int postCharIndex)192 static inline EArcNameMode ParseArcNameMode(int postCharIndex)
193 {
194   switch (postCharIndex)
195   {
196     case 1: return k_ArcNameMode_Exact;
197     case 2: return k_ArcNameMode_Add;
198     default: return k_ArcNameMode_Smart;
199   }
200 }
201 
202 namespace NRecursedPostCharIndex {
203   enum EEnum
204   {
205     kWildcardRecursionOnly = 0,
206     kNoRecursion = 1
207   };
208 }
209 
210 // static const char
211 #define kImmediateNameID '!'
212 #ifdef _WIN32
213 #define kMapNameID '#'
214 #endif
215 #define kFileListID '@'
216 
217 static const Byte kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be
218 static const Byte kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be
219 
220 static const char * const kOverwritePostCharSet = "asut";
221 
222 static const NExtract::NOverwriteMode::EEnum k_OverwriteModes[] =
223 {
224   NExtract::NOverwriteMode::kOverwrite,
225   NExtract::NOverwriteMode::kSkip,
226   NExtract::NOverwriteMode::kRename,
227   NExtract::NOverwriteMode::kRenameExisting
228 };
229 
230 
231 
232 #define SWFRM_3(t, mu, mi) t, mu, mi, NULL
233 
234 #define SWFRM_1(t) SWFRM_3(t, false, 0)
235 #define SWFRM_SIMPLE SWFRM_1(NSwitchType::kSimple)
236 #define SWFRM_MINUS  SWFRM_1(NSwitchType::kMinus)
237 #define SWFRM_STRING SWFRM_1(NSwitchType::kString)
238 
239 #define SWFRM_STRING_SINGL(mi) SWFRM_3(NSwitchType::kString, false, mi)
240 #define SWFRM_STRING_MULT(mi)  SWFRM_3(NSwitchType::kString, true, mi)
241 
242 
243 static const CSwitchForm kSwitchForms[] =
244 {
245   { "?", SWFRM_SIMPLE },
246   { "h", SWFRM_SIMPLE },
247   { "-help", SWFRM_SIMPLE },
248 
249   { "ba", SWFRM_SIMPLE },
250   { "bd", SWFRM_SIMPLE },
251   { "bt", SWFRM_SIMPLE },
252   { "bb", SWFRM_STRING_SINGL(0) },
253 
254   { "bso", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
255   { "bse", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
256   { "bsp", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
257 
258   { "y", SWFRM_SIMPLE },
259 
260   { "ad", SWFRM_SIMPLE },
261   { "ao", NSwitchType::kChar, false, 1, kOverwritePostCharSet},
262 
263   { "t",  SWFRM_STRING_SINGL(1) },
264   { "stx", SWFRM_STRING_MULT(1) },
265 
266   { "m",  SWFRM_STRING_MULT(1) },
267   { "o",  SWFRM_STRING_SINGL(1) },
268   { "w",  SWFRM_STRING },
269 
270   { "i",  SWFRM_STRING_MULT(kSomeCludePostStringMinSize) },
271   { "x",  SWFRM_STRING_MULT(kSomeCludePostStringMinSize) },
272   { "ai", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) },
273   { "ax", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) },
274   { "an", SWFRM_SIMPLE },
275 
276   { "u",  SWFRM_STRING_MULT(1) },
277   { "v",  SWFRM_STRING_MULT(1) },
278   { "r",  NSwitchType::kChar, false, 0, kRecursedPostCharSet },
279 
280   { "stm", SWFRM_STRING },
281   { "sfx", SWFRM_STRING },
282   { "seml", SWFRM_STRING_SINGL(0) },
283   { "scrc", SWFRM_STRING_MULT(0) },
284   // { "scrf", SWFRM_STRING_SINGL(1) },
285   { "shd", SWFRM_STRING_SINGL(1) },
286 
287   { "si", SWFRM_STRING },
288   { "so", SWFRM_SIMPLE },
289 
290   { "slp", SWFRM_STRING },
291   { "scs", SWFRM_STRING },
292   { "scc", SWFRM_STRING },
293   { "slt", SWFRM_SIMPLE },
294   { "slf", SWFRM_STRING_SINGL(1) },
295 
296   { "ssp", SWFRM_SIMPLE },
297   { "ssw", SWFRM_SIMPLE },
298   { "sse", SWFRM_SIMPLE },
299   { "ssc", SWFRM_MINUS },
300   { "sa",  NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet },
301 
302   { "spm", SWFRM_STRING_SINGL(0) },
303   { "spd", SWFRM_SIMPLE },
304   { "spe", SWFRM_MINUS },
305   { "spf", SWFRM_STRING_SINGL(0) },
306 
307   { "snh", SWFRM_MINUS },
308   { "snld", SWFRM_MINUS },
309   { "snl", SWFRM_MINUS },
310   { "sni", SWFRM_SIMPLE },
311 
312   { "snoi", SWFRM_MINUS },
313   { "snon", SWFRM_MINUS },
314 
315   { "snz", SWFRM_STRING_SINGL(0) },
316   { "sns", SWFRM_MINUS },
317   { "snr", SWFRM_SIMPLE },
318   { "snc", SWFRM_SIMPLE },
319 
320   { "snt", SWFRM_MINUS },
321 
322   { "sdel", SWFRM_SIMPLE },
323   { "stl", SWFRM_SIMPLE }
324 
325   #ifndef _NO_CRYPTO
326   , { "p", SWFRM_STRING }
327   #endif
328 };
329 
330 static const char * const kUniversalWildcard = "*";
331 static const unsigned kMinNonSwitchWords = 1;
332 static const unsigned kCommandIndex = 0;
333 
334 // static const char * const kUserErrorMessage  = "Incorrect command line";
335 // static const char * const kCannotFindListFile = "Cannot find listfile";
336 static const char * const kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch.";
337 static const char * const kTerminalOutError = "I won't write compressed data to a terminal";
338 static const char * const kSameTerminalError = "I won't write data and program's messages to same stream";
339 static const char * const kEmptyFilePath = "Empty file path";
340 
IsFromExtractGroup() const341 bool CArcCommand::IsFromExtractGroup() const
342 {
343   switch (CommandType)
344   {
345     case NCommandType::kTest:
346     case NCommandType::kExtract:
347     case NCommandType::kExtractFull:
348       return true;
349     default:
350       return false;
351   }
352 }
353 
GetPathMode() const354 NExtract::NPathMode::EEnum CArcCommand::GetPathMode() const
355 {
356   switch (CommandType)
357   {
358     case NCommandType::kTest:
359     case NCommandType::kExtractFull:
360       return NExtract::NPathMode::kFullPaths;
361     default:
362       return NExtract::NPathMode::kNoPaths;
363   }
364 }
365 
IsFromUpdateGroup() const366 bool CArcCommand::IsFromUpdateGroup() const
367 {
368   switch (CommandType)
369   {
370     case NCommandType::kAdd:
371     case NCommandType::kUpdate:
372     case NCommandType::kDelete:
373     case NCommandType::kRename:
374       return true;
375     default:
376       return false;
377   }
378 }
379 
GetRecursedTypeFromIndex(int index)380 static NRecursedType::EEnum GetRecursedTypeFromIndex(int index)
381 {
382   switch (index)
383   {
384     case NRecursedPostCharIndex::kWildcardRecursionOnly:
385       return NRecursedType::kWildcardOnlyRecursed;
386     case NRecursedPostCharIndex::kNoRecursion:
387       return NRecursedType::kNonRecursed;
388     default:
389       return NRecursedType::kRecursed;
390   }
391 }
392 
393 static const char *g_Commands = "audtexlbih";
394 
ParseArchiveCommand(const UString & commandString,CArcCommand & command)395 static bool ParseArchiveCommand(const UString &commandString, CArcCommand &command)
396 {
397   UString s (commandString);
398   s.MakeLower_Ascii();
399   if (s.Len() == 1)
400   {
401     if (s[0] > 0x7F)
402       return false;
403     int index = FindCharPosInString(g_Commands, (char)s[0]);
404     if (index < 0)
405       return false;
406     command.CommandType = (NCommandType::EEnum)index;
407     return true;
408   }
409   if (s.Len() == 2 && s[0] == 'r' && s[1] == 'n')
410   {
411     command.CommandType = (NCommandType::kRename);
412     return true;
413   }
414   return false;
415 }
416 
417 // ------------------------------------------------------------------
418 // filenames functions
419 
420 struct CNameOption
421 {
422   bool Include;
423   bool WildcardMatching;
424   Byte MarkMode;
425   NRecursedType::EEnum RecursedType;
426 
CNameOptionCNameOption427   CNameOption():
428       Include(true),
429       WildcardMatching(true),
430       MarkMode(NWildcard::kMark_FileOrDir),
431       RecursedType(NRecursedType::kNonRecursed)
432       {}
433 };
434 
435 
AddNameToCensor(NWildcard::CCensor & censor,const CNameOption & nop,const UString & name)436 static void AddNameToCensor(NWildcard::CCensor &censor,
437     const CNameOption &nop, const UString &name)
438 {
439   bool recursed = false;
440 
441   switch (nop.RecursedType)
442   {
443     case NRecursedType::kWildcardOnlyRecursed:
444       recursed = DoesNameContainWildcard(name);
445       break;
446     case NRecursedType::kRecursed:
447       recursed = true;
448       break;
449     default:
450       break;
451   }
452 
453   NWildcard::CCensorPathProps props;
454   props.Recursive = recursed;
455   props.WildcardMatching = nop.WildcardMatching;
456   props.MarkMode = nop.MarkMode;
457   censor.AddPreItem(nop.Include, name, props);
458 }
459 
AddRenamePair(CObjectVector<CRenamePair> * renamePairs,const UString & oldName,const UString & newName,NRecursedType::EEnum type,bool wildcardMatching)460 static void AddRenamePair(CObjectVector<CRenamePair> *renamePairs,
461     const UString &oldName, const UString &newName, NRecursedType::EEnum type,
462     bool wildcardMatching)
463 {
464   CRenamePair &pair = renamePairs->AddNew();
465   pair.OldName = oldName;
466   pair.NewName = newName;
467   pair.RecursedType = type;
468   pair.WildcardParsing = wildcardMatching;
469 
470   if (!pair.Prepare())
471   {
472     UString val;
473     val += pair.OldName;
474     val.Add_LF();
475     val += pair.NewName;
476     val.Add_LF();
477     if (type == NRecursedType::kRecursed)
478       val += "-r";
479     else if (type == NRecursedType::kWildcardOnlyRecursed)
480       val += "-r0";
481     throw CArcCmdLineException("Unsupported rename command:", val);
482   }
483 }
484 
AddToCensorFromListFile(CObjectVector<CRenamePair> * renamePairs,NWildcard::CCensor & censor,const CNameOption & nop,LPCWSTR fileName,UInt32 codePage)485 static void AddToCensorFromListFile(
486     CObjectVector<CRenamePair> *renamePairs,
487     NWildcard::CCensor &censor,
488     const CNameOption &nop, LPCWSTR fileName, UInt32 codePage)
489 {
490   UStringVector names;
491   /*
492   if (!NFind::DoesFileExist_FollowLink(us2fs(fileName)))
493     throw CArcCmdLineException(kCannotFindListFile, fileName);
494   */
495   DWORD lastError = 0;
496   if (!ReadNamesFromListFile2(us2fs(fileName), names, codePage, lastError))
497   {
498     if (lastError != 0)
499     {
500       UString m;
501       m = "The file operation error for listfile";
502       m.Add_LF();
503       m += NError::MyFormatMessage(lastError);
504       throw CArcCmdLineException(m, fileName);
505     }
506     throw CArcCmdLineException(kIncorrectListFile, fileName);
507   }
508   if (renamePairs)
509   {
510     if ((names.Size() & 1) != 0)
511       throw CArcCmdLineException(kIncorrectListFile, fileName);
512     for (unsigned i = 0; i < names.Size(); i += 2)
513     {
514       // change type !!!!
515       AddRenamePair(renamePairs, names[i], names[i + 1], nop.RecursedType, nop.WildcardMatching);
516     }
517   }
518   else
519     FOR_VECTOR (i, names)
520       AddNameToCensor(censor, nop, names[i]);
521 }
522 
AddToCensorFromNonSwitchesStrings(CObjectVector<CRenamePair> * renamePairs,unsigned startIndex,NWildcard::CCensor & censor,const UStringVector & nonSwitchStrings,int stopSwitchIndex,const CNameOption & nop,bool thereAreSwitchIncludes,UInt32 codePage)523 static void AddToCensorFromNonSwitchesStrings(
524     CObjectVector<CRenamePair> *renamePairs,
525     unsigned startIndex,
526     NWildcard::CCensor &censor,
527     const UStringVector &nonSwitchStrings,
528     int stopSwitchIndex,
529     const CNameOption &nop,
530     bool thereAreSwitchIncludes, UInt32 codePage)
531 {
532   // another default
533   if ((renamePairs || nonSwitchStrings.Size() == startIndex) && !thereAreSwitchIncludes)
534   {
535     /* for rename command: -i switch sets the mask for archive item reading.
536        if (thereAreSwitchIncludes), { we don't use UniversalWildcard. }
537        also for non-rename command: we set UniversalWildcard, only if there are no nonSwitches. */
538     // we use default fileds in (CNameOption) for UniversalWildcard.
539     CNameOption nop2;
540     // recursive mode is not important for UniversalWildcard (*)
541     // nop2.RecursedType = nop.RecursedType; // we don't need it
542     /*
543     nop2.RecursedType = NRecursedType::kNonRecursed;
544     nop2.Include = true;
545     nop2.WildcardMatching = true;
546     nop2.MarkMode = NWildcard::kMark_FileOrDir;
547     */
548     AddNameToCensor(censor, nop2, UString(kUniversalWildcard));
549   }
550 
551   int oldIndex = -1;
552 
553   if (stopSwitchIndex < 0)
554     stopSwitchIndex = (int)nonSwitchStrings.Size();
555 
556   for (unsigned i = startIndex; i < nonSwitchStrings.Size(); i++)
557   {
558     const UString &s = nonSwitchStrings[i];
559     if (s.IsEmpty())
560       throw CArcCmdLineException(kEmptyFilePath);
561     if (i < (unsigned)stopSwitchIndex && s[0] == kFileListID)
562       AddToCensorFromListFile(renamePairs, censor, nop, s.Ptr(1), codePage);
563     else if (renamePairs)
564     {
565       if (oldIndex == -1)
566         oldIndex = (int)i;
567       else
568       {
569         // NRecursedType::EEnum type is used for global wildcard (-i! switches)
570         AddRenamePair(renamePairs, nonSwitchStrings[(unsigned)oldIndex], s, NRecursedType::kNonRecursed, nop.WildcardMatching);
571         // AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, type);
572         oldIndex = -1;
573       }
574     }
575     else
576       AddNameToCensor(censor, nop, s);
577   }
578 
579   if (oldIndex != -1)
580   {
581     throw CArcCmdLineException("There is no second file name for rename pair:", nonSwitchStrings[(unsigned)oldIndex]);
582   }
583 }
584 
585 #ifdef _WIN32
586 
587 struct CEventSetEnd
588 {
589   UString Name;
590 
CEventSetEndCEventSetEnd591   CEventSetEnd(const wchar_t *name): Name(name) {}
~CEventSetEndCEventSetEnd592   ~CEventSetEnd()
593   {
594     NSynchronization::CManualResetEvent event;
595     if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(Name)) == 0)
596       event.Set();
597   }
598 };
599 
600 static const char * const k_IncorrectMapCommand = "Incorrect Map command";
601 
ParseMapWithPaths(NWildcard::CCensor & censor,const UString & s2,const CNameOption & nop)602 static const char *ParseMapWithPaths(
603     NWildcard::CCensor &censor,
604     const UString &s2,
605     const CNameOption &nop)
606 {
607   UString s (s2);
608   int pos = s.Find(L':');
609   if (pos < 0)
610     return k_IncorrectMapCommand;
611   int pos2 = s.Find(L':', (unsigned)(pos + 1));
612   if (pos2 < 0)
613     return k_IncorrectMapCommand;
614 
615   CEventSetEnd eventSetEnd((const wchar_t *)s + (unsigned)(pos2 + 1));
616   s.DeleteFrom((unsigned)pos2);
617   UInt32 size;
618   if (!StringToUInt32(s.Ptr((unsigned)(pos + 1)), size)
619       || size < sizeof(wchar_t)
620       || size > ((UInt32)1 << 31)
621       || size % sizeof(wchar_t) != 0)
622     return "Unsupported Map data size";
623 
624   s.DeleteFrom((unsigned)pos);
625   CFileMapping map;
626   if (map.Open(FILE_MAP_READ, GetSystemString(s)) != 0)
627     return "Cannot open mapping";
628   LPVOID data = map.Map(FILE_MAP_READ, 0, size);
629   if (!data)
630     return "MapViewOfFile error";
631   CFileUnmapper unmapper(data);
632 
633   UString name;
634   const wchar_t *p = (const wchar_t *)data;
635   if (*p != 0) // data format marker
636     return "Unsupported Map data";
637   UInt32 numChars = size / sizeof(wchar_t);
638   for (UInt32 i = 1; i < numChars; i++)
639   {
640     wchar_t c = p[i];
641     if (c == 0)
642     {
643       // MessageBoxW(0, name, L"7-Zip", 0);
644       AddNameToCensor(censor, nop, name);
645       name.Empty();
646     }
647     else
648       name += c;
649   }
650   if (!name.IsEmpty())
651     return "Map data error";
652 
653   return NULL;
654 }
655 
656 #endif
657 
AddSwitchWildcardsToCensor(NWildcard::CCensor & censor,const UStringVector & strings,const CNameOption & nop,UInt32 codePage)658 static void AddSwitchWildcardsToCensor(
659     NWildcard::CCensor &censor,
660     const UStringVector &strings,
661     const CNameOption &nop,
662     UInt32 codePage)
663 {
664   const char *errorMessage = NULL;
665   unsigned i;
666   for (i = 0; i < strings.Size(); i++)
667   {
668     const UString &name = strings[i];
669     unsigned pos = 0;
670 
671     if (name.Len() < kSomeCludePostStringMinSize)
672     {
673       errorMessage = "Too short switch";
674       break;
675     }
676 
677     if (!nop.Include)
678     {
679       if (name.IsEqualTo_Ascii_NoCase("td"))
680       {
681         censor.ExcludeDirItems = true;
682         continue;
683       }
684       if (name.IsEqualTo_Ascii_NoCase("tf"))
685       {
686         censor.ExcludeFileItems = true;
687         continue;
688       }
689     }
690 
691     CNameOption nop2 = nop;
692 
693     bool type_WasUsed = false;
694     bool recursed_WasUsed = false;
695     bool matching_WasUsed = false;
696     bool error = false;
697 
698     for (;;)
699     {
700       wchar_t c = ::MyCharLower_Ascii(name[pos]);
701       if (c == kRecursedIDChar)
702       {
703         if (recursed_WasUsed)
704         {
705           error = true;
706           break;
707         }
708         recursed_WasUsed = true;
709         pos++;
710         c = name[pos];
711         int index = -1;
712         if (c <= 0x7F)
713           index = FindCharPosInString(kRecursedPostCharSet, (char)c);
714         nop2.RecursedType = GetRecursedTypeFromIndex(index);
715         if (index >= 0)
716         {
717           pos++;
718           continue;
719         }
720       }
721 
722       if (c == 'w')
723       {
724         if (matching_WasUsed)
725         {
726           error = true;
727           break;
728         }
729         matching_WasUsed = true;
730         nop2.WildcardMatching = true;
731         pos++;
732         if (name[pos] == '-')
733         {
734           nop2.WildcardMatching = false;
735           pos++;
736         }
737       }
738       else if (c == 'm')
739       {
740         if (type_WasUsed)
741         {
742           error = true;
743           break;
744         }
745         type_WasUsed = true;
746         pos++;
747         nop2.MarkMode = NWildcard::kMark_StrictFile;
748         c = name[pos];
749         if (c == '-')
750         {
751           nop2.MarkMode = NWildcard::kMark_FileOrDir;
752           pos++;
753         }
754         else if (c == '2')
755         {
756           nop2.MarkMode = NWildcard::kMark_StrictFile_IfWildcard;
757           pos++;
758         }
759       }
760       else
761         break;
762     }
763 
764     if (error)
765     {
766       errorMessage = "inorrect switch";
767       break;
768     }
769 
770     if (name.Len() < pos + kSomeCludeAfterRecursedPostStringMinSize)
771     {
772       errorMessage = "Too short switch";
773       break;
774     }
775 
776     const UString tail = name.Ptr(pos + 1);
777 
778     const wchar_t c = name[pos];
779 
780     if (c == kImmediateNameID)
781       AddNameToCensor(censor, nop2, tail);
782     else if (c == kFileListID)
783       AddToCensorFromListFile(NULL, censor, nop2, tail, codePage);
784     #ifdef _WIN32
785     else if (c == kMapNameID)
786     {
787       errorMessage = ParseMapWithPaths(censor, tail, nop2);
788       if (errorMessage)
789         break;
790     }
791     #endif
792     else
793     {
794       errorMessage = "Incorrect wildcard type marker";
795       break;
796     }
797   }
798 
799   if (i != strings.Size())
800     throw CArcCmdLineException(errorMessage, strings[i]);
801 }
802 
803 /*
804 static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i)
805 {
806   switch (i)
807   {
808     case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairAction::kIgnore;
809     case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction::kCopy;
810     case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAction::kCompress;
811     case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NPairAction::kCompressAsAnti;
812   }
813   throw 98111603;
814 }
815 */
816 
817 static const char * const kUpdatePairStateIDSet = "pqrxyzw";
818 static const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1};
819 
820 static const unsigned kNumUpdatePairActions = 4;
821 static const char * const kUpdateIgnoreItselfPostStringID = "-";
822 static const wchar_t kUpdateNewArchivePostCharID = '!';
823 
824 
ParseUpdateCommandString2(const UString & command,NUpdateArchive::CActionSet & actionSet,UString & postString)825 static bool ParseUpdateCommandString2(const UString &command,
826     NUpdateArchive::CActionSet &actionSet, UString &postString)
827 {
828   for (unsigned i = 0; i < command.Len();)
829   {
830     wchar_t c = MyCharLower_Ascii(command[i]);
831     int statePos = FindCharPosInString(kUpdatePairStateIDSet, (char)c);
832     if (c > 0x7F || statePos < 0)
833     {
834       postString = command.Ptr(i);
835       return true;
836     }
837     i++;
838     if (i >= command.Len())
839       return false;
840     c = command[i];
841     if (c < '0' || c >= (wchar_t)('0' + kNumUpdatePairActions))
842       return false;
843     unsigned actionPos = (unsigned)(c - '0');
844     actionSet.StateActions[(unsigned)statePos] = (NUpdateArchive::NPairAction::EEnum)(actionPos);
845     if (kUpdatePairStateNotSupportedActions[(unsigned)statePos] == (int)actionPos)
846       return false;
847     i++;
848   }
849   postString.Empty();
850   return true;
851 }
852 
ParseUpdateCommandString(CUpdateOptions & options,const UStringVector & updatePostStrings,const NUpdateArchive::CActionSet & defaultActionSet)853 static void ParseUpdateCommandString(CUpdateOptions &options,
854     const UStringVector &updatePostStrings,
855     const NUpdateArchive::CActionSet &defaultActionSet)
856 {
857   const char *errorMessage = "incorrect update switch command";
858   unsigned i;
859   for (i = 0; i < updatePostStrings.Size(); i++)
860   {
861     const UString &updateString = updatePostStrings[i];
862     if (updateString.IsEqualTo(kUpdateIgnoreItselfPostStringID))
863     {
864       if (options.UpdateArchiveItself)
865       {
866         options.UpdateArchiveItself = false;
867         options.Commands.Delete(0);
868       }
869     }
870     else
871     {
872       NUpdateArchive::CActionSet actionSet = defaultActionSet;
873 
874       UString postString;
875       if (!ParseUpdateCommandString2(updateString, actionSet, postString))
876         break;
877       if (postString.IsEmpty())
878       {
879         if (options.UpdateArchiveItself)
880           options.Commands[0].ActionSet = actionSet;
881       }
882       else
883       {
884         if (postString[0] != kUpdateNewArchivePostCharID)
885           break;
886         CUpdateArchiveCommand uc;
887         UString archivePath = postString.Ptr(1);
888         if (archivePath.IsEmpty())
889           break;
890         uc.UserArchivePath = archivePath;
891         uc.ActionSet = actionSet;
892         options.Commands.Add(uc);
893       }
894     }
895   }
896   if (i != updatePostStrings.Size())
897     throw CArcCmdLineException(errorMessage, updatePostStrings[i]);
898 }
899 
900 bool ParseComplexSize(const wchar_t *s, UInt64 &result);
901 
SetAddCommandOptions(NCommandType::EEnum commandType,const CParser & parser,CUpdateOptions & options)902 static void SetAddCommandOptions(
903     NCommandType::EEnum commandType,
904     const CParser &parser,
905     CUpdateOptions &options)
906 {
907   NUpdateArchive::CActionSet defaultActionSet;
908   switch (commandType)
909   {
910     case NCommandType::kAdd:
911       defaultActionSet = NUpdateArchive::k_ActionSet_Add;
912       break;
913     case NCommandType::kDelete:
914       defaultActionSet = NUpdateArchive::k_ActionSet_Delete;
915       break;
916     default:
917       defaultActionSet = NUpdateArchive::k_ActionSet_Update;
918   }
919 
920   options.UpdateArchiveItself = true;
921 
922   options.Commands.Clear();
923   CUpdateArchiveCommand updateMainCommand;
924   updateMainCommand.ActionSet = defaultActionSet;
925   options.Commands.Add(updateMainCommand);
926   if (parser[NKey::kUpdate].ThereIs)
927     ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings,
928         defaultActionSet);
929   if (parser[NKey::kWorkingDir].ThereIs)
930   {
931     const UString &postString = parser[NKey::kWorkingDir].PostStrings[0];
932     if (postString.IsEmpty())
933       NDir::MyGetTempPath(options.WorkingDir);
934     else
935       options.WorkingDir = us2fs(postString);
936   }
937   options.SfxMode = parser[NKey::kSfx].ThereIs;
938   if (options.SfxMode)
939     options.SfxModule = us2fs(parser[NKey::kSfx].PostStrings[0]);
940 
941   if (parser[NKey::kVolume].ThereIs)
942   {
943     const UStringVector &sv = parser[NKey::kVolume].PostStrings;
944     FOR_VECTOR (i, sv)
945     {
946       UInt64 size;
947       if (!ParseComplexSize(sv[i], size) || size == 0)
948         throw CArcCmdLineException("Incorrect volume size:", sv[i]);
949       options.VolumesSizes.Add(size);
950     }
951   }
952 }
953 
SetMethodOptions(const CParser & parser,CObjectVector<CProperty> & properties)954 static void SetMethodOptions(const CParser &parser, CObjectVector<CProperty> &properties)
955 {
956   if (parser[NKey::kProperty].ThereIs)
957   {
958     FOR_VECTOR (i, parser[NKey::kProperty].PostStrings)
959     {
960       CProperty prop;
961       prop.Name = parser[NKey::kProperty].PostStrings[i];
962       int index = prop.Name.Find(L'=');
963       if (index >= 0)
964       {
965         prop.Value = prop.Name.Ptr((unsigned)(index + 1));
966         prop.Name.DeleteFrom((unsigned)index);
967       }
968       properties.Add(prop);
969     }
970   }
971 }
972 
973 
SetStreamMode(const CSwitchResult & sw,unsigned & res)974 static inline void SetStreamMode(const CSwitchResult &sw, unsigned &res)
975 {
976   if (sw.ThereIs)
977     res = (unsigned)sw.PostCharIndex;
978 }
979 
980 
981 #if defined(_WIN32) && !defined(UNDER_CE)
PrintHex(UString & s,UInt64 v)982 static void PrintHex(UString &s, UInt64 v)
983 {
984   char temp[32];
985   ConvertUInt64ToHex(v, temp);
986   s += temp;
987 }
988 #endif
989 
990 
Parse1(const UStringVector & commandStrings,CArcCmdLineOptions & options)991 void CArcCmdLineParser::Parse1(const UStringVector &commandStrings,
992     CArcCmdLineOptions &options)
993 {
994   Parse1Log.Empty();
995   if (!parser.ParseStrings(kSwitchForms, ARRAY_SIZE(kSwitchForms), commandStrings))
996     throw CArcCmdLineException(parser.ErrorMessage, parser.ErrorLine);
997 
998   options.IsInTerminal = MY_IS_TERMINAL(stdin);
999   options.IsStdOutTerminal = MY_IS_TERMINAL(stdout);
1000   options.IsStdErrTerminal = MY_IS_TERMINAL(stderr);
1001 
1002   options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs  || parser[NKey::kHelp3].ThereIs;
1003 
1004   options.StdInMode = parser[NKey::kStdIn].ThereIs;
1005   options.StdOutMode = parser[NKey::kStdOut].ThereIs;
1006   options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs;
1007   if (parser[NKey::kListFields].ThereIs)
1008   {
1009     const UString &s = parser[NKey::kListFields].PostStrings[0];
1010     options.ListFields = GetAnsiString(s);
1011   }
1012   options.TechMode = parser[NKey::kTechMode].ThereIs;
1013   options.ShowTime = parser[NKey::kShowTime].ThereIs;
1014 
1015   if (parser[NKey::kDisablePercents].ThereIs
1016       || options.StdOutMode
1017       || !options.IsStdOutTerminal)
1018     options.Number_for_Percents = k_OutStream_disabled;
1019 
1020   if (options.StdOutMode)
1021     options.Number_for_Out = k_OutStream_disabled;
1022 
1023   SetStreamMode(parser[NKey::kOutStream], options.Number_for_Out);
1024   SetStreamMode(parser[NKey::kErrStream], options.Number_for_Errors);
1025   SetStreamMode(parser[NKey::kPercentStream], options.Number_for_Percents);
1026 
1027   if (parser[NKey::kLogLevel].ThereIs)
1028   {
1029     const UString &s = parser[NKey::kLogLevel].PostStrings[0];
1030     if (s.IsEmpty())
1031       options.LogLevel = 1;
1032     else
1033     {
1034       UInt32 v;
1035       if (!StringToUInt32(s, v))
1036         throw CArcCmdLineException("Unsupported switch postfix -bb", s);
1037       options.LogLevel = (unsigned)v;
1038     }
1039   }
1040 
1041   if (parser[NKey::kCaseSensitive].ThereIs)
1042   {
1043     options.CaseSensitive =
1044     g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus;
1045     options.CaseSensitive_Change = true;
1046   }
1047 
1048 
1049   #if defined(_WIN32) && !defined(UNDER_CE)
1050   NSecurity::EnablePrivilege_SymLink();
1051   #endif
1052 
1053   // options.LargePages = false;
1054 
1055   if (parser[NKey::kLargePages].ThereIs)
1056   {
1057     unsigned slp = 0;
1058     const UString &s = parser[NKey::kLargePages].PostStrings[0];
1059     if (s.IsEmpty())
1060       slp = 1;
1061     else if (s != L"-")
1062     {
1063       if (!StringToUInt32(s, slp))
1064         throw CArcCmdLineException("Unsupported switch postfix for -slp", s);
1065     }
1066 
1067     #ifdef _7ZIP_LARGE_PAGES
1068     if (slp >
1069           #if defined(_WIN32) && !defined(UNDER_CE)
1070             (unsigned)NSecurity::Get_LargePages_RiskLevel()
1071           #else
1072             0
1073           #endif
1074         )
1075     {
1076       #ifdef _WIN32 // change it !
1077       SetLargePageSize();
1078       #endif
1079       // note: this process also can inherit that Privilege from parent process
1080       g_LargePagesMode =
1081       #if defined(_WIN32) && !defined(UNDER_CE)
1082         NSecurity::EnablePrivilege_LockMemory();
1083       #else
1084         true;
1085       #endif
1086     }
1087     #endif
1088   }
1089 
1090 
1091   #ifndef UNDER_CE
1092 
1093   if (parser[NKey::kAffinity].ThereIs)
1094   {
1095     const UString &s = parser[NKey::kAffinity].PostStrings[0];
1096     if (!s.IsEmpty())
1097     {
1098       AString a;
1099       a.SetFromWStr_if_Ascii(s);
1100       Parse1Log += "Set process affinity mask: ";
1101 
1102       #ifdef _WIN32
1103 
1104       UInt64 v = 0;
1105       {
1106         const char *end;
1107         v = ConvertHexStringToUInt64(a, &end);
1108         if (*end != 0)
1109           a.Empty();
1110       }
1111       if (a.IsEmpty())
1112         throw CArcCmdLineException("Unsupported switch postfix -stm", s);
1113 
1114       {
1115         #ifndef _WIN64
1116         if (v >= ((UInt64)1 << 32))
1117           throw CArcCmdLineException("unsupported value -stm", s);
1118         #endif
1119         {
1120           PrintHex(Parse1Log, v);
1121           if (!SetProcessAffinityMask(GetCurrentProcess(), (DWORD_PTR)v))
1122           {
1123             DWORD lastError = GetLastError();
1124             Parse1Log += " : ERROR : ";
1125             Parse1Log += NError::MyFormatMessage(lastError);
1126           }
1127         }
1128       }
1129 
1130       #else // _WIN32
1131 
1132       {
1133         Parse1Log += a;
1134         NSystem::CProcessAffinity aff;
1135         aff.CpuZero();
1136         for (unsigned i = 0; i < a.Len(); i++)
1137         {
1138           char c = a[i];
1139           unsigned v;
1140                if (c >= '0' && c <= '9') v =      (unsigned)(c - '0');
1141           else if (c >= 'A' && c <= 'F') v = 10 + (unsigned)(c - 'A');
1142           else if (c >= 'a' && c <= 'f') v = 10 + (unsigned)(c - 'a');
1143           else
1144             throw CArcCmdLineException("Unsupported switch postfix -stm", s);
1145           for (unsigned k = 0; k < 4; k++)
1146           {
1147             const unsigned cpu = (a.Len() - 1 - i) * 4 + k;
1148             if (v & ((unsigned)1 << k))
1149               aff.CpuSet(cpu);
1150           }
1151         }
1152 
1153         if (!aff.SetProcAffinity())
1154         {
1155           DWORD lastError = GetLastError();
1156           Parse1Log += " : ERROR : ";
1157           Parse1Log += NError::MyFormatMessage(lastError);
1158         }
1159       }
1160       #endif // _WIN32
1161 
1162       Parse1Log.Add_LF();
1163     }
1164   }
1165 
1166   #endif
1167 }
1168 
1169 
1170 
1171 struct CCodePagePair
1172 {
1173   const char *Name;
1174   UInt32 CodePage;
1175 };
1176 
1177 static const unsigned kNumByteOnlyCodePages = 3;
1178 
1179 static const CCodePagePair g_CodePagePairs[] =
1180 {
1181   { "utf-8", CP_UTF8 },
1182   { "win", CP_ACP },
1183   { "dos", CP_OEMCP },
1184   { "utf-16le", MY__CP_UTF16 },
1185   { "utf-16be", MY__CP_UTF16BE }
1186 };
1187 
FindCharset(const NCommandLineParser::CParser & parser,unsigned keyIndex,bool byteOnlyCodePages,Int32 defaultVal)1188 static Int32 FindCharset(const NCommandLineParser::CParser &parser, unsigned keyIndex,
1189     bool byteOnlyCodePages, Int32 defaultVal)
1190 {
1191   if (!parser[keyIndex].ThereIs)
1192     return defaultVal;
1193 
1194   UString name (parser[keyIndex].PostStrings.Back());
1195   UInt32 v;
1196   if (StringToUInt32(name, v))
1197     if (v < ((UInt32)1 << 16))
1198       return (Int32)v;
1199   name.MakeLower_Ascii();
1200   unsigned num = byteOnlyCodePages ? kNumByteOnlyCodePages : ARRAY_SIZE(g_CodePagePairs);
1201   for (unsigned i = 0;; i++)
1202   {
1203     if (i == num) // to disable warnings from different compilers
1204       throw CArcCmdLineException("Unsupported charset:", name);
1205     const CCodePagePair &pair = g_CodePagePairs[i];
1206     if (name.IsEqualTo(pair.Name))
1207       return (Int32)pair.CodePage;
1208   }
1209 }
1210 
1211 
SetBoolPair(NCommandLineParser::CParser & parser,unsigned switchID,CBoolPair & bp)1212 static void SetBoolPair(NCommandLineParser::CParser &parser, unsigned switchID, CBoolPair &bp)
1213 {
1214   bp.Def = parser[switchID].ThereIs;
1215   if (bp.Def)
1216     bp.Val = !parser[switchID].WithMinus;
1217 }
1218 
Parse2(CArcCmdLineOptions & options)1219 void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
1220 {
1221   const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
1222   const unsigned numNonSwitchStrings = nonSwitchStrings.Size();
1223   if (numNonSwitchStrings < kMinNonSwitchWords)
1224     throw CArcCmdLineException("The command must be specified");
1225 
1226   if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command))
1227     throw CArcCmdLineException("Unsupported command:", nonSwitchStrings[kCommandIndex]);
1228 
1229   if (parser[NKey::kHash].ThereIs)
1230     options.HashMethods = parser[NKey::kHash].PostStrings;
1231 
1232   /*
1233   if (parser[NKey::kHashGenFile].ThereIs)
1234   {
1235     const UString &s = parser[NKey::kHashGenFile].PostStrings[0];
1236     for (unsigned i = 0 ; i < s.Len();)
1237     {
1238       const wchar_t c = s[i++];
1239       if (!options.HashOptions.ParseFlagCharOption(c, true))
1240       {
1241         if (c != '=')
1242           throw CArcCmdLineException("Unsupported hash mode switch:", s);
1243         options.HashOptions.HashFilePath = s.Ptr(i);
1244         break;
1245       }
1246     }
1247   }
1248   */
1249 
1250   if (parser[NKey::kHashDir].ThereIs)
1251     options.ExtractOptions.HashDir = parser[NKey::kHashDir].PostStrings[0];
1252 
1253   if (parser[NKey::kElimDup].ThereIs)
1254   {
1255     options.ExtractOptions.ElimDup.Def = true;
1256     options.ExtractOptions.ElimDup.Val = !parser[NKey::kElimDup].WithMinus;
1257   }
1258 
1259   NWildcard::ECensorPathMode censorPathMode = NWildcard::k_RelatPath;
1260   bool fullPathMode = parser[NKey::kFullPathMode].ThereIs;
1261   if (fullPathMode)
1262   {
1263     censorPathMode = NWildcard::k_AbsPath;
1264     const UString &s = parser[NKey::kFullPathMode].PostStrings[0];
1265     if (!s.IsEmpty())
1266     {
1267       if (s == L"2")
1268         censorPathMode = NWildcard::k_FullPath;
1269       else
1270         throw CArcCmdLineException("Unsupported -spf:", s);
1271     }
1272   }
1273 
1274   if (parser[NKey::kNameTrailReplace].ThereIs)
1275     g_PathTrailReplaceMode = !parser[NKey::kNameTrailReplace].WithMinus;
1276 
1277   CNameOption nop;
1278 
1279   if (parser[NKey::kRecursed].ThereIs)
1280     nop.RecursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex);
1281 
1282   if (parser[NKey::kDisableWildcardParsing].ThereIs)
1283     nop.WildcardMatching = false;
1284 
1285   if (parser[NKey::kUseSlashMark].ThereIs)
1286   {
1287     const UString &s = parser[NKey::kUseSlashMark].PostStrings[0];
1288     if (s.IsEmpty())
1289       nop.MarkMode = NWildcard::kMark_StrictFile;
1290     else if (s.IsEqualTo_Ascii_NoCase("-"))
1291       nop.MarkMode = NWildcard::kMark_FileOrDir;
1292     else if (s.IsEqualTo_Ascii_NoCase("2"))
1293       nop.MarkMode = NWildcard::kMark_StrictFile_IfWildcard;
1294     else
1295       throw CArcCmdLineException("Unsupported -spm:", s);
1296   }
1297 
1298 
1299   options.ConsoleCodePage = FindCharset(parser, NKey::kConsoleCharSet, true, -1);
1300 
1301   UInt32 codePage = (UInt32)FindCharset(parser, NKey::kListfileCharSet, false, CP_UTF8);
1302 
1303   bool thereAreSwitchIncludes = false;
1304 
1305   if (parser[NKey::kInclude].ThereIs)
1306   {
1307     thereAreSwitchIncludes = true;
1308     nop.Include = true;
1309     AddSwitchWildcardsToCensor(options.Censor,
1310         parser[NKey::kInclude].PostStrings, nop, codePage);
1311   }
1312 
1313   if (parser[NKey::kExclude].ThereIs)
1314   {
1315     nop.Include = false;
1316     AddSwitchWildcardsToCensor(options.Censor,
1317         parser[NKey::kExclude].PostStrings, nop, codePage);
1318   }
1319 
1320   unsigned curCommandIndex = kCommandIndex + 1;
1321   bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs &&
1322       options.Command.CommandType != NCommandType::kBenchmark &&
1323       options.Command.CommandType != NCommandType::kInfo &&
1324       options.Command.CommandType != NCommandType::kHash;
1325 
1326   const bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
1327   const bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList;
1328   const bool isRename = options.Command.CommandType == NCommandType::kRename;
1329 
1330   if ((isExtractOrList || isRename) && options.StdInMode)
1331     thereIsArchiveName = false;
1332 
1333   if (parser[NKey::kArcNameMode].ThereIs)
1334     options.UpdateOptions.ArcNameMode = ParseArcNameMode(parser[NKey::kArcNameMode].PostCharIndex);
1335 
1336   if (thereIsArchiveName)
1337   {
1338     if (curCommandIndex >= numNonSwitchStrings)
1339       throw CArcCmdLineException("Cannot find archive name");
1340     options.ArchiveName = nonSwitchStrings[curCommandIndex++];
1341     if (options.ArchiveName.IsEmpty())
1342       throw CArcCmdLineException("Archive name cannot by empty");
1343     #ifdef _WIN32
1344     // options.ArchiveName.Replace(L'/', WCHAR_PATH_SEPARATOR);
1345     #endif
1346   }
1347 
1348   nop.Include = true;
1349   AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL,
1350       curCommandIndex, options.Censor,
1351       nonSwitchStrings, parser.StopSwitchIndex,
1352       nop,
1353       thereAreSwitchIncludes, codePage);
1354 
1355   options.YesToAll = parser[NKey::kYes].ThereIs;
1356 
1357 
1358   #ifndef _NO_CRYPTO
1359   options.PasswordEnabled = parser[NKey::kPassword].ThereIs;
1360   if (options.PasswordEnabled)
1361     options.Password = parser[NKey::kPassword].PostStrings[0];
1362   #endif
1363 
1364   options.ShowDialog = parser[NKey::kShowDialog].ThereIs;
1365 
1366   if (parser[NKey::kArchiveType].ThereIs)
1367     options.ArcType = parser[NKey::kArchiveType].PostStrings[0];
1368 
1369   options.ExcludedArcTypes = parser[NKey::kExcludedArcType].PostStrings;
1370 
1371   SetMethodOptions(parser, options.Properties);
1372 
1373   if (parser[NKey::kNtSecurity].ThereIs) options.NtSecurity.SetTrueTrue();
1374 
1375   SetBoolPair(parser, NKey::kAltStreams, options.AltStreams);
1376   SetBoolPair(parser, NKey::kHardLinks, options.HardLinks);
1377   SetBoolPair(parser, NKey::kSymLinks, options.SymLinks);
1378 
1379   SetBoolPair(parser, NKey::kStoreOwnerId, options.StoreOwnerId);
1380   SetBoolPair(parser, NKey::kStoreOwnerName, options.StoreOwnerName);
1381 
1382   CBoolPair symLinks_AllowDangerous;
1383   SetBoolPair(parser, NKey::kSymLinks_AllowDangerous, symLinks_AllowDangerous);
1384 
1385 
1386   /*
1387   bool supportSymLink = options.SymLinks.Val;
1388 
1389   if (!options.SymLinks.Def)
1390   {
1391     if (isExtractOrList)
1392       supportSymLink = true;
1393     else
1394       supportSymLink = false;
1395   }
1396 
1397   #ifdef ENV_HAVE_LSTAT
1398   if (supportSymLink)
1399     global_use_lstat = 1;
1400   else
1401     global_use_lstat = 0;
1402   #endif
1403   */
1404 
1405 
1406   if (isExtractOrList)
1407   {
1408     CExtractOptionsBase &eo = options.ExtractOptions;
1409 
1410     eo.ExcludeDirItems = options.Censor.ExcludeDirItems;
1411     eo.ExcludeFileItems = options.Censor.ExcludeFileItems;
1412 
1413     {
1414       CExtractNtOptions &nt = eo.NtOptions;
1415       nt.NtSecurity = options.NtSecurity;
1416 
1417       nt.AltStreams = options.AltStreams;
1418       if (!options.AltStreams.Def)
1419         nt.AltStreams.Val = true;
1420 
1421       nt.HardLinks = options.HardLinks;
1422       if (!options.HardLinks.Def)
1423         nt.HardLinks.Val = true;
1424 
1425       nt.SymLinks = options.SymLinks;
1426       if (!options.SymLinks.Def)
1427         nt.SymLinks.Val = true;
1428 
1429       nt.SymLinks_AllowDangerous = symLinks_AllowDangerous;
1430 
1431       nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs;
1432       nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs;
1433 
1434       nt.ExtractOwner = options.StoreOwnerId.Val; // StoreOwnerName
1435 
1436       if (parser[NKey::kPreserveATime].ThereIs)
1437         nt.PreserveATime = true;
1438       if (parser[NKey::kShareForWrite].ThereIs)
1439         nt.OpenShareForWrite = true;
1440     }
1441 
1442     if (parser[NKey::kZoneFile].ThereIs)
1443     {
1444       eo.ZoneMode = NExtract::NZoneIdMode::kAll;
1445       const UString &s = parser[NKey::kZoneFile].PostStrings[0];
1446       if (!s.IsEmpty())
1447       {
1448              if (s == L"0") eo.ZoneMode = NExtract::NZoneIdMode::kNone;
1449         else if (s == L"1") eo.ZoneMode = NExtract::NZoneIdMode::kAll;
1450         else if (s == L"2") eo.ZoneMode = NExtract::NZoneIdMode::kOffice;
1451         else
1452           throw CArcCmdLineException("Unsupported -snz:", s);
1453       }
1454     }
1455 
1456     options.Censor.AddPathsToCensor(NWildcard::k_AbsPath);
1457     options.Censor.ExtendExclude();
1458 
1459     // are there paths that look as non-relative (!Prefix.IsEmpty())
1460     if (!options.Censor.AllAreRelative())
1461       throw CArcCmdLineException("Cannot use absolute pathnames for this command");
1462 
1463     NWildcard::CCensor &arcCensor = options.arcCensor;
1464 
1465     CNameOption nopArc;
1466     // nopArc.RecursedType = NRecursedType::kNonRecursed; // default:  we don't want recursing for archives, if -r specified
1467     // is it OK, external switches can disable WildcardMatching and MarcMode for arc.
1468     nopArc.WildcardMatching = nop.WildcardMatching;
1469     nopArc.MarkMode = nop.MarkMode;
1470 
1471     if (parser[NKey::kArInclude].ThereIs)
1472     {
1473       nopArc.Include = true;
1474       AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, nopArc, codePage);
1475     }
1476     if (parser[NKey::kArExclude].ThereIs)
1477     {
1478       nopArc.Include = false;
1479       AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, nopArc, codePage);
1480     }
1481 
1482     if (thereIsArchiveName)
1483     {
1484       nopArc.Include = true;
1485       AddNameToCensor(arcCensor, nopArc, options.ArchiveName);
1486     }
1487 
1488     arcCensor.AddPathsToCensor(NWildcard::k_RelatPath);
1489 
1490     #ifdef _WIN32
1491     ConvertToLongNames(arcCensor);
1492     #endif
1493 
1494     arcCensor.ExtendExclude();
1495 
1496     if (options.StdInMode)
1497       options.ArcName_for_StdInMode = parser[NKey::kStdIn].PostStrings.Front();
1498 
1499     if (isExtractGroupCommand)
1500     {
1501       if (options.StdOutMode)
1502       {
1503         if (
1504                   options.Number_for_Percents == k_OutStream_stdout
1505             // || options.Number_for_Out      == k_OutStream_stdout
1506             // || options.Number_for_Errors   == k_OutStream_stdout
1507             ||
1508             (
1509               (options.IsStdOutTerminal && options.IsStdErrTerminal)
1510               &&
1511               (
1512                       options.Number_for_Percents != k_OutStream_disabled
1513                 // || options.Number_for_Out      != k_OutStream_disabled
1514                 // || options.Number_for_Errors   != k_OutStream_disabled
1515               )
1516             )
1517            )
1518           throw CArcCmdLineException(kSameTerminalError);
1519       }
1520 
1521       if (parser[NKey::kOutputDir].ThereIs)
1522       {
1523         eo.OutputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]);
1524         #ifdef _WIN32
1525           NFile::NName::NormalizeDirSeparators(eo.OutputDir);
1526         #endif
1527         NFile::NName::NormalizeDirPathPrefix(eo.OutputDir);
1528       }
1529 
1530       eo.OverwriteMode = NExtract::NOverwriteMode::kAsk;
1531       if (parser[NKey::kOverwrite].ThereIs)
1532       {
1533         eo.OverwriteMode = k_OverwriteModes[(unsigned)parser[NKey::kOverwrite].PostCharIndex];
1534         eo.OverwriteMode_Force = true;
1535       }
1536       else if (options.YesToAll)
1537       {
1538         eo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite;
1539         eo.OverwriteMode_Force = true;
1540       }
1541     }
1542 
1543     eo.PathMode = options.Command.GetPathMode();
1544     if (censorPathMode == NWildcard::k_AbsPath)
1545     {
1546       eo.PathMode = NExtract::NPathMode::kAbsPaths;
1547       eo.PathMode_Force = true;
1548     }
1549     else if (censorPathMode == NWildcard::k_FullPath)
1550     {
1551       eo.PathMode = NExtract::NPathMode::kFullPaths;
1552       eo.PathMode_Force = true;
1553     }
1554   }
1555   else if (options.Command.IsFromUpdateGroup())
1556   {
1557     if (parser[NKey::kArInclude].ThereIs)
1558       throw CArcCmdLineException("-ai switch is not supported for this command");
1559 
1560     CUpdateOptions &updateOptions = options.UpdateOptions;
1561 
1562     SetAddCommandOptions(options.Command.CommandType, parser, updateOptions);
1563 
1564     updateOptions.MethodMode.Properties = options.Properties;
1565 
1566     if (parser[NKey::kPreserveATime].ThereIs)
1567       updateOptions.PreserveATime = true;
1568     if (parser[NKey::kShareForWrite].ThereIs)
1569       updateOptions.OpenShareForWrite = true;
1570     if (parser[NKey::kStopAfterOpenError].ThereIs)
1571       updateOptions.StopAfterOpenError = true;
1572 
1573     updateOptions.PathMode = censorPathMode;
1574 
1575     updateOptions.AltStreams = options.AltStreams;
1576     updateOptions.NtSecurity = options.NtSecurity;
1577     updateOptions.HardLinks = options.HardLinks;
1578     updateOptions.SymLinks = options.SymLinks;
1579 
1580     updateOptions.StoreOwnerId = options.StoreOwnerId;
1581     updateOptions.StoreOwnerName = options.StoreOwnerName;
1582 
1583     updateOptions.EMailMode = parser[NKey::kEmail].ThereIs;
1584     if (updateOptions.EMailMode)
1585     {
1586       updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front();
1587       if (updateOptions.EMailAddress.Len() > 0)
1588         if (updateOptions.EMailAddress[0] == L'.')
1589         {
1590           updateOptions.EMailRemoveAfter = true;
1591           updateOptions.EMailAddress.Delete(0);
1592         }
1593     }
1594 
1595     updateOptions.StdOutMode = options.StdOutMode;
1596     updateOptions.StdInMode = options.StdInMode;
1597 
1598     updateOptions.DeleteAfterCompressing = parser[NKey::kDeleteAfterCompressing].ThereIs;
1599     updateOptions.SetArcMTime = parser[NKey::kSetArcMTime].ThereIs;
1600 
1601     if (updateOptions.StdOutMode && updateOptions.EMailMode)
1602       throw CArcCmdLineException("stdout mode and email mode cannot be combined");
1603 
1604     if (updateOptions.StdOutMode)
1605     {
1606       if (options.IsStdOutTerminal)
1607         throw CArcCmdLineException(kTerminalOutError);
1608 
1609       if (options.Number_for_Percents == k_OutStream_stdout
1610           || options.Number_for_Out == k_OutStream_stdout
1611           || options.Number_for_Errors == k_OutStream_stdout)
1612         throw CArcCmdLineException(kSameTerminalError);
1613     }
1614 
1615     if (updateOptions.StdInMode)
1616       updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front();
1617 
1618     if (options.Command.CommandType == NCommandType::kRename)
1619       if (updateOptions.Commands.Size() != 1)
1620         throw CArcCmdLineException("Only one archive can be created with rename command");
1621   }
1622   else if (options.Command.CommandType == NCommandType::kBenchmark)
1623   {
1624     options.NumIterations = 1;
1625     options.NumIterations_Defined = false;
1626     if (curCommandIndex < numNonSwitchStrings)
1627     {
1628       if (!StringToUInt32(nonSwitchStrings[curCommandIndex], options.NumIterations))
1629         throw CArcCmdLineException("Incorrect number of benchmark iterations", nonSwitchStrings[curCommandIndex]);
1630       curCommandIndex++;
1631       options.NumIterations_Defined = true;
1632     }
1633   }
1634   else if (options.Command.CommandType == NCommandType::kHash)
1635   {
1636     options.Censor.AddPathsToCensor(censorPathMode);
1637     options.Censor.ExtendExclude();
1638 
1639     CHashOptions &hashOptions = options.HashOptions;
1640     hashOptions.PathMode = censorPathMode;
1641     hashOptions.Methods = options.HashMethods;
1642     // hashOptions.HashFilePath = options.HashFilePath;
1643     if (parser[NKey::kPreserveATime].ThereIs)
1644       hashOptions.PreserveATime = true;
1645     if (parser[NKey::kShareForWrite].ThereIs)
1646       hashOptions.OpenShareForWrite = true;
1647     hashOptions.StdInMode = options.StdInMode;
1648     hashOptions.AltStreamsMode = options.AltStreams.Val;
1649     hashOptions.SymLinks = options.SymLinks;
1650   }
1651   else if (options.Command.CommandType == NCommandType::kInfo)
1652   {
1653   }
1654   else
1655     throw 20150919;
1656 }
1657 
1658 
1659 
1660 #ifndef _WIN32
1661 
1662 static AString g_ModuleDirPrefix;
1663 
1664 void Set_ModuleDirPrefix_From_ProgArg0(const char *s);
Set_ModuleDirPrefix_From_ProgArg0(const char * s)1665 void Set_ModuleDirPrefix_From_ProgArg0(const char *s)
1666 {
1667   AString a (s);
1668   int sep = a.ReverseFind_PathSepar();
1669   a.DeleteFrom((unsigned)(sep + 1));
1670   g_ModuleDirPrefix = a;
1671 }
1672 
1673 namespace NWindows {
1674 namespace NDLL {
1675 
1676 FString GetModuleDirPrefix();
GetModuleDirPrefix()1677 FString GetModuleDirPrefix()
1678 {
1679   FString s;
1680 
1681   s = fas2fs(g_ModuleDirPrefix);
1682   if (s.IsEmpty())
1683     s = FTEXT(".") FSTRING_PATH_SEPARATOR;
1684   return s;
1685   /*
1686   setenv("_7ZIP_HOME_DIR", "/test/", 0);
1687   const char *home = getenv("_7ZIP_HOME_DIR");
1688   if (home)
1689     s = home;
1690   else
1691     s = FTEXT(".") FSTRING_PATH_SEPARATOR;
1692   return s;
1693   */
1694 }
1695 
1696 }}
1697 
1698 #endif // ! _WIN32
1699