diff --git a/src/bin/unrar/archive.cpp b/src/bin/unrar/archive.cpp index d770142354..3460f993ef 100644 --- a/src/bin/unrar/archive.cpp +++ b/src/bin/unrar/archive.cpp @@ -197,6 +197,10 @@ bool Archive::IsArchive(bool EnableBroken) #ifdef RARDLL SilentOpen=true; #endif + + //if not encrypted, we'll check it below + NotFirstVolume=Encrypted && (NewMhd.Flags & MHD_FIRSTVOLUME)==0; + if (!SilentOpen || !Encrypted) { SaveFilePos SavePos(*this); @@ -226,6 +230,12 @@ bool Archive::IsArchive(bool EnableBroken) CurBlockPos=SaveCurBlockPos; NextBlockPos=SaveNextBlockPos; } + if (!Volume || !NotFirstVolume) + { + strcpy(FirstVolumeName,FileName); + strcpyw(FirstVolumeNameW,FileNameW); + } + return(true); } diff --git a/src/bin/unrar/archive.hpp b/src/bin/unrar/archive.hpp index 5c31ca17ae..1e0675e759 100644 --- a/src/bin/unrar/archive.hpp +++ b/src/bin/unrar/archive.hpp @@ -10,11 +10,9 @@ class Archive:public File private: bool IsSignature(byte *D); void UpdateLatestTime(FileHeader *CurBlock); - void Protect(int RecSectors); void ConvertNameCase(char *Name); void ConvertNameCase(wchar *Name); void ConvertUnknownHeader(); - bool AddArcComment(char *NameToShow); int ReadOldHeader(); void PrepareExtraTime(FileHeader *hd,EXTTIME_MODE etm,EXTTIME_MODE etc,EXTTIME_MODE eta,EXTTIME_MODE etarc,Array &TimeData); diff --git a/src/bin/unrar/arcread.cpp b/src/bin/unrar/arcread.cpp index e15affb797..43a23db074 100644 --- a/src/bin/unrar/arcread.cpp +++ b/src/bin/unrar/arcread.cpp @@ -162,8 +162,7 @@ int Archive::ReadHeader() Raw.Get((byte *)FileName,NameSize); FileName[NameSize]=0; - strncpy(hd->FileName,FileName,sizeof(hd->FileName)); - hd->FileName[sizeof(hd->FileName)-1]=0; + strncpyz(hd->FileName,FileName,ASIZE(hd->FileName)); if (hd->HeadType==NEWSUB_HEAD) { diff --git a/src/bin/unrar/cmddata.cpp b/src/bin/unrar/cmddata.cpp index 7d9c5f1202..979c0303d9 100644 --- a/src/bin/unrar/cmddata.cpp +++ b/src/bin/unrar/cmddata.cpp @@ -55,10 +55,10 @@ void CommandData::ParseArg(char *Arg,wchar *ArgW) else if (*Command==0) { - strncpy(Command,Arg,sizeof(Command)); + strncpyz(Command,Arg,ASIZE(Command)); if (ArgW!=NULL) strncpyw(CommandW,ArgW,sizeof(CommandW)/sizeof(CommandW[0])); - if (toupper(*Command)=='S') + if (etoupper(*Command)=='S') { const char *SFXName=Command[1] ? Command+1:DefSFXName; if (PointToName(SFXName)!=SFXName || FileExist(SFXName)) @@ -67,7 +67,7 @@ void CommandData::ParseArg(char *Arg,wchar *ArgW) GetConfigName(SFXName,SFXModule,true); } #ifndef GUI - *Command=toupper(*Command); + *Command=etoupper(*Command); if (*Command!='I' && *Command!='S') strupper(Command); #endif @@ -75,19 +75,23 @@ void CommandData::ParseArg(char *Arg,wchar *ArgW) else if (*ArcName==0) { - strncpy(ArcName,Arg,sizeof(ArcName)); + strncpyz(ArcName,Arg,ASIZE(ArcName)); if (ArgW!=NULL) - strncpyw(ArcNameW,ArgW,sizeof(ArcNameW)/sizeof(ArcNameW[0])); + strncpyzw(ArcNameW,ArgW,ASIZE(ArcNameW)); } else { int Length=strlen(Arg); char EndChar=Arg[Length-1]; - char CmdChar=toupper(*Command); + char CmdChar=etoupper(*Command); bool Add=strchr("AFUM",CmdChar)!=NULL; bool Extract=CmdChar=='X' || CmdChar=='E'; if ((IsDriveDiv(EndChar) || IsPathDiv(EndChar)) && !Add) - strcpy(ExtrPath,Arg); + { + strncpyz(ExtrPath,Arg,ASIZE(ExtrPath)); + if (ArgW!=NULL) + strncpyzw(ExtrPathW,ArgW,ASIZE(ExtrPathW)); + } else if ((Add || CmdChar=='T') && *Arg!='@') FileArgs->AddString(Arg); @@ -98,7 +102,18 @@ void CommandData::ParseArg(char *Arg,wchar *ArgW) if (!Found && *Arg=='@' && !IsWildcard(Arg)) { FileLists=true; - ReadTextFile(Arg+1,FileArgs,false,true,true,true,true); + + RAR_CHARSET Charset=FilelistCharset; + +#if defined(_WIN_32) && !defined(GUI) + // for compatibility reasons we use OEM encoding + // in Win32 console version by default + + if (Charset==RCH_DEFAULT) + Charset=RCH_OEM; +#endif + + ReadTextFile(Arg+1,FileArgs,false,true,Charset,true,true); } else if (Found && FileData.IsDir && Extract && *ExtrPath==0) @@ -118,7 +133,7 @@ void CommandData::ParseDone() { if (FileArgs->ItemsCount()==0 && !FileLists) FileArgs->AddString(MASKALL); - char CmdChar=toupper(*Command); + char CmdChar=etoupper(*Command); bool Extract=CmdChar=='X' || CmdChar=='E'; if (Test && Extract) Test=false; @@ -136,7 +151,11 @@ void CommandData::ParseEnvVar() #endif -#if !defined(GUI) && !defined(SFX_MODULE) + +// return 'false' if -cfg- is present and preprocess switches +// which must be processed before the rest of command line + +#ifndef SFX_MODULE bool CommandData::IsConfigEnabled(int argc,char *argv[]) { bool ConfigEnabled=true; @@ -145,11 +164,20 @@ bool CommandData::IsConfigEnabled(int argc,char *argv[]) { if (stricomp(&argv[I][1],"cfg-")==0) ConfigEnabled=false; +#ifndef GUI if (strnicomp(&argv[I][1],"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(&argv[I][1]); InitLogOptions(LogName); } +#endif + if (strnicomp(&argv[I][1],"sc",2)==0) + { + // process -cs before reading any file lists + ProcessSwitch(&argv[I][1]); + } } return(ConfigEnabled); } @@ -201,12 +229,12 @@ void CommandData::ProcessSwitchesString(char *Str) void CommandData::ProcessSwitch(char *Switch) { - switch(toupper(Switch[0])) + switch(etoupper(Switch[0])) { case 'I': if (strnicomp(&Switch[1],"LOG",3)==0) { - strncpy(LogName,Switch[4] ? Switch+4:DefLogName,sizeof(LogName)); + strncpyz(LogName,Switch[4] ? Switch+4:DefLogName,ASIZE(LogName)); break; } if (stricomp(&Switch[1],"SND")==0) @@ -221,7 +249,7 @@ void CommandData::ProcessSwitch(char *Switch) } if (strnicomp(&Switch[1],"EML",3)==0) { - strncpy(EmailTo,Switch[4] ? Switch+4:"@",sizeof(EmailTo)); + strncpyz(EmailTo,Switch[4] ? Switch+4:"@",ASIZE(EmailTo)); EmailTo[sizeof(EmailTo)-1]=0; break; } @@ -230,10 +258,10 @@ void CommandData::ProcessSwitch(char *Switch) MsgStream=MSG_NULL; break; } - if (toupper(Switch[1])=='D') + if (etoupper(Switch[1])=='D') { for (int I=2;Switch[I]!=0;I++) - switch(toupper(Switch[I])) + switch(etoupper(Switch[I])) { case 'Q': MsgStream=MSG_ERRONLY; @@ -257,7 +285,7 @@ void CommandData::ProcessSwitch(char *Switch) } break; case 'T': - switch(toupper(Switch[1])) + switch(etoupper(Switch[1])) { case 'K': ArcTime=ARCTIME_KEEP; @@ -293,7 +321,7 @@ void CommandData::ProcessSwitch(char *Switch) Mode=(EXTTIME_MODE)(Switch[3]-'0'); if (Switch[3]=='-') Mode=EXTTIME_NONE; - switch(toupper(Switch[2])) + switch(etoupper(Switch[2])) { case 'M': xmtime=Mode; @@ -323,7 +351,7 @@ void CommandData::ProcessSwitch(char *Switch) } break; case 'A': - switch(toupper(Switch[1])) + switch(etoupper(Switch[1])) { case 'C': ClearArc=true; @@ -337,7 +365,7 @@ void CommandData::ProcessSwitch(char *Switch) else { GenerateArcName=true; - strncpy(GenerateMask,Switch+2,sizeof(GenerateMask)); + strncpyz(GenerateMask,Switch+2,ASIZE(GenerateMask)); } break; case 'N': //reserved for archive name @@ -351,11 +379,14 @@ void CommandData::ProcessSwitch(char *Switch) case 'S': SyncFiles=true; break; + default: + BadSwitch(Switch); + break; } break; case 'D': if (Switch[2]==0) - switch(toupper(Switch[1])) + switch(etoupper(Switch[1])) { case 'S': DisableSortSolid=true; @@ -369,7 +400,7 @@ void CommandData::ProcessSwitch(char *Switch) } break; case 'O': - switch(toupper(Switch[1])) + switch(etoupper(Switch[1])) { case '+': Overwrite=OVERWRITE_ALL; @@ -402,7 +433,7 @@ void CommandData::ProcessSwitch(char *Switch) } break; case 'R': - switch(toupper(Switch[1])) + switch(etoupper(Switch[1])) { case 0: Recurse=RECURSE_ALWAYS; @@ -435,16 +466,28 @@ void CommandData::ProcessSwitch(char *Switch) case 'N': case 'X': if (Switch[1]!=0) - { - StringList *Args=toupper(Switch[0])=='N' ? InclArgs:ExclArgs; + { + StringList *Args=etoupper(Switch[0])=='N' ? InclArgs:ExclArgs; if (Switch[1]=='@' && !IsWildcard(Switch)) - ReadTextFile(Switch+2,Args,false,true,true,true,true); + { + RAR_CHARSET Charset=FilelistCharset; + +#if defined(_WIN_32) && !defined(GUI) + // for compatibility reasons we use OEM encoding + // in Win32 console version by default + + if (Charset==RCH_DEFAULT) + Charset=RCH_OEM; +#endif + + ReadTextFile(Switch+2,Args,false,true,Charset,true,true); + } else Args->AddString(Switch+1); } break; case 'E': - switch(toupper(Switch[1])) + switch(etoupper(Switch[1])) { case 'P': switch(Switch[2]) @@ -490,14 +533,14 @@ void CommandData::ProcessSwitch(char *Switch) eprintf("\n"); } else - strncpy(Password,Switch+1,sizeof(Password)); + strncpyz(Password,Switch+1,ASIZE(Password)); break; case 'H': - if (toupper(Switch[1])=='P') + if (etoupper(Switch[1])=='P') { EncryptHeaders=true; if (Switch[2]!=0) - strncpy(Password,Switch+2,sizeof(Password)); + strncpyz(Password,Switch+2,ASIZE(Password)); else if (*Password==0) { @@ -507,11 +550,10 @@ void CommandData::ProcessSwitch(char *Switch) } break; case 'Z': - strncpy(CommentFile,Switch[1]!=0 ? Switch+1:"stdin",sizeof(CommentFile)-1); - CommentFile[sizeof(CommentFile)-1]=0; + strncpyz(CommentFile,Switch[1]!=0 ? Switch+1:"stdin",ASIZE(CommentFile)); break; case 'M': - switch(toupper(Switch[1])) + switch(etoupper(Switch[1])) { case 'C': { @@ -537,7 +579,7 @@ void CommandData::ProcessSwitch(char *Switch) while (isdigit(*Str)) Str++; } - switch(toupper(*(Str++))) + switch(etoupper(*(Str++))) { case 'T': Type=FILTER_PPM; break; case 'E': Type=FILTER_E8; break; @@ -560,7 +602,7 @@ void CommandData::ProcessSwitch(char *Switch) case 'D': { if ((WinSize=atoi(&Switch[2]))==0) - WinSize=0x10000<<(toupper(Switch[2])-'A'); + WinSize=0x10000<<(etoupper(Switch[2])-'A'); else WinSize*=1024; if (!CheckWinSize()) @@ -612,7 +654,7 @@ void CommandData::ProcessSwitch(char *Switch) } break; case 'V': - switch(toupper(Switch[1])) + switch(etoupper(Switch[1])) { #ifdef _WIN_32 case 'D': @@ -626,7 +668,7 @@ void CommandData::ProcessSwitch(char *Switch) VolumePause=true; break; case 'E': - if (toupper(Switch[2])=='R') + if (etoupper(Switch[2])=='R') VersionControl=atoi(Switch+3)+1; break; case '-': @@ -695,30 +737,19 @@ void CommandData::ProcessSwitch(char *Switch) } break; case 'F': - switch(toupper(Switch[1])) - { - case 0: - FreshFiles=true; - break; - case 'C': - if (toupper(Switch[2])=='U') - { - UnicodeComment=true; - if (*CommentFile==0 || Switch[3]!=0) - { - strncpy(CommentFile,Switch[3]!=0 ? Switch+3:"stdin",sizeof(CommentFile)-1); - CommentFile[sizeof(CommentFile)-1]=0; - } - } - break; - } + if (Switch[1]==0) + FreshFiles=true; + else + BadSwitch(Switch); break; case 'U': if (Switch[1]==0) UpdateFiles=true; + else + BadSwitch(Switch); break; case 'W': - strncpy(TempPath,&Switch[1],sizeof(TempPath)-1); + strncpyz(TempPath,&Switch[1],ASIZE(TempPath)); AddEndSlash(TempPath); break; case 'S': @@ -736,7 +767,7 @@ void CommandData::ProcessSwitch(char *Switch) SolidCount=atoi(&Switch[1]); } else - switch(toupper(Switch[1])) + switch(etoupper(Switch[1])) { case 0: Solid|=SOLID_NORMAL; @@ -761,11 +792,48 @@ void CommandData::ProcessSwitch(char *Switch) if (isdigit(Switch[2])) FileSizeMore=atoil(Switch+2); break; + case 'C': + { + RAR_CHARSET rch; + switch(etoupper(Switch[2])) + { + case 'A': + rch=RCH_ANSI; + break; + case 'O': + rch=RCH_OEM; + break; + case 'U': + rch=RCH_UNICODE; + break; + default : + BadSwitch(Switch); + break; + }; + if (Switch[3]==0) + CommentCharset=FilelistCharset=rch; + else + for (int I=3;Switch[I]!=0;I++) + switch(etoupper(Switch[I])) + { + case 'C': + CommentCharset=rch; + break; + case 'L': + FilelistCharset=rch; + break; + default: + BadSwitch(Switch); + break; + } + } + break; + } break; case 'C': if (Switch[2]==0) - switch(toupper(Switch[1])) + switch(etoupper(Switch[1])) { case '-': DisableComment=true; @@ -779,7 +847,7 @@ void CommandData::ProcessSwitch(char *Switch) } break; case 'K': - switch(toupper(Switch[1])) + switch(etoupper(Switch[1])) { case 'B': KeepBroken=true; @@ -866,17 +934,17 @@ void CommandData::OutHelp() MCHelpSwAO,MCHelpSwAP,MCHelpSwAS,MCHelpSwAV,MCHelpSwAVm,MCHelpSwCm, MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU,MCHelpSwDF,MCHelpSwDH,MCHelpSwDS, MCHelpSwEa,MCHelpSwED,MCHelpSwEE,MCHelpSwEN,MCHelpSwEP,MCHelpSwEP1, - MCHelpSwEP2,MCHelpSwEP3,MCHelpSwF,MCHelpSwFCU,MCHelpSwHP,MCHelpSwIDP, + MCHelpSwEP2,MCHelpSwEP3,MCHelpSwF,MCHelpSwHP,MCHelpSwIDP, MCHelpSwIEML,MCHelpSwIERR,MCHelpSwILOG,MCHelpSwINUL,MCHelpSwIOFF, MCHelpSwISND,MCHelpSwK,MCHelpSwKB,MCHelpSwMn,MCHelpSwMC,MCHelpSwMD, MCHelpSwMS,MCHelpSwMT,MCHelpSwN,MCHelpSwNa,MCHelpSwNal,MCHelpSwOp, MCHelpSwOm,MCHelpSwOC,MCHelpSwOL,MCHelpSwOR,MCHelpSwOS,MCHelpSwOW, MCHelpSwP,MCHelpSwPm,MCHelpSwR,MCHelpSwR0,MCHelpSwRI,MCHelpSwRR, - MCHelpSwRV,MCHelpSwS,MCHelpSwSm,MCHelpSwSFX,MCHelpSwSI,MCHelpSwSL, - MCHelpSwSM,MCHelpSwT,MCHelpSwTA,MCHelpSwTB,MCHelpSwTK,MCHelpSwTL, - MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU,MCHelpSwV,MCHelpSwVn, - MCHelpSwVD,MCHelpSwVER,MCHelpSwVN,MCHelpSwVP,MCHelpSwW,MCHelpSwX, - MCHelpSwXa,MCHelpSwXal,MCHelpSwY,MCHelpSwZ + MCHelpSwRV,MCHelpSwS,MCHelpSwSm,MCHelpSwSC,MCHelpSwSFX,MCHelpSwSI, + MCHelpSwSL,MCHelpSwSM,MCHelpSwT,MCHelpSwTA,MCHelpSwTB,MCHelpSwTK, + MCHelpSwTL,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU,MCHelpSwV, + MCHelpSwVn,MCHelpSwVD,MCHelpSwVER,MCHelpSwVN,MCHelpSwVP,MCHelpSwW, + MCHelpSwX,MCHelpSwXa,MCHelpSwXal,MCHelpSwY,MCHelpSwZ #endif }; @@ -1079,7 +1147,9 @@ int CommandData::IsProcessFile(FileHeader &NewLhd,bool *ExactMatch,int MatchType void CommandData::ProcessCommand() { #ifndef SFX_MODULE - if (Command[1] && strchr("FUADPXETK",*Command)!=NULL || *ArcName==0) + + const char *SingleCharCommands="FUADPXETK"; + if (Command[1] && strchr(SingleCharCommands,*Command)!=NULL || *ArcName==0) OutHelp(); #ifdef _UNIX @@ -1163,7 +1233,7 @@ uint CommandData::GetExclAttr(char *Str) { uint Attr; for (Attr=0;*Str;Str++) - switch(toupper(*Str)) + switch(etoupper(*Str)) { #ifdef _UNIX case 'D': diff --git a/src/bin/unrar/compress.hpp b/src/bin/unrar/compress.hpp index 2ba7b23efe..3181e45de7 100644 --- a/src/bin/unrar/compress.hpp +++ b/src/bin/unrar/compress.hpp @@ -29,7 +29,7 @@ enum {CODE_HUFFMAN,CODE_LZ,CODE_LZ2,CODE_REPEATLZ,CODE_CACHELZ, enum FilterType { FILTER_NONE, FILTER_PPM /*dummy*/, FILTER_E8, FILTER_E8E9, - FILTER_UPCASETOLOW, FILTER_AUDIO, FILTER_RGB, FILTER_DELTA, + FILTER_UPCASETOLOW, FILTER_AUDIO, FILTER_RGB, FILTER_DELTA, FILTER_ITANIUM, FILTER_E8E9V2 }; diff --git a/src/bin/unrar/consio.cpp b/src/bin/unrar/consio.cpp index 491a1ffc74..f1f4ba0965 100644 --- a/src/bin/unrar/consio.cpp +++ b/src/bin/unrar/consio.cpp @@ -124,8 +124,9 @@ void GetPasswordText(char *Str,int MaxLength) #elif defined(_EMX) || defined(_BEOS) || defined(__sparc) || defined(sparc) || defined (__VMS) fgets(Str,MaxLength-1,stdin); #else - strncpy(Str,getpass(""),MaxLength-1); + strncpyz(Str,getpass(""),MaxLength); #endif + Str[MaxLength-1]=0; RemoveLF(Str); } #endif @@ -159,7 +160,7 @@ bool GetPassword(PASSWORD_TYPE Type,const char *FileName,char *Password,int MaxL Alarm(); while (true) { - char PromptStr[256]; + char PromptStr[NM+256]; #if defined(_EMX) || defined(_BEOS) strcpy(PromptStr,St(MAskPswEcho)); #else @@ -168,7 +169,9 @@ bool GetPassword(PASSWORD_TYPE Type,const char *FileName,char *Password,int MaxL if (Type!=PASSWORD_GLOBAL) { strcat(PromptStr,St(MFor)); - strcat(PromptStr,PointToName(FileName)); + char *NameOnly=PointToName(FileName); + if (strlen(PromptStr)+strlen(NameOnly)>8); return(StartCRC); } @@ -51,7 +51,7 @@ uint CRC(uint StartCRC,const void *Addr,uint Size) ushort OldCRC(ushort StartCRC,const void *Addr,uint Size) { byte *Data=(byte *)Addr; - for (uint I=0;I>15))&0xffff; diff --git a/src/bin/unrar/crypt.cpp b/src/bin/unrar/crypt.cpp index 2cdc8a78e3..04a1d7086b 100644 --- a/src/bin/unrar/crypt.cpp +++ b/src/bin/unrar/crypt.cpp @@ -204,7 +204,7 @@ void CryptData::SetCryptKeys(char *Password,byte *Salt,bool Encrypt,bool OldOnly #if defined(_WIN_32) && !defined(GUI) CharToOemBuff(Password,(char*)Psw,strlen(Password)); #else - strncpy((char *)Psw,Password,MAXPASSWORD-1); + strncpyz((char *)Psw,Password,ASIZE(Psw)); #endif int PswLength=strlen(Password); memcpy(SubstTable,InitSubstTable,sizeof(SubstTable)); @@ -223,7 +223,7 @@ void CryptData::SetCryptKeys(char *Password,byte *Salt,bool Encrypt,bool OldOnly } bool Cached=false; - for (uint I=0;IArc.EndArcHead.Flags & EARC_NEXT_VOLUME)) if (MergeArchive(Data->Arc,NULL,false,'L')) { + Data->Extract.SignatureFound=false; Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET); return(RARReadHeader(hArcData,D)); } @@ -125,8 +126,8 @@ int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *D) else return(Code); } - strncpy(D->ArcName,Data->Arc.FileName,sizeof(D->ArcName)); - strncpy(D->FileName,Data->Arc.NewLhd.FileName,sizeof(D->FileName)); + strncpyz(D->ArcName,Data->Arc.FileName,ASIZE(D->ArcName)); + strncpyz(D->FileName,Data->Arc.NewLhd.FileName,ASIZE(D->FileName)); D->Flags=Data->Arc.NewLhd.Flags; D->PackSize=Data->Arc.NewLhd.PackSize; D->UnpSize=Data->Arc.NewLhd.UnpSize; @@ -158,6 +159,7 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D) (Data->Arc.EndArcHead.Flags & EARC_NEXT_VOLUME)) if (MergeArchive(Data->Arc,NULL,false,'L')) { + Data->Extract.SignatureFound=false; Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET); return(RARReadHeaderEx(hArcData,D)); } @@ -173,12 +175,12 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D) else return(Code); } - strncpy(D->ArcName,Data->Arc.FileName,sizeof(D->ArcName)); + strncpyz(D->ArcName,Data->Arc.FileName,ASIZE(D->ArcName)); if (*Data->Arc.FileNameW) strncpyw(D->ArcNameW,Data->Arc.FileNameW,sizeof(D->ArcNameW)); else CharToWide(Data->Arc.FileName,D->ArcNameW); - strncpy(D->FileName,Data->Arc.NewLhd.FileName,sizeof(D->FileName)); + strncpyz(D->FileName,Data->Arc.NewLhd.FileName,ASIZE(D->FileName)); if (*Data->Arc.NewLhd.FileNameW) strncpyw(D->FileNameW,Data->Arc.NewLhd.FileNameW,sizeof(D->FileNameW)); else @@ -226,6 +228,7 @@ int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestNa (Data->Arc.NewLhd.Flags & LHD_SPLIT_AFTER)!=0) if (MergeArchive(Data->Arc,NULL,false,'L')) { + Data->Extract.SignatureFound=false; Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET); return(0); } @@ -327,7 +330,7 @@ void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataPro void PASCAL RARSetPassword(HANDLE hArcData,char *Password) { DataSet *Data=(DataSet *)hArcData; - strncpy(Data->Cmd.Password,Password,sizeof(Data->Cmd.Password)); + strncpyz(Data->Cmd.Password,Password,ASIZE(Data->Cmd.Password)); } diff --git a/src/bin/unrar/dll.hpp b/src/bin/unrar/dll.hpp index 6b3a26dfa7..4b677441f3 100644 --- a/src/bin/unrar/dll.hpp +++ b/src/bin/unrar/dll.hpp @@ -1,18 +1,19 @@ #ifndef _UNRAR_DLL_ #define _UNRAR_DLL_ -#define ERAR_END_ARCHIVE 10 -#define ERAR_NO_MEMORY 11 -#define ERAR_BAD_DATA 12 -#define ERAR_BAD_ARCHIVE 13 -#define ERAR_UNKNOWN_FORMAT 14 -#define ERAR_EOPEN 15 -#define ERAR_ECREATE 16 -#define ERAR_ECLOSE 17 -#define ERAR_EREAD 18 -#define ERAR_EWRITE 19 -#define ERAR_SMALL_BUF 20 -#define ERAR_UNKNOWN 21 +#define ERAR_END_ARCHIVE 10 +#define ERAR_NO_MEMORY 11 +#define ERAR_BAD_DATA 12 +#define ERAR_BAD_ARCHIVE 13 +#define ERAR_UNKNOWN_FORMAT 14 +#define ERAR_EOPEN 15 +#define ERAR_ECREATE 16 +#define ERAR_ECLOSE 17 +#define ERAR_EREAD 18 +#define ERAR_EWRITE 19 +#define ERAR_SMALL_BUF 20 +#define ERAR_UNKNOWN 21 +#define ERAR_MISSING_PASSWORD 22 #define RAR_OM_LIST 0 #define RAR_OM_EXTRACT 1 diff --git a/src/bin/unrar/extract.cpp b/src/bin/unrar/extract.cpp index acc2b2349c..4871ec9234 100644 --- a/src/bin/unrar/extract.cpp +++ b/src/bin/unrar/extract.cpp @@ -357,7 +357,7 @@ bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,int HeaderSize if (ExactMatch || (SkipSolid=Arc.Solid)!=0) { - if (Arc.NewLhd.Flags & LHD_PASSWORD) + if ((Arc.NewLhd.Flags & LHD_PASSWORD)!=0) #ifndef RARDLL if (*Password==0) #endif @@ -410,7 +410,7 @@ bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,int HeaderSize #ifndef SFX_MODULE if (Cmd->AppendArcNameToPath) { - strcat(DestFileName,PointToName(Arc.FileName)); + strcat(DestFileName,PointToName(Arc.FirstVolumeName)); SetExt(DestFileName,NULL); AddEndSlash(DestFileName); } @@ -443,7 +443,7 @@ bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,int HeaderSize else strcat(DestFileName,ExtrName); - char DiskLetter=toupper(DestFileName[0]); + char DiskLetter=etoupper(DestFileName[0]); if (AbsPaths && DestFileName[1]=='_' && IsPathDiv(DestFileName[2]) && DiskLetter>='A' && DiskLetter<='Z') @@ -469,10 +469,10 @@ bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,int HeaderSize if (Cmd->AppendArcNameToPath) { wchar FileNameW[NM]; - if (*Arc.FileNameW!=0) - strcpyw(FileNameW,Arc.FileNameW); + if (*Arc.FirstVolumeNameW!=0) + strcpyw(FileNameW,Arc.FirstVolumeNameW); else - CharToWide(Arc.FileName,FileNameW); + CharToWide(Arc.FirstVolumeName,FileNameW); strcatw(DestFileNameW,PointToName(FileNameW)); SetExt(DestFileNameW,NULL); AddEndSlash(DestFileNameW); @@ -505,7 +505,8 @@ bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,int HeaderSize else *DestFileNameW=0; - ExtrFile=!SkipSolid && !EmptyName && (Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)==0/* && *ExtrName*/; + ExtrFile=!SkipSolid && !EmptyName && (Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)==0; + if ((Cmd->FreshFiles || Cmd->UpdateFiles) && (Command=='E' || Command=='X')) { struct FindData FD; @@ -519,17 +520,27 @@ bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,int HeaderSize ExtrFile=false; } + // skip encrypted file if no password is specified + if ((Arc.NewLhd.Flags & LHD_PASSWORD)!=0 && *Password==0) + { + ErrHandler.SetErrorCode(WARNING); +#ifdef RARDLL + Cmd->DllError=ERAR_MISSING_PASSWORD; +#endif + ExtrFile=false; + } + #ifdef RARDLL if (*Cmd->DllDestName) { - strncpy(DestFileName,Cmd->DllDestName,sizeof(DestFileName)); + strncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName)); *DestFileNameW=0; if (Cmd->DllOpMode!=RAR_EXTRACT) ExtrFile=false; } if (*Cmd->DllDestNameW) { - strncpyw(DestFileNameW,Cmd->DllDestNameW,sizeof(DestFileNameW)/sizeof(DestFileNameW[0])); + strncpyzw(DestFileNameW,Cmd->DllDestNameW,ASIZE(DestFileNameW)); DestNameW=DestFileNameW; if (Cmd->DllOpMode!=RAR_EXTRACT) ExtrFile=false; @@ -655,8 +666,7 @@ bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,int HeaderSize { Log(Arc.FileName,St(MCorrectingName)); char OrigName[sizeof(DestFileName)]; - strncpy(OrigName,DestFileName,sizeof(OrigName)-1); - OrigName[sizeof(OrigName)-1]=0; + strncpyz(OrigName,DestFileName,ASIZE(OrigName)); MakeNameUsable(DestFileName,true); CreatePath(DestFileName,NULL,true); @@ -799,6 +809,10 @@ bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,int HeaderSize #if defined(_WIN_32) || defined(_EMX) if (Cmd->ClearArc) Arc.NewLhd.FileAttr&=~FA_ARCH; +/* + else + Arc.NewLhd.FileAttr|=FA_ARCH; //set archive bit for unpacked files (file is not backed up) +*/ #endif if (!BrokenFile || Cmd->KeepBroken) { diff --git a/src/bin/unrar/extract.hpp b/src/bin/unrar/extract.hpp index 2161aaee65..09dfc94f8f 100644 --- a/src/bin/unrar/extract.hpp +++ b/src/bin/unrar/extract.hpp @@ -24,7 +24,6 @@ class CmdExtract char Password[MAXPASSWORD]; bool PasswordAll; bool PrevExtracted; - bool SignatureFound; char DestFileName[NM]; wchar DestFileNameW[NM]; bool PasswordCancelled; @@ -36,6 +35,8 @@ class CmdExtract bool ExtractCurrentFile(CommandData *Cmd,Archive &Arc,int HeaderSize, bool &Repeat); static void UnstoreFile(ComprDataIO &DataIO,Int64 DestUnpSize); + + bool SignatureFound; }; #endif diff --git a/src/bin/unrar/filcreat.cpp b/src/bin/unrar/filcreat.cpp index 91ef3f277b..175736a663 100644 --- a/src/bin/unrar/filcreat.cpp +++ b/src/bin/unrar/filcreat.cpp @@ -139,7 +139,7 @@ bool UpdateExistingShortName(char *Name,wchar *NameW) char NewName[NM]; for (int I=0;I<10000;I+=123) { - strncpy(NewName,Name,sizeof(NewName)); + strncpyz(NewName,Name,ASIZE(NewName)); sprintf(PointToName(NewName),"rtmp%d",I); if (!FileExist(NewName)) break; @@ -147,7 +147,7 @@ bool UpdateExistingShortName(char *Name,wchar *NameW) if (FileExist(NewName)) return(false); char FullName[NM]; - strncpy(FullName,Name,sizeof(FullName)); + strncpyz(FullName,Name,ASIZE(FullName)); strcpy(PointToName(FullName),PointToName(fd.Name)); if (!MoveFile(FullName,NewName)) return(false); diff --git a/src/bin/unrar/filefn.cpp b/src/bin/unrar/filefn.cpp index fd3500699d..da76763ea6 100644 --- a/src/bin/unrar/filefn.cpp +++ b/src/bin/unrar/filefn.cpp @@ -41,7 +41,7 @@ MKDIR_CODE MakeDir(const char *Name,const wchar *NameW,uint Attr) } -void CreatePath(const char *Path,const wchar *PathW,bool SkipLastName) +bool CreatePath(const char *Path,const wchar *PathW,bool SkipLastName) { #ifdef _WIN_32 uint DirAttr=0; @@ -54,6 +54,7 @@ void CreatePath(const char *Path,const wchar *PathW,bool SkipLastName) bool Wide=false; #endif bool IgnoreAscii=false; + bool Success=true; const char *s=Path; for (int PosW=0;;PosW++) @@ -95,12 +96,16 @@ void CreatePath(const char *Path,const wchar *PathW,bool SkipLastName) mprintf(" %s",St(MOk)); #endif } + else + Success=false; } if (!IgnoreAscii) s=charnext(s); } if (!SkipLastName && !IsPathDiv(*PointToLastChar(Path))) - MakeDir(Path,PathW,DirAttr); + if (MakeDir(Path,PathW,DirAttr)!=MKDIR_SUCCESS) + Success=false; + return(Success); } @@ -148,7 +153,7 @@ bool IsRemovable(const char *Name) int Type=GetDriveType(*Root ? Root:NULL); return(Type==DRIVE_REMOVABLE || Type==DRIVE_CDROM); #elif defined(_EMX) - char Drive=toupper(Name[0]); + char Drive=etoupper(Name[0]); return((Drive=='A' || Drive=='B') && Name[1]==':'); #else return(false); @@ -176,7 +181,7 @@ Int64 GetFreeDisk(const char *Name) } if (pGetDiskFreeSpaceEx!=NULL) { - GetFilePath(Name,Root); + GetFilePath(Name,Root,ASIZE(Root)); ULARGE_INTEGER uiTotalSize,uiTotalFree,uiUserFree; uiUserFree.u.LowPart=uiUserFree.u.HighPart=0; if (pGetDiskFreeSpaceEx(*Root ? Root:NULL,&uiUserFree,&uiTotalSize,&uiTotalFree) && @@ -192,7 +197,7 @@ Int64 GetFreeDisk(const char *Name) return(FreeSize); #elif defined(_BEOS) char Root[NM]; - GetFilePath(Name,Root); + GetFilePath(Name,Root,ASIZE(Root)); dev_t Dev=dev_for_path(*Root ? Root:"."); if (Dev<0) return(1457664); @@ -205,7 +210,7 @@ Int64 GetFreeDisk(const char *Name) #elif defined(_UNIX) return(1457664); #elif defined(_EMX) - int Drive=(!isalpha(Name[0]) || Name[1]!=':') ? 0:toupper(Name[0])-'A'+1; + int Drive=(!isalpha(Name[0]) || Name[1]!=':') ? 0:etoupper(Name[0])-'A'+1; if (_osmode == OS2_MODE) { FSALLOCATE fsa; @@ -465,7 +470,7 @@ char *MkTemp(char *Name) #ifndef SFX_MODULE -uint CalcFileCRC(File *SrcFile,Int64 Size) +uint CalcFileCRC(File *SrcFile,Int64 Size,CALCCRC_SHOWMODE ShowMode) { SaveFilePos SavePos(*SrcFile); const int BufSize=0x10000; @@ -474,6 +479,15 @@ uint CalcFileCRC(File *SrcFile,Int64 Size) uint DataCRC=0xffffffff; int ReadSize; +#if !defined(SILENT) && !defined(_WIN_CE) + Int64 FileLength=SrcFile->FileLength(); + if (ShowMode!=CALCCRC_SHOWNONE) + { + mprintf(St(MCalcCRC)); + mprintf(" "); + } + +#endif SrcFile->Seek(0,SEEK_SET); while ((ReadSize=SrcFile->Read(&Data[0],int64to32(Size==INT64ERR ? Int64(BufSize):Min(Int64(BufSize),Size))))!=0) @@ -481,12 +495,20 @@ uint CalcFileCRC(File *SrcFile,Int64 Size) ++BlockCount; if ((BlockCount & 15)==0) { +#if !defined(SILENT) && !defined(_WIN_CE) + if (ShowMode==CALCCRC_SHOWALL) + mprintf("\b\b\b\b%3d%%",ToPercent(BlockCount*Int64(BufSize),FileLength)); +#endif Wait(); } DataCRC=CRC(DataCRC,&Data[0],ReadSize); if (Size!=INT64ERR) Size-=ReadSize; } +#if !defined(SILENT) && !defined(_WIN_CE) + if (ShowMode==CALCCRC_SHOWALL) + mprintf("\b\b\b\b "); +#endif return(DataCRC^0xffffffff); } #endif diff --git a/src/bin/unrar/filefn.hpp b/src/bin/unrar/filefn.hpp index 3ad31b5e80..ec6cba528a 100644 --- a/src/bin/unrar/filefn.hpp +++ b/src/bin/unrar/filefn.hpp @@ -4,7 +4,7 @@ enum MKDIR_CODE {MKDIR_SUCCESS,MKDIR_ERROR,MKDIR_BADPATH}; MKDIR_CODE MakeDir(const char *Name,const wchar *NameW,uint Attr); -void CreatePath(const char *Path,const wchar *PathW,bool SkipLastName); +bool CreatePath(const char *Path,const wchar *PathW,bool SkipLastName); void SetDirTime(const char *Name,RarTime *ftm,RarTime *ftc,RarTime *fta); bool IsRemovable(const char *Name); Int64 GetFreeDisk(const char *Name); @@ -25,7 +25,9 @@ void ConvertNameToFull(const wchar *Src,wchar *Dest); char* MkTemp(char *Name); -uint CalcFileCRC(File *SrcFile,Int64 Size=INT64ERR); +enum CALCCRC_SHOWMODE {CALCCRC_SHOWNONE,CALCCRC_SHOWTEXT,CALCCRC_SHOWALL}; +uint CalcFileCRC(File *SrcFile,Int64 Size=INT64ERR,CALCCRC_SHOWMODE ShowMode=CALCCRC_SHOWNONE); + bool RenameFile(const char *SrcName,const wchar *SrcNameW,const char *DestName,const wchar *DestNameW); bool DelFile(const char *Name); bool DelFile(const char *Name,const wchar *NameW); diff --git a/src/bin/unrar/filestr.cpp b/src/bin/unrar/filestr.cpp index 7109c51c95..55e79a1fd7 100644 --- a/src/bin/unrar/filestr.cpp +++ b/src/bin/unrar/filestr.cpp @@ -3,7 +3,7 @@ static bool IsUnicode(byte *Data,int Size); bool ReadTextFile(char *Name,StringList *List,bool Config,bool AbortOnError, - bool ConvertToAnsi,bool Unquote,bool SkipComments) + RAR_CHARSET SrcCharset,bool Unquote,bool SkipComments) { char FileName[NM]; if (Config) @@ -37,9 +37,15 @@ bool ReadTextFile(char *Name,StringList *List,bool Config,bool AbortOnError, memset(&Data[DataSize],0,5); - if (IsUnicode((byte *)&Data[0],DataSize)) + if (SrcCharset==RCH_UNICODE || + SrcCharset==RCH_DEFAULT && IsUnicode((byte *)&Data[0],DataSize)) { - wchar *CurStr=(wchar *)&Data[2]; + // Unicode in native system format, can be more than 2 bytes per character + Array DataW(Data.Size()/2+1); + for (int I=2;I AnsiName; while (*CurStr!=0) @@ -114,7 +120,7 @@ bool ReadTextFile(char *Name,StringList *List,bool Config,bool AbortOnError, } } #if defined(_WIN_32) - if (ConvertToAnsi) + if (SrcCharset==RCH_OEM) OemToChar(CurStr,CurStr); #endif List->AddString(CurStr); @@ -133,7 +139,7 @@ bool IsUnicode(byte *Data,int Size) if (Size<4 || Data[0]!=0xff || Data[1]!=0xfe) return(false); for (int I=2;Id_name); + *PointToName(FullName)=0; + if (strlen(FullName)+strlen(ent->d_name)>=ASIZE(FullName)-1) + { +#ifndef SILENT + Log(NULL,"\n%s%s",FullName,ent->d_name); + Log(NULL,St(MPathTooLong)); +#endif + return(false); + } + strcat(FullName,ent->d_name); if (!FastFind(FullName,NULL,fd,GetSymLink)) { ErrHandler.OpenErrorMsg(FullName); diff --git a/src/bin/unrar/getbits.hpp b/src/bin/unrar/getbits.hpp index 8819f53ab5..eff4dafcbf 100644 --- a/src/bin/unrar/getbits.hpp +++ b/src/bin/unrar/getbits.hpp @@ -33,5 +33,6 @@ class BitInput } void faddbits(int Bits); unsigned int fgetbits(); + bool Overflow(int IncPtr) {return(InAddr+IncPtr>=MAX_SIZE);} }; #endif diff --git a/src/bin/unrar/headers.hpp b/src/bin/unrar/headers.hpp index 7668f980eb..acf597d758 100644 --- a/src/bin/unrar/headers.hpp +++ b/src/bin/unrar/headers.hpp @@ -64,7 +64,7 @@ #define SKIP_IF_UNKNOWN 0x4000 #define LONG_BLOCK 0x8000 -#define EARC_NEXT_VOLUME 0x0001 +#define EARC_NEXT_VOLUME 0x0001 // not last volume #define EARC_DATACRC 0x0002 #define EARC_REVSPACE 0x0004 #define EARC_VOLNUMBER 0x0008 diff --git a/src/bin/unrar/list.cpp b/src/bin/unrar/list.cpp index 820f653c67..9aed15469d 100644 --- a/src/bin/unrar/list.cpp +++ b/src/bin/unrar/list.cpp @@ -118,7 +118,7 @@ void ListArchive(CommandData *Cmd) itoa(TotalPackSize,PackSizeText); mprintf("\n%5lu %16s %8s %3d%%",FileCount,UnpSizeText, - PackSizeText,ToPercent(TotalPackSize,TotalUnpSize)); + PackSizeText,ToPercentUnlim(TotalPackSize,TotalUnpSize)); SumFileCount+=FileCount; SumUnpSize+=TotalUnpSize; SumPackSize+=TotalPackSize; @@ -162,7 +162,7 @@ void ListArchive(CommandData *Cmd) itoa(SumUnpSize,UnpSizeText); itoa(SumPackSize,PackSizeText); mprintf("\n%5lu %16s %8s %3d%%\n",SumFileCount,UnpSizeText, - PackSizeText,ToPercent(SumPackSize,SumUnpSize)); + PackSizeText,ToPercentUnlim(SumPackSize,SumUnpSize)); } } @@ -231,7 +231,7 @@ void ListFileHeader(FileHeader &hd,bool Verbose,bool Technical,bool &TitleShown, if (hd.Flags & LHD_SPLIT_AFTER) mprintf(" -->"); else - mprintf("%3d%%",ToPercent(hd.FullPackSize,hd.FullUnpSize)); + mprintf("%3d%%",ToPercentUnlim(hd.FullPackSize,hd.FullUnpSize)); char DateStr[50]; hd.mtime.GetText(DateStr,false); @@ -355,7 +355,7 @@ void ListOldSubHeader(Archive &Arc) void ListNewSubHeader(CommandData *Cmd,Archive &Arc,bool Technical) { - if (Technical && Arc.SubHead.CmpName(SUBHEAD_TYPE_CMT) && + if (Arc.SubHead.CmpName(SUBHEAD_TYPE_CMT) && (Arc.SubHead.Flags & LHD_SPLIT_BEFORE)==0 && !Cmd->DisableComment) { Array CmtData; diff --git a/src/bin/unrar/loclang.hpp b/src/bin/unrar/loclang.hpp index c550449153..c425bb3b25 100644 --- a/src/bin/unrar/loclang.hpp +++ b/src/bin/unrar/loclang.hpp @@ -73,7 +73,6 @@ #define MCHelpSwEP2 "\n ep2 Expand paths to full" #define MCHelpSwEP3 "\n ep3 Expand paths to full including the drive letter" #define MCHelpSwF "\n f Freshen files" -#define MCHelpSwFCU "\n fcu[file] Read archive comment from Unicode file" #define MCHelpSwHP "\n hp[password] Encrypt both file data and headers" #define MCHelpSwIDP "\n id[c,d,p,q] Disable messages" #define MCHelpSwIEML "\n ieml[addr] Send archive by email" @@ -108,6 +107,7 @@ #define MCHelpSwRV "\n rv[N] Create recovery volumes" #define MCHelpSwS "\n s[,v[-],e] Create solid archive" #define MCHelpSwSm "\n s- Disable solid archiving" +#define MCHelpSwSC "\n sc[obj] Specify the character set" #define MCHelpSwSFX "\n sfx[name] Create SFX archive" #define MCHelpSwSI "\n si[name] Read data from standard input (stdin)" #define MCHelpSwSL "\n sl Process files with size less than specified" @@ -345,3 +345,5 @@ #define MRecVolLimit "\nTotal number of usual and recovery volumes must not exceed 255" #define MVolumeNumber "volume %d" #define MCannotDelete "\nCannot delete %s" +#define MCalcCRC "\nCalculating the control sum" +#define MTooLargeSFXArc "\nWARNING: Too large SFX archive. Windows cannot run the executable file exceeding 4 GB." diff --git a/src/bin/unrar/match.cpp b/src/bin/unrar/match.cpp index 2c0662b46f..de03fb4cfa 100644 --- a/src/bin/unrar/match.cpp +++ b/src/bin/unrar/match.cpp @@ -50,8 +50,8 @@ bool CmpName(char *Wildcard,char *Name,int CmpPath) return(true); } char Path1[NM],Path2[NM]; - GetFilePath(Wildcard,Path1); - GetFilePath(Name,Path2); + GetFilePath(Wildcard,Path1,ASIZE(Path1)); + GetFilePath(Name,Path2,ASIZE(Path1)); if (mstricompc(Wildcard,Path2,ForceCase)==0) return(true); if ((CmpPath==MATCH_PATH || CmpPath==MATCH_EXACTPATH) && mstricompc(Path1,Path2,ForceCase)!=0) @@ -94,8 +94,8 @@ bool CmpName(wchar *Wildcard,wchar *Name,int CmpPath) return(true); } wchar Path1[NM],Path2[NM]; - GetFilePath(Wildcard,Path1); - GetFilePath(Name,Path2); + GetFilePath(Wildcard,Path1,ASIZE(Path1)); + GetFilePath(Name,Path2,ASIZE(Path2)); if ((CmpPath==MATCH_PATH || CmpPath==MATCH_EXACTPATH) && mstricompcw(Path1,Path2,ForceCase)!=0) return(false); if (CmpPath==MATCH_SUBPATH || CmpPath==MATCH_WILDSUBPATH) diff --git a/src/bin/unrar/options.hpp b/src/bin/unrar/options.hpp index 9f0fe5fe10..cc2db48ffa 100644 --- a/src/bin/unrar/options.hpp +++ b/src/bin/unrar/options.hpp @@ -21,6 +21,8 @@ enum OVERWRITE_MODE { OVERWRITE_ASK,OVERWRITE_ALL,OVERWRITE_NONE,OVERWRITE_AUTORENAME }; +enum RAR_CHARSET { RCH_DEFAULT=0,RCH_ANSI,RCH_OEM,RCH_UNICODE }; + #define MAX_FILTERS 16 enum FilterState {FILTER_DEFAULT=0,FILTER_AUTO,FILTER_FORCE,FILTER_DISABLE}; @@ -49,7 +51,8 @@ class RAROptions char ExtrPath[NM]; wchar ExtrPathW[NM]; char CommentFile[NM]; - bool UnicodeComment; + RAR_CHARSET CommentCharset; + RAR_CHARSET FilelistCharset; char ArcPath[NM]; char Password[MAXPASSWORD]; bool EncryptHeaders; diff --git a/src/bin/unrar/os.hpp b/src/bin/unrar/os.hpp index fab98e396b..a033e37fa1 100644 --- a/src/bin/unrar/os.hpp +++ b/src/bin/unrar/os.hpp @@ -33,6 +33,7 @@ #include #ifndef _WIN_CE + #include #include #endif diff --git a/src/bin/unrar/pathfn.cpp b/src/bin/unrar/pathfn.cpp index 76861c9efb..ca2a58ad1c 100644 --- a/src/bin/unrar/pathfn.cpp +++ b/src/bin/unrar/pathfn.cpp @@ -44,12 +44,13 @@ char* ConvertPath(const char *SrcPath,char *DestPath) const char *s=DestPtr; if (s[0] && IsDriveDiv(s[1])) s+=2; - if (s[0]=='\\' && s[1]=='\\') - { - const char *Slash=strchr(s+2,'\\'); - if (Slash!=NULL && (Slash=strchr(Slash+1,'\\'))!=NULL) - s=Slash+1; - } + else + if (s[0]=='\\' && s[1]=='\\') + { + const char *Slash=strchr(s+2,'\\'); + if (Slash!=NULL && (Slash=strchr(Slash+1,'\\'))!=NULL) + s=Slash+1; + } for (const char *t=s;*t!=0;t++) if (IsPathDiv(*t)) s=t+1; @@ -68,7 +69,7 @@ char* ConvertPath(const char *SrcPath,char *DestPath) if (DestPath!=NULL) { char TmpStr[NM]; - strncpy(TmpStr,DestPtr,sizeof(TmpStr)-1); + strncpyz(TmpStr,DestPtr,ASIZE(TmpStr)); strcpy(DestPath,TmpStr); } return((char *)DestPtr); @@ -235,7 +236,7 @@ bool IsDriveDiv(int Ch) int GetPathDisk(const char *Path) { if (IsDiskLetter(Path)) - return(toupper(*Path)-'A'); + return(etoupper(*Path)-'A'); else return(-1); } @@ -257,23 +258,26 @@ void AddEndSlash(wchar *Path) } -void GetFilePath(const char *FullName,char *Path) +// returns file path including the trailing path separator symbol +void GetFilePath(const char *FullName,char *Path,int MaxLength) { - int PathLength=PointToName(FullName)-FullName; + int PathLength=Min(MaxLength-1,PointToName(FullName)-FullName); strncpy(Path,FullName,PathLength); Path[PathLength]=0; } -void GetFilePath(const wchar *FullName,wchar *Path) +// returns file path including the trailing path separator symbol +void GetFilePath(const wchar *FullName,wchar *Path,int MaxLength) { - const wchar *PathPtr=/*(*FullName && IsDriveDiv(FullName[1])) ? FullName+2:*/FullName; - int PathLength=PointToName(FullName)-FullName; - strncpyw(Path,PathPtr,PathLength); + int PathLength=Min(MaxLength-1,PointToName(FullName)-FullName); + strncpyw(Path,FullName,PathLength); Path[PathLength]=0; } +// removes name and returns file path without the trailing +// path separator symbol void RemoveNameFromPath(char *Path) { char *Name=PointToName(Path); @@ -284,6 +288,8 @@ void RemoveNameFromPath(char *Path) #ifndef SFX_MODULE +// removes name and returns file path without the trailing +// path separator symbol void RemoveNameFromPath(wchar *Path) { wchar *Name=PointToName(Path); @@ -294,6 +300,31 @@ void RemoveNameFromPath(wchar *Path) #endif +#if defined(_WIN_32) && !defined(_WIN_CE) && !defined(SFX_MODULE) +void GetAppDataPath(char *Path) +{ + LPMALLOC g_pMalloc; + SHGetMalloc(&g_pMalloc); + LPITEMIDLIST ppidl; + *Path=0; + bool Success=false; + if (SHGetSpecialFolderLocation(NULL,CSIDL_APPDATA,&ppidl)==NOERROR && + SHGetPathFromIDList(ppidl,Path) && *Path!=0) + { + AddEndSlash(Path); + strcat(Path,"WinRAR"); + Success=FileExist(Path) || MakeDir(Path,NULL,0)==MKDIR_SUCCESS; + } + if (!Success) + { + GetModuleFileName(NULL,Path,NM); + RemoveNameFromPath(Path); + } + g_pMalloc->Free(ppidl); +} +#endif + + #ifndef SFX_MODULE bool EnumConfigPaths(char *Path,int Number) { @@ -320,7 +351,7 @@ bool EnumConfigPaths(char *Path,int Number) char *EnvStr=getenv("HOME"); if (EnvStr==NULL) return(false); - strncpy(Path,EnvStr,NM); + strncpy(Path,EnvStr,NM-1); Path[NM-1]=0; return(true); } @@ -333,11 +364,18 @@ bool EnumConfigPaths(char *Path,int Number) strcpy(Path,AltPath[Number]); return(true); #elif defined(_WIN_32) - if (Number!=0) + + if (Number<0 || Number>1) return(false); - GetModuleFileName(NULL,Path,NM); - RemoveNameFromPath(Path); + if (Number==0) + GetAppDataPath(Path); + else + { + GetModuleFileName(NULL,Path,NM); + RemoveNameFromPath(Path); + } return(true); + #else return(false); #endif @@ -359,6 +397,7 @@ void GetConfigName(const char *Name,char *FullName,bool CheckExist) #endif +// returns a pointer to rightmost digit of volume number char* GetVolNumPart(char *ArcName) { char *ChPtr=ArcName+strlen(ArcName)-1; @@ -506,10 +545,32 @@ char* DosSlashToUnix(char *SrcName,char *DestName,uint MaxLength) } +wchar* UnixSlashToDos(wchar *SrcName,wchar *DestName,uint MaxLength) +{ + if (DestName!=NULL && DestName!=SrcName) + if (strlenw(SrcName)>=MaxLength) + { + *DestName=0; + return(DestName); + } + else + strcpyw(DestName,SrcName); + for (wchar *s=SrcName;*s!=0;s++) + { + if (*s=='/') + if (DestName==NULL) + *s='\\'; + else + DestName[s-SrcName]='\\'; + } + return(DestName==NULL ? SrcName:DestName); +} + + bool IsFullPath(const char *Path) { char PathOnly[NM]; - GetFilePath(Path,PathOnly); + GetFilePath(Path,PathOnly,ASIZE(PathOnly)); if (IsWildcard(PathOnly)) return(true); #if defined(_WIN_32) || defined(_EMX) @@ -523,7 +584,7 @@ bool IsFullPath(const char *Path) bool IsDiskLetter(const char *Path) { - char Letter=toupper(Path[0]); + char Letter=etoupper(Path[0]); return(Letter>='A' && Letter<='Z' && IsDriveDiv(Path[1])); } diff --git a/src/bin/unrar/pathfn.hpp b/src/bin/unrar/pathfn.hpp index c6d2d9b97d..6975993ce6 100644 --- a/src/bin/unrar/pathfn.hpp +++ b/src/bin/unrar/pathfn.hpp @@ -19,10 +19,11 @@ bool IsDriveDiv(int Ch); int GetPathDisk(const char *Path); void AddEndSlash(char *Path); void AddEndSlash(wchar *Path); -void GetFilePath(const char *FullName,char *Path); -void GetFilePath(const wchar *FullName,wchar *Path); +void GetFilePath(const char *FullName,char *Path,int MaxLength); +void GetFilePath(const wchar *FullName,wchar *Path,int MaxLength); void RemoveNameFromPath(char *Path); void RemoveNameFromPath(wchar *Path); +void GetAppDataPath(char *Path); bool EnumConfigPaths(char *Path,int Number); void GetConfigName(const char *Name,char *FullName,bool CheckExist); char* GetVolNumPart(char *ArcName); @@ -31,6 +32,7 @@ bool IsNameUsable(const char *Name); void MakeNameUsable(char *Name,bool Extended); char* UnixSlashToDos(char *SrcName,char *DestName=NULL,uint MaxLength=NM); char* DosSlashToUnix(char *SrcName,char *DestName=NULL,uint MaxLength=NM); +wchar* UnixSlashToDos(wchar *SrcName,wchar *DestName=NULL,uint MaxLength=NM); bool IsFullPath(const char *Path); bool IsDiskLetter(const char *Path); void GetPathRoot(const char *Path,char *Root); diff --git a/src/bin/unrar/rar.cpp b/src/bin/unrar/rar.cpp index 04621ffbc6..a55fd5535b 100644 --- a/src/bin/unrar/rar.cpp +++ b/src/bin/unrar/rar.cpp @@ -46,6 +46,9 @@ int main(int argc, char *argv[]) #endif +#if defined(_WIN_32) && !defined(SFX_MODULE) && !defined(SHELL_EXT) + bool ShutdownOnClose; +#endif #ifdef ALLOW_EXCEPTIONS try @@ -71,7 +74,7 @@ int main(int argc, char *argv[]) #endif if (Switch!=NULL && Cmd.IsSwitch(Switch[0])) { - int UpperCmd=toupper(Switch[1]); + int UpperCmd=etoupper(Switch[1]); switch(UpperCmd) { case 'T': @@ -95,6 +98,9 @@ int main(int argc, char *argv[]) #endif Cmd.ParseDone(); +#if defined(_WIN_32) && !defined(SFX_MODULE) && !defined(SHELL_EXT) + ShutdownOnClose=Cmd.Shutdown; +#endif InitConsoleOptions(Cmd.MsgStream,Cmd.Sound); InitLogOptions(Cmd.LogName); @@ -126,6 +132,10 @@ int main(int argc, char *argv[]) #endif #if defined(_EMX) && !defined(_DJGPP) uni_done(); +#endif +#if defined(_WIN_32) && !defined(SFX_MODULE) && !defined(SHELL_EXT) + if (ShutdownOnClose) + Shutdown(); #endif return(ErrHandler.GetErrorCode()); } diff --git a/src/bin/unrar/rar.hpp b/src/bin/unrar/rar.hpp index 70b6826b1c..229ee094d7 100644 --- a/src/bin/unrar/rar.hpp +++ b/src/bin/unrar/rar.hpp @@ -20,6 +20,7 @@ #include "errhnd.hpp" #include "array.hpp" #include "timefn.hpp" +#include "options.hpp" #include "headers.hpp" #include "rarfn.hpp" #include "pathfn.hpp" @@ -37,7 +38,6 @@ #include "savepos.hpp" #include "getbits.hpp" #include "rdwrfn.hpp" -#include "options.hpp" #include "archive.hpp" #include "match.hpp" #include "cmddata.hpp" diff --git a/src/bin/unrar/rarvm.cpp b/src/bin/unrar/rarvm.cpp index 05aec9c452..3276c45df3 100644 --- a/src/bin/unrar/rarvm.cpp +++ b/src/bin/unrar/rarvm.cpp @@ -20,16 +20,37 @@ void RarVM::Init() Mem=new byte[VM_MEMSIZE+4]; } +/********************************************************************* + IS_VM_MEM macro checks if address belongs to VM memory pool (Mem). + Only Mem data are always low endian regardless of machine architecture, + so we need to convert them to native format when reading or writing. + VM registers have endianness of host machine. +**********************************************************************/ +#define IS_VM_MEM(a) (((byte*)a)>=Mem && ((byte*)a)>8); - ((byte *)Addr)[2]=(byte)(Value>>16); - ((byte *)Addr)[3]=(byte)(Value>>24); + if (IS_VM_MEM(Addr)) + { + ((byte *)Addr)[0]=(byte)Value; + ((byte *)Addr)[1]=(byte)(Value>>8); + ((byte *)Addr)[2]=(byte)(Value>>16); + ((byte *)Addr)[3]=(byte)(Value>>24); + } + else + *(uint *)Addr=Value; #else *(uint32 *)Addr=Value; #endif @@ -67,9 +102,16 @@ inline void RarVM::SetValue(bool ByteMode,uint *Addr,uint Value) #endif -void RarVM::SetValue(uint *Addr,uint Value) +void RarVM::SetLowEndianValue(uint *Addr,uint Value) { - SetValue(false,Addr,Value); +#if defined(BIG_ENDIAN) || !defined(ALLOW_NOT_ALIGNED_INT) || !defined(PRESENT_INT32) + ((byte *)Addr)[0]=(byte)Value; + ((byte *)Addr)[1]=(byte)(Value>>8); + ((byte *)Addr)[2]=(byte)(Value>>16); + ((byte *)Addr)[3]=(byte)(Value>>24); +#else + *(uint32 *)Addr=Value; +#endif } @@ -88,7 +130,7 @@ void RarVM::Execute(VM_PreparedProgram *Prg) unsigned int GlobalSize=Min(Prg->GlobalData.Size(),VM_GLOBALMEMSIZE); if (GlobalSize) memcpy(Mem+VM_GLOBALMEMADDR,&Prg->GlobalData[0],GlobalSize); - uint StaticSize=Min((uint)Prg->StaticData.Size(),VM_GLOBALMEMSIZE-GlobalSize); + unsigned int StaticSize=Min(Prg->StaticData.Size(),VM_GLOBALMEMSIZE-GlobalSize); if (StaticSize) memcpy(Mem+VM_GLOBALMEMADDR+GlobalSize,&Prg->StaticData[0],StaticSize); @@ -106,7 +148,8 @@ void RarVM::Execute(VM_PreparedProgram *Prg) Prg->FilteredDataSize=NewBlockSize; Prg->GlobalData.Reset(); - uint DataSize=Min(GET_VALUE(false,(uint*)&Mem[VM_GLOBALMEMADDR+0x30]),VM_GLOBALMEMSIZE); + + uint DataSize=Min(GET_VALUE(false,(uint*)&Mem[VM_GLOBALMEMADDR+0x30]),VM_GLOBALMEMSIZE-VM_FIXEDGLOBALSIZE); if (DataSize!=0) { Prg->GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE); @@ -115,6 +158,14 @@ void RarVM::Execute(VM_PreparedProgram *Prg) } +/* +Note: + Due to performance considerations RAR VM may set VM_FS, VM_FC, VM_FZ + incorrectly for byte operands. These flags are always valid only + for 32-bit operands. Check implementation of concrete VM command + to see if it sets flags right. +*/ + #define SET_IP(IP) \ if ((IP)>=CodeSize) \ return(true); \ @@ -171,7 +222,13 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) { uint Value1=GET_VALUE(Cmd->ByteMode,Op1); uint Result=UINT32(Value1+GET_VALUE(Cmd->ByteMode,Op2)); - Flags=Result==0 ? VM_FZ:(ResultByteMode) + { + Result&=0xff; + Flags=(ResultByteMode,Op1,Result); } break; @@ -209,13 +266,15 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) case VM_JNZ: if ((Flags & VM_FZ)==0) { - SET_IP(GET_VALUE(false,(uint)Op1)); + SET_IP(GET_VALUE(false,Op1)); continue; } break; case VM_INC: { uint Result=UINT32(GET_VALUE(Cmd->ByteMode,Op1)+1); + if (Cmd->ByteMode) + Result&=0xff; SET_VALUE(Cmd->ByteMode,Op1,Result); Flags=Result==0 ? VM_FZ:Result&VM_FS; } @@ -244,7 +303,7 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) break; #endif case VM_JMP: - SET_IP(GET_VALUE((uint)false,Op1)); + SET_IP(GET_VALUE(false,Op1)); continue; case VM_XOR: { @@ -276,42 +335,42 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) case VM_JS: if ((Flags & VM_FS)!=0) { - SET_IP(GET_VALUE((uint)false,Op1)); + SET_IP(GET_VALUE(false,Op1)); continue; } break; case VM_JNS: if ((Flags & VM_FS)==0) { - SET_IP(GET_VALUE((uint)false,Op1)); + SET_IP(GET_VALUE(false,Op1)); continue; } break; case VM_JB: if ((Flags & VM_FC)!=0) { - SET_IP(GET_VALUE((uint)false,Op1)); + SET_IP(GET_VALUE(false,Op1)); continue; } break; case VM_JBE: if ((Flags & (VM_FC|VM_FZ))!=0) { - SET_IP(GET_VALUE((uint)false,Op1)); + SET_IP(GET_VALUE(false,Op1)); continue; } break; case VM_JA: if ((Flags & (VM_FC|VM_FZ))==0) { - SET_IP(GET_VALUE((uint)false,Op1)); + SET_IP(GET_VALUE(false,Op1)); continue; } break; case VM_JAE: if ((Flags & VM_FC)==0) { - SET_IP(GET_VALUE((uint)false,Op1)); + SET_IP(GET_VALUE(false,Op1)); continue; } break; @@ -430,7 +489,9 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) uint Value1=GET_VALUE(Cmd->ByteMode,Op1); uint FC=(Flags&VM_FC); uint Result=UINT32(Value1+GET_VALUE(Cmd->ByteMode,Op2)+FC); - Flags=Result==0 ? VM_FZ:(ResultByteMode) + Result&=0xff; + Flags=(ResultByteMode,Op1,Result); } break; @@ -439,7 +500,9 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,int CodeSize) uint Value1=GET_VALUE(Cmd->ByteMode,Op1); uint FC=(Flags&VM_FC); uint Result=UINT32(Value1-GET_VALUE(Cmd->ByteMode,Op2)-FC); - Flags=Result==0 ? VM_FZ:(Result>Value1 || Result==Value1 && FC)|(Result&VM_FS); + if (Cmd->ByteMode) + Result&=0xff; + Flags=(Result>Value1 || Result==Value1 && FC)|(Result==0 ? VM_FZ:(Result&VM_FS)); SET_VALUE(Cmd->ByteMode,Op1,Result); } break; @@ -496,6 +559,10 @@ void RarVM::Prepare(byte *Code,int CodeSize,VM_PreparedProgram *Prg) #endif uint DataFlag=fgetbits(); faddbits(1); + +/* Read static data contained in DB operators. This data cannot be changed, + it is a part of VM code, not a filter parameter. +*/ if (DataFlag&0x8000) { int DataSize=ReadData(*this)+1; @@ -506,6 +573,7 @@ void RarVM::Prepare(byte *Code,int CodeSize,VM_PreparedProgram *Prg) faddbits(8); } } + while (InAddrCmd.Add(1); @@ -699,8 +767,6 @@ void RarVM::Optimize(VM_PreparedProgram *Prg) case VM_CMP: Cmd->OpCode=Cmd->ByteMode ? VM_CMPB:VM_CMPD; continue; - default: - break; } if ((VM_CmdFlags[Cmd->OpCode] & VMCF_CHFLAGS)==0) continue; @@ -735,8 +801,6 @@ void RarVM::Optimize(VM_PreparedProgram *Prg) case VM_NEG: Cmd->OpCode=Cmd->ByteMode ? VM_NEGB:VM_NEGD; continue; - default: - break; } } } @@ -864,6 +928,10 @@ void RarVM::ExecuteStandardFilter(VM_StandardFilters FilterType) SET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x20],DataSize); if (DataSize>=VM_GLOBALMEMADDR/2) break; + +// bytes from same channels are grouped to continual data blocks, +// so we need to place them back to their interleaving positions + for (int CurChannel=0;CurChannel=VM_GLOBALMEMADDR/2) + if (DataSize>=VM_GLOBALMEMADDR/2 || PosR<0) break; for (int CurChannel=0;CurChannel GlobalData; - Array StaticData; + Array StaticData; // static data contained in DB operators uint InitR[7]; byte *FilteredData; @@ -101,7 +101,7 @@ class RarVM:private BitInput void Init(); void Prepare(byte *Code,int CodeSize,VM_PreparedProgram *Prg); void Execute(VM_PreparedProgram *Prg); - void SetValue(uint *Addr,uint Value); + void SetLowEndianValue(uint *Addr,uint Value); void SetMemory(unsigned int Pos,byte *Data,unsigned int DataSize); static uint ReadData(BitInput &Inp); }; diff --git a/src/bin/unrar/rawread.cpp b/src/bin/unrar/rawread.cpp index e032aaef85..bbba948e89 100644 --- a/src/bin/unrar/rawread.cpp +++ b/src/bin/unrar/rawread.cpp @@ -52,23 +52,38 @@ void RawRead::Read(byte *SrcData,int Size) void RawRead::Get(byte &Field) { - Field=Data[ReadPos]; - ReadPos++; + if (ReadPosGetString(CurMask,CurMaskW,sizeof(CurMask))) return(false); + CurMask[ASIZE(CurMask)-1]=0; + CurMaskW[ASIZE(CurMaskW)-1]=0; #ifdef _WIN_32 UnixSlashToDos(CurMask); #endif diff --git a/src/bin/unrar/smallfn.cpp b/src/bin/unrar/smallfn.cpp index 094691f028..51997c5b3d 100644 --- a/src/bin/unrar/smallfn.cpp +++ b/src/bin/unrar/smallfn.cpp @@ -2,10 +2,16 @@ int ToPercent(Int64 N1,Int64 N2) { - if (N2==0) - return(0); if (N2 I conversion +// problem +int etoupper(int ch) +{ + if (ch=='i') + return('I'); + return(toupper(ch)); +} + + + @@ -163,3 +174,26 @@ int stricompcw(const wchar *Str1,const wchar *Str2) #endif } #endif + + +// safe strncpy: copies maxlen-1 max and always returns zero terminated dest +char* strncpyz(char *dest, const char *src, size_t maxlen) +{ + if (maxlen>0) + { + strncpy(dest,src,maxlen-1); + dest[maxlen-1]=0; + } + return(dest); +} + +// safe strncpyw: copies maxlen-1 max and always returns zero terminated dest +wchar* strncpyzw(wchar *dest, const wchar *src, size_t maxlen) +{ + if (maxlen>0) + { + strncpyw(dest,src,maxlen-1); + dest[maxlen-1]=0; + } + return(dest); +} diff --git a/src/bin/unrar/strfn.hpp b/src/bin/unrar/strfn.hpp index 5c5ac108be..a167667c99 100644 --- a/src/bin/unrar/strfn.hpp +++ b/src/bin/unrar/strfn.hpp @@ -15,6 +15,11 @@ char* RemoveLF(char *Str); unsigned int loctolower(byte ch); unsigned int loctoupper(byte ch); +char* strncpyz(char *dest, const char *src, size_t maxlen); +wchar* strncpyzw(wchar *dest, const wchar *src, size_t maxlen); + +int etoupper(int ch); + bool LowAscii(const char *Str); diff --git a/src/bin/unrar/strlist.cpp b/src/bin/unrar/strlist.cpp index a9fccafe8f..86cace573d 100644 --- a/src/bin/unrar/strlist.cpp +++ b/src/bin/unrar/strlist.cpp @@ -96,13 +96,13 @@ char* StringList::GetString() bool StringList::GetString(char **Str,wchar **StrW) { - if (CurPos>=(uint)StringData.Size()) + if (CurPos>=StringData.Size()) { *Str=NULL; return(false); } *Str=&StringData[CurPos]; - if (PosDataItem<(uint)PosDataW.Size() && (uint)PosDataW[PosDataItem]==CurPos) + if (PosDataItem=(uint)StringData.Size()) + if (StringPos>=StringData.Size()) return(NULL); return(&StringData[StringPos]); } diff --git a/src/bin/unrar/system.cpp b/src/bin/unrar/system.cpp index 1d3cdafedc..9f776dd35d 100644 --- a/src/bin/unrar/system.cpp +++ b/src/bin/unrar/system.cpp @@ -77,3 +77,26 @@ void Wait() +#if defined(_WIN_32) && !defined(_WIN_CE) && !defined(SFX_MODULE) && !defined(SHELL_EXT) + +#ifndef SHTDN_REASON_MAJOR_APPLICATION +#define SHTDN_REASON_MAJOR_APPLICATION 0x00040000 +#define SHTDN_REASON_FLAG_PLANNED 0x80000000 +#define SHTDN_REASON_MINOR_MAINTENANCE 0x00000001 +#endif + +void Shutdown() +{ + HANDLE hToken; + TOKEN_PRIVILEGES tkp; + if (OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken)) + { + LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid); + tkp.PrivilegeCount = 1; + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + AdjustTokenPrivileges(hToken,FALSE,&tkp,0,(PTOKEN_PRIVILEGES)NULL,0); + } + ExitWindowsEx(EWX_SHUTDOWN|EWX_FORCE|EWX_POWEROFF,SHTDN_REASON_FLAG_PLANNED); +} +#endif diff --git a/src/bin/unrar/timefn.cpp b/src/bin/unrar/timefn.cpp index efe430bd45..d11c6635f8 100644 --- a/src/bin/unrar/timefn.cpp +++ b/src/bin/unrar/timefn.cpp @@ -223,7 +223,7 @@ void RarTime::SetAgeText(char *TimeText) Value=Value*10+Ch-'0'; else { - switch(toupper(Ch)) + switch(etoupper(Ch)) { case 'D': Seconds+=Value*24*3600; diff --git a/src/bin/unrar/unicode.cpp b/src/bin/unrar/unicode.cpp index 66a23b6948..f58a8f75ce 100644 --- a/src/bin/unrar/unicode.cpp +++ b/src/bin/unrar/unicode.cpp @@ -18,6 +18,17 @@ bool WideToChar(const wchar *Src,char *Dest,int DestSize) // TODO: haiku fix this! if (wcstombs(Dest,Src,DestSize)==(size_t)-1) RetCode=false; + + if ((!RetCode || *Dest==0 && *Src!=0) && DestSize>NM && strlenw(Src)NM && strlen(Src)Filters.Size() || FiltPos>OldFilterLengths.Size()) return(false); LastFilter=FiltPos; bool NewFilter=(FiltPos==Filters.Size()); + UnpackFilter *StackFilter=new UnpackFilter; // new filter for PrgStack + UnpackFilter *Filter; - if (NewFilter) + if (NewFilter) // new filter code, never used before since VM reset { + // too many different filters, corrupt archive + if (FiltPos>1024) + return(false); + Filters.Add(1); Filters[Filters.Size()-1]=Filter=new UnpackFilter; + StackFilter->ParentFilter=Filters.Size()-1; OldFilterLengths.Add(1); Filter->ExecCount=0; } - else + else // filter was used in the past { Filter=Filters[FiltPos]; + StackFilter->ParentFilter=FiltPos; Filter->ExecCount++; } - UnpackFilter *StackFilter=new UnpackFilter; - int EmptyCount=0; for (int I=0;IPrg.InitR[3]=VM_GLOBALMEMADDR; StackFilter->Prg.InitR[4]=StackFilter->BlockLength; StackFilter->Prg.InitR[5]=StackFilter->ExecCount; - if (FirstByte & 0x10) + + if (FirstByte & 0x10) // set registers to optional parameters if any { unsigned int InitMask=Inp.fgetbits()>>9; Inp.faddbits(7); @@ -558,6 +566,7 @@ bool Unpack::AddVMCode(unsigned int FirstByte,byte *Code,int CodeSize) if (InitMask & (1<Prg.InitR[I]=RarVM::ReadData(Inp); } + if (NewFilter) { uint VMCodeSize=RarVM::ReadData(Inp); @@ -566,6 +575,8 @@ bool Unpack::AddVMCode(unsigned int FirstByte,byte *Code,int CodeSize) Array VMCode(VMCodeSize); for (int I=0;I>8; Inp.faddbits(8); } @@ -577,6 +588,7 @@ bool Unpack::AddVMCode(unsigned int FirstByte,byte *Code,int CodeSize) int StaticDataSize=Filter->Prg.StaticData.Size(); if (StaticDataSize>0 && StaticDataSizePrg.StaticData.Add(StaticDataSize); memcpy(&StackFilter->Prg.StaticData[0],&Filter->Prg.StaticData[0],StaticDataSize); } @@ -588,16 +600,18 @@ bool Unpack::AddVMCode(unsigned int FirstByte,byte *Code,int CodeSize) } byte *GlobalData=&StackFilter->Prg.GlobalData[0]; for (int I=0;I<7;I++) - VM.SetValue((uint *)&GlobalData[I*4],StackFilter->Prg.InitR[I]); - VM.SetValue((uint *)&GlobalData[0x1c],StackFilter->BlockLength); - VM.SetValue((uint *)&GlobalData[0x20],0); - VM.SetValue((uint *)&GlobalData[0x2c],StackFilter->ExecCount); + VM.SetLowEndianValue((uint *)&GlobalData[I*4],StackFilter->Prg.InitR[I]); + VM.SetLowEndianValue((uint *)&GlobalData[0x1c],StackFilter->BlockLength); + VM.SetLowEndianValue((uint *)&GlobalData[0x20],0); + VM.SetLowEndianValue((uint *)&GlobalData[0x2c],StackFilter->ExecCount); memset(&GlobalData[0x30],0,16); - if (FirstByte & 8) + if (FirstByte & 8) // put data block passed as parameter if any { + if (Inp.Overflow(3)) + return(false); uint DataSize=RarVM::ReadData(Inp); - if (DataSize>=0x10000) + if (DataSize>VM_GLOBALMEMSIZE-VM_FIXEDGLOBALSIZE) return(false); unsigned int CurSize=StackFilter->Prg.GlobalData.Size(); if (CurSizePrg.GlobalData[VM_FIXEDGLOBALSIZE]; for (int I=0;I>8; Inp.faddbits(8); } @@ -670,9 +686,29 @@ void Unpack::UnpWriteBuf() VM.SetMemory(0,Window+BlockStart,FirstPartLength); VM.SetMemory(FirstPartLength,Window,BlockEnd); } + + VM_PreparedProgram *ParentPrg=&Filters[flt->ParentFilter]->Prg; VM_PreparedProgram *Prg=&flt->Prg; + + if (ParentPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE) + { + // copy global data from previous script execution if any + Prg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); + memcpy(&Prg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + } + ExecuteCode(Prg); + if (Prg->GlobalData.Size()>VM_FIXEDGLOBALSIZE) + { + // save global data for next script execution + if (ParentPrg->GlobalData.Size()GlobalData.Size()) + ParentPrg->GlobalData.Alloc(Prg->GlobalData.Size()); + memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&Prg->GlobalData[VM_FIXEDGLOBALSIZE],Prg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + } + else + ParentPrg->GlobalData.Reset(); + byte *FilteredData=Prg->FilteredData; unsigned int FilteredDataSize=Prg->FilteredDataSize; @@ -684,9 +720,33 @@ void Unpack::UnpWriteBuf() if (NextFilter==NULL || NextFilter->BlockStart!=BlockStart || NextFilter->BlockLength!=FilteredDataSize || NextFilter->NextWindow) break; + + // apply several filters to same data block + VM.SetMemory(0,FilteredData,FilteredDataSize); - VM_PreparedProgram *NextPrg=&PrgStack[I+1]->Prg; + + VM_PreparedProgram *ParentPrg=&Filters[NextFilter->ParentFilter]->Prg; + VM_PreparedProgram *NextPrg=&NextFilter->Prg; + + if (ParentPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE) + { + // copy global data from previous script execution if any + NextPrg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); + memcpy(&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + } + ExecuteCode(NextPrg); + + if (NextPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE) + { + // save global data for next script execution + if (ParentPrg->GlobalData.Size()GlobalData.Size()) + ParentPrg->GlobalData.Alloc(NextPrg->GlobalData.Size()); + memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],NextPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); + } + else + ParentPrg->GlobalData.Reset(); + FilteredData=NextPrg->FilteredData; FilteredDataSize=NextPrg->FilteredDataSize; I++; @@ -723,8 +783,8 @@ void Unpack::ExecuteCode(VM_PreparedProgram *Prg) if (Prg->GlobalData.Size()>0) { Prg->InitR[6]=int64to32(WrittenFileSize); - VM.SetValue((uint *)&Prg->GlobalData[0x24],int64to32(WrittenFileSize)); - VM.SetValue((uint *)&Prg->GlobalData[0x28],int64to32(WrittenFileSize>>32)); + VM.SetLowEndianValue((uint *)&Prg->GlobalData[0x24],int64to32(WrittenFileSize)); + VM.SetLowEndianValue((uint *)&Prg->GlobalData[0x28],int64to32(WrittenFileSize>>32)); VM.Execute(Prg); } } diff --git a/src/bin/unrar/unpack.hpp b/src/bin/unrar/unpack.hpp index 83fb0f0254..4def6a566f 100644 --- a/src/bin/unrar/unpack.hpp +++ b/src/bin/unrar/unpack.hpp @@ -57,6 +57,11 @@ struct UnpackFilter unsigned int BlockLength; unsigned int ExecCount; bool NextWindow; + + // position of parent filter in Filters array used as prototype for filter + // in PrgStack array. Not defined for filters in Filters array. + unsigned int ParentFilter; + VM_PreparedProgram Prg; }; @@ -111,9 +116,17 @@ class Unpack:private BitInput int PPMEscChar; RarVM VM; + + /* Filters code, one entry per filter */ Array Filters; + + /* Filters stack, several entrances of same filter are possible */ Array PrgStack; + + /* lengths of preceding blocks, one length per filter. Used to reduce + size required to write block length if lengths are repeating */ Array OldFilterLengths; + int LastFilter; bool TablesRead; diff --git a/src/bin/unrar/unpack15.cpp b/src/bin/unrar/unpack15.cpp index a0fa897f3a..170085bbeb 100644 --- a/src/bin/unrar/unpack15.cpp +++ b/src/bin/unrar/unpack15.cpp @@ -136,6 +136,9 @@ void Unpack::OldUnpWriteBuf() } +#define GetShortLen1(pos) ((pos)==1 ? Buf60+3:ShortLen1[pos]) +#define GetShortLen2(pos) ((pos)==3 ? Buf60+3:ShortLen2[pos]) + void Unpack::ShortLZ() { static unsigned int ShortLen1[]={1,3,4,4,5,6,7,8,8,4,4,5,6,6,4,0}; @@ -167,21 +170,22 @@ void Unpack::ShortLZ() BitField>>=8; - ShortLen1[1]=ShortLen2[3]=Buf60+3; +// not thread safe, replaced by GetShortLen1 and GetShortLen2 macro +// ShortLen1[1]=ShortLen2[3]=Buf60+3; if (AvrLn1<37) { for (Length=0;;Length++) - if (((BitField^ShortXor1[Length]) & (~(0xff>>ShortLen1[Length])))==0) + if (((BitField^ShortXor1[Length]) & (~(0xff>>GetShortLen1(Length))))==0) break; - faddbits(ShortLen1[Length]); + faddbits(GetShortLen1(Length)); } else { for (Length=0;;Length++) - if (((BitField^ShortXor2[Length]) & (~(0xff>>ShortLen2[Length])))==0) + if (((BitField^ShortXor2[Length]) & (~(0xff>>GetShortLen2(Length))))==0) break; - faddbits(ShortLen2[Length]); + faddbits(GetShortLen2(Length)); } if (Length >= 9) diff --git a/src/bin/unrar/unrar.rdef b/src/bin/unrar/unrar.rdef index 3f0cc03411..8263e91e06 100755 --- a/src/bin/unrar/unrar.rdef +++ b/src/bin/unrar/unrar.rdef @@ -4,10 +4,10 @@ resource app_flags B_MULTIPLE_LAUNCH | B_BACKGROUND_APP; resource app_version { major = 3, - middle = 6, - minor = 7, + middle = 7, + minor = 6, variety = 0, internal = 0, - short_info = "3.67", - long_info = "3.67 Alexander Roshal" + short_info = "3.76", + long_info = "3.76 Alexander Roshal" }; diff --git a/src/bin/unrar/version.hpp b/src/bin/unrar/version.hpp index a7652efbae..3e628dd3ff 100644 --- a/src/bin/unrar/version.hpp +++ b/src/bin/unrar/version.hpp @@ -1,6 +1,6 @@ #define RARVER_MAJOR 3 -#define RARVER_MINOR 60 -#define RARVER_BETA 7 -#define RARVER_DAY 13 -#define RARVER_MONTH 7 -#define RARVER_YEAR 2006 +#define RARVER_MINOR 70 +#define RARVER_BETA 0 +#define RARVER_DAY 22 +#define RARVER_MONTH 5 +#define RARVER_YEAR 2007 diff --git a/src/bin/unrar/volume.cpp b/src/bin/unrar/volume.cpp index 9c2ab39ad4..28f0757b29 100644 --- a/src/bin/unrar/volume.cpp +++ b/src/bin/unrar/volume.cpp @@ -22,15 +22,43 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,char Comman Arc.Close(); char NextName[NM]; + wchar NextNameW[NM]; + *NextNameW=0; strcpy(NextName,Arc.FileName); NextVolumeName(NextName,(Arc.NewMhd.Flags & MHD_NEWNUMBERING)==0 || Arc.OldFormat); + if (*Arc.FileNameW!=0) + { + // Copy incremented trailing low ASCII volume name part to Unicode name. + // It is simpler than also implementing Unicode version of NextVolumeName. + + strcpyw(NextNameW,Arc.FileNameW); + char *NumPtr=GetVolNumPart(NextName); + + // moving to first digit in volume number + while (NumPtr>NextName && isdigit(*NumPtr) && isdigit(*(NumPtr-1))) + NumPtr--; + + // also copy the first character before volume number, + // because it can be changed when going from .r99 to .s00 + if (NumPtr>NextName) + NumPtr--; + + int CharsToCopy=strlen(NextName)-(NumPtr-NextName); + int DestPos=strlenw(NextNameW)-CharsToCopy; + if (DestPos>0) + { + CharToWide(NumPtr,NextNameW+DestPos,ASIZE(NextNameW)-DestPos-1); + NextNameW[ASIZE(NextNameW)-1]=0; + } + } + #if !defined(SFX_MODULE) && !defined(RARDLL) bool RecoveryDone=false; #endif bool FailedOpen=false,OldSchemeTested=false; - while (!Arc.Open(NextName)) + while (!Arc.Open(NextName,NextNameW)) { if (!OldSchemeTested) { @@ -41,6 +69,7 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,char Comman if (Arc.Open(AltNextName)) { strcpy(NextName,AltNextName); + *NextNameW=0; break; } } @@ -94,6 +123,7 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,char Comman FailedOpen=true; break; } + *NextNameW=0; #endif } if (FailedOpen) diff --git a/src/bin/unrar/win32stm.cpp b/src/bin/unrar/win32stm.cpp index 680d03b7c9..79092913b8 100644 --- a/src/bin/unrar/win32stm.cpp +++ b/src/bin/unrar/win32stm.cpp @@ -33,7 +33,8 @@ void ExtractStreams(Archive &Arc,char *FileName,wchar *FileNameW) } else strcpy(StreamName,FileName); - if (strlen(StreamName)+strlen((char *)Arc.StreamHead.StreamName)>=sizeof(StreamName)) + if (strlen(StreamName)+strlen((char *)Arc.StreamHead.StreamName)>=sizeof(StreamName) || + Arc.StreamHead.StreamName[0]!=':') { #ifndef SILENT Log(Arc.FileName,St(MStreamBroken),FileName); @@ -42,6 +43,8 @@ void ExtractStreams(Archive &Arc,char *FileName,wchar *FileNameW) return; } + ConvertPath((char *)Arc.StreamHead.StreamName+1,(char *)Arc.StreamHead.StreamName+1); + strcat(StreamName,(char *)Arc.StreamHead.StreamName); FindData fd; @@ -119,6 +122,17 @@ void ExtractStreamsNew(Archive &Arc,char *FileName,wchar *FileNameW) RawToWide(SrcName,DestName,DestSize); DestName[DestSize]=0; + if (*DestName!=':') + { +#if !defined(SILENT) && !defined(SFX_MODULE) + Log(Arc.FileName,St(MStreamBroken),FileName); +#endif + ErrHandler.SetErrorCode(CRC_ERROR); + return; + } + + ConvertPath(DestName+1,DestName+1); + FindData fd; bool Found=FindFile::FastFind(FileName,FileNameW,&fd); @@ -133,6 +147,8 @@ void ExtractStreamsNew(Archive &Arc,char *FileName,wchar *FileNameW) if (Found && HostFile.Open(FileName,FileNameW,true,true)) SetFileTime(HostFile.GetHandle(),&fd.ftCreationTime,&fd.ftLastAccessTime, &fd.ftLastWriteTime); - if (fd.FileAttr & FILE_ATTRIBUTE_READONLY) - SetFileAttr(FileName,FileNameW,fd.FileAttr); + + // Restoring original file attributes. Important if file was read only + // or did not have "Archive" attribute + SetFileAttr(FileName,FileNameW,fd.FileAttr); }