diff options
Diffstat (limited to 'src/thirdparty/unrar')
75 files changed, 1312 insertions, 493 deletions
diff --git a/src/thirdparty/unrar/archive.cpp b/src/thirdparty/unrar/archive.cpp index 7ca0b7461..203899fef 100644 --- a/src/thirdparty/unrar/archive.cpp +++ b/src/thirdparty/unrar/archive.cpp @@ -109,9 +109,9 @@ RARFORMAT Archive::IsSignature(const byte *D,size_t Size) #endif if (Size>=7 && D[1]==0x61 && D[2]==0x72 && D[3]==0x21 && D[4]==0x1a && D[5]==0x07) { - // We check for non-zero last signature byte, so we can return - // a sensible warning in case we'll want to change the archive - // format sometimes in the future. + // We check the last signature byte, so we can return a sensible + // warning in case we'll want to change the archive format + // sometimes in the future. if (D[6]==0) Type=RARFMT15; else @@ -240,13 +240,22 @@ bool Archive::IsArchive(bool EnableBroken) { HEADER_TYPE HeaderType=GetHeaderType(); if (HeaderType==HEAD_SERVICE) + { + // If we have a split service headers, it surely indicates non-first + // volume. But not split service header does not guarantee the first + // volume, because we can have split file after non-split archive + // comment. So we do not quit from loop here. FirstVolume=Volume && !SubHead.SplitBefore; + } else if (HeaderType==HEAD_FILE) { FirstVolume=Volume && !FileHead.SplitBefore; break; } + else + if (HeaderType==HEAD_ENDARC) // Might happen if archive contains only a split service header. + break; SeekToNext(); } CurBlockPos=SaveCurBlockPos; diff --git a/src/thirdparty/unrar/archive.hpp b/src/thirdparty/unrar/archive.hpp index 522709608..6d1515697 100644 --- a/src/thirdparty/unrar/archive.hpp +++ b/src/thirdparty/unrar/archive.hpp @@ -61,7 +61,7 @@ class Archive:public File public: Archive(RAROptions *InitCmd=NULL); ~Archive(); - RARFORMAT IsSignature(const byte *D,size_t Size); + static RARFORMAT IsSignature(const byte *D,size_t Size); bool IsArchive(bool EnableBroken); size_t SearchBlock(HEADER_TYPE HeaderType); size_t SearchSubBlock(const wchar *Type); diff --git a/src/thirdparty/unrar/arcread.cpp b/src/thirdparty/unrar/arcread.cpp index 047289b7a..146393872 100644 --- a/src/thirdparty/unrar/arcread.cpp +++ b/src/thirdparty/unrar/arcread.cpp @@ -53,9 +53,11 @@ size_t Archive::SearchBlock(HEADER_TYPE HeaderType) size_t Archive::SearchSubBlock(const wchar *Type) { - size_t Size; + size_t Size,Count=0; while ((Size=ReadHeader())!=0 && GetHeaderType()!=HEAD_ENDARC) { + if ((++Count & 127)==0) + Wait(); if (GetHeaderType()==HEAD_SERVICE && SubHead.CmpName(Type)) return Size; SeekToNext(); @@ -318,9 +320,8 @@ size_t Archive::ReadHeader15() else *hd->FileName=0; - char AnsiName[NM]; - IntToExt(FileName,AnsiName,ASIZE(AnsiName)); - GetWideName(AnsiName,hd->FileName,hd->FileName,ASIZE(hd->FileName)); + if (*hd->FileName==0) + ArcCharToWide(FileName,hd->FileName,ASIZE(hd->FileName),ACTW_OEM); #ifndef SFX_MODULE ConvertNameCase(hd->FileName); @@ -784,7 +785,12 @@ size_t Archive::ReadHeader50() uint CompInfo=(uint)Raw.GetV(); hd->Method=(CompInfo>>7) & 7; - hd->UnpVer=CompInfo & 0x3f; + + // "+ 50" to not mix with old RAR format algorithms. For example, + // we may need to use the compression algorithm 15 in the future, + // but it was already used in RAR 1.5 and Unpack needs to distinguish + // them. + hd->UnpVer=(CompInfo & 0x3f) + 50; hd->HostOS=(byte)Raw.GetV(); size_t NameSize=(size_t)Raw.GetV(); @@ -915,7 +921,7 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb) size_t NextPos=size_t(Raw->GetPos()+FieldSize); uint64 FieldType=Raw->GetV(); - FieldSize=Raw->DataLeft(); // Field size without size and type fields. + FieldSize=int64(NextPos-Raw->GetPos()); // Field size without size and type fields. if (bb->HeaderType==HEAD_MAIN) { @@ -982,6 +988,11 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb) sha256_done(&ctx, Digest); hd->UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0; + + // RAR 5.21 and earlier set PswCheck field in service records to 0 + // even if UsePswCheck was present. + if (bb->HeaderType==HEAD_SERVICE && memcmp(hd->PswCheck,"\0\0\0\0\0\0\0\0",SIZE_PSWCHECK)==0) + hd->UsePswCheck=0; } hd->SaltSet=true; hd->CryptMethod=CRYPT_RAR50; @@ -1095,6 +1106,19 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb) break; case FHEXTRA_SUBDATA: { + // RAR 5.21 and earlier set FHEXTRA_SUBDATA size to 1 less than + // required. It did not hurt extraction, because UnRAR 5.21 + // and earlier ignored this field and set FieldSize as data left + // in entire extra area. But now we set the correct field size + // and set FieldSize based on actual extra record size, + // so we need to adjust it for those older archives here. + // FHEXTRA_SUBDATA in those archives always belongs to HEAD_SERVICE + // and always is last in extra area. So since its size is by 1 + // less than needed, we always have 1 byte left in extra area, + // which fact we use here to detect such archives. + if (bb->HeaderType==HEAD_SERVICE && Raw->Size()-NextPos==1) + FieldSize++; + hd->SubData.Alloc((size_t)FieldSize); Raw->GetB(hd->SubData.Addr(0),(size_t)FieldSize); } @@ -1266,6 +1290,11 @@ void Archive::ConvertFileHeader(FileHeader *hd) else hd->FileAttr=0x20; +#ifdef _WIN_ALL + if (hd->HSType==HSYS_UNIX) // Convert Unix, OS X and Android decomposed chracters to Windows precomposed. + ConvertToPrecomposed(hd->FileName,ASIZE(hd->FileName)); +#endif + for (wchar *s=hd->FileName;*s!=0;s++) { #ifdef _UNIX @@ -1344,14 +1373,19 @@ bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile) uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName); return false; } - UnpData->Alloc((size_t)SubHead.UnpSize); - SubDataIO.SetUnpackToMemory(&(*UnpData)[0],(uint)SubHead.UnpSize); + if (UnpData==NULL) + SubDataIO.SetTestMode(true); + else + { + UnpData->Alloc((size_t)SubHead.UnpSize); + SubDataIO.SetUnpackToMemory(&(*UnpData)[0],(uint)SubHead.UnpSize); + } } if (SubHead.Encrypted) if (Cmd->Password.IsSet()) SubDataIO.SetEncryption(false,SubHead.CryptMethod,&Cmd->Password, SubHead.SaltSet ? SubHead.Salt:NULL,SubHead.InitV, - SubHead.Lg2Count,SubHead.PswCheck,SubHead.HashKey); + SubHead.Lg2Count,SubHead.HashKey,SubHead.PswCheck); else return false; SubDataIO.UnpHash.Init(SubHead.FileHash.Type,1); diff --git a/src/thirdparty/unrar/blake2s.cpp b/src/thirdparty/unrar/blake2s.cpp index d481bc63a..a7207d33b 100644 --- a/src/thirdparty/unrar/blake2s.cpp +++ b/src/thirdparty/unrar/blake2s.cpp @@ -162,7 +162,7 @@ void blake2s_update( blake2s_state *S, const byte *in, size_t inlen ) memcpy( S->buf + left, in, (size_t)inlen ); S->buflen += (size_t)inlen; // Be lazy, do not compress in += inlen; - inlen -= inlen; + inlen = 0; } } } diff --git a/src/thirdparty/unrar/cmddata.cpp b/src/thirdparty/unrar/cmddata.cpp index 3f84cc373..8502210f6 100644 --- a/src/thirdparty/unrar/cmddata.cpp +++ b/src/thirdparty/unrar/cmddata.cpp @@ -52,6 +52,7 @@ void CommandData::ParseCommandLine(bool Preprocess,int argc, char *argv[]) // 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. + // Also our own parser is Unicode compatible. const wchar *CmdLine=GetCommandLine(); wchar *Par; @@ -466,6 +467,11 @@ void CommandData::ProcessSwitch(const wchar *Switch) Shutdown=true; break; } + if (wcsicomp(Switch+1,L"VER")==0) + { + PrintVersion=true; + break; + } break; case 'K': switch(toupperw(Switch[1])) @@ -620,6 +626,12 @@ void CommandData::ProcessSwitch(const wchar *Switch) AbsoluteLinks=true; break; #endif +#ifdef _WIN_ALL + case 'N': + if (toupperw(Switch[2])=='I') + AllowIncompatNames=true; + break; +#endif case 'R': Overwrite=OVERWRITE_AUTORENAME; break; @@ -766,6 +778,9 @@ void CommandData::ProcessSwitch(const wchar *Switch) case 'L': FilelistCharset=rch; break; + case 'R': + RedirectCharset=rch; + break; default: BadSwitch(Switch); AlreadyBad=true; @@ -916,12 +931,26 @@ void CommandData::OutTitle() if (TitleShown) return; TitleShown=true; - wchar Version[50]; - int Beta=RARVER_BETA; - if (Beta!=0) + + wchar Version[80]; + if (RARVER_BETA!=0) swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA); else swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR); +#if defined(_WIN_32) || defined(_WIN_64) + wcsncatz(Version,L" ",ASIZE(Version)); +#endif +#ifdef _WIN_32 + wcsncatz(Version,St(Mx86),ASIZE(Version)); +#endif +#ifdef _WIN_64 + wcsncatz(Version,St(Mx64),ASIZE(Version)); +#endif + if (PrintVersion) + { + mprintf(L"%s",Version); + exit(0); + } #ifdef UNRAR mprintf(St(MUCopyright),Version,RARVER_YEAR); #else @@ -977,7 +1006,7 @@ void CommandData::OutHelp(RAR_EXIT ExitCode) #ifndef _WIN_ALL static MSGID Win32Only[]={ MCHelpSwIEML,MCHelpSwVD,MCHelpSwAO,MCHelpSwOS,MCHelpSwIOFF, - MCHelpSwEP2,MCHelpSwOC,MCHelpSwDR,MCHelpSwRI + MCHelpSwEP2,MCHelpSwOC,MCHelpSwONI,MCHelpSwDR,MCHelpSwRI }; bool Found=false; for (int J=0;J<sizeof(Win32Only)/sizeof(Win32Only[0]);J++) @@ -1019,24 +1048,24 @@ void CommandData::OutHelp(RAR_EXIT ExitCode) // the include list created with -n switch. bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList) { - if (ExclCheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH)) + if (CheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH)) return true; if (!CheckInclList || InclArgs.ItemsCount()==0) return false; - if (ExclCheckArgs(&InclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH)) + if (CheckArgs(&InclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH)) return false; return true; } -bool CommandData::ExclCheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode) +bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode) { wchar *Name=ConvertPath(CheckName,NULL); wchar FullName[NM]; - wchar CurMask[NM+1]; // We reserve the space to append "*" to mask. + wchar CurMask[NM]; *FullName=0; Args->Rewind(); - while (Args->GetString(CurMask,ASIZE(CurMask)-1)) + while (Args->GetString(CurMask,ASIZE(CurMask))) { wchar *LastMaskChar=PointToLastChar(CurMask); bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only. @@ -1053,23 +1082,24 @@ bool CommandData::ExclCheckArgs(StringList *Args,bool Dir,const wchar *CheckName } else { + // REMOVED, we want -npath\* to match empty folders too. // If mask has wildcards in name part and does not have the trailing // '\' character, we cannot use it for directories. - if (IsWildcard(PointToName(CurMask))) - continue; + // if (IsWildcard(PointToName(CurMask))) + // continue; } } else { // If we process a file inside of directory excluded by "dirmask\". // we want to exclude such file too. So we convert "dirmask\" to - // "dirmask\*". It is important for operations other than archiving. - // When archiving, directory matched by "dirmask\" is excluded - // from further scanning. + // "dirmask\*". It is important for operations other than archiving + // with -x. When archiving with -x, directory matched by "dirmask\" + // is excluded from further scanning. if (DirMask) - wcscat(CurMask,L"*"); + wcsncatz(CurMask,L"*",ASIZE(CurMask)); } #ifndef SFX_MODULE @@ -1090,7 +1120,12 @@ bool CommandData::ExclCheckArgs(StringList *Args,bool Dir,const wchar *CheckName #endif { wchar NewName[NM+2],*CurName=Name; - if (CurMask[0]=='*' && IsPathDiv(CurMask[1])) + + // Important to convert before "*\" check below, so masks like + // d:*\something are processed properly. + wchar *CmpMask=ConvertPath(CurMask,NULL); + + if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1])) { // We want "*\name" to match 'name' not only in subdirectories, // but also in the current directory. We convert the name @@ -1102,7 +1137,7 @@ bool CommandData::ExclCheckArgs(StringList *Args,bool Dir,const wchar *CheckName CurName=NewName; } - if (CmpName(ConvertPath(CurMask,NULL),CurName,MatchMode)) + if (CmpName(CmpMask,CurName,MatchMode)) return true; } } @@ -1201,13 +1236,24 @@ void CommandData::ProcessCommand() 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 (GetExt(ArcName)==NULL && (!FileExist(ArcName) || IsDir(GetFileAttr(ArcName)))) + if (ArcExt==NULL && (!FileExist(ArcName) || IsDir(GetFileAttr(ArcName)))) wcsncatz(ArcName,L".rar",ASIZE(ArcName)); #else - if (GetExt(ArcName)==NULL) + 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) { diff --git a/src/thirdparty/unrar/cmddata.hpp b/src/thirdparty/unrar/cmddata.hpp index d2cdbb94d..8b54ce3e2 100644 --- a/src/thirdparty/unrar/cmddata.hpp +++ b/src/thirdparty/unrar/cmddata.hpp @@ -12,7 +12,6 @@ class CommandData:public RAROptions void ProcessSwitchesString(const wchar *Str); void ProcessSwitch(const wchar *Switch); void BadSwitch(const wchar *Switch); - bool ExclCheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode); uint GetExclAttr(const wchar *Str); bool FileLists; @@ -33,6 +32,7 @@ class CommandData:public RAROptions void OutHelp(RAR_EXIT ExitCode); bool IsSwitch(int Ch); bool ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList); + static bool CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode); bool ExclDirByAttr(uint FileAttr); bool TimeCheck(RarTime &ft); bool SizeCheck(int64 Size); diff --git a/src/thirdparty/unrar/consio.cpp b/src/thirdparty/unrar/consio.cpp index 55cb5ce50..7f39a2b11 100644 --- a/src/thirdparty/unrar/consio.cpp +++ b/src/thirdparty/unrar/consio.cpp @@ -2,12 +2,11 @@ #include "log.cpp" static MESSAGE_TYPE MsgStream=MSG_STDOUT; +static RAR_CHARSET RedirectCharset=RCH_DEFAULT; + const int MaxMsgSize=2*NM+2048; -#ifdef _WIN_ALL static bool StdoutRedirected=false,StderrRedirected=false,StdinRedirected=false; -#endif - #ifdef _WIN_ALL static bool IsRedirected(DWORD nStdHandle) @@ -42,13 +41,18 @@ void InitConsole() if (!StderrRedirected) _setmode(_fileno(stderr), _O_U16TEXT); #endif +#elif defined(_UNIX) + StdoutRedirected=!isatty(fileno(stdout)); + StderrRedirected=!isatty(fileno(stderr)); + StdinRedirected=!isatty(fileno(stdin)); #endif } -void InitConsoleOptions(MESSAGE_TYPE MsgStream) +void InitConsoleOptions(MESSAGE_TYPE MsgStream,RAR_CHARSET RedirectCharset) { ::MsgStream=MsgStream; + ::RedirectCharset=RedirectCharset; } @@ -63,17 +67,23 @@ static void cvt_wprintf(FILE *dest,const wchar *fmt,va_list arglist) safebuf wchar Msg[MaxMsgSize]; if (dest==stdout && StdoutRedirected || dest==stderr && StderrRedirected) { - // Avoid Unicode for redirect in Windows, it does not work with pipes. - vswprintf(Msg,ASIZE(Msg),fmtw,arglist); - safebuf char MsgA[MaxMsgSize]; - WideToChar(Msg,MsgA,ASIZE(MsgA)); - CharToOemA(MsgA,MsgA); // Console tools like 'more' expect OEM encoding. - - // We already converted \n to \r\n above, so we use WriteFile instead - // of C library to avoid unnecessary additional conversion. HANDLE hOut=GetStdHandle(dest==stdout ? STD_OUTPUT_HANDLE:STD_ERROR_HANDLE); + vswprintf(Msg,ASIZE(Msg),fmtw,arglist); DWORD Written; - WriteFile(hOut,MsgA,(DWORD)strlen(MsgA),&Written,NULL); + if (RedirectCharset==RCH_UNICODE) + WriteFile(hOut,Msg,(DWORD)wcslen(Msg)*sizeof(*Msg),&Written,NULL); + else + { + // Avoid Unicode for redirect in Windows, it does not work with pipes. + safebuf char MsgA[MaxMsgSize]; + WideToChar(Msg,MsgA,ASIZE(MsgA)); + if (RedirectCharset!=RCH_ANSI) + CharToOemA(MsgA,MsgA); // Console tools like 'more' expect OEM encoding. + + // We already converted \n to \r\n above, so we use WriteFile instead + // of C library to avoid unnecessary additional conversion. + WriteFile(hOut,MsgA,(DWORD)strlen(MsgA),&Written,NULL); + } return; } // MSVC2008 vfwprintf writes every character to console separately @@ -127,32 +137,37 @@ static void GetPasswordText(wchar *Str,uint MaxLength) { if (MaxLength==0) return; + if (StdinRedirected) + getwstr(Str,MaxLength); // Read from pipe or redirected file. + else + { #ifdef _WIN_ALL - HANDLE hConIn=GetStdHandle(STD_INPUT_HANDLE); - HANDLE hConOut=GetStdHandle(STD_OUTPUT_HANDLE); - DWORD ConInMode,ConOutMode; - DWORD Read=0; - GetConsoleMode(hConIn,&ConInMode); - GetConsoleMode(hConOut,&ConOutMode); - SetConsoleMode(hConIn,ENABLE_LINE_INPUT); - SetConsoleMode(hConOut,ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT); - - ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL); - Str[Read]=0; - SetConsoleMode(hConIn,ConInMode); - SetConsoleMode(hConOut,ConOutMode); + HANDLE hConIn=GetStdHandle(STD_INPUT_HANDLE); + HANDLE hConOut=GetStdHandle(STD_OUTPUT_HANDLE); + DWORD ConInMode,ConOutMode; + DWORD Read=0; + GetConsoleMode(hConIn,&ConInMode); + GetConsoleMode(hConOut,&ConOutMode); + SetConsoleMode(hConIn,ENABLE_LINE_INPUT); + SetConsoleMode(hConOut,ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT); + + ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL); + Str[Read]=0; + SetConsoleMode(hConIn,ConInMode); + SetConsoleMode(hConOut,ConOutMode); #else - char StrA[MAXPASSWORD]; + char StrA[MAXPASSWORD]; #if defined(_EMX) || defined (__VMS) - fgets(StrA,ASIZE(StrA)-1,stdin); + fgets(StrA,ASIZE(StrA)-1,stdin); #elif defined(__sun) - strncpyz(StrA,getpassphrase(""),ASIZE(StrA)); + strncpyz(StrA,getpassphrase(""),ASIZE(StrA)); #else - strncpyz(StrA,getpass(""),ASIZE(StrA)); + strncpyz(StrA,getpass(""),ASIZE(StrA)); #endif - CharToWide(StrA,Str,MaxLength); - cleandata(StrA,sizeof(StrA)); + CharToWide(StrA,Str,MaxLength); + cleandata(StrA,sizeof(StrA)); #endif + } Str[MaxLength-1]=0; RemoveLF(Str); } @@ -162,20 +177,22 @@ static void GetPasswordText(wchar *Str,uint MaxLength) #ifndef SILENT bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password) { - uiAlarm(UIALARM_QUESTION); + if (!StdinRedirected) + uiAlarm(UIALARM_QUESTION); while (true) { - if (Type==UIPASSWORD_GLOBAL) - eprintf(L"\n%s: ",St(MAskPsw)); - else - eprintf(St(MAskPswFor),FileName); + if (!StdinRedirected) + if (Type==UIPASSWORD_GLOBAL) + eprintf(L"\n%s: ",St(MAskPsw)); + else + eprintf(St(MAskPswFor),FileName); wchar PlainPsw[MAXPASSWORD]; GetPasswordText(PlainPsw,ASIZE(PlainPsw)); if (*PlainPsw==0 && Type==UIPASSWORD_GLOBAL) return false; - if (Type==UIPASSWORD_GLOBAL) + if (!StdinRedirected && Type==UIPASSWORD_GLOBAL) { eprintf(St(MReAskPsw)); wchar CmpStr[MAXPASSWORD]; @@ -222,8 +239,9 @@ bool getwstr(wchar *str,size_t n) // calling Ask(), so let's better exit. ErrHandler.Exit(RARX_USERBREAK); } - StrA[ReadSize-1]=0; + StrA[ReadSize]=0; CharToWide(&StrA[0],str,n); + cleandata(&StrA[0],StrA.Size()); // We can use this function to enter passwords. } else { diff --git a/src/thirdparty/unrar/consio.hpp b/src/thirdparty/unrar/consio.hpp index 5c9e67da1..4a0ed128e 100644 --- a/src/thirdparty/unrar/consio.hpp +++ b/src/thirdparty/unrar/consio.hpp @@ -2,7 +2,7 @@ #define _RAR_CONSIO_ void InitConsole(); -void InitConsoleOptions(MESSAGE_TYPE MsgStream); +void InitConsoleOptions(MESSAGE_TYPE MsgStream,RAR_CHARSET RedirectCharset); void OutComment(const wchar *Comment,size_t Size); #ifndef SILENT diff --git a/src/thirdparty/unrar/crc.cpp b/src/thirdparty/unrar/crc.cpp index d593281e7..d77fa030c 100644 --- a/src/thirdparty/unrar/crc.cpp +++ b/src/thirdparty/unrar/crc.cpp @@ -37,15 +37,15 @@ static void InitTables() { InitCRC32(crc_tables[0]); - for (uint I=0;I<256;I++) // Build additional lookup tables. + for (uint I=0;I<256;I++) // Build additional lookup tables. { - uint C=crc_tables[0][I]; - for (uint J=1;J<8;J++) + uint C=crc_tables[0][I]; + for (uint J=1;J<8;J++) { - C=crc_tables[0][(byte)C]^(C>>8); - crc_tables[J][I]=C; - } - } + C=crc_tables[0][(byte)C]^(C>>8); + crc_tables[J][I]=C; + } + } } @@ -62,13 +62,13 @@ uint CRC32(uint StartCRC,const void *Addr,size_t Size) for (;Size>=8;Size-=8,Data+=8) { #ifdef BIG_ENDIAN - StartCRC ^= Data[0]|(Data[1] << 8)|(Data[2] << 16)|(Data[3] << 24); + StartCRC ^= Data[0]|(Data[1] << 8)|(Data[2] << 16)|(Data[3] << 24); uint NextData = Data[4]|(Data[5] << 8)|(Data[6] << 16)|(Data[7] << 24); #else - StartCRC ^= *(uint32 *) Data; + StartCRC ^= *(uint32 *) Data; uint NextData = *(uint32 *) (Data +4); #endif - StartCRC = crc_tables[7][(byte) StartCRC ] ^ + StartCRC = crc_tables[7][(byte) StartCRC ] ^ crc_tables[6][(byte)(StartCRC >> 8) ] ^ crc_tables[5][(byte)(StartCRC >> 16)] ^ crc_tables[4][(byte)(StartCRC >> 24)] ^ @@ -76,7 +76,7 @@ uint CRC32(uint StartCRC,const void *Addr,size_t Size) crc_tables[2][(byte)(NextData >>8 ) ] ^ crc_tables[1][(byte)(NextData >> 16)] ^ crc_tables[0][(byte)(NextData >> 24)]; - } + } for (;Size>0;Size--,Data++) // Process left data. StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8); diff --git a/src/thirdparty/unrar/dll.cpp b/src/thirdparty/unrar/dll.cpp index 5617f45b2..a9aa112d8 100644 --- a/src/thirdparty/unrar/dll.cpp +++ b/src/thirdparty/unrar/dll.cpp @@ -74,7 +74,7 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r) delete Data; return NULL; } - if (!Data->Arc.IsArchive(false)) + if (!Data->Arc.IsArchive(true)) { if (Data->Cmd.DllError!=0) r->OpenResult=Data->Cmd.DllError; @@ -271,7 +271,16 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D) D->HashType=RAR_HASH_NONE; break; } - + + D->RedirType=hd->RedirType; + // RedirNameSize sanity check is useful in case some developer + // did not initialize Reserved area with 0 as required in docs. + // We have taken 'Redir*' fields from Reserved area. We may remove + // this RedirNameSize check sometimes later. + if (hd->RedirType!=FSREDIR_NONE && D->RedirName!=NULL && + D->RedirNameSize>0 && D->RedirNameSize<100000) + wcsncpyz(D->RedirName,hd->RedirName,D->RedirNameSize); + D->DirTarget=hd->DirTarget; } catch (RAR_EXIT ErrCode) { diff --git a/src/thirdparty/unrar/dll.hpp b/src/thirdparty/unrar/dll.hpp index 9fd560939..8dc975eb9 100644 --- a/src/thirdparty/unrar/dll.hpp +++ b/src/thirdparty/unrar/dll.hpp @@ -31,7 +31,7 @@ #define RAR_VOL_ASK 0 #define RAR_VOL_NOTIFY 1 -#define RAR_DLL_VERSION 6 +#define RAR_DLL_VERSION 7 #define RAR_HASH_NONE 0 #define RAR_HASH_CRC32 1 @@ -98,7 +98,11 @@ struct RARHeaderDataEx unsigned int DictSize; unsigned int HashType; char Hash[32]; - unsigned int Reserved[1014]; + unsigned int RedirType; + wchar_t *RedirName; + unsigned int RedirNameSize; + unsigned int DirTarget; + unsigned int Reserved[994]; }; diff --git a/src/thirdparty/unrar/dll.rc b/src/thirdparty/unrar/dll.rc index fa7ab25cb..011b4c174 100644 --- a/src/thirdparty/unrar/dll.rc +++ b/src/thirdparty/unrar/dll.rc @@ -2,8 +2,8 @@ #include <commctrl.h>
VS_VERSION_INFO VERSIONINFO
-FILEVERSION 5, 21, 100, 1510
-PRODUCTVERSION 5, 21, 100, 1510
+FILEVERSION 5, 40, 100, 2057
+PRODUCTVERSION 5, 40, 100, 2057
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
{
@@ -14,15 +14,15 @@ FILETYPE VFT_APP VALUE "CompanyName", "Alexander Roshal\0"
VALUE "ProductName", "RAR decompression library\0"
VALUE "FileDescription", "RAR decompression library\0"
- VALUE "FileVersion", "5.21.0\0"
- VALUE "ProductVersion", "5.21.0\0"
- VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2015\0"
+ VALUE "FileVersion", "5.40.0\0"
+ VALUE "ProductVersion", "5.40.0\0"
+ VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2016\0"
VALUE "OriginalFilename", "Unrar.dll\0"
}
}
BLOCK "VarFileInfo"
{
- VALUE "Translation", 0, 0
+ VALUE "Translation", 0x0409, 0x04E4
}
}
diff --git a/src/thirdparty/unrar/errhnd.cpp b/src/thirdparty/unrar/errhnd.cpp index 6486e400d..2f39556fe 100644 --- a/src/thirdparty/unrar/errhnd.cpp +++ b/src/thirdparty/unrar/errhnd.cpp @@ -12,9 +12,9 @@ void ErrorHandler::Clean() ErrCount=0; EnableBreak=true; Silent=false; - DoShutdown=false; UserBreak=false; MainExit=false; + DisableShutdown=false; } @@ -64,7 +64,10 @@ bool ErrorHandler::AskRepeatRead(const wchar *FileName) if (!Silent) { SysErrMsg(); - return uiAskRepeatRead(FileName); + bool Repeat=uiAskRepeatRead(FileName); + if (!Repeat) // Disable shutdown if user pressed Cancel in error dialog. + DisableShutdown=true; + return Repeat; } #endif return false; @@ -99,8 +102,15 @@ bool ErrorHandler::AskRepeatWrite(const wchar *FileName,bool DiskFull) #ifndef SILENT if (!Silent) { +#ifndef _ANDROID + // We do not display "repeat write" prompt in Android, so we do not + // need the matching system error message. SysErrMsg(); - return uiAskRepeatWrite(FileName,DiskFull); +#endif + bool Repeat=uiAskRepeatWrite(FileName,DiskFull); + if (!Repeat) // Disable shutdown if user pressed Cancel in error dialog. + DisableShutdown=true; + return Repeat; } #endif return false; diff --git a/src/thirdparty/unrar/errhnd.hpp b/src/thirdparty/unrar/errhnd.hpp index 1f5878d39..26df96d5b 100644 --- a/src/thirdparty/unrar/errhnd.hpp +++ b/src/thirdparty/unrar/errhnd.hpp @@ -25,7 +25,7 @@ class ErrorHandler uint ErrCount; bool EnableBreak; bool Silent; - bool DoShutdown; + bool DisableShutdown; // Shutdown is not suitable after last error. public: ErrorHandler(); void Clean(); @@ -57,11 +57,12 @@ class ErrorHandler void SetSignalHandlers(bool Enable); void Throw(RAR_EXIT Code); void SetSilent(bool Mode) {Silent=Mode;}; - void SetShutdown(bool Mode) {DoShutdown=Mode;}; void SysErrMsg(); int GetSystemErrorCode(); void SetSystemErrorCode(int Code); - bool UserBreak; + bool IsShutdownEnabled() {return !DisableShutdown;} + + bool UserBreak; // Ctrl+Break is pressed. bool MainExit; // main() is completed. }; diff --git a/src/thirdparty/unrar/extinfo.cpp b/src/thirdparty/unrar/extinfo.cpp index 01827eba0..15130ad81 100644 --- a/src/thirdparty/unrar/extinfo.cpp +++ b/src/thirdparty/unrar/extinfo.cpp @@ -20,6 +20,8 @@ #ifndef SFX_MODULE void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name) { + if (Cmd->Test) + return; switch(Arc.SubBlockHead.SubType) { #ifdef _UNIX @@ -45,15 +47,15 @@ void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name) void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name) { #ifdef _UNIX - if (Cmd->ProcessOwners && Arc.Format==RARFMT15 && + if (!Cmd->Test && Cmd->ProcessOwners && Arc.Format==RARFMT15 && Arc.SubHead.CmpName(SUBHEAD_TYPE_UOWNER)) ExtractUnixOwner30(Arc,Name); #endif #ifdef _WIN_ALL - if (Cmd->ProcessOwners && Arc.SubHead.CmpName(SUBHEAD_TYPE_ACL)) + if (!Cmd->Test && Cmd->ProcessOwners && Arc.SubHead.CmpName(SUBHEAD_TYPE_ACL)) ExtractACL(Arc,Name); if (Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM)) - ExtractStreams(Arc,Name); + ExtractStreams(Arc,Name,Cmd->Test); #endif } diff --git a/src/thirdparty/unrar/extract.cpp b/src/thirdparty/unrar/extract.cpp index a24eb9405..6a95067df 100644 --- a/src/thirdparty/unrar/extract.cpp +++ b/src/thirdparty/unrar/extract.cpp @@ -89,7 +89,7 @@ void CmdExtract::ExtractArchiveInit(Archive &Arc) DataIO.UnpVolume=false;
- PrevExtracted=false;
+ PrevProcessed=false;
AllMatchesExact=true;
ReconstructDone=false;
AnySolidDataUnpackedWell=false;
@@ -106,10 +106,31 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive() if (!Arc.IsArchive(true))
{
+#if !defined(SFX_MODULE) && !defined(RARDLL)
+ if (CmpExt(ArcName,L"rev"))
+ {
+ wchar FirstVolName[NM];
+ VolNameToFirstName(ArcName,FirstVolName,ASIZE(FirstVolName),true);
+
+ // If several volume names from same volume set are specified
+ // and current volume is not first in set and first volume is present
+ // and specified too, let's skip the current volume.
+ if (wcsicomp(ArcName,FirstVolName)!=0 && FileExist(FirstVolName) &&
+ Cmd->ArcNames.Search(FirstVolName,false))
+ return EXTRACT_ARC_NEXT;
+ RecVolumesTest(Cmd,NULL,ArcName);
+ TotalFileCount++; // Suppress "No files to extract" message.
+ return EXTRACT_ARC_NEXT;
+ }
+#endif
+
#ifndef GUI
mprintf(St(MNotRAR),ArcName);
#endif
+
+#ifndef SFX_MODULE
if (CmpExt(ArcName,L"rar"))
+#endif
ErrHandler.SetErrorCode(RARX_WARNING);
return EXTRACT_ARC_NEXT;
}
@@ -200,12 +221,29 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive() }
+#if !defined(SFX_MODULE) && !defined(RARDLL)
+ if (Cmd->Test && Arc.Volume)
+ RecVolumesTest(Cmd,&Arc,ArcName);
+#endif
+
return EXTRACT_ARC_NEXT;
}
bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
{
+ // We can get negative sizes in corrupt archive and it is unacceptable
+ // for size comparisons in CmdExtract::UnstoreFile and ComprDataIO::UnpRead,
+ // where we cast sizes to size_t and can exceed another read or available
+ // size. We could fix it when reading an archive. But we prefer to do it
+ // here, because this function is called directly in unrar.dll, so we fix
+ // bad parameters passed to dll. Also we want to see real negative sizes
+ // in the listing of corrupt archive.
+ if (Arc.FileHead.PackSize<0)
+ Arc.FileHead.PackSize=0;
+ if (Arc.FileHead.UnpSize<0)
+ Arc.FileHead.UnpSize=0;
+
wchar Command=Cmd->Command[0];
if (HeaderSize==0)
if (DataIO.UnpVolume)
@@ -228,10 +266,10 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) if (HeaderType!=HEAD_FILE)
{
#ifndef SFX_MODULE
- if (HeaderType==HEAD3_OLDSERVICE && PrevExtracted)
+ if (HeaderType==HEAD3_OLDSERVICE && PrevProcessed)
SetExtraInfo20(Cmd,Arc,DestFileName);
#endif
- if (HeaderType==HEAD_SERVICE && PrevExtracted)
+ if (HeaderType==HEAD_SERVICE && PrevProcessed)
SetExtraInfo(Cmd,Arc,DestFileName);
if (HeaderType==HEAD_ENDARC)
if (Arc.EndArcHead.NextVolume)
@@ -251,7 +289,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) Arc.SeekToNext();
return true;
}
- PrevExtracted=false;
+ PrevProcessed=false;
if (!Cmd->Recurse && MatchedArgs>=Cmd->FileArgs.ItemsCount() && AllMatchesExact)
return false;
@@ -307,6 +345,10 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) wchar ArcFileName[NM];
ConvertPath(Arc.FileHead.FileName,ArcFileName);
+#ifdef _WIN_ALL
+ if (!Cmd->AllowIncompatNames)
+ MakeNameCompatible(ArcFileName);
+#endif
if (Arc.FileHead.Version)
{
@@ -422,11 +464,43 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) if (!CheckUnpVer(Arc,ArcFileName))
{
- ExtrFile=false;
ErrHandler.SetErrorCode(RARX_FATAL);
#ifdef RARDLL
Cmd->DllError=ERAR_UNKNOWN_FORMAT;
#endif
+ Arc.SeekToNext();
+ return !Arc.Solid; // Can try extracting next file only in non-solid archive.
+ }
+
+
+ // Set a password before creating the file, so we can skip creating
+ // in case of wrong password.
+ SecPassword FilePassword=Cmd->Password;
+#if defined(_WIN_ALL) && !defined(SFX_MODULE)
+ ConvertDosPassword(Arc,FilePassword);
+#endif
+
+ byte PswCheck[SIZE_PSWCHECK];
+ DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword,
+ Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL,
+ Arc.FileHead.InitV,Arc.FileHead.Lg2Count,
+ Arc.FileHead.HashKey,PswCheck);
+
+ // If header is damaged, we cannot rely on password check value,
+ // because it can be damaged too.
+ if (Arc.FileHead.Encrypted && Arc.FileHead.UsePswCheck &&
+ memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 &&
+ !Arc.BrokenHeader)
+ {
+ uiMsg(UIERROR_BADPSW,Arc.FileName);
+ ErrHandler.SetErrorCode(RARX_BADPWD);
+ ExtrFile=false;
+#ifdef RARDLL
+ // If we already have ERAR_EOPEN as result of missing volume,
+ // we should not replace it with less precise ERAR_BAD_DATA.
+ if (Cmd->DllError!=ERAR_EOPEN)
+ Cmd->DllError=ERAR_BAD_PASSWORD;
+#endif
}
File CurFile;
@@ -472,6 +546,11 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) }
if (ExtrFile)
{
+ // Set it in test mode, so we also test subheaders such as NTFS streams
+ // after tested file.
+ if (Cmd->Test)
+ PrevProcessed=true;
+
bool TestMode=Cmd->Test || SkipSolid; // Unpack to memory, not to disk.
if (!SkipSolid)
@@ -508,28 +587,6 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) mprintf(L" ");
#endif
- SecPassword FilePassword=Cmd->Password;
-#if defined(_WIN_ALL) && !defined(SFX_MODULE)
- ConvertDosPassword(Arc,FilePassword);
-#endif
-
- byte PswCheck[SIZE_PSWCHECK];
- DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword,
- Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL,
- Arc.FileHead.InitV,Arc.FileHead.Lg2Count,
- PswCheck,Arc.FileHead.HashKey);
- bool WrongPassword=false;
-
- // If header is damaged, we cannot rely on password check value,
- // because it can be damaged too.
- if (Arc.FileHead.Encrypted && Arc.FileHead.UsePswCheck &&
- memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 &&
- !Arc.BrokenHeader)
- {
- uiMsg(UIERROR_BADPSW,Arc.FileName);
- ErrHandler.SetErrorCode(RARX_BADPWD);
- WrongPassword=true;
- }
DataIO.CurUnpRead=0;
DataIO.CurUnpWrite=0;
DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads);
@@ -540,7 +597,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) DataIO.SetSkipUnpCRC(SkipSolid);
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
- if (!TestMode && !WrongPassword && !Arc.BrokenHeader &&
+ if (!TestMode && !Arc.BrokenHeader &&
Arc.FileHead.UnpSize>0xffffffff && (Fat32 || !NotFat32))
{
if (!Fat32) // Not detected yet.
@@ -550,7 +607,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) }
#endif
- if (!TestMode && !WrongPassword && !Arc.BrokenHeader &&
+ if (!TestMode && !Arc.BrokenHeader &&
(Arc.FileHead.PackSize<<11)>Arc.FileHead.UnpSize &&
(Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize))
CurFile.Prealloc(Arc.FileHead.UnpSize);
@@ -596,10 +653,10 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) // but not when testing an archive.
ShowChecksum=false;
}
- PrevExtracted=FileCreateMode && LinkSuccess;
+ PrevProcessed=FileCreateMode && LinkSuccess;
}
else
- if (!Arc.FileHead.SplitBefore && !WrongPassword)
+ if (!Arc.FileHead.SplitBefore)
if (Arc.FileHead.Method==0)
UnstoreFile(DataIO,Arc.FileHead.UnpSize);
else
@@ -646,7 +703,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) // Checksum is not calculated in skip solid mode for performance reason.
if (!SkipSolid && ShowChecksum)
{
- if (!WrongPassword && ValidCRC)
+ if (ValidCRC)
{
#ifndef GUI
if (Command!='P' && Command!='I')
@@ -656,19 +713,19 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) }
else
{
- if (!WrongPassword)
- if (Arc.FileHead.Encrypted && (!Arc.FileHead.UsePswCheck ||
- Arc.BrokenHeader) && !AnySolidDataUnpackedWell)
- uiMsg(UIERROR_CHECKSUMENC,Arc.FileName,ArcFileName);
- else
- uiMsg(UIERROR_CHECKSUM,Arc.FileName,ArcFileName);
+ if (Arc.FileHead.Encrypted && (!Arc.FileHead.UsePswCheck ||
+ Arc.BrokenHeader) && !AnySolidDataUnpackedWell)
+ uiMsg(UIERROR_CHECKSUMENC,Arc.FileName,ArcFileName);
+ else
+ uiMsg(UIERROR_CHECKSUM,Arc.FileName,ArcFileName);
BrokenFile=true;
ErrHandler.SetErrorCode(RARX_CRC);
#ifdef RARDLL
- // If we already have ERAR_EOPEN as result of missing volume,
+ // If we already have ERAR_EOPEN as result of missing volume
+ // or ERAR_BAD_PASSWORD for RAR5 wrong password,
// we should not replace it with less precise ERAR_BAD_DATA.
- if (Cmd->DllError!=ERAR_EOPEN)
- Cmd->DllError=WrongPassword ? ERAR_BAD_PASSWORD : ERAR_BAD_DATA;
+ if (Cmd->DllError!=ERAR_EOPEN && Cmd->DllError!=ERAR_BAD_PASSWORD)
+ Cmd->DllError=ERAR_BAD_DATA;
#endif
}
}
@@ -677,7 +734,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) mprintf(L"\b\b\b\b\b ");
#endif
- if (!TestMode && !WrongPassword && (Command=='X' || Command=='E') &&
+ if (!TestMode && (Command=='X' || Command=='E') &&
(!LinkEntry || Arc.FileHead.RedirType==FSREDIR_FILECOPY && LinkSuccess) &&
(!BrokenFile || Cmd->KeepBroken))
{
@@ -712,7 +769,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) if (!Cmd->IgnoreGeneralAttr && !SetFileAttr(CurFile.FileName,Arc.FileHead.FileAttr))
uiMsg(UIERROR_FILEATTR,Arc.FileName,CurFile.FileName);
- PrevExtracted=true;
+ PrevProcessed=true;
}
}
}
@@ -785,12 +842,17 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De {
wcsncpyz(DestName,Cmd->ExtrPath,DestSize);
- // We need IsPathDiv check here to correctly handle Unix forward slash
- // in the end of destination path in Windows: rar x arc dest/
- if (*Cmd->ExtrPath!=0 && !IsPathDiv(*PointToLastChar(Cmd->ExtrPath)))
+ if (*Cmd->ExtrPath!=0)
{
- // Destination path can be without trailing slash if it come from GUI shell.
- AddEndSlash(DestName,DestSize);
+ wchar LastChar=*PointToLastChar(Cmd->ExtrPath);
+ // We need IsPathDiv check here to correctly handle Unix forward slash
+ // in the end of destination path in Windows: rar x arc dest/
+ // IsDriveDiv is needed for current drive dir: rar x arc d:
+ if (!IsPathDiv(LastChar) && !IsDriveDiv(LastChar))
+ {
+ // Destination path can be without trailing slash if it come from GUI shell.
+ AddEndSlash(DestName,DestSize);
+ }
}
#ifndef SFX_MODULE
@@ -990,14 +1052,14 @@ void CmdExtract::ExtrCreateDir(Archive &Arc,const wchar *ArcFileName) mprintf(St(MCreatDir),DestFileName);
mprintf(L" %s",St(MOk));
#endif
- PrevExtracted=true;
+ PrevProcessed=true;
}
else
if (DirExist)
{
if (!Cmd->IgnoreGeneralAttr)
SetFileAttr(DestFileName,Arc.FileHead.FileAttr);
- PrevExtracted=true;
+ PrevProcessed=true;
}
else
{
@@ -1008,7 +1070,7 @@ void CmdExtract::ExtrCreateDir(Archive &Arc,const wchar *ArcFileName) #endif
ErrHandler.SetErrorCode(RARX_CREATE);
}
- if (PrevExtracted)
+ if (PrevProcessed)
{
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
if (Cmd->SetCompressedAttr &&
diff --git a/src/thirdparty/unrar/extract.hpp b/src/thirdparty/unrar/extract.hpp index 4ea317b61..85a21f532 100644 --- a/src/thirdparty/unrar/extract.hpp +++ b/src/thirdparty/unrar/extract.hpp @@ -44,7 +44,7 @@ class CmdExtract wchar ArcName[NM]; bool PasswordAll; - bool PrevExtracted; + bool PrevProcessed; // If previous file was successfully extracted or tested. wchar DestFileName[NM]; bool PasswordCancelled; #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT) diff --git a/src/thirdparty/unrar/filcreat.cpp b/src/thirdparty/unrar/filcreat.cpp index 6717eee90..d2bf0ac69 100644 --- a/src/thirdparty/unrar/filcreat.cpp +++ b/src/thirdparty/unrar/filcreat.cpp @@ -42,9 +42,13 @@ bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize, if (Choice==UIASKREP_R_CANCEL) ErrHandler.Exit(RARX_USERBREAK); } + + // Try to truncate the existing file first instead of delete, + // so we preserve existing file permissions such as NTFS permissions. uint FileMode=WriteOnly ? FMF_WRITE|FMF_SHAREREAD:FMF_UPDATE|FMF_SHAREREAD; if (NewFile!=NULL && NewFile->Create(Name,FileMode)) return true; + CreatePath(Name,true); return NewFile!=NULL ? NewFile->Create(Name,FileMode):DelFile(Name); } @@ -63,13 +67,13 @@ bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize) Ext=Name+NameLength; for (uint FileVer=1;;FileVer++) { -#ifdef _ANDROID // No swprintf in Android NDK r9. +#ifdef _ANDROID // No swprintf in Android prior to Android 5.0. uint NamePrefixLength=Ext-Name; wcsncpy(NewName,Name,NamePrefixLength); wcscpy(NewName+NamePrefixLength,L"("); - itoa(FileVer,NewName+NamePrefixLength+1); - wcscat(NewName,L")"); - wcscat(NewName,Ext); + itoa(FileVer,NewName+NamePrefixLength+1,ASIZE(NewName)-NamePrefixLength-1); + wcsncatz(NewName,L")",ASIZE(NewName)); + wcsncatz(NewName,Ext,ASIZE(NewName)); #else swprintf(NewName,ASIZE(NewName),L"%.*ls(%u)%ls",uint(Ext-Name),Name,FileVer,Ext); #endif diff --git a/src/thirdparty/unrar/file.cpp b/src/thirdparty/unrar/file.cpp index 185474c25..7fbfb6e67 100644 --- a/src/thirdparty/unrar/file.cpp +++ b/src/thirdparty/unrar/file.cpp @@ -121,6 +121,12 @@ bool File::Open(const wchar *Name,uint Mode) hNewFile=fdopen(handle,UpdateMode ? UPDATEBINARY:READBINARY); #endif } +#ifdef _ANDROID + // If we open an existing file in r&w mode and external card is read-only + // for usual file API. + if (hNewFile==FILE_BAD_HANDLE && UpdateMode && errno!=ENOENT) + hNewFile=JniOpenFile(Name); +#endif if (hNewFile==FILE_BAD_HANDLE && errno==ENOENT) ErrorType=FILE_NOTFOUND; #endif @@ -193,6 +199,8 @@ bool File::Create(const wchar *Name,uint Mode) #ifdef _ANDROID if (hFile==FILE_BAD_HANDLE) hFile=JniCreateFile(Name); // If external card is read-only for usual file API. + if (hFile!=FILE_BAD_HANDLE) + JniFileNotify(Name,false); #endif #else hFile=fopen(NameA,WriteMode ? WRITEBINARY:CREATEBINARY); @@ -541,7 +549,7 @@ void File::Prealloc(int64 Size) #if defined(_UNIX) && defined(USE_FALLOCATE) // fallocate is rather new call. Only latest kernels support it. // So we are not using it by default yet. - int fd = GetFD(hFile); + int fd = GetFD(); if (fd >= 0) fallocate(fd, 0, 0, Size); #endif @@ -567,7 +575,20 @@ bool File::Truncate() #ifdef _WIN_ALL return SetEndOfFile(hFile)==TRUE; #else - return false; + return ftruncate(GetFD(),(off_t)Tell())==0; +#endif +} + + +void File::Flush() +{ +#ifdef _WIN_ALL + FlushFileBuffers(hFile); +#else +#ifndef FILE_USE_OPEN + fflush(hFile); +#endif + fsync(GetFD()); #endif } diff --git a/src/thirdparty/unrar/file.hpp b/src/thirdparty/unrar/file.hpp index 0d6534ff7..139a40c6e 100644 --- a/src/thirdparty/unrar/file.hpp +++ b/src/thirdparty/unrar/file.hpp @@ -90,6 +90,7 @@ class File byte GetByte(); void PutByte(byte Byte); bool Truncate(); + void Flush(); void SetOpenFileTime(RarTime *ftm,RarTime *ftc=NULL,RarTime *fta=NULL); void SetCloseFileTime(RarTime *ftm,RarTime *fta=NULL); static void SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta); diff --git a/src/thirdparty/unrar/filefn.cpp b/src/thirdparty/unrar/filefn.cpp index 6526f4337..0c2b03dd7 100644 --- a/src/thirdparty/unrar/filefn.cpp +++ b/src/thirdparty/unrar/filefn.cpp @@ -32,6 +32,8 @@ MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr) #ifdef _ANDROID if (ErrCode==-1 && errno!=ENOENT) ErrCode=JniMkdir(Name) ? 0 : -1; // If external card is read-only for usual file API. + if (ErrCode!=-1) + JniFileNotify(Name,false); #endif if (ErrCode==-1) return errno==ENOENT ? MKDIR_BADPATH:MKDIR_ERROR; @@ -333,11 +335,11 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size, { SaveFilePos SavePos(*SrcFile); #ifndef SILENT - int64 FileLength=SrcFile->FileLength(); + int64 FileLength=Size==INT64NDF ? SrcFile->FileLength() : Size; #endif #ifndef GUI - if ((Flags & (CALCFSUM_SHOWTEXT|CALCFSUM_SHOWALL))!=0) + if ((Flags & (CALCFSUM_SHOWTEXT|CALCFSUM_SHOWPERCENT))!=0) #endif uiMsg(UIEVENT_FILESUMSTART); @@ -353,6 +355,7 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size, HashBlake2.Init(HASH_BLAKE2,Threads); int64 BlockCount=0; + int64 TotalRead=0; while (true) { size_t SizeToRead; @@ -363,14 +366,20 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size, int ReadSize=SrcFile->Read(&Data[0],SizeToRead); if (ReadSize==0) break; + TotalRead+=ReadSize; if ((++BlockCount & 0xf)==0) { #ifndef SILENT + if ((Flags & CALCFSUM_SHOWPROGRESS)!=0) + uiExtractProgress(TotalRead,FileLength,TotalRead,FileLength); + else + { #ifndef GUI - if ((Flags & CALCFSUM_SHOWALL)!=0) + if ((Flags & CALCFSUM_SHOWPERCENT)!=0) #endif - uiMsg(UIEVENT_FILESUMPROGRESS,ToPercent(BlockCount*int64(BufSize),FileLength)); + uiMsg(UIEVENT_FILESUMPROGRESS,ToPercent(TotalRead,FileLength)); + } #endif Wait(); } @@ -384,7 +393,7 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size, Size-=ReadSize; } #ifndef GUI - if ((Flags & CALCFSUM_SHOWALL)!=0) + if ((Flags & CALCFSUM_SHOWPERCENT)!=0) #endif uiMsg(UIEVENT_FILESUMEND); @@ -420,6 +429,11 @@ bool RenameFile(const wchar *SrcName,const wchar *DestName) #ifdef _ANDROID if (!Success) Success=JniRename(SrcName,DestName); // If external card is read-only for usual file API. + if (Success) + { + JniFileNotify(SrcName,true); + JniFileNotify(DestName,false); + } #endif return Success; #endif @@ -444,6 +458,8 @@ bool DelFile(const wchar *Name) #ifdef _ANDROID if (!Success) Success=JniDelete(Name); + if (Success) + JniFileNotify(Name,true); #endif return Success; #endif diff --git a/src/thirdparty/unrar/filefn.hpp b/src/thirdparty/unrar/filefn.hpp index b06cc64e1..3a0c7a798 100644 --- a/src/thirdparty/unrar/filefn.hpp +++ b/src/thirdparty/unrar/filefn.hpp @@ -28,7 +28,7 @@ void PrepareToDelete(const wchar *Name); uint GetFileAttr(const wchar *Name); bool SetFileAttr(const wchar *Name,uint Attr); -enum CALCFSUM_FLAGS {CALCFSUM_SHOWTEXT=1,CALCFSUM_SHOWALL=2,CALCFSUM_CURPOS=4}; +enum CALCFSUM_FLAGS {CALCFSUM_SHOWTEXT=1,CALCFSUM_SHOWPERCENT=2,CALCFSUM_SHOWPROGRESS=4,CALCFSUM_CURPOS=8}; void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size=INT64NDF,uint Flags=0); diff --git a/src/thirdparty/unrar/filestr.cpp b/src/thirdparty/unrar/filestr.cpp index 5fa946a4d..d8ac36da5 100644 --- a/src/thirdparty/unrar/filestr.cpp +++ b/src/thirdparty/unrar/filestr.cpp @@ -1,7 +1,5 @@ #include "rar.hpp" -static bool IsUnicode(byte *Data,int Size); - bool ReadTextFile( const wchar *Name, StringList *List, @@ -36,7 +34,7 @@ bool ReadTextFile( else SrcFile.SetHandleType(FILE_HANDLESTD); - unsigned int DataSize=0,ReadSize; + uint DataSize=0,ReadSize; const int ReadBlock=4096; // Our algorithm below needs at least two trailing zeroes after data. @@ -44,7 +42,7 @@ bool ReadTextFile( // in case read Unicode data contains uneven number of bytes. const size_t ZeroPadding=5; - Array<char> Data(ReadBlock+ZeroPadding); + Array<byte> Data(ReadBlock+ZeroPadding); while ((ReadSize=SrcFile.Read(&Data[DataSize],ReadBlock))!=0) { DataSize+=ReadSize; @@ -55,17 +53,30 @@ bool ReadTextFile( Array<wchar> WideStr; - if (SrcCharset==RCH_UNICODE || - SrcCharset==RCH_DEFAULT && IsUnicode((byte *)&Data[0],DataSize)) + int LowEndian=Data[0]==255 && Data[1]==254 ? 1:0; + int BigEndian=Data[0]==254 && Data[1]==255 ? 1:0; + + bool IsUnicode=false; + if (LowEndian || BigEndian) + for (size_t I=2;I<DataSize;I++) + if (Data[I]<32 && Data[I]!='\r' && Data[I]!='\n') + { + IsUnicode=true; // High byte in UTF-16 char is found. + break; + } + + if (SrcCharset==RCH_UNICODE || SrcCharset==RCH_DEFAULT && IsUnicode) { - // Unicode in native system format, can be more than 2 bytes per character. - Array<wchar> DataW(Data.Size()/2+1); - for (size_t I=2;I<Data.Size()-1;I+=2) + size_t Start=2; // Skip byte order mark. + if (!LowEndian && !BigEndian) // No byte order mask. { - // Need to convert Data to (byte) first to prevent the sign extension - // to higher bytes. - DataW[(I-2)/2]=(wchar)((byte)Data[I])+(wchar)((byte)Data[I+1])*256; + Start=0; + LowEndian=1; } + + Array<wchar> DataW(Data.Size()/2+1); + for (size_t I=Start;I<Data.Size()-1;I+=2) + DataW[(I-Start)/2]=Data[I+BigEndian]+Data[I+LowEndian]*256; wchar *CurStr=&DataW[0]; @@ -122,7 +133,7 @@ bool ReadTextFile( } else { - char *CurStr=&Data[0]; + char *CurStr=(char *)&Data[0]; while (*CurStr!=0) { char *NextStr=CurStr,*CmtPtr=NULL; @@ -183,14 +194,3 @@ bool ReadTextFile( } return true; } - - -bool IsUnicode(byte *Data,int Size) -{ - if (Size<4 || Data[0]!=0xff || Data[1]!=0xfe) - return false; - for (int I=2;I<Size;I++) - if (Data[I]<32 && Data[I]!='\r' && Data[I]!='\n') - return true; - return false; -} diff --git a/src/thirdparty/unrar/getbits.cpp b/src/thirdparty/unrar/getbits.cpp index e57b3e32f..e4db2695f 100644 --- a/src/thirdparty/unrar/getbits.cpp +++ b/src/thirdparty/unrar/getbits.cpp @@ -38,7 +38,7 @@ void BitInput::faddbits(uint Bits) uint BitInput::fgetbits() { // Function wrapped version of inline getbits to save code size. - return(getbits()); + return getbits(); } diff --git a/src/thirdparty/unrar/getbits.hpp b/src/thirdparty/unrar/getbits.hpp index 6a5430b0b..2e151da9a 100644 --- a/src/thirdparty/unrar/getbits.hpp +++ b/src/thirdparty/unrar/getbits.hpp @@ -37,7 +37,7 @@ class BitInput BitField|=(uint)InBuf[InAddr+1] << 8; BitField|=(uint)InBuf[InAddr+2]; BitField >>= (8-InBit); - return(BitField & 0xffff); + return BitField & 0xffff; } // Return 32 bits from current position in the buffer. @@ -50,7 +50,7 @@ class BitInput BitField|=(uint)InBuf[InAddr+3]; BitField <<= InBit; BitField|=(uint)InBuf[InAddr+4] >> (8-InBit); - return(BitField & 0xffffffff); + return BitField & 0xffffffff; } void faddbits(uint Bits); @@ -60,7 +60,7 @@ class BitInput // if buffer will be overflown. bool Overflow(uint IncPtr) { - return(InAddr+IncPtr>=MAX_SIZE); + return InAddr+IncPtr>=MAX_SIZE; } void SetExternalBuffer(byte *Buf); diff --git a/src/thirdparty/unrar/hash.cpp b/src/thirdparty/unrar/hash.cpp index 578e32fa0..42791f4f4 100644 --- a/src/thirdparty/unrar/hash.cpp +++ b/src/thirdparty/unrar/hash.cpp @@ -41,6 +41,7 @@ bool HashValue::operator == (const HashValue &cmp) DataHash::DataHash() { + blake2ctx=NULL; HashType=HASH_NONE; #ifdef RAR_SMP ThPool=NULL; @@ -54,20 +55,26 @@ DataHash::~DataHash() #ifdef RAR_SMP DestroyThreadPool(ThPool); #endif - cleandata(&blake2ctx, sizeof(blake2ctx)); cleandata(&CurCRC32, sizeof(CurCRC32)); + if (blake2ctx!=NULL) + { + cleandata(blake2ctx, sizeof(blake2sp_state)); + delete blake2ctx; + } } void DataHash::Init(HASH_TYPE Type,uint MaxThreads) { + if (blake2ctx==NULL) + blake2ctx=new blake2sp_state; HashType=Type; if (Type==HASH_RAR14) CurCRC32=0; if (Type==HASH_CRC32) CurCRC32=0xffffffff; // Initial CRC32 value. if (Type==HASH_BLAKE2) - blake2sp_init( &blake2ctx ); + blake2sp_init(blake2ctx); #ifdef RAR_SMP DataHash::MaxThreads=Min(MaxThreads,MaxHashThreads); #endif @@ -88,10 +95,10 @@ void DataHash::Update(const void *Data,size_t DataSize) #ifdef RAR_SMP if (MaxThreads>1 && ThPool==NULL) ThPool=CreateThreadPool(); - blake2ctx.ThPool=ThPool; - blake2ctx.MaxThreads=MaxThreads; + blake2ctx->ThPool=ThPool; + blake2ctx->MaxThreads=MaxThreads; #endif - blake2sp_update( &blake2ctx, (byte *)Data, DataSize); + blake2sp_update( blake2ctx, (byte *)Data, DataSize); } } @@ -106,8 +113,8 @@ void DataHash::Result(HashValue *Result) if (HashType==HASH_BLAKE2) { // Preserve the original context, so we can continue hashing if necessary. - blake2sp_state res=blake2ctx; - blake2sp_final( &res, Result->Digest ); + blake2sp_state res=*blake2ctx; + blake2sp_final(&res,Result->Digest); } } diff --git a/src/thirdparty/unrar/hash.hpp b/src/thirdparty/unrar/hash.hpp index dae31d1b2..b7d879f66 100644 --- a/src/thirdparty/unrar/hash.hpp +++ b/src/thirdparty/unrar/hash.hpp @@ -29,7 +29,7 @@ class DataHash private: HASH_TYPE HashType; uint CurCRC32; - blake2sp_state blake2ctx; + blake2sp_state *blake2ctx; #ifdef RAR_SMP ThreadPool *ThPool; diff --git a/src/thirdparty/unrar/headers.hpp b/src/thirdparty/unrar/headers.hpp index 7f15a67b6..948647899 100644 --- a/src/thirdparty/unrar/headers.hpp +++ b/src/thirdparty/unrar/headers.hpp @@ -20,9 +20,9 @@ #define SIZEOF_STREAMHEAD 26 #define VER_PACK 29 -#define VER_PACK5 0 +#define VER_PACK5 50 // It is stored as 0, but we subtract 50 when saving an archive. #define VER_UNPACK 29 -#define VER_UNPACK5 0 +#define VER_UNPACK5 50 // It is stored as 0, but we add 50 when reading an archive. #define MHD_VOLUME 0x0001U diff --git a/src/thirdparty/unrar/isnt.cpp b/src/thirdparty/unrar/isnt.cpp index 53c722ab4..6fadec049 100644 --- a/src/thirdparty/unrar/isnt.cpp +++ b/src/thirdparty/unrar/isnt.cpp @@ -19,6 +19,6 @@ DWORD WinNT() Result=dwMajorVersion*0x100+dwMinorVersion; - return(Result); + return Result; } #endif diff --git a/src/thirdparty/unrar/isnt.hpp b/src/thirdparty/unrar/isnt.hpp index 520ac8ad7..877d88012 100644 --- a/src/thirdparty/unrar/isnt.hpp +++ b/src/thirdparty/unrar/isnt.hpp @@ -3,7 +3,8 @@ enum WINNT_VERSION { WNT_NONE=0,WNT_NT351=0x0333,WNT_NT4=0x0400,WNT_W2000=0x0500, - WNT_WXP=0x0501,WNT_W2003=0x0502,WNT_VISTA=0x0600,WNT_W7=0x0601 + WNT_WXP=0x0501,WNT_W2003=0x0502,WNT_VISTA=0x0600,WNT_W7=0x0601, + WNT_W8=0x0602,WNT_W81=0x0603,WNT_W10=0x0a00 }; DWORD WinNT(); diff --git a/src/thirdparty/unrar/list.cpp b/src/thirdparty/unrar/list.cpp index d64e274a6..561122b45 100644 --- a/src/thirdparty/unrar/list.cpp +++ b/src/thirdparty/unrar/list.cpp @@ -77,7 +77,7 @@ void ListArchive(CommandData *Cmd) #ifndef SFX_MODULE // Only RAR 1.5 archives store the volume number in end record. if (Arc.EndArcHead.StoreVolNumber && Arc.Format==RARFMT15) - swprintf(VolNumText,ASIZE(VolNumText),L"%.10ls %d",St(MListVolume),Arc.VolNumber+1); + swprintf(VolNumText,ASIZE(VolNumText),L"%.10ls %u",St(MListVolume),Arc.VolNumber+1); #endif if (Technical && ShowService) { @@ -117,22 +117,22 @@ void ListArchive(CommandData *Cmd) if (TitleShown) { wchar UnpSizeText[20]; - itoa(TotalUnpSize,UnpSizeText); + itoa(TotalUnpSize,UnpSizeText,ASIZE(UnpSizeText)); wchar PackSizeText[20]; - itoa(TotalPackSize,PackSizeText); + itoa(TotalPackSize,PackSizeText,ASIZE(PackSizeText)); if (Verbose) { - mprintf(L"\n----------- --------- -------- ----- -------- ----- -------- ----"); - mprintf(L"\n%21ls %9ls %3d%% %-25ls %u",UnpSizeText, + mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----"); + mprintf(L"\n%21ls %9ls %3d%% %-27ls %u",UnpSizeText, PackSizeText,ToPercentUnlim(TotalPackSize,TotalUnpSize), VolNumText,FileCount); } else { - mprintf(L"\n----------- --------- -------- ----- ----"); - mprintf(L"\n%21ls %-14ls %u",UnpSizeText,VolNumText,FileCount); + mprintf(L"\n----------- --------- ---------- ----- ----"); + mprintf(L"\n%21ls %-16ls %u",UnpSizeText,VolNumText,FileCount); } SumFileCount+=FileCount; @@ -149,9 +149,7 @@ void ListArchive(CommandData *Cmd) if (Cmd->VolSize!=0 && (Arc.FileHead.SplitAfter || Arc.GetHeaderType()==HEAD_ENDARC && Arc.EndArcHead.NextVolume) && MergeArchive(Arc,NULL,false,Cmd->Command[0])) - { Arc.Seek(0,SEEK_SET); - } else #endif break; @@ -172,14 +170,14 @@ void ListArchive(CommandData *Cmd) if (ArcCount>1 && !Bare && !Technical) { wchar UnpSizeText[20],PackSizeText[20]; - itoa(SumUnpSize,UnpSizeText); - itoa(SumPackSize,PackSizeText); + itoa(SumUnpSize,UnpSizeText,ASIZE(UnpSizeText)); + itoa(SumPackSize,PackSizeText,ASIZE(PackSizeText)); if (Verbose) - mprintf(L"%21ls %9ls %3d%% %26ls %u",UnpSizeText,PackSizeText, + mprintf(L"%21ls %9ls %3d%% %28ls %u",UnpSizeText,PackSizeText, ToPercentUnlim(SumPackSize,SumUnpSize),L"",SumFileCount); else - mprintf(L"%21ls %16s %lu",UnpSizeText,L"",SumFileCount); + mprintf(L"%21ls %18s %lu",UnpSizeText,L"",SumFileCount); } } @@ -205,22 +203,22 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo if (Verbose) { mprintf(L"\n%ls",St(MListTitleV)); - mprintf(L"\n----------- --------- -------- ----- -------- ----- -------- ----"); + mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----"); } else { mprintf(L"\n%ls",St(MListTitleL)); - mprintf(L"\n----------- --------- -------- ----- ----"); + mprintf(L"\n----------- --------- ---------- ----- ----"); } TitleShown=true; } - wchar UnpSizeText[20],PackSizeText[20]; + wchar UnpSizeText[30],PackSizeText[30]; if (hd.UnpSize==INT64NDF) wcscpy(UnpSizeText,L"?"); else - itoa(hd.UnpSize,UnpSizeText); - itoa(hd.PackSize,PackSizeText); + itoa(hd.UnpSize,UnpSizeText,ASIZE(UnpSizeText)); + itoa(hd.PackSize,PackSizeText,ASIZE(PackSizeText)); wchar AttrStr[30]; if (hd.HeaderType==HEAD_SERVICE) @@ -242,7 +240,7 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo swprintf(RatioStr,ASIZE(RatioStr),L"%d%%",ToPercentUnlim(hd.PackSize,hd.UnpSize)); wchar DateStr[50]; - hd.mtime.GetText(DateStr,ASIZE(DateStr),Technical,Technical); + hd.mtime.GetText(DateStr,ASIZE(DateStr),Technical); if (Technical) { @@ -309,12 +307,12 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo mprintf(L"\n%12ls: %ls",St(MListMtime),DateStr); if (hd.ctime.IsSet()) { - hd.ctime.GetText(DateStr,ASIZE(DateStr),true,true); + hd.ctime.GetText(DateStr,ASIZE(DateStr),true); mprintf(L"\n%12ls: %ls",St(MListCtime),DateStr); } if (hd.atime.IsSet()) { - hd.atime.GetText(DateStr,ASIZE(DateStr),true,true); + hd.atime.GetText(DateStr,ASIZE(DateStr),true); mprintf(L"\n%12ls: %ls",St(MListAtime),DateStr); } mprintf(L"\n%12ls: %ls",St(MListAttr),AttrStr); @@ -405,7 +403,7 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo else mprintf(L"???????? "); } - mprintf(L"%-12ls",Name); + mprintf(L"%ls",Name); } /* @@ -435,13 +433,13 @@ void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSiz { case HSYS_WINDOWS: swprintf(AttrStr,AttrSize,L"%c%c%c%c%c%c%c", - (A & 0x2000) ? 'I' : '.', // Not content indexed. - (A & 0x0800) ? 'C' : '.', // Compressed. - (A & 0x0020) ? 'A' : '.', // Archive. - (A & 0x0010) ? 'D' : '.', // Directory. - (A & 0x0004) ? 'S' : '.', // System. - (A & 0x0002) ? 'H' : '.', // Hidden. - (A & 0x0001) ? 'R' : '.'); // Read-only. + (A & 0x2000)!=0 ? 'I' : '.', // Not content indexed. + (A & 0x0800)!=0 ? 'C' : '.', // Compressed. + (A & 0x0020)!=0 ? 'A' : '.', // Archive. + (A & 0x0010)!=0 ? 'D' : '.', // Directory. + (A & 0x0004)!=0 ? 'S' : '.', // System. + (A & 0x0002)!=0 ? 'H' : '.', // Hidden. + (A & 0x0001)!=0 ? 'R' : '.'); // Read-only. break; case HSYS_UNIX: switch (A & 0xF000) @@ -459,13 +457,13 @@ void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSiz swprintf(AttrStr+1,AttrSize-1,L"%c%c%c%c%c%c%c%c%c", (A & 0x0100) ? 'r' : '-', (A & 0x0080) ? 'w' : '-', - (A & 0x0040) ? ((A & 0x0800) ? 's':'x'):((A & 0x0800) ? 'S':'-'), + (A & 0x0040) ? ((A & 0x0800)!=0 ? 's':'x'):((A & 0x0800)!=0 ? 'S':'-'), (A & 0x0020) ? 'r' : '-', (A & 0x0010) ? 'w' : '-', - (A & 0x0008) ? ((A & 0x0400) ? 's':'x'):((A & 0x0400) ? 'S':'-'), + (A & 0x0008) ? ((A & 0x0400)!=0 ? 's':'x'):((A & 0x0400)!=0 ? 'S':'-'), (A & 0x0004) ? 'r' : '-', (A & 0x0002) ? 'w' : '-', - (A & 0x0001) ? 'x' : '-'); + (A & 0x0001) ? ((A & 0x200)!=0 ? 't' : 'x') : '-'); break; case HSYS_UNKNOWN: wcscpy(AttrStr,L"?"); diff --git a/src/thirdparty/unrar/loclang.hpp b/src/thirdparty/unrar/loclang.hpp index 52bcafe92..71b8985d1 100644 --- a/src/thirdparty/unrar/loclang.hpp +++ b/src/thirdparty/unrar/loclang.hpp @@ -9,6 +9,8 @@ #define MShare L"\nTrial version Type RAR -? for help\n" #define MUCopyright L"\nUNRAR %s freeware Copyright (c) 1993-%d Alexander Roshal\n" #define MBeta L"beta" +#define Mx86 L"x86" +#define Mx64 L"x64" #define MMonthJan L"Jan" #define MMonthFeb L"Feb" #define MMonthMar L"Mar" @@ -83,6 +85,7 @@ #define MCHelpSwINUL L"\n inul Disable all messages" #define MCHelpSwIOFF L"\n ioff Turn PC off after completing an operation" #define MCHelpSwISND L"\n isnd Enable sound" +#define MCHelpSwIVER L"\n iver Display the version number" #define MCHelpSwK L"\n k Lock archive" #define MCHelpSwKB L"\n kb Keep broken extracted files" #define MCHelpSwLog L"\n log[f][=name] Write names to log file" @@ -100,6 +103,7 @@ #define MCHelpSwOH L"\n oh Save hard links as the link instead of the file" #define MCHelpSwOI L"\n oi[0-4][:min] Save identical files as references" #define MCHelpSwOL L"\n ol[a] Process symbolic links as the link [absolute paths]" +#define MCHelpSwONI L"\n oni Allow potentially incompatible names" #define MCHelpSwOR L"\n or Rename files automatically" #define MCHelpSwOS L"\n os Save NTFS streams" #define MCHelpSwOW L"\n ow Save or restore file owner and group" @@ -237,7 +241,7 @@ #define MDeleting L"\nDeleting %s" #define MEraseArc L"\nErasing empty archive %s" #define MNoDelFiles L"\nNo files to delete" -#define MLogTitle L"\n\n-------- %2d %s %d, archive %s\n" +#define MLogTitle L"-------- %2d %s %d, archive %s" #define MPathTooLong L"\nERROR: Path too long\n" #define MListArchive L"Archive" #define MListDetails L"Details" @@ -248,8 +252,8 @@ #define MListLock L"lock" #define MListEnc L"encrypted" #define MListEncHead L"encrypted headers" -#define MListTitleL L" Attributes Size Date Time Name" -#define MListTitleV L" Attributes Size Packed Ratio Date Time Checksum Name" +#define MListTitleL L" Attributes Size Date Time Name" +#define MListTitleV L" Attributes Size Packed Ratio Date Time Checksum Name" #define MListName L"Name" #define MListType L"Type" #define MListFile L"File" @@ -258,7 +262,7 @@ #define MListWSymlink L"Windows symbolic link" #define MListJunction L"NTFS junction point" #define MListHardlink L"Hard link" -#define MListCopy L"File copy" +#define MListCopy L"File reference" #define MListStream L"NTFS alternate data stream" #define MListTarget L"Target" #define MListSize L"Size" @@ -375,7 +379,7 @@ #define MNumFound L"%d found." #define MUnknownExtra L"\nUnknown extra field in %s." #define MCopyError L"\nCannot copy %s to %s." -#define MCopyErrorHint L"\nYou need to unpack the entire archive to create file copy entries." +#define MCopyErrorHint L"\nYou need to unpack the entire archive to create file reference entries." #define MCopyingData L"\nCopying data" #define MErrCreateLnkS L"\nCannot create symbolic link %s" #define MErrCreateLnkH L"\nCannot create hard link %s" diff --git a/src/thirdparty/unrar/options.hpp b/src/thirdparty/unrar/options.hpp index a6ec227f0..05d9e10cc 100644 --- a/src/thirdparty/unrar/options.hpp +++ b/src/thirdparty/unrar/options.hpp @@ -95,6 +95,7 @@ class RAROptions RAR_CHARSET CommentCharset; RAR_CHARSET FilelistCharset; RAR_CHARSET ErrlogCharset; + RAR_CHARSET RedirectCharset; wchar ArcPath[NM]; SecPassword Password; @@ -113,6 +114,7 @@ class RAROptions bool DisablePercentage; bool DisableCopyright; bool DisableDone; + bool PrintVersion; int Solid; int SolidCount; bool ClearArc; @@ -139,6 +141,10 @@ class RAROptions bool OpenShared; bool DeleteFiles; +#ifdef _WIN_ALL + bool AllowIncompatNames; // Allow names with trailing dots and spaces. +#endif + #ifndef SFX_MODULE bool GenerateArcName; diff --git a/src/thirdparty/unrar/pathfn.cpp b/src/thirdparty/unrar/pathfn.cpp index b6e220eee..1fe6b98dc 100644 --- a/src/thirdparty/unrar/pathfn.cpp +++ b/src/thirdparty/unrar/pathfn.cpp @@ -144,9 +144,16 @@ bool IsDriveDiv(int Ch) } +bool IsDriveLetter(const wchar *Path) +{ + wchar Letter=etoupperw(Path[0]); + return Letter>='A' && Letter<='Z' && IsDriveDiv(Path[1]); +} + + int GetPathDisk(const wchar *Path) { - if (IsDiskLetter(Path)) + if (IsDriveLetter(Path)) return etoupperw(*Path)-'A'; else return -1; @@ -534,7 +541,7 @@ bool IsFullPath(const wchar *Path) return true; */ #if defined(_WIN_ALL) || defined(_EMX) - return Path[0]=='\\' && Path[1]=='\\' || IsDiskLetter(Path) && IsPathDiv(Path[2]); + return Path[0]=='\\' && Path[1]=='\\' || IsDriveLetter(Path) && IsPathDiv(Path[2]); #else return IsPathDiv(Path[0]); #endif @@ -547,17 +554,10 @@ bool IsFullRootPath(const wchar *Path) } -bool IsDiskLetter(const wchar *Path) -{ - wchar Letter=etoupperw(Path[0]); - return Letter>='A' && Letter<='Z' && IsDriveDiv(Path[1]); -} - - void GetPathRoot(const wchar *Path,wchar *Root,size_t MaxSize) { *Root=0; - if (IsDiskLetter(Path)) + if (IsDriveLetter(Path)) swprintf(Root,MaxSize,L"%c:\\",*Path); else if (Path[0]=='\\' && Path[1]=='\\') @@ -733,16 +733,16 @@ static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,b char Field[10][6]; - sprintf(Field[0],"%04d",rlt.Year); - sprintf(Field[1],"%02d",rlt.Month); - sprintf(Field[2],"%02d",rlt.Day); - sprintf(Field[3],"%02d",rlt.Hour); - sprintf(Field[4],"%02d",rlt.Minute); - sprintf(Field[5],"%02d",rlt.Second); - sprintf(Field[6],"%02d",CurWeek); - sprintf(Field[7],"%d",WeekDay+1); - sprintf(Field[8],"%03d",rlt.yDay+1); - sprintf(Field[9],"%05d",ArcNumber); + sprintf(Field[0],"%04u",rlt.Year); + sprintf(Field[1],"%02u",rlt.Month); + sprintf(Field[2],"%02u",rlt.Day); + sprintf(Field[3],"%02u",rlt.Hour); + sprintf(Field[4],"%02u",rlt.Minute); + sprintf(Field[5],"%02u",rlt.Second); + sprintf(Field[6],"%02u",(uint)CurWeek); + sprintf(Field[7],"%u",(uint)WeekDay+1); + sprintf(Field[8],"%03u",rlt.yDay+1); + sprintf(Field[9],"%05u",ArcNumber); const wchar *MaskChars=L"YMDHISWAEN"; @@ -873,7 +873,7 @@ wchar* GetWideName(const char *Name,const wchar *NameW,wchar *DestW,size_t DestS if (DestSize>0) DestW[DestSize-1]=0; - return(DestW); + return DestW; } @@ -887,11 +887,11 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize) return false; const wchar *Prefix=L"\\\\?\\"; const size_t PrefixLength=4; - bool FullPath=IsDiskLetter(Src) && IsPathDiv(Src[2]); + bool FullPath=IsDriveLetter(Src) && IsPathDiv(Src[2]); size_t SrcLength=wcslen(Src); if (IsFullPath(Src)) // Paths in d:\path\name format. { - if (IsDiskLetter(Src)) + if (IsDriveLetter(Src)) { if (MaxSize<=PrefixLength+SrcLength) return false; @@ -945,4 +945,39 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize) } return false; } + + +// Convert Unix, OS X and Android decomposed chracters to Windows precomposed. +void ConvertToPrecomposed(wchar *Name,size_t NameSize) +{ + wchar FileName[NM]; + if (WinNT()>=WNT_VISTA && // MAP_PRECOMPOSED is not supported in XP. + FoldString(MAP_PRECOMPOSED,Name,-1,FileName,ASIZE(FileName))!=0) + { + FileName[ASIZE(FileName)-1]=0; + wcsncpyz(Name,FileName,NameSize); + } +} + + +// Remove trailing spaces and dots in file name and in dir names in path. +void MakeNameCompatible(wchar *Name) +{ + int Src=0,Dest=0; + while (true) + { + if (IsPathDiv(Name[Src]) || Name[Src]==0) + for (int I=Dest-1;I>0 && (Name[I]==' ' || Name[I]=='.');I--) + { + if (IsPathDiv(Name[I-1])) // Permit path1/./path2 paths. + break; + Dest--; + } + Name[Dest]=Name[Src]; + if (Name[Src]==0) + break; + Src++; + Dest++; + } +} #endif diff --git a/src/thirdparty/unrar/pathfn.hpp b/src/thirdparty/unrar/pathfn.hpp index ae1f8c2e8..f08269464 100644 --- a/src/thirdparty/unrar/pathfn.hpp +++ b/src/thirdparty/unrar/pathfn.hpp @@ -12,6 +12,7 @@ bool CmpExt(const wchar *Name,const wchar *Ext); bool IsWildcard(const wchar *Str); bool IsPathDiv(int Ch); bool IsDriveDiv(int Ch); +bool IsDriveLetter(const wchar *Path); int GetPathDisk(const wchar *Path); void AddEndSlash(wchar *Path,size_t MaxLength); void MakeName(const wchar *Path,const wchar *Name,wchar *Pathname,size_t MaxSize); @@ -57,7 +58,6 @@ inline void SlashToNative(const wchar *SrcName,wchar *DestName,size_t MaxLength) void ConvertNameToFull(const wchar *Src,wchar *Dest,size_t MaxSize); bool IsFullPath(const wchar *Path); bool IsFullRootPath(const wchar *Path); -bool IsDiskLetter(const wchar *Path); void GetPathRoot(const wchar *Path,wchar *Root,size_t MaxSize); int ParseVersionFileName(wchar *Name,bool Truncate); wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,size_t MaxSize,bool NewNumbering); @@ -69,6 +69,8 @@ void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask #ifdef _WIN_ALL bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize); +void ConvertToPrecomposed(wchar *Name,size_t NameSize); +void MakeNameCompatible(wchar *Name); #endif #endif diff --git a/src/thirdparty/unrar/rar.cpp b/src/thirdparty/unrar/rar.cpp index 6c8f07240..c1f070be9 100644 --- a/src/thirdparty/unrar/rar.cpp +++ b/src/thirdparty/unrar/rar.cpp @@ -55,6 +55,7 @@ int main(int argc, char *argv[]) } Cmd->AddArcName(ModuleName); Cmd->ParseDone(); + Cmd->AbsoluteLinks=true; // If users runs SFX, he trusts an archive source. #else // !SFX_MODULE Cmd->ParseCommandLine(true,argc,argv); if (!Cmd->ConfigDisabled) @@ -70,10 +71,9 @@ int main(int argc, char *argv[]) #endif uiInit(Cmd->Sound); - InitConsoleOptions(Cmd->MsgStream); + InitConsoleOptions(Cmd->MsgStream,Cmd->RedirectCharset); InitLogOptions(Cmd->LogName,Cmd->ErrlogCharset); ErrHandler.SetSilent(Cmd->AllYes || Cmd->MsgStream==MSG_NULL); - ErrHandler.SetShutdown(Cmd->Shutdown); Cmd->OutTitle(); Cmd->ProcessCommand(); @@ -94,7 +94,7 @@ int main(int argc, char *argv[]) } #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SHELL_EXT) - if (ShutdownOnClose) + if (ShutdownOnClose && ErrHandler.IsShutdownEnabled()) Shutdown(); #endif ErrHandler.MainExit=true; diff --git a/src/thirdparty/unrar/rardefs.hpp b/src/thirdparty/unrar/rardefs.hpp index 93276233b..80f39b129 100644 --- a/src/thirdparty/unrar/rardefs.hpp +++ b/src/thirdparty/unrar/rardefs.hpp @@ -13,7 +13,9 @@ // for CryptProtectMemory in SecPassword. #define MAXPASSWORD 128 -#define MAXSFXSIZE 0x100000 +#define MAXSFXSIZE 0x200000 + +#define MAXCMTSIZE 0x40000 #define DefSFXName L"default.sfx" #define DefSortListName L"rarfiles.lst" diff --git a/src/thirdparty/unrar/raros.hpp b/src/thirdparty/unrar/raros.hpp index de3bbeb76..4f4f2ae79 100644 --- a/src/thirdparty/unrar/raros.hpp +++ b/src/thirdparty/unrar/raros.hpp @@ -19,7 +19,7 @@ #endif #endif -#ifdef ANDROID +#if defined(ANDROID) || defined(__ANDROID__) #define _UNIX #define _ANDROID #endif diff --git a/src/thirdparty/unrar/rdwrfn.cpp b/src/thirdparty/unrar/rdwrfn.cpp index 50c715d3c..5d2598e40 100644 --- a/src/thirdparty/unrar/rdwrfn.cpp +++ b/src/thirdparty/unrar/rdwrfn.cpp @@ -2,6 +2,10 @@ ComprDataIO::ComprDataIO() { +#ifndef RAR_NOCRYPT + Crypt=new CryptData; + Decrypt=new CryptData; +#endif Init(); } @@ -33,6 +37,13 @@ void ComprDataIO::Init() } +ComprDataIO::~ComprDataIO() +{ +#ifndef RAR_NOCRYPT + delete Crypt; + delete Decrypt; +#endif +} @@ -127,7 +138,7 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count) ReadSize=TotalRead; #ifndef RAR_NOCRYPT if (Decryption) - Decrypt.DecryptBlock(Addr,ReadSize); + Decrypt->DecryptBlock(Addr,ReadSize); #endif } Wait(); @@ -269,13 +280,13 @@ void ComprDataIO::GetUnpackedData(byte **Data,size_t *Size) void ComprDataIO::SetEncryption(bool Encrypt,CRYPT_METHOD Method, SecPassword *Password,const byte *Salt,const byte *InitV, - uint Lg2Cnt,byte *PswCheck,byte *HashKey) + uint Lg2Cnt,byte *HashKey,byte *PswCheck) { #ifndef RAR_NOCRYPT if (Encrypt) - Encryption=Crypt.SetCryptKeys(true,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck); + Encryption=Crypt->SetCryptKeys(true,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck); else - Decryption=Decrypt.SetCryptKeys(false,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck); + Decryption=Decrypt->SetCryptKeys(false,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck); #endif } @@ -284,7 +295,7 @@ void ComprDataIO::SetEncryption(bool Encrypt,CRYPT_METHOD Method, void ComprDataIO::SetAV15Encryption() { Decryption=true; - Decrypt.SetAV15Encryption(); + Decrypt->SetAV15Encryption(); } #endif @@ -293,7 +304,7 @@ void ComprDataIO::SetAV15Encryption() void ComprDataIO::SetCmt13Encryption() { Decryption=true; - Decrypt.SetCmt13Encryption(); + Decrypt->SetCmt13Encryption(); } #endif diff --git a/src/thirdparty/unrar/rdwrfn.hpp b/src/thirdparty/unrar/rdwrfn.hpp index c61128d77..a8508d60b 100644 --- a/src/thirdparty/unrar/rdwrfn.hpp +++ b/src/thirdparty/unrar/rdwrfn.hpp @@ -38,8 +38,8 @@ class ComprDataIO int64 *SubHeadPos; #ifndef RAR_NOCRYPT - CryptData Crypt; - CryptData Decrypt; + CryptData *Crypt; + CryptData *Decrypt; #endif @@ -49,6 +49,7 @@ class ComprDataIO public: ComprDataIO(); + ~ComprDataIO(); void Init(); int UnpRead(byte *Addr,size_t Count); void UnpWrite(byte *Addr,size_t Count); @@ -61,7 +62,7 @@ class ComprDataIO void SetCommand(CmdAdd *Cmd) {Command=Cmd;} void SetSubHeader(FileHeader *hd,int64 *Pos) {SubHead=hd;SubHeadPos=Pos;} void SetEncryption(bool Encrypt,CRYPT_METHOD Method,SecPassword *Password, - const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *PswCheck,byte *HashKey); + const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck); void SetAV15Encryption(); void SetCmt13Encryption(); void SetUnpackToMemory(byte *Addr,uint Size); diff --git a/src/thirdparty/unrar/recvol.cpp b/src/thirdparty/unrar/recvol.cpp index beb2ce57f..c15863428 100644 --- a/src/thirdparty/unrar/recvol.cpp +++ b/src/thirdparty/unrar/recvol.cpp @@ -31,12 +31,83 @@ bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent) // handling exceptions. So it can close and delete files on Cancel. if (Fmt==RARFMT15) { - RecVolumes3 RecVol; + RecVolumes3 RecVol(false); return RecVol.Restore(Cmd,Name,Silent); } else { - RecVolumes5 RecVol; + RecVolumes5 RecVol(false); return RecVol.Restore(Cmd,Name,Silent); } } + + +void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name) +{ + wchar RevName[NM]; + *RevName=0; + if (Arc!=NULL) + { + // We received .rar or .exe volume as a parameter, trying to find + // the matching .rev file number 1. + bool NewNumbering=Arc->NewNumbering; + + wchar ArcName[NM]; + wcsncpyz(ArcName,Name,ASIZE(ArcName)); + + wchar *VolNumStart=VolNameToFirstName(ArcName,ArcName,ASIZE(ArcName),NewNumbering); + wchar RecVolMask[NM]; + wcsncpyz(RecVolMask,ArcName,ASIZE(RecVolMask)); + size_t BaseNamePartLength=VolNumStart-ArcName; + wcsncpyz(RecVolMask+BaseNamePartLength,L"*.rev",ASIZE(RecVolMask)-BaseNamePartLength); + + FindFile Find; + Find.SetMask(RecVolMask); + FindData RecData; + + while (Find.Next(&RecData)) + { + wchar *Num=GetVolNumPart(RecData.Name); + if (*Num!='1') // Name must have "0...01" numeric part. + continue; + bool FirstVol=true; + while (--Num>=RecData.Name && IsDigit(*Num)) + if (*Num!='0') + { + FirstVol=false; + break; + } + if (FirstVol) + { + wcsncpyz(RevName,RecData.Name,ASIZE(RevName)); + Name=RevName; + break; + } + } + if (*RevName==0) // First .rev file not found. + return; + } + + File RevFile; + if (!RevFile.Open(Name)) + { + ErrHandler.OpenErrorMsg(Name); // It also sets RARX_OPEN. + return; + } +#ifndef GUI + mprintf(L"\n"); +#endif + byte Sign[REV5_SIGN_SIZE]; + bool Rev5=RevFile.Read(Sign,REV5_SIGN_SIZE)==REV5_SIGN_SIZE && memcmp(Sign,REV5_SIGN,REV5_SIGN_SIZE)==0; + RevFile.Close(); + if (Rev5) + { + RecVolumes5 RecVol(true); + RecVol.Test(Cmd,Name); + } + else + { + RecVolumes3 RecVol(true); + RecVol.Test(Cmd,Name); + } +} diff --git a/src/thirdparty/unrar/recvol.hpp b/src/thirdparty/unrar/recvol.hpp index 5956d7bbb..7f2f1adb9 100644 --- a/src/thirdparty/unrar/recvol.hpp +++ b/src/thirdparty/unrar/recvol.hpp @@ -14,10 +14,11 @@ class RecVolumes3 ThreadPool *RSThreadPool; #endif public: - RecVolumes3(); + RecVolumes3(bool TestOnly); ~RecVolumes3(); void Make(RAROptions *Cmd,wchar *ArcName); bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent); + void Test(RAROptions *Cmd,const wchar *Name); }; @@ -74,11 +75,13 @@ class RecVolumes5 public: // 'public' only because called from thread functions. void ProcessAreaRS(RecRSThreadData *td); public: - RecVolumes5(); + RecVolumes5(bool TestOnly); ~RecVolumes5(); bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent); + void Test(RAROptions *Cmd,const wchar *Name); }; bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent); +void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name); #endif diff --git a/src/thirdparty/unrar/recvol3.cpp b/src/thirdparty/unrar/recvol3.cpp index 3c77eba37..4cbc39c86 100644 --- a/src/thirdparty/unrar/recvol3.cpp +++ b/src/thirdparty/unrar/recvol3.cpp @@ -38,13 +38,23 @@ THREAD_PROC(RSDecodeThread) } #endif -RecVolumes3::RecVolumes3() +RecVolumes3::RecVolumes3(bool TestOnly) { - Buf.Alloc(TotalBufferSize); memset(SrcFile,0,sizeof(SrcFile)); + if (TestOnly) + { +#ifdef RAR_SMP + RSThreadPool=NULL; +#endif + } + else + { + Buf.Alloc(TotalBufferSize); + memset(SrcFile,0,sizeof(SrcFile)); #ifdef RAR_SMP - RSThreadPool=CreateThreadPool(); + RSThreadPool=CreateThreadPool(); #endif + } } @@ -74,26 +84,34 @@ void RSEncode::EncodeBuf() } +// Check for names like arc5_3_1.rev created by RAR 3.0. +static bool IsNewStyleRev(const wchar *Name) +{ + wchar *Ext=GetExt(Name); + if (Ext==NULL) + return true; + int DigitGroup=0; + for (Ext--;Ext>Name;Ext--) + if (!IsDigit(*Ext)) + if (*Ext=='_' && IsDigit(*(Ext-1))) + DigitGroup++; + else + break; + return DigitGroup<2; +} + + bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) { wchar ArcName[NM]; wcsncpyz(ArcName,Name,ASIZE(ArcName)); wchar *Ext=GetExt(ArcName); - bool NewStyle=false; + bool NewStyle=false; // New style .rev volumes are supported since RAR 3.10. bool RevName=Ext!=NULL && wcsicomp(Ext,L".rev")==0; if (RevName) { - for (int DigitGroup=0;Ext>ArcName && DigitGroup<3;Ext--) - if (!IsDigit(*Ext)) - if (IsDigit(*(Ext-1)) && (*Ext=='_' || DigitGroup<2)) - DigitGroup++; - else - if (DigitGroup<2) - { - NewStyle=true; - break; - } - while (IsDigit(*Ext) && Ext>ArcName+1) + NewStyle=IsNewStyleRev(ArcName); + while (Ext>ArcName+1 && (IsDigit(*(Ext-1)) || *(Ext-1)=='_')) Ext--; wcscpy(Ext,L"*.*"); @@ -480,3 +498,54 @@ void RSEncode::DecodeBuf() Buf[Erasures[I]*RecBufferSize+BufPos]=Data[Erasures[I]]; } } + + +void RecVolumes3::Test(RAROptions *Cmd,const wchar *Name) +{ + if (!IsNewStyleRev(Name)) // RAR 3.0 name#_#_#.rev do not include CRC32. + { + ErrHandler.UnknownMethodMsg(Name,Name); + return; + } + + wchar VolName[NM]; + wcsncpyz(VolName,Name,ASIZE(VolName)); + + while (FileExist(VolName)) + { + File CurFile; + if (!CurFile.Open(VolName)) + { + ErrHandler.OpenErrorMsg(VolName); // It also sets RARX_OPEN. + continue; + } + if (!uiStartFileExtract(VolName,false,true,false)) + return; +#ifndef GUI + mprintf(St(MExtrTestFile),VolName); + mprintf(L" "); +#endif + CurFile.Seek(0,SEEK_END); + int64 Length=CurFile.Tell(); + CurFile.Seek(Length-4,SEEK_SET); + uint FileCRC=0; + for (int I=0;I<4;I++) + FileCRC|=CurFile.GetByte()<<(I*8); + + uint CalcCRC; + CalcFileSum(&CurFile,&CalcCRC,NULL,1,Length-4,Cmd->DisablePercentage ? 0 : CALCFSUM_SHOWPROGRESS); + if (FileCRC==CalcCRC) + { +#ifndef GUI + mprintf(L"%s%s ",L"\b\b\b\b\b ",St(MOk)); +#endif + } + else + { + uiMsg(UIERROR_CHECKSUM,VolName,VolName); + ErrHandler.SetErrorCode(RARX_CRC); + } + + NextVolumeName(VolName,ASIZE(VolName),false); + } +} diff --git a/src/thirdparty/unrar/recvol5.cpp b/src/thirdparty/unrar/recvol5.cpp index 4cb0fc72d..bd5534ed7 100644 --- a/src/thirdparty/unrar/recvol5.cpp +++ b/src/thirdparty/unrar/recvol5.cpp @@ -2,8 +2,9 @@ static const uint MaxVolumes=65535; -RecVolumes5::RecVolumes5() +RecVolumes5::RecVolumes5(bool TestOnly) { + RealBuf=NULL; RealReadBuffer=NULL; DataCount=0; @@ -16,13 +17,21 @@ RecVolumes5::RecVolumes5() ThreadData[I].RecRSPtr=this; ThreadData[I].RS=NULL; } + + if (TestOnly) + { #ifdef RAR_SMP - RecThreadPool=CreateThreadPool(); + RecThreadPool=NULL; #endif - - RealBuf=NULL; // Might be needed in case of exception. - RealBuf=new byte[TotalBufferSize+SSE_ALIGNMENT]; - Buf=(byte *)ALIGN_VALUE(RealBuf,SSE_ALIGNMENT); + } + else + { +#ifdef RAR_SMP + RecThreadPool=CreateThreadPool(); +#endif + RealBuf=new byte[TotalBufferSize+SSE_ALIGNMENT]; + Buf=(byte *)ALIGN_VALUE(RealBuf,SSE_ALIGNMENT); + } } @@ -129,7 +138,7 @@ void RecVolumes5::ProcessAreaRS(RecRSThreadData *td) bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) { wchar ArcName[NM]; - wcscpy(ArcName,Name); + wcsncpyz(ArcName,Name,ASIZE(ArcName)); wchar *Num=GetVolNumPart(ArcName); while (Num>ArcName && IsDigit(*(Num-1))) @@ -288,7 +297,7 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) Item->f=NULL; } - if (Item->New=(Item->f==NULL)) + if ((Item->New=(Item->f==NULL))) // Additional parentheses to avoid GCC warning. { wcsncpyz(Item->Name,FirstVolName,ASIZE(Item->Name)); uiMsg(UIMSG_CREATING,Item->Name); @@ -339,7 +348,11 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) RSCoder16 RS; if (!RS.Init(DataCount,RecCount,ValidFlags)) + { + delete[] ValidFlags; + delete[] Data; return false; // Should not happen, we check parameter validity above. + } RealReadBuffer=new byte[RecBufferSize+SSE_ALIGNMENT]; byte *ReadBuf=(byte *)ALIGN_VALUE(RealReadBuffer,SSE_ALIGNMENT); @@ -462,3 +475,51 @@ uint RecVolumes5::ReadHeader(File *RecFile,bool FirstRev) return RecNum; } + + +void RecVolumes5::Test(RAROptions *Cmd,const wchar *Name) +{ + wchar VolName[NM]; + wcsncpyz(VolName,Name,ASIZE(VolName)); + + uint FoundRecVolumes=0; + while (FileExist(VolName)) + { + File CurFile; + if (!CurFile.Open(VolName)) + { + ErrHandler.OpenErrorMsg(VolName); // It also sets RARX_OPEN. + continue; + } + if (!uiStartFileExtract(VolName,false,true,false)) + return; +#ifndef GUI + mprintf(St(MExtrTestFile),VolName); + mprintf(L" "); +#endif + bool Valid=false; + uint RecNum=ReadHeader(&CurFile,FoundRecVolumes==0); + if (RecNum!=0) + { + FoundRecVolumes++; + + uint RevCRC; + CalcFileSum(&CurFile,&RevCRC,NULL,1,INT64NDF,CALCFSUM_CURPOS|(Cmd->DisablePercentage ? 0 : CALCFSUM_SHOWPROGRESS)); + Valid=RevCRC==RecItems[RecNum].CRC; + } + + if (Valid) + { +#ifndef GUI + mprintf(L"%s%s ",L"\b\b\b\b\b ",St(MOk)); +#endif + } + else + { + uiMsg(UIERROR_CHECKSUM,VolName,VolName); + ErrHandler.SetErrorCode(RARX_CRC); + } + + NextVolumeName(VolName,ASIZE(VolName),false); + } +} diff --git a/src/thirdparty/unrar/rs16.cpp b/src/thirdparty/unrar/rs16.cpp index 082ab83f4..e1b4af1d3 100644 --- a/src/thirdparty/unrar/rs16.cpp +++ b/src/thirdparty/unrar/rs16.cpp @@ -215,6 +215,7 @@ void RSCoder16::InvertDecoderMatrix() } +#if 0 // Multiply matrix to data vector. When encoding, it contains data in Data // and stores error correction codes in Out. When decoding it contains // broken data followed by ECC in Data and stores recovered data to Out. @@ -252,6 +253,7 @@ void RSCoder16::Process(const uint *Data, uint *Out) Out[I] = R; } } +#endif // We update ECC in blocks by applying every data block to all ECC blocks. diff --git a/src/thirdparty/unrar/rs16.hpp b/src/thirdparty/unrar/rs16.hpp index ba518ac1d..b67a7ca86 100644 --- a/src/thirdparty/unrar/rs16.hpp +++ b/src/thirdparty/unrar/rs16.hpp @@ -35,7 +35,9 @@ class RSCoder16 ~RSCoder16(); bool Init(uint DataCount, uint RecCount, bool *ValidityFlags); +#if 0 // We use only UpdateECC now. void Process(const uint *Data, uint *Out); +#endif void UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte *ECC, size_t BlockSize); }; diff --git a/src/thirdparty/unrar/scantree.cpp b/src/thirdparty/unrar/scantree.cpp index 40e4e47c9..ed48efe4b 100644 --- a/src/thirdparty/unrar/scantree.cpp +++ b/src/thirdparty/unrar/scantree.cpp @@ -8,6 +8,7 @@ ScanTree::ScanTree(StringList *FileMasks,RECURSE_MODE Recurse,bool GetLinks,SCAN ScanTree::GetDirs=GetDirs; ScanEntireDisk=false; + FolderWildcards=false; SetAllMaskDepth=0; *CurMask=0; @@ -16,6 +17,8 @@ ScanTree::ScanTree(StringList *FileMasks,RECURSE_MODE Recurse,bool GetLinks,SCAN Errors=0; *ErrArcName=0; Cmd=NULL; + ErrDirList=NULL; + ErrDirSpecPathLength=NULL; } @@ -27,11 +30,14 @@ ScanTree::~ScanTree() } -SCAN_CODE ScanTree::GetNext(FindData *FindData) +SCAN_CODE ScanTree::GetNext(FindData *FD) { if (Depth<0) return SCAN_DONE; +#ifndef SILENT + uint LoopCount=0; +#endif SCAN_CODE FindCode; while (1) @@ -39,8 +45,15 @@ SCAN_CODE ScanTree::GetNext(FindData *FindData) if (*CurMask==0 && !GetNextMask()) return SCAN_DONE; +#ifndef SILENT + // Let's return some ticks to system or WinRAR can become irresponsible + // while scanning files in command like "winrar a -r arc c:\file.ext". + // Also we reset system sleep timer here. + if ((++LoopCount & 0x3ff)==0) + Wait(); +#endif - FindCode=FindProc(FindData); + FindCode=FindProc(FD); if (FindCode==SCAN_ERROR) { Errors++; @@ -48,21 +61,151 @@ SCAN_CODE ScanTree::GetNext(FindData *FindData) } if (FindCode==SCAN_NEXT) continue; - if (FindCode==SCAN_SUCCESS && FindData->IsDir && GetDirs==SCAN_SKIPDIRS) + if (FindCode==SCAN_SUCCESS && FD->IsDir && GetDirs==SCAN_SKIPDIRS) continue; if (FindCode==SCAN_DONE && GetNextMask()) continue; + if (FilterList.ItemsCount()>0 && FindCode==SCAN_SUCCESS) + if (!CommandData::CheckArgs(&FilterList,FD->IsDir,FD->Name,false,MATCH_WILDSUBPATH)) + continue; break; } - return(FindCode); + return FindCode; } -bool ScanTree::GetNextMask() +// For masks like dir1\dir2*\*.ext in non-recursive mode. +bool ScanTree::ExpandFolderMask() { + bool WildcardFound=false; + uint SlashPos=0; + for (int I=0;CurMask[I]!=0;I++) + { + if (CurMask[I]=='?' || CurMask[I]=='*') + WildcardFound=true; + if (WildcardFound && IsPathDiv(CurMask[I])) + { + // First path separator position after folder wildcard mask. + // In case of dir1\dir2*\dir3\name.ext mask it may point not to file + // name, so we cannot use PointToName() here. + SlashPos=I; + break; + } + } + + wchar Mask[NM]; + wcsncpyz(Mask,CurMask,ASIZE(Mask)); + Mask[SlashPos]=0; + + // Prepare the list of all folders matching the wildcard mask. + ExpandedFolderList.Reset(); + FindFile Find; + Find.SetMask(Mask); + FindData FD; + while (Find.Next(&FD)) + if (FD.IsDir) + { + wcsncatz(FD.Name,CurMask+SlashPos,ASIZE(FD.Name)); + + // Treat dir*\* or dir*\*.* as dir, so empty 'dir' is also matched + // by such mask. Skipping empty dir with dir*\*.* confused some users. + wchar *LastMask=PointToName(FD.Name); + if (wcscmp(LastMask,L"*")==0 || wcscmp(LastMask,L"*.*")==0) + RemoveNameFromPath(FD.Name); + + ExpandedFolderList.AddString(FD.Name); + } + if (ExpandedFolderList.ItemsCount()==0) + return false; + // Return the first matching folder name now. + ExpandedFolderList.GetString(CurMask,ASIZE(CurMask)); + return true; +} + + +// For masks like dir1\dir2*\file.ext this function sets 'dir1' recursive mask +// and '*\dir2*\file.ext' filter. Masks without folder wildcards are +// returned as is. +bool ScanTree::GetFilteredMask() +{ + // If we have some matching folders left for non-recursive folder wildcard + // mask, we return it here. + if (ExpandedFolderList.ItemsCount()>0 && ExpandedFolderList.GetString(CurMask,ASIZE(CurMask))) + return true; + + FolderWildcards=false; + FilterList.Reset(); if (!FileMasks->GetString(CurMask,ASIZE(CurMask))) return false; - CurMask[ASIZE(CurMask)-1]=0; + + // Check if folder wildcards present. + bool WildcardFound=false; + uint FolderWildcardCount=0; + uint SlashPos=0; + for (int I=0;CurMask[I]!=0;I++) + { + if (CurMask[I]=='?' || CurMask[I]=='*') + WildcardFound=true; + if (IsPathDiv(CurMask[I]) || IsDriveDiv(CurMask[I])) + { + if (WildcardFound) + { + // Calculate a number of folder wildcards in current mask. + FolderWildcardCount++; + WildcardFound=false; + } + if (FolderWildcardCount==0) + SlashPos=I; // Slash position before first folder wildcard mask. + } + } + if (FolderWildcardCount==0) + return true; + FolderWildcards=true; // Global folder wildcards flag. + + // If we have only one folder wildcard component and -r is missing or -r- + // is specified, prepare matching folders in non-recursive mode. + // We assume -r for masks like dir1*\dir2*\file*, because it is complicated + // to fast find them using OS file find API call. + if ((Recurse==RECURSE_NONE || Recurse==RECURSE_DISABLE) && FolderWildcardCount==1) + return ExpandFolderMask(); + + wchar Filter[NM]; + // Convert path\dir*\ to *\dir filter to search for 'dir' in all 'path' subfolders. + wcscpy(Filter,L"*"); + AddEndSlash(Filter,ASIZE(Filter)); + // SlashPos might point or not point to path separator for masks like 'dir*', '\dir*' or 'd:dir*' + wchar *WildName=IsPathDiv(CurMask[SlashPos]) || IsDriveDiv(CurMask[SlashPos]) ? CurMask+SlashPos+1 : CurMask+SlashPos; + wcsncatz(Filter,WildName,ASIZE(Filter)); + + // Treat dir*\* or dir*\*.* as dir\, so empty 'dir' is also matched + // by such mask. Skipping empty dir with dir*\*.* confused some users. + wchar *LastMask=PointToName(Filter); + if (wcscmp(LastMask,L"*")==0 || wcscmp(LastMask,L"*.*")==0) + *LastMask=0; + + FilterList.AddString(Filter); + + bool RelativeDrive=IsDriveDiv(CurMask[SlashPos]); + if (RelativeDrive) + SlashPos++; // Use "d:" instead of "d" for d:* mask. + + CurMask[SlashPos]=0; + + if (!RelativeDrive) // Keep d: mask as is, not convert to d:\* + { + // We need to append "\*" both for -ep1 to work correctly and to + // convert d:\* masks previously truncated to d: back to original form. + AddEndSlash(CurMask,ASIZE(CurMask)); + wcsncatz(CurMask,MASKALL,ASIZE(CurMask)); + } + return true; +} + + +bool ScanTree::GetNextMask() +{ + if (!GetFilteredMask()) + return false; #ifdef _WIN_ALL UnixSlashToDos(CurMask,CurMask,ASIZE(CurMask)); #endif @@ -70,7 +213,7 @@ bool ScanTree::GetNextMask() // We wish to scan entire disk if mask like c:\ is specified // regardless of recursion mode. Use c:\*.* mask when need to scan only // the root directory. - ScanEntireDisk=IsDiskLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0; + ScanEntireDisk=IsDriveLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0; wchar *Name=PointToName(CurMask); if (*Name==0) @@ -111,8 +254,10 @@ SCAN_CODE ScanTree::FindProc(FindData *FD) // SearchAll means that we'll use "*" mask for search, so we'll find // subdirectories and will be able to recurse into them. // We do not use "*" for directories at any level or for files - // at top level in recursion mode. + // at top level in recursion mode. We always comrpess the entire directory + // if folder wildcard is specified. bool SearchAll=!IsDir && (Depth>0 || Recurse==RECURSE_ALWAYS || + FolderWildcards && Recurse!=RECURSE_DISABLE || Wildcards && Recurse==RECURSE_WILDCARDS || ScanEntireDisk && Recurse!=RECURSE_DISABLE); if (Depth==0) @@ -324,6 +469,10 @@ void ScanTree::ScanError(bool &Error) if (Error) { + if (ErrDirList!=NULL) + ErrDirList->AddString(CurMask); + if (ErrDirSpecPathLength!=NULL) + ErrDirSpecPathLength->Push((uint)SpecPathLength); wchar FullName[NM]; // This conversion works for wildcard masks too. ConvertNameToFull(CurMask,FullName,ASIZE(FullName)); diff --git a/src/thirdparty/unrar/scantree.hpp b/src/thirdparty/unrar/scantree.hpp index 7ed9a3833..40a6d8497 100644 --- a/src/thirdparty/unrar/scantree.hpp +++ b/src/thirdparty/unrar/scantree.hpp @@ -18,6 +18,8 @@ class CommandData; class ScanTree { private: + bool ExpandFolderMask(); + bool GetFilteredMask(); bool GetNextMask(); SCAN_CODE FindProc(FindData *FD); void ScanError(bool &Error); @@ -33,11 +35,25 @@ class ScanTree SCAN_DIRS GetDirs; int Errors; - // set when processing paths like c:\ (root directory without wildcards) + // Set when processing paths like c:\ (root directory without wildcards). bool ScanEntireDisk; wchar CurMask[NM]; wchar OrigCurMask[NM]; + + // Store all folder masks generated from folder wildcard mask in non-recursive mode. + StringList ExpandedFolderList; + + // Store a filter string for folder wildcard in recursive mode. + StringList FilterList; + + // Save the list of unreadable dirs here. + StringList *ErrDirList; + Array<uint> *ErrDirSpecPathLength; + + // Set if processing a folder wildcard mask. + bool FolderWildcards; + bool SearchAllInRoot; size_t SpecPathLength; @@ -52,6 +68,11 @@ class ScanTree int GetErrors() {return Errors;}; void SetErrArcName(const wchar *Name) {wcsncpyz(ErrArcName,Name,ASIZE(ErrArcName));} void SetCommandData(CommandData *Cmd) {ScanTree::Cmd=Cmd;} + void SetErrDirList(StringList *List,Array<uint> *Lengths) + { + ErrDirList=List; + ErrDirSpecPathLength=Lengths; + } }; #endif diff --git a/src/thirdparty/unrar/secpassword.cpp b/src/thirdparty/unrar/secpassword.cpp index 2ac289b72..242b16702 100644 --- a/src/thirdparty/unrar/secpassword.cpp +++ b/src/thirdparty/unrar/secpassword.cpp @@ -35,7 +35,7 @@ class CryptLoader { if (!LoadCalled) { - hCrypt = LoadLibraryW(L"Crypt32.dll"); + hCrypt = LoadSysLibrary(L"Crypt32.dll"); if (hCrypt != NULL) { pCryptProtectMemory = (CRYPTPROTECTMEMORY)GetProcAddress(hCrypt, "CryptProtectMemory"); diff --git a/src/thirdparty/unrar/smallfn.cpp b/src/thirdparty/unrar/smallfn.cpp index fe7cb1dc2..81259d02f 100644 --- a/src/thirdparty/unrar/smallfn.cpp +++ b/src/thirdparty/unrar/smallfn.cpp @@ -3,7 +3,7 @@ int ToPercent(int64 N1,int64 N2) { if (N2<N1) - return(100); + return 100; return ToPercentUnlim(N1,N2); } @@ -12,7 +12,7 @@ int ToPercent(int64 N1,int64 N2) int ToPercentUnlim(int64 N1,int64 N2) { if (N2==0) - return(0); + return 0; return (int)(N1*100/N2); } diff --git a/src/thirdparty/unrar/strfn.cpp b/src/thirdparty/unrar/strfn.cpp index e234da834..8c46543b5 100644 --- a/src/thirdparty/unrar/strfn.cpp +++ b/src/thirdparty/unrar/strfn.cpp @@ -15,6 +15,10 @@ const wchar *NullToEmpty(const wchar *Str) void IntToExt(const char *Src,char *Dest,size_t DestSize) { #ifdef _WIN_ALL + // OemToCharBuff does not stop at 0, so let's check source length. + size_t SrcLength=strlen(Src)+1; + if (DestSize>SrcLength) + DestSize=SrcLength; OemToCharBuffA(Src,Dest,(DWORD)DestSize); Dest[DestSize-1]=0; #elif defined(_ANDROID) @@ -28,6 +32,21 @@ void IntToExt(const char *Src,char *Dest,size_t DestSize) } +// Convert archived names to Unicode. Allow user to select a code page in GUI. +void ArcCharToWide(const char *Src,wchar *Dest,size_t DestSize,ACTW_ENCODING Encoding) +{ + if (Encoding==ACTW_UTF8) + UtfToWide(Src,Dest,DestSize); + else + CharToWide(Src,Dest,DestSize); + // Ensure that we return a zero terminate string for security reason. + // While [Jni]CharToWide might already do it, be protected in case of future + // changes in these functions. + if (DestSize>0) + Dest[DestSize-1]=0; +} + + int stricomp(const char *s1,const char *s2) { #ifdef _WIN_ALL @@ -83,7 +102,7 @@ wchar* RemoveLF(wchar *Str) { for (int I=(int)wcslen(Str)-1;I>=0 && (Str[I]=='\r' || Str[I]=='\n');I--) Str[I]=0; - return(Str); + return Str; } @@ -91,9 +110,9 @@ unsigned char loctolower(unsigned char ch) { #ifdef _WIN_ALL // Convert to LPARAM first to avoid a warning in 64 bit mode. - return((int)(LPARAM)CharLowerA((LPSTR)ch)); + return (int)(LPARAM)CharLowerA((LPSTR)ch); #else - return(tolower(ch)); + return tolower(ch); #endif } @@ -102,9 +121,9 @@ unsigned char loctoupper(unsigned char ch) { #ifdef _WIN_ALL // Convert to LPARAM first to avoid a warning in 64 bit mode. - return((int)(LPARAM)CharUpperA((LPSTR)ch)); + return (int)(LPARAM)CharUpperA((LPSTR)ch); #else - return(toupper(ch)); + return toupper(ch); #endif } @@ -116,8 +135,8 @@ unsigned char loctoupper(unsigned char ch) unsigned char etoupper(unsigned char ch) { if (ch=='i') - return('I'); - return(toupper(ch)); + return 'I'; + return toupper(ch); } @@ -125,8 +144,8 @@ unsigned char etoupper(unsigned char ch) wchar etoupperw(wchar ch) { if (ch=='i') - return('I'); - return(toupperw(ch)); + return 'I'; + return toupperw(ch); } @@ -136,7 +155,7 @@ wchar etoupperw(wchar ch) // values, resulting in undefined behavior in standard isdigit. bool IsDigit(int ch) { - return(ch>='0' && ch<='9'); + return ch>='0' && ch<='9'; } @@ -146,7 +165,7 @@ bool IsDigit(int ch) // values, resulting in undefined behavior in standard isspace. bool IsSpace(int ch) { - return(ch==' ' || ch=='\t'); + return ch==' ' || ch=='\t'; } @@ -156,7 +175,7 @@ bool IsSpace(int ch) // values, resulting in undefined behavior in standard function. bool IsAlpha(int ch) { - return(ch>='A' && ch<='Z' || ch>='a' && ch<='z'); + return ch>='A' && ch<='Z' || ch>='a' && ch<='z'; } @@ -285,34 +304,52 @@ wchar* wcsncatz(wchar* dest, const wchar* src, size_t maxlen) } -void itoa(int64 n,char *Str) +void itoa(int64 n,char *Str,size_t MaxSize) { char NumStr[50]; size_t Pos=0; + int Neg=n < 0 ? 1 : 0; + if (Neg) + n=-n; + do { + if (Pos+1>=MaxSize-Neg) + break; NumStr[Pos++]=char(n%10)+'0'; n=n/10; } while (n!=0); + if (Neg) + NumStr[Pos++]='-'; + for (size_t I=0;I<Pos;I++) Str[I]=NumStr[Pos-I-1]; Str[Pos]=0; } -void itoa(int64 n,wchar *Str) +void itoa(int64 n,wchar *Str,size_t MaxSize) { wchar NumStr[50]; size_t Pos=0; + int Neg=n < 0 ? 1 : 0; + if (Neg) + n=-n; + do { + if (Pos+1>=MaxSize-Neg) + break; NumStr[Pos++]=wchar(n%10)+'0'; n=n/10; } while (n!=0); + if (Neg) + NumStr[Pos++]='-'; + for (size_t I=0;I<Pos;I++) Str[I]=NumStr[Pos-I-1]; Str[Pos]=0; diff --git a/src/thirdparty/unrar/strfn.hpp b/src/thirdparty/unrar/strfn.hpp index eae67747c..d6d8d124d 100644 --- a/src/thirdparty/unrar/strfn.hpp +++ b/src/thirdparty/unrar/strfn.hpp @@ -4,6 +4,10 @@ const char* NullToEmpty(const char *Str); const wchar* NullToEmpty(const wchar *Str); void IntToExt(const char *Src,char *Dest,size_t DestSize); + +enum ACTW_ENCODING { ACTW_DEFAULT, ACTW_OEM, ACTW_UTF8}; +void ArcCharToWide(const char *Src,wchar *Dest,size_t DestSize,ACTW_ENCODING Encoding); + int stricomp(const char *s1,const char *s2); int strnicomp(const char *s1,const char *s2,size_t n); wchar* RemoveEOL(wchar *Str); @@ -34,8 +38,8 @@ bool LowAscii(const wchar *Str); int wcsicompc(const wchar *Str1,const wchar *Str2); -void itoa(int64 n,char *Str); -void itoa(int64 n,wchar *Str); +void itoa(int64 n,char *Str,size_t MaxSize); +void itoa(int64 n,wchar *Str,size_t MaxSize); const wchar* GetWide(const char *Src); const wchar* GetCmdParam(const wchar *CmdLine,wchar *Param,size_t MaxSize); #ifndef SILENT diff --git a/src/thirdparty/unrar/suballoc.cpp b/src/thirdparty/unrar/suballoc.cpp index 4bc07bf9d..d1fb690d0 100644 --- a/src/thirdparty/unrar/suballoc.cpp +++ b/src/thirdparty/unrar/suballoc.cpp @@ -66,8 +66,6 @@ inline void SubAllocator::SplitBlock(void* pv,int OldIndx,int NewIndx) } - - void SubAllocator::StopSubAllocator() { if ( SubAllocatorSize ) diff --git a/src/thirdparty/unrar/suballoc.hpp b/src/thirdparty/unrar/suballoc.hpp index 0280289cf..5989e82e8 100644 --- a/src/thirdparty/unrar/suballoc.hpp +++ b/src/thirdparty/unrar/suballoc.hpp @@ -57,7 +57,6 @@ class SubAllocator inline void* RemoveNode(int indx); inline uint U2B(int NU); inline void SplitBlock(void* pv,int OldIndx,int NewIndx); - uint GetUsedMemory(); inline void GlueFreeBlocks(); void* AllocUnitsRare(int indx); inline RARPPM_MEM_BLK* MBPtr(RARPPM_MEM_BLK *BasePtr,int Items); diff --git a/src/thirdparty/unrar/system.cpp b/src/thirdparty/unrar/system.cpp index dc858744a..6c9d8ba7b 100644 --- a/src/thirdparty/unrar/system.cpp +++ b/src/thirdparty/unrar/system.cpp @@ -21,6 +21,10 @@ void SetPriority(int Priority) { PriorityClass=IDLE_PRIORITY_CLASS; PriorityLevel=THREAD_PRIORITY_IDLE; + +// Background mode for Vista, can be slow for many small files. +// if (WinNT()>=WNT_VISTA) +// SetPriorityClass(GetCurrentProcess(),PROCESS_MODE_BACKGROUND_BEGIN); } else if (Priority<7) @@ -58,15 +62,29 @@ void SetPriority(int Priority) ThreadPool::SetPriority(PriorityLevel); #endif -// Background mode for Vista, too slow for real life use. -// if (WinNT()>=WNT_VISTA && Priority==1) -// SetPriorityClass(GetCurrentProcess(),PROCESS_MODE_BACKGROUND_BEGIN); - #endif } #endif +// Monotonic clock. Like clock(), returns time passed in CLOCKS_PER_SEC items. +// In Android 5+ and Unix usual clock() returns time spent by all threads +// together, so we cannot use it to measure time intervals anymore. +clock_t MonoClock() +{ +#if defined(_ANDROID) && defined(_UNIX) && defined(CLOCK_MONOTONIC) + struct timespec CurTime; + clock_gettime(CLOCK_MONOTONIC, &CurTime); + int64 nsec = int64(CurTime.tv_sec)*1000000000 + CurTime.tv_nsec; + nsec /= 1000000000 / CLOCKS_PER_SEC; + return (clock_t)nsec; +#else + return clock(); +#endif +} + + + #ifndef SETUP void Wait() { @@ -74,7 +92,18 @@ void Wait() ErrHandler.Exit(RARX_USERBREAK); #if defined(_WIN_ALL) && !defined(SFX_MODULE) if (SleepTime!=0) - Sleep(SleepTime); + { + static clock_t LastTime=MonoClock(); + if (MonoClock()-LastTime>10*CLOCKS_PER_SEC/1000) + { + Sleep(SleepTime); + LastTime=MonoClock(); + } + } +#endif +#ifdef _WIN_ALL + // Reset system sleep timer to prevent system going sleep. + SetThreadExecutionState(ES_SYSTEM_REQUIRED); #endif } #endif @@ -101,6 +130,21 @@ void Shutdown() + +#ifdef _WIN_ALL +// Load library from Windows System32 folder. Use this function to prevent +// loading a malicious code from current folder or same folder as exe. +HMODULE WINAPI LoadSysLibrary(const wchar *Name) +{ + wchar SysDir[NM]; + if (GetSystemDirectory(SysDir,ASIZE(SysDir))==0) + return NULL; + MakeName(SysDir,Name,SysDir,ASIZE(SysDir)); + return LoadLibrary(SysDir); +} +#endif + + #ifdef USE_SSE SSE_VERSION _SSE_Version=GetSSEVersion(); diff --git a/src/thirdparty/unrar/system.hpp b/src/thirdparty/unrar/system.hpp index 88445be79..bc7cda3bf 100644 --- a/src/thirdparty/unrar/system.hpp +++ b/src/thirdparty/unrar/system.hpp @@ -19,10 +19,14 @@ void InitSystemOptions(int SleepTime); void SetPriority(int Priority); +clock_t MonoClock(); void Wait(); bool EmailFile(const wchar *FileName,const wchar *MailToW); void Shutdown(); +#ifdef _WIN_ALL +HMODULE WINAPI LoadSysLibrary(const wchar *Name); +#endif #ifdef USE_SSE diff --git a/src/thirdparty/unrar/threadmisc.cpp b/src/thirdparty/unrar/threadmisc.cpp index d1524e0cf..4ad5af2e5 100644 --- a/src/thirdparty/unrar/threadmisc.cpp +++ b/src/thirdparty/unrar/threadmisc.cpp @@ -58,7 +58,6 @@ ThreadPool* CreateThreadPool() if (GlobalPoolUseCount++ == 0) GlobalPool=new ThreadPool(MaxPoolThreads); -#ifdef RARDLL // We use a simple thread pool, which does not allow to add tasks from // different functions and threads in the same time. It is ok for RAR, // but UnRAR.dll can be used in multithreaded environment. So if one of @@ -70,7 +69,6 @@ ThreadPool* CreateThreadPool() CriticalSectionEnd(&PoolCreateSync.CritSection); return Pool; } -#endif CriticalSectionEnd(&PoolCreateSync.CritSection); return GlobalPool; @@ -79,18 +77,20 @@ ThreadPool* CreateThreadPool() void DestroyThreadPool(ThreadPool *Pool) { - CriticalSectionStart(&PoolCreateSync.CritSection); + if (Pool!=NULL) + { + CriticalSectionStart(&PoolCreateSync.CritSection); - if (Pool!=NULL && Pool==GlobalPool && GlobalPoolUseCount > 0 && --GlobalPoolUseCount == 0) - delete GlobalPool; -#ifdef RARDLL - // To correctly work in multithreaded environment UnRAR.dll creates - // new pools if global pool is already in use. We delete such pools here. - if (Pool!=NULL && Pool!=GlobalPool) - delete Pool; -#endif + if (Pool==GlobalPool && GlobalPoolUseCount > 0 && --GlobalPoolUseCount == 0) + delete GlobalPool; - CriticalSectionEnd(&PoolCreateSync.CritSection); + // To correctly work in multithreaded environment UnRAR.dll creates + // new pools if global pool is already in use. We delete such pools here. + if (Pool!=GlobalPool) + delete Pool; + + CriticalSectionEnd(&PoolCreateSync.CritSection); + } } diff --git a/src/thirdparty/unrar/timefn.cpp b/src/thirdparty/unrar/timefn.cpp index ba9f49686..b524f7744 100644 --- a/src/thirdparty/unrar/timefn.cpp +++ b/src/thirdparty/unrar/timefn.cpp @@ -122,6 +122,7 @@ void RarTime::SetLocal(RarLocalTime *lt) st.wMinute=lt->Minute; st.wSecond=lt->Second; st.wMilliseconds=0; + st.wDayOfWeek=0; FILETIME lft; if (SystemTimeToFileTime(&st,&lft)) { @@ -140,7 +141,7 @@ void RarTime::SetLocal(RarLocalTime *lt) { // Reverse procedure which we do in GetLocal. SYSTEMTIME st1,st2; - FileTimeToSystemTime(&lft,&st2); + FileTimeToSystemTime(&lft,&st2); // st2 might be unequal to st, because we added lt->Reminder to lft. TzSpecificLocalTimeToSystemTime(NULL,&st2,&st1); SystemTimeToFileTime(&st1,&ft); @@ -174,6 +175,51 @@ void RarTime::SetLocal(RarLocalTime *lt) } +void RarTime::SetUTC(RarLocalTime *lt) // Input is in UTC format. +{ +#ifdef _WIN_ALL + SYSTEMTIME st; + st.wYear=lt->Year; + st.wMonth=lt->Month; + st.wDay=lt->Day; + st.wHour=lt->Hour; + st.wMinute=lt->Minute; + st.wSecond=lt->Second; + st.wMilliseconds=0; + st.wDayOfWeek=0; + FILETIME ft; + if (SystemTimeToFileTime(&st,&ft)) + *this=ft; + else + Reset(); +#else + struct tm t; + + t.tm_sec=lt->Second; + t.tm_min=lt->Minute; + t.tm_hour=lt->Hour; + t.tm_mday=lt->Day; + t.tm_mon=lt->Month-1; + t.tm_year=lt->Year-1900; + t.tm_isdst=-1; + + /* get the local time for Jan 2, 1900 00:00 UTC */ + time_t zero = 24*60*60L; + struct tm *timeptr = localtime( &zero ); + int gmtime_hours = timeptr->tm_hour; + + /* if the local time is the "day before" the UTC, subtract 24 hours + from the hours to get the UTC offset */ + if( timeptr->tm_mday < 2 ) + gmtime_hours -= 24; + + *this=mktime(&t)+gmtime_hours*3600; + itime+=lt->Reminder; + +#endif +} + + // Return the stored time as 64-bit number of 100-nanosecond intervals since // 01.01.1601. Actually we do not care since which date this time starts from // as long as this date is the same for GetRaw and SetRaw. We use the value @@ -216,7 +262,7 @@ void RarTime::SetDos(uint DosTime) #if !defined(GUI) || !defined(SFX_MODULE) -void RarTime::GetText(wchar *DateStr,size_t MaxSize,bool FullYear,bool FullMS) +void RarTime::GetText(wchar *DateStr,size_t MaxSize,bool FullMS) { if (IsSet()) { @@ -225,15 +271,12 @@ void RarTime::GetText(wchar *DateStr,size_t MaxSize,bool FullYear,bool FullMS) if (FullMS) swprintf(DateStr,MaxSize,L"%u-%02u-%02u %02u:%02u:%02u,%03u",lt.Year,lt.Month,lt.Day,lt.Hour,lt.Minute,lt.Second,lt.Reminder/10000); else - if (FullYear) - swprintf(DateStr,MaxSize,L"%02u-%02u-%u %02u:%02u",lt.Day,lt.Month,lt.Year,lt.Hour,lt.Minute); - else - swprintf(DateStr,MaxSize,L"%02u-%02u-%02u %02u:%02u",lt.Day,lt.Month,lt.Year%100,lt.Hour,lt.Minute); + swprintf(DateStr,MaxSize,L"%u-%02u-%02u %02u:%02u",lt.Year,lt.Month,lt.Day,lt.Hour,lt.Minute); } else { // We use escape before '?' to avoid weird C trigraph characters. - wcscpy(DateStr,FullYear ? L"\?\?-\?\?-\?\?\?\? \?\?:\?\?":L"\?\?-\?\?-\?\? \?\?:\?\?"); + wcscpy(DateStr,L"\?\?\?\?-\?\?-\?\? \?\?:\?\?"); } } #endif diff --git a/src/thirdparty/unrar/timefn.hpp b/src/thirdparty/unrar/timefn.hpp index 355baaf74..e9d775866 100644 --- a/src/thirdparty/unrar/timefn.hpp +++ b/src/thirdparty/unrar/timefn.hpp @@ -17,6 +17,8 @@ struct RarLocalTime class RarTime { + public: + static const uint TICKS_PER_SECOND = 10000000; // Raw time items per second. private: // Internal FILETIME like time representation in 100 nanoseconds // since 01.01.1601. @@ -39,11 +41,12 @@ class RarTime bool operator >= (RarTime &rt) {return itime>rt.itime || itime==rt.itime;} void GetLocal(RarLocalTime *lt); void SetLocal(RarLocalTime *lt); + void SetUTC(RarLocalTime *lt); uint64 GetRaw(); void SetRaw(uint64 RawTime); uint GetDos(); void SetDos(uint DosTime); - void GetText(wchar *DateStr,size_t MaxSize,bool FullYear,bool FullMS); + void GetText(wchar *DateStr,size_t MaxSize,bool FullMS); void SetIsoText(const wchar *TimeText); void SetAgeText(const wchar *TimeText); void SetCurrentTime(); diff --git a/src/thirdparty/unrar/uiconsole.cpp b/src/thirdparty/unrar/uiconsole.cpp index ba7550c6b..d1457fcd8 100644 --- a/src/thirdparty/unrar/uiconsole.cpp +++ b/src/thirdparty/unrar/uiconsole.cpp @@ -6,8 +6,8 @@ UIASKREP_RESULT uiAskReplace(wchar *Name,size_t MaxNameSize,int64 FileSize,RarTi FindData ExistingFD; memset(&ExistingFD,0,sizeof(ExistingFD)); // In case find fails. FindFile::FastFind(Name,&ExistingFD); - itoa(ExistingFD.Size,SizeText1); - ExistingFD.mtime.GetText(DateStr1,ASIZE(DateStr1),true,false); + itoa(ExistingFD.Size,SizeText1,ASIZE(SizeText1)); + ExistingFD.mtime.GetText(DateStr1,ASIZE(DateStr1),false); if (FileSize==INT64NDF || FileTime==NULL) { @@ -16,8 +16,8 @@ UIASKREP_RESULT uiAskReplace(wchar *Name,size_t MaxNameSize,int64 FileSize,RarTi } else { - itoa(FileSize,SizeText2); - FileTime->GetText(DateStr2,ASIZE(DateStr2),true,false); + itoa(FileSize,SizeText2,ASIZE(SizeText2)); + FileTime->GetText(DateStr2,ASIZE(DateStr2),false); eprintf(St(MAskReplace),Name,SizeText1,DateStr1,SizeText2,DateStr2); } @@ -135,6 +135,7 @@ void uiMsgStore::Msg() break; case UIERROR_FILECOPYHINT: Log(Str[0],St(MCopyErrorHint)); + mprintf(L" "); // For progress percent. break; case UIERROR_DIRCREATE: Log(Str[0],St(MExtrErrMkDir),Str[1]); @@ -342,14 +343,15 @@ void uiAlarm(UIALARM_TYPE Type) { if (uiSoundEnabled) { - static clock_t LastTime=clock(); - if ((clock()-LastTime)/CLOCKS_PER_SEC>5) + static clock_t LastTime=-10; // Negative to always beep first time. + if ((MonoClock()-LastTime)/CLOCKS_PER_SEC>5) { #ifdef _WIN_ALL MessageBeep(-1); #else putwchar('\007'); #endif + LastTime=MonoClock(); } } } diff --git a/src/thirdparty/unrar/unicode.cpp b/src/thirdparty/unrar/unicode.cpp index 9c1080aa7..be3363293 100644 --- a/src/thirdparty/unrar/unicode.cpp +++ b/src/thirdparty/unrar/unicode.cpp @@ -359,7 +359,7 @@ bool UtfToWide(const char *Src,wchar *Dest,size_t DestSize) continue; } if (Dest!=NULL) - if (sizeof(*Dest)==2) // Use the surrogate pair for 2 byte Unicode. + if (sizeof(*Dest)==2) // Use the surrogate pair. { *(Dest++)=((d-0x10000)>>10)+0xd800; *(Dest++)=(d&0x3ff)+0xdc00; @@ -380,7 +380,7 @@ bool UtfToWide(const char *Src,wchar *Dest,size_t DestSize) int wcsicomp(const wchar *s1,const wchar *s2) { #ifdef _WIN_ALL - return CompareStringW(LOCALE_USER_DEFAULT,NORM_IGNORECASE|SORT_STRINGSORT,s1,-1,s2,-1)-2; + return CompareString(LOCALE_USER_DEFAULT,NORM_IGNORECASE|SORT_STRINGSORT,s1,-1,s2,-1)-2; #else while (true) { @@ -476,7 +476,7 @@ int toupperw(int ch) // CharUpper is more reliable than towupper in Windows, which seems to be // C locale dependent even in Unicode version. For example, towupper failed // to convert lowercase Russian characters. - return (int)CharUpper((wchar *)ch); + return (int)(INT_PTR)CharUpper((wchar *)(INT_PTR)ch); #else return towupper(ch); #endif @@ -488,7 +488,7 @@ int tolowerw(int ch) #ifdef _WIN_ALL // CharLower is more reliable than towlower in Windows. // See comment for towupper above. - return (int)CharLower((wchar *)ch); + return (int)(INT_PTR)CharLower((wchar *)(INT_PTR)ch); #else return towlower(ch); #endif diff --git a/src/thirdparty/unrar/unpack.cpp b/src/thirdparty/unrar/unpack.cpp index a7f19805c..9b4c8540e 100644 --- a/src/thirdparty/unrar/unpack.cpp +++ b/src/thirdparty/unrar/unpack.cpp @@ -47,7 +47,7 @@ Unpack::Unpack(ComprDataIO *DataIO) Unpack::~Unpack() { - InitFilters30(); + InitFilters30(false); if (Window!=NULL) free(Window); @@ -114,7 +114,7 @@ void Unpack::Init(size_t WinSize,bool Solid) if (!Fragmented) { // Clean the window to generate the same output when unpacking corrupt - // RAR files, which may access to unused areas of sliding dictionary. + // RAR files, which may access unused areas of sliding dictionary. memset(NewWindow,0,WinSize); // If Window is not NULL, it means that window size has grown. @@ -122,7 +122,7 @@ void Unpack::Init(size_t WinSize,bool Solid) // RAR archiving code does not allow it in solid streams now, // but let's implement it anyway just in case we'll change it sometimes. if (Grow) - for (size_t I=1;I<MaxWinSize;I++) + for (size_t I=1;I<=MaxWinSize;I++) NewWindow[(UnpPtr-I)&(WinSize-1)]=Window[(UnpPtr-I)&(MaxWinSize-1)]; if (Window!=NULL) @@ -137,21 +137,27 @@ void Unpack::Init(size_t WinSize,bool Solid) void Unpack::DoUnpack(int Method,bool Solid) { + // Methods <50 will crash in Fragmented mode when accessing NULL Window. + // They cannot be called in such mode now, but we check it below anyway + // just for extra safety. switch(Method) { #ifndef SFX_MODULE case 15: // rar 1.5 compression - Unpack15(Solid); + if (!Fragmented) + Unpack15(Solid); break; case 20: // rar 2.x compression case 26: // files larger than 2GB - Unpack20(Solid); + if (!Fragmented) + Unpack20(Solid); break; #endif case 29: // rar 3.x compression - Unpack29(Solid); + if (!Fragmented) + Unpack29(Solid); break; - case 0: // RAR 5.0 compression algorithm 0. + case 50: // RAR 5.0 compression algorithm. #ifdef RAR_SMP if (MaxUserThreads>1) { @@ -184,9 +190,11 @@ void Unpack::UnpInitData(bool Solid) memset(&BlockTables,0,sizeof(BlockTables)); UnpPtr=WrPtr=0; WriteBorder=Min(MaxWinSize,UNPACK_MAX_WRITE)&MaxWinMask; - - InitFilters(); } + // Filters never share several solid files, so we can safely reset them + // even in solid archive. + InitFilters(); + Inp.InitBitInput(); WrittenFileSize=0; ReadTop=0; @@ -311,7 +319,7 @@ void Unpack::MakeDecodeTables(byte *LengthTable,DecodeTable *Dec,uint Size) // Find the upper limit for current bit field and adjust the bit length // accordingly if necessary. - while (BitField>=Dec->DecodeLen[CurBitLength] && CurBitLength<ASIZE(Dec->DecodeLen)) + while (CurBitLength<ASIZE(Dec->DecodeLen) && BitField>=Dec->DecodeLen[CurBitLength]) CurBitLength++; // Translation of right aligned bit string to bit length. diff --git a/src/thirdparty/unrar/unpack.hpp b/src/thirdparty/unrar/unpack.hpp index 2c0ed48dd..d47ce4324 100644 --- a/src/thirdparty/unrar/unpack.hpp +++ b/src/thirdparty/unrar/unpack.hpp @@ -4,13 +4,17 @@ // Maximum allowed number of compressed bits processed in quick mode. #define MAX_QUICK_DECODE_BITS 10 -// Maximum number of filters per entire data block. +// Maximum number of filters per entire data block. Must be at least +// twice more than MAX_PACK_FILTERS to store filters from two data blocks. #define MAX_UNPACK_FILTERS 8192 // Maximum number of filters per entire data block for RAR3 unpack. -#define MAX3_FILTERS 1024 +// Must be at least twice more than v3_MAX_PACK_FILTERS to store filters +// from two data blocks. +#define MAX3_UNPACK_FILTERS 8192 -// Write data in 4 MB or smaller blocks. +// Write data in 4 MB or smaller blocks. Must not exceed PACK_MAX_WRITE, +// so we keep number of buffered filter in unpacker reasonable. #define UNPACK_MAX_WRITE 0x400000 // Decode compressed bit fields to alphabet numbers. @@ -146,7 +150,7 @@ struct UnpackFilter30 unsigned int ExecCount; bool NextWindow; - // position of parent filter in Filters array used as prototype for filter + // 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; @@ -309,7 +313,7 @@ class Unpack:PackDef void UnpInitData30(bool Solid); void Unpack29(bool Solid); - void InitFilters30(); + void InitFilters30(bool Solid); bool ReadEndOfBlock(); bool ReadVMCode(); bool ReadVMCodePPM(); diff --git a/src/thirdparty/unrar/unpack15.cpp b/src/thirdparty/unrar/unpack15.cpp index 131d2665c..0bcb31454 100644 --- a/src/thirdparty/unrar/unpack15.cpp +++ b/src/thirdparty/unrar/unpack15.cpp @@ -401,6 +401,14 @@ void Unpack::GetFlagsBuf() unsigned int Flags,NewFlagsPlace; unsigned int FlagsPlace=DecodeNum(Inp.fgetbits(),STARTHF2,DecHf2,PosHf2); + // Our Huffman table stores 257 items and needs all them in other parts + // of code such as when StMode is on, so the first item is control item. + // While normally we do not use the last item to code the flags byte here, + // we need to check for value 256 when unpacking in case we unpack + // a corrupt archive. + if (FlagsPlace>=sizeof(ChSetC)/sizeof(ChSetC[0])) + return; + while (1) { Flags=ChSetC[FlagsPlace]; diff --git a/src/thirdparty/unrar/unpack30.cpp b/src/thirdparty/unrar/unpack30.cpp index 980df0244..c5b72e2cb 100644 --- a/src/thirdparty/unrar/unpack30.cpp +++ b/src/thirdparty/unrar/unpack30.cpp @@ -310,11 +310,11 @@ bool Unpack::ReadVMCode() // Try to read the new buffer if only one byte is left. // But if we read all bytes except the last, one byte is enough. if (Inp.InAddr>=ReadTop-1 && !UnpReadBuf30() && I<Length-1) - return(false); + return false; VMCode[I]=Inp.getbits()>>8; Inp.addbits(8); } - return(AddVMCode(FirstByte,&VMCode[0],Length)); + return AddVMCode(FirstByte,&VMCode[0],Length); } @@ -322,7 +322,7 @@ bool Unpack::ReadVMCodePPM() { unsigned int FirstByte=SafePPMDecodeChar(); if ((int)FirstByte==-1) - return(false); + return false; int Length=(FirstByte & 7)+1; if (Length==7) { @@ -336,10 +336,10 @@ bool Unpack::ReadVMCodePPM() { int B1=SafePPMDecodeChar(); if (B1==-1) - return(false); + return false; int B2=SafePPMDecodeChar(); if (B2==-1) - return(false); + return false; Length=B1*256+B2; } Array<byte> VMCode(Length); @@ -350,7 +350,7 @@ bool Unpack::ReadVMCodePPM() return(false); VMCode[I]=Ch; } - return(AddVMCode(FirstByte,&VMCode[0],Length)); + return AddVMCode(FirstByte,&VMCode[0],Length); } @@ -361,11 +361,11 @@ bool Unpack::AddVMCode(uint FirstByte,byte *Code,int CodeSize) VM.Init(); uint FiltPos; - if (FirstByte & 0x80) + if ((FirstByte & 0x80)!=0) { FiltPos=RarVM::ReadData(VMCodeInp); if (FiltPos==0) - InitFilters30(); + InitFilters30(false); else FiltPos--; } @@ -373,7 +373,7 @@ bool Unpack::AddVMCode(uint FirstByte,byte *Code,int CodeSize) FiltPos=LastFilter; // Use the same filter as last time. if (FiltPos>Filters30.Size() || FiltPos>OldFilterLengths.Size()) - return(false); + return false; LastFilter=FiltPos; bool NewFilter=(FiltPos==Filters30.Size()); @@ -382,7 +382,7 @@ bool Unpack::AddVMCode(uint FirstByte,byte *Code,int CodeSize) UnpackFilter30 *Filter; if (NewFilter) // New filter code, never used before since VM reset. { - if (FiltPos>MAX3_FILTERS) + if (FiltPos>MAX3_UNPACK_FILTERS) { // Too many different filters, corrupt archive. delete StackFilter; @@ -418,6 +418,11 @@ bool Unpack::AddVMCode(uint FirstByte,byte *Code,int CodeSize) } if (EmptyCount==0) { + if (PrgStack.Size()>MAX3_UNPACK_FILTERS) + { + delete StackFilter; + return false; + } PrgStack.Add(1); EmptyCount=1; } @@ -426,10 +431,10 @@ bool Unpack::AddVMCode(uint FirstByte,byte *Code,int CodeSize) StackFilter->ExecCount=Filter->ExecCount; uint BlockStart=RarVM::ReadData(VMCodeInp); - if (FirstByte & 0x40) + if ((FirstByte & 0x40)!=0) BlockStart+=258; StackFilter->BlockStart=(uint)((BlockStart+UnpPtr)&MaxWinMask); - if (FirstByte & 0x20) + if ((FirstByte & 0x20)!=0) { StackFilter->BlockLength=RarVM::ReadData(VMCodeInp); @@ -454,9 +459,9 @@ bool Unpack::AddVMCode(uint FirstByte,byte *Code,int CodeSize) StackFilter->Prg.InitR[4]=StackFilter->BlockLength; StackFilter->Prg.InitR[5]=StackFilter->ExecCount; - if (FirstByte & 0x10) // set registers to optional parameters if any + if ((FirstByte & 0x10)!=0) // Set registers to optional parameters if any. { - unsigned int InitMask=VMCodeInp.fgetbits()>>9; + uint InitMask=VMCodeInp.fgetbits()>>9; VMCodeInp.faddbits(7); for (int I=0;I<7;I++) if (InitMask & (1<<I)) @@ -467,12 +472,12 @@ bool Unpack::AddVMCode(uint FirstByte,byte *Code,int CodeSize) { uint VMCodeSize=RarVM::ReadData(VMCodeInp); if (VMCodeSize>=0x10000 || VMCodeSize==0) - return(false); + return false; Array<byte> VMCode(VMCodeSize); for (uint I=0;I<VMCodeSize;I++) { if (VMCodeInp.Overflow(3)) - return(false); + return false; VMCode[I]=VMCodeInp.fgetbits()>>8; VMCodeInp.faddbits(8); } @@ -502,13 +507,13 @@ bool Unpack::AddVMCode(uint FirstByte,byte *Code,int CodeSize) VM.SetLowEndianValue((uint *)&GlobalData[0x2c],StackFilter->ExecCount); memset(&GlobalData[0x30],0,16); - if (FirstByte & 8) // Put the data block passed as parameter if any. + if ((FirstByte & 8)!=0) // Put the data block passed as parameter if any. { if (VMCodeInp.Overflow(3)) - return(false); + return false; uint DataSize=RarVM::ReadData(VMCodeInp); if (DataSize>VM_GLOBALMEMSIZE-VM_FIXEDGLOBALSIZE) - return(false); + return false; size_t CurSize=StackFilter->Prg.GlobalData.Size(); if (CurSize<DataSize+VM_FIXEDGLOBALSIZE) StackFilter->Prg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize); @@ -516,12 +521,12 @@ bool Unpack::AddVMCode(uint FirstByte,byte *Code,int CodeSize) for (uint I=0;I<DataSize;I++) { if (VMCodeInp.Overflow(3)) - return(false); + return false; GlobalData[I]=VMCodeInp.fgetbits()>>8; VMCodeInp.faddbits(8); } } - return(true); + return true; } @@ -529,7 +534,7 @@ bool Unpack::UnpReadBuf30() { int DataSize=ReadTop-Inp.InAddr; // Data left to process. if (DataSize<0) - return(false); + return false; if (Inp.InAddr>BitInput::MAX_SIZE/2) { // If we already processed more than half of buffer, let's move @@ -549,7 +554,7 @@ bool Unpack::UnpReadBuf30() if (ReadCode>0) ReadTop+=ReadCode; ReadBorder=ReadTop-30; - return(ReadCode!=-1); + return ReadCode!=-1; } @@ -625,6 +630,7 @@ void Unpack::UnpWriteBuf30() while (I+1<PrgStack.Size()) { UnpackFilter30 *NextFilter=PrgStack[I+1]; + // It is required to check NextWindow here. if (NextFilter==NULL || NextFilter->BlockStart!=BlockStart || NextFilter->BlockLength!=FilteredDataSize || NextFilter->NextWindow) break; @@ -816,21 +822,23 @@ void Unpack::UnpInitData30(bool Solid) memset(UnpOldTable,0,sizeof(UnpOldTable)); PPMEscChar=2; UnpBlockType=BLOCK_LZ; - - InitFilters30(); } + InitFilters30(Solid); } -void Unpack::InitFilters30() +void Unpack::InitFilters30(bool Solid) { - OldFilterLengths.Reset(); - LastFilter=0; + if (!Solid) + { + OldFilterLengths.SoftReset(); + LastFilter=0; - for (size_t I=0;I<Filters30.Size();I++) - delete Filters30[I]; - Filters30.Reset(); + for (size_t I=0;I<Filters30.Size();I++) + delete Filters30[I]; + Filters30.SoftReset(); + } for (size_t I=0;I<PrgStack.Size();I++) delete PrgStack[I]; - PrgStack.Reset(); + PrgStack.SoftReset(); } diff --git a/src/thirdparty/unrar/unpack50.cpp b/src/thirdparty/unrar/unpack50.cpp index 7821a3e6b..894e3495f 100644 --- a/src/thirdparty/unrar/unpack50.cpp +++ b/src/thirdparty/unrar/unpack50.cpp @@ -189,11 +189,15 @@ bool Unpack::ReadFilter(BitInput &Inp,UnpackFilter &Filter) bool Unpack::AddFilter(UnpackFilter &Filter) { - if (Filters.Size()>=MAX_UNPACK_FILTERS-1) + if (Filters.Size()>=MAX_UNPACK_FILTERS) + { UnpWriteBuf(); // Write data, apply and flush filters. + if (Filters.Size()>=MAX_UNPACK_FILTERS) + InitFilters(); // Still too many filters, prevent excessive memory use. + } // If distance to filter start is that large that due to circular dictionary - // mode it points to old not written yet data, then we set 'NextWindow' + // mode now it points to old not written yet data, then we set 'NextWindow' // flag and process this filter only after processing that older data. Filter.NextWindow=WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MaxWinMask)<=Filter.BlockStart; @@ -250,7 +254,7 @@ void Unpack::UnpWriteBuf() for (size_t I=0;I<Filters.Size();I++) { // Here we apply filters to data which we need to write. - // We always copy data to virtual machine memory before processing. + // We always copy data to another memory block before processing. // We cannot process them just in place in Window buffer, because // these data can be used for future string matches, so we must // preserve them in original form. @@ -261,7 +265,7 @@ void Unpack::UnpWriteBuf() if (flt->NextWindow) { // Here we skip filters which have block start in current data range - // due to address warp around in circular dictionary, but actually + // due to address wrap around in circular dictionary, but actually // belong to next dictionary block. If such filter start position // is included to current write range, then we reset 'NextWindow' flag. // In fact we can reset it even without such check, because current @@ -372,7 +376,8 @@ void Unpack::UnpWriteBuf() } // We prefer to write data in blocks not exceeding UNPACK_MAX_WRITE - // instead of potentially huge MaxWinSize blocks. + // instead of potentially huge MaxWinSize blocks. It also allows us + // to keep the size of Filters array reasonable. WriteBorder=(UnpPtr+Min(MaxWinSize,UNPACK_MAX_WRITE))&MaxWinMask; // Choose the nearest among WriteBorder and WrPtr actual written border. @@ -644,5 +649,5 @@ bool Unpack::ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTable void Unpack::InitFilters() { - Filters.Reset(); + Filters.SoftReset(); } diff --git a/src/thirdparty/unrar/unpack50mt.cpp b/src/thirdparty/unrar/unpack50mt.cpp index 9925cf2b8..ce31f0a32 100644 --- a/src/thirdparty/unrar/unpack50mt.cpp +++ b/src/thirdparty/unrar/unpack50mt.cpp @@ -43,6 +43,7 @@ void Unpack::InitMT() { // Typical number of items in RAR blocks does not exceed 0x4000. CurData->DecodedAllocated=0x4100; + // It will be freed in the object destructor, not in this file. CurData->Decoded=(UnpackDecodedItem *)malloc(CurData->DecodedAllocated*sizeof(UnpackDecodedItem)); if (CurData->Decoded==NULL) ErrHandler.MemoryError(); @@ -96,7 +97,6 @@ void Unpack::Unpack5MT(bool Solid) if (ReadSize>0 && DataSize<TooSmallToProcess) continue; - bool BufferProcessed=false; while (BlockStart<DataSize && !Done) { uint BlockNumber=0,BlockNumberMT=0; @@ -275,6 +275,7 @@ void Unpack::Unpack5MT(bool Solid) } } } + UnpPtr&=MaxWinMask; // ProcessDecoded and maybe others can leave UnpPtr > MaxWinMask here. UnpWriteBuf(); BlockHeader=UnpThreadData[LastBlockNum].BlockHeader; @@ -328,9 +329,10 @@ void Unpack::UnpackDecode(UnpackThreadData &D) if (D.DecodedSize>D.DecodedAllocated-8) // Filter can use several slots. { D.DecodedAllocated=D.DecodedAllocated*2; - D.Decoded=(UnpackDecodedItem *)realloc(D.Decoded,D.DecodedAllocated*sizeof(UnpackDecodedItem)); - if (D.Decoded==NULL) - ErrHandler.MemoryError(); + void *Decoded=realloc(D.Decoded,D.DecodedAllocated*sizeof(UnpackDecodedItem)); + if (Decoded==NULL) + ErrHandler.MemoryError(); // D.Decoded will be freed in the destructor. + D.Decoded=(UnpackDecodedItem *)Decoded; } UnpackDecodedItem *CurItem=D.Decoded+D.DecodedSize++; diff --git a/src/thirdparty/unrar/unpackinline.cpp b/src/thirdparty/unrar/unpackinline.cpp index 70b533dbb..1dc6980c5 100644 --- a/src/thirdparty/unrar/unpackinline.cpp +++ b/src/thirdparty/unrar/unpackinline.cpp @@ -44,6 +44,11 @@ _forceinline void Unpack::CopyString(uint Length,uint Distance) else while (Length>=8) { + // In theory we still could overlap here. + // Supposing Distance == MaxWinSize - 1 we have memcpy(Src, Src + 1, 8). + // But for real RAR archives Distance <= MaxWinSize - MAX_LZ_MATCH + // always, so overlap here is impossible. + // This memcpy expanded inline by MSVC. We could also use uint64 // assignment, which seems to provide about the same speed. memcpy(Dest,Src,8); diff --git a/src/thirdparty/unrar/unrar.vcxproj b/src/thirdparty/unrar/unrar.vcxproj index 88eede44a..ff6457293 100644 --- a/src/thirdparty/unrar/unrar.vcxproj +++ b/src/thirdparty/unrar/unrar.vcxproj @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?>
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
@@ -25,65 +25,20 @@ </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="..\..\platform.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <CharacterSet>MultiByte</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <CharacterSet>MultiByte</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
- <ConfigurationType>StaticLibrary</ConfigurationType>
- <CharacterSet>MultiByte</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- <Import Project="..\..\common.props" />
- <Import Project="..\..\common-3rd-party.props" />
- </ImportGroup>
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- <Import Project="..\..\common.props" />
- <Import Project="..\..\common-3rd-party.props" />
- </ImportGroup>
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- <Import Project="..\..\common.props" />
- <Import Project="..\..\common-3rd-party.props" />
- </ImportGroup>
- <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\common.props" />
<Import Project="..\..\common-3rd-party.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
- <PreprocessorDefinitions>_LIB;RARDLL;SILENT;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ClCompile>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
- <ClCompile>
- <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
- <PreprocessorDefinitions>_LIB;RARDLL;SILENT;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ClCompile>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
- <PreprocessorDefinitions>_LIB;RARDLL;SILENT;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- </ClCompile>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ItemDefinitionGroup>
<ClCompile>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<PreprocessorDefinitions>_LIB;RARDLL;SILENT;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
diff --git a/src/thirdparty/unrar/unrar.vcxproj.filters b/src/thirdparty/unrar/unrar.vcxproj.filters index fa5898820..b03c6d792 100644 --- a/src/thirdparty/unrar/unrar.vcxproj.filters +++ b/src/thirdparty/unrar/unrar.vcxproj.filters @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
diff --git a/src/thirdparty/unrar/version.hpp b/src/thirdparty/unrar/version.hpp index 8518b5516..f9085307c 100644 --- a/src/thirdparty/unrar/version.hpp +++ b/src/thirdparty/unrar/version.hpp @@ -1,6 +1,6 @@ #define RARVER_MAJOR 5 -#define RARVER_MINOR 21 +#define RARVER_MINOR 40 #define RARVER_BETA 0 #define RARVER_DAY 15 -#define RARVER_MONTH 2 -#define RARVER_YEAR 2015 +#define RARVER_MONTH 8 +#define RARVER_YEAR 2016 diff --git a/src/thirdparty/unrar/volume.cpp b/src/thirdparty/unrar/volume.cpp index 8e317ba3f..f0d010fd2 100644 --- a/src/thirdparty/unrar/volume.cpp +++ b/src/thirdparty/unrar/volume.cpp @@ -247,7 +247,8 @@ bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize) // We quit only on 'abort' condition, but not on 'name not changed'. // It is legitimate for program to return the same name when waiting // for currently non-existent volume. - if (DllVolAborted) + // Also we quit to prevent an infinite loop if no callback is defined. + if (DllVolAborted || Cmd->Callback==NULL && Cmd->ChangeVolProc==NULL) { Cmd->DllError=ERAR_EOPEN; return false; diff --git a/src/thirdparty/unrar/win32acl.cpp b/src/thirdparty/unrar/win32acl.cpp index 315d4db57..44d0bfa45 100644 --- a/src/thirdparty/unrar/win32acl.cpp +++ b/src/thirdparty/unrar/win32acl.cpp @@ -49,7 +49,7 @@ void ExtractACL20(Archive &Arc,const wchar *FileName) si|=SACL_SECURITY_INFORMATION; SECURITY_DESCRIPTOR *sd=(SECURITY_DESCRIPTOR *)&UnpData[0]; - int SetCode=SetFileSecurityW(FileName,si,sd); + int SetCode=SetFileSecurity(FileName,si,sd); if (!SetCode) { diff --git a/src/thirdparty/unrar/win32lnk.cpp b/src/thirdparty/unrar/win32lnk.cpp index b291056f0..71c20b95e 100644 --- a/src/thirdparty/unrar/win32lnk.cpp +++ b/src/thirdparty/unrar/win32lnk.cpp @@ -62,7 +62,11 @@ bool CreateReparsePoint(CommandData *Cmd,const wchar *Name,FileHeader *hd) size_t PrintLength=wcslen(PrintName); bool AbsPath=WinPrefix; - if (!Cmd->AbsoluteLinks && (AbsPath || !IsRelativeSymlinkSafe(hd->FileName,hd->RedirName))) + // IsFullPath is not really needed here, AbsPath check is enough. + // We added it just for extra safety, in case some Windows version would + // allow to create absolute targets with SYMLINK_FLAG_RELATIVE. + if (!Cmd->AbsoluteLinks && (AbsPath || IsFullPath(hd->RedirName) || + !IsRelativeSymlinkSafe(hd->FileName,hd->RedirName))) return false; CreatePath(Name,true); diff --git a/src/thirdparty/unrar/win32stm.cpp b/src/thirdparty/unrar/win32stm.cpp index edcd7b5fa..9e24c13ec 100644 --- a/src/thirdparty/unrar/win32stm.cpp +++ b/src/thirdparty/unrar/win32stm.cpp @@ -78,7 +78,7 @@ void ExtractStreams20(Archive &Arc,const wchar *FileName) #ifdef _WIN_ALL -void ExtractStreams(Archive &Arc,const wchar *FileName) +void ExtractStreams(Archive &Arc,const wchar *FileName,bool TestMode) { wchar FullName[NM+2]; if (FileName[0]!=0 && FileName[1]==0) @@ -89,9 +89,6 @@ void ExtractStreams(Archive &Arc,const wchar *FileName) else wcsncpyz(FullName,FileName,ASIZE(FullName)); - byte *Data=&Arc.SubHead.SubData[0]; - size_t DataSize=Arc.SubHead.SubData.Size(); - wchar StreamName[NM]; GetStreamNameNTFS(Arc,StreamName,ASIZE(StreamName)); if (*StreamName!=':') @@ -101,6 +98,12 @@ void ExtractStreams(Archive &Arc,const wchar *FileName) return; } + if (TestMode) + { + Arc.ReadSubData(NULL,NULL); + return; + } + wcsncatz(FullName,StreamName,ASIZE(FullName)); FindData fd; |