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