1114 lines
27 KiB
C++
1114 lines
27 KiB
C++
|
#include "rar.hpp"
|
||
|
|
||
|
#include "cmdfilter.cpp"
|
||
|
#include "cmdmix.cpp"
|
||
|
|
||
|
CommandData::CommandData()
|
||
|
{
|
||
|
Init();
|
||
|
}
|
||
|
|
||
|
|
||
|
void CommandData::Init()
|
||
|
{
|
||
|
RAROptions::Init();
|
||
|
|
||
|
*Command=0;
|
||
|
*ArcName=0;
|
||
|
FileLists=false;
|
||
|
NoMoreSwitches=false;
|
||
|
|
||
|
ListMode=RCLM_AUTO;
|
||
|
|
||
|
BareOutput=false;
|
||
|
|
||
|
|
||
|
FileArgs.Reset();
|
||
|
ExclArgs.Reset();
|
||
|
InclArgs.Reset();
|
||
|
StoreArgs.Reset();
|
||
|
ArcNames.Reset();
|
||
|
NextVolSizes.Reset();
|
||
|
}
|
||
|
|
||
|
|
||
|
// Return the pointer to next position in the string and store dynamically
|
||
|
// allocated command line parameter in Par.
|
||
|
static const wchar *AllocCmdParam(const wchar *CmdLine,wchar **Par)
|
||
|
{
|
||
|
const wchar *NextCmd=GetCmdParam(CmdLine,NULL,0);
|
||
|
if (NextCmd==NULL)
|
||
|
return NULL;
|
||
|
size_t ParSize=NextCmd-CmdLine+2; // Parameter size including the trailing zero.
|
||
|
*Par=(wchar *)malloc(ParSize*sizeof(wchar));
|
||
|
if (*Par==NULL)
|
||
|
return NULL;
|
||
|
return GetCmdParam(CmdLine,*Par,ParSize);
|
||
|
}
|
||
|
|
||
|
|
||
|
#if !defined(SFX_MODULE)
|
||
|
void CommandData::ParseCommandLine(bool Preprocess,int argc, char *argv[])
|
||
|
{
|
||
|
*Command=0;
|
||
|
NoMoreSwitches=false;
|
||
|
#ifdef CUSTOM_CMDLINE_PARSER
|
||
|
// In Windows we may prefer to implement our own command line parser
|
||
|
// to avoid replacing \" by " in standard parser. Such replacing corrupts
|
||
|
// destination paths like "dest path\" in extraction commands.
|
||
|
const wchar *CmdLine=GetCommandLine();
|
||
|
|
||
|
wchar *Par;
|
||
|
for (bool FirstParam=true;;FirstParam=false)
|
||
|
{
|
||
|
if ((CmdLine=AllocCmdParam(CmdLine,&Par))==NULL)
|
||
|
break;
|
||
|
if (!FirstParam) // First parameter is the executable name.
|
||
|
if (Preprocess)
|
||
|
PreprocessArg(Par);
|
||
|
else
|
||
|
ParseArg(Par);
|
||
|
free(Par);
|
||
|
}
|
||
|
#else
|
||
|
Array<wchar> Arg;
|
||
|
for (int I=1;I<argc;I++)
|
||
|
{
|
||
|
Arg.Alloc(strlen(argv[I])+1);
|
||
|
CharToWide(argv[I],&Arg[0],Arg.Size());
|
||
|
if (Preprocess)
|
||
|
PreprocessArg(&Arg[0]);
|
||
|
else
|
||
|
ParseArg(&Arg[0]);
|
||
|
}
|
||
|
#endif
|
||
|
if (!Preprocess)
|
||
|
ParseDone();
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#if !defined(SFX_MODULE)
|
||
|
void CommandData::ParseArg(wchar *Arg)
|
||
|
{
|
||
|
if (IsSwitch(*Arg) && !NoMoreSwitches)
|
||
|
if (Arg[1]=='-' && Arg[2]==0)
|
||
|
NoMoreSwitches=true;
|
||
|
else
|
||
|
ProcessSwitch(Arg+1);
|
||
|
else
|
||
|
if (*Command==0)
|
||
|
{
|
||
|
wcsncpyz(Command,Arg,ASIZE(Command));
|
||
|
|
||
|
|
||
|
*Command=toupperw(*Command);
|
||
|
// 'I' and 'S' commands can contain case sensitive strings after
|
||
|
// the first character, so we must not modify their case.
|
||
|
// 'S' can contain SFX name, which case is important in Unix.
|
||
|
if (*Command!='I' && *Command!='S')
|
||
|
wcsupper(Command);
|
||
|
if (*Command=='P') // Enforce -idq for print command.
|
||
|
{
|
||
|
MsgStream=MSG_ERRONLY;
|
||
|
SetConsoleMsgStream(MSG_ERRONLY);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (*ArcName==0)
|
||
|
wcsncpyz(ArcName,Arg,ASIZE(ArcName));
|
||
|
else
|
||
|
{
|
||
|
// Check if last character is the path separator.
|
||
|
size_t Length=wcslen(Arg);
|
||
|
wchar EndChar=Length==0 ? 0:Arg[Length-1];
|
||
|
bool EndSeparator=IsDriveDiv(EndChar) || IsPathDiv(EndChar);
|
||
|
|
||
|
wchar CmdChar=toupperw(*Command);
|
||
|
bool Add=wcschr(L"AFUM",CmdChar)!=NULL;
|
||
|
bool Extract=CmdChar=='X' || CmdChar=='E';
|
||
|
bool Repair=CmdChar=='R' && Command[1]==0;
|
||
|
if (EndSeparator && !Add)
|
||
|
wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
|
||
|
else
|
||
|
if ((Add || CmdChar=='T') && (*Arg!='@' || ListMode==RCLM_REJECT_LISTS))
|
||
|
FileArgs.AddString(Arg);
|
||
|
else
|
||
|
{
|
||
|
FindData FileData;
|
||
|
bool Found=FindFile::FastFind(Arg,&FileData);
|
||
|
if ((!Found || ListMode==RCLM_ACCEPT_LISTS) &&
|
||
|
ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg+1))
|
||
|
{
|
||
|
FileLists=true;
|
||
|
|
||
|
ReadTextFile(Arg+1,&FileArgs,false,true,FilelistCharset,true,true,true);
|
||
|
|
||
|
}
|
||
|
else // We use 'destpath\' when extracting and reparing.
|
||
|
if (Found && FileData.IsDir && (Extract || Repair) && *ExtrPath==0)
|
||
|
{
|
||
|
wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
|
||
|
AddEndSlash(ExtrPath,ASIZE(ExtrPath));
|
||
|
}
|
||
|
else
|
||
|
FileArgs.AddString(Arg);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
void CommandData::ParseDone()
|
||
|
{
|
||
|
if (FileArgs.ItemsCount()==0 && !FileLists)
|
||
|
FileArgs.AddString(MASKALL);
|
||
|
wchar CmdChar=toupperw(Command[0]);
|
||
|
bool Extract=CmdChar=='X' || CmdChar=='E' || CmdChar=='P';
|
||
|
if (Test && Extract)
|
||
|
Test=false; // Switch '-t' is senseless for 'X', 'E', 'P' commands.
|
||
|
|
||
|
// Suppress the copyright message and final end of line for 'lb' and 'vb'.
|
||
|
if ((CmdChar=='L' || CmdChar=='V') && Command[1]=='B')
|
||
|
BareOutput=true;
|
||
|
}
|
||
|
|
||
|
|
||
|
#if !defined(SFX_MODULE)
|
||
|
void CommandData::ParseEnvVar()
|
||
|
{
|
||
|
char *EnvStr=getenv("RAR");
|
||
|
if (EnvStr!=NULL)
|
||
|
{
|
||
|
Array<wchar> EnvStrW(strlen(EnvStr)+1);
|
||
|
CharToWide(EnvStr,&EnvStrW[0],EnvStrW.Size());
|
||
|
ProcessSwitchesString(&EnvStrW[0]);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
#if !defined(SFX_MODULE)
|
||
|
// Preprocess those parameters, which must be processed before the rest of
|
||
|
// command line. Return 'false' to stop further processing.
|
||
|
void CommandData::PreprocessArg(const wchar *Arg)
|
||
|
{
|
||
|
if (IsSwitch(Arg[0]) && !NoMoreSwitches)
|
||
|
{
|
||
|
Arg++;
|
||
|
if (Arg[0]=='-' && Arg[1]==0) // Switch "--".
|
||
|
NoMoreSwitches=true;
|
||
|
if (wcsicomp(Arg,L"cfg-")==0)
|
||
|
ConfigDisabled=true;
|
||
|
if (wcsnicomp(Arg,L"ilog",4)==0)
|
||
|
{
|
||
|
// Ensure that correct log file name is already set
|
||
|
// if we need to report an error when processing the command line.
|
||
|
ProcessSwitch(Arg);
|
||
|
InitLogOptions(LogName,ErrlogCharset);
|
||
|
}
|
||
|
if (wcsnicomp(Arg,L"sc",2)==0)
|
||
|
{
|
||
|
// Process -sc before reading any file lists.
|
||
|
ProcessSwitch(Arg);
|
||
|
if (*LogName!=0)
|
||
|
InitLogOptions(LogName,ErrlogCharset);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (*Command==0)
|
||
|
wcsncpy(Command,Arg,ASIZE(Command)); // Need for rar.ini.
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#if !defined(SFX_MODULE)
|
||
|
void CommandData::ReadConfig()
|
||
|
{
|
||
|
StringList List;
|
||
|
if (ReadTextFile(DefConfigName,&List,true))
|
||
|
{
|
||
|
wchar *Str;
|
||
|
while ((Str=List.GetString())!=NULL)
|
||
|
{
|
||
|
while (IsSpace(*Str))
|
||
|
Str++;
|
||
|
if (wcsnicomp(Str,L"switches=",9)==0)
|
||
|
ProcessSwitchesString(Str+9);
|
||
|
if (*Command!=0)
|
||
|
{
|
||
|
wchar Cmd[16];
|
||
|
wcsncpyz(Cmd,Command,ASIZE(Cmd));
|
||
|
wchar C0=toupperw(Cmd[0]);
|
||
|
wchar C1=toupperw(Cmd[1]);
|
||
|
if (C0=='I' || C0=='L' || C0=='M' || C0=='S' || C0=='V')
|
||
|
Cmd[1]=0;
|
||
|
if (C0=='R' && (C1=='R' || C1=='V'))
|
||
|
Cmd[2]=0;
|
||
|
wchar SwName[16+ASIZE(Cmd)];
|
||
|
swprintf(SwName,ASIZE(SwName),L"switches_%ls=",Cmd);
|
||
|
size_t Length=wcslen(SwName);
|
||
|
if (wcsnicomp(Str,SwName,Length)==0)
|
||
|
ProcessSwitchesString(Str+Length);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#if !defined(SFX_MODULE)
|
||
|
void CommandData::ProcessSwitchesString(const wchar *Str)
|
||
|
{
|
||
|
wchar *Par;
|
||
|
while ((Str=AllocCmdParam(Str,&Par))!=NULL)
|
||
|
{
|
||
|
if (IsSwitch(*Par))
|
||
|
ProcessSwitch(Par+1);
|
||
|
free(Par);
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#if !defined(SFX_MODULE)
|
||
|
void CommandData::ProcessSwitch(const wchar *Switch)
|
||
|
{
|
||
|
|
||
|
switch(toupperw(Switch[0]))
|
||
|
{
|
||
|
case '@':
|
||
|
ListMode=Switch[1]=='+' ? RCLM_ACCEPT_LISTS:RCLM_REJECT_LISTS;
|
||
|
break;
|
||
|
case 'A':
|
||
|
switch(toupperw(Switch[1]))
|
||
|
{
|
||
|
case 'C':
|
||
|
ClearArc=true;
|
||
|
break;
|
||
|
case 'D':
|
||
|
if (Switch[2]==0)
|
||
|
AppendArcNameToPath=APPENDARCNAME_DESTPATH;
|
||
|
else
|
||
|
if (Switch[2]=='1')
|
||
|
AppendArcNameToPath=APPENDARCNAME_OWNSUBDIR;
|
||
|
else
|
||
|
if (Switch[2]=='2')
|
||
|
AppendArcNameToPath=APPENDARCNAME_OWNDIR;
|
||
|
break;
|
||
|
#ifndef SFX_MODULE
|
||
|
case 'G':
|
||
|
if (Switch[2]=='-' && Switch[3]==0)
|
||
|
GenerateArcName=0;
|
||
|
else
|
||
|
if (toupperw(Switch[2])=='F')
|
||
|
wcsncpyz(DefGenerateMask,Switch+3,ASIZE(DefGenerateMask));
|
||
|
else
|
||
|
{
|
||
|
GenerateArcName=true;
|
||
|
wcsncpyz(GenerateMask,Switch+2,ASIZE(GenerateMask));
|
||
|
}
|
||
|
break;
|
||
|
#endif
|
||
|
case 'I':
|
||
|
IgnoreGeneralAttr=true;
|
||
|
break;
|
||
|
case 'N': // Reserved for archive name.
|
||
|
break;
|
||
|
case 'O':
|
||
|
AddArcOnly=true;
|
||
|
break;
|
||
|
case 'P':
|
||
|
wcsncpyz(ArcPath,Switch+2,ASIZE(ArcPath));
|
||
|
break;
|
||
|
case 'S':
|
||
|
SyncFiles=true;
|
||
|
break;
|
||
|
default:
|
||
|
BadSwitch(Switch);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 'C':
|
||
|
if (Switch[2]==0)
|
||
|
switch(toupperw(Switch[1]))
|
||
|
{
|
||
|
case '-':
|
||
|
DisableComment=true;
|
||
|
break;
|
||
|
case 'U':
|
||
|
ConvertNames=NAMES_UPPERCASE;
|
||
|
break;
|
||
|
case 'L':
|
||
|
ConvertNames=NAMES_LOWERCASE;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 'D':
|
||
|
if (Switch[2]==0)
|
||
|
switch(toupperw(Switch[1]))
|
||
|
{
|
||
|
case 'S':
|
||
|
DisableSortSolid=true;
|
||
|
break;
|
||
|
case 'H':
|
||
|
OpenShared=true;
|
||
|
break;
|
||
|
case 'F':
|
||
|
DeleteFiles=true;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 'E':
|
||
|
switch(toupperw(Switch[1]))
|
||
|
{
|
||
|
case 'P':
|
||
|
switch(Switch[2])
|
||
|
{
|
||
|
case 0:
|
||
|
ExclPath=EXCL_SKIPWHOLEPATH;
|
||
|
break;
|
||
|
case '1':
|
||
|
ExclPath=EXCL_BASEPATH;
|
||
|
break;
|
||
|
case '2':
|
||
|
ExclPath=EXCL_SAVEFULLPATH;
|
||
|
break;
|
||
|
case '3':
|
||
|
ExclPath=EXCL_ABSPATH;
|
||
|
break;
|
||
|
case '4':
|
||
|
wcsncpyz(ExclArcPath,Switch+3,ASIZE(ExclArcPath));
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
if (Switch[1]=='+')
|
||
|
{
|
||
|
InclFileAttr|=GetExclAttr(Switch+2,InclDir);
|
||
|
InclAttrSet=true;
|
||
|
}
|
||
|
else
|
||
|
ExclFileAttr|=GetExclAttr(Switch+1,ExclDir);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 'F':
|
||
|
if (Switch[1]==0)
|
||
|
FreshFiles=true;
|
||
|
else
|
||
|
BadSwitch(Switch);
|
||
|
break;
|
||
|
case 'H':
|
||
|
switch (toupperw(Switch[1]))
|
||
|
{
|
||
|
case 'P':
|
||
|
EncryptHeaders=true;
|
||
|
if (Switch[2]!=0)
|
||
|
{
|
||
|
if (wcslen(Switch+2)>=MAXPASSWORD)
|
||
|
uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
|
||
|
Password.Set(Switch+2);
|
||
|
cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0]));
|
||
|
}
|
||
|
else
|
||
|
if (!Password.IsSet())
|
||
|
{
|
||
|
uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password);
|
||
|
eprintf(L"\n");
|
||
|
}
|
||
|
break;
|
||
|
default :
|
||
|
BadSwitch(Switch);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 'I':
|
||
|
if (wcsnicomp(Switch+1,L"LOG",3)==0)
|
||
|
{
|
||
|
wcsncpyz(LogName,Switch[4]!=0 ? Switch+4:DefLogName,ASIZE(LogName));
|
||
|
break;
|
||
|
}
|
||
|
if (wcsnicomp(Switch+1,L"SND",3)==0)
|
||
|
{
|
||
|
Sound=Switch[4]=='-' ? SOUND_NOTIFY_OFF : SOUND_NOTIFY_ON;
|
||
|
break;
|
||
|
}
|
||
|
if (wcsicomp(Switch+1,L"ERR")==0)
|
||
|
{
|
||
|
MsgStream=MSG_STDERR;
|
||
|
// Set it immediately when parsing the command line, so it also
|
||
|
// affects messages issued while parsing the command line.
|
||
|
SetConsoleMsgStream(MSG_STDERR);
|
||
|
break;
|
||
|
}
|
||
|
if (wcsnicomp(Switch+1,L"EML",3)==0)
|
||
|
{
|
||
|
wcsncpyz(EmailTo,Switch[4]!=0 ? Switch+4:L"@",ASIZE(EmailTo));
|
||
|
break;
|
||
|
}
|
||
|
if (wcsicomp(Switch+1,L"M")==0) // For compatibility with pre-WinRAR 6.0 -im syntax. Replaced with -idv.
|
||
|
{
|
||
|
VerboseOutput=true;
|
||
|
break;
|
||
|
}
|
||
|
if (wcsicomp(Switch+1,L"NUL")==0)
|
||
|
{
|
||
|
MsgStream=MSG_NULL;
|
||
|
SetConsoleMsgStream(MSG_NULL);
|
||
|
break;
|
||
|
}
|
||
|
if (toupperw(Switch[1])=='D')
|
||
|
{
|
||
|
for (uint I=2;Switch[I]!=0;I++)
|
||
|
switch(toupperw(Switch[I]))
|
||
|
{
|
||
|
case 'Q':
|
||
|
MsgStream=MSG_ERRONLY;
|
||
|
SetConsoleMsgStream(MSG_ERRONLY);
|
||
|
break;
|
||
|
case 'C':
|
||
|
DisableCopyright=true;
|
||
|
break;
|
||
|
case 'D':
|
||
|
DisableDone=true;
|
||
|
break;
|
||
|
case 'P':
|
||
|
DisablePercentage=true;
|
||
|
break;
|
||
|
case 'N':
|
||
|
DisableNames=true;
|
||
|
break;
|
||
|
case 'V':
|
||
|
VerboseOutput=true;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
if (wcsnicomp(Switch+1,L"OFF",3)==0)
|
||
|
{
|
||
|
switch(Switch[4])
|
||
|
{
|
||
|
case 0:
|
||
|
case '1':
|
||
|
Shutdown=POWERMODE_OFF;
|
||
|
break;
|
||
|
case '2':
|
||
|
Shutdown=POWERMODE_HIBERNATE;
|
||
|
break;
|
||
|
case '3':
|
||
|
Shutdown=POWERMODE_SLEEP;
|
||
|
break;
|
||
|
case '4':
|
||
|
Shutdown=POWERMODE_RESTART;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
if (wcsicomp(Switch+1,L"VER")==0)
|
||
|
{
|
||
|
PrintVersion=true;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 'K':
|
||
|
switch(toupperw(Switch[1]))
|
||
|
{
|
||
|
case 'B':
|
||
|
KeepBroken=true;
|
||
|
break;
|
||
|
case 0:
|
||
|
Lock=true;
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 'M':
|
||
|
switch(toupperw(Switch[1]))
|
||
|
{
|
||
|
case 'C':
|
||
|
{
|
||
|
const wchar *Str=Switch+2;
|
||
|
if (*Str=='-')
|
||
|
for (uint I=0;I<ASIZE(FilterModes);I++)
|
||
|
FilterModes[I].State=FILTER_DISABLE;
|
||
|
else
|
||
|
while (*Str!=0)
|
||
|
{
|
||
|
int Param1=0,Param2=0;
|
||
|
FilterState State=FILTER_AUTO;
|
||
|
FilterType Type=FILTER_NONE;
|
||
|
if (IsDigit(*Str))
|
||
|
{
|
||
|
Param1=atoiw(Str);
|
||
|
while (IsDigit(*Str))
|
||
|
Str++;
|
||
|
}
|
||
|
if (*Str==':' && IsDigit(Str[1]))
|
||
|
{
|
||
|
Param2=atoiw(++Str);
|
||
|
while (IsDigit(*Str))
|
||
|
Str++;
|
||
|
}
|
||
|
switch(toupperw(*(Str++)))
|
||
|
{
|
||
|
case 'T': Type=FILTER_PPM; break;
|
||
|
case 'E': Type=FILTER_E8; break;
|
||
|
case 'D': Type=FILTER_DELTA; break;
|
||
|
case 'A': Type=FILTER_AUDIO; break;
|
||
|
case 'C': Type=FILTER_RGB; break;
|
||
|
case 'R': Type=FILTER_ARM; break;
|
||
|
}
|
||
|
if (*Str=='+' || *Str=='-')
|
||
|
State=*(Str++)=='+' ? FILTER_FORCE:FILTER_DISABLE;
|
||
|
FilterModes[Type].State=State;
|
||
|
FilterModes[Type].Param1=Param1;
|
||
|
FilterModes[Type].Param2=Param2;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case 'M':
|
||
|
break;
|
||
|
case 'D':
|
||
|
break;
|
||
|
case 'E':
|
||
|
if (toupperw(Switch[2])=='S' && Switch[3]==0)
|
||
|
SkipEncrypted=true;
|
||
|
break;
|
||
|
case 'S':
|
||
|
{
|
||
|
wchar StoreNames[1024];
|
||
|
wcsncpyz(StoreNames,(Switch[2]==0 ? DefaultStoreList:Switch+2),ASIZE(StoreNames));
|
||
|
wchar *Names=StoreNames;
|
||
|
while (*Names!=0)
|
||
|
{
|
||
|
wchar *End=wcschr(Names,';');
|
||
|
if (End!=NULL)
|
||
|
*End=0;
|
||
|
if (*Names=='.')
|
||
|
Names++;
|
||
|
wchar Mask[NM];
|
||
|
if (wcspbrk(Names,L"*?.")==NULL)
|
||
|
swprintf(Mask,ASIZE(Mask),L"*.%ls",Names);
|
||
|
else
|
||
|
wcsncpyz(Mask,Names,ASIZE(Mask));
|
||
|
StoreArgs.AddString(Mask);
|
||
|
if (End==NULL)
|
||
|
break;
|
||
|
Names=End+1;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
#ifdef RAR_SMP
|
||
|
case 'T':
|
||
|
Threads=atoiw(Switch+2);
|
||
|
if (Threads>MaxPoolThreads || Threads<1)
|
||
|
BadSwitch(Switch);
|
||
|
else
|
||
|
{
|
||
|
}
|
||
|
break;
|
||
|
#endif
|
||
|
default:
|
||
|
Method=Switch[1]-'0';
|
||
|
if (Method>5 || Method<0)
|
||
|
BadSwitch(Switch);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 'N':
|
||
|
case 'X':
|
||
|
if (Switch[1]!=0)
|
||
|
{
|
||
|
StringList *Args=toupperw(Switch[0])=='N' ? &InclArgs:&ExclArgs;
|
||
|
if (Switch[1]=='@' && !IsWildcard(Switch))
|
||
|
ReadTextFile(Switch+2,Args,false,true,FilelistCharset,true,true,true);
|
||
|
else
|
||
|
Args->AddString(Switch+1);
|
||
|
}
|
||
|
break;
|
||
|
case 'O':
|
||
|
switch(toupperw(Switch[1]))
|
||
|
{
|
||
|
case '+':
|
||
|
Overwrite=OVERWRITE_ALL;
|
||
|
break;
|
||
|
case '-':
|
||
|
Overwrite=OVERWRITE_NONE;
|
||
|
break;
|
||
|
case 0:
|
||
|
Overwrite=OVERWRITE_FORCE_ASK;
|
||
|
break;
|
||
|
#ifdef _WIN_ALL
|
||
|
case 'C':
|
||
|
SetCompressedAttr=true;
|
||
|
break;
|
||
|
#endif
|
||
|
case 'H':
|
||
|
SaveHardLinks=true;
|
||
|
break;
|
||
|
|
||
|
|
||
|
#ifdef SAVE_LINKS
|
||
|
case 'L':
|
||
|
SaveSymLinks=true;
|
||
|
if (toupperw(Switch[2])=='A')
|
||
|
AbsoluteLinks=true;
|
||
|
break;
|
||
|
#endif
|
||
|
#ifdef _WIN_ALL
|
||
|
case 'N':
|
||
|
if (toupperw(Switch[2])=='I')
|
||
|
AllowIncompatNames=true;
|
||
|
break;
|
||
|
#endif
|
||
|
case 'P':
|
||
|
wcsncpyz(ExtrPath,Switch+2,ASIZE(ExtrPath));
|
||
|
AddEndSlash(ExtrPath,ASIZE(ExtrPath));
|
||
|
break;
|
||
|
case 'R':
|
||
|
Overwrite=OVERWRITE_AUTORENAME;
|
||
|
break;
|
||
|
#ifdef _WIN_ALL
|
||
|
case 'S':
|
||
|
SaveStreams=true;
|
||
|
break;
|
||
|
#endif
|
||
|
case 'W':
|
||
|
ProcessOwners=true;
|
||
|
break;
|
||
|
default :
|
||
|
BadSwitch(Switch);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 'P':
|
||
|
if (Switch[1]==0)
|
||
|
{
|
||
|
uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password);
|
||
|
eprintf(L"\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (wcslen(Switch+1)>=MAXPASSWORD)
|
||
|
uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
|
||
|
Password.Set(Switch+1);
|
||
|
cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0]));
|
||
|
}
|
||
|
break;
|
||
|
#ifndef SFX_MODULE
|
||
|
case 'Q':
|
||
|
if (toupperw(Switch[1])=='O')
|
||
|
switch(toupperw(Switch[2]))
|
||
|
{
|
||
|
case 0:
|
||
|
QOpenMode=QOPEN_AUTO;
|
||
|
break;
|
||
|
case '-':
|
||
|
QOpenMode=QOPEN_NONE;
|
||
|
break;
|
||
|
case '+':
|
||
|
QOpenMode=QOPEN_ALWAYS;
|
||
|
break;
|
||
|
default:
|
||
|
BadSwitch(Switch);
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
BadSwitch(Switch);
|
||
|
break;
|
||
|
#endif
|
||
|
case 'R':
|
||
|
switch(toupperw(Switch[1]))
|
||
|
{
|
||
|
case 0:
|
||
|
Recurse=RECURSE_ALWAYS;
|
||
|
break;
|
||
|
case '-':
|
||
|
Recurse=RECURSE_DISABLE;
|
||
|
break;
|
||
|
case '0':
|
||
|
Recurse=RECURSE_WILDCARDS;
|
||
|
break;
|
||
|
case 'I':
|
||
|
{
|
||
|
Priority=atoiw(Switch+2);
|
||
|
if (Priority<0 || Priority>15)
|
||
|
BadSwitch(Switch);
|
||
|
const wchar *ChPtr=wcschr(Switch+2,':');
|
||
|
if (ChPtr!=NULL)
|
||
|
{
|
||
|
SleepTime=atoiw(ChPtr+1);
|
||
|
if (SleepTime>1000)
|
||
|
BadSwitch(Switch);
|
||
|
InitSystemOptions(SleepTime);
|
||
|
}
|
||
|
SetPriority(Priority);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 'S':
|
||
|
if (IsDigit(Switch[1]))
|
||
|
{
|
||
|
Solid|=SOLID_COUNT;
|
||
|
SolidCount=atoiw(&Switch[1]);
|
||
|
}
|
||
|
else
|
||
|
switch(toupperw(Switch[1]))
|
||
|
{
|
||
|
case 0:
|
||
|
Solid|=SOLID_NORMAL;
|
||
|
break;
|
||
|
case '-':
|
||
|
Solid=SOLID_NONE;
|
||
|
break;
|
||
|
case 'E':
|
||
|
Solid|=SOLID_FILEEXT;
|
||
|
break;
|
||
|
case 'V':
|
||
|
Solid|=Switch[2]=='-' ? SOLID_VOLUME_DEPENDENT:SOLID_VOLUME_INDEPENDENT;
|
||
|
break;
|
||
|
case 'D':
|
||
|
Solid|=SOLID_VOLUME_DEPENDENT;
|
||
|
break;
|
||
|
case 'I':
|
||
|
ProhibitConsoleInput();
|
||
|
wcsncpyz(UseStdin,Switch[2] ? Switch+2:L"stdin",ASIZE(UseStdin));
|
||
|
break;
|
||
|
case 'L':
|
||
|
if (IsDigit(Switch[2]))
|
||
|
FileSizeLess=atoilw(Switch+2);
|
||
|
break;
|
||
|
case 'M':
|
||
|
if (IsDigit(Switch[2]))
|
||
|
FileSizeMore=atoilw(Switch+2);
|
||
|
break;
|
||
|
case 'C':
|
||
|
{
|
||
|
bool AlreadyBad=false; // Avoid reporting "bad switch" several times.
|
||
|
|
||
|
RAR_CHARSET rch=RCH_DEFAULT;
|
||
|
switch(toupperw(Switch[2]))
|
||
|
{
|
||
|
case 'A':
|
||
|
rch=RCH_ANSI;
|
||
|
break;
|
||
|
case 'O':
|
||
|
rch=RCH_OEM;
|
||
|
break;
|
||
|
case 'U':
|
||
|
rch=RCH_UNICODE;
|
||
|
break;
|
||
|
case 'F':
|
||
|
rch=RCH_UTF8;
|
||
|
break;
|
||
|
default :
|
||
|
BadSwitch(Switch);
|
||
|
AlreadyBad=true;
|
||
|
break;
|
||
|
};
|
||
|
if (!AlreadyBad)
|
||
|
if (Switch[3]==0)
|
||
|
CommentCharset=FilelistCharset=ErrlogCharset=RedirectCharset=rch;
|
||
|
else
|
||
|
for (uint I=3;Switch[I]!=0 && !AlreadyBad;I++)
|
||
|
switch(toupperw(Switch[I]))
|
||
|
{
|
||
|
case 'C':
|
||
|
CommentCharset=rch;
|
||
|
break;
|
||
|
case 'L':
|
||
|
FilelistCharset=rch;
|
||
|
break;
|
||
|
case 'R':
|
||
|
RedirectCharset=rch;
|
||
|
break;
|
||
|
default:
|
||
|
BadSwitch(Switch);
|
||
|
AlreadyBad=true;
|
||
|
break;
|
||
|
}
|
||
|
// Set it immediately when parsing the command line, so it also
|
||
|
// affects messages issued while parsing the command line.
|
||
|
SetConsoleRedirectCharset(RedirectCharset);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
case 'T':
|
||
|
switch(toupperw(Switch[1]))
|
||
|
{
|
||
|
case 'K':
|
||
|
ArcTime=ARCTIME_KEEP;
|
||
|
break;
|
||
|
case 'L':
|
||
|
ArcTime=ARCTIME_LATEST;
|
||
|
break;
|
||
|
case 'O':
|
||
|
SetTimeFilters(Switch+2,true,true);
|
||
|
break;
|
||
|
case 'N':
|
||
|
SetTimeFilters(Switch+2,false,true);
|
||
|
break;
|
||
|
case 'B':
|
||
|
SetTimeFilters(Switch+2,true,false);
|
||
|
break;
|
||
|
case 'A':
|
||
|
SetTimeFilters(Switch+2,false,false);
|
||
|
break;
|
||
|
case 'S':
|
||
|
SetStoreTimeMode(Switch+2);
|
||
|
break;
|
||
|
case '-':
|
||
|
Test=false;
|
||
|
break;
|
||
|
case 0:
|
||
|
Test=true;
|
||
|
break;
|
||
|
default:
|
||
|
BadSwitch(Switch);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 'U':
|
||
|
if (Switch[1]==0)
|
||
|
UpdateFiles=true;
|
||
|
else
|
||
|
BadSwitch(Switch);
|
||
|
break;
|
||
|
case 'V':
|
||
|
switch(toupperw(Switch[1]))
|
||
|
{
|
||
|
case 'P':
|
||
|
VolumePause=true;
|
||
|
break;
|
||
|
case 'E':
|
||
|
if (toupperw(Switch[2])=='R')
|
||
|
VersionControl=atoiw(Switch+3)+1;
|
||
|
break;
|
||
|
case '-':
|
||
|
VolSize=0;
|
||
|
break;
|
||
|
default:
|
||
|
VolSize=VOLSIZE_AUTO; // UnRAR -v switch for list command.
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case 'W':
|
||
|
wcsncpyz(TempPath,Switch+1,ASIZE(TempPath));
|
||
|
AddEndSlash(TempPath,ASIZE(TempPath));
|
||
|
break;
|
||
|
case 'Y':
|
||
|
AllYes=true;
|
||
|
break;
|
||
|
case 'Z':
|
||
|
if (Switch[1]==0)
|
||
|
{
|
||
|
// If comment file is not specified, we read data from stdin.
|
||
|
wcsncpyz(CommentFile,L"stdin",ASIZE(CommentFile));
|
||
|
}
|
||
|
else
|
||
|
wcsncpyz(CommentFile,Switch+1,ASIZE(CommentFile));
|
||
|
break;
|
||
|
case '?' :
|
||
|
OutHelp(RARX_SUCCESS);
|
||
|
break;
|
||
|
default :
|
||
|
BadSwitch(Switch);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#if !defined(SFX_MODULE)
|
||
|
void CommandData::BadSwitch(const wchar *Switch)
|
||
|
{
|
||
|
mprintf(St(MUnknownOption),Switch);
|
||
|
ErrHandler.Exit(RARX_USERERROR);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
void CommandData::ProcessCommand()
|
||
|
{
|
||
|
#ifndef SFX_MODULE
|
||
|
|
||
|
const wchar *SingleCharCommands=L"FUADPXETK";
|
||
|
if (Command[0]!=0 && Command[1]!=0 && wcschr(SingleCharCommands,Command[0])!=NULL || *ArcName==0)
|
||
|
OutHelp(*Command==0 ? RARX_SUCCESS:RARX_USERERROR); // Return 'success' for 'rar' without parameters.
|
||
|
|
||
|
const wchar *ArcExt=GetExt(ArcName);
|
||
|
#ifdef _UNIX
|
||
|
if (ArcExt==NULL && (!FileExist(ArcName) || IsDir(GetFileAttr(ArcName))))
|
||
|
wcsncatz(ArcName,L".rar",ASIZE(ArcName));
|
||
|
#else
|
||
|
if (ArcExt==NULL)
|
||
|
wcsncatz(ArcName,L".rar",ASIZE(ArcName));
|
||
|
#endif
|
||
|
// Treat arcname.part1 as arcname.part1.rar.
|
||
|
if (ArcExt!=NULL && wcsnicomp(ArcExt,L".part",5)==0 && IsDigit(ArcExt[5]) &&
|
||
|
!FileExist(ArcName))
|
||
|
{
|
||
|
wchar Name[NM];
|
||
|
wcsncpyz(Name,ArcName,ASIZE(Name));
|
||
|
wcsncatz(Name,L".rar",ASIZE(Name));
|
||
|
if (FileExist(Name))
|
||
|
wcsncpyz(ArcName,Name,ASIZE(ArcName));
|
||
|
}
|
||
|
|
||
|
if (wcschr(L"AFUMD",*Command)==NULL && *UseStdin==0)
|
||
|
{
|
||
|
if (GenerateArcName)
|
||
|
{
|
||
|
const wchar *Mask=*GenerateMask!=0 ? GenerateMask:DefGenerateMask;
|
||
|
GenerateArchiveName(ArcName,ASIZE(ArcName),Mask,false);
|
||
|
}
|
||
|
|
||
|
StringList ArcMasks;
|
||
|
ArcMasks.AddString(ArcName);
|
||
|
ScanTree Scan(&ArcMasks,Recurse,SaveSymLinks,SCAN_SKIPDIRS);
|
||
|
FindData FindData;
|
||
|
while (Scan.GetNext(&FindData)==SCAN_SUCCESS)
|
||
|
AddArcName(FindData.Name);
|
||
|
}
|
||
|
else
|
||
|
AddArcName(ArcName);
|
||
|
#endif
|
||
|
|
||
|
switch(Command[0])
|
||
|
{
|
||
|
case 'P':
|
||
|
case 'X':
|
||
|
case 'E':
|
||
|
case 'T':
|
||
|
{
|
||
|
CmdExtract Extract(this);
|
||
|
Extract.DoExtract();
|
||
|
}
|
||
|
break;
|
||
|
#ifndef SILENT
|
||
|
case 'V':
|
||
|
case 'L':
|
||
|
ListArchive(this);
|
||
|
break;
|
||
|
default:
|
||
|
OutHelp(RARX_USERERROR);
|
||
|
#endif
|
||
|
}
|
||
|
if (!BareOutput)
|
||
|
mprintf(L"\n");
|
||
|
}
|
||
|
|
||
|
|
||
|
void CommandData::AddArcName(const wchar *Name)
|
||
|
{
|
||
|
ArcNames.AddString(Name);
|
||
|
}
|
||
|
|
||
|
|
||
|
bool CommandData::GetArcName(wchar *Name,int MaxSize)
|
||
|
{
|
||
|
return ArcNames.GetString(Name,MaxSize);
|
||
|
}
|
||
|
|
||
|
|
||
|
bool CommandData::IsSwitch(int Ch)
|
||
|
{
|
||
|
#if defined(_WIN_ALL) || defined(_EMX)
|
||
|
return Ch=='-' || Ch=='/';
|
||
|
#else
|
||
|
return Ch=='-';
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifndef SFX_MODULE
|
||
|
uint CommandData::GetExclAttr(const wchar *Str,bool &Dir)
|
||
|
{
|
||
|
if (IsDigit(*Str))
|
||
|
return wcstol(Str,NULL,0);
|
||
|
|
||
|
uint Attr=0;
|
||
|
while (*Str!=0)
|
||
|
{
|
||
|
switch(toupperw(*Str))
|
||
|
{
|
||
|
case 'D':
|
||
|
Dir=true;
|
||
|
break;
|
||
|
#ifdef _UNIX
|
||
|
case 'V':
|
||
|
Attr|=S_IFCHR;
|
||
|
break;
|
||
|
#elif defined(_WIN_ALL) || defined(_EMX)
|
||
|
case 'R':
|
||
|
Attr|=0x1;
|
||
|
break;
|
||
|
case 'H':
|
||
|
Attr|=0x2;
|
||
|
break;
|
||
|
case 'S':
|
||
|
Attr|=0x4;
|
||
|
break;
|
||
|
case 'A':
|
||
|
Attr|=0x20;
|
||
|
break;
|
||
|
#endif
|
||
|
}
|
||
|
Str++;
|
||
|
}
|
||
|
return Attr;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#ifndef SFX_MODULE
|
||
|
bool CommandData::CheckWinSize()
|
||
|
{
|
||
|
// Define 0x100000000 as macro to avoid troubles with older compilers.
|
||
|
const uint64 MaxDictSize=INT32TO64(1,0);
|
||
|
// Limit the dictionary size to 4 GB.
|
||
|
for (uint64 I=0x10000;I<=MaxDictSize;I*=2)
|
||
|
if (WinSize==I)
|
||
|
return true;
|
||
|
WinSize=0x400000;
|
||
|
return false;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#ifndef SFX_MODULE
|
||
|
void CommandData::ReportWrongSwitches(RARFORMAT Format)
|
||
|
{
|
||
|
if (Format==RARFMT15)
|
||
|
{
|
||
|
if (HashType!=HASH_CRC32)
|
||
|
uiMsg(UIERROR_INCOMPATSWITCH,L"-ht",4);
|
||
|
#ifdef _WIN_ALL
|
||
|
if (SaveSymLinks)
|
||
|
uiMsg(UIERROR_INCOMPATSWITCH,L"-ol",4);
|
||
|
#endif
|
||
|
if (SaveHardLinks)
|
||
|
uiMsg(UIERROR_INCOMPATSWITCH,L"-oh",4);
|
||
|
|
||
|
#ifdef _WIN_ALL
|
||
|
// Do not report a wrong dictionary size here, because we are not sure
|
||
|
// yet about archive format. We can switch to RAR5 mode later
|
||
|
// if we update RAR5 archive.
|
||
|
|
||
|
|
||
|
#endif
|
||
|
if (QOpenMode!=QOPEN_AUTO)
|
||
|
uiMsg(UIERROR_INCOMPATSWITCH,L"-qo",4);
|
||
|
}
|
||
|
if (Format==RARFMT50)
|
||
|
{
|
||
|
}
|
||
|
}
|
||
|
#endif
|