cmddata.cpp 27 KB

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