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