1 #include "rar.hpp"
2
3 #include "cmdfilter.cpp"
4 #include "cmdmix.cpp"
5
CommandData()6 CommandData::CommandData()
7 {
8 Init();
9 }
10
11
Init()12 void CommandData::Init()
13 {
14 RAROptions::Init();
15
16 *Command=0;
17 *ArcName=0;
18 FileLists=false;
19 NoMoreSwitches=false;
20
21 ListMode=RCLM_AUTO;
22
23 BareOutput=false;
24
25
26 FileArgs.Reset();
27 ExclArgs.Reset();
28 InclArgs.Reset();
29 StoreArgs.Reset();
30 ArcNames.Reset();
31 NextVolSizes.Reset();
32 }
33
34
35 // Return the pointer to next position in the string and store dynamically
36 // allocated command line parameter in Par.
AllocCmdParam(const wchar * CmdLine,wchar ** Par)37 static const wchar *AllocCmdParam(const wchar *CmdLine,wchar **Par)
38 {
39 const wchar *NextCmd=GetCmdParam(CmdLine,NULL,0);
40 if (NextCmd==NULL)
41 return NULL;
42 size_t ParSize=NextCmd-CmdLine+2; // Parameter size including the trailing zero.
43 *Par=(wchar *)malloc(ParSize*sizeof(wchar));
44 if (*Par==NULL)
45 return NULL;
46 return GetCmdParam(CmdLine,*Par,ParSize);
47 }
48
49
50 #if !defined(SFX_MODULE)
ParseCommandLine(bool Preprocess,int argc,char * argv[])51 void CommandData::ParseCommandLine(bool Preprocess,int argc, char *argv[])
52 {
53 *Command=0;
54 NoMoreSwitches=false;
55 #ifdef CUSTOM_CMDLINE_PARSER
56 // In Windows we may prefer to implement our own command line parser
57 // to avoid replacing \" by " in standard parser. Such replacing corrupts
58 // destination paths like "dest path\" in extraction commands.
59 // Also our own parser is Unicode compatible.
60 const wchar *CmdLine=GetCommandLine();
61
62 wchar *Par;
63 for (bool FirstParam=true;;FirstParam=false)
64 {
65 if ((CmdLine=AllocCmdParam(CmdLine,&Par))==NULL)
66 break;
67 if (!FirstParam) // First parameter is the executable name.
68 if (Preprocess)
69 PreprocessArg(Par);
70 else
71 ParseArg(Par);
72 free(Par);
73 }
74 #else
75 Array<wchar> Arg;
76 for (int I=1;I<argc;I++)
77 {
78 Arg.Alloc(strlen(argv[I])+1);
79 CharToWide(argv[I],&Arg[0],Arg.Size());
80 if (Preprocess)
81 PreprocessArg(&Arg[0]);
82 else
83 ParseArg(&Arg[0]);
84 }
85 #endif
86 if (!Preprocess)
87 ParseDone();
88 }
89 #endif
90
91
92 #if !defined(SFX_MODULE)
ParseArg(wchar * Arg)93 void CommandData::ParseArg(wchar *Arg)
94 {
95 if (IsSwitch(*Arg) && !NoMoreSwitches)
96 if (Arg[1]=='-' && Arg[2]==0)
97 NoMoreSwitches=true;
98 else
99 ProcessSwitch(Arg+1);
100 else
101 if (*Command==0)
102 {
103 wcsncpyz(Command,Arg,ASIZE(Command));
104
105
106 *Command=toupperw(*Command);
107 // 'I' and 'S' commands can contain case sensitive strings after
108 // the first character, so we must not modify their case.
109 // 'S' can contain SFX name, which case is important in Unix.
110 if (*Command!='I' && *Command!='S')
111 wcsupper(Command);
112 }
113 else
114 if (*ArcName==0)
115 wcsncpyz(ArcName,Arg,ASIZE(ArcName));
116 else
117 {
118 // Check if last character is the path separator.
119 size_t Length=wcslen(Arg);
120 wchar EndChar=Length==0 ? 0:Arg[Length-1];
121 bool EndSeparator=IsDriveDiv(EndChar) || IsPathDiv(EndChar);
122
123 wchar CmdChar=toupperw(*Command);
124 bool Add=wcschr(L"AFUM",CmdChar)!=NULL;
125 bool Extract=CmdChar=='X' || CmdChar=='E';
126 bool Repair=CmdChar=='R' && Command[1]==0;
127 if (EndSeparator && !Add)
128 wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
129 else
130 if ((Add || CmdChar=='T') && (*Arg!='@' || ListMode==RCLM_REJECT_LISTS))
131 FileArgs.AddString(Arg);
132 else
133 {
134 FindData FileData;
135 bool Found=FindFile::FastFind(Arg,&FileData);
136 if ((!Found || ListMode==RCLM_ACCEPT_LISTS) &&
137 ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg+1))
138 {
139 FileLists=true;
140
141 ReadTextFile(Arg+1,&FileArgs,false,true,FilelistCharset,true,true,true);
142
143 }
144 else // We use 'destpath\' when extracting and reparing.
145 if (Found && FileData.IsDir && (Extract || Repair) && *ExtrPath==0)
146 {
147 wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
148 AddEndSlash(ExtrPath,ASIZE(ExtrPath));
149 }
150 else
151 FileArgs.AddString(Arg);
152 }
153 }
154 }
155 #endif
156
157
ParseDone()158 void CommandData::ParseDone()
159 {
160 if (FileArgs.ItemsCount()==0 && !FileLists)
161 FileArgs.AddString(MASKALL);
162 wchar CmdChar=toupperw(Command[0]);
163 bool Extract=CmdChar=='X' || CmdChar=='E' || CmdChar=='P';
164 if (Test && Extract)
165 Test=false; // Switch '-t' is senseless for 'X', 'E', 'P' commands.
166
167 // Suppress the copyright message and final end of line for 'lb' and 'vb'.
168 if ((CmdChar=='L' || CmdChar=='V') && Command[1]=='B')
169 BareOutput=true;
170 }
171
172
173 #if !defined(SFX_MODULE)
ParseEnvVar()174 void CommandData::ParseEnvVar()
175 {
176 char *EnvStr=getenv("RAR");
177 if (EnvStr!=NULL)
178 {
179 Array<wchar> EnvStrW(strlen(EnvStr)+1);
180 CharToWide(EnvStr,&EnvStrW[0],EnvStrW.Size());
181 ProcessSwitchesString(&EnvStrW[0]);
182 }
183 }
184 #endif
185
186
187
188 #if !defined(SFX_MODULE)
189 // Preprocess those parameters, which must be processed before the rest of
190 // command line. Return 'false' to stop further processing.
PreprocessArg(const wchar * Arg)191 void CommandData::PreprocessArg(const wchar *Arg)
192 {
193 if (IsSwitch(Arg[0]) && !NoMoreSwitches)
194 {
195 Arg++;
196 if (Arg[0]=='-' && Arg[1]==0) // Switch "--".
197 NoMoreSwitches=true;
198 if (wcsicomp(Arg,L"cfg-")==0)
199 ConfigDisabled=true;
200 if (wcsnicomp(Arg,L"ilog",4)==0)
201 {
202 // Ensure that correct log file name is already set
203 // if we need to report an error when processing the command line.
204 ProcessSwitch(Arg);
205 InitLogOptions(LogName,ErrlogCharset);
206 }
207 if (wcsnicomp(Arg,L"sc",2)==0)
208 {
209 // Process -sc before reading any file lists.
210 ProcessSwitch(Arg);
211 if (*LogName!=0)
212 InitLogOptions(LogName,ErrlogCharset);
213 }
214 }
215 else
216 if (*Command==0)
217 wcsncpy(Command,Arg,ASIZE(Command)); // Need for rar.ini.
218 }
219 #endif
220
221
222 #if !defined(SFX_MODULE)
ReadConfig()223 void CommandData::ReadConfig()
224 {
225 StringList List;
226 if (ReadTextFile(DefConfigName,&List,true))
227 {
228 wchar *Str;
229 while ((Str=List.GetString())!=NULL)
230 {
231 while (IsSpace(*Str))
232 Str++;
233 if (wcsnicomp(Str,L"switches=",9)==0)
234 ProcessSwitchesString(Str+9);
235 if (*Command!=0)
236 {
237 wchar Cmd[16];
238 wcsncpyz(Cmd,Command,ASIZE(Cmd));
239 wchar C0=toupperw(Cmd[0]);
240 wchar C1=toupperw(Cmd[1]);
241 if (C0=='I' || C0=='L' || C0=='M' || C0=='S' || C0=='V')
242 Cmd[1]=0;
243 if (C0=='R' && (C1=='R' || C1=='V'))
244 Cmd[2]=0;
245 wchar SwName[16+ASIZE(Cmd)];
246 swprintf(SwName,ASIZE(SwName),L"switches_%ls=",Cmd);
247 size_t Length=wcslen(SwName);
248 if (wcsnicomp(Str,SwName,Length)==0)
249 ProcessSwitchesString(Str+Length);
250 }
251 }
252 }
253 }
254 #endif
255
256
257 #if !defined(SFX_MODULE)
ProcessSwitchesString(const wchar * Str)258 void CommandData::ProcessSwitchesString(const wchar *Str)
259 {
260 wchar *Par;
261 while ((Str=AllocCmdParam(Str,&Par))!=NULL)
262 {
263 if (IsSwitch(*Par))
264 ProcessSwitch(Par+1);
265 free(Par);
266 }
267 }
268 #endif
269
270
271 #if !defined(SFX_MODULE)
ProcessSwitch(const wchar * Switch)272 void CommandData::ProcessSwitch(const wchar *Switch)
273 {
274
275 switch(toupperw(Switch[0]))
276 {
277 case '@':
278 ListMode=Switch[1]=='+' ? RCLM_ACCEPT_LISTS:RCLM_REJECT_LISTS;
279 break;
280 case 'A':
281 switch(toupperw(Switch[1]))
282 {
283 case 'C':
284 ClearArc=true;
285 break;
286 case 'D':
287 if (Switch[2]==0)
288 AppendArcNameToPath=APPENDARCNAME_DESTPATH;
289 else
290 if (Switch[2]=='1')
291 AppendArcNameToPath=APPENDARCNAME_OWNDIR;
292 break;
293 #ifndef SFX_MODULE
294 case 'G':
295 if (Switch[2]=='-' && Switch[3]==0)
296 GenerateArcName=0;
297 else
298 if (toupperw(Switch[2])=='F')
299 wcsncpyz(DefGenerateMask,Switch+3,ASIZE(DefGenerateMask));
300 else
301 {
302 GenerateArcName=true;
303 wcsncpyz(GenerateMask,Switch+2,ASIZE(GenerateMask));
304 }
305 break;
306 #endif
307 case 'I':
308 IgnoreGeneralAttr=true;
309 break;
310 case 'N': // Reserved for archive name.
311 break;
312 case 'O':
313 AddArcOnly=true;
314 break;
315 case 'P':
316 wcsncpyz(ArcPath,Switch+2,ASIZE(ArcPath));
317 break;
318 case 'S':
319 SyncFiles=true;
320 break;
321 default:
322 BadSwitch(Switch);
323 break;
324 }
325 break;
326 case 'C':
327 if (Switch[2]==0)
328 switch(toupperw(Switch[1]))
329 {
330 case '-':
331 DisableComment=true;
332 break;
333 case 'U':
334 ConvertNames=NAMES_UPPERCASE;
335 break;
336 case 'L':
337 ConvertNames=NAMES_LOWERCASE;
338 break;
339 }
340 break;
341 case 'D':
342 if (Switch[2]==0)
343 switch(toupperw(Switch[1]))
344 {
345 case 'S':
346 DisableSortSolid=true;
347 break;
348 case 'H':
349 OpenShared=true;
350 break;
351 case 'F':
352 DeleteFiles=true;
353 break;
354 }
355 break;
356 case 'E':
357 switch(toupperw(Switch[1]))
358 {
359 case 'P':
360 switch(Switch[2])
361 {
362 case 0:
363 ExclPath=EXCL_SKIPWHOLEPATH;
364 break;
365 case '1':
366 ExclPath=EXCL_BASEPATH;
367 break;
368 case '2':
369 ExclPath=EXCL_SAVEFULLPATH;
370 break;
371 case '3':
372 ExclPath=EXCL_ABSPATH;
373 break;
374 }
375 break;
376 default:
377 if (Switch[1]=='+')
378 {
379 InclFileAttr|=GetExclAttr(Switch+2,InclDir);
380 InclAttrSet=true;
381 }
382 else
383 ExclFileAttr|=GetExclAttr(Switch+1,ExclDir);
384 break;
385 }
386 break;
387 case 'F':
388 if (Switch[1]==0)
389 FreshFiles=true;
390 else
391 BadSwitch(Switch);
392 break;
393 case 'H':
394 switch (toupperw(Switch[1]))
395 {
396 case 'P':
397 EncryptHeaders=true;
398 if (Switch[2]!=0)
399 {
400 Password.Set(Switch+2);
401 cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0]));
402 }
403 else
404 if (!Password.IsSet())
405 {
406 uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password);
407 eprintf(L"\n");
408 }
409 break;
410 default :
411 BadSwitch(Switch);
412 break;
413 }
414 break;
415 case 'I':
416 if (wcsnicomp(Switch+1,L"LOG",3)==0)
417 {
418 wcsncpyz(LogName,Switch[4]!=0 ? Switch+4:DefLogName,ASIZE(LogName));
419 break;
420 }
421 if (wcsnicomp(Switch+1,L"SND",3)==0)
422 {
423 Sound=Switch[4]=='-' ? SOUND_NOTIFY_OFF : SOUND_NOTIFY_ON;
424 break;
425 }
426 if (wcsicomp(Switch+1,L"ERR")==0)
427 {
428 MsgStream=MSG_STDERR;
429 // Set it immediately when parsing the command line, so it also
430 // affects messages issued while parsing the command line.
431 SetConsoleMsgStream(MSG_STDERR);
432 break;
433 }
434 if (wcsnicomp(Switch+1,L"EML",3)==0)
435 {
436 wcsncpyz(EmailTo,Switch[4]!=0 ? Switch+4:L"@",ASIZE(EmailTo));
437 break;
438 }
439 if (wcsicomp(Switch+1,L"M")==0)
440 {
441 MoreInfo=true;
442 break;
443 }
444 if (wcsicomp(Switch+1,L"NUL")==0)
445 {
446 MsgStream=MSG_NULL;
447 SetConsoleMsgStream(MSG_NULL);
448 break;
449 }
450 if (toupperw(Switch[1])=='D')
451 {
452 for (uint I=2;Switch[I]!=0;I++)
453 switch(toupperw(Switch[I]))
454 {
455 case 'Q':
456 MsgStream=MSG_ERRONLY;
457 SetConsoleMsgStream(MSG_ERRONLY);
458 break;
459 case 'C':
460 DisableCopyright=true;
461 break;
462 case 'D':
463 DisableDone=true;
464 break;
465 case 'P':
466 DisablePercentage=true;
467 break;
468 }
469 break;
470 }
471 if (wcsnicomp(Switch+1,L"OFF",3)==0)
472 {
473 switch(Switch[4])
474 {
475 case 0:
476 case '1':
477 Shutdown=POWERMODE_OFF;
478 break;
479 case '2':
480 Shutdown=POWERMODE_HIBERNATE;
481 break;
482 case '3':
483 Shutdown=POWERMODE_SLEEP;
484 break;
485 case '4':
486 Shutdown=POWERMODE_RESTART;
487 break;
488 }
489 break;
490 }
491 if (wcsicomp(Switch+1,L"VER")==0)
492 {
493 PrintVersion=true;
494 break;
495 }
496 break;
497 case 'K':
498 switch(toupperw(Switch[1]))
499 {
500 case 'B':
501 KeepBroken=true;
502 break;
503 case 0:
504 Lock=true;
505 break;
506 }
507 break;
508 case 'M':
509 switch(toupperw(Switch[1]))
510 {
511 case 'C':
512 {
513 const wchar *Str=Switch+2;
514 if (*Str=='-')
515 for (uint I=0;I<ASIZE(FilterModes);I++)
516 FilterModes[I].State=FILTER_DISABLE;
517 else
518 while (*Str!=0)
519 {
520 int Param1=0,Param2=0;
521 FilterState State=FILTER_AUTO;
522 FilterType Type=FILTER_NONE;
523 if (IsDigit(*Str))
524 {
525 Param1=atoiw(Str);
526 while (IsDigit(*Str))
527 Str++;
528 }
529 if (*Str==':' && IsDigit(Str[1]))
530 {
531 Param2=atoiw(++Str);
532 while (IsDigit(*Str))
533 Str++;
534 }
535 switch(toupperw(*(Str++)))
536 {
537 case 'T': Type=FILTER_PPM; break;
538 case 'E': Type=FILTER_E8; break;
539 case 'D': Type=FILTER_DELTA; break;
540 case 'A': Type=FILTER_AUDIO; break;
541 case 'C': Type=FILTER_RGB; break;
542 case 'I': Type=FILTER_ITANIUM; break;
543 case 'R': Type=FILTER_ARM; break;
544 }
545 if (*Str=='+' || *Str=='-')
546 State=*(Str++)=='+' ? FILTER_FORCE:FILTER_DISABLE;
547 FilterModes[Type].State=State;
548 FilterModes[Type].Param1=Param1;
549 FilterModes[Type].Param2=Param2;
550 }
551 }
552 break;
553 case 'M':
554 break;
555 case 'D':
556 break;
557 case 'S':
558 {
559 wchar StoreNames[1024];
560 wcsncpyz(StoreNames,(Switch[2]==0 ? DefaultStoreList:Switch+2),ASIZE(StoreNames));
561 wchar *Names=StoreNames;
562 while (*Names!=0)
563 {
564 wchar *End=wcschr(Names,';');
565 if (End!=NULL)
566 *End=0;
567 if (*Names=='.')
568 Names++;
569 wchar Mask[NM];
570 if (wcspbrk(Names,L"*?.")==NULL)
571 swprintf(Mask,ASIZE(Mask),L"*.%ls",Names);
572 else
573 wcsncpyz(Mask,Names,ASIZE(Mask));
574 StoreArgs.AddString(Mask);
575 if (End==NULL)
576 break;
577 Names=End+1;
578 }
579 }
580 break;
581 #ifdef RAR_SMP
582 case 'T':
583 Threads=atoiw(Switch+2);
584 if (Threads>MaxPoolThreads || Threads<1)
585 BadSwitch(Switch);
586 else
587 {
588 }
589 break;
590 #endif
591 default:
592 Method=Switch[1]-'0';
593 if (Method>5 || Method<0)
594 BadSwitch(Switch);
595 break;
596 }
597 break;
598 case 'N':
599 case 'X':
600 if (Switch[1]!=0)
601 {
602 StringList *Args=toupperw(Switch[0])=='N' ? &InclArgs:&ExclArgs;
603 if (Switch[1]=='@' && !IsWildcard(Switch))
604 ReadTextFile(Switch+2,Args,false,true,FilelistCharset,true,true,true);
605 else
606 Args->AddString(Switch+1);
607 }
608 break;
609 case 'O':
610 switch(toupperw(Switch[1]))
611 {
612 case '+':
613 Overwrite=OVERWRITE_ALL;
614 break;
615 case '-':
616 Overwrite=OVERWRITE_NONE;
617 break;
618 case 0:
619 Overwrite=OVERWRITE_FORCE_ASK;
620 break;
621 #ifdef _WIN_ALL
622 case 'C':
623 SetCompressedAttr=true;
624 break;
625 #endif
626 case 'H':
627 SaveHardLinks=true;
628 break;
629
630
631 #ifdef SAVE_LINKS
632 case 'L':
633 SaveSymLinks=true;
634 if (toupperw(Switch[2])=='A')
635 AbsoluteLinks=true;
636 break;
637 #endif
638 #ifdef _WIN_ALL
639 case 'N':
640 if (toupperw(Switch[2])=='I')
641 AllowIncompatNames=true;
642 break;
643 #endif
644 case 'R':
645 Overwrite=OVERWRITE_AUTORENAME;
646 break;
647 #ifdef _WIN_ALL
648 case 'S':
649 SaveStreams=true;
650 break;
651 #endif
652 case 'W':
653 ProcessOwners=true;
654 break;
655 default :
656 BadSwitch(Switch);
657 break;
658 }
659 break;
660 case 'P':
661 if (Switch[1]==0)
662 {
663 uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password);
664 eprintf(L"\n");
665 }
666 else
667 {
668 Password.Set(Switch+1);
669 cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0]));
670 }
671 break;
672 #ifndef SFX_MODULE
673 case 'Q':
674 if (toupperw(Switch[1])=='O')
675 switch(toupperw(Switch[2]))
676 {
677 case 0:
678 QOpenMode=QOPEN_AUTO;
679 break;
680 case '-':
681 QOpenMode=QOPEN_NONE;
682 break;
683 case '+':
684 QOpenMode=QOPEN_ALWAYS;
685 break;
686 default:
687 BadSwitch(Switch);
688 break;
689 }
690 else
691 BadSwitch(Switch);
692 break;
693 #endif
694 case 'R':
695 switch(toupperw(Switch[1]))
696 {
697 case 0:
698 Recurse=RECURSE_ALWAYS;
699 break;
700 case '-':
701 Recurse=RECURSE_DISABLE;
702 break;
703 case '0':
704 Recurse=RECURSE_WILDCARDS;
705 break;
706 case 'I':
707 {
708 Priority=atoiw(Switch+2);
709 if (Priority<0 || Priority>15)
710 BadSwitch(Switch);
711 const wchar *ChPtr=wcschr(Switch+2,':');
712 if (ChPtr!=NULL)
713 {
714 SleepTime=atoiw(ChPtr+1);
715 if (SleepTime>1000)
716 BadSwitch(Switch);
717 InitSystemOptions(SleepTime);
718 }
719 SetPriority(Priority);
720 }
721 break;
722 }
723 break;
724 case 'S':
725 if (IsDigit(Switch[1]))
726 {
727 Solid|=SOLID_COUNT;
728 SolidCount=atoiw(&Switch[1]);
729 }
730 else
731 switch(toupperw(Switch[1]))
732 {
733 case 0:
734 Solid|=SOLID_NORMAL;
735 break;
736 case '-':
737 Solid=SOLID_NONE;
738 break;
739 case 'E':
740 Solid|=SOLID_FILEEXT;
741 break;
742 case 'V':
743 Solid|=Switch[2]=='-' ? SOLID_VOLUME_DEPENDENT:SOLID_VOLUME_INDEPENDENT;
744 break;
745 case 'D':
746 Solid|=SOLID_VOLUME_DEPENDENT;
747 break;
748 case 'L':
749 if (IsDigit(Switch[2]))
750 FileSizeLess=atoilw(Switch+2);
751 break;
752 case 'M':
753 if (IsDigit(Switch[2]))
754 FileSizeMore=atoilw(Switch+2);
755 break;
756 case 'C':
757 {
758 bool AlreadyBad=false; // Avoid reporting "bad switch" several times.
759
760 RAR_CHARSET rch=RCH_DEFAULT;
761 switch(toupperw(Switch[2]))
762 {
763 case 'A':
764 rch=RCH_ANSI;
765 break;
766 case 'O':
767 rch=RCH_OEM;
768 break;
769 case 'U':
770 rch=RCH_UNICODE;
771 break;
772 case 'F':
773 rch=RCH_UTF8;
774 break;
775 default :
776 BadSwitch(Switch);
777 AlreadyBad=true;
778 break;
779 };
780 if (!AlreadyBad)
781 if (Switch[3]==0)
782 CommentCharset=FilelistCharset=ErrlogCharset=RedirectCharset=rch;
783 else
784 for (uint I=3;Switch[I]!=0 && !AlreadyBad;I++)
785 switch(toupperw(Switch[I]))
786 {
787 case 'C':
788 CommentCharset=rch;
789 break;
790 case 'L':
791 FilelistCharset=rch;
792 break;
793 case 'R':
794 RedirectCharset=rch;
795 break;
796 default:
797 BadSwitch(Switch);
798 AlreadyBad=true;
799 break;
800 }
801 // Set it immediately when parsing the command line, so it also
802 // affects messages issued while parsing the command line.
803 SetConsoleRedirectCharset(RedirectCharset);
804 }
805 break;
806
807 }
808 break;
809 case 'T':
810 switch(toupperw(Switch[1]))
811 {
812 case 'K':
813 ArcTime=ARCTIME_KEEP;
814 break;
815 case 'L':
816 ArcTime=ARCTIME_LATEST;
817 break;
818 case 'O':
819 SetTimeFilters(Switch+2,true,true);
820 break;
821 case 'N':
822 SetTimeFilters(Switch+2,false,true);
823 break;
824 case 'B':
825 SetTimeFilters(Switch+2,true,false);
826 break;
827 case 'A':
828 SetTimeFilters(Switch+2,false,false);
829 break;
830 case 'S':
831 SetStoreTimeMode(Switch+2);
832 break;
833 case '-':
834 Test=false;
835 break;
836 case 0:
837 Test=true;
838 break;
839 default:
840 BadSwitch(Switch);
841 break;
842 }
843 break;
844 case 'U':
845 if (Switch[1]==0)
846 UpdateFiles=true;
847 else
848 BadSwitch(Switch);
849 break;
850 case 'V':
851 switch(toupperw(Switch[1]))
852 {
853 case 'P':
854 VolumePause=true;
855 break;
856 case 'E':
857 if (toupperw(Switch[2])=='R')
858 VersionControl=atoiw(Switch+3)+1;
859 break;
860 case '-':
861 VolSize=0;
862 break;
863 default:
864 VolSize=VOLSIZE_AUTO; // UnRAR -v switch for list command.
865 break;
866 }
867 break;
868 case 'W':
869 wcsncpyz(TempPath,Switch+1,ASIZE(TempPath));
870 AddEndSlash(TempPath,ASIZE(TempPath));
871 break;
872 case 'Y':
873 AllYes=true;
874 break;
875 case 'Z':
876 if (Switch[1]==0)
877 {
878 // If comment file is not specified, we read data from stdin.
879 wcsncpyz(CommentFile,L"stdin",ASIZE(CommentFile));
880 }
881 else
882 wcsncpyz(CommentFile,Switch+1,ASIZE(CommentFile));
883 break;
884 case '?' :
885 OutHelp(RARX_SUCCESS);
886 break;
887 default :
888 BadSwitch(Switch);
889 break;
890 }
891 }
892 #endif
893
894
895 #if !defined(SFX_MODULE)
BadSwitch(const wchar * Switch)896 void CommandData::BadSwitch(const wchar *Switch)
897 {
898 mprintf(St(MUnknownOption),Switch);
899 ErrHandler.Exit(RARX_USERERROR);
900 }
901 #endif
902
903
ProcessCommand()904 void CommandData::ProcessCommand()
905 {
906 #ifndef SFX_MODULE
907
908 const wchar *SingleCharCommands=L"FUADPXETK";
909 if (Command[0]!=0 && Command[1]!=0 && wcschr(SingleCharCommands,Command[0])!=NULL || *ArcName==0)
910 OutHelp(*Command==0 ? RARX_SUCCESS:RARX_USERERROR); // Return 'success' for 'rar' without parameters.
911
912 const wchar *ArcExt=GetExt(ArcName);
913 #ifdef _UNIX
914 if (ArcExt==NULL && (!FileExist(ArcName) || IsDir(GetFileAttr(ArcName))))
915 wcsncatz(ArcName,L".rar",ASIZE(ArcName));
916 #else
917 if (ArcExt==NULL)
918 wcsncatz(ArcName,L".rar",ASIZE(ArcName));
919 #endif
920 // Treat arcname.part1 as arcname.part1.rar.
921 if (ArcExt!=NULL && wcsnicomp(ArcExt,L".part",5)==0 && IsDigit(ArcExt[5]) &&
922 !FileExist(ArcName))
923 {
924 wchar Name[NM];
925 wcsncpyz(Name,ArcName,ASIZE(Name));
926 wcsncatz(Name,L".rar",ASIZE(Name));
927 if (FileExist(Name))
928 wcsncpyz(ArcName,Name,ASIZE(ArcName));
929 }
930
931 if (wcschr(L"AFUMD",*Command)==NULL)
932 {
933 if (GenerateArcName)
934 {
935 const wchar *Mask=*GenerateMask!=0 ? GenerateMask:DefGenerateMask;
936 GenerateArchiveName(ArcName,ASIZE(ArcName),Mask,false);
937 }
938
939 StringList ArcMasks;
940 ArcMasks.AddString(ArcName);
941 ScanTree Scan(&ArcMasks,Recurse,SaveSymLinks,SCAN_SKIPDIRS);
942 FindData FindData;
943 while (Scan.GetNext(&FindData)==SCAN_SUCCESS)
944 AddArcName(FindData.Name);
945 }
946 else
947 AddArcName(ArcName);
948 #endif
949
950 switch(Command[0])
951 {
952 case 'P':
953 case 'X':
954 case 'E':
955 case 'T':
956 {
957 CmdExtract Extract(this);
958 Extract.DoExtract();
959 }
960 break;
961 #ifndef SILENT
962 case 'V':
963 case 'L':
964 ListArchive(this);
965 break;
966 default:
967 OutHelp(RARX_USERERROR);
968 #endif
969 }
970 if (!BareOutput)
971 mprintf(L"\n");
972 }
973
974
AddArcName(const wchar * Name)975 void CommandData::AddArcName(const wchar *Name)
976 {
977 ArcNames.AddString(Name);
978 }
979
980
GetArcName(wchar * Name,int MaxSize)981 bool CommandData::GetArcName(wchar *Name,int MaxSize)
982 {
983 return ArcNames.GetString(Name,MaxSize);
984 }
985
986
IsSwitch(int Ch)987 bool CommandData::IsSwitch(int Ch)
988 {
989 #if defined(_WIN_ALL) || defined(_EMX)
990 return Ch=='-' || Ch=='/';
991 #else
992 return Ch=='-';
993 #endif
994 }
995
996
997 #ifndef SFX_MODULE
GetExclAttr(const wchar * Str,bool & Dir)998 uint CommandData::GetExclAttr(const wchar *Str,bool &Dir)
999 {
1000 if (IsDigit(*Str))
1001 return wcstol(Str,NULL,0);
1002
1003 uint Attr=0;
1004 while (*Str!=0)
1005 {
1006 switch(toupperw(*Str))
1007 {
1008 case 'D':
1009 Dir=true;
1010 break;
1011 #ifdef _UNIX
1012 case 'V':
1013 Attr|=S_IFCHR;
1014 break;
1015 #elif defined(_WIN_ALL) || defined(_EMX)
1016 case 'R':
1017 Attr|=0x1;
1018 break;
1019 case 'H':
1020 Attr|=0x2;
1021 break;
1022 case 'S':
1023 Attr|=0x4;
1024 break;
1025 case 'A':
1026 Attr|=0x20;
1027 break;
1028 #endif
1029 }
1030 Str++;
1031 }
1032 return Attr;
1033 }
1034 #endif
1035
1036
1037
1038
1039 #ifndef SFX_MODULE
CheckWinSize()1040 bool CommandData::CheckWinSize()
1041 {
1042 // Define 0x100000000 as macro to avoid troubles with older compilers.
1043 const uint64 MaxDictSize=INT32TO64(1,0);
1044 // Limit the dictionary size to 4 GB.
1045 for (uint64 I=0x10000;I<=MaxDictSize;I*=2)
1046 if (WinSize==I)
1047 return true;
1048 WinSize=0x400000;
1049 return false;
1050 }
1051 #endif
1052
1053
1054 #ifndef SFX_MODULE
ReportWrongSwitches(RARFORMAT Format)1055 void CommandData::ReportWrongSwitches(RARFORMAT Format)
1056 {
1057 if (Format==RARFMT15)
1058 {
1059 if (HashType!=HASH_CRC32)
1060 uiMsg(UIERROR_INCOMPATSWITCH,L"-ht",4);
1061 #ifdef _WIN_ALL
1062 if (SaveSymLinks)
1063 uiMsg(UIERROR_INCOMPATSWITCH,L"-ol",4);
1064 #endif
1065 if (SaveHardLinks)
1066 uiMsg(UIERROR_INCOMPATSWITCH,L"-oh",4);
1067
1068 #ifdef _WIN_ALL
1069 // Do not report a wrong dictionary size here, because we are not sure
1070 // yet about archive format. We can switch to RAR5 mode later
1071 // if we update RAR5 archive.
1072
1073
1074 #endif
1075 if (QOpenMode!=QOPEN_AUTO)
1076 uiMsg(UIERROR_INCOMPATSWITCH,L"-qo",4);
1077 }
1078 if (Format==RARFMT50)
1079 {
1080 }
1081 }
1082 #endif
1083