Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mpc-hc/mpc-hc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/thirdparty/unrar')
-rw-r--r--src/thirdparty/unrar/archive.cpp15
-rw-r--r--src/thirdparty/unrar/archive.hpp2
-rw-r--r--src/thirdparty/unrar/arcread.cpp52
-rw-r--r--src/thirdparty/unrar/blake2s.cpp2
-rw-r--r--src/thirdparty/unrar/cmddata.cpp84
-rw-r--r--src/thirdparty/unrar/cmddata.hpp2
-rw-r--r--src/thirdparty/unrar/consio.cpp96
-rw-r--r--src/thirdparty/unrar/consio.hpp2
-rw-r--r--src/thirdparty/unrar/crc.cpp22
-rw-r--r--src/thirdparty/unrar/dll.cpp13
-rw-r--r--src/thirdparty/unrar/dll.hpp8
-rw-r--r--src/thirdparty/unrar/dll.rc12
-rw-r--r--src/thirdparty/unrar/errhnd.cpp16
-rw-r--r--src/thirdparty/unrar/errhnd.hpp7
-rw-r--r--src/thirdparty/unrar/extinfo.cpp8
-rw-r--r--src/thirdparty/unrar/extract.cpp164
-rw-r--r--src/thirdparty/unrar/extract.hpp2
-rw-r--r--src/thirdparty/unrar/filcreat.cpp12
-rw-r--r--src/thirdparty/unrar/file.cpp25
-rw-r--r--src/thirdparty/unrar/file.hpp1
-rw-r--r--src/thirdparty/unrar/filefn.cpp26
-rw-r--r--src/thirdparty/unrar/filefn.hpp2
-rw-r--r--src/thirdparty/unrar/filestr.cpp48
-rw-r--r--src/thirdparty/unrar/getbits.cpp2
-rw-r--r--src/thirdparty/unrar/getbits.hpp6
-rw-r--r--src/thirdparty/unrar/hash.cpp21
-rw-r--r--src/thirdparty/unrar/hash.hpp2
-rw-r--r--src/thirdparty/unrar/headers.hpp4
-rw-r--r--src/thirdparty/unrar/isnt.cpp2
-rw-r--r--src/thirdparty/unrar/isnt.hpp3
-rw-r--r--src/thirdparty/unrar/list.cpp62
-rw-r--r--src/thirdparty/unrar/loclang.hpp14
-rw-r--r--src/thirdparty/unrar/options.hpp6
-rw-r--r--src/thirdparty/unrar/pathfn.cpp81
-rw-r--r--src/thirdparty/unrar/pathfn.hpp4
-rw-r--r--src/thirdparty/unrar/rar.cpp6
-rw-r--r--src/thirdparty/unrar/rardefs.hpp4
-rw-r--r--src/thirdparty/unrar/raros.hpp2
-rw-r--r--src/thirdparty/unrar/rdwrfn.cpp23
-rw-r--r--src/thirdparty/unrar/rdwrfn.hpp7
-rw-r--r--src/thirdparty/unrar/recvol.cpp75
-rw-r--r--src/thirdparty/unrar/recvol.hpp7
-rw-r--r--src/thirdparty/unrar/recvol3.cpp99
-rw-r--r--src/thirdparty/unrar/recvol5.cpp77
-rw-r--r--src/thirdparty/unrar/rs16.cpp2
-rw-r--r--src/thirdparty/unrar/rs16.hpp2
-rw-r--r--src/thirdparty/unrar/scantree.cpp165
-rw-r--r--src/thirdparty/unrar/scantree.hpp23
-rw-r--r--src/thirdparty/unrar/secpassword.cpp2
-rw-r--r--src/thirdparty/unrar/smallfn.cpp4
-rw-r--r--src/thirdparty/unrar/strfn.cpp65
-rw-r--r--src/thirdparty/unrar/strfn.hpp8
-rw-r--r--src/thirdparty/unrar/suballoc.cpp2
-rw-r--r--src/thirdparty/unrar/suballoc.hpp1
-rw-r--r--src/thirdparty/unrar/system.cpp54
-rw-r--r--src/thirdparty/unrar/system.hpp4
-rw-r--r--src/thirdparty/unrar/threadmisc.cpp24
-rw-r--r--src/thirdparty/unrar/timefn.cpp57
-rw-r--r--src/thirdparty/unrar/timefn.hpp5
-rw-r--r--src/thirdparty/unrar/uiconsole.cpp14
-rw-r--r--src/thirdparty/unrar/unicode.cpp8
-rw-r--r--src/thirdparty/unrar/unpack.cpp28
-rw-r--r--src/thirdparty/unrar/unpack.hpp14
-rw-r--r--src/thirdparty/unrar/unpack15.cpp8
-rw-r--r--src/thirdparty/unrar/unpack30.cpp72
-rw-r--r--src/thirdparty/unrar/unpack50.cpp17
-rw-r--r--src/thirdparty/unrar/unpack50mt.cpp10
-rw-r--r--src/thirdparty/unrar/unpackinline.cpp5
-rw-r--r--src/thirdparty/unrar/unrar.vcxproj53
-rw-r--r--src/thirdparty/unrar/unrar.vcxproj.filters2
-rw-r--r--src/thirdparty/unrar/version.hpp6
-rw-r--r--src/thirdparty/unrar/volume.cpp3
-rw-r--r--src/thirdparty/unrar/win32acl.cpp2
-rw-r--r--src/thirdparty/unrar/win32lnk.cpp6
-rw-r--r--src/thirdparty/unrar/win32stm.cpp11
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;