1 #include "rar.hpp"
2 
CommandData()3 CommandData::CommandData()
4 {
5   FileArgs=ExclArgs=InclArgs=StoreArgs=ArcNames=NULL;
6   Init();
7 }
8 
9 
~CommandData()10 CommandData::~CommandData()
11 {
12   Close();
13 }
14 
15 
Init()16 void CommandData::Init()
17 {
18   Close();
19 
20   *Command=0;
21   *ArcName=0;
22   *ArcNameW=0;
23   FileLists=false;
24   NoMoreSwitches=false;
25 
26   FileArgs=new StringList;
27   ExclArgs=new StringList;
28   InclArgs=new StringList;
29   StoreArgs=new StringList;
30   ArcNames=new StringList;
31 }
32 
33 
Close()34 void CommandData::Close()
35 {
36   delete FileArgs;
37   delete ExclArgs;
38   delete InclArgs;
39   delete StoreArgs;
40   delete ArcNames;
41   FileArgs=ExclArgs=InclArgs=StoreArgs=ArcNames=NULL;
42   NextVolSizes.Reset();
43 }
44 
45 
46 #if !defined(SFX_MODULE)
ParseArg(char * Arg,wchar * ArgW)47 void CommandData::ParseArg(char *Arg,wchar *ArgW)
48 {
49   if (IsSwitch(*Arg) && !NoMoreSwitches)
50     if (Arg[1]=='-')
51       NoMoreSwitches=true;
52     else
53       ProcessSwitch(&Arg[1],(ArgW!=NULL && *ArgW!=0 ? &ArgW[1]:NULL));
54   else
55     if (*Command==0)
56     {
57       strncpyz(Command,Arg,ASIZE(Command));
58       if (ArgW!=NULL)
59         strncpyw(CommandW,ArgW,sizeof(CommandW)/sizeof(CommandW[0]));
60       if (etoupper(*Command)=='S')
61       {
62         const char *SFXName=Command[1] ? Command+1:DefSFXName;
63         if (PointToName(SFXName)!=SFXName || FileExist(SFXName))
64           strcpy(SFXModule,SFXName);
65         else
66           GetConfigName(SFXName,SFXModule,true);
67       }
68 #ifndef GUI
69       *Command=etoupper(*Command);
70       if (*Command!='I' && *Command!='S')
71         strupper(Command);
72 #endif
73     }
74     else
75       if (*ArcName==0)
76       {
77         strncpyz(ArcName,Arg,ASIZE(ArcName));
78         if (ArgW!=NULL)
79           strncpyzw(ArcNameW,ArgW,ASIZE(ArcNameW));
80       }
81       else
82       {
83         size_t Length=strlen(Arg);
84         char EndChar=Length==0 ? 0:Arg[Length-1];
85         char CmdChar=etoupper(*Command);
86         bool Add=strchr("AFUM",CmdChar)!=NULL;
87         bool Extract=CmdChar=='X' || CmdChar=='E';
88         if ((IsDriveDiv(EndChar) || IsPathDiv(EndChar)) && !Add)
89         {
90           strncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
91           if (ArgW!=NULL)
92             strncpyzw(ExtrPathW,ArgW,ASIZE(ExtrPathW));
93         }
94         else
95           if ((Add || CmdChar=='T') && *Arg!='@')
96             FileArgs->AddString(Arg);
97           else
98           {
99             struct FindData FileData;
100             bool Found=FindFile::FastFind(Arg,NULL,&FileData);
101             if (!Found && *Arg=='@' && !IsWildcard(Arg))
102             {
103               FileLists=true;
104 
105               RAR_CHARSET Charset=FilelistCharset;
106 
107 #if defined(_WIN_32) && !defined(GUI)
108               // for compatibility reasons we use OEM encoding
109               // in Win32 console version by default
110 
111               if (Charset==RCH_DEFAULT)
112                 Charset=RCH_OEM;
113 #endif
114 
115               ReadTextFile(Arg+1,FileArgs,false,true,Charset,true,true,true);
116             }
117             else
118               if (Found && FileData.IsDir && Extract && *ExtrPath==0)
119               {
120                 strcpy(ExtrPath,Arg);
121                 AddEndSlash(ExtrPath);
122               }
123               else
124                 FileArgs->AddString(Arg);
125           }
126       }
127 }
128 #endif
129 
130 
ParseDone()131 void CommandData::ParseDone()
132 {
133   if (FileArgs->ItemsCount()==0 && !FileLists)
134     FileArgs->AddString(MASKALL);
135   char CmdChar=etoupper(*Command);
136   bool Extract=CmdChar=='X' || CmdChar=='E' || CmdChar=='P';
137   if (Test && Extract)
138     Test=false;        // Switch '-t' is senseless for 'X', 'E', 'P' commands.
139   BareOutput=(CmdChar=='L' || CmdChar=='V') && Command[1]=='B';
140 }
141 
142 
143 #if !defined(SFX_MODULE) && !defined(_WIN_CE)
ParseEnvVar()144 void CommandData::ParseEnvVar()
145 {
146   char *EnvStr=getenv("RAR");
147   if (EnvStr!=NULL)
148     ProcessSwitchesString(EnvStr);
149 }
150 #endif
151 
152 
153 
154 // return 'false' if -cfg- is present and preprocess switches
155 // which must be processed before the rest of command line
156 
157 #ifndef SFX_MODULE
IsConfigEnabled(int argc,char * argv[])158 bool CommandData::IsConfigEnabled(int argc,char *argv[])
159 {
160   bool ConfigEnabled=true;
161   for (int I=1;I<argc;I++)
162     if (IsSwitch(*argv[I]))
163     {
164       if (stricomp(&argv[I][1],"-")==0)
165         break;
166       if (stricomp(&argv[I][1],"cfg-")==0)
167         ConfigEnabled=false;
168 #ifndef GUI
169       if (strnicomp(&argv[I][1],"ilog",4)==0)
170       {
171         // ensure that correct log file name is already set
172         // if we need to report an error when processing the command line
173         ProcessSwitch(&argv[I][1]);
174         InitLogOptions(LogName);
175       }
176 #endif
177       if (strnicomp(&argv[I][1],"sc",2)==0)
178       {
179         // Process -sc before reading any file lists.
180         ProcessSwitch(&argv[I][1]);
181       }
182     }
183   return(ConfigEnabled);
184 }
185 #endif
186 
187 
188 #if !defined(GUI) && !defined(SFX_MODULE)
ReadConfig(int argc,char * argv[])189 void CommandData::ReadConfig(int argc,char *argv[])
190 {
191   StringList List;
192   if (ReadTextFile(DefConfigName,&List,true))
193   {
194     char *Str;
195     while ((Str=List.GetString())!=NULL)
196     {
197       while (IsSpace(*Str))
198         Str++;
199       if (strnicomp(Str,"switches=",9)==0)
200         ProcessSwitchesString(Str+9);
201     }
202   }
203 }
204 #endif
205 
206 
207 #if !defined(SFX_MODULE) && !defined(_WIN_CE)
ProcessSwitchesString(char * Str)208 void CommandData::ProcessSwitchesString(char *Str)
209 {
210   while (*Str)
211   {
212     while (!IsSwitch(*Str) && *Str!=0)
213       Str++;
214     if (*Str==0)
215       break;
216     char *Next=Str;
217     while (!(Next[0]==' ' && IsSwitch(Next[1])) && *Next!=0)
218       Next++;
219     char NextChar=*Next;
220     *Next=0;
221     ProcessSwitch(Str+1);
222     *Next=NextChar;
223     Str=Next;
224   }
225 }
226 #endif
227 
228 
229 #if !defined(SFX_MODULE)
ProcessSwitch(char * Switch,wchar * SwitchW)230 void CommandData::ProcessSwitch(char *Switch,wchar *SwitchW)
231 {
232 
233   switch(etoupper(Switch[0]))
234   {
235     case 'I':
236       if (strnicomp(&Switch[1],"LOG",3)==0)
237       {
238         strncpyz(LogName,Switch[4] ? Switch+4:DefLogName,ASIZE(LogName));
239         break;
240       }
241       if (stricomp(&Switch[1],"SND")==0)
242       {
243         Sound=true;
244         break;
245       }
246       if (stricomp(&Switch[1],"ERR")==0)
247       {
248         MsgStream=MSG_STDERR;
249         break;
250       }
251       if (strnicomp(&Switch[1],"EML",3)==0)
252       {
253         strncpyz(EmailTo,Switch[4] ? Switch+4:"@",ASIZE(EmailTo));
254         EmailTo[sizeof(EmailTo)-1]=0;
255         break;
256       }
257       if (stricomp(&Switch[1],"NUL")==0)
258       {
259         MsgStream=MSG_NULL;
260         break;
261       }
262       if (etoupper(Switch[1])=='D')
263       {
264         for (int I=2;Switch[I]!=0;I++)
265           switch(etoupper(Switch[I]))
266           {
267             case 'Q':
268               MsgStream=MSG_ERRONLY;
269               break;
270             case 'C':
271               DisableCopyright=true;
272               break;
273             case 'D':
274               DisableDone=true;
275               break;
276             case 'P':
277               DisablePercentage=true;
278               break;
279           }
280         break;
281       }
282       if (stricomp(&Switch[1],"OFF")==0)
283       {
284         Shutdown=true;
285         break;
286       }
287       break;
288     case 'T':
289       switch(etoupper(Switch[1]))
290       {
291         case 'K':
292           ArcTime=ARCTIME_KEEP;
293           break;
294         case 'L':
295           ArcTime=ARCTIME_LATEST;
296           break;
297         case 'O':
298           FileTimeBefore.SetAgeText(Switch+2);
299           break;
300         case 'N':
301           FileTimeAfter.SetAgeText(Switch+2);
302           break;
303         case 'B':
304           FileTimeBefore.SetIsoText(Switch+2);
305           break;
306         case 'A':
307           FileTimeAfter.SetIsoText(Switch+2);
308           break;
309         case 'S':
310           {
311             EXTTIME_MODE Mode=EXTTIME_HIGH3;
312             bool CommonMode=Switch[2]>='0' && Switch[2]<='4';
313             if (CommonMode)
314               Mode=(EXTTIME_MODE)(Switch[2]-'0');
315             if (Switch[2]=='-')
316               Mode=EXTTIME_NONE;
317             if (CommonMode || Switch[2]=='-' || Switch[2]=='+' || Switch[2]==0)
318               xmtime=xctime=xatime=Mode;
319             else
320             {
321               if (Switch[3]>='0' && Switch[3]<='4')
322                 Mode=(EXTTIME_MODE)(Switch[3]-'0');
323               if (Switch[3]=='-')
324                 Mode=EXTTIME_NONE;
325               switch(etoupper(Switch[2]))
326               {
327                 case 'M':
328                   xmtime=Mode;
329                   break;
330                 case 'C':
331                   xctime=Mode;
332                   break;
333                 case 'A':
334                   xatime=Mode;
335                   break;
336                 case 'R':
337                   xarctime=Mode;
338                   break;
339               }
340             }
341           }
342           break;
343         case '-':
344           Test=false;
345           break;
346         case 0:
347           Test=true;
348           break;
349         default:
350           BadSwitch(Switch);
351           break;
352       }
353       break;
354     case 'A':
355       switch(etoupper(Switch[1]))
356       {
357         case 'C':
358           ClearArc=true;
359           break;
360         case 'D':
361           AppendArcNameToPath=true;
362           break;
363         case 'G':
364           if (Switch[2]=='-' && Switch[3]==0)
365             GenerateArcName=0;
366           else
367           {
368             GenerateArcName=true;
369             strncpyz(GenerateMask,Switch+2,ASIZE(GenerateMask));
370           }
371           break;
372         case 'I':
373           IgnoreGeneralAttr=true;
374           break;
375         case 'N': //reserved for archive name
376           break;
377         case 'O':
378           AddArcOnly=true;
379           break;
380         case 'P':
381           strcpy(ArcPath,Switch+2);
382           if (SwitchW!=NULL && *SwitchW!=0)
383             strcpyw(ArcPathW,SwitchW+2);
384           break;
385         case 'S':
386           SyncFiles=true;
387           break;
388         default:
389           BadSwitch(Switch);
390           break;
391       }
392       break;
393     case 'D':
394       if (Switch[2]==0)
395         switch(etoupper(Switch[1]))
396         {
397           case 'S':
398             DisableSortSolid=true;
399             break;
400           case 'H':
401             OpenShared=true;
402             break;
403           case 'F':
404             DeleteFiles=true;
405             break;
406         }
407       break;
408     case 'O':
409       switch(etoupper(Switch[1]))
410       {
411         case '+':
412           Overwrite=OVERWRITE_ALL;
413           break;
414         case '-':
415           Overwrite=OVERWRITE_NONE;
416           break;
417         case 0:
418           Overwrite=OVERWRITE_FORCE_ASK;
419           break;
420         case 'R':
421           Overwrite=OVERWRITE_AUTORENAME;
422           break;
423         case 'W':
424           ProcessOwners=true;
425           break;
426 #ifdef SAVE_LINKS
427         case 'L':
428           SaveLinks=true;
429           break;
430 #endif
431 #ifdef _WIN_32
432         case 'S':
433           SaveStreams=true;
434           break;
435         case 'C':
436           SetCompressedAttr=true;
437           break;
438 #endif
439         default :
440           BadSwitch(Switch);
441           break;
442       }
443       break;
444     case 'R':
445       switch(etoupper(Switch[1]))
446       {
447         case 0:
448           Recurse=RECURSE_ALWAYS;
449           break;
450         case '-':
451           Recurse=RECURSE_DISABLE;
452           break;
453         case '0':
454           Recurse=RECURSE_WILDCARDS;
455           break;
456 #ifndef _WIN_CE
457         case 'I':
458           {
459             Priority=atoi(Switch+2);
460             char *ChPtr=strchr(Switch+2,':');
461             if (ChPtr!=NULL)
462             {
463               SleepTime=atoi(ChPtr+1);
464               InitSystemOptions(SleepTime);
465             }
466             SetPriority(Priority);
467           }
468           break;
469 #endif
470       }
471       break;
472     case 'Y':
473       AllYes=true;
474       break;
475     case 'N':
476     case 'X':
477       if (Switch[1]!=0)
478       {
479         StringList *Args=etoupper(Switch[0])=='N' ? InclArgs:ExclArgs;
480         if (Switch[1]=='@' && !IsWildcard(Switch))
481         {
482           RAR_CHARSET Charset=FilelistCharset;
483 
484 #if defined(_WIN_32) && !defined(GUI)
485           // for compatibility reasons we use OEM encoding
486           // in Win32 console version by default
487 
488           if (Charset==RCH_DEFAULT)
489             Charset=RCH_OEM;
490 #endif
491 
492           ReadTextFile(Switch+2,Args,false,true,Charset,true,true,true);
493         }
494         else
495           Args->AddString(Switch+1);
496       }
497       break;
498     case 'E':
499       switch(etoupper(Switch[1]))
500       {
501         case 'P':
502           switch(Switch[2])
503           {
504             case 0:
505               ExclPath=EXCL_SKIPWHOLEPATH;
506               break;
507             case '1':
508               ExclPath=EXCL_BASEPATH;
509               break;
510             case '2':
511               ExclPath=EXCL_SAVEFULLPATH;
512               break;
513             case '3':
514               ExclPath=EXCL_ABSPATH;
515               break;
516           }
517           break;
518         case 'E':
519           ProcessEA=false;
520           break;
521         case 'N':
522           NoEndBlock=true;
523           break;
524         default:
525           if (Switch[1]=='+')
526           {
527             InclFileAttr=GetExclAttr(&Switch[2]);
528             InclAttrSet=true;
529           }
530           else
531             ExclFileAttr=GetExclAttr(&Switch[1]);
532           break;
533       }
534       break;
535     case 'P':
536       if (Switch[1]==0)
537       {
538         GetPassword(PASSWORD_GLOBAL,NULL,Password,sizeof(Password));
539         eprintf("\n");
540       }
541       else
542         strncpyz(Password,Switch+1,ASIZE(Password));
543       break;
544     case 'H':
545       if (etoupper(Switch[1])=='P')
546       {
547         EncryptHeaders=true;
548         if (Switch[2]!=0)
549           strncpyz(Password,Switch+2,ASIZE(Password));
550         else
551           if (*Password==0)
552           {
553             GetPassword(PASSWORD_GLOBAL,NULL,Password,sizeof(Password));
554             eprintf("\n");
555           }
556       }
557       break;
558     case 'Z':
559       strncpyz(CommentFile,Switch[1]!=0 ? Switch+1:"stdin",ASIZE(CommentFile));
560       break;
561     case 'M':
562       switch(etoupper(Switch[1]))
563       {
564         case 'C':
565           {
566             char *Str=Switch+2;
567             if (*Str=='-')
568               for (int I=0;I<sizeof(FilterModes)/sizeof(FilterModes[0]);I++)
569                 FilterModes[I].State=FILTER_DISABLE;
570             else
571               while (*Str)
572               {
573                 int Param1=0,Param2=0;
574                 FilterState State=FILTER_AUTO;
575                 FilterType Type=FILTER_NONE;
576                 if (IsDigit(*Str))
577                 {
578                   Param1=atoi(Str);
579                   while (IsDigit(*Str))
580                     Str++;
581                 }
582                 if (*Str==':' && IsDigit(Str[1]))
583                 {
584                   Param2=atoi(++Str);
585                   while (IsDigit(*Str))
586                     Str++;
587                 }
588                 switch(etoupper(*(Str++)))
589                 {
590                   case 'T': Type=FILTER_PPM;         break;
591                   case 'E': Type=FILTER_E8;          break;
592                   case 'D': Type=FILTER_DELTA;       break;
593                   case 'A': Type=FILTER_AUDIO;       break;
594                   case 'C': Type=FILTER_RGB;         break;
595                   case 'I': Type=FILTER_ITANIUM;     break;
596                   case 'L': Type=FILTER_UPCASETOLOW; break;
597                 }
598                 if (*Str=='+' || *Str=='-')
599                   State=*(Str++)=='+' ? FILTER_FORCE:FILTER_DISABLE;
600                 FilterModes[Type].State=State;
601                 FilterModes[Type].Param1=Param1;
602                 FilterModes[Type].Param2=Param2;
603               }
604             }
605           break;
606         case 'M':
607           break;
608         case 'D':
609           {
610             if ((WinSize=atoi(&Switch[2]))==0)
611               WinSize=0x10000<<(etoupper(Switch[2])-'A');
612             else
613               WinSize*=1024;
614             if (!CheckWinSize())
615               BadSwitch(Switch);
616           }
617           break;
618         case 'S':
619           {
620             char *Names=Switch+2,DefNames[512];
621             if (*Names==0)
622             {
623               strcpy(DefNames,DefaultStoreList);
624               Names=DefNames;
625             }
626             while (*Names!=0)
627             {
628               char *End=strchr(Names,';');
629               if (End!=NULL)
630                 *End=0;
631               if (*Names=='.')
632                 Names++;
633               char Mask[NM];
634               if (strpbrk(Names,"*?.")==NULL)
635                 sprintf(Mask,"*.%s",Names);
636               else
637                 strcpy(Mask,Names);
638               StoreArgs->AddString(Mask);
639               if (End==NULL)
640                 break;
641               Names=End+1;
642             }
643           }
644           break;
645 #ifdef PACK_SMP
646         case 'T':
647           Threads=atoi(Switch+2);
648           if (Threads>16)
649             BadSwitch(Switch);
650           else
651           {
652           }
653           break;
654 #endif
655         default:
656           Method=Switch[1]-'0';
657           if (Method>5 || Method<0)
658             BadSwitch(Switch);
659           break;
660       }
661       break;
662     case 'V':
663       switch(etoupper(Switch[1]))
664       {
665 #ifdef _WIN_32
666         case 'D':
667           EraseDisk=true;
668           break;
669 #endif
670         case 'N':
671           OldNumbering=true;
672           break;
673         case 'P':
674           VolumePause=true;
675           break;
676         case 'E':
677           if (etoupper(Switch[2])=='R')
678             VersionControl=atoi(Switch+3)+1;
679           break;
680         case '-':
681           VolSize=0;
682           break;
683         default:
684           {
685             int64 NewVolSize=atoil(&Switch[1]);
686 
687             if (NewVolSize==0)
688               NewVolSize=INT64NDF; // Autodetecting volume size.
689             else
690               switch (Switch[strlen(Switch)-1])
691               {
692                 case 'f':
693                 case 'F':
694                   switch(NewVolSize)
695                   {
696                     case 360:
697                       NewVolSize=362496;
698                       break;
699                     case 720:
700                       NewVolSize=730112;
701                       break;
702                     case 1200:
703                       NewVolSize=1213952;
704                       break;
705                     case 1440:
706                       NewVolSize=1457664;
707                       break;
708                     case 2880:
709                       NewVolSize=2915328;
710                       break;
711                   }
712                   break;
713                 case 'k':
714                   NewVolSize*=1024;
715                   break;
716                 case 'm':
717                   NewVolSize*=1024*1024;
718                   break;
719                 case 'M':
720                   NewVolSize*=1000*1000;
721                   break;
722                 case 'g':
723                   NewVolSize*=1024*1024;
724                   NewVolSize*=1024;
725                   break;
726                 case 'G':
727                   NewVolSize*=1000*1000;
728                   NewVolSize*=1000;
729                   break;
730                 case 'b':
731                 case 'B':
732                   break;
733                 default:
734                   NewVolSize*=1000;
735                   break;
736               }
737             if (VolSize==0)
738               VolSize=NewVolSize;
739             else
740               NextVolSizes.Push(NewVolSize);
741           }
742           break;
743       }
744       break;
745     case 'F':
746       if (Switch[1]==0)
747         FreshFiles=true;
748       else
749         BadSwitch(Switch);
750       break;
751     case 'U':
752       if (Switch[1]==0)
753         UpdateFiles=true;
754       else
755         BadSwitch(Switch);
756       break;
757     case 'W':
758       strncpyz(TempPath,&Switch[1],ASIZE(TempPath));
759       AddEndSlash(TempPath);
760       break;
761     case 'S':
762       if (strnicomp(Switch,"SFX",3)==0)
763       {
764         const char *SFXName=Switch[3] ? Switch+3:DefSFXName;
765         if (PointToName(SFXName)!=SFXName || FileExist(SFXName))
766           strcpy(SFXModule,SFXName);
767         else
768           GetConfigName(SFXName,SFXModule,true);
769       }
770       if (IsDigit(Switch[1]))
771       {
772         Solid|=SOLID_COUNT;
773         SolidCount=atoi(&Switch[1]);
774       }
775       else
776         switch(etoupper(Switch[1]))
777         {
778           case 0:
779             Solid|=SOLID_NORMAL;
780             break;
781           case '-':
782             Solid=SOLID_NONE;
783             break;
784           case 'E':
785             Solid|=SOLID_FILEEXT;
786             break;
787           case 'V':
788             Solid|=Switch[2]=='-' ? SOLID_VOLUME_DEPENDENT:SOLID_VOLUME_INDEPENDENT;
789             break;
790           case 'D':
791             Solid|=SOLID_VOLUME_DEPENDENT;
792             break;
793           case 'L':
794             if (IsDigit(Switch[2]))
795               FileSizeLess=atoil(Switch+2);
796             break;
797           case 'M':
798             if (IsDigit(Switch[2]))
799               FileSizeMore=atoil(Switch+2);
800             break;
801           case 'C':
802             {
803               // Switch is already found bad, avoid reporting it several times.
804               bool AlreadyBad=false;
805 
806               RAR_CHARSET rch=RCH_DEFAULT;
807               switch(etoupper(Switch[2]))
808               {
809                 case 'A':
810                   rch=RCH_ANSI;
811                   break;
812                 case 'O':
813                   rch=RCH_OEM;
814                   break;
815                 case 'U':
816                   rch=RCH_UNICODE;
817                   break;
818                 default :
819                   BadSwitch(Switch);
820                   AlreadyBad=true;
821                   break;
822               };
823               if (!AlreadyBad)
824                 if (Switch[3]==0)
825                   CommentCharset=FilelistCharset=rch;
826                 else
827                   for (int I=3;Switch[I]!=0 && !AlreadyBad;I++)
828                     switch(etoupper(Switch[I]))
829                     {
830                       case 'C':
831                         CommentCharset=rch;
832                         break;
833                       case 'L':
834                         FilelistCharset=rch;
835                         break;
836                       default:
837                         BadSwitch(Switch);
838                         AlreadyBad=true;
839                         break;
840                     }
841             }
842             break;
843 
844         }
845       break;
846     case 'C':
847       if (Switch[2]==0)
848         switch(etoupper(Switch[1]))
849         {
850           case '-':
851             DisableComment=true;
852             break;
853           case 'U':
854             ConvertNames=NAMES_UPPERCASE;
855             break;
856           case 'L':
857             ConvertNames=NAMES_LOWERCASE;
858             break;
859         }
860       break;
861     case 'K':
862       switch(etoupper(Switch[1]))
863       {
864         case 'B':
865           KeepBroken=true;
866           break;
867         case 0:
868           Lock=true;
869           break;
870       }
871       break;
872 #ifndef GUI
873     case '?' :
874       OutHelp();
875       break;
876 #endif
877     default :
878       BadSwitch(Switch);
879       break;
880   }
881 }
882 #endif
883 
884 
885 #ifndef SFX_MODULE
BadSwitch(char * Switch)886 void CommandData::BadSwitch(char *Switch)
887 {
888   mprintf(St(MUnknownOption),Switch);
889   ErrHandler.Exit(USER_ERROR);
890 }
891 #endif
892 
893 
894 #ifndef GUI
OutTitle()895 void CommandData::OutTitle()
896 {
897   if (BareOutput || DisableCopyright)
898     return;
899 #if defined(__GNUC__) && defined(SFX_MODULE)
900   mprintf(St(MCopyrightS));
901 #else
902 #ifndef SILENT
903   static bool TitleShown=false;
904   if (TitleShown)
905     return;
906   TitleShown=true;
907   char Version[50];
908   int Beta=RARVER_BETA;
909   if (Beta!=0)
910     sprintf(Version,"%d.%02d %s %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA);
911   else
912     sprintf(Version,"%d.%02d",RARVER_MAJOR,RARVER_MINOR);
913 #ifdef UNRAR
914   mprintf(St(MUCopyright),Version,RARVER_YEAR);
915 #else
916 #endif
917 #endif
918 #endif
919 }
920 #endif
921 
922 
CmpMSGID(MSGID i1,MSGID i2)923 inline bool CmpMSGID(MSGID i1,MSGID i2)
924 {
925 #ifdef MSGID_INT
926   return(i1==i2);
927 #else
928   // If MSGID is const char*, we cannot compare pointers only.
929   // Pointers to different instances of same strings can differ,
930   // so we need to compare complete strings.
931   return(strcmp(i1,i2)==0);
932 #endif
933 }
934 
OutHelp()935 void CommandData::OutHelp()
936 {
937 #if !defined(GUI) && !defined(SILENT)
938   OutTitle();
939   static MSGID Help[]={
940 #ifdef SFX_MODULE
941     // Console SFX switches definition.
942     MCHelpCmd,MSHelpCmdE,MSHelpCmdT,MSHelpCmdV
943 #elif defined(UNRAR)
944     // UnRAR switches definition.
945     MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL,
946     MCHelpCmdP,MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,
947     MCHelpSwm,MCHelpSwAC,MCHelpSwAD,MCHelpSwAI,MCHelpSwAP,
948     MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU,
949     MCHelpSwDH,MCHelpSwEP,MCHelpSwEP3,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR,
950     MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwN,MCHelpSwNa,MCHelpSwNal,
951     MCHelpSwO,MCHelpSwOC,MCHelpSwOR,MCHelpSwOW,MCHelpSwP,
952     MCHelpSwPm,MCHelpSwR,MCHelpSwRI,MCHelpSwSL,MCHelpSwSM,MCHelpSwTA,
953     MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU,MCHelpSwVUnr,
954     MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal,MCHelpSwY
955 #else
956 #endif
957   };
958 
959   for (int I=0;I<sizeof(Help)/sizeof(Help[0]);I++)
960   {
961 #ifndef SFX_MODULE
962 #ifdef DISABLEAUTODETECT
963     if (Help[I]==MCHelpSwV)
964       continue;
965 #endif
966 #ifndef _WIN_32
967     static MSGID Win32Only[]={
968       MCHelpSwIEML,MCHelpSwVD,MCHelpSwAO,MCHelpSwOS,MCHelpSwIOFF,
969       MCHelpSwEP2,MCHelpSwOC,MCHelpSwDR,MCHelpSwRI
970     };
971     bool Found=false;
972     for (int J=0;J<sizeof(Win32Only)/sizeof(Win32Only[0]);J++)
973       if (CmpMSGID(Help[I],Win32Only[J]))
974       {
975         Found=true;
976         break;
977       }
978     if (Found)
979       continue;
980 #endif
981 #if !defined(_UNIX) && !defined(_WIN_32)
982     if (CmpMSGID(Help[I],MCHelpSwOW))
983       continue;
984 #endif
985 #if !defined(_WIN_32) && !defined(_EMX)
986     if (CmpMSGID(Help[I],MCHelpSwAC))
987       continue;
988 #endif
989 #ifndef SAVE_LINKS
990     if (CmpMSGID(Help[I],MCHelpSwOL))
991       continue;
992 #endif
993 #ifndef PACK_SMP
994     if (CmpMSGID(Help[I],MCHelpSwMT))
995       continue;
996 #endif
997 #ifndef _BEOS
998     if (CmpMSGID(Help[I],MCHelpSwEE))
999     {
1000 #if defined(_EMX) && !defined(_DJGPP)
1001       if (_osmode != OS2_MODE)
1002         continue;
1003 #else
1004       continue;
1005 #endif
1006     }
1007 #endif
1008 #endif
1009     mprintf(St(Help[I]));
1010   }
1011   mprintf("\n");
1012   ErrHandler.Exit(USER_ERROR);
1013 #endif
1014 }
1015 
1016 
ExclCheckArgs(StringList * Args,char * CheckName,bool CheckFullPath,int MatchMode)1017 bool CommandData::ExclCheckArgs(StringList *Args,char *CheckName,bool CheckFullPath,int MatchMode)
1018 {
1019   char *Name=ConvertPath(CheckName,NULL);
1020   char FullName[NM],*CurName;
1021   *FullName=0;
1022   Args->Rewind();
1023   while ((CurName=Args->GetString())!=NULL)
1024 #ifndef SFX_MODULE
1025     if (CheckFullPath && IsFullPath(CurName))
1026     {
1027       if (*FullName==0)
1028         ConvertNameToFull(CheckName,FullName);
1029       if (CmpName(CurName,FullName,MatchMode))
1030         return(true);
1031     }
1032     else
1033 #endif
1034       if (CmpName(ConvertPath(CurName,NULL),Name,MatchMode))
1035         return(true);
1036   return(false);
1037 }
1038 
1039 
1040 // Return 'true' if we need to exclude the file from processing as result
1041 // of -x switch. If CheckInclList is true, we also check the file against
1042 // the include list created with -n switch.
ExclCheck(char * CheckName,bool CheckFullPath,bool CheckInclList)1043 bool CommandData::ExclCheck(char *CheckName,bool CheckFullPath,bool CheckInclList)
1044 {
1045   if (ExclCheckArgs(ExclArgs,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
1046     return(true);
1047   if (!CheckInclList || InclArgs->ItemsCount()==0)
1048     return(false);
1049   if (ExclCheckArgs(InclArgs,CheckName,false,MATCH_WILDSUBPATH))
1050     return(false);
1051   return(true);
1052 }
1053 
1054 
1055 // Return 'true' if we need to exclude the directory from archiving as result
1056 // of -x switch. We do not want -x*. switch to exclude all directories,
1057 // so when archiving we process exclusion arguments for directories specially.
ExclCheckDir(char * CheckName)1058 bool CommandData::ExclCheckDir(char *CheckName)
1059 {
1060   // If exclusion mask and directory name match exactly, return true.
1061   if (ExclCheckArgs(ExclArgs,CheckName,true,MATCH_EXACT))
1062     return(true);
1063 
1064   // Now we want to allow wildcards in exclusion mask only if it has
1065   // '\' at the end. So 'dir*\' will exclude all dir* directories.
1066   // We append '\' to directory name, so it will match only masks having
1067   // '\' at the end.
1068   char DirName[NM+1];
1069   ConvertPath(CheckName,DirName);
1070   AddEndSlash(DirName);
1071 
1072   char *CurMask;
1073   ExclArgs->Rewind();
1074   while ((CurMask=ExclArgs->GetString())!=NULL)
1075     if (IsPathDiv(*PointToLastChar(CurMask)))
1076       if (CmpName(CurMask,DirName,MATCH_SUBPATH))
1077         return(true);
1078 
1079   return(false);
1080 }
1081 
1082 
1083 
1084 
1085 #ifndef SFX_MODULE
1086 // Return 'true' if we need to exclude the file from processing.
TimeCheck(RarTime & ft)1087 bool CommandData::TimeCheck(RarTime &ft)
1088 {
1089   if (FileTimeBefore.IsSet() && ft>=FileTimeBefore)
1090     return(true);
1091   if (FileTimeAfter.IsSet() && ft<=FileTimeAfter)
1092     return(true);
1093   return(false);
1094 }
1095 #endif
1096 
1097 
1098 #ifndef SFX_MODULE
1099 // Return 'true' if we need to exclude the file from processing.
SizeCheck(int64 Size)1100 bool CommandData::SizeCheck(int64 Size)
1101 {
1102   if (FileSizeLess!=INT64NDF && Size>=FileSizeLess)
1103     return(true);
1104   if (FileSizeMore!=INT64NDF && Size<=FileSizeMore)
1105     return(true);
1106   return(false);
1107 }
1108 #endif
1109 
1110 
1111 
1112 
IsProcessFile(FileHeader & NewLhd,bool * ExactMatch,int MatchType)1113 int CommandData::IsProcessFile(FileHeader &NewLhd,bool *ExactMatch,int MatchType)
1114 {
1115   if (strlen(NewLhd.FileName)>=NM || strlenw(NewLhd.FileNameW)>=NM)
1116     return(0);
1117   if (ExclCheck(NewLhd.FileName,false,true))
1118     return(0);
1119 #ifndef SFX_MODULE
1120   if (TimeCheck(NewLhd.mtime))
1121     return(0);
1122   if ((NewLhd.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (NewLhd.FileAttr & InclFileAttr)==0)
1123     return(0);
1124   if ((NewLhd.Flags & LHD_WINDOWMASK)!=LHD_DIRECTORY && SizeCheck(NewLhd.FullUnpSize))
1125     return(0);
1126 #endif
1127   char *ArgName;
1128   wchar *ArgNameW;
1129   FileArgs->Rewind();
1130   for (int StringCount=1;FileArgs->GetString(&ArgName,&ArgNameW);StringCount++)
1131   {
1132 #ifndef SFX_MODULE
1133     bool Unicode=(NewLhd.Flags & LHD_UNICODE) || ArgNameW!=NULL;
1134     if (Unicode)
1135     {
1136       wchar NameW[NM],ArgW[NM],*NamePtr=NewLhd.FileNameW;
1137       bool CorrectUnicode=true;
1138       if (ArgNameW==NULL)
1139       {
1140         if (!CharToWide(ArgName,ArgW) || *ArgW==0)
1141           CorrectUnicode=false;
1142         ArgNameW=ArgW;
1143       }
1144       if ((NewLhd.Flags & LHD_UNICODE)==0)
1145       {
1146         if (!CharToWide(NewLhd.FileName,NameW) || *NameW==0)
1147           CorrectUnicode=false;
1148         NamePtr=NameW;
1149       }
1150       if (CmpName(ArgNameW,NamePtr,MatchType))
1151       {
1152         if (ExactMatch!=NULL)
1153           *ExactMatch=stricompcw(ArgNameW,NamePtr)==0;
1154         return(StringCount);
1155       }
1156       if (CorrectUnicode)
1157         continue;
1158     }
1159 #endif
1160     if (CmpName(ArgName,NewLhd.FileName,MatchType))
1161     {
1162       if (ExactMatch!=NULL)
1163         *ExactMatch=stricompc(ArgName,NewLhd.FileName)==0;
1164       return(StringCount);
1165     }
1166   }
1167   return(0);
1168 }
1169 
1170 
1171 #ifndef GUI
ProcessCommand()1172 void CommandData::ProcessCommand()
1173 {
1174 #ifndef SFX_MODULE
1175 
1176   const char *SingleCharCommands="FUADPXETK";
1177   if (Command[1] && strchr(SingleCharCommands,*Command)!=NULL || *ArcName==0)
1178     OutHelp();
1179 
1180 #ifdef _UNIX
1181   if (GetExt(ArcName)==NULL && (!FileExist(ArcName) || IsDir(GetFileAttr(ArcName))))
1182     strcat(ArcName,".rar");
1183 #else
1184   if (GetExt(ArcName)==NULL)
1185     strcat(ArcName,".rar");
1186 #endif
1187 
1188   if (strchr("AFUMD",*Command)==NULL)
1189   {
1190     StringList ArcMasks;
1191     ArcMasks.AddString(ArcName);
1192     ScanTree Scan(&ArcMasks,Recurse,SaveLinks,SCAN_SKIPDIRS);
1193     FindData FindData;
1194     while (Scan.GetNext(&FindData)==SCAN_SUCCESS)
1195       AddArcName(FindData.Name,FindData.NameW);
1196   }
1197   else
1198     AddArcName(ArcName,NULL);
1199 #endif
1200 
1201   switch(Command[0])
1202   {
1203     case 'P':
1204     case 'X':
1205     case 'E':
1206     case 'T':
1207     case 'I':
1208       {
1209         CmdExtract Extract;
1210         Extract.DoExtract(this);
1211       }
1212       break;
1213 #ifndef SILENT
1214     case 'V':
1215     case 'L':
1216       ListArchive(this);
1217       break;
1218     default:
1219       OutHelp();
1220 #endif
1221   }
1222   if (!BareOutput)
1223     mprintf("\n");
1224 }
1225 #endif
1226 
1227 
AddArcName(char * Name,wchar * NameW)1228 void CommandData::AddArcName(char *Name,wchar *NameW)
1229 {
1230   ArcNames->AddString(Name,NameW);
1231 }
1232 
1233 
GetArcName(char * Name,wchar * NameW,int MaxSize)1234 bool CommandData::GetArcName(char *Name,wchar *NameW,int MaxSize)
1235 {
1236   if (!ArcNames->GetString(Name,NameW,NM))
1237     return(false);
1238   return(true);
1239 }
1240 
1241 
IsSwitch(int Ch)1242 bool CommandData::IsSwitch(int Ch)
1243 {
1244 #if defined(_WIN_32) || defined(_EMX)
1245   return(Ch=='-' || Ch=='/');
1246 #else
1247   return(Ch=='-');
1248 #endif
1249 }
1250 
1251 
1252 #ifndef SFX_MODULE
GetExclAttr(char * Str)1253 uint CommandData::GetExclAttr(char *Str)
1254 {
1255   if (IsDigit(*Str))
1256     return(strtol(Str,NULL,0));
1257   else
1258   {
1259     uint Attr;
1260     for (Attr=0;*Str;Str++)
1261       switch(etoupper(*Str))
1262       {
1263 #ifdef _UNIX
1264         case 'D':
1265           Attr|=S_IFDIR;
1266           break;
1267         case 'V':
1268           Attr|=S_IFCHR;
1269           break;
1270 #elif defined(_WIN_32) || defined(_EMX)
1271         case 'R':
1272           Attr|=0x1;
1273           break;
1274         case 'H':
1275           Attr|=0x2;
1276           break;
1277         case 'S':
1278           Attr|=0x4;
1279           break;
1280         case 'D':
1281           Attr|=0x10;
1282           break;
1283         case 'A':
1284           Attr|=0x20;
1285           break;
1286 #endif
1287       }
1288     return(Attr);
1289   }
1290 }
1291 #endif
1292 
1293 
1294 
1295 
1296 #ifndef SFX_MODULE
CheckWinSize()1297 bool CommandData::CheckWinSize()
1298 {
1299   static int ValidSize[]={
1300     0x10000,0x20000,0x40000,0x80000,0x100000,0x200000,0x400000
1301   };
1302   for (int I=0;I<sizeof(ValidSize)/sizeof(ValidSize[0]);I++)
1303     if (WinSize==ValidSize[I])
1304       return(true);
1305   WinSize=0x400000;
1306   return(false);
1307 }
1308 #endif
1309