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:
authorXhmikosR <xhmikosr@users.sourceforge.net>2013-05-05 11:39:47 +0400
committerXhmikosR <xhmikosr@users.sourceforge.net>2013-05-06 02:56:22 +0400
commit00f8520475b119d50d40b8a4b2298f04afa821b9 (patch)
treee389319284c45b5305bb5156e1d8f8310849902a
parentb18faab4208d8368d28c7b51afe5a73bbc90b05e (diff)
update unrar to v5.0.2
-rw-r--r--docs/Changelog.txt1
-rw-r--r--include/unrar.h20
-rw-r--r--src/thirdparty/unrar/acknow.txt11
-rw-r--r--src/thirdparty/unrar/arccmt.cpp203
-rw-r--r--src/thirdparty/unrar/archive.cpp234
-rw-r--r--src/thirdparty/unrar/archive.hpp116
-rw-r--r--src/thirdparty/unrar/arcread.cpp1426
-rw-r--r--src/thirdparty/unrar/array.hpp58
-rw-r--r--src/thirdparty/unrar/beosea.cpp113
-rw-r--r--src/thirdparty/unrar/blake2s.cpp184
-rw-r--r--src/thirdparty/unrar/blake2s.hpp57
-rw-r--r--src/thirdparty/unrar/blake2s_sse.cpp105
-rw-r--r--src/thirdparty/unrar/blake2sp.cpp153
-rw-r--r--src/thirdparty/unrar/cmddata.cpp1202
-rw-r--r--src/thirdparty/unrar/cmddata.hpp51
-rw-r--r--src/thirdparty/unrar/compress.hpp35
-rw-r--r--src/thirdparty/unrar/consio.cpp347
-rw-r--r--src/thirdparty/unrar/consio.hpp37
-rw-r--r--src/thirdparty/unrar/crc.cpp49
-rw-r--r--src/thirdparty/unrar/crc.hpp13
-rw-r--r--src/thirdparty/unrar/crypt.cpp426
-rw-r--r--src/thirdparty/unrar/crypt.hpp104
-rw-r--r--src/thirdparty/unrar/crypt1.cpp82
-rw-r--r--src/thirdparty/unrar/crypt2.cpp195
-rw-r--r--src/thirdparty/unrar/crypt3.cpp90
-rw-r--r--src/thirdparty/unrar/crypt5.cpp195
-rw-r--r--src/thirdparty/unrar/dll.cpp257
-rw-r--r--src/thirdparty/unrar/dll.hpp20
-rw-r--r--src/thirdparty/unrar/dll.rc10
-rw-r--r--src/thirdparty/unrar/errhnd.cpp199
-rw-r--r--src/thirdparty/unrar/errhnd.hpp47
-rw-r--r--src/thirdparty/unrar/extinfo.cpp74
-rw-r--r--src/thirdparty/unrar/extinfo.hpp16
-rw-r--r--src/thirdparty/unrar/extract.cpp2086
-rw-r--r--src/thirdparty/unrar/extract.hpp24
-rw-r--r--src/thirdparty/unrar/filcreat.cpp164
-rw-r--r--src/thirdparty/unrar/filcreat.hpp9
-rw-r--r--src/thirdparty/unrar/file.cpp298
-rw-r--r--src/thirdparty/unrar/file.hpp49
-rw-r--r--src/thirdparty/unrar/filefn.cpp534
-rw-r--r--src/thirdparty/unrar/filefn.hpp40
-rw-r--r--src/thirdparty/unrar/filestr.cpp76
-rw-r--r--src/thirdparty/unrar/filestr.hpp3
-rw-r--r--src/thirdparty/unrar/find.cpp249
-rw-r--r--src/thirdparty/unrar/find.hpp18
-rw-r--r--src/thirdparty/unrar/getbits.cpp41
-rw-r--r--src/thirdparty/unrar/getbits.hpp21
-rw-r--r--src/thirdparty/unrar/global.hpp1
-rw-r--r--src/thirdparty/unrar/hardlinks.cpp34
-rw-r--r--src/thirdparty/unrar/hash.cpp128
-rw-r--r--src/thirdparty/unrar/hash.hpp52
-rw-r--r--src/thirdparty/unrar/headers.cpp62
-rw-r--r--src/thirdparty/unrar/headers.hpp271
-rw-r--r--src/thirdparty/unrar/headers5.hpp99
-rw-r--r--src/thirdparty/unrar/license.txt4
-rw-r--r--src/thirdparty/unrar/list.cpp542
-rw-r--r--src/thirdparty/unrar/loclang.hpp115
-rw-r--r--src/thirdparty/unrar/log.cpp31
-rw-r--r--src/thirdparty/unrar/log.hpp12
-rw-r--r--src/thirdparty/unrar/match.cpp165
-rw-r--r--src/thirdparty/unrar/match.hpp1
-rw-r--r--src/thirdparty/unrar/options.cpp10
-rw-r--r--src/thirdparty/unrar/options.hpp56
-rw-r--r--src/thirdparty/unrar/os.hpp84
-rw-r--r--src/thirdparty/unrar/os2ea.cpp94
-rw-r--r--src/thirdparty/unrar/pathfn.cpp1053
-rw-r--r--src/thirdparty/unrar/pathfn.hpp62
-rw-r--r--src/thirdparty/unrar/qopen.cpp272
-rw-r--r--src/thirdparty/unrar/qopen.hpp61
-rw-r--r--src/thirdparty/unrar/rar.cpp78
-rw-r--r--src/thirdparty/unrar/rar.hpp20
-rw-r--r--src/thirdparty/unrar/rardefs.hpp22
-rw-r--r--src/thirdparty/unrar/raros.hpp5
-rw-r--r--src/thirdparty/unrar/rartypes.hpp9
-rw-r--r--src/thirdparty/unrar/rarvm.cpp31
-rw-r--r--src/thirdparty/unrar/rarvm.hpp10
-rw-r--r--src/thirdparty/unrar/rawread.cpp144
-rw-r--r--src/thirdparty/unrar/rawread.hpp72
-rw-r--r--src/thirdparty/unrar/rdwrfn.cpp89
-rw-r--r--src/thirdparty/unrar/rdwrfn.hpp17
-rw-r--r--src/thirdparty/unrar/readme.txt34
-rw-r--r--src/thirdparty/unrar/recvol.cpp578
-rw-r--r--src/thirdparty/unrar/recvol.hpp76
-rw-r--r--src/thirdparty/unrar/recvol3.cpp513
-rw-r--r--src/thirdparty/unrar/recvol5.cpp461
-rw-r--r--src/thirdparty/unrar/resource.cpp10
-rw-r--r--src/thirdparty/unrar/resource.hpp6
-rw-r--r--src/thirdparty/unrar/rijndael.cpp95
-rw-r--r--src/thirdparty/unrar/rijndael.hpp10
-rw-r--r--src/thirdparty/unrar/rs.cpp22
-rw-r--r--src/thirdparty/unrar/rs16.cpp416
-rw-r--r--src/thirdparty/unrar/rs16.hpp42
-rw-r--r--src/thirdparty/unrar/savepos.cpp15
-rw-r--r--src/thirdparty/unrar/savepos.hpp12
-rw-r--r--src/thirdparty/unrar/scantree.cpp269
-rw-r--r--src/thirdparty/unrar/scantree.hpp17
-rw-r--r--src/thirdparty/unrar/secpassword.cpp109
-rw-r--r--src/thirdparty/unrar/secpassword.hpp3
-rw-r--r--src/thirdparty/unrar/sha256.cpp175
-rw-r--r--src/thirdparty/unrar/sha256.hpp22
-rw-r--r--src/thirdparty/unrar/smallfn.cpp25
-rw-r--r--src/thirdparty/unrar/strfn.cpp220
-rw-r--r--src/thirdparty/unrar/strfn.hpp25
-rw-r--r--src/thirdparty/unrar/strlist.cpp125
-rw-r--r--src/thirdparty/unrar/strlist.hpp26
-rw-r--r--src/thirdparty/unrar/system.cpp21
-rw-r--r--src/thirdparty/unrar/system.hpp8
-rw-r--r--src/thirdparty/unrar/threadmisc.cpp148
-rw-r--r--src/thirdparty/unrar/threadpool.cpp206
-rw-r--r--src/thirdparty/unrar/threadpool.hpp103
-rw-r--r--src/thirdparty/unrar/timefn.cpp322
-rw-r--r--src/thirdparty/unrar/timefn.hpp36
-rw-r--r--src/thirdparty/unrar/ulinks.cpp84
-rw-r--r--src/thirdparty/unrar/unicode.cpp359
-rw-r--r--src/thirdparty/unrar/unicode.hpp47
-rw-r--r--src/thirdparty/unrar/unios2.cpp128
-rw-r--r--src/thirdparty/unrar/unpack.cpp1058
-rw-r--r--src/thirdparty/unrar/unpack.hpp256
-rw-r--r--src/thirdparty/unrar/unpack15.cpp123
-rw-r--r--src/thirdparty/unrar/unpack20.cpp130
-rw-r--r--src/thirdparty/unrar/unpack30.cpp836
-rw-r--r--src/thirdparty/unrar/unpack50.cpp820
-rw-r--r--src/thirdparty/unrar/unpack50mt.cpp657
-rw-r--r--src/thirdparty/unrar/unpackinline.cpp140
-rw-r--r--src/thirdparty/unrar/unrar.vcxproj18
-rw-r--r--src/thirdparty/unrar/unrar.vcxproj.filters96
-rw-r--r--src/thirdparty/unrar/uowners.cpp89
-rw-r--r--src/thirdparty/unrar/version.hpp12
-rw-r--r--src/thirdparty/unrar/volume.cpp312
-rw-r--r--src/thirdparty/unrar/volume.hpp4
-rw-r--r--src/thirdparty/unrar/win32acl.cpp72
-rw-r--r--src/thirdparty/unrar/win32lnk.cpp232
-rw-r--r--src/thirdparty/unrar/win32stm.cpp126
133 files changed, 14014 insertions, 9183 deletions
diff --git a/docs/Changelog.txt b/docs/Changelog.txt
index 840fb9431..84318f25a 100644
--- a/docs/Changelog.txt
+++ b/docs/Changelog.txt
@@ -13,6 +13,7 @@ Legend:
* Updated Basque, German, Greek, Japanese, Simplified and Traditional Chinese translations
* Updated Little CMS to v2.5 (git 61d73f8)
* Updated zlib to v1.2.8
+* Updated Unrar to v5.0.2
* Audio Switcher improvements:
- Ticket #1936, Improve the normalization algorithm to avoid huge volume variations
- Use percentage for the boost setting since it is easier to understand for most people
diff --git a/include/unrar.h b/include/unrar.h
index 282caf221..a704b7f84 100644
--- a/include/unrar.h
+++ b/include/unrar.h
@@ -3,6 +3,7 @@
#pragma pack(1)
+#define ERAR_SUCCESS 0
#define ERAR_END_ARCHIVE 10
#define ERAR_NO_MEMORY 11
#define ERAR_BAD_DATA 12
@@ -28,7 +29,12 @@
#define RAR_VOL_ASK 0
#define RAR_VOL_NOTIFY 1
-#define RAR_DLL_VERSION 5
+#define RAR_DLL_VERSION 6
+
+#define RAR_HASH_NONE 0
+#define RAR_HASH_CRC32 1
+#define RAR_HASH_BLAKE2 2
+
#ifdef _UNIX
#define CALLBACK
@@ -39,6 +45,13 @@
#define UINT unsigned int
#endif
+#define RHDF_SPLITBEFORE 0x01
+#define RHDF_SPLITAFTER 0x02
+#define RHDF_ENCRYPTED 0x04
+#define RHDF_SOLID 0x10
+#define RHDF_DIRECTORY 0x20
+
+
struct RARHeaderData
{
char ArcName[260];
@@ -80,7 +93,10 @@ struct RARHeaderDataEx
unsigned int CmtBufSize;
unsigned int CmtSize;
unsigned int CmtState;
- unsigned int Reserved[1024];
+ unsigned int DictSize;
+ unsigned int HashType;
+ char Hash[32];
+ unsigned int Reserved[1014];
};
diff --git a/src/thirdparty/unrar/acknow.txt b/src/thirdparty/unrar/acknow.txt
index 69bb0ba81..6f7a99924 100644
--- a/src/thirdparty/unrar/acknow.txt
+++ b/src/thirdparty/unrar/acknow.txt
@@ -1,5 +1,12 @@
ACKNOWLEDGMENTS
+* We used "Screaming Fast Galois Field Arithmetic Using Intel
+ SIMD Instructions" paper by James S. Plank, Kevin M. Greenan
+ and Ethan L. Miller to improve Reed-Solomon coding performance.
+ Also we are grateful to Artem Drobanov and Bulat Ziganshin
+ for samples and ideas allowed to make Reed-Solomon coding
+ more efficient.
+
* RAR text compression algorithm is based on Dmitry Shkarin PPMII
and Dmitry Subbotin carryless rangecoder public domain source code.
You may find it in ftp.elf.stuba.sk/pub/pc/pack.
@@ -77,5 +84,9 @@
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
+* RAR archives may optionally include BLAKE2sp hash ( https://blake2.net ),
+ designed by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn
+ and Christian Winnerlein.
+
* Useful hints provided by Alexander Khoroshev and Bulat Ziganshin allowed
to significantly improve RAR compression and speed.
diff --git a/src/thirdparty/unrar/arccmt.cpp b/src/thirdparty/unrar/arccmt.cpp
index 189fc791e..c8e6f0e1c 100644
--- a/src/thirdparty/unrar/arccmt.cpp
+++ b/src/thirdparty/unrar/arccmt.cpp
@@ -1,56 +1,55 @@
-bool IsAnsiComment(const char *Data,int Size);
+static bool IsAnsiEscComment(const wchar *Data,size_t Size);
-bool Archive::GetComment(Array<byte> *CmtData,Array<wchar> *CmtDataW)
+bool Archive::GetComment(Array<wchar> *CmtData)
{
if (!MainComment)
- return(false);
+ return false;
SaveFilePos SavePos(*this);
#ifndef SFX_MODULE
ushort CmtLength;
- if (OldFormat)
+ if (Format==RARFMT14)
{
- Seek(SFXSize+SIZEOF_OLDMHD,SEEK_SET);
+ Seek(SFXSize+SIZEOF_MAINHEAD14,SEEK_SET);
CmtLength=GetByte();
CmtLength+=(GetByte()<<8);
}
else
#endif
{
- if ((NewMhd.Flags & MHD_COMMENT)!=0)
+ if (MainHead.CommentInHeader)
{
// Old style (RAR 2.9) archive comment embedded into the main
// archive header.
- Seek(SFXSize+SIZEOF_MARKHEAD+SIZEOF_NEWMHD,SEEK_SET);
+ Seek(SFXSize+SIZEOF_MARKHEAD3+SIZEOF_MAINHEAD3,SEEK_SET);
ReadHeader();
}
else
{
// Current (RAR 3.0+) version of archive comment.
- Seek(SFXSize+SIZEOF_MARKHEAD+NewMhd.HeadSize,SEEK_SET);
- return(SearchSubBlock(SUBHEAD_TYPE_CMT)!=0 && ReadCommentData(CmtData,CmtDataW)!=0);
+ Seek(GetStartPos(),SEEK_SET);
+ return(SearchSubBlock(SUBHEAD_TYPE_CMT)!=0 && ReadCommentData(CmtData));
}
#ifndef SFX_MODULE
// Old style (RAR 2.9) comment header embedded into the main
// archive header.
- if (CommHead.HeadCRC!=HeaderCRC)
+ if (BrokenHeader)
{
Log(FileName,St(MLogCommHead));
- Alarm();
- return(false);
+ return false;
}
CmtLength=CommHead.HeadSize-SIZEOF_COMMHEAD;
#endif
}
#ifndef SFX_MODULE
- if (OldFormat && (OldMhd.Flags & MHD_PACK_COMMENT)!=0 || !OldFormat && CommHead.Method!=0x30)
+ if (Format==RARFMT14 && MainHead.PackComment || Format!=RARFMT14 && CommHead.Method!=0x30)
{
- if (!OldFormat && (CommHead.UnpVer < 15 || CommHead.UnpVer > UNP_VER || CommHead.Method > 0x35))
+ if (Format!=RARFMT14 && (CommHead.UnpVer < 15 || CommHead.UnpVer > VER_UNPACK || CommHead.Method > 0x35))
return(false);
ComprDataIO DataIO;
DataIO.SetTestMode(true);
uint UnpCmtLength;
- if (OldFormat)
+ if (Format==RARFMT14)
{
#ifdef RAR_NOCRYPT
return(false);
@@ -59,6 +58,7 @@ bool Archive::GetComment(Array<byte> *CmtData,Array<wchar> *CmtDataW)
UnpCmtLength+=(GetByte()<<8);
CmtLength-=2;
DataIO.SetCmt13Encryption();
+ CommHead.UnpVer=15;
#endif
}
else
@@ -66,100 +66,78 @@ bool Archive::GetComment(Array<byte> *CmtData,Array<wchar> *CmtDataW)
DataIO.SetFiles(this,NULL);
DataIO.EnableShowProgress(false);
DataIO.SetPackedSizeToRead(CmtLength);
+ DataIO.UnpHash.Init(HASH_CRC32,1);
- Unpack Unpack(&DataIO);
- Unpack.Init();
- Unpack.SetDestSize(UnpCmtLength);
- Unpack.DoUnpack(CommHead.UnpVer,false);
+ Unpack CmtUnpack(&DataIO);
+ CmtUnpack.Init(0x10000,false);
+ CmtUnpack.SetDestSize(UnpCmtLength);
+ CmtUnpack.DoUnpack(CommHead.UnpVer,false);
- if (!OldFormat && ((~DataIO.UnpFileCRC)&0xffff)!=CommHead.CommCRC)
+ if (Format!=RARFMT14 && (DataIO.UnpHash.GetCRC32()&0xffff)!=CommHead.CommCRC)
{
Log(FileName,St(MLogCommBrk));
- Alarm();
- return(false);
+ return false;
}
else
{
byte *UnpData;
size_t UnpDataSize;
DataIO.GetUnpackedData(&UnpData,&UnpDataSize);
- CmtData->Alloc(UnpDataSize);
- memcpy(&((*CmtData)[0]),UnpData,UnpDataSize);
+#ifdef _WIN_ALL
+ OemToCharBuffA((char *)UnpData,(char *)UnpData,(DWORD)UnpDataSize);
+#endif
+ CmtData->Alloc(UnpDataSize+1);
+ memset(CmtData->Addr(0),0,CmtData->Size()*sizeof(wchar));
+ CharToWide((char *)UnpData,CmtData->Addr(0),UnpDataSize);
+ CmtData->Alloc(wcslen(CmtData->Addr(0)));
}
}
else
{
- CmtData->Alloc(CmtLength);
-
- Read(&((*CmtData)[0]),CmtLength);
- if (!OldFormat && CommHead.CommCRC!=(~CRC(0xffffffff,&((*CmtData)[0]),CmtLength)&0xffff))
+ Array<byte> CmtRaw(CmtLength);
+ Read(&CmtRaw[0],CmtLength);
+
+ if (Format!=RARFMT14 && CommHead.CommCRC!=(~CRC32(0xffffffff,&CmtRaw[0],CmtLength)&0xffff))
{
Log(FileName,St(MLogCommBrk));
- Alarm();
- CmtData->Reset();
- return(false);
+ return false;
}
- }
+ CmtData->Alloc(CmtLength+1);
+ CmtRaw.Push(0);
+#ifdef _WIN_ALL
+ OemToCharA((char *)&CmtRaw[0],(char *)&CmtRaw[0]);
#endif
-#if defined(_WIN_ALL) && !defined(_WIN_CE)
- if (CmtData->Size()>0)
- {
- size_t CmtSize=CmtData->Size();
- char *DataA=(char *)CmtData->Addr();
- OemToCharBuffA(DataA,DataA,(DWORD)CmtSize);
-
- if (CmtDataW!=NULL)
- {
- CmtDataW->Alloc(CmtSize+1);
-
- // It can cause reallocation, so we should not use 'DataA' variable
- // with previosuly saved CmtData->Addr() after Push() call.
- CmtData->Push(0);
-
- CharToWide((char *)CmtData->Addr(),CmtDataW->Addr(),CmtSize+1);
- CmtData->Alloc(CmtSize);
- CmtDataW->Alloc(wcslen(CmtDataW->Addr()));
- }
+ CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtLength);
+ CmtData->Alloc(wcslen(CmtData->Addr(0)));
}
#endif
- return(CmtData->Size()>0);
+ return CmtData->Size() > 0;
}
-size_t Archive::ReadCommentData(Array<byte> *CmtData,Array<wchar> *CmtDataW)
+bool Archive::ReadCommentData(Array<wchar> *CmtData)
{
- bool Unicode=SubHead.SubFlags & SUBHEAD_FLAGS_CMT_UNICODE;
- if (!ReadSubData(CmtData,NULL))
- return(0);
- size_t CmtSize=CmtData->Size();
- if (Unicode)
- {
- CmtSize/=2;
- Array<wchar> DataW(CmtSize+1);
- RawToWide(CmtData->Addr(),DataW.Addr(),CmtSize);
- DataW[CmtSize]=0;
- size_t DestSize=CmtSize*4;
- CmtData->Alloc(DestSize+1);
- WideToChar(DataW.Addr(),(char *)CmtData->Addr(),DestSize);
- (*CmtData)[DestSize]=0;
- CmtSize=strlen((char *)CmtData->Addr());
- CmtData->Alloc(CmtSize);
- if (CmtDataW!=NULL)
+ Array<byte> CmtRaw;
+ if (!ReadSubData(&CmtRaw,NULL))
+ return false;
+ size_t CmtSize=CmtRaw.Size();
+ CmtRaw.Push(0);
+ CmtData->Alloc(CmtSize+1);
+ if (Format==RARFMT50)
+ UtfToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
+ else
+ if ((SubHead.SubFlags & SUBHEAD_FLAGS_CMT_UNICODE)!=0)
{
- *CmtDataW=DataW;
- CmtDataW->Alloc(CmtSize);
+ RawToWide(&CmtRaw[0],CmtData->Addr(0),CmtSize/2);
+ (*CmtData)[CmtSize/2]=0;
+
}
- }
- else
- if (CmtDataW!=NULL)
+ else
{
- CmtData->Push(0);
- CmtDataW->Alloc(CmtSize+1);
- CharToWide((char *)CmtData->Addr(),CmtDataW->Addr(),CmtSize+1);
- CmtData->Alloc(CmtSize);
- CmtDataW->Alloc(wcslen(CmtDataW->Addr()));
+ CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
}
- return(CmtSize);
+ CmtData->Alloc(wcslen(CmtData->Addr(0))); // Set buffer size to actual comment length.
+ return true;
}
@@ -168,68 +146,17 @@ void Archive::ViewComment()
#ifndef GUI
if (Cmd->DisableComment)
return;
- Array<byte> CmtBuf;
- if (GetComment(&CmtBuf,NULL))
+ Array<wchar> CmtBuf;
+ if (GetComment(&CmtBuf))
{
size_t CmtSize=CmtBuf.Size();
- char *ChPtr=(char *)memchr(&CmtBuf[0],0x1A,CmtSize);
+ wchar *ChPtr=wcschr(&CmtBuf[0],0x1A);
if (ChPtr!=NULL)
- CmtSize=ChPtr-(char *)&CmtBuf[0];
- mprintf("\n");
- OutComment((char *)&CmtBuf[0],CmtSize);
+ CmtSize=ChPtr-&CmtBuf[0];
+ mprintf(L"\n");
+ OutComment(&CmtBuf[0],CmtSize);
}
#endif
}
-#ifndef SFX_MODULE
-// Used for archives created by old RAR versions up to and including RAR 2.9.
-// New RAR versions store file comments in separate headers and such comments
-// are displayed in ListNewSubHeader function.
-void Archive::ViewFileComment()
-{
- if (!(NewLhd.Flags & LHD_COMMENT) || Cmd->DisableComment || OldFormat)
- return;
-#ifndef GUI
- mprintf(St(MFileComment));
-#endif
- const int MaxSize=0x8000;
- Array<char> CmtBuf(MaxSize);
- SaveFilePos SavePos(*this);
- Seek(CurBlockPos+SIZEOF_NEWLHD+NewLhd.NameSize,SEEK_SET);
- int64 SaveCurBlockPos=CurBlockPos;
- int64 SaveNextBlockPos=NextBlockPos;
-
- size_t Size=ReadHeader();
-
- CurBlockPos=SaveCurBlockPos;
- NextBlockPos=SaveNextBlockPos;
-
- if (Size<7 || CommHead.HeadType!=COMM_HEAD)
- return;
- if (CommHead.HeadCRC!=HeaderCRC)
- {
-#ifndef GUI
- Log(FileName,St(MLogCommHead));
-#endif
- return;
- }
- if (CommHead.UnpVer < 15 || CommHead.UnpVer > UNP_VER ||
- CommHead.Method > 0x30 || CommHead.UnpSize > MaxSize)
- return;
- Read(&CmtBuf[0],CommHead.UnpSize);
- if (CommHead.CommCRC!=((~CRC(0xffffffff,&CmtBuf[0],CommHead.UnpSize)&0xffff)))
- {
- Log(FileName,St(MLogBrokFCmt));
- }
- else
- {
- OutComment(&CmtBuf[0],CommHead.UnpSize);
-#ifndef GUI
- mprintf("\n");
-#endif
- }
-}
-#endif
-
-
diff --git a/src/thirdparty/unrar/archive.cpp b/src/thirdparty/unrar/archive.cpp
index b061e540a..b05eef462 100644
--- a/src/thirdparty/unrar/archive.cpp
+++ b/src/thirdparty/unrar/archive.cpp
@@ -7,48 +7,48 @@
Archive::Archive(RAROptions *InitCmd)
{
- Cmd=InitCmd==NULL ? &DummyCmd:InitCmd;
+ Cmd=NULL; // Just in case we'll have an exception in 'new' below.
+
+ DummyCmd=(InitCmd==NULL);
+ Cmd=DummyCmd ? (new RAROptions):InitCmd;
+
OpenShared=Cmd->OpenShared;
- OldFormat=false;
+ Format=RARFMT15;
Solid=false;
Volume=false;
MainComment=false;
Locked=false;
Signed=false;
- NotFirstVolume=false;
+ FirstVolume=false;
+ NewNumbering=false;
SFXSize=0;
LatestTime.Reset();
Protected=false;
Encrypted=false;
FailedHeaderDecryption=false;
- BrokenFileHeader=false;
+ BrokenHeader=false;
LastReadBlock=0;
CurBlockPos=0;
NextBlockPos=0;
- RecoveryPos=SIZEOF_MARKHEAD;
- RecoverySectors=-1;
+ RecoverySize=-1;
+ RecoveryPercent=-1;
- memset(&NewMhd,0,sizeof(NewMhd));
- NewMhd.HeadType=MAIN_HEAD;
- NewMhd.HeadSize=SIZEOF_NEWMHD;
- HeaderCRC=0;
+ memset(&MainHead,0,sizeof(MainHead));
+ memset(&CryptHead,0,sizeof(CryptHead));
+ memset(&EndArcHead,0,sizeof(EndArcHead));
+
+ VolNumber=0;
VolWrite=0;
AddingFilesSize=0;
AddingHeadersSize=0;
-#if !defined(SHELL_EXT) && !defined(RAR_NOCRYPT)
- *HeadersSalt=0;
- *SubDataSalt=0;
-#endif
*FirstVolumeName=0;
- *FirstVolumeNameW=0;
Splitting=false;
NewArchive=false;
SilentOpen=false;
-
}
@@ -66,37 +66,37 @@ void Archive::CheckArc(bool EnableBroken)
#if !defined(SHELL_EXT) && !defined(SFX_MODULE)
-void Archive::CheckOpen(const char *Name,const wchar *NameW)
+void Archive::CheckOpen(const wchar *Name)
{
- TOpen(Name,NameW);
+ TOpen(Name);
CheckArc(false);
}
#endif
-bool Archive::WCheckOpen(const char *Name,const wchar *NameW)
+bool Archive::WCheckOpen(const wchar *Name)
{
- if (!WOpen(Name,NameW))
- return(false);
+ if (!WOpen(Name))
+ return false;
if (!IsArchive(false))
{
#ifndef SHELL_EXT
Log(FileName,St(MNotRAR),FileName);
#endif
Close();
- return(false);
+ return false;
}
- return(true);
+ return true;
}
-ARCSIGN_TYPE Archive::IsSignature(const byte *D,size_t Size)
+RARFORMAT Archive::IsSignature(const byte *D,size_t Size)
{
- ARCSIGN_TYPE Type=ARCSIGN_NONE;
+ RARFORMAT Type=RARFMT_NONE;
if (Size>=1 && D[0]==0x52)
#ifndef SFX_MODULE
if (Size>=4 && D[1]==0x45 && D[2]==0x7e && D[3]==0x5e)
- Type=ARCSIGN_OLD;
+ Type=RARFMT14;
else
#endif
if (Size>=7 && D[1]==0x61 && D[2]==0x72 && D[3]==0x21 && D[4]==0x1a && D[5]==0x07)
@@ -104,7 +104,14 @@ ARCSIGN_TYPE Archive::IsSignature(const byte *D,size_t Size)
// 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.
- Type=D[6]==0 ? ARCSIGN_CURRENT:ARCSIGN_FUTURE;
+ if (D[6]==0)
+ Type=RARFMT15;
+ else
+ if (D[6]==1)
+ Type=RARFMT50;
+ else
+ if (D[6]==2)
+ Type=RARFMT_FUTURE;
}
return Type;
}
@@ -113,24 +120,32 @@ ARCSIGN_TYPE Archive::IsSignature(const byte *D,size_t Size)
bool Archive::IsArchive(bool EnableBroken)
{
Encrypted=false;
+#ifdef USE_QOPEN
+ QOpen.Unload();
+#endif
+
+ // Important if we reuse Archive object and it has virtual QOpen
+ // file position not matching real. For example, for 'l -v volname'.
+ Seek(0,SEEK_SET);
+
#ifndef SFX_MODULE
if (IsDevice())
{
#ifndef SHELL_EXT
Log(FileName,St(MInvalidName),FileName);
#endif
- return(false);
+ return false;
}
#endif
- if (Read(MarkHead.Mark,SIZEOF_MARKHEAD)!=SIZEOF_MARKHEAD)
+ if (Read(MarkHead.Mark,SIZEOF_MARKHEAD3)!=SIZEOF_MARKHEAD3)
return(false);
SFXSize=0;
- ARCSIGN_TYPE Type;
- if ((Type=IsSignature(MarkHead.Mark,sizeof(MarkHead.Mark)))!=ARCSIGN_NONE)
+ RARFORMAT Type;
+ if ((Type=IsSignature(MarkHead.Mark,SIZEOF_MARKHEAD3))!=RARFMT_NONE)
{
- OldFormat=(Type==ARCSIGN_OLD);
- if (OldFormat)
+ Format=Type;
+ if (Format==RARFMT14)
Seek(0,SEEK_SET);
}
else
@@ -139,10 +154,10 @@ bool Archive::IsArchive(bool EnableBroken)
long CurPos=(long)Tell();
int ReadSize=Read(&Buffer[0],Buffer.Size()-16);
for (int I=0;I<ReadSize;I++)
- if (Buffer[I]==0x52 && (Type=IsSignature((byte *)&Buffer[I],ReadSize-I))!=ARCSIGN_NONE)
+ if (Buffer[I]==0x52 && (Type=IsSignature((byte *)&Buffer[I],ReadSize-I))!=RARFMT_NONE)
{
- OldFormat=(Type==ARCSIGN_OLD);
- if (OldFormat && I>0 && CurPos<28 && ReadSize>31)
+ Format=Type;
+ if (Format==RARFMT14 && I>0 && CurPos<28 && ReadSize>31)
{
char *D=&Buffer[28-CurPos];
if (D[0]!=0x52 || D[1]!=0x53 || D[2]!=0x46 || D[3]!=0x58)
@@ -150,50 +165,52 @@ bool Archive::IsArchive(bool EnableBroken)
}
SFXSize=CurPos+I;
Seek(SFXSize,SEEK_SET);
- if (!OldFormat)
- Read(MarkHead.Mark,SIZEOF_MARKHEAD);
+ if (Format==RARFMT15 || Format==RARFMT50)
+ Read(MarkHead.Mark,SIZEOF_MARKHEAD3);
break;
}
if (SFXSize==0)
return false;
}
- if (Type==ARCSIGN_FUTURE)
+ if (Format==RARFMT_FUTURE)
{
#if !defined(SHELL_EXT) && !defined(SFX_MODULE)
Log(FileName,St(MNewRarFormat));
#endif
return false;
}
- ReadHeader();
- SeekToNext();
-#ifndef SFX_MODULE
- if (OldFormat)
+ if (Format==RARFMT50) // RAR 5.0 signature is by one byte longer.
{
- NewMhd.Flags=OldMhd.Flags & 0x3f;
- NewMhd.HeadSize=OldMhd.HeadSize;
+ Read(MarkHead.Mark+SIZEOF_MARKHEAD3,1);
+ if (MarkHead.Mark[SIZEOF_MARKHEAD3]!=0)
+ return false;
+ MarkHead.HeadSize=SIZEOF_MARKHEAD5;
}
else
-#endif
+ MarkHead.HeadSize=SIZEOF_MARKHEAD3;
+
+ // Skip the archive encryption header if any and read the main header.
+ while (ReadHeader()!=0 && GetHeaderType()!=HEAD_MAIN)
+ SeekToNext();
+
+ // This check allows to make RS based recovery even if password is incorrect.
+ // But we should not do it for EnableBroken or we'll get 'not RAR archive'
+ // messages when extracting encrypted archives with wrong password.
+ if (FailedHeaderDecryption && !EnableBroken)
+ return false;
+
+ SeekToNext();
+ if (BrokenHeader)
{
- if (HeaderCRC!=NewMhd.HeadCRC)
- {
#ifndef SHELL_EXT
- Log(FileName,St(MLogMainHead));
+ Log(FileName,St(MMainHeaderBroken));
#endif
- Alarm();
- if (!EnableBroken)
- return(false);
- }
+ if (!EnableBroken)
+ return false;
}
- Volume=(NewMhd.Flags & MHD_VOLUME);
- Solid=(NewMhd.Flags & MHD_SOLID)!=0;
- MainComment=(NewMhd.Flags & MHD_COMMENT)!=0;
- Locked=(NewMhd.Flags & MHD_LOCK)!=0;
- Signed=(NewMhd.PosAV!=0);
- Protected=(NewMhd.Flags & MHD_PROTECT)!=0;
- Encrypted=(NewMhd.Flags & MHD_PASSWORD)!=0;
-
- if (NewMhd.EncryptVer>UNP_VER)
+
+/*
+ if (MainHead.EncryptVer>VER_UNPACK)
{
#ifdef RARDLL
Cmd->DllError=ERAR_UNKNOWN_FORMAT;
@@ -201,11 +218,13 @@ bool Archive::IsArchive(bool EnableBroken)
ErrHandler.SetErrorCode(RARX_WARNING);
#if !defined(SILENT) && !defined(SFX_MODULE)
Log(FileName,St(MUnknownMeth),FileName);
- Log(FileName,St(MVerRequired),NewMhd.EncryptVer/10,NewMhd.EncryptVer%10);
+ Log(FileName,St(MVerRequired),MainHead.EncryptVer/10,MainHead.EncryptVer%10);
#endif
#endif
return(false);
}
+*/
+
#ifdef RARDLL
// If callback function is not set, we cannot get the password,
// so we skip the initial header processing for encrypted header archive.
@@ -215,31 +234,37 @@ bool Archive::IsArchive(bool EnableBroken)
SilentOpen=true;
#endif
- // If not encrypted, we'll check it below.
- NotFirstVolume=Encrypted && (NewMhd.Flags & MHD_FIRSTVOLUME)==0;
+ MainComment=MainHead.CommentInHeader;
+#ifdef USE_QOPEN
+ if (MainHead.Locator && MainHead.QOpenOffset>0 && Cmd->QOpenMode!=QOPEN_NONE)
+ {
+ QOpen.Init(this,false);
+ QOpen.Load(MainHead.QOpenOffset);
+ }
+#endif
+
+ // If we process non-encrypted archive or can request a password,
+ // we set 'first volume' flag based on file attributes below.
+ // It is necessary for RAR 2.x archives, which did not have 'first volume'
+ // flag in main header.
if (!SilentOpen || !Encrypted)
{
SaveFilePos SavePos(*this);
int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;
- NotFirstVolume=false;
while (ReadHeader()!=0)
{
- int HeaderType=GetHeaderType();
- if (HeaderType==NEWSUB_HEAD)
+ HEADER_TYPE HeaderType=GetHeaderType();
+ if (HeaderType==HEAD_SERVICE)
{
if (SubHead.CmpName(SUBHEAD_TYPE_CMT))
MainComment=true;
- if ((SubHead.Flags & LHD_SPLIT_BEFORE) ||
- Volume && (NewMhd.Flags & MHD_FIRSTVOLUME)==0)
- NotFirstVolume=true;
+ FirstVolume=!SubHead.SplitBefore;
}
else
{
- if (HeaderType==FILE_HEAD && ((NewLhd.Flags & LHD_SPLIT_BEFORE)!=0 ||
- Volume && NewLhd.UnpVer>=29 && (NewMhd.Flags & MHD_FIRSTVOLUME)==0))
- NotFirstVolume=true;
+ FirstVolume=HeaderType==HEAD_FILE && !FileHead.SplitBefore;
break;
}
SeekToNext();
@@ -247,13 +272,10 @@ bool Archive::IsArchive(bool EnableBroken)
CurBlockPos=SaveCurBlockPos;
NextBlockPos=SaveNextBlockPos;
}
- if (!Volume || !NotFirstVolume)
- {
- strcpy(FirstVolumeName,FileName);
- wcscpy(FirstVolumeNameW,FileNameW);
- }
+ if (!Volume || FirstVolume)
+ wcscpy(FirstVolumeName,FileName);
- return(true);
+ return true;
}
@@ -265,20 +287,50 @@ void Archive::SeekToNext()
}
-#ifndef SFX_MODULE
-int Archive::GetRecoverySize(bool Required)
+
+
+
+
+// Calculate the block size including encryption fields and padding if any.
+uint Archive::FullHeaderSize(size_t Size)
{
- if (!Protected)
- return(0);
- if (RecoverySectors!=-1 || !Required)
- return(RecoverySectors);
- SaveFilePos SavePos(*this);
- Seek(SFXSize,SEEK_SET);
- SearchSubBlock(SUBHEAD_TYPE_RR);
- return(RecoverySectors);
+ if (Encrypted)
+ {
+ Size = ALIGN_VALUE(Size, CRYPT_BLOCK_SIZE); // Align to encryption block size.
+ if (Format == RARFMT50)
+ Size += SIZE_INITV;
+ else
+ Size += SIZE_SALT30;
+ }
+ return uint(Size);
}
-#endif
+#ifdef USE_QOPEN
+int Archive::Read(void *Data,size_t Size)
+{
+ size_t Result;
+ if (QOpen.Read(Data,Size,Result))
+ return (int)Result;
+ return File::Read(Data,Size);
+}
+
+
+void Archive::Seek(int64 Offset,int Method)
+{
+ if (!QOpen.Seek(Offset,Method))
+ File::Seek(Offset,Method);
+}
+
+
+int64 Archive::Tell()
+{
+ int64 QPos;
+ if (QOpen.Tell(&QPos))
+ return QPos;
+ return File::Tell();
+}
+#endif
+
diff --git a/src/thirdparty/unrar/archive.hpp b/src/thirdparty/unrar/archive.hpp
index 58b4cd3ef..93e034838 100644
--- a/src/thirdparty/unrar/archive.hpp
+++ b/src/thirdparty/unrar/archive.hpp
@@ -1,81 +1,105 @@
#ifndef _RAR_ARCHIVE_
#define _RAR_ARCHIVE_
-class Pack;
+class PPack;
+class RawRead;
+class RawWrite;
-enum {EN_LOCK=1,EN_VOL=2,EN_FIRSTVOL=4};
+enum NOMODIFY_FLAGS
+{
+ NMDF_ALLOWLOCK=1,NMDF_ALLOWANYVOLUME=2,NMDF_ALLOWFIRSTVOLUME=4
+};
+
+enum RARFORMAT {RARFMT_NONE,RARFMT14,RARFMT15,RARFMT50,RARFMT_FUTURE};
-enum ARCSIGN_TYPE {ARCSIGN_NONE,ARCSIGN_OLD,ARCSIGN_CURRENT,ARCSIGN_FUTURE};
+enum ADDSUBDATA_FLAGS
+{
+ ASDF_SPLIT = 1, // Allow to split archive just before header if necessary.
+ ASDF_COMPRESS = 2, // Allow to compress data following subheader.
+ ASDF_CRYPT = 4, // Encrypt data after subheader if password is set.
+ ASDF_CRYPTIFHEADERS = 8 // Encrypt data after subheader only in -hp mode.
+};
class Archive:public File
{
private:
- ARCSIGN_TYPE IsSignature(const byte *D,size_t Size);
void UpdateLatestTime(FileHeader *CurBlock);
- void ConvertNameCase(char *Name);
void ConvertNameCase(wchar *Name);
- void ConvertUnknownHeader();
- size_t ReadOldHeader();
+ void ConvertFileHeader(FileHeader *hd);
+ void WriteBlock50(HEADER_TYPE HeaderType,BaseBlock *wb,bool OnlySetSize,bool NonFinalWrite);
+ size_t ReadHeader14();
+ size_t ReadHeader15();
+ size_t ReadHeader50();
+ void ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb);
+ void RequestArcPassword();
void UnexpEndArcMsg();
+ void BrokenHeaderMsg();
+ void UnkEncVerMsg(const wchar *Name);
+ void UnkEncVerMsg();
+ bool ReadCommentData(Array<wchar> *CmtData);
#if !defined(SHELL_EXT) && !defined(RAR_NOCRYPT)
CryptData HeadersCrypt;
- byte HeadersSalt[SALT_SIZE];
#endif
#ifndef SHELL_EXT
ComprDataIO SubDataIO;
- byte SubDataSalt[SALT_SIZE];
#endif
- RAROptions *Cmd,DummyCmd;
+ bool DummyCmd;
+ RAROptions *Cmd;
- MarkHeader MarkHead;
- OldMainHeader OldMhd;
-
- int RecoverySectors;
- int64 RecoveryPos;
-
- bool FailedHeaderDecryption;
+ int64 RecoverySize;
+ int RecoveryPercent;
RarTime LatestTime;
int LastReadBlock;
- int CurHeaderType;
+ HEADER_TYPE CurHeaderType;
bool SilentOpen;
+#ifdef USE_QOPEN
+ QuickOpen QOpen;
+#endif
public:
Archive(RAROptions *InitCmd=NULL);
+ RARFORMAT IsSignature(const byte *D,size_t Size);
bool IsArchive(bool EnableBroken);
- size_t SearchBlock(int BlockType);
- size_t SearchSubBlock(const char *Type);
- int ReadBlock(int BlockType);
- void WriteBlock(int BlockType,BaseBlock *wb=NULL);
- int PrepareNamesToWrite(char *Name,wchar *NameW,char *DestName,byte *DestNameW);
- void SetLhdSize();
+ size_t SearchBlock(HEADER_TYPE HeaderType);
+ size_t SearchSubBlock(const wchar *Type);
+ size_t SearchRR();
+ void WriteBlock(HEADER_TYPE HeaderType,BaseBlock *wb=NULL,bool OnlySetSize=false,bool NonFinalWrite=false);
+ void SetBlockSize(HEADER_TYPE HeaderType,BaseBlock *wb=NULL) {WriteBlock(HeaderType,wb,true);}
size_t ReadHeader();
void CheckArc(bool EnableBroken);
- void CheckOpen(const char *Name,const wchar *NameW=NULL);
- bool WCheckOpen(const char *Name,const wchar *NameW=NULL);
- bool GetComment(Array<byte> *CmtData,Array<wchar> *CmtDataW);
+ void CheckOpen(const wchar *Name);
+ bool WCheckOpen(const wchar *Name);
+ bool GetComment(Array<wchar> *CmtData);
void ViewComment();
- void ViewFileComment();
void SetLatestTime(RarTime *NewTime);
void SeekToNext();
bool CheckAccess();
bool IsArcDir();
- bool IsArcLabel();
void ConvertAttributes();
- int GetRecoverySize(bool Required);
void VolSubtractHeaderSize(size_t SubSize);
- void AddSubData(byte *SrcData,size_t DataSize,File *SrcFile,const char *Name,bool AllowSplit);
+ uint FullHeaderSize(size_t Size);
+ int64 GetStartPos();
+ void AddSubData(byte *SrcData,uint64 DataSize,File *SrcFile,
+ const wchar *Name,uint Flags);
bool ReadSubData(Array<byte> *UnpData,File *DestFile);
- int GetHeaderType() {return(CurHeaderType);};
- size_t ReadCommentData(Array<byte> *CmtData,Array<wchar> *CmtDataW);
+ HEADER_TYPE GetHeaderType() {return(CurHeaderType);};
void WriteCommentData(byte *Data,size_t DataSize,bool FileComment);
RAROptions* GetRAROptions() {return(Cmd);}
void SetSilentOpen(bool Mode) {SilentOpen=Mode;}
+#ifdef USE_QOPEN
+ int Read(void *Data,size_t Size);
+ void Seek(int64 Offset,int Method);
+ int64 Tell();
+ void QOpenUnload() {QOpen.Unload();}
+#endif
BaseBlock ShortBlock;
- MainHeader NewMhd;
- FileHeader NewLhd;
+ MarkHeader MarkHead;
+ MainHeader MainHead;
+ CryptHeader CryptHead;
+ FileHeader FileHead;
EndArcHeader EndArcHead;
SubBlockHeader SubBlockHead;
FileHeader SubHead;
@@ -91,30 +115,34 @@ class Archive:public File
int64 CurBlockPos;
int64 NextBlockPos;
- bool OldFormat;
+ RARFORMAT Format;
bool Solid;
bool Volume;
bool MainComment;
bool Locked;
bool Signed;
- bool NotFirstVolume;
+ bool FirstVolume;
+ bool NewNumbering;
bool Protected;
bool Encrypted;
size_t SFXSize;
- bool BrokenFileHeader;
+ bool BrokenHeader;
+ bool FailedHeaderDecryption;
- bool Splitting;
+#if !defined(SHELL_EXT) && !defined(RAR_NOCRYPT)
+ byte ArcSalt[SIZE_SALT50];
+#endif
- ushort HeaderCRC;
+ bool Splitting;
+ uint VolNumber;
int64 VolWrite;
- int64 AddingFilesSize;
- size_t AddingHeadersSize;
+ uint64 AddingFilesSize;
+ uint64 AddingHeadersSize;
bool NewArchive;
- char FirstVolumeName[NM];
- wchar FirstVolumeNameW[NM];
+ wchar FirstVolumeName[NM];
};
diff --git a/src/thirdparty/unrar/arcread.cpp b/src/thirdparty/unrar/arcread.cpp
index a524a9612..3fa4f80fb 100644
--- a/src/thirdparty/unrar/arcread.cpp
+++ b/src/thirdparty/unrar/arcread.cpp
@@ -1,14 +1,49 @@
#include "rar.hpp"
-size_t Archive::SearchBlock(int BlockType)
+size_t Archive::ReadHeader()
+{
+ // Once we failed to decrypt an encrypted block, there is no reason to
+ // attempt to do it further. We'll never be successful and only generate
+ // endless errors.
+ if (FailedHeaderDecryption)
+ return 0;
+
+ CurBlockPos=Tell();
+
+ size_t ReadSize;
+ switch(Format)
+ {
+#ifndef SFX_MODULE
+ case RARFMT14:
+ ReadSize=ReadHeader14();
+ break;
+#endif
+ case RARFMT15:
+ ReadSize=ReadHeader15();
+ break;
+ case RARFMT50:
+ ReadSize=ReadHeader50();
+ break;
+ }
+
+ if (ReadSize>0 && NextBlockPos<=CurBlockPos)
+ {
+ BrokenHeaderMsg();
+ return 0;
+ }
+ return ReadSize;
+}
+
+
+size_t Archive::SearchBlock(HEADER_TYPE HeaderType)
{
size_t Size,Count=0;
while ((Size=ReadHeader())!=0 &&
- (BlockType==ENDARC_HEAD || GetHeaderType()!=ENDARC_HEAD))
+ (HeaderType==HEAD_ENDARC || GetHeaderType()!=HEAD_ENDARC))
{
if ((++Count & 127)==0)
Wait();
- if (GetHeaderType()==BlockType)
+ if (GetHeaderType()==HeaderType)
return(Size);
SeekToNext();
}
@@ -16,22 +51,43 @@ size_t Archive::SearchBlock(int BlockType)
}
-size_t Archive::SearchSubBlock(const char *Type)
+size_t Archive::SearchSubBlock(const wchar *Type)
{
size_t Size;
- while ((Size=ReadHeader())!=0 && GetHeaderType()!=ENDARC_HEAD)
+ while ((Size=ReadHeader())!=0 && GetHeaderType()!=HEAD_ENDARC)
{
- if (GetHeaderType()==NEWSUB_HEAD && SubHead.CmpName(Type))
- return(Size);
+ if (GetHeaderType()==HEAD_SERVICE && SubHead.CmpName(Type))
+ return Size;
SeekToNext();
}
- return(0);
+ return 0;
+}
+
+
+size_t Archive::SearchRR()
+{
+ // If locator extra field is available for recovery record, let's utilize it.
+ if (MainHead.Locator && MainHead.RROffset!=0)
+ {
+ uint64 CurPos=Tell();
+ Seek(MainHead.RROffset,SEEK_SET);
+ size_t Size=ReadHeader();
+ if (Size!=0 && !BrokenHeader && GetHeaderType()==HEAD_SERVICE && SubHead.CmpName(SUBHEAD_TYPE_RR))
+ return Size;
+ Seek(CurPos,SEEK_SET);
+ }
+ // Otherwise scan the entire archive to find the recovery record.
+ return SearchSubBlock(SUBHEAD_TYPE_RR);
}
void Archive::UnexpEndArcMsg()
{
int64 ArcSize=FileLength();
+
+ // If block positions are equal to file size, this is not an error.
+ // It can happen when we reached the end of older RAR 1.5 archive,
+ // which did not have the end of archive block.
if (CurBlockPos>ArcSize || NextBlockPos>ArcSize)
{
#ifndef SHELL_EXT
@@ -42,71 +98,45 @@ void Archive::UnexpEndArcMsg()
}
-size_t Archive::ReadHeader()
+void Archive::BrokenHeaderMsg()
{
- // Once we failed to decrypt an encrypted block, there is no reason to
- // attempt to do it further. We'll never be successful and only generate
- // endless errors.
- if (FailedHeaderDecryption)
- return 0;
+#ifndef SHELL_EXT
+ Log(FileName,St(MHeaderBroken));
+#endif
+ BrokenHeader=true;
+ ErrHandler.SetErrorCode(RARX_CRC);
+}
- CurBlockPos=Tell();
-#ifndef SFX_MODULE
- if (OldFormat)
- return(ReadOldHeader());
+void Archive::UnkEncVerMsg(const wchar *Name)
+{
+#ifndef SHELL_EXT
+ Log(FileName,St(MUnkEncMethod),Name);
#endif
+ ErrHandler.SetErrorCode(RARX_WARNING);
+}
+
+size_t Archive::ReadHeader15()
+{
RawRead Raw(this);
- bool Decrypt=Encrypted && CurBlockPos>=(int64)SFXSize+SIZEOF_MARKHEAD+SIZEOF_NEWMHD;
+ bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD3;
if (Decrypt)
{
-#if defined(SHELL_EXT) || defined(RAR_NOCRYPT)
- return(0);
+#ifdef RAR_NOCRYPT // For rarext.dll and unrar_nocrypt.dll.
+ return 0;
#else
- if (Read(HeadersSalt,SALT_SIZE)!=SALT_SIZE)
+ RequestArcPassword();
+
+ byte Salt[SIZE_SALT30];
+ if (Read(Salt,SIZE_SALT30)!=SIZE_SALT30)
{
UnexpEndArcMsg();
return(0);
}
- if (!Cmd->Password.IsSet())
- {
-#ifdef RARDLL
- if (Cmd->Callback!=NULL)
- {
- wchar PasswordW[MAXPASSWORD];
- *PasswordW=0;
- if (Cmd->Callback(UCM_NEEDPASSWORDW,Cmd->UserData,(LPARAM)PasswordW,ASIZE(PasswordW))==-1)
- *PasswordW=0;
- if (*PasswordW==0)
- {
- char PasswordA[MAXPASSWORD];
- *PasswordA=0;
- if (Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1)
- *PasswordA=0;
- GetWideName(PasswordA,NULL,PasswordW,ASIZE(PasswordW));
- cleandata(PasswordA,sizeof(PasswordA));
- }
- Cmd->Password.Set(PasswordW);
- cleandata(PasswordW,sizeof(PasswordW));
- }
- if (!Cmd->Password.IsSet())
- {
- Close();
- Cmd->DllError=ERAR_MISSING_PASSWORD;
- ErrHandler.Exit(RARX_USERBREAK);
- }
-#else
- if (!GetPassword(PASSWORD_ARCHIVE,FileName,FileNameW,&Cmd->Password))
- {
- Close();
- ErrHandler.Exit(RARX_USERBREAK);
- }
-#endif
- }
- HeadersCrypt.SetCryptKeys(&Cmd->Password,HeadersSalt,false,false,NewMhd.EncryptVer>=36);
+ HeadersCrypt.SetCryptKeys(false,CRYPT_RAR30,&Cmd->Password,Salt,NULL,0,NULL,NULL);
Raw.SetCrypt(&HeadersCrypt);
#endif
}
@@ -115,26 +145,38 @@ size_t Archive::ReadHeader()
if (Raw.Size()==0)
{
UnexpEndArcMsg();
- return(0);
+ return 0;
}
- Raw.Get(ShortBlock.HeadCRC);
- byte HeadType;
- Raw.Get(HeadType);
- ShortBlock.HeadType=(HEADER_TYPE)HeadType;
- Raw.Get(ShortBlock.Flags);
- Raw.Get(ShortBlock.HeadSize);
+ ShortBlock.HeadCRC=Raw.Get2();
+
+ ShortBlock.Reset();
+
+ uint HeaderType=Raw.Get1();
+ ShortBlock.Flags=Raw.Get2();
+ ShortBlock.SkipIfUnknown=(ShortBlock.Flags & SKIP_IF_UNKNOWN)!=0;
+ ShortBlock.HeadSize=Raw.Get2();
+
+ ShortBlock.HeaderType=(HEADER_TYPE)HeaderType;
if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD)
{
-#ifndef SHELL_EXT
- Log(FileName,St(MLogFileHead),"???");
-#endif
- BrokenFileHeader=true;
- ErrHandler.SetErrorCode(RARX_CRC);
+ BrokenHeaderMsg();
return(0);
}
- if (ShortBlock.HeadType==COMM_HEAD)
+ // For simpler further processing we map header types common
+ // for RAR 1.5 and 5.0 formats to RAR 5.0 values. It does not include
+ // header types specific for RAR 1.5 - 4.x only.
+ switch(ShortBlock.HeaderType)
+ {
+ case HEAD3_MAIN: ShortBlock.HeaderType=HEAD_MAIN; break;
+ case HEAD3_FILE: ShortBlock.HeaderType=HEAD_FILE; break;
+ case HEAD3_SERVICE: ShortBlock.HeaderType=HEAD_SERVICE; break;
+ case HEAD3_ENDARC: ShortBlock.HeaderType=HEAD_ENDARC; break;
+ }
+ CurHeaderType=ShortBlock.HeaderType;
+
+ if (ShortBlock.HeaderType==HEAD3_CMT)
{
// Old style (up to RAR 2.9) comment header embedded into main
// or file header. We must not read the entire ShortBlock.HeadSize here
@@ -142,153 +184,204 @@ size_t Archive::ReadHeader()
Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD);
}
else
- if (ShortBlock.HeadType==MAIN_HEAD && (ShortBlock.Flags & MHD_COMMENT)!=0)
+ if (ShortBlock.HeaderType==HEAD_MAIN && (ShortBlock.Flags & MHD_COMMENT)!=0)
{
// Old style (up to RAR 2.9) main archive comment embedded into
// the main archive header found. While we can read the entire
// ShortBlock.HeadSize here and remove this part of "if", it would be
// waste of memory, because we'll read and process this comment data
// in other function anyway and we do not need them here now.
- Raw.Read(SIZEOF_NEWMHD-SIZEOF_SHORTBLOCKHEAD);
+ Raw.Read(SIZEOF_MAINHEAD3-SIZEOF_SHORTBLOCKHEAD);
}
else
Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD);
- NextBlockPos=CurBlockPos+ShortBlock.HeadSize;
+ NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize);
- switch(ShortBlock.HeadType)
+ switch(ShortBlock.HeaderType)
{
- case MAIN_HEAD:
- *(BaseBlock *)&NewMhd=ShortBlock;
- Raw.Get(NewMhd.HighPosAV);
- Raw.Get(NewMhd.PosAV);
- if (NewMhd.Flags & MHD_ENCRYPTVER)
- Raw.Get(NewMhd.EncryptVer);
- break;
- case ENDARC_HEAD:
- *(BaseBlock *)&EndArcHead=ShortBlock;
- if (EndArcHead.Flags & EARC_DATACRC)
- Raw.Get(EndArcHead.ArcDataCRC);
- if (EndArcHead.Flags & EARC_VOLNUMBER)
- Raw.Get(EndArcHead.VolNumber);
+ case HEAD_MAIN:
+ MainHead.Reset();
+ *(BaseBlock *)&MainHead=ShortBlock;
+ MainHead.HighPosAV=Raw.Get2();
+ MainHead.PosAV=Raw.Get4();
+
+ Volume=(MainHead.Flags & MHD_VOLUME)!=0;
+ Solid=(MainHead.Flags & MHD_SOLID)!=0;
+ Locked=(MainHead.Flags & MHD_LOCK)!=0;
+ Protected=(MainHead.Flags & MHD_PROTECT)!=0;
+ Encrypted=(MainHead.Flags & MHD_PASSWORD)!=0;
+ Signed=MainHead.PosAV!=0 || MainHead.HighPosAV!=0;
+ MainHead.CommentInHeader=(MainHead.Flags & MHD_COMMENT)!=0;
+
+ // Only for encrypted 3.0+ archives. 2.x archives did not have this
+ // flag, so for non-encrypted archives, we'll set it later based on
+ // file attributes.
+ FirstVolume=(MainHead.Flags & MHD_FIRSTVOLUME)!=0;
+
+ NewNumbering=(MainHead.Flags & MHD_NEWNUMBERING)!=0;
break;
- case FILE_HEAD:
- case NEWSUB_HEAD:
+ case HEAD_FILE:
+ case HEAD_SERVICE:
{
- FileHeader *hd=ShortBlock.HeadType==FILE_HEAD ? &NewLhd:&SubHead;
+ bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
+ FileHeader *hd=FileBlock ? &FileHead:&SubHead;
+ hd->Reset();
+
*(BaseBlock *)hd=ShortBlock;
- Raw.Get(hd->PackSize);
- Raw.Get(hd->UnpSize);
- Raw.Get(hd->HostOS);
- Raw.Get(hd->FileCRC);
- Raw.Get(hd->FileTime);
- Raw.Get(hd->UnpVer);
- Raw.Get(hd->Method);
- Raw.Get(hd->NameSize);
- Raw.Get(hd->FileAttr);
- if (hd->Flags & LHD_LARGE)
+
+ hd->SplitBefore=(hd->Flags & LHD_SPLIT_BEFORE)!=0;
+ hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0;
+ hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0;
+ hd->SaltSet=(hd->Flags & LHD_SALT)!=0;
+ hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0;
+ hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0;
+ hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY;
+ hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5);
+ hd->CommentInHeader=(hd->Flags & LHD_COMMENT)!=0;
+ hd->Version=(hd->Flags & LHD_VERSION)!=0;
+
+ hd->DataSize=Raw.Get4();
+ uint LowUnpSize=Raw.Get4();
+ hd->HostOS=Raw.Get1();
+
+ hd->FileHash.Type=HASH_CRC32;
+ hd->FileHash.CRC32=Raw.Get4();
+
+ uint FileTime=Raw.Get4();
+ hd->UnpVer=Raw.Get1();
+ hd->Method=Raw.Get1()-0x30;
+ size_t NameSize=Raw.Get2();
+ hd->FileAttr=Raw.Get4();
+
+ hd->CryptMethod=CRYPT_NONE;
+ if (hd->Encrypted)
+ switch(hd->UnpVer)
+ {
+ case 13: hd->CryptMethod=CRYPT_RAR13; break;
+ case 15: hd->CryptMethod=CRYPT_RAR15; break;
+ case 20:
+ case 26: hd->CryptMethod=CRYPT_RAR20; break;
+ default: hd->CryptMethod=CRYPT_RAR30; break;
+ }
+
+ hd->HSType=HSYS_UNKNOWN;
+ if (hd->HostOS==HOST_UNIX || hd->HostOS==HOST_BEOS)
+ hd->HSType=HSYS_UNIX;
+ else
+ if (hd->HostOS<HOST_MAX)
+ hd->HSType=HSYS_WINDOWS;
+
+ hd->RedirType=FSREDIR_NONE;
+
+ // RAR 4.x Unix symlink.
+ if (hd->HostOS==HOST_UNIX && (hd->FileAttr & 0xF000)==0xA000)
+ {
+ hd->RedirType=FSREDIR_UNIXSYMLINK;
+ *hd->RedirName=0;
+ }
+
+ hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0;
+
+ hd->LargeFile=(hd->Flags & LHD_LARGE)!=0;
+
+ uint HighPackSize,HighUnpSize;
+ if (hd->LargeFile)
{
- Raw.Get(hd->HighPackSize);
- Raw.Get(hd->HighUnpSize);
+ HighPackSize=Raw.Get4();
+ HighUnpSize=Raw.Get4();
+ hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff);
}
else
{
- hd->HighPackSize=hd->HighUnpSize=0;
- if (hd->UnpSize==0xffffffff)
- {
- // UnpSize equal to 0xffffffff without LHD_LARGE flag indicates
- // that we do not know the unpacked file size and must unpack it
- // until we find the end of file marker in compressed data.
- hd->UnpSize=(uint)(INT64NDF);
- hd->HighUnpSize=(uint)(INT64NDF>>32);
- }
+ HighPackSize=HighUnpSize=0;
+ // UnpSize equal to 0xffffffff without LHD_LARGE flag indicates
+ // that we do not know the unpacked file size and must unpack it
+ // until we find the end of file marker in compressed data.
+ hd->UnknownUnpSize=(LowUnpSize==0xffffffff);
}
- hd->FullPackSize=INT32TO64(hd->HighPackSize,hd->PackSize);
- hd->FullUnpSize=INT32TO64(hd->HighUnpSize,hd->UnpSize);
+ hd->PackSize=INT32TO64(HighPackSize,hd->DataSize);
+ hd->UnpSize=INT32TO64(HighUnpSize,LowUnpSize);
+ if (hd->UnknownUnpSize)
+ hd->UnpSize=INT64NDF;
char FileName[NM*4];
- size_t NameSize=Min(hd->NameSize,sizeof(FileName)-1);
- Raw.Get((byte *)FileName,NameSize);
- FileName[NameSize]=0;
+ size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
+ Raw.GetB((byte *)FileName,ReadNameSize);
+ FileName[ReadNameSize]=0;
- strncpyz(hd->FileName,FileName,ASIZE(hd->FileName));
+ if (FileBlock)
+ {
+ if ((hd->Flags & LHD_UNICODE)!=0)
+ {
+ EncodeFileName NameCoder;
+ size_t Length=strlen(FileName);
+ if (Length==NameSize)
+ UtfToWide(FileName,hd->FileName,ASIZE(hd->FileName)-1);
+ else
+ {
+ Length++;
+ NameCoder.Decode(FileName,(byte *)FileName+Length,
+ NameSize-Length,hd->FileName,
+ ASIZE(hd->FileName));
+ }
+ }
+ else
+ *hd->FileName=0;
+
+ char AnsiName[NM];
+ IntToExt(FileName,AnsiName,ASIZE(AnsiName));
+ GetWideName(AnsiName,hd->FileName,hd->FileName,ASIZE(hd->FileName));
- if (hd->HeadType==NEWSUB_HEAD)
+#ifndef SFX_MODULE
+ ConvertNameCase(hd->FileName);
+#endif
+ ConvertFileHeader(hd);
+ }
+ else
{
- // Let's calculate the size of optional data.
- int DataSize=hd->HeadSize-hd->NameSize-SIZEOF_NEWLHD;
- if (hd->Flags & LHD_SALT)
- DataSize-=SALT_SIZE;
+ CharToWide(FileName,hd->FileName,ASIZE(hd->FileName));
+
+ // Calculate the size of optional data.
+ int DataSize=int(hd->HeadSize-NameSize-SIZEOF_FILEHEAD3);
+ if ((hd->Flags & LHD_SALT)!=0)
+ DataSize-=SIZE_SALT30;
if (DataSize>0)
{
// Here we read optional additional fields for subheaders.
// They are stored after the file name and before salt.
hd->SubData.Alloc(DataSize);
- Raw.Get(&hd->SubData[0],DataSize);
+ Raw.GetB(&hd->SubData[0],DataSize);
if (hd->CmpName(SUBHEAD_TYPE_RR))
{
byte *D=&hd->SubData[8];
- RecoverySectors=D[0]+((uint)D[1]<<8)+((uint)D[2]<<16)+((uint)D[3]<<24);
+ RecoverySize=D[0]+((uint)D[1]<<8)+((uint)D[2]<<16)+((uint)D[3]<<24);
+ RecoverySize*=512; // Sectors to size.
+ RecoveryPercent=ToPercent(RecoverySize,Tell());
}
}
}
- else
- if (hd->HeadType==FILE_HEAD)
- {
- if (hd->Flags & LHD_UNICODE)
- {
- EncodeFileName NameCoder;
- size_t Length=strlen(FileName);
- if (Length==hd->NameSize)
- {
- UtfToWide(FileName,hd->FileNameW,sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0])-1);
- WideToChar(hd->FileNameW,hd->FileName,sizeof(hd->FileName)/sizeof(hd->FileName[0])-1);
- ExtToInt(hd->FileName,hd->FileName);
- }
- else
- {
- Length++;
- NameCoder.Decode(FileName,(byte *)FileName+Length,
- hd->NameSize-Length,hd->FileNameW,
- sizeof(hd->FileNameW)/sizeof(hd->FileNameW[0]));
- }
- if (*hd->FileNameW==0)
- hd->Flags &= ~LHD_UNICODE;
- }
- else
- *hd->FileNameW=0;
-#ifndef SFX_MODULE
- ConvertNameCase(hd->FileName);
- ConvertNameCase(hd->FileNameW);
-#endif
- ConvertUnknownHeader();
- }
- if (hd->Flags & LHD_SALT)
- Raw.Get(hd->Salt,SALT_SIZE);
- hd->mtime.SetDos(hd->FileTime);
- hd->ctime.Reset();
- hd->atime.Reset();
- hd->arctime.Reset();
- if (hd->Flags & LHD_EXTTIME)
+ if ((hd->Flags & LHD_SALT)!=0)
+ Raw.GetB(hd->Salt,SIZE_SALT30);
+ hd->mtime.SetDos(FileTime);
+ if ((hd->Flags & LHD_EXTTIME)!=0)
{
- ushort Flags;
- Raw.Get(Flags);
+ ushort Flags=Raw.Get2();
RarTime *tbl[4];
- tbl[0]=&NewLhd.mtime;
- tbl[1]=&NewLhd.ctime;
- tbl[2]=&NewLhd.atime;
- tbl[3]=&NewLhd.arctime;
+ tbl[0]=&FileHead.mtime;
+ tbl[1]=&FileHead.ctime;
+ tbl[2]=&FileHead.atime;
+ tbl[3]=NULL; // Archive time is not used now.
for (int I=0;I<4;I++)
{
RarTime *CurTime=tbl[I];
uint rmode=Flags>>(3-I)*4;
- if ((rmode & 8)==0)
+ if ((rmode & 8)==0 || CurTime==NULL)
continue;
if (I!=0)
{
- uint DosTime;
- Raw.Get(DosTime);
+ uint DosTime=Raw.Get4();
CurTime->SetDos(DosTime);
}
RarLocalTime rlt;
@@ -299,21 +392,18 @@ size_t Archive::ReadHeader()
int count=rmode&3;
for (int J=0;J<count;J++)
{
- byte CurByte;
- Raw.Get(CurByte);
+ byte CurByte=Raw.Get1();
rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
}
CurTime->SetLocal(&rlt);
}
}
- NextBlockPos+=hd->FullPackSize;
- bool CRCProcessedOnly=(hd->Flags & LHD_COMMENT)!=0;
- HeaderCRC=~Raw.GetCRC(CRCProcessedOnly)&0xffff;
+ NextBlockPos+=hd->PackSize;
+ bool CRCProcessedOnly=hd->CommentInHeader;
+ ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly);
if (hd->HeadCRC!=HeaderCRC)
{
- if (hd->HeadType==NEWSUB_HEAD && strlen(hd->FileName)<ASIZE(hd->FileName)-5)
- strcat(hd->FileName,"- ???");
- BrokenFileHeader=true;
+ BrokenHeader=true;
ErrHandler.SetErrorCode(RARX_WARNING);
// If we have a broken encrypted header, we do not need to display
@@ -321,93 +411,102 @@ size_t Archive::ReadHeader()
// headers later in this function. Also such headers are unlikely
// to have anything sensible in file name field, so it is useless
// to display the file name.
- bool EncBroken=Decrypt && ShortBlock.HeadCRC!=(~Raw.GetCRC(false)&0xffff);
- if (!EncBroken)
+ if (!Decrypt)
{
#ifndef SHELL_EXT
- Log(Archive::FileName,St(MLogFileHead),IntNameToExt(hd->FileName));
- Alarm();
+ Log(Archive::FileName,St(MLogFileHead),hd->FileName);
#endif
}
}
}
break;
+ case HEAD_ENDARC:
+ *(BaseBlock *)&EndArcHead=ShortBlock;
+ EndArcHead.NextVolume=(EndArcHead.Flags & EARC_NEXT_VOLUME)!=0;
+ EndArcHead.DataCRC=(EndArcHead.Flags & EARC_DATACRC)!=0;
+ EndArcHead.RevSpace=(EndArcHead.Flags & EARC_REVSPACE)!=0;
+ EndArcHead.StoreVolNumber=(EndArcHead.Flags & EARC_VOLNUMBER)!=0;
+ if (EndArcHead.DataCRC)
+ EndArcHead.ArcDataCRC=Raw.Get4();
+ if (EndArcHead.StoreVolNumber)
+ VolNumber=EndArcHead.VolNumber=Raw.Get2();
+ break;
#ifndef SFX_MODULE
- case COMM_HEAD:
+ case HEAD3_CMT:
*(BaseBlock *)&CommHead=ShortBlock;
- Raw.Get(CommHead.UnpSize);
- Raw.Get(CommHead.UnpVer);
- Raw.Get(CommHead.Method);
- Raw.Get(CommHead.CommCRC);
+ CommHead.UnpSize=Raw.Get2();
+ CommHead.UnpVer=Raw.Get1();
+ CommHead.Method=Raw.Get1();
+ CommHead.CommCRC=Raw.Get2();
break;
- case SIGN_HEAD:
+ case HEAD3_SIGN:
*(BaseBlock *)&SignHead=ShortBlock;
- Raw.Get(SignHead.CreationTime);
- Raw.Get(SignHead.ArcNameSize);
- Raw.Get(SignHead.UserNameSize);
+ SignHead.CreationTime=Raw.Get4();
+ SignHead.ArcNameSize=Raw.Get2();
+ SignHead.UserNameSize=Raw.Get2();
break;
- case AV_HEAD:
+ case HEAD3_AV:
*(BaseBlock *)&AVHead=ShortBlock;
- Raw.Get(AVHead.UnpVer);
- Raw.Get(AVHead.Method);
- Raw.Get(AVHead.AVVer);
- Raw.Get(AVHead.AVInfoCRC);
+ AVHead.UnpVer=Raw.Get1();
+ AVHead.Method=Raw.Get1();
+ AVHead.AVVer=Raw.Get1();
+ AVHead.AVInfoCRC=Raw.Get4();
break;
- case PROTECT_HEAD:
+ case HEAD3_PROTECT:
*(BaseBlock *)&ProtectHead=ShortBlock;
- Raw.Get(ProtectHead.DataSize);
- Raw.Get(ProtectHead.Version);
- Raw.Get(ProtectHead.RecSectors);
- Raw.Get(ProtectHead.TotalBlocks);
- Raw.Get(ProtectHead.Mark,8);
+ ProtectHead.DataSize=Raw.Get4();
+ ProtectHead.Version=Raw.Get1();
+ ProtectHead.RecSectors=Raw.Get2();
+ ProtectHead.TotalBlocks=Raw.Get4();
+ Raw.GetB(ProtectHead.Mark,8);
NextBlockPos+=ProtectHead.DataSize;
- RecoverySectors=ProtectHead.RecSectors;
+ RecoverySize=ProtectHead.RecSectors*512;
break;
- case SUB_HEAD:
+ case HEAD3_OLDSERVICE:
*(BaseBlock *)&SubBlockHead=ShortBlock;
- Raw.Get(SubBlockHead.DataSize);
+ SubBlockHead.DataSize=Raw.Get4();
NextBlockPos+=SubBlockHead.DataSize;
- Raw.Get(SubBlockHead.SubType);
- Raw.Get(SubBlockHead.Level);
+ SubBlockHead.SubType=Raw.Get2();
+ SubBlockHead.Level=Raw.Get1();
switch(SubBlockHead.SubType)
{
case UO_HEAD:
*(SubBlockHeader *)&UOHead=SubBlockHead;
- Raw.Get(UOHead.OwnerNameSize);
- Raw.Get(UOHead.GroupNameSize);
- if (UOHead.OwnerNameSize>NM-1)
- UOHead.OwnerNameSize=NM-1;
- if (UOHead.GroupNameSize>NM-1)
- UOHead.GroupNameSize=NM-1;
- Raw.Get((byte *)UOHead.OwnerName,UOHead.OwnerNameSize);
- Raw.Get((byte *)UOHead.GroupName,UOHead.GroupNameSize);
+ UOHead.OwnerNameSize=Raw.Get2();
+ UOHead.GroupNameSize=Raw.Get2();
+ if (UOHead.OwnerNameSize>=ASIZE(UOHead.OwnerName))
+ UOHead.OwnerNameSize=ASIZE(UOHead.OwnerName)-1;
+ if (UOHead.GroupNameSize>=ASIZE(UOHead.GroupName))
+ UOHead.GroupNameSize=ASIZE(UOHead.GroupName)-1;
+ Raw.GetB(UOHead.OwnerName,UOHead.OwnerNameSize);
+ Raw.GetB(UOHead.GroupName,UOHead.GroupNameSize);
UOHead.OwnerName[UOHead.OwnerNameSize]=0;
UOHead.GroupName[UOHead.GroupNameSize]=0;
break;
case MAC_HEAD:
*(SubBlockHeader *)&MACHead=SubBlockHead;
- Raw.Get(MACHead.fileType);
- Raw.Get(MACHead.fileCreator);
+ MACHead.fileType=Raw.Get4();
+ MACHead.fileCreator=Raw.Get4();
break;
case EA_HEAD:
case BEEA_HEAD:
case NTACL_HEAD:
*(SubBlockHeader *)&EAHead=SubBlockHead;
- Raw.Get(EAHead.UnpSize);
- Raw.Get(EAHead.UnpVer);
- Raw.Get(EAHead.Method);
- Raw.Get(EAHead.EACRC);
+ EAHead.UnpSize=Raw.Get4();
+ EAHead.UnpVer=Raw.Get1();
+ EAHead.Method=Raw.Get1();
+ EAHead.EACRC=Raw.Get4();
break;
case STREAM_HEAD:
*(SubBlockHeader *)&StreamHead=SubBlockHead;
- Raw.Get(StreamHead.UnpSize);
- Raw.Get(StreamHead.UnpVer);
- Raw.Get(StreamHead.Method);
- Raw.Get(StreamHead.StreamCRC);
- Raw.Get(StreamHead.StreamNameSize);
- if (StreamHead.StreamNameSize>NM-1)
- StreamHead.StreamNameSize=NM-1;
- Raw.Get((byte *)StreamHead.StreamName,StreamHead.StreamNameSize);
+ StreamHead.UnpSize=Raw.Get4();
+ StreamHead.UnpVer=Raw.Get1();
+ StreamHead.Method=Raw.Get1();
+ StreamHead.StreamCRC=Raw.Get4();
+ StreamHead.StreamNameSize=Raw.Get2();
+ if (StreamHead.StreamNameSize>=ASIZE(StreamHead.StreamName))
+ StreamHead.StreamNameSize=ASIZE(StreamHead.StreamName)-1;
+ Raw.GetB(StreamHead.StreamName,StreamHead.StreamNameSize);
StreamHead.StreamName[StreamHead.StreamNameSize]=0;
break;
}
@@ -415,135 +514,649 @@ size_t Archive::ReadHeader()
#endif
default:
if (ShortBlock.Flags & LONG_BLOCK)
- {
- uint DataSize;
- Raw.Get(DataSize);
- NextBlockPos+=DataSize;
- }
+ NextBlockPos+=Raw.Get4();
break;
}
- HeaderCRC=~Raw.GetCRC(false)&0xffff;
- CurHeaderType=ShortBlock.HeadType;
- if (Decrypt)
- {
- NextBlockPos+=Raw.PaddedSize()+SALT_SIZE;
+
+ ushort HeaderCRC=Raw.GetCRC15(false);
- if (ShortBlock.HeadCRC!=HeaderCRC)
+ // Old AV header does not have header CRC properly set.
+ if (ShortBlock.HeadCRC!=HeaderCRC && ShortBlock.HeaderType!=HEAD3_SIGN &&
+ ShortBlock.HeaderType!=HEAD3_AV)
+ {
+ bool Recovered=false;
+ if (ShortBlock.HeaderType==HEAD_ENDARC && EndArcHead.RevSpace)
{
- bool Recovered=false;
- if (ShortBlock.HeadType==ENDARC_HEAD && (EndArcHead.Flags & EARC_REVSPACE)!=0)
- {
- // Last 7 bytes of recovered volume can contain zeroes, because
- // REV files store its own information (volume number, etc.) here.
- SaveFilePos SavePos(*this);
- int64 Length=Tell();
- Seek(Length-7,SEEK_SET);
- Recovered=true;
- for (int J=0;J<7;J++)
- if (GetByte()!=0)
- Recovered=false;
- }
- if (!Recovered)
+ // Last 7 bytes of recovered volume can contain zeroes, because
+ // REV files store its own information (volume number, etc.) here.
+ SaveFilePos SavePos(*this);
+ int64 Length=Tell();
+ Seek(Length-7,SEEK_SET);
+ Recovered=true;
+ for (int J=0;J<7;J++)
+ if (GetByte()!=0)
+ Recovered=false;
+ }
+ if (!Recovered)
+ {
+ BrokenHeader=true;
+ ErrHandler.SetErrorCode(RARX_CRC);
+
+ if (Decrypt)
{
#ifndef SILENT
Log(FileName,St(MEncrBadCRC),FileName);
#endif
-// Close();
FailedHeaderDecryption=true;
- BrokenFileHeader=true;
-
- ErrHandler.SetErrorCode(RARX_CRC);
- return(0);
+ return 0;
}
}
}
if (NextBlockPos<=CurBlockPos)
{
-#ifndef SHELL_EXT
- Log(FileName,St(MLogFileHead),"???");
-#endif
- BrokenFileHeader=true;
- ErrHandler.SetErrorCode(RARX_CRC);
- return(0);
+ BrokenHeaderMsg();
+ return 0;
}
- return(Raw.Size());
+
+ return Raw.Size();
}
-#ifndef SFX_MODULE
-size_t Archive::ReadOldHeader()
+size_t Archive::ReadHeader50()
{
RawRead Raw(this);
- if (CurBlockPos<=(int64)SFXSize)
+
+ bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD5;
+
+ if (Decrypt)
+ {
+#if defined(SHELL_EXT) || defined(RAR_NOCRYPT)
+ return(0);
+#else
+ RequestArcPassword();
+
+ byte HeadersInitV[SIZE_INITV];
+ if (Read(HeadersInitV,SIZE_INITV)!=SIZE_INITV)
+ {
+ UnexpEndArcMsg();
+ return(0);
+ }
+
+ byte PswCheck[SIZE_PSWCHECK];
+ HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck);
+ // Verify password validity.
+ if (CryptHead.UsePswCheck && memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0)
+ {
+ Log(FileName,St(MWrongPassword));
+ FailedHeaderDecryption=true;
+ ErrHandler.SetErrorCode(RARX_BADPWD);
+ return 0;
+ }
+
+ Raw.SetCrypt(&HeadersCrypt);
+#endif
+ }
+
+ // Header size must not occupy more than 3 variable length integer bytes
+ // resulting in 2 MB maximum header size, so here we read 4 byte CRC32
+ // followed by 3 bytes or less of header size.
+ const size_t FirstReadSize=7;
+ Raw.Read(FirstReadSize);
+
+ ShortBlock.Reset();
+ ShortBlock.HeadCRC=Raw.Get4();
+ uint SizeBytes=Raw.GetVSize(4);
+ uint64 BlockSize=Raw.GetV();
+
+ if (BlockSize==0 || SizeBytes==0)
{
- Raw.Read(SIZEOF_OLDMHD);
- Raw.Get(OldMhd.Mark,4);
- Raw.Get(OldMhd.HeadSize);
- Raw.Get(OldMhd.Flags);
- NextBlockPos=CurBlockPos+OldMhd.HeadSize;
- CurHeaderType=MAIN_HEAD;
+ UnexpEndArcMsg(); // Incomplete or broken block size field.
+ return 0;
}
- else
+
+ int SizeToRead=int(BlockSize);
+ SizeToRead-=FirstReadSize-SizeBytes-4; // Adjust overread size bytes if any.
+ uint HeaderSize=4+SizeBytes+(uint)BlockSize;
+
+ if (SizeToRead<0 || HeaderSize<SIZEOF_SHORTBLOCKHEAD5)
{
- OldFileHeader OldLhd;
- Raw.Read(SIZEOF_OLDLHD);
- NewLhd.HeadType=FILE_HEAD;
- Raw.Get(NewLhd.PackSize);
- Raw.Get(NewLhd.UnpSize);
- Raw.Get(OldLhd.FileCRC);
- Raw.Get(NewLhd.HeadSize);
- Raw.Get(NewLhd.FileTime);
- Raw.Get(OldLhd.FileAttr);
- Raw.Get(OldLhd.Flags);
- Raw.Get(OldLhd.UnpVer);
- Raw.Get(OldLhd.NameSize);
- Raw.Get(OldLhd.Method);
-
- NewLhd.Flags=OldLhd.Flags|LONG_BLOCK;
- NewLhd.UnpVer=(OldLhd.UnpVer==2) ? 13 : 10;
- NewLhd.Method=OldLhd.Method+0x30;
- NewLhd.NameSize=OldLhd.NameSize;
- NewLhd.FileAttr=OldLhd.FileAttr;
- NewLhd.FileCRC=OldLhd.FileCRC;
- NewLhd.FullPackSize=NewLhd.PackSize;
- NewLhd.FullUnpSize=NewLhd.UnpSize;
-
- NewLhd.mtime.SetDos(NewLhd.FileTime);
- NewLhd.ctime.Reset();
- NewLhd.atime.Reset();
- NewLhd.arctime.Reset();
-
- Raw.Read(OldLhd.NameSize);
- Raw.Get((byte *)NewLhd.FileName,OldLhd.NameSize);
- NewLhd.FileName[OldLhd.NameSize]=0;
- ConvertNameCase(NewLhd.FileName);
- *NewLhd.FileNameW=0;
+ BrokenHeaderMsg();
+ return 0;
+ }
+
+ Raw.Read(SizeToRead);
- if (Raw.Size()!=0)
- NextBlockPos=CurBlockPos+NewLhd.HeadSize+NewLhd.PackSize;
- CurHeaderType=FILE_HEAD;
+ if (Raw.Size()<HeaderSize)
+ {
+ UnexpEndArcMsg();
+ return 0;
+ }
+
+ uint HeaderCRC=Raw.GetCRC50();
+
+ ShortBlock.HeaderType=(HEADER_TYPE)Raw.GetV();
+ ShortBlock.Flags=(uint)Raw.GetV();
+ ShortBlock.SkipIfUnknown=(ShortBlock.Flags & HFL_SKIPIFUNKNOWN)!=0;
+ ShortBlock.HeadSize=HeaderSize;
+
+ CurHeaderType=ShortBlock.HeaderType;
+
+ bool BadCRC=(ShortBlock.HeadCRC!=HeaderCRC);
+ if (BadCRC)
+ {
+ BrokenHeaderMsg(); // Report, but attempt to process.
+
+ BrokenHeader=true;
+ ErrHandler.SetErrorCode(RARX_CRC);
+
+ if (Decrypt)
+ {
+#ifndef SILENT
+ Log(FileName,St(MEncrBadCRC),FileName);
+#endif
+ FailedHeaderDecryption=true;
+ return 0;
+ }
+ }
+
+ uint64 ExtraSize=0;
+ if ((ShortBlock.Flags & HFL_EXTRA)!=0)
+ {
+ ExtraSize=Raw.GetV();
+ if (ExtraSize>=ShortBlock.HeadSize)
+ {
+ BrokenHeaderMsg();
+ return 0;
+ }
+ }
+
+ uint64 DataSize=0;
+ if ((ShortBlock.Flags & HFL_DATA)!=0)
+ DataSize=Raw.GetV();
+
+ NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize)+DataSize;
+
+ switch(ShortBlock.HeaderType)
+ {
+ case HEAD_CRYPT:
+ {
+ *(BaseBlock *)&CryptHead=ShortBlock;
+ uint CryptVersion=(uint)Raw.GetV();
+ if (CryptVersion>CRYPT_VERSION)
+ {
+ UnkEncVerMsg(FileName);
+ return 0;
+ }
+ uint EncFlags=(uint)Raw.GetV();
+ CryptHead.UsePswCheck=(EncFlags & CHFL_CRYPT_PSWCHECK)!=0;
+ CryptHead.Lg2Count=Raw.Get1();
+ if (CryptHead.Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
+ {
+ UnkEncVerMsg(FileName);
+ return 0;
+ }
+ Raw.GetB(CryptHead.Salt,SIZE_SALT50);
+ if (CryptHead.UsePswCheck)
+ {
+ Raw.GetB(CryptHead.PswCheck,SIZE_PSWCHECK);
+
+ byte csum[SIZE_PSWCHECK_CSUM];
+ Raw.GetB(csum,SIZE_PSWCHECK_CSUM);
+
+ sha256_context ctx;
+ sha256_init(&ctx);
+ sha256_process(&ctx, CryptHead.PswCheck, SIZE_PSWCHECK);
+
+ byte Digest[SHA256_DIGEST_SIZE];
+ sha256_done(&ctx, Digest);
+
+ CryptHead.UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
+ }
+ Encrypted=true;
+ }
+ break;
+ case HEAD_MAIN:
+ {
+ MainHead.Reset();
+ *(BaseBlock *)&MainHead=ShortBlock;
+ uint ArcFlags=(uint)Raw.GetV();
+
+ Volume=(ArcFlags & MHFL_VOLUME)!=0;
+ Solid=(ArcFlags & MHFL_SOLID)!=0;
+ Locked=(ArcFlags & MHFL_LOCK)!=0;
+ Protected=(ArcFlags & MHFL_PROTECT)!=0;
+ Signed=false;
+ NewNumbering=true;
+
+ if ((ArcFlags & MHFL_VOLNUMBER)!=0)
+ VolNumber=(uint)Raw.GetV();
+ else
+ VolNumber=0;
+ FirstVolume=Volume && VolNumber==0;
+
+ if (ExtraSize!=0)
+ ProcessExtra50(&Raw,(size_t)ExtraSize,&MainHead);
+ }
+ break;
+ case HEAD_FILE:
+ case HEAD_SERVICE:
+ {
+ FileHeader *hd=ShortBlock.HeaderType==HEAD_FILE ? &FileHead:&SubHead;
+ hd->Reset();
+ *(BaseBlock *)hd=ShortBlock;
+
+ bool FileBlock=ShortBlock.HeaderType==HEAD_FILE;
+
+ hd->LargeFile=true;
+
+ hd->PackSize=DataSize;
+ hd->FileFlags=(uint)Raw.GetV();
+ hd->UnpSize=Raw.GetV();
+
+ hd->UnknownUnpSize=(hd->FileFlags & FHFL_UNPUNKNOWN)!=0;
+ if (hd->UnknownUnpSize)
+ hd->UnpSize=INT64NDF;
+
+ hd->MaxSize=Max(hd->PackSize,hd->UnpSize);
+ hd->FileAttr=(uint)Raw.GetV();
+ if ((hd->FileFlags & FHFL_UTIME)!=0)
+ hd->mtime=(time_t)Raw.Get4();
+
+ hd->FileHash.Type=HASH_NONE;
+ if ((hd->FileFlags & FHFL_CRC32)!=0)
+ {
+ hd->FileHash.Type=HASH_CRC32;
+ hd->FileHash.CRC32=Raw.Get4();
+ }
+
+ hd->RedirType=FSREDIR_NONE;
+
+ uint CompInfo=(uint)Raw.GetV();
+ hd->Method=(CompInfo>>7) & 7;
+ hd->UnpVer=CompInfo & 0x3f;
+
+ hd->HostOS=(byte)Raw.GetV();
+ size_t NameSize=(size_t)Raw.GetV();
+ hd->Inherited=(ShortBlock.Flags & HFL_INHERITED)!=0;
+
+ hd->HSType=HSYS_UNKNOWN;
+ if (hd->HostOS==HOST5_UNIX)
+ hd->HSType=HSYS_UNIX;
+ else
+ if (hd->HostOS==HOST5_WINDOWS)
+ hd->HSType=HSYS_WINDOWS;
+
+ hd->SplitBefore=(hd->Flags & HFL_SPLITBEFORE)!=0;
+ hd->SplitAfter=(hd->Flags & HFL_SPLITAFTER)!=0;
+ hd->SubBlock=(hd->Flags & HFL_CHILD)!=0;
+ hd->Solid=FileBlock && (CompInfo & FCI_SOLID)!=0;
+ hd->Dir=(hd->FileFlags & FHFL_DIRECTORY)!=0;
+ hd->WinSize=hd->Dir ? 0:size_t(0x20000)<<((CompInfo>>10)&0xf);
+
+ hd->CryptMethod=hd->Encrypted ? CRYPT_RAR50:CRYPT_NONE;
+
+ char FileName[NM*4];
+ size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
+ Raw.GetB((byte *)FileName,ReadNameSize);
+ FileName[ReadNameSize]=0;
+
+ UtfToWide(FileName,hd->FileName,ASIZE(hd->FileName)-1);
+
+ // Should do it before converting names, because extra fields can
+ // affect name processing, like in case of NTFS streams.
+ if (ExtraSize!=0)
+ ProcessExtra50(&Raw,(size_t)ExtraSize,hd);
+
+ if (FileBlock)
+ {
+#ifndef SFX_MODULE
+ ConvertNameCase(hd->FileName);
+#endif
+ ConvertFileHeader(hd);
+ }
+
+
+ if (BadCRC)
+ {
+ // Add the file name to broken header message displayed above.
+#ifndef SHELL_EXT
+ Log(Archive::FileName,St(MLogFileHead),hd->FileName);
+#endif
+ }
+ }
+ break;
+ case HEAD_ENDARC:
+ {
+ *(BaseBlock *)&EndArcHead=ShortBlock;
+ uint ArcFlags=(uint)Raw.GetV();
+ EndArcHead.NextVolume=(ArcFlags & EHFL_NEXTVOLUME)!=0;
+ EndArcHead.StoreVolNumber=false;
+ EndArcHead.DataCRC=false;
+ EndArcHead.RevSpace=false;
+ }
+ break;
+ }
+
+ if (NextBlockPos<=CurBlockPos)
+ {
+ BrokenHeaderMsg();
+ return 0;
+ }
+ return Raw.Size();
+}
+
+
+#if !defined(SHELL_EXT) && !defined(RAR_NOCRYPT)
+void Archive::RequestArcPassword()
+{
+ if (!Cmd->Password.IsSet())
+ {
+#ifdef RARDLL
+ if (Cmd->Callback!=NULL)
+ {
+ wchar PasswordW[MAXPASSWORD];
+ *PasswordW=0;
+ if (Cmd->Callback(UCM_NEEDPASSWORDW,Cmd->UserData,(LPARAM)PasswordW,ASIZE(PasswordW))==-1)
+ *PasswordW=0;
+ if (*PasswordW==0)
+ {
+ char PasswordA[MAXPASSWORD];
+ *PasswordA=0;
+ if (Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1)
+ *PasswordA=0;
+ GetWideName(PasswordA,NULL,PasswordW,ASIZE(PasswordW));
+ cleandata(PasswordA,sizeof(PasswordA));
+ }
+ Cmd->Password.Set(PasswordW);
+ cleandata(PasswordW,sizeof(PasswordW));
+ }
+ if (!Cmd->Password.IsSet())
+ {
+ Close();
+ Cmd->DllError=ERAR_MISSING_PASSWORD;
+ ErrHandler.Exit(RARX_USERBREAK);
+ }
+#else
+ if (!GetPassword(PASSWORD_ARCHIVE,FileName,&Cmd->Password))
+ {
+ Close();
+ ErrHandler.Exit(RARX_USERBREAK);
+ }
+#endif
}
- return(NextBlockPos>CurBlockPos ? Raw.Size():0);
}
#endif
-void Archive::ConvertNameCase(char *Name)
+void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
{
- if (Cmd->ConvertNames==NAMES_UPPERCASE)
+ // Read extra data from the end of block skipping any fields before it.
+ size_t ExtraStart=Raw->Size()-ExtraSize;
+ if (ExtraStart<Raw->GetPos())
+ return;
+ Raw->SetPos(ExtraStart);
+ while (Raw->DataLeft()>=2)
+ {
+ int64 FieldSize=Raw->GetV();
+ if (FieldSize==0 || Raw->DataLeft()==0 || FieldSize>(int64)Raw->DataLeft())
+ break;
+ size_t NextPos=size_t(Raw->GetPos()+FieldSize);
+ uint64 FieldType=Raw->GetV();
+
+ FieldSize=Raw->DataLeft(); // Field size without size and type fields.
+
+ if (bb->HeaderType==HEAD_MAIN)
+ {
+ MainHeader *hd=(MainHeader *)bb;
+ if (FieldType==MHEXTRA_LOCATOR)
+ {
+ hd->Locator=true;
+ uint Flags=(uint)Raw->GetV();
+ if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0)
+ {
+ uint64 Offset=Raw->GetV();
+ if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
+ hd->QOpenOffset=Offset+CurBlockPos;
+ }
+ if ((Flags & MHEXTRA_LOCATOR_RR)!=0)
+ {
+ uint64 Offset=Raw->GetV();
+ if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
+ hd->RROffset=Offset+CurBlockPos;
+ }
+ }
+ }
+
+ if (bb->HeaderType==HEAD_FILE || bb->HeaderType==HEAD_SERVICE)
+ {
+ FileHeader *hd=(FileHeader *)bb;
+ switch(FieldType)
+ {
+ case FHEXTRA_CRYPT:
+ {
+ FileHeader *hd=(FileHeader *)bb;
+ uint EncVersion=(uint)Raw->GetV();
+ if (EncVersion > CRYPT_VERSION)
+ UnkEncVerMsg(hd->FileName);
+ else
+ {
+ uint Flags=(uint)Raw->GetV();
+ hd->UsePswCheck=(Flags & FHEXTRA_CRYPT_PSWCHECK)!=0;
+ hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0;
+ hd->Lg2Count=Raw->Get1();
+ if (hd->Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
+ UnkEncVerMsg(hd->FileName);
+ Raw->GetB(hd->Salt,SIZE_SALT50);
+ Raw->GetB(hd->InitV,SIZE_INITV);
+ if (hd->UsePswCheck)
+ {
+ Raw->GetB(hd->PswCheck,SIZE_PSWCHECK);
+
+ // It is important to know if password check data is valid.
+ // If it is damaged and header CRC32 fails to detect it,
+ // archiver would refuse to decompress a possibly valid file.
+ // Since we want to be sure distinguishing a wrong password
+ // or corrupt file data, we use 64-bit password check data
+ // and to control its validity we use 32 bits of password
+ // check data SHA-256 additionally to 32-bit header CRC32.
+ byte csum[SIZE_PSWCHECK_CSUM];
+ Raw->GetB(csum,SIZE_PSWCHECK_CSUM);
+
+ sha256_context ctx;
+ sha256_init(&ctx);
+ sha256_process(&ctx, hd->PswCheck, SIZE_PSWCHECK);
+
+ byte Digest[SHA256_DIGEST_SIZE];
+ sha256_done(&ctx, Digest);
+
+ hd->UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0;
+ }
+ hd->SaltSet=true;
+ hd->CryptMethod=CRYPT_RAR50;
+ hd->Encrypted=true;
+ }
+ }
+ break;
+ case FHEXTRA_HASH:
+ {
+ FileHeader *hd=(FileHeader *)bb;
+ uint Type=(uint)Raw->GetV();
+ if (Type==FHEXTRA_HASH_BLAKE2)
+ {
+ hd->FileHash.Type=HASH_BLAKE2;
+ Raw->GetB(hd->FileHash.Digest,BLAKE2_DIGEST_SIZE);
+ }
+ }
+ break;
+ case FHEXTRA_HTIME:
+ if (FieldSize>=9)
+ {
+ byte Flags=(byte)Raw->GetV();
+ bool UnixTime=(Flags & FHEXTRA_HTIME_UNIXTIME)!=0;
+ if ((Flags & FHEXTRA_HTIME_MTIME)!=0)
+ if (UnixTime)
+ hd->mtime=(time_t)Raw->Get4();
+ else
+ hd->mtime.SetRaw(Raw->Get8());
+ if ((Flags & FHEXTRA_HTIME_CTIME)!=0)
+ if (UnixTime)
+ hd->ctime=(time_t)Raw->Get4();
+ else
+ hd->ctime.SetRaw(Raw->Get8());
+ if ((Flags & FHEXTRA_HTIME_ATIME)!=0)
+ if (UnixTime)
+ hd->atime=(time_t)Raw->Get4();
+ else
+ hd->atime.SetRaw(Raw->Get8());
+ }
+ break;
+ case FHEXTRA_VERSION:
+ if (FieldSize>=1)
+ {
+ Raw->GetV(); // Skip flags field.
+ uint Version=(uint)Raw->GetV();
+ if (Version!=0)
+ {
+ hd->Version=true;
+
+ wchar VerText[20];
+ swprintf(VerText,ASIZE(VerText),L";%u",Version);
+ wcsncatz(FileHead.FileName,VerText,ASIZE(FileHead.FileName));
+ }
+ }
+ break;
+ case FHEXTRA_REDIR:
+ {
+ hd->RedirType=(FILE_SYSTEM_REDIRECT)Raw->GetV();
+ uint Flags=(uint)Raw->GetV();
+ hd->DirTarget=(Flags & FHEXTRA_REDIR_DIR)!=0;
+ size_t NameSize=(size_t)Raw->GetV();
+
+ char UtfName[NM*4];
+ *UtfName=0;
+ if (NameSize<ASIZE(UtfName)-1)
+ {
+ Raw->GetB(UtfName,NameSize);
+ UtfName[NameSize]=0;
+ }
+ UtfToWide(UtfName,hd->RedirName,ASIZE(hd->RedirName));
+ }
+ break;
+ case FHEXTRA_UOWNER:
+ {
+ uint Flags=(uint)Raw->GetV();
+ hd->UnixOwnerNumeric=(Flags & FHEXTRA_UOWNER_NUMUID)!=0;
+ hd->UnixGroupNumeric=(Flags & FHEXTRA_UOWNER_NUMGID)!=0;
+ *hd->UnixOwnerName=*hd->UnixGroupName=0;
+ if ((Flags & FHEXTRA_UOWNER_UNAME)!=0)
+ {
+ size_t Length=(size_t)Raw->GetV();
+ Length=Min(Length,ASIZE(hd->UnixOwnerName)-1);
+ Raw->GetB(hd->UnixOwnerName,Length);
+ hd->UnixOwnerName[Length]=0;
+ }
+ if ((Flags & FHEXTRA_UOWNER_GNAME)!=0)
+ {
+ size_t Length=(size_t)Raw->GetV();
+ Length=Min(Length,ASIZE(hd->UnixGroupName)-1);
+ Raw->GetB(hd->UnixGroupName,Length);
+ hd->UnixGroupName[Length]=0;
+ }
+#ifdef _UNIX
+ if (hd->UnixOwnerNumeric)
+ hd->UnixOwnerID=(uid_t)Raw->GetV();
+ if (hd->UnixGroupNumeric)
+ hd->UnixGroupID=(gid_t)Raw->GetV();
+#else
+ // Need these fields in Windows too for 'list' command,
+ // but uid_t and gid_t are not defined.
+ if (hd->UnixOwnerNumeric)
+ hd->UnixOwnerID=(uint)Raw->GetV();
+ if (hd->UnixGroupNumeric)
+ hd->UnixGroupID=(uint)Raw->GetV();
+#endif
+ hd->UnixOwnerSet=true;
+ }
+ break;
+ case FHEXTRA_SUBDATA:
+ {
+ hd->SubData.Alloc((size_t)FieldSize);
+ Raw->GetB(hd->SubData.Addr(0),(size_t)FieldSize);
+ }
+ break;
+ }
+ }
+
+ Raw->SetPos(NextPos);
+ }
+}
+
+
+#ifndef SFX_MODULE
+size_t Archive::ReadHeader14()
+{
+ RawRead Raw(this);
+ if (CurBlockPos<=(int64)SFXSize)
{
- IntToExt(Name,Name);
- strupper(Name);
- ExtToInt(Name,Name);
+ Raw.Read(SIZEOF_MAINHEAD14);
+ MainHead.Reset();
+ byte Mark[4];
+ Raw.GetB(Mark,4);
+ uint HeadSize=Raw.Get2();
+ byte Flags=Raw.Get1();
+ NextBlockPos=CurBlockPos+HeadSize;
+ CurHeaderType=HEAD_MAIN;
+
+ Volume=(Flags & MHD_VOLUME)!=0;
+ Solid=(Flags & MHD_SOLID)!=0;
+ Locked=(Flags & MHD_LOCK)!=0;
+ MainHead.CommentInHeader=(Flags & MHD_COMMENT)!=0;
+ MainHead.PackComment=(Flags & MHD_PACK_COMMENT)!=0;
}
- if (Cmd->ConvertNames==NAMES_LOWERCASE)
+ else
{
- IntToExt(Name,Name);
- strlower(Name);
- ExtToInt(Name,Name);
+ Raw.Read(SIZEOF_FILEHEAD14);
+ FileHead.Reset();
+
+ FileHead.HeaderType=HEAD_FILE;
+ FileHead.DataSize=Raw.Get4();
+ FileHead.UnpSize=Raw.Get4();
+ FileHead.FileHash.Type=HASH_RAR14;
+ FileHead.FileHash.CRC32=Raw.Get2();
+ FileHead.HeadSize=Raw.Get2();
+ uint FileTime=Raw.Get4();
+ FileHead.FileAttr=Raw.Get1();
+ FileHead.Flags=Raw.Get1()|LONG_BLOCK;
+ FileHead.UnpVer=(Raw.Get1()==2) ? 13 : 10;
+ size_t NameSize=Raw.Get1();
+ FileHead.Method=Raw.Get1();
+
+ FileHead.SplitBefore=(FileHead.Flags & LHD_SPLIT_BEFORE)!=0;
+ FileHead.SplitAfter=(FileHead.Flags & LHD_SPLIT_AFTER)!=0;
+ FileHead.Encrypted=(FileHead.Flags & LHD_PASSWORD)!=0;
+ FileHead.CryptMethod=FileHead.Encrypted ? CRYPT_RAR13:CRYPT_NONE;
+
+ FileHead.PackSize=FileHead.DataSize;
+ FileHead.WinSize=0x10000;
+
+ FileHead.mtime.SetDos(FileTime);
+
+ Raw.Read(NameSize);
+
+ char FileName[NM];
+ Raw.GetB((byte *)FileName,Min(NameSize,ASIZE(FileName)));
+ FileName[NameSize]=0;
+ CharToWide(FileName,FileHead.FileName,ASIZE(FileHead.FileName));
+ ConvertNameCase(FileHead.FileName);
+
+ if (Raw.Size()!=0)
+ NextBlockPos=CurBlockPos+FileHead.HeadSize+FileHead.PackSize;
+ CurHeaderType=HEAD_FILE;
}
+ return(NextBlockPos>CurBlockPos ? Raw.Size():0);
}
+#endif
#ifndef SFX_MODULE
@@ -559,39 +1172,15 @@ void Archive::ConvertNameCase(wchar *Name)
bool Archive::IsArcDir()
{
- return((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY);
-}
-
-
-bool Archive::IsArcLabel()
-{
- return(NewLhd.HostOS<=HOST_WIN32 && (NewLhd.FileAttr & 8));
+ return FileHead.Dir;
}
void Archive::ConvertAttributes()
{
#if defined(_WIN_ALL) || defined(_EMX)
- switch(NewLhd.HostOS)
- {
- case HOST_MSDOS:
- case HOST_OS2:
- case HOST_WIN32:
- break;
- case HOST_UNIX:
- case HOST_BEOS:
- if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
- NewLhd.FileAttr=0x10;
- else
- NewLhd.FileAttr=0x20;
- break;
- default:
- if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
- NewLhd.FileAttr=0x10;
- else
- NewLhd.FileAttr=0x20;
- break;
- }
+ if (FileHead.HSType!=HSYS_WINDOWS)
+ FileHead.FileAttr=FileHead.Dir ? 0x10 : 0x20;
#endif
#ifdef _UNIX
// umask defines which permission bits must not be set by default
@@ -610,68 +1199,70 @@ void Archive::ConvertAttributes()
umask(mask);
}
- switch(NewLhd.HostOS)
+ switch(FileHead.HSType)
{
- case HOST_MSDOS:
- case HOST_OS2:
- case HOST_WIN32:
+ case HSYS_WINDOWS:
{
// Mapping MSDOS, OS/2 and Windows file attributes to Unix.
- if (NewLhd.FileAttr & 0x10) // FILE_ATTRIBUTE_DIRECTORY
+ if (FileHead.FileAttr & 0x10) // FILE_ATTRIBUTE_DIRECTORY
{
// For directories we use 0777 mask.
- NewLhd.FileAttr=0777 & ~mask;
+ FileHead.FileAttr=0777 & ~mask;
}
else
- if (NewLhd.FileAttr & 1) // FILE_ATTRIBUTE_READONLY
+ if (FileHead.FileAttr & 1) // FILE_ATTRIBUTE_READONLY
{
// For read only files we use 0444 mask with 'w' bits turned off.
- NewLhd.FileAttr=0444 & ~mask;
+ FileHead.FileAttr=0444 & ~mask;
}
else
{
// umask does not set +x for regular files, so we use 0666
// instead of 0777 as for directories.
- NewLhd.FileAttr=0666 & ~mask;
+ FileHead.FileAttr=0666 & ~mask;
}
}
break;
- case HOST_UNIX:
- case HOST_BEOS:
+ case HSYS_UNIX:
break;
default:
- if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
- NewLhd.FileAttr=0x41ff & ~mask;
+ if (FileHead.Dir)
+ FileHead.FileAttr=0x41ff & ~mask;
else
- NewLhd.FileAttr=0x81b6 & ~mask;
+ FileHead.FileAttr=0x81b6 & ~mask;
break;
}
#endif
}
-void Archive::ConvertUnknownHeader()
+void Archive::ConvertFileHeader(FileHeader *hd)
{
- if (NewLhd.UnpVer<20 && (NewLhd.FileAttr & 0x10))
- NewLhd.Flags|=LHD_DIRECTORY;
- if (NewLhd.HostOS>=HOST_MAX)
- {
- if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY)
- NewLhd.FileAttr=0x10;
+ if (Format==RARFMT15 && hd->UnpVer<20 && (hd->FileAttr & 0x10))
+ hd->Dir=true;
+ if (hd->HSType==HSYS_UNKNOWN)
+ if (hd->Dir)
+ hd->FileAttr=0x10;
else
- NewLhd.FileAttr=0x20;
- }
- for (char *s=NewLhd.FileName;*s!=0;s=charnext(s))
+ hd->FileAttr=0x20;
+
+ for (wchar *s=hd->FileName;*s!=0;s++)
{
- if (*s=='/' || *s=='\\')
- *s=CPATHDIVIDER;
-#if defined(_APPLE) && !defined(UNICODE_SUPPORTED)
- if ((byte)*s<32 || (byte)*s>127)
+#ifdef _UNIX
+ // Backslash is the invalid character for Windows file headers,
+ // but it can present in Unix file names extracted in Unix.
+ if (*s=='\\' && Format==RARFMT50 && hd->HSType==HSYS_WINDOWS)
*s='_';
#endif
#if defined(_WIN_ALL) || defined(_EMX)
+ // RAR 5.0 archives do not use '\' as path separator, so if we see it,
+ // it means that it is a part of Unix file name, which we cannot
+ // extract in Windows.
+ if (*s=='\\' && Format==RARFMT50)
+ *s='_';
+
// ':' in file names is allowed in Unix, but not in Windows.
// Even worse, file data will be written to NTFS stream on NTFS,
// so automatic name correction on file create error in extraction
@@ -681,76 +1272,87 @@ void Archive::ConvertUnknownHeader()
*s='_';
#endif
+ // This code must be performed only after other path separator checks,
+ // because it produces backslashes illegal for some of checks above.
+ // Backslash is allowed in file names in Unix, but not in Windows.
+ // Forward slash is not allowed in both systems. In RAR 5.0 we use
+ // the backslash as universal path separator.
+ if (*s=='/' || *s=='\\' && hd->HSType!=HSYS_UNIX && Format!=RARFMT50)
+ *s=CPATHDIVIDER;
}
+}
- for (wchar *s=NewLhd.FileNameW;*s!=0;s++)
- {
- if (*s=='/' || *s=='\\')
- *s=CPATHDIVIDER;
-#if defined(_WIN_ALL) || defined(_EMX)
- // ':' in file names is allowed in Unix, but not in Windows.
- // Even worse, file data will be written to NTFS stream on NTFS,
- // so automatic name correction on file create error in extraction
- // routine does not work. In Windows and DOS versions we better
- // replace ':' now.
- if (*s==':')
- *s='_';
-#endif
- }
+int64 Archive::GetStartPos()
+{
+ int64 StartPos=SFXSize+MarkHead.HeadSize;
+ if (Format==RARFMT15)
+ StartPos+=MainHead.HeadSize;
+ else // RAR 5.0.
+ StartPos+=CryptHead.HeadSize+FullHeaderSize(MainHead.HeadSize);
+ return StartPos;
}
#ifndef SHELL_EXT
bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile)
{
- if (HeaderCRC!=SubHead.HeadCRC)
+ if (BrokenHeader)
{
#ifndef SHELL_EXT
Log(FileName,St(MSubHeadCorrupt));
#endif
ErrHandler.SetErrorCode(RARX_CRC);
- return(false);
+ return false;
}
- if (SubHead.Method<0x30 || SubHead.Method>0x35 || SubHead.UnpVer>/*PACK_VER*/36)
+ if (SubHead.Method>5 || SubHead.UnpVer>(Format==RARFMT50 ? VER_UNPACK5:VER_UNPACK))
{
#ifndef SHELL_EXT
Log(FileName,St(MSubHeadUnknown));
#endif
- return(false);
+ return false;
}
- if (SubHead.PackSize==0 && (SubHead.Flags & LHD_SPLIT_AFTER)==0)
- return(true);
+ if (SubHead.PackSize==0 && !SubHead.SplitAfter)
+ return true;
SubDataIO.Init();
Unpack Unpack(&SubDataIO);
- Unpack.Init();
+ Unpack.Init(SubHead.WinSize,false);
if (DestFile==NULL)
{
- UnpData->Alloc(SubHead.UnpSize);
- SubDataIO.SetUnpackToMemory(&(*UnpData)[0],SubHead.UnpSize);
+ if (SubHead.UnpSize>0x1000000)
+ {
+ // So huge allocation must never happen in valid archives.
+#ifndef SHELL_EXT
+ Log(FileName,St(MSubHeadUnknown));
+#endif
+ return false;
+ }
+ UnpData->Alloc((size_t)SubHead.UnpSize);
+ SubDataIO.SetUnpackToMemory(&(*UnpData)[0],(uint)SubHead.UnpSize);
}
- if (SubHead.Flags & LHD_PASSWORD)
+ if (SubHead.Encrypted)
if (Cmd->Password.IsSet())
- SubDataIO.SetEncryption(SubHead.UnpVer,&Cmd->Password,
- (SubHead.Flags & LHD_SALT) ? SubHead.Salt:NULL,false,
- SubHead.UnpVer>=36);
+ SubDataIO.SetEncryption(false,SubHead.CryptMethod,&Cmd->Password,
+ SubHead.SaltSet ? SubHead.Salt:NULL,SubHead.InitV,
+ SubHead.Lg2Count,SubHead.PswCheck,SubHead.HashKey);
else
- return(false);
+ return false;
+ SubDataIO.UnpHash.Init(SubHead.FileHash.Type,1);
SubDataIO.SetPackedSizeToRead(SubHead.PackSize);
SubDataIO.EnableShowProgress(false);
SubDataIO.SetFiles(this,DestFile);
- SubDataIO.UnpVolume=(SubHead.Flags & LHD_SPLIT_AFTER)!=0;
+ SubDataIO.UnpVolume=SubHead.SplitAfter;
SubDataIO.SetSubHeader(&SubHead,NULL);
Unpack.SetDestSize(SubHead.UnpSize);
- if (SubHead.Method==0x30)
+ if (SubHead.Method==0)
CmdExtract::UnstoreFile(SubDataIO,SubHead.UnpSize);
else
Unpack.DoUnpack(SubHead.UnpVer,false);
- if (SubHead.FileCRC!=~SubDataIO.UnpFileCRC)
+ if (!SubDataIO.UnpHash.Cmp(&SubHead.FileHash,SubHead.UseHashKey ? SubHead.HashKey:NULL))
{
#ifndef SHELL_EXT
Log(FileName,St(MSubHeadDataCRC),SubHead.FileName);
@@ -758,8 +1360,8 @@ bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile)
ErrHandler.SetErrorCode(RARX_CRC);
if (UnpData!=NULL)
UnpData->Reset();
- return(false);
+ return false;
}
- return(true);
+ return true;
}
#endif
diff --git a/src/thirdparty/unrar/array.hpp b/src/thirdparty/unrar/array.hpp
index f3821bc47..63d89c31e 100644
--- a/src/thirdparty/unrar/array.hpp
+++ b/src/thirdparty/unrar/array.hpp
@@ -9,12 +9,15 @@ template <class T> class Array
T *Buffer;
size_t BufSize;
size_t AllocSize;
+ size_t MaxSize;
public:
Array();
Array(size_t Size);
+ Array(const Array &Src); // Copy constructor.
~Array();
inline void CleanData();
- inline T& operator [](size_t Item);
+ inline T& operator [](size_t Item) const;
+ inline T* operator + (size_t Pos);
inline size_t Size(); // Returns the size in items, not in bytes.
void Add(size_t Items);
void Alloc(size_t Items);
@@ -22,7 +25,9 @@ template <class T> class Array
void SoftReset();
void operator = (Array<T> &Src);
void Push(T Item);
- T* Addr() {return(Buffer);}
+ void Append(T *Item,size_t Count);
+ T* Addr(size_t Item) {return Buffer+Item;}
+ void SetMaxSize(size_t Size) {MaxSize=Size;}
};
template <class T> void Array<T>::CleanData()
@@ -30,6 +35,7 @@ template <class T> void Array<T>::CleanData()
Buffer=NULL;
BufSize=0;
AllocSize=0;
+ MaxSize=0;
}
@@ -41,11 +47,18 @@ template <class T> Array<T>::Array()
template <class T> Array<T>::Array(size_t Size)
{
- Buffer=(T *)malloc(sizeof(T)*Size);
- if (Buffer==NULL && Size!=0)
- ErrHandler.MemoryError();
+ CleanData();
+ Add(Size);
+}
+
- AllocSize=BufSize=Size;
+// Copy constructor in case we need to pass an object as value.
+template <class T> Array<T>::Array(const Array &Src)
+{
+ CleanData();
+ Alloc(Src.BufSize);
+ if (Src.BufSize!=0)
+ memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
}
@@ -56,15 +69,21 @@ template <class T> Array<T>::~Array()
}
-template <class T> inline T& Array<T>::operator [](size_t Item)
+template <class T> inline T& Array<T>::operator [](size_t Item) const
+{
+ return Buffer[Item];
+}
+
+
+template <class T> inline T* Array<T>::operator +(size_t Pos)
{
- return(Buffer[Item]);
+ return Buffer+Pos;
}
template <class T> inline size_t Array<T>::Size()
{
- return(BufSize);
+ return BufSize;
}
@@ -73,12 +92,19 @@ template <class T> void Array<T>::Add(size_t Items)
BufSize+=Items;
if (BufSize>AllocSize)
{
+ if (MaxSize!=0 && BufSize>MaxSize)
+ {
+ ErrHandler.GeneralErrMsg(L"Maximum allowed array size (%u) is exceeded",MaxSize);
+ ErrHandler.MemoryError();
+ }
+
size_t Suggested=AllocSize+AllocSize/4+32;
size_t NewSize=Max(BufSize,Suggested);
- Buffer=(T *)realloc(Buffer,NewSize*sizeof(T));
- if (Buffer==NULL)
+ T *NewBuffer=(T *)realloc(Buffer,NewSize*sizeof(T));
+ if (NewBuffer==NULL)
ErrHandler.MemoryError();
+ Buffer=NewBuffer;
AllocSize=NewSize;
}
}
@@ -105,7 +131,7 @@ template <class T> void Array<T>::Reset()
}
-// Reste buffer size, but preserve already allocated memory if any,
+// Reset buffer size, but preserve already allocated memory if any,
// so we can reuse it without wasting time to allocation.
template <class T> void Array<T>::SoftReset()
{
@@ -128,4 +154,12 @@ template <class T> void Array<T>::Push(T Item)
(*this)[Size()-1]=Item;
}
+
+template <class T> void Array<T>::Append(T *Items,size_t Count)
+{
+ size_t CurSize=Size();
+ Add(Count);
+ memcpy(Buffer+CurSize,Items,Count*sizeof(T));
+}
+
#endif
diff --git a/src/thirdparty/unrar/beosea.cpp b/src/thirdparty/unrar/beosea.cpp
deleted file mode 100644
index 3b6e862e4..000000000
--- a/src/thirdparty/unrar/beosea.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-
-
-void ExtractBeEA(Archive &Arc,char *FileName)
-{
- if (Arc.HeaderCRC!=Arc.EAHead.HeadCRC)
- {
- Log(Arc.FileName,St(MEABroken),FileName);
- ErrHandler.SetErrorCode(RARX_CRC);
- return;
- }
- if (Arc.EAHead.Method<0x31 || Arc.EAHead.Method>0x35 || Arc.EAHead.UnpVer>PACK_VER)
- {
- Log(Arc.FileName,St(MEAUnknHeader),FileName);
- return;
- }
-
- ComprDataIO DataIO;
- Unpack Unpack(&DataIO);
- Unpack.Init();
-
- Array<byte> UnpData(Arc.EAHead.UnpSize);
- DataIO.SetUnpackToMemory(&UnpData[0],Arc.EAHead.UnpSize);
- DataIO.SetPackedSizeToRead(Arc.EAHead.DataSize);
- DataIO.EnableShowProgress(false);
- DataIO.SetFiles(&Arc,NULL);
- Unpack.SetDestSize(Arc.EAHead.UnpSize);
- Unpack.DoUnpack(Arc.EAHead.UnpVer,false);
-
- if (Arc.EAHead.EACRC!=~DataIO.UnpFileCRC)
- {
- Log(Arc.FileName,St(MEABroken),FileName);
- ErrHandler.SetErrorCode(RARX_CRC);
- return;
- }
- int fd = open(FileName,O_WRONLY);
- if (fd==-1)
- {
- Log(Arc.FileName,St(MCannotSetEA),FileName);
- ErrHandler.SetErrorCode(RARX_WARNING);
- return;
- }
-
- int AttrPos=0;
- while (AttrPos<Arc.EAHead.UnpSize)
- {
- unsigned char *CurItem=&UnpData[AttrPos];
- int NameSize=CurItem[0]+((int)CurItem[1]<<8);
- int Type=CurItem[2]+((int)CurItem[3]<<8)+((int)CurItem[4]<<16)+((int)CurItem[5]<<24);
- int Size=CurItem[6]+((int)CurItem[7]<<8)+((int)CurItem[8]<<16)+((int)CurItem[9]<<24);
- char Name[1024];
- if (NameSize>=sizeof(Name))
- {
- Log(Arc.FileName,St(MCannotSetEA),FileName);
- ErrHandler.SetErrorCode(RARX_WARNING);
- break;
- }
- memcpy(Name,CurItem+10,NameSize);
- Name[NameSize]=0;
- if (fs_write_attr(fd,Name,Type,0,CurItem+10+NameSize,Size)==-1)
- {
- Log(Arc.FileName,St(MCannotSetEA),FileName);
- ErrHandler.SetErrorCode(RARX_WARNING);
- break;
- }
- AttrPos+=10+NameSize+Size;
- }
- close(fd);
- mprintf(St(MShowEA));
-}
-
-
-void ExtractBeEANew(Archive &Arc,char *FileName)
-{
- Array<byte> SubData;
- if (!Arc.ReadSubData(&SubData,NULL))
- return;
-
- int fd = open(FileName,O_WRONLY);
- if (fd==-1)
- {
- Log(Arc.FileName,St(MCannotSetEA),FileName);
- ErrHandler.SetErrorCode(RARX_WARNING);
- return;
- }
-
- int AttrPos=0;
- while (AttrPos<Arc.EAHead.UnpSize)
- {
- unsigned char *CurItem=&SubData[AttrPos];
- int NameSize=CurItem[0]+((int)CurItem[1]<<8);
- int Type=CurItem[2]+((int)CurItem[3]<<8)+((int)CurItem[4]<<16)+((int)CurItem[5]<<24);
- int Size=CurItem[6]+((int)CurItem[7]<<8)+((int)CurItem[8]<<16)+((int)CurItem[9]<<24);
- char Name[1024];
- if (NameSize>=sizeof(Name))
- {
- Log(Arc.FileName,St(MCannotSetEA),FileName);
- ErrHandler.SetErrorCode(RARX_WARNING);
- break;
- }
- memcpy(Name,CurItem+10,NameSize);
- Name[NameSize]=0;
- if (fs_write_attr(fd,Name,Type,0,CurItem+10+NameSize,Size)==-1)
- {
- Log(Arc.FileName,St(MCannotSetEA),FileName);
- ErrHandler.SetErrorCode(RARX_WARNING);
- break;
- }
- AttrPos+=10+NameSize+Size;
- }
- close(fd);
- mprintf(St(MShowEA));
-}
-
diff --git a/src/thirdparty/unrar/blake2s.cpp b/src/thirdparty/unrar/blake2s.cpp
new file mode 100644
index 000000000..c66b2e719
--- /dev/null
+++ b/src/thirdparty/unrar/blake2s.cpp
@@ -0,0 +1,184 @@
+// Based on public domain code written in 2012 by Samuel Neves
+
+#include "rar.hpp"
+
+#ifdef USE_SSE
+#include "blake2s_sse.cpp"
+#endif
+
+static void blake2s_init_param( blake2s_state *S, uint32 node_offset, uint32 node_depth);
+static void blake2s_update( blake2s_state *S, const byte *in, size_t inlen );
+static void blake2s_final( blake2s_state *S, byte *digest );
+
+#include "blake2sp.cpp"
+
+static const uint32 blake2s_IV[8] =
+{
+ 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
+ 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
+};
+
+static const byte blake2s_sigma[10][16] =
+{
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
+ { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
+ { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
+ { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
+ { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
+ { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
+ { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
+ { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
+ { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
+};
+
+static inline void blake2s_set_lastnode( blake2s_state *S )
+{
+ S->f[1] = ~0U;
+}
+
+
+/* Some helper functions, not necessarily useful */
+static inline void blake2s_set_lastblock( blake2s_state *S )
+{
+ if( S->last_node ) blake2s_set_lastnode( S );
+
+ S->f[0] = ~0U;
+}
+
+
+static inline void blake2s_increment_counter( blake2s_state *S, const uint32 inc )
+{
+ S->t[0] += inc;
+ S->t[1] += ( S->t[0] < inc );
+}
+
+
+/* init2 xors IV with input parameter block */
+void blake2s_init_param( blake2s_state *S, uint32 node_offset, uint32 node_depth)
+{
+ memset( S, 0, sizeof( blake2s_state ) );
+ for( int i = 0; i < 8; ++i )
+ S->h[i] = blake2s_IV[i];
+
+ S->h[0] ^= 0x02080020; // We use BLAKE2sp parameters block.
+ S->h[2] ^= node_offset;
+ S->h[3] ^= (node_depth<<16)|0x20000000;
+}
+
+
+static _forceinline uint32 rotr32( const uint32 w, const unsigned c )
+{
+ return ( w >> c ) | ( w << ( 32 - c ) );
+}
+
+
+#define G(r,i,m,a,b,c,d) \
+ a = a + b + m[blake2s_sigma[r][2*i+0]]; \
+ d = rotr32(d ^ a, 16); \
+ c = c + d; \
+ b = rotr32(b ^ c, 12); \
+ a = a + b + m[blake2s_sigma[r][2*i+1]]; \
+ d = rotr32(d ^ a, 8); \
+ c = c + d; \
+ b = rotr32(b ^ c, 7);
+
+
+static void blake2s_compress( blake2s_state *S, const byte block[BLAKE2S_BLOCKBYTES] )
+{
+ uint32 m[16];
+ uint32 v[16];
+
+ for( size_t i = 0; i < 16; ++i )
+ m[i] = RawGet4( block + i * 4 );
+
+ for( size_t i = 0; i < 8; ++i )
+ v[i] = S->h[i];
+
+ v[ 8] = blake2s_IV[0];
+ v[ 9] = blake2s_IV[1];
+ v[10] = blake2s_IV[2];
+ v[11] = blake2s_IV[3];
+ v[12] = S->t[0] ^ blake2s_IV[4];
+ v[13] = S->t[1] ^ blake2s_IV[5];
+ v[14] = S->f[0] ^ blake2s_IV[6];
+ v[15] = S->f[1] ^ blake2s_IV[7];
+
+ for ( uint r = 0; r <= 9; ++r ) // No gain on i7 if unrolled, but exe size grows.
+ {
+ G(r,0,m,v[ 0],v[ 4],v[ 8],v[12]);
+ G(r,1,m,v[ 1],v[ 5],v[ 9],v[13]);
+ G(r,2,m,v[ 2],v[ 6],v[10],v[14]);
+ G(r,3,m,v[ 3],v[ 7],v[11],v[15]);
+ G(r,4,m,v[ 0],v[ 5],v[10],v[15]);
+ G(r,5,m,v[ 1],v[ 6],v[11],v[12]);
+ G(r,6,m,v[ 2],v[ 7],v[ 8],v[13]);
+ G(r,7,m,v[ 3],v[ 4],v[ 9],v[14]);
+ }
+
+ for( size_t i = 0; i < 8; ++i )
+ S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
+}
+
+
+void blake2s_update( blake2s_state *S, const byte *in, size_t inlen )
+{
+ while( inlen > 0 )
+ {
+ size_t left = S->buflen;
+ size_t fill = 2 * BLAKE2S_BLOCKBYTES - left;
+
+ if( inlen > fill )
+ {
+ memcpy( S->buf + left, in, fill ); // Fill buffer
+ S->buflen += fill;
+ blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
+
+#ifdef USE_SSE
+#ifdef _WIN_32 // We use SSSE3 _mm_shuffle_epi8 only in x64 mode.
+ if (_SSE_Version>=SSE_SSE2)
+#else
+ if (_SSE_Version>=SSE_SSSE3)
+#endif
+ blake2s_compress_sse( S, S->buf );
+ else
+ blake2s_compress( S, S->buf ); // Compress
+#else
+ blake2s_compress( S, S->buf ); // Compress
+#endif
+
+ memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); // Shift buffer left
+ S->buflen -= BLAKE2S_BLOCKBYTES;
+ in += fill;
+ inlen -= fill;
+ }
+ else // inlen <= fill
+ {
+ memcpy( S->buf + left, in, (size_t)inlen );
+ S->buflen += (size_t)inlen; // Be lazy, do not compress
+ in += inlen;
+ inlen -= inlen;
+ }
+ }
+}
+
+
+void blake2s_final( blake2s_state *S, byte *digest )
+{
+ if( S->buflen > BLAKE2S_BLOCKBYTES )
+ {
+ blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES );
+ blake2s_compress( S, S->buf );
+ S->buflen -= BLAKE2S_BLOCKBYTES;
+ memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, S->buflen );
+ }
+
+ blake2s_increment_counter( S, ( uint32 )S->buflen );
+ blake2s_set_lastblock( S );
+ memset( S->buf + S->buflen, 0, 2 * BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */
+ blake2s_compress( S, S->buf );
+
+ for( int i = 0; i < 8; ++i ) /* Output full hash */
+ RawPut4( S->h[i], digest + 4 * i );
+}
+
diff --git a/src/thirdparty/unrar/blake2s.hpp b/src/thirdparty/unrar/blake2s.hpp
new file mode 100644
index 000000000..f41662cfb
--- /dev/null
+++ b/src/thirdparty/unrar/blake2s.hpp
@@ -0,0 +1,57 @@
+// Based on public domain code written in 2012 by Samuel Neves
+#ifndef _RAR_BLAKE2_
+#define _RAR_BLAKE2_
+
+#if defined(_MSC_VER)
+#define BLAKE_ALIGN(x) __declspec(align(x))
+#else
+#define BLAKE_ALIGN(x) __attribute__((aligned(x)))
+#endif
+
+#define BLAKE2_DIGEST_SIZE 32
+
+enum blake2s_constant
+{
+ BLAKE2S_BLOCKBYTES = 64,
+ BLAKE2S_OUTBYTES = 32
+};
+
+
+// Alignment improves performance of non-SSE version a little
+// and is required for SSE version.
+BLAKE_ALIGN( 64 )
+typedef struct __blake2s_state
+{
+ uint32 h[8];
+ uint32 t[2];
+ uint32 f[2];
+ byte buf[2 * BLAKE2S_BLOCKBYTES];
+ size_t buflen;
+ byte last_node;
+} blake2s_state ;
+
+
+#ifdef RAR_SMP
+class ThreadPool;
+#endif
+
+typedef struct __blake2sp_state
+{
+ blake2s_state S[8][1];
+ blake2s_state R[1];
+ byte buf[8 * BLAKE2S_BLOCKBYTES];
+ size_t buflen;
+
+#ifdef RAR_SMP
+ ThreadPool *ThPool;
+ uint MaxThreads;
+#endif
+
+} blake2sp_state;
+
+void blake2sp_init( blake2sp_state *S );
+void blake2sp_update( blake2sp_state *S, const byte *in, size_t inlen );
+void blake2sp_final( blake2sp_state *S, byte *digest );
+
+#endif
+
diff --git a/src/thirdparty/unrar/blake2s_sse.cpp b/src/thirdparty/unrar/blake2s_sse.cpp
new file mode 100644
index 000000000..93b28b07d
--- /dev/null
+++ b/src/thirdparty/unrar/blake2s_sse.cpp
@@ -0,0 +1,105 @@
+// Based on public domain code written in 2012 by Samuel Neves
+
+extern const byte blake2s_sigma[10][16];
+
+#define LOAD(p) _mm_load_si128( (__m128i *)(p) )
+#define STORE(p,r) _mm_store_si128((__m128i *)(p), r)
+
+#ifdef _WIN_32
+// 32-bit mode has less SSE2 registers and in MSVC2008 it is more efficient
+// to not use _mm_shuffle_epi8 here.
+#define mm_rotr_epi32(r, c) ( \
+ _mm_xor_si128(_mm_srli_epi32( (r), c ),_mm_slli_epi32( (r), 32-c )) )
+#else
+// Constants for cyclic rotation.
+static const __m128i crotr8 = _mm_set_epi8( 12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1 );
+static const __m128i crotr16 = _mm_set_epi8( 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2 );
+#define mm_rotr_epi32(r, c) ( \
+ c==8 ? _mm_shuffle_epi8(r,crotr8) \
+ : c==16 ? _mm_shuffle_epi8(r,crotr16) \
+ : _mm_xor_si128(_mm_srli_epi32( (r), c ),_mm_slli_epi32( (r), 32-c )) )
+#endif
+
+
+#define G1(row1,row2,row3,row4,buf) \
+ row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \
+ row4 = _mm_xor_si128( row4, row1 ); \
+ row4 = mm_rotr_epi32(row4, 16); \
+ row3 = _mm_add_epi32( row3, row4 ); \
+ row2 = _mm_xor_si128( row2, row3 ); \
+ row2 = mm_rotr_epi32(row2, 12);
+
+#define G2(row1,row2,row3,row4,buf) \
+ row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \
+ row4 = _mm_xor_si128( row4, row1 ); \
+ row4 = mm_rotr_epi32(row4, 8); \
+ row3 = _mm_add_epi32( row3, row4 ); \
+ row2 = _mm_xor_si128( row2, row3 ); \
+ row2 = mm_rotr_epi32(row2, 7);
+
+#define DIAGONALIZE(row1,row2,row3,row4) \
+ row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(2,1,0,3) ); \
+ row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(1,0,3,2) ); \
+ row2 = _mm_shuffle_epi32( row2, _MM_SHUFFLE(0,3,2,1) );
+
+#define UNDIAGONALIZE(row1,row2,row3,row4) \
+ row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(0,3,2,1) ); \
+ row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(1,0,3,2) ); \
+ row2 = _mm_shuffle_epi32( row2, _MM_SHUFFLE(2,1,0,3) );
+
+#ifdef _WIN_64
+ // MSVC 2008 in x64 mode expands _mm_set_epi32 to store to stack and load
+ // from stack operations, which are slower than this code.
+ #define _mm_set_epi32(i3,i2,i1,i0) \
+ _mm_unpacklo_epi32(_mm_unpacklo_epi32(_mm_cvtsi32_si128(i0),_mm_cvtsi32_si128(i2)), \
+ _mm_unpacklo_epi32(_mm_cvtsi32_si128(i1),_mm_cvtsi32_si128(i3)))
+#endif
+
+// Original BLAKE2 SSE4.1 message loading code was a little slower in x86 mode
+// and about the same in x64 mode in our test. Perhaps depends on compiler.
+#define SSE_ROUND(m,row,r) \
+{ \
+ __m128i buf; \
+ buf=_mm_set_epi32(m[blake2s_sigma[r][6]],m[blake2s_sigma[r][4]],m[blake2s_sigma[r][2]],m[blake2s_sigma[r][0]]); \
+ G1(row[0],row[1],row[2],row[3],buf); \
+ buf=_mm_set_epi32(m[blake2s_sigma[r][7]],m[blake2s_sigma[r][5]],m[blake2s_sigma[r][3]],m[blake2s_sigma[r][1]]); \
+ G2(row[0],row[1],row[2],row[3],buf); \
+ DIAGONALIZE(row[0],row[1],row[2],row[3]); \
+ buf=_mm_set_epi32(m[blake2s_sigma[r][14]],m[blake2s_sigma[r][12]],m[blake2s_sigma[r][10]],m[blake2s_sigma[r][8]]); \
+ G1(row[0],row[1],row[2],row[3],buf); \
+ buf=_mm_set_epi32(m[blake2s_sigma[r][15]],m[blake2s_sigma[r][13]],m[blake2s_sigma[r][11]],m[blake2s_sigma[r][9]]); \
+ G2(row[0],row[1],row[2],row[3],buf); \
+ UNDIAGONALIZE(row[0],row[1],row[2],row[3]); \
+}
+
+
+// Initialization vector.
+static const __m128i blake2s_IV_0_3 = _mm_setr_epi32( 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A );
+static const __m128i blake2s_IV_4_7 = _mm_setr_epi32( 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 );
+
+static int blake2s_compress_sse( blake2s_state *S, const byte block[BLAKE2S_BLOCKBYTES] )
+{
+ __m128i row[4];
+ __m128i ff0, ff1;
+
+ const uint32 *m = ( uint32 * )block;
+
+ row[0] = ff0 = LOAD( &S->h[0] );
+ row[1] = ff1 = LOAD( &S->h[4] );
+
+ row[2] = blake2s_IV_0_3;
+ row[3] = _mm_xor_si128( blake2s_IV_4_7, LOAD( &S->t[0] ) );
+ SSE_ROUND( m, row, 0 );
+ SSE_ROUND( m, row, 1 );
+ SSE_ROUND( m, row, 2 );
+ SSE_ROUND( m, row, 3 );
+ SSE_ROUND( m, row, 4 );
+ SSE_ROUND( m, row, 5 );
+ SSE_ROUND( m, row, 6 );
+ SSE_ROUND( m, row, 7 );
+ SSE_ROUND( m, row, 8 );
+ SSE_ROUND( m, row, 9 );
+ STORE( &S->h[0], _mm_xor_si128( ff0, _mm_xor_si128( row[0], row[2] ) ) );
+ STORE( &S->h[4], _mm_xor_si128( ff1, _mm_xor_si128( row[1], row[3] ) ) );
+ return 0;
+}
diff --git a/src/thirdparty/unrar/blake2sp.cpp b/src/thirdparty/unrar/blake2sp.cpp
new file mode 100644
index 000000000..730283e45
--- /dev/null
+++ b/src/thirdparty/unrar/blake2sp.cpp
@@ -0,0 +1,153 @@
+/*
+ BLAKE2 reference source code package - reference C implementations
+
+ Written in 2012 by Samuel Neves <sneves@dei.uc.pt>
+
+ To the extent possible under law, the author(s) have dedicated all copyright
+ and related and neighboring rights to this software to the public domain
+ worldwide. This software is distributed without any warranty.
+
+ You should have received a copy of the CC0 Public Domain Dedication along with
+ this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
+*/
+
+#define PARALLELISM_DEGREE 8
+
+void blake2sp_init( blake2sp_state *S )
+{
+ memset( S->buf, 0, sizeof( S->buf ) );
+ S->buflen = 0;
+
+ blake2s_init_param( S->R, 0, 1 ); // Init root.
+
+ for( uint i = 0; i < PARALLELISM_DEGREE; ++i )
+ blake2s_init_param( S->S[i], i, 0 ); // Init leaf.
+
+ S->R->last_node = 1;
+ S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
+}
+
+
+struct Blake2ThreadData
+{
+ void Update();
+ blake2s_state *S;
+ const byte *in;
+ size_t inlen;
+};
+
+
+void Blake2ThreadData::Update()
+{
+ size_t inlen__ = inlen;
+ const byte *in__ = ( const byte * )in;
+
+ while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
+ {
+#ifdef USE_SSE
+ // We gain 5% in i7 SSE mode by prefetching next data block.
+ if (_SSE_Version>=SSE_SSE && inlen__ >= 2 * PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES)
+ _mm_prefetch((char*)(in__ + PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES), _MM_HINT_T0);
+#endif
+ blake2s_update( S, in__, BLAKE2S_BLOCKBYTES );
+ in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
+ inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
+ }
+}
+
+#ifdef RAR_SMP
+THREAD_PROC(Blake2Thread)
+{
+ Blake2ThreadData *td=(Blake2ThreadData *)Data;
+ td->Update();
+}
+#endif
+
+
+void blake2sp_update( blake2sp_state *S, const byte *in, size_t inlen )
+{
+ size_t left = S->buflen;
+ size_t fill = sizeof( S->buf ) - left;
+
+ if( left && inlen >= fill )
+ {
+ memcpy( S->buf + left, in, fill );
+
+ for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
+ blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES );
+
+ in += fill;
+ inlen -= fill;
+ left = 0;
+ }
+
+ Blake2ThreadData btd_array[PARALLELISM_DEGREE];
+
+#ifdef RAR_SMP
+ uint ThreadNumber = inlen < 0x1000 ? 1 : S->MaxThreads;
+
+ if (ThreadNumber==6 || ThreadNumber==7) // 6 and 7 threads work slower than 4 here.
+ ThreadNumber=4;
+#else
+ uint ThreadNumber=1;
+#endif
+
+ for (size_t id__=0;id__<PARALLELISM_DEGREE;)
+ {
+ for (uint Thread=0;Thread<ThreadNumber && id__<PARALLELISM_DEGREE;Thread++)
+ {
+ Blake2ThreadData *btd=btd_array+Thread;
+
+ btd->inlen = inlen;
+ btd->in = in + id__ * BLAKE2S_BLOCKBYTES;
+ btd->S = S->S[id__];
+
+#ifdef RAR_SMP
+ if (ThreadNumber>1)
+ S->ThPool->AddTask(Blake2Thread,(void*)btd);
+ else
+ btd->Update();
+#else
+ btd->Update();
+#endif
+ id__++;
+ }
+#ifdef RAR_SMP
+ if (S->ThPool!=NULL) // Can be NULL in -mt1 mode.
+ S->ThPool->WaitDone();
+#endif // RAR_SMP
+ }
+
+ in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES );
+ inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
+
+ if( inlen > 0 )
+ memcpy( S->buf + left, in, (size_t)inlen );
+
+ S->buflen = left + (size_t)inlen;
+}
+
+
+void blake2sp_final( blake2sp_state *S, byte *digest )
+{
+ byte hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
+
+ for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
+ {
+ if( S->buflen > i * BLAKE2S_BLOCKBYTES )
+ {
+ size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES;
+
+ if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES;
+
+ blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left );
+ }
+
+ blake2s_final( S->S[i], hash[i] );
+ }
+
+ for( size_t i = 0; i < PARALLELISM_DEGREE; ++i )
+ blake2s_update( S->R, hash[i], BLAKE2S_OUTBYTES );
+
+ blake2s_final( S->R, digest );
+}
diff --git a/src/thirdparty/unrar/cmddata.cpp b/src/thirdparty/unrar/cmddata.cpp
index e17fa2061..d34b6033d 100644
--- a/src/thirdparty/unrar/cmddata.cpp
+++ b/src/thirdparty/unrar/cmddata.cpp
@@ -3,80 +3,50 @@
CommandData::CommandData()
{
- FileArgs=ExclArgs=InclArgs=StoreArgs=ArcNames=NULL;
Init();
}
-CommandData::~CommandData()
-{
- Close();
-}
-
-
void CommandData::Init()
{
RAROptions::Init();
- Close();
*Command=0;
- *CommandW=0;
*ArcName=0;
- *ArcNameW=0;
FileLists=false;
NoMoreSwitches=false;
ListMode=RCLM_AUTO;
-
- FileArgs=new StringList;
- ExclArgs=new StringList;
- InclArgs=new StringList;
- StoreArgs=new StringList;
- ArcNames=new StringList;
-}
+ BareOutput=false;
-void CommandData::Close()
-{
- delete FileArgs;
- delete ExclArgs;
- delete InclArgs;
- delete StoreArgs;
- delete ArcNames;
- FileArgs=ExclArgs=InclArgs=StoreArgs=ArcNames=NULL;
+ FileArgs.Reset();
+ ExclArgs.Reset();
+ InclArgs.Reset();
+ StoreArgs.Reset();
+ ArcNames.Reset();
NextVolSizes.Reset();
}
-#ifdef CUSTOM_CMDLINE_PARSER
// Return the pointer to next position in the string and store dynamically
-// allocated command line parameters in Unicode and ASCII in ParW and ParA.
-static const wchar *AllocCmdParam(const wchar *CmdLine,wchar **ParW,char **ParA)
+// allocated command line parameter in Par.
+static const wchar *AllocCmdParam(const wchar *CmdLine,wchar **Par)
{
const wchar *NextCmd=GetCmdParam(CmdLine,NULL,0);
if (NextCmd==NULL)
return NULL;
size_t ParSize=NextCmd-CmdLine+2; // Parameter size including the trailing zero.
- *ParW=(wchar *)malloc(ParSize*sizeof(wchar));
- if (*ParW==NULL)
- return NULL;
- CmdLine=GetCmdParam(CmdLine,*ParW,ParSize);
- size_t ParSizeA=ParSize*2; // One Unicode char can be converted to several MBCS chars.
- *ParA=(char *)malloc(ParSizeA);
- if (*ParA==NULL)
- {
- free(*ParW);
+ *Par=(wchar *)malloc(ParSize*sizeof(wchar));
+ if (*Par==NULL)
return NULL;
- }
- GetAsciiName(*ParW,*ParA,ParSizeA);
- return CmdLine;
+ return GetCmdParam(CmdLine,*Par,ParSize);
}
-#endif
#ifndef SFX_MODULE
-void CommandData::PreprocessCommandLine(int argc, char *argv[])
+void CommandData::ParseCommandLine(bool Preprocess,int argc, char *argv[])
{
#ifdef CUSTOM_CMDLINE_PARSER
// In Windows we may prefer to implement our own command line parser
@@ -84,122 +54,89 @@ void CommandData::PreprocessCommandLine(int argc, char *argv[])
// destination paths like "dest path\" in extraction commands.
const wchar *CmdLine=GetCommandLine();
- wchar *ParW;
- char *ParA;
+ wchar *Par;
for (bool FirstParam=true;;FirstParam=false)
{
- if ((CmdLine=AllocCmdParam(CmdLine,&ParW,&ParA))==NULL)
+ if ((CmdLine=AllocCmdParam(CmdLine,&Par))==NULL)
break;
- bool Code=FirstParam ? true:PreprocessSwitch(ParA);
- free(ParW);
- free(ParA);
- if (!Code)
+ bool Code=true;
+ if (!FirstParam) // First parameter is the executable name.
+ if (Preprocess)
+ Code=PreprocessSwitch(Par);
+ else
+ ParseArg(Par);
+ free(Par);
+ if (Preprocess && !Code)
break;
}
#else
+ Array<wchar> Arg;
for (int I=1;I<argc;I++)
- if (!PreprocessSwitch(argv[I]))
- break;
-#endif
-}
-#endif
-
-
-#ifndef SFX_MODULE
-void CommandData::ParseCommandLine(int argc, char *argv[])
-{
-#ifdef CUSTOM_CMDLINE_PARSER
- // In Windows we may prefer to implement our own command line parser
- // to avoid replacing \" by " in standard parser. Such replacing corrupts
- // destination paths like "dest path\" in extraction commands.
- const wchar *CmdLine=GetCommandLine();
-
- wchar *ParW;
- char *ParA;
- for (bool FirstParam=true;;FirstParam=false)
{
- if ((CmdLine=AllocCmdParam(CmdLine,&ParW,&ParA))==NULL)
- break;
- if (!FirstParam) // First parameter is the executable name.
- ParseArg(ParA,ParW);
- free(ParW);
- free(ParA);
+ Arg.Alloc(strlen(argv[I])+1);
+ CharToWide(argv[I],&Arg[0],Arg.Size());
+ if (Preprocess)
+ {
+ if (!PreprocessSwitch(&Arg[0]))
+ break;
+ }
+ else
+ ParseArg(&Arg[0]);
}
-#else
- for (int I=1;I<argc;I++)
- ParseArg(argv[I],NULL);
#endif
- ParseDone();
+ if (!Preprocess)
+ ParseDone();
}
#endif
#ifndef SFX_MODULE
-void CommandData::ParseArg(char *Arg,wchar *ArgW)
+void CommandData::ParseArg(wchar *Arg)
{
if (IsSwitch(*Arg) && !NoMoreSwitches)
if (Arg[1]=='-')
NoMoreSwitches=true;
else
- ProcessSwitch(Arg+1,(ArgW!=NULL && *ArgW!=0 ? ArgW+1:NULL));
+ ProcessSwitch(Arg+1);
else
if (*Command==0)
{
- strncpyz(Command,Arg,ASIZE(Command));
- if (ArgW!=NULL)
- wcsncpy(CommandW,ArgW,ASIZE(CommandW));
+ wcsncpy(Command,Arg,ASIZE(Command));
#ifndef GUI
- *Command=etoupper(*Command);
+ *Command=toupperw(*Command);
// 'I' and 'S' commands can contain case sensitive strings after
// the first character, so we must not modify their case.
// 'S' can contain SFX name, which case is important in Unix.
if (*Command!='I' && *Command!='S')
- strupper(Command);
+ wcsupper(Command);
#endif
}
else
- if (*ArcName==0 && *ArcNameW==0)
- {
- strncpyz(ArcName,Arg,ASIZE(ArcName));
- if (ArgW!=NULL)
- wcsncpyz(ArcNameW,ArgW,ASIZE(ArcNameW));
- }
+ if (*ArcName==0)
+ wcsncpyz(ArcName,Arg,ASIZE(ArcName));
else
{
- bool EndSeparator; // If last character is the path separator.
- if (ArgW!=NULL)
- {
- size_t Length=wcslen(ArgW);
- wchar EndChar=Length==0 ? 0:ArgW[Length-1];
- EndSeparator=IsDriveDiv(EndChar) || IsPathDiv(EndChar);
- }
- else
- {
- size_t Length=strlen(Arg);
- char EndChar=Length==0 ? 0:Arg[Length-1];
- EndSeparator=IsDriveDiv(EndChar) || IsPathDiv(EndChar);
- }
+ // Check if last character is the path separator.
+ size_t Length=wcslen(Arg);
+ wchar EndChar=Length==0 ? 0:Arg[Length-1];
+ bool EndSeparator=IsDriveDiv(EndChar) || IsPathDiv(EndChar);
- char CmdChar=etoupper(*Command);
- bool Add=strchr("AFUM",CmdChar)!=NULL;
+ wchar CmdChar=toupperw(*Command);
+ bool Add=wcschr(L"AFUM",CmdChar)!=NULL;
bool Extract=CmdChar=='X' || CmdChar=='E';
if (EndSeparator && !Add)
- {
- strncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
- if (ArgW!=NULL)
- wcsncpyz(ExtrPathW,ArgW,ASIZE(ExtrPathW));
- }
+ wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
else
if ((Add || CmdChar=='T') && (*Arg!='@' || ListMode==RCLM_REJECT_LISTS))
- FileArgs->AddString(Arg,ArgW);
+ FileArgs.AddString(Arg);
else
{
FindData FileData;
- bool Found=FindFile::FastFind(Arg,ArgW,&FileData);
+ bool Found=FindFile::FastFind(Arg,&FileData);
if ((!Found || ListMode==RCLM_ACCEPT_LISTS) &&
- ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg,ArgW))
+ ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg))
{
FileLists=true;
@@ -209,27 +146,21 @@ void CommandData::ParseArg(char *Arg,wchar *ArgW)
// for compatibility reasons we use OEM encoding
// in Win32 console version by default
- if (Charset==RCH_DEFAULT)
- Charset=RCH_OEM;
+// if (Charset==RCH_DEFAULT)
+// Charset=RCH_OEM;
#endif
- wchar *WideArgName=(ArgW!=NULL && *ArgW!=0 ? ArgW+1:NULL);
- ReadTextFile(Arg+1,WideArgName,FileArgs,false,true,Charset,true,true,true);
+ ReadTextFile(Arg+1,&FileArgs,false,true,Charset,true,true,true);
}
else
- if (Found && FileData.IsDir && Extract && *ExtrPath==0 && *ExtrPathW==0)
+ if (Found && FileData.IsDir && Extract && *ExtrPath==0)
{
- strncpyz(ExtrPath,Arg,ASIZE(ExtrPath)-1);
- AddEndSlash(ExtrPath);
- if (ArgW!=NULL)
- {
- wcsncpyz(ExtrPathW,ArgW,ASIZE(ExtrPathW)-1);
- AddEndSlash(ExtrPathW);
- }
+ wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
+ AddEndSlash(ExtrPath,ASIZE(ExtrPath));
}
else
- FileArgs->AddString(Arg,ArgW);
+ FileArgs.AddString(Arg);
}
}
}
@@ -238,23 +169,28 @@ void CommandData::ParseArg(char *Arg,wchar *ArgW)
void CommandData::ParseDone()
{
- if (FileArgs->ItemsCount()==0 && !FileLists)
- FileArgs->AddString(MASKALL);
- char CmdChar=etoupper(*Command);
+ if (FileArgs.ItemsCount()==0 && !FileLists)
+ FileArgs.AddString(MASKALL);
+ wchar CmdChar=toupperw(Command[0]);
bool Extract=CmdChar=='X' || CmdChar=='E' || CmdChar=='P';
if (Test && Extract)
Test=false; // Switch '-t' is senseless for 'X', 'E', 'P' commands.
- BareOutput=(CmdChar=='L' || CmdChar=='V') && Command[1]=='B';
+
+ // Suppress the copyright message and final end of line for 'lb' and 'vb'.
+ if ((CmdChar=='L' || CmdChar=='V') && Command[1]=='B')
+ BareOutput=true;
}
-#if !defined(SFX_MODULE) && !defined(_WIN_CE)
+#ifndef SFX_MODULE
void CommandData::ParseEnvVar()
{
char *EnvStr=getenv("RAR");
if (EnvStr!=NULL)
{
- ProcessSwitchesString(EnvStr);
+ Array<wchar> EnvStrW(strlen(EnvStr)+1);
+ CharToWide(EnvStr,&EnvStrW[0],EnvStrW.Size());
+ ProcessSwitchesString(&EnvStrW[0]);
}
}
#endif
@@ -264,17 +200,19 @@ void CommandData::ParseEnvVar()
#ifndef SFX_MODULE
// Preprocess those parameters, which must be processed before the rest of
// command line. Return 'false' to stop further processing.
-bool CommandData::PreprocessSwitch(const char *Switch)
+bool CommandData::PreprocessSwitch(const wchar *Switch)
{
if (IsSwitch(Switch[0]))
{
Switch++;
- if (stricomp(Switch,"-")==0) // Switch "--".
+ char SwitchA[1024];
+ WideToChar(Switch,SwitchA,ASIZE(SwitchA));
+ if (wcsicomp(Switch,L"-")==0) // Switch "--".
return false;
- if (stricomp(Switch,"cfg-")==0)
+ if (wcsicomp(Switch,L"cfg-")==0)
ConfigDisabled=true;
#ifndef GUI
- if (strnicomp(Switch,"ilog",4)==0)
+ if (wcsnicomp(Switch,L"ilog",4)==0)
{
// Ensure that correct log file name is already set
// if we need to report an error when processing the command line.
@@ -282,7 +220,7 @@ bool CommandData::PreprocessSwitch(const char *Switch)
InitLogOptions(LogName);
}
#endif
- if (strnicomp(Switch,"sc",2)==0)
+ if (wcsnicomp(Switch,L"sc",2)==0)
{
// Process -sc before reading any file lists.
ProcessSwitch(Switch);
@@ -297,14 +235,14 @@ bool CommandData::PreprocessSwitch(const char *Switch)
void CommandData::ReadConfig()
{
StringList List;
- if (ReadTextFile(DefConfigName,NULL,&List,true))
+ if (ReadTextFile(DefConfigName,&List,true))
{
- char *Str;
+ wchar *Str;
while ((Str=List.GetString())!=NULL)
{
while (IsSpace(*Str))
Str++;
- if (strnicomp(Str,"switches=",9)==0)
+ if (wcsnicomp(Str,L"switches=",9)==0)
ProcessSwitchesString(Str+9);
}
}
@@ -312,160 +250,31 @@ void CommandData::ReadConfig()
#endif
-#if !defined(SFX_MODULE) && !defined(_WIN_CE)
-void CommandData::ProcessSwitchesString(char *Str)
+#ifndef SFX_MODULE
+void CommandData::ProcessSwitchesString(const wchar *Str)
{
- while (*Str)
+ wchar *Par;
+ while ((Str=AllocCmdParam(Str,&Par))!=NULL)
{
- while (!IsSwitch(*Str) && *Str!=0)
- Str++;
- if (*Str==0)
- break;
- char *Next=Str;
- while (!(Next[0]==' ' && IsSwitch(Next[1])) && *Next!=0)
- Next++;
- char NextChar=*Next;
- *Next=0;
- ProcessSwitch(Str+1);
- *Next=NextChar;
- Str=Next;
+ if (IsSwitch(*Par))
+ ProcessSwitch(Par+1);
+ free(Par);
}
}
#endif
#if !defined(SFX_MODULE)
-void CommandData::ProcessSwitch(const char *Switch,const wchar *SwitchW)
+void CommandData::ProcessSwitch(const wchar *Switch)
{
- bool WidePresent=SwitchW!=NULL && *SwitchW!=0; // If 'true', SwitchW is not empty.
-
- switch(etoupper(Switch[0]))
+ switch(toupperw(Switch[0]))
{
case '@':
ListMode=Switch[1]=='+' ? RCLM_ACCEPT_LISTS:RCLM_REJECT_LISTS;
break;
- case 'I':
- if (strnicomp(&Switch[1],"LOG",3)==0)
- {
- strncpyz(LogName,Switch[4] ? Switch+4:DefLogName,ASIZE(LogName));
- break;
- }
- if (stricomp(&Switch[1],"SND")==0)
- {
- Sound=true;
- break;
- }
- if (stricomp(&Switch[1],"ERR")==0)
- {
- MsgStream=MSG_STDERR;
- break;
- }
- if (strnicomp(&Switch[1],"EML",3)==0)
- {
- strncpyz(EmailTo,Switch[4] ? Switch+4:"@",ASIZE(EmailTo));
- EmailTo[sizeof(EmailTo)-1]=0;
- break;
- }
- if (stricomp(&Switch[1],"NUL")==0)
- {
- MsgStream=MSG_NULL;
- break;
- }
- if (etoupper(Switch[1])=='D')
- {
- for (int I=2;Switch[I]!=0;I++)
- switch(etoupper(Switch[I]))
- {
- case 'Q':
- MsgStream=MSG_ERRONLY;
- break;
- case 'C':
- DisableCopyright=true;
- break;
- case 'D':
- DisableDone=true;
- break;
- case 'P':
- DisablePercentage=true;
- break;
- }
- break;
- }
- if (stricomp(&Switch[1],"OFF")==0)
- {
- Shutdown=true;
- break;
- }
- break;
- case 'T':
- switch(etoupper(Switch[1]))
- {
- case 'K':
- ArcTime=ARCTIME_KEEP;
- break;
- case 'L':
- ArcTime=ARCTIME_LATEST;
- break;
- case 'O':
- FileTimeBefore.SetAgeText(Switch+2);
- break;
- case 'N':
- FileTimeAfter.SetAgeText(Switch+2);
- break;
- case 'B':
- FileTimeBefore.SetIsoText(Switch+2);
- break;
- case 'A':
- FileTimeAfter.SetIsoText(Switch+2);
- break;
- case 'S':
- {
- EXTTIME_MODE Mode=EXTTIME_HIGH3;
- bool CommonMode=Switch[2]>='0' && Switch[2]<='4';
- if (CommonMode)
- Mode=(EXTTIME_MODE)(Switch[2]-'0');
- if (Switch[2]=='-')
- Mode=EXTTIME_NONE;
- if (CommonMode || Switch[2]=='-' || Switch[2]=='+' || Switch[2]==0)
- xmtime=xctime=xatime=Mode;
- else
- {
- if (Switch[3]>='0' && Switch[3]<='4')
- Mode=(EXTTIME_MODE)(Switch[3]-'0');
- if (Switch[3]=='-')
- Mode=EXTTIME_NONE;
- switch(etoupper(Switch[2]))
- {
- case 'M':
- xmtime=Mode;
- break;
- case 'C':
- xctime=Mode;
- break;
- case 'A':
- xatime=Mode;
- break;
- case 'R':
- xarctime=Mode;
- break;
- }
- }
- }
- break;
- case '-':
- Test=false;
- break;
- case 0:
- Test=true;
- break;
- default:
- BadSwitch(Switch);
- break;
- }
- break;
case 'A':
- switch(etoupper(Switch[1]))
+ switch(toupperw(Switch[1]))
{
case 'C':
ClearArc=true;
@@ -480,7 +289,7 @@ void CommandData::ProcessSwitch(const char *Switch,const wchar *SwitchW)
else
{
GenerateArcName=true;
- strncpyz(GenerateMask,Switch+2,ASIZE(GenerateMask));
+ wcsncpyz(GenerateMask,Switch+2,ASIZE(GenerateMask));
}
break;
#endif
@@ -493,9 +302,7 @@ void CommandData::ProcessSwitch(const char *Switch,const wchar *SwitchW)
AddArcOnly=true;
break;
case 'P':
- strcpy(ArcPath,Switch+2);
- if (WidePresent)
- wcscpy(ArcPathW,SwitchW+2);
+ wcscpy(ArcPath,Switch+2);
break;
case 'S':
SyncFiles=true;
@@ -505,9 +312,24 @@ void CommandData::ProcessSwitch(const char *Switch,const wchar *SwitchW)
break;
}
break;
+ case 'C':
+ if (Switch[2]==0)
+ switch(toupperw(Switch[1]))
+ {
+ case '-':
+ DisableComment=true;
+ break;
+ case 'U':
+ ConvertNames=NAMES_UPPERCASE;
+ break;
+ case 'L':
+ ConvertNames=NAMES_LOWERCASE;
+ break;
+ }
+ break;
case 'D':
if (Switch[2]==0)
- switch(etoupper(Switch[1]))
+ switch(toupperw(Switch[1]))
{
case 'S':
DisableSortSolid=true;
@@ -520,102 +342,8 @@ void CommandData::ProcessSwitch(const char *Switch,const wchar *SwitchW)
break;
}
break;
- case 'O':
- switch(etoupper(Switch[1]))
- {
- case '+':
- Overwrite=OVERWRITE_ALL;
- break;
- case '-':
- Overwrite=OVERWRITE_NONE;
- break;
- case 0:
- Overwrite=OVERWRITE_FORCE_ASK;
- break;
- case 'R':
- Overwrite=OVERWRITE_AUTORENAME;
- break;
- case 'W':
- ProcessOwners=true;
- break;
-#ifdef SAVE_LINKS
- case 'L':
- SaveLinks=true;
- break;
-#endif
-#ifdef _WIN_ALL
- case 'S':
- SaveStreams=true;
- break;
- case 'C':
- SetCompressedAttr=true;
- break;
-#endif
- default :
- BadSwitch(Switch);
- break;
- }
- break;
- case 'R':
- switch(etoupper(Switch[1]))
- {
- case 0:
- Recurse=RECURSE_ALWAYS;
- break;
- case '-':
- Recurse=RECURSE_DISABLE;
- break;
- case '0':
- Recurse=RECURSE_WILDCARDS;
- break;
-#ifndef _WIN_CE
- case 'I':
- {
- Priority=atoi(Switch+2);
- if (Priority<0 || Priority>15)
- BadSwitch(Switch);
- const char *ChPtr=strchr(Switch+2,':');
- if (ChPtr!=NULL)
- {
- SleepTime=atoi(ChPtr+1);
- if (SleepTime>1000)
- BadSwitch(Switch);
- InitSystemOptions(SleepTime);
- }
- SetPriority(Priority);
- }
- break;
-#endif
- }
- break;
- case 'Y':
- AllYes=true;
- break;
- case 'N':
- case 'X':
- if (Switch[1]!=0)
- {
- StringList *Args=etoupper(Switch[0])=='N' ? InclArgs:ExclArgs;
- if (Switch[1]=='@' && !IsWildcard(Switch))
- {
- RAR_CHARSET Charset=FilelistCharset;
-
-#if defined(_WIN_ALL) && !defined(GUI)
- // for compatibility reasons we use OEM encoding
- // in Win32 console version by default
-
- if (Charset==RCH_DEFAULT)
- Charset=RCH_OEM;
-#endif
-
- ReadTextFile(Switch+2,NULL,Args,false,true,Charset,true,true,true);
- }
- else
- Args->AddString(Switch+1);
- }
- break;
case 'E':
- switch(etoupper(Switch[1]))
+ switch(toupperw(Switch[1]))
{
case 'P':
switch(Switch[2])
@@ -637,98 +365,133 @@ void CommandData::ProcessSwitch(const char *Switch,const wchar *SwitchW)
case 'E':
ProcessEA=false;
break;
- case 'N':
- NoEndBlock=true;
- break;
default:
if (Switch[1]=='+')
{
- InclFileAttr=GetExclAttr(&Switch[2]);
+ InclFileAttr=GetExclAttr(Switch+2);
InclAttrSet=true;
}
else
- ExclFileAttr=GetExclAttr(&Switch[1]);
+ ExclFileAttr=GetExclAttr(Switch+1);
break;
}
break;
- case 'P':
+ case 'F':
if (Switch[1]==0)
- {
- GetPassword(PASSWORD_GLOBAL,NULL,NULL,&Password);
- eprintf("\n");
- }
+ FreshFiles=true;
else
+ BadSwitch(Switch);
+ break;
+ case 'H':
+ switch (toupperw(Switch[1]))
{
- wchar PlainPsw[MAXPASSWORD];
- CharToWide(Switch+1,PlainPsw,ASIZE(PlainPsw));
- PlainPsw[ASIZE(PlainPsw)-1]=0;
- Password.Set(PlainPsw);
- cleandata(PlainPsw,ASIZE(PlainPsw));
+ case 'P':
+ EncryptHeaders=true;
+ if (Switch[2]!=0)
+ Password.Set(Switch+2);
+ else
+ if (!Password.IsSet())
+ {
+ GetPassword(PASSWORD_GLOBAL,NULL,&Password);
+ eprintf(L"\n");
+ }
+ break;
+ default :
+ BadSwitch(Switch);
+ break;
}
break;
- case 'H':
- if (etoupper(Switch[1])=='P')
+ case 'I':
+ if (wcsnicomp(Switch+1,L"LOG",3)==0)
{
- EncryptHeaders=true;
- if (Switch[2]!=0)
- {
- wchar PlainPsw[MAXPASSWORD];
- CharToWide(Switch+2,PlainPsw,ASIZE(PlainPsw));
- PlainPsw[ASIZE(PlainPsw)-1]=0;
- Password.Set(PlainPsw);
- cleandata(PlainPsw,ASIZE(PlainPsw));
- }
- else
- if (!Password.IsSet())
+ wcsncpyz(LogName,Switch[4]!=0 ? Switch+4:DefLogName,ASIZE(LogName));
+ break;
+ }
+ if (wcsicomp(Switch+1,L"SND")==0)
+ {
+ Sound=true;
+ break;
+ }
+ if (wcsicomp(Switch+1,L"ERR")==0)
+ {
+ MsgStream=MSG_STDERR;
+ break;
+ }
+ if (wcsnicomp(Switch+1,L"EML",3)==0)
+ {
+ wcsncpyz(EmailTo,Switch[4]!=0 ? Switch+4:L"@",ASIZE(EmailTo));
+ break;
+ }
+ if (wcsicomp(Switch+1,L"NUL")==0)
+ {
+ MsgStream=MSG_NULL;
+ break;
+ }
+ if (toupperw(Switch[1])=='D')
+ {
+ for (uint I=2;Switch[I]!=0;I++)
+ switch(toupperw(Switch[I]))
{
- GetPassword(PASSWORD_GLOBAL,NULL,NULL,&Password);
- eprintf("\n");
+ case 'Q':
+ MsgStream=MSG_ERRONLY;
+ break;
+ case 'C':
+ DisableCopyright=true;
+ break;
+ case 'D':
+ DisableDone=true;
+ break;
+ case 'P':
+ DisablePercentage=true;
+ break;
}
+ break;
}
- break;
- case 'Z':
- if (Switch[1]==0 && (!WidePresent || SwitchW[1]==0))
+ if (wcsicomp(Switch+1,L"OFF")==0)
{
-#ifndef GUI // stdin is not supported by WinRAR.
- // If comment file is not specified, we read data from stdin.
- strcpy(CommentFile,"stdin");
-#endif
+ Shutdown=true;
+ break;
}
- else
+ break;
+ case 'K':
+ switch(toupperw(Switch[1]))
{
- strncpyz(CommentFile,Switch+1,ASIZE(CommentFile));
- if (WidePresent)
- wcsncpyz(CommentFileW,SwitchW+1,ASIZE(CommentFileW));
+ case 'B':
+ KeepBroken=true;
+ break;
+ case 0:
+ Lock=true;
+ break;
}
break;
case 'M':
- switch(etoupper(Switch[1]))
+ switch(toupperw(Switch[1]))
{
case 'C':
{
- const char *Str=Switch+2;
+ const wchar *Str=Switch+2;
if (*Str=='-')
for (uint I=0;I<ASIZE(FilterModes);I++)
FilterModes[I].State=FILTER_DISABLE;
else
- while (*Str)
+ while (*Str!=0)
{
int Param1=0,Param2=0;
FilterState State=FILTER_AUTO;
FilterType Type=FILTER_NONE;
if (IsDigit(*Str))
{
- Param1=atoi(Str);
+ Param1=atoiw(Str);
while (IsDigit(*Str))
Str++;
}
if (*Str==':' && IsDigit(Str[1]))
{
- Param2=atoi(++Str);
+ Param2=atoiw(++Str);
while (IsDigit(*Str))
Str++;
}
- switch(etoupper(*(Str++)))
+ switch(toupperw(*(Str++)))
{
case 'T': Type=FILTER_PPM; break;
case 'E': Type=FILTER_E8; break;
@@ -736,7 +499,7 @@ void CommandData::ProcessSwitch(const char *Switch,const wchar *SwitchW)
case 'A': Type=FILTER_AUDIO; break;
case 'C': Type=FILTER_RGB; break;
case 'I': Type=FILTER_ITANIUM; break;
- case 'L': Type=FILTER_UPCASETOLOW; break;
+ case 'R': Type=FILTER_ARM; break;
}
if (*Str=='+' || *Str=='-')
State=*(Str++)=='+' ? FILTER_FORCE:FILTER_DISABLE;
@@ -749,33 +512,25 @@ void CommandData::ProcessSwitch(const char *Switch,const wchar *SwitchW)
case 'M':
break;
case 'D':
- {
- if ((WinSize=atoi(&Switch[2]))==0)
- WinSize=0x10000<<(etoupper(Switch[2])-'A');
- else
- WinSize*=1024;
- if (!CheckWinSize())
- BadSwitch(Switch);
- }
break;
case 'S':
{
- char StoreNames[1024];
- strncpyz(StoreNames,(Switch[2]==0 ? DefaultStoreList:Switch+2),ASIZE(StoreNames));
- char *Names=StoreNames;
+ wchar StoreNames[1024];
+ wcsncpyz(StoreNames,(Switch[2]==0 ? DefaultStoreList:Switch+2),ASIZE(StoreNames));
+ wchar *Names=StoreNames;
while (*Names!=0)
{
- char *End=strchr(Names,';');
+ wchar *End=wcschr(Names,';');
if (End!=NULL)
*End=0;
if (*Names=='.')
Names++;
- char Mask[NM];
- if (strpbrk(Names,"*?.")==NULL)
- sprintf(Mask,"*.%s",Names);
+ wchar Mask[NM];
+ if (wcspbrk(Names,L"*?.")==NULL)
+ swprintf(Mask,ASIZE(Mask),L"*.%s",Names);
else
- strcpy(Mask,Names);
- StoreArgs->AddString(Mask);
+ wcsncpyz(Mask,Names,ASIZE(Mask));
+ StoreArgs.AddString(Mask);
if (End==NULL)
break;
Names=End+1;
@@ -784,7 +539,7 @@ void CommandData::ProcessSwitch(const char *Switch,const wchar *SwitchW)
break;
#ifdef RAR_SMP
case 'T':
- Threads=atoi(Switch+2);
+ Threads=atoiw(Switch+2);
if (Threads>MaxPoolThreads || Threads<1)
BadSwitch(Switch);
else
@@ -799,51 +554,143 @@ void CommandData::ProcessSwitch(const char *Switch,const wchar *SwitchW)
break;
}
break;
- case 'V':
- switch(etoupper(Switch[1]))
+ case 'N':
+ case 'X':
+ if (Switch[1]!=0)
{
- case 'N':
- OldNumbering=true;
+ StringList *Args=toupperw(Switch[0])=='N' ? &InclArgs:&ExclArgs;
+ if (Switch[1]=='@' && !IsWildcard(Switch))
+ {
+ RAR_CHARSET Charset=FilelistCharset;
+
+#if defined(_WIN_ALL) && !defined(GUI)
+ // for compatibility reasons we use OEM encoding
+ // in Win32 console version by default
+
+// if (Charset==RCH_DEFAULT)
+// Charset=RCH_OEM;
+#endif
+
+ ReadTextFile(Switch+2,Args,false,true,Charset,true,true,true);
+ }
+ else
+ Args->AddString(Switch+1);
+ }
+ break;
+ case 'O':
+ switch(toupperw(Switch[1]))
+ {
+ case '+':
+ Overwrite=OVERWRITE_ALL;
break;
- case 'P':
- VolumePause=true;
+ case '-':
+ Overwrite=OVERWRITE_NONE;
break;
- case 'E':
- if (etoupper(Switch[2])=='R')
- VersionControl=atoi(Switch+3)+1;
+ case 0:
+ Overwrite=OVERWRITE_FORCE_ASK;
break;
- case '-':
- VolSize=0;
+#ifdef _WIN_ALL
+ case 'C':
+ SetCompressedAttr=true;
break;
- default:
- VolSize=VOLSIZE_AUTO; // UnRAR -v switch for list command.
+#endif
+ case 'H':
+ SaveHardLinks=true;
+ break;
+
+
+#ifdef SAVE_LINKS
+ case 'L':
+ SaveSymLinks=true;
+ break;
+#endif
+ case 'R':
+ Overwrite=OVERWRITE_AUTORENAME;
+ break;
+#ifdef _WIN_ALL
+ case 'S':
+ SaveStreams=true;
+ break;
+#endif
+ case 'W':
+ ProcessOwners=true;
+ break;
+ default :
+ BadSwitch(Switch);
break;
}
break;
- case 'F':
+ case 'P':
if (Switch[1]==0)
- FreshFiles=true;
+ {
+ GetPassword(PASSWORD_GLOBAL,NULL,&Password);
+ eprintf(L"\n");
+ }
else
- BadSwitch(Switch);
+ Password.Set(Switch+1);
break;
- case 'U':
- if (Switch[1]==0)
- UpdateFiles=true;
+#ifndef SFX_MODULE
+ case 'Q':
+ if (toupperw(Switch[1])=='O')
+ switch(toupperw(Switch[2]))
+ {
+ case 0:
+ QOpenMode=QOPEN_AUTO;
+ break;
+ case '-':
+ QOpenMode=QOPEN_NONE;
+ break;
+ case '+':
+ QOpenMode=QOPEN_ALWAYS;
+ break;
+ default:
+ BadSwitch(Switch);
+ break;
+ }
else
BadSwitch(Switch);
break;
- case 'W':
- strncpyz(TempPath,&Switch[1],ASIZE(TempPath));
- AddEndSlash(TempPath);
+#endif
+ case 'R':
+ switch(toupperw(Switch[1]))
+ {
+ case 0:
+ Recurse=RECURSE_ALWAYS;
+ break;
+ case '-':
+ Recurse=RECURSE_DISABLE;
+ break;
+ case '0':
+ Recurse=RECURSE_WILDCARDS;
+ break;
+#ifndef _WIN_CE
+ case 'I':
+ {
+ Priority=atoiw(Switch+2);
+ if (Priority<0 || Priority>15)
+ BadSwitch(Switch);
+ const wchar *ChPtr=wcschr(Switch+2,':');
+ if (ChPtr!=NULL)
+ {
+ SleepTime=atoiw(ChPtr+1);
+ if (SleepTime>1000)
+ BadSwitch(Switch);
+ InitSystemOptions(SleepTime);
+ }
+ SetPriority(Priority);
+ }
+ break;
+#endif
+ }
break;
case 'S':
if (IsDigit(Switch[1]))
{
Solid|=SOLID_COUNT;
- SolidCount=atoi(&Switch[1]);
+ SolidCount=atoiw(&Switch[1]);
}
else
- switch(etoupper(Switch[1]))
+ switch(toupperw(Switch[1]))
{
case 0:
Solid|=SOLID_NORMAL;
@@ -862,19 +709,18 @@ void CommandData::ProcessSwitch(const char *Switch,const wchar *SwitchW)
break;
case 'L':
if (IsDigit(Switch[2]))
- FileSizeLess=atoil(Switch+2);
+ FileSizeLess=atoilw(Switch+2);
break;
case 'M':
if (IsDigit(Switch[2]))
- FileSizeMore=atoil(Switch+2);
+ FileSizeMore=atoilw(Switch+2);
break;
case 'C':
{
- // Switch is already found bad, avoid reporting it several times.
- bool AlreadyBad=false;
+ bool AlreadyBad=false; // Avoid reporting "bad switch" several times.
RAR_CHARSET rch=RCH_DEFAULT;
- switch(etoupper(Switch[2]))
+ switch(toupperw(Switch[2]))
{
case 'A':
rch=RCH_ANSI;
@@ -894,8 +740,8 @@ void CommandData::ProcessSwitch(const char *Switch,const wchar *SwitchW)
if (Switch[3]==0)
CommentCharset=FilelistCharset=rch;
else
- for (int I=3;Switch[I]!=0 && !AlreadyBad;I++)
- switch(etoupper(Switch[I]))
+ for (uint I=3;Switch[I]!=0 && !AlreadyBad;I++)
+ switch(toupperw(Switch[I]))
{
case 'C':
CommentCharset=rch;
@@ -913,32 +759,111 @@ void CommandData::ProcessSwitch(const char *Switch,const wchar *SwitchW)
}
break;
- case 'C':
- if (Switch[2]==0)
- switch(etoupper(Switch[1]))
- {
- case '-':
- DisableComment=true;
- break;
- case 'U':
- ConvertNames=NAMES_UPPERCASE;
- break;
- case 'L':
- ConvertNames=NAMES_LOWERCASE;
- break;
- }
- break;
- case 'K':
- switch(etoupper(Switch[1]))
+ case 'T':
+ switch(toupperw(Switch[1]))
{
+ case 'K':
+ ArcTime=ARCTIME_KEEP;
+ break;
+ case 'L':
+ ArcTime=ARCTIME_LATEST;
+ break;
+ case 'O':
+ FileTimeBefore.SetAgeText(Switch+2);
+ break;
+ case 'N':
+ FileTimeAfter.SetAgeText(Switch+2);
+ break;
case 'B':
- KeepBroken=true;
+ FileTimeBefore.SetIsoText(Switch+2);
+ break;
+ case 'A':
+ FileTimeAfter.SetIsoText(Switch+2);
+ break;
+ case 'S':
+ {
+ EXTTIME_MODE Mode=EXTTIME_HIGH3;
+ bool CommonMode=Switch[2]>='0' && Switch[2]<='4';
+ if (CommonMode)
+ Mode=(EXTTIME_MODE)(Switch[2]-'0');
+ if (Switch[2]=='-')
+ Mode=EXTTIME_NONE;
+ if (CommonMode || Switch[2]=='-' || Switch[2]=='+' || Switch[2]==0)
+ xmtime=xctime=xatime=Mode;
+ else
+ {
+ if (Switch[3]>='0' && Switch[3]<='4')
+ Mode=(EXTTIME_MODE)(Switch[3]-'0');
+ if (Switch[3]=='-')
+ Mode=EXTTIME_NONE;
+ switch(toupperw(Switch[2]))
+ {
+ case 'M':
+ xmtime=Mode;
+ break;
+ case 'C':
+ xctime=Mode;
+ break;
+ case 'A':
+ xatime=Mode;
+ break;
+ }
+ }
+ }
+ break;
+ case '-':
+ Test=false;
break;
case 0:
- Lock=true;
+ Test=true;
+ break;
+ default:
+ BadSwitch(Switch);
break;
}
break;
+ case 'U':
+ if (Switch[1]==0)
+ UpdateFiles=true;
+ else
+ BadSwitch(Switch);
+ break;
+ case 'V':
+ switch(toupperw(Switch[1]))
+ {
+ case 'P':
+ VolumePause=true;
+ break;
+ case 'E':
+ if (toupperw(Switch[2])=='R')
+ VersionControl=atoiw(Switch+3)+1;
+ break;
+ case '-':
+ VolSize=0;
+ break;
+ default:
+ VolSize=VOLSIZE_AUTO; // UnRAR -v switch for list command.
+ break;
+ }
+ break;
+ case 'W':
+ wcsncpyz(TempPath,Switch+1,ASIZE(TempPath));
+ AddEndSlash(TempPath,ASIZE(TempPath));
+ break;
+ case 'Y':
+ AllYes=true;
+ break;
+ case 'Z':
+ if (Switch[1]==0)
+ {
+#ifndef GUI // stdin is not supported by WinRAR.
+ // If comment file is not specified, we read data from stdin.
+ wcscpy(CommentFile,L"stdin");
+#endif
+ }
+ else
+ wcsncpyz(CommentFile,Switch+1,ASIZE(CommentFile));
+ break;
#ifndef GUI
case '?' :
OutHelp(RARX_SUCCESS);
@@ -953,7 +878,7 @@ void CommandData::ProcessSwitch(const char *Switch,const wchar *SwitchW)
#ifndef SFX_MODULE
-void CommandData::BadSwitch(const char *Switch)
+void CommandData::BadSwitch(const wchar *Switch)
{
mprintf(St(MUnknownOption),Switch);
ErrHandler.Exit(RARX_USERERROR);
@@ -974,12 +899,12 @@ void CommandData::OutTitle()
if (TitleShown)
return;
TitleShown=true;
- char Version[50];
+ wchar Version[50];
int Beta=RARVER_BETA;
if (Beta!=0)
- sprintf(Version,"%d.%02d %s %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA);
+ swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA);
else
- sprintf(Version,"%d.%02d",RARVER_MAJOR,RARVER_MINOR);
+ swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR);
#ifdef UNRAR
mprintf(St(MUCopyright),Version,RARVER_YEAR);
#else
@@ -996,7 +921,7 @@ inline bool CmpMSGID(MSGID i1,MSGID i2)
return(i1==i2);
#else
// If MSGID is const char*, we cannot compare pointers only.
- // Pointers to different instances of same strings can differ,
+ // Pointers to different instances of same string can differ,
// so we need to compare complete strings.
return(strcmp(i1,i2)==0);
#endif
@@ -1026,13 +951,11 @@ void CommandData::OutHelp(RAR_EXIT ExitCode)
#endif
};
- for (int I=0;I<sizeof(Help)/sizeof(Help[0]);I++)
+ for (uint I=0;I<ASIZE(Help);I++)
{
#ifndef SFX_MODULE
-#ifdef DISABLEAUTODETECT
if (Help[I]==MCHelpSwV)
continue;
-#endif
#ifndef _WIN_ALL
static MSGID Win32Only[]={
MCHelpSwIEML,MCHelpSwVD,MCHelpSwAO,MCHelpSwOS,MCHelpSwIOFF,
@@ -1064,7 +987,6 @@ void CommandData::OutHelp(RAR_EXIT ExitCode)
if (CmpMSGID(Help[I],MCHelpSwMT))
continue;
#endif
-#ifndef _BEOS
if (CmpMSGID(Help[I],MCHelpSwEE))
{
#if defined(_EMX) && !defined(_DJGPP)
@@ -1075,10 +997,9 @@ void CommandData::OutHelp(RAR_EXIT ExitCode)
#endif
}
#endif
-#endif
mprintf(St(Help[I]));
}
- mprintf("\n");
+ mprintf(L"\n");
ErrHandler.Exit(ExitCode);
#endif
}
@@ -1087,28 +1008,28 @@ void CommandData::OutHelp(RAR_EXIT ExitCode)
// Return 'true' if we need to exclude the file from processing as result
// of -x switch. If CheckInclList is true, we also check the file against
// the include list created with -n switch.
-bool CommandData::ExclCheck(char *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList)
+bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList)
{
- if (ExclCheckArgs(ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
- return(true);
- if (!CheckInclList || InclArgs->ItemsCount()==0)
- return(false);
- if (ExclCheckArgs(InclArgs,Dir,CheckName,false,MATCH_WILDSUBPATH))
- return(false);
- return(true);
+ if (ExclCheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
+ return true;
+ if (!CheckInclList || InclArgs.ItemsCount()==0)
+ return false;
+ if (ExclCheckArgs(&InclArgs,Dir,CheckName,false,MATCH_WILDSUBPATH))
+ return false;
+ return true;
}
-bool CommandData::ExclCheckArgs(StringList *Args,bool Dir,char *CheckName,bool CheckFullPath,int MatchMode)
+bool CommandData::ExclCheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode)
{
- char *Name=ConvertPath(CheckName,NULL);
- char FullName[NM];
- char CurMask[NM+1]; // We reserve the space to append "*" to mask.
+ wchar *Name=ConvertPath(CheckName,NULL);
+ wchar FullName[NM];
+ wchar CurMask[NM+1]; // We reserve the space to append "*" to mask.
*FullName=0;
Args->Rewind();
while (Args->GetString(CurMask,ASIZE(CurMask)-1))
{
- char *LastMaskChar=PointToLastChar(CurMask);
+ wchar *LastMaskChar=PointToLastChar(CurMask);
bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only.
if (Dir)
@@ -1139,7 +1060,7 @@ bool CommandData::ExclCheckArgs(StringList *Args,bool Dir,char *CheckName,bool C
// from further scanning.
if (DirMask)
- strcat(CurMask,"*");
+ wcscat(CurMask,L"*");
}
#ifndef SFX_MODULE
@@ -1152,14 +1073,14 @@ bool CommandData::ExclCheckArgs(StringList *Args,bool Dir,char *CheckName,bool C
// the comparison, because now all names have the path.
if (*FullName==0)
- ConvertNameToFull(CheckName,FullName);
+ ConvertNameToFull(CheckName,FullName,ASIZE(FullName));
if (CmpName(CurMask,FullName,MatchMode))
- return(true);
+ return true;
}
else
#endif
{
- char NewName[NM+2],*CurName=Name;
+ wchar NewName[NM+2],*CurName=Name;
if (CurMask[0]=='*' && IsPathDiv(CurMask[1]))
{
// We want "*\name" to match 'name' not only in subdirectories,
@@ -1168,15 +1089,15 @@ bool CommandData::ExclCheckArgs(StringList *Args,bool Dir,char *CheckName,bool C
// in current directory.
NewName[0]='.';
NewName[1]=CPATHDIVIDER;
- strncpyz(NewName+2,Name,ASIZE(NewName)-2);
+ wcsncpyz(NewName+2,Name,ASIZE(NewName)-2);
CurName=NewName;
}
if (CmpName(ConvertPath(CurMask,NULL),CurName,MatchMode))
- return(true);
+ return true;
}
}
- return(false);
+ return false;
}
@@ -1206,10 +1127,10 @@ bool CommandData::ExclDirByAttr(uint FileAttr)
bool CommandData::TimeCheck(RarTime &ft)
{
if (FileTimeBefore.IsSet() && ft>=FileTimeBefore)
- return(true);
+ return true;
if (FileTimeAfter.IsSet() && ft<=FileTimeAfter)
- return(true);
- return(false);
+ return true;
+ return false;
}
#endif
@@ -1229,62 +1150,31 @@ bool CommandData::SizeCheck(int64 Size)
-int CommandData::IsProcessFile(FileHeader &NewLhd,bool *ExactMatch,int MatchType)
+int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType)
{
- if (strlen(NewLhd.FileName)>=NM || wcslen(NewLhd.FileNameW)>=NM)
- return(0);
- bool Dir=(NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY;
- if (ExclCheck(NewLhd.FileName,Dir,false,true))
- return(0);
+ if (wcslen(FileHead.FileName)>=NM)
+ return 0;
+ bool Dir=FileHead.Dir;
+ if (ExclCheck(FileHead.FileName,Dir,false,true))
+ return 0;
#ifndef SFX_MODULE
- if (TimeCheck(NewLhd.mtime))
- return(0);
- if ((NewLhd.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (NewLhd.FileAttr & InclFileAttr)==0)
- return(0);
- if (!Dir && SizeCheck(NewLhd.FullUnpSize))
- return(0);
+ if (TimeCheck(FileHead.mtime))
+ return 0;
+ if ((FileHead.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0)
+ return 0;
+ if (!Dir && SizeCheck(FileHead.UnpSize))
+ return 0;
#endif
- char *ArgName;
- wchar *ArgNameW;
- FileArgs->Rewind();
- for (int StringCount=1;FileArgs->GetString(&ArgName,&ArgNameW);StringCount++)
- {
-#ifndef SFX_MODULE
- bool Unicode=(NewLhd.Flags & LHD_UNICODE) || ArgNameW!=NULL && *ArgNameW!=0;
- if (Unicode)
- {
- wchar NameW[NM],ArgW[NM],*NamePtr=NewLhd.FileNameW;
- bool CorrectUnicode=true;
- if (ArgNameW==NULL || *ArgNameW==0)
- {
- if (!CharToWide(ArgName,ArgW) || *ArgW==0)
- CorrectUnicode=false;
- ArgNameW=ArgW;
- }
- if ((NewLhd.Flags & LHD_UNICODE)==0)
- {
- if (!CharToWide(NewLhd.FileName,NameW) || *NameW==0)
- CorrectUnicode=false;
- NamePtr=NameW;
- }
- if (CmpName(ArgNameW,NamePtr,MatchType))
- {
- if (ExactMatch!=NULL)
- *ExactMatch=wcsicompc(ArgNameW,NamePtr)==0;
- return(StringCount);
- }
- if (CorrectUnicode)
- continue;
- }
-#endif
- if (CmpName(ArgName,NewLhd.FileName,MatchType))
+ wchar *ArgName;
+ FileArgs.Rewind();
+ for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++)
+ if (CmpName(ArgName,FileHead.FileName,MatchType))
{
if (ExactMatch!=NULL)
- *ExactMatch=stricompc(ArgName,NewLhd.FileName)==0;
- return(StringCount);
+ *ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0;
+ return StringCount;
}
- }
- return(0);
+ return 0;
}
@@ -1293,32 +1183,32 @@ void CommandData::ProcessCommand()
{
#ifndef SFX_MODULE
- const char *SingleCharCommands="FUADPXETK";
- if (Command[0]!=0 && Command[1]!=0 && strchr(SingleCharCommands,*Command)!=NULL || *ArcName==0)
+ const wchar *SingleCharCommands=L"FUADPXETK";
+ if (Command[0]!=0 && Command[1]!=0 && wcschr(SingleCharCommands,Command[0])!=NULL || *ArcName==0)
OutHelp(*Command==0 ? RARX_SUCCESS:RARX_USERERROR); // Return 'success' for 'rar' without parameters.
#ifdef _UNIX
if (GetExt(ArcName)==NULL && (!FileExist(ArcName) || IsDir(GetFileAttr(ArcName))))
- strncatz(ArcName,".rar",ASIZE(ArcName));
+ wcsncatz(ArcName,L".rar",ASIZE(ArcName));
#else
if (GetExt(ArcName)==NULL)
- strncatz(ArcName,".rar",ASIZE(ArcName));
+ wcsncatz(ArcName,L".rar",ASIZE(ArcName));
#endif
- if (strchr("AFUMD",*Command)==NULL)
+ if (wcschr(L"AFUMD",*Command)==NULL)
{
if (GenerateArcName)
- GenerateArchiveName(ArcName,ArcNameW,ASIZE(ArcName),GenerateMask,false);
+ GenerateArchiveName(ArcName,ASIZE(ArcName),GenerateMask,false);
StringList ArcMasks;
ArcMasks.AddString(ArcName);
- ScanTree Scan(&ArcMasks,Recurse,SaveLinks,SCAN_SKIPDIRS);
+ ScanTree Scan(&ArcMasks,Recurse,SaveSymLinks,SCAN_SKIPDIRS);
FindData FindData;
while (Scan.GetNext(&FindData)==SCAN_SUCCESS)
- AddArcName(FindData.Name,FindData.NameW);
+ AddArcName(FindData.Name);
}
else
- AddArcName(ArcName,NULL);
+ AddArcName(ArcName);
#endif
switch(Command[0])
@@ -1329,7 +1219,7 @@ void CommandData::ProcessCommand()
case 'T':
case 'I':
{
- CmdExtract Extract;
+ CmdExtract Extract(this);
Extract.DoExtract(this);
}
break;
@@ -1343,22 +1233,20 @@ void CommandData::ProcessCommand()
#endif
}
if (!BareOutput)
- mprintf("\n");
+ mprintf(L"\n");
}
#endif
-void CommandData::AddArcName(const char *Name,const wchar *NameW)
+void CommandData::AddArcName(const wchar *Name)
{
- ArcNames->AddString(Name,NameW);
+ ArcNames.AddString(Name);
}
-bool CommandData::GetArcName(char *Name,wchar *NameW,int MaxSize)
+bool CommandData::GetArcName(wchar *Name,int MaxSize)
{
- if (!ArcNames->GetString(Name,NameW,NM))
- return(false);
- return(true);
+ return ArcNames.GetString(Name,MaxSize);
}
@@ -1373,43 +1261,44 @@ bool CommandData::IsSwitch(int Ch)
#ifndef SFX_MODULE
-uint CommandData::GetExclAttr(const char *Str)
+uint CommandData::GetExclAttr(const wchar *Str)
{
if (IsDigit(*Str))
- return(strtol(Str,NULL,0));
- else
+ return(wcstol(Str,NULL,0));
+
+ uint Attr=0;
+ while (*Str!=0)
{
- uint Attr;
- for (Attr=0;*Str;Str++)
- switch(etoupper(*Str))
- {
+ switch(toupperw(*Str))
+ {
#ifdef _UNIX
- case 'D':
- Attr|=S_IFDIR;
- break;
- case 'V':
- Attr|=S_IFCHR;
- break;
+ case 'D':
+ Attr|=S_IFDIR;
+ break;
+ case 'V':
+ Attr|=S_IFCHR;
+ break;
#elif defined(_WIN_ALL) || defined(_EMX)
- case 'R':
- Attr|=0x1;
- break;
- case 'H':
- Attr|=0x2;
- break;
- case 'S':
- Attr|=0x4;
- break;
- case 'D':
- Attr|=0x10;
- break;
- case 'A':
- Attr|=0x20;
- break;
+ case 'R':
+ Attr|=0x1;
+ break;
+ case 'H':
+ Attr|=0x2;
+ break;
+ case 'S':
+ Attr|=0x4;
+ break;
+ case 'D':
+ Attr|=0x10;
+ break;
+ case 'A':
+ Attr|=0x20;
+ break;
#endif
- }
- return(Attr);
+ }
+ Str++;
}
+ return Attr;
}
#endif
@@ -1419,13 +1308,58 @@ uint CommandData::GetExclAttr(const char *Str)
#ifndef SFX_MODULE
bool CommandData::CheckWinSize()
{
- static int ValidSize[]={
- 0x10000,0x20000,0x40000,0x80000,0x100000,0x200000,0x400000
- };
- for (int I=0;I<sizeof(ValidSize)/sizeof(ValidSize[0]);I++)
- if (WinSize==ValidSize[I])
- return(true);
+ // Define 0x100000000 as macro to avoid troubles with older compilers.
+ const uint64 MaxDictSize=INT32TO64(1,0);
+ // Limit the dictionary size to 4 GB.
+ for (uint64 I=0x10000;I<=MaxDictSize;I*=2)
+ if (WinSize==I)
+ return true;
WinSize=0x400000;
- return(false);
+ return false;
+}
+#endif
+
+
+#ifndef SFX_MODULE
+void CommandData::ReportWrongSwitches(RARFORMAT Format)
+{
+ if (Format==RARFMT15)
+ {
+ if (HashType!=HASH_CRC32)
+ {
+ mprintf(St(MIncompatSwitch),L"-ht",4);
+ }
+#ifdef _WIN_ALL
+ if (SaveSymLinks)
+ {
+ mprintf(St(MIncompatSwitch),L"-ol",4);
+ }
+#endif
+ if (SaveHardLinks)
+ {
+ mprintf(St(MIncompatSwitch),L"-oh",4);
+ }
+
+#ifdef _WIN_ALL
+
+
+#endif
+ if (QOpenMode!=QOPEN_AUTO)
+ {
+ mprintf(St(MIncompatSwitch),L"-qo",4);
+ }
+/*
+ // We use 64 MB for both formats and reduce it for RAR 4.x later.
+ if (WinSize>0x400000)
+ {
+ wchar SwMD[10];
+ swprintf(SwMD,ASIZE(SwMD),L"-md%dm",WinSize/0x100000);
+ mprintf(St(MIncompatSwitch),SwMD,4);
+ }
+*/
+ }
+ if (Format==RARFMT50)
+ {
+ }
}
#endif
diff --git a/src/thirdparty/unrar/cmddata.hpp b/src/thirdparty/unrar/cmddata.hpp
index aef6deb3b..b2f3b1ae1 100644
--- a/src/thirdparty/unrar/cmddata.hpp
+++ b/src/thirdparty/unrar/cmddata.hpp
@@ -2,18 +2,18 @@
#define _RAR_CMDDATA_
-#define DefaultStoreList "7z;ace;arj;bz2;cab;gz;jpeg;jpg;lha;lzh;mp3;rar;taz;tgz;z;zip"
+#define DefaultStoreList L"7z;ace;arj;bz2;cab;gz;jpeg;jpg;lha;lzh;mp3;rar;taz;tgz;xz;z;zip"
enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS};
class CommandData:public RAROptions
{
private:
- void ProcessSwitchesString(char *Str);
- void ProcessSwitch(const char *Switch,const wchar *SwitchW=NULL);
- void BadSwitch(const char *Switch);
- bool ExclCheckArgs(StringList *Args,bool Dir,char *CheckName,bool CheckFullPath,int MatchMode);
- uint GetExclAttr(const char *Str);
+ 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;
bool NoMoreSwitches;
@@ -21,44 +21,43 @@ class CommandData:public RAROptions
bool BareOutput;
public:
CommandData();
- ~CommandData();
void Init();
- void Close();
- void PreprocessCommandLine(int argc, char *argv[]);
- void ParseCommandLine(int argc, char *argv[]);
- void ParseArg(char *Arg,wchar *ArgW);
+ void ParseCommandLine(bool Preprocess,int argc, char *argv[]);
+ void ParseArg(wchar *ArgW);
void ParseDone();
void ParseEnvVar();
void ReadConfig();
- bool PreprocessSwitch(const char *Switch);
+ bool PreprocessSwitch(const wchar *Switch);
void OutTitle();
void OutHelp(RAR_EXIT ExitCode);
bool IsSwitch(int Ch);
- bool ExclCheck(char *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList);
+ bool ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList);
bool ExclDirByAttr(uint FileAttr);
bool TimeCheck(RarTime &ft);
bool SizeCheck(int64 Size);
bool AnyFiltersActive();
- int IsProcessFile(FileHeader &NewLhd,bool *ExactMatch=NULL,int MatchType=MATCH_WILDSUBPATH);
+ int IsProcessFile(FileHeader &FileHead,bool *ExactMatch=NULL,int MatchType=MATCH_WILDSUBPATH);
void ProcessCommand();
- void AddArcName(const char *Name,const wchar *NameW);
- bool GetArcName(char *Name,wchar *NameW,int MaxSize);
+ void AddArcName(const wchar *Name);
+ bool GetArcName(wchar *Name,int MaxSize);
bool CheckWinSize();
- int GetRecoverySize(const char *Str,int DefSize);
+ int GetRecoverySize(const wchar *Str,int DefSize);
- char Command[NM+16];
- wchar CommandW[NM+16];
+#ifndef SFX_MODULE
+ void ReportWrongSwitches(RARFORMAT Format);
+#endif
+
+ wchar Command[NM+16];
- char ArcName[NM];
- wchar ArcNameW[NM];
+ wchar ArcName[NM];
- StringList *FileArgs;
- StringList *ExclArgs;
- StringList *InclArgs;
- StringList *ArcNames;
- StringList *StoreArgs;
+ StringList FileArgs;
+ StringList ExclArgs;
+ StringList InclArgs;
+ StringList ArcNames;
+ StringList StoreArgs;
};
#endif
diff --git a/src/thirdparty/unrar/compress.hpp b/src/thirdparty/unrar/compress.hpp
index 3157e1a3b..edaed3084 100644
--- a/src/thirdparty/unrar/compress.hpp
+++ b/src/thirdparty/unrar/compress.hpp
@@ -1,23 +1,25 @@
#ifndef _RAR_COMPRESS_
#define _RAR_COMPRESS_
-class ComprDataIO;
-class PackingFileTable;
-
-#define MAX_LZ_MATCH 0x101
-
-#define MAXWINSIZE 0x400000
-#define MAXWINMASK (MAXWINSIZE-1)
+#define MAX_LZ_MATCH 0x1001
+#define MAX3_LZ_MATCH 0x101 // Maximum match length for RAR v3.
#define LOW_DIST_REP_COUNT 16
-#define NC 299 /* alphabet = {0, 1, 2, ..., NC - 1} */
-#define DC 60
-#define LDC 17
-#define RC 28
+#define NC 306 /* alphabet = {0, 1, 2, ..., NC - 1} */
+#define DC 64
+#define LDC 16
+#define RC 44
#define HUFF_TABLE_SIZE (NC+DC+RC+LDC)
#define BC 20
+#define NC30 299 /* alphabet = {0, 1, 2, ..., NC - 1} */
+#define DC30 60
+#define LDC30 17
+#define RC30 28
+#define BC30 20
+#define HUFF_TABLE_SIZE30 (NC30+DC30+RC30+LDC30)
+
#define NC20 298 /* alphabet = {0, 1, 2, ..., NC - 1} */
#define DC20 48
#define RC20 28
@@ -25,16 +27,15 @@ class PackingFileTable;
#define MC20 257
// Largest alphabet size among all values listed above.
-#define LARGEST_TABLE_SIZE 299
+#define LARGEST_TABLE_SIZE 306
-enum {CODE_HUFFMAN,CODE_LZ,CODE_LZ2,CODE_REPEATLZ,CODE_CACHELZ,
- CODE_STARTFILE,CODE_ENDFILE,CODE_VM,CODE_VMDATA};
+enum {CODE_HUFFMAN,CODE_LZ,CODE_REPEATLZ,CODE_CACHELZ,
+ CODE_STARTFILE,CODE_ENDFILE,CODE_FILTER,CODE_FILTERDATA};
enum FilterType {
- FILTER_NONE, FILTER_PPM /*dummy*/, FILTER_E8, FILTER_E8E9,
- FILTER_UPCASETOLOW, FILTER_AUDIO, FILTER_RGB, FILTER_DELTA,
- FILTER_ITANIUM, FILTER_E8E9V2
+ FILTER_DELTA=0, FILTER_E8, FILTER_E8E9, FILTER_ARM,
+ FILTER_AUDIO, FILTER_RGB, FILTER_ITANIUM, FILTER_PPM /*dummy*/, FILTER_NONE
};
#endif
diff --git a/src/thirdparty/unrar/consio.cpp b/src/thirdparty/unrar/consio.cpp
index 42b72a617..46079d2ef 100644
--- a/src/thirdparty/unrar/consio.cpp
+++ b/src/thirdparty/unrar/consio.cpp
@@ -1,19 +1,51 @@
#include "rar.hpp"
-
-#ifndef GUI
#include "log.cpp"
+
+static MESSAGE_TYPE MsgStream=MSG_STDOUT;
+static bool Sound=false;
+const int MaxMsgSize=2*NM+2048;
+
+#ifdef _WIN_ALL
+static bool StdoutRedirected=false,StderrRedirected=false,StdinRedirected=false;
#endif
-static int KbdAnsi(char *Addr,int Size);
-#if !defined(GUI) && !defined(SILENT)
-static void RawPrint(char *Msg,MESSAGE_TYPE MessageType);
-static byte GetKey();
+#ifdef _WIN_ALL
+static bool IsRedirected(DWORD nStdHandle)
+{
+ HANDLE hStd=GetStdHandle(nStdHandle);
+ DWORD Mode;
+ return GetFileType(hStd)!=FILE_TYPE_CHAR || GetConsoleMode(hStd,&Mode)==0;
+}
#endif
-static MESSAGE_TYPE MsgStream=MSG_STDOUT;
-static bool Sound=false;
-const int MaxMsgSize=2*NM+2048;
+
+void InitConsole()
+{
+#ifdef _WIN_ALL
+ // We want messages like file names or progress percent to be printed
+ // immediately. Use only in Windows, in Unix they can cause wprintf %ls
+ // to fail with non-English strings.
+ setbuf(stdout,NULL);
+ setbuf(stderr,NULL);
+
+ // Detect if output is redirected and set output mode properly.
+ // We do not want to send Unicode output to files and especially to pipes
+ // like '|more', which cannot handle them correctly in Windows.
+ // In Unix console output is UTF-8 and it is handled correctly
+ // when redirecting, so no need to perform any adjustments.
+ StdoutRedirected=IsRedirected(STD_OUTPUT_HANDLE);
+ StderrRedirected=IsRedirected(STD_ERROR_HANDLE);
+ StdinRedirected=IsRedirected(STD_INPUT_HANDLE);
+#ifdef _MSC_VER
+ if (!StdoutRedirected)
+ _setmode(_fileno(stdout), _O_U16TEXT);
+ if (!StderrRedirected)
+ _setmode(_fileno(stderr), _O_U16TEXT);
+#endif
+#endif
+}
+
void InitConsoleOptions(MESSAGE_TYPE MsgStream,bool Sound)
{
@@ -21,89 +53,73 @@ void InitConsoleOptions(MESSAGE_TYPE MsgStream,bool Sound)
::Sound=Sound;
}
-#if !defined(GUI) && !defined(SILENT)
-void mprintf(const char *fmt,...)
+
+#ifndef SILENT
+static void cvt_wprintf(FILE *dest,const wchar *fmt,va_list arglist)
{
- if (MsgStream==MSG_NULL || MsgStream==MSG_ERRONLY)
+ // This buffer is for format string only, not for entire output,
+ // so it can be short enough.
+ wchar fmtw[1024];
+ PrintfPrepareFmt(fmt,fmtw,ASIZE(fmtw));
+#ifdef _WIN_ALL
+ 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);
+ DWORD Written;
+ WriteFile(hOut,MsgA,(DWORD)strlen(MsgA),&Written,NULL);
return;
- char Msg[MaxMsgSize];
- va_list argptr;
- va_start(argptr,fmt);
- vsnprintf(Msg,ASIZE(Msg),fmt,argptr);
-
- // Different vsnprintf implementation can return either -1 or >=MaxMsgSize
- // if string is truncated. So we do not check exit code and always zero
- // terminate the string for safety. It is faster than check for error.
- Msg[ASIZE(Msg)-1] = 0;
-
- RawPrint(Msg,MsgStream);
- va_end(argptr);
-}
+ }
+ // MSVC2008 vfwprintf writes every character to console separately
+ // and it is too slow. We use direct WriteConsole call instead.
+ vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
+ HANDLE hOut=GetStdHandle(dest==stderr ? STD_ERROR_HANDLE:STD_OUTPUT_HANDLE);
+ DWORD Written;
+ WriteConsole(hOut,Msg,(DWORD)wcslen(Msg),&Written,NULL);
+#else
+ vfwprintf(dest,fmtw,arglist);
+ // We do not use setbuf(NULL) in Unix (see comments in InitConsole).
+ fflush(dest);
#endif
+}
-#if !defined(GUI) && !defined(SILENT)
-void eprintf(const char *fmt,...)
+void mprintf(const wchar *fmt,...)
{
- if (MsgStream==MSG_NULL)
+ if (MsgStream==MSG_NULL || MsgStream==MSG_ERRONLY)
return;
- safebuf char Msg[MaxMsgSize];
- va_list argptr;
- va_start(argptr,fmt);
- vsnprintf(Msg,ASIZE(Msg),fmt,argptr);
-
- // Different vsnprintf implementation can return either -1 or >=MaxMsgSize
- // if string is truncated. So we do not check exit code and always zero
- // terminate the string for safety. It is faster than check for error.
- Msg[ASIZE(Msg)-1] = 0;
-
- RawPrint(Msg,MSG_STDERR);
- va_end(argptr);
+
+ fflush(stderr); // Ensure proper message order.
+
+ va_list arglist;
+ va_start(arglist,fmt);
+ FILE *dest=MsgStream==MSG_STDERR ? stderr:stdout;
+ cvt_wprintf(dest,fmt,arglist);
+ va_end(arglist);
}
#endif
-#if !defined(GUI) && !defined(SILENT)
-void RawPrint(char *Msg,MESSAGE_TYPE MessageType)
+#ifndef SILENT
+void eprintf(const wchar *fmt,...)
{
- File OutFile;
- switch(MessageType)
- {
- case MSG_STDOUT:
- OutFile.SetHandleType(FILE_HANDLESTD);
- break;
- case MSG_STDERR:
- case MSG_ERRONLY:
- OutFile.SetHandleType(FILE_HANDLEERR);
- break;
- default:
- return;
- }
-#ifdef _WIN_ALL
- CharToOemA(Msg,Msg);
+ if (MsgStream==MSG_NULL)
+ return;
- char OutMsg[MaxMsgSize];
- size_t OutPos=0;
- for (size_t I=0;Msg[I]!=0;I++)
- {
- if (Msg[I]=='\n' && (I==0 || Msg[I-1]!='\r') && OutPos<ASIZE(OutMsg)-1)
- OutMsg[OutPos++]='\r';
- if (OutPos<ASIZE(OutMsg)-1)
- OutMsg[OutPos++]=Msg[I];
- }
- OutMsg[OutPos]=0;
- strcpy(Msg,OutMsg);
-#endif
-#if defined(_UNIX) || defined(_EMX)
- char OutMsg[MaxMsgSize],*OutPos=OutMsg;
- for (size_t I=0;Msg[I]!=0;I++)
- if (Msg[I]!='\r')
- *(OutPos++)=Msg[I];
- *OutPos=0;
- strcpy(Msg,OutMsg);
-#endif
+ fflush(stdout); // Ensure proper message order.
- OutFile.Write(Msg,strlen(Msg));
+ va_list arglist;
+ va_start(arglist,fmt);
+ cvt_wprintf(stderr,fmt,arglist);
+ va_end(arglist);
}
#endif
@@ -111,17 +127,24 @@ void RawPrint(char *Msg,MESSAGE_TYPE MessageType)
#ifndef SILENT
void Alarm()
{
-#ifndef SFX_MODULE
if (Sound)
- putchar('\007');
+ {
+ static clock_t LastTime=clock();
+ if ((clock()-LastTime)/CLOCKS_PER_SEC>5)
+ {
+#ifdef _WIN_ALL
+ MessageBeep(-1);
+#else
+ putwchar('\007');
#endif
+ }
+ }
}
#endif
#ifndef SILENT
-#ifndef GUI
-void GetPasswordText(wchar *Str,uint MaxLength)
+static void GetPasswordText(wchar *Str,uint MaxLength)
{
if (MaxLength==0)
return;
@@ -135,14 +158,16 @@ void GetPasswordText(wchar *Str,uint MaxLength)
SetConsoleMode(hConIn,ENABLE_LINE_INPUT);
SetConsoleMode(hConOut,ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT);
- ReadConsoleW(hConIn,Str,MaxLength-1,&Read,NULL);
+ ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL);
Str[Read]=0;
SetConsoleMode(hConIn,ConInMode);
SetConsoleMode(hConOut,ConOutMode);
#else
char StrA[MAXPASSWORD];
-#if defined(_EMX) || defined(_BEOS) || defined(__sparc) || defined(sparc) || defined (__VMS)
+#if defined(_EMX) || defined (__VMS)
fgets(StrA,ASIZE(StrA)-1,stdin);
+#elif defined(__sun)
+ strncpyz(StrA,getpassphrase(""),ASIZE(StrA));
#else
strncpyz(StrA,getpass(""),ASIZE(StrA));
#endif
@@ -153,35 +178,24 @@ void GetPasswordText(wchar *Str,uint MaxLength)
RemoveLF(Str);
}
#endif
-#endif
#ifndef SILENT
-bool GetPassword(PASSWORD_TYPE Type,const char *FileName,const wchar *FileNameW,
- SecPassword *Password)
+bool GetConsolePassword(PASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
{
Alarm();
+
while (true)
{
- char PromptStr[NM+256];
-#if defined(_EMX) || defined(_BEOS)
- strcpy(PromptStr,St(MAskPswEcho));
-#else
- strcpy(PromptStr,St(MAskPsw));
-#endif
- if (Type!=PASSWORD_GLOBAL)
- {
- strcat(PromptStr,St(MFor));
- char *NameOnly=PointToName(FileName);
- if (strlen(PromptStr)+strlen(NameOnly)<ASIZE(PromptStr))
- strcat(PromptStr,NameOnly);
- }
- eprintf("\n%s: ",PromptStr);
+ if (Type==PASSWORD_GLOBAL)
+ eprintf(L"\n%s: ",St(MAskPsw));
+ else
+ eprintf(St(MAskPswFor),FileName);
wchar PlainPsw[MAXPASSWORD];
GetPasswordText(PlainPsw,ASIZE(PlainPsw));
if (*PlainPsw==0 && Type==PASSWORD_GLOBAL)
- return(false);
+ return false;
if (Type==PASSWORD_GLOBAL)
{
eprintf(St(MReAskPsw));
@@ -200,46 +214,69 @@ bool GetPassword(PASSWORD_TYPE Type,const char *FileName,const wchar *FileNameW,
cleandata(PlainPsw,sizeof(PlainPsw));
break;
}
- return(true);
+ return true;
}
#endif
-#if !defined(GUI) && !defined(SILENT)
-byte GetKey()
+#ifndef SILENT
+bool getwstr(wchar *str,size_t n)
{
- char Str[80];
- bool EndOfFile;
-#if defined(__GNUC__) || defined(sun)
- EndOfFile=(fgets(Str,sizeof(Str),stdin)==NULL);
-#else
- File SrcFile;
- SrcFile.SetHandleType(FILE_HANDLESTD);
- EndOfFile=(SrcFile.Read(Str,sizeof(Str))==0);
-#endif
- if (EndOfFile)
+ // Print buffered prompt title function before waiting for input.
+ fflush(stderr);
+
+ *str=0;
+#if defined(_WIN_ALL)
+ // fgetws does not work well with non-English text in Windows,
+ // so we do not use it.
+ if (StdinRedirected) // ReadConsole does not work if redirected.
{
- // Looks like stdin is a null device. We can enter to infinite loop
- // calling Ask(), so let's better exit.
- ErrHandler.Exit(RARX_USERBREAK);
+ // fgets does not work well with pipes in Windows in our test.
+ // Let's use files.
+ Array<char> StrA(n*4); // Up to 4 UTF-8 characters per wchar_t.
+ File SrcFile;
+ SrcFile.SetHandleType(FILE_HANDLESTD);
+ int ReadSize=SrcFile.Read(&StrA[0],StrA.Size()-1);
+ if (ReadSize<=0)
+ {
+ // Looks like stdin is a null device. We can enter to infinite loop
+ // calling Ask(), so let's better exit.
+ ErrHandler.Exit(RARX_USERBREAK);
+ }
+ StrA[ReadSize-1]=0;
+ CharToWide(&StrA[0],str,n);
}
- return (byte)Str[0];
+ else
+ {
+ DWORD ReadSize=0;
+ if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE),str,DWORD(n-1),&ReadSize,NULL)==0)
+ return false;
+ str[ReadSize]=0;
+ }
+#else
+ if (fgetws(str,n,stdin)==NULL)
+ ErrHandler.Exit(RARX_USERBREAK); // Avoid infinite Ask() loop.
+#endif
+ RemoveLF(str);
+ return true;
}
#endif
-#if !defined(GUI) && !defined(SILENT)
-int Ask(const char *AskStr)
+#ifndef SILENT
+int Ask(const wchar *AskStr)
{
+ Alarm();
+
const int MaxItems=10;
- char Item[MaxItems][40];
+ wchar Item[MaxItems][40];
int ItemKeyPos[MaxItems],NumItems=0;
- for (const char *NextItem=AskStr;NextItem!=NULL;NextItem=strchr(NextItem+1,'_'))
+ for (const wchar *NextItem=AskStr;NextItem!=NULL;NextItem=wcschr(NextItem+1,'_'))
{
- char *CurItem=Item[NumItems];
- strncpyz(CurItem,NextItem+1,ASIZE(Item[0]));
- char *EndItem=strchr(CurItem,'_');
+ wchar *CurItem=Item[NumItems];
+ wcsncpyz(CurItem,NextItem+1,ASIZE(Item[0]));
+ wchar *EndItem=wcschr(CurItem,'_');
if (EndItem!=NULL)
*EndItem=0;
int KeyPos=0,CurKey;
@@ -247,7 +284,7 @@ int Ask(const char *AskStr)
{
bool Found=false;
for (int I=0;I<NumItems && !Found;I++)
- if (loctoupper(Item[I][ItemKeyPos[I]])==loctoupper(CurKey))
+ if (toupperw(Item[I][ItemKeyPos[I]])==toupperw(CurKey))
Found=true;
if (!Found && CurKey!=' ')
break;
@@ -259,61 +296,53 @@ int Ask(const char *AskStr)
for (int I=0;I<NumItems;I++)
{
- eprintf(I==0 ? (NumItems>4 ? "\n":" "):", ");
+ eprintf(I==0 ? (NumItems>4 ? L"\n":L" "):L", ");
int KeyPos=ItemKeyPos[I];
for (int J=0;J<KeyPos;J++)
- eprintf("%c",Item[I][J]);
- eprintf("[%c]%s",Item[I][KeyPos],&Item[I][KeyPos+1]);
+ eprintf(L"%c",Item[I][J]);
+ eprintf(L"[%c]%ls",Item[I][KeyPos],&Item[I][KeyPos+1]);
}
- eprintf(" ");
- byte Ch=GetKey();
-#if defined(_WIN_ALL)
- OemToCharBuffA((LPCSTR)&Ch,(LPSTR)&Ch,1);
-#endif
- Ch=loctoupper(Ch);
+ eprintf(L" ");
+ wchar Str[50];
+ getwstr(Str,ASIZE(Str));
+ wchar Ch=toupperw(Str[0]);
for (int I=0;I<NumItems;I++)
- if (Ch==(byte)Item[I][ItemKeyPos[I]])
- return(I+1);
- return(0);
+ if (Ch==Item[I][ItemKeyPos[I]])
+ return I+1;
+ return 0;
}
#endif
-int KbdAnsi(char *Addr,size_t Size)
+static bool IsCommentUnsafe(const wchar *Data,size_t Size)
{
- int RetCode=0;
-#ifndef GUI
for (size_t I=0;I<Size;I++)
- if (Addr[I]==27 && Addr[I+1]=='[')
- {
+ if (Data[I]==27 && Data[I+1]=='[')
for (size_t J=I+2;J<Size;J++)
{
- if (Addr[J]=='\"')
- return(2);
- if (!IsDigit(Addr[J]) && Addr[J]!=';')
+ // Return true for <ESC>[{key};"{string}"p used to redefine
+ // a keyboard key on some terminals.
+ if (Data[J]=='\"')
+ return true;
+ if (!IsDigit(Data[J]) && Data[J]!=';')
break;
}
- RetCode=1;
- }
-#endif
- return(RetCode);
+ return false;
}
-void OutComment(char *Comment,size_t Size)
+void OutComment(const wchar *Comment,size_t Size)
{
-#ifndef GUI
- if (KbdAnsi(Comment,Size)==2)
+ if (IsCommentUnsafe(Comment,Size))
return;
const size_t MaxOutSize=0x400;
for (size_t I=0;I<Size;I+=MaxOutSize)
{
- char Msg[MaxOutSize+1];
+ wchar Msg[MaxOutSize+1];
size_t CopySize=Min(MaxOutSize,Size-I);
- strncpy(Msg,Comment+I,CopySize);
+ wcsncpy(Msg,Comment+I,CopySize);
Msg[CopySize]=0;
- mprintf("%s",Msg);
+ mprintf(L"%s",Msg);
}
- mprintf("\n");
-#endif
+ mprintf(L"\n");
}
diff --git a/src/thirdparty/unrar/consio.hpp b/src/thirdparty/unrar/consio.hpp
index 45489c39f..225755e77 100644
--- a/src/thirdparty/unrar/consio.hpp
+++ b/src/thirdparty/unrar/consio.hpp
@@ -1,37 +1,26 @@
#ifndef _RAR_CONSIO_
#define _RAR_CONSIO_
-#if !defined(SILENT) && !defined(SFX_MODULE)
- enum {SOUND_OK,SOUND_ALARM,SOUND_ERROR,SOUND_QUESTION};
-#endif
-
-enum PASSWORD_TYPE {PASSWORD_GLOBAL,PASSWORD_FILE,PASSWORD_ARCHIVE};
-
+void InitConsole();
void InitConsoleOptions(MESSAGE_TYPE MsgStream,bool Sound);
+void OutComment(const wchar *Comment,size_t Size);
#ifndef SILENT
- void mprintf(const char *fmt,...);
- void eprintf(const char *fmt,...);
- void Alarm();
- void GetPasswordText(wchar *Str,uint MaxLength);
- bool GetPassword(PASSWORD_TYPE Type,const char *FileName,const wchar *FileNameW,SecPassword *Password);
- int Ask(const char *AskStr);
+bool GetConsolePassword(PASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password);
#endif
-void OutComment(char *Comment,size_t Size);
-
#ifdef SILENT
- #ifdef __GNUC__
- #define mprintf(args...)
- #define eprintf(args...)
- #else
- inline void mprintf(const char *fmt,...) {}
- inline void eprintf(const char *fmt,...) {}
- #endif
+ inline void mprintf(const wchar *fmt,...) {}
+ inline void eprintf(const wchar *fmt,...) {}
inline void Alarm() {}
- inline void GetPasswordText(wchar *Str,uint MaxLength) {}
- inline bool GetPassword(PASSWORD_TYPE Type,const char *FileName,const wchar *FileNameW,SecPassword *Password) {return(false);}
- inline int Ask(const char *AskStr) {return(0);}
+ inline int Ask(const wchar *AskStr) {return 0;}
+ inline bool getwstr(wchar *str,size_t n) {return false;}
+#else
+ void mprintf(const wchar *fmt,...);
+ void eprintf(const wchar *fmt,...);
+ void Alarm();
+ int Ask(const wchar *AskStr);
+ bool getwstr(wchar *str,size_t n);
#endif
#endif
diff --git a/src/thirdparty/unrar/crc.cpp b/src/thirdparty/unrar/crc.cpp
index 26590fda1..ddd6dc8de 100644
--- a/src/thirdparty/unrar/crc.cpp
+++ b/src/thirdparty/unrar/crc.cpp
@@ -14,23 +14,30 @@
#include "rar.hpp"
-// CRCTab duplicates crc_tables[0], but we still need it to decrypt
-// old version RAR archives. GUI code might use it for ZIP encryption.
-uint CRCTab[256];
-
static uint crc_tables[8][256]; // Tables for Slicing-by-8.
-void InitCRC()
+
+// Build the classic CRC32 lookup table.
+// We also provide this function to legacy RAR and ZIP decryption code.
+void InitCRC32(uint *CRCTab)
{
- for (uint I=0;I<256;I++) // Build the classic CRC32 lookup table.
+ if (CRCTab[1]!=0)
+ return;
+ for (uint I=0;I<256;I++)
{
uint C=I;
for (uint J=0;J<8;J++)
- C=(C & 1) ? (C>>1)^0xEDB88320L : (C>>1);
- CRCTab[I]=crc_tables[0][I]=C;
+ C=(C & 1) ? (C>>1)^0xEDB88320 : (C>>1);
+ CRCTab[I]=C;
}
+}
- for (uint I=0;I<=256;I++) // Build additional lookup tables.
+
+static void InitTables()
+{
+ InitCRC32(crc_tables[0]);
+
+ for (uint I=0;I<256;I++) // Build additional lookup tables.
{
uint C=crc_tables[0][I];
for (uint J=1;J<8;J++)
@@ -42,10 +49,10 @@ void InitCRC()
}
-uint CRC(uint StartCRC,const void *Addr,size_t Size)
+struct CallInitCRC {CallInitCRC() {InitTables();}} static CallInit32;
+
+uint CRC32(uint StartCRC,const void *Addr,size_t Size)
{
- if (CRCTab[1]==0)
- InitCRC();
byte *Data=(byte *)Addr;
// Align Data to 8 for better performance.
@@ -56,29 +63,31 @@ uint CRC(uint StartCRC,const void *Addr,size_t Size)
{
#ifdef BIG_ENDIAN
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;
+ uint NextData = *(uint32 *) (Data +4);
#endif
StartCRC = crc_tables[7][(byte) StartCRC ] ^
crc_tables[6][(byte)(StartCRC >> 8) ] ^
crc_tables[5][(byte)(StartCRC >> 16)] ^
crc_tables[4][(byte)(StartCRC >> 24)] ^
- crc_tables[3][Data[4]] ^
- crc_tables[2][Data[5]] ^
- crc_tables[1][Data[6]] ^
- crc_tables[0][Data[7]];
+ crc_tables[3][(byte) NextData ] ^
+ 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);
- return(StartCRC);
+ return StartCRC;
}
#ifndef SFX_MODULE
// For RAR 1.4 archives in case somebody still has them.
-ushort OldCRC(ushort StartCRC,const void *Addr,size_t Size)
+ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size)
{
byte *Data=(byte *)Addr;
for (size_t I=0;I<Size;I++)
@@ -86,6 +95,8 @@ ushort OldCRC(ushort StartCRC,const void *Addr,size_t Size)
StartCRC=(StartCRC+Data[I])&0xffff;
StartCRC=((StartCRC<<1)|(StartCRC>>15))&0xffff;
}
- return(StartCRC);
+ return StartCRC;
}
#endif
+
+
diff --git a/src/thirdparty/unrar/crc.hpp b/src/thirdparty/unrar/crc.hpp
index 196a7e6ab..d8fea2816 100644
--- a/src/thirdparty/unrar/crc.hpp
+++ b/src/thirdparty/unrar/crc.hpp
@@ -1,8 +1,15 @@
#ifndef _RAR_CRC_
#define _RAR_CRC_
-void InitCRC();
-uint CRC(uint StartCRC,const void *Addr,size_t Size);
-ushort OldCRC(ushort StartCRC,const void *Addr,size_t Size);
+// This function is only to intialize external CRC tables. We do not need to
+// call it before calculating CRC32.
+void InitCRC32(uint *CRCTab);
+
+uint CRC32(uint StartCRC,const void *Addr,size_t Size);
+
+#ifndef SFX_MODULE
+ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size);
+#endif
+
#endif
diff --git a/src/thirdparty/unrar/crypt.cpp b/src/thirdparty/unrar/crypt.cpp
index 5cc5aefbf..3ebc9dc12 100644
--- a/src/thirdparty/unrar/crypt.cpp
+++ b/src/thirdparty/unrar/crypt.cpp
@@ -1,387 +1,125 @@
#include "rar.hpp"
#ifndef SFX_MODULE
-extern uint CRCTab[256];
+#include "crypt1.cpp"
+#include "crypt2.cpp"
#endif
+#include "crypt3.cpp"
+#include "crypt5.cpp"
-#define NROUNDS 32
-#define rol(x,n,xsize) (((x)<<(n)) | ((x)>>(xsize-(n))))
-#define ror(x,n,xsize) (((x)>>(n)) | ((x)<<(xsize-(n))))
-
-#define substLong(t) ( (uint)SubstTable[(uint)t&255] | \
- ((uint)SubstTable[(int)(t>> 8)&255]<< 8) | \
- ((uint)SubstTable[(int)(t>>16)&255]<<16) | \
- ((uint)SubstTable[(int)(t>>24)&255]<<24) )
-
-CryptKeyCacheItem CryptData::Cache[4];
-int CryptData::CachePos=0;
-
-
-#ifndef SFX_MODULE
-static byte InitSubstTable[256]={
- 215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221, 2, 42,
- 232, 1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137,
- 255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86, 6,
- 71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235,
- 107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36,
- 158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251,
- 97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11,
- 164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51,
- 207,120,189,210, 8,226, 41, 72,183,203,135,165,166, 60, 98, 7,
- 122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80,
- 131, 3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129,
- 224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10,
- 118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45, 4,148,108,
- 161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225,
- 0, 46,169,186, 68, 95,237, 65, 53,208,253,168, 9, 18,100, 52,
- 116,184,160, 96,109, 37, 30,106,140,104,150, 5,204,117,112, 84
-};
-#endif
-
-
-
-void CryptData::DecryptBlock(byte *Buf,size_t Size)
+CryptData::CryptData()
{
- rin.blockDecrypt(Buf,Size,Buf);
+ Method=CRYPT_NONE;
+ memset(KDFCache,0,sizeof(KDFCache));
+ KDFCachePos=0;
+ memset(CRCTab,0,sizeof(CRCTab));
}
-#ifndef SFX_MODULE
-void CryptData::EncryptBlock20(byte *Buf)
+CryptData::~CryptData()
{
- uint A,B,C,D,T,TA,TB;
-#if defined(BIG_ENDIAN) || !defined(PRESENT_INT32) || !defined(ALLOW_NOT_ALIGNED_INT)
- A=((uint)Buf[0]|((uint)Buf[1]<<8)|((uint)Buf[2]<<16)|((uint)Buf[3]<<24))^Key[0];
- B=((uint)Buf[4]|((uint)Buf[5]<<8)|((uint)Buf[6]<<16)|((uint)Buf[7]<<24))^Key[1];
- C=((uint)Buf[8]|((uint)Buf[9]<<8)|((uint)Buf[10]<<16)|((uint)Buf[11]<<24))^Key[2];
- D=((uint)Buf[12]|((uint)Buf[13]<<8)|((uint)Buf[14]<<16)|((uint)Buf[15]<<24))^Key[3];
-#else
- uint32 *BufPtr=(uint32 *)Buf;
- A=BufPtr[0]^Key[0];
- B=BufPtr[1]^Key[1];
- C=BufPtr[2]^Key[2];
- D=BufPtr[3]^Key[3];
-#endif
- for(int I=0;I<NROUNDS;I++)
- {
- T=((C+rol(D,11,32))^Key[I&3]);
- TA=A^substLong(T);
- T=((D^rol(C,17,32))+Key[I&3]);
- TB=B^substLong(T);
- A=C;
- B=D;
- C=TA;
- D=TB;
- }
-#if defined(BIG_ENDIAN) || !defined(PRESENT_INT32) || !defined(ALLOW_NOT_ALIGNED_INT)
- C^=Key[0];
- Buf[0]=(byte)C;
- Buf[1]=(byte)(C>>8);
- Buf[2]=(byte)(C>>16);
- Buf[3]=(byte)(C>>24);
- D^=Key[1];
- Buf[4]=(byte)D;
- Buf[5]=(byte)(D>>8);
- Buf[6]=(byte)(D>>16);
- Buf[7]=(byte)(D>>24);
- A^=Key[2];
- Buf[8]=(byte)A;
- Buf[9]=(byte)(A>>8);
- Buf[10]=(byte)(A>>16);
- Buf[11]=(byte)(A>>24);
- B^=Key[3];
- Buf[12]=(byte)B;
- Buf[13]=(byte)(B>>8);
- Buf[14]=(byte)(B>>16);
- Buf[15]=(byte)(B>>24);
-#else
- BufPtr[0]=C^Key[0];
- BufPtr[1]=D^Key[1];
- BufPtr[2]=A^Key[2];
- BufPtr[3]=B^Key[3];
-#endif
- UpdKeys(Buf);
+ cleandata(KDFCache,sizeof(KDFCache));
}
-void CryptData::DecryptBlock20(byte *Buf)
-{
- byte InBuf[16];
- uint A,B,C,D,T,TA,TB;
-#if defined(BIG_ENDIAN) || !defined(PRESENT_INT32) || !defined(ALLOW_NOT_ALIGNED_INT)
- A=((uint)Buf[0]|((uint)Buf[1]<<8)|((uint)Buf[2]<<16)|((uint)Buf[3]<<24))^Key[0];
- B=((uint)Buf[4]|((uint)Buf[5]<<8)|((uint)Buf[6]<<16)|((uint)Buf[7]<<24))^Key[1];
- C=((uint)Buf[8]|((uint)Buf[9]<<8)|((uint)Buf[10]<<16)|((uint)Buf[11]<<24))^Key[2];
- D=((uint)Buf[12]|((uint)Buf[13]<<8)|((uint)Buf[14]<<16)|((uint)Buf[15]<<24))^Key[3];
-#else
- uint32 *BufPtr=(uint32 *)Buf;
- A=BufPtr[0]^Key[0];
- B=BufPtr[1]^Key[1];
- C=BufPtr[2]^Key[2];
- D=BufPtr[3]^Key[3];
-#endif
- memcpy(InBuf,Buf,sizeof(InBuf));
- for(int I=NROUNDS-1;I>=0;I--)
- {
- T=((C+rol(D,11,32))^Key[I&3]);
- TA=A^substLong(T);
- T=((D^rol(C,17,32))+Key[I&3]);
- TB=B^substLong(T);
- A=C;
- B=D;
- C=TA;
- D=TB;
- }
-#if defined(BIG_ENDIAN) || !defined(PRESENT_INT32) || !defined(ALLOW_NOT_ALIGNED_INT)
- C^=Key[0];
- Buf[0]=(byte)C;
- Buf[1]=(byte)(C>>8);
- Buf[2]=(byte)(C>>16);
- Buf[3]=(byte)(C>>24);
- D^=Key[1];
- Buf[4]=(byte)D;
- Buf[5]=(byte)(D>>8);
- Buf[6]=(byte)(D>>16);
- Buf[7]=(byte)(D>>24);
- A^=Key[2];
- Buf[8]=(byte)A;
- Buf[9]=(byte)(A>>8);
- Buf[10]=(byte)(A>>16);
- Buf[11]=(byte)(A>>24);
- B^=Key[3];
- Buf[12]=(byte)B;
- Buf[13]=(byte)(B>>8);
- Buf[14]=(byte)(B>>16);
- Buf[15]=(byte)(B>>24);
-#else
- BufPtr[0]=C^Key[0];
- BufPtr[1]=D^Key[1];
- BufPtr[2]=A^Key[2];
- BufPtr[3]=B^Key[3];
-#endif
- UpdKeys(InBuf);
-}
-void CryptData::UpdKeys(byte *Buf)
+void CryptData::DecryptBlock(byte *Buf,size_t Size)
{
- for (int I=0;I<16;I+=4)
+ switch(Method)
{
- Key[0]^=CRCTab[Buf[I]];
- Key[1]^=CRCTab[Buf[I+1]];
- Key[2]^=CRCTab[Buf[I+2]];
- Key[3]^=CRCTab[Buf[I+3]];
+#ifndef SFX_MODULE
+ case CRYPT_RAR13:
+ Decrypt13(Buf,Size);
+ break;
+ case CRYPT_RAR15:
+ Crypt15(Buf,Size);
+ break;
+ case CRYPT_RAR20:
+ for (size_t I=0;I<Size;I+=CRYPT_BLOCK_SIZE)
+ DecryptBlock20(Buf+I);
+ break;
+#endif
+ case CRYPT_RAR30:
+ case CRYPT_RAR50:
+ rin.blockDecrypt(Buf,Size,Buf);
+ break;
}
}
-void CryptData::Swap(byte *Ch1,byte *Ch2)
-{
- byte Ch=*Ch1;
- *Ch1=*Ch2;
- *Ch2=Ch;
-}
-#endif
-
-
-void CryptData::SetCryptKeys(SecPassword *Password,const byte *Salt,bool Encrypt,bool OldOnly,bool HandsOffHash)
+void CryptData::SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,
+ SecPassword *Password,const byte *Salt,
+ const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck)
{
- if (!Password->IsSet())
+ if (!Password->IsSet() || Method==CRYPT_NONE)
return;
- wchar PlainPsw[MAXPASSWORD];
- Password->Get(PlainPsw,ASIZE(PlainPsw));
- if (OldOnly)
- {
-#ifndef SFX_MODULE
- if (CRCTab[1]==0)
- InitCRC();
- char Psw[MAXPASSWORD];
- memset(Psw,0,sizeof(Psw));
-
- // We need to use ASCII password for older encryption algorithms.
- WideToChar(PlainPsw,Psw,ASIZE(Psw));
- Psw[ASIZE(Psw)-1]=0;
- size_t PswLength=strlen(Psw);
+ CryptData::Method=Method;
- SetOldKeys(Psw);
- Key[0]=0xD3A3B879L;
- Key[1]=0x3F6D12F7L;
- Key[2]=0x7515A235L;
- Key[3]=0xA4E7F123L;
-
- memcpy(SubstTable,InitSubstTable,sizeof(SubstTable));
- for (int J=0;J<256;J++)
- for (size_t I=0;I<PswLength;I+=2)
- {
- uint N1=(byte)CRCTab [ (byte(Psw[I]) - J) &0xff];
- uint N2=(byte)CRCTab [ (byte(Psw[I+1]) + J) &0xff];
- for (int K=1;N1!=N2;N1=(N1+1)&0xff,K++)
- Swap(&SubstTable[N1],&SubstTable[(N1+I+K)&0xff]);
- }
- for (size_t I=0;I<PswLength;I+=16)
- EncryptBlock20((byte *)&Psw[I]);
- cleandata(Psw,sizeof(Psw));
-#endif
- cleandata(PlainPsw,sizeof(PlainPsw));
- return;
- }
+ wchar PwdW[MAXPASSWORD];
+ Password->Get(PwdW,ASIZE(PwdW));
+ char PwdA[MAXPASSWORD];
+ WideToChar(PwdW,PwdA,ASIZE(PwdA));
- bool Cached=false;
- for (uint I=0;I<ASIZE(Cache);I++)
- if (Cache[I].Password==*Password &&
- (Salt==NULL && !Cache[I].SaltPresent || Salt!=NULL &&
- Cache[I].SaltPresent && memcmp(Cache[I].Salt,Salt,SALT_SIZE)==0) &&
- Cache[I].HandsOffHash==HandsOffHash)
- {
- memcpy(AESKey,Cache[I].AESKey,sizeof(AESKey));
- memcpy(AESInit,Cache[I].AESInit,sizeof(AESInit));
- Cached=true;
- break;
- }
-
- if (!Cached)
+ switch(Method)
{
- byte RawPsw[2*MAXPASSWORD+SALT_SIZE];
- WideToRaw(PlainPsw,RawPsw);
- size_t RawLength=2*wcslen(PlainPsw);
- if (Salt!=NULL)
- {
- memcpy(RawPsw+RawLength,Salt,SALT_SIZE);
- RawLength+=SALT_SIZE;
- }
- hash_context c;
- hash_initial(&c);
-
- const int HashRounds=0x40000;
- for (int I=0;I<HashRounds;I++)
- {
- hash_process( &c, RawPsw, RawLength, HandsOffHash);
- byte PswNum[3];
- PswNum[0]=(byte)I;
- PswNum[1]=(byte)(I>>8);
- PswNum[2]=(byte)(I>>16);
- hash_process( &c, PswNum, 3, HandsOffHash);
- if (I%(HashRounds/16)==0)
- {
- hash_context tempc=c;
- uint32 digest[5];
- hash_final( &tempc, digest, HandsOffHash);
- AESInit[I/(HashRounds/16)]=(byte)digest[4];
- }
- }
- uint32 digest[5];
- hash_final( &c, digest, HandsOffHash);
- for (int I=0;I<4;I++)
- for (int J=0;J<4;J++)
- AESKey[I*4+J]=(byte)(digest[I]>>(J*8));
-
- Cache[CachePos].Password=*Password;
- if ((Cache[CachePos].SaltPresent=(Salt!=NULL))==true)
- memcpy(Cache[CachePos].Salt,Salt,SALT_SIZE);
- Cache[CachePos].HandsOffHash=HandsOffHash;
- memcpy(Cache[CachePos].AESKey,AESKey,sizeof(AESKey));
- memcpy(Cache[CachePos].AESInit,AESInit,sizeof(AESInit));
- CachePos=(CachePos+1)%ASIZE(Cache);
-
- cleandata(RawPsw,sizeof(RawPsw));
- }
- rin.init(Encrypt ? Rijndael::Encrypt : Rijndael::Decrypt,AESKey,AESInit);
- cleandata(PlainPsw,sizeof(PlainPsw));
-}
-
-
#ifndef SFX_MODULE
-void CryptData::SetOldKeys(const char *Password)
-{
- uint PswCRC=CRC(0xffffffff,Password,strlen(Password));
- OldKey[0]=PswCRC&0xffff;
- OldKey[1]=(PswCRC>>16)&0xffff;
- OldKey[2]=OldKey[3]=0;
- PN1=PN2=PN3=0;
- byte Ch;
- while ((Ch=*Password)!=0)
- {
- PN1+=Ch;
- PN2^=Ch;
- PN3+=Ch;
- PN3=(byte)rol(PN3,1,8);
- OldKey[2]^=Ch^CRCTab[Ch];
- OldKey[3]+=Ch+(CRCTab[Ch]>>16);
- Password++;
+ case CRYPT_RAR13:
+ SetKey13(PwdA);
+ break;
+ case CRYPT_RAR15:
+ SetKey15(PwdA);
+ break;
+ case CRYPT_RAR20:
+ SetKey20(PwdA);
+ break;
+#endif
+ case CRYPT_RAR30:
+ SetKey30(Encrypt,Password,PwdW,Salt);
+ return;
+ case CRYPT_RAR50:
+ SetKey50(Encrypt,Password,PwdW,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
+ return;
}
+ cleandata(PwdA,sizeof(PwdA));
+ cleandata(PwdW,sizeof(PwdW));
}
-void CryptData::SetAV15Encryption()
-{
- OldKey[0]=0x4765;
- OldKey[1]=0x9021;
- OldKey[2]=0x7382;
- OldKey[3]=0x5215;
-}
-
-
-void CryptData::SetCmt13Encryption()
-{
- PN1=0;
- PN2=7;
- PN3=77;
-}
-void CryptData::Crypt(byte *Data,uint Count,int Method)
+// Fill buffer with random data.
+void GetRnd(byte *RndBuf,size_t BufSize)
{
- if (Method==OLD_DECODE)
- Decode13(Data,Count);
- else
- if (Method==OLD_ENCODE)
- Encode13(Data,Count);
- else
- Crypt15(Data,Count);
-}
-
-
-void CryptData::Encode13(byte *Data,uint Count)
-{
- while (Count--)
+ bool Success=false;
+#if defined(_WIN_ALL)
+ HCRYPTPROV hProvider = 0;
+ if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
{
- PN2+=PN3;
- PN1+=PN2;
- *Data+=PN1;
- Data++;
+ Success=CryptGenRandom(hProvider, (DWORD)BufSize, RndBuf) == TRUE;
+ CryptReleaseContext(hProvider, 0);
}
-}
-
-
-void CryptData::Decode13(byte *Data,uint Count)
-{
- while (Count--)
+#elif defined(_UNIX)
+ FILE *rndf = fopen("/dev/urandom", "r");
+ if (rndf!=NULL)
{
- PN2+=PN3;
- PN1+=PN2;
- *Data-=PN1;
- Data++;
+ Success=fread(RndBuf, BufSize, 1, rndf) == BufSize;
+ fclose(rndf);
}
-}
-
-
-void CryptData::Crypt15(byte *Data,uint Count)
-{
- while (Count--)
+#endif
+ // We use this code only as the last resort if code above failed.
+ if (!Success)
{
- OldKey[0]+=0x1234;
- OldKey[1]^=CRCTab[(OldKey[0] & 0x1fe)>>1];
- OldKey[2]-=CRCTab[(OldKey[0] & 0x1fe)>>1]>>16;
- OldKey[0]^=OldKey[2];
- OldKey[3]=ror(OldKey[3]&0xffff,1,16)^OldKey[1];
- OldKey[3]=ror(OldKey[3]&0xffff,1,16);
- OldKey[0]^=OldKey[3];
- *Data^=(byte)(OldKey[0]>>8);
- Data++;
+ static uint Count=0;
+ RarTime CurTime;
+ CurTime.SetCurrentTime();
+ uint64 Random=CurTime.GetRaw()+clock();
+ for (size_t I=0;I<BufSize;I++)
+ {
+ byte RndByte = byte (Random >> ( (I & 7) * 8 ));
+ RndBuf[I]=byte( (RndByte ^ I) + Count++);
+ }
}
}
-#endif
-
-
diff --git a/src/thirdparty/unrar/crypt.hpp b/src/thirdparty/unrar/crypt.hpp
index 96b8a27f1..cb21100e6 100644
--- a/src/thirdparty/unrar/crypt.hpp
+++ b/src/thirdparty/unrar/crypt.hpp
@@ -1,62 +1,88 @@
#ifndef _RAR_CRYPT_
#define _RAR_CRYPT_
-enum { OLD_DECODE=0,OLD_ENCODE=1,NEW_CRYPT=2 };
+
+enum CRYPT_METHOD {
+ CRYPT_NONE,CRYPT_RAR13,CRYPT_RAR15,CRYPT_RAR20,CRYPT_RAR30,CRYPT_RAR50
+};
+
+#define SIZE_SALT50 16
+#define SIZE_SALT30 8
+#define SIZE_INITV 16
+#define SIZE_PSWCHECK 8
+#define SIZE_PSWCHECK_CSUM 4
+
+#define CRYPT_BLOCK_SIZE 16
+#define CRYPT_BLOCK_MASK (CRYPT_BLOCK_SIZE-1) // 0xf
+
+#define CRYPT5_KDF_LG2_COUNT 15 // LOG2 of PDKDF2 iteration count.
+#define CRYPT5_KDF_LG2_COUNT_MAX 24 // LOG2 of maximum accepted iteration count.
+#define CRYPT_VERSION 0 // Supported encryption version.
-struct CryptKeyCacheItem
+struct KDFCacheItem
{
-#ifndef _SFX_RTL_
- CryptKeyCacheItem()
- {
- Password.Set(L"");
- }
-
- ~CryptKeyCacheItem()
- {
- memset(AESKey,0,sizeof(AESKey));
- memset(AESInit,0,sizeof(AESInit));
- memset(&Password,0,sizeof(Password));
- }
-#endif
- byte AESKey[16],AESInit[16];
- SecPassword Password;
- bool SaltPresent;
- byte Salt[SALT_SIZE];
- bool HandsOffHash;
+ SecPassword Pwd;
+ byte Salt[SIZE_SALT50];
+ uint Lg2Count; // Log2 of PBKDF2 repetition count.
+ byte Key[32];
+ byte PswCheckValue[SHA256_DIGEST_SIZE];
+ byte HashKeyValue[SHA256_DIGEST_SIZE];
};
class CryptData
{
private:
- void Encode13(byte *Data,uint Count);
- void Decode13(byte *Data,uint Count);
- void Crypt15(byte *Data,uint Count);
- void UpdKeys(byte *Buf);
- void Swap(byte *Ch1,byte *Ch2);
- void SetOldKeys(const char *Password);
+ void SetKey13(const char *Password);
+ void Decrypt13(byte *Data,size_t Count);
+
+ void SetKey15(const char *Password);
+ void Crypt15(byte *Data,size_t Count);
+
+ void SetKey20(const char *Password);
+ void Swap20(byte *Ch1,byte *Ch2);
+ void UpdKeys20(byte *Buf);
+ void EncryptBlock20(byte *Buf);
+ void DecryptBlock20(byte *Buf);
+
+ void SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt);
+
+ void SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck);
+ KDFCacheItem KDFCache[4];
+ uint KDFCachePos;
+
+ CRYPT_METHOD Method;
Rijndael rin;
-
- byte SubstTable[256];
- uint Key[4];
- ushort OldKey[4];
- byte PN1,PN2,PN3;
- byte AESKey[16],AESInit[16];
+ uint CRCTab[256]; // For RAR 1.5 and RAR 2.0 encryption.
+
+ byte SubstTable20[256];
+ uint Key20[4];
- static CryptKeyCacheItem Cache[4];
- static int CachePos;
+ byte Key13[3];
+ ushort Key15[4];
public:
- void SetCryptKeys(SecPassword *Password,const byte *Salt,bool Encrypt,bool OldOnly,bool HandsOffHash);
+ CryptData();
+ ~CryptData();
+ void SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,SecPassword *Password,
+ const byte *Salt,const byte *InitV,uint Lg2Cnt,
+ byte *HashKey,byte *PswCheck);
void SetAV15Encryption();
void SetCmt13Encryption();
- void EncryptBlock20(byte *Buf);
- void DecryptBlock20(byte *Buf);
void EncryptBlock(byte *Buf,size_t Size);
void DecryptBlock(byte *Buf,size_t Size);
- void Crypt(byte *Data,uint Count,int Method);
- static void SetSalt(byte *Salt,int SaltSize);
+ static void SetSalt(byte *Salt,size_t SaltSize);
};
+void GetRnd(byte *RndBuf,size_t BufSize);
+
+void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data,
+ size_t DataLength,byte *ResDigest);
+void pbkdf2(const byte *pass, size_t pass_len, const byte *salt,
+ size_t salt_len,byte *key, byte *Value1, byte *Value2,
+ uint rounds);
+
+void ConvertHashToMAC(HashValue *Value,byte *Key);
+
#endif
diff --git a/src/thirdparty/unrar/crypt1.cpp b/src/thirdparty/unrar/crypt1.cpp
new file mode 100644
index 000000000..f840f4775
--- /dev/null
+++ b/src/thirdparty/unrar/crypt1.cpp
@@ -0,0 +1,82 @@
+extern uint CRCTab[256];
+
+#define rol(x,n,xsize) (((x)<<(n)) | ((x)>>(xsize-(n))))
+#define ror(x,n,xsize) (((x)>>(n)) | ((x)<<(xsize-(n))))
+
+void CryptData::SetKey13(const char *Password)
+{
+ Key13[0]=Key13[1]=Key13[2]=0;
+ for (size_t I=0;Password[I]!=0;I++)
+ {
+ byte P=Password[I];
+ Key13[0]+=P;
+ Key13[1]^=P;
+ Key13[2]+=P;
+ Key13[2]=(byte)rol(Key13[2],1,8);
+ }
+}
+
+
+void CryptData::SetKey15(const char *Password)
+{
+ InitCRC32(CRCTab);
+ uint PswCRC=CRC32(0xffffffff,Password,strlen(Password));
+ Key15[0]=PswCRC&0xffff;
+ Key15[1]=(PswCRC>>16)&0xffff;
+ Key15[2]=Key15[3]=0;
+ for (size_t I=0;Password[I]!=0;I++)
+ {
+ byte P=Password[I];
+ Key15[2]^=P^CRCTab[P];
+ Key15[3]+=P+(CRCTab[P]>>16);
+ }
+}
+
+
+void CryptData::SetAV15Encryption()
+{
+ InitCRC32(CRCTab);
+ Method=CRYPT_RAR15;
+ Key15[0]=0x4765;
+ Key15[1]=0x9021;
+ Key15[2]=0x7382;
+ Key15[3]=0x5215;
+}
+
+
+void CryptData::SetCmt13Encryption()
+{
+ Method=CRYPT_RAR13;
+ Key13[0]=0;
+ Key13[1]=7;
+ Key13[2]=77;
+}
+
+
+void CryptData::Decrypt13(byte *Data,size_t Count)
+{
+ while (Count--)
+ {
+ Key13[1]+=Key13[2];
+ Key13[0]+=Key13[1];
+ *Data-=Key13[0];
+ Data++;
+ }
+}
+
+
+void CryptData::Crypt15(byte *Data,size_t Count)
+{
+ while (Count--)
+ {
+ Key15[0]+=0x1234;
+ Key15[1]^=CRCTab[(Key15[0] & 0x1fe)>>1];
+ Key15[2]-=CRCTab[(Key15[0] & 0x1fe)>>1]>>16;
+ Key15[0]^=Key15[2];
+ Key15[3]=ror(Key15[3]&0xffff,1,16)^Key15[1];
+ Key15[3]=ror(Key15[3]&0xffff,1,16);
+ Key15[0]^=Key15[3];
+ *Data^=(byte)(Key15[0]>>8);
+ Data++;
+ }
+}
diff --git a/src/thirdparty/unrar/crypt2.cpp b/src/thirdparty/unrar/crypt2.cpp
new file mode 100644
index 000000000..08c7ecf3a
--- /dev/null
+++ b/src/thirdparty/unrar/crypt2.cpp
@@ -0,0 +1,195 @@
+#define NROUNDS 32
+
+#define substLong(t) ( (uint)SubstTable20[(uint)t&255] | \
+ ((uint)SubstTable20[(int)(t>> 8)&255]<< 8) | \
+ ((uint)SubstTable20[(int)(t>>16)&255]<<16) | \
+ ((uint)SubstTable20[(int)(t>>24)&255]<<24) )
+
+
+static byte InitSubstTable20[256]={
+ 215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221, 2, 42,
+ 232, 1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137,
+ 255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86, 6,
+ 71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235,
+ 107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36,
+ 158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251,
+ 97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11,
+ 164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51,
+ 207,120,189,210, 8,226, 41, 72,183,203,135,165,166, 60, 98, 7,
+ 122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80,
+ 131, 3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129,
+ 224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10,
+ 118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45, 4,148,108,
+ 161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225,
+ 0, 46,169,186, 68, 95,237, 65, 53,208,253,168, 9, 18,100, 52,
+ 116,184,160, 96,109, 37, 30,106,140,104,150, 5,204,117,112, 84
+};
+
+
+void CryptData::SetKey20(const char *Password)
+{
+ InitCRC32(CRCTab);
+
+ char Psw[MAXPASSWORD];
+ strncpyz(Psw,Password,ASIZE(Psw)); // We'll need to modify it below.
+ size_t PswLength=strlen(Psw);
+
+ Key20[0]=0xD3A3B879L;
+ Key20[1]=0x3F6D12F7L;
+ Key20[2]=0x7515A235L;
+ Key20[3]=0xA4E7F123L;
+
+ memcpy(SubstTable20,InitSubstTable20,sizeof(SubstTable20));
+ for (int J=0;J<256;J++)
+ for (size_t I=0;I<PswLength;I+=2)
+ {
+ uint N1=(byte)CRCTab [ (byte(Password[I]) - J) &0xff];
+ uint N2=(byte)CRCTab [ (byte(Password[I+1]) + J) &0xff];
+ for (int K=1;N1!=N2;N1=(N1+1)&0xff,K++)
+ Swap20(&SubstTable20[N1],&SubstTable20[(N1+I+K)&0xff]);
+ }
+
+ // Incomplete last block of password must be zero padded.
+ if ((PswLength & CRYPT_BLOCK_MASK)!=0)
+ for (size_t I=PswLength;I<=(PswLength|CRYPT_BLOCK_MASK);I++)
+ Psw[I]=0;
+
+ for (size_t I=0;I<PswLength;I+=CRYPT_BLOCK_SIZE)
+ EncryptBlock20((byte *)Psw+I);
+}
+
+
+void CryptData::EncryptBlock20(byte *Buf)
+{
+ uint A,B,C,D,T,TA,TB;
+#if defined(BIG_ENDIAN) || !defined(PRESENT_INT32) || !defined(ALLOW_NOT_ALIGNED_INT)
+ A=((uint)Buf[0]|((uint)Buf[1]<<8)|((uint)Buf[2]<<16)|((uint)Buf[3]<<24))^Key20[0];
+ B=((uint)Buf[4]|((uint)Buf[5]<<8)|((uint)Buf[6]<<16)|((uint)Buf[7]<<24))^Key20[1];
+ C=((uint)Buf[8]|((uint)Buf[9]<<8)|((uint)Buf[10]<<16)|((uint)Buf[11]<<24))^Key20[2];
+ D=((uint)Buf[12]|((uint)Buf[13]<<8)|((uint)Buf[14]<<16)|((uint)Buf[15]<<24))^Key20[3];
+#else
+ uint32 *BufPtr=(uint32 *)Buf;
+ A=BufPtr[0]^Key20[0];
+ B=BufPtr[1]^Key20[1];
+ C=BufPtr[2]^Key20[2];
+ D=BufPtr[3]^Key20[3];
+#endif
+ for(int I=0;I<NROUNDS;I++)
+ {
+ T=((C+rol(D,11,32))^Key20[I&3]);
+ TA=A^substLong(T);
+ T=((D^rol(C,17,32))+Key20[I&3]);
+ TB=B^substLong(T);
+ A=C;
+ B=D;
+ C=TA;
+ D=TB;
+ }
+#if defined(BIG_ENDIAN) || !defined(PRESENT_INT32) || !defined(ALLOW_NOT_ALIGNED_INT)
+ C^=Key20[0];
+ Buf[0]=(byte)C;
+ Buf[1]=(byte)(C>>8);
+ Buf[2]=(byte)(C>>16);
+ Buf[3]=(byte)(C>>24);
+ D^=Key20[1];
+ Buf[4]=(byte)D;
+ Buf[5]=(byte)(D>>8);
+ Buf[6]=(byte)(D>>16);
+ Buf[7]=(byte)(D>>24);
+ A^=Key20[2];
+ Buf[8]=(byte)A;
+ Buf[9]=(byte)(A>>8);
+ Buf[10]=(byte)(A>>16);
+ Buf[11]=(byte)(A>>24);
+ B^=Key20[3];
+ Buf[12]=(byte)B;
+ Buf[13]=(byte)(B>>8);
+ Buf[14]=(byte)(B>>16);
+ Buf[15]=(byte)(B>>24);
+#else
+ BufPtr[0]=C^Key20[0];
+ BufPtr[1]=D^Key20[1];
+ BufPtr[2]=A^Key20[2];
+ BufPtr[3]=B^Key20[3];
+#endif
+ UpdKeys20(Buf);
+}
+
+
+void CryptData::DecryptBlock20(byte *Buf)
+{
+ byte InBuf[16];
+ uint A,B,C,D,T,TA,TB;
+#if defined(BIG_ENDIAN) || !defined(PRESENT_INT32) || !defined(ALLOW_NOT_ALIGNED_INT)
+ A=((uint)Buf[0]|((uint)Buf[1]<<8)|((uint)Buf[2]<<16)|((uint)Buf[3]<<24))^Key20[0];
+ B=((uint)Buf[4]|((uint)Buf[5]<<8)|((uint)Buf[6]<<16)|((uint)Buf[7]<<24))^Key20[1];
+ C=((uint)Buf[8]|((uint)Buf[9]<<8)|((uint)Buf[10]<<16)|((uint)Buf[11]<<24))^Key20[2];
+ D=((uint)Buf[12]|((uint)Buf[13]<<8)|((uint)Buf[14]<<16)|((uint)Buf[15]<<24))^Key20[3];
+#else
+ uint32 *BufPtr=(uint32 *)Buf;
+ A=BufPtr[0]^Key20[0];
+ B=BufPtr[1]^Key20[1];
+ C=BufPtr[2]^Key20[2];
+ D=BufPtr[3]^Key20[3];
+#endif
+ memcpy(InBuf,Buf,sizeof(InBuf));
+ for(int I=NROUNDS-1;I>=0;I--)
+ {
+ T=((C+rol(D,11,32))^Key20[I&3]);
+ TA=A^substLong(T);
+ T=((D^rol(C,17,32))+Key20[I&3]);
+ TB=B^substLong(T);
+ A=C;
+ B=D;
+ C=TA;
+ D=TB;
+ }
+#if defined(BIG_ENDIAN) || !defined(PRESENT_INT32) || !defined(ALLOW_NOT_ALIGNED_INT)
+ C^=Key20[0];
+ Buf[0]=(byte)C;
+ Buf[1]=(byte)(C>>8);
+ Buf[2]=(byte)(C>>16);
+ Buf[3]=(byte)(C>>24);
+ D^=Key20[1];
+ Buf[4]=(byte)D;
+ Buf[5]=(byte)(D>>8);
+ Buf[6]=(byte)(D>>16);
+ Buf[7]=(byte)(D>>24);
+ A^=Key20[2];
+ Buf[8]=(byte)A;
+ Buf[9]=(byte)(A>>8);
+ Buf[10]=(byte)(A>>16);
+ Buf[11]=(byte)(A>>24);
+ B^=Key20[3];
+ Buf[12]=(byte)B;
+ Buf[13]=(byte)(B>>8);
+ Buf[14]=(byte)(B>>16);
+ Buf[15]=(byte)(B>>24);
+#else
+ BufPtr[0]=C^Key20[0];
+ BufPtr[1]=D^Key20[1];
+ BufPtr[2]=A^Key20[2];
+ BufPtr[3]=B^Key20[3];
+#endif
+ UpdKeys20(InBuf);
+}
+
+
+void CryptData::UpdKeys20(byte *Buf)
+{
+ for (int I=0;I<16;I+=4)
+ {
+ Key20[0]^=CRCTab[Buf[I]];
+ Key20[1]^=CRCTab[Buf[I+1]];
+ Key20[2]^=CRCTab[Buf[I+2]];
+ Key20[3]^=CRCTab[Buf[I+3]];
+ }
+}
+
+
+void CryptData::Swap20(byte *Ch1,byte *Ch2)
+{
+ byte Ch=*Ch1;
+ *Ch1=*Ch2;
+ *Ch2=Ch;
+}
diff --git a/src/thirdparty/unrar/crypt3.cpp b/src/thirdparty/unrar/crypt3.cpp
new file mode 100644
index 000000000..42679b37b
--- /dev/null
+++ b/src/thirdparty/unrar/crypt3.cpp
@@ -0,0 +1,90 @@
+struct CryptKeyCacheItem
+{
+#ifndef _SFX_RTL_
+ CryptKeyCacheItem()
+ {
+ Password.Set(L"");
+ }
+
+ ~CryptKeyCacheItem()
+ {
+ cleandata(AESKey,sizeof(AESKey));
+ cleandata(AESInit,sizeof(AESInit));
+ cleandata(&Password,sizeof(Password));
+ }
+#endif
+ byte AESKey[16],AESInit[16];
+ SecPassword Password;
+ bool SaltPresent;
+ byte Salt[SIZE_SALT30];
+};
+
+static CryptKeyCacheItem Cache[4];
+static int CachePos=0;
+
+void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt)
+{
+ byte AESKey[16],AESInit[16];
+
+ bool Cached=false;
+ for (uint I=0;I<ASIZE(Cache);I++)
+ if (Cache[I].Password==*Password &&
+ (Salt==NULL && !Cache[I].SaltPresent || Salt!=NULL &&
+ Cache[I].SaltPresent && memcmp(Cache[I].Salt,Salt,SIZE_SALT30)==0))
+ {
+ memcpy(AESKey,Cache[I].AESKey,sizeof(AESKey));
+ memcpy(AESInit,Cache[I].AESInit,sizeof(AESInit));
+ Cached=true;
+ break;
+ }
+
+ if (!Cached)
+ {
+ byte RawPsw[2*MAXPASSWORD+SIZE_SALT30];
+ WideToRaw(PwdW,RawPsw,ASIZE(RawPsw));
+ size_t RawLength=2*wcslen(PwdW);
+ if (Salt!=NULL)
+ {
+ memcpy(RawPsw+RawLength,Salt,SIZE_SALT30);
+ RawLength+=SIZE_SALT30;
+ }
+ hash_context c;
+ hash_initial(&c);
+
+ const int HashRounds=0x40000;
+ for (int I=0;I<HashRounds;I++)
+ {
+ hash_process( &c, RawPsw, RawLength, false);
+ byte PswNum[3];
+ PswNum[0]=(byte)I;
+ PswNum[1]=(byte)(I>>8);
+ PswNum[2]=(byte)(I>>16);
+ hash_process( &c, PswNum, 3, false);
+ if (I%(HashRounds/16)==0)
+ {
+ hash_context tempc=c;
+ uint32 digest[5];
+ hash_final( &tempc, digest, false);
+ AESInit[I/(HashRounds/16)]=(byte)digest[4];
+ }
+ }
+ uint32 digest[5];
+ hash_final( &c, digest, false);
+ for (int I=0;I<4;I++)
+ for (int J=0;J<4;J++)
+ AESKey[I*4+J]=(byte)(digest[I]>>(J*8));
+
+ Cache[CachePos].Password=*Password;
+ if ((Cache[CachePos].SaltPresent=(Salt!=NULL))==true)
+ memcpy(Cache[CachePos].Salt,Salt,SIZE_SALT30);
+ memcpy(Cache[CachePos].AESKey,AESKey,sizeof(AESKey));
+ memcpy(Cache[CachePos].AESInit,AESInit,sizeof(AESInit));
+ CachePos=(CachePos+1)%ASIZE(Cache);
+
+ cleandata(RawPsw,sizeof(RawPsw));
+ }
+ rin.Init(Encrypt, AESKey, 128, AESInit);
+ cleandata(AESKey,sizeof(AESKey));
+ cleandata(AESInit,sizeof(AESInit));
+}
+
diff --git a/src/thirdparty/unrar/crypt5.cpp b/src/thirdparty/unrar/crypt5.cpp
new file mode 100644
index 000000000..fab3cc975
--- /dev/null
+++ b/src/thirdparty/unrar/crypt5.cpp
@@ -0,0 +1,195 @@
+void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data,
+ size_t DataLength,byte *ResDigest)
+{
+ const size_t Sha256BlockSize=64; // As defined in RFC 4868.
+
+ byte KeyHash[SHA256_DIGEST_SIZE];
+ if (KeyLength > Sha256BlockSize) // Convert longer keys to key hash.
+ {
+ sha256_context KCtx;
+ sha256_init(&KCtx);
+ sha256_process(&KCtx, Key, KeyLength);
+ sha256_done(&KCtx, KeyHash);
+
+ Key = KeyHash;
+ KeyLength = SHA256_DIGEST_SIZE;
+ }
+
+ byte KeyBuf[Sha256BlockSize]; // Store the padded key here.
+ for (size_t I = 0; I < KeyLength; I++) // Use 0x36 padding for inner digest.
+ KeyBuf[I] = Key[I] ^ 0x36;
+ for (size_t I = KeyLength; I < Sha256BlockSize; I++)
+ KeyBuf[I] = 0x36;
+
+ sha256_context ICtx;
+ sha256_init(&ICtx);
+ sha256_process(&ICtx, KeyBuf, Sha256BlockSize); // Hash padded key.
+ sha256_process(&ICtx, Data, DataLength); // Hash data.
+
+ byte IDig[SHA256_DIGEST_SIZE]; // Internal digest for padded key and data.
+ sha256_done(&ICtx, IDig);
+
+ sha256_context RCtx;
+ sha256_init(&RCtx);
+
+ for (size_t I = 0; I < KeyLength; I++) // Use 0x5c for outer key padding.
+ KeyBuf[I] = Key[I] ^ 0x5c;
+ for (size_t I = KeyLength; I < Sha256BlockSize; I++)
+ KeyBuf[I] = 0x5c;
+
+ sha256_process(&RCtx, KeyBuf, Sha256BlockSize); // Hash padded key.
+ sha256_process(&RCtx, IDig, SHA256_DIGEST_SIZE); // Hash internal digest.
+
+ sha256_done(&RCtx, ResDigest);
+}
+
+
+// PBKDF2 for 32 byte key length. We generate the key for specified number
+// of iteration count also as two supplementary values (key for checksums
+// and password verification) for iterations+16 and iterations+32.
+void pbkdf2(const byte *Pwd, size_t PwdLength,
+ const byte *Salt, size_t SaltLength,
+ byte *Key, byte *V1, byte *V2, uint Count)
+{
+ const size_t MaxSalt=64;
+ byte SaltData[MaxSalt+4];
+ memcpy(SaltData, Salt, Min(SaltLength,MaxSalt));
+
+ SaltData[SaltLength + 0] = 0; // Salt concatenated to 1.
+ SaltData[SaltLength + 1] = 0;
+ SaltData[SaltLength + 2] = 0;
+ SaltData[SaltLength + 3] = 1;
+
+ // First iteration: HMAC of password, salt and block index (1).
+ byte U1[SHA256_DIGEST_SIZE];
+ hmac_sha256(Pwd, PwdLength, SaltData, SaltLength + 4, U1);
+ byte Fn[SHA256_DIGEST_SIZE]; // Current function value.
+ memcpy(Fn, U1, sizeof(Fn)); // Function at first iteration.
+
+ uint CurCount[] = { Count-1, 16, 16 };
+ byte *CurValue[] = { Key , V1, V2 };
+
+ byte U2[SHA256_DIGEST_SIZE];
+ for (uint I = 0; I < 3; I++) // For output key and 2 supplementary values.
+ {
+ for (uint J = 0; J < CurCount[I]; J++)
+ {
+ hmac_sha256(Pwd, PwdLength, U1, sizeof(U1), U2); // U2 = PRF (P, U1).
+ memcpy(U1, U2, sizeof(U1));
+ for (uint K = 0; K < sizeof(Fn); K++) // Function ^= U.
+ Fn[K] ^= U1[K];
+ }
+ memcpy(CurValue[I], Fn, SHA256_DIGEST_SIZE);
+ }
+
+ cleandata(SaltData, sizeof(SaltData));
+ cleandata(Fn, sizeof(Fn));
+ cleandata(U1, sizeof(U1));
+ cleandata(U2, sizeof(U2));
+}
+
+
+void CryptData::SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,
+ const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,
+ byte *PswCheck)
+{
+ if (Lg2Cnt>CRYPT5_KDF_LG2_COUNT_MAX)
+ return;
+
+ byte Key[32],PswCheckValue[SHA256_DIGEST_SIZE],HashKeyValue[SHA256_DIGEST_SIZE];
+ bool Found=false;
+ for (uint I=0;I<ASIZE(KDFCache);I++)
+ {
+ KDFCacheItem *Item=KDFCache+I;
+ if (Item->Lg2Count==Lg2Cnt && Item->Pwd==*Password &&
+ memcmp(Item->Salt,Salt,SIZE_SALT50)==0)
+ {
+ SecHideData(Item->Key,sizeof(Item->Key),false);
+ memcpy(Key,Item->Key,sizeof(Key));
+ SecHideData(Item->Key,sizeof(Item->Key),true);
+
+ memcpy(PswCheckValue,Item->PswCheckValue,sizeof(PswCheckValue));
+ memcpy(HashKeyValue,Item->HashKeyValue,sizeof(HashKeyValue));
+ Found=true;
+ break;
+ }
+ }
+
+ if (!Found)
+ {
+ char PwdUtf[MAXPASSWORD*4];
+ WideToUtf(PwdW,PwdUtf,ASIZE(PwdUtf));
+
+ pbkdf2((byte *)PwdUtf,strlen(PwdUtf),Salt,SIZE_SALT50,Key,HashKeyValue,PswCheckValue,(1<<Lg2Cnt));
+ cleandata(PwdUtf,sizeof(PwdUtf));
+
+ KDFCacheItem *Item=KDFCache+(KDFCachePos++ % ASIZE(KDFCache));
+ Item->Lg2Count=Lg2Cnt;
+ Item->Pwd=*Password;
+ memcpy(Item->Salt,Salt,SIZE_SALT50);
+ memcpy(Item->Key,Key,sizeof(Key));
+ memcpy(Item->PswCheckValue,PswCheckValue,sizeof(PswCheckValue));
+ memcpy(Item->HashKeyValue,HashKeyValue,sizeof(HashKeyValue));
+ SecHideData(Item->Key,sizeof(Key),true);
+ }
+ if (HashKey!=NULL)
+ memcpy(HashKey,HashKeyValue,SHA256_DIGEST_SIZE);
+ if (PswCheck!=NULL)
+ {
+ memset(PswCheck,0,SIZE_PSWCHECK);
+ for (uint I=0;I<SHA256_DIGEST_SIZE;I++)
+ PswCheck[I%SIZE_PSWCHECK]^=PswCheckValue[I];
+ cleandata(PswCheckValue,sizeof(PswCheckValue));
+ }
+
+ // NULL initialization vector is possible if we only need the password
+ // check value for archive encryption header.
+ if (InitV!=NULL)
+ rin.Init(Encrypt, Key, 256, InitV);
+
+ cleandata(Key,sizeof(Key));
+}
+
+
+void ConvertHashToMAC(HashValue *Value,byte *Key)
+{
+ if (Value->Type==HASH_CRC32)
+ {
+ byte RawCRC[4];
+ RawPut4(Value->CRC32,RawCRC);
+ byte Digest[SHA256_DIGEST_SIZE];
+ hmac_sha256(Key,SHA256_DIGEST_SIZE,RawCRC,sizeof(RawCRC),Digest);
+ Value->CRC32=0;
+ for (uint I=0;I<ASIZE(Digest);I++)
+ Value->CRC32^=Digest[I] << ((I & 3) * 8);
+ }
+ if (Value->Type==HASH_BLAKE2)
+ {
+ byte Digest[BLAKE2_DIGEST_SIZE];
+ hmac_sha256(Key,BLAKE2_DIGEST_SIZE,Value->Digest,sizeof(Value->Digest),Digest);
+ memcpy(Value->Digest,Digest,sizeof(Value->Digest));
+ }
+}
+
+
+#if 0
+static void TestPBKDF2();
+struct TestKDF {TestKDF() {TestPBKDF2();exit(0);}} GlobalTestKDF;
+
+void TestPBKDF2() // Test PBKDF2 HMAC-SHA256
+{
+ byte Key[32],V1[32],V2[32];
+
+ pbkdf2((byte *)"password", 8, (byte *)"salt", 4, Key, V1, V2, 1);
+ byte Res1[32]={0x12, 0x0f, 0xb6, 0xcf, 0xfc, 0xf8, 0xb3, 0x2c, 0x43, 0xe7, 0x22, 0x52, 0x56, 0xc4, 0xf8, 0x37, 0xa8, 0x65, 0x48, 0xc9, 0x2c, 0xcc, 0x35, 0x48, 0x08, 0x05, 0x98, 0x7c, 0xb7, 0x0b, 0xe1, 0x7b };
+ mprintf(L"\nPBKDF2 test1: %s", memcmp(Key,Res1,32)==0 ? L"OK":L"Failed");
+
+ pbkdf2((byte *)"password", 8, (byte *)"salt", 4, Key, V1, V2, 4096);
+ byte Res2[32]={0xc5, 0xe4, 0x78, 0xd5, 0x92, 0x88, 0xc8, 0x41, 0xaa, 0x53, 0x0d, 0xb6, 0x84, 0x5c, 0x4c, 0x8d, 0x96, 0x28, 0x93, 0xa0, 0x01, 0xce, 0x4e, 0x11, 0xa4, 0x96, 0x38, 0x73, 0xaa, 0x98, 0x13, 0x4a };
+ mprintf(L"\nPBKDF2 test2: %s", memcmp(Key,Res2,32)==0 ? L"OK":L"Failed");
+
+ pbkdf2((byte *)"just some long string pretending to be a password", 49, (byte *)"salt, salt, salt, a lot of salt", 31, Key, V1, V2, 65536);
+ byte Res3[32]={0x08, 0x0f, 0xa3, 0x1d, 0x42, 0x2d, 0xb0, 0x47, 0x83, 0x9b, 0xce, 0x3a, 0x3b, 0xce, 0x49, 0x51, 0xe2, 0x62, 0xb9, 0xff, 0x76, 0x2f, 0x57, 0xe9, 0xc4, 0x71, 0x96, 0xce, 0x4b, 0x6b, 0x6e, 0xbf};
+ mprintf(L"\nPBKDF2 test3: %s", memcmp(Key,Res3,32)==0 ? L"OK":L"Failed");
+}
+#endif
diff --git a/src/thirdparty/unrar/dll.cpp b/src/thirdparty/unrar/dll.cpp
index 535656caf..f44e7fdc1 100644
--- a/src/thirdparty/unrar/dll.cpp
+++ b/src/thirdparty/unrar/dll.cpp
@@ -6,12 +6,12 @@ static int RarErrorToDll(RAR_EXIT ErrCode);
struct DataSet
{
CommandData Cmd;
- CmdExtract Extract;
Archive Arc;
+ CmdExtract Extract;
int OpenMode;
int HeaderSize;
- DataSet():Arc(&Cmd) {};
+ DataSet():Arc(&Cmd),Extract(&Cmd) {};
};
@@ -27,7 +27,7 @@ HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *r)
r->OpenResult=rx.OpenResult;
r->CmtSize=rx.CmtSize;
r->CmtState=rx.CmtState;
- return(hArc);
+ return hArc;
}
@@ -40,40 +40,72 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
Data=new DataSet;
Data->Cmd.DllError=0;
Data->OpenMode=r->OpenMode;
- Data->Cmd.FileArgs->AddString("*");
+ Data->Cmd.FileArgs.AddString(L"*");
- char an[NM];
- if (r->ArcName==NULL && r->ArcNameW!=NULL)
+ char AnsiArcName[NM];
+ *AnsiArcName=0;
+ if (r->ArcName!=NULL)
{
- WideToChar(r->ArcNameW,an,NM);
- r->ArcName=an;
+ strncpyz(AnsiArcName,r->ArcName,ASIZE(AnsiArcName));
+#ifdef _WIN_ALL
+ if (!AreFileApisANSI())
+ {
+ OemToCharBuffA(r->ArcName,AnsiArcName,ASIZE(AnsiArcName));
+ AnsiArcName[ASIZE(AnsiArcName)-1]=0;
+ }
+#endif
}
- Data->Cmd.AddArcName(r->ArcName,r->ArcNameW);
+ wchar ArcName[NM];
+ GetWideName(AnsiArcName,r->ArcNameW,ArcName,ASIZE(ArcName));
+
+ Data->Cmd.AddArcName(ArcName);
Data->Cmd.Overwrite=OVERWRITE_ALL;
Data->Cmd.VersionControl=1;
Data->Cmd.Callback=r->Callback;
Data->Cmd.UserData=r->UserData;
- if (!Data->Arc.Open(r->ArcName,r->ArcNameW,0))
+ if (!Data->Arc.Open(ArcName,0))
{
r->OpenResult=ERAR_EOPEN;
delete Data;
- return(NULL);
+ return NULL;
}
if (!Data->Arc.IsArchive(false))
{
r->OpenResult=Data->Cmd.DllError!=0 ? Data->Cmd.DllError:ERAR_BAD_ARCHIVE;
delete Data;
- return(NULL);
+ return NULL;
}
- r->Flags=Data->Arc.NewMhd.Flags;
- Array<byte> CmtData;
- if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtData,NULL))
+ r->Flags=0;
+
+ if (Data->Arc.Volume)
+ r->Flags|=0x01;
+ if (Data->Arc.Locked)
+ r->Flags|=0x04;
+ if (Data->Arc.Solid)
+ r->Flags|=0x08;
+ if (Data->Arc.NewNumbering)
+ r->Flags|=0x10;
+ if (Data->Arc.Signed)
+ r->Flags|=0x20;
+ if (Data->Arc.Protected)
+ r->Flags|=0x40;
+ if (Data->Arc.Encrypted)
+ r->Flags|=0x80;
+ if (Data->Arc.FirstVolume)
+ r->Flags|=0x100;
+
+ Array<wchar> CmtDataW;
+ if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtDataW))
{
+ Array<char> CmtData(CmtDataW.Size()*4+1);
+ memset(&CmtData[0],0,CmtData.Size());
+ WideToChar(&CmtDataW[0],&CmtData[0],CmtData.Size()-1);
+ size_t Size=strlen(&CmtData[0])+1;
+
r->Flags|=2;
- size_t Size=CmtData.Size()+1;
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1);
@@ -82,10 +114,8 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
}
else
r->CmtState=r->CmtSize=0;
- if (Data->Arc.Signed)
- r->Flags|=0x20;
Data->Extract.ExtractArchiveInit(&Data->Cmd,Data->Arc);
- return((HANDLE)Data);
+ return (HANDLE)Data;
}
catch (RAR_EXIT ErrCode)
{
@@ -95,7 +125,7 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
r->OpenResult=RarErrorToDll(ErrCode);
if (Data != NULL)
delete Data;
- return(NULL);
+ return NULL;
}
catch (std::bad_alloc) // Catch 'new' exception.
{
@@ -103,6 +133,7 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
if (Data != NULL)
delete Data;
}
+ return NULL; // To make compilers happy.
}
@@ -111,7 +142,7 @@ int PASCAL RARCloseArchive(HANDLE hArcData)
DataSet *Data=(DataSet *)hArcData;
bool Success=Data==NULL ? false:Data->Arc.Close();
delete Data;
- return(Success ? 0:ERAR_ECLOSE);
+ return Success ? ERAR_SUCCESS : ERAR_ECLOSE;
}
@@ -145,67 +176,88 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D)
DataSet *Data=(DataSet *)hArcData;
try
{
- if ((Data->HeaderSize=(int)Data->Arc.SearchBlock(FILE_HEAD))<=0)
+ if ((Data->HeaderSize=(int)Data->Arc.SearchBlock(HEAD_FILE))<=0)
{
- if (Data->Arc.Volume && Data->Arc.GetHeaderType()==ENDARC_HEAD &&
- (Data->Arc.EndArcHead.Flags & EARC_NEXT_VOLUME))
+ if (Data->Arc.Volume && Data->Arc.GetHeaderType()==HEAD_ENDARC &&
+ Data->Arc.EndArcHead.NextVolume)
if (MergeArchive(Data->Arc,NULL,false,'L'))
{
- Data->Extract.SignatureFound=false;
Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
- return(RARReadHeaderEx(hArcData,D));
+ return RARReadHeaderEx(hArcData,D);
}
else
- return(ERAR_EOPEN);
- return(Data->Arc.BrokenFileHeader ? ERAR_BAD_DATA:ERAR_END_ARCHIVE);
+ return ERAR_EOPEN;
+ return(Data->Arc.BrokenHeader ? ERAR_BAD_DATA:ERAR_END_ARCHIVE);
}
- if (Data->OpenMode==RAR_OM_LIST && (Data->Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)!=0)
+ FileHeader *hd=&Data->Arc.FileHead;
+ if (Data->OpenMode==RAR_OM_LIST && hd->SplitBefore)
{
int Code=RARProcessFile(hArcData,RAR_SKIP,NULL,NULL);
if (Code==0)
- return(RARReadHeaderEx(hArcData,D));
+ return RARReadHeaderEx(hArcData,D);
else
- return(Code);
+ return Code;
}
- strncpyz(D->ArcName,Data->Arc.FileName,ASIZE(D->ArcName));
- if (*Data->Arc.FileNameW)
- wcsncpy(D->ArcNameW,Data->Arc.FileNameW,ASIZE(D->ArcNameW));
- else
- CharToWide(Data->Arc.FileName,D->ArcNameW);
- strncpyz(D->FileName,Data->Arc.NewLhd.FileName,ASIZE(D->FileName));
- if (*Data->Arc.NewLhd.FileNameW)
- wcsncpy(D->FileNameW,Data->Arc.NewLhd.FileNameW,ASIZE(D->FileNameW));
- else
- {
+ wcsncpy(D->ArcNameW,hd->FileName,ASIZE(D->ArcNameW));
+ WideToChar(D->ArcNameW,D->ArcName,ASIZE(D->ArcName));
+
+ wcsncpy(D->FileNameW,hd->FileName,ASIZE(D->FileNameW));
+ WideToChar(D->FileNameW,D->FileName,ASIZE(D->FileName));
#ifdef _WIN_ALL
- char AnsiName[NM];
- OemToCharA(Data->Arc.NewLhd.FileName,AnsiName);
- if (!CharToWide(AnsiName,D->FileNameW,ASIZE(D->FileNameW)))
- *D->FileNameW=0;
-#else
- if (!CharToWide(Data->Arc.NewLhd.FileName,D->FileNameW,ASIZE(D->FileNameW)))
- *D->FileNameW=0;
+ CharToOemA(D->FileName,D->FileName);
#endif
- }
- D->Flags=Data->Arc.NewLhd.Flags;
- D->PackSize=Data->Arc.NewLhd.PackSize;
- D->PackSizeHigh=Data->Arc.NewLhd.HighPackSize;
- D->UnpSize=Data->Arc.NewLhd.UnpSize;
- D->UnpSizeHigh=Data->Arc.NewLhd.HighUnpSize;
- D->HostOS=Data->Arc.NewLhd.HostOS;
- D->FileCRC=Data->Arc.NewLhd.FileCRC;
- D->FileTime=Data->Arc.NewLhd.FileTime;
- D->UnpVer=Data->Arc.NewLhd.UnpVer;
- D->Method=Data->Arc.NewLhd.Method;
- D->FileAttr=Data->Arc.NewLhd.FileAttr;
+
+ D->Flags=0;
+ if (hd->SplitBefore)
+ D->Flags|=RHDF_SPLITBEFORE;
+ if (hd->SplitAfter)
+ D->Flags|=RHDF_SPLITAFTER;
+ if (hd->Encrypted)
+ D->Flags|=RHDF_ENCRYPTED;
+ if (hd->Solid)
+ D->Flags|=RHDF_SOLID;
+ if (hd->Dir)
+ D->Flags|=RHDF_DIRECTORY;
+
+ D->PackSize=uint(hd->PackSize & 0xffffffff);
+ D->PackSizeHigh=uint(hd->PackSize>>32);
+ D->UnpSize=uint(hd->UnpSize & 0xffffffff);
+ D->UnpSizeHigh=uint(hd->UnpSize>>32);
+ D->HostOS=hd->HSType==HSYS_WINDOWS ? HOST_WIN32:HOST_UNIX;
+ if (Data->Arc.Format==RARFMT50)
+ D->UnpVer=Data->Arc.FileHead.UnpVer==0 ? 50 : 200; // If it is not 0, just set it to something big.
+ else
+ D->UnpVer=Data->Arc.FileHead.UnpVer;
+ D->FileCRC=hd->FileHash.CRC32;
+ D->FileTime=hd->mtime.GetDos();
+ D->Method=hd->Method+0x30;
+ D->FileAttr=hd->FileAttr;
D->CmtSize=0;
D->CmtState=0;
+
+ D->DictSize=uint(hd->WinSize/1024);
+
+ switch (hd->FileHash.Type)
+ {
+ case HASH_RAR14:
+ case HASH_CRC32:
+ D->HashType=RAR_HASH_CRC32;
+ break;
+ case HASH_BLAKE2:
+ D->HashType=RAR_HASH_BLAKE2;
+ memcpy(D->Hash,hd->FileHash.Digest,BLAKE2_DIGEST_SIZE);
+ break;
+ default:
+ D->HashType=RAR_HASH_NONE;
+ break;
+ }
+
}
catch (RAR_EXIT ErrCode)
{
- return(Data->Cmd.DllError!=0 ? Data->Cmd.DllError:RarErrorToDll(ErrCode));
+ return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode);
}
- return(0);
+ return ERAR_SUCCESS;
}
@@ -218,59 +270,56 @@ int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestNa
if (Data->OpenMode==RAR_OM_LIST || Data->OpenMode==RAR_OM_LIST_INCSPLIT ||
Operation==RAR_SKIP && !Data->Arc.Solid)
{
- if (Data->Arc.Volume &&
- Data->Arc.GetHeaderType()==FILE_HEAD &&
- (Data->Arc.NewLhd.Flags & LHD_SPLIT_AFTER)!=0)
+ if (Data->Arc.Volume && Data->Arc.GetHeaderType()==HEAD_FILE &&
+ Data->Arc.FileHead.SplitAfter)
if (MergeArchive(Data->Arc,NULL,false,'L'))
{
- Data->Extract.SignatureFound=false;
Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET);
- return(0);
+ return ERAR_SUCCESS;
}
else
- return(ERAR_EOPEN);
+ return ERAR_EOPEN;
Data->Arc.SeekToNext();
}
else
{
Data->Cmd.DllOpMode=Operation;
- if (DestPath!=NULL || DestName!=NULL)
+ *Data->Cmd.ExtrPath=0;
+ *Data->Cmd.DllDestName=0;
+
+ if (DestPath!=NULL)
{
+ char ExtrPathA[NM];
#ifdef _WIN_ALL
- OemToCharA(NullToEmpty(DestPath),Data->Cmd.ExtrPath);
+ OemToCharBuffA(DestPath,ExtrPathA,ASIZE(ExtrPathA)-2);
#else
- strcpy(Data->Cmd.ExtrPath,NullToEmpty(DestPath));
+ strncpyz(ExtrPathA,DestPath,ASIZE(ExtrPathA)-2);
#endif
- AddEndSlash(Data->Cmd.ExtrPath);
+ CharToWide(ExtrPathA,Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
+ AddEndSlash(Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
+ }
+ if (DestName!=NULL)
+ {
+ char DestNameA[NM];
#ifdef _WIN_ALL
- OemToCharA(NullToEmpty(DestName),Data->Cmd.DllDestName);
+ OemToCharBuffA(DestName,DestNameA,ASIZE(DestNameA)-2);
#else
- strcpy(Data->Cmd.DllDestName,NullToEmpty(DestName));
+ strncpyz(DestNameA,DestName,ASIZE(DestNameA)-2);
#endif
+ CharToWide(DestNameA,Data->Cmd.DllDestName,ASIZE(Data->Cmd.DllDestName));
}
- else
- {
- *Data->Cmd.ExtrPath=0;
- *Data->Cmd.DllDestName=0;
- }
-
- if (DestPathW!=NULL || DestNameW!=NULL)
- {
- wcsncpy(Data->Cmd.ExtrPathW,NullToEmpty(DestPathW),NM-2);
- AddEndSlash(Data->Cmd.ExtrPathW);
- wcsncpy(Data->Cmd.DllDestNameW,NullToEmpty(DestNameW),NM-1);
- if (*Data->Cmd.DllDestNameW!=0 && *Data->Cmd.DllDestName==0)
- WideToChar(Data->Cmd.DllDestNameW,Data->Cmd.DllDestName);
- }
- else
+ if (DestPathW!=NULL)
{
- *Data->Cmd.ExtrPathW=0;
- *Data->Cmd.DllDestNameW=0;
+ wcsncpy(Data->Cmd.ExtrPath,DestPathW,ASIZE(Data->Cmd.ExtrPath));
+ AddEndSlash(Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath));
}
- strcpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? "X":"T");
+ if (DestNameW!=NULL)
+ wcsncpyz(Data->Cmd.DllDestName,DestNameW,ASIZE(Data->Cmd.DllDestName));
+
+ wcscpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T");
Data->Cmd.Test=Operation!=RAR_EXTRACT;
bool Repeat=false;
Data->Extract.ExtractCurrentFile(&Data->Cmd,Data->Arc,Data->HeaderSize,Repeat);
@@ -283,7 +332,7 @@ int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestNa
// the invalid file handle. Some of our file operations like Seek()
// process such invalid handle correctly, some not.
while (Data->Arc.IsOpened() && Data->Arc.ReadHeader()!=0 &&
- Data->Arc.GetHeaderType()==NEWSUB_HEAD)
+ Data->Arc.GetHeaderType()==HEAD_SERVICE)
{
Data->Extract.ExtractCurrentFile(&Data->Cmd,Data->Arc,Data->HeaderSize,Repeat);
Data->Arc.SeekToNext();
@@ -293,9 +342,9 @@ int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestNa
}
catch (RAR_EXIT ErrCode)
{
- return(Data->Cmd.DllError!=0 ? Data->Cmd.DllError:RarErrorToDll(ErrCode));
+ return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode);
}
- return(Data->Cmd.DllError);
+ return Data->Cmd.DllError;
}
@@ -347,7 +396,7 @@ void PASCAL RARSetPassword(HANDLE hArcData,char *Password)
int PASCAL RARGetDllVersion()
{
- return(RAR_DLL_VERSION);
+ return RAR_DLL_VERSION;
}
@@ -356,20 +405,20 @@ static int RarErrorToDll(RAR_EXIT ErrCode)
switch(ErrCode)
{
case RARX_FATAL:
- return(ERAR_EREAD);
+ return ERAR_EREAD;
case RARX_CRC:
- return(ERAR_BAD_DATA);
+ return ERAR_BAD_DATA;
case RARX_WRITE:
- return(ERAR_EWRITE);
+ return ERAR_EWRITE;
case RARX_OPEN:
- return(ERAR_EOPEN);
+ return ERAR_EOPEN;
case RARX_CREATE:
- return(ERAR_ECREATE);
+ return ERAR_ECREATE;
case RARX_MEMORY:
- return(ERAR_NO_MEMORY);
+ return ERAR_NO_MEMORY;
case RARX_SUCCESS:
- return(0);
+ return ERAR_SUCCESS; // 0.
default:
- return(ERAR_UNKNOWN);
+ return ERAR_UNKNOWN;
}
}
diff --git a/src/thirdparty/unrar/dll.hpp b/src/thirdparty/unrar/dll.hpp
index 1d929bece..2c5868b8a 100644
--- a/src/thirdparty/unrar/dll.hpp
+++ b/src/thirdparty/unrar/dll.hpp
@@ -3,6 +3,7 @@
#pragma pack(1)
+#define ERAR_SUCCESS 0
#define ERAR_END_ARCHIVE 10
#define ERAR_NO_MEMORY 11
#define ERAR_BAD_DATA 12
@@ -28,7 +29,12 @@
#define RAR_VOL_ASK 0
#define RAR_VOL_NOTIFY 1
-#define RAR_DLL_VERSION 5
+#define RAR_DLL_VERSION 6
+
+#define RAR_HASH_NONE 0
+#define RAR_HASH_CRC32 1
+#define RAR_HASH_BLAKE2 2
+
#ifdef _UNIX
#define CALLBACK
@@ -39,6 +45,13 @@
#define UINT unsigned int
#endif
+#define RHDF_SPLITBEFORE 0x01
+#define RHDF_SPLITAFTER 0x02
+#define RHDF_ENCRYPTED 0x04
+#define RHDF_SOLID 0x10
+#define RHDF_DIRECTORY 0x20
+
+
struct RARHeaderData
{
char ArcName[260];
@@ -80,7 +93,10 @@ struct RARHeaderDataEx
unsigned int CmtBufSize;
unsigned int CmtSize;
unsigned int CmtState;
- unsigned int Reserved[1024];
+ unsigned int DictSize;
+ unsigned int HashType;
+ char Hash[32];
+ unsigned int Reserved[1014];
};
diff --git a/src/thirdparty/unrar/dll.rc b/src/thirdparty/unrar/dll.rc
index 7a93039ad..bcf38c090 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 4, 20, 100, 526
-PRODUCTVERSION 4, 20, 100, 526
+FILEVERSION 5, 0, 2, 851
+PRODUCTVERSION 5, 0, 2, 851
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
{
@@ -14,9 +14,9 @@ FILETYPE VFT_APP
VALUE "CompanyName", "Alexander Roshal\0"
VALUE "ProductName", "RAR decompression library\0"
VALUE "FileDescription", "RAR decompression library\0"
- VALUE "FileVersion", "4.20.0\0"
- VALUE "ProductVersion", "4.20.0\0"
- VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2012\0"
+ VALUE "FileVersion", "5.0.2\0"
+ VALUE "ProductVersion", "5.0.2\0"
+ VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2013\0"
VALUE "OriginalFilename", "Unrar.dll\0"
}
}
diff --git a/src/thirdparty/unrar/errhnd.cpp b/src/thirdparty/unrar/errhnd.cpp
index 9323518b8..e1fc9fb1d 100644
--- a/src/thirdparty/unrar/errhnd.cpp
+++ b/src/thirdparty/unrar/errhnd.cpp
@@ -1,8 +1,6 @@
#include "rar.hpp"
-static bool UserBreak;
-
ErrorHandler::ErrorHandler()
{
Clean();
@@ -16,6 +14,7 @@ void ErrorHandler::Clean()
EnableBreak=true;
Silent=false;
DoShutdown=false;
+ UserBreak=false;
}
@@ -26,7 +25,7 @@ void ErrorHandler::MemoryError()
}
-void ErrorHandler::OpenError(const char *FileName,const wchar *FileNameW)
+void ErrorHandler::OpenError(const wchar *FileName)
{
#ifndef SILENT
OpenErrorMsg(FileName);
@@ -35,12 +34,12 @@ void ErrorHandler::OpenError(const char *FileName,const wchar *FileNameW)
}
-void ErrorHandler::CloseError(const char *FileName,const wchar *FileNameW)
+void ErrorHandler::CloseError(const wchar *FileName)
{
#ifndef SILENT
if (!UserBreak)
{
- ErrMsg(NULL,St(MErrFClose),FileName);
+ Log(NULL,St(MErrFClose),FileName);
SysErrMsg();
}
#endif
@@ -50,10 +49,10 @@ void ErrorHandler::CloseError(const char *FileName,const wchar *FileNameW)
}
-void ErrorHandler::ReadError(const char *FileName,const wchar *FileNameW)
+void ErrorHandler::ReadError(const wchar *FileName)
{
#ifndef SILENT
- ReadErrorMsg(NULL,NULL,FileName,FileNameW);
+ ReadErrorMsg(FileName);
#endif
#if !defined(SILENT) || defined(RARDLL)
Throw(RARX_FATAL);
@@ -61,25 +60,25 @@ void ErrorHandler::ReadError(const char *FileName,const wchar *FileNameW)
}
-bool ErrorHandler::AskRepeatRead(const char *FileName,const wchar *FileNameW)
+bool ErrorHandler::AskRepeatRead(const wchar *FileName)
{
-#if !defined(SILENT) && !defined(SFX_MODULE) && !defined(_WIN_CE)
+#if !defined(SILENT) && !defined(SFX_MODULE)
if (!Silent)
{
SysErrMsg();
- mprintf("\n");
+ mprintf(L"\n");
Log(NULL,St(MErrRead),FileName);
- return(Ask(St(MRetryAbort))==1);
+ return Ask(St(MRetryAbort))==1;
}
#endif
- return(false);
+ return false;
}
-void ErrorHandler::WriteError(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW)
+void ErrorHandler::WriteError(const wchar *ArcName,const wchar *FileName)
{
#ifndef SILENT
- WriteErrorMsg(ArcName,ArcNameW,FileName,FileNameW);
+ WriteErrorMsg(ArcName,FileName);
#endif
#if !defined(SILENT) || defined(RARDLL)
Throw(RARX_WRITE);
@@ -88,11 +87,11 @@ void ErrorHandler::WriteError(const char *ArcName,const wchar *ArcNameW,const ch
#ifdef _WIN_ALL
-void ErrorHandler::WriteErrorFAT(const char *FileName,const wchar *FileNameW)
+void ErrorHandler::WriteErrorFAT(const wchar *FileName)
{
#if !defined(SILENT) && !defined(SFX_MODULE)
SysErrMsg();
- ErrMsg(NULL,St(MNTFSRequired),FileName);
+ Log(NULL,St(MNTFSRequired),FileName);
#endif
#if !defined(SILENT) && !defined(SFX_MODULE) || defined(RARDLL)
Throw(RARX_WRITE);
@@ -101,27 +100,27 @@ void ErrorHandler::WriteErrorFAT(const char *FileName,const wchar *FileNameW)
#endif
-bool ErrorHandler::AskRepeatWrite(const char *FileName,const wchar *FileNameW,bool DiskFull)
+bool ErrorHandler::AskRepeatWrite(const wchar *FileName,bool DiskFull)
{
-#if !defined(SILENT) && !defined(_WIN_CE)
+#ifndef SILENT
if (!Silent)
{
SysErrMsg();
- mprintf("\n");
+ mprintf(L"\n");
Log(NULL,St(DiskFull ? MNotEnoughDisk:MErrWrite),FileName);
- return(Ask(St(MRetryAbort))==1);
+ return Ask(St(MRetryAbort))==1;
}
#endif
- return(false);
+ return false;
}
-void ErrorHandler::SeekError(const char *FileName,const wchar *FileNameW)
+void ErrorHandler::SeekError(const wchar *FileName)
{
#ifndef SILENT
if (!UserBreak)
{
- ErrMsg(NULL,St(MErrSeek),FileName);
+ Log(NULL,St(MErrSeek),FileName);
SysErrMsg();
}
#endif
@@ -131,55 +130,58 @@ void ErrorHandler::SeekError(const char *FileName,const wchar *FileNameW)
}
-void ErrorHandler::GeneralErrMsg(const char *Msg)
+void ErrorHandler::GeneralErrMsg(const wchar *fmt,...)
{
+ va_list arglist;
+ va_start(arglist,fmt);
+ wchar Msg[1024];
+ vswprintf(Msg,ASIZE(Msg),fmt,arglist);
#ifndef SILENT
- Log(NULL,"%s",Msg);
+ Log(NULL,L"%ls",Msg);
+ mprintf(L"\n");
SysErrMsg();
#endif
+ va_end(arglist);
}
void ErrorHandler::MemoryErrorMsg()
{
#ifndef SILENT
- ErrMsg(NULL,St(MErrOutMem));
+ Log(NULL,St(MErrOutMem));
#endif
}
-void ErrorHandler::OpenErrorMsg(const char *FileName,const wchar *FileNameW)
+void ErrorHandler::OpenErrorMsg(const wchar *FileName)
{
- OpenErrorMsg(NULL,NULL,FileName,FileNameW);
+ OpenErrorMsg(NULL,FileName);
}
-void ErrorHandler::OpenErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW)
+void ErrorHandler::OpenErrorMsg(const wchar *ArcName,const wchar *FileName)
{
#ifndef SILENT
if (FileName!=NULL)
Log(ArcName,St(MCannotOpen),FileName);
- Alarm();
SysErrMsg();
#endif
}
-void ErrorHandler::CreateErrorMsg(const char *FileName,const wchar *FileNameW)
+void ErrorHandler::CreateErrorMsg(const wchar *FileName)
{
- CreateErrorMsg(NULL,NULL,FileName,FileNameW);
+ CreateErrorMsg(NULL,FileName);
}
-void ErrorHandler::CreateErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW)
+void ErrorHandler::CreateErrorMsg(const wchar *ArcName,const wchar *FileName)
{
#ifndef SILENT
- if (FileName!=NULL)
- Log(ArcName,St(MCannotCreate),FileName);
- Alarm();
+ Log(ArcName,St(MCannotCreate),FileName);
-#if defined(_WIN_ALL) && !defined(_WIN_CE) && defined(MAX_PATH)
- CheckLongPathErrMsg(FileName,FileNameW);
+#if defined(_WIN_ALL) && defined(MAX_PATH)
+ CheckLongPathErrMsg(FileName);
#endif
SysErrMsg();
@@ -188,18 +190,16 @@ void ErrorHandler::CreateErrorMsg(const char *ArcName,const wchar *ArcNameW,cons
// Check the path length and display the error message if it is too long.
-void ErrorHandler::CheckLongPathErrMsg(const char *FileName,const wchar *FileNameW)
+void ErrorHandler::CheckLongPathErrMsg(const wchar *FileName)
{
-#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined (SILENT) && defined(MAX_PATH)
+#if defined(_WIN_ALL) && !defined (SILENT) && defined(MAX_PATH)
if (GetLastError()==ERROR_PATH_NOT_FOUND)
{
- wchar WideFileName[NM];
- GetWideName(FileName,FileNameW,WideFileName,ASIZE(WideFileName));
- size_t NameLength=wcslen(WideFileName);
- if (!IsFullPath(WideFileName))
+ size_t NameLength=wcslen(FileName);
+ if (!IsFullPath(FileName))
{
wchar CurDir[NM];
- GetCurrentDirectoryW(ASIZE(CurDir),CurDir);
+ GetCurrentDirectory(ASIZE(CurDir),CurDir);
NameLength+=wcslen(CurDir)+1;
}
if (NameLength>MAX_PATH)
@@ -211,19 +211,25 @@ void ErrorHandler::CheckLongPathErrMsg(const char *FileName,const wchar *FileNam
}
-void ErrorHandler::ReadErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW)
+void ErrorHandler::ReadErrorMsg(const wchar *FileName)
+{
+ ReadErrorMsg(NULL,FileName);
+}
+
+
+void ErrorHandler::ReadErrorMsg(const wchar *ArcName,const wchar *FileName)
{
#ifndef SILENT
- ErrMsg(ArcName,St(MErrRead),FileName);
+ Log(ArcName,St(MErrRead),FileName);
SysErrMsg();
#endif
}
-void ErrorHandler::WriteErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW)
+void ErrorHandler::WriteErrorMsg(const wchar *ArcName,const wchar *FileName)
{
#ifndef SILENT
- ErrMsg(ArcName,St(MErrWrite),FileName);
+ Log(ArcName,St(MErrWrite),FileName);
SysErrMsg();
#endif
}
@@ -231,35 +237,13 @@ void ErrorHandler::WriteErrorMsg(const char *ArcName,const wchar *ArcNameW,const
void ErrorHandler::Exit(RAR_EXIT ExitCode)
{
-#ifndef SFX_MODULE
+#ifndef GUI
Alarm();
#endif
Throw(ExitCode);
}
-#ifndef GUI
-void ErrorHandler::ErrMsg(const char *ArcName,const char *fmt,...)
-{
- safebuf char Msg[NM+1024];
- va_list argptr;
- va_start(argptr,fmt);
- vsprintf(Msg,fmt,argptr);
- va_end(argptr);
-#ifdef _WIN_ALL
- if (UserBreak)
- Sleep(5000);
-#endif
- Alarm();
- if (*Msg)
- {
- Log(ArcName,"\n%s",Msg);
- mprintf("\n%s\n",St(MProgAborted));
- }
-}
-#endif
-
-
void ErrorHandler::SetErrorCode(RAR_EXIT Code)
{
switch(Code)
@@ -295,23 +279,34 @@ void _stdfunction ProcessSignal(int SigType)
// When a console application is run as a service, this allows the service
// to continue running after the user logs off.
if (SigType==CTRL_LOGOFF_EVENT)
- return(TRUE);
+ return TRUE;
#endif
- UserBreak=true;
+
+ ErrHandler.UserBreak=true;
mprintf(St(MBreak));
- for (int I=0;!File::RemoveCreated() && I<3;I++)
- {
+
#ifdef _WIN_ALL
- Sleep(100);
-#endif
- }
+ // Let the main thread to handle 'throw' and destroy file objects.
+ Sleep(200);
#if defined(USE_RC) && !defined(SFX_MODULE) && !defined(_WIN_CE) && !defined(RARDLL)
ExtRes.UnloadDLL();
#endif
exit(RARX_USERBREAK);
+#endif
+
+#ifdef _UNIX
+ static uint BreakCount=0;
+ // User continues to press Ctrl+C, exit immediately without cleanup.
+ if (++BreakCount>1)
+ exit(RARX_USERBREAK);
+ // Otherwise return from signal handler and let Wait() function to close
+ // files and quit. We cannot use the same approach as in Windows,
+ // because Unix signal handler can block execution of our main code.
+#endif
+
#if defined(_WIN_ALL) && !defined(_MSC_VER)
// never reached, just to avoid a compiler warning
- return(TRUE);
+ return TRUE;
#endif
}
#endif
@@ -336,13 +331,13 @@ void ErrorHandler::Throw(RAR_EXIT Code)
{
if (Code==RARX_USERBREAK && !EnableBreak)
return;
+#if !defined(GUI) && !defined(SILENT)
+ // Do not write "aborted" when just displaying online help.
+ if (Code!=RARX_SUCCESS && Code!=RARX_USERERROR)
+ mprintf(L"\n%s\n",St(MProgAborted));
+#endif
ErrHandler.SetErrorCode(Code);
-#ifdef ALLOW_EXCEPTIONS
throw Code;
-#else
- File::RemoveCreated();
- exit(Code);
-#endif
}
@@ -371,17 +366,7 @@ void ErrorHandler::SysErrMsg()
*EndMsg=0;
EndMsg++;
}
- // We use ASCII for output in Windows console, so let's convert Unicode
- // message to single byte.
- size_t Length=wcslen(CurMsg)*2; // Must be enough for DBCS characters.
- char *MsgA=(char *)malloc(Length+2);
- if (MsgA!=NULL)
- {
- WideToChar(CurMsg,MsgA,Length+1);
- MsgA[Length]=0;
- Log(NULL,"\n%s",MsgA);
- free(MsgA);
- }
+ Log(NULL,L"\n%ls",CurMsg);
CurMsg=EndMsg;
}
}
@@ -393,7 +378,11 @@ void ErrorHandler::SysErrMsg()
{
char *err=strerror(errno);
if (err!=NULL)
- Log(NULL,"\n%s",err);
+ {
+ wchar MsgW[1024];
+ CharToWide(err,MsgW,ASIZE(MsgW));
+ Log(NULL,L"\n%s",MsgW);
+ }
}
#endif
@@ -401,5 +390,21 @@ void ErrorHandler::SysErrMsg()
}
+int ErrorHandler::GetSystemErrorCode()
+{
+#ifdef _WIN_ALL
+ return GetLastError();
+#else
+ return errno;
+#endif
+}
+void ErrorHandler::SetSystemErrorCode(int Code)
+{
+#ifdef _WIN_ALL
+ SetLastError(Code);
+#else
+ errno=Code;
+#endif
+}
diff --git a/src/thirdparty/unrar/errhnd.hpp b/src/thirdparty/unrar/errhnd.hpp
index ab84e0b54..2edfb316b 100644
--- a/src/thirdparty/unrar/errhnd.hpp
+++ b/src/thirdparty/unrar/errhnd.hpp
@@ -1,10 +1,6 @@
#ifndef _RAR_ERRHANDLER_
#define _RAR_ERRHANDLER_
-#ifndef SFX_MODULE
-#define ALLOW_EXCEPTIONS
-#endif
-
enum RAR_EXIT // RAR exit code.
{
RARX_SUCCESS = 0,
@@ -18,16 +14,15 @@ enum RAR_EXIT // RAR exit code.
RARX_MEMORY = 8,
RARX_CREATE = 9,
RARX_NOFILES = 10,
+ RARX_BADPWD = 11,
RARX_USERBREAK = 255
};
class ErrorHandler
{
private:
- void ErrMsg(const char *ArcName,const char *fmt,...);
-
RAR_EXIT ExitCode;
- int ErrCount;
+ uint ErrCount;
bool EnableBreak;
bool Silent;
bool DoShutdown;
@@ -35,32 +30,36 @@ class ErrorHandler
ErrorHandler();
void Clean();
void MemoryError();
- void OpenError(const char *FileName,const wchar *FileNameW);
- void CloseError(const char *FileName,const wchar *FileNameW);
- void ReadError(const char *FileName,const wchar *FileNameW);
- bool AskRepeatRead(const char *FileName,const wchar *FileNameW);
- void WriteError(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW);
- void WriteErrorFAT(const char *FileName,const wchar *FileNameW);
- bool AskRepeatWrite(const char *FileName,const wchar *FileNameW,bool DiskFull);
- void SeekError(const char *FileName,const wchar *FileNameW);
- void GeneralErrMsg(const char *Msg);
+ void OpenError(const wchar *FileName);
+ void CloseError(const wchar *FileName);
+ void ReadError(const wchar *FileName);
+ bool AskRepeatRead(const wchar *FileName);
+ void WriteError(const wchar *ArcName,const wchar *FileName);
+ void WriteErrorFAT(const wchar *FileName);
+ bool AskRepeatWrite(const wchar *FileName,bool DiskFull);
+ void SeekError(const wchar *FileName);
+ void GeneralErrMsg(const wchar *fmt,...);
void MemoryErrorMsg();
- void OpenErrorMsg(const char *FileName,const wchar *FileNameW=NULL);
- void OpenErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW);
- void CreateErrorMsg(const char *FileName,const wchar *FileNameW=NULL);
- void CreateErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW);
- void CheckLongPathErrMsg(const char *FileName,const wchar *FileNameW);
- void ReadErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW);
- void WriteErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW);
+ void OpenErrorMsg(const wchar *FileName);
+ void OpenErrorMsg(const wchar *ArcName,const wchar *FileName);
+ void CreateErrorMsg(const wchar *FileName);
+ void CreateErrorMsg(const wchar *ArcName,const wchar *FileName);
+ void CheckLongPathErrMsg(const wchar *FileName);
+ void ReadErrorMsg(const wchar *FileName);
+ void ReadErrorMsg(const wchar *ArcName,const wchar *FileName);
+ void WriteErrorMsg(const wchar *ArcName,const wchar *FileName);
void Exit(RAR_EXIT ExitCode);
void SetErrorCode(RAR_EXIT Code);
RAR_EXIT GetErrorCode() {return(ExitCode);}
- int GetErrorCount() {return(ErrCount);}
+ uint GetErrorCount() {return ErrCount;}
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;
};
diff --git a/src/thirdparty/unrar/extinfo.cpp b/src/thirdparty/unrar/extinfo.cpp
index 538f6a7f3..141967f2a 100644
--- a/src/thirdparty/unrar/extinfo.cpp
+++ b/src/thirdparty/unrar/extinfo.cpp
@@ -1,51 +1,40 @@
#include "rar.hpp"
+#include "hardlinks.cpp"
+#include "win32stm.cpp"
+
#ifdef _WIN_ALL
#include "win32acl.cpp"
-#include "win32stm.cpp"
-#endif
-#ifdef _BEOS
-#include "beosea.cpp"
-#endif
-#if defined(_EMX) && !defined(_DJGPP)
-#include "os2ea.cpp"
+#include "win32lnk.cpp"
#endif
+
#ifdef _UNIX
#include "uowners.cpp"
+#ifdef SAVE_LINKS
+#include "ulinks.cpp"
+#endif
#endif
#ifndef SFX_MODULE
-void SetExtraInfo(CommandData *Cmd,Archive &Arc,char *Name,wchar *NameW)
+void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name)
{
switch(Arc.SubBlockHead.SubType)
{
-#if defined(_EMX) && !defined(_DJGPP)
- case EA_HEAD:
- if (Cmd->ProcessEA)
- ExtractOS2EA(Arc,Name);
- break;
-#endif
#ifdef _UNIX
case UO_HEAD:
if (Cmd->ProcessOwners)
- ExtractUnixOwner(Arc,Name);
- break;
-#endif
-#ifdef _BEOS
- case BEEA_HEAD:
- if (Cmd->ProcessEA)
- ExtractBeEA(Arc,Name);
+ ExtractUnixOwner20(Arc,Name);
break;
#endif
#ifdef _WIN_ALL
case NTACL_HEAD:
if (Cmd->ProcessOwners)
- ExtractACL(Arc,Name,NameW);
+ ExtractACL20(Arc,Name);
break;
case STREAM_HEAD:
- ExtractStreams(Arc,Name,NameW);
+ ExtractStreams20(Arc,Name);
break;
#endif
}
@@ -53,24 +42,37 @@ void SetExtraInfo(CommandData *Cmd,Archive &Arc,char *Name,wchar *NameW)
#endif
-void SetExtraInfoNew(CommandData *Cmd,Archive &Arc,char *Name,wchar *NameW)
+void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name)
{
-#if defined(_EMX) && !defined(_DJGPP)
- if (Cmd->ProcessEA && Arc.SubHead.CmpName(SUBHEAD_TYPE_OS2EA))
- ExtractOS2EANew(Arc,Name);
-#endif
#ifdef _UNIX
- if (Cmd->ProcessOwners && Arc.SubHead.CmpName(SUBHEAD_TYPE_UOWNER))
- ExtractUnixOwnerNew(Arc,Name);
-#endif
-#ifdef _BEOS
- if (Cmd->ProcessEA && Arc.SubHead.CmpName(SUBHEAD_TYPE_UOWNER))
- ExtractUnixOwnerNew(Arc,Name);
+ if (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))
- ExtractACLNew(Arc,Name,NameW);
+ ExtractACL(Arc,Name);
if (Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM))
- ExtractStreamsNew(Arc,Name,NameW);
+ ExtractStreams(Arc,Name);
+#endif
+}
+
+
+
+
+bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName)
+{
+#if defined(SAVE_LINKS) && defined(_UNIX)
+ // For RAR 3.x archives we process links even in test mode to skip link data.
+ if (Arc.Format==RARFMT15)
+ return ExtractUnixLink30(DataIO,Arc,LinkName);
+ if (Arc.Format==RARFMT50)
+ return ExtractUnixLink50(LinkName,&Arc.FileHead);
+#elif defined _WIN_ALL
+ // RAR 5.0 archives store link information in file header, so there is
+ // no need to additionally test it if we do not create a file.
+ if (Arc.Format==RARFMT50)
+ return CreateReparsePoint(Cmd,LinkName,&Arc.FileHead);
#endif
+ return false;
}
diff --git a/src/thirdparty/unrar/extinfo.hpp b/src/thirdparty/unrar/extinfo.hpp
index db7cea53f..224564da8 100644
--- a/src/thirdparty/unrar/extinfo.hpp
+++ b/src/thirdparty/unrar/extinfo.hpp
@@ -1,8 +1,20 @@
#ifndef _RAR_EXTINFO_
#define _RAR_EXTINFO_
+bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName);
+#ifdef _UNIX
+void SetUnixOwner(Archive &Arc,const wchar *FileName);
+#endif
+
+bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize);
+
+void GetStreamNameNTFS(Archive &Arc,wchar *StreamName,size_t MaxSize);
+
+#ifdef _WIN_ALL
+bool SetPrivilege(LPCTSTR PrivName);
+#endif
-void SetExtraInfo(CommandData *Cmd,Archive &Arc,char *Name,wchar *NameW);
-void SetExtraInfoNew(CommandData *Cmd,Archive &Arc,char *Name,wchar *NameW);
+void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name);
+void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name);
#endif
diff --git a/src/thirdparty/unrar/extract.cpp b/src/thirdparty/unrar/extract.cpp
index ddd71a038..2d3279d30 100644
--- a/src/thirdparty/unrar/extract.cpp
+++ b/src/thirdparty/unrar/extract.cpp
@@ -1,1026 +1,1060 @@
-#include "rar.hpp"
-
-CmdExtract::CmdExtract()
-{
- *ArcName=0;
- *ArcNameW=0;
-
- *DestFileName=0;
- *DestFileNameW=0;
-
- TotalFileCount=0;
- Password.Set(L"");
- Unp=new Unpack(&DataIO);
- Unp->Init();
-}
-
-
-CmdExtract::~CmdExtract()
-{
- delete Unp;
-}
-
-
-void CmdExtract::DoExtract(CommandData *Cmd)
-{
- PasswordCancelled=false;
- DataIO.SetCurrentCommand(*Cmd->Command);
-
- FindData FD;
- while (Cmd->GetArcName(ArcName,ArcNameW,ASIZE(ArcName)))
- if (FindFile::FastFind(ArcName,ArcNameW,&FD))
- DataIO.TotalArcSize+=FD.Size;
-
- Cmd->ArcNames->Rewind();
- while (Cmd->GetArcName(ArcName,ArcNameW,ASIZE(ArcName)))
- {
- while (true)
- {
- SecPassword PrevCmdPassword;
- PrevCmdPassword=Cmd->Password;
-
- EXTRACT_ARC_CODE Code=ExtractArchive(Cmd);
-
- // Restore Cmd->Password, which could be changed in IsArchive() call
- // for next header encrypted archive.
- Cmd->Password=PrevCmdPassword;
-
- if (Code!=EXTRACT_ARC_REPEAT)
- break;
- }
- if (FindFile::FastFind(ArcName,ArcNameW,&FD))
- DataIO.ProcessedArcSize+=FD.Size;
- }
-
- if (TotalFileCount==0 && *Cmd->Command!='I')
- {
- if (!PasswordCancelled)
- {
- mprintf(St(MExtrNoFiles));
- }
- ErrHandler.SetErrorCode(RARX_NOFILES);
- }
-#ifndef GUI
- else
- if (!Cmd->DisableDone)
- if (*Cmd->Command=='I')
- mprintf(St(MDone));
- else
- if (ErrHandler.GetErrorCount()==0)
- mprintf(St(MExtrAllOk));
- else
- mprintf(St(MExtrTotalErr),ErrHandler.GetErrorCount());
-#endif
-}
-
-
-void CmdExtract::ExtractArchiveInit(CommandData *Cmd,Archive &Arc)
-{
- DataIO.UnpArcSize=Arc.FileLength();
-
- FileCount=0;
- MatchedArgs=0;
-#ifndef SFX_MODULE
- FirstFile=true;
-#endif
-
- PasswordAll=(Cmd->Password.IsSet());
- if (PasswordAll)
- Password=Cmd->Password;
-
- DataIO.UnpVolume=false;
-
- PrevExtracted=false;
- SignatureFound=false;
- AllMatchesExact=true;
- ReconstructDone=false;
- AnySolidDataUnpackedWell=false;
-
- StartTime.SetCurrentTime();
-}
-
-
-EXTRACT_ARC_CODE CmdExtract::ExtractArchive(CommandData *Cmd)
-{
- Archive Arc(Cmd);
- if (!Arc.WOpen(ArcName,ArcNameW))
- {
- ErrHandler.SetErrorCode(RARX_OPEN);
- return(EXTRACT_ARC_NEXT);
- }
-
- if (!Arc.IsArchive(true))
- {
-#ifndef GUI
- mprintf(St(MNotRAR),ArcName);
-#endif
- if (CmpExt(ArcName,"rar"))
- ErrHandler.SetErrorCode(RARX_WARNING);
- return(EXTRACT_ARC_NEXT);
- }
-
- // Archive with corrupt encrypted header can be closed in IsArchive() call.
-// if (!Arc.IsOpened())
-// return(EXTRACT_ARC_NEXT);
-
-#ifndef SFX_MODULE
- if (Arc.Volume && Arc.NotFirstVolume)
- {
- char FirstVolName[NM];
- VolNameToFirstName(ArcName,FirstVolName,(Arc.NewMhd.Flags & MHD_NEWNUMBERING)!=0);
-
- // 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 (stricomp(ArcName,FirstVolName)!=0 && FileExist(FirstVolName) &&
- Cmd->ArcNames->Search(FirstVolName,NULL,false))
- return(EXTRACT_ARC_NEXT);
- }
-#endif
-
- int64 VolumeSetSize=0; // Total size of volumes after the current volume.
-
- if (Arc.Volume)
- {
- // Calculate the total size of all accessible volumes.
- // This size is necessary to display the correct total progress indicator.
-
- char NextName[NM];
- wchar NextNameW[NM];
-
- strcpy(NextName,Arc.FileName);
- wcscpy(NextNameW,Arc.FileNameW);
-
- while (true)
- {
- // First volume is already added to DataIO.TotalArcSize
- // in initial TotalArcSize calculation in DoExtract.
- // So we skip it and start from second volume.
- NextVolumeName(NextName,NextNameW,ASIZE(NextName),(Arc.NewMhd.Flags & MHD_NEWNUMBERING)==0 || Arc.OldFormat);
- struct FindData FD;
- if (FindFile::FastFind(NextName,NextNameW,&FD))
- VolumeSetSize+=FD.Size;
- else
- break;
- }
- DataIO.TotalArcSize+=VolumeSetSize;
- }
-
- ExtractArchiveInit(Cmd,Arc);
-
- if (*Cmd->Command=='T' || *Cmd->Command=='I')
- Cmd->Test=true;
-
-
-#ifndef GUI
- if (*Cmd->Command=='I')
- Cmd->DisablePercentage=true;
- else
- if (Cmd->Test)
- mprintf(St(MExtrTest),ArcName);
- else
- mprintf(St(MExtracting),ArcName);
-#endif
-
- Arc.ViewComment();
-
- // RAR can close a corrupt encrypted archive
-// if (!Arc.IsOpened())
-// return(EXTRACT_ARC_NEXT);
-
-
- while (1)
- {
- size_t Size=Arc.ReadHeader();
- bool Repeat=false;
- if (!ExtractCurrentFile(Cmd,Arc,Size,Repeat))
- if (Repeat)
- {
- // If we started extraction from not first volume and need to
- // restart it from first, we must correct DataIO.TotalArcSize
- // for correct total progress display. We subtract the size
- // of current volume and all volumes after it and add the size
- // of new (first) volume.
- FindData OldArc,NewArc;
- if (FindFile::FastFind(Arc.FileName,Arc.FileNameW,&OldArc) &&
- FindFile::FastFind(ArcName,ArcNameW,&NewArc))
- DataIO.TotalArcSize-=VolumeSetSize+OldArc.Size-NewArc.Size;
- return(EXTRACT_ARC_REPEAT);
- }
- else
- break;
- }
-
- return(EXTRACT_ARC_NEXT);
-}
-
-
-bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,size_t HeaderSize,bool &Repeat)
-{
- char Command=*Cmd->Command;
- if (HeaderSize==0)
- if (DataIO.UnpVolume)
- {
-#ifdef NOVOLUME
- return(false);
-#else
- if (!MergeArchive(Arc,&DataIO,false,Command))
- {
- ErrHandler.SetErrorCode(RARX_WARNING);
- return(false);
- }
- SignatureFound=false;
-#endif
- }
- else
- return(false);
- int HeadType=Arc.GetHeaderType();
- if (HeadType!=FILE_HEAD)
- {
- if (HeadType==AV_HEAD || HeadType==SIGN_HEAD)
- SignatureFound=true;
-#if !defined(SFX_MODULE) && !defined(_WIN_CE)
- if (HeadType==SUB_HEAD && PrevExtracted)
- SetExtraInfo(Cmd,Arc,DestFileName,*DestFileNameW ? DestFileNameW:NULL);
-#endif
- if (HeadType==NEWSUB_HEAD)
- {
- if (Arc.SubHead.CmpName(SUBHEAD_TYPE_AV))
- SignatureFound=true;
-#if !defined(NOSUBBLOCKS) && !defined(_WIN_CE)
- if (PrevExtracted)
- SetExtraInfoNew(Cmd,Arc,DestFileName,*DestFileNameW ? DestFileNameW:NULL);
-#endif
- }
- if (HeadType==ENDARC_HEAD)
- if (Arc.EndArcHead.Flags & EARC_NEXT_VOLUME)
- {
-#ifndef NOVOLUME
- if (!MergeArchive(Arc,&DataIO,false,Command))
- {
- ErrHandler.SetErrorCode(RARX_WARNING);
- return(false);
- }
- SignatureFound=false;
-#endif
- Arc.Seek(Arc.CurBlockPos,SEEK_SET);
- return(true);
- }
- else
- return(false);
- Arc.SeekToNext();
- return(true);
- }
- PrevExtracted=false;
-
- if (SignatureFound ||
- !Cmd->Recurse && MatchedArgs>=Cmd->FileArgs->ItemsCount() &&
- AllMatchesExact)
- return(false);
-
- char ArcFileName[NM];
- IntToExt(Arc.NewLhd.FileName,Arc.NewLhd.FileName);
- strcpy(ArcFileName,Arc.NewLhd.FileName);
-
- wchar ArcFileNameW[NM];
- *ArcFileNameW=0;
-
- int MatchType=MATCH_WILDSUBPATH;
-
- bool EqualNames=false;
- int MatchNumber=Cmd->IsProcessFile(Arc.NewLhd,&EqualNames,MatchType);
- bool ExactMatch=MatchNumber!=0;
-#if !defined(SFX_MODULE) && !defined(_WIN_CE)
- if (Cmd->ExclPath==EXCL_BASEPATH)
- {
- *Cmd->ArcPath=0;
- if (ExactMatch)
- {
- Cmd->FileArgs->Rewind();
- if (Cmd->FileArgs->GetString(Cmd->ArcPath,NULL,sizeof(Cmd->ArcPath),MatchNumber-1))
- *PointToName(Cmd->ArcPath)=0;
- }
- }
-#endif
- if (ExactMatch && !EqualNames)
- AllMatchesExact=false;
-
-#ifdef UNICODE_SUPPORTED
- bool WideName=(Arc.NewLhd.Flags & LHD_UNICODE) && UnicodeEnabled();
-#else
- bool WideName=false;
-#endif
-
-#ifdef _APPLE
- if (WideName)
- {
- // Prepare UTF-8 name for OS X. Since we are sure that destination
- // is UTF-8, we can avoid calling the less reliable WideToChar function.
- WideToUtf(Arc.NewLhd.FileNameW,ArcFileName,ASIZE(ArcFileName));
- WideName=false;
- }
-#endif
-
- wchar *DestNameW=WideName ? DestFileNameW:NULL;
-
-#ifdef UNICODE_SUPPORTED
- if (WideName)
- {
- // Prepare the name in single byte native encoding (typically UTF-8
- // for Unix-based systems). Windows does not really need it,
- // but Unix system will use this name instead of Unicode.
- ConvertPath(Arc.NewLhd.FileNameW,ArcFileNameW);
- char Name[NM];
- if (WideToChar(ArcFileNameW,Name) && IsNameUsable(Name))
- strcpy(ArcFileName,Name);
- }
-#endif
-
- ConvertPath(ArcFileName,ArcFileName);
-
- if (Arc.IsArcLabel())
- return(true);
-
- if (Arc.NewLhd.Flags & LHD_VERSION)
- {
- if (Cmd->VersionControl!=1 && !EqualNames)
- {
- if (Cmd->VersionControl==0)
- ExactMatch=false;
- int Version=ParseVersionFileName(ArcFileName,ArcFileNameW,false);
- if (Cmd->VersionControl-1==Version)
- ParseVersionFileName(ArcFileName,ArcFileNameW,true);
- else
- ExactMatch=false;
- }
- }
- else
- if (!Arc.IsArcDir() && Cmd->VersionControl>1)
- ExactMatch=false;
-
- Arc.ConvertAttributes();
-
-#if !defined(SFX_MODULE) && !defined(RARDLL)
- if ((Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)!=0 && FirstFile)
- {
- char CurVolName[NM];
- strcpy(CurVolName,ArcName);
-
- bool NewNumbering=(Arc.NewMhd.Flags & MHD_NEWNUMBERING)!=0;
- VolNameToFirstName(ArcName,ArcName,NewNumbering);
- if (*ArcNameW!=0)
- VolNameToFirstName(ArcNameW,ArcNameW,NewNumbering);
-
- if (stricomp(ArcName,CurVolName)!=0 && FileExist(ArcName,ArcNameW))
- {
- // If first volume name does not match the current name and if
- // such volume name really exists, let's unpack from this first volume.
- Repeat=true;
- return(false);
- }
-#if !defined(RARDLL) && !defined(_WIN_CE)
- if (!ReconstructDone)
- {
- ReconstructDone=true;
-
- RecVolumes RecVol;
- if (RecVol.Restore(Cmd,Arc.FileName,Arc.FileNameW,true))
- {
- Repeat=true;
- return(false);
- }
- }
-#endif
- strcpy(ArcName,CurVolName);
- }
-#endif
-
- DataIO.UnpVolume=(Arc.NewLhd.Flags & LHD_SPLIT_AFTER)!=0;
- DataIO.NextVolumeMissing=false;
-
- Arc.Seek(Arc.NextBlockPos-Arc.NewLhd.FullPackSize,SEEK_SET);
-
- bool TestMode=false;
- bool ExtrFile=false;
- bool SkipSolid=false;
-
-#ifndef SFX_MODULE
- if (FirstFile && (ExactMatch || Arc.Solid) && (Arc.NewLhd.Flags & (LHD_SPLIT_BEFORE/*|LHD_SOLID*/))!=0)
- {
- if (ExactMatch)
- {
- Log(Arc.FileName,St(MUnpCannotMerge),ArcFileName);
-#ifdef RARDLL
- Cmd->DllError=ERAR_BAD_DATA;
-#endif
- ErrHandler.SetErrorCode(RARX_OPEN);
- }
- ExactMatch=false;
- }
-
- FirstFile=false;
-#endif
-
- if (ExactMatch || (SkipSolid=Arc.Solid)!=0)
- {
- if ((Arc.NewLhd.Flags & LHD_PASSWORD)!=0)
-#ifndef RARDLL
- if (!Password.IsSet())
-#endif
- {
-#ifdef RARDLL
- if (!Cmd->Password.IsSet())
- {
- if (Cmd->Callback!=NULL)
- {
- wchar PasswordW[MAXPASSWORD];
- *PasswordW=0;
- if (Cmd->Callback(UCM_NEEDPASSWORDW,Cmd->UserData,(LPARAM)PasswordW,ASIZE(PasswordW))==-1)
- *PasswordW=0;
- if (*PasswordW==0)
- {
- char PasswordA[MAXPASSWORD];
- *PasswordA=0;
- if (Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1)
- *PasswordA=0;
- GetWideName(PasswordA,NULL,PasswordW,ASIZE(PasswordW));
- cleandata(PasswordA,sizeof(PasswordA));
- }
- Cmd->Password.Set(PasswordW);
- cleandata(PasswordW,sizeof(PasswordW));
- }
- if (!Cmd->Password.IsSet())
- return false;
- }
- Password=Cmd->Password;
-
-#else
- if (!GetPassword(PASSWORD_FILE,ArcFileName,ArcFileNameW,&Password))
- {
- PasswordCancelled=true;
- return(false);
- }
-#endif
- }
-#if !defined(GUI) && !defined(SILENT)
- else
- if (!PasswordAll && (!Arc.Solid || Arc.NewLhd.UnpVer>=20 && (Arc.NewLhd.Flags & LHD_SOLID)==0))
- {
- eprintf(St(MUseCurPsw),ArcFileName);
- switch(Cmd->AllYes ? 1:Ask(St(MYesNoAll)))
- {
- case -1:
- ErrHandler.Exit(RARX_USERBREAK);
- case 2:
- if (!GetPassword(PASSWORD_FILE,ArcFileName,ArcFileNameW,&Password))
- {
- return(false);
- }
- break;
- case 3:
- PasswordAll=true;
- break;
- }
- }
-#endif
-
-#ifndef SFX_MODULE
- if (*Cmd->ExtrPath==0 && *Cmd->ExtrPathW!=0)
- WideToChar(Cmd->ExtrPathW,DestFileName);
- else
-#endif
- strcpy(DestFileName,Cmd->ExtrPath);
-
-
-#ifndef SFX_MODULE
- if (Cmd->AppendArcNameToPath)
- {
- strcat(DestFileName,PointToName(Arc.FirstVolumeName));
- SetExt(DestFileName,NULL);
- AddEndSlash(DestFileName);
- }
-#endif
-
- char *ExtrName=ArcFileName;
-
- bool EmptyName=false;
-#ifndef SFX_MODULE
- size_t Length=strlen(Cmd->ArcPath);
- if (Length>1 && IsPathDiv(Cmd->ArcPath[Length-1]) &&
- strlen(ArcFileName)==Length-1)
- Length--;
- if (Length>0 && strnicomp(Cmd->ArcPath,ArcFileName,Length)==0)
- {
- ExtrName+=Length;
- while (*ExtrName==CPATHDIVIDER)
- ExtrName++;
- if (*ExtrName==0)
- EmptyName=true;
- }
-#endif
-
- // Use -ep3 only in systems, where disk letters are exist, not in Unix.
- bool AbsPaths=Cmd->ExclPath==EXCL_ABSPATH && Command=='X' && IsDriveDiv(':');
-
- // We do not use any user specified destination paths when extracting
- // absolute paths in -ep3 mode.
- if (AbsPaths)
- *DestFileName=0;
-
- if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
- strcat(DestFileName,PointToName(ExtrName));
- else
- strcat(DestFileName,ExtrName);
-
- char DiskLetter=etoupper(DestFileName[0]);
-
- if (AbsPaths)
- {
- if (DestFileName[1]=='_' && IsPathDiv(DestFileName[2]) &&
- DiskLetter>='A' && DiskLetter<='Z')
- DestFileName[1]=':';
- else
- if (DestFileName[0]=='_' && DestFileName[1]=='_')
- {
- // Convert __server\share to \\server\share.
- DestFileName[0]=CPATHDIVIDER;
- DestFileName[1]=CPATHDIVIDER;
- }
- }
-
-#ifndef SFX_MODULE
- if (!WideName && *Cmd->ExtrPathW!=0)
- {
- DestNameW=DestFileNameW;
- WideName=true;
- CharToWide(ArcFileName,ArcFileNameW);
- }
-#endif
-
- if (WideName)
- {
- if (*Cmd->ExtrPathW!=0)
- wcscpy(DestFileNameW,Cmd->ExtrPathW);
- else
- CharToWide(Cmd->ExtrPath,DestFileNameW);
-
-#ifndef SFX_MODULE
- if (Cmd->AppendArcNameToPath)
- {
- wchar FileNameW[NM];
- if (*Arc.FirstVolumeNameW!=0)
- wcscpy(FileNameW,Arc.FirstVolumeNameW);
- else
- CharToWide(Arc.FirstVolumeName,FileNameW);
- wcscat(DestFileNameW,PointToName(FileNameW));
- SetExt(DestFileNameW,NULL);
- AddEndSlash(DestFileNameW);
- }
-#endif
- wchar *ExtrNameW=ArcFileNameW;
-#ifndef SFX_MODULE
- if (Length>0)
- {
- wchar ArcPathW[NM];
- GetWideName(Cmd->ArcPath,Cmd->ArcPathW,ArcPathW,ASIZE(ArcPathW));
- Length=wcslen(ArcPathW);
- }
- ExtrNameW+=Length;
- while (*ExtrNameW==CPATHDIVIDER)
- ExtrNameW++;
-#endif
-
- if (AbsPaths)
- *DestFileNameW=0;
-
- if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
- wcscat(DestFileNameW,PointToName(ExtrNameW));
- else
- wcscat(DestFileNameW,ExtrNameW);
-
- if (AbsPaths && DestFileNameW[1]=='_' && IsPathDiv(DestFileNameW[2]))
- DestFileNameW[1]=':';
- }
- else
- *DestFileNameW=0;
-
- ExtrFile=!SkipSolid && !EmptyName && (Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)==0;
-
- if ((Cmd->FreshFiles || Cmd->UpdateFiles) && (Command=='E' || Command=='X'))
- {
- struct FindData FD;
- if (FindFile::FastFind(DestFileName,DestNameW,&FD))
- {
- if (FD.mtime >= Arc.NewLhd.mtime)
- {
- // If directory already exists and its modification time is newer
- // than start of extraction, it is likely it was created
- // when creating a path to one of already extracted items.
- // In such case we'll better update its time even if archived
- // directory is older.
-
- if (!FD.IsDir || FD.mtime<StartTime)
- ExtrFile=false;
- }
- }
- else
- if (Cmd->FreshFiles)
- ExtrFile=false;
- }
-
- // Skip encrypted file if no password is specified.
- if ((Arc.NewLhd.Flags & LHD_PASSWORD)!=0 && !Password.IsSet())
- {
- ErrHandler.SetErrorCode(RARX_WARNING);
-#ifdef RARDLL
- Cmd->DllError=ERAR_MISSING_PASSWORD;
-#endif
- ExtrFile=false;
- }
-
-#ifdef RARDLL
- if (*Cmd->DllDestName)
- {
- strncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName));
- *DestFileNameW=0;
- if (Cmd->DllOpMode!=RAR_EXTRACT)
- ExtrFile=false;
- }
- if (*Cmd->DllDestNameW)
- {
- wcsncpyz(DestFileNameW,Cmd->DllDestNameW,ASIZE(DestFileNameW));
- DestNameW=DestFileNameW;
- if (Cmd->DllOpMode!=RAR_EXTRACT)
- ExtrFile=false;
- }
-#endif
-
-#ifdef SFX_MODULE
- if ((Arc.NewLhd.UnpVer!=UNP_VER && Arc.NewLhd.UnpVer!=29) &&
- Arc.NewLhd.Method!=0x30)
-#else
- if (Arc.NewLhd.UnpVer<13 || Arc.NewLhd.UnpVer>UNP_VER)
-#endif
- {
-#ifndef SILENT
- Log(Arc.FileName,St(MUnknownMeth),ArcFileName);
-#ifndef SFX_MODULE
- Log(Arc.FileName,St(MVerRequired),Arc.NewLhd.UnpVer/10,Arc.NewLhd.UnpVer%10);
-#endif
-#endif
- ExtrFile=false;
- ErrHandler.SetErrorCode(RARX_WARNING);
-#ifdef RARDLL
- Cmd->DllError=ERAR_UNKNOWN_FORMAT;
-#endif
- }
-
- File CurFile;
-
- if (!IsLink(Arc.NewLhd.FileAttr))
- if (Arc.IsArcDir())
- {
- if (!ExtrFile || Command=='P' || Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
- return(true);
- if (SkipSolid)
- {
-#ifndef GUI
- mprintf(St(MExtrSkipFile),ArcFileName);
-#endif
- return(true);
- }
- TotalFileCount++;
- if (Cmd->Test)
- {
-#ifndef GUI
- mprintf(St(MExtrTestFile),ArcFileName);
- mprintf(" %s",St(MOk));
-#endif
- return(true);
- }
- MKDIR_CODE MDCode=MakeDir(DestFileName,DestNameW,!Cmd->IgnoreGeneralAttr,Arc.NewLhd.FileAttr);
- bool DirExist=false;
- if (MDCode!=MKDIR_SUCCESS)
- {
- DirExist=FileExist(DestFileName,DestNameW);
- if (DirExist && !IsDir(GetFileAttr(DestFileName,DestNameW)))
- {
- // File with name same as this directory exists. Propose user
- // to overwrite it.
- bool UserReject;
- FileCreate(Cmd,NULL,DestFileName,DestNameW,Cmd->Overwrite,&UserReject,Arc.NewLhd.FullUnpSize,Arc.NewLhd.FileTime);
- DirExist=false;
- }
- if (!DirExist)
- {
- CreatePath(DestFileName,DestNameW,true);
- MDCode=MakeDir(DestFileName,DestNameW,!Cmd->IgnoreGeneralAttr,Arc.NewLhd.FileAttr);
- }
- }
- if (MDCode==MKDIR_SUCCESS)
- {
-#ifndef GUI
- mprintf(St(MCreatDir),DestFileName);
- mprintf(" %s",St(MOk));
-#endif
- PrevExtracted=true;
- }
- else
- if (DirExist)
- {
- if (!Cmd->IgnoreGeneralAttr)
- SetFileAttr(DestFileName,DestNameW,Arc.NewLhd.FileAttr);
- PrevExtracted=true;
- }
- else
- {
- Log(Arc.FileName,St(MExtrErrMkDir),DestFileName);
- ErrHandler.CheckLongPathErrMsg(DestFileName,DestNameW);
- ErrHandler.SysErrMsg();
-#ifdef RARDLL
- Cmd->DllError=ERAR_ECREATE;
-#endif
- ErrHandler.SetErrorCode(RARX_CREATE);
- }
- if (PrevExtracted)
- {
-#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
- if (Cmd->SetCompressedAttr &&
- (Arc.NewLhd.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT())
- SetFileCompression(DestFileName,DestNameW,true);
-#endif
- SetDirTime(DestFileName,DestNameW,
- Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
- Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.NewLhd.ctime,
- Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime);
- }
- return(true);
- }
- else
- {
- if (Cmd->Test && ExtrFile)
- TestMode=true;
-#if !defined(GUI) && !defined(SFX_MODULE)
- if (Command=='P' && ExtrFile)
- CurFile.SetHandleType(FILE_HANDLESTD);
-#endif
- if ((Command=='E' || Command=='X') && ExtrFile && !Cmd->Test)
- {
- bool UserReject;
- // Specify "write only" mode to avoid OpenIndiana NAS problems
- // with SetFileTime and read+write files.
- if (!FileCreate(Cmd,&CurFile,DestFileName,DestNameW,Cmd->Overwrite,&UserReject,Arc.NewLhd.FullUnpSize,Arc.NewLhd.FileTime,true))
- {
- ExtrFile=false;
- if (!UserReject)
- {
- ErrHandler.CreateErrorMsg(Arc.FileName,Arc.FileNameW,DestFileName,DestFileNameW);
- ErrHandler.SetErrorCode(RARX_CREATE);
-#ifdef RARDLL
- Cmd->DllError=ERAR_ECREATE;
-#endif
- if (!IsNameUsable(DestFileName) && (!WideName || !IsNameUsable(DestNameW)))
- {
- Log(Arc.FileName,St(MCorrectingName));
- char OrigName[ASIZE(DestFileName)];
- wchar OrigNameW[ASIZE(DestFileNameW)];
- strncpyz(OrigName,DestFileName,ASIZE(OrigName));
- wcsncpyz(OrigNameW,NullToEmpty(DestNameW),ASIZE(OrigNameW));
-
- MakeNameUsable(DestFileName,true);
-
- if (WideName)
- MakeNameUsable(DestNameW,true);
-
- CreatePath(DestFileName,DestNameW,true);
- if (FileCreate(Cmd,&CurFile,DestFileName,DestNameW,Cmd->Overwrite,&UserReject,Arc.NewLhd.FullUnpSize,Arc.NewLhd.FileTime,true))
- {
-#ifndef SFX_MODULE
- Log(Arc.FileName,St(MRenaming),OrigName,DestFileName);
-#endif
- ExtrFile=true;
- }
- else
- ErrHandler.CreateErrorMsg(Arc.FileName,Arc.FileNameW,DestFileName,DestFileNameW);
- }
- }
- }
- }
- }
-
- if (!ExtrFile && Arc.Solid)
- {
- SkipSolid=true;
- TestMode=true;
- ExtrFile=true;
-
- }
- if (ExtrFile)
- {
-
- if (!SkipSolid)
- {
- if (!TestMode && Command!='P' && CurFile.IsDevice())
- {
- Log(Arc.FileName,St(MInvalidName),DestFileName);
- ErrHandler.WriteError(Arc.FileName,Arc.FileNameW,DestFileName,DestFileNameW);
- }
- TotalFileCount++;
- }
- FileCount++;
-#ifndef GUI
- if (Command!='I')
- if (SkipSolid)
- mprintf(St(MExtrSkipFile),ArcFileName);
- else
- switch(Cmd->Test ? 'T':Command)
- {
- case 'T':
- mprintf(St(MExtrTestFile),ArcFileName);
- break;
-#ifndef SFX_MODULE
- case 'P':
- mprintf(St(MExtrPrinting),ArcFileName);
- break;
-#endif
- case 'X':
- case 'E':
- mprintf(St(MExtrFile),DestFileName);
- break;
- }
- if (!Cmd->DisablePercentage)
- mprintf(" ");
-#endif
- DataIO.CurUnpRead=0;
- DataIO.CurUnpWrite=0;
- DataIO.UnpFileCRC=Arc.OldFormat ? 0 : 0xffffffff;
- DataIO.PackedCRC=0xffffffff;
-
- SecPassword FilePassword;
-#ifdef _WIN_ALL
- if (Arc.NewLhd.HostOS==HOST_MSDOS/* && Arc.NewLhd.UnpVer<=25*/)
- {
- // We need the password in OEM encoding if file was encrypted by
- // native RAR/DOS (not extender based). Let's make the conversion.
- wchar PlainPsw[MAXPASSWORD];
- Password.Get(PlainPsw,ASIZE(PlainPsw));
- char PswA[MAXPASSWORD];
- CharToOemBuffW(PlainPsw,PswA,ASIZE(PswA));
- PswA[ASIZE(PswA)-1]=0;
- CharToWide(PswA,PlainPsw,ASIZE(PlainPsw));
- PlainPsw[ASIZE(PlainPsw)-1]=0;
- FilePassword.Set(PlainPsw);
- cleandata(PlainPsw,sizeof(PlainPsw));
- cleandata(PswA,sizeof(PswA));
- }
- else
-#endif
- FilePassword=Password;
-
- DataIO.SetEncryption(
- (Arc.NewLhd.Flags & LHD_PASSWORD)!=0 ? Arc.NewLhd.UnpVer:0,&FilePassword,
- (Arc.NewLhd.Flags & LHD_SALT)!=0 ? Arc.NewLhd.Salt:NULL,false,
- Arc.NewLhd.UnpVer>=36);
- DataIO.SetPackedSizeToRead(Arc.NewLhd.FullPackSize);
- DataIO.SetFiles(&Arc,&CurFile);
- DataIO.SetTestMode(TestMode);
- DataIO.SetSkipUnpCRC(SkipSolid);
-#ifndef _WIN_CE
- if (!TestMode && !Arc.BrokenFileHeader &&
- (Arc.NewLhd.FullPackSize<<11)>Arc.NewLhd.FullUnpSize &&
- (Arc.NewLhd.FullUnpSize<100000000 || Arc.FileLength()>Arc.NewLhd.FullPackSize))
- CurFile.Prealloc(Arc.NewLhd.FullUnpSize);
-#endif
-
- CurFile.SetAllowDelete(!Cmd->KeepBroken);
-
- bool LinkCreateMode=!Cmd->Test && !SkipSolid;
- if (ExtractLink(DataIO,Arc,DestFileName,DataIO.UnpFileCRC,LinkCreateMode))
- PrevExtracted=LinkCreateMode;
- else
- if ((Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)==0)
- if (Arc.NewLhd.Method==0x30)
- UnstoreFile(DataIO,Arc.NewLhd.FullUnpSize);
- else
- {
- Unp->SetDestSize(Arc.NewLhd.FullUnpSize);
-#ifndef SFX_MODULE
- if (Arc.NewLhd.UnpVer<=15)
- Unp->DoUnpack(15,FileCount>1 && Arc.Solid);
- else
-#endif
- Unp->DoUnpack(Arc.NewLhd.UnpVer,(Arc.NewLhd.Flags & LHD_SOLID)!=0);
- }
-
-// if (Arc.IsOpened())
- Arc.SeekToNext();
-
- bool ValidCRC=Arc.OldFormat && GET_UINT32(DataIO.UnpFileCRC)==GET_UINT32(Arc.NewLhd.FileCRC) ||
- !Arc.OldFormat && GET_UINT32(DataIO.UnpFileCRC)==GET_UINT32(Arc.NewLhd.FileCRC^0xffffffff);
-
- // We set AnySolidDataUnpackedWell to true if we found at least one
- // valid non-zero solid file in preceding solid stream. If it is true
- // and if current encrypted file is broken, we do not need to hint
- // about a wrong password and can report CRC error only.
- if ((Arc.NewLhd.Flags & LHD_SOLID)==0)
- AnySolidDataUnpackedWell=false; // Reset the flag, because non-solid file is found.
- else
- if (Arc.NewLhd.Method!=0x30 && Arc.NewLhd.FullUnpSize>0 && ValidCRC)
- AnySolidDataUnpackedWell=true;
-
- bool BrokenFile=false;
- if (!SkipSolid)
- {
- if (ValidCRC)
- {
-#ifndef GUI
- if (Command!='P' && Command!='I')
- mprintf("%s%s ",Cmd->DisablePercentage ? " ":"\b\b\b\b\b ",St(MOk));
-#endif
- }
- else
- {
- if ((Arc.NewLhd.Flags & LHD_PASSWORD)!=0 && !AnySolidDataUnpackedWell)
- {
- Log(Arc.FileName,St(MEncrBadCRC),ArcFileName);
- }
- else
- {
- Log(Arc.FileName,St(MCRCFailed),ArcFileName);
- }
- BrokenFile=true;
- ErrHandler.SetErrorCode(RARX_CRC);
-#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_DATA;
-#endif
- Alarm();
- }
- }
-#ifndef GUI
- else
- mprintf("\b\b\b\b\b ");
-#endif
-
- if (!TestMode && (Command=='X' || Command=='E') &&
- !IsLink(Arc.NewLhd.FileAttr))
- {
-#if defined(_WIN_ALL) || defined(_EMX)
- if (Cmd->ClearArc)
- Arc.NewLhd.FileAttr&=~FA_ARCH;
-#endif
- if (!BrokenFile || Cmd->KeepBroken)
- {
- if (BrokenFile)
- CurFile.Truncate();
- CurFile.SetOpenFileTime(
- Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
- Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.NewLhd.ctime,
- Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime);
- CurFile.Close();
-#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
- if (Cmd->SetCompressedAttr &&
- (Arc.NewLhd.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT())
- SetFileCompression(CurFile.FileName,CurFile.FileNameW,true);
-#endif
- CurFile.SetCloseFileTime(
- Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.NewLhd.mtime,
- Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.NewLhd.atime);
- if (!Cmd->IgnoreGeneralAttr)
- SetFileAttr(CurFile.FileName,CurFile.FileNameW,Arc.NewLhd.FileAttr);
- PrevExtracted=true;
- }
- }
- }
- }
- if (ExactMatch)
- MatchedArgs++;
- if (DataIO.NextVolumeMissing/* || !Arc.IsOpened()*/)
- return(false);
- if (!ExtrFile)
- if (!Arc.Solid)
- Arc.SeekToNext();
- else
- if (!SkipSolid)
- return(false);
- return(true);
-}
-
-
-void CmdExtract::UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize)
-{
- Array<byte> Buffer(0x10000);
- while (1)
- {
- uint Code=DataIO.UnpRead(&Buffer[0],Buffer.Size());
- if (Code==0 || (int)Code==-1)
- break;
- Code=Code<DestUnpSize ? Code:(uint)DestUnpSize;
- DataIO.UnpWrite(&Buffer[0],Code);
- if (DestUnpSize>=0)
- DestUnpSize-=Code;
- }
-}
-
+#include "rar.hpp"
+
+CmdExtract::CmdExtract(CommandData *Cmd)
+{
+ *ArcName=0;
+
+ *DestFileName=0;
+
+ TotalFileCount=0;
+ Password.Set(L"");
+ Unp=new Unpack(&DataIO);
+#ifdef RAR_SMP
+ Unp->SetThreads(Cmd->Threads);
+#endif
+}
+
+
+CmdExtract::~CmdExtract()
+{
+ delete Unp;
+}
+
+
+void CmdExtract::DoExtract(CommandData *Cmd)
+{
+ PasswordCancelled=false;
+ DataIO.SetCurrentCommand(Cmd->Command[0]);
+
+ FindData FD;
+ while (Cmd->GetArcName(ArcName,ASIZE(ArcName)))
+ if (FindFile::FastFind(ArcName,&FD))
+ DataIO.TotalArcSize+=FD.Size;
+
+ Cmd->ArcNames.Rewind();
+ while (Cmd->GetArcName(ArcName,ASIZE(ArcName)))
+ {
+ while (true)
+ {
+ SecPassword PrevCmdPassword;
+ PrevCmdPassword=Cmd->Password;
+
+ EXTRACT_ARC_CODE Code=ExtractArchive(Cmd);
+
+ // Restore Cmd->Password, which could be changed in IsArchive() call
+ // for next header encrypted archive.
+ Cmd->Password=PrevCmdPassword;
+
+ if (Code!=EXTRACT_ARC_REPEAT)
+ break;
+ }
+ if (FindFile::FastFind(ArcName,&FD))
+ DataIO.ProcessedArcSize+=FD.Size;
+ }
+
+ if (TotalFileCount==0 && Cmd->Command[0]!='I' &&
+ ErrHandler.GetErrorCode()!=RARX_BADPWD) // Not in case of wrong archive password.
+ {
+ if (!PasswordCancelled)
+ {
+ mprintf(St(MExtrNoFiles));
+ }
+ ErrHandler.SetErrorCode(RARX_NOFILES);
+ }
+#ifndef GUI
+ else
+ if (!Cmd->DisableDone)
+ if (Cmd->Command[0]=='I')
+ mprintf(St(MDone));
+ else
+ if (ErrHandler.GetErrorCount()==0)
+ mprintf(St(MExtrAllOk));
+ else
+ mprintf(St(MExtrTotalErr),ErrHandler.GetErrorCount());
+#endif
+}
+
+
+void CmdExtract::ExtractArchiveInit(CommandData *Cmd,Archive &Arc)
+{
+ DataIO.UnpArcSize=Arc.FileLength();
+
+ FileCount=0;
+ MatchedArgs=0;
+#ifndef SFX_MODULE
+ FirstFile=true;
+#endif
+
+ PasswordAll=(Cmd->Password.IsSet());
+ if (PasswordAll)
+ Password=Cmd->Password;
+
+ DataIO.UnpVolume=false;
+
+ PrevExtracted=false;
+ AllMatchesExact=true;
+ ReconstructDone=false;
+ AnySolidDataUnpackedWell=false;
+
+ StartTime.SetCurrentTime();
+}
+
+
+EXTRACT_ARC_CODE CmdExtract::ExtractArchive(CommandData *Cmd)
+{
+ Archive Arc(Cmd);
+ if (!Arc.WOpen(ArcName))
+ {
+ ErrHandler.SetErrorCode(RARX_OPEN);
+ return EXTRACT_ARC_NEXT;
+ }
+
+ if (!Arc.IsArchive(true))
+ {
+#ifndef GUI
+ mprintf(St(MNotRAR),ArcName);
+#endif
+ if (CmpExt(ArcName,L"rar"))
+ ErrHandler.SetErrorCode(RARX_WARNING);
+ return EXTRACT_ARC_NEXT;
+ }
+
+ if (Arc.FailedHeaderDecryption) // Bad archive password.
+ return EXTRACT_ARC_NEXT;
+
+#ifndef SFX_MODULE
+ if (Arc.Volume && !Arc.FirstVolume)
+ {
+ wchar FirstVolName[NM];
+ VolNameToFirstName(ArcName,FirstVolName,Arc.NewNumbering);
+
+ // 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;
+ }
+#endif
+
+ int64 VolumeSetSize=0; // Total size of volumes after the current volume.
+
+ if (Arc.Volume)
+ {
+ // Calculate the total size of all accessible volumes.
+ // This size is necessary to display the correct total progress indicator.
+
+ wchar NextName[NM];
+ wcscpy(NextName,Arc.FileName);
+
+ while (true)
+ {
+ // First volume is already added to DataIO.TotalArcSize
+ // in initial TotalArcSize calculation in DoExtract.
+ // So we skip it and start from second volume.
+ NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering);
+ FindData FD;
+ if (FindFile::FastFind(NextName,&FD))
+ VolumeSetSize+=FD.Size;
+ else
+ break;
+ }
+ DataIO.TotalArcSize+=VolumeSetSize;
+ }
+
+ ExtractArchiveInit(Cmd,Arc);
+
+ if (*Cmd->Command=='T' || *Cmd->Command=='I')
+ Cmd->Test=true;
+
+
+#ifndef GUI
+ if (*Cmd->Command=='I')
+ Cmd->DisablePercentage=true;
+ else
+ if (Cmd->Test)
+ mprintf(St(MExtrTest),ArcName);
+ else
+ mprintf(St(MExtracting),ArcName);
+#endif
+
+ Arc.ViewComment();
+
+
+ while (1)
+ {
+ size_t Size=Arc.ReadHeader();
+
+
+ bool Repeat=false;
+ if (!ExtractCurrentFile(Cmd,Arc,Size,Repeat))
+ if (Repeat)
+ {
+ // If we started extraction from not first volume and need to
+ // restart it from first, we must correct DataIO.TotalArcSize
+ // for correct total progress display. We subtract the size
+ // of current volume and all volumes after it and add the size
+ // of new (first) volume.
+ FindData OldArc,NewArc;
+ if (FindFile::FastFind(Arc.FileName,&OldArc) &&
+ FindFile::FastFind(ArcName,&NewArc))
+ DataIO.TotalArcSize-=VolumeSetSize+OldArc.Size-NewArc.Size;
+ return EXTRACT_ARC_REPEAT;
+ }
+ else
+ break;
+ }
+
+
+ return EXTRACT_ARC_NEXT;
+}
+
+
+bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,size_t HeaderSize,bool &Repeat)
+{
+ wchar Command=Cmd->Command[0];
+ if (HeaderSize==0)
+ if (DataIO.UnpVolume)
+ {
+#ifdef NOVOLUME
+ return false;
+#else
+ if (!MergeArchive(Arc,&DataIO,false,Command))
+ {
+ ErrHandler.SetErrorCode(RARX_WARNING);
+ return false;
+ }
+#endif
+ }
+ else
+ return false;
+ HEADER_TYPE HeaderType=Arc.GetHeaderType();
+ if (HeaderType!=HEAD_FILE)
+ {
+#if !defined(SFX_MODULE) && !defined(_WIN_CE)
+ if (HeaderType==HEAD3_OLDSERVICE && PrevExtracted)
+ SetExtraInfo20(Cmd,Arc,DestFileName);
+#endif
+ if (HeaderType==HEAD_SERVICE && PrevExtracted)
+ SetExtraInfo(Cmd,Arc,DestFileName);
+ if (HeaderType==HEAD_ENDARC)
+ if (Arc.EndArcHead.NextVolume)
+ {
+#ifndef NOVOLUME
+ if (!MergeArchive(Arc,&DataIO,false,Command))
+ {
+ ErrHandler.SetErrorCode(RARX_WARNING);
+ return false;
+ }
+#endif
+ Arc.Seek(Arc.CurBlockPos,SEEK_SET);
+ return true;
+ }
+ else
+ return false;
+ Arc.SeekToNext();
+ return true;
+ }
+ PrevExtracted=false;
+
+ if (!Cmd->Recurse && MatchedArgs>=Cmd->FileArgs.ItemsCount() && AllMatchesExact)
+ return false;
+
+ int MatchType=MATCH_WILDSUBPATH;
+
+ bool EqualNames=false;
+ int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType);
+ bool ExactMatch=MatchNumber!=0;
+#ifndef SFX_MODULE
+ if (Cmd->ExclPath==EXCL_BASEPATH)
+ {
+ *Cmd->ArcPath=0;
+ if (ExactMatch)
+ {
+ Cmd->FileArgs.Rewind();
+ if (Cmd->FileArgs.GetString(Cmd->ArcPath,ASIZE(Cmd->ArcPath),MatchNumber-1))
+ *PointToName(Cmd->ArcPath)=0;
+ }
+ }
+#endif
+ if (ExactMatch && !EqualNames)
+ AllMatchesExact=false;
+
+ Arc.ConvertAttributes();
+
+#if !defined(SFX_MODULE) && !defined(RARDLL)
+ if (Arc.FileHead.SplitBefore && FirstFile)
+ {
+ wchar CurVolName[NM];
+ wcsncpyz(CurVolName,ArcName,ASIZE(CurVolName));
+ VolNameToFirstName(ArcName,ArcName,Arc.NewNumbering);
+
+ if (wcsicomp(ArcName,CurVolName)!=0 && FileExist(ArcName))
+ {
+ // If first volume name does not match the current name and if such
+ // volume name really exists, let's unpack from this first volume.
+ Repeat=true;
+ return false;
+ }
+#ifndef RARDLL
+ if (!ReconstructDone)
+ {
+ ReconstructDone=true;
+
+ if (RecVolumesRestore(Cmd,Arc.FileName,true))
+ {
+ Repeat=true;
+ return false;
+ }
+ }
+#endif
+ wcsncpyz(ArcName,CurVolName,ASIZE(ArcName));
+ }
+#endif
+
+ wchar ArcFileName[NM];
+ ConvertPath(Arc.FileHead.FileName,ArcFileName);
+
+ if (Arc.FileHead.Version)
+ {
+ if (Cmd->VersionControl!=1 && !EqualNames)
+ {
+ if (Cmd->VersionControl==0)
+ ExactMatch=false;
+ int Version=ParseVersionFileName(ArcFileName,false);
+ if (Cmd->VersionControl-1==Version)
+ ParseVersionFileName(ArcFileName,true);
+ else
+ ExactMatch=false;
+ }
+ }
+ else
+ if (!Arc.IsArcDir() && Cmd->VersionControl>1)
+ ExactMatch=false;
+
+ DataIO.UnpVolume=Arc.FileHead.SplitAfter;
+ DataIO.NextVolumeMissing=false;
+
+ Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET);
+
+ bool ExtrFile=false;
+ bool SkipSolid=false;
+
+#ifndef SFX_MODULE
+ if (FirstFile && (ExactMatch || Arc.Solid) && Arc.FileHead.SplitBefore)
+ {
+ if (ExactMatch)
+ {
+ Log(Arc.FileName,St(MUnpCannotMerge),ArcFileName);
+#ifdef RARDLL
+ Cmd->DllError=ERAR_BAD_DATA;
+#endif
+ ErrHandler.SetErrorCode(RARX_OPEN);
+ }
+ ExactMatch=false;
+ }
+
+ FirstFile=false;
+#endif
+
+ if (ExactMatch || (SkipSolid=Arc.Solid)!=0)
+ {
+
+ ExtrPrepareName(Cmd,Arc,ArcFileName,DestFileName,ASIZE(DestFileName));
+
+ // DestFileName can be set empty in case of excessive -ap switch.
+ ExtrFile=!SkipSolid && *DestFileName!=0 && !Arc.FileHead.SplitBefore;
+
+ if ((Cmd->FreshFiles || Cmd->UpdateFiles) && (Command=='E' || Command=='X'))
+ {
+ FindData FD;
+ if (FindFile::FastFind(DestFileName,&FD))
+ {
+ if (FD.mtime >= Arc.FileHead.mtime)
+ {
+ // If directory already exists and its modification time is newer
+ // than start of extraction, it is likely it was created
+ // when creating a path to one of already extracted items.
+ // In such case we'll better update its time even if archived
+ // directory is older.
+
+ if (!FD.IsDir || FD.mtime<StartTime)
+ ExtrFile=false;
+ }
+ }
+ else
+ if (Cmd->FreshFiles)
+ ExtrFile=false;
+ }
+
+ if (Arc.FileHead.Encrypted)
+ {
+#ifdef RARDLL
+ if (!ExtrDllGetPassword(Cmd))
+ return false;
+#else
+ if (!ExtrGetPassword(Cmd,Arc,ArcFileName))
+ {
+ PasswordCancelled=true;
+ return false;
+ }
+#endif
+ // Skip only the current encrypted file if empty password is entered.
+ if (!Password.IsSet())
+ {
+ ErrHandler.SetErrorCode(RARX_WARNING);
+#ifdef RARDLL
+ Cmd->DllError=ERAR_MISSING_PASSWORD;
+#endif
+ ExtrFile=false;
+ }
+ }
+
+#ifdef RARDLL
+ if (*Cmd->DllDestName!=0)
+ {
+ wcsncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName));
+
+// Do we need this code?
+// if (Cmd->DllOpMode!=RAR_EXTRACT)
+// ExtrFile=false;
+ }
+#endif
+
+ if (!CheckUnpVer(Arc,ArcFileName))
+ {
+ ExtrFile=false;
+ ErrHandler.SetErrorCode(RARX_WARNING);
+#ifdef RARDLL
+ Cmd->DllError=ERAR_UNKNOWN_FORMAT;
+#endif
+ }
+
+ File CurFile;
+
+ bool LinkEntry=Arc.FileHead.RedirType!=FSREDIR_NONE;
+ if (LinkEntry && Arc.FileHead.RedirType!=FSREDIR_FILECOPY)
+ {
+ if (ExtrFile && Command!='P' && !Cmd->Test)
+ {
+ // Overwrite prompt for symbolic and hard links.
+ bool UserReject=false;
+ if (FileExist(DestFileName) && !UserReject)
+ FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),Cmd->Overwrite,&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime);
+ if (UserReject)
+ ExtrFile=false;
+ }
+ }
+ else
+ if (Arc.IsArcDir())
+ {
+ if (!ExtrFile || Command=='P' || Command=='I' || Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
+ return true;
+ TotalFileCount++;
+ ExtrCreateDir(Cmd,Arc,ArcFileName);
+ return true;
+ }
+ else
+ if (ExtrFile) // Create files and file copies (FSREDIR_FILECOPY).
+ ExtrFile=ExtrCreateFile(Cmd,Arc,CurFile);
+
+ if (!ExtrFile && Arc.Solid)
+ {
+ SkipSolid=true;
+ ExtrFile=true;
+
+ }
+ if (ExtrFile)
+ {
+ bool TestMode=Cmd->Test || SkipSolid; // Unpack to memory, not to disk.
+
+ if (!SkipSolid)
+ {
+ if (!TestMode && Command!='P' && CurFile.IsDevice())
+ {
+ Log(Arc.FileName,St(MInvalidName),DestFileName);
+ ErrHandler.WriteError(Arc.FileName,DestFileName);
+ }
+ TotalFileCount++;
+ }
+ FileCount++;
+#ifndef GUI
+ if (Command!='I')
+ if (SkipSolid)
+ mprintf(St(MExtrSkipFile),ArcFileName);
+ else
+ switch(Cmd->Test ? 'T':Command) // "Test" can be also enabled by -t switch.
+ {
+ case 'T':
+ mprintf(St(MExtrTestFile),ArcFileName);
+ break;
+#ifndef SFX_MODULE
+ case 'P':
+ mprintf(St(MExtrPrinting),ArcFileName);
+ break;
+#endif
+ case 'X':
+ case 'E':
+ mprintf(St(MExtrFile),DestFileName);
+ break;
+ }
+ if (!Cmd->DisablePercentage)
+ mprintf(L" ");
+#endif
+
+ SecPassword FilePassword=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)
+ {
+ Log(Arc.FileName,St(MWrongPassword));
+ ErrHandler.SetErrorCode(RARX_BADPWD);
+ WrongPassword=true;
+ }
+ DataIO.CurUnpRead=0;
+ DataIO.CurUnpWrite=0;
+ DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads);
+ DataIO.PackedDataHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads);
+ DataIO.SetPackedSizeToRead(Arc.FileHead.PackSize);
+ DataIO.SetFiles(&Arc,&CurFile);
+ DataIO.SetTestMode(TestMode);
+ DataIO.SetSkipUnpCRC(SkipSolid);
+ if (!TestMode && !WrongPassword && !Arc.BrokenHeader &&
+ (Arc.FileHead.PackSize<<11)>Arc.FileHead.UnpSize &&
+ (Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize))
+ CurFile.Prealloc(Arc.FileHead.UnpSize);
+
+ CurFile.SetAllowDelete(!Cmd->KeepBroken);
+
+ bool FileCreateMode=!TestMode && !SkipSolid && Command!='P';
+ bool ShowChecksum=true; // Display checksum verification result.
+
+ if (LinkEntry)
+ {
+ FILE_SYSTEM_REDIRECT Type=Arc.FileHead.RedirType;
+
+ bool LinkSuccess=true; // Assume success for test mode.
+ if (Type==FSREDIR_HARDLINK || Type==FSREDIR_FILECOPY)
+ {
+ wchar NameExisting[NM];
+ ExtrPrepareName(Cmd,Arc,Arc.FileHead.RedirName,NameExisting,ASIZE(NameExisting));
+ if (FileCreateMode && *NameExisting!=0) // *NameExisting can be 0 in case of excessive -ap switch.
+ if (Type==FSREDIR_HARDLINK)
+ LinkSuccess=ExtractHardlink(DestFileName,NameExisting,ASIZE(NameExisting));
+ else
+ LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,DestFileName,NameExisting,ASIZE(NameExisting));
+ }
+ else
+ if (Type==FSREDIR_UNIXSYMLINK || Type==FSREDIR_WINSYMLINK || Type==FSREDIR_JUNCTION)
+ {
+ if (FileCreateMode)
+ LinkSuccess=ExtractSymlink(Cmd,DataIO,Arc,DestFileName);
+ }
+ else
+ {
+#ifndef SFX_MODULE
+ Log(Arc.FileName,St(MUnknownExtra),DestFileName);
+#endif
+ LinkSuccess=false;
+ }
+
+ if (!LinkSuccess || Arc.Format==RARFMT15 && !FileCreateMode)
+ {
+ // RAR 5.x links have a valid data checksum even in case of
+ // failure, because they do not store any data.
+ // We do not want to display "OK" in this case.
+ // For 4.x symlinks we verify the checksum only when extracting,
+ // but not when testing an archive.
+ ShowChecksum=false;
+ }
+ PrevExtracted=FileCreateMode && LinkSuccess;
+ }
+ else
+ if (!Arc.FileHead.SplitBefore && !WrongPassword)
+ if (Arc.FileHead.Method==0)
+ UnstoreFile(DataIO,Arc.FileHead.UnpSize);
+ else
+ {
+ Unp->Init(Arc.FileHead.WinSize,Arc.FileHead.Solid);
+ Unp->SetDestSize(Arc.FileHead.UnpSize);
+#ifndef SFX_MODULE
+ if (Arc.Format!=RARFMT50 && Arc.FileHead.UnpVer<=15)
+ Unp->DoUnpack(15,FileCount>1 && Arc.Solid);
+ else
+#endif
+ Unp->DoUnpack(Arc.FileHead.UnpVer,Arc.FileHead.Solid);
+ }
+
+ Arc.SeekToNext();
+
+ bool ValidCRC=DataIO.UnpHash.Cmp(&Arc.FileHead.FileHash,Arc.FileHead.UseHashKey ? Arc.FileHead.HashKey:NULL);
+
+ // We set AnySolidDataUnpackedWell to true if we found at least one
+ // valid non-zero solid file in preceding solid stream. If it is true
+ // and if current encrypted file is broken, we do not need to hint
+ // about a wrong password and can report CRC error only.
+ if (!Arc.FileHead.Solid)
+ AnySolidDataUnpackedWell=false; // Reset the flag, because non-solid file is found.
+ else
+ if (Arc.FileHead.Method!=0 && Arc.FileHead.UnpSize>0 && ValidCRC)
+ AnySolidDataUnpackedWell=true;
+
+ bool BrokenFile=false;
+
+ // Checksum is not calculated in skip solid mode for performance reason.
+ if (!SkipSolid && ShowChecksum)
+ {
+ if (!WrongPassword && ValidCRC)
+ {
+#ifndef GUI
+ if (Command!='P' && Command!='I')
+ mprintf(L"%s%s ",Cmd->DisablePercentage ? L" ":L"\b\b\b\b\b ",
+ Arc.FileHead.FileHash.Type==HASH_NONE ? L" ?":St(MOk));
+#endif
+ }
+ else
+ {
+ if (!WrongPassword)
+ if (Arc.FileHead.Encrypted && (!Arc.FileHead.UsePswCheck ||
+ Arc.BrokenHeader) && !AnySolidDataUnpackedWell)
+ {
+ Log(Arc.FileName,St(MEncrBadCRC),ArcFileName);
+ }
+ else
+ {
+ Log(Arc.FileName,St(MCRCFailed),ArcFileName);
+ }
+ BrokenFile=true;
+ ErrHandler.SetErrorCode(RARX_CRC);
+#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_DATA;
+#endif
+ }
+ }
+#ifndef GUI
+ else
+ mprintf(L"\b\b\b\b\b ");
+#endif
+
+ if (!TestMode && !WrongPassword && (Command=='X' || Command=='E') &&
+ (!LinkEntry || Arc.FileHead.RedirType==FSREDIR_FILECOPY) &&
+ (!BrokenFile || Cmd->KeepBroken))
+ {
+ // We could preallocate more space that really written to broken file.
+ if (BrokenFile)
+ CurFile.Truncate();
+
+#if defined(_WIN_ALL) || defined(_EMX)
+ if (Cmd->ClearArc)
+ Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE;
+#endif
+
+
+ CurFile.SetOpenFileTime(
+ Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime,
+ Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime,
+ Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
+ CurFile.Close();
+#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
+ if (Cmd->SetCompressedAttr &&
+ (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0)
+ SetFileCompression(CurFile.FileName,true);
+#endif
+#ifdef _UNIX
+ if (Cmd->ProcessOwners && Arc.Format==RARFMT50 && Arc.FileHead.UnixOwnerSet)
+ SetUnixOwner(Arc,CurFile.FileName);
+#endif
+
+ CurFile.SetCloseFileTime(
+ Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime,
+ Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
+ if (!Cmd->IgnoreGeneralAttr)
+ SetFileAttr(CurFile.FileName,Arc.FileHead.FileAttr);
+ PrevExtracted=true;
+ }
+ }
+ }
+ if (ExactMatch)
+ MatchedArgs++;
+ if (DataIO.NextVolumeMissing)
+ return false;
+ if (!ExtrFile)
+ if (!Arc.Solid)
+ Arc.SeekToNext();
+ else
+ if (!SkipSolid)
+ return false;
+ return true;
+}
+
+
+void CmdExtract::UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize)
+{
+ Array<byte> Buffer(0x100000);
+ while (1)
+ {
+ uint Code=DataIO.UnpRead(&Buffer[0],Buffer.Size());
+ if (Code==0 || (int)Code==-1)
+ break;
+ Code=Code<DestUnpSize ? Code:(uint)DestUnpSize;
+ DataIO.UnpWrite(&Buffer[0],Code);
+ if (DestUnpSize>=0)
+ DestUnpSize-=Code;
+ }
+}
+
+
+bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize)
+{
+#ifdef _WIN_ALL
+ UnixSlashToDos(NameExisting,NameExisting,NameExistingSize);
+#elif defined(_UNIX)
+ DosSlashToUnix(NameExisting,NameExisting,NameExistingSize);
+#endif
+ File Existing;
+ if (!Existing.Open(NameExisting))
+ {
+ ErrHandler.OpenErrorMsg(ArcName,NameExisting);
+ Log(ArcName,St(MCopyError),NameExisting,NameNew);
+ Log(ArcName,St(MCopyErrorHint));
+ return false;
+ }
+
+ Array<char> Buffer(0x100000);
+ int64 CopySize=0;
+
+ while (true)
+ {
+ Wait();
+ int ReadSize=Existing.Read(&Buffer[0],Buffer.Size());
+ if (ReadSize==0)
+ break;
+ New.Write(&Buffer[0],ReadSize);
+ CopySize+=ReadSize;
+ }
+
+ return true;
+}
+
+
+void CmdExtract::ExtrPrepareName(CommandData *Cmd,Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize)
+{
+ 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)))
+ {
+ // Destination path can be without trailing slash if it come from GUI shell.
+ AddEndSlash(DestName,DestSize);
+ }
+
+#ifndef SFX_MODULE
+ if (Cmd->AppendArcNameToPath)
+ {
+ wcsncatz(DestName,PointToName(Arc.FirstVolumeName),DestSize);
+ SetExt(DestName,NULL);
+ AddEndSlash(DestName,DestSize);
+ }
+#endif
+
+#ifndef SFX_MODULE
+ size_t ArcPathLength=wcslen(Cmd->ArcPath);
+ if (ArcPathLength>0)
+ {
+ size_t NameLength=wcslen(ArcFileName);
+ ArcFileName+=Min(ArcPathLength,NameLength);
+ while (*ArcFileName==CPATHDIVIDER)
+ ArcFileName++;
+ if (*ArcFileName==0) // Excessive -ap switch.
+ {
+ *DestName=0;
+ return;
+ }
+ }
+#endif
+
+ wchar Command=Cmd->Command[0];
+ // Use -ep3 only in systems, where disk letters are exist, not in Unix.
+ bool AbsPaths=Cmd->ExclPath==EXCL_ABSPATH && Command=='X' && IsDriveDiv(':');
+
+ // We do not use any user specified destination paths when extracting
+ // absolute paths in -ep3 mode.
+ if (AbsPaths)
+ *DestName=0;
+
+ if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH)
+ wcsncatz(DestName,PointToName(ArcFileName),DestSize);
+ else
+ wcsncatz(DestName,ArcFileName,DestSize);
+
+ wchar DiskLetter=toupperw(DestName[0]);
+
+ if (AbsPaths)
+ {
+ if (DestName[1]=='_' && IsPathDiv(DestName[2]) &&
+ DiskLetter>='A' && DiskLetter<='Z')
+ DestName[1]=':';
+ else
+ if (DestName[0]=='_' && DestName[1]=='_')
+ {
+ // Convert __server\share to \\server\share.
+ DestName[0]=CPATHDIVIDER;
+ DestName[1]=CPATHDIVIDER;
+ }
+ }
+}
+
+
+#ifdef RARDLL
+bool CmdExtract::ExtrDllGetPassword(CommandData *Cmd)
+{
+ if (!Cmd->Password.IsSet())
+ {
+ if (Cmd->Callback!=NULL)
+ {
+ wchar PasswordW[MAXPASSWORD];
+ *PasswordW=0;
+ if (Cmd->Callback(UCM_NEEDPASSWORDW,Cmd->UserData,(LPARAM)PasswordW,ASIZE(PasswordW))==-1)
+ *PasswordW=0;
+ if (*PasswordW==0)
+ {
+ char PasswordA[MAXPASSWORD];
+ *PasswordA=0;
+ if (Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1)
+ *PasswordA=0;
+ GetWideName(PasswordA,NULL,PasswordW,ASIZE(PasswordW));
+ cleandata(PasswordA,sizeof(PasswordA));
+ }
+ Cmd->Password.Set(PasswordW);
+ cleandata(PasswordW,sizeof(PasswordW));
+ }
+ if (!Cmd->Password.IsSet())
+ return false;
+ }
+ Password=Cmd->Password;
+ return true;
+}
+#endif
+
+
+#ifndef RARDLL
+bool CmdExtract::ExtrGetPassword(CommandData *Cmd,Archive &Arc,const wchar *ArcFileName)
+{
+ if (!Password.IsSet())
+ {
+ if (!GetPassword(PASSWORD_FILE,ArcFileName,&Password))
+ {
+ return false;
+ }
+ }
+#if !defined(GUI) && !defined(SILENT)
+ else
+ if (!PasswordAll && !Arc.FileHead.Solid)
+ {
+ eprintf(St(MUseCurPsw),ArcFileName);
+ switch(Cmd->AllYes ? 1:Ask(St(MYesNoAll)))
+ {
+ case -1:
+ ErrHandler.Exit(RARX_USERBREAK);
+ case 2:
+ if (!GetPassword(PASSWORD_FILE,ArcFileName,&Password))
+ return false;
+ break;
+ case 3:
+ PasswordAll=true;
+ break;
+ }
+ }
+#endif
+ return true;
+}
+#endif
+
+
+#if defined(_WIN_ALL) && !defined(SFX_MODULE)
+void CmdExtract::ConvertDosPassword(Archive &Arc,SecPassword &DestPwd)
+{
+ if (Arc.Format==RARFMT15 && Arc.FileHead.HostOS==HOST_MSDOS)
+ {
+ // We need the password in OEM encoding if file was encrypted by
+ // native RAR/DOS (not extender based). Let's make the conversion.
+ wchar PlainPsw[MAXPASSWORD];
+ Password.Get(PlainPsw,ASIZE(PlainPsw));
+ char PswA[MAXPASSWORD];
+ CharToOemBuffW(PlainPsw,PswA,ASIZE(PswA));
+ PswA[ASIZE(PswA)-1]=0;
+ CharToWide(PswA,PlainPsw,ASIZE(PlainPsw));
+ DestPwd.Set(PlainPsw);
+ cleandata(PlainPsw,sizeof(PlainPsw));
+ cleandata(PswA,sizeof(PswA));
+ }
+}
+#endif
+
+
+void CmdExtract::ExtrCreateDir(CommandData *Cmd,Archive &Arc,const wchar *ArcFileName)
+{
+ if (Cmd->Test)
+ {
+#ifndef GUI
+ mprintf(St(MExtrTestFile),ArcFileName);
+ mprintf(L" %s",St(MOk));
+#endif
+ return;
+ }
+
+ MKDIR_CODE MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr);
+ bool DirExist=false;
+ if (MDCode!=MKDIR_SUCCESS)
+ {
+ DirExist=FileExist(DestFileName);
+ if (DirExist && !IsDir(GetFileAttr(DestFileName)))
+ {
+ // File with name same as this directory exists. Propose user
+ // to overwrite it.
+ bool UserReject;
+ FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),Cmd->Overwrite,&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime);
+ DirExist=false;
+ }
+ if (!DirExist)
+ {
+ CreatePath(DestFileName,true);
+ MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr);
+ }
+ }
+ if (MDCode==MKDIR_SUCCESS)
+ {
+#ifndef GUI
+ mprintf(St(MCreatDir),DestFileName);
+ mprintf(L" %s",St(MOk));
+#endif
+ PrevExtracted=true;
+ }
+ else
+ if (DirExist)
+ {
+ if (!Cmd->IgnoreGeneralAttr)
+ SetFileAttr(DestFileName,Arc.FileHead.FileAttr);
+ PrevExtracted=true;
+ }
+ else
+ {
+ Log(Arc.FileName,St(MExtrErrMkDir),DestFileName);
+ ErrHandler.CheckLongPathErrMsg(DestFileName);
+ ErrHandler.SysErrMsg();
+#ifdef RARDLL
+ Cmd->DllError=ERAR_ECREATE;
+#endif
+ ErrHandler.SetErrorCode(RARX_CREATE);
+ }
+ if (PrevExtracted)
+ {
+#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
+ if (Cmd->SetCompressedAttr &&
+ (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT())
+ SetFileCompression(DestFileName,true);
+#endif
+ SetDirTime(DestFileName,
+ Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime,
+ Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime,
+ Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
+ }
+}
+
+
+bool CmdExtract::ExtrCreateFile(CommandData *Cmd,Archive &Arc,File &CurFile)
+{
+ bool Success=true;
+ wchar Command=Cmd->Command[0];
+#if !defined(GUI) && !defined(SFX_MODULE)
+ if (Command=='P')
+ CurFile.SetHandleType(FILE_HANDLESTD);
+#endif
+ if ((Command=='E' || Command=='X') && !Cmd->Test)
+ {
+ bool UserReject;
+ // Specify "write only" mode to avoid OpenIndiana NAS problems
+ // with SetFileTime and read+write files.
+ if (!FileCreate(Cmd,&CurFile,DestFileName,ASIZE(DestFileName),Cmd->Overwrite,&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,true))
+ {
+ Success=false;
+ if (!UserReject)
+ {
+ ErrHandler.CreateErrorMsg(Arc.FileName,DestFileName);
+ ErrHandler.SetErrorCode(RARX_CREATE);
+#ifdef RARDLL
+ Cmd->DllError=ERAR_ECREATE;
+#endif
+ if (!IsNameUsable(DestFileName))
+ {
+ Log(Arc.FileName,St(MCorrectingName));
+ wchar OrigName[ASIZE(DestFileName)];
+ wcsncpyz(OrigName,DestFileName,ASIZE(OrigName));
+
+ MakeNameUsable(DestFileName,true);
+
+ CreatePath(DestFileName,true);
+ if (FileCreate(Cmd,&CurFile,DestFileName,ASIZE(DestFileName),Cmd->Overwrite,&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,true))
+ {
+#ifndef SFX_MODULE
+ Log(Arc.FileName,St(MRenaming),OrigName,DestFileName);
+#endif
+ Success=true;
+ }
+ else
+ ErrHandler.CreateErrorMsg(Arc.FileName,DestFileName);
+ }
+ }
+ }
+ }
+ return Success;
+}
+
+
+bool CmdExtract::CheckUnpVer(Archive &Arc,const wchar *ArcFileName)
+{
+ bool WrongVer;
+ if (Arc.Format==RARFMT50) // Both SFX and RAR can unpack RAR 5.0 archives.
+ WrongVer=Arc.FileHead.UnpVer>VER_UNPACK5;
+ else
+ {
+#ifdef SFX_MODULE // SFX can unpack only RAR 2.9 archives.
+ WrongVer=Arc.FileHead.UnpVer!=VER_UNPACK;
+#else // All formats since 1.3 for RAR.
+ WrongVer=Arc.FileHead.UnpVer<13 || Arc.FileHead.UnpVer>VER_UNPACK;
+#endif
+ }
+
+ // We can unpack stored files regardless of compression version field.
+ if (Arc.FileHead.Method==0)
+ WrongVer=false;
+
+ if (WrongVer)
+ {
+#ifndef SILENT
+ Log(Arc.FileName,St(MUnknownMeth),ArcFileName);
+#ifndef SFX_MODULE
+// Log(Arc.FileName,St(MVerRequired),Arc.FileHead.UnpVer/10,Arc.FileHead.UnpVer%10);
+ Log(Arc.FileName,St(MNewerRAR));
+#endif
+#endif
+ }
+ return !WrongVer;
+}
diff --git a/src/thirdparty/unrar/extract.hpp b/src/thirdparty/unrar/extract.hpp
index 0995e8eda..11eb2e498 100644
--- a/src/thirdparty/unrar/extract.hpp
+++ b/src/thirdparty/unrar/extract.hpp
@@ -7,6 +7,20 @@ class CmdExtract
{
private:
EXTRACT_ARC_CODE ExtractArchive(CommandData *Cmd);
+ bool ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize);
+ void ExtrPrepareName(CommandData *Cmd,Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize);
+#ifdef RARDLL
+ bool ExtrDllGetPassword(CommandData *Cmd);
+#else
+ bool ExtrGetPassword(CommandData *Cmd,Archive &Arc,const wchar *ArcFileName);
+#endif
+#if defined(_WIN_ALL) && !defined(SFX_MODULE)
+ void ConvertDosPassword(Archive &Arc,SecPassword &DestPwd);
+#endif
+ void ExtrCreateDir(CommandData *Cmd,Archive &Arc,const wchar *ArcFileName);
+ bool ExtrCreateFile(CommandData *Cmd,Archive &Arc,File &CurFile);
+ bool CheckUnpVer(Archive &Arc,const wchar *ArcFileName);
+
RarTime StartTime; // time when extraction started
ComprDataIO DataIO;
@@ -25,25 +39,21 @@ class CmdExtract
// any wrong password hints.
bool AnySolidDataUnpackedWell;
- char ArcName[NM];
- wchar ArcNameW[NM];
+ wchar ArcName[NM];
SecPassword Password;
bool PasswordAll;
bool PrevExtracted;
- char DestFileName[NM];
- wchar DestFileNameW[NM];
+ wchar DestFileName[NM];
bool PasswordCancelled;
public:
- CmdExtract();
+ CmdExtract(CommandData *Cmd);
~CmdExtract();
void DoExtract(CommandData *Cmd);
void ExtractArchiveInit(CommandData *Cmd,Archive &Arc);
bool ExtractCurrentFile(CommandData *Cmd,Archive &Arc,size_t HeaderSize,
bool &Repeat);
static void UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize);
-
- bool SignatureFound;
};
#endif
diff --git a/src/thirdparty/unrar/filcreat.cpp b/src/thirdparty/unrar/filcreat.cpp
index 2bd176f79..62103cd99 100644
--- a/src/thirdparty/unrar/filcreat.cpp
+++ b/src/thirdparty/unrar/filcreat.cpp
@@ -1,17 +1,20 @@
#include "rar.hpp"
-bool FileCreate(RAROptions *Cmd,File *NewFile,char *Name,wchar *NameW,
+// If NewFile==NULL, we delete created file after user confirmation.
+// It is useful we we need to overwrite an existing folder or file,
+// but need user confirmation for that.
+bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
OVERWRITE_MODE Mode,bool *UserReject,int64 FileSize,
- uint FileTime,bool WriteOnly)
+ RarTime *FileTime,bool WriteOnly)
{
if (UserReject!=NULL)
*UserReject=false;
-#if defined(_WIN_ALL) && !defined(_WIN_CE)
+#ifdef _WIN_ALL
bool ShortNameChanged=false;
#endif
- while (FileExist(Name,NameW))
+ while (FileExist(Name))
{
-#if defined(_WIN_ALL) && !defined(_WIN_CE)
+#ifdef _WIN_ALL
if (!ShortNameChanged)
{
// Avoid the infinite loop if UpdateExistingShortName returns
@@ -20,16 +23,8 @@ bool FileCreate(RAROptions *Cmd,File *NewFile,char *Name,wchar *NameW,
// Maybe our long name matches the short name of existing file.
// Let's check if we can change the short name.
- wchar WideName[NM];
- GetWideName(Name,NameW,WideName,ASIZE(WideName));
- if (UpdateExistingShortName(WideName))
- {
- if (Name!=NULL && *Name!=0)
- WideToChar(WideName,Name);
- if (NameW!=NULL && *NameW!=0)
- wcscpy(NameW,WideName);
+ if (UpdateExistingShortName(Name))
continue;
- }
}
// Allow short name check again. It is necessary, because rename and
// autorename below can change the name, so we need to check it again.
@@ -39,13 +34,13 @@ bool FileCreate(RAROptions *Cmd,File *NewFile,char *Name,wchar *NameW,
{
if (UserReject!=NULL)
*UserReject=true;
- return(false);
+ return false;
}
// Must be before Cmd->AllYes check or -y switch would override -or.
if (Mode==OVERWRITE_AUTORENAME)
{
- if (!GetAutoRenamedName(Name,NameW))
+ if (!GetAutoRenamedName(Name,MaxNameSize))
Mode=OVERWRITE_DEFAULT;
continue;
}
@@ -61,9 +56,8 @@ bool FileCreate(RAROptions *Cmd,File *NewFile,char *Name,wchar *NameW,
if (Mode==OVERWRITE_DEFAULT || Mode==OVERWRITE_FORCE_ASK)
{
- char NewName[NM];
- wchar NewNameW[NM];
- *NewNameW=0;
+ wchar NewName[NM];
+ *NewName=0;
eprintf(St(MFileExists),Name);
int Choice=Ask(St(MYesNoAllRenQ));
if (Choice==1)
@@ -72,7 +66,7 @@ bool FileCreate(RAROptions *Cmd,File *NewFile,char *Name,wchar *NameW,
{
if (UserReject!=NULL)
*UserReject=true;
- return(false);
+ return false;
}
if (Choice==3)
{
@@ -84,40 +78,24 @@ bool FileCreate(RAROptions *Cmd,File *NewFile,char *Name,wchar *NameW,
if (UserReject!=NULL)
*UserReject=true;
Cmd->Overwrite=OVERWRITE_NONE;
- return(false);
+ return false;
}
if (Choice==5)
{
#ifndef GUI
mprintf(St(MAskNewName));
-
-#ifdef _WIN_ALL
- File SrcFile;
- SrcFile.SetHandleType(FILE_HANDLESTD);
- int Size=SrcFile.Read(NewName,sizeof(NewName)-1);
- NewName[Size]=0;
- OemToCharA(NewName,NewName);
-#else
- if (fgets(NewName,sizeof(NewName),stdin)==NULL)
+ if (!getwstr(NewName,ASIZE(NewName)))
{
- // Process fgets failure as if user answered 'No'.
+ // Process fwgets failure as if user answered 'No'.
if (UserReject!=NULL)
*UserReject=true;
- return(false);
+ return false;
}
#endif
- RemoveLF(NewName);
-#endif
if (PointToName(NewName)==NewName)
- strcpy(PointToName(Name),NewName);
+ SetName(Name,NewName,MaxNameSize);
else
- strcpy(Name,NewName);
-
- if (NameW!=NULL)
- if (PointToName(NewNameW)==NewNameW)
- wcscpy(PointToName(NameW),NewNameW);
- else
- wcscpy(NameW,NewNameW);
+ wcsncpyz(Name,NewName,MaxNameSize);
continue;
}
if (Choice==6)
@@ -125,79 +103,63 @@ bool FileCreate(RAROptions *Cmd,File *NewFile,char *Name,wchar *NameW,
}
}
uint FileMode=WriteOnly ? FMF_WRITE|FMF_SHAREREAD:FMF_UPDATE|FMF_SHAREREAD;
- if (NewFile!=NULL && NewFile->Create(Name,NameW,FileMode))
- return(true);
- PrepareToDelete(Name,NameW);
- CreatePath(Name,NameW,true);
- return(NewFile!=NULL ? NewFile->Create(Name,NameW,FileMode):DelFile(Name,NameW));
+ if (NewFile!=NULL && NewFile->Create(Name,FileMode))
+ return true;
+ PrepareToDelete(Name);
+ CreatePath(Name,true);
+ return NewFile!=NULL ? NewFile->Create(Name,FileMode):DelFile(Name);
}
-bool GetAutoRenamedName(char *Name,wchar *NameW)
+bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize)
{
- char NewName[NM];
- wchar NewNameW[NM];
-
- if (Name!=NULL && strlen(Name)>ASIZE(NewName)-10 ||
- NameW!=NULL && wcslen(NameW)>ASIZE(NewNameW)-10)
- return(false);
- char *Ext=NULL;
- if (Name!=NULL && *Name!=0)
- {
- Ext=GetExt(Name);
- if (Ext==NULL)
- Ext=Name+strlen(Name);
- }
- wchar *ExtW=NULL;
- if (NameW!=NULL && *NameW!=0)
- {
- ExtW=GetExt(NameW);
- if (ExtW==NULL)
- ExtW=NameW+wcslen(NameW);
- }
+ wchar NewName[NM];
+ if (wcslen(Name)>ASIZE(NewName)-10)
+ return false;
+ wchar *Ext=GetExt(Name);
+ if (Ext==NULL)
+ Ext=Name+wcslen(Name);
*NewName=0;
- *NewNameW=0;
- for (int FileVer=1;;FileVer++)
+ for (uint FileVer=1;;FileVer++)
{
- if (Name!=NULL && *Name!=0)
- sprintf(NewName,"%.*s(%d)%s",int(Ext-Name),Name,FileVer,Ext);
- if (NameW!=NULL && *NameW!=0)
- sprintfw(NewNameW,ASIZE(NewNameW),L"%.*s(%d)%s",int(ExtW-NameW),NameW,FileVer,ExtW);
- if (!FileExist(NewName,NewNameW))
+ swprintf(NewName,ASIZE(NewName),L"%.*ls(%u)%ls",uint(Ext-Name),Name,FileVer,Ext);
+ if (!FileExist(NewName))
{
- if (Name!=NULL && *Name!=0)
- strcpy(Name,NewName);
- if (NameW!=NULL && *NameW!=0)
- wcscpy(NameW,NewNameW);
+ wcsncpyz(Name,NewName,MaxNameSize);
break;
}
if (FileVer>=1000000)
- return(false);
+ return false;
}
- return(true);
+ return true;
}
-#if defined(_WIN_ALL) && !defined(_WIN_CE)
+#ifdef _WIN_ALL
// If we find a file, which short name is equal to 'Name', we try to change
// its short name, while preserving the long name. It helps when unpacking
// an archived file, which long name is equal to short name of already
// existing file. Otherwise we would overwrite the already existing file,
// even though its long name does not match the name of unpacking file.
-bool UpdateExistingShortName(wchar *Name)
+bool UpdateExistingShortName(const wchar *Name)
{
- // 'Name' is the name of file which we want to create. Let's check
- // if file with such name is exist. If it does not, we return.
- FindData fd;
- if (!FindFile::FastFind(NULL,Name,&fd))
- return(false);
+ wchar LongPathName[NM];
+ DWORD Res=GetLongPathName(Name,LongPathName,ASIZE(LongPathName));
+ if (Res==0 || Res>=ASIZE(LongPathName))
+ return false;
+ wchar ShortPathName[NM];
+ Res=GetShortPathName(Name,ShortPathName,ASIZE(ShortPathName));
+ if (Res==0 || Res>=ASIZE(ShortPathName))
+ return false;
+ wchar *LongName=PointToName(LongPathName);
+ wchar *ShortName=PointToName(ShortPathName);
// We continue only if file has a short name, which does not match its
// long name, and this short name is equal to name of file which we need
// to create.
- if (*fd.ShortName==0 || wcsicomp(PointToName(fd.NameW),fd.ShortName)==0 ||
- wcsicomp(PointToName(Name),fd.ShortName)!=0)
- return(false);
+ if (*ShortName==0 || wcsicomp(LongName,ShortName)==0 ||
+ wcsicomp(PointToName(Name),ShortName)!=0)
+ return false;
// Generate the temporary new name for existing file.
wchar NewName[NM];
@@ -209,28 +171,28 @@ bool UpdateExistingShortName(wchar *Name)
wcsncpyz(NewName,Name,ASIZE(NewName));
// Here we set the random name part.
- sprintfw(PointToName(NewName),ASIZE(NewName),L"rtmp%d",I);
+ swprintf(PointToName(NewName),ASIZE(NewName),L"rtmp%d",I);
// If such file is already exist, try next random name.
- if (FileExist(NULL,NewName))
+ if (FileExist(NewName))
*NewName=0;
}
// If we could not generate the name not used by any other file, we return.
if (*NewName==0)
- return(false);
+ return false;
// FastFind returns the name without path, but we need the fully qualified
// name for renaming, so we use the path from file to create and long name
// from existing file.
wchar FullName[NM];
wcsncpyz(FullName,Name,ASIZE(FullName));
- wcscpy(PointToName(FullName),PointToName(fd.NameW));
+ SetName(FullName,LongName,ASIZE(FullName));
// Rename the existing file to randomly generated name. Normally it changes
// the short name too.
- if (!MoveFileW(FullName,NewName))
- return(false);
+ if (!MoveFile(FullName,NewName))
+ return false;
// Now we need to create the temporary empty file with same name as
// short name of our already existing file. We do it to occupy its previous
@@ -238,13 +200,13 @@ bool UpdateExistingShortName(wchar *Name)
// its original long name.
File KeepShortFile;
bool Created=false;
- if (!FileExist(NULL,Name))
- Created=KeepShortFile.Create(NULL,Name);
+ if (!FileExist(Name))
+ Created=KeepShortFile.Create(Name);
// Now we rename the existing file from temporary name to original long name.
// Since its previous short name is occupied by another file, it should
// get another short name.
- MoveFileW(NewName,FullName);
+ MoveFile(NewName,FullName);
if (Created)
{
@@ -255,6 +217,6 @@ bool UpdateExistingShortName(wchar *Name)
// We successfully changed the short name. Maybe sometimes we'll simplify
// this function by use of SetFileShortName Windows API call.
// But SetFileShortName is not available in older Windows.
- return(true);
+ return true;
}
#endif
diff --git a/src/thirdparty/unrar/filcreat.hpp b/src/thirdparty/unrar/filcreat.hpp
index 7e758bfc7..d2084debf 100644
--- a/src/thirdparty/unrar/filcreat.hpp
+++ b/src/thirdparty/unrar/filcreat.hpp
@@ -1,13 +1,14 @@
#ifndef _RAR_FILECREATE_
#define _RAR_FILECREATE_
-bool FileCreate(RAROptions *Cmd,File *NewFile,char *Name,wchar *NameW,
+bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
OVERWRITE_MODE Mode,bool *UserReject,int64 FileSize=INT64NDF,
- uint FileTime=0,bool WriteOnly=false);
-bool GetAutoRenamedName(char *Name,wchar *NameW);
+ RarTime *FileTime=NULL,bool WriteOnly=false);
+
+bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize);
#if defined(_WIN_ALL) && !defined(_WIN_CE)
-bool UpdateExistingShortName(wchar *Name);
+bool UpdateExistingShortName(const wchar *Name);
#endif
#endif
diff --git a/src/thirdparty/unrar/file.cpp b/src/thirdparty/unrar/file.cpp
index dcf4e612a..c67692c99 100644
--- a/src/thirdparty/unrar/file.cpp
+++ b/src/thirdparty/unrar/file.cpp
@@ -1,13 +1,9 @@
#include "rar.hpp"
-static File *CreatedFiles[256];
-static int RemoveCreatedActive=0;
-
File::File()
{
hFile=BAD_HANDLE;
*FileName=0;
- *FileNameW=0;
NewFile=false;
LastWrite=false;
HandleType=FILE_HANDLENORMAL;
@@ -16,7 +12,6 @@ File::File()
ErrorType=FILE_SUCCESS;
OpenShared=false;
AllowDelete=true;
- CloseCount=0;
AllowExceptions=true;
#ifdef _WIN_ALL
NoSequentialRead=false;
@@ -38,7 +33,6 @@ File::~File()
void File::operator = (File &SrcFile)
{
hFile=SrcFile.hFile;
- strcpy(FileName,SrcFile.FileName);
NewFile=SrcFile.NewFile;
LastWrite=SrcFile.LastWrite;
HandleType=SrcFile.HandleType;
@@ -46,7 +40,7 @@ void File::operator = (File &SrcFile)
}
-bool File::Open(const char *Name,const wchar *NameW,uint Mode)
+bool File::Open(const wchar *Name,uint Mode)
{
ErrorType=FILE_SUCCESS;
FileHandle hNewFile;
@@ -61,10 +55,14 @@ bool File::Open(const char *Name,const wchar *NameW,uint Mode)
if (OpenShared)
ShareMode|=FILE_SHARE_WRITE;
uint Flags=NoSequentialRead ? 0:FILE_FLAG_SEQUENTIAL_SCAN;
- if (WinNT() && NameW!=NULL && *NameW!=0)
- hNewFile=CreateFileW(NameW,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
- else
- hNewFile=CreateFileA(Name,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
+ hNewFile=CreateFile(Name,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
+
+ if (hNewFile==BAD_HANDLE)
+ {
+ wchar LongName[NM];
+ if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
+ hNewFile=CreateFile(LongName,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
+ }
if (hNewFile==BAD_HANDLE && GetLastError()==ERROR_FILE_NOT_FOUND)
ErrorType=FILE_NOTFOUND;
@@ -76,11 +74,10 @@ bool File::Open(const char *Name,const wchar *NameW,uint Mode)
flags|=O_LARGEFILE;
#endif
#endif
-#if defined(_EMX) && !defined(_DJGPP)
- int sflags=OpenShared ? SH_DENYNO:SH_DENYWR;
- int handle=sopen(Name,flags,sflags);
-#else
- int handle=open(Name,flags);
+ char NameA[NM];
+ WideToChar(Name,NameA,ASIZE(NameA));
+
+ int handle=open(NameA,flags);
#ifdef LOCK_EX
#ifdef _OSF_SOURCE
@@ -90,10 +87,9 @@ bool File::Open(const char *Name,const wchar *NameW,uint Mode)
if (!OpenShared && UpdateMode && handle>=0 && flock(handle,LOCK_EX|LOCK_NB)==-1)
{
close(handle);
- return(false);
+ return false;
}
#endif
-#endif
hNewFile=handle==-1 ? BAD_HANDLE:fdopen(handle,UpdateMode ? UPDATEBINARY:READBINARY);
if (hNewFile==BAD_HANDLE && errno==ENOENT)
ErrorType=FILE_NOTFOUND;
@@ -105,44 +101,31 @@ bool File::Open(const char *Name,const wchar *NameW,uint Mode)
if (Success)
{
hFile=hNewFile;
-
- // We use memove instead of strcpy and wcscpy to avoid problems
- // with overlapped buffers. While we do not call this function with
- // really overlapped buffers yet, we do call it with Name equal to
- // FileName like Arc.Open(Arc.FileName,Arc.FileNameW,...).
- if (NameW!=NULL)
- memmove(FileNameW,NameW,(wcslen(NameW)+1)*sizeof(*NameW));
- else
- *FileNameW=0;
- if (Name!=NULL)
- memmove(FileName,Name,strlen(Name)+1);
- else
- WideToChar(NameW,FileName);
- AddFileToList(hFile);
+ wcsncpyz(FileName,Name,ASIZE(FileName));
}
- return(Success);
+ return Success;
}
#if !defined(SHELL_EXT) && !defined(SFX_MODULE)
-void File::TOpen(const char *Name,const wchar *NameW)
+void File::TOpen(const wchar *Name)
{
- if (!WOpen(Name,NameW))
+ if (!WOpen(Name))
ErrHandler.Exit(RARX_OPEN);
}
#endif
-bool File::WOpen(const char *Name,const wchar *NameW)
+bool File::WOpen(const wchar *Name)
{
- if (Open(Name,NameW))
- return(true);
- ErrHandler.OpenErrorMsg(Name,NameW);
- return(false);
+ if (Open(Name))
+ return true;
+ ErrHandler.OpenErrorMsg(Name);
+ return false;
}
-bool File::Create(const char *Name,const wchar *NameW,uint Mode)
+bool File::Create(const wchar *Name,uint Mode)
{
// OpenIndiana based NAS and CIFS shares fail to set the file time if file
// was created in read+write mode and some data was written and not flushed
@@ -154,57 +137,44 @@ bool File::Create(const char *Name,const wchar *NameW,uint Mode)
CreateMode=Mode;
uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ|GENERIC_WRITE;
DWORD ShareMode=ShareRead ? FILE_SHARE_READ:0;
- if (WinNT() && NameW!=NULL && *NameW!=0)
- hFile=CreateFileW(NameW,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
- else
- hFile=CreateFileA(Name,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
+ hFile=CreateFile(Name,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
+
+ if (hFile==BAD_HANDLE)
+ {
+ wchar LongName[NM];
+ if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
+ hFile=CreateFile(LongName,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
+ }
+
#else
- hFile=fopen(Name,WriteMode ? WRITEBINARY:CREATEBINARY);
+ char NameA[NM];
+ WideToChar(Name,NameA,ASIZE(NameA));
+ hFile=fopen(NameA,WriteMode ? WRITEBINARY:CREATEBINARY);
#endif
NewFile=true;
HandleType=FILE_HANDLENORMAL;
SkipClose=false;
- if (NameW!=NULL)
- wcscpy(FileNameW,NameW);
- else
- *FileNameW=0;
- if (Name!=NULL)
- strcpy(FileName,Name);
- else
- WideToChar(NameW,FileName);
- AddFileToList(hFile);
- return(hFile!=BAD_HANDLE);
-}
-
-
-void File::AddFileToList(FileHandle hFile)
-{
- if (hFile!=BAD_HANDLE)
- for (int I=0;I<sizeof(CreatedFiles)/sizeof(CreatedFiles[0]);I++)
- if (CreatedFiles[I]==NULL)
- {
- CreatedFiles[I]=this;
- break;
- }
+ wcsncpyz(FileName,Name,ASIZE(FileName));
+ return hFile!=BAD_HANDLE;
}
#if !defined(SHELL_EXT) && !defined(SFX_MODULE)
-void File::TCreate(const char *Name,const wchar *NameW,uint Mode)
+void File::TCreate(const wchar *Name,uint Mode)
{
- if (!WCreate(Name,NameW,Mode))
+ if (!WCreate(Name,Mode))
ErrHandler.Exit(RARX_FATAL);
}
#endif
-bool File::WCreate(const char *Name,const wchar *NameW,uint Mode)
+bool File::WCreate(const wchar *Name,uint Mode)
{
- if (Create(Name,NameW,Mode))
- return(true);
+ if (Create(Name,Mode))
+ return true;
ErrHandler.SetErrorCode(RARX_CREATE);
- ErrHandler.CreateErrorMsg(Name,NameW);
- return(false);
+ ErrHandler.CreateErrorMsg(Name);
+ return false;
}
@@ -223,20 +193,12 @@ bool File::Close()
#else
Success=fclose(hFile)!=EOF;
#endif
- if (Success || !RemoveCreatedActive)
- for (int I=0;I<sizeof(CreatedFiles)/sizeof(CreatedFiles[0]);I++)
- if (CreatedFiles[I]==this)
- {
- CreatedFiles[I]=NULL;
- break;
- }
}
hFile=BAD_HANDLE;
if (!Success && AllowExceptions)
- ErrHandler.CloseError(FileName,FileNameW);
+ ErrHandler.CloseError(FileName);
}
- CloseCount++;
- return(Success);
+ return Success;
}
@@ -253,32 +215,27 @@ void File::Flush()
bool File::Delete()
{
if (HandleType!=FILE_HANDLENORMAL)
- return(false);
+ return false;
if (hFile!=BAD_HANDLE)
Close();
if (!AllowDelete)
- return(false);
- return(DelFile(FileName,FileNameW));
+ return false;
+ return DelFile(FileName);
}
-bool File::Rename(const char *NewName,const wchar *NewNameW)
+bool File::Rename(const wchar *NewName)
{
- // we do not need to rename if names are already same
- bool Success=strcmp(FileName,NewName)==0;
- if (Success && *FileNameW!=0 && *NullToEmpty(NewNameW)!=0)
- Success=wcscmp(FileNameW,NewNameW)==0;
+ // No need to rename if names are already same.
+ bool Success=wcscmp(FileName,NewName)==0;
if (!Success)
- Success=RenameFile(FileName,FileNameW,NewName,NewNameW);
+ Success=RenameFile(FileName,NewName);
if (Success)
- {
- // renamed successfully, storing the new name
- strcpy(FileName,NewName);
- wcscpy(FileNameW,NullToEmpty(NewNameW));
- }
- return(Success);
+ wcscpy(FileName,NewName);
+
+ return Success;
}
@@ -336,9 +293,9 @@ void File::Write(const void *Data,size_t Size)
uint64 FreeSize=GetFreeDisk(FileName);
SetLastError(ErrCode);
if (FreeSize>Size && FilePos-Size<=0xffffffff && FilePos+Size>0xffffffff)
- ErrHandler.WriteErrorFAT(FileName,FileNameW);
+ ErrHandler.WriteErrorFAT(FileName);
#endif
- if (ErrHandler.AskRepeatWrite(FileName,FileNameW,false))
+ if (ErrHandler.AskRepeatWrite(FileName,false))
{
#ifndef _WIN_ALL
clearerr(hFile);
@@ -347,7 +304,7 @@ void File::Write(const void *Data,size_t Size)
Seek(Tell()-Written,SEEK_SET);
continue;
}
- ErrHandler.WriteError(NULL,NULL,FileName,FileNameW);
+ ErrHandler.WriteError(NULL,FileName);
}
break;
}
@@ -382,14 +339,14 @@ int File::Read(void *Data,size_t Size)
}
else
{
- if (HandleType==FILE_HANDLENORMAL && ErrHandler.AskRepeatRead(FileName,FileNameW))
+ if (HandleType==FILE_HANDLENORMAL && ErrHandler.AskRepeatRead(FileName))
continue;
- ErrHandler.ReadError(FileName,FileNameW);
+ ErrHandler.ReadError(FileName);
}
}
break;
}
- return(ReadSize);
+ return ReadSize;
}
@@ -398,6 +355,7 @@ int File::DirectRead(void *Data,size_t Size)
{
#ifdef _WIN_ALL
const size_t MaxDeviceRead=20000;
+ const size_t MaxLockedRead=32768;
#endif
#ifndef _WIN_CE
if (HandleType==FILE_HANDLESTD)
@@ -416,12 +374,23 @@ int File::DirectRead(void *Data,size_t Size)
if (!ReadFile(hFile,Data,(DWORD)Size,&Read,NULL))
{
if (IsDevice() && Size>MaxDeviceRead)
- return(DirectRead(Data,MaxDeviceRead));
+ return DirectRead(Data,MaxDeviceRead);
if (HandleType==FILE_HANDLESTD && GetLastError()==ERROR_BROKEN_PIPE)
- return(0);
- return(-1);
+ return 0;
+
+ // We had a bug report about failure to archive 1C database lock file
+ // 1Cv8tmp.1CL, which is a zero length file with a region above 200 KB
+ // permanently locked. If our first read request uses too large buffer
+ // and if we are in -dh mode, so we were able to open the file,
+ // we'll fail with "Read error". So now we use try a smaller buffer size
+ // in case of lock error.
+ if (HandleType==FILE_HANDLENORMAL && Size>MaxLockedRead &&
+ GetLastError()==ERROR_LOCK_VIOLATION)
+ return DirectRead(Data,MaxLockedRead);
+
+ return -1;
}
- return(Read);
+ return Read;
#else
if (LastWrite)
{
@@ -431,8 +400,8 @@ int File::DirectRead(void *Data,size_t Size)
clearerr(hFile);
size_t ReadSize=fread(Data,1,Size,hFile);
if (ferror(hFile))
- return(-1);
- return((int)ReadSize);
+ return -1;
+ return (int)ReadSize;
#endif
}
@@ -440,14 +409,14 @@ int File::DirectRead(void *Data,size_t Size)
void File::Seek(int64 Offset,int Method)
{
if (!RawSeek(Offset,Method) && AllowExceptions)
- ErrHandler.SeekError(FileName,FileNameW);
+ ErrHandler.SeekError(FileName);
}
bool File::RawSeek(int64 Offset,int Method)
{
if (hFile==BAD_HANDLE)
- return(true);
+ return true;
if (Offset<0 && Method!=SEEK_SET)
{
Offset=(Method==SEEK_CUR ? Tell():FileLength())+Offset;
@@ -457,7 +426,7 @@ bool File::RawSeek(int64 Offset,int Method)
LONG HighDist=(LONG)(Offset>>32);
if (SetFilePointer(hFile,(LONG)Offset,&HighDist,Method)==0xffffffff &&
GetLastError()!=NO_ERROR)
- return(false);
+ return false;
#else
LastWrite=false;
#if defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE) && !defined(__VMS)
@@ -465,9 +434,9 @@ bool File::RawSeek(int64 Offset,int Method)
#else
if (fseek(hFile,(long)Offset,Method)!=0)
#endif
- return(false);
+ return false;
#endif
- return(true);
+ return true;
}
@@ -475,23 +444,23 @@ int64 File::Tell()
{
if (hFile==BAD_HANDLE)
if (AllowExceptions)
- ErrHandler.SeekError(FileName,FileNameW);
+ ErrHandler.SeekError(FileName);
else
- return(-1);
+ return -1;
#ifdef _WIN_ALL
LONG HighDist=0;
uint LowDist=SetFilePointer(hFile,0,&HighDist,FILE_CURRENT);
if (LowDist==0xffffffff && GetLastError()!=NO_ERROR)
if (AllowExceptions)
- ErrHandler.SeekError(FileName,FileNameW);
+ ErrHandler.SeekError(FileName);
else
- return(-1);
- return(INT32TO64(HighDist,LowDist));
+ return -1;
+ return INT32TO64(HighDist,LowDist);
#else
#if defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE)
- return(ftello(hFile));
+ return ftello(hFile);
#else
- return(ftell(hFile));
+ return ftell(hFile);
#endif
#endif
}
@@ -521,7 +490,7 @@ byte File::GetByte()
{
byte Byte=0;
Read(&Byte,1);
- return(Byte);
+ return Byte;
}
@@ -534,9 +503,9 @@ void File::PutByte(byte Byte)
bool File::Truncate()
{
#ifdef _WIN_ALL
- return(SetEndOfFile(hFile)==TRUE);
+ return SetEndOfFile(hFile)==TRUE;
#else
- return(false);
+ return false;
#endif
}
@@ -567,15 +536,15 @@ void File::SetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta)
void File::SetCloseFileTime(RarTime *ftm,RarTime *fta)
{
-#if defined(_UNIX) || defined(_EMX)
+#ifdef _UNIX
SetCloseFileTimeByName(FileName,ftm,fta);
#endif
}
-void File::SetCloseFileTimeByName(const char *Name,RarTime *ftm,RarTime *fta)
+void File::SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta)
{
-#if defined(_UNIX) || defined(_EMX)
+#ifdef _UNIX
bool setm=ftm!=NULL && ftm->IsSet();
bool seta=fta!=NULL && fta->IsSet();
if (setm || seta)
@@ -589,7 +558,9 @@ void File::SetCloseFileTimeByName(const char *Name,RarTime *ftm,RarTime *fta)
ut.actime=fta->GetUnix();
else
ut.actime=ut.modtime;
- utime(Name,&ut);
+ char NameA[NM];
+ WideToChar(Name,NameA,ASIZE(NameA));
+ utime(NameA,&ut);
}
#endif
}
@@ -614,79 +585,24 @@ int64 File::FileLength()
{
SaveFilePos SavePos(*this);
Seek(0,SEEK_END);
- return(Tell());
-}
-
-
-void File::SetHandleType(FILE_HANDLETYPE Type)
-{
- HandleType=Type;
+ return Tell();
}
bool File::IsDevice()
{
if (hFile==BAD_HANDLE)
- return(false);
+ return false;
#ifdef _WIN_ALL
uint Type=GetFileType(hFile);
- return(Type==FILE_TYPE_CHAR || Type==FILE_TYPE_PIPE);
+ return Type==FILE_TYPE_CHAR || Type==FILE_TYPE_PIPE;
#else
- return(isatty(fileno(hFile)));
+ return isatty(fileno(hFile));
#endif
}
#ifndef SFX_MODULE
-void File::fprintf(const char *fmt,...)
-{
- va_list argptr;
- va_start(argptr,fmt);
- safebuf char Msg[2*NM+1024],OutMsg[2*NM+1024];
- vsprintf(Msg,fmt,argptr);
-#ifdef _WIN_ALL
- for (int Src=0,Dest=0;;Src++)
- {
- char CurChar=Msg[Src];
- if (CurChar=='\n')
- OutMsg[Dest++]='\r';
- OutMsg[Dest++]=CurChar;
- if (CurChar==0)
- break;
- }
-#else
- strcpy(OutMsg,Msg);
-#endif
- Write(OutMsg,strlen(OutMsg));
- va_end(argptr);
-}
-#endif
-
-
-bool File::RemoveCreated()
-{
- RemoveCreatedActive++;
- bool RetCode=true;
- for (int I=0;I<sizeof(CreatedFiles)/sizeof(CreatedFiles[0]);I++)
- if (CreatedFiles[I]!=NULL)
- {
- CreatedFiles[I]->SetExceptions(false);
- bool Success;
- if (CreatedFiles[I]->NewFile)
- Success=CreatedFiles[I]->Delete();
- else
- Success=CreatedFiles[I]->Close();
- if (Success)
- CreatedFiles[I]=NULL;
- else
- RetCode=false;
- }
- RemoveCreatedActive--;
- return(RetCode);
-}
-
-
-#ifndef SFX_MODULE
int64 File::Copy(File &Dest,int64 Length)
{
Array<char> Buffer(0x10000);
@@ -705,6 +621,6 @@ int64 File::Copy(File &Dest,int64 Length)
if (!CopyAll)
Length-=ReadSize;
}
- return(CopySize);
+ return CopySize;
}
#endif
diff --git a/src/thirdparty/unrar/file.hpp b/src/thirdparty/unrar/file.hpp
index 666b5196e..c50295edd 100644
--- a/src/thirdparty/unrar/file.hpp
+++ b/src/thirdparty/unrar/file.hpp
@@ -15,15 +15,6 @@ enum FILE_HANDLETYPE {FILE_HANDLENORMAL,FILE_HANDLESTD,FILE_HANDLEERR};
enum FILE_ERRORTYPE {FILE_SUCCESS,FILE_NOTFOUND,FILE_READERROR};
-struct FileStat
-{
- uint FileAttr;
- uint FileTime;
- int64 FileSize;
- bool IsDir;
-};
-
-
enum FILE_MODE_FLAGS {
// Request read only access to file. Default for Open.
FMF_READ=0,
@@ -48,8 +39,6 @@ enum FILE_MODE_FLAGS {
class File
{
private:
- void AddFileToList(FileHandle hFile);
-
FileHandle hFile;
bool LastWrite;
FILE_HANDLETYPE HandleType;
@@ -65,50 +54,46 @@ class File
protected:
bool OpenShared; // Set by 'Archive' class.
public:
- char FileName[NM];
- wchar FileNameW[NM];
+ wchar FileName[NM];
FILE_ERRORTYPE ErrorType;
-
- uint CloseCount;
public:
File();
virtual ~File();
void operator = (File &SrcFile);
- bool Open(const char *Name,const wchar *NameW=NULL,uint Mode=FMF_READ);
- void TOpen(const char *Name,const wchar *NameW=NULL);
- bool WOpen(const char *Name,const wchar *NameW=NULL);
- bool Create(const char *Name,const wchar *NameW=NULL,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
- void TCreate(const char *Name,const wchar *NameW=NULL,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
- bool WCreate(const char *Name,const wchar *NameW=NULL,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
+ bool Open(const wchar *Name,uint Mode=FMF_READ);
+ void TOpen(const wchar *Name);
+ bool WOpen(const wchar *Name);
+ bool Create(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
+ void TCreate(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
+ bool WCreate(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
bool Close();
void Flush();
bool Delete();
- bool Rename(const char *NewName,const wchar *NewNameW=NULL);
+ bool Rename(const wchar *NewName);
void Write(const void *Data,size_t Size);
- int Read(void *Data,size_t Size);
+ virtual int Read(void *Data,size_t Size);
int DirectRead(void *Data,size_t Size);
- void Seek(int64 Offset,int Method);
+ virtual void Seek(int64 Offset,int Method);
bool RawSeek(int64 Offset,int Method);
- int64 Tell();
+ virtual int64 Tell();
void Prealloc(int64 Size);
byte GetByte();
void PutByte(byte Byte);
bool Truncate();
void SetOpenFileTime(RarTime *ftm,RarTime *ftc=NULL,RarTime *fta=NULL);
void SetCloseFileTime(RarTime *ftm,RarTime *fta=NULL);
- static void SetCloseFileTimeByName(const char *Name,RarTime *ftm,RarTime *fta);
+ static void SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta);
void GetOpenFileTime(RarTime *ft);
bool IsOpened() {return(hFile!=BAD_HANDLE);};
int64 FileLength();
- void SetHandleType(FILE_HANDLETYPE Type);
- FILE_HANDLETYPE GetHandleType() {return(HandleType);};
+ void SetHandleType(FILE_HANDLETYPE Type) {HandleType=Type;}
+ FILE_HANDLETYPE GetHandleType() {return HandleType;}
bool IsDevice();
- void fprintf(const char *fmt,...);
static bool RemoveCreated();
- FileHandle GetHandle() {return(hFile);};
- void SetIgnoreReadErrors(bool Mode) {IgnoreReadErrors=Mode;};
- char *GetName() {return(FileName);}
+ FileHandle GetHandle() {return hFile;}
+ void SetHandle(FileHandle Handle) {Close();hFile=Handle;}
+ void SetIgnoreReadErrors(bool Mode) {IgnoreReadErrors=Mode;}
int64 Copy(File &Dest,int64 Length=INT64NDF);
void SetAllowDelete(bool Allow) {AllowDelete=Allow;}
void SetExceptions(bool Allow) {AllowExceptions=Allow;}
diff --git a/src/thirdparty/unrar/filefn.cpp b/src/thirdparty/unrar/filefn.cpp
index e7cc8fd6b..d09f50af5 100644
--- a/src/thirdparty/unrar/filefn.cpp
+++ b/src/thirdparty/unrar/filefn.cpp
@@ -1,106 +1,43 @@
#include "rar.hpp"
-MKDIR_CODE MakeDir(const char *Name,const wchar *NameW,bool SetAttr,uint Attr)
+MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr)
{
#ifdef _WIN_ALL
- BOOL RetCode;
- if (WinNT() && NameW!=NULL && *NameW!=0)
- RetCode=CreateDirectoryW(NameW,NULL);
- else
- if (Name!=NULL)
- RetCode=CreateDirectoryA(Name,NULL);
- else
- return(MKDIR_BADPATH);
+ BOOL RetCode=CreateDirectory(Name,NULL);
+ if (RetCode==0)
+ {
+ wchar LongName[NM];
+ if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
+ RetCode=CreateDirectory(LongName,NULL);
+ }
if (RetCode!=0) // Non-zero return code means success for CreateDirectory.
{
if (SetAttr)
- SetFileAttr(Name,NameW,Attr);
- return(MKDIR_SUCCESS);
+ SetFileAttr(Name,Attr);
+ return MKDIR_SUCCESS;
}
int ErrCode=GetLastError();
if (ErrCode==ERROR_FILE_NOT_FOUND || ErrCode==ERROR_PATH_NOT_FOUND)
- return(MKDIR_BADPATH);
- return(MKDIR_ERROR);
-#else
-
- // No Unicode in the rest of function, so Name must be not NULL.
- if (Name==NULL)
- return(MKDIR_BADPATH);
-#endif
-
-#ifdef _EMX
- #ifdef _DJGPP
- if (mkdir(Name,(Attr & FA_RDONLY) ? 0:S_IWUSR)==0)
- #else
- if (__mkdir(Name)==0)
- #endif
- {
- if (SetAttr)
- SetFileAttr(Name,NameW,Attr);
- return(MKDIR_SUCCESS);
- }
- return(errno==ENOENT ? MKDIR_BADPATH:MKDIR_ERROR);
-#endif
-
-#ifdef _UNIX
+ return MKDIR_BADPATH;
+ return MKDIR_ERROR;
+#elif defined(_UNIX)
+ char NameA[NM];
+ WideToChar(Name,NameA,ASIZE(NameA));
mode_t uattr=SetAttr ? (mode_t)Attr:0777;
- int ErrCode=mkdir(Name,uattr);
+ int ErrCode=mkdir(NameA,uattr);
if (ErrCode==-1)
- return(errno==ENOENT ? MKDIR_BADPATH:MKDIR_ERROR);
- return(MKDIR_SUCCESS);
-#endif
-}
-
-
-bool CreatePath(const char *Path,bool SkipLastName)
-{
- if (Path==NULL || *Path==0)
- return(false);
-
-#if defined(_WIN_ALL) || defined(_EMX)
- uint DirAttr=0;
+ return errno==ENOENT ? MKDIR_BADPATH:MKDIR_ERROR;
+ return MKDIR_SUCCESS;
#else
- uint DirAttr=0777;
+ return MKDIR_ERROR;
#endif
-
- bool Success=true;
-
- for (const char *s=Path;*s!=0;s=charnext(s))
- {
- if (s-Path>=NM)
- break;
-
- // Process all kinds of path separators, so user can enter Unix style
- // path in Windows or Windows in Unix.
- if (IsPathDiv(*s))
- {
- char DirName[NM];
- strncpy(DirName,Path,s-Path);
- DirName[s-Path]=0;
-
- if (MakeDir(DirName,NULL,true,DirAttr)==MKDIR_SUCCESS)
- {
-#ifndef GUI
- mprintf(St(MCreatDir),DirName);
- mprintf(" %s",St(MOk));
-#endif
- }
- else
- Success=false;
- }
- }
- if (!SkipLastName)
- if (!IsPathDiv(*PointToLastChar(Path)))
- if (MakeDir(Path,NULL,true,DirAttr)!=MKDIR_SUCCESS)
- Success=false;
- return(Success);
}
bool CreatePath(const wchar *Path,bool SkipLastName)
{
if (Path==NULL || *Path==0)
- return(false);
+ return false;
#if defined(_WIN_ALL) || defined(_EMX)
uint DirAttr=0;
@@ -112,73 +49,56 @@ bool CreatePath(const wchar *Path,bool SkipLastName)
for (const wchar *s=Path;*s!=0;s++)
{
- if (s-Path>=NM)
+ wchar DirName[NM];
+ if (s-Path>=ASIZE(DirName))
break;
// Process all kinds of path separators, so user can enter Unix style
// path in Windows or Windows in Unix.
if (IsPathDiv(*s))
{
- wchar DirName[NM];
wcsncpy(DirName,Path,s-Path);
DirName[s-Path]=0;
- if (MakeDir(NULL,DirName,true,DirAttr)==MKDIR_SUCCESS)
- {
+ Success=MakeDir(DirName,true,DirAttr)==MKDIR_SUCCESS;
#ifndef GUI
- char DirNameA[NM];
- WideToChar(DirName,DirNameA,ASIZE(DirNameA));
- DirNameA[ASIZE(DirNameA)-1]=0;
- mprintf(St(MCreatDir),DirNameA);
- mprintf(" %s",St(MOk));
-#endif
+ if (Success)
+ {
+ mprintf(St(MCreatDir),DirName);
+ mprintf(L" %s",St(MOk));
}
- else
- Success=false;
+#endif
}
}
- if (!SkipLastName)
- if (!IsPathDiv(*PointToLastChar(Path)))
- if (MakeDir(NULL,Path,true,DirAttr)!=MKDIR_SUCCESS)
- Success=false;
- return(Success);
+ if (!SkipLastName && !IsPathDiv(*PointToLastChar(Path)))
+ Success=MakeDir(Path,true,DirAttr)==MKDIR_SUCCESS;
+ return Success;
}
-bool CreatePath(const char *Path,const wchar *PathW,bool SkipLastName)
+void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta)
{
#ifdef _WIN_ALL
- // If we are in Windows, let's try Unicode path first. In Unix we do not
- // need it (Unix MakeDir will fails with Unicode only name).
- if (PathW!=NULL && *PathW!=0)
- return(CreatePath(PathW,SkipLastName));
-#endif
- if (Path!=NULL && *Path!=0)
- return(CreatePath(Path,SkipLastName));
- return(false);
-}
-
-
-void SetDirTime(const char *Name,const wchar *NameW,RarTime *ftm,RarTime *ftc,RarTime *fta)
-{
-#ifdef _WIN_ALL
- if (!WinNT())
- return;
-
bool sm=ftm!=NULL && ftm->IsSet();
bool sc=ftc!=NULL && ftc->IsSet();
bool sa=fta!=NULL && fta->IsSet();
- unsigned int DirAttr=GetFileAttr(Name,NameW);
- bool ResetAttr=(DirAttr!=0xffffffff && (DirAttr & FA_RDONLY)!=0);
+ uint DirAttr=GetFileAttr(Name);
+ bool ResetAttr=(DirAttr!=0xffffffff && (DirAttr & FILE_ATTRIBUTE_READONLY)!=0);
if (ResetAttr)
- SetFileAttr(Name,NameW,0);
+ SetFileAttr(Name,0);
- wchar DirNameW[NM];
- GetWideName(Name,NameW,DirNameW,ASIZE(DirNameW));
- HANDLE hFile=CreateFileW(DirNameW,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
+ HANDLE hFile=CreateFile(Name,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
if (hFile==INVALID_HANDLE_VALUE)
+ {
+ wchar LongName[NM];
+ if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
+ hFile=CreateFile(LongName,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL);
+ }
+
+ if (hFile==INVALID_HANDLE_VALUE)
return;
FILETIME fm,fc,fa;
if (sm)
@@ -190,7 +110,7 @@ void SetDirTime(const char *Name,const wchar *NameW,RarTime *ftm,RarTime *ftc,Ra
SetFileTime(hFile,sc ? &fc:NULL,sa ? &fa:NULL,sm ? &fm:NULL);
CloseHandle(hFile);
if (ResetAttr)
- SetFileAttr(Name,NameW,DirAttr);
+ SetFileAttr(Name,DirAttr);
#endif
#if defined(_UNIX) || defined(_EMX)
File::SetCloseFileTimeByName(Name,ftm,fta);
@@ -198,106 +118,45 @@ void SetDirTime(const char *Name,const wchar *NameW,RarTime *ftm,RarTime *ftc,Ra
}
-bool IsRemovable(const char *Name)
+bool IsRemovable(const wchar *Name)
{
#ifdef _WIN_ALL
- char Root[NM];
- GetPathRoot(Name,Root);
- int Type=GetDriveTypeA(*Root!=0 ? Root:NULL);
- return(Type==DRIVE_REMOVABLE || Type==DRIVE_CDROM);
-#elif defined(_EMX)
- char Drive=etoupper(Name[0]);
- return((Drive=='A' || Drive=='B') && Name[1]==':');
+ wchar Root[NM];
+ GetPathRoot(Name,Root,ASIZE(Root));
+ int Type=GetDriveType(*Root!=0 ? Root:NULL);
+ return Type==DRIVE_REMOVABLE || Type==DRIVE_CDROM;
#else
- return(false);
+ return false;
#endif
}
-
-
#ifndef SFX_MODULE
-int64 GetFreeDisk(const char *Name)
+int64 GetFreeDisk(const wchar *Name)
{
#ifdef _WIN_ALL
- char Root[NM];
- GetPathRoot(Name,Root);
-
- typedef BOOL (WINAPI *GETDISKFREESPACEEX)(
- LPCSTR,PULARGE_INTEGER,PULARGE_INTEGER,PULARGE_INTEGER
- );
- static GETDISKFREESPACEEX pGetDiskFreeSpaceEx=NULL;
-
- if (pGetDiskFreeSpaceEx==NULL)
- {
- HMODULE hKernel=GetModuleHandleW(L"kernel32.dll");
- if (hKernel!=NULL)
- pGetDiskFreeSpaceEx=(GETDISKFREESPACEEX)GetProcAddress(hKernel,"GetDiskFreeSpaceExA");
- }
- if (pGetDiskFreeSpaceEx!=NULL)
- {
- GetFilePath(Name,Root,ASIZE(Root));
- ULARGE_INTEGER uiTotalSize,uiTotalFree,uiUserFree;
- uiUserFree.u.LowPart=uiUserFree.u.HighPart=0;
- if (pGetDiskFreeSpaceEx(*Root ? Root:NULL,&uiUserFree,&uiTotalSize,&uiTotalFree) &&
- uiUserFree.u.HighPart<=uiTotalFree.u.HighPart)
- return(INT32TO64(uiUserFree.u.HighPart,uiUserFree.u.LowPart));
- }
-
- // We are here if we failed to load GetDiskFreeSpaceExA.
- DWORD SectorsPerCluster,BytesPerSector,FreeClusters,TotalClusters;
- if (!GetDiskFreeSpaceA(*Root ? Root:NULL,&SectorsPerCluster,&BytesPerSector,&FreeClusters,&TotalClusters))
- return(1457664);
- int64 FreeSize=SectorsPerCluster*BytesPerSector;
- FreeSize=FreeSize*FreeClusters;
- return(FreeSize);
-#elif defined(_BEOS)
- char Root[NM];
+ wchar Root[NM];
GetFilePath(Name,Root,ASIZE(Root));
- dev_t Dev=dev_for_path(*Root ? Root:".");
- if (Dev<0)
- return(1457664);
- fs_info Info;
- if (fs_stat_dev(Dev,&Info)!=0)
- return(1457664);
- int64 FreeSize=Info.block_size;
- FreeSize=FreeSize*Info.free_blocks;
- return(FreeSize);
+
+ ULARGE_INTEGER uiTotalSize,uiTotalFree,uiUserFree;
+ uiUserFree.u.LowPart=uiUserFree.u.HighPart=0;
+ if (GetDiskFreeSpaceEx(*Root!=0 ? Root:NULL,&uiUserFree,&uiTotalSize,&uiTotalFree) &&
+ uiUserFree.u.HighPart<=uiTotalFree.u.HighPart)
+ return INT32TO64(uiUserFree.u.HighPart,uiUserFree.u.LowPart);
+ return 0;
#elif defined(_UNIX)
- return(1457664);
-#elif defined(_EMX)
- int Drive=IsDiskLetter(Name) ? etoupper(Name[0])-'A'+1:0;
-#ifndef _DJGPP
- if (_osmode == OS2_MODE)
- {
- FSALLOCATE fsa;
- if (DosQueryFSInfo(Drive,1,&fsa,sizeof(fsa))!=0)
- return(1457664);
- int64 FreeSize=fsa.cSectorUnit*fsa.cbSector;
- FreeSize=FreeSize*fsa.cUnitAvail;
- return(FreeSize);
- }
- else
-#endif
- {
- union REGS regs,outregs;
- memset(&regs,0,sizeof(regs));
- regs.h.ah=0x36;
- regs.h.dl=Drive;
-#ifdef _DJGPP
- int86 (0x21,&regs,&outregs);
-#else
- _int86 (0x21,&regs,&outregs);
-#endif
- if (outregs.x.ax==0xffff)
- return(1457664);
- int64 FreeSize=outregs.x.ax*outregs.x.cx;
- FreeSize=FreeSize*outregs.x.bx;
- return(FreeSize);
- }
+ wchar Root[NM];
+ GetFilePath(Name,Root,ASIZE(Root));
+ char RootA[NM];
+ WideToChar(Root,RootA,ASIZE(RootA));
+ struct statfs sfs;
+ if (statfs(*RootA!=0 ? RootA:".",&sfs)!=0)
+ return 0;
+ int64 FreeSize=sfs.f_bsize;
+ FreeSize=FreeSize*sfs.f_bavail;
+ return FreeSize;
#else
- #define DISABLEAUTODETECT
- return(1457664);
+ return 0;
#endif
}
#endif
@@ -305,50 +164,41 @@ int64 GetFreeDisk(const char *Name)
-
-bool FileExist(const char *Name,const wchar *NameW)
+bool FileExist(const wchar *Name)
{
#ifdef _WIN_ALL
- if (WinNT() && NameW!=NULL && *NameW!=0)
- return(GetFileAttributesW(NameW)!=0xffffffff);
- else
- return(Name!=NULL && GetFileAttributesA(Name)!=0xffffffff);
+ return GetFileAttr(Name)!=0xffffffff;
#elif defined(ENABLE_ACCESS)
- return(access(Name,0)==0);
+ char NameA[NM];
+ WideToChar(Name,NameA,ASIZE(NameA));
+ return access(NameA,0)==0;
#else
FindData FD;
- return(FindFile::FastFind(Name,NameW,&FD));
+ return FindFile::FastFind(Name,&FD);
#endif
}
-
-
-bool FileExist(const wchar *Name)
-{
- return FileExist(NULL,Name);
-}
-bool WildFileExist(const char *Name,const wchar *NameW)
+bool WildFileExist(const wchar *Name)
{
- if (IsWildcard(Name,NameW))
+ if (IsWildcard(Name))
{
FindFile Find;
Find.SetMask(Name);
- Find.SetMaskW(NameW);
FindData fd;
- return(Find.Next(&fd));
+ return Find.Next(&fd);
}
- return(FileExist(Name,NameW));
+ return FileExist(Name);
}
bool IsDir(uint Attr)
{
-#if defined (_WIN_ALL) || defined(_EMX)
- return(Attr!=0xffffffff && (Attr & 0x10)!=0);
+#ifdef _WIN_ALL
+ return Attr!=0xffffffff && (Attr & FILE_ATTRIBUTE_DIRECTORY)!=0;
#endif
#if defined(_UNIX)
- return((Attr & 0xF000)==0x4000);
+ return (Attr & 0xF000)==0x4000;
#endif
}
@@ -356,28 +206,20 @@ bool IsDir(uint Attr)
bool IsUnreadable(uint Attr)
{
#if defined(_UNIX) && defined(S_ISFIFO) && defined(S_ISSOCK) && defined(S_ISCHR)
- return(S_ISFIFO(Attr) || S_ISSOCK(Attr) || S_ISCHR(Attr));
-#endif
- return(false);
-}
-
-
-bool IsLabel(uint Attr)
-{
-#if defined (_WIN_ALL) || defined(_EMX)
- return((Attr & 8)!=0);
-#else
- return(false);
+ return S_ISFIFO(Attr) || S_ISSOCK(Attr) || S_ISCHR(Attr);
#endif
+ return false;
}
bool IsLink(uint Attr)
{
#ifdef _UNIX
- return((Attr & 0xF000)==0xA000);
+ return (Attr & 0xF000)==0xA000;
+#elif defined(_WIN_ALL)
+ return (Attr & FILE_ATTRIBUTE_REPARSE_POINT)!=0;
#else
- return(false);
+ return false;
#endif
}
@@ -388,94 +230,101 @@ bool IsLink(uint Attr)
bool IsDeleteAllowed(uint FileAttr)
{
-#if defined(_WIN_ALL) || defined(_EMX)
- return((FileAttr & (FA_RDONLY|FA_SYSTEM|FA_HIDDEN))==0);
+#ifdef _WIN_ALL
+ return (FileAttr & (FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN))==0;
#else
- return((FileAttr & (S_IRUSR|S_IWUSR))==(S_IRUSR|S_IWUSR));
+ return (FileAttr & (S_IRUSR|S_IWUSR))==(S_IRUSR|S_IWUSR);
#endif
}
-void PrepareToDelete(const char *Name,const wchar *NameW)
+void PrepareToDelete(const wchar *Name)
{
#if defined(_WIN_ALL) || defined(_EMX)
- SetFileAttr(Name,NameW,0);
+ SetFileAttr(Name,0);
#endif
#ifdef _UNIX
if (Name!=NULL)
- chmod(Name,S_IRUSR|S_IWUSR|S_IXUSR);
+ {
+ char NameA[NM];
+ WideToChar(Name,NameA,ASIZE(NameA));
+ chmod(NameA,S_IRUSR|S_IWUSR|S_IXUSR);
+ }
#endif
}
-uint GetFileAttr(const char *Name,const wchar *NameW)
+uint GetFileAttr(const wchar *Name)
{
#ifdef _WIN_ALL
- if (WinNT() && NameW!=NULL && *NameW!=0)
- return(GetFileAttributesW(NameW));
- else
- return(GetFileAttributesA(Name));
-#elif defined(_DJGPP)
- return(_chmod(Name,0));
+ DWORD Attr=GetFileAttributes(Name);
+ if (Attr==0xffffffff)
+ {
+ wchar LongName[NM];
+ if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
+ Attr=GetFileAttributes(LongName);
+ }
+ return Attr;
#else
+ char NameA[NM];
+ WideToChar(Name,NameA,ASIZE(NameA));
struct stat st;
- if (stat(Name,&st)!=0)
- return(0);
-#ifdef _EMX
- return(st.st_attr);
-#else
- return(st.st_mode);
-#endif
+ if (stat(NameA,&st)!=0)
+ return 0;
+ return st.st_mode;
#endif
}
-bool SetFileAttr(const char *Name,const wchar *NameW,uint Attr)
+bool SetFileAttr(const wchar *Name,uint Attr)
{
- bool Success;
#ifdef _WIN_ALL
- if (WinNT() && NameW!=NULL && *NameW!=0)
- Success=SetFileAttributesW(NameW,Attr)!=0;
- else
- if (Name!=NULL)
- Success=SetFileAttributesA(Name,Attr)!=0;
- else
- Success=false;
-#elif defined(_DJGPP)
- Success=_chmod(Name,1,Attr)!=-1;
-#elif defined(_EMX)
- Success=__chmod(Name,1,Attr)!=-1;
+ bool Success=SetFileAttributes(Name,Attr)!=0;
+ if (!Success)
+ {
+ wchar LongName[NM];
+ if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
+ Success=SetFileAttributes(LongName,Attr)!=0;
+ }
+ return Success;
#elif defined(_UNIX)
- Success=chmod(Name,(mode_t)Attr)==0;
+ char NameA[NM];
+ WideToChar(Name,NameA,ASIZE(NameA));
+ return chmod(NameA,(mode_t)Attr)==0;
#else
- Success=false;
+ return false;
#endif
- return(Success);
}
-#ifndef SFX_MODULE
-uint CalcFileCRC(File *SrcFile,int64 Size,CALCCRC_SHOWMODE ShowMode)
+#if !defined(SFX_MODULE) && !defined(SHELL_EXT) && !defined(SETUP)
+void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,uint Flags)
{
SaveFilePos SavePos(*SrcFile);
- const size_t BufSize=0x10000;
- Array<byte> Data(BufSize);
- int64 BlockCount=0;
- uint DataCRC=0xffffffff;
-
#if !defined(SILENT) && !defined(_WIN_CE)
int64 FileLength=SrcFile->FileLength();
- if (ShowMode!=CALCCRC_SHOWNONE)
+ if ((Flags & (CALCFSUM_SHOWTEXT|CALCFSUM_SHOWALL))!=0)
{
mprintf(St(MCalcCRC));
- mprintf(" ");
+ mprintf(L" ");
}
#endif
- SrcFile->Seek(0,SEEK_SET);
+ if ((Flags & CALCFSUM_CURPOS)==0)
+ SrcFile->Seek(0,SEEK_SET);
+
+ const size_t BufSize=0x100000;
+ Array<byte> Data(BufSize);
+
+
+ DataHash HashCRC,HashBlake2;
+ HashCRC.Init(HASH_CRC32,Threads);
+ HashBlake2.Init(HASH_BLAKE2,Threads);
+
+ int64 BlockCount=0;
while (true)
{
size_t SizeToRead;
@@ -487,70 +336,104 @@ uint CalcFileCRC(File *SrcFile,int64 Size,CALCCRC_SHOWMODE ShowMode)
if (ReadSize==0)
break;
- ++BlockCount;
- if ((BlockCount & 15)==0)
+ if ((++BlockCount & 0xf)==0)
{
#if !defined(SILENT) && !defined(_WIN_CE)
- if (ShowMode==CALCCRC_SHOWALL)
- mprintf("\b\b\b\b%3d%%",ToPercent(BlockCount*int64(BufSize),FileLength));
+ if ((Flags & CALCFSUM_SHOWALL)!=0)
+ mprintf(L"\b\b\b\b%3d%%",ToPercent(BlockCount*int64(BufSize),FileLength));
#endif
Wait();
}
- DataCRC=CRC(DataCRC,&Data[0],ReadSize);
+
+ if (CRC32!=NULL)
+ HashCRC.Update(&Data[0],ReadSize);
+ if (Blake2!=NULL)
+ HashBlake2.Update(&Data[0],ReadSize);
+
if (Size!=INT64NDF)
Size-=ReadSize;
}
-#if !defined(SILENT) && !defined(_WIN_CE)
- if (ShowMode==CALCCRC_SHOWALL)
- mprintf("\b\b\b\b ");
-#endif
- return(DataCRC^0xffffffff);
-}
+#ifndef SILENT
+ if ((Flags & CALCFSUM_SHOWALL)!=0)
+ mprintf(L"\b\b\b\b ");
#endif
-
-bool RenameFile(const char *SrcName,const wchar *SrcNameW,const char *DestName,const wchar *DestNameW)
-{
- return(rename(SrcName,DestName)==0);
+ if (CRC32!=NULL)
+ *CRC32=HashCRC.GetCRC32();
+ if (Blake2!=NULL)
+ {
+ HashValue Result;
+ HashBlake2.Result(&Result);
+ memcpy(Blake2,Result.Digest,sizeof(Result.Digest));
+ }
}
+#endif
-bool DelFile(const char *Name)
+bool RenameFile(const wchar *SrcName,const wchar *DestName)
{
- return(DelFile(Name,NULL));
+#ifdef _WIN_ALL
+ bool Success=MoveFile(SrcName,DestName)!=0;
+ if (!Success)
+ {
+ wchar LongName1[NM],LongName2[NM];
+ if (GetWinLongPath(SrcName,LongName1,ASIZE(LongName1)) &&
+ GetWinLongPath(DestName,LongName2,ASIZE(LongName2)))
+ Success=MoveFile(LongName1,LongName2)!=0;
+ }
+ return Success;
+#else
+ char SrcNameA[NM],DestNameA[NM];
+ WideToChar(SrcName,SrcNameA,ASIZE(SrcNameA));
+ WideToChar(DestName,DestNameA,ASIZE(DestNameA));
+ return rename(SrcNameA,DestNameA)==0;
+#endif
}
-
-
-bool DelFile(const char *Name,const wchar *NameW)
+bool DelFile(const wchar *Name)
{
- return(Name!=NULL && remove(Name)==0);
+#ifdef _WIN_ALL
+ bool Success=DeleteFile(Name)!=0;
+ if (!Success)
+ {
+ wchar LongName[NM];
+ if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
+ Success=DeleteFile(LongName)!=0;
+ }
+ return Success;
+#else
+ char NameA[NM];
+ WideToChar(Name,NameA,ASIZE(NameA));
+ return remove(NameA)==0;
+#endif
}
-
-
-
-
#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
-bool SetFileCompression(char *Name,wchar *NameW,bool State)
+bool SetFileCompression(const wchar *Name,bool State)
{
- wchar FileNameW[NM];
- GetWideName(Name,NameW,FileNameW,ASIZE(FileNameW));
- HANDLE hFile=CreateFileW(FileNameW,FILE_READ_DATA|FILE_WRITE_DATA,
+ HANDLE hFile=CreateFile(Name,FILE_READ_DATA|FILE_WRITE_DATA,
FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (hFile==INVALID_HANDLE_VALUE)
- return(false);
+ {
+ wchar LongName[NM];
+ if (GetWinLongPath(Name,LongName,ASIZE(LongName)))
+ hFile=CreateFile(LongName,FILE_READ_DATA|FILE_WRITE_DATA,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
+ }
+ if (hFile==INVALID_HANDLE_VALUE)
+ return false;
SHORT NewState=State ? COMPRESSION_FORMAT_DEFAULT:COMPRESSION_FORMAT_NONE;
DWORD Result;
int RetCode=DeviceIoControl(hFile,FSCTL_SET_COMPRESSION,&NewState,
sizeof(NewState),NULL,0,&Result,NULL);
CloseHandle(hFile);
- return(RetCode!=0);
+ return RetCode!=0;
}
#endif
@@ -562,3 +445,4 @@ bool SetFileCompression(char *Name,wchar *NameW,bool State)
+
diff --git a/src/thirdparty/unrar/filefn.hpp b/src/thirdparty/unrar/filefn.hpp
index bdf193e80..eaf3fcc5f 100644
--- a/src/thirdparty/unrar/filefn.hpp
+++ b/src/thirdparty/unrar/filefn.hpp
@@ -3,46 +3,42 @@
enum MKDIR_CODE {MKDIR_SUCCESS,MKDIR_ERROR,MKDIR_BADPATH};
-MKDIR_CODE MakeDir(const char *Name,const wchar *NameW,bool SetAttr,uint Attr);
-bool CreatePath(const char *Path,bool SkipLastName);
+MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr);
bool CreatePath(const wchar *Path,bool SkipLastName);
-bool CreatePath(const char *Path,const wchar *PathW,bool SkipLastName);
-void SetDirTime(const char *Name,const wchar *NameW,RarTime *ftm,RarTime *ftc,RarTime *fta);
-bool IsRemovable(const char *Name);
+void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta);
+bool IsRemovable(const wchar *Name);
#ifndef SFX_MODULE
-int64 GetFreeDisk(const char *Name);
+int64 GetFreeDisk(const wchar *Name);
#endif
-bool FileExist(const char *Name,const wchar *NameW=NULL);
bool FileExist(const wchar *Name);
-bool WildFileExist(const char *Name,const wchar *NameW=NULL);
+bool WildFileExist(const wchar *Name);
bool IsDir(uint Attr);
bool IsUnreadable(uint Attr);
-bool IsLabel(uint Attr);
bool IsLink(uint Attr);
-void SetSFXMode(const char *FileName);
-void EraseDiskContents(const char *FileName);
+void SetSFXMode(const wchar *FileName);
+void EraseDiskContents(const wchar *FileName);
bool IsDeleteAllowed(uint FileAttr);
-void PrepareToDelete(const char *Name,const wchar *NameW=NULL);
-uint GetFileAttr(const char *Name,const wchar *NameW=NULL);
-bool SetFileAttr(const char *Name,const wchar *NameW,uint Attr);
+void PrepareToDelete(const wchar *Name);
+uint GetFileAttr(const wchar *Name);
+bool SetFileAttr(const wchar *Name,uint Attr);
-enum CALCCRC_SHOWMODE {CALCCRC_SHOWNONE,CALCCRC_SHOWTEXT,CALCCRC_SHOWALL};
-uint CalcFileCRC(File *SrcFile,int64 Size=INT64NDF,CALCCRC_SHOWMODE ShowMode=CALCCRC_SHOWNONE);
+enum CALCFSUM_FLAGS {CALCFSUM_SHOWTEXT=1,CALCFSUM_SHOWALL=2,CALCFSUM_CURPOS=4};
-bool RenameFile(const char *SrcName,const wchar *SrcNameW,const char *DestName,const wchar *DestNameW);
-bool DelFile(const char *Name);
-bool DelFile(const char *Name,const wchar *NameW);
-bool DelDir(const char *Name);
-bool DelDir(const char *Name,const wchar *NameW);
+void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size=INT64NDF,uint Flags=0);
+
+bool RenameFile(const wchar *SrcName,const wchar *DestName);
+bool DelFile(const wchar *Name);
+bool DelDir(const wchar *Name);
#if defined(_WIN_ALL) && !defined(_WIN_CE)
-bool SetFileCompression(char *Name,wchar *NameW,bool State);
+bool SetFileCompression(const wchar *Name,bool State);
#endif
+
#endif
diff --git a/src/thirdparty/unrar/filestr.cpp b/src/thirdparty/unrar/filestr.cpp
index 49e865b9a..3d8eaa8d2 100644
--- a/src/thirdparty/unrar/filestr.cpp
+++ b/src/thirdparty/unrar/filestr.cpp
@@ -3,8 +3,7 @@
static bool IsUnicode(byte *Data,int Size);
bool ReadTextFile(
- const char *Name,
- const wchar *NameW,
+ const wchar *Name,
StringList *List,
bool Config,
bool AbortOnError,
@@ -13,29 +12,19 @@ bool ReadTextFile(
bool SkipComments,
bool ExpandEnvStr)
{
- char FileName[NM];
+ wchar FileName[NM];
*FileName=0;
- if (Name!=NULL)
- if (Config)
- GetConfigName(Name,FileName,true);
- else
- strcpy(FileName,Name);
-
- wchar FileNameW[NM];
- *FileNameW=0;
-#ifdef _WIN_ALL
- if (NameW!=NULL)
+ if (Name!=NULL)
if (Config)
- GetConfigName(NameW,FileNameW,true);
+ GetConfigName(Name,FileName,ASIZE(FileName),true);
else
- wcscpy(FileNameW,NameW);
-#endif
+ wcsncpyz(FileName,Name,ASIZE(FileName));
File SrcFile;
- if (FileName!=NULL && *FileName!=0 || FileNameW!=NULL && *FileNameW!=0)
+ if (FileName!=NULL && *FileName!=0)
{
- bool OpenCode=AbortOnError ? SrcFile.WOpen(FileName,FileNameW):SrcFile.Open(FileName,FileNameW,0);
+ bool OpenCode=AbortOnError ? SrcFile.WOpen(FileName):SrcFile.Open(FileName,0);
if (!OpenCode)
{
@@ -58,6 +47,8 @@ bool ReadTextFile(
memset(&Data[DataSize],0,5);
+ Array<wchar> WideStr;
+
if (SrcCharset==RCH_UNICODE ||
SrcCharset==RCH_DEFAULT && IsUnicode((byte *)&Data[0],DataSize))
{
@@ -71,7 +62,6 @@ bool ReadTextFile(
}
wchar *CurStr=&DataW[0];
- Array<char> AnsiName;
while (*CurStr!=0)
{
@@ -92,21 +82,15 @@ bool ReadTextFile(
break;
*SpacePtr=0;
}
- if (*CurStr)
+ if (*CurStr!=0)
{
- // Length and AddSize must be defined as signed, because AddSize
- // can be negative.
- int Length=(int)wcslen(CurStr);
- int AddSize=4*(Length-(int)AnsiName.Size()+1);
+ size_t Length=wcslen(CurStr);
- if (AddSize>0)
- AnsiName.Add(AddSize);
if (Unquote && *CurStr=='\"' && CurStr[Length-1]=='\"')
{
CurStr[Length-1]=0;
CurStr++;
}
- WideToChar(CurStr,&AnsiName[0],AnsiName.Size());
bool Expanded=false;
#if defined(_WIN_ALL) && !defined(_WIN_CE)
@@ -114,21 +98,16 @@ bool ReadTextFile(
{
// Expanding environment variables in Windows version.
- char ExpName[NM];
- wchar ExpNameW[NM];
- *ExpNameW=0;
- int ret,retw=1;
- ret=ExpandEnvironmentStringsA(&AnsiName[0],ExpName,ASIZE(ExpName));
- if (ret!=0 && WinNT())
- retw=ExpandEnvironmentStringsW(CurStr,ExpNameW,ASIZE(ExpNameW));
- Expanded=ret!=0 && ret<ASIZE(ExpName) &&
- retw!=0 && retw<ASIZE(ExpNameW);
+ wchar ExpName[NM];
+ *ExpName=0;
+ DWORD Result=ExpandEnvironmentStrings(CurStr,ExpName,ASIZE(ExpName));
+ Expanded=Result!=0 && Result<ASIZE(ExpName);
if (Expanded)
- List->AddString(ExpName,ExpNameW);
+ List->AddString(ExpName);
}
#endif
if (!Expanded)
- List->AddString(&AnsiName[0],CurStr);
+ List->AddString(CurStr);
}
CurStr=NextStr+1;
while (*CurStr=='\r' || *CurStr=='\n')
@@ -174,35 +153,38 @@ bool ReadTextFile(
#endif
bool Expanded=false;
-#if defined(_WIN_ALL) && !defined(_WIN_CE)
+
+ WideStr.Alloc(strlen(CurStr)+1);
+ CharToWide(CurStr,&WideStr[0],WideStr.Size());
+#ifdef _WIN_ALL
if (ExpandEnvStr && *CurStr=='%')
{
// Expanding environment variables in Windows version.
- char ExpName[NM];
- int ret=ExpandEnvironmentStringsA(CurStr,ExpName,ASIZE(ExpName));
- Expanded=ret!=0 && ret<ASIZE(ExpName);
+ wchar ExpName[NM];
+ DWORD Result=ExpandEnvironmentStringsW(&WideStr[0],ExpName,ASIZE(ExpName));
+ Expanded=Result!=0 && Result<ASIZE(ExpName);
if (Expanded)
List->AddString(ExpName);
}
#endif
if (!Expanded)
- List->AddString(CurStr);
+ List->AddString(&WideStr[0]);
}
CurStr=NextStr+1;
while (*CurStr=='\r' || *CurStr=='\n')
CurStr++;
}
}
- return(true);
+ return true;
}
bool IsUnicode(byte *Data,int Size)
{
if (Size<4 || Data[0]!=0xff || Data[1]!=0xfe)
- return(false);
+ return false;
for (int I=2;I<Size;I++)
if (Data[I]<32 && Data[I]!='\r' && Data[I]!='\n')
- return(true);
- return(false);
+ return true;
+ return false;
}
diff --git a/src/thirdparty/unrar/filestr.hpp b/src/thirdparty/unrar/filestr.hpp
index 3bdcfe737..8dfdf64bd 100644
--- a/src/thirdparty/unrar/filestr.hpp
+++ b/src/thirdparty/unrar/filestr.hpp
@@ -2,8 +2,7 @@
#define _RAR_FILESTR_
bool ReadTextFile(
- const char *Name,
- const wchar *NameW,
+ const wchar *Name,
StringList *List,
bool Config,
bool AbortOnError=false,
diff --git a/src/thirdparty/unrar/find.cpp b/src/thirdparty/unrar/find.cpp
index 7ba14c055..58e3c243c 100644
--- a/src/thirdparty/unrar/find.cpp
+++ b/src/thirdparty/unrar/find.cpp
@@ -3,7 +3,6 @@
FindFile::FindFile()
{
*FindMask=0;
- *FindMaskW=0;
FirstCall=true;
#ifdef _WIN_ALL
hFind=INVALID_HANDLE_VALUE;
@@ -25,267 +24,185 @@ FindFile::~FindFile()
}
-void FindFile::SetMask(const char *FindMask)
+void FindFile::SetMask(const wchar *Mask)
{
- strcpy(FindFile::FindMask,NullToEmpty(FindMask));
- if (*FindMaskW==0)
- CharToWide(FindMask,FindMaskW);
+ wcscpy(FindMask,Mask);
FirstCall=true;
}
-void FindFile::SetMaskW(const wchar *FindMaskW)
-{
- if (FindMaskW==NULL)
- return;
- wcscpy(FindFile::FindMaskW,FindMaskW);
- if (*FindMask==0)
- WideToChar(FindMaskW,FindMask);
- FirstCall=true;
-}
-
-
-bool FindFile::Next(struct FindData *fd,bool GetSymLink)
+bool FindFile::Next(FindData *fd,bool GetSymLink)
{
fd->Error=false;
if (*FindMask==0)
- return(false);
+ return false;
#ifdef _WIN_ALL
if (FirstCall)
{
- if ((hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,FindMaskW,fd))==INVALID_HANDLE_VALUE)
- return(false);
+ if ((hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,fd))==INVALID_HANDLE_VALUE)
+ return false;
}
else
- if (Win32Find(hFind,FindMask,FindMaskW,fd)==INVALID_HANDLE_VALUE)
- return(false);
+ if (Win32Find(hFind,FindMask,fd)==INVALID_HANDLE_VALUE)
+ return false;
#else
if (FirstCall)
{
- char DirName[NM];
- strcpy(DirName,FindMask);
+ wchar DirName[NM];
+ wcsncpyz(DirName,FindMask,ASIZE(DirName));
RemoveNameFromPath(DirName);
if (*DirName==0)
- strcpy(DirName,".");
- if ((dirp=opendir(DirName))==NULL)
+ wcscpy(DirName,L".");
+ char DirNameA[NM];
+ WideToChar(DirName,DirNameA,ASIZE(DirNameA));
+ if ((dirp=opendir(DirNameA))==NULL)
{
fd->Error=(errno!=ENOENT);
- return(false);
+ return false;
}
}
while (1)
{
struct dirent *ent=readdir(dirp);
if (ent==NULL)
- return(false);
+ return false;
if (strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0)
continue;
- if (CmpName(FindMask,ent->d_name,MATCH_NAMES))
+ wchar Name[NM];
+ if (!CharToWide(ent->d_name,Name,ASIZE(Name)))
+ Log(NULL,St(MInvalidName),Name);
+
+ if (CmpName(FindMask,Name,MATCH_NAMES))
{
- char FullName[NM];
- strcpy(FullName,FindMask);
+ wchar FullName[NM];
+ wcscpy(FullName,FindMask);
*PointToName(FullName)=0;
- if (strlen(FullName)+strlen(ent->d_name)>=ASIZE(FullName)-1)
+ if (wcslen(FullName)+wcslen(Name)>=ASIZE(FullName)-1)
{
#ifndef SILENT
- Log(NULL,"\n%s%s",FullName,ent->d_name);
+ Log(NULL,L"\n%ls%ls",FullName,Name);
Log(NULL,St(MPathTooLong));
#endif
- return(false);
+ return false;
}
- strcat(FullName,ent->d_name);
- if (!FastFind(FullName,NULL,fd,GetSymLink))
+ wcscat(FullName,Name);
+ if (!FastFind(FullName,fd,GetSymLink))
{
- ErrHandler.OpenErrorMsg(FullName);
+ ErrHandler.OpenErrorMsg(NULL,FullName);
continue;
}
- strcpy(fd->Name,FullName);
+ wcscpy(fd->Name,FullName);
break;
}
}
- *fd->NameW=0;
-#ifdef _APPLE
- if (!LowAscii(fd->Name))
- UtfToWide(fd->Name,fd->NameW,sizeof(fd->NameW));
-#elif defined(UNICODE_SUPPORTED)
- if (!LowAscii(fd->Name) && UnicodeEnabled())
- CharToWide(fd->Name,fd->NameW);
-#endif
#endif
fd->Flags=0;
fd->IsDir=IsDir(fd->FileAttr);
+ fd->IsLink=IsLink(fd->FileAttr);
+
FirstCall=false;
- char *Name=PointToName(fd->Name);
- if (strcmp(Name,".")==0 || strcmp(Name,"..")==0)
- return(Next(fd));
- return(true);
+ wchar *NameOnly=PointToName(fd->Name);
+ if (wcscmp(NameOnly,L".")==0 || wcscmp(NameOnly,L"..")==0)
+ return Next(fd);
+ return true;
}
-bool FindFile::FastFind(const char *FindMask,const wchar *FindMaskW,FindData *fd,bool GetSymLink)
+bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
{
fd->Error=false;
#ifndef _UNIX
- if (IsWildcard(FindMask,FindMaskW))
- return(false);
+ if (IsWildcard(FindMask))
+ return false;
#endif
#ifdef _WIN_ALL
- HANDLE hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,FindMaskW,fd);
+ HANDLE hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,fd);
if (hFind==INVALID_HANDLE_VALUE)
- return(false);
+ return false;
FindClose(hFind);
#else
+ char FindMaskA[NM];
+ WideToChar(FindMask,FindMaskA,ASIZE(FindMaskA));
+
struct stat st;
if (GetSymLink)
{
#ifdef SAVE_LINKS
- if (lstat(FindMask,&st)!=0)
+ if (lstat(FindMaskA,&st)!=0)
#else
- if (stat(FindMask,&st)!=0)
+ if (stat(FindMaskA,&st)!=0)
#endif
{
fd->Error=(errno!=ENOENT);
- return(false);
+ return false;
}
}
else
- if (stat(FindMask,&st)!=0)
+ if (stat(FindMaskA,&st)!=0)
{
fd->Error=(errno!=ENOENT);
- return(false);
+ return false;
}
-#ifdef _DJGPP
- fd->FileAttr=_chmod(FindMask,0);
-#elif defined(_EMX)
- fd->FileAttr=st.st_attr;
-#else
fd->FileAttr=st.st_mode;
-#endif
- fd->IsDir=IsDir(st.st_mode);
fd->Size=st.st_size;
fd->mtime=st.st_mtime;
fd->atime=st.st_atime;
fd->ctime=st.st_ctime;
- fd->FileTime=fd->mtime.GetDos();
- strcpy(fd->Name,FindMask);
-
- *fd->NameW=0;
-#ifdef _APPLE
- if (!LowAscii(fd->Name))
- UtfToWide(fd->Name,fd->NameW,sizeof(fd->NameW));
-#elif defined(UNICODE_SUPPORTED)
- if (!LowAscii(fd->Name) && UnicodeEnabled())
- CharToWide(fd->Name,fd->NameW);
-#endif
+ wcsncpyz(fd->Name,FindMask,ASIZE(fd->Name));
#endif
fd->Flags=0;
fd->IsDir=IsDir(fd->FileAttr);
- return(true);
+ fd->IsLink=IsLink(fd->FileAttr);
+
+ return true;
}
#ifdef _WIN_ALL
-HANDLE FindFile::Win32Find(HANDLE hFind,const char *Mask,const wchar *MaskW,FindData *fd)
+HANDLE FindFile::Win32Find(HANDLE hFind,const wchar *Mask,FindData *fd)
{
-#ifndef _WIN_CE
- if (WinNT())
-#endif
+ WIN32_FIND_DATAW FindData;
+ if (hFind==INVALID_HANDLE_VALUE)
{
- wchar WideMask[NM];
- if (MaskW!=NULL && *MaskW!=0)
- wcscpy(WideMask,MaskW);
- else
- CharToWide(Mask,WideMask);
-
- WIN32_FIND_DATAW FindData;
+ hFind=FindFirstFile(Mask,&FindData);
if (hFind==INVALID_HANDLE_VALUE)
{
- hFind=FindFirstFileW(WideMask,&FindData);
- if (hFind==INVALID_HANDLE_VALUE)
- {
- int SysErr=GetLastError();
- fd->Error=(SysErr!=ERROR_FILE_NOT_FOUND &&
- SysErr!=ERROR_PATH_NOT_FOUND &&
- SysErr!=ERROR_NO_MORE_FILES);
- }
+ wchar LongMask[NM];
+ if (GetWinLongPath(Mask,LongMask,ASIZE(LongMask)))
+ hFind=FindFirstFile(LongMask,&FindData);
}
- else
- if (!FindNextFileW(hFind,&FindData))
- {
- hFind=INVALID_HANDLE_VALUE;
- fd->Error=GetLastError()!=ERROR_NO_MORE_FILES;
- }
-
- if (hFind!=INVALID_HANDLE_VALUE)
+ if (hFind==INVALID_HANDLE_VALUE)
{
- wcscpy(fd->NameW,WideMask);
- wcscpy(PointToName(fd->NameW),FindData.cFileName);
- WideToChar(fd->NameW,fd->Name);
- fd->Size=INT32TO64(FindData.nFileSizeHigh,FindData.nFileSizeLow);
- fd->FileAttr=FindData.dwFileAttributes;
- wcscpy(fd->ShortName,FindData.cAlternateFileName);
- fd->ftCreationTime=FindData.ftCreationTime;
- fd->ftLastAccessTime=FindData.ftLastAccessTime;
- fd->ftLastWriteTime=FindData.ftLastWriteTime;
- fd->mtime=FindData.ftLastWriteTime;
- fd->ctime=FindData.ftCreationTime;
- fd->atime=FindData.ftLastAccessTime;
- fd->FileTime=fd->mtime.GetDos();
-
-#ifndef _WIN_CE
-// if (LowAscii(fd->NameW))
-// *fd->NameW=0;
-#endif
+ int SysErr=GetLastError();
+ fd->Error=(SysErr!=ERROR_FILE_NOT_FOUND &&
+ SysErr!=ERROR_PATH_NOT_FOUND &&
+ SysErr!=ERROR_NO_MORE_FILES);
}
}
-#ifndef _WIN_CE
else
- {
- char CharMask[NM];
- if (Mask!=NULL && *Mask!=0)
- strcpy(CharMask,Mask);
- else
- WideToChar(MaskW,CharMask);
-
- WIN32_FIND_DATAA FindData;
- if (hFind==INVALID_HANDLE_VALUE)
+ if (!FindNextFile(hFind,&FindData))
{
- hFind=FindFirstFileA(CharMask,&FindData);
- if (hFind==INVALID_HANDLE_VALUE)
- {
- int SysErr=GetLastError();
- fd->Error=SysErr!=ERROR_FILE_NOT_FOUND && SysErr!=ERROR_PATH_NOT_FOUND;
- }
+ hFind=INVALID_HANDLE_VALUE;
+ fd->Error=GetLastError()!=ERROR_NO_MORE_FILES;
}
- else
- if (!FindNextFileA(hFind,&FindData))
- {
- hFind=INVALID_HANDLE_VALUE;
- fd->Error=GetLastError()!=ERROR_NO_MORE_FILES;
- }
- if (hFind!=INVALID_HANDLE_VALUE)
- {
- strcpy(fd->Name,CharMask);
- strcpy(PointToName(fd->Name),FindData.cFileName);
- CharToWide(fd->Name,fd->NameW);
- fd->Size=INT32TO64(FindData.nFileSizeHigh,FindData.nFileSizeLow);
- fd->FileAttr=FindData.dwFileAttributes;
- CharToWide(FindData.cAlternateFileName,fd->ShortName);
- fd->ftCreationTime=FindData.ftCreationTime;
- fd->ftLastAccessTime=FindData.ftLastAccessTime;
- fd->ftLastWriteTime=FindData.ftLastWriteTime;
- fd->mtime=FindData.ftLastWriteTime;
- fd->ctime=FindData.ftCreationTime;
- fd->atime=FindData.ftLastAccessTime;
- fd->FileTime=fd->mtime.GetDos();
-// if (LowAscii(fd->Name))
-// *fd->NameW=0;
- }
+ if (hFind!=INVALID_HANDLE_VALUE)
+ {
+ wcsncpyz(fd->Name,Mask,ASIZE(fd->Name));
+ SetName(fd->Name,FindData.cFileName,ASIZE(fd->Name));
+ fd->Size=INT32TO64(FindData.nFileSizeHigh,FindData.nFileSizeLow);
+ fd->FileAttr=FindData.dwFileAttributes;
+ fd->ftCreationTime=FindData.ftCreationTime;
+ fd->ftLastAccessTime=FindData.ftLastAccessTime;
+ fd->ftLastWriteTime=FindData.ftLastWriteTime;
+ fd->mtime=FindData.ftLastWriteTime;
+ fd->ctime=FindData.ftCreationTime;
+ fd->atime=FindData.ftLastAccessTime;
+
+
}
-#endif
fd->Flags=0;
- return(hFind);
+ return hFind;
}
#endif
diff --git a/src/thirdparty/unrar/find.hpp b/src/thirdparty/unrar/find.hpp
index 05f5d7f0e..250637f8a 100644
--- a/src/thirdparty/unrar/find.hpp
+++ b/src/thirdparty/unrar/find.hpp
@@ -7,17 +7,15 @@ enum FINDDATA_FLAGS {
struct FindData
{
- char Name[NM];
- wchar NameW[NM];
- int64 Size;
+ wchar Name[NM];
+ uint64 Size;
uint FileAttr;
- uint FileTime;
bool IsDir;
+ bool IsLink;
RarTime mtime;
RarTime ctime;
RarTime atime;
#ifdef _WIN_ALL
- wchar ShortName[NM];
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
@@ -30,11 +28,10 @@ class FindFile
{
private:
#ifdef _WIN_ALL
- static HANDLE Win32Find(HANDLE hFind,const char *Mask,const wchar *MaskW,struct FindData *fd);
+ static HANDLE Win32Find(HANDLE hFind,const wchar *Mask,FindData *fd);
#endif
- char FindMask[NM];
- wchar FindMaskW[NM];
+ wchar FindMask[NM];
bool FirstCall;
#ifdef _WIN_ALL
HANDLE hFind;
@@ -44,10 +41,9 @@ class FindFile
public:
FindFile();
~FindFile();
- void SetMask(const char *FindMask);
- void SetMaskW(const wchar *FindMaskW);
+ void SetMask(const wchar *Mask);
bool Next(FindData *fd,bool GetSymLink=false);
- static bool FastFind(const char *FindMask,const wchar *FindMaskW,FindData *fd,bool GetSymLink=false);
+ static bool FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink=false);
};
#endif
diff --git a/src/thirdparty/unrar/getbits.cpp b/src/thirdparty/unrar/getbits.cpp
index 02b3a0b46..e57b3e32f 100644
--- a/src/thirdparty/unrar/getbits.cpp
+++ b/src/thirdparty/unrar/getbits.cpp
@@ -1,23 +1,30 @@
#include "rar.hpp"
-BitInput::BitInput()
+BitInput::BitInput(bool AllocBuffer)
{
- // getbits attempts to read data from InAddr, InAddr+1, InAddr+2 positions.
- // So let's allocate two additional bytes for situation, when we need to
- // read only 1 byte from the last position of buffer and avoid a crash
- // from access to next 2 bytes, which contents we do not need.
- size_t BufSize=MAX_SIZE+2;
- InBuf=new byte[BufSize];
-
- // Ensure that we get predictable results when accessing bytes in area
- // not filled with read data.
- memset(InBuf,0,BufSize);
+ ExternalBuffer=false;
+ if (AllocBuffer)
+ {
+ // getbits32 attempts to read data from InAddr, ... InAddr+3 positions.
+ // So let's allocate 3 additional bytes for situation, when we need to
+ // read only 1 byte from the last position of buffer and avoid a crash
+ // from access to next 3 bytes, which contents we do not need.
+ size_t BufSize=MAX_SIZE+3;
+ InBuf=new byte[BufSize];
+
+ // Ensure that we get predictable results when accessing bytes in area
+ // not filled with read data.
+ memset(InBuf,0,BufSize);
+ }
+ else
+ InBuf=NULL;
}
BitInput::~BitInput()
{
- delete[] InBuf;
+ if (!ExternalBuffer)
+ delete[] InBuf;
}
@@ -33,3 +40,13 @@ uint BitInput::fgetbits()
// Function wrapped version of inline getbits to save code size.
return(getbits());
}
+
+
+void BitInput::SetExternalBuffer(byte *Buf)
+{
+ if (InBuf!=NULL && !ExternalBuffer)
+ delete[] InBuf;
+ InBuf=Buf;
+ ExternalBuffer=true;
+}
+
diff --git a/src/thirdparty/unrar/getbits.hpp b/src/thirdparty/unrar/getbits.hpp
index d44fb9f06..6a5430b0b 100644
--- a/src/thirdparty/unrar/getbits.hpp
+++ b/src/thirdparty/unrar/getbits.hpp
@@ -5,11 +5,13 @@ class BitInput
{
public:
enum BufferSize {MAX_SIZE=0x8000}; // Size of input buffer.
- protected:
+
int InAddr; // Curent byte position in the buffer.
int InBit; // Current bit position in the current byte.
+
+ bool ExternalBuffer;
public:
- BitInput();
+ BitInput(bool AllocBuffer);
~BitInput();
byte *InBuf; // Dynamically allocated input buffer.
@@ -37,6 +39,19 @@ class BitInput
BitField >>= (8-InBit);
return(BitField & 0xffff);
}
+
+ // Return 32 bits from current position in the buffer.
+ // Bit at (InAddr,InBit) has the highest position in returning data.
+ uint getbits32()
+ {
+ uint BitField=(uint)InBuf[InAddr] << 24;
+ BitField|=(uint)InBuf[InAddr+1] << 16;
+ BitField|=(uint)InBuf[InAddr+2] << 8;
+ BitField|=(uint)InBuf[InAddr+3];
+ BitField <<= InBit;
+ BitField|=(uint)InBuf[InAddr+4] >> (8-InBit);
+ return(BitField & 0xffffffff);
+ }
void faddbits(uint Bits);
uint fgetbits();
@@ -47,5 +62,7 @@ class BitInput
{
return(InAddr+IncPtr>=MAX_SIZE);
}
+
+ void SetExternalBuffer(byte *Buf);
};
#endif
diff --git a/src/thirdparty/unrar/global.hpp b/src/thirdparty/unrar/global.hpp
index 30eff082a..35c6cf913 100644
--- a/src/thirdparty/unrar/global.hpp
+++ b/src/thirdparty/unrar/global.hpp
@@ -11,5 +11,4 @@ EXTVAR ErrorHandler ErrHandler;
-
#endif
diff --git a/src/thirdparty/unrar/hardlinks.cpp b/src/thirdparty/unrar/hardlinks.cpp
new file mode 100644
index 000000000..f783e1f47
--- /dev/null
+++ b/src/thirdparty/unrar/hardlinks.cpp
@@ -0,0 +1,34 @@
+bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize)
+{
+ if (!FileExist(NameExisting))
+ return false;
+#ifdef _WIN_ALL
+ UnixSlashToDos(NameExisting,NameExisting,NameExistingSize);
+
+ bool Success=CreateHardLink(NameNew,NameExisting,NULL)!=0;
+ if (!Success)
+ {
+ ErrHandler.CreateErrorMsg(NameNew);
+ ErrHandler.SysErrMsg();
+ ErrHandler.SetErrorCode(RARX_CREATE);
+ }
+ return Success;
+#elif defined(_UNIX)
+ DosSlashToUnix(NameExisting,NameExisting,NameExistingSize);
+
+ char NameExistingA[NM],NameNewA[NM];
+ WideToChar(NameExisting,NameExistingA,ASIZE(NameExistingA));
+ WideToChar(NameNew,NameNewA,ASIZE(NameNewA));
+ bool Success=link(NameExistingA,NameNewA)==0;
+ if (!Success)
+ {
+ ErrHandler.CreateErrorMsg(NameNew);
+ ErrHandler.SysErrMsg();
+ ErrHandler.SetErrorCode(RARX_CREATE);
+ }
+ return Success;
+#else
+ return false;
+#endif
+}
+
diff --git a/src/thirdparty/unrar/hash.cpp b/src/thirdparty/unrar/hash.cpp
new file mode 100644
index 000000000..578e32fa0
--- /dev/null
+++ b/src/thirdparty/unrar/hash.cpp
@@ -0,0 +1,128 @@
+#include "rar.hpp"
+
+void HashValue::Init(HASH_TYPE Type)
+{
+ HashValue::Type=Type;
+
+ // Zero length data CRC32 is 0. It is important to set it when creating
+ // headers with no following data like directories or symlinks.
+ if (Type==HASH_RAR14 || Type==HASH_CRC32)
+ CRC32=0;
+ if (Type==HASH_BLAKE2)
+ {
+ // dd0e891776933f43c7d032b08a917e25741f8aa9a12c12e1cac8801500f2ca4f
+ // is BLAKE2sp hash of empty data. We init the structure to this value,
+ // so if we create a file or service header with no following data like
+ // "file copy" or "symlink", we set the checksum to proper value avoiding
+ // additional header type or size checks when extracting.
+ static byte EmptyHash[32]={
+ 0xdd, 0x0e, 0x89, 0x17, 0x76, 0x93, 0x3f, 0x43,
+ 0xc7, 0xd0, 0x32, 0xb0, 0x8a, 0x91, 0x7e, 0x25,
+ 0x74, 0x1f, 0x8a, 0xa9, 0xa1, 0x2c, 0x12, 0xe1,
+ 0xca, 0xc8, 0x80, 0x15, 0x00, 0xf2, 0xca, 0x4f
+ };
+ memcpy(Digest,EmptyHash,sizeof(Digest));
+ }
+}
+
+
+bool HashValue::operator == (const HashValue &cmp)
+{
+ if (Type==HASH_NONE || cmp.Type==HASH_NONE)
+ return true;
+ if (Type==HASH_RAR14 && cmp.Type==HASH_RAR14 ||
+ Type==HASH_CRC32 && cmp.Type==HASH_CRC32)
+ return CRC32==cmp.CRC32;
+ if (Type==HASH_BLAKE2 && cmp.Type==HASH_BLAKE2)
+ return memcmp(Digest,cmp.Digest,sizeof(Digest))==0;
+ return false;
+}
+
+
+DataHash::DataHash()
+{
+ HashType=HASH_NONE;
+#ifdef RAR_SMP
+ ThPool=NULL;
+ MaxThreads=0;
+#endif
+}
+
+
+DataHash::~DataHash()
+{
+#ifdef RAR_SMP
+ DestroyThreadPool(ThPool);
+#endif
+ cleandata(&blake2ctx, sizeof(blake2ctx));
+ cleandata(&CurCRC32, sizeof(CurCRC32));
+}
+
+
+void DataHash::Init(HASH_TYPE Type,uint MaxThreads)
+{
+ HashType=Type;
+ if (Type==HASH_RAR14)
+ CurCRC32=0;
+ if (Type==HASH_CRC32)
+ CurCRC32=0xffffffff; // Initial CRC32 value.
+ if (Type==HASH_BLAKE2)
+ blake2sp_init( &blake2ctx );
+#ifdef RAR_SMP
+ DataHash::MaxThreads=Min(MaxThreads,MaxHashThreads);
+#endif
+}
+
+
+void DataHash::Update(const void *Data,size_t DataSize)
+{
+#ifndef SFX_MODULE
+ if (HashType==HASH_RAR14)
+ CurCRC32=Checksum14((ushort)CurCRC32,Data,DataSize);
+#endif
+ if (HashType==HASH_CRC32)
+ CurCRC32=CRC32(CurCRC32,Data,DataSize);
+
+ if (HashType==HASH_BLAKE2)
+ {
+#ifdef RAR_SMP
+ if (MaxThreads>1 && ThPool==NULL)
+ ThPool=CreateThreadPool();
+ blake2ctx.ThPool=ThPool;
+ blake2ctx.MaxThreads=MaxThreads;
+#endif
+ blake2sp_update( &blake2ctx, (byte *)Data, DataSize);
+ }
+}
+
+
+void DataHash::Result(HashValue *Result)
+{
+ Result->Type=HashType;
+ if (HashType==HASH_RAR14)
+ Result->CRC32=CurCRC32;
+ if (HashType==HASH_CRC32)
+ Result->CRC32=CurCRC32^0xffffffff;
+ if (HashType==HASH_BLAKE2)
+ {
+ // Preserve the original context, so we can continue hashing if necessary.
+ blake2sp_state res=blake2ctx;
+ blake2sp_final( &res, Result->Digest );
+ }
+}
+
+
+uint DataHash::GetCRC32()
+{
+ return HashType==HASH_CRC32 ? CurCRC32^0xffffffff : 0;
+}
+
+
+bool DataHash::Cmp(HashValue *CmpValue,byte *Key)
+{
+ HashValue Final;
+ Result(&Final);
+ if (Key!=NULL)
+ ConvertHashToMAC(&Final,Key);
+ return Final==*CmpValue;
+}
diff --git a/src/thirdparty/unrar/hash.hpp b/src/thirdparty/unrar/hash.hpp
new file mode 100644
index 000000000..dae31d1b2
--- /dev/null
+++ b/src/thirdparty/unrar/hash.hpp
@@ -0,0 +1,52 @@
+#ifndef _RAR_DATAHASH_
+#define _RAR_DATAHASH_
+
+enum HASH_TYPE {HASH_NONE,HASH_RAR14,HASH_CRC32,HASH_BLAKE2};
+
+struct HashValue
+{
+ void Init(HASH_TYPE Type);
+ bool operator == (const HashValue &cmp);
+ bool operator != (const HashValue &cmp) {return !(*this==cmp);}
+
+ HASH_TYPE Type;
+ union
+ {
+ uint CRC32;
+ byte Digest[SHA256_DIGEST_SIZE];
+ };
+};
+
+
+#ifdef RAR_SMP
+class ThreadPool;
+class DataHash;
+#endif
+
+
+class DataHash
+{
+ private:
+ HASH_TYPE HashType;
+ uint CurCRC32;
+ blake2sp_state blake2ctx;
+
+#ifdef RAR_SMP
+ ThreadPool *ThPool;
+
+ uint MaxThreads;
+ // Upper limit for maximum threads to prevent wasting threads in pool.
+ static const uint MaxHashThreads=8;
+#endif
+ public:
+ DataHash();
+ ~DataHash();
+ void Init(HASH_TYPE Type,uint MaxThreads);
+ void Update(const void *Data,size_t DataSize);
+ void Result(HashValue *Result);
+ uint GetCRC32();
+ bool Cmp(HashValue *CmpValue,byte *Key);
+ HASH_TYPE Type() {return HashType;}
+};
+
+#endif
diff --git a/src/thirdparty/unrar/headers.cpp b/src/thirdparty/unrar/headers.cpp
new file mode 100644
index 000000000..5c8d486e2
--- /dev/null
+++ b/src/thirdparty/unrar/headers.cpp
@@ -0,0 +1,62 @@
+#include "rar.hpp"
+
+void FileHeader::Reset(size_t SubDataSize)
+{
+ SubData.Alloc(SubDataSize);
+ BaseBlock::Reset();
+#ifndef SHELL_EXT
+ FileHash.Init(HASH_NONE);
+#endif
+ mtime.Reset();
+ atime.Reset();
+ ctime.Reset();
+ SplitBefore=false;
+ SplitAfter=false;
+
+ UnknownUnpSize=0;
+
+ SubFlags=0; // Important for RAR 3.0 subhead.
+
+ CryptMethod=CRYPT_NONE;
+ Encrypted=false;
+ SaltSet=false;
+ UsePswCheck=false;
+ UseHashKey=false;
+ Lg2Count=0;
+
+ Solid=false;
+ Dir=false;
+ WinSize=0;
+ Inherited=false;
+ SubBlock=false;
+ CommentInHeader=false;
+ Version=false;
+ LargeFile=false;
+
+ RedirType=FSREDIR_NONE;
+ UnixOwnerSet=false;
+}
+
+
+FileHeader& FileHeader::operator = (FileHeader &hd)
+{
+ SubData.Reset();
+ memcpy(this,&hd,sizeof(*this));
+ SubData.CleanData();
+ SubData=hd.SubData;
+ return *this;
+}
+
+
+void MainHeader::Reset()
+{
+ HighPosAV=0;
+ PosAV=0;
+ CommentInHeader=false;
+ PackComment=false;
+ Locator=false;
+ QOpenOffset=0;
+ QOpenMaxSize=0;
+ RROffset=0;
+ RRMaxSize=0;
+}
diff --git a/src/thirdparty/unrar/headers.hpp b/src/thirdparty/unrar/headers.hpp
index 75343a258..7f15a67b6 100644
--- a/src/thirdparty/unrar/headers.hpp
+++ b/src/thirdparty/unrar/headers.hpp
@@ -1,11 +1,11 @@
#ifndef _RAR_HEADERS_
#define _RAR_HEADERS_
-#define SIZEOF_MARKHEAD 7
-#define SIZEOF_OLDMHD 7
-#define SIZEOF_NEWMHD 13
-#define SIZEOF_OLDLHD 21
-#define SIZEOF_NEWLHD 32
+#define SIZEOF_MARKHEAD3 7 // Size of RAR 4.x archive mark header.
+#define SIZEOF_MAINHEAD14 7 // Size of RAR 1.4 main archive header.
+#define SIZEOF_MAINHEAD3 13 // Size of RAR 4.x main archive header.
+#define SIZEOF_FILEHEAD14 21 // Size of RAR 1.4 file header.
+#define SIZEOF_FILEHEAD3 32 // Size of RAR 3.0 file header.
#define SIZEOF_SHORTBLOCKHEAD 7
#define SIZEOF_LONGBLOCKHEAD 11
#define SIZEOF_SUBBLOCKHEAD 14
@@ -19,20 +19,15 @@
#define SIZEOF_BEEAHEAD 24
#define SIZEOF_STREAMHEAD 26
-#define PACK_VER 29
-#define PACK_CRYPT_VER 29
-#define UNP_VER 36
-#define CRYPT_VER 29
-#define AV_VER 20
-#define PROTECT_VER 20
-
+#define VER_PACK 29
+#define VER_PACK5 0
+#define VER_UNPACK 29
+#define VER_UNPACK5 0
#define MHD_VOLUME 0x0001U
// Old style main archive comment embed into main archive header. Must not
-// be used in new archives anymore. Must never be used with MHD_ENCRYPTVER
-// or other flags changing the size of main header. RAR expects the fixed
-// size of main header preceding the comment if MHD_COMMENT is found.
+// be used in new archives anymore.
#define MHD_COMMENT 0x0002U
#define MHD_LOCK 0x0004U
@@ -43,7 +38,6 @@
#define MHD_PROTECT 0x0040U
#define MHD_PASSWORD 0x0080U
#define MHD_FIRSTVOLUME 0x0100U
-#define MHD_ENCRYPTVER 0x0200U
#define LHD_SPLIT_BEFORE 0x0001U
#define LHD_SPLIT_AFTER 0x0002U
@@ -53,6 +47,7 @@
// in new archives anymore.
#define LHD_COMMENT 0x0008U
+// For non-file subheaders it denotes 'subblock having a parent file' flag.
#define LHD_SOLID 0x0010U
@@ -71,7 +66,6 @@
#define LHD_SALT 0x0400U
#define LHD_VERSION 0x0800U
#define LHD_EXTTIME 0x1000U
-#define LHD_EXTAREA 0x2000U
#define SKIP_IF_UNKNOWN 0x4000U
#define LONG_BLOCK 0x8000U
@@ -82,85 +76,86 @@
#define EARC_VOLNUMBER 0x0008U // Store a number of current volume.
enum HEADER_TYPE {
- MARK_HEAD=0x72,MAIN_HEAD=0x73,FILE_HEAD=0x74,COMM_HEAD=0x75,AV_HEAD=0x76,
- SUB_HEAD=0x77,PROTECT_HEAD=0x78,SIGN_HEAD=0x79,NEWSUB_HEAD=0x7a,
- ENDARC_HEAD=0x7b
+ // RAR 5.0 header types.
+ HEAD_MARK=0x00, HEAD_MAIN=0x01, HEAD_FILE=0x02, HEAD_SERVICE=0x03,
+ HEAD_CRYPT=0x04, HEAD_ENDARC=0x05, HEAD_UNKNOWN=0xff,
+
+ // RAR 1.5 - 4.x header types.
+ HEAD3_MARK=0x72,HEAD3_MAIN=0x73,HEAD3_FILE=0x74,HEAD3_CMT=0x75,
+ HEAD3_AV=0x76,HEAD3_OLDSERVICE=0x77,HEAD3_PROTECT=0x78,HEAD3_SIGN=0x79,
+ HEAD3_SERVICE=0x7a,HEAD3_ENDARC=0x7b
};
enum { EA_HEAD=0x100,UO_HEAD=0x101,MAC_HEAD=0x102,BEEA_HEAD=0x103,
NTACL_HEAD=0x104,STREAM_HEAD=0x105 };
+
+// Internal implementation, depends on archive format version.
enum HOST_SYSTEM {
+ // RAR 5.0 host OS
+ HOST5_WINDOWS=0,HOST5_UNIX=1,
+
+ // RAR 3.0 host OS.
HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4,
HOST_BEOS=5,HOST_MAX
};
-#define SUBHEAD_TYPE_CMT "CMT"
-#define SUBHEAD_TYPE_ACL "ACL"
-#define SUBHEAD_TYPE_STREAM "STM"
-#define SUBHEAD_TYPE_UOWNER "UOW"
-#define SUBHEAD_TYPE_AV "AV"
-#define SUBHEAD_TYPE_RR "RR"
-#define SUBHEAD_TYPE_OS2EA "EA2"
-#define SUBHEAD_TYPE_BEOSEA "EABE"
-
-/* new file inherits a subblock when updating a host file */
-#define SUBHEAD_FLAGS_INHERITED 0x80000000
+// Unified archive format independent implementation.
+enum HOST_SYSTEM_TYPE {
+ HSYS_WINDOWS, HSYS_UNIX, HSYS_UNKNOWN
+};
-#define SUBHEAD_FLAGS_CMT_UNICODE 0x00000001
-struct OldMainHeader
-{
- byte Mark[4];
- ushort HeadSize;
- byte Flags;
+// We also use these values in extra field, so do not modify them.
+enum FILE_SYSTEM_REDIRECT {
+ FSREDIR_NONE=0, FSREDIR_UNIXSYMLINK, FSREDIR_WINSYMLINK, FSREDIR_JUNCTION,
+ FSREDIR_HARDLINK, FSREDIR_FILECOPY
};
-struct OldFileHeader
-{
- uint PackSize;
- uint UnpSize;
- ushort FileCRC;
- ushort HeadSize;
- uint FileTime;
- byte FileAttr;
- byte Flags;
- byte UnpVer;
- byte NameSize;
- byte Method;
-};
+#define SUBHEAD_TYPE_CMT L"CMT"
+#define SUBHEAD_TYPE_QOPEN L"QO"
+#define SUBHEAD_TYPE_ACL L"ACL"
+#define SUBHEAD_TYPE_STREAM L"STM"
+#define SUBHEAD_TYPE_UOWNER L"UOW"
+#define SUBHEAD_TYPE_AV L"AV"
+#define SUBHEAD_TYPE_RR L"RR"
+#define SUBHEAD_TYPE_OS2EA L"EA2"
+
+/* new file inherits a subblock when updating a host file */
+#define SUBHEAD_FLAGS_INHERITED 0x80000000
+
+#define SUBHEAD_FLAGS_CMT_UNICODE 0x00000001
struct MarkHeader
{
- byte Mark[7];
+ byte Mark[8];
+
+ // Following fields are virtual and not present in real blocks.
+ uint HeadSize;
};
struct BaseBlock
{
- ushort HeadCRC;
- HEADER_TYPE HeadType; // 1 byte.
- ushort Flags;
- ushort HeadSize;
+ uint HeadCRC; // 'ushort' for RAR 1.5.
+ HEADER_TYPE HeaderType; // 1 byte for RAR 1.5.
+ uint Flags; // 'ushort' for RAR 1.5.
+ uint HeadSize; // 'ushort' for RAR 1.5, up to 2 MB for RAR 5.0.
- bool IsSubBlock()
+ bool SkipIfUnknown;
+
+ void Reset()
{
- if (HeadType==SUB_HEAD)
- return(true);
- if (HeadType==NEWSUB_HEAD && (Flags & LHD_SOLID)!=0)
- return(true);
- return(false);
+ SkipIfUnknown=false;
}
};
+
struct BlockHeader:BaseBlock
{
- union {
- uint DataSize;
- uint PackSize;
- };
+ uint DataSize;
};
@@ -168,82 +163,141 @@ struct MainHeader:BaseBlock
{
ushort HighPosAV;
uint PosAV;
- byte EncryptVer;
+ bool CommentInHeader;
+ bool PackComment; // For RAR 1.4 archive format only.
+ bool Locator;
+ uint64 QOpenOffset; // Offset of quick list record.
+ uint64 QOpenMaxSize; // Maximum size of QOpen offset in locator extra field.
+ uint64 RROffset; // Offset of recovery record.
+ uint64 RRMaxSize; // Maximum size of RR offset in locator extra field.
+ void Reset();
};
-#define SALT_SIZE 8
-
struct FileHeader:BlockHeader
{
- uint UnpSize;
byte HostOS;
- uint FileCRC;
- uint FileTime;
byte UnpVer;
byte Method;
- ushort NameSize;
union {
uint FileAttr;
uint SubFlags;
};
-/* optional */
- uint HighPackSize;
- uint HighUnpSize;
-/* names */
- char FileName[NM];
- wchar FileNameW[NM];
-/* optional */
+ wchar FileName[NM];
+
Array<byte> SubData;
- byte Salt[SALT_SIZE];
RarTime mtime;
RarTime ctime;
RarTime atime;
- RarTime arctime;
-/* dummy */
- int64 FullPackSize;
- int64 FullUnpSize;
- void Clear(size_t SubDataSize)
- {
- SubData.Alloc(SubDataSize);
- Flags=LONG_BLOCK;
- SubFlags=0;
- }
+ int64 PackSize;
+ int64 UnpSize;
+ int64 MaxSize; // Reserve size bytes for vint of this size.
- bool CmpName(const char *Name)
- {
- return(strcmp(FileName,Name)==0);
- }
+ HashValue FileHash;
+
+ uint FileFlags;
+
+ bool SplitBefore;
+ bool SplitAfter;
+
+ bool UnknownUnpSize;
+
+ bool Encrypted;
+ CRYPT_METHOD CryptMethod;
+ bool SaltSet;
+ byte Salt[SIZE_SALT50];
+ byte InitV[SIZE_INITV];
+ bool UsePswCheck;
+ byte PswCheck[SIZE_PSWCHECK];
+
+ // Use HMAC calculated from HashKey and checksum instead of plain checksum.
+ bool UseHashKey;
+
+ // Key to convert checksum to HMAC. Derived from password with PBKDF2
+ // using additional iterations.
+ byte HashKey[SHA256_DIGEST_SIZE];
+
+ uint Lg2Count; // Log2 of PBKDF2 repetition count.
+
+ bool Solid;
+ bool Dir;
+ bool CommentInHeader; // RAR 2.0 file comment.
+ bool Version; // name.ext;ver file name containing the version number.
+ size_t WinSize;
+ bool Inherited; // New file inherits a subblock when updating a host file (for subblocks only).
- FileHeader& operator = (FileHeader &hd)
+ // 'true' if file sizes use 8 bytes instead of 4. Not used in RAR 5.0.
+ bool LargeFile;
+
+ // 'true' for HEAD_SERVICE block, which is a child of preceding file block.
+ // RAR 4.x uses 'solid' flag to indicate child subheader blocks in archives.
+ bool SubBlock;
+
+ HOST_SYSTEM_TYPE HSType;
+
+ FILE_SYSTEM_REDIRECT RedirType;
+ wchar RedirName[NM];
+ bool DirTarget;
+
+ bool UnixOwnerSet,UnixOwnerNumeric,UnixGroupNumeric;
+ char UnixOwnerName[256],UnixGroupName[256];
+#ifdef _UNIX
+ uid_t UnixOwnerID;
+ gid_t UnixGroupID;
+#else // Need these Unix fields in Windows too for 'list' command.
+ uint UnixOwnerID;
+ uint UnixGroupID;
+#endif
+
+ void Reset(size_t SubDataSize=0);
+
+ bool CmpName(const wchar *Name)
{
- SubData.Reset();
- memcpy(this,&hd,sizeof(*this));
- SubData.CleanData();
- SubData=hd.SubData;
- return(*this);
+ return(wcscmp(FileName,Name)==0);
}
+
+ FileHeader& operator = (FileHeader &hd);
};
struct EndArcHeader:BaseBlock
{
// Optional CRC32 of entire archive up to start of EndArcHeader block.
- // Present if EARC_DATACRC flag is set.
+ // Present in RAR 4.x archives if EARC_DATACRC flag is set.
uint ArcDataCRC;
- // Optional number of current volume.
- // Present if EARC_VOLNUMBER flag is set.
- ushort VolNumber;
+ uint VolNumber; // Optional number of current volume.
// 7 additional zero bytes can be stored here if EARC_REVSPACE is set.
+
+ bool NextVolume; // Not last volume.
+ bool DataCRC;
+ bool RevSpace;
+ bool StoreVolNumber;
+ void Reset()
+ {
+ BaseBlock::Reset();
+ NextVolume=false;
+ DataCRC=false;
+ RevSpace=false;
+ StoreVolNumber=false;
+ }
+};
+
+
+struct CryptHeader:BaseBlock
+{
+ bool UsePswCheck;
+ uint Lg2Count; // Log2 of PBKDF2 repetition count.
+ byte Salt[SIZE_SALT50];
+ byte PswCheck[SIZE_PSWCHECK];
};
// SubBlockHeader and its successors were used in RAR 2.x format.
-// RAR 3.x uses FileHeader with NEWSUB_HEAD HeadType for subblocks.
+// RAR 4.x uses FileHeader with HEAD_SERVICE HeaderType for subblocks.
struct SubBlockHeader:BlockHeader
{
ushort SubType;
@@ -291,8 +345,8 @@ struct UnixOwnersHeader:SubBlockHeader
ushort OwnerNameSize;
ushort GroupNameSize;
/* dummy */
- char OwnerName[NM];
- char GroupName[NM];
+ char OwnerName[256];
+ char GroupName[256];
};
@@ -312,8 +366,7 @@ struct StreamHeader:SubBlockHeader
byte Method;
uint StreamCRC;
ushort StreamNameSize;
-/* dummy */
- byte StreamName[NM];
+ char StreamName[260];
};
diff --git a/src/thirdparty/unrar/headers5.hpp b/src/thirdparty/unrar/headers5.hpp
new file mode 100644
index 000000000..4f403c216
--- /dev/null
+++ b/src/thirdparty/unrar/headers5.hpp
@@ -0,0 +1,99 @@
+#ifndef _RAR_HEADERS5_
+#define _RAR_HEADERS5_
+
+#define SIZEOF_MARKHEAD5 8 // RAR 5.0 signature length.
+#define SIZEOF_SHORTBLOCKHEAD5 7 // Smallest RAR 5.0 block size.
+
+// RAR 5.0 block flags common for all blocks.
+
+// Additional extra area is present in the end of block header.
+#define HFL_EXTRA 0x0001
+// Additional data area is present in the end of block header.
+#define HFL_DATA 0x0002
+// Unknown blocks with this flag must be skipped when updating an archive.
+#define HFL_SKIPIFUNKNOWN 0x0004
+// Data area of this block is continuing from previous volume.
+#define HFL_SPLITBEFORE 0x0008
+// Data area of this block is continuing in next volume.
+#define HFL_SPLITAFTER 0x0010
+// Block depends on preceding file block.
+#define HFL_CHILD 0x0020
+// Preserve a child block if host is modified.
+#define HFL_INHERITED 0x0040
+
+// RAR 5.0 main archive header specific flags.
+#define MHFL_VOLUME 0x0001 // Volume.
+#define MHFL_VOLNUMBER 0x0002 // Volume number field is present. True for all volumes except first.
+#define MHFL_SOLID 0x0004 // Solid archive.
+#define MHFL_PROTECT 0x0008 // Recovery record is present.
+#define MHFL_LOCK 0x0010 // Locked archive.
+
+// RAR 5.0 file header specific flags.
+#define FHFL_DIRECTORY 0x0001 // Directory.
+#define FHFL_UTIME 0x0002 // Time field in Unix format is present.
+#define FHFL_CRC32 0x0004 // CRC32 field is present.
+#define FHFL_UNPUNKNOWN 0x0008 // Unknown unpacked size.
+
+// RAR 5.0 end of archive header specific flags.
+#define EHFL_NEXTVOLUME 0x0001 // Not last volume.
+
+// RAR 5.0 archive encryption header specific flags.
+#define CHFL_CRYPT_PSWCHECK 0x0001 // Password check data is present.
+
+
+// RAR 5.0 file compression flags.
+#define FCI_ALGO_BIT0 0x0001 // Version of compression algorithm.
+#define FCI_ALGO_BIT1 0x0002 // 0 .. 63.
+#define FCI_ALGO_BIT2 0x0004
+#define FCI_ALGO_BIT3 0x0008
+#define FCI_ALGO_BIT4 0x0010
+#define FCI_ALGO_BIT5 0x0020
+#define FCI_SOLID 0x0040 // Solid flag.
+#define FCI_METHOD_BIT0 0x0080 // Compression method.
+#define FCI_METHOD_BIT1 0x0100 // 0 .. 5 (6 and 7 are not used).
+#define FCI_METHOD_BIT2 0x0200
+#define FCI_DICT_BIT0 0x0400 // Dictionary size.
+#define FCI_DICT_BIT1 0x0800 // 128 KB .. 4 GB.
+#define FCI_DICT_BIT2 0x1000
+#define FCI_DICT_BIT3 0x2000
+
+// Main header extra field values.
+#define MHEXTRA_LOCATOR 0x01 // Position of quick list and other blocks.
+
+// Flags for MHEXTRA_LOCATOR.
+#define MHEXTRA_LOCATOR_QLIST 0x01 // Quick open offset is present.
+#define MHEXTRA_LOCATOR_RR 0x02 // Recovery record offset is present.
+
+// File and service header extra field values.
+#define FHEXTRA_CRYPT 0x01 // Encryption parameters.
+#define FHEXTRA_HASH 0x02 // File hash.
+#define FHEXTRA_HTIME 0x03 // High precision file time.
+#define FHEXTRA_VERSION 0x04 // File version information.
+#define FHEXTRA_REDIR 0x05 // File system redirection (links, etc.).
+#define FHEXTRA_UOWNER 0x06 // Unix owner and group information.
+#define FHEXTRA_SUBDATA 0x07 // Service header subdata array.
+
+
+// Hash type values for FHEXTRA_HASH.
+#define FHEXTRA_HASH_BLAKE2 0x00
+
+// Flags for FHEXTRA_HTIME.
+#define FHEXTRA_HTIME_UNIXTIME 0x01 // Use Unix time_t format.
+#define FHEXTRA_HTIME_MTIME 0x02 // mtime is present.
+#define FHEXTRA_HTIME_CTIME 0x04 // ctime is present.
+#define FHEXTRA_HTIME_ATIME 0x08 // atime is present.
+
+// Flags for FHEXTRA_CRYPT.
+#define FHEXTRA_CRYPT_PSWCHECK 0x01 // Store password check data.
+#define FHEXTRA_CRYPT_HASHMAC 0x02 // Use MAC for unpacked data checksums.
+
+// Flags for FHEXTRA_REDIR.
+#define FHEXTRA_REDIR_DIR 0x01 // Link target is directory.
+
+// Flags for FHEXTRA_UOWNER.
+#define FHEXTRA_UOWNER_UNAME 0x01 // User name string is present.
+#define FHEXTRA_UOWNER_GNAME 0x02 // Group name string is present.
+#define FHEXTRA_UOWNER_NUMUID 0x04 // Numeric user ID is present.
+#define FHEXTRA_UOWNER_NUMGID 0x08 // Numeric group ID is present.
+
+#endif
diff --git a/src/thirdparty/unrar/license.txt b/src/thirdparty/unrar/license.txt
index 4fc82a7d7..0811276a1 100644
--- a/src/thirdparty/unrar/license.txt
+++ b/src/thirdparty/unrar/license.txt
@@ -24,8 +24,8 @@
to distribute UnRAR inside of other software packages.
4. THE RAR ARCHIVER AND THE UnRAR UTILITY ARE DISTRIBUTED "AS IS".
- NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT
- YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS,
+ NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT
+ YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS,
DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING
OR MISUSING THIS SOFTWARE.
diff --git a/src/thirdparty/unrar/list.cpp b/src/thirdparty/unrar/list.cpp
index 000e92d3f..abc3c7dc3 100644
--- a/src/thirdparty/unrar/list.cpp
+++ b/src/thirdparty/unrar/list.cpp
@@ -1,29 +1,28 @@
#include "rar.hpp"
-static void ListFileHeader(FileHeader &hd,bool Verbose,bool Technical,bool &TitleShown,bool Bare);
+static void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare);
static void ListSymLink(Archive &Arc);
-static void ListFileAttr(uint A,int HostOS);
+static void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize);
static void ListOldSubHeader(Archive &Arc);
-static void ListNewSubHeader(CommandData *Cmd,Archive &Arc,bool Technical);
+static void ListNewSubHeader(CommandData *Cmd,Archive &Arc);
void ListArchive(CommandData *Cmd)
{
int64 SumPackSize=0,SumUnpSize=0;
uint ArcCount=0,SumFileCount=0;
bool Technical=(Cmd->Command[1]=='T');
+ bool ShowService=Technical && Cmd->Command[2]=='A';
bool Bare=(Cmd->Command[1]=='B');
- bool Verbose=(*Cmd->Command=='V');
+ bool Verbose=(Cmd->Command[0]=='V');
- char ArcName[NM];
- wchar ArcNameW[NM];
-
- while (Cmd->GetArcName(ArcName,ArcNameW,sizeof(ArcName)))
+ wchar ArcName[NM];
+ while (Cmd->GetArcName(ArcName,ASIZE(ArcName)))
{
Archive Arc(Cmd);
#ifdef _WIN_ALL
Arc.RemoveSequentialFlag();
#endif
- if (!Arc.WOpen(ArcName,ArcNameW))
+ if (!Arc.WOpen(ArcName))
continue;
bool FileMatched=true;
while (1)
@@ -32,105 +31,111 @@ void ListArchive(CommandData *Cmd)
uint FileCount=0;
if (Arc.IsArchive(true))
{
-// if (!Arc.IsOpened())
-// break;
bool TitleShown=false;
if (!Bare)
{
Arc.ViewComment();
- mprintf("\n");
+ mprintf(L"\n%s: %s",St(MListArchive),Arc.FileName);
+ mprintf(L"\n%s: ",St(MListDetails));
+ uint SetCount=0;
+ const wchar *Fmt=Arc.Format==RARFMT14 ? L"RAR 1.4":(Arc.Format==RARFMT15 ? L"RAR 4":L"RAR 5");
+ mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", Fmt);
if (Arc.Solid)
- mprintf(St(MListSolid));
+ mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSolid));
if (Arc.SFXSize>0)
- mprintf(St(MListSFX));
+ mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSFX));
if (Arc.Volume)
- if (Arc.Solid)
- mprintf(St(MListVol1));
- else
- mprintf(St(MListVol2));
- else
- if (Arc.Solid)
- mprintf(St(MListArc1));
+ if (Arc.Format==RARFMT50)
+ {
+ // RAR 5.0 archives store the volume number in main header,
+ // so it is already available now.
+ if (SetCount++ > 0)
+ mprintf(L", ");
+ mprintf(St(MVolumeNumber),Arc.VolNumber+1);
+ }
else
- mprintf(St(MListArc2));
- mprintf(" %s\n",Arc.FileName);
- if (Technical)
- {
- if (Arc.Protected)
- mprintf(St(MListRecRec));
- if (Arc.Locked)
- mprintf(St(MListLock));
- }
+ mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListVolume));
+ if (Arc.Protected)
+ mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListRR));
+ if (Arc.Locked)
+ mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListLock));
+ if (Arc.Encrypted)
+ mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListEncHead));
+ mprintf(L"\n");
}
+
+ wchar VolNumText[50];
+ *VolNumText=0;
while(Arc.ReadHeader()>0)
{
- int HeaderType=Arc.GetHeaderType();
- if (HeaderType==ENDARC_HEAD)
+ HEADER_TYPE HeaderType=Arc.GetHeaderType();
+ if (HeaderType==HEAD_ENDARC)
+ {
+#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);
+#endif
+ if (Technical && ShowService)
+ {
+ mprintf(L"\n%12ls: %ls",St(MListService),L"EOF");
+ if (*VolNumText!=0)
+ mprintf(L"\n%12ls: %ls",St(MListFlags),VolNumText);
+ mprintf(L"\n");
+ }
break;
+ }
switch(HeaderType)
{
- case FILE_HEAD:
- IntToExt(Arc.NewLhd.FileName,Arc.NewLhd.FileName);
- FileMatched=Cmd->IsProcessFile(Arc.NewLhd)!=0;
+ case HEAD_FILE:
+ FileMatched=Cmd->IsProcessFile(Arc.FileHead)!=0;
if (FileMatched)
{
- ListFileHeader(Arc.NewLhd,Verbose,Technical,TitleShown,Bare);
- if (!(Arc.NewLhd.Flags & LHD_SPLIT_BEFORE))
+ ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare);
+ if (!Arc.FileHead.SplitBefore)
{
- TotalUnpSize+=Arc.NewLhd.FullUnpSize;
+ TotalUnpSize+=Arc.FileHead.UnpSize;
FileCount++;
}
- TotalPackSize+=Arc.NewLhd.FullPackSize;
- if (Technical)
- ListSymLink(Arc);
-#ifndef SFX_MODULE
- if (Verbose)
- Arc.ViewFileComment();
-#endif
+ TotalPackSize+=Arc.FileHead.PackSize;
}
break;
-#ifndef SFX_MODULE
- case SUB_HEAD:
- if (Technical && FileMatched && !Bare)
- ListOldSubHeader(Arc);
- break;
-#endif
- case NEWSUB_HEAD:
+ case HEAD_SERVICE:
if (FileMatched && !Bare)
{
- if (Technical)
- ListFileHeader(Arc.SubHead,Verbose,true,TitleShown,false);
- ListNewSubHeader(Cmd,Arc,Technical);
+ if (Technical && ShowService)
+ ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false);
}
break;
}
Arc.SeekToNext();
}
- if (!Bare)
+ if (!Bare && !Technical)
if (TitleShown)
{
- mprintf("\n");
- for (int I=0;I<79;I++)
- mprintf("-");
- char UnpSizeText[20];
+ wchar UnpSizeText[20];
itoa(TotalUnpSize,UnpSizeText);
- char PackSizeText[20];
+ wchar PackSizeText[20];
itoa(TotalPackSize,PackSizeText);
- mprintf("\n%5lu %16s %8s %3d%%",FileCount,UnpSizeText,
- PackSizeText,ToPercentUnlim(TotalPackSize,TotalUnpSize));
+ if (Verbose)
+ {
+ mprintf(L"\n----------- --------- -------- ----- -------- ----- -------- ----");
+ mprintf(L"\n%21ls %9ls %3d%% %-25ls %u",UnpSizeText,
+ PackSizeText,ToPercentUnlim(TotalPackSize,TotalUnpSize),
+ VolNumText,FileCount);
+ }
+ else
+ {
+ mprintf(L"\n----------- --------- -------- ----- ----");
+ mprintf(L"\n%21ls %-14ls %u",UnpSizeText,VolNumText,FileCount);
+ }
+
SumFileCount+=FileCount;
SumUnpSize+=TotalUnpSize;
SumPackSize+=TotalPackSize;
-#ifndef SFX_MODULE
- if (Arc.EndArcHead.Flags & EARC_VOLNUMBER)
- {
- mprintf(" ");
- mprintf(St(MVolumeNumber),Arc.EndArcHead.VolNumber+1);
- }
-#endif
- mprintf("\n");
+ mprintf(L"\n");
}
else
mprintf(St(MListNoFiles));
@@ -138,10 +143,9 @@ void ListArchive(CommandData *Cmd)
ArcCount++;
#ifndef NOVOLUME
- if (Cmd->VolSize!=0 && ((Arc.NewLhd.Flags & LHD_SPLIT_AFTER) ||
- Arc.GetHeaderType()==ENDARC_HEAD &&
- (Arc.EndArcHead.Flags & EARC_NEXT_VOLUME)!=0) &&
- MergeArchive(Arc,NULL,false,*Cmd->Command))
+ 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);
}
@@ -151,170 +155,281 @@ void ListArchive(CommandData *Cmd)
}
else
{
- if (Cmd->ArcNames->ItemsCount()<2 && !Bare)
+ if (Cmd->ArcNames.ItemsCount()<2 && !Bare)
mprintf(St(MNotRAR),Arc.FileName);
break;
}
}
}
- if (ArcCount>1 && !Bare)
+
+ if (ArcCount>1 && !Bare && !Technical)
{
- char UnpSizeText[20],PackSizeText[20];
+ wchar UnpSizeText[20],PackSizeText[20];
itoa(SumUnpSize,UnpSizeText);
itoa(SumPackSize,PackSizeText);
- mprintf("\n%5lu %16s %8s %3d%%\n",SumFileCount,UnpSizeText,
- PackSizeText,ToPercentUnlim(SumPackSize,SumUnpSize));
+
+ if (Verbose)
+ mprintf(L"%21ls %9ls %3d%% %26ls %u",UnpSizeText,PackSizeText,
+ ToPercentUnlim(SumPackSize,SumUnpSize),L"",SumFileCount);
+ else
+ mprintf(L"%21ls %16s %lu",UnpSizeText,L"",SumFileCount);
}
}
-void ListFileHeader(FileHeader &hd,bool Verbose,bool Technical,bool &TitleShown,bool Bare)
-{
- if (!Bare)
- {
- if (!TitleShown)
- {
- if (Verbose)
- mprintf(St(MListPathComm));
- else
- mprintf(St(MListName));
- mprintf(St(MListTitle));
- if (Technical)
- mprintf(St(MListTechTitle));
- for (int I=0;I<79;I++)
- mprintf("-");
- TitleShown=true;
- }
+enum LISTCOL_TYPE {
+ LCOL_NAME,LCOL_ATTR,LCOL_SIZE,LCOL_PACKED,LCOL_RATIO,LCOL_CSUM,LCOL_ENCR
+};
- if (hd.HeadType==NEWSUB_HEAD)
- mprintf(St(MSubHeadType),hd.FileName);
-
- mprintf("\n%c",(hd.Flags & LHD_PASSWORD) ? '*' : ' ');
- }
- char *Name=hd.FileName;
+void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare)
+{
+ wchar *Name=hd.FileName;
+ RARFORMAT Format=Arc.Format;
-#ifdef UNICODE_SUPPORTED
- char ConvertedName[NM];
- if ((hd.Flags & LHD_UNICODE)!=0 && *hd.FileNameW!=0 && UnicodeEnabled())
+ if (Bare)
{
- if (WideToChar(hd.FileNameW,ConvertedName) && *ConvertedName!=0)
- Name=ConvertedName;
+ mprintf(L"%s\n",Name);
+ return;
}
-#endif
- if (Bare)
+ if (!TitleShown && !Technical)
{
- mprintf("%s\n",Verbose ? Name:PointToName(Name));
- return;
+ if (Verbose)
+ {
+ mprintf(L"\n%ls",St(MListTitleV));
+ mprintf(L"\n----------- --------- -------- ----- -------- ----- -------- ----");
+ }
+ else
+ {
+ mprintf(L"\n%ls",St(MListTitleL));
+ mprintf(L"\n----------- --------- -------- ----- ----");
+ }
+ TitleShown=true;
}
- if (Verbose)
- mprintf("%s\n%12s ",Name,"");
+ wchar UnpSizeText[20],PackSizeText[20];
+ if (hd.UnpSize==INT64NDF)
+ wcscpy(UnpSizeText,L"?");
else
- mprintf("%-12s",PointToName(Name));
+ itoa(hd.UnpSize,UnpSizeText);
+ itoa(hd.PackSize,PackSizeText);
- char UnpSizeText[20],PackSizeText[20];
- if (hd.FullUnpSize==INT64NDF)
- strcpy(UnpSizeText,"?");
+ wchar AttrStr[30];
+ if (hd.HeaderType==HEAD_SERVICE)
+ swprintf(AttrStr,ASIZE(AttrStr),L"%cB",hd.Inherited ? 'I' : '.');
else
- itoa(hd.FullUnpSize,UnpSizeText);
- itoa(hd.FullPackSize,PackSizeText);
+ ListFileAttr(hd.FileAttr,hd.HSType,AttrStr,ASIZE(AttrStr));
- mprintf(" %8s %8s ",UnpSizeText,PackSizeText);
+ wchar RatioStr[10];
- if ((hd.Flags & LHD_SPLIT_BEFORE) && (hd.Flags & LHD_SPLIT_AFTER))
- mprintf(" <->");
+ if (hd.SplitBefore && hd.SplitAfter)
+ wcscpy(RatioStr,L"<->");
else
- if (hd.Flags & LHD_SPLIT_BEFORE)
- mprintf(" <--");
+ if (hd.SplitBefore)
+ wcscpy(RatioStr,L"<--");
else
- if (hd.Flags & LHD_SPLIT_AFTER)
- mprintf(" -->");
+ if (hd.SplitAfter)
+ wcscpy(RatioStr,L"-->");
else
- mprintf("%3d%%",ToPercentUnlim(hd.FullPackSize,hd.FullUnpSize));
+ swprintf(RatioStr,ASIZE(RatioStr),L"%d%%",ToPercentUnlim(hd.PackSize,hd.UnpSize));
- char DateStr[50];
- hd.mtime.GetText(DateStr,false);
- mprintf(" %s ",DateStr);
+ wchar DateStr[50];
+ hd.mtime.GetText(DateStr,ASIZE(DateStr),Technical,Technical);
- if (hd.HeadType==NEWSUB_HEAD)
- mprintf(" %c....B ",(hd.SubFlags & SUBHEAD_FLAGS_INHERITED) ? 'I' : '.');
- else
- ListFileAttr(hd.FileAttr,hd.HostOS);
+ if (Technical)
+ {
+ mprintf(L"\n%12s: %s",St(MListName),Name);
- mprintf(" %8.8X",hd.FileCRC);
- mprintf(" m%d",hd.Method-0x30);
- if ((hd.Flags & LHD_WINDOWMASK)<=6*32)
- mprintf("%c",((hd.Flags&LHD_WINDOWMASK)>>5)+'a');
- else
- mprintf(" ");
- mprintf(" %d.%d",hd.UnpVer/10,hd.UnpVer%10);
+ bool FileBlock=hd.HeaderType==HEAD_FILE;
- static const char *RarOS[]={
- "DOS","OS/2","Windows","Unix","Mac OS","BeOS","WinCE","","",""
- };
+ if (!FileBlock && Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM))
+ {
+ mprintf(L"\n%12ls: %ls",St(MListType),St(MListStream));
+ wchar StreamName[NM];
+ GetStreamNameNTFS(Arc,StreamName,ASIZE(StreamName));
+ mprintf(L"\n%12ls: %ls",St(MListTarget),StreamName);
+ }
+ else
+ {
+ const wchar *Type=St(FileBlock ? (hd.Dir ? MListDir:MListFile):MListService);
+
+ if (hd.RedirType!=FSREDIR_NONE)
+ switch(hd.RedirType)
+ {
+ case FSREDIR_UNIXSYMLINK:
+ Type=St(MListUSymlink); break;
+ case FSREDIR_WINSYMLINK:
+ Type=St(MListWSymlink); break;
+ case FSREDIR_JUNCTION:
+ Type=St(MListJunction); break;
+ case FSREDIR_HARDLINK:
+ Type=St(MListHardlink); break;
+ case FSREDIR_FILECOPY:
+ Type=St(MListCopy); break;
+ }
+ mprintf(L"\n%12ls: %ls",St(MListType),Type);
+ if (hd.RedirType!=FSREDIR_NONE)
+ mprintf(L"\n%12ls: %ls",St(MListTarget),hd.RedirName);
+ }
+ if (!hd.Dir)
+ {
+ mprintf(L"\n%12ls: %ls",St(MListSize),UnpSizeText);
+ mprintf(L"\n%12ls: %ls",St(MListPacked),PackSizeText);
+ mprintf(L"\n%12ls: %ls",St(MListRatio),RatioStr);
+ }
+ if (hd.mtime.IsSet())
+ mprintf(L"\n%12ls: %ls",St(MListMtime),DateStr);
+ if (hd.ctime.IsSet())
+ {
+ hd.ctime.GetText(DateStr,ASIZE(DateStr),true,true);
+ mprintf(L"\n%12ls: %ls",St(MListCtime),DateStr);
+ }
+ if (hd.atime.IsSet())
+ {
+ hd.atime.GetText(DateStr,ASIZE(DateStr),true,true);
+ mprintf(L"\n%12ls: %ls",St(MListAtime),DateStr);
+ }
+ mprintf(L"\n%12ls: %ls",St(MListAttr),AttrStr);
+ if (hd.FileHash.Type==HASH_CRC32)
+ mprintf(L"\n%12ls: %8.8X",
+ hd.UseHashKey ? L"CRC32 MAC":hd.SplitAfter ? L"Pack-CRC32":L"CRC32",
+ hd.FileHash.CRC32);
+ if (hd.FileHash.Type==HASH_BLAKE2)
+ {
+ wchar BlakeStr[BLAKE2_DIGEST_SIZE*2+1];
+ BinToHex(hd.FileHash.Digest,BLAKE2_DIGEST_SIZE,NULL,BlakeStr,ASIZE(BlakeStr));
+ mprintf(L"\n%12ls: %ls",
+ hd.UseHashKey ? L"BLAKE2 MAC":hd.SplitAfter ? L"Pack-BLAKE2":L"BLAKE2",
+ BlakeStr);
+ }
- if (Technical)
- mprintf("\n%22s %8s %4s",
- (hd.HostOS<ASIZE(RarOS) ? RarOS[hd.HostOS]:""),
- (hd.Flags & LHD_SOLID) ? St(MYes):St(MNo),
- (hd.Flags & LHD_VERSION) ? St(MYes):St(MNo));
-}
+ const wchar *HostOS=L"";
+ if (Format==RARFMT50 && hd.HSType!=HSYS_UNKNOWN)
+ HostOS=hd.HSType==HSYS_WINDOWS ? L"Windows":L"Unix";
+ if (Format==RARFMT15)
+ {
+ static const wchar *RarOS[]={
+ L"DOS",L"OS/2",L"Windows",L"Unix",L"Mac OS",L"BeOS",L"WinCE",L"",L"",L""
+ };
+ if (hd.HostOS<ASIZE(RarOS))
+ HostOS=RarOS[hd.HostOS];
+ }
+ if (*HostOS!=0)
+ mprintf(L"\n%12ls: %ls",St(MListHostOS),HostOS);
+ mprintf(L"\n%12ls: RAR %ls(v%d) -m%d -md=%d%s",St(MListCompInfo),
+ Format==RARFMT15 ? L"3.0":L"5.0",hd.UnpVer,hd.Method,
+ hd.WinSize>=0x100000 ? hd.WinSize/0x100000:hd.WinSize/0x400,
+ hd.WinSize>=0x100000 ? L"M":L"K");
-void ListSymLink(Archive &Arc)
-{
- if (Arc.NewLhd.HostOS==HOST_UNIX && (Arc.NewLhd.FileAttr & 0xF000)==0xA000)
- if ((Arc.NewLhd.Flags & LHD_PASSWORD)==0)
+ if (hd.Solid || hd.Encrypted)
{
- char FileName[NM];
- int DataSize=Min(Arc.NewLhd.PackSize,sizeof(FileName)-1);
- Arc.Read(FileName,DataSize);
- FileName[DataSize]=0;
- mprintf("\n%22s %s","-->",FileName);
+ mprintf(L"\n%12ls: ",St(MListFlags));
+ if (hd.Solid)
+ mprintf(L"%ls ",St(MListSolid));
+ if (hd.Encrypted)
+ mprintf(L"%ls ",St(MListEnc));
+ }
+
+ if (hd.Version)
+ {
+ uint Version=ParseVersionFileName(Name,false);
+ if (Version!=0)
+ mprintf(L"\n%12ls: %u",St(MListFileVer),Version);
+ }
+
+ if (hd.UnixOwnerSet)
+ {
+ mprintf(L"\n%12ls: ",L"Unix owner");
+ if (*hd.UnixOwnerName!=0)
+ mprintf(L"%ls:",GetWide(hd.UnixOwnerName));
+ if (*hd.UnixGroupName!=0)
+ mprintf(L"%ls",GetWide(hd.UnixGroupName));
+ if ((*hd.UnixOwnerName!=0 || *hd.UnixGroupName!=0) && (hd.UnixOwnerNumeric || hd.UnixGroupNumeric))
+ mprintf(L" ");
+ if (hd.UnixOwnerNumeric)
+ mprintf(L"#%d:",hd.UnixOwnerID);
+ if (hd.UnixGroupNumeric)
+ mprintf(L"#%d:",hd.UnixGroupID);
}
+
+ mprintf(L"\n");
+ return;
+ }
+
+ mprintf(L"\n%c%10ls %9ls ",hd.Encrypted ? '*' : ' ',AttrStr,UnpSizeText);
+
+ if (Verbose)
+ mprintf(L"%9ls %4ls ",PackSizeText,RatioStr);
+
+ mprintf(L" %ls ",DateStr);
+
+ if (Verbose)
+ {
+ if (hd.FileHash.Type==HASH_CRC32)
+ mprintf(L"%8.8X ",hd.FileHash.CRC32);
else
+ if (hd.FileHash.Type==HASH_BLAKE2)
+ {
+ byte *S=hd.FileHash.Digest;
+ mprintf(L"%02x%02x..%02x ",S[0],S[1],S[31]);
+ }
+ else
+ mprintf(L"???????? ");
+ }
+ mprintf(L"%-12ls",Name);
+}
+
+/*
+void ListSymLink(Archive &Arc)
+{
+ if (Arc.FileHead.HSType==HSYS_UNIX && (Arc.FileHead.FileAttr & 0xF000)==0xA000)
+ if (Arc.FileHead.Encrypted)
{
// Link data are encrypted. We would need to ask for password
// and initialize decryption routine to display the link target.
- mprintf("\n%22s %s","-->","*<-?->");
+ mprintf(L"\n%22ls %ls",L"-->",L"*<-?->");
+ }
+ else
+ {
+ char FileName[NM];
+ uint DataSize=(uint)Min(Arc.FileHead.PackSize,sizeof(FileName)-1);
+ Arc.Read(FileName,DataSize);
+ FileName[DataSize]=0;
+ mprintf(L"\n%22ls %ls",L"-->",GetWide(FileName));
}
}
+*/
-
-void ListFileAttr(uint A,int HostOS)
+void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize)
{
- switch(HostOS)
+ switch(HostType)
{
- case HOST_MSDOS:
- case HOST_OS2:
- case HOST_WIN32:
- case HOST_MACOS:
- mprintf(" %c%c%c%c%c%c%c ",
- (A & 0x08) ? 'V' : '.',
- (A & 0x10) ? 'D' : '.',
- (A & 0x01) ? 'R' : '.',
- (A & 0x02) ? 'H' : '.',
- (A & 0x04) ? 'S' : '.',
- (A & 0x20) ? 'A' : '.',
- (A & 0x800) ? 'C' : '.');
+ 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.
break;
- case HOST_UNIX:
- case HOST_BEOS:
+ case HSYS_UNIX:
switch (A & 0xF000)
{
case 0x4000:
- mprintf("d");
+ AttrStr[0]='d';
break;
case 0xA000:
- mprintf("l");
+ AttrStr[0]='l';
break;
default:
- mprintf("-");
+ AttrStr[0]='-';
break;
}
- mprintf("%c%c%c%c%c%c%c%c%c",
+ 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':'-'),
@@ -325,67 +440,8 @@ void ListFileAttr(uint A,int HostOS)
(A & 0x0002) ? 'w' : '-',
(A & 0x0001) ? 'x' : '-');
break;
- }
-}
-
-
-#ifndef SFX_MODULE
-void ListOldSubHeader(Archive &Arc)
-{
- switch(Arc.SubBlockHead.SubType)
- {
- case EA_HEAD:
- mprintf(St(MListEAHead));
- break;
- case UO_HEAD:
- mprintf(St(MListUOHead),Arc.UOHead.OwnerName,Arc.UOHead.GroupName);
- break;
- case MAC_HEAD:
- mprintf(St(MListMACHead1),Arc.MACHead.fileType>>24,Arc.MACHead.fileType>>16,Arc.MACHead.fileType>>8,Arc.MACHead.fileType);
- mprintf(St(MListMACHead2),Arc.MACHead.fileCreator>>24,Arc.MACHead.fileCreator>>16,Arc.MACHead.fileCreator>>8,Arc.MACHead.fileCreator);
+ case HSYS_UNKNOWN:
+ wcscpy(AttrStr,L"?");
break;
- case BEEA_HEAD:
- mprintf(St(MListBeEAHead));
- break;
- case NTACL_HEAD:
- mprintf(St(MListNTACLHead));
- break;
- case STREAM_HEAD:
- mprintf(St(MListStrmHead),Arc.StreamHead.StreamName);
- break;
- default:
- mprintf(St(MListUnkHead),Arc.SubBlockHead.SubType);
- break;
- }
-}
-#endif
-
-
-void ListNewSubHeader(CommandData *Cmd,Archive &Arc,bool Technical)
-{
- if (Arc.SubHead.CmpName(SUBHEAD_TYPE_CMT) &&
- (Arc.SubHead.Flags & LHD_SPLIT_BEFORE)==0 && !Cmd->DisableComment)
- {
- Array<byte> CmtData;
- size_t ReadSize=Arc.ReadCommentData(&CmtData,NULL);
- if (ReadSize!=0)
- {
- mprintf(St(MFileComment));
- OutComment((char *)&CmtData[0],ReadSize);
- }
- }
- if (Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM) &&
- (Arc.SubHead.Flags & LHD_SPLIT_BEFORE)==0)
- {
- size_t DestSize=Arc.SubHead.SubData.Size()/2;
- wchar DestNameW[NM];
- char DestName[NM];
- if (DestSize<sizeof(DestName))
- {
- RawToWide(&Arc.SubHead.SubData[0],DestNameW,DestSize);
- DestNameW[DestSize]=0;
- WideToChar(DestNameW,DestName);
- mprintf("\n %s",DestName);
- }
}
}
diff --git a/src/thirdparty/unrar/loclang.hpp b/src/thirdparty/unrar/loclang.hpp
index 2d69b3972..2d84c44ac 100644
--- a/src/thirdparty/unrar/loclang.hpp
+++ b/src/thirdparty/unrar/loclang.hpp
@@ -27,15 +27,14 @@
#define MCHelpCmd "\n\n<Commands>"
#define MCHelpCmdA "\n a Add files to archive"
#define MCHelpCmdC "\n c Add archive comment"
-#define MCHelpCmdCF "\n cf Add files comment"
#define MCHelpCmdCH "\n ch Change archive parameters"
#define MCHelpCmdCW "\n cw Write archive comment to file"
#define MCHelpCmdD "\n d Delete files from archive"
-#define MCHelpCmdE "\n e Extract files to current directory"
+#define MCHelpCmdE "\n e Extract files without archived paths"
#define MCHelpCmdF "\n f Freshen files in archive"
#define MCHelpCmdI "\n i[par]=<str> Find string in archives"
#define MCHelpCmdK "\n k Lock archive"
-#define MCHelpCmdL "\n l[t,b] List archive [technical, bare]"
+#define MCHelpCmdL "\n l[t[a],b] List archive contents [technical[all], bare]"
#define MCHelpCmdM "\n m[f] Move to archive [files only]"
#define MCHelpCmdP "\n p Print file to stdout"
#define MCHelpCmdR "\n r Repair archive"
@@ -46,7 +45,7 @@
#define MCHelpCmdS "\n s[name|-] Convert archive to or from SFX"
#define MCHelpCmdT "\n t Test archive files"
#define MCHelpCmdU "\n u Update files in archive"
-#define MCHelpCmdV "\n v[t,b] Verbosely list archive [technical,bare]"
+#define MCHelpCmdV "\n v[t[a],b] Verbosely list archive contents [technical[all],bare]"
#define MCHelpCmdX "\n x Extract files with full path"
#define MCHelpSw "\n\n<Switches>"
#define MCHelpSwm "\n - Stop switches scanning"
@@ -58,8 +57,6 @@
#define MCHelpSwAO "\n ao Add files with Archive attribute set"
#define MCHelpSwAP "\n ap<path> Set path inside archive"
#define MCHelpSwAS "\n as Synchronize archive contents"
-#define MCHelpSwAV "\n av Put authenticity verification (registered versions only)"
-#define MCHelpSwAVm "\n av- Disable authenticity verification check"
#define MCHelpSwCm "\n c- Disable comments show"
#define MCHelpSwCFGm "\n cfg- Disable read configuration"
#define MCHelpSwCL "\n cl Convert names to lower case"
@@ -79,6 +76,7 @@
#define MCHelpSwEP3 "\n ep3 Expand paths to full including the drive letter"
#define MCHelpSwF "\n f Freshen files"
#define MCHelpSwHP "\n hp[password] Encrypt both file data and headers"
+#define MCHelpSwHT "\n ht[b|c] Select hash type [BLAKE2,CRC32] for file checksum"
#define MCHelpSwIDP "\n id[c,d,p,q] Disable messages"
#define MCHelpSwIEML "\n ieml[addr] Send archive by email"
#define MCHelpSwIERR "\n ierr Send all messages to stderr"
@@ -90,21 +88,25 @@
#define MCHelpSwKB "\n kb Keep broken extracted files"
#define MCHelpSwLog "\n log[f][=name] Write names to log file"
#define MCHelpSwMn "\n m<0..5> Set compression level (0-store...3-default...5-maximal)"
+#define MCHelpSwMA "\n ma[4|5] Specify a version of archiving format"
#define MCHelpSwMC "\n mc<par> Set advanced compression parameters"
-#define MCHelpSwMD "\n md<size> Dictionary size in KB (64,128,256,512,1024,2048,4096 or A-G)"
+#define MCHelpSwMD "\n md<n>[k,m,g] Dictionary size in KB, MB or GB"
#define MCHelpSwMS "\n ms[ext;ext] Specify file types to store"
#define MCHelpSwMT "\n mt<threads> Set the number of threads"
-#define MCHelpSwN "\n n<file> Include only specified file"
-#define MCHelpSwNa "\n n@ Read file names to include from stdin"
-#define MCHelpSwNal "\n n@<list> Include files listed in specified list file"
+#define MCHelpSwN "\n n<file> Additionally filter included files"
+#define MCHelpSwNa "\n n@ Read additional filter masks from stdin"
+#define MCHelpSwNal "\n n@<list> Read additional filter masks from list file"
#define MCHelpSwO "\n o[+|-] Set the overwrite mode"
#define MCHelpSwOC "\n oc Set NTFS Compressed attribute"
+#define MCHelpSwOH "\n oh Save hard links as the link instead of the file"
+#define MCHelpSwOI "\n oi[0-4][:min] Save identical files as references"
#define MCHelpSwOL "\n ol Save symbolic links as the link instead of the file"
#define MCHelpSwOR "\n or Rename files automatically"
#define MCHelpSwOS "\n os Save NTFS streams"
#define MCHelpSwOW "\n ow Save or restore file owner and group"
#define MCHelpSwP "\n p[password] Set password"
#define MCHelpSwPm "\n p- Do not query password"
+#define MCHelpSwQO "\n qo[-|+] Add quick open information [none|force]"
#define MCHelpSwR "\n r Recurse subdirectories"
#define MCHelpSwRm "\n r- Disable recursion"
#define MCHelpSwR0 "\n r0 Recurse subdirectories for wildcard names only"
@@ -142,9 +144,8 @@
#define MCHelpSwZ "\n z[file] Read archive comment from file"
#define MBadArc "\nERROR: Bad archive %s\n"
#define MAskPsw "Enter password (will not be echoed)"
-#define MAskPswEcho "Enter password"
+#define MAskPswFor "\nEnter password (will not be echoed) for %s: "
#define MReAskPsw "\nReenter password: "
-#define MFor " for "
#define MNotMatchPsw "\nERROR: Passwords do not match\n"
#define MErrWrite "Write error in the file %s"
#define MErrRead "Read error in the file %s"
@@ -180,14 +181,6 @@
#define MNotMdfOld "\n\nERROR: Cannot modify old format archive"
#define MNotMdfLock "\n\nERROR: Locked archive"
#define MNotMdfVol "\n\nERROR: Cannot modify volume"
-#define MVerifyAV "\nVerifying authenticity information ... "
-#define MFailedAV " Failed\n"
-#define MStrAV1 "\n\nArchive %s"
-#define MStrAV2 "\ncreated at %s"
-#define MStrAV3 "\nby %s\n"
-#define MLogFailedAV "Invalid authenticity information"
-#define MAddingAV "\nAdding authenticity verification "
-#define MAVOldStyle "\n\nOld style authenticity information"
#define MPackAskReg "\nEvaluation copy. Please register.\n"
#define MCreateArchive "\nCreating %sarchive %s\n"
#define MUpdateArchive "\nUpdating %sarchive %s\n"
@@ -211,7 +204,7 @@
#define MCannotMdfEncrSol "\nCannot modify solid archive containing encrypted files"
#define MAddAnalyze "\nAnalyzing archived files: "
#define MRepacking "\nRepacking archived files: "
-#define MCRCFailed "\n%-20s - CRC failed"
+#define MCRCFailed "\n%-20s - checksum error"
#define MExtrTest "\n\nTesting archive %s\n"
#define MExtracting "\n\nExtracting from %s\n"
#define MUseCurPsw "\n%s - use current password ?"
@@ -222,14 +215,15 @@
#define MExtrPoints "\n... %-56s"
#define MExtrErrMkDir "\nCannot create directory %s"
#define MExtrPrinting "\n------ Printing %s\n\n"
-#define MEncrBadCRC "\nCRC failed in the encrypted file %s. Corrupt file or wrong password."
+#define MEncrBadCRC "\nChecksum error in the encrypted file %s. Corrupt file or wrong password."
#define MExtrNoFiles "\nNo files to extract"
#define MExtrAllOk "\nAll OK"
#define MExtrTotalErr "\nTotal errors: %ld"
#define MFileExists "\n\n%s already exists. Overwrite it ?"
#define MAskOverwrite "\nOverwrite %s ?"
#define MAskNewName "\nEnter new name: "
-#define MLogMainHead "\nThe archive header is corrupt"
+#define MHeaderBroken "\nCorrupt header is found"
+#define MMainHeaderBroken "\nMain archive header is corrupt"
#define MLogFileHead "\n%s - the file header is corrupt"
#define MLogCommHead "\nThe comment header is corrupt\n"
#define MLogProtectHead "The data recovery header is corrupt"
@@ -241,7 +235,6 @@
#define MAskFComm "\n\nReading comment for %s : %s from stdin\n"
#define MLogCommBrk "\nThe archive comment is corrupt"
#define MCommAskCont "\nPress 'Enter' to continue or 'Q' to quit:"
-#define MLogBrokFCmt "\nThe file comment is corrupt"
#define MWriteCommTo "\nWrite comment to %s"
#define MCommNotPres "\nComment is not present"
#define MDelFrom "\nDeleting from %s"
@@ -250,18 +243,40 @@
#define MNoDelFiles "\nNo files to delete"
#define MLogTitle "\n\n-------- %2d %s %d, archive %s\n"
#define MPathTooLong "\nERROR: Path too long\n"
-#define MListSolid "Solid "
-#define MListSFX "SFX "
-#define MListVol1 "volume"
-#define MListVol2 "Volume"
-#define MListArc1 "archive"
-#define MListArc2 "Archive"
-#define MListRecRec "\nRecovery record is present\n"
-#define MListLock "\nLock is present\n"
-#define MListPathComm "\nPathname/Comment\n "
-#define MListName "\n Name "
-#define MListTitle " Size Packed Ratio Date Time Attr CRC Meth Ver\n"
-#define MListTechTitle " Host OS Solid Old\n"
+#define MListArchive "Archive"
+#define MListDetails "Details"
+#define MListSolid "solid"
+#define MListSFX "SFX"
+#define MListVolume "volume"
+#define MListRR "recovery record"
+#define MListLock "lock"
+#define MListEnc "encrypted"
+#define MListEncHead "encrypted headers"
+#define MListTitleL " Attributes Size Date Time Name"
+#define MListTitleV " Attributes Size Packed Ratio Date Time Checksum Name"
+#define MListName "Name"
+#define MListType "Type"
+#define MListFile "File"
+#define MListDir "Directory"
+#define MListUSymlink "Unix symbolic link"
+#define MListWSymlink "Windows symbolic link"
+#define MListJunction "NTFS junction point"
+#define MListHardlink "Hard link"
+#define MListCopy "File copy"
+#define MListStream "NTFS alternate data stream"
+#define MListTarget "Target"
+#define MListSize "Size"
+#define MListPacked "Packed size"
+#define MListRatio "Ratio"
+#define MListMtime "mtime"
+#define MListCtime "ctime"
+#define MListAtime "atime"
+#define MListAttr "Attributes"
+#define MListFlags "Flags"
+#define MListCompInfo "Compression"
+#define MListHostOS "Host OS"
+#define MListFileVer "File version"
+#define MListService "Service"
#define MListEAHead "\n OS/2 extended attributes"
#define MListUOHead "\n Unix Owner/Group data: %-14s %-14s"
#define MListBeEAHead "\n BeOS extended attributes"
@@ -278,10 +293,6 @@
#define MRprFind "\nFound %s"
#define MRprAskIsSol "\nThe archive header is corrupt. Mark archive as solid ?"
#define MRprNoFiles "\nNo files found"
-#define MRprSuspEntry "\n\nSuspicious entry %s"
-#define MRprDir "\nDirectory"
-#define MRprSuspSize "\nSize %ld Packed %ld"
-#define MRprSuspAdd "\nAdd it to archive ?"
#define MLogUnexpEOF "\nUnexpected end of archive"
#define MRepAskReconst "\nReconstruct archive structure ?"
#define MRecScanning "\nScanning..."
@@ -303,7 +314,7 @@
#define MAskRetryCreate "\nCannot create %s. Retry ?"
#define MListMACHead1 "\n Mac OS file type: %c%c%c%c ; "
#define MListMACHead2 "file creator: %c%c%c%c\n"
-#define MDataBadCRC "\n%-20s : packed data CRC failed in volume %s"
+#define MDataBadCRC "\n%-20s : packed data checksum error in volume %s"
#define MFileRO "\n%s is read-only"
#define MACLGetError "\nWARNING: Cannot get %s security data\n"
#define MACLSetError "\nWARNING: Cannot set %s security data\n"
@@ -348,10 +359,26 @@
#define MSHelpCmdT "\n -t Test archive files"
#define MSHelpCmdV "\n -v Verbosely list contents of archive"
#define MMaxPathLimit "\nTotal path and file name length must not exceed %d characters"
-#define MRecVolLimit "\nTotal number of usual and recovery volumes must not exceed 255"
+#define MRecVolLimit "\nTotal number of usual and recovery volumes must not exceed %d"
#define MVolumeNumber "volume %d"
#define MCannotDelete "\nCannot delete %s"
-#define MCalcCRC "\nCalculating the control sum"
+#define MCalcCRC "\nCalculating the checksum"
#define MTooLargeSFXArc "\nWARNING: Too large SFX archive. Windows cannot run the executable file exceeding 4 GB."
-#define MCalcCRCAllVol "\nCalculating control sums of all volumes."
+#define MCalcCRCAllVol "\nCalculating checksums of all volumes."
#define MNotEnoughDisk "\nERROR: Not enough disk space for %s."
+#define MNewerRAR "\nYou may need a newer version of RAR."
+#define MUnkEncMethod "\nUnknown encryption method in %s"
+#define MWrongPassword "\nThe specified password is incorrect."
+#define MRepairing "\nRepairing"
+#define MAreaDamaged "\nCorrupt %d bytes at %08x %08x"
+#define MBlocksRecovered "\n%d blocks recovered."
+#define MRRDamaged "\nRecovery record is corrupt."
+#define MTestingRR "\nTesting the recovery record"
+#define MFailed "Failed"
+#define MIncompatSwitch "\n%s switch is not supported for RAR %d.x archive format."
+#define MSearchDupFiles "\nSearching for identical files"
+#define MNumFound "%d found."
+#define MUnknownExtra "\nUnknown extra field in %s."
+#define MCopyError "\nCannot copy %s to %s."
+#define MCopyErrorHint "\nYou need to unpack the entire archive to create file copy entries."
+#define MCopyingData "\nCopying data"
diff --git a/src/thirdparty/unrar/log.cpp b/src/thirdparty/unrar/log.cpp
index 966e9de15..b84980116 100644
--- a/src/thirdparty/unrar/log.cpp
+++ b/src/thirdparty/unrar/log.cpp
@@ -1,23 +1,34 @@
#include "rar.hpp"
-static char LogName[NM];
+static wchar LogName[NM];
-void InitLogOptions(char *LogName)
+void InitLogOptions(const wchar *LogFileName)
{
- strcpy(::LogName,LogName);
+ wcsncpyz(LogName,LogFileName,ASIZE(LogName));
}
#ifndef SILENT
-void Log(const char *ArcName,const char *Format,...)
+void Log(const wchar *ArcName,const wchar *fmt,...)
{
- safebuf char Msg[2*NM+1024];
- va_list ArgPtr;
- va_start(ArgPtr,Format);
- vsprintf(Msg,Format,ArgPtr);
- va_end(ArgPtr);
- eprintf("%s",Msg);
+ // Preserve the error code for possible following system error message.
+ int Code=ErrHandler.GetSystemErrorCode();
+
+ Alarm();
+
+ // This buffer is for format string only, not for entire output,
+ // so it can be short enough.
+ wchar fmtw[1024];
+ PrintfPrepareFmt(fmt,fmtw,ASIZE(fmtw));
+
+ safebuf wchar Msg[2*NM+1024];
+ va_list arglist;
+ va_start(arglist,fmt);
+ vswprintf(Msg,ASIZE(Msg),fmtw,arglist);
+ va_end(arglist);
+ eprintf(L"%ls",Msg);
+ ErrHandler.SetSystemErrorCode(Code);
}
#endif
diff --git a/src/thirdparty/unrar/log.hpp b/src/thirdparty/unrar/log.hpp
index 52d6b8d56..c10c5c873 100644
--- a/src/thirdparty/unrar/log.hpp
+++ b/src/thirdparty/unrar/log.hpp
@@ -1,18 +1,12 @@
#ifndef _RAR_LOG_
#define _RAR_LOG_
-void InitLogOptions(char *LogName);
-
-#ifndef SILENT
-void Log(const char *ArcName,const char *Format,...);
-#endif
+void InitLogOptions(const wchar *LogFileName);
#ifdef SILENT
-#ifdef __GNUC__
-#define Log(args...)
+inline void Log(const wchar *ArcName,const wchar *fmt,...) {}
#else
-inline void Log(const char *a,const char *b,const char *c=NULL,const char *d=NULL) {}
-#endif
+void Log(const wchar *ArcName,const wchar *fmt,...);
#endif
#endif
diff --git a/src/thirdparty/unrar/match.cpp b/src/thirdparty/unrar/match.cpp
index 4d5a1d053..3486b0e2d 100644
--- a/src/thirdparty/unrar/match.cpp
+++ b/src/thirdparty/unrar/match.cpp
@@ -1,98 +1,21 @@
#include "rar.hpp"
-static bool match(const char *pattern,const char *string,bool ForceCase);
static bool match(const wchar *pattern,const wchar *string,bool ForceCase);
-
-static int mstricompc(const char *Str1,const char *Str2,bool ForceCase);
static int mwcsicompc(const wchar *Str1,const wchar *Str2,bool ForceCase);
-static int mstrnicompc(const char *Str1,const char *Str2,size_t N,bool ForceCase);
static int mwcsnicompc(const wchar *Str1,const wchar *Str2,size_t N,bool ForceCase);
-inline uint toupperc(byte ch,bool ForceCase)
-{
- if (ForceCase)
- return(ch);
-#ifdef _WIN_ALL
- return((uint)(LPARAM)CharUpper((LPTSTR)(ch)));
-#elif defined(_UNIX)
- return(ch);
-#else
- return(toupper(ch));
-#endif
-}
-
-
inline uint touppercw(uint ch,bool ForceCase)
{
if (ForceCase)
- return(ch);
+ return ch;
#if defined(_UNIX)
- return(ch);
+ return ch;
#else
- return(toupperw(ch));
+ return toupperw(ch);
#endif
}
-bool CmpName(const char *Wildcard,const char *Name,int CmpMode)
-{
- bool ForceCase=(CmpMode&MATCH_FORCECASESENSITIVE)!=0;
-
- CmpMode&=MATCH_MODEMASK;
-
- if (CmpMode!=MATCH_NAMES)
- {
- size_t WildLength=strlen(Wildcard);
- if (CmpMode!=MATCH_EXACT && CmpMode!=MATCH_EXACTPATH &&
- mstrnicompc(Wildcard,Name,WildLength,ForceCase)==0)
- {
- // For all modes except MATCH_NAMES, MATCH_EXACT and MATCH_EXACTPATH
- // "path1" mask must match "path1\path2\filename.ext" and "path1" names.
- char NextCh=Name[WildLength];
- if (NextCh=='\\' || NextCh=='/' || NextCh==0)
- return(true);
- }
-
- // Nothing more to compare for MATCH_SUBPATHONLY.
- if (CmpMode==MATCH_SUBPATHONLY)
- return(false);
-
- char Path1[NM],Path2[NM];
- GetFilePath(Wildcard,Path1,ASIZE(Path1));
- GetFilePath(Name,Path2,ASIZE(Path1));
-
- if ((CmpMode==MATCH_EXACT || CmpMode==MATCH_EXACTPATH) &&
- mstricompc(Path1,Path2,ForceCase)!=0)
- return(false);
- if (CmpMode==MATCH_SUBPATH || CmpMode==MATCH_WILDSUBPATH)
- if (IsWildcard(Path1))
- return(match(Wildcard,Name,ForceCase));
- else
- if (CmpMode==MATCH_SUBPATH || IsWildcard(Wildcard))
- {
- if (*Path1 && mstrnicompc(Path1,Path2,strlen(Path1),ForceCase)!=0)
- return(false);
- }
- else
- if (mstricompc(Path1,Path2,ForceCase)!=0)
- return(false);
- }
- char *Name1=PointToName(Wildcard);
- char *Name2=PointToName(Name);
-
- // Always return false for RAR temporary files to exclude them
- // from archiving operations.
- if (mstrnicompc("__rar_",Name2,6,false)==0)
- return(false);
-
- if (CmpMode==MATCH_EXACT)
- return(mstricompc(Name1,Name2,ForceCase)==0);
-
- return(match(Name1,Name2,ForceCase));
-}
-
-
-#ifndef SFX_MODULE
bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode)
{
bool ForceCase=(CmpMode&MATCH_FORCECASESENSITIVE)!=0;
@@ -124,10 +47,10 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode)
mwcsicompc(Path1,Path2,ForceCase)!=0)
return(false);
if (CmpMode==MATCH_SUBPATH || CmpMode==MATCH_WILDSUBPATH)
- if (IsWildcard(NULL,Path1))
+ if (IsWildcard(Path1))
return(match(Wildcard,Name,ForceCase));
else
- if (CmpMode==MATCH_SUBPATH || IsWildcard(NULL,Wildcard))
+ if (CmpMode==MATCH_SUBPATH || IsWildcard(Wildcard))
{
if (*Path1 && mwcsnicompc(Path1,Path2,wcslen(Path1),ForceCase)!=0)
return(false);
@@ -149,61 +72,8 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode)
return(match(Name1,Name2,ForceCase));
}
-#endif
-bool match(const char *pattern,const char *string,bool ForceCase)
-{
- for (;; ++string)
- {
- char stringc=toupperc(*string,ForceCase);
- char patternc=toupperc(*pattern++,ForceCase);
- switch (patternc)
- {
- case 0:
- return(stringc==0);
- case '?':
- if (stringc == 0)
- return(false);
- break;
- case '*':
- if (*pattern==0)
- return(true);
- if (*pattern=='.')
- {
- if (pattern[1]=='*' && pattern[2]==0)
- return(true);
- const char *dot=strchr(string,'.');
- if (pattern[1]==0)
- return (dot==NULL || dot[1]==0);
- if (dot!=NULL)
- {
- string=dot;
- if (strpbrk(pattern,"*?")==NULL && strchr(string+1,'.')==NULL)
- return(mstricompc(pattern+1,string+1,ForceCase)==0);
- }
- }
-
- while (*string)
- if (match(pattern,string++,ForceCase))
- return(true);
- return(false);
- default:
- if (patternc != stringc)
- {
- // Allow "name." mask match "name" and "name.\" match "name\".
- if (patternc=='.' && (stringc==0 || stringc=='\\' || stringc=='.'))
- return(match(pattern,string,ForceCase));
- else
- return(false);
- }
- break;
- }
- }
-}
-
-
-#ifndef SFX_MODULE
bool match(const wchar *pattern,const wchar *string,bool ForceCase)
{
for (;; ++string)
@@ -253,40 +123,16 @@ bool match(const wchar *pattern,const wchar *string,bool ForceCase)
}
}
}
-#endif
-
-
-int mstricompc(const char *Str1,const char *Str2,bool ForceCase)
-{
- if (ForceCase)
- return(strcmp(Str1,Str2));
- return(stricompc(Str1,Str2));
-}
-#ifndef SFX_MODULE
int mwcsicompc(const wchar *Str1,const wchar *Str2,bool ForceCase)
{
if (ForceCase)
return(wcscmp(Str1,Str2));
return(wcsicompc(Str1,Str2));
}
-#endif
-
-
-int mstrnicompc(const char *Str1,const char *Str2,size_t N,bool ForceCase)
-{
- if (ForceCase)
- return(strncmp(Str1,Str2,N));
-#if defined(_UNIX)
- return(strncmp(Str1,Str2,N));
-#else
- return(strnicomp(Str1,Str2,N));
-#endif
-}
-#ifndef SFX_MODULE
int mwcsnicompc(const wchar *Str1,const wchar *Str2,size_t N,bool ForceCase)
{
if (ForceCase)
@@ -297,4 +143,3 @@ int mwcsnicompc(const wchar *Str1,const wchar *Str2,size_t N,bool ForceCase)
return(wcsnicomp(Str1,Str2,N));
#endif
}
-#endif
diff --git a/src/thirdparty/unrar/match.hpp b/src/thirdparty/unrar/match.hpp
index 697286d85..65493ff2a 100644
--- a/src/thirdparty/unrar/match.hpp
+++ b/src/thirdparty/unrar/match.hpp
@@ -29,7 +29,6 @@ enum {
#define MATCH_MODEMASK 0x0000ffff
#define MATCH_FORCECASESENSITIVE 0x80000000
-bool CmpName(const char *Wildcard,const char *Name,int CmpMode);
bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode);
#endif
diff --git a/src/thirdparty/unrar/options.cpp b/src/thirdparty/unrar/options.cpp
index 585ce5243..031535462 100644
--- a/src/thirdparty/unrar/options.cpp
+++ b/src/thirdparty/unrar/options.cpp
@@ -17,14 +17,20 @@ RAROptions::~RAROptions()
void RAROptions::Init()
{
memset(this,0,sizeof(RAROptions));
- WinSize=0x400000;
+ WinSize=0x2000000;
Overwrite=OVERWRITE_DEFAULT;
Method=3;
MsgStream=MSG_STDOUT;
ConvertNames=NAMES_ORIGINALCASE;
ProcessEA=true;
xmtime=EXTTIME_HIGH3;
- CurVolNum=0;
FileSizeLess=INT64NDF;
FileSizeMore=INT64NDF;
+ HashType=HASH_CRC32;
+#ifdef RAR_SMP
+ Threads=GetNumberOfThreads();
+#endif
+#ifdef USE_QOPEN
+ QOpenMode=QOPEN_AUTO;
+#endif
}
diff --git a/src/thirdparty/unrar/options.hpp b/src/thirdparty/unrar/options.hpp
index b01912967..e4967810b 100644
--- a/src/thirdparty/unrar/options.hpp
+++ b/src/thirdparty/unrar/options.hpp
@@ -1,7 +1,7 @@
#ifndef _RAR_OPTIONS_
#define _RAR_OPTIONS_
-#define DEFAULT_RECOVERY -1
+#define DEFAULT_RECOVERY -3
#define DEFAULT_RECVOLUMES -10
@@ -42,19 +42,27 @@ enum RECURSE_MODE
enum OVERWRITE_MODE
{
- OVERWRITE_DEFAULT=0, // ask for extraction, silently overwrite for archiving
+ OVERWRITE_DEFAULT=0, // Ask when extracting, silently overwrite when archiving.
OVERWRITE_ALL,
OVERWRITE_NONE,
OVERWRITE_AUTORENAME,
OVERWRITE_FORCE_ASK
};
+
+enum QOPEN_MODE { QOPEN_NONE, QOPEN_AUTO, QOPEN_ALWAYS };
+
enum RAR_CHARSET { RCH_DEFAULT=0,RCH_ANSI,RCH_OEM,RCH_UNICODE };
#define MAX_FILTER_TYPES 16
enum FilterState {FILTER_DEFAULT=0,FILTER_AUTO,FILTER_FORCE,FILTER_DISABLE};
+enum SAVECOPY_MODE {
+ SAVECOPY_NONE=0, SAVECOPY_SILENT, SAVECOPY_LIST, SAVECOPY_LISTEXIT,
+ SAVECOPY_DUPLISTEXIT
+};
+
struct FilterMode
{
FilterState State;
@@ -75,24 +83,26 @@ class RAROptions
uint ExclFileAttr;
uint InclFileAttr;
bool InclAttrSet;
- uint WinSize;
- char TempPath[NM];
+ size_t WinSize;
+ wchar TempPath[NM];
+#ifdef USE_QOPEN
+ wchar SFXModule[NM];
+ QOPEN_MODE QOpenMode;
+#endif
bool ConfigDisabled; // Switch -cfg-.
- char ExtrPath[NM];
- wchar ExtrPathW[NM];
- char CommentFile[NM];
- wchar CommentFileW[NM];
+ wchar ExtrPath[NM];
+ wchar CommentFile[NM];
RAR_CHARSET CommentCharset;
RAR_CHARSET FilelistCharset;
- char ArcPath[NM];
- wchar ArcPathW[NM];
+ wchar ArcPath[NM];
SecPassword Password;
bool EncryptHeaders;
- char LogName[NM];
+ wchar LogName[NM];
MESSAGE_TYPE MsgStream;
bool Sound;
OVERWRITE_MODE Overwrite;
int Method;
+ HASH_TYPE HashType;
int Recovery;
int RecVolNumber;
bool DisablePercentage;
@@ -102,7 +112,6 @@ class RAROptions
int SolidCount;
bool ClearArc;
bool AddArcOnly;
- bool AV;
bool DisableComment;
bool FreshFiles;
bool UpdateFiles;
@@ -112,20 +121,22 @@ class RAROptions
Array<int64> NextVolSizes;
uint CurVolNum;
bool AllYes;
- bool DisableViewAV;
bool DisableSortSolid;
int ArcTime;
int ConvertNames;
bool ProcessOwners;
- bool SaveLinks;
+ bool SaveSymLinks;
+ bool SaveHardLinks;
int Priority;
int SleepTime;
bool KeepBroken;
bool OpenShared;
bool DeleteFiles;
+
+
#ifndef SFX_MODULE
bool GenerateArcName;
- char GenerateMask[MAX_GENERATE_MASK];
+ wchar GenerateMask[MAX_GENERATE_MASK];
#endif
bool SyncFiles;
bool ProcessEA;
@@ -136,34 +147,27 @@ class RAROptions
RarTime FileTimeAfter;
int64 FileSizeLess;
int64 FileSizeMore;
- bool OldNumbering;
bool Lock;
bool Test;
bool VolumePause;
FilterMode FilterModes[MAX_FILTER_TYPES];
- char EmailTo[NM];
+ wchar EmailTo[NM];
uint VersionControl;
- bool NoEndBlock;
bool AppendArcNameToPath;
bool Shutdown;
EXTTIME_MODE xmtime;
EXTTIME_MODE xctime;
EXTTIME_MODE xatime;
- EXTTIME_MODE xarctime;
- char CompressStdin[NM];
-
-#ifdef RAR_SMP
- uint Threads;
-#endif
+ wchar CompressStdin[NM];
+ uint Threads; // We use it to init hash even if RAR_SMP is not defined.
#ifdef RARDLL
- char DllDestName[NM];
- wchar DllDestNameW[NM];
+ wchar DllDestName[NM];
int DllOpMode;
int DllError;
LPARAM UserData;
diff --git a/src/thirdparty/unrar/os.hpp b/src/thirdparty/unrar/os.hpp
index 21488a849..0056946e0 100644
--- a/src/thirdparty/unrar/os.hpp
+++ b/src/thirdparty/unrar/os.hpp
@@ -12,17 +12,13 @@
#define SILENT
#endif
-#define ENABLE_BAD_ALLOC // Undefine if std::bad_alloc is not supported.
-
-#ifdef ENABLE_BAD_ALLOC
- #include <new>
-#endif
+#include <new>
#if defined(_WIN_ALL) || defined(_EMX)
#define LITTLE_ENDIAN
-#define NM 1024
+#define NM 2048
#ifdef _WIN_ALL
@@ -33,6 +29,9 @@
#define WINVER 0x0501
#define _WIN32_WINNT 0x0501
+#if !defined(ZIPSFX) && !defined(SHELL_EXT) && !defined(SETUP)
+#define RAR_SMP
+#endif
#define WIN32_LEAN_AND_MEAN
@@ -42,8 +41,11 @@
#include <shellapi.h>
#include <shlobj.h>
#include <winioctl.h>
+#include <wincrypt.h>
+#include <wchar.h>
+#include <wctype.h>
#endif // _WIN_ALL
@@ -59,24 +61,14 @@
#define for if (0) ; else for
#endif
#include <direct.h>
+ #include <intrin.h>
+
+ #define USE_SSE
+ #define SSE_ALIGNMENT 16
#else
#include <dirent.h>
#endif // _MSC_VER
-#ifdef _EMX
- #include <unistd.h>
- #include <pwd.h>
- #include <grp.h>
- #include <errno.h>
- #ifdef _DJGPP
- #include <utime.h>
- #else
- #include <os2.h>
- #include <sys/utime.h>
- #include <emx/syscalls.h>
- #endif
-#endif
-
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -88,17 +80,18 @@
#include <time.h>
#include <signal.h>
+#define SAVE_LINKS
+
#define ENABLE_ACCESS
-#define DefConfigName "rar.ini"
-#define DefLogName "rar.log"
+#define DefConfigName L"rar.ini"
+#define DefLogName L"rar.log"
#define PATHDIVIDER "\\"
#define PATHDIVIDERW L"\\"
#define CPATHDIVIDER '\\'
-#define MASKALL "*"
-#define MASKALLW L"*"
+#define MASKALL L"*"
#define READBINARY "rb"
#define READTEXT "rt"
@@ -110,14 +103,7 @@
#if defined(_WIN_ALL)
#ifdef _MSC_VER
#define _stdfunction __cdecl
-
- #ifdef SFX_MODULE
- // We want to keep SFX module small, so let compiler to decide.
- #define _forceinline inline
- #else
- #define _forceinline __forceinline
- #endif
-
+ #define _forceinline __forceinline
#else
#define _stdfunction _USERENTRY
#define _forceinline inline
@@ -131,12 +117,7 @@
#ifdef _UNIX
-#define NM 1024
-
-#ifdef _BEOS
-#include <be/kernel/fs_info.h>
-#include <be/kernel/fs_attr.h>
-#endif
+#define NM 2048
#include <unistd.h>
#include <sys/types.h>
@@ -152,10 +133,14 @@
#include <sys/param.h>
#include <sys/mount.h>
#else
+ #ifndef SFX_MODULE
+ #include <sys/statfs.h>
+ #endif
#endif
#include <pwd.h>
#include <grp.h>
#include <wchar.h>
+#include <wctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -175,15 +160,14 @@
#define ENABLE_ACCESS
-#define DefConfigName ".rarrc"
-#define DefLogName ".rarlog"
+#define DefConfigName L".rarrc"
+#define DefLogName L".rarlog"
#define PATHDIVIDER "/"
#define PATHDIVIDERW L"/"
#define CPATHDIVIDER '/'
-#define MASKALL "*"
-#define MASKALLW L"*"
+#define MASKALL L"*"
#define READBINARY "r"
#define READTEXT "r"
@@ -216,10 +200,22 @@
typedef const char* MSGID;
+#ifndef SSE_ALIGNMENT // No SSE use and no special data alignment is required.
+ #define SSE_ALIGNMENT 1
+#endif
+
#define safebuf static
+// Solaris defines _LITTLE_ENDIAN or _BIG_ENDIAN.
+#if defined(_LITTLE_ENDIAN) && !defined(LITTLE_ENDIAN)
+ #define LITTLE_ENDIAN
+#endif
+#if defined(_BIG_ENDIAN) && !defined(BIG_ENDIAN)
+ #define BIG_ENDIAN
+#endif
+
#if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
- #if defined(__i386) || defined(i386) || defined(__i386__)
+ #if defined(__i386) || defined(i386) || defined(__i386__) || defined(__x86_64)
#define LITTLE_ENDIAN
#elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN
#define LITTLE_ENDIAN
@@ -247,7 +243,7 @@
#if defined(__sparc) || defined(sparc) || defined(__sparcv9)
// Prohibit not aligned access to data structures in text compression
-// algorithm, increases memory requirements
+// algorithm, increases memory requirements.
#define STRICT_ALIGNMENT_REQUIRED
#endif
diff --git a/src/thirdparty/unrar/os2ea.cpp b/src/thirdparty/unrar/os2ea.cpp
deleted file mode 100644
index fbb12dbdc..000000000
--- a/src/thirdparty/unrar/os2ea.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-#include <os2.h>
-
-
-
-void ExtractOS2EA(Archive &Arc,char *FileName)
-{
- if (_osmode != OS2_MODE)
- {
- mprintf(St(MSkipEA));
- return;
- }
-
- if (Arc.HeaderCRC!=Arc.EAHead.HeadCRC)
- {
- Log(Arc.FileName,St(MEABroken),FileName);
- ErrHandler.SetErrorCode(RARX_CRC);
- return;
- }
-
- if (Arc.EAHead.Method<0x31 || Arc.EAHead.Method>0x35 || Arc.EAHead.UnpVer>PACK_VER)
- {
- Log(Arc.FileName,St(MEAUnknHeader),FileName);
- ErrHandler.SetErrorCode(RARX_WARNING);
- return;
- }
-
- struct StructEAOP2
- {
- char *GEAPtr;
- char *FEAPtr;
- unsigned long Error;
- } EAOP2;
-
- ComprDataIO DataIO;
- Unpack Unpack(&DataIO);
- Unpack.Init();
-
- Array<unsigned char> UnpData(Arc.EAHead.UnpSize);
- DataIO.SetUnpackToMemory(&UnpData[0],Arc.EAHead.UnpSize);
- DataIO.SetPackedSizeToRead(Arc.EAHead.DataSize);
- DataIO.EnableShowProgress(false);
- DataIO.SetFiles(&Arc,NULL);
- Unpack.SetDestSize(Arc.EAHead.UnpSize);
- Unpack.DoUnpack(Arc.EAHead.UnpVer,false);
-
- if (Arc.EAHead.EACRC!=~DataIO.UnpFileCRC)
- {
- Log(Arc.FileName,St(MEABroken),FileName);
- ErrHandler.SetErrorCode(RARX_CRC);
- return;
- }
-
- EAOP2.FEAPtr=(char *)&UnpData[0];
- EAOP2.GEAPtr=NULL;
- if (DosSetPathInfo((unsigned char *)FileName,2,&EAOP2,sizeof(EAOP2),0x10)!=0)
- {
- Log(Arc.FileName,St(MCannotSetEA),FileName);
- ErrHandler.SetErrorCode(RARX_WARNING);
- }
- File::SetCloseFileTimeByName(FileName,&Arc.NewLhd.mtime,&Arc.NewLhd.atime);
- mprintf(St(MShowEA));
-}
-
-
-void ExtractOS2EANew(Archive &Arc,char *FileName)
-{
- if (_osmode != OS2_MODE)
- {
- mprintf(St(MSkipEA));
- return;
- }
-
- Array<byte> SubData;
- if (!Arc.ReadSubData(&SubData,NULL))
- return;
-
- struct StructEAOP2
- {
- char *GEAPtr;
- char *FEAPtr;
- unsigned long Error;
- } EAOP2;
-
- EAOP2.FEAPtr=(char *)&SubData[0];
- EAOP2.GEAPtr=NULL;
- if (DosSetPathInfo((unsigned char *)FileName,2,&EAOP2,sizeof(EAOP2),0x10)!=0)
- {
- Log(Arc.FileName,St(MCannotSetEA),FileName);
- ErrHandler.SetErrorCode(RARX_WARNING);
- }
- File::SetCloseFileTimeByName(FileName,&Arc.NewLhd.mtime,&Arc.NewLhd.atime);
- mprintf(St(MShowEA));
-}
-
diff --git a/src/thirdparty/unrar/pathfn.cpp b/src/thirdparty/unrar/pathfn.cpp
index b9244cdec..5f7f5f928 100644
--- a/src/thirdparty/unrar/pathfn.cpp
+++ b/src/thirdparty/unrar/pathfn.cpp
@@ -1,17 +1,5 @@
#include "rar.hpp"
-char* PointToName(const char *Path)
-{
- const char *Found=NULL;
- for (const char *s=Path;*s!=0;s=charnext(s))
- if (IsPathDiv(*s))
- Found=(char*)(s+1);
- if (Found!=NULL)
- return((char*)Found);
- return (char*)((*Path && IsDriveDiv(Path[1]) && charnext(Path)==Path+1) ? Path+2:Path);
-}
-
-
wchar* PointToName(const wchar *Path)
{
for (int I=(int)wcslen(Path)-1;I>=0;I--)
@@ -21,67 +9,10 @@ wchar* PointToName(const wchar *Path)
}
-char* PointToLastChar(const char *Path)
-{
- for (const char *s=Path,*p=Path;;p=s,s=charnext(s))
- if (*s==0)
- return((char *)p);
-}
-
-
wchar* PointToLastChar(const wchar *Path)
{
size_t Length=wcslen(Path);
- return((wchar*)(Length>0 ? Path+Length-1:Path));
-}
-
-
-char* ConvertPath(const char *SrcPath,char *DestPath)
-{
- const char *DestPtr=SrcPath;
-
- // Prevent \..\ in any part of path string.
- for (const char *s=DestPtr;*s!=0;s++)
- if (IsPathDiv(s[0]) && s[1]=='.' && s[2]=='.' && IsPathDiv(s[3]))
- DestPtr=s+4;
-
- // Remove <d>:\ and any sequence of . and \ in the beginning of path string.
- while (*DestPtr!=0)
- {
- const char *s=DestPtr;
- if (s[0] && IsDriveDiv(s[1]))
- s+=2;
- else
- if (s[0]=='\\' && s[1]=='\\')
- {
- const char *Slash=strchr(s+2,'\\');
- if (Slash!=NULL && (Slash=strchr(Slash+1,'\\'))!=NULL)
- s=Slash+1;
- }
- for (const char *t=s;*t!=0;t++)
- if (IsPathDiv(*t))
- s=t+1;
- else
- if (*t!='.')
- break;
- if (s==DestPtr)
- break;
- DestPtr=s;
- }
-
- // Code above does not remove last "..", doing here.
- if (DestPtr[0]=='.' && DestPtr[1]=='.' && DestPtr[2]==0)
- DestPtr+=2;
-
- if (DestPath!=NULL)
- {
- // SrcPath and DestPath can point to same memory area,
- // so we use the temporary buffer for copying.
- char TmpStr[NM];
- strncpyz(TmpStr,DestPtr,ASIZE(TmpStr));
- strcpy(DestPath,TmpStr);
- }
- return((char *)DestPtr);
+ return (wchar*)(Length>0 ? Path+Length-1:Path);
}
@@ -129,26 +60,14 @@ wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath)
wcsncpyz(TmpStr,DestPtr,ASIZE(TmpStr));
wcscpy(DestPath,TmpStr);
}
- return((wchar *)DestPtr);
+ return (wchar *)DestPtr;
}
-void SetExt(char *Name,const char *NewExt)
+void SetName(wchar *FullName,const wchar *Name,size_t MaxSize)
{
- char *Dot=GetExt(Name);
- if (NewExt==NULL)
- {
- if (Dot!=NULL)
- *Dot=0;
- }
- else
- if (Dot==NULL)
- {
- strcat(Name,".");
- strcat(Name,NewExt);
- }
- else
- strcpy(Dot+1,NewExt);
+ wchar *NamePtr=PointToName(FullName);
+ wcsncpyz(NamePtr,Name,MaxSize-(NamePtr-FullName));
}
@@ -174,20 +93,6 @@ void SetExt(wchar *Name,const wchar *NewExt)
#ifndef SFX_MODULE
-void SetSFXExt(char *SFXName)
-{
-#ifdef _UNIX
- SetExt(SFXName,"sfx");
-#endif
-
-#if defined(_WIN_ALL) || defined(_EMX)
- SetExt(SFXName,"exe");
-#endif
-}
-#endif
-
-
-#ifndef SFX_MODULE
void SetSFXExt(wchar *SFXName)
{
if (SFXName==NULL || *SFXName==0)
@@ -204,23 +109,9 @@ void SetSFXExt(wchar *SFXName)
#endif
-char *GetExt(const char *Name)
-{
- return(Name==NULL ? NULL:strrchrd(PointToName(Name),'.'));
-}
-
-
wchar *GetExt(const wchar *Name)
{
- return(Name==NULL ? NULL:wcsrchr(PointToName(Name),'.'));
-}
-
-
-// 'Ext' is an extension without the leading dot, like "rar".
-bool CmpExt(const char *Name,const char *Ext)
-{
- char *NameExt=GetExt(Name);
- return(NameExt!=NULL && stricomp(NameExt+1,Ext)==0);
+ return Name==NULL ? NULL:wcsrchr(PointToName(Name),'.');
}
@@ -228,24 +119,22 @@ bool CmpExt(const char *Name,const char *Ext)
bool CmpExt(const wchar *Name,const wchar *Ext)
{
wchar *NameExt=GetExt(Name);
- return(NameExt!=NULL && wcsicomp(NameExt+1,Ext)==0);
+ return NameExt!=NULL && wcsicomp(NameExt+1,Ext)==0;
}
-bool IsWildcard(const char *Str,const wchar *StrW)
+bool IsWildcard(const wchar *Str)
{
- if (StrW!=NULL && *StrW!=0)
- return(wcspbrk(StrW,L"*?")!=NULL);
- return(Str==NULL ? false:strpbrk(Str,"*?")!=NULL);
+ return Str==NULL ? false:wcspbrk(Str,L"*?")!=NULL;
}
bool IsPathDiv(int Ch)
{
-#if defined(_WIN_ALL) || defined(_EMX)
- return(Ch=='\\' || Ch=='/');
+#ifdef _WIN_ALL
+ return Ch=='\\' || Ch=='/';
#else
- return(Ch==CPATHDIVIDER);
+ return Ch==CPATHDIVIDER;
#endif
}
@@ -253,60 +142,48 @@ bool IsPathDiv(int Ch)
bool IsDriveDiv(int Ch)
{
#ifdef _UNIX
- return(false);
+ return false;
#else
- return(Ch==':');
+ return Ch==':';
#endif
}
-int GetPathDisk(const char *Path)
-{
- if (IsDiskLetter(Path))
- return(etoupper(*Path)-'A');
- else
- return(-1);
-}
-
-
int GetPathDisk(const wchar *Path)
{
if (IsDiskLetter(Path))
- return(etoupperw(*Path)-'A');
+ return etoupperw(*Path)-'A';
else
- return(-1);
+ return -1;
}
-void AddEndSlash(char *Path)
-{
- char *LastChar=PointToLastChar(Path);
- if (*LastChar!=0 && *LastChar!=CPATHDIVIDER)
- strcat(LastChar,PATHDIVIDER);
-}
-
-
-void AddEndSlash(wchar *Path)
+void AddEndSlash(wchar *Path,size_t MaxLength)
{
size_t Length=wcslen(Path);
- if (Length>0 && Path[Length-1]!=CPATHDIVIDER)
+ if (Length>0 && Path[Length-1]!=CPATHDIVIDER && Length+1<MaxLength)
wcscat(Path,PATHDIVIDERW);
}
-// Returns file path including the trailing path separator symbol.
-void GetFilePath(const char *FullName,char *Path,int MaxLength)
+void MakeName(const wchar *Path,const wchar *Name,wchar *Pathname,size_t MaxSize)
{
- size_t PathLength=Min(MaxLength-1,PointToName(FullName)-FullName);
- strncpy(Path,FullName,PathLength);
- Path[PathLength]=0;
+ // 'Name' and 'Pathname' can point to same memory area. This is why we use
+ // the temporary buffer instead of constructing the name in 'Pathname'.
+ wchar OutName[NM];
+ wcsncpyz(OutName,Path,ASIZE(OutName));
+ AddEndSlash(OutName,ASIZE(OutName));
+ wcsncatz(OutName,Name,ASIZE(OutName));
+ wcsncpyz(Pathname,OutName,MaxSize);
}
// Returns file path including the trailing path separator symbol.
-void GetFilePath(const wchar *FullName,wchar *Path,int MaxLength)
+void GetFilePath(const wchar *FullName,wchar *Path,size_t MaxLength)
{
- size_t PathLength=Min(MaxLength-1,PointToName(FullName)-FullName);
+ if (MaxLength==0)
+ return;
+ size_t PathLength=Min(MaxLength-1,size_t(PointToName(FullName)-FullName));
wcsncpy(Path,FullName,PathLength);
Path[PathLength]=0;
}
@@ -314,17 +191,6 @@ void GetFilePath(const wchar *FullName,wchar *Path,int MaxLength)
// Removes name and returns file path without the trailing
// path separator symbol.
-void RemoveNameFromPath(char *Path)
-{
- char *Name=PointToName(Path);
- if (Name>=Path+2 && (!IsDriveDiv(Path[1]) || Name>=Path+4))
- Name--;
- *Name=0;
-}
-
-
-// Removes name and returns file path without the trailing
-// path separator symbol.
void RemoveNameFromPath(wchar *Path)
{
wchar *Name=PointToName(Path);
@@ -335,32 +201,7 @@ void RemoveNameFromPath(wchar *Path)
#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
-void GetAppDataPath(char *Path)
-{
- LPMALLOC g_pMalloc;
- SHGetMalloc(&g_pMalloc);
- LPITEMIDLIST ppidl;
- *Path=0;
- bool Success=false;
- if (SHGetSpecialFolderLocation(NULL,CSIDL_APPDATA,&ppidl)==NOERROR &&
- SHGetPathFromIDListA(ppidl,Path) && *Path!=0)
- {
- AddEndSlash(Path);
- strcat(Path,"WinRAR");
- Success=FileExist(Path) || MakeDir(Path,NULL,false,0)==MKDIR_SUCCESS;
- }
- if (!Success)
- {
- GetModuleFileNameA(NULL,Path,NM);
- RemoveNameFromPath(Path);
- }
- g_pMalloc->Free(ppidl);
-}
-#endif
-
-
-#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
-void GetAppDataPath(wchar *Path)
+static void GetAppDataPath(wchar *Path,size_t MaxSize)
{
LPMALLOC g_pMalloc;
SHGetMalloc(&g_pMalloc);
@@ -368,15 +209,15 @@ void GetAppDataPath(wchar *Path)
*Path=0;
bool Success=false;
if (SHGetSpecialFolderLocation(NULL,CSIDL_APPDATA,&ppidl)==NOERROR &&
- SHGetPathFromIDListW(ppidl,Path) && *Path!=0)
+ SHGetPathFromIDList(ppidl,Path) && *Path!=0)
{
- AddEndSlash(Path);
- wcscat(Path,L"WinRAR");
- Success=FileExist(NULL,Path) || MakeDir(NULL,Path,false,0)==MKDIR_SUCCESS;
+ AddEndSlash(Path,MaxSize);
+ wcsncatz(Path,L"WinRAR",MaxSize);
+ Success=FileExist(Path) || MakeDir(Path,false,0)==MKDIR_SUCCESS;
}
if (!Success)
{
- GetModuleFileNameW(NULL,Path,NM);
+ GetModuleFileName(NULL,Path,(DWORD)MaxSize);
RemoveNameFromPath(Path);
}
g_pMalloc->Free(ppidl);
@@ -384,28 +225,8 @@ void GetAppDataPath(wchar *Path)
#endif
-#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
-void GetRarDataPath(char *Path)
-{
- *Path=0;
-
- HKEY hKey;
- if (RegOpenKeyExA(HKEY_CURRENT_USER,"Software\\WinRAR\\Paths",0,
- KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS)
- {
- DWORD DataSize=NM,Type;
- RegQueryValueExA(hKey,"AppData",0,&Type,(BYTE *)Path,&DataSize);
- RegCloseKey(hKey);
- }
-
- if (*Path==0 || !FileExist(Path))
- GetAppDataPath(Path);
-}
-#endif
-
-
-#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
-void GetRarDataPath(wchar *Path)
+#if defined(_WIN_ALL) && !defined(SFX_MODULE)
+void GetRarDataPath(wchar *Path,size_t MaxSize)
{
*Path=0;
@@ -413,100 +234,64 @@ void GetRarDataPath(wchar *Path)
if (RegOpenKeyExW(HKEY_CURRENT_USER,L"Software\\WinRAR\\Paths",0,
KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS)
{
- DWORD DataSize=NM,Type;
+ DWORD DataSize=(DWORD)MaxSize,Type;
RegQueryValueExW(hKey,L"AppData",0,&Type,(BYTE *)Path,&DataSize);
RegCloseKey(hKey);
}
- if (*Path==0 || !FileExist(NULL,Path))
- GetAppDataPath(Path);
+ if (*Path==0 || !FileExist(Path))
+ GetAppDataPath(Path,MaxSize);
}
#endif
#ifndef SFX_MODULE
-bool EnumConfigPaths(char *Path,int Number)
+bool EnumConfigPaths(uint Number,wchar *Path,size_t MaxSize)
{
-#ifdef _EMX
- static char RARFileName[NM];
- if (Number==-1)
- strcpy(RARFileName,Path);
- if (Number!=0)
- return(false);
-#ifndef _DJGPP
- if (_osmode==OS2_MODE)
- {
- PTIB ptib;
- PPIB ppib;
- DosGetInfoBlocks(&ptib, &ppib);
- DosQueryModuleName(ppib->pib_hmte,NM,Path);
- }
- else
-#endif
- strcpy(Path,RARFileName);
- RemoveNameFromPath(Path);
- return(true);
-#elif defined(_UNIX)
- static const char *AltPath[]={
- "/etc","/etc/rar","/usr/lib","/usr/local/lib","/usr/local/etc"
+#ifdef _UNIX
+ static const wchar *ConfPath[]={
+ L"/etc", L"/etc/rar", L"/usr/lib", L"/usr/local/lib", L"/usr/local/etc"
};
if (Number==0)
{
char *EnvStr=getenv("HOME");
- strncpy(Path, (EnvStr==NULL) ? AltPath[0] : EnvStr, NM-1);
- Path[NM-1]=0;
- return(true);
+ if (EnvStr!=NULL)
+ GetWideName(EnvStr,NULL,Path,MaxSize);
+ else
+ wcsncpyz(Path, ConfPath[0], MaxSize);
+ return true;
}
Number--;
- if (Number<0 || Number>=sizeof(AltPath)/sizeof(AltPath[0]))
- return(false);
- strcpy(Path,AltPath[Number]);
- return(true);
+ if (Number>=ASIZE(ConfPath))
+ return false;
+ wcsncpyz(Path,ConfPath[Number], MaxSize);
+ return true;
#elif defined(_WIN_ALL)
-
- if (Number<0 || Number>1)
- return(false);
+ if (Number>1)
+ return false;
if (Number==0)
- GetRarDataPath(Path);
+ GetRarDataPath(Path,MaxSize);
else
{
- GetModuleFileNameA(NULL,Path,NM);
+ GetModuleFileNameW(NULL,Path,(DWORD)MaxSize);
RemoveNameFromPath(Path);
}
- return(true);
-
+ return true;
#else
- return(false);
+ return false;
#endif
}
#endif
-#if defined(_WIN_ALL) && !defined(SFX_MODULE)
-bool EnumConfigPaths(wchar *Path,int Number)
-{
- if (Number<0 || Number>1)
- return(false);
- if (Number==0)
- GetRarDataPath(Path);
- else
- {
- GetModuleFileNameW(NULL,Path,NM);
- RemoveNameFromPath(Path);
- }
- return(true);
-}
-#endif
-
-
#ifndef SFX_MODULE
-void GetConfigName(const char *Name,char *FullName,bool CheckExist)
+void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckExist)
{
*FullName=0;
- for (int I=0;EnumConfigPaths(FullName,I);I++)
+ for (uint I=0;EnumConfigPaths(I,FullName,MaxSize);I++)
{
- AddEndSlash(FullName);
- strcat(FullName,Name);
+ AddEndSlash(FullName,MaxSize);
+ wcsncatz(FullName,Name,MaxSize);
if (!CheckExist || WildFileExist(FullName))
break;
}
@@ -514,33 +299,18 @@ void GetConfigName(const char *Name,char *FullName,bool CheckExist)
#endif
-#if defined(_WIN_ALL) && !defined(SFX_MODULE)
-void GetConfigName(const wchar *Name,wchar *FullName,bool CheckExist)
-{
- *FullName=0;
- for (int I=0;EnumConfigPaths(FullName,I);I++)
- {
- AddEndSlash(FullName);
- wcscat(FullName,Name);
- if (!CheckExist || WildFileExist(NULL,FullName))
- break;
- }
-}
-#endif
-
-
// Returns a pointer to rightmost digit of volume number.
-char* GetVolNumPart(char *ArcName)
+wchar* GetVolNumPart(const wchar *ArcName)
{
// Pointing to last name character.
- char *ChPtr=ArcName+strlen(ArcName)-1;
+ const wchar *ChPtr=ArcName+wcslen(ArcName)-1;
// Skipping the archive extension.
while (!IsDigit(*ChPtr) && ChPtr>ArcName)
ChPtr--;
// Skipping the numeric part of name.
- char *NumPtr=ChPtr;
+ const wchar *NumPtr=ChPtr;
while (IsDigit(*NumPtr) && NumPtr>ArcName)
NumPtr--;
@@ -552,174 +322,63 @@ char* GetVolNumPart(char *ArcName)
{
// Validate the first numeric part only if it has a dot somewhere
// before it.
- char *Dot=strchrd(PointToName(ArcName),'.');
+ wchar *Dot=wcschr(PointToName(ArcName),'.');
if (Dot!=NULL && Dot<NumPtr)
ChPtr=NumPtr;
break;
}
NumPtr--;
}
- return(ChPtr);
+ return (wchar *)ChPtr;
}
-// Returns a pointer to rightmost digit of volume number.
-wchar* GetVolNumPart(wchar *ArcName)
+void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering)
{
- // Pointing to last name character.
- wchar *ChPtr=ArcName+wcslen(ArcName)-1;
-
- // Skipping the archive extension.
- while (!IsDigit(*ChPtr) && ChPtr>ArcName)
- ChPtr--;
-
- // Skipping the numeric part of name.
- wchar *NumPtr=ChPtr;
- while (IsDigit(*NumPtr) && NumPtr>ArcName)
- NumPtr--;
-
- // Searching for first numeric part in names like name.part##of##.rar.
- // Stop search on the first dot.
- while (NumPtr>ArcName && *NumPtr!='.')
+ wchar *ChPtr;
+ if ((ChPtr=GetExt(ArcName))==NULL)
{
- if (IsDigit(*NumPtr))
- {
- // Validate the first numeric part only if it has a dot somewhere
- // before it.
- wchar *Dot=wcschr(PointToName(ArcName),'.');
- if (Dot!=NULL && Dot<NumPtr)
- ChPtr=NumPtr;
- break;
- }
- NumPtr--;
+ wcsncatz(ArcName,L".rar",MaxLength);
+ ChPtr=GetExt(ArcName);
}
- return(ChPtr);
-}
-
-
-void NextVolumeName(char *ArcName,wchar *ArcNameW,uint MaxLength,bool OldNumbering)
-{
- if (ArcName!=NULL && *ArcName!=0)
+ else
+ if (ChPtr[1]==0 && wcslen(ArcName)<MaxLength-3 || wcsicomp(ChPtr+1,L"exe")==0 || wcsicomp(ChPtr+1,L"sfx")==0)
+ wcscpy(ChPtr+1,L"rar");
+ if (!OldNumbering)
{
- char *ChPtr;
- if ((ChPtr=GetExt(ArcName))==NULL)
- {
- strncatz(ArcName,".rar",MaxLength);
- ChPtr=GetExt(ArcName);
- }
- else
- if (ChPtr[1]==0 && strlen(ArcName)<MaxLength-3 || stricomp(ChPtr+1,"exe")==0 || stricomp(ChPtr+1,"sfx")==0)
- strcpy(ChPtr+1,"rar");
- if (!OldNumbering)
- {
- ChPtr=GetVolNumPart(ArcName);
+ ChPtr=GetVolNumPart(ArcName);
- while ((++(*ChPtr))=='9'+1)
+ while ((++(*ChPtr))=='9'+1)
+ {
+ *ChPtr='0';
+ ChPtr--;
+ if (ChPtr<ArcName || !IsDigit(*ChPtr))
{
- *ChPtr='0';
- ChPtr--;
- if (ChPtr<ArcName || !IsDigit(*ChPtr))
- {
- for (char *EndPtr=ArcName+strlen(ArcName);EndPtr!=ChPtr;EndPtr--)
- *(EndPtr+1)=*EndPtr;
- *(ChPtr+1)='1';
- break;
- }
+ for (wchar *EndPtr=ArcName+wcslen(ArcName);EndPtr!=ChPtr;EndPtr--)
+ *(EndPtr+1)=*EndPtr;
+ *(ChPtr+1)='1';
+ break;
}
}
- else
- if (!IsDigit(*(ChPtr+2)) || !IsDigit(*(ChPtr+3)))
- strcpy(ChPtr+2,"00");
- else
- {
- ChPtr+=3;
- while ((++(*ChPtr))=='9'+1)
- if (*(ChPtr-1)=='.')
- {
- *ChPtr='A';
- break;
- }
- else
- {
- *ChPtr='0';
- ChPtr--;
- }
- }
}
-
- if (ArcNameW!=NULL && *ArcNameW!=0)
- {
- wchar *ChPtr;
- if ((ChPtr=GetExt(ArcNameW))==NULL)
- {
- wcsncatz(ArcNameW,L".rar",MaxLength);
- ChPtr=GetExt(ArcNameW);
- }
+ else
+ if (!IsDigit(*(ChPtr+2)) || !IsDigit(*(ChPtr+3)))
+ wcscpy(ChPtr+2,L"00");
else
- if (ChPtr[1]==0 && wcslen(ArcNameW)<MaxLength-3 || wcsicomp(ChPtr+1,L"exe")==0 || wcsicomp(ChPtr+1,L"sfx")==0)
- wcscpy(ChPtr+1,L"rar");
- if (!OldNumbering)
{
- ChPtr=GetVolNumPart(ArcNameW);
-
+ ChPtr+=3;
while ((++(*ChPtr))=='9'+1)
- {
- *ChPtr='0';
- ChPtr--;
- if (ChPtr<ArcNameW || !IsDigit(*ChPtr))
+ if (*(ChPtr-1)=='.')
{
- for (wchar *EndPtr=ArcNameW+wcslen(ArcNameW);EndPtr!=ChPtr;EndPtr--)
- *(EndPtr+1)=*EndPtr;
- *(ChPtr+1)='1';
+ *ChPtr='A';
break;
}
- }
+ else
+ {
+ *ChPtr='0';
+ ChPtr--;
+ }
}
- else
- if (!IsDigit(*(ChPtr+2)) || !IsDigit(*(ChPtr+3)))
- wcscpy(ChPtr+2,L"00");
- else
- {
- ChPtr+=3;
- while ((++(*ChPtr))=='9'+1)
- if (*(ChPtr-1)=='.')
- {
- *ChPtr='A';
- break;
- }
- else
- {
- *ChPtr='0';
- ChPtr--;
- }
- }
- }
-}
-
-
-bool IsNameUsable(const char *Name)
-{
-#ifndef _UNIX
- if (Name[0] && Name[1] && strchr(Name+2,':')!=NULL)
- return(false);
- for (const char *s=Name;*s!=0;s=charnext(s))
- {
- if ((byte)*s<32)
- return(false);
- if (*s==' ' && IsPathDiv(s[1]))
- return(false);
- }
-#endif
-#ifdef _WIN_ALL
- // In Windows we need to check if all file name characters are defined
- // in current code page. For example, in Korean CP949 a lot of high ASCII
- // characters are not defined, cannot be used in file names, but cannot be
- // detected by other checks in this function.
- if (MultiByteToWideChar(CP_ACP,MB_ERR_INVALID_CHARS,Name,-1,NULL,0)==0 &&
- GetLastError()==ERROR_NO_UNICODE_TRANSLATION)
- return false;
-#endif
- return(*Name!=0 && strpbrk(Name,"?*<>|\"")==NULL);
}
@@ -727,16 +386,16 @@ bool IsNameUsable(const wchar *Name)
{
#ifndef _UNIX
if (Name[0] && Name[1] && wcschr(Name+2,':')!=NULL)
- return(false);
+ return false;
for (const wchar *s=Name;*s!=0;s++)
{
if ((uint)*s<32)
- return(false);
- if (*s==' ' && IsPathDiv(s[1]))
- return(false);
+ return false;
+ if ((*s==' ' || *s=='.') && IsPathDiv(s[1]))
+ return false;
}
#endif
- return(*Name!=0 && wcspbrk(Name,L"?*<>|\"")==NULL);
+ return *Name!=0 && wcspbrk(Name,L"?*<>|\"")==NULL;
}
@@ -763,7 +422,7 @@ void MakeNameUsable(char *Name,bool Extended)
#ifndef _UNIX
if (s-Name>1 && *s==':')
*s='_';
- if (*s==' ' && IsPathDiv(s[1]))
+ if ((*s==' ' || *s=='.') && IsPathDiv(s[1]))
*s='_';
#endif
}
@@ -779,20 +438,20 @@ void MakeNameUsable(wchar *Name,bool Extended)
#ifndef _UNIX
if (s-Name>1 && *s==':')
*s='_';
- if (*s==' ' && IsPathDiv(s[1]))
+ if ((*s==' ' || *s=='.') && IsPathDiv(s[1]))
*s='_';
#endif
}
}
-char* UnixSlashToDos(char *SrcName,char *DestName,uint MaxLength)
+char* UnixSlashToDos(char *SrcName,char *DestName,size_t MaxLength)
{
if (DestName!=NULL && DestName!=SrcName)
if (strlen(SrcName)>=MaxLength)
{
*DestName=0;
- return(DestName);
+ return DestName;
}
else
strcpy(DestName,SrcName);
@@ -804,17 +463,17 @@ char* UnixSlashToDos(char *SrcName,char *DestName,uint MaxLength)
else
DestName[s-SrcName]='\\';
}
- return(DestName==NULL ? SrcName:DestName);
+ return DestName==NULL ? SrcName:DestName;
}
-char* DosSlashToUnix(char *SrcName,char *DestName,uint MaxLength)
+char* DosSlashToUnix(char *SrcName,char *DestName,size_t MaxLength)
{
if (DestName!=NULL && DestName!=SrcName)
if (strlen(SrcName)>=MaxLength)
{
*DestName=0;
- return(DestName);
+ return DestName;
}
else
strcpy(DestName,SrcName);
@@ -826,17 +485,17 @@ char* DosSlashToUnix(char *SrcName,char *DestName,uint MaxLength)
else
DestName[s-SrcName]='/';
}
- return(DestName==NULL ? SrcName:DestName);
+ return DestName==NULL ? SrcName:DestName;
}
-wchar* UnixSlashToDos(wchar *SrcName,wchar *DestName,uint MaxLength)
+wchar* UnixSlashToDos(wchar *SrcName,wchar *DestName,size_t MaxLength)
{
if (DestName!=NULL && DestName!=SrcName)
if (wcslen(SrcName)>=MaxLength)
{
*DestName=0;
- return(DestName);
+ return DestName;
}
else
wcscpy(DestName,SrcName);
@@ -848,17 +507,17 @@ wchar* UnixSlashToDos(wchar *SrcName,wchar *DestName,uint MaxLength)
else
DestName[s-SrcName]='\\';
}
- return(DestName==NULL ? SrcName:DestName);
+ return DestName==NULL ? SrcName:DestName;
}
-wchar* DosSlashToUnix(wchar *SrcName,wchar *DestName,uint MaxLength)
+wchar* DosSlashToUnix(wchar *SrcName,wchar *DestName,size_t MaxLength)
{
if (DestName!=NULL && DestName!=SrcName)
if (wcslen(SrcName)>=MaxLength)
{
*DestName=0;
- return(DestName);
+ return DestName;
}
else
wcscpy(DestName,SrcName);
@@ -870,116 +529,68 @@ wchar* DosSlashToUnix(wchar *SrcName,wchar *DestName,uint MaxLength)
else
DestName[s-SrcName]='/';
}
- return(DestName==NULL ? SrcName:DestName);
-}
-
-
-void ConvertNameToFull(const char *Src,char *Dest)
-{
-#ifdef _WIN_ALL
-#ifndef _WIN_CE
- char FullName[NM],*NamePtr;
- DWORD Code=GetFullPathNameA(Src,ASIZE(FullName),FullName,&NamePtr);
- if (Code!=0 && Code<ASIZE(FullName))
- strcpy(Dest,FullName);
- else
-#endif
- if (Src!=Dest)
- strcpy(Dest,Src);
-#else
- char FullName[NM];
- if (IsPathDiv(*Src) || IsDiskLetter(Src))
- strcpy(FullName,Src);
- else
- {
- if (getcwd(FullName,sizeof(FullName))==NULL)
- *FullName=0;
- else
- AddEndSlash(FullName);
- strcat(FullName,Src);
- }
- strcpy(Dest,FullName);
-#endif
+ return DestName==NULL ? SrcName:DestName;
}
-void ConvertNameToFull(const wchar *Src,wchar *Dest)
+void ConvertNameToFull(const wchar *Src,wchar *Dest,size_t MaxSize)
{
if (Src==NULL || *Src==0)
{
- *Dest=0;
+ if (MaxSize>0)
+ *Dest=0;
return;
}
#ifdef _WIN_ALL
-#ifndef _WIN_CE
- if (WinNT())
-#endif
{
-#ifndef _WIN_CE
wchar FullName[NM],*NamePtr;
- DWORD Code=GetFullPathNameW(Src,ASIZE(FullName),FullName,&NamePtr);
+ DWORD Code=GetFullPathName(Src,ASIZE(FullName),FullName,&NamePtr);
+ if (Code==0 || Code>ASIZE(FullName))
+ {
+ wchar LongName[NM];
+ if (GetWinLongPath(Src,LongName,ASIZE(LongName)))
+ Code=GetFullPathName(LongName,ASIZE(FullName),FullName,&NamePtr);
+ }
if (Code!=0 && Code<ASIZE(FullName))
- wcscpy(Dest,FullName);
+ wcsncpyz(Dest,FullName,MaxSize);
else
-#endif
if (Src!=Dest)
- wcscpy(Dest,Src);
+ wcsncpyz(Dest,Src,MaxSize);
}
-#ifndef _WIN_CE
+#elif defined(_UNIX)
+ if (IsFullPath(Src))
+ *Dest=0;
else
{
- char AnsiName[NM];
- WideToChar(Src,AnsiName);
- ConvertNameToFull(AnsiName,AnsiName);
- CharToWide(AnsiName,Dest);
+ char CurDirA[NM];
+ if (getcwd(CurDirA,ASIZE(CurDirA))==NULL)
+ *CurDirA=0;
+ CharToWide(CurDirA,Dest,MaxSize);
+ AddEndSlash(Dest,MaxSize);
}
-#endif
+ wcsncatz(Dest,Src,MaxSize);
#else
- char AnsiName[NM];
- WideToChar(Src,AnsiName);
- ConvertNameToFull(AnsiName,AnsiName);
- CharToWide(AnsiName,Dest);
-#endif
-}
-
-
-bool IsFullPath(const char *Path)
-{
- char PathOnly[NM];
- GetFilePath(Path,PathOnly,ASIZE(PathOnly));
- if (IsWildcard(PathOnly,NULL))
- return(true);
-#if defined(_WIN_ALL) || defined(_EMX)
- return(Path[0]=='\\' && Path[1]=='\\' ||
- IsDiskLetter(Path) && IsPathDiv(Path[2]));
-#else
- return(IsPathDiv(Path[0]));
+ wcsncpyz(Dest,Src,MaxSize);
#endif
}
bool IsFullPath(const wchar *Path)
{
+/*
wchar PathOnly[NM];
GetFilePath(Path,PathOnly,ASIZE(PathOnly));
- if (IsWildcard(NULL,PathOnly))
- return(true);
+ if (IsWildcard(PathOnly))
+ return true;
+*/
#if defined(_WIN_ALL) || defined(_EMX)
- return(Path[0]=='\\' && Path[1]=='\\' ||
- IsDiskLetter(Path) && IsPathDiv(Path[2]));
+ return Path[0]=='\\' && Path[1]=='\\' || IsDiskLetter(Path) && IsPathDiv(Path[2]);
#else
- return(IsPathDiv(Path[0]));
+ return IsPathDiv(Path[0]);
#endif
}
-bool IsDiskLetter(const char *Path)
-{
- char Letter=etoupper(Path[0]);
- return(Letter>='A' && Letter<='Z' && IsDriveDiv(Path[1]));
-}
-
-
bool IsDiskLetter(const wchar *Path)
{
wchar Letter=etoupperw(Path[0]);
@@ -987,34 +598,11 @@ bool IsDiskLetter(const wchar *Path)
}
-void GetPathRoot(const char *Path,char *Root)
+void GetPathRoot(const wchar *Path,wchar *Root,size_t MaxSize)
{
*Root=0;
if (IsDiskLetter(Path))
- sprintf(Root,"%c:\\",*Path);
- else
- if (Path[0]=='\\' && Path[1]=='\\')
- {
- const char *Slash=strchr(Path+2,'\\');
- if (Slash!=NULL)
- {
- size_t Length;
- if ((Slash=strchr(Slash+1,'\\'))!=NULL)
- Length=Slash-Path+1;
- else
- Length=strlen(Path);
- strncpy(Root,Path,Length);
- Root[Length]=0;
- }
- }
-}
-
-
-void GetPathRoot(const wchar *Path,wchar *Root)
-{
- *Root=0;
- if (IsDiskLetter(Path))
- sprintfw(Root,4,L"%c:\\",*Path);
+ swprintf(Root,MaxSize,L"%c:\\",*Path);
else
if (Path[0]=='\\' && Path[1]=='\\')
{
@@ -1026,6 +614,8 @@ void GetPathRoot(const wchar *Path,wchar *Root)
Length=Slash-Path+1;
else
Length=wcslen(Path);
+ if (Length>=MaxSize)
+ Length=0;
wcsncpy(Root,Path,Length);
Root[Length]=0;
}
@@ -1033,90 +623,23 @@ void GetPathRoot(const wchar *Path,wchar *Root)
}
-int ParseVersionFileName(char *Name,wchar *NameW,bool Truncate)
+int ParseVersionFileName(wchar *Name,bool Truncate)
{
int Version=0;
- char *VerText=strrchrd(Name,';');
+ wchar *VerText=wcsrchr(Name,';');
if (VerText!=NULL)
{
- Version=atoi(VerText+1);
+ if (Version==0)
+ Version=atoiw(VerText+1);
if (Truncate)
*VerText=0;
}
- if (NameW!=NULL)
- {
- wchar *VerTextW=wcsrchr(NameW,';');
- if (VerTextW!=NULL)
- {
- if (Version==0)
- Version=atoiw(VerTextW+1);
- if (Truncate)
- *VerTextW=0;
- }
- }
- return(Version);
+ return Version;
}
#if !defined(SFX_MODULE) && !defined(SETUP)
// Get the name of first volume. Return the leftmost digit of volume number.
-char* VolNameToFirstName(const char *VolName,char *FirstName,bool NewNumbering)
-{
- if (FirstName!=VolName)
- strcpy(FirstName,VolName);
- char *VolNumStart=FirstName;
- if (NewNumbering)
- {
- char N='1';
-
- // From the rightmost digit of volume number to the left.
- for (char *ChPtr=GetVolNumPart(FirstName);ChPtr>FirstName;ChPtr--)
- if (IsDigit(*ChPtr))
- {
- *ChPtr=N; // Set the rightmost digit to '1' and others to '0'.
- N='0';
- }
- else
- if (N=='0')
- {
- VolNumStart=ChPtr+1; // Store the position of leftmost digit in volume number.
- break;
- }
- }
- else
- {
- // Old volume numbering scheme. Just set the extension to ".rar".
- SetExt(FirstName,"rar");
- VolNumStart=GetExt(FirstName);
- }
- if (!FileExist(FirstName))
- {
- // If the first volume, which name we just generated, is not exist,
- // check if volume with same name and any other extension is available.
- // It can help in case of *.exe or *.sfx first volume.
- char Mask[NM];
- strcpy(Mask,FirstName);
- SetExt(Mask,"*");
- FindFile Find;
- Find.SetMask(Mask);
- FindData FD;
- while (Find.Next(&FD))
- {
- Archive Arc;
- if (Arc.Open(FD.Name,FD.NameW,0) && Arc.IsArchive(true) && !Arc.NotFirstVolume)
- {
- strcpy(FirstName,FD.Name);
- break;
- }
- }
- }
- return(VolNumStart);
-}
-#endif
-
-
-#if !defined(SFX_MODULE) && !defined(SETUP)
-// Get the name of first volume. Return the leftmost digit of volume number.
wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,bool NewNumbering)
{
if (FirstName!=VolName)
@@ -1146,7 +669,7 @@ wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,bool NewNumberin
SetExt(FirstName,L"rar");
VolNumStart=GetExt(FirstName);
}
- if (!FileExist(NULL,FirstName))
+ if (!FileExist(FirstName))
{
// If the first volume, which name we just generated, is not exist,
// check if volume with same name and any other extension is available.
@@ -1155,73 +678,25 @@ wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,bool NewNumberin
wcscpy(Mask,FirstName);
SetExt(Mask,L"*");
FindFile Find;
- Find.SetMaskW(Mask);
+ Find.SetMask(Mask);
FindData FD;
while (Find.Next(&FD))
{
Archive Arc;
- if (Arc.Open(FD.Name,FD.NameW,0) && Arc.IsArchive(true) && !Arc.NotFirstVolume)
+ if (Arc.Open(FD.Name,0) && Arc.IsArchive(true) && Arc.FirstVolume)
{
- wcscpy(FirstName,FD.NameW);
+ wcscpy(FirstName,FD.Name);
break;
}
}
}
- return(VolNumStart);
+ return VolNumStart;
}
#endif
#ifndef SFX_MODULE
-static void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
- uint ArcNumber,bool &ArcNumPresent);
-
-void GenerateArchiveName(char *ArcName,wchar *ArcNameW,size_t MaxSize,
- char *GenerateMask,bool Archiving)
-{
- // Must be enough space for archive name plus all stuff in mask plus
- // extra overhead produced by mask 'N' (archive number) characters.
- // One 'N' character can result in several numbers if we process more
- // than 9 archives.
- char NewName[NM+MAX_GENERATE_MASK+20];
- wchar NewNameW[NM+MAX_GENERATE_MASK+20];
-
- uint ArcNumber=1;
- while (true) // Loop for 'N' (archive number) processing.
- {
- strncpyz(NewName,NullToEmpty(ArcName),ASIZE(NewName));
- wcsncpyz(NewNameW,NullToEmpty(ArcNameW),ASIZE(NewNameW));
-
- bool ArcNumPresent=false;
-
- GenArcName(NewName,NewNameW,GenerateMask,ArcNumber,ArcNumPresent);
-
- if (!ArcNumPresent)
- break;
- if (!FileExist(NewName,NewNameW))
- {
- if (!Archiving && ArcNumber>1)
- {
- // If we perform non-archiving operation, we need to use the last
- // existing archive before the first unused name. So we generate
- // the name for (ArcNumber-1) below.
- strncpyz(NewName,NullToEmpty(ArcName),ASIZE(NewName));
- wcsncpyz(NewNameW,NullToEmpty(ArcNameW),ASIZE(NewNameW));
- GenArcName(NewName,NewNameW,GenerateMask,ArcNumber-1,ArcNumPresent);
- }
- break;
- }
- ArcNumber++;
- }
- if (ArcName!=NULL && *ArcName!=0)
- strncpyz(ArcName,NewName,MaxSize);
- if (ArcNameW!=NULL && *ArcNameW!=0)
- wcsncpyz(ArcNameW,NewNameW,MaxSize);
-}
-
-
-void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
- uint ArcNumber,bool &ArcNumPresent)
+static void GenArcName(wchar *ArcName,wchar *GenerateMask,uint ArcNumber,bool &ArcNumPresent)
{
bool Prefix=false;
if (*GenerateMask=='+')
@@ -1230,8 +705,8 @@ void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
GenerateMask++; // Skip '+' in the beginning of time mask.
}
- char Mask[MAX_GENERATE_MASK];
- strncpyz(Mask,*GenerateMask ? GenerateMask:"yyyymmddhhmmss",ASIZE(Mask));
+ wchar Mask[MAX_GENERATE_MASK];
+ wcsncpyz(Mask,*GenerateMask!=0 ? GenerateMask:L"yyyymmddhhmmss",ASIZE(Mask));
bool QuoteMode=false,Hours=false;
for (uint I=0;Mask[I]!=0;I++)
@@ -1243,7 +718,7 @@ void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
}
if (QuoteMode)
continue;
- int CurChar=etoupper(Mask[I]);
+ int CurChar=toupperw(Mask[I]);
if (CurChar=='H')
Hours=true;
@@ -1257,7 +732,7 @@ void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
{
uint Digits=GetDigits(ArcNumber);
uint NCount=0;
- while (etoupper(Mask[I+NCount])=='N')
+ while (toupperw(Mask[I+NCount])=='N')
NCount++;
// Here we ensure that we have enough 'N' characters to fit all digits
@@ -1265,8 +740,8 @@ void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
// in this function.
if (NCount<Digits)
{
- memmove(Mask+I+Digits,Mask+I+NCount,strlen(Mask+I+NCount)+1);
- memset(Mask+I,'N',Digits);
+ wmemmove(Mask+I+Digits,Mask+I+NCount,wcslen(Mask+I+NCount)+1);
+ wmemset(Mask+I,'N',Digits);
}
I+=Max(Digits,NCount)-1;
ArcNumPresent=true;
@@ -1279,32 +754,14 @@ void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
RarLocalTime rlt;
CurTime.GetLocal(&rlt);
- char Ext[NM];
+ wchar Ext[NM],*Dot=GetExt(ArcName);
*Ext=0;
- if (ArcName!=NULL && *ArcName!=0)
+ if (Dot==NULL)
+ wcscpy(Ext,*PointToName(ArcName)==0 ? L".rar":L"");
+ else
{
- char *Dot;
- if ((Dot=GetExt(ArcName))==NULL)
- strcpy(Ext,*PointToName(ArcName)==0 ? ".rar":"");
- else
- {
- strcpy(Ext,Dot);
- *Dot=0;
- }
- }
-
- wchar ExtW[NM];
- *ExtW=0;
- if (ArcNameW!=NULL && *ArcNameW!=0)
- {
- wchar *DotW;
- if ((DotW=GetExt(ArcNameW))==NULL)
- wcscpy(ExtW,*PointToName(ArcNameW)==0 ? L".rar":L"");
- else
- {
- wcscpy(ExtW,DotW);
- *DotW=0;
- }
+ wcsncpyz(Ext,Dot,ASIZE(Ext));
+ *Dot=0;
}
int WeekDay=rlt.wDay==0 ? 6:rlt.wDay-1;
@@ -1331,7 +788,7 @@ void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
sprintf(Field[8],"%03d",rlt.yDay+1);
sprintf(Field[9],"%05d",ArcNumber);
- const char *MaskChars="YMDHISWAEN";
+ const wchar *MaskChars=L"YMDHISWAEN";
int CField[sizeof(Field)/sizeof(Field[0])];
memset(CField,0,sizeof(CField));
@@ -1345,12 +802,12 @@ void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
}
if (QuoteMode)
continue;
- const char *Ch=strchr(MaskChars,etoupper(Mask[I]));
- if (Ch!=NULL)
- CField[Ch-MaskChars]++;
+ const wchar *ChPtr=wcschr(MaskChars,toupperw(Mask[I]));
+ if (ChPtr!=NULL)
+ CField[ChPtr-MaskChars]++;
}
- char DateText[MAX_GENERATE_MASK];
+ wchar DateText[MAX_GENERATE_MASK];
*DateText=0;
QuoteMode=false;
for (size_t I=0,J=0;Mask[I]!=0 && J<ASIZE(DateText)-1;I++)
@@ -1360,17 +817,17 @@ void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
QuoteMode=(Mask[I]=='{');
continue;
}
- const char *Ch=strchr(MaskChars,etoupper(Mask[I]));
- if (Ch==NULL || QuoteMode)
+ const wchar *ChPtr=wcschr(MaskChars,toupperw(Mask[I]));
+ if (ChPtr==NULL || QuoteMode)
DateText[J]=Mask[I];
else
{
- size_t FieldPos=Ch-MaskChars;
+ size_t FieldPos=ChPtr-MaskChars;
int CharPos=(int)strlen(Field[FieldPos])-CField[FieldPos]--;
- if (FieldPos==1 && etoupper(Mask[I+1])=='M' && etoupper(Mask[I+2])=='M')
+ if (FieldPos==1 && toupperw(Mask[I+1])=='M' && toupperw(Mask[I+2])=='M')
{
- strncpyz(DateText+J,GetMonthName(rlt.Month-1),ASIZE(DateText)-J);
- J=strlen(DateText);
+ wcsncpyz(DateText+J,GetMonthName(rlt.Month-1),ASIZE(DateText)-J);
+ J=wcslen(DateText);
I+=2;
continue;
}
@@ -1382,41 +839,55 @@ void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
DateText[++J]=0;
}
- wchar DateTextW[ASIZE(DateText)];
- CharToWide(DateText,DateTextW);
-
if (Prefix)
{
- if (ArcName!=NULL && *ArcName!=0)
- {
- char NewName[NM];
- GetFilePath(ArcName,NewName,ASIZE(NewName));
- AddEndSlash(NewName);
- strcat(NewName,DateText);
- strcat(NewName,PointToName(ArcName));
- strcpy(ArcName,NewName);
- }
- if (ArcNameW!=NULL && *ArcNameW!=0)
- {
- wchar NewNameW[NM];
- GetFilePath(ArcNameW,NewNameW,ASIZE(NewNameW));
- AddEndSlash(NewNameW);
- wcscat(NewNameW,DateTextW);
- wcscat(NewNameW,PointToName(ArcNameW));
- wcscpy(ArcNameW,NewNameW);
- }
+ wchar NewName[NM];
+ GetFilePath(ArcName,NewName,ASIZE(NewName));
+ AddEndSlash(NewName,ASIZE(NewName));
+ wcsncatz(NewName,DateText,ASIZE(NewName));
+ wcsncatz(NewName,PointToName(ArcName),ASIZE(NewName));
+ wcscpy(ArcName,NewName);
}
else
+ wcscat(ArcName,DateText);
+ wcscat(ArcName,Ext);
+}
+
+
+void GenerateArchiveName(wchar *ArcName,size_t MaxSize,wchar *GenerateMask,bool Archiving)
+{
+ // Must be enough space for archive name plus all stuff in mask plus
+ // extra overhead produced by mask 'N' (archive number) characters.
+ // One 'N' character can result in several numbers if we process more
+ // than 9 archives.
+ wchar NewName[NM+MAX_GENERATE_MASK+20];
+
+ uint ArcNumber=1;
+ while (true) // Loop for 'N' (archive number) processing.
{
- if (ArcName!=NULL && *ArcName!=0)
- strcat(ArcName,DateText);
- if (ArcNameW!=NULL && *ArcNameW!=0)
- wcscat(ArcNameW,DateTextW);
+ wcsncpyz(NewName,ArcName,ASIZE(NewName));
+
+ bool ArcNumPresent=false;
+
+ GenArcName(NewName,GenerateMask,ArcNumber,ArcNumPresent);
+
+ if (!ArcNumPresent)
+ break;
+ if (!FileExist(NewName))
+ {
+ if (!Archiving && ArcNumber>1)
+ {
+ // If we perform non-archiving operation, we need to use the last
+ // existing archive before the first unused name. So we generate
+ // the name for (ArcNumber-1) below.
+ wcsncpyz(NewName,NullToEmpty(ArcName),ASIZE(NewName));
+ GenArcName(NewName,GenerateMask,ArcNumber-1,ArcNumPresent);
+ }
+ break;
+ }
+ ArcNumber++;
}
- if (ArcName!=NULL && *ArcName!=0)
- strcat(ArcName,Ext);
- if (ArcNameW!=NULL && *ArcNameW!=0)
- wcscat(ArcNameW,ExtW);
+ wcsncpyz(ArcName,NewName,MaxSize);
}
#endif
@@ -1442,16 +913,66 @@ wchar* GetWideName(const char *Name,const wchar *NameW,wchar *DestW,size_t DestS
}
-// Unlike WideToChar, always returns the zero terminated string,
-// even if the destination buffer size is not enough.
-char* GetAsciiName(const wchar *NameW,char *Name,size_t DestSize)
-{
- if (DestSize>0)
- {
- WideToChar(NameW,Name,DestSize);
- Name[DestSize-1]=0;
+#ifdef _WIN_ALL
+// We should return 'true' even if resulting path is shorter than MAX_PATH,
+// because we can also use this function to open files with non-standard
+// characters, even if their path length is normal.
+bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize)
+{
+ const wchar *Prefix=L"\\\\?\\";
+ const size_t PrefixLength=4;
+ bool FullPath=IsDiskLetter(Src) && IsPathDiv(Src[2]);
+ size_t SrcLength=wcslen(Src);
+ if (IsFullPath(Src)) // Paths in d:\path\name format.
+ {
+ if (IsDiskLetter(Src))
+ {
+ if (MaxSize<=PrefixLength+SrcLength)
+ return false;
+ wcsncpy(Dest,Prefix,PrefixLength);
+ wcscpy(Dest+PrefixLength,Src);
+ return true;
+ }
+ else
+ if (Src[0]=='\\' && Src[1]=='\\')
+ {
+ if (MaxSize<=PrefixLength+SrcLength+2)
+ return false;
+ wcsncpy(Dest,Prefix,PrefixLength);
+ wcscpy(Dest+PrefixLength,L"UNC");
+ wcscpy(Dest+PrefixLength+3,Src+1);
+ return true;
+ }
+ // We may be here only if we modify IsFullPath in the future.
+ return false;
}
else
- *Name=0;
- return Name;
+ {
+ wchar CurDir[NM];
+ DWORD DirCode=GetCurrentDirectory(ASIZE(CurDir)-1,CurDir);
+ if (DirCode==0 || DirCode>ASIZE(CurDir)-1)
+ return false;
+
+ if (IsPathDiv(Src[0])) // Paths in \path\name format.
+ {
+ if (MaxSize<=PrefixLength+SrcLength+2)
+ return false;
+ wcsncpy(Dest,Prefix,PrefixLength);
+ wcsncpy(Dest+PrefixLength,CurDir,2); // Copy drive letter 'd:'.
+ wcscpy(Dest+PrefixLength+2,Src);
+ return true;
+ }
+ else // Paths in path\name format.
+ {
+ AddEndSlash(CurDir,ASIZE(CurDir));
+ if (MaxSize<=PrefixLength+wcslen(CurDir)+SrcLength)
+ return false;
+ wcsncpy(Dest,Prefix,PrefixLength);
+ wcscpy(Dest+PrefixLength,CurDir);
+ wcsncatz(Dest,Src,MaxSize);
+ return true;
+ }
+ }
+ return false;
}
+#endif
diff --git a/src/thirdparty/unrar/pathfn.hpp b/src/thirdparty/unrar/pathfn.hpp
index 5ee614696..755c8b646 100644
--- a/src/thirdparty/unrar/pathfn.hpp
+++ b/src/thirdparty/unrar/pathfn.hpp
@@ -1,66 +1,48 @@
#ifndef _RAR_PATHFN_
#define _RAR_PATHFN_
-char* PointToName(const char *Path);
wchar* PointToName(const wchar *Path);
-char* PointToLastChar(const char *Path);
wchar* PointToLastChar(const wchar *Path);
-char* ConvertPath(const char *SrcPath,char *DestPath);
wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath);
-void SetExt(char *Name,const char *NewExt);
+void SetName(wchar *FullName,const wchar *Name,size_t MaxSize);
void SetExt(wchar *Name,const wchar *NewExt);
-void SetSFXExt(char *SFXName);
void SetSFXExt(wchar *SFXName);
-char *GetExt(const char *Name);
wchar *GetExt(const wchar *Name);
-bool CmpExt(const char *Name,const char *Ext);
bool CmpExt(const wchar *Name,const wchar *Ext);
-bool IsWildcard(const char *Str,const wchar *StrW=NULL);
+bool IsWildcard(const wchar *Str);
bool IsPathDiv(int Ch);
bool IsDriveDiv(int Ch);
-int GetPathDisk(const char *Path);
int GetPathDisk(const wchar *Path);
-void AddEndSlash(char *Path);
-void AddEndSlash(wchar *Path);
-void GetFilePath(const char *FullName,char *Path,int MaxLength);
-void GetFilePath(const wchar *FullName,wchar *Path,int MaxLength);
-void RemoveNameFromPath(char *Path);
+void AddEndSlash(wchar *Path,size_t MaxLength);
+void MakeName(const wchar *Path,const wchar *Name,wchar *Pathname,size_t MaxSize);
+void GetFilePath(const wchar *FullName,wchar *Path,size_t MaxLength);
void RemoveNameFromPath(wchar *Path);
-void GetAppDataPath(char *Path);
-void GetAppDataPath(wchar *Path);
-void GetRarDataPath(char *Path);
-void GetRarDataPath(wchar *Path);
-bool EnumConfigPaths(wchar *Path,int Number);
-bool EnumConfigPaths(char *Path,int Number);
-void GetConfigName(const char *Name,char *FullName,bool CheckExist);
-void GetConfigName(const wchar *Name,wchar *FullName,bool CheckExist);
-char* GetVolNumPart(char *ArcName);
-wchar* GetVolNumPart(wchar *ArcName);
-void NextVolumeName(char *ArcName,wchar *ArcNameW,uint MaxLength,bool OldNumbering);
-bool IsNameUsable(const char *Name);
+void GetRarDataPath(wchar *Path,size_t MaxSize);
+bool EnumConfigPaths(uint Number,wchar *Path,size_t MaxSize);
+void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckExist);
+wchar* GetVolNumPart(const wchar *ArcName);
+void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering);
bool IsNameUsable(const wchar *Name);
void MakeNameUsable(char *Name,bool Extended);
void MakeNameUsable(wchar *Name,bool Extended);
-char* UnixSlashToDos(char *SrcName,char *DestName=NULL,uint MaxLength=NM);
-char* DosSlashToUnix(char *SrcName,char *DestName=NULL,uint MaxLength=NM);
-wchar* UnixSlashToDos(wchar *SrcName,wchar *DestName=NULL,uint MaxLength=NM);
-wchar* DosSlashToUnix(wchar *SrcName,wchar *DestName=NULL,uint MaxLength=NM);
-void ConvertNameToFull(const char *Src,char *Dest);
-void ConvertNameToFull(const wchar *Src,wchar *Dest);
-bool IsFullPath(const char *Path);
+char* UnixSlashToDos(char *SrcName,char *DestName=NULL,size_t MaxLength=NM);
+char* DosSlashToUnix(char *SrcName,char *DestName=NULL,size_t MaxLength=NM);
+wchar* UnixSlashToDos(wchar *SrcName,wchar *DestName=NULL,size_t MaxLength=NM);
+wchar* DosSlashToUnix(wchar *SrcName,wchar *DestName=NULL,size_t MaxLength=NM);
+void ConvertNameToFull(const wchar *Src,wchar *Dest,size_t MaxSize);
bool IsFullPath(const wchar *Path);
-bool IsDiskLetter(const char *Path);
bool IsDiskLetter(const wchar *Path);
-void GetPathRoot(const char *Path,char *Root);
-void GetPathRoot(const wchar *Path,wchar *Root);
-int ParseVersionFileName(char *Name,wchar *NameW,bool Truncate);
-char* VolNameToFirstName(const char *VolName,char *FirstName,bool NewNumbering);
+void GetPathRoot(const wchar *Path,wchar *Root,size_t MaxSize);
+int ParseVersionFileName(wchar *Name,bool Truncate);
wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,bool NewNumbering);
wchar* GetWideName(const char *Name,const wchar *NameW,wchar *DestW,size_t DestSize);
-char* GetAsciiName(const wchar *NameW,char *Name,size_t DestSize);
#ifndef SFX_MODULE
-void GenerateArchiveName(char *ArcName,wchar *ArcNameW,size_t MaxSize,char *GenerateMask,bool Archiving);
+void GenerateArchiveName(wchar *ArcName,size_t MaxSize,wchar *GenerateMask,bool Archiving);
+#endif
+
+#ifdef _WIN_ALL
+bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize);
#endif
#endif
diff --git a/src/thirdparty/unrar/qopen.cpp b/src/thirdparty/unrar/qopen.cpp
new file mode 100644
index 000000000..789e5c03d
--- /dev/null
+++ b/src/thirdparty/unrar/qopen.cpp
@@ -0,0 +1,272 @@
+#include "rar.hpp"
+
+QuickOpen::QuickOpen()
+{
+ Buf=NULL;
+ Init(NULL,false);
+}
+
+
+QuickOpen::~QuickOpen()
+{
+ Close();
+ delete[] Buf;
+}
+
+
+void QuickOpen::Init(Archive *Arc,bool WriteMode)
+{
+ if (Arc!=NULL) // Unless called from constructor.
+ Close();
+
+ QuickOpen::Arc=Arc;
+ QuickOpen::WriteMode=WriteMode;
+
+ ListStart=NULL;
+ ListEnd=NULL;
+
+ if (Buf==NULL)
+ Buf=new byte[MaxBufSize];
+
+ CurBufSize=0; // Current size of buffered data in write mode.
+
+ Loaded=false;
+}
+
+
+void QuickOpen::Close()
+{
+ QuickOpenItem *Item=ListStart;
+ while (Item!=NULL)
+ {
+ QuickOpenItem *Next=Item->Next;
+ delete[] Item->Header;
+ delete Item;
+ Item=Next;
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void QuickOpen::Load(uint64 BlockPos)
+{
+ if (!Loaded) // If loading the first time, perform additional intialization.
+ {
+ SeekPos=Arc->Tell();
+ UnsyncSeekPos=false;
+
+ SaveFilePos SavePos(*Arc);
+ Arc->Seek(BlockPos,SEEK_SET);
+ if (Arc->ReadHeader()==0 || Arc->GetHeaderType()!=HEAD_SERVICE ||
+ !Arc->SubHead.CmpName(SUBHEAD_TYPE_QOPEN))
+ return;
+ QLHeaderPos=Arc->CurBlockPos;
+ RawDataStart=Arc->Tell();
+ RawDataSize=Arc->SubHead.UnpSize;
+
+ Loaded=true; // Set only after all file processing calls like Tell, Seek, ReadHeader.
+ }
+
+ if (Arc->SubHead.Encrypted)
+ {
+ RAROptions *Cmd=Arc->GetRAROptions();
+#ifndef RAR_NOCRYPT
+ if (Cmd->Password.IsSet())
+ Crypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,Arc->SubHead.Salt,
+ Arc->SubHead.InitV,Arc->SubHead.Lg2Count,
+ Arc->SubHead.HashKey,Arc->SubHead.PswCheck);
+ else
+#endif
+ return;
+ }
+
+ RawDataPos=0;
+ ReadBufSize=0;
+ ReadBufPos=0;
+ LastReadHeader.Reset();
+ LastReadHeaderPos=0;
+
+ ReadBuffer();
+}
+
+
+bool QuickOpen::Read(void *Data,size_t Size,size_t &Result)
+{
+ if (!Loaded)
+ return false;
+ // Find next suitable cached block.
+ while (LastReadHeaderPos+LastReadHeader.Size()<=SeekPos)
+ if (!ReadNext())
+ break;
+ if (!Loaded)
+ {
+ // If something wrong happened, let's set the correct file pointer
+ // and stop further quick open processing.
+ if (UnsyncSeekPos)
+ Arc->File::Seek(SeekPos,SEEK_SET);
+ return false;
+ }
+
+ if (SeekPos>=LastReadHeaderPos && SeekPos+Size<=LastReadHeaderPos+LastReadHeader.Size())
+ {
+ memcpy(Data,LastReadHeader+size_t(SeekPos-LastReadHeaderPos),Size);
+ Result=Size;
+ SeekPos+=Size;
+ UnsyncSeekPos=true;
+ }
+ else
+ {
+ if (UnsyncSeekPos)
+ {
+ Arc->File::Seek(SeekPos,SEEK_SET);
+ UnsyncSeekPos=false;
+ }
+ int ReadSize=Arc->File::Read(Data,Size);
+ if (ReadSize<0)
+ {
+ Loaded=false;
+ return false;
+ }
+ Result=ReadSize;
+ SeekPos+=ReadSize;
+ }
+
+ return true;
+}
+
+
+bool QuickOpen::Seek(int64 Offset,int Method)
+{
+ if (!Loaded)
+ return false;
+
+ // Normally we process an archive sequentially from beginning to end,
+ // so we read quick open data sequentially. But some operations like
+ // archive updating involve several passes. So if we detect that file
+ // pointer is moved back, we reload quick open data from beginning.
+ if (Method==SEEK_SET && (uint64)Offset<SeekPos && (uint64)Offset<LastReadHeaderPos)
+ Load(QLHeaderPos);
+
+ if (Method==SEEK_SET)
+ SeekPos=Offset;
+ if (Method==SEEK_CUR)
+ SeekPos+=Offset;
+ UnsyncSeekPos=true;
+
+ if (Method==SEEK_END)
+ {
+ Arc->File::Seek(Offset,SEEK_END);
+ SeekPos=Arc->File::Tell();
+ UnsyncSeekPos=false;
+ }
+ return true;
+}
+
+
+bool QuickOpen::Tell(int64 *Pos)
+{
+ if (!Loaded)
+ return false;
+ *Pos=SeekPos;
+ return true;
+}
+
+
+uint QuickOpen::ReadBuffer()
+{
+ SaveFilePos SavePos(*Arc);
+ Arc->File::Seek(RawDataStart+RawDataPos,SEEK_SET);
+ size_t SizeToRead=(size_t)Min(RawDataSize-RawDataPos,MaxBufSize-ReadBufSize);
+ if (Arc->SubHead.Encrypted)
+ SizeToRead &= ~CRYPT_BLOCK_MASK;
+ if (SizeToRead==0)
+ return 0;
+ int ReadSize=Arc->File::Read(Buf+ReadBufSize,SizeToRead);
+ if (ReadSize<=0)
+ return 0;
+#ifndef RAR_NOCRYPT
+ if (Arc->SubHead.Encrypted)
+ Crypt.DecryptBlock(Buf+ReadBufSize,ReadSize & ~CRYPT_BLOCK_MASK);
+#endif
+ RawDataPos+=ReadSize;
+ ReadBufSize+=ReadSize;
+ return ReadSize;
+}
+
+
+// Fill RawRead object from buffer.
+bool QuickOpen::ReadRaw(RawRead &Raw)
+{
+ if (MaxBufSize-ReadBufPos<0x100) // We are close to end of buffer.
+ {
+ // Ensure that we have enough data to read CRC and header size.
+ size_t DataLeft=ReadBufSize-ReadBufPos;
+ memcpy(Buf,Buf+ReadBufPos,DataLeft);
+ ReadBufPos=0;
+ ReadBufSize=DataLeft;
+ ReadBuffer();
+ }
+ const size_t FirstReadSize=7;
+ if (ReadBufPos+FirstReadSize>ReadBufSize)
+ return false;
+ Raw.Read(Buf+ReadBufPos,FirstReadSize);
+ ReadBufPos+=FirstReadSize;
+
+ uint SavedCRC=Raw.Get4();
+ uint SizeBytes=Raw.GetVSize(4);
+ uint64 BlockSize=Raw.GetV();
+ int SizeToRead=int(BlockSize);
+ SizeToRead-=FirstReadSize-SizeBytes-4; // Adjust overread size bytes if any.
+ if (SizeToRead<0 || SizeBytes==0 || BlockSize==0)
+ {
+ Loaded=false; // Invalid data.
+ return false;
+ }
+
+ // If rest of block data crosses buffer boundary, read it in loop.
+ size_t DataLeft=ReadBufSize-ReadBufPos;
+ while (SizeToRead>0)
+ {
+ size_t CurSizeToRead=Min(DataLeft,(size_t)SizeToRead);
+ Raw.Read(Buf+ReadBufPos,CurSizeToRead);
+ ReadBufPos+=CurSizeToRead;
+ SizeToRead-=int(CurSizeToRead);
+ if (SizeToRead>0) // We read the entire buffer and still need more data.
+ {
+ ReadBufPos=0;
+ ReadBufSize=0;
+ if (ReadBuffer()==0)
+ return false;
+ }
+ }
+
+ return SavedCRC==Raw.GetCRC50();
+}
+
+
+// Read next cached header.
+bool QuickOpen::ReadNext()
+{
+ RawRead Raw(NULL);
+ if (!ReadRaw(Raw)) // Read internal quick open header preceding stored block.
+ return false;
+ uint Flags=(uint)Raw.GetV();
+ uint64 Offset=Raw.GetV();
+ size_t HeaderSize=(size_t)Raw.GetV();
+ LastReadHeader.Alloc(HeaderSize);
+ Raw.GetB(&LastReadHeader[0],HeaderSize);
+ // Calculate the absolute position as offset from quick open service header.
+ LastReadHeaderPos=QLHeaderPos-Offset;
+ return true;
+}
diff --git a/src/thirdparty/unrar/qopen.hpp b/src/thirdparty/unrar/qopen.hpp
new file mode 100644
index 000000000..e04af182d
--- /dev/null
+++ b/src/thirdparty/unrar/qopen.hpp
@@ -0,0 +1,61 @@
+#ifndef _RAR_QOPEN_
+#define _RAR_QOPEN_
+
+struct QuickOpenItem
+{
+ byte *Header;
+ size_t HeaderSize;
+ uint64 ArcPos;
+ QuickOpenItem *Next;
+};
+
+
+class Archive;
+class RawRead;
+
+class QuickOpen
+{
+ private:
+ void Close();
+
+
+ uint ReadBuffer();
+ bool ReadRaw(RawRead &Raw);
+ bool ReadNext();
+
+ Archive *Arc;
+ bool WriteMode;
+
+ QuickOpenItem *ListStart;
+ QuickOpenItem *ListEnd;
+
+ byte *Buf;
+ static const size_t MaxBufSize=0x10000; // Must be multiple of CRYPT_BLOCK_SIZE.
+ size_t CurBufSize;
+#ifndef RAR_NOCRYPT // For shell extension.
+ CryptData Crypt;
+#endif
+
+ bool Loaded;
+ uint64 QLHeaderPos;
+ uint64 RawDataStart;
+ uint64 RawDataSize;
+ uint64 RawDataPos;
+ size_t ReadBufSize;
+ size_t ReadBufPos;
+ Array<byte> LastReadHeader;
+ uint64 LastReadHeaderPos;
+ uint64 SeekPos;
+ bool UnsyncSeekPos; // QOpen SeekPos does not match an actual file pointer.
+ public:
+ QuickOpen();
+ ~QuickOpen();
+ void Init(Archive *Arc,bool WriteMode);
+ void Load(uint64 BlockPos);
+ void Unload() { Loaded=false; }
+ bool Read(void *Data,size_t Size,size_t &Result);
+ bool Seek(int64 Offset,int Method);
+ bool Tell(int64 *Pos);
+};
+
+#endif
diff --git a/src/thirdparty/unrar/rar.cpp b/src/thirdparty/unrar/rar.cpp
index e487cc639..bf3b6c83e 100644
--- a/src/thirdparty/unrar/rar.cpp
+++ b/src/thirdparty/unrar/rar.cpp
@@ -8,31 +8,15 @@ int main(int argc, char *argv[])
setlocale(LC_ALL,"");
#endif
-#if defined(_EMX) && !defined(_DJGPP)
- uni_init(0);
-#endif
-
-#if !defined(_SFX_RTL_) && !defined(_WIN_ALL)
- setbuf(stdout,NULL);
-#endif
-
-#if !defined(SFX_MODULE) && defined(_EMX)
- EnumConfigPaths(argv[0],-1);
-#endif
-
+ InitConsole();
ErrHandler.SetSignalHandlers(true);
- RARInitData();
-
#ifdef SFX_MODULE
- char ModuleNameA[NM];
- wchar ModuleNameW[NM];
+ wchar ModuleName[NM];
#ifdef _WIN_ALL
- GetModuleFileNameW(NULL,ModuleNameW,ASIZE(ModuleNameW));
- WideToChar(ModuleNameW,ModuleNameA);
+ GetModuleFileName(NULL,ModuleName,ASIZE(ModuleName));
#else
- strcpy(ModuleNameA,argv[0]);
- *ModuleNameW=0;
+ CharToWide(argv[0],ModuleName,ASIZE(ModuleName));
#endif
#endif
@@ -48,14 +32,12 @@ int main(int argc, char *argv[])
bool ShutdownOnClose=false;
#endif
-#ifdef ALLOW_EXCEPTIONS
try
-#endif
{
- CommandData Cmd;
+ CommandData *Cmd=new CommandData;
#ifdef SFX_MODULE
- strcpy(Cmd.Command,"X");
+ wcscpy(Cmd->Command,L"X");
char *Switch=NULL;
#ifdef _SFX_RTL_
char *CmdLine=GetCommandLineA();
@@ -70,74 +52,64 @@ int main(int argc, char *argv[])
#else
Switch=argc>1 ? argv[1]:NULL;
#endif
- if (Switch!=NULL && Cmd.IsSwitch(Switch[0]))
+ if (Switch!=NULL && Cmd->IsSwitch(Switch[0]))
{
int UpperCmd=etoupper(Switch[1]);
switch(UpperCmd)
{
case 'T':
case 'V':
- Cmd.Command[0]=UpperCmd;
+ Cmd->Command[0]=UpperCmd;
break;
case '?':
- Cmd.OutHelp(RARX_SUCCESS);
+ Cmd->OutHelp(RARX_SUCCESS);
break;
}
}
- Cmd.AddArcName(ModuleNameA,ModuleNameW);
- Cmd.ParseDone();
+ Cmd->AddArcName(ModuleName);
+ Cmd->ParseDone();
#else // !SFX_MODULE
- Cmd.PreprocessCommandLine(argc,argv);
- if (!Cmd.ConfigDisabled)
+ Cmd->ParseCommandLine(true,argc,argv);
+ if (!Cmd->ConfigDisabled)
{
- Cmd.ReadConfig();
- Cmd.ParseEnvVar();
+ Cmd->ReadConfig();
+ Cmd->ParseEnvVar();
}
- Cmd.ParseCommandLine(argc,argv);
+ Cmd->ParseCommandLine(false,argc,argv);
#endif
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SHELL_EXT)
- ShutdownOnClose=Cmd.Shutdown;
+ ShutdownOnClose=Cmd->Shutdown;
#endif
- InitConsoleOptions(Cmd.MsgStream,Cmd.Sound);
- InitLogOptions(Cmd.LogName);
- ErrHandler.SetSilent(Cmd.AllYes || Cmd.MsgStream==MSG_NULL);
- ErrHandler.SetShutdown(Cmd.Shutdown);
+ InitConsoleOptions(Cmd->MsgStream,Cmd->Sound);
+ InitLogOptions(Cmd->LogName);
+ ErrHandler.SetSilent(Cmd->AllYes || Cmd->MsgStream==MSG_NULL);
+ ErrHandler.SetShutdown(Cmd->Shutdown);
- Cmd.OutTitle();
- Cmd.ProcessCommand();
+ Cmd->OutTitle();
+ Cmd->ProcessCommand();
+ delete Cmd;
}
-#ifdef ALLOW_EXCEPTIONS
catch (RAR_EXIT ErrCode)
{
ErrHandler.SetErrorCode(ErrCode);
}
-#ifdef ENABLE_BAD_ALLOC
catch (std::bad_alloc)
{
ErrHandler.MemoryErrorMsg();
ErrHandler.SetErrorCode(RARX_MEMORY);
}
-#endif
catch (...)
{
ErrHandler.SetErrorCode(RARX_FATAL);
}
-#endif
- File::RemoveCreated();
-#if defined(SFX_MODULE) && defined(_DJGPP)
- _chmod(ModuleNameA,1,0x20);
-#endif
-#if defined(_EMX) && !defined(_DJGPP)
- uni_done();
-#endif
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SHELL_EXT)
if (ShutdownOnClose)
Shutdown();
#endif
- return(ErrHandler.GetErrorCode());
+ return ErrHandler.GetErrorCode();
}
#endif
diff --git a/src/thirdparty/unrar/rar.hpp b/src/thirdparty/unrar/rar.hpp
index 73ebd2bc7..2cdf4db49 100644
--- a/src/thirdparty/unrar/rar.hpp
+++ b/src/thirdparty/unrar/rar.hpp
@@ -8,7 +8,6 @@
#include "dll.hpp"
#endif
-
#ifndef _WIN_CE
#include "version.hpp"
#endif
@@ -20,16 +19,20 @@
#include "array.hpp"
#include "timefn.hpp"
#include "secpassword.hpp"
+#include "sha1.hpp"
+#include "sha256.hpp"
+#include "blake2s.hpp"
+#include "hash.hpp"
#include "options.hpp"
+#include "rijndael.hpp"
+#include "crypt.hpp"
+#include "headers5.hpp"
#include "headers.hpp"
#include "pathfn.hpp"
#include "strfn.hpp"
#include "strlist.hpp"
#include "file.hpp"
-#include "sha1.hpp"
#include "crc.hpp"
-#include "rijndael.hpp"
-#include "crypt.hpp"
#include "filefn.hpp"
#include "filestr.hpp"
#include "find.hpp"
@@ -37,11 +40,16 @@
#include "savepos.hpp"
#include "getbits.hpp"
#include "rdwrfn.hpp"
+#ifdef USE_QOPEN
+#include "qopen.hpp"
+#endif
#include "archive.hpp"
#include "match.hpp"
#include "cmddata.hpp"
#include "filcreat.hpp"
+#ifndef GUI
#include "consio.hpp"
+#endif
#include "system.hpp"
#ifdef _WIN_ALL
#include "isnt.hpp"
@@ -55,6 +63,8 @@
#include "rarvm.hpp"
#include "model.hpp"
+#include "threadpool.hpp"
+
#include "unpack.hpp"
@@ -68,10 +78,10 @@
#include "rs.hpp"
+#include "rs16.hpp"
#include "recvol.hpp"
#include "volume.hpp"
#include "smallfn.hpp"
-#include "ulinks.hpp"
#include "global.hpp"
diff --git a/src/thirdparty/unrar/rardefs.hpp b/src/thirdparty/unrar/rardefs.hpp
index 1e9788b38..ed8729b3d 100644
--- a/src/thirdparty/unrar/rardefs.hpp
+++ b/src/thirdparty/unrar/rardefs.hpp
@@ -12,17 +12,19 @@
#define MAXSFXSIZE 0x100000
-#define DefSFXName "default.sfx"
-#define DefSortListName "rarfiles.lst"
-
-#ifndef FA_RDONLY
- #define FA_RDONLY 0x01
- #define FA_HIDDEN 0x02
- #define FA_SYSTEM 0x04
- #define FA_LABEL 0x08
- #define FA_DIREC 0x10
- #define FA_ARCH 0x20
+#define DefSFXName L"default.sfx"
+#define DefSortListName L"rarfiles.lst"
+
+
+#ifndef SFX_MODULE
+#define USE_QOPEN
#endif
+// Suppress GCC warn_unused_result warning in -O2 mode
+// for those function calls where we do not need it.
+#define ignore_result(x) if (x)
+
+// Produce the value, which is larger than 'v' and aligned to 'a'.
+#define ALIGN_VALUE(v,a) (size_t(v) + ( (~size_t(v) + 1) & (a - 1) ) )
#endif
diff --git a/src/thirdparty/unrar/raros.hpp b/src/thirdparty/unrar/raros.hpp
index ce853bd7d..c560b2e6f 100644
--- a/src/thirdparty/unrar/raros.hpp
+++ b/src/thirdparty/unrar/raros.hpp
@@ -29,11 +29,6 @@
#endif
#endif
-#ifdef __BEOS__
- #define _UNIX
- #define _BEOS
-#endif
-
#ifdef __APPLE__
#define _UNIX
#define _APPLE
diff --git a/src/thirdparty/unrar/rartypes.hpp b/src/thirdparty/unrar/rartypes.hpp
index a2d8b44a0..547f2eb11 100644
--- a/src/thirdparty/unrar/rartypes.hpp
+++ b/src/thirdparty/unrar/rartypes.hpp
@@ -21,12 +21,7 @@ typedef unsigned long long uint64; // unsigned 64 bits
typedef signed long long int64; // signed 64 bits
#endif
-
-#if defined(_WIN_ALL) || defined(__GNUC__) || defined(__sgi) || defined(_AIX) || defined(__sun) || defined(__hpux) || defined(_OSF_SOURCE)
typedef wchar_t wchar;
-#else
-typedef ushort wchar;
-#endif
// Get lowest 16 bits.
#define GET_SHORT16(x) (sizeof(ushort)==2 ? (ushort)(x):((x)&0xffff))
@@ -44,4 +39,8 @@ typedef ushort wchar;
// compatible with 32 bit int64.
#define INT64NDF INT32TO64(0x7fffffff,0x7fffffff)
+// Maximum uint64 value.
+#define MAX_UINT64 INT32TO64(0xffffffff,0xffffffff)
+#define UINT64NDF MAX_UINT64
+
#endif
diff --git a/src/thirdparty/unrar/rarvm.cpp b/src/thirdparty/unrar/rarvm.cpp
index 8b8580064..d29ce3ff9 100644
--- a/src/thirdparty/unrar/rarvm.cpp
+++ b/src/thirdparty/unrar/rarvm.cpp
@@ -3,6 +3,7 @@
#include "rarvmtbl.cpp"
RarVM::RarVM()
+:BitInput(true)
{
Mem=NULL;
}
@@ -524,7 +525,7 @@ bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,uint CodeSize)
#ifdef VM_STANDARDFILTERS
case VM_STANDARD:
ExecuteStandardFilter((VM_StandardFilters)Cmd->Op1.Data);
- break;
+ return true;
#endif
case VM_PRINT:
break;
@@ -565,8 +566,10 @@ void RarVM::Prepare(byte *Code,uint CodeSize,VM_PreparedProgram *Prg)
CurCmd->Op2.Addr=&CurCmd->Op2.Data;
CurCmd->Op1.Type=CurCmd->Op2.Type=VM_OPNONE;
CodeSize=0;
+ return;
}
#endif
+#ifndef NORARVM
uint DataFlag=fgetbits();
faddbits(1);
@@ -640,6 +643,7 @@ void RarVM::Prepare(byte *Code,uint CodeSize,VM_PreparedProgram *Prg)
}
Prg->CmdCount++;
}
+#endif
}
// Adding RET command at the end of program.
@@ -671,6 +675,7 @@ void RarVM::Prepare(byte *Code,uint CodeSize,VM_PreparedProgram *Prg)
}
+#ifndef NORARVM
void RarVM::DecodeArg(VM_PreparedOperand &Op,bool ByteMode)
{
uint Data=fgetbits();
@@ -727,6 +732,7 @@ void RarVM::DecodeArg(VM_PreparedOperand &Op,bool ByteMode)
}
}
}
+#endif
uint RarVM::ReadData(BitInput &Inp)
@@ -765,7 +771,7 @@ uint RarVM::ReadData(BitInput &Inp)
}
-void RarVM::SetMemory(uint Pos,byte *Data,uint DataSize)
+void RarVM::SetMemory(size_t Pos,byte *Data,size_t DataSize)
{
if (Pos<VM_MEMSIZE && Data!=Mem+Pos)
memmove(Mem+Pos,Data,Min(DataSize,VM_MEMSIZE-Pos));
@@ -855,10 +861,9 @@ VM_StandardFilters RarVM::IsStandardFilter(byte *Code,uint CodeSize)
120, 0x3769893f, VMSF_ITANIUM,
29, 0x0e06077d, VMSF_DELTA,
149, 0x1c2c5dc8, VMSF_RGB,
- 216, 0xbc85e701, VMSF_AUDIO,
- 40, 0x46b9c560, VMSF_UPCASE
+ 216, 0xbc85e701, VMSF_AUDIO
};
- uint CodeCRC=CRC(0xffffffff,Code,CodeSize)^0xffffffff;
+ uint CodeCRC=CRC32(0xffffffff,Code,CodeSize)^0xffffffff;
for (uint I=0;I<ASIZE(StdList);I++)
if (StdList[I].CRC==CodeCRC && StdList[I].Length==CodeSize)
return(StdList[I].Type);
@@ -1086,22 +1091,6 @@ void RarVM::ExecuteStandardFilter(VM_StandardFilters FilterType)
}
}
break;
- case VMSF_UPCASE:
- {
- int DataSize=R[4],SrcPos=0,DestPos=DataSize;
- if ((uint)DataSize>=VM_GLOBALMEMADDR/2)
- break;
- while (SrcPos<DataSize)
- {
- byte CurByte=Mem[SrcPos++];
- if (CurByte==2 && (CurByte=Mem[SrcPos++])!=2)
- CurByte-=32;
- Mem[DestPos++]=CurByte;
- }
- SET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x1c],DestPos-DataSize);
- SET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x20],DataSize);
- }
- break;
}
}
diff --git a/src/thirdparty/unrar/rarvm.hpp b/src/thirdparty/unrar/rarvm.hpp
index 96d42c233..785d5dfc3 100644
--- a/src/thirdparty/unrar/rarvm.hpp
+++ b/src/thirdparty/unrar/rarvm.hpp
@@ -2,11 +2,7 @@
#define _RAR_VM_
#define VM_STANDARDFILTERS
-
-#ifndef SFX_MODULE
-#define VM_OPTIMIZE
-#endif
-
+#define NORARVM
#define VM_MEMSIZE 0x40000
#define VM_MEMMASK (VM_MEMSIZE-1)
@@ -34,7 +30,7 @@ enum VM_Commands
enum VM_StandardFilters {
VMSF_NONE, VMSF_E8, VMSF_E8E9, VMSF_ITANIUM, VMSF_RGB, VMSF_AUDIO,
- VMSF_DELTA, VMSF_UPCASE
+ VMSF_DELTA
};
enum VM_Flags {VM_FC=1,VM_FZ=2,VM_FS=0x80000000};
@@ -106,7 +102,7 @@ class RarVM:private BitInput
void Prepare(byte *Code,uint CodeSize,VM_PreparedProgram *Prg);
void Execute(VM_PreparedProgram *Prg);
void SetLowEndianValue(uint *Addr,uint Value);
- void SetMemory(uint Pos,byte *Data,uint DataSize);
+ void SetMemory(size_t Pos,byte *Data,size_t DataSize);
static uint ReadData(BitInput &Inp);
};
diff --git a/src/thirdparty/unrar/rawread.cpp b/src/thirdparty/unrar/rawread.cpp
index df90171eb..2daad9119 100644
--- a/src/thirdparty/unrar/rawread.cpp
+++ b/src/thirdparty/unrar/rawread.cpp
@@ -3,6 +3,13 @@
RawRead::RawRead(File *SrcFile)
{
RawRead::SrcFile=SrcFile;
+ Reset();
+}
+
+
+void RawRead::Reset()
+{
+ Data.SoftReset();
ReadPos=0;
DataSize=0;
#ifndef SHELL_EXT
@@ -11,31 +18,43 @@ RawRead::RawRead(File *SrcFile)
}
-void RawRead::Read(size_t Size)
+size_t RawRead::Read(size_t Size)
{
+ size_t ReadSize=0;
#if !defined(SHELL_EXT) && !defined(RAR_NOCRYPT)
if (Crypt!=NULL)
{
- size_t CurSize=Data.Size();
- size_t SizeToRead=Size-(CurSize-DataSize);
- if (SizeToRead>0)
+ // Full size of buffer with already read data including data read
+ // for encryption block alignment.
+ size_t FullSize=Data.Size();
+
+ // Data read for alignment and not processed yet.
+ size_t DataLeft=FullSize-DataSize;
+
+ if (Size>DataLeft) // Need to read more than we already have.
{
- size_t AlignedReadSize=SizeToRead+((~SizeToRead+1)&0xf);
+ size_t SizeToRead=Size-DataLeft;
+ size_t AlignedReadSize=SizeToRead+((~SizeToRead+1) & CRYPT_BLOCK_MASK);
Data.Add(AlignedReadSize);
- size_t ReadSize=SrcFile->Read(&Data[CurSize],AlignedReadSize);
- Crypt->DecryptBlock(&Data[CurSize],AlignedReadSize);
+ ReadSize=SrcFile->Read(&Data[FullSize],AlignedReadSize);
+ Crypt->DecryptBlock(&Data[FullSize],AlignedReadSize);
DataSize+=ReadSize==0 ? 0:Size;
}
- else
+ else // Use buffered data, no real read.
+ {
+ ReadSize=Size;
DataSize+=Size;
+ }
}
else
#endif
if (Size!=0)
{
Data.Add(Size);
- DataSize+=SrcFile->Read(&Data[DataSize],Size);
+ ReadSize=SrcFile->Read(&Data[DataSize],Size);
+ DataSize+=ReadSize;
}
+ return ReadSize;
}
@@ -50,65 +69,82 @@ void RawRead::Read(byte *SrcData,size_t Size)
}
-void RawRead::Get(byte &Field)
+byte RawRead::Get1()
{
- if (ReadPos<DataSize)
- {
- Field=Data[ReadPos];
- ReadPos++;
- }
- else
- Field=0;
+ return ReadPos<DataSize ? Data[ReadPos++]:0;
}
-void RawRead::Get(ushort &Field)
+ushort RawRead::Get2()
{
if (ReadPos+1<DataSize)
{
- Field=Data[ReadPos]+(Data[ReadPos+1]<<8);
+ ushort Result=Data[ReadPos]+(Data[ReadPos+1]<<8);
ReadPos+=2;
+ return Result;
}
- else
- Field=0;
+ return 0;
}
-void RawRead::Get(uint &Field)
+uint RawRead::Get4()
{
if (ReadPos+3<DataSize)
{
- Field=Data[ReadPos]+(Data[ReadPos+1]<<8)+(Data[ReadPos+2]<<16)+
- (Data[ReadPos+3]<<24);
+ uint Result=Data[ReadPos]+(Data[ReadPos+1]<<8)+(Data[ReadPos+2]<<16)+
+ (Data[ReadPos+3]<<24);
ReadPos+=4;
+ return Result;
}
- else
- Field=0;
+ return 0;
}
-void RawRead::Get8(int64 &Field)
+uint64 RawRead::Get8()
{
- uint Low,High;
- Get(Low);
- Get(High);
- Field=INT32TO64(High,Low);
+ uint Low=Get4(),High=Get4();
+ return INT32TO64(High,Low);
}
-void RawRead::Get(byte *Field,size_t Size)
+uint64 RawRead::GetV()
{
- if (ReadPos+Size-1<DataSize)
+ uint64 Result=0;
+ for (uint Shift=0;ReadPos<DataSize;Shift+=7)
{
- memcpy(Field,&Data[ReadPos],Size);
- ReadPos+=Size;
+ byte CurByte=Data[ReadPos++];
+ Result+=uint64(CurByte & 0x7f)<<Shift;
+ if ((CurByte & 0x80)==0)
+ return Result; // Decoded successfully.
}
- else
- memset(Field,0,Size);
+ return 0; // Out of buffer border.
+}
+
+
+// Return a number of bytes in current variable length integer.
+uint RawRead::GetVSize(size_t Pos)
+{
+ for (size_t CurPos=Pos;CurPos<DataSize;CurPos++)
+ if ((Data[CurPos] & 0x80)==0)
+ return int(CurPos-Pos+1);
+ return 0; // Buffer overflow.
+}
+
+
+size_t RawRead::GetB(void *Field,size_t Size)
+{
+ byte *F=(byte *)Field;
+ size_t CopySize=Min(DataSize-ReadPos,Size);
+ if (CopySize>0)
+ memcpy(F,&Data[ReadPos],CopySize);
+ if (Size>CopySize)
+ memset(F+CopySize,0,Size-CopySize);
+ ReadPos+=CopySize;
+ return CopySize;
}
-void RawRead::Get(wchar *Field,size_t Size)
+void RawRead::GetW(wchar *Field,size_t Size)
{
if (ReadPos+2*Size-1<DataSize)
{
@@ -120,7 +156,35 @@ void RawRead::Get(wchar *Field,size_t Size)
}
-uint RawRead::GetCRC(bool ProcessedOnly)
+uint RawRead::GetCRC15(bool ProcessedOnly) // RAR 1.5 block CRC.
+{
+ if (DataSize<=2)
+ return 0;
+ uint HeaderCRC=CRC32(0xffffffff,&Data[2],(ProcessedOnly ? ReadPos:DataSize)-2);
+ return ~HeaderCRC & 0xffff;
+}
+
+
+uint RawRead::GetCRC50() // RAR 5.0 block CRC.
+{
+ if (DataSize<=4)
+ return 0xffffffff;
+ return CRC32(0xffffffff,&Data[4],DataSize-4) ^ 0xffffffff;
+}
+
+
+// Read vint from arbitrary byte array.
+uint64 RawGetV(const byte *Data,uint &ReadPos,uint DataSize,bool &Overflow)
{
- return(DataSize>2 ? CRC(0xffffffff,&Data[2],(ProcessedOnly ? ReadPos:DataSize)-2):0xffffffff);
+ Overflow=false;
+ uint64 Result=0;
+ for (uint Shift=0;ReadPos<DataSize;Shift+=7)
+ {
+ byte CurByte=Data[ReadPos++];
+ Result+=uint64(CurByte & 0x7f)<<Shift;
+ if ((CurByte & 0x80)==0)
+ return Result; // Decoded successfully.
+ }
+ Overflow=true;
+ return 0; // Out of buffer border.
}
diff --git a/src/thirdparty/unrar/rawread.hpp b/src/thirdparty/unrar/rawread.hpp
index 39fefe6f7..9eedd6254 100644
--- a/src/thirdparty/unrar/rawread.hpp
+++ b/src/thirdparty/unrar/rawread.hpp
@@ -13,20 +13,76 @@ class RawRead
#endif
public:
RawRead(File *SrcFile);
- void Read(size_t Size);
+ void Reset();
+ size_t Read(size_t Size);
void Read(byte *SrcData,size_t Size);
- void Get(byte &Field);
- void Get(ushort &Field);
- void Get(uint &Field);
- void Get8(int64 &Field);
- void Get(byte *Field,size_t Size);
- void Get(wchar *Field,size_t Size);
- uint GetCRC(bool ProcessedOnly);
+ byte Get1();
+ ushort Get2();
+ uint Get4();
+ uint64 Get8();
+ uint64 GetV();
+ uint GetVSize(size_t Pos);
+ size_t GetB(void *Field,size_t Size);
+ void GetW(wchar *Field,size_t Size);
+ uint GetCRC15(bool ProcessedOnly);
+ uint GetCRC50();
+ byte* GetDataPtr() {return &Data[0];}
size_t Size() {return DataSize;}
size_t PaddedSize() {return Data.Size()-DataSize;}
+ size_t DataLeft() {return DataSize-ReadPos;}
+ size_t GetPos() {return ReadPos;}
+ void SetPos(size_t Pos) {ReadPos=Pos;}
#ifndef SHELL_EXT
void SetCrypt(CryptData *Crypt) {RawRead::Crypt=Crypt;}
#endif
};
+uint64 RawGetV(const byte *Data,uint &ReadPos,uint DataSize,bool &Overflow);
+
+inline uint RawGet2(const byte *D)
+{
+ return D[0]+(D[1]<<8);
+}
+
+inline uint RawGet4(const byte *D)
+{
+ return D[0]+(D[1]<<8)+(D[2]<<16)+(D[3]<<24);
+}
+
+inline uint64 RawGet8(const byte *D)
+{
+ return INT32TO64(RawGet4(D+4),RawGet4(D));
+}
+
+
+// We need these "put" functions also in UnRAR code. This is why they are
+// in rawread.hpp file even though they are "write" functions.
+inline void RawPut2(uint Field,byte *Data)
+{
+ Data[0]=(byte)(Field);
+ Data[1]=(byte)(Field>>8);
+}
+
+
+inline void RawPut4(uint Field,byte *Data)
+{
+ Data[0]=(byte)(Field);
+ Data[1]=(byte)(Field>>8);
+ Data[2]=(byte)(Field>>16);
+ Data[3]=(byte)(Field>>24);
+}
+
+
+inline void RawPut8(uint64 Field,byte *Data)
+{
+ Data[0]=(byte)(Field);
+ Data[1]=(byte)(Field>>8);
+ Data[2]=(byte)(Field>>16);
+ Data[3]=(byte)(Field>>24);
+ Data[4]=(byte)(Field>>32);
+ Data[5]=(byte)(Field>>40);
+ Data[6]=(byte)(Field>>48);
+ Data[7]=(byte)(Field>>56);
+}
+
#endif
diff --git a/src/thirdparty/unrar/rdwrfn.cpp b/src/thirdparty/unrar/rdwrfn.cpp
index d7bacd478..736dc3b33 100644
--- a/src/thirdparty/unrar/rdwrfn.cpp
+++ b/src/thirdparty/unrar/rdwrfn.cpp
@@ -2,6 +2,7 @@
ComprDataIO::ComprDataIO()
{
+
Init();
}
@@ -21,11 +22,9 @@ void ComprDataIO::Init()
DestFile=NULL;
UnpWrSize=0;
Command=NULL;
- Encryption=0;
- Decryption=0;
- TotalPackRead=0;
+ Encryption=false;
+ Decryption=false;
CurPackRead=CurPackWrite=CurUnpRead=CurUnpWrite=0;
- PackFileCRC=UnpFileCRC=PackedCRC=0xffffffff;
LastPercent=-1;
SubHead=NULL;
SubHeadPos=NULL;
@@ -36,40 +35,51 @@ void ComprDataIO::Init()
+
+
int ComprDataIO::UnpRead(byte *Addr,size_t Count)
{
- int RetCode=0,TotalRead=0;
+#ifndef RAR_NOCRYPT
+ // In case of encryption we need to align read size to encryption
+ // block size. We can do it by simple masking, because unpack read code
+ // always reads more than CRYPT_BLOCK_SIZE, so we do not risk to make it 0.
+ if (Decryption)
+ Count&=~CRYPT_BLOCK_MASK;
+#endif
+ int ReadSize=0,TotalRead=0;
byte *ReadAddr;
ReadAddr=Addr;
while (Count > 0)
{
Archive *SrcArc=(Archive *)SrcFile;
- size_t ReadSize=((int64)Count>UnpPackedSize) ? (size_t)UnpPackedSize:Count;
if (UnpackFromMemory)
{
memcpy(Addr,UnpackFromMemoryAddr,UnpackFromMemorySize);
- RetCode=(int)UnpackFromMemorySize;
+ ReadSize=(int)UnpackFromMemorySize;
UnpackFromMemorySize=0;
}
else
{
+ size_t SizeToRead=((int64)Count>UnpPackedSize) ? (size_t)UnpPackedSize:Count;
+ if (SizeToRead==0)
+ return 0;
if (!SrcFile->IsOpened())
return(-1);
- RetCode=SrcFile->Read(ReadAddr,ReadSize);
- FileHeader *hd=SubHead!=NULL ? SubHead:&SrcArc->NewLhd;
- if (hd->Flags & LHD_SPLIT_AFTER)
- PackedCRC=CRC(PackedCRC,ReadAddr,RetCode);
+ ReadSize=SrcFile->Read(ReadAddr,SizeToRead);
+ FileHeader *hd=SubHead!=NULL ? SubHead:&SrcArc->FileHead;
+ if (hd->SplitAfter)
+ PackedDataHash.Update(ReadAddr,ReadSize);
}
- CurUnpRead+=RetCode;
- TotalRead+=RetCode;
+ CurUnpRead+=ReadSize;
+ TotalRead+=ReadSize;
#ifndef NOVOLUME
// These variable are not used in NOVOLUME mode, so it is better
// to exclude commands below to avoid compiler warnings.
- ReadAddr+=RetCode;
- Count-=RetCode;
+ ReadAddr+=ReadSize;
+ Count-=ReadSize;
#endif
- UnpPackedSize-=RetCode;
+ UnpPackedSize-=ReadSize;
if (UnpPackedSize == 0 && UnpVolume)
{
#ifndef NOVOLUME
@@ -86,28 +96,16 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
Archive *SrcArc=(Archive *)SrcFile;
if (SrcArc!=NULL)
ShowUnpRead(SrcArc->CurBlockPos+CurUnpRead,UnpArcSize);
- if (RetCode!=-1)
+ if (ReadSize!=-1)
{
- RetCode=TotalRead;
+ ReadSize=TotalRead;
#ifndef RAR_NOCRYPT
if (Decryption)
-#ifndef SFX_MODULE
- if (Decryption<20)
- Decrypt.Crypt(Addr,RetCode,(Decryption==15) ? NEW_CRYPT : OLD_DECODE);
- else
- if (Decryption==20)
- for (int I=0;I<RetCode;I+=16)
- Decrypt.DecryptBlock20(&Addr[I]);
- else
-#endif
- {
- int CryptSize=(RetCode & 0xf)==0 ? RetCode:((RetCode & ~0xf)+16);
- Decrypt.DecryptBlock(Addr,CryptSize);
- }
+ Decrypt.DecryptBlock(Addr,ReadSize);
#endif
}
Wait();
- return(RetCode);
+ return ReadSize;
}
@@ -174,12 +172,7 @@ void ComprDataIO::UnpWrite(byte *Addr,size_t Count)
DestFile->Write(Addr,Count);
CurUnpWrite+=Count;
if (!SkipUnpCRC)
-#ifndef SFX_MODULE
- if (((Archive *)SrcFile)->OldFormat)
- UnpFileCRC=OldCRC((ushort)UnpFileCRC,Addr,Count);
- else
-#endif
- UnpFileCRC=CRC(UnpFileCRC,Addr,Count);
+ UnpHash.Update(Addr,Count);
ShowUnpWrite();
Wait();
}
@@ -211,7 +204,7 @@ void ComprDataIO::ShowUnpRead(int64 ArcPos,int64 ArcSize)
int CurPercent=ToPercent(ArcPos,ArcSize);
if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
{
- mprintf("\b\b\b\b%3d%%",CurPercent);
+ mprintf(L"\b\b\b\b%3d%%",CurPercent);
LastPercent=CurPercent;
}
}
@@ -229,6 +222,8 @@ void ComprDataIO::ShowUnpWrite()
+
+
void ComprDataIO::SetFiles(File *SrcFile,File *DestFile)
{
if (SrcFile!=NULL)
@@ -246,20 +241,22 @@ void ComprDataIO::GetUnpackedData(byte **Data,size_t *Size)
}
-void ComprDataIO::SetEncryption(int Method,SecPassword *Password,const byte *Salt,bool Encrypt,bool HandsOffHash)
+void ComprDataIO::SetEncryption(bool Encrypt,CRYPT_METHOD Method,
+ SecPassword *Password,const byte *Salt,const byte *InitV,
+ uint Lg2Cnt,byte *PswCheck,byte *HashKey)
{
if (Encrypt)
{
- Encryption=Password->IsSet() ? Method:0;
+ Encryption=Password->IsSet();
#ifndef RAR_NOCRYPT
- Crypt.SetCryptKeys(Password,Salt,Encrypt,false,HandsOffHash);
+ Crypt.SetCryptKeys(true,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
#endif
}
else
{
- Decryption=Password->IsSet() ? Method:0;
+ Decryption=Password->IsSet();
#ifndef RAR_NOCRYPT
- Decrypt.SetCryptKeys(Password,Salt,Encrypt,Method<29,HandsOffHash);
+ Decrypt.SetCryptKeys(false,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck);
#endif
}
}
@@ -268,7 +265,7 @@ void ComprDataIO::SetEncryption(int Method,SecPassword *Password,const byte *Sal
#if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT)
void ComprDataIO::SetAV15Encryption()
{
- Decryption=15;
+ Decryption=true;
Decrypt.SetAV15Encryption();
}
#endif
@@ -277,7 +274,7 @@ void ComprDataIO::SetAV15Encryption()
#if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT)
void ComprDataIO::SetCmt13Encryption()
{
- Decryption=13;
+ Decryption=true;
Decrypt.SetCmt13Encryption();
}
#endif
diff --git a/src/thirdparty/unrar/rdwrfn.hpp b/src/thirdparty/unrar/rdwrfn.hpp
index 0c6fd1dc5..408ee3d2a 100644
--- a/src/thirdparty/unrar/rdwrfn.hpp
+++ b/src/thirdparty/unrar/rdwrfn.hpp
@@ -45,7 +45,7 @@ class ComprDataIO
int LastPercent;
- char CurrentCommand;
+ wchar CurrentCommand;
public:
ComprDataIO();
@@ -60,29 +60,32 @@ class ComprDataIO
void SetFiles(File *SrcFile,File *DestFile);
void SetCommand(CmdAdd *Cmd) {Command=Cmd;}
void SetSubHeader(FileHeader *hd,int64 *Pos) {SubHead=hd;SubHeadPos=Pos;}
- void SetEncryption(int Method,SecPassword *Password,const byte *Salt,bool Encrypt,bool HandsOffHash);
+ void SetEncryption(bool Encrypt,CRYPT_METHOD Method,SecPassword *Password,
+ const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *PswCheck,byte *HashKey);
void SetAV15Encryption();
void SetCmt13Encryption();
void SetUnpackToMemory(byte *Addr,uint Size);
- void SetCurrentCommand(char Cmd) {CurrentCommand=Cmd;}
+ void SetCurrentCommand(wchar Cmd) {CurrentCommand=Cmd;}
bool PackVolume;
bool UnpVolume;
bool NextVolumeMissing;
- int64 TotalPackRead;
int64 UnpArcSize;
int64 CurPackRead,CurPackWrite,CurUnpRead,CurUnpWrite;
+
// Size of already processed archives.
// Used to calculate the total operation progress.
int64 ProcessedArcSize;
int64 TotalArcSize;
- uint PackFileCRC,UnpFileCRC,PackedCRC;
+ DataHash PackedDataHash; // Packed write and unpack read hash.
+ DataHash PackHash; // Pack read hash.
+ DataHash UnpHash; // Unpack write hash.
- int Encryption;
- int Decryption;
+ bool Encryption;
+ bool Decryption;
};
#endif
diff --git a/src/thirdparty/unrar/readme.txt b/src/thirdparty/unrar/readme.txt
index fd7137d95..a1f820af1 100644
--- a/src/thirdparty/unrar/readme.txt
+++ b/src/thirdparty/unrar/readme.txt
@@ -4,12 +4,13 @@
1. General
- This package includes freeware Unrar C++ source and a few makefiles
- (makefile.bcc, makefile.msc+msc.dep, makefile.unix). Unrar source
- is subset of RAR and generated from RAR source automatically,
+ This package includes freeware Unrar C++ source and makefile for
+ several Unix compilers.
+
+ Unrar source is subset of RAR and generated from RAR source automatically,
by a small program removing blocks like '#ifndef UNRAR ... #endif'.
- Such method is not perfect and you may find some RAR related
- stuff unnecessary in Unrar, especially in header files.
+ Such method is not perfect and you may find some RAR related stuff
+ unnecessary in Unrar, especially in header files.
If you wish to port Unrar to a new platform, you may need to edit
'#define LITTLE_ENDIAN' in os.hpp and data type definitions
@@ -17,16 +18,7 @@
if computer architecture does not allow not aligned data access,
you need to undefine ALLOW_NOT_ALIGNED_INT and define
- STRICT_ALIGNMENT_REQUIRED in os.h. Note that it will increase memory
- requirements.
-
- If you use Borland C++ makefile (makefile.bcc), you need to define
- BASEPATHCC environment (or makefile) variable containing
- the path to Borland C++ installation.
-
- Makefile.unix contains numerous compiler option sets.
- GCC Linux is selected by default. If you need to compile Unrar
- for other platforms, uncomment corresponding lines.
+ STRICT_ALIGNMENT_REQUIRED in os.h.
UnRAR.vcproj and UnRARDll.vcproj are projects for Microsoft Visual C++.
UnRARDll.vcproj lets to build unrar.dll library.
@@ -41,16 +33,8 @@
3. Acknowledgements
- This source includes parts of code written by the following authors:
-
- Dmitry Shkarin PPMII v.H text compression
- Dmitry Subbotin Carryless rangecoder
- Szymon Stefanek AES encryption
- Brian Gladman AES encryption
- Steve Reid SHA-1 hash function
- Marcus Herbert makefile.unix file
- Tomasz Klim fixes for libunrar.so
- Robert Riebisch makefile.dj and patches for DJGPP
+ This source includes parts of code written by other authors.
+ Please see acknow.txt file for details.
4. Legal stuff
diff --git a/src/thirdparty/unrar/recvol.cpp b/src/thirdparty/unrar/recvol.cpp
index 0d6162e17..d3d16dde9 100644
--- a/src/thirdparty/unrar/recvol.cpp
+++ b/src/thirdparty/unrar/recvol.cpp
@@ -1,572 +1,42 @@
#include "rar.hpp"
-// Buffer size for all volumes involved.
-static const size_t TotalBufferSize=0x4000000;
+#include "recvol3.cpp"
+#include "recvol5.cpp"
-class RSEncode // Encode or decode data area, one object per one thread.
-{
- private:
- RSCoder RSC;
- public:
- void EncodeBuf();
- void DecodeBuf();
-
- void Init(int RecVolNumber) {RSC.Init(RecVolNumber);}
- byte *Buf;
- byte *OutBuf;
- int BufStart;
- int BufEnd;
- int FileNumber;
- int RecVolNumber;
- size_t RecBufferSize;
- int *Erasures;
- int EraSize;
-};
-
-
-#ifdef RAR_SMP
-THREAD_PROC(RSEncodeThread)
-{
- RSEncode *rs=(RSEncode *)Data;
- rs->EncodeBuf();
-}
-THREAD_PROC(RSDecodeThread)
-{
- RSEncode *rs=(RSEncode *)Data;
- rs->DecodeBuf();
-}
-#endif
-RecVolumes::RecVolumes()
+bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent)
{
- Buf.Alloc(TotalBufferSize);
- memset(SrcFile,0,sizeof(SrcFile));
-}
-
-
-RecVolumes::~RecVolumes()
-{
- for (int I=0;I<ASIZE(SrcFile);I++)
- delete SrcFile[I];
-}
-
-
-
-
-void RSEncode::EncodeBuf()
-{
- for (int BufPos=BufStart;BufPos<BufEnd;BufPos++)
- {
- byte Data[256],Code[256];
- for (int I=0;I<FileNumber;I++)
- Data[I]=Buf[I*RecBufferSize+BufPos];
- RSC.Encode(Data,FileNumber,Code);
- for (int I=0;I<RecVolNumber;I++)
- OutBuf[I*RecBufferSize+BufPos]=Code[I];
- }
-}
-
-
-bool RecVolumes::Restore(RAROptions *Cmd,const char *Name,
- const wchar *NameW,bool Silent)
-{
- char ArcName[NM];
- wchar ArcNameW[NM];
- strcpy(ArcName,Name);
- wcscpy(ArcNameW,NameW);
- char *Ext=GetExt(ArcName);
- bool NewStyle=false;
- bool RevName=Ext!=NULL && stricomp(Ext,".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)
- Ext--;
- strcpy(Ext,"*.*");
-
- if (*ArcNameW!=0)
- {
- wchar *ExtW=GetExt(ArcNameW);
- for (int DigitGroup=0;ExtW>ArcNameW && DigitGroup<3;ExtW--)
- if (!IsDigit(*ExtW))
- if (IsDigit(*(ExtW-1)) && (*ExtW=='_' || DigitGroup<2))
- DigitGroup++;
- else
- if (DigitGroup<2)
- {
- NewStyle=true;
- break;
- }
- while (IsDigit(*ExtW) && ExtW>ArcNameW+1)
- ExtW--;
- wcscpy(ExtW,L"*.*");
- }
-
- FindFile Find;
- Find.SetMask(ArcName);
- Find.SetMaskW(ArcNameW);
- FindData fd;
- while (Find.Next(&fd))
- {
- Archive Arc(Cmd);
- if (Arc.WOpen(fd.Name,fd.NameW) && Arc.IsArchive(true))
- {
- strcpy(ArcName,fd.Name);
- wcscpy(ArcNameW,fd.NameW);
- break;
- }
- }
- }
-
Archive Arc(Cmd);
- if (!Arc.WCheckOpen(ArcName,ArcNameW))
- return(false);
- if (!Arc.Volume)
- {
-#ifndef SILENT
- Log(ArcName,St(MNotVolume),ArcName);
-#endif
- return(false);
- }
- bool NewNumbering=(Arc.NewMhd.Flags & MHD_NEWNUMBERING)!=0;
- Arc.Close();
-
- char *VolNumStart=VolNameToFirstName(ArcName,ArcName,NewNumbering);
- char RecVolMask[NM];
- strcpy(RecVolMask,ArcName);
- size_t BaseNamePartLength=VolNumStart-ArcName;
- strcpy(RecVolMask+BaseNamePartLength,"*.rev");
-
- wchar RecVolMaskW[NM];
- size_t BaseNamePartLengthW=0;
- *RecVolMaskW=0;
- if (*ArcNameW!=0)
- {
- wchar *VolNumStartW=VolNameToFirstName(ArcNameW,ArcNameW,NewNumbering);
- wcscpy(RecVolMaskW,ArcNameW);
- BaseNamePartLengthW=VolNumStartW-ArcNameW;
- wcscpy(RecVolMaskW+BaseNamePartLengthW,L"*.rev");
- }
-
-
-#ifndef SILENT
- int64 RecFileSize=0;
-#endif
-
- // We cannot display "Calculating CRC..." message here, because we do not
- // know if we'll find any recovery volumes. We'll display it after finding
- // the first recovery volume.
- bool CalcCRCMessageDone=false;
-
- FindFile Find;
- Find.SetMask(RecVolMask);
- Find.SetMaskW(RecVolMaskW);
- FindData RecData;
- int FileNumber=0,RecVolNumber=0,FoundRecVolumes=0,MissingVolumes=0;
- char PrevName[NM];
- wchar PrevNameW[NM];
- while (Find.Next(&RecData))
- {
- char *CurName=RecData.Name;
- wchar *CurNameW=RecData.NameW;
- int P[3];
- if (!RevName && !NewStyle)
- {
- NewStyle=true;
-
- char *Dot=GetExt(CurName);
- if (Dot!=NULL)
- {
- int LineCount=0;
- Dot--;
- while (Dot>CurName && *Dot!='.')
- {
- if (*Dot=='_')
- LineCount++;
- Dot--;
- }
- if (LineCount==2)
- NewStyle=false;
- }
-
- wchar *DotW=GetExt(CurNameW);
- if (DotW!=NULL)
- {
- int LineCount=0;
- DotW--;
- while (DotW>CurNameW && *DotW!='.')
- {
- if (*DotW=='_')
- LineCount++;
- DotW--;
- }
- if (LineCount==2)
- NewStyle=false;
- }
- }
- if (NewStyle)
- {
- if (!CalcCRCMessageDone)
- {
-#ifndef SILENT
- mprintf(St(MCalcCRCAllVol));
-#endif
- CalcCRCMessageDone=true;
- }
-
-#ifndef SILENT
- mprintf("\r\n%s",CurName);
-#endif
-
- File CurFile;
- CurFile.TOpen(CurName,CurNameW);
- CurFile.Seek(0,SEEK_END);
- int64 Length=CurFile.Tell();
- CurFile.Seek(Length-7,SEEK_SET);
- for (int I=0;I<3;I++)
- P[2-I]=CurFile.GetByte()+1;
- uint FileCRC=0;
- for (int I=0;I<4;I++)
- FileCRC|=CurFile.GetByte()<<(I*8);
- if (FileCRC!=CalcFileCRC(&CurFile,Length-4))
- {
-#ifndef SILENT
- mprintf(St(MCRCFailed),CurName);
-#endif
- continue;
- }
- }
- else
- {
- char *Dot=GetExt(CurName);
- if (Dot==NULL)
- continue;
- bool WrongParam=false;
- for (int I=0;I<ASIZE(P);I++)
- {
- do
- {
- Dot--;
- } while (IsDigit(*Dot) && Dot>=CurName+BaseNamePartLength);
- P[I]=atoi(Dot+1);
- if (P[I]==0 || P[I]>255)
- WrongParam=true;
- }
- if (WrongParam)
- continue;
- }
- if (P[1]+P[2]>255)
- continue;
- if (RecVolNumber!=0 && RecVolNumber!=P[1] || FileNumber!=0 && FileNumber!=P[2])
- {
-#ifndef SILENT
- Log(NULL,St(MRecVolDiffSets),CurName,PrevName);
-#endif
- return(false);
- }
- RecVolNumber=P[1];
- FileNumber=P[2];
- strcpy(PrevName,CurName);
- wcscpy(PrevNameW,CurNameW);
- File *NewFile=new File;
- NewFile->TOpen(CurName,CurNameW);
- SrcFile[FileNumber+P[0]-1]=NewFile;
- FoundRecVolumes++;
-#ifndef SILENT
- if (RecFileSize==0)
- RecFileSize=NewFile->FileLength();
-#endif
- }
-#ifndef SILENT
- if (!Silent || FoundRecVolumes!=0)
+ if (!Arc.Open(Name))
{
- mprintf(St(MRecVolFound),FoundRecVolumes);
+ if (!Silent)
+ ErrHandler.OpenErrorMsg(NULL,Name);
+ return false;
}
-#endif
- if (FoundRecVolumes==0)
- return(false);
-
- bool WriteFlags[256];
- memset(WriteFlags,0,sizeof(WriteFlags));
- char LastVolName[NM];
- *LastVolName=0;
- wchar LastVolNameW[NM];
- *LastVolNameW=0;
-
- for (int CurArcNum=0;CurArcNum<FileNumber;CurArcNum++)
+ RARFORMAT Fmt=RARFMT15;
+ if (Arc.IsArchive(true))
+ Fmt=Arc.Format;
+ else
{
- Archive *NewFile=new Archive;
- bool ValidVolume=FileExist(ArcName,ArcNameW);
- if (ValidVolume)
- {
- NewFile->TOpen(ArcName,ArcNameW);
- ValidVolume=NewFile->IsArchive(false);
- if (ValidVolume)
- {
- while (NewFile->ReadHeader()!=0)
- {
- if (NewFile->GetHeaderType()==ENDARC_HEAD)
- {
-#ifndef SILENT
- mprintf("\r\n%s",ArcName);
-#endif
- if ((NewFile->EndArcHead.Flags&EARC_DATACRC)!=0 &&
- NewFile->EndArcHead.ArcDataCRC!=CalcFileCRC(NewFile,NewFile->CurBlockPos))
- {
- ValidVolume=false;
-#ifndef SILENT
- mprintf(St(MCRCFailed),ArcName);
-#endif
- }
- break;
- }
- NewFile->SeekToNext();
- }
- }
- if (!ValidVolume)
- {
- NewFile->Close();
- char NewName[NM];
- strcpy(NewName,ArcName);
- strcat(NewName,".bad");
-
- wchar NewNameW[NM];
- wcscpy(NewNameW,ArcNameW);
- if (*NewNameW!=0)
- wcscat(NewNameW,L".bad");
-#ifndef SILENT
- mprintf(St(MBadArc),ArcName);
- mprintf(St(MRenaming),ArcName,NewName);
-#endif
- RenameFile(ArcName,ArcNameW,NewName,NewNameW);
- }
- NewFile->Seek(0,SEEK_SET);
- }
- if (!ValidVolume)
- {
- // It is important to return 'false' instead of aborting here,
- // so if we are called from extraction, we will be able to continue
- // extracting. It may happen if .rar and .rev are on read-only disks
- // like CDs.
- if (!NewFile->Create(ArcName,ArcNameW))
- {
- // We need to display the title of operation before the error message,
- // to make clear for user that create error is related to recovery
- // volumes. This is why we cannot use WCreate call here. Title must be
- // before create error, not after that.
-#ifndef SILENT
- mprintf(St(MReconstructing));
-#endif
- ErrHandler.CreateErrorMsg(ArcName,ArcNameW);
- return false;
- }
-
- WriteFlags[CurArcNum]=true;
- MissingVolumes++;
-
- if (CurArcNum==FileNumber-1)
- {
- strcpy(LastVolName,ArcName);
- wcscpy(LastVolNameW,ArcNameW);
- }
-
-#ifndef SILENT
- mprintf(St(MAbsNextVol),ArcName);
-#endif
- }
- SrcFile[CurArcNum]=(File*)NewFile;
- NextVolumeName(ArcName,ArcNameW,ASIZE(ArcName),!NewNumbering);
+ byte Sign[REV5_SIGN_SIZE];
+ Arc.Seek(0,SEEK_SET);
+ if (Arc.Read(Sign,REV5_SIGN_SIZE)==REV5_SIGN_SIZE && memcmp(Sign,REV5_SIGN,REV5_SIGN_SIZE)==0)
+ Fmt=RARFMT50;
}
+ Arc.Close();
-#ifndef SILENT
- mprintf(St(MRecVolMissing),MissingVolumes);
-#endif
-
- if (MissingVolumes==0)
- {
-#ifndef SILENT
- mprintf(St(MRecVolAllExist));
-#endif
- return(false);
- }
-
- if (MissingVolumes>FoundRecVolumes)
- {
-#ifndef SILENT
- mprintf(St(MRecVolCannotFix));
-#endif
- return(false);
- }
-#ifndef SILENT
- mprintf(St(MReconstructing));
-#endif
-
- int TotalFiles=FileNumber+RecVolNumber;
- int Erasures[256],EraSize=0;
-
- for (int I=0;I<TotalFiles;I++)
- if (WriteFlags[I] || SrcFile[I]==NULL)
- Erasures[EraSize++]=I;
-
-#ifndef SILENT
- int64 ProcessedSize=0;
-#ifndef GUI
- int LastPercent=-1;
- mprintf(" ");
-#endif
-#endif
- // Size of per file buffer.
- size_t RecBufferSize=TotalBufferSize/TotalFiles;
-
-#ifdef RAR_SMP
- uint ThreadNumber=Cmd->Threads;
- RSEncode rse[MaxPoolThreads];
- uint WaitHandles[MaxPoolThreads];
-#else
- uint ThreadNumber=1;
- RSEncode rse[1];
-#endif
- for (uint I=0;I<ThreadNumber;I++)
- rse[I].Init(RecVolNumber);
-
- while (true)
- {
- Wait();
- int MaxRead=0;
- for (int I=0;I<TotalFiles;I++)
- if (WriteFlags[I] || SrcFile[I]==NULL)
- memset(&Buf[I*RecBufferSize],0,RecBufferSize);
- else
- {
- int ReadSize=SrcFile[I]->Read(&Buf[I*RecBufferSize],RecBufferSize);
- if (ReadSize!=RecBufferSize)
- memset(&Buf[I*RecBufferSize+ReadSize],0,RecBufferSize-ReadSize);
- if (ReadSize>MaxRead)
- MaxRead=ReadSize;
- }
- if (MaxRead==0)
- break;
-#ifndef SILENT
- int CurPercent=ToPercent(ProcessedSize,RecFileSize);
- if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
- {
- mprintf("\b\b\b\b%3d%%",CurPercent);
- LastPercent=CurPercent;
- }
- ProcessedSize+=MaxRead;
-#endif
-
-
- int BlockStart=0;
- int BlockSize=MaxRead/ThreadNumber;
- if (BlockSize<0x100)
- BlockSize=MaxRead;
- uint CurThread=0;
-
- while (BlockStart<MaxRead)
- {
- // Last thread processes all left data including increasement
- // from rounding error.
- if (CurThread==ThreadNumber-1)
- BlockSize=MaxRead-BlockStart;
-
- RSEncode *curenc=rse+CurThread;
- curenc->Buf=&Buf[0];
- curenc->BufStart=BlockStart;
- curenc->BufEnd=BlockStart+BlockSize;
- curenc->FileNumber=TotalFiles;
- curenc->RecBufferSize=RecBufferSize;
- curenc->Erasures=Erasures;
- curenc->EraSize=EraSize;
-
-#ifdef RAR_SMP
- if (ThreadNumber>1)
- {
- uint Handle=RSThreadPool.Start(RSDecodeThread,(void*)curenc);
- WaitHandles[CurThread++]=Handle;
- }
- else
- curenc->DecodeBuf();
-#else
- curenc->DecodeBuf();
-#endif
-
- BlockStart+=BlockSize;
- }
-
-#ifdef RAR_SMP
- if (CurThread>0)
- RSThreadPool.Wait(WaitHandles,CurThread);
-#endif // RAR_SMP
-
- for (int I=0;I<FileNumber;I++)
- if (WriteFlags[I])
- SrcFile[I]->Write(&Buf[I*RecBufferSize],MaxRead);
- }
- for (int I=0;I<RecVolNumber+FileNumber;I++)
- if (SrcFile[I]!=NULL)
- {
- File *CurFile=SrcFile[I];
- if (NewStyle && WriteFlags[I])
- {
- int64 Length=CurFile->Tell();
- CurFile->Seek(Length-7,SEEK_SET);
- for (int J=0;J<7;J++)
- CurFile->PutByte(0);
- }
- CurFile->Close();
- SrcFile[I]=NULL;
- }
- if (*LastVolName!=0 || *LastVolNameW!=0)
+ // We define RecVol as local variable for proper stack unwinding when
+ // handling exceptions. So it can close and delete files on Cancel.
+ if (Fmt==RARFMT15)
{
- // Truncate the last volume to its real size.
- Archive Arc(Cmd);
- if (Arc.Open(LastVolName,LastVolNameW,FMF_UPDATE) && Arc.IsArchive(true) &&
- Arc.SearchBlock(ENDARC_HEAD))
- {
- Arc.Seek(Arc.NextBlockPos,SEEK_SET);
- char Buf[8192];
- int ReadSize=Arc.Read(Buf,sizeof(Buf));
- int ZeroCount=0;
- while (ZeroCount<ReadSize && Buf[ZeroCount]==0)
- ZeroCount++;
- if (ZeroCount==ReadSize)
- {
- Arc.Seek(Arc.NextBlockPos,SEEK_SET);
- Arc.Truncate();
- }
- }
+ RecVolumes3 RecVol;
+ return RecVol.Restore(Cmd,Name,Silent);
}
-#if !defined(GUI) && !defined(SILENT)
- if (!Cmd->DisablePercentage)
- mprintf("\b\b\b\b100%%");
- if (!Silent && !Cmd->DisableDone)
- mprintf(St(MDone));
-#endif
- return(true);
-}
-
-
-void RSEncode::DecodeBuf()
-{
- for (int BufPos=BufStart;BufPos<BufEnd;BufPos++)
+ else
{
- byte Data[256];
- for (int I=0;I<FileNumber;I++)
- Data[I]=Buf[I*RecBufferSize+BufPos];
- RSC.Decode(Data,FileNumber,Erasures,EraSize);
- for (int I=0;I<EraSize;I++)
- Buf[Erasures[I]*RecBufferSize+BufPos]=Data[Erasures[I]];
+ RecVolumes5 RecVol;
+ return RecVol.Restore(Cmd,Name,Silent);
}
}
diff --git a/src/thirdparty/unrar/recvol.hpp b/src/thirdparty/unrar/recvol.hpp
index 9a97465eb..5956d7bbb 100644
--- a/src/thirdparty/unrar/recvol.hpp
+++ b/src/thirdparty/unrar/recvol.hpp
@@ -1,20 +1,84 @@
#ifndef _RAR_RECVOL_
#define _RAR_RECVOL_
-class RecVolumes
+#define REV5_SIGN "Rar!\x1aRev"
+#define REV5_SIGN_SIZE 8
+
+class RecVolumes3
{
private:
File *SrcFile[256];
Array<byte> Buf;
#ifdef RAR_SMP
- ThreadPool RSThreadPool;
+ ThreadPool *RSThreadPool;
#endif
public:
- RecVolumes();
- ~RecVolumes();
- void Make(RAROptions *Cmd,char *ArcName,wchar *ArcNameW);
- bool Restore(RAROptions *Cmd,const char *Name,const wchar *NameW,bool Silent);
+ RecVolumes3();
+ ~RecVolumes3();
+ void Make(RAROptions *Cmd,wchar *ArcName);
+ bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent);
+};
+
+
+struct RecVolItem
+{
+ File *f;
+ wchar Name[NM];
+ uint CRC;
+ uint64 FileSize;
+ bool New; // Newly created RAR volume.
+ bool Valid; // If existing RAR volume is valid.
+};
+
+
+class RecVolumes5;
+struct RecRSThreadData
+{
+ RecVolumes5 *RecRSPtr;
+ RSCoder16 *RS;
+ bool Encode;
+ uint DataNum;
+ const byte *Data;
+ size_t StartPos;
+ size_t Size;
};
+class RecVolumes5
+{
+ private:
+ void ProcessRS(RAROptions *Cmd,uint DataNum,const byte *Data,uint MaxRead,bool Encode);
+ void ProcessRS(RAROptions *Cmd,uint MaxRead,bool Encode);
+ uint ReadHeader(File *RecFile,bool FirstRev);
+
+ Array<RecVolItem> RecItems;
+
+ byte *RealReadBuffer; // Real pointer returned by 'new'.
+ byte *ReadBuffer; // Pointer aligned for SSE instructions.
+
+ byte *RealBuf; // Real pointer returned by 'new'.
+ byte *Buf; // Store ECC or recovered data here, aligned for SSE.
+ size_t RecBufferSize; // Buffer area allocated for single volume.
+
+ uint DataCount; // Number of archives.
+ uint RecCount; // Number of recovery volumes.
+ uint TotalCount; // Total number of archives and recovery volumes.
+
+ bool *ValidFlags; // Volume validity flags for recovering.
+ uint MissingVolumes; // Number of missing or bad RAR volumes.
+
+#ifdef RAR_SMP
+ ThreadPool *RecThreadPool;
+#endif
+ RecRSThreadData ThreadData[MaxPoolThreads]; // Store thread parameters.
+ public: // 'public' only because called from thread functions.
+ void ProcessAreaRS(RecRSThreadData *td);
+ public:
+ RecVolumes5();
+ ~RecVolumes5();
+ bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent);
+};
+
+bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent);
+
#endif
diff --git a/src/thirdparty/unrar/recvol3.cpp b/src/thirdparty/unrar/recvol3.cpp
new file mode 100644
index 000000000..7ccacff0f
--- /dev/null
+++ b/src/thirdparty/unrar/recvol3.cpp
@@ -0,0 +1,513 @@
+#include "rar.hpp"
+
+// Buffer size for all volumes involved.
+static const size_t TotalBufferSize=0x4000000;
+
+class RSEncode // Encode or decode data area, one object per one thread.
+{
+ private:
+ RSCoder RSC;
+ public:
+ void EncodeBuf();
+ void DecodeBuf();
+
+ void Init(int RecVolNumber) {RSC.Init(RecVolNumber);}
+ byte *Buf;
+ byte *OutBuf;
+ int BufStart;
+ int BufEnd;
+ int FileNumber;
+ int RecVolNumber;
+ size_t RecBufferSize;
+ int *Erasures;
+ int EraSize;
+};
+
+
+#ifdef RAR_SMP
+THREAD_PROC(RSEncodeThread)
+{
+ RSEncode *rs=(RSEncode *)Data;
+ rs->EncodeBuf();
+}
+
+THREAD_PROC(RSDecodeThread)
+{
+ RSEncode *rs=(RSEncode *)Data;
+ rs->DecodeBuf();
+}
+#endif
+
+RecVolumes3::RecVolumes3()
+{
+ Buf.Alloc(TotalBufferSize);
+ memset(SrcFile,0,sizeof(SrcFile));
+#ifdef RAR_SMP
+ RSThreadPool=CreateThreadPool();
+#endif
+}
+
+
+RecVolumes3::~RecVolumes3()
+{
+ for (int I=0;I<ASIZE(SrcFile);I++)
+ delete SrcFile[I];
+#ifdef RAR_SMP
+ DestroyThreadPool(RSThreadPool);
+#endif
+}
+
+
+
+
+void RSEncode::EncodeBuf()
+{
+ for (int BufPos=BufStart;BufPos<BufEnd;BufPos++)
+ {
+ byte Data[256],Code[256];
+ for (int I=0;I<FileNumber;I++)
+ Data[I]=Buf[I*RecBufferSize+BufPos];
+ RSC.Encode(Data,FileNumber,Code);
+ for (int I=0;I<RecVolNumber;I++)
+ OutBuf[I*RecBufferSize+BufPos]=Code[I];
+ }
+}
+
+
+bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
+{
+ wchar ArcName[NM];
+ wcscpy(ArcName,Name);
+ wchar *Ext=GetExt(ArcName);
+ bool NewStyle=false;
+ 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)
+ Ext--;
+ wcscpy(Ext,L"*.*");
+
+ FindFile Find;
+ Find.SetMask(ArcName);
+ FindData fd;
+ while (Find.Next(&fd))
+ {
+ Archive Arc(Cmd);
+ if (Arc.WOpen(fd.Name) && Arc.IsArchive(true))
+ {
+ wcscpy(ArcName,fd.Name);
+ break;
+ }
+ }
+ }
+
+ Archive Arc(Cmd);
+ if (!Arc.WCheckOpen(ArcName))
+ return false;
+ if (!Arc.Volume)
+ {
+#ifndef SILENT
+ Log(ArcName,St(MNotVolume),ArcName);
+#endif
+ return false;
+ }
+ bool NewNumbering=Arc.NewNumbering;
+ Arc.Close();
+
+ wchar *VolNumStart=VolNameToFirstName(ArcName,ArcName,NewNumbering);
+ wchar RecVolMask[NM];
+ wcscpy(RecVolMask,ArcName);
+ size_t BaseNamePartLength=VolNumStart-ArcName;
+ wcscpy(RecVolMask+BaseNamePartLength,L"*.rev");
+
+#ifndef SILENT
+ int64 RecFileSize=0;
+#endif
+
+ // We cannot display "Calculating CRC..." message here, because we do not
+ // know if we'll find any recovery volumes. We'll display it after finding
+ // the first recovery volume.
+ bool CalcCRCMessageDone=false;
+
+ FindFile Find;
+ Find.SetMask(RecVolMask);
+ FindData RecData;
+ int FileNumber=0,RecVolNumber=0,FoundRecVolumes=0,MissingVolumes=0;
+ wchar PrevName[NM];
+ while (Find.Next(&RecData))
+ {
+ wchar *CurName=RecData.Name;
+ int P[3];
+ if (!RevName && !NewStyle)
+ {
+ NewStyle=true;
+
+ wchar *Dot=GetExt(CurName);
+ if (Dot!=NULL)
+ {
+ int LineCount=0;
+ Dot--;
+ while (Dot>CurName && *Dot!='.')
+ {
+ if (*Dot=='_')
+ LineCount++;
+ Dot--;
+ }
+ if (LineCount==2)
+ NewStyle=false;
+ }
+ }
+ if (NewStyle)
+ {
+ if (!CalcCRCMessageDone)
+ {
+#ifndef SILENT
+ mprintf(St(MCalcCRCAllVol));
+#endif
+ CalcCRCMessageDone=true;
+ }
+
+#ifndef SILENT
+ mprintf(L"\n%s",CurName);
+#endif
+
+ File CurFile;
+ CurFile.TOpen(CurName);
+ CurFile.Seek(0,SEEK_END);
+ int64 Length=CurFile.Tell();
+ CurFile.Seek(Length-7,SEEK_SET);
+ for (int I=0;I<3;I++)
+ P[2-I]=CurFile.GetByte()+1;
+ uint FileCRC=0;
+ for (int I=0;I<4;I++)
+ FileCRC|=CurFile.GetByte()<<(I*8);
+ uint CalcCRC;
+ CalcFileSum(&CurFile,&CalcCRC,NULL,Cmd->Threads,Length-4);
+ if (FileCRC!=CalcCRC)
+ {
+#ifndef SILENT
+ mprintf(St(MCRCFailed),CurName);
+#endif
+ continue;
+ }
+ }
+ else
+ {
+ wchar *Dot=GetExt(CurName);
+ if (Dot==NULL)
+ continue;
+ bool WrongParam=false;
+ for (int I=0;I<ASIZE(P);I++)
+ {
+ do
+ {
+ Dot--;
+ } while (IsDigit(*Dot) && Dot>=CurName+BaseNamePartLength);
+ P[I]=atoiw(Dot+1);
+ if (P[I]==0 || P[I]>255)
+ WrongParam=true;
+ }
+ if (WrongParam)
+ continue;
+ }
+ if (P[1]+P[2]>255)
+ continue;
+ if (RecVolNumber!=0 && RecVolNumber!=P[1] || FileNumber!=0 && FileNumber!=P[2])
+ {
+#ifndef SILENT
+ Log(NULL,St(MRecVolDiffSets),CurName,PrevName);
+#endif
+ return(false);
+ }
+ RecVolNumber=P[1];
+ FileNumber=P[2];
+ wcscpy(PrevName,CurName);
+ File *NewFile=new File;
+ NewFile->TOpen(CurName);
+ SrcFile[FileNumber+P[0]-1]=NewFile;
+ FoundRecVolumes++;
+#ifndef SILENT
+ if (RecFileSize==0)
+ RecFileSize=NewFile->FileLength();
+#endif
+ }
+#ifndef SILENT
+ if (!Silent || FoundRecVolumes!=0)
+ {
+ mprintf(St(MRecVolFound),FoundRecVolumes);
+ }
+#endif
+ if (FoundRecVolumes==0)
+ return(false);
+
+ bool WriteFlags[256];
+ memset(WriteFlags,0,sizeof(WriteFlags));
+
+ wchar LastVolName[NM];
+ *LastVolName=0;
+
+ for (int CurArcNum=0;CurArcNum<FileNumber;CurArcNum++)
+ {
+ Archive *NewFile=new Archive(Cmd);
+ bool ValidVolume=FileExist(ArcName);
+ if (ValidVolume)
+ {
+ NewFile->TOpen(ArcName);
+ ValidVolume=NewFile->IsArchive(false);
+ if (ValidVolume)
+ {
+ while (NewFile->ReadHeader()!=0)
+ {
+ if (NewFile->GetHeaderType()==HEAD_ENDARC)
+ {
+#ifndef SILENT
+ mprintf(L"\n%s",ArcName);
+#endif
+ if (NewFile->EndArcHead.DataCRC)
+ {
+ uint CalcCRC;
+ CalcFileSum(NewFile,&CalcCRC,NULL,Cmd->Threads,NewFile->CurBlockPos);
+ if (NewFile->EndArcHead.ArcDataCRC!=CalcCRC)
+ {
+ ValidVolume=false;
+#ifndef SILENT
+ mprintf(St(MCRCFailed),ArcName);
+#endif
+ }
+ }
+ break;
+ }
+ NewFile->SeekToNext();
+ }
+ }
+ if (!ValidVolume)
+ {
+ NewFile->Close();
+ wchar NewName[NM];
+ wcscpy(NewName,ArcName);
+ wcscat(NewName,L".bad");
+#ifndef SILENT
+ mprintf(St(MBadArc),ArcName);
+ mprintf(St(MRenaming),ArcName,NewName);
+#endif
+ RenameFile(ArcName,NewName);
+ }
+ NewFile->Seek(0,SEEK_SET);
+ }
+ if (!ValidVolume)
+ {
+ // It is important to return 'false' instead of aborting here,
+ // so if we are called from extraction, we will be able to continue
+ // extracting. It may happen if .rar and .rev are on read-only disks
+ // like CDs.
+ if (!NewFile->Create(ArcName))
+ {
+ // We need to display the title of operation before the error message,
+ // to make clear for user that create error is related to recovery
+ // volumes. This is why we cannot use WCreate call here. Title must be
+ // before create error, not after that.
+#ifndef SILENT
+ mprintf(St(MReconstructing));
+#endif
+ ErrHandler.CreateErrorMsg(NULL,ArcName);
+ return false;
+ }
+
+ WriteFlags[CurArcNum]=true;
+ MissingVolumes++;
+
+ if (CurArcNum==FileNumber-1)
+ wcscpy(LastVolName,ArcName);
+
+#ifndef SILENT
+ mprintf(St(MAbsNextVol),ArcName);
+#endif
+ }
+ SrcFile[CurArcNum]=(File*)NewFile;
+ NextVolumeName(ArcName,ASIZE(ArcName),!NewNumbering);
+ }
+
+#ifndef SILENT
+ mprintf(St(MRecVolMissing),MissingVolumes);
+#endif
+
+ if (MissingVolumes==0)
+ {
+#ifndef SILENT
+ mprintf(St(MRecVolAllExist));
+#endif
+ return false;
+ }
+
+ if (MissingVolumes>FoundRecVolumes)
+ {
+#ifndef SILENT
+ mprintf(St(MRecVolCannotFix));
+#endif
+ return false;
+ }
+#ifndef SILENT
+ mprintf(St(MReconstructing));
+#endif
+
+ int TotalFiles=FileNumber+RecVolNumber;
+ int Erasures[256],EraSize=0;
+
+ for (int I=0;I<TotalFiles;I++)
+ if (WriteFlags[I] || SrcFile[I]==NULL)
+ Erasures[EraSize++]=I;
+
+#ifndef SILENT
+ int64 ProcessedSize=0;
+#ifndef GUI
+ int LastPercent=-1;
+ mprintf(L" ");
+#endif
+#endif
+ // Size of per file buffer.
+ size_t RecBufferSize=TotalBufferSize/TotalFiles;
+
+#ifdef RAR_SMP
+ uint ThreadNumber=Cmd->Threads;
+ RSEncode rse[MaxPoolThreads];
+#else
+ uint ThreadNumber=1;
+ RSEncode rse[1];
+#endif
+ for (uint I=0;I<ThreadNumber;I++)
+ rse[I].Init(RecVolNumber);
+
+ while (true)
+ {
+ Wait();
+ int MaxRead=0;
+ for (int I=0;I<TotalFiles;I++)
+ if (WriteFlags[I] || SrcFile[I]==NULL)
+ memset(&Buf[I*RecBufferSize],0,RecBufferSize);
+ else
+ {
+ int ReadSize=SrcFile[I]->Read(&Buf[I*RecBufferSize],RecBufferSize);
+ if (ReadSize!=RecBufferSize)
+ memset(&Buf[I*RecBufferSize+ReadSize],0,RecBufferSize-ReadSize);
+ if (ReadSize>MaxRead)
+ MaxRead=ReadSize;
+ }
+ if (MaxRead==0)
+ break;
+#ifndef SILENT
+ int CurPercent=ToPercent(ProcessedSize,RecFileSize);
+ if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
+ {
+ mprintf(L"\b\b\b\b%3d%%",CurPercent);
+ LastPercent=CurPercent;
+ }
+ ProcessedSize+=MaxRead;
+#endif
+
+ int BlockStart=0;
+ int BlockSize=MaxRead/ThreadNumber;
+ if (BlockSize<0x100)
+ BlockSize=MaxRead;
+
+ for (uint CurThread=0;BlockStart<MaxRead;CurThread++)
+ {
+ // Last thread processes all left data including increasement
+ // from rounding error.
+ if (CurThread==ThreadNumber-1)
+ BlockSize=MaxRead-BlockStart;
+
+ RSEncode *curenc=rse+CurThread;
+ curenc->Buf=&Buf[0];
+ curenc->BufStart=BlockStart;
+ curenc->BufEnd=BlockStart+BlockSize;
+ curenc->FileNumber=TotalFiles;
+ curenc->RecBufferSize=RecBufferSize;
+ curenc->Erasures=Erasures;
+ curenc->EraSize=EraSize;
+
+#ifdef RAR_SMP
+ if (ThreadNumber>1)
+ RSThreadPool->AddTask(RSDecodeThread,(void*)curenc);
+ else
+ curenc->DecodeBuf();
+#else
+ curenc->DecodeBuf();
+#endif
+
+ BlockStart+=BlockSize;
+ }
+
+#ifdef RAR_SMP
+ RSThreadPool->WaitDone();
+#endif // RAR_SMP
+
+ for (int I=0;I<FileNumber;I++)
+ if (WriteFlags[I])
+ SrcFile[I]->Write(&Buf[I*RecBufferSize],MaxRead);
+ }
+ for (int I=0;I<RecVolNumber+FileNumber;I++)
+ if (SrcFile[I]!=NULL)
+ {
+ File *CurFile=SrcFile[I];
+ if (NewStyle && WriteFlags[I])
+ {
+ int64 Length=CurFile->Tell();
+ CurFile->Seek(Length-7,SEEK_SET);
+ for (int J=0;J<7;J++)
+ CurFile->PutByte(0);
+ }
+ CurFile->Close();
+ SrcFile[I]=NULL;
+ }
+ if (*LastVolName!=0)
+ {
+ // Truncate the last volume to its real size.
+ Archive Arc(Cmd);
+ if (Arc.Open(LastVolName,FMF_UPDATE) && Arc.IsArchive(true) &&
+ Arc.SearchBlock(HEAD_ENDARC))
+ {
+ Arc.Seek(Arc.NextBlockPos,SEEK_SET);
+ char Buf[8192];
+ int ReadSize=Arc.Read(Buf,sizeof(Buf));
+ int ZeroCount=0;
+ while (ZeroCount<ReadSize && Buf[ZeroCount]==0)
+ ZeroCount++;
+ if (ZeroCount==ReadSize)
+ {
+ Arc.Seek(Arc.NextBlockPos,SEEK_SET);
+ Arc.Truncate();
+ }
+ }
+ }
+#if !defined(GUI) && !defined(SILENT)
+ if (!Cmd->DisablePercentage)
+ mprintf(L"\b\b\b\b100%%");
+ if (!Silent && !Cmd->DisableDone)
+ mprintf(St(MDone));
+#endif
+ return true;
+}
+
+
+void RSEncode::DecodeBuf()
+{
+ for (int BufPos=BufStart;BufPos<BufEnd;BufPos++)
+ {
+ byte Data[256];
+ for (int I=0;I<FileNumber;I++)
+ Data[I]=Buf[I*RecBufferSize+BufPos];
+ RSC.Decode(Data,FileNumber,Erasures,EraSize);
+ for (int I=0;I<EraSize;I++)
+ Buf[Erasures[I]*RecBufferSize+BufPos]=Data[Erasures[I]];
+ }
+}
diff --git a/src/thirdparty/unrar/recvol5.cpp b/src/thirdparty/unrar/recvol5.cpp
new file mode 100644
index 000000000..7ca137fe0
--- /dev/null
+++ b/src/thirdparty/unrar/recvol5.cpp
@@ -0,0 +1,461 @@
+#include "rar.hpp"
+
+static const uint MaxVolumes=65535;
+
+RecVolumes5::RecVolumes5()
+{
+ RealReadBuffer=NULL;
+
+ DataCount=0;
+ RecCount=0;
+ TotalCount=0;
+ RecBufferSize=0;
+
+ for (uint I=0;I<ASIZE(ThreadData);I++)
+ {
+ ThreadData[I].RecRSPtr=this;
+ ThreadData[I].RS=NULL;
+ }
+#ifdef RAR_SMP
+ RecThreadPool=CreateThreadPool();
+#endif
+
+ RealBuf=NULL; // Might be needed in case of exception.
+ RealBuf=new byte[TotalBufferSize+SSE_ALIGNMENT];
+ Buf=(byte *)ALIGN_VALUE(RealBuf,SSE_ALIGNMENT);
+}
+
+
+RecVolumes5::~RecVolumes5()
+{
+ delete[] RealBuf;
+ delete[] RealReadBuffer;
+ for (uint I=0;I<RecItems.Size();I++)
+ delete RecItems[I].f;
+ for (uint I=0;I<ASIZE(ThreadData);I++)
+ delete ThreadData[I].RS;
+#ifdef RAR_SMP
+ DestroyThreadPool(RecThreadPool);
+#endif
+}
+
+
+
+
+#ifdef RAR_SMP
+THREAD_PROC(RecThreadRS)
+{
+ RecRSThreadData *td=(RecRSThreadData *)Data;
+ td->RecRSPtr->ProcessAreaRS(td);
+}
+#endif
+
+
+void RecVolumes5::ProcessRS(RAROptions *Cmd,uint DataNum,const byte *Data,uint MaxRead,bool Encode)
+{
+/*
+ RSCoder16 RS;
+ RS.Init(DataCount,RecCount,Encode ? NULL:ValidFlags);
+ uint Count=Encode ? RecCount : MissingVolumes;
+ for (uint I=0;I<Count;I++)
+ RS.UpdateECC(DataNum, I, Data, Buf+I*RecBufferSize, MaxRead);
+*/
+
+#ifdef RAR_SMP
+ uint ThreadNumber=Cmd->Threads;
+#else
+ uint ThreadNumber=1;
+#endif
+
+ const uint MinThreadBlock=0x1000;
+ ThreadNumber=Min(ThreadNumber,MaxRead/MinThreadBlock);
+
+ if (ThreadNumber<1)
+ ThreadNumber=1;
+ uint ThreadDataSize=MaxRead/ThreadNumber;
+ ThreadDataSize+=(ThreadDataSize&1); // Must be even for 16-bit RS coder.
+#ifdef USE_SSE
+ ThreadDataSize=ALIGN_VALUE(ThreadDataSize,SSE_ALIGNMENT); // Alignment for SSE operations.
+#endif
+ if (ThreadDataSize<MinThreadBlock)
+ ThreadDataSize=MinThreadBlock;
+
+ for (size_t I=0,CurPos=0;I<ThreadNumber && CurPos<MaxRead;I++)
+ {
+ RecRSThreadData *td=ThreadData+I;
+ if (td->RS==NULL)
+ {
+ td->RS=new RSCoder16;
+ td->RS->Init(DataCount,RecCount,Encode ? NULL:ValidFlags);
+ }
+ td->DataNum=DataNum;
+ td->Data=Data;
+ td->Encode=Encode;
+ td->StartPos=CurPos;
+
+ size_t EndPos=CurPos+ThreadDataSize;
+ if (EndPos>MaxRead || I==ThreadNumber-1)
+ EndPos=MaxRead;
+
+ td->Size=EndPos-CurPos;
+
+ CurPos=EndPos;
+
+#ifdef RAR_SMP
+ if (ThreadNumber>1)
+ RecThreadPool->AddTask(RecThreadRS,(void*)td);
+ else
+ ProcessAreaRS(td);
+#else
+ ProcessAreaRS(td);
+#endif
+ }
+#ifdef RAR_SMP
+ RecThreadPool->WaitDone();
+#endif // RAR_SMP
+}
+
+
+void RecVolumes5::ProcessAreaRS(RecRSThreadData *td)
+{
+ uint Count=td->Encode ? RecCount : MissingVolumes;
+ for (uint I=0;I<Count;I++)
+ td->RS->UpdateECC(td->DataNum, I, td->Data+td->StartPos, Buf+I*RecBufferSize+td->StartPos, td->Size);
+}
+
+
+
+
+bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
+{
+ wchar ArcName[NM];
+ wcscpy(ArcName,Name);
+
+ wchar *Num=GetVolNumPart(ArcName);
+ while (Num>ArcName && IsDigit(*(Num-1)))
+ Num--;
+ wcsncpyz(Num,L"*.*",ASIZE(ArcName)-(Num-ArcName));
+
+ wchar FirstVolName[NM];
+ *FirstVolName=0;
+
+ int64 RecFileSize=0;
+
+ FindFile VolFind;
+ VolFind.SetMask(ArcName);
+ FindData fd;
+ uint FoundRecVolumes=0;
+ while (VolFind.Next(&fd))
+ {
+ Wait();
+
+ Archive *Vol=new Archive(Cmd);
+ int ItemPos=-1;
+ if (Vol->WOpen(fd.Name))
+ {
+ if (CmpExt(fd.Name,L"rev"))
+ {
+ uint RecNum=ReadHeader(Vol,FoundRecVolumes==0);
+ if (RecNum!=0)
+ {
+ if (FoundRecVolumes==0)
+ RecFileSize=Vol->FileLength();
+
+ ItemPos=RecNum;
+ FoundRecVolumes++;
+ }
+ }
+ else
+ if (Vol->IsArchive(true) && (Vol->SFXSize>0 || CmpExt(fd.Name,L"rar")))
+ {
+ if (!Vol->Volume && !Vol->BrokenHeader)
+ {
+ Log(ArcName,St(MNotVolume),ArcName);
+ return false;
+ }
+ // We work with archive as with raw data file, so we do not want
+ // to spend time to QOpen I/O redirection.
+ Vol->QOpenUnload();
+
+ Vol->Seek(0,SEEK_SET);
+
+ // RAR volume found. Get its number, store the handle in appropriate
+ // array slot, clean slots in between if we had to grow the array.
+ wchar *Num=GetVolNumPart(fd.Name);
+ uint VolNum=0;
+ for (uint K=1;Num>=fd.Name && IsDigit(*Num);K*=10,Num--)
+ VolNum+=(*Num-'0')*K;
+ if (VolNum==0 || VolNum>MaxVolumes)
+ continue;
+ size_t CurSize=RecItems.Size();
+ if (VolNum>CurSize)
+ {
+ RecItems.Alloc(VolNum);
+ for (size_t I=CurSize;I<VolNum;I++)
+ RecItems[I].f=NULL;
+ }
+ ItemPos=VolNum-1;
+
+ if (*FirstVolName==0)
+ VolNameToFirstName(fd.Name,FirstVolName,true);
+ }
+ }
+ if (ItemPos==-1)
+ delete Vol; // Skip found file, it is not RAR or REV volume.
+ else
+ if ((uint)ItemPos<RecItems.Size()) // Check if found more REV than needed.
+ {
+ // Store found RAR or REV volume.
+ RecVolItem *Item=RecItems+ItemPos;
+ Item->f=Vol;
+ Item->New=false;
+ wcsncpyz(Item->Name,fd.Name,ASIZE(Item->Name));
+ }
+ }
+
+#ifndef SILENT
+ if (!Silent || FoundRecVolumes!=0)
+ {
+ mprintf(St(MRecVolFound),FoundRecVolumes);
+ }
+#endif
+ if (FoundRecVolumes==0)
+ return false;
+
+ mprintf(St(MCalcCRCAllVol));
+
+ MissingVolumes=0;
+ for (uint I=0;I<TotalCount;I++)
+ {
+ RecVolItem *Item=&RecItems[I];
+ if (Item->f!=NULL)
+ {
+ mprintf(L"\n%s",Item->Name);
+ uint RevCRC;
+ CalcFileSum(Item->f,&RevCRC,NULL,Cmd->Threads,INT64NDF,CALCFSUM_CURPOS);
+ Item->Valid=RevCRC==Item->CRC;
+ if (!Item->Valid)
+ {
+ mprintf(St(MCRCFailed),Item->Name);
+ // Close only corrupt REV volumes here. We'll close and rename corrupt
+ // RAR volumes later, if we'll know that recovery is possible.
+ if (I>=DataCount)
+ {
+ Item->f->Close();
+ Item->f=NULL;
+ FoundRecVolumes--;
+ }
+ }
+ }
+ if (I<DataCount && (Item->f==NULL || !Item->Valid))
+ MissingVolumes++;
+ }
+
+ mprintf(St(MRecVolMissing),MissingVolumes);
+
+ if (MissingVolumes==0)
+ {
+ mprintf(St(MRecVolAllExist));
+ return false;
+ }
+
+ if (MissingVolumes>FoundRecVolumes)
+ {
+ mprintf(St(MRecVolCannotFix));
+ return false;
+ }
+
+ mprintf(St(MReconstructing));
+
+ // Create missing and rename bad volumes.
+ for (uint I=0;I<DataCount;I++)
+ {
+ RecVolItem *Item=&RecItems[I];
+ if (Item->f!=NULL && !Item->Valid)
+ {
+ Item->f->Close();
+
+ wchar NewName[NM];
+ wcscpy(NewName,Item->Name);
+ wcscat(NewName,L".bad");
+#ifndef SILENT
+ mprintf(St(MBadArc),Item->Name);
+ mprintf(St(MRenaming),Item->Name,NewName);
+#endif
+ RenameFile(Item->Name,NewName);
+ delete Item->f;
+ Item->f=NULL;
+ }
+
+ if (Item->New=(Item->f==NULL))
+ {
+ wcsncpyz(Item->Name,FirstVolName,ASIZE(Item->Name));
+ mprintf(St(MCreating),Item->Name);
+ File *NewVol=new File;
+ bool UserReject;
+ if (!FileCreate(Cmd,NewVol,Item->Name,ASIZE(Item->Name),Cmd->Overwrite,&UserReject))
+ {
+ if (!UserReject)
+ ErrHandler.CreateErrorMsg(NULL,Item->Name);
+ ErrHandler.Exit(UserReject ? RARX_USERBREAK:RARX_CREATE);
+ }
+ NewVol->Prealloc(Item->FileSize);
+ Item->f=NewVol;
+ Item->New=true;
+ }
+ NextVolumeName(FirstVolName,ASIZE(FirstVolName),false);
+ }
+
+
+ int64 ProcessedSize=0;
+#ifndef GUI
+ int LastPercent=-1;
+ mprintf(L" ");
+#endif
+
+ // Even though we already preliminary calculated missing volume number,
+ // let's do it again now, when we have the final and exact information.
+ MissingVolumes=0;
+
+ ValidFlags=new bool[TotalCount];
+ for (uint I=0;I<TotalCount;I++)
+ {
+ ValidFlags[I]=RecItems[I].f!=NULL && !RecItems[I].New;
+ if (I<DataCount && !ValidFlags[I])
+ MissingVolumes++;
+ }
+
+ // Size of per file buffer.
+ RecBufferSize=TotalBufferSize/MissingVolumes;
+ if ((RecBufferSize&1)==1) // Must be even for our RS16 codec.
+ RecBufferSize--;
+#ifdef USE_SSE
+ RecBufferSize&=~(SSE_ALIGNMENT-1); // Align for SSE.
+#endif
+
+ uint *Data=new uint[TotalCount];
+
+ RSCoder16 RS;
+ if (!RS.Init(DataCount,RecCount,ValidFlags))
+ return false; // Should not happen, we check parameter validity above.
+
+ RealReadBuffer=new byte[RecBufferSize+SSE_ALIGNMENT];
+ byte *ReadBuf=(byte *)ALIGN_VALUE(RealReadBuffer,SSE_ALIGNMENT);
+
+ while (true)
+ {
+ Wait();
+
+ int MaxRead=0;
+ for (uint I=0,J=DataCount;I<DataCount;I++)
+ {
+ uint VolNum=I;
+ if (!ValidFlags[I]) // If next RAR volume is missing or invalid.
+ {
+ while (!ValidFlags[J]) // Find next valid REV volume.
+ J++;
+ VolNum=J++; // Use next valid REV volume data instead of RAR.
+ }
+ RecVolItem *Item=RecItems+VolNum;
+
+ byte *B=&ReadBuf[0];
+ int ReadSize=0;
+ if (Item->f!=NULL && !Item->New)
+ ReadSize=Item->f->Read(B,RecBufferSize);
+ if (ReadSize!=RecBufferSize)
+ memset(B+ReadSize,0,RecBufferSize-ReadSize);
+ if (ReadSize>MaxRead)
+ MaxRead=ReadSize;
+
+ ProcessRS(Cmd,I,B,MaxRead,false);
+ }
+ if (MaxRead==0)
+ break;
+
+ for (uint I=0,J=0;I<DataCount;I++)
+ if (!ValidFlags[I])
+ {
+ RecVolItem *Item=RecItems+I;
+ size_t WriteSize=(size_t)Min(MaxRead,Item->FileSize);
+ Item->f->Write(Buf+(J++)*RecBufferSize,WriteSize);
+ Item->FileSize-=WriteSize;
+ }
+
+#ifndef SILENT
+ int CurPercent=ToPercent(ProcessedSize,RecFileSize);
+ if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
+ {
+ mprintf(L"\b\b\b\b%3d%%",CurPercent);
+ LastPercent=CurPercent;
+ }
+ ProcessedSize+=MaxRead;
+#endif
+ }
+
+ for (uint I=0;I<TotalCount;I++)
+ if (RecItems[I].f!=NULL)
+ RecItems[I].f->Close();
+
+ delete[] ValidFlags;
+ delete[] Data;
+#if !defined(GUI) && !defined(SILENT)
+ if (!Cmd->DisablePercentage)
+ mprintf(L"\b\b\b\b100%%");
+ if (!Silent && !Cmd->DisableDone)
+ mprintf(St(MDone));
+#endif
+ return(true);
+}
+
+
+uint RecVolumes5::ReadHeader(File *RecFile,bool FirstRev)
+{
+ const size_t FirstReadSize=REV5_SIGN_SIZE+8;
+ byte ShortBuf[FirstReadSize];
+ if (RecFile->Read(ShortBuf,FirstReadSize)!=FirstReadSize)
+ return 0;
+ if (memcmp(ShortBuf,REV5_SIGN,REV5_SIGN_SIZE)!=0)
+ return 0;
+ uint HeaderSize=RawGet4(ShortBuf+REV5_SIGN_SIZE+4);
+ if (HeaderSize>0x100000 || HeaderSize<=5)
+ return 0;
+ uint BlockCRC=RawGet4(ShortBuf+REV5_SIGN_SIZE);
+
+ RawRead Raw(RecFile);
+ if (Raw.Read(HeaderSize)!=HeaderSize)
+ return 0;
+
+ // Calculate CRC32 of entire header including 4 byte size field.
+ uint CalcCRC=CRC32(0xffffffff,ShortBuf+REV5_SIGN_SIZE+4,4);
+ if ((CRC32(CalcCRC,Raw.GetDataPtr(),HeaderSize)^0xffffffff)!=BlockCRC)
+ return 0;
+
+ if (Raw.Get1()!=1) // Version check.
+ return 0;
+ DataCount=Raw.Get2();
+ RecCount=Raw.Get2();
+ TotalCount=DataCount+RecCount;
+ uint RecNum=Raw.Get2(); // Number of recovery volume.
+ if (RecNum>=TotalCount || TotalCount>MaxVolumes)
+ return 0;
+ uint RevCRC=Raw.Get4(); // CRC of current REV volume.
+
+ if (FirstRev)
+ {
+ // If we have read the first valid REV file, init data structures
+ // using information from REV header.
+ size_t CurSize=RecItems.Size();
+ RecItems.Alloc(TotalCount);
+ for (size_t I=CurSize;I<TotalCount;I++)
+ RecItems[I].f=NULL;
+ for (uint I=0;I<DataCount;I++)
+ {
+ RecItems[I].FileSize=Raw.Get8();
+ RecItems[I].CRC=Raw.Get4();
+ }
+ }
+
+ RecItems[RecNum].CRC=RevCRC; // Assign it here, after allocating RecItems.
+
+ return RecNum;
+}
diff --git a/src/thirdparty/unrar/resource.cpp b/src/thirdparty/unrar/resource.cpp
index 1c966ce88..37e2c7594 100644
--- a/src/thirdparty/unrar/resource.cpp
+++ b/src/thirdparty/unrar/resource.cpp
@@ -3,15 +3,7 @@
#ifndef RARDLL
-const char *St(MSGID StringId)
-{
- return(StringId);
-}
-#endif
-
-
-#ifndef RARDLL
-const wchar *StW(MSGID StringId)
+const wchar *St(MSGID StringId)
{
static wchar StrTable[8][512];
static int StrNum=0;
diff --git a/src/thirdparty/unrar/resource.hpp b/src/thirdparty/unrar/resource.hpp
index 7df584438..98a6c6ba5 100644
--- a/src/thirdparty/unrar/resource.hpp
+++ b/src/thirdparty/unrar/resource.hpp
@@ -2,11 +2,9 @@
#define _RAR_RESOURCE_
#ifdef RARDLL
-#define St(x) ( "")
-#define StW(x) (L"")
+#define St(x) (L"")
#else
-const char *St (MSGID StringId);
-const wchar *StW (MSGID StringId);
+const wchar *St(MSGID StringId);
#endif
diff --git a/src/thirdparty/unrar/rijndael.cpp b/src/thirdparty/unrar/rijndael.cpp
index 67434ba20..b267d6764 100644
--- a/src/thirdparty/unrar/rijndael.cpp
+++ b/src/thirdparty/unrar/rijndael.cpp
@@ -1,14 +1,12 @@
-/**************************************************************************
- * This code is based on Szymon Stefanek AES implementation: *
- * http://www.esat.kuleuven.ac.be/~rijmen/rijndael/rijndael-cpplib.tar.gz *
- * *
- * Dynamic tables generation is based on the Brian Gladman work: *
- * http://fp.gladman.plus.com/cryptography_technology/rijndael *
- **************************************************************************/
+/***************************************************************************
+ * This code is based on public domain Szymon Stefanek AES implementation: *
+ * http://www.pragmaware.net/software/rijndael/index.php *
+ * *
+ * Dynamic tables generation is based on the Brian Gladman work: *
+ * http://fp.gladman.plus.com/cryptography_technology/rijndael *
+ ***************************************************************************/
#include "rar.hpp"
-const int uKeyLenInBytes=16, m_uRounds=10;
-
static byte S[256],S5[256],rcon[30];
static byte T1[256][4],T2[256][4],T3[256][4],T4[256][4];
static byte T5[256][4],T6[256][4],T7[256][4],T8[256][4];
@@ -66,21 +64,36 @@ Rijndael::Rijndael()
}
-void Rijndael::init(Direction dir,const byte * key,byte * initVector)
+void Rijndael::Init(bool Encrypt,const byte *key,uint keyLen,const byte * initVector)
{
- m_direction = dir;
+ uint uKeyLenInBytes;
+ switch(keyLen)
+ {
+ case 128:
+ uKeyLenInBytes = 16;
+ m_uRounds = 10;
+ break;
+ case 192:
+ uKeyLenInBytes = 24;
+ m_uRounds = 12;
+ break;
+ case 256:
+ uKeyLenInBytes = 32;
+ m_uRounds = 14;
+ break;
+ }
byte keyMatrix[_MAX_KEY_COLUMNS][4];
- for(uint i = 0;i < uKeyLenInBytes;i++)
+ for(uint i = 0; i < uKeyLenInBytes; i++)
keyMatrix[i >> 2][i & 3] = key[i];
- for(int i = 0;i < MAX_IV_SIZE;i++)
+ for(int i = 0; i < MAX_IV_SIZE; i++)
m_initVector[i] = initVector[i];
keySched(keyMatrix);
- if(m_direction == Decrypt)
+ if(!Encrypt)
keyEncToDec();
}
@@ -197,8 +210,8 @@ void Rijndael::keyEncToDec()
for(int r = 1; r < m_uRounds; r++)
{
byte n_expandedKey[4][4];
- for (int i=0;i<4;i++)
- for (int j=0;j<4;j++)
+ for (int i = 0; i < 4; i++)
+ for (int j = 0; j < 4; j++)
{
byte *w=m_expandedKey[r][j];
n_expandedKey[j][i]=U1[w[0]][i]^U2[w[1]][i]^U3[w[2]][i]^U4[w[3]][i];
@@ -296,3 +309,53 @@ void Rijndael::GenerateTables()
U1[b][0]=U2[b][1]=U3[b][2]=U4[b][3]=T5[i][0]=T6[i][1]=T7[i][2]=T8[i][3]=FFmul0e(b);
}
}
+
+
+#if 0
+static void TestRijndael();
+struct TestRij {TestRij() {TestRijndael();exit(0);}} GlobalTestRij;
+
+// Test CBC encryption according to NIST 800-38A.
+void TestRijndael()
+{
+ byte IV[16]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f};
+ byte PT[64]={
+ 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a,
+ 0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51,
+ 0x30,0xc8,0x1c,0x46,0xa3,0x5c,0xe4,0x11,0xe5,0xfb,0xc1,0x19,0x1a,0x0a,0x52,0xef,
+ 0xf6,0x9f,0x24,0x45,0xdf,0x4f,0x9b,0x17,0xad,0x2b,0x41,0x7b,0xe6,0x6c,0x37,0x10,
+ };
+
+ byte Key128[16]={0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c};
+ byte Chk128[16]={0x3f,0xf1,0xca,0xa1,0x68,0x1f,0xac,0x09,0x12,0x0e,0xca,0x30,0x75,0x86,0xe1,0xa7};
+ byte Key192[24]={0x8e,0x73,0xb0,0xf7,0xda,0x0e,0x64,0x52,0xc8,0x10,0xf3,0x2b,0x80,0x90,0x79,0xe5,0x62,0xf8,0xea,0xd2,0x52,0x2c,0x6b,0x7b};
+ byte Chk192[16]={0x08,0xb0,0xe2,0x79,0x88,0x59,0x88,0x81,0xd9,0x20,0xa9,0xe6,0x4f,0x56,0x15,0xcd};
+ byte Key256[32]={0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4};
+ byte Chk256[16]={0xb2,0xeb,0x05,0xe2,0xc3,0x9b,0xe9,0xfc,0xda,0x6c,0x19,0x07,0x8c,0x6a,0x9d,0x1b};
+ byte *Key[3]={Key128,Key192,Key256};
+ byte *Chk[3]={Chk128,Chk192,Chk256};
+
+ Rijndael rij; // Declare outside of loop to test re-initialization.
+ for (uint L=0;L<3;L++)
+ {
+ byte Out[16];
+ wchar Str[sizeof(Out)*2+1];
+
+ uint KeyLength=128+L*64;
+ rij.Init(true,Key[L],KeyLength,IV);
+ for (uint I=0;I<sizeof(PT);I+=16)
+ rij.blockEncrypt(PT+I,16,Out);
+ BinToHex(Chk[L],16,NULL,Str,ASIZE(Str));
+ mprintf(L"\nAES-%d expected: %s",KeyLength,Str);
+ BinToHex(Out,sizeof(Out),NULL,Str,ASIZE(Str));
+ mprintf(L"\nAES-%d result: %s",KeyLength,Str);
+ if (memcmp(Out,Chk[L],16)==0)
+ mprintf(L" OK");
+ else
+ {
+ mprintf(L" FAILED");
+ getchar();
+ }
+ }
+}
+#endif
diff --git a/src/thirdparty/unrar/rijndael.hpp b/src/thirdparty/unrar/rijndael.hpp
index bb5bd881c..bf1439e69 100644
--- a/src/thirdparty/unrar/rijndael.hpp
+++ b/src/thirdparty/unrar/rijndael.hpp
@@ -14,9 +14,7 @@
#define MAX_IV_SIZE 16
class Rijndael
-{
- public:
- enum Direction { Encrypt , Decrypt };
+{
private:
void keySched(byte key[_MAX_KEY_COLUMNS][4]);
void keyEncToDec();
@@ -24,14 +22,14 @@ class Rijndael
void decrypt(const byte a[16], byte b[16]);
void GenerateTables();
- Direction m_direction;
+ int m_uRounds;
byte m_initVector[MAX_IV_SIZE];
byte m_expandedKey[_MAX_ROUNDS+1][4][4];
public:
Rijndael();
- void init(Direction dir,const byte *key,byte *initVector);
+ void Init(bool Encrypt,const byte *key,uint keyLen,const byte *initVector);
size_t blockEncrypt(const byte *input, size_t inputLen, byte *outBuffer);
size_t blockDecrypt(const byte *input, size_t inputLen, byte *outBuffer);
};
-
+
#endif // _RIJNDAEL_H_
diff --git a/src/thirdparty/unrar/rs.cpp b/src/thirdparty/unrar/rs.cpp
index b7ce1db60..10ccc6d7e 100644
--- a/src/thirdparty/unrar/rs.cpp
+++ b/src/thirdparty/unrar/rs.cpp
@@ -19,10 +19,10 @@ void RSCoder::gfInit()
gfLog[J]=I;
gfExp[I]=J;
J<<=1;
- if (J & 0x100)
+ if (J > MAXPAR)
J^=0x11D; // 0x11D field-generator polynomial (x^8+x^4+x^3+x^2+1).
}
- for (int I=MAXPAR;I<MAXPOL;I++)
+ for (int I=MAXPAR;I<MAXPOL;I++) // Avoid gfExp overflow check.
gfExp[I]=gfExp[I-MAXPAR];
}
@@ -97,21 +97,9 @@ bool RSCoder::Decode(byte *Data,int DataSize,int *EraLoc,int EraSize)
bool AllZeroes=true;
for (int I=0;I<ParSize;I++)
{
- int Sum=Data[0],J=1,Exp=gfExp[I+1];
- for (;J+8<=DataSize;J+=8) // Unroll the loop for speed.
- {
- Sum=Data[J]^gfMult(Exp,Sum);
- Sum=Data[J+1]^gfMult(Exp,Sum);
- Sum=Data[J+2]^gfMult(Exp,Sum);
- Sum=Data[J+3]^gfMult(Exp,Sum);
- Sum=Data[J+4]^gfMult(Exp,Sum);
- Sum=Data[J+5]^gfMult(Exp,Sum);
- Sum=Data[J+6]^gfMult(Exp,Sum);
- Sum=Data[J+7]^gfMult(Exp,Sum);
- }
-
- for (;J<DataSize;J++)
- Sum=Data[J]^gfMult(Exp,Sum);
+ int Sum=0;
+ for (int J=0;J<DataSize;J++)
+ Sum=Data[J]^gfMult(gfExp[I+1],Sum);
if ((SynData[I]=Sum)!=0)
AllZeroes=false;
}
diff --git a/src/thirdparty/unrar/rs16.cpp b/src/thirdparty/unrar/rs16.cpp
new file mode 100644
index 000000000..2e3f20da0
--- /dev/null
+++ b/src/thirdparty/unrar/rs16.cpp
@@ -0,0 +1,416 @@
+#include "rar.hpp"
+
+// We used "Screaming Fast Galois Field Arithmetic Using Intel SIMD
+// Instructions" paper by James S. Plank, Kevin M. Greenan
+// and Ethan L. Miller for fast SSE based multiplication.
+// Also we are grateful to Artem Drobanov and Bulat Ziganshin
+// for samples and ideas allowed to make Reed-Solomon codec more efficient.
+
+RSCoder16::RSCoder16()
+{
+ Decoding=false;
+ ND=NR=NE=0;
+ ValidFlags=NULL;
+ MX=NULL;
+ DataLog=NULL;
+ DataLogSize=0;
+
+ gfInit();
+}
+
+
+RSCoder16::~RSCoder16()
+{
+ delete[] gfExp;
+ delete[] gfLog;
+ delete[] DataLog;
+ delete[] MX;
+ delete[] ValidFlags;
+}
+
+
+// Initialize logarithms and exponents Galois field tables.
+void RSCoder16::gfInit()
+{
+ gfExp=new uint[4*gfSize+1];
+ gfLog=new uint[gfSize+1];
+
+ for (uint L=0,E=1;L<gfSize;L++)
+ {
+ gfLog[E]=L;
+ gfExp[L]=E;
+ gfExp[L+gfSize]=E; // Duplicate the table to avoid gfExp overflow check.
+ E<<=1;
+ if (E>gfSize)
+ E^=0x1100B; // Irreducible field-generator polynomial.
+ }
+
+ // log(0)+log(x) must be outside of usual log table, so we can set it
+ // to 0 and avoid check for 0 in multiplication parameters.
+ gfLog[0]= 2*gfSize;
+ for (uint I=2*gfSize;I<=4*gfSize;I++) // Results for log(0)+log(x).
+ gfExp[I]=0;
+}
+
+
+uint RSCoder16::gfAdd(uint a,uint b) // Addition in Galois field.
+{
+ return a^b;
+}
+
+
+uint RSCoder16::gfMul(uint a,uint b) // Multiplication in Galois field.
+{
+ return gfExp[gfLog[a]+gfLog[b]];
+}
+
+
+uint RSCoder16::gfInv(uint a) // Inverse element in Galois field.
+{
+ return a==0 ? 0:gfExp[gfSize-gfLog[a]];
+}
+
+
+bool RSCoder16::Init(uint DataCount, uint RecCount, bool *ValidityFlags)
+{
+ ND = DataCount;
+ NR = RecCount;
+ NE = 0;
+
+ Decoding=ValidityFlags!=NULL;
+ if (Decoding)
+ {
+ delete[] ValidFlags;
+ ValidFlags=new bool[ND + NR];
+
+ for (uint I = 0; I < ND + NR; I++)
+ ValidFlags[I]=ValidityFlags[I];
+ for (uint I = 0; I < ND; I++)
+ if (!ValidFlags[I])
+ NE++;
+ uint ValidECC=0;
+ for (uint I = ND; I < ND + NR; I++)
+ if (ValidFlags[I])
+ ValidECC++;
+ if (NE > ValidECC || NE == 0 || ValidECC == 0)
+ return false;
+ }
+ if (ND + NR > gfSize || NR > ND || ND == 0 || NR == 0)
+ return false;
+
+ delete[] MX;
+ if (Decoding)
+ {
+ MX=new uint[NE * ND];
+ MakeDecoderMatrix();
+ InvertDecoderMatrix();
+ }
+ else
+ {
+ MX=new uint[NR * ND];
+ MakeEncoderMatrix();
+ }
+ return true;
+}
+
+
+void RSCoder16::MakeEncoderMatrix()
+{
+ // Create Cauchy encoder generator matrix. Skip trivial "1" diagonal rows,
+ // which would just copy source data to destination.
+ for (uint I = 0; I < NR; I++)
+ for (uint J = 0; J < ND; J++)
+ MX[I * ND + J] = gfInv( gfAdd( (I+ND), J) );
+}
+
+
+void RSCoder16::MakeDecoderMatrix()
+{
+ // Create Cauchy decoder matrix. Skip trivial rows matching valid data
+ // units and containing "1" on main diagonal. Such rows would just copy
+ // source data to destination and they have no real value for us.
+ // Include rows only for broken data units and replace them by first
+ // available valid recovery code rows.
+ for (uint Flag=0, R=ND, Dest=0; Flag < ND; Flag++)
+ if (!ValidFlags[Flag]) // For every broken data unit.
+ {
+ while (!ValidFlags[R]) // Find a valid recovery unit.
+ R++;
+ for (uint J = 0; J < ND; J++) // And place its row to matrix.
+ MX[Dest*ND + J] = gfInv( gfAdd(R,J) );
+ Dest++;
+ R++;
+ }
+}
+
+
+// Apply Gauss–Jordan elimination to find inverse of decoder matrix.
+// We have the square NDxND matrix, but we do not store its trivial
+// diagonal "1" rows matching valid data, so we work with NExND matrix.
+// Our original Cauchy matrix does not contain 0, so we skip search
+// for non-zero pivot.
+void RSCoder16::InvertDecoderMatrix()
+{
+ uint *MI=new uint[NE * ND]; // We'll create inverse matrix here.
+ memset(MI, 0, ND * NE * sizeof(*MI)); // Initialize to identity matrix.
+ for (uint Kr = 0, Kf = 0; Kr < NE; Kr++, Kf++)
+ {
+ while (ValidFlags[Kf]) // Skip trivial rows.
+ Kf++;
+ MI[Kr * ND + Kf] = 1; // Set diagonal 1.
+ }
+
+ // Kr is the number of row in our actual reduced NE x ND matrix,
+ // which does not contain trivial diagonal 1 rows.
+ // Kf is the number of row in full ND x ND matrix with all trivial rows
+ // included.
+ for (uint Kr = 0, Kf = 0; Kf < ND; Kr++, Kf++) // Select pivot row.
+ {
+ while (ValidFlags[Kf] && Kf < ND)
+ {
+ // Here we process trivial diagonal 1 rows matching valid data units.
+ // Their processing can be simplified comparing to usual rows.
+ // In full version of elimination we would set MX[I * ND + Kf] to zero
+ // after MI[..]^=, but we do not need it for matrix inversion.
+ for (uint I = 0; I < NE; I++)
+ MI[I * ND + Kf] ^= MX[I * ND + Kf];
+ Kf++;
+ }
+
+ if (Kf == ND)
+ break;
+
+ uint *MXk = MX + Kr * ND; // k-th row of main matrix.
+ uint *MIk = MI + Kr * ND; // k-th row of inversion matrix.
+
+ uint PInv = gfInv( MXk[Kf] ); // Pivot inverse.
+ // Divide the pivot row by pivot, so pivot cell contains 1.
+ for (uint I = 0; I < ND; I++)
+ {
+ MXk[I] = gfMul( MXk[I], PInv );
+ MIk[I] = gfMul( MIk[I], PInv );
+ }
+
+ for (uint I = 0; I < NE; I++)
+ if (I != Kr) // For all rows except containing the pivot cell.
+ {
+ // Apply Gaussian elimination Mij -= Mkj * Mik / pivot.
+ // Since pivot is already 1, it is reduced to Mij -= Mkj * Mik.
+ uint *MXi = MX + I * ND; // i-th row of main matrix.
+ uint *MIi = MI + I * ND; // i-th row of inversion matrix.
+ uint Mik = MXi[Kf]; // Cell in pivot position.
+ for (uint J = 0; J < ND; J++)
+ {
+ MXi[J] ^= gfMul(MXk[J] , Mik);
+ MIi[J] ^= gfMul(MIk[J] , Mik);
+ }
+ }
+ }
+
+ // Copy data to main matrix.
+ for (uint I = 0; I < NE * ND; I++)
+ MX[I] = MI[I];
+
+ delete[] MI;
+}
+
+
+// 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.
+// We do not use this function now, everything is moved to UpdateECC.
+void RSCoder16::Process(const uint *Data, uint *Out)
+{
+ uint ProcData[gfSize];
+
+ for (uint I = 0; I < ND; I++)
+ ProcData[I]=Data[I];
+
+ if (Decoding)
+ {
+ // Replace broken data units with first available valid recovery codes.
+ // 'Data' array must contain recovery codes after data.
+ for (uint I=0, R=ND, Dest=0; I < ND; I++)
+ if (!ValidFlags[I]) // For every broken data unit.
+ {
+ while (!ValidFlags[R]) // Find a valid recovery unit.
+ R++;
+ ProcData[I]=Data[R];
+ R++;
+ }
+ }
+
+ uint H=Decoding ? NE : NR;
+ for (uint I = 0; I < H; I++)
+ {
+ uint R = 0; // Result of matrix row multiplication to data.
+
+ uint *MXi=MX + I * ND;
+ for (uint J = 0; J < ND; J++)
+ R ^= gfMul(MXi[J], ProcData[J]);
+
+ Out[I] = R;
+ }
+}
+
+
+// We update ECC in blocks by applying every data block to all ECC blocks.
+// This function applies one data block to one ECC block.
+void RSCoder16::UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte *ECC, size_t BlockSize)
+{
+ if (DataNum==0) // Init ECC data.
+ memset(ECC, 0, BlockSize);
+
+ bool DirectAccess;
+#ifdef LITTLE_ENDIAN
+ // We can access data and ECC directly if we have little endian 16 bit uint.
+ DirectAccess=sizeof(ushort)==2;
+#else
+ DirectAccess=false;
+#endif
+
+#ifdef USE_SSE
+ if (DirectAccess && SSE_UpdateECC(DataNum,ECCNum,Data,ECC,BlockSize))
+ return;
+#endif
+
+ if (ECCNum==0)
+ {
+ if (DataLogSize!=BlockSize)
+ {
+ delete[] DataLog;
+ DataLog=new uint[BlockSize];
+ DataLogSize=BlockSize;
+
+ }
+ if (DirectAccess)
+ for (size_t I=0; I<BlockSize; I+=2)
+ DataLog[I] = gfLog[ *(ushort*)(Data+I) ];
+ else
+ for (size_t I=0; I<BlockSize; I+=2)
+ {
+ uint D=Data[I]+Data[I+1]*256;
+ DataLog[I] = gfLog[ D ];
+ }
+ }
+
+ uint ML = gfLog[ MX[ECCNum * ND + DataNum] ];
+
+ if (DirectAccess)
+ for (size_t I=0; I<BlockSize; I+=2)
+ *(ushort*)(ECC+I) ^= gfExp[ ML + DataLog[I] ];
+ else
+ for (size_t I=0; I<BlockSize; I+=2)
+ {
+ uint R=gfExp[ ML + DataLog[I] ];
+ ECC[I]^=byte(R);
+ ECC[I+1]^=byte(R/256);
+ }
+}
+
+
+#ifdef USE_SSE
+// Data and ECC addresses must be properly aligned for SSE.
+bool RSCoder16::SSE_UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte *ECC, size_t BlockSize)
+{
+ // Check data alignment and SSSE3 support.
+ if ((size_t(Data) & (SSE_ALIGNMENT-1))!=0 || (size_t(ECC) & (SSE_ALIGNMENT-1))!=0 ||
+ _SSE_Version<SSE_SSSE3)
+ return false;
+
+ uint M=MX[ECCNum * ND + DataNum];
+
+ // Prepare tables containing products of M and 4, 8, 12, 16 bit length
+ // numbers, which have 4 high bits in 0..15 range and other bits set to 0.
+ // Store high and low bytes of resulting 16 bit product in separate tables.
+ __m128i T0L,T1L,T2L,T3L; // Low byte tables.
+ __m128i T0H,T1H,T2H,T3H; // High byte tables.
+
+ for (uint I=0;I<16;I++)
+ {
+ ((byte *)&T0L)[I]=gfMul(I,M);
+ ((byte *)&T0H)[I]=gfMul(I,M)>>8;
+ ((byte *)&T1L)[I]=gfMul(I<<4,M);
+ ((byte *)&T1H)[I]=gfMul(I<<4,M)>>8;
+ ((byte *)&T2L)[I]=gfMul(I<<8,M);
+ ((byte *)&T2H)[I]=gfMul(I<<8,M)>>8;
+ ((byte *)&T3L)[I]=gfMul(I<<12,M);
+ ((byte *)&T3H)[I]=gfMul(I<<12,M)>>8;
+ }
+
+ size_t Pos=0;
+
+ __m128i LowByteMask=_mm_set1_epi16(0xff); // 00ff00ff...00ff
+ __m128i Low4Mask=_mm_set1_epi8(0xf); // 0f0f0f0f...0f0f
+ __m128i High4Mask=_mm_slli_epi16(Low4Mask,4); // f0f0f0f0...f0f0
+
+ for (; Pos<=BlockSize-2*sizeof(__m128i); Pos+=2*sizeof(__m128i))
+ {
+ // We process two 128 bit chunks of source data at once.
+ __m128i *D=(__m128i *)(Data+Pos);
+
+ // Place high bytes of both chunks to one variable and low bytes to
+ // another, so we can use the table lookup multiplication for 16 values
+ // 4 bit length each at once.
+ __m128i HighBytes0=_mm_srli_epi16(D[0],8);
+ __m128i LowBytes0=_mm_and_si128(D[0],LowByteMask);
+ __m128i HighBytes1=_mm_srli_epi16(D[1],8);
+ __m128i LowBytes1=_mm_and_si128(D[1],LowByteMask);
+ __m128i HighBytes=_mm_packus_epi16(HighBytes0,HighBytes1);
+ __m128i LowBytes=_mm_packus_epi16(LowBytes0,LowBytes1);
+
+ // Multiply bits 0..3 of low bytes. Store low and high product bytes
+ // separately in cumulative sum variables.
+ __m128i LowBytesLow4=_mm_and_si128(LowBytes,Low4Mask);
+ __m128i LowBytesMultSum=_mm_shuffle_epi8(T0L,LowBytesLow4);
+ __m128i HighBytesMultSum=_mm_shuffle_epi8(T0H,LowBytesLow4);
+
+ // Multiply bits 4..7 of low bytes. Store low and high product bytes separately.
+ __m128i LowBytesHigh4=_mm_and_si128(LowBytes,High4Mask);
+ LowBytesHigh4=_mm_srli_epi16(LowBytesHigh4,4);
+ __m128i LowBytesHigh4MultLow=_mm_shuffle_epi8(T1L,LowBytesHigh4);
+ __m128i LowBytesHigh4MultHigh=_mm_shuffle_epi8(T1H,LowBytesHigh4);
+
+ // Add new product to existing sum, low and high bytes separately.
+ LowBytesMultSum=_mm_xor_si128(LowBytesMultSum,LowBytesHigh4MultLow);
+ HighBytesMultSum=_mm_xor_si128(HighBytesMultSum,LowBytesHigh4MultHigh);
+
+ // Multiply bits 0..3 of high bytes. Store low and high product bytes separately.
+ __m128i HighBytesLow4=_mm_and_si128(HighBytes,Low4Mask);
+ __m128i HighBytesLow4MultLow=_mm_shuffle_epi8(T2L,HighBytesLow4);
+ __m128i HighBytesLow4MultHigh=_mm_shuffle_epi8(T2H,HighBytesLow4);
+
+ // Add new product to existing sum, low and high bytes separately.
+ LowBytesMultSum=_mm_xor_si128(LowBytesMultSum,HighBytesLow4MultLow);
+ HighBytesMultSum=_mm_xor_si128(HighBytesMultSum,HighBytesLow4MultHigh);
+
+ // Multiply bits 4..7 of high bytes. Store low and high product bytes separately.
+ __m128i HighBytesHigh4=_mm_and_si128(HighBytes,High4Mask);
+ HighBytesHigh4=_mm_srli_epi16(HighBytesHigh4,4);
+ __m128i HighBytesHigh4MultLow=_mm_shuffle_epi8(T3L,HighBytesHigh4);
+ __m128i HighBytesHigh4MultHigh=_mm_shuffle_epi8(T3H,HighBytesHigh4);
+
+ // Add new product to existing sum, low and high bytes separately.
+ LowBytesMultSum=_mm_xor_si128(LowBytesMultSum,HighBytesHigh4MultLow);
+ HighBytesMultSum=_mm_xor_si128(HighBytesMultSum,HighBytesHigh4MultHigh);
+
+ // Combine separate low and high cumulative sum bytes to 16-bit words.
+ __m128i HighBytesHigh4Mult0=_mm_unpacklo_epi8(LowBytesMultSum,HighBytesMultSum);
+ __m128i HighBytesHigh4Mult1=_mm_unpackhi_epi8(LowBytesMultSum,HighBytesMultSum);
+
+ // Add result to ECC.
+ __m128i *StoreECC=(__m128i *)(ECC+Pos);
+
+ StoreECC[0]=_mm_xor_si128(StoreECC[0],HighBytesHigh4Mult0);
+ StoreECC[1]=_mm_xor_si128(StoreECC[1],HighBytesHigh4Mult1);
+ }
+
+ // If we have non 128 bit aligned data in the end of block, process them
+ // in a usual way. We cannot do the same in the beginning of block,
+ // because Data and ECC can have different alignment offsets.
+ for (; Pos<BlockSize; Pos+=2)
+ *(ushort*)(ECC+Pos) ^= gfMul( M, *(ushort*)(Data+Pos) );
+
+ return true;
+}
+#endif
diff --git a/src/thirdparty/unrar/rs16.hpp b/src/thirdparty/unrar/rs16.hpp
new file mode 100644
index 000000000..ba518ac1d
--- /dev/null
+++ b/src/thirdparty/unrar/rs16.hpp
@@ -0,0 +1,42 @@
+#ifndef _RAR_RS16_
+#define _RAR_RS16_
+
+class RSCoder16
+{
+ private:
+ static const uint gfSize=65535; // Galois field size.
+ void gfInit(); // Galois field inititalization.
+ inline uint gfAdd(uint a,uint b); // Addition in Galois field.
+ inline uint gfMul(uint a,uint b); // Multiplication in Galois field.
+ inline uint gfInv(uint a); // Inverse element in Galois field.
+ uint *gfExp; // Galois field exponents.
+ uint *gfLog; // Galois field logarithms.
+
+ void MakeEncoderMatrix();
+ void MakeDecoderMatrix();
+ void InvertDecoderMatrix();
+
+#ifdef USE_SSE
+ bool SSE_UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte *ECC, size_t BlockSize);
+#endif
+
+ bool Decoding; // If we are decoding or encoding data.
+ uint ND; // Number of data units.
+ uint NR; // Number of Reed-Solomon code units.
+ uint NE; // Number of erasures.
+ bool *ValidFlags; // Validity flags for data and ECC units.
+ uint *MX; // Cauchy based coding or decoding matrix.
+
+ uint *DataLog; // Buffer to store data logarithms for UpdateECC.
+ size_t DataLogSize;
+
+ public:
+ RSCoder16();
+ ~RSCoder16();
+
+ bool Init(uint DataCount, uint RecCount, bool *ValidityFlags);
+ void Process(const uint *Data, uint *Out);
+ void UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte *ECC, size_t BlockSize);
+};
+
+#endif
diff --git a/src/thirdparty/unrar/savepos.cpp b/src/thirdparty/unrar/savepos.cpp
deleted file mode 100644
index e46c4e666..000000000
--- a/src/thirdparty/unrar/savepos.cpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "rar.hpp"
-
-SaveFilePos::SaveFilePos(File &SaveFile)
-{
- SaveFilePos::SaveFile=&SaveFile;
- SavePos=SaveFile.Tell();
- CloseCount=SaveFile.CloseCount;
-}
-
-
-SaveFilePos::~SaveFilePos()
-{
- if (CloseCount==SaveFile->CloseCount)
- SaveFile->Seek(SavePos,SEEK_SET);
-}
diff --git a/src/thirdparty/unrar/savepos.hpp b/src/thirdparty/unrar/savepos.hpp
index b3b237339..df617105c 100644
--- a/src/thirdparty/unrar/savepos.hpp
+++ b/src/thirdparty/unrar/savepos.hpp
@@ -6,10 +6,16 @@ class SaveFilePos
private:
File *SaveFile;
int64 SavePos;
- uint CloseCount;
public:
- SaveFilePos(File &SaveFile);
- ~SaveFilePos();
+ SaveFilePos(File &Src)
+ {
+ SaveFile=&Src;
+ SavePos=Src.Tell();
+ }
+ ~SaveFilePos()
+ {
+ SaveFile->Seek(SavePos,SEEK_SET);
+ }
};
#endif
diff --git a/src/thirdparty/unrar/scantree.cpp b/src/thirdparty/unrar/scantree.cpp
index 9fbfd10cd..5bf170504 100644
--- a/src/thirdparty/unrar/scantree.cpp
+++ b/src/thirdparty/unrar/scantree.cpp
@@ -11,7 +11,6 @@ ScanTree::ScanTree(StringList *FileMasks,RECURSE_MODE Recurse,bool GetLinks,SCAN
SetAllMaskDepth=0;
*CurMask=0;
- *CurMaskW=0;
memset(FindStack,0,sizeof(FindStack));
Depth=0;
Errors=0;
@@ -31,14 +30,14 @@ ScanTree::~ScanTree()
SCAN_CODE ScanTree::GetNext(FindData *FindData)
{
if (Depth<0)
- return(SCAN_DONE);
+ return SCAN_DONE;
SCAN_CODE FindCode;
while (1)
{
if (*CurMask==0 && !GetNextMask())
- return(SCAN_DONE);
+ return SCAN_DONE;
FindCode=FindProc(FindData);
@@ -61,20 +60,9 @@ SCAN_CODE ScanTree::GetNext(FindData *FindData)
bool ScanTree::GetNextMask()
{
- if (!FileMasks->GetString(CurMask,CurMaskW,ASIZE(CurMask)))
- return(false);
-
- if (*CurMask==0 && *CurMaskW!=0)
- {
- // Unicode only mask is present. It is very unlikely in console tools,
- // but possible if called from GUI WinRAR. We still need to have
- // ASCII mask, because we use ASCII only mask in some checks later.
- // So let's convert Unicode to ASCII.
- WideToChar(CurMaskW,CurMask,ASIZE(CurMask));
- }
-
+ if (!FileMasks->GetString(CurMask,ASIZE(CurMask)))
+ return false;
CurMask[ASIZE(CurMask)-1]=0;
- CurMaskW[ASIZE(CurMaskW)-1]=0;
#ifdef _WIN_ALL
UnixSlashToDos(CurMask);
#endif
@@ -84,65 +72,41 @@ bool ScanTree::GetNextMask()
// the root directory.
ScanEntireDisk=IsDiskLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0;
- char *Name=PointToName(CurMask);
+ wchar *Name=PointToName(CurMask);
if (*Name==0)
- strcat(CurMask,MASKALL);
+ wcsncatz(CurMask,MASKALL,ASIZE(CurMask));
if (Name[0]=='.' && (Name[1]==0 || Name[1]=='.' && Name[2]==0))
{
- AddEndSlash(CurMask);
- strcat(CurMask,MASKALL);
+ AddEndSlash(CurMask,ASIZE(CurMask));
+ wcsncatz(CurMask,MASKALL,ASIZE(CurMask));
}
SpecPathLength=Name-CurMask;
-
- bool WideName=(*CurMaskW!=0);
-
- if (WideName)
- {
- wchar *NameW=PointToName(CurMaskW);
- if (*NameW==0)
- wcscat(CurMaskW,MASKALLW);
- if (NameW[0]=='.' && (NameW[1]==0 || NameW[1]=='.' && NameW[2]==0))
- {
- AddEndSlash(CurMaskW);
- wcscat(CurMaskW,MASKALLW);
- }
- SpecPathLengthW=NameW-CurMaskW;
- }
- else
- {
- wchar WideMask[NM];
- CharToWide(CurMask,WideMask);
- SpecPathLengthW=PointToName(WideMask)-WideMask;
- }
Depth=0;
- strcpy(OrigCurMask,CurMask);
-
- // It is better to have non-empty OrigCurMaskW even if CurMaskW is empty.
- // We need OrigCurMaskW to process Unicode masks generated by FindProc
- // when encountering Unicode directory name.
- GetWideName(CurMask,CurMaskW,OrigCurMaskW,ASIZE(OrigCurMaskW));
+ wcscpy(OrigCurMask,CurMask);
- return(true);
+ return true;
}
SCAN_CODE ScanTree::FindProc(FindData *FD)
{
if (*CurMask==0)
- return(SCAN_NEXT);
+ return SCAN_NEXT;
bool FastFindFile=false;
if (FindStack[Depth]==NULL) // No FindFile object for this depth yet.
{
- bool Wildcards=IsWildcard(CurMask,CurMaskW);
+ bool Wildcards=IsWildcard(CurMask);
// If we have a file name without wildcards, we can try to use
// FastFind to optimize speed. For example, in Unix it results in
// stat call instead of opendir/readdir/closedir.
- bool FindCode=!Wildcards && FindFile::FastFind(CurMask,CurMaskW,FD,GetLinks);
+ bool FindCode=!Wildcards && FindFile::FastFind(CurMask,FD,GetLinks);
- bool IsDir=FindCode && FD->IsDir;
+ // Link check is important for NTFS, where links can have "Directory"
+ // attribute, but we do not want to recurse to them in "get links" mode.
+ bool IsDir=FindCode && FD->IsDir && (!GetLinks || !FD->IsLink);
// SearchAll means that we'll use "*" mask for search, so we'll find
// subdirectories and will be able to recurse into them.
@@ -157,19 +121,12 @@ SCAN_CODE ScanTree::FindProc(FindData *FD)
{
// Create the new FindFile object for wildcard based search.
FindStack[Depth]=new FindFile;
- char SearchMask[NM];
- strcpy(SearchMask,CurMask);
+
+ wchar SearchMask[NM];
+ wcsncpyz(SearchMask,CurMask,ASIZE(SearchMask));
if (SearchAll)
- strcpy(PointToName(SearchMask),MASKALL);
+ SetName(SearchMask,MASKALL,ASIZE(SearchMask));
FindStack[Depth]->SetMask(SearchMask);
- if (*CurMaskW!=0)
- {
- wchar SearchMaskW[NM];
- wcscpy(SearchMaskW,CurMaskW);
- if (SearchAll)
- wcscpy(PointToName(SearchMaskW),MASKALLW);
- FindStack[Depth]->SetMaskW(SearchMaskW);
- }
}
else
{
@@ -177,7 +134,7 @@ SCAN_CODE ScanTree::FindProc(FindData *FD)
// a directory in RECURSE_DISABLE mode, so we do not need to scan it.
// We can return here and do not need to process further.
// We need to process further only if we fast found a directory.
- if (!FindCode || !FD->IsDir || Recurse==RECURSE_DISABLE)
+ if (!FindCode || !IsDir || Recurse==RECURSE_DISABLE)
{
// Return SCAN_SUCCESS if we found a file.
SCAN_CODE RetCode=SCAN_SUCCESS;
@@ -193,7 +150,7 @@ SCAN_CODE ScanTree::FindProc(FindData *FD)
if (Cmd!=NULL && Cmd->ExclCheck(CurMask,false,true,true))
RetCode=SCAN_NEXT;
else
- ErrHandler.OpenErrorMsg(ErrArcName,NULL,CurMask,CurMaskW);
+ ErrHandler.OpenErrorMsg(ErrArcName,CurMask);
}
// If we searched only for one file or directory in "fast find"
@@ -204,9 +161,8 @@ SCAN_CODE ScanTree::FindProc(FindData *FD)
// mode, directory recursing will quit by (Depth < 0) condition,
// which returns SCAN_DONE to calling function.
*CurMask=0;
- *CurMaskW=0;
- return(RetCode);
+ return RetCode;
}
// We found a directory using only FindFile::FastFind function.
@@ -220,38 +176,11 @@ SCAN_CODE ScanTree::FindProc(FindData *FD)
// some error or just as result of all directory entries already read.
bool Error=FD->Error;
-
-#ifdef _WIN_ALL
- if (Error)
- {
- // Do not display an error if we cannot scan contents of reparse
- // point. Vista contains a lot of reparse (or junction) points,
- // which are not accessible.
- if ((FD->FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0)
- Error=false;
-
- // Do not display an error if we cannot scan contents of
- // "System Volume Information" folder. Normally it is not accessible.
- if (strstr(CurMask,"System Volume Information\\")!=NULL)
- Error=false;
- }
-#endif
-
- if (Error && Cmd!=NULL && Cmd->ExclCheck(CurMask,false,true,true))
- Error=false;
-
-#ifndef SILENT
if (Error)
- {
- Log(NULL,St(MScanError),CurMask);
- ErrHandler.SysErrMsg();
- }
-#endif
+ ScanError(Error);
- char DirName[NM];
- wchar DirNameW[NM];
+ wchar DirName[NM];
*DirName=0;
- *DirNameW=0;
// Going to at least one directory level higher.
delete FindStack[Depth];
@@ -265,68 +194,35 @@ SCAN_CODE ScanTree::FindProc(FindData *FD)
if (Error)
Errors++;
- return(SCAN_DONE);
+ return SCAN_DONE;
}
- char *Slash=strrchrd(CurMask,CPATHDIVIDER);
+
+ wchar *Slash=wcsrchr(CurMask,CPATHDIVIDER);
if (Slash!=NULL)
{
- char Mask[NM];
- strcpy(Mask,Slash);
+ wchar Mask[NM];
+ wcscpy(Mask,Slash);
if (Depth<SetAllMaskDepth)
- strcpy(Mask+1,PointToName(OrigCurMask));
+ wcscpy(Mask+1,PointToName(OrigCurMask));
*Slash=0;
- strcpy(DirName,CurMask);
- char *PrevSlash=strrchrd(CurMask,CPATHDIVIDER);
+ wcscpy(DirName,CurMask);
+ wchar *PrevSlash=wcsrchr(CurMask,CPATHDIVIDER);
if (PrevSlash==NULL)
- strcpy(CurMask,Mask+1);
+ wcscpy(CurMask,Mask+1);
else
- strcpy(PrevSlash,Mask);
- }
-
- if (*CurMaskW!=0)
- {
- wchar *Slash=wcsrchr(CurMaskW,CPATHDIVIDER);
- if (Slash!=NULL)
- {
- wchar Mask[NM];
- wcscpy(Mask,Slash);
- if (Depth<SetAllMaskDepth)
- {
- wcscpy(Mask+1,PointToName(OrigCurMaskW));
-
- // FindProc function can generate Unicode CurMaskW when encountering
- // Unicode directory name even if Unicode mask was not specified.
- // But we must reset such temporary mask here if OrigCurMaskW is
- // empty, because we cannot shorten it correctly. It should not
- // happen normally though, because we attempt to ensure that
- // OrigCurMaskW is not empty. So it can happen only if converting
- // OrigCurMask to OrigCurMaskW has been failed.
- if (*OrigCurMaskW==0)
- *CurMaskW=Mask[0]=Mask[1]=0;
- }
- *Slash=0;
- wcscpy(DirNameW,CurMaskW);
- wchar *PrevSlash=wcsrchr(CurMaskW,CPATHDIVIDER);
- if (PrevSlash==NULL)
- wcscpy(CurMaskW,Mask+1);
- else
- wcscpy(PrevSlash,Mask);
- }
-#ifndef _WIN_CE
-// if (LowAscii(CurMaskW))
-// *CurMaskW=0;
-#endif
+ wcscpy(PrevSlash,Mask);
}
if (GetDirs==SCAN_GETDIRSTWICE &&
- FindFile::FastFind(DirName,DirNameW,FD,GetLinks) && FD->IsDir)
+ FindFile::FastFind(DirName,FD,GetLinks) && FD->IsDir)
{
FD->Flags|=FDDF_SECONDDIR;
- return(Error ? SCAN_ERROR:SCAN_SUCCESS);
+ return Error ? SCAN_ERROR:SCAN_SUCCESS;
}
- return(Error ? SCAN_ERROR:SCAN_NEXT);
+ return Error ? SCAN_ERROR:SCAN_NEXT;
}
- if (FD->IsDir)
+ // Link check is required for NTFS links, not for Unix.
+ if (FD->IsDir && (!GetLinks || !FD->IsLink))
{
// If we found the directory in top (Depth==0) directory
// and if we are not in "fast find" (directory name only as argument)
@@ -334,7 +230,7 @@ SCAN_CODE ScanTree::FindProc(FindData *FD)
// we do not recurse into this directory. We either return it by itself
// or skip it.
if (!FastFindFile && Depth==0 && !SearchAllInRoot)
- return(GetDirs==SCAN_GETCURDIRS ? SCAN_SUCCESS:SCAN_NEXT);
+ return GetDirs==SCAN_GETCURDIRS ? SCAN_SUCCESS:SCAN_NEXT;
// Let's check if directory name is excluded, so we do not waste
// time searching in directory, which will be excluded anyway.
@@ -347,42 +243,26 @@ SCAN_CODE ScanTree::FindProc(FindData *FD)
// in GetNext() function. Such loop would be possible in case of
// SCAN_NEXT code and "rar a arc dir -xdir" command.
- return(FastFindFile ? SCAN_DONE:SCAN_NEXT);
+ return FastFindFile ? SCAN_DONE:SCAN_NEXT;
}
- char Mask[NM];
+ wchar Mask[NM];
- strcpy(Mask,FastFindFile ? MASKALL:PointToName(CurMask));
- strcpy(CurMask,FD->Name);
+ wcscpy(Mask,FastFindFile ? MASKALL:PointToName(CurMask));
+ wcscpy(CurMask,FD->Name);
- if (strlen(CurMask)+strlen(Mask)+1>=NM || Depth>=MAXSCANDEPTH-1)
+ if (wcslen(CurMask)+wcslen(Mask)+1>=NM || Depth>=MAXSCANDEPTH-1)
{
#ifndef SILENT
- Log(NULL,"\n%s%c%s",CurMask,CPATHDIVIDER,Mask);
+ Log(NULL,L"\n%ls%c%ls",CurMask,CPATHDIVIDER,Mask);
Log(NULL,St(MPathTooLong));
#endif
- return(SCAN_ERROR);
+ return SCAN_ERROR;
}
- AddEndSlash(CurMask);
- strcat(CurMask,Mask);
+ AddEndSlash(CurMask,ASIZE(CurMask));
+ wcsncatz(CurMask,Mask,ASIZE(CurMask));
- if (*CurMaskW!=0 && *FD->NameW==0)
- CharToWide(FD->Name,FD->NameW);
- if (*FD->NameW!=0)
- {
- wchar Mask[NM];
- if (FastFindFile)
- wcscpy(Mask,MASKALLW);
- else
- if (*CurMaskW!=0)
- wcscpy(Mask,PointToName(CurMaskW));
- else
- CharToWide(PointToName(CurMask),Mask);
- wcscpy(CurMaskW,FD->NameW);
- AddEndSlash(CurMaskW);
- wcscat(CurMaskW,Mask);
- }
Depth++;
// We need to use OrigCurMask for depths less than SetAllMaskDepth
@@ -407,7 +287,52 @@ SCAN_CODE ScanTree::FindProc(FindData *FD)
SetAllMaskDepth=Depth;
}
if (!FastFindFile && !CmpName(CurMask,FD->Name,MATCH_NAMES))
- return(SCAN_NEXT);
+ return SCAN_NEXT;
+
+ return SCAN_SUCCESS;
+}
+
- return(SCAN_SUCCESS);
+void ScanTree::ScanError(bool &Error)
+{
+#ifdef _WIN_ALL
+ if (Error)
+ {
+ // Get attributes of parent folder and do not display an error
+ // if it is reparse point. We cannot scan contents of standard
+ // Windows reparse points like "C:\Documents and Settings"
+ // and we do not want to issue numerous useless errors for them.
+ // We cannot just check FD->FileAttr here, it can be undefined
+ // if we process "folder\*" mask or if we process "folder" mask,
+ // but "folder" is inaccessible.
+ wchar *Slash=PointToName(CurMask);
+ if (Slash>CurMask)
+ {
+ *(Slash-1)=0;
+ DWORD Attr=GetFileAttributes(CurMask);
+ *(Slash-1)=CPATHDIVIDER;
+ if (Attr!=0xffffffff && (Attr & FILE_ATTRIBUTE_REPARSE_POINT)!=0)
+ Error=false;
+ }
+
+ // Do not display an error if we cannot scan contents of
+ // "System Volume Information" folder. Normally it is not accessible.
+ if (wcsstr(CurMask,L"System Volume Information\\")!=NULL)
+ Error=false;
+ }
+#endif
+
+ if (Error && Cmd!=NULL && Cmd->ExclCheck(CurMask,false,true,true))
+ Error=false;
+
+#ifndef SILENT
+ if (Error)
+ {
+ wchar FullName[NM];
+ // This conversion works for wildcard masks too.
+ ConvertNameToFull(CurMask,FullName,ASIZE(FullName));
+ Log(NULL,St(MScanError),FullName);
+ ErrHandler.SysErrMsg();
+ }
+#endif
}
diff --git a/src/thirdparty/unrar/scantree.hpp b/src/thirdparty/unrar/scantree.hpp
index 33a6d4678..7ed9a3833 100644
--- a/src/thirdparty/unrar/scantree.hpp
+++ b/src/thirdparty/unrar/scantree.hpp
@@ -20,6 +20,7 @@ class ScanTree
private:
bool GetNextMask();
SCAN_CODE FindProc(FindData *FD);
+ void ScanError(bool &Error);
FindFile *FindStack[MAXSCANDEPTH];
int Depth;
@@ -35,25 +36,21 @@ class ScanTree
// set when processing paths like c:\ (root directory without wildcards)
bool ScanEntireDisk;
- char CurMask[NM];
- wchar CurMaskW[NM];
- char OrigCurMask[NM];
- wchar OrigCurMaskW[NM];
+ wchar CurMask[NM];
+ wchar OrigCurMask[NM];
bool SearchAllInRoot;
size_t SpecPathLength;
- size_t SpecPathLengthW;
- char ErrArcName[NM];
+ wchar ErrArcName[NM];
CommandData *Cmd;
public:
ScanTree(StringList *FileMasks,RECURSE_MODE Recurse,bool GetLinks,SCAN_DIRS GetDirs);
~ScanTree();
SCAN_CODE GetNext(FindData *FindData);
- size_t GetSpecPathLength() {return(SpecPathLength);};
- size_t GetSpecPathLengthW() {return(SpecPathLengthW);};
- int GetErrors() {return(Errors);};
- void SetErrArcName(const char *Name) {strcpy(ErrArcName,Name);}
+ size_t GetSpecPathLength() {return SpecPathLength;};
+ int GetErrors() {return Errors;};
+ void SetErrArcName(const wchar *Name) {wcsncpyz(ErrArcName,Name,ASIZE(ErrArcName));}
void SetCommandData(CommandData *Cmd) {ScanTree::Cmd=Cmd;}
};
diff --git a/src/thirdparty/unrar/secpassword.cpp b/src/thirdparty/unrar/secpassword.cpp
index 016e1360c..ba7152595 100644
--- a/src/thirdparty/unrar/secpassword.cpp
+++ b/src/thirdparty/unrar/secpassword.cpp
@@ -94,58 +94,12 @@ void cleandata(void *data,size_t size)
// people share the same computer and somebody left WinRAR copy with entered
// password. So we decided to obfuscate the password to make it more difficult
// to find it in dump.
-void SecPassword::Process(const wchar *Src,wchar *Dst,size_t MaxSize,bool Encode)
+void SecPassword::Process(const wchar *Src,size_t SrcSize,wchar *Dst,size_t DstSize,bool Encode)
{
-#ifdef _WIN_ALL
- // Try to utilize the secure Crypt[Un]ProtectMemory if possible.
- if (GlobalCryptLoader.pCryptProtectMemory==NULL)
- GlobalCryptLoader.Load();
- if (Encode)
- {
- if (GlobalCryptLoader.pCryptProtectMemory!=NULL &&
- MaxSize%CRYPTPROTECTMEMORY_BLOCK_SIZE==0)
- {
- memcpy(Dst,Src,MaxSize*sizeof(*Dst));
- if (!GlobalCryptLoader.pCryptProtectMemory(Dst,DWORD(MaxSize*sizeof(*Dst)),
- CRYPTPROTECTMEMORY_SAME_PROCESS))
- {
- ErrHandler.GeneralErrMsg("CryptProtectMemory failed");
- ErrHandler.SysErrMsg();
- ErrHandler.Exit(RARX_FATAL);
- }
- return;
- }
- }
- else
- {
- if (GlobalCryptLoader.pCryptUnprotectMemory!=NULL &&
- MaxSize%CRYPTPROTECTMEMORY_BLOCK_SIZE==0)
- {
- memcpy(Dst,Src,MaxSize*sizeof(*Dst));
- if (!GlobalCryptLoader.pCryptUnprotectMemory(Dst,DWORD(MaxSize*sizeof(*Dst)),
- CRYPTPROTECTMEMORY_SAME_PROCESS))
- {
- ErrHandler.GeneralErrMsg("CryptUnprotectMemory failed");
- ErrHandler.SysErrMsg();
- ErrHandler.Exit(RARX_FATAL);
- }
- return;
- }
- }
-#endif
-
- // CryptProtectMemory is not available, so only slightly obfuscate data.
- uint Key;
-#ifdef _WIN_ALL
- Key=GetCurrentProcessId();
-#elif defined(_UNIX)
- Key=getpid();
-#else
- Key=10203040; // Just an arbitrary value.
-#endif
-
- for (size_t I=0;I<MaxSize;I++)
- Dst[I]=wchar(Src[I]^(Key+I+75));
+ // Source string can be shorter than destination as in case when we process
+ // -p<pwd> parameter, so we need to take into account both sizes.
+ memcpy(Dst,Src,Min(SrcSize,DstSize)*sizeof(*Dst));
+ SecHideData(Dst,DstSize*sizeof(*Dst),Encode);
}
@@ -153,7 +107,7 @@ void SecPassword::Get(wchar *Psw,size_t MaxSize)
{
if (PasswordSet)
{
- Process(Password,Psw,MaxSize,false);
+ Process(Password,ASIZE(Password),Psw,MaxSize,false);
Psw[MaxSize-1]=0;
}
else
@@ -171,7 +125,7 @@ void SecPassword::Set(const wchar *Psw)
else
{
PasswordSet=true;
- Process(Psw,Password,ASIZE(Password),true);
+ Process(Psw,wcslen(Psw)+1,Password,ASIZE(Password),true);
}
}
@@ -201,3 +155,52 @@ bool SecPassword::operator == (SecPassword &psw)
return Result;
}
+
+void SecHideData(void *Data,size_t DataSize,bool Encode)
+{
+#ifdef _WIN_ALL
+ // Try to utilize the secure Crypt[Un]ProtectMemory if possible.
+ if (GlobalCryptLoader.pCryptProtectMemory==NULL)
+ GlobalCryptLoader.Load();
+ size_t Aligned=DataSize-DataSize%CRYPTPROTECTMEMORY_BLOCK_SIZE;
+ if (Encode)
+ {
+ if (GlobalCryptLoader.pCryptProtectMemory!=NULL)
+ {
+ if (!GlobalCryptLoader.pCryptProtectMemory(Data,DWORD(Aligned),CRYPTPROTECTMEMORY_SAME_PROCESS))
+ {
+ ErrHandler.GeneralErrMsg(L"CryptProtectMemory failed");
+ ErrHandler.SysErrMsg();
+ ErrHandler.Exit(RARX_FATAL);
+ }
+ return;
+ }
+ }
+ else
+ {
+ if (GlobalCryptLoader.pCryptUnprotectMemory!=NULL)
+ {
+ if (!GlobalCryptLoader.pCryptUnprotectMemory(Data,DWORD(Aligned),CRYPTPROTECTMEMORY_SAME_PROCESS))
+ {
+ ErrHandler.GeneralErrMsg(L"CryptUnprotectMemory failed");
+ ErrHandler.SysErrMsg();
+ ErrHandler.Exit(RARX_FATAL);
+ }
+ return;
+ }
+ }
+#endif
+
+ // CryptProtectMemory is not available, so only slightly obfuscate data.
+ uint Key;
+#ifdef _WIN_ALL
+ Key=GetCurrentProcessId();
+#elif defined(_UNIX)
+ Key=getpid();
+#else
+ Key=0; // Just an arbitrary value.
+#endif
+
+ for (size_t I=0;I<DataSize;I++)
+ *((byte *)Data+I)^=Key+I+75;
+}
diff --git a/src/thirdparty/unrar/secpassword.hpp b/src/thirdparty/unrar/secpassword.hpp
index b93d97bc3..7e166a23b 100644
--- a/src/thirdparty/unrar/secpassword.hpp
+++ b/src/thirdparty/unrar/secpassword.hpp
@@ -6,7 +6,7 @@
class SecPassword
{
private:
- void Process(const wchar *Src,wchar *Dst,size_t MaxSize,bool Encode);
+ void Process(const wchar *Src,size_t SrcSize,wchar *Dst,size_t DstSize,bool Encode);
wchar Password[MAXPASSWORD];
@@ -26,5 +26,6 @@ class SecPassword
void cleandata(void *data,size_t size);
+void SecHideData(void *Data,size_t DataSize,bool Encode);
#endif
diff --git a/src/thirdparty/unrar/sha256.cpp b/src/thirdparty/unrar/sha256.cpp
new file mode 100644
index 000000000..49859c0f8
--- /dev/null
+++ b/src/thirdparty/unrar/sha256.cpp
@@ -0,0 +1,175 @@
+#include "rar.hpp"
+#include "sha256.hpp"
+
+static const uint32 K[64] =
+{
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+#define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
+
+// SHA-256 functions. We could optimize Ch and Maj a little,
+// but with no visible speed benefit.
+#define Ch(x, y, z) ((x & y) ^ (~x & z))
+#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
+
+// Sigma functions.
+#define Sg0(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x, 22))
+#define Sg1(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x, 25))
+#define sg0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ (x >> 3))
+#define sg1(x) (ROTR(x,17) ^ ROTR(x,19) ^ (x >> 10))
+
+void sha256_init(sha256_context *ctx)
+{
+ ctx->H[0] = 0x6a09e667; // Set the initial hash value.
+ ctx->H[1] = 0xbb67ae85;
+ ctx->H[2] = 0x3c6ef372;
+ ctx->H[3] = 0xa54ff53a;
+ ctx->H[4] = 0x510e527f;
+ ctx->H[5] = 0x9b05688c;
+ ctx->H[6] = 0x1f83d9ab;
+ ctx->H[7] = 0x5be0cd19;
+ ctx->Count = 0; // Processed data counter.
+}
+
+
+inline uint32 b2i(const byte *b) // Big endian bytes to integer.
+{
+#if defined(_MSC_VER)/* && defined(LITTLE_ENDIAN)*/
+ return _byteswap_ulong(*(uint32 *)b);
+#else
+ return uint32(b[0]<<24) | uint32(b[1]<<16) | uint32(b[2]<<8) | b[3];
+#endif
+}
+
+
+static void sha256_transform(sha256_context *ctx)
+{
+ uint32 W[64]; // Words of message schedule.
+ uint32 v[8]; // FIPS a, b, c, d, e, f, g, h working variables.
+
+ if (ctx == NULL) // Clean variables and return.
+ {
+ cleandata(v,sizeof(v));
+ cleandata(W,sizeof(W));
+ return;
+ }
+
+ // Prepare message schedule. Loop unrolling provides some small gain here.
+ W[0] = b2i(ctx->Data + 0 * 4 ); W[1] = b2i(ctx->Data + 1 * 4 );
+ W[2] = b2i(ctx->Data + 2 * 4 ); W[3] = b2i(ctx->Data + 3 * 4 );
+ W[4] = b2i(ctx->Data + 4 * 4 ); W[5] = b2i(ctx->Data + 5 * 4 );
+ W[6] = b2i(ctx->Data + 6 * 4 ); W[7] = b2i(ctx->Data + 7 * 4 );
+ W[8] = b2i(ctx->Data + 8 * 4 ); W[9] = b2i(ctx->Data + 9 * 4 );
+ W[10] = b2i(ctx->Data + 10 * 4 ); W[11] = b2i(ctx->Data + 11 * 4 );
+ W[12] = b2i(ctx->Data + 12 * 4 ); W[13] = b2i(ctx->Data + 13 * 4 );
+ W[14] = b2i(ctx->Data + 14 * 4 ); W[15] = b2i(ctx->Data + 15 * 4 );
+
+ for (uint I = 16; I < 64; I++)
+ W[I] = sg1(W[I-2]) + W[I-7] + sg0(W[I-15]) + W[I-16];
+
+ uint32 *H=ctx->H;
+ v[0]=H[0]; v[1]=H[1]; v[2]=H[2]; v[3]=H[3];
+ v[4]=H[4]; v[5]=H[5]; v[6]=H[6]; v[7]=H[7];
+
+ // MSVC -O2 partially unrolls this loop automatically.
+ for (uint I = 0; I < 64; I++)
+ {
+ uint T1 = v[7] + Sg1(v[4]) + Ch(v[4], v[5], v[6]) + K[I] + W[I];
+
+ // It is possible to eliminate variable copying if we unroll loop
+ // and rename variables every time. But my test did not show any speed
+ // gain on i7 for such full or partial unrolling.
+ v[7] = v[6];
+ v[6] = v[5];
+ v[5] = v[4];
+ v[4] = v[3] + T1;
+
+ // It works a little faster when moved here from beginning of loop.
+ uint T2 = Sg0(v[0]) + Maj(v[0], v[1], v[2]);
+
+ v[3] = v[2];
+ v[2] = v[1];
+ v[1] = v[0];
+ v[0] = T1 + T2;
+ }
+
+ H[0]+=v[0]; H[1]+=v[1]; H[2]+=v[2]; H[3]+=v[3];
+ H[4]+=v[4]; H[5]+=v[5]; H[6]+=v[6]; H[7]+=v[7];
+}
+
+
+void sha256_process(sha256_context *ctx, const void *Data, size_t Size)
+{
+ const byte *Src=(const byte *)Data;
+ size_t BufPos = (uint)ctx->Count & 0x3f;
+ ctx->Count+=Size;
+ while (Size > 0)
+ {
+ size_t BufSpace=sizeof(ctx->Buffer)-BufPos;
+ size_t CopySize=Size>BufSpace ? BufSpace:Size;
+
+ if (CopySize == 64)
+ ctx->Data=Src; // Point to source data instead of copying it to buffer.
+ else
+ {
+ ctx->Data=ctx->Buffer;
+ memcpy(ctx->Buffer+BufPos,Src,CopySize);
+ }
+ Src+=CopySize;
+ BufPos+=CopySize;
+ Size-=CopySize;
+ if (BufPos == 64)
+ {
+ BufPos = 0;
+ sha256_transform(ctx);
+ }
+ }
+ sha256_transform(NULL);
+}
+
+
+void sha256_done(sha256_context *ctx, byte *Digest)
+{
+ ctx->Data = ctx->Buffer;
+ uint64 BitLength = ctx->Count * 8;
+ uint BufPos = (uint)ctx->Count & 0x3f;
+ ctx->Buffer[BufPos++] = 0x80; // Padding the message with "1" bit.
+ while (BufPos != 56) // We need 56 bytes block followed by 8 byte length.
+ {
+ BufPos &= 0x3f;
+ if (BufPos == 0)
+ sha256_transform(ctx);
+ ctx->Buffer[BufPos++] = 0;
+ }
+
+ for (uint i = 0; i < 8; i++) // Store bit length of entire message.
+ {
+ ctx->Buffer[BufPos++] = (byte)(BitLength >> 56);
+ BitLength <<= 8;
+ }
+ sha256_transform(ctx);
+
+ for (uint i = 0; i < 32; i++)
+ Digest[i] = byte(ctx->H[i / 4] >> ((3 - i % 4) * 8));
+
+ sha256_init(ctx);
+ sha256_transform(NULL);
+ cleandata(ctx->Buffer, sizeof(ctx->Buffer));
+}
diff --git a/src/thirdparty/unrar/sha256.hpp b/src/thirdparty/unrar/sha256.hpp
new file mode 100644
index 000000000..fd3bddd83
--- /dev/null
+++ b/src/thirdparty/unrar/sha256.hpp
@@ -0,0 +1,22 @@
+#ifndef _RAR_SHA256_
+#define _RAR_SHA256_
+
+#ifndef PRESENT_INT32
+#error 32-bit integer type is required for SHA-256.
+#endif
+
+#define SHA256_DIGEST_SIZE 32
+
+typedef struct
+{
+ uint32 H[8];
+ uint64 Count;
+ const byte *Data;
+ byte Buffer[64];
+} sha256_context;
+
+void sha256_init(sha256_context *ctx);
+void sha256_process(sha256_context *ctx, const void *Data, size_t Size);
+void sha256_done(sha256_context *ctx, byte *Digest);
+
+#endif
diff --git a/src/thirdparty/unrar/smallfn.cpp b/src/thirdparty/unrar/smallfn.cpp
index f7d6fa162..5b5e6f66b 100644
--- a/src/thirdparty/unrar/smallfn.cpp
+++ b/src/thirdparty/unrar/smallfn.cpp
@@ -15,28 +15,3 @@ int ToPercentUnlim(int64 N1,int64 N2)
return(0);
return((int)(N1*100/N2));
}
-
-
-void RARInitData()
-{
- InitCRC();
- ErrHandler.Clean();
-}
-
-
-#ifdef _DJGPP
-// Disable wildcard expansion in DJGPP DOS SFX module.
-extern "C" char **__crt0_glob_function (char *arg)
-{
- return 0;
-}
-#endif
-
-
-#ifdef _DJGPP
-// Disable environments variable loading in DJGPP DOS SFX module
-// to reduce the module size.
-extern "C" void __crt0_load_environment_file (char *progname)
-{
-}
-#endif
diff --git a/src/thirdparty/unrar/strfn.cpp b/src/thirdparty/unrar/strfn.cpp
index faf48e8ed..eb72348bf 100644
--- a/src/thirdparty/unrar/strfn.cpp
+++ b/src/thirdparty/unrar/strfn.cpp
@@ -12,93 +12,64 @@ const wchar *NullToEmpty(const wchar *Str)
}
-
-
-char *IntNameToExt(const char *Name)
-{
- static char OutName[NM];
- IntToExt(Name,OutName);
- return(OutName);
-}
-
-
-void ExtToInt(const char *Src,char *Dest)
-{
-#ifdef _WIN_ALL
- CharToOemA(Src,Dest);
-#else
- if (Dest!=Src)
- strcpy(Dest,Src);
-#endif
-}
-
-
-void IntToExt(const char *Src,char *Dest)
+void IntToExt(const char *Src,char *Dest,size_t DestSize)
{
#ifdef _WIN_ALL
- OemToCharA(Src,Dest);
+ OemToCharBuffA(Src,Dest,(DWORD)DestSize);
+ Dest[DestSize-1]=0;
#else
if (Dest!=Src)
- strcpy(Dest,Src);
+ strncpyz(Dest,Src,DestSize);
#endif
}
-char* strlower(char *Str)
+int stricomp(const char *s1,const char *s2)
{
#ifdef _WIN_ALL
- CharLowerA((LPSTR)Str);
+ return(CompareStringA(LOCALE_USER_DEFAULT,NORM_IGNORECASE|SORT_STRINGSORT,s1,-1,s2,-1)-2);
#else
- for (char *ChPtr=Str;*ChPtr;ChPtr++)
- *ChPtr=(char)loctolower(*ChPtr);
+ while (toupper(*s1)==toupper(*s2))
+ {
+ if (*s1==0)
+ return 0;
+ s1++;
+ s2++;
+ }
+ return s1 < s2 ? -1 : 1;
#endif
- return(Str);
}
-char* strupper(char *Str)
+int strnicomp(const char *s1,const char *s2,size_t n)
{
#ifdef _WIN_ALL
- CharUpperA((LPSTR)Str);
+ // If we specify 'n' exceeding the actual string length, CompareString goes
+ // beyond the trailing zero and compares garbage. So we need to limit 'n'
+ // to real string length.
+ size_t l1=Min(strlen(s1)+1,n);
+ size_t l2=Min(strlen(s2)+1,n);
+ return(CompareStringA(LOCALE_USER_DEFAULT,NORM_IGNORECASE|SORT_STRINGSORT,s1,(int)l1,s2,(int)l2)-2);
#else
- for (char *ChPtr=Str;*ChPtr;ChPtr++)
- *ChPtr=(char)loctoupper(*ChPtr);
+ if (n==0)
+ return 0;
+ while (toupper(*s1)==toupper(*s2))
+ {
+ if (*s1==0 || --n==0)
+ return 0;
+ s1++;
+ s2++;
+ }
+ return s1 < s2 ? -1 : 1;
#endif
- return(Str);
-}
-
-
-int stricomp(const char *Str1,const char *Str2)
-{
- char S1[NM*2],S2[NM*2];
- strncpyz(S1,Str1,ASIZE(S1));
- strncpyz(S2,Str2,ASIZE(S2));
- return(strcmp(strupper(S1),strupper(S2)));
}
-int strnicomp(const char *Str1,const char *Str2,size_t N)
+wchar* RemoveEOL(wchar *Str)
{
- char S1[NM*2],S2[NM*2];
- strncpyz(S1,Str1,ASIZE(S1));
- strncpyz(S2,Str2,ASIZE(S2));
- return(strncmp(strupper(S1),strupper(S2),N));
-}
-
-
-char* RemoveEOL(char *Str)
-{
- for (int I=(int)strlen(Str)-1;I>=0 && (Str[I]=='\r' || Str[I]=='\n' || Str[I]==' ' || Str[I]=='\t');I--)
- Str[I]=0;
- return(Str);
-}
-
-
-char* RemoveLF(char *Str)
-{
- for (int I=(int)strlen(Str)-1;I>=0 && (Str[I]=='\r' || Str[I]=='\n');I--)
+ for (int I=(int)wcslen(Str)-1;I>=0 && (Str[I]=='\r' || Str[I]=='\n' || Str[I]==' ' || Str[I]=='\t');I--)
Str[I]=0;
- return(Str);
+ return Str;
}
@@ -185,6 +156,33 @@ bool IsAlpha(int ch)
+void BinToHex(const byte *Bin,size_t BinSize,char *HexA,wchar *HexW,size_t HexSize)
+{
+ uint A=0,W=0; // ASCII and Unicode hex output positions.
+ for (uint I=0;I<BinSize;I++)
+ {
+ uint High=Bin[I] >> 4;
+ uint Low=Bin[I] & 0xf;
+ uint HighHex=High>9 ? 'a'+High-10:'0'+High;
+ uint LowHex=Low>9 ? 'a'+Low-10:'0'+Low;
+ if (HexA!=NULL && A<HexSize-2) // Need space for 2 chars and final zero.
+ {
+ HexA[A++]=(char)HighHex;
+ HexA[A++]=(char)LowHex;
+ }
+ if (HexW!=NULL && W<HexSize-2) // Need space for 2 chars and final zero.
+ {
+ HexW[W++]=HighHex;
+ HexW[W++]=LowHex;
+ }
+ }
+ if (HexA!=NULL && HexSize>0)
+ HexA[A]=0;
+ if (HexW!=NULL && HexSize>0)
+ HexW[W]=0;
+}
+
+
#ifndef SFX_MODULE
uint GetDigits(uint Number)
{
@@ -221,19 +219,6 @@ bool LowAscii(const wchar *Str)
}
-
-
-int stricompc(const char *Str1,const char *Str2)
-{
-#if defined(_UNIX)
- return(strcmp(Str1,Str2));
-#else
- return(stricomp(Str1,Str2));
-#endif
-}
-
-
-#ifndef SFX_MODULE
int wcsicompc(const wchar *Str1,const wchar *Str2)
{
#if defined(_UNIX)
@@ -242,7 +227,6 @@ int wcsicompc(const wchar *Str1,const wchar *Str2)
return(wcsicomp(Str1,Str2));
#endif
}
-#endif
// safe strncpy: copies maxlen-1 max and always returns zero terminated dest
@@ -265,7 +249,7 @@ wchar* wcsncpyz(wchar *dest, const wchar *src, size_t maxlen)
wcsncpy(dest,src,maxlen-1);
dest[maxlen-1]=0;
}
- return(dest);
+ return dest;
}
@@ -310,19 +294,6 @@ void itoa(int64 n,char *Str)
}
-
-int64 atoil(const char *Str)
-{
- int64 n=0;
- while (*Str>='0' && *Str<='9')
- {
- n=n*10+*Str-'0';
- Str++;
- }
- return(n);
-}
-
-
void itoa(int64 n,wchar *Str)
{
wchar NumStr[50];
@@ -340,18 +311,6 @@ void itoa(int64 n,wchar *Str)
}
-int64 atoil(const wchar *Str)
-{
- int64 n=0;
- while (*Str>='0' && *Str<='9')
- {
- n=n*10+*Str-'0';
- Str++;
- }
- return(n);
-}
-
-
const wchar* GetWide(const char *Src)
{
const size_t MaxLength=NM;
@@ -366,15 +325,6 @@ const wchar* GetWide(const char *Src)
}
-const wchar* GetWide(const char *Src,const wchar *SrcW)
-{
- if (SrcW!=NULL && *SrcW!=0)
- return SrcW;
- return GetWide(Src);
-}
-
-
-#ifdef _WIN_ALL
// Parse string containing parameters separated with spaces.
// Support quote marks. Param can be NULL to return the pointer to next
// parameter, which can be used to estimate the buffer size for Param.
@@ -410,4 +360,50 @@ const wchar* GetCmdParam(const wchar *CmdLine,wchar *Param,size_t MaxSize)
Param[ParamSize]=0;
return CmdLine;
}
+
+
+#ifndef SILENT
+// For compatibility with existing translations we use %s to print Unicode
+// strings in format strings and convert them to %ls here. %s could work
+// without such conversion in Windows, but not in Unix wprintf.
+void PrintfPrepareFmt(const wchar *Org,wchar *Cvt,size_t MaxSize)
+{
+ uint Src=0,Dest=0;
+ while (Org[Src]!=0 && Dest<MaxSize-1)
+ {
+ if (Org[Src]=='%' && (Src==0 || Org[Src-1]!='%'))
+ {
+ uint SPos=Src+1;
+ // Skipping a possible width specifier like %-50s.
+ while (IsDigit(Org[SPos]) || Org[SPos]=='-')
+ SPos++;
+ if (Org[SPos]=='s' && Dest<MaxSize-(SPos-Src+1))
+ {
+ while (Src<SPos)
+ Cvt[Dest++]=Org[Src++];
+ Cvt[Dest++]='l';
+ }
+ }
+#ifdef _WIN_ALL
+ // Convert \n to \r\n in Windows. Important when writing to log,
+ // so other tools like Notebook can view resulting log properly.
+ if (Org[Src]=='\n' && (Src==0 || Org[Src-1]!='\r'))
+ Cvt[Dest++]='\r';
+#endif
+
+ Cvt[Dest++]=Org[Src++];
+ }
+ Cvt[Dest]=0;
+}
+#endif
+
+
+bool GetPassword(PASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
+{
+#ifdef SILENT
+ return false;
+#else
+ return GetConsolePassword(Type,FileName,Password);
#endif
+}
+
diff --git a/src/thirdparty/unrar/strfn.hpp b/src/thirdparty/unrar/strfn.hpp
index 9d7fee899..56e076de8 100644
--- a/src/thirdparty/unrar/strfn.hpp
+++ b/src/thirdparty/unrar/strfn.hpp
@@ -3,15 +3,10 @@
const char* NullToEmpty(const char *Str);
const wchar* NullToEmpty(const wchar *Str);
-char* IntNameToExt(const char *Name);
-void ExtToInt(const char *Src,char *Dest);
-void IntToExt(const char *Src,char *Dest);
-char* strlower(char *Str);
-char* strupper(char *Str);
-int stricomp(const char *Str1,const char *Str2);
-int strnicomp(const char *Str1,const char *Str2,size_t N);
-char* RemoveEOL(char *Str);
-char* RemoveLF(char *Str);
+void IntToExt(const char *Src,char *Dest,size_t DestSize);
+int stricomp(const char *s1,const char *s2);
+int strnicomp(const char *s1,const char *s2,size_t n);
+wchar* RemoveEOL(wchar *Str);
wchar* RemoveLF(wchar *Str);
unsigned char loctolower(unsigned char ch);
unsigned char loctoupper(unsigned char ch);
@@ -28,6 +23,7 @@ bool IsDigit(int ch);
bool IsSpace(int ch);
bool IsAlpha(int ch);
+void BinToHex(const byte *Bin,size_t BinSize,char *Hex,wchar *HexW,size_t HexSize);
#ifndef SFX_MODULE
uint GetDigits(uint Number);
@@ -36,18 +32,15 @@ uint GetDigits(uint Number);
bool LowAscii(const char *Str);
bool LowAscii(const wchar *Str);
-
-int stricompc(const char *Str1,const char *Str2);
-#ifndef SFX_MODULE
int wcsicompc(const wchar *Str1,const wchar *Str2);
-#endif
void itoa(int64 n,char *Str);
-int64 atoil(const char *Str);
void itoa(int64 n,wchar *Str);
-int64 atoil(const wchar *Str);
const wchar* GetWide(const char *Src);
-const wchar* GetWide(const char *Src,const wchar *SrcW);
const wchar* GetCmdParam(const wchar *CmdLine,wchar *Param,size_t MaxSize);
+void PrintfPrepareFmt(const wchar *Org,wchar *Cvt,size_t MaxSize);
+
+enum PASSWORD_TYPE {PASSWORD_GLOBAL,PASSWORD_FILE,PASSWORD_ARCHIVE};
+bool GetPassword(PASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password);
#endif
diff --git a/src/thirdparty/unrar/strlist.cpp b/src/thirdparty/unrar/strlist.cpp
index 5e5ace28b..50d69c715 100644
--- a/src/thirdparty/unrar/strlist.cpp
+++ b/src/thirdparty/unrar/strlist.cpp
@@ -10,170 +10,119 @@ void StringList::Reset()
{
Rewind();
StringData.Reset();
- StringDataW.Reset();
StringsCount=0;
SavePosNumber=0;
}
-void StringList::AddString(const char *Str)
+void StringList::AddStringA(const char *Str)
{
- AddString(Str,NULL);
+ Array<wchar> StrW(strlen(Str));
+ CharToWide(Str,&StrW[0],StrW.Size());
+ AddString(&StrW[0]);
}
void StringList::AddString(const wchar *Str)
{
- AddString(NULL,Str);
-}
-
-
-
-
-void StringList::AddString(const char *Str,const wchar *StrW)
-{
if (Str==NULL)
- Str="";
- if (StrW==NULL)
- StrW=L"";
+ Str=L"";
size_t PrevSize=StringData.Size();
- StringData.Add(strlen(Str)+1);
- strcpy(&StringData[PrevSize],Str);
-
- size_t PrevSizeW=StringDataW.Size();
- StringDataW.Add(wcslen(StrW)+1);
- wcscpy(&StringDataW[PrevSizeW],StrW);
+ StringData.Add(wcslen(Str)+1);
+ wcscpy(&StringData[PrevSize],Str);
StringsCount++;
}
-bool StringList::GetString(char *Str,size_t MaxLength)
+bool StringList::GetStringA(char *Str,size_t MaxLength)
{
- return(GetString(Str,NULL,MaxLength));
+ Array<wchar> StrW(MaxLength);
+ if (!GetString(&StrW[0],StrW.Size()))
+ return false;
+ WideToChar(&StrW[0],Str,MaxLength);
+ return true;
}
bool StringList::GetString(wchar *Str,size_t MaxLength)
{
- return(GetString(NULL,Str,MaxLength));
-}
-
-
-bool StringList::GetString(char *Str,wchar *StrW,size_t MaxLength)
-{
- char *StrPtr;
- wchar *StrPtrW;
- if (!GetString(&StrPtr,&StrPtrW))
- return(false);
- if (Str!=NULL)
- strncpy(Str,StrPtr,MaxLength);
- if (StrW!=NULL)
- wcsncpy(StrW,StrPtrW,MaxLength);
- return(true);
+ wchar *StrPtr;
+ if (!GetString(&StrPtr))
+ return false;
+ wcsncpyz(Str,StrPtr,MaxLength);
+ return true;
}
#ifndef SFX_MODULE
-bool StringList::GetString(char *Str,wchar *StrW,size_t MaxLength,int StringNum)
+bool StringList::GetString(wchar *Str,size_t MaxLength,int StringNum)
{
SavePosition();
Rewind();
bool RetCode=true;
while (StringNum-- >=0)
- if (!GetString(Str,StrW,MaxLength))
+ if (!GetString(Str,MaxLength))
{
RetCode=false;
break;
}
RestorePosition();
- return(RetCode);
+ return RetCode;
}
#endif
-char* StringList::GetString()
-{
- char *Str;
- GetString(&Str,NULL);
- return(Str);
-}
-
-
-wchar* StringList::GetStringW()
+wchar* StringList::GetString()
{
- wchar *StrW;
- GetString(NULL,&StrW);
- return(StrW);
+ wchar *Str;
+ GetString(&Str);
+ return Str;
}
-bool StringList::GetString(char **Str,wchar **StrW)
+bool StringList::GetString(wchar **Str)
{
- // First check would be enough, because both buffers grow synchronously,
- // but we check both for extra fail proof.
- if (CurPos>=StringData.Size() || CurPosW>=StringDataW.Size())
+ if (CurPos>=StringData.Size()) // No more strings left unprocessed.
{
- // No more strings left unprocessed.
if (Str!=NULL)
*Str=NULL;
- if (StrW!=NULL)
- *StrW=NULL;
- return(false);
+ return false;
}
- // We move ASCII and Unicode buffer pointers synchronously.
-
- char *CurStr=&StringData[CurPos];
- CurPos+=strlen(CurStr)+1;
+ wchar *CurStr=&StringData[CurPos];
+ CurPos+=wcslen(CurStr)+1;
if (Str!=NULL)
*Str=CurStr;
- wchar *CurStrW=&StringDataW[CurPosW];
- CurPosW+=wcslen(CurStrW)+1;
- if (StrW!=NULL)
- *StrW=CurStrW;
-
- return(true);
+ return true;
}
void StringList::Rewind()
{
CurPos=0;
- CurPosW=0;
-}
-
-
-// Return the total size of usual and Unicode characters stored in the list.
-size_t StringList::GetCharCount()
-{
- return(StringData.Size()+StringDataW.Size());
}
#ifndef SFX_MODULE
-bool StringList::Search(char *Str,wchar *StrW,bool CaseSensitive)
+bool StringList::Search(const wchar *Str,bool CaseSensitive)
{
SavePosition();
Rewind();
bool Found=false;
- char *CurStr;
- wchar *CurStrW;
- while (GetString(&CurStr,&CurStrW))
+ wchar *CurStr;
+ while (GetString(&CurStr))
{
if (Str!=NULL && CurStr!=NULL)
- if ((CaseSensitive ? strcmp(Str,CurStr):stricomp(Str,CurStr))!=0)
- continue;
- if (StrW!=NULL && CurStrW!=NULL)
- if ((CaseSensitive ? wcscmp(StrW,CurStrW):wcsicomp(StrW,CurStrW))!=0)
+ if ((CaseSensitive ? wcscmp(Str,CurStr):wcsicomp(Str,CurStr))!=0)
continue;
Found=true;
break;
}
RestorePosition();
- return(Found);
+ return Found;
}
#endif
@@ -184,7 +133,6 @@ void StringList::SavePosition()
if (SavePosNumber<ASIZE(SaveCurPos))
{
SaveCurPos[SavePosNumber]=CurPos;
- SaveCurPosW[SavePosNumber]=CurPosW;
SavePosNumber++;
}
}
@@ -198,7 +146,6 @@ void StringList::RestorePosition()
{
SavePosNumber--;
CurPos=SaveCurPos[SavePosNumber];
- CurPosW=SaveCurPosW[SavePosNumber];
}
}
#endif
diff --git a/src/thirdparty/unrar/strlist.hpp b/src/thirdparty/unrar/strlist.hpp
index 4c8985ef0..cc6bc5d42 100644
--- a/src/thirdparty/unrar/strlist.hpp
+++ b/src/thirdparty/unrar/strlist.hpp
@@ -4,32 +4,26 @@
class StringList
{
private:
- Array<char> StringData;
+ Array<wchar> StringData;
size_t CurPos;
- Array<wchar> StringDataW;
- size_t CurPosW;
-
uint StringsCount;
- size_t SaveCurPos[16],SaveCurPosW[16],SavePosNumber;
+ size_t SaveCurPos[16],SavePosNumber;
public:
StringList();
void Reset();
- void AddString(const char *Str);
+ void AddStringA(const char *Str);
void AddString(const wchar *Str);
- void AddString(const char *Str,const wchar *StrW);
- bool GetString(char *Str,size_t MaxLength);
+ bool GetStringA(char *Str,size_t MaxLength);
bool GetString(wchar *Str,size_t MaxLength);
- bool GetString(char *Str,wchar *StrW,size_t MaxLength);
- bool GetString(char *Str,wchar *StrW,size_t MaxLength,int StringNum);
- char* GetString();
- wchar* GetStringW();
- bool GetString(char **Str,wchar **StrW);
+ bool GetString(wchar *Str,size_t MaxLength,int StringNum);
+ wchar* GetString();
+ bool GetString(wchar **Str);
void Rewind();
- uint ItemsCount() {return(StringsCount);};
- size_t GetCharCount();
- bool Search(char *Str,wchar *StrW,bool CaseSensitive);
+ uint ItemsCount() {return StringsCount;};
+ size_t GetCharCount() {return StringData.Size();}
+ bool Search(const wchar *Str,bool CaseSensitive);
void SavePosition();
void RestorePosition();
};
diff --git a/src/thirdparty/unrar/system.cpp b/src/thirdparty/unrar/system.cpp
index a3746aa12..64a8e130f 100644
--- a/src/thirdparty/unrar/system.cpp
+++ b/src/thirdparty/unrar/system.cpp
@@ -72,6 +72,8 @@ void SetPriority(int Priority)
#ifndef SETUP
void Wait()
{
+ if (ErrHandler.UserBreak)
+ ErrHandler.Exit(RARX_USERBREAK);
#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
if (SleepTime!=0)
Sleep(SleepTime);
@@ -100,3 +102,22 @@ void Shutdown()
#endif
+
+#ifdef USE_SSE
+SSE_VERSION _SSE_Version=GetSSEVersion();
+
+SSE_VERSION GetSSEVersion()
+{
+ int CPUInfo[4];
+ __cpuid(CPUInfo, 1);
+ if ((CPUInfo[2] & 0x80000)!=0)
+ return SSE_SSE41;
+ if ((CPUInfo[2] & 0x200)!=0)
+ return SSE_SSSE3;
+ if ((CPUInfo[3] & 0x4000000)!=0)
+ return SSE_SSE2;
+ if ((CPUInfo[3] & 0x2000000)!=0)
+ return SSE_SSE;
+ return SSE_NONE;
+}
+#endif
diff --git a/src/thirdparty/unrar/system.hpp b/src/thirdparty/unrar/system.hpp
index a76556470..88445be79 100644
--- a/src/thirdparty/unrar/system.hpp
+++ b/src/thirdparty/unrar/system.hpp
@@ -20,9 +20,15 @@
void InitSystemOptions(int SleepTime);
void SetPriority(int Priority);
void Wait();
-bool EmailFile(char *FileName,char *MailTo);
+bool EmailFile(const wchar *FileName,const wchar *MailToW);
void Shutdown();
+#ifdef USE_SSE
+enum SSE_VERSION {SSE_NONE,SSE_SSE,SSE_SSE2,SSE_SSSE3,SSE_SSE41};
+SSE_VERSION GetSSEVersion();
+extern SSE_VERSION _SSE_Version;
+#endif
+
#endif
diff --git a/src/thirdparty/unrar/threadmisc.cpp b/src/thirdparty/unrar/threadmisc.cpp
new file mode 100644
index 000000000..c069fc185
--- /dev/null
+++ b/src/thirdparty/unrar/threadmisc.cpp
@@ -0,0 +1,148 @@
+// Typically we use the same global thread pool for all RAR modules.
+static ThreadPool *GlobalPool=NULL;
+static uint GlobalPoolUseCount=0;
+
+ThreadPool* CreateThreadPool()
+{
+ if (GlobalPoolUseCount++ == 0)
+ GlobalPool=new ThreadPool(MaxPoolThreads);
+ return GlobalPool;
+}
+
+
+void DestroyThreadPool(ThreadPool *Pool)
+{
+ if (Pool!=NULL && Pool==GlobalPool && GlobalPoolUseCount > 0 && --GlobalPoolUseCount == 0)
+ delete GlobalPool;
+}
+
+
+static THREAD_HANDLE ThreadCreate(PTHREAD_PROC Proc,void *Data)
+{
+#ifdef _UNIX
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ pthread_t pt;
+ int Code=pthread_create(&pt,&attr,Proc,(void*)Data);
+ if (Code!=0)
+ {
+ wchar Msg[100];
+ swprintf(Msg,ASIZE(Msg),L"\npthread_create failed, code %d\n",Code);
+ ErrHandler.GeneralErrMsg(Msg);
+ ErrHandler.SysErrMsg();
+ ErrHandler.Exit(RARX_FATAL);
+ }
+ return pt;
+#else
+ DWORD ThreadId;
+ HANDLE hThread=CreateThread(NULL,0x10000,(LPTHREAD_START_ROUTINE)Proc,Data,0,&ThreadId);
+ if (hThread==NULL)
+ {
+ ErrHandler.GeneralErrMsg(L"CreateThread failed");
+ ErrHandler.SysErrMsg();
+ ErrHandler.Exit(RARX_FATAL);
+ }
+ return hThread;
+#endif
+}
+
+
+static void ThreadClose(THREAD_HANDLE hThread)
+{
+#ifdef _UNIX
+ pthread_join(hThread,NULL);
+#else
+ CloseHandle(hThread);
+#endif
+}
+
+
+static inline void CriticalSectionStart(CRITSECT_HANDLE *CritSection)
+{
+#ifdef _WIN_ALL
+ EnterCriticalSection(CritSection);
+#elif defined(_UNIX)
+ pthread_mutex_lock(CritSection);
+#endif
+}
+
+
+static inline void CriticalSectionEnd(CRITSECT_HANDLE *CritSection)
+{
+#ifdef _WIN_ALL
+ LeaveCriticalSection(CritSection);
+#elif defined(_UNIX)
+ pthread_mutex_unlock(CritSection);
+#endif
+}
+
+
+#ifdef _WIN_ALL
+static void CWaitForSingleObject(HANDLE hHandle)
+{
+ DWORD rc=WaitForSingleObject(hHandle,INFINITE);
+ if (rc==WAIT_FAILED)
+ {
+ ErrHandler.GeneralErrMsg(L"\nWaitForMultipleObjects error %d, GetLastError %d",rc,GetLastError());
+ ErrHandler.Exit(RARX_FATAL);
+ }
+}
+#endif
+
+
+#ifdef _UNIX
+static void cpthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ int rc=pthread_cond_wait(cond,mutex);
+ if (rc!=0)
+ {
+ ErrHandler.GeneralErrMsg(L"\npthread_cond_wait error %d",rc);
+ ErrHandler.Exit(RARX_FATAL);
+ }
+}
+#endif
+
+
+uint GetNumberOfCPU()
+{
+#ifndef RAR_SMP
+ return 1;
+#else
+#ifdef _UNIX
+#ifdef _SC_NPROCESSORS_ONLN
+ uint Count=(uint)sysconf(_SC_NPROCESSORS_ONLN);
+ return Count<1 ? 1:Count;
+#elif defined(_APPLE)
+ uint Count;
+ size_t Size=sizeof(Count);
+ return sysctlbyname("hw.ncpu",&Count,&Size,NULL,0)==0 ? Count:1;
+#endif
+#else // !_UNIX
+ DWORD_PTR ProcessMask;
+ DWORD_PTR SystemMask;
+
+ if (!GetProcessAffinityMask(GetCurrentProcess(),&ProcessMask,&SystemMask))
+ return 1;
+ uint Count=0;
+ for (DWORD_PTR Mask=1;Mask!=0;Mask<<=1)
+ if ((ProcessMask & Mask)!=0)
+ Count++;
+ return Count<1 ? 1:Count;
+#endif
+
+#endif // RAR_SMP
+}
+
+
+uint GetNumberOfThreads()
+{
+ uint NumCPU=GetNumberOfCPU();
+ if (NumCPU<1)
+ return 1;
+ if (NumCPU>MaxPoolThreads)
+ return MaxPoolThreads;
+ return NumCPU;
+}
+
diff --git a/src/thirdparty/unrar/threadpool.cpp b/src/thirdparty/unrar/threadpool.cpp
new file mode 100644
index 000000000..16e697c77
--- /dev/null
+++ b/src/thirdparty/unrar/threadpool.cpp
@@ -0,0 +1,206 @@
+#include "rar.hpp"
+
+#ifdef RAR_SMP
+#include "threadmisc.cpp"
+
+#ifdef _WIN_ALL
+int ThreadPool::ThreadPriority=THREAD_PRIORITY_NORMAL;
+#endif
+
+ThreadPool::ThreadPool(uint MaxThreads)
+{
+ MaxAllowedThreads = MaxThreads;
+ if (MaxAllowedThreads>MaxPoolThreads)
+ MaxAllowedThreads=MaxPoolThreads;
+ if (MaxAllowedThreads==0)
+ MaxAllowedThreads=1;
+
+ // If we have more threads than queue size, we'll hang on pool destroying,
+ // not releasing all waiting threads.
+ if (MaxAllowedThreads>ASIZE(TaskQueue))
+ MaxAllowedThreads=ASIZE(TaskQueue);
+
+ Closing=false;
+
+ bool Success;
+#ifdef _WIN_ALL
+ QueuedTasksCnt=CreateSemaphore(NULL,0,ASIZE(TaskQueue),NULL);
+ NoneActive=CreateEvent(NULL,TRUE,TRUE,NULL);
+ InitializeCriticalSection(&CritSection);
+ Success=QueuedTasksCnt!=NULL && NoneActive!=NULL;
+#elif defined(_UNIX)
+ AnyActive = false;
+ QueuedTasksCnt = 0;
+ Success=pthread_mutex_init(&CritSection,NULL)==0 &&
+ pthread_cond_init(&AnyActiveCond,NULL)==0 &&
+ pthread_mutex_init(&AnyActiveMutex,NULL)==0 &&
+ pthread_cond_init(&QueuedTasksCntCond,NULL)==0 &&
+ pthread_mutex_init(&QueuedTasksCntMutex,NULL)==0;
+#endif
+ if (!Success)
+ {
+ ErrHandler.GeneralErrMsg(L"\nThread pool initialization failed.");
+ ErrHandler.Exit(RARX_FATAL);
+ }
+
+ for(uint I=0;I<MaxAllowedThreads;I++)
+ {
+ ThreadHandles[I] = ThreadCreate( PoolThread, this);
+#ifdef _WIN_ALL
+ if (ThreadPool::ThreadPriority!=THREAD_PRIORITY_NORMAL)
+ SetThreadPriority(ThreadHandles[I],ThreadPool::ThreadPriority);
+#endif
+ }
+
+ QueueTop = 0;
+ QueueBottom = 0;
+ ActiveThreads = 0;
+}
+
+
+ThreadPool::~ThreadPool()
+{
+ WaitDone();
+ Closing=true;
+
+#ifdef _WIN_ALL
+ ReleaseSemaphore(QueuedTasksCnt,ASIZE(TaskQueue),NULL);
+#elif defined(_UNIX)
+ // Threads still can access QueuedTasksCnt for a short time after WaitDone(),
+ // so lock is required. We would occassionally hang without it.
+ pthread_mutex_lock(&QueuedTasksCntMutex);
+ QueuedTasksCnt+=ASIZE(TaskQueue);
+ pthread_mutex_unlock(&QueuedTasksCntMutex);
+
+ pthread_cond_broadcast(&QueuedTasksCntCond);
+#endif
+
+ for(uint I=0;I<MaxAllowedThreads;I++)
+ {
+#ifdef _WIN_ALL
+ // Waiting until the thread terminates.
+ CWaitForSingleObject(ThreadHandles[I]);
+#endif
+ // Close the thread handle. In Unix it is results in pthread_join call,
+ // which also waits for thread termination.
+ ThreadClose(ThreadHandles[I]);
+ }
+
+#ifdef _WIN_ALL
+ DeleteCriticalSection(&CritSection);
+ CloseHandle(QueuedTasksCnt);
+ CloseHandle(NoneActive);
+#elif defined(_UNIX)
+ pthread_mutex_destroy(&CritSection);
+ pthread_cond_destroy(&AnyActiveCond);
+ pthread_mutex_destroy(&AnyActiveMutex);
+ pthread_cond_destroy(&QueuedTasksCntCond);
+ pthread_mutex_destroy(&QueuedTasksCntMutex);
+#endif
+}
+
+
+THREAD_TYPE THREAD_ATTR ThreadPool::PoolThread(void *Param)
+{
+ ((ThreadPool*)Param)->PoolThreadLoop();
+}
+
+
+void ThreadPool::PoolThreadLoop()
+{
+ QueueEntry Task;
+ while (GetQueuedTask(&Task))
+ {
+ Task.Proc(Task.Param);
+
+ CriticalSectionStart(&CritSection);
+ if (--ActiveThreads == 0)
+ {
+#ifdef _WIN_ALL
+ SetEvent(NoneActive);
+#elif defined(_UNIX)
+ pthread_mutex_lock(&AnyActiveMutex);
+ AnyActive=false;
+ pthread_cond_signal(&AnyActiveCond);
+ pthread_mutex_unlock(&AnyActiveMutex);
+#endif
+ }
+ CriticalSectionEnd(&CritSection);
+ }
+}
+
+
+bool ThreadPool::GetQueuedTask(QueueEntry *Task)
+{
+#ifdef _WIN_ALL
+ CWaitForSingleObject(QueuedTasksCnt);
+#elif defined(_UNIX)
+ pthread_mutex_lock(&QueuedTasksCntMutex);
+ while (QueuedTasksCnt==0)
+ cpthread_cond_wait(&QueuedTasksCntCond,&QueuedTasksCntMutex);
+ QueuedTasksCnt--;
+ pthread_mutex_unlock(&QueuedTasksCntMutex);
+#endif
+
+ if (Closing)
+ return false;
+
+ CriticalSectionStart(&CritSection);
+
+ *Task = TaskQueue[QueueBottom];
+ QueueBottom = (QueueBottom + 1) % ASIZE(TaskQueue);
+
+ CriticalSectionEnd(&CritSection);
+
+ return true;
+}
+
+
+// Add task to queue. We assume that it is always called from main thread,
+// it allows to avoid any locks here. We process collected tasks only
+// when StartWait is called.
+void ThreadPool::AddTask(PTHREAD_PROC Proc,void *Data)
+{
+ // If queue is full, wait until it is empty.
+ if ((QueueTop + 1) % ASIZE(TaskQueue) == QueueBottom)
+ WaitDone();
+
+ TaskQueue[QueueTop].Proc = Proc;
+ TaskQueue[QueueTop].Param = Data;
+ QueueTop = (QueueTop + 1) % ASIZE(TaskQueue);
+}
+
+
+// Start queued tasks and wait until all threads are inactive.
+// We assume that it is always called from main thread, when pool threads
+// are sleeping yet.
+void ThreadPool::WaitDone()
+{
+ // We add ASIZE(TaskQueue) for case if TaskQueue array size is not
+ // a power of two. Negative numbers would not suit our purpose here.
+ ActiveThreads=(QueueTop+ASIZE(TaskQueue)-QueueBottom) % ASIZE(TaskQueue);
+ if (ActiveThreads==0)
+ return;
+#ifdef _WIN_ALL
+ ResetEvent(NoneActive);
+ ReleaseSemaphore(QueuedTasksCnt,ActiveThreads,NULL);
+ CWaitForSingleObject(NoneActive);
+#elif defined(_UNIX)
+ AnyActive=true;
+
+ // Threads reset AnyActive before accessing QueuedTasksCnt and even
+ // preceding WaitDone() call does not guarantee that some slow thread
+ // is not accessing QueuedTasksCnt now. So lock is necessary.
+ pthread_mutex_lock(&QueuedTasksCntMutex);
+ QueuedTasksCnt+=ActiveThreads;
+ pthread_mutex_unlock(&QueuedTasksCntMutex);
+
+ pthread_cond_broadcast(&QueuedTasksCntCond);
+
+ pthread_mutex_lock(&AnyActiveMutex);
+ while (AnyActive)
+ cpthread_cond_wait(&AnyActiveCond,&AnyActiveMutex);
+ pthread_mutex_unlock(&AnyActiveMutex);
+#endif
+}
+#endif // RAR_SMP
diff --git a/src/thirdparty/unrar/threadpool.hpp b/src/thirdparty/unrar/threadpool.hpp
new file mode 100644
index 000000000..817d61a2d
--- /dev/null
+++ b/src/thirdparty/unrar/threadpool.hpp
@@ -0,0 +1,103 @@
+#ifndef _RAR_THREADPOOL_
+#define _RAR_THREADPOOL_
+
+#ifndef RAR_SMP
+const uint MaxPoolThreads=1; // For single threaded version.
+#else
+const uint MaxPoolThreads=32;
+
+
+#ifdef _UNIX
+ #include <pthread.h>
+ #include <semaphore.h>
+#endif
+
+// Undefine for debugging.
+#define USE_THREADS
+
+#ifdef _UNIX
+ #define THREAD_ATTR
+ #define THREAD_TYPE void*
+ typedef pthread_t THREAD_HANDLE;
+ typedef pthread_mutex_t CRITSECT_HANDLE;
+#else
+ #define THREAD_ATTR WINAPI
+ #define THREAD_TYPE void
+ typedef HANDLE THREAD_HANDLE;
+ typedef CRITICAL_SECTION CRITSECT_HANDLE;
+#endif
+
+typedef THREAD_TYPE (THREAD_ATTR *PTHREAD_PROC)(void *Data);
+#define THREAD_PROC(fn) THREAD_TYPE THREAD_ATTR fn(void *Data)
+
+uint GetNumberOfCPU();
+uint GetNumberOfThreads();
+
+
+class ThreadPool
+{
+ private:
+ struct QueueEntry
+ {
+ PTHREAD_PROC Proc;
+ void *Param;
+ };
+
+ static THREAD_TYPE THREAD_ATTR PoolThread(void *Param);
+ void PoolThreadLoop();
+ bool GetQueuedTask(QueueEntry *Task);
+
+ // Number of threads in the pool. Must not exceed MaxPoolThreads.
+ uint MaxAllowedThreads;
+ THREAD_HANDLE ThreadHandles[MaxPoolThreads];
+
+ uint ActiveThreads;
+
+ QueueEntry TaskQueue[MaxPoolThreads];
+ uint QueueTop;
+ uint QueueBottom;
+
+ bool Closing; // Set true to quit all threads.
+
+#ifdef _WIN_ALL
+ // Semaphore counting number of tasks stored in queue.
+ HANDLE QueuedTasksCnt;
+
+ // Event signalling if no active tasks are performing now.
+ HANDLE NoneActive;
+
+#elif defined(_UNIX)
+ // Semaphores seem to be slower than conditional variables in pthreads,
+ // so we use the conditional variable to count tasks stored in queue.
+ uint QueuedTasksCnt;
+ pthread_cond_t QueuedTasksCntCond;
+ pthread_mutex_t QueuedTasksCntMutex;
+
+ bool AnyActive; // Active tasks present flag.
+ pthread_cond_t AnyActiveCond;
+ pthread_mutex_t AnyActiveMutex;
+#endif
+
+ // Pool critical section. We use the single section for all branches
+ // to avoid deadlocks, when thread1 has section1 and wants section2
+ // and thread2 has section2 and wants section1.
+ CRITSECT_HANDLE CritSection;
+ public:
+ ThreadPool(uint MaxThreads);
+ ~ThreadPool();
+ void AddTask(PTHREAD_PROC Proc,void *Data);
+ void WaitDone();
+
+#ifdef _WIN_ALL
+ static int ThreadPriority;
+ static void SetPriority(int Priority) {ThreadPriority=Priority;}
+#endif
+};
+
+ThreadPool* CreateThreadPool();
+void DestroyThreadPool(ThreadPool *Pool);
+
+#endif // RAR_SMP
+
+#endif // _RAR_THREADPOOL_
+
diff --git a/src/thirdparty/unrar/timefn.cpp b/src/thirdparty/unrar/timefn.cpp
index ed2bd8861..1d6d5d16d 100644
--- a/src/thirdparty/unrar/timefn.cpp
+++ b/src/thirdparty/unrar/timefn.cpp
@@ -8,262 +8,220 @@ RarTime::RarTime()
#ifdef _WIN_ALL
RarTime& RarTime::operator =(FILETIME &ft)
{
- FILETIME lft;
- FileTimeToLocalFileTime(&ft,&lft);
- SYSTEMTIME st;
- FileTimeToSystemTime(&lft,&st);
- rlt.Year=st.wYear;
- rlt.Month=st.wMonth;
- rlt.Day=st.wDay;
- rlt.Hour=st.wHour;
- rlt.Minute=st.wMinute;
- rlt.Second=st.wSecond;
- rlt.wDay=st.wDayOfWeek;
- rlt.yDay=rlt.Day-1;
- for (uint I=1;I<rlt.Month;I++)
- {
- static int mdays[12]={31,28,31,30,31,30,31,31,30,31,30,31};
- rlt.yDay+=mdays[I-1];
- }
- if (rlt.Month>2 && IsLeapYear(rlt.Year))
- rlt.yDay++;
-
- st.wMilliseconds=0;
- FILETIME zft;
- SystemTimeToFileTime(&st,&zft);
-
- // Calculate the time reminder, which is the part of time smaller
- // than 1 second, represented in 100-nanosecond intervals.
- rlt.Reminder=INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime)-
- INT32TO64(zft.dwHighDateTime,zft.dwLowDateTime);
- return(*this);
+ _ULARGE_INTEGER ul = {ft.dwLowDateTime, ft.dwHighDateTime};
+ itime=ul.QuadPart;
+ return *this;
}
void RarTime::GetWin32(FILETIME *ft)
{
- SYSTEMTIME st;
- st.wYear=rlt.Year;
- st.wMonth=rlt.Month;
- st.wDay=rlt.Day;
- st.wHour=rlt.Hour;
- st.wMinute=rlt.Minute;
- st.wSecond=rlt.Second;
- st.wMilliseconds=0;
- FILETIME lft;
- SystemTimeToFileTime(&st,&lft);
- lft.dwLowDateTime+=rlt.Reminder;
- if (lft.dwLowDateTime<rlt.Reminder)
- lft.dwHighDateTime++;
- LocalFileTimeToFileTime(&lft,ft);
+ _ULARGE_INTEGER ul;
+ ul.QuadPart=itime;
+ ft->dwLowDateTime=ul.LowPart;
+ ft->dwHighDateTime=ul.HighPart;
}
#endif
-#if defined(_UNIX) || defined(_EMX)
RarTime& RarTime::operator =(time_t ut)
{
- struct tm *t;
- t=localtime(&ut);
-
- rlt.Year=t->tm_year+1900;
- rlt.Month=t->tm_mon+1;
- rlt.Day=t->tm_mday;
- rlt.Hour=t->tm_hour;
- rlt.Minute=t->tm_min;
- rlt.Second=t->tm_sec;
- rlt.Reminder=0;
- rlt.wDay=t->tm_wday;
- rlt.yDay=t->tm_yday;
- return(*this);
+ uint64 ushift=INT32TO64(0x19DB1DE,0xD53E8000); // 116444736000000000.
+ itime=uint64(ut)*10000000+ushift;
+ return *this;
}
time_t RarTime::GetUnix()
{
- struct tm t;
-
- t.tm_sec=rlt.Second;
- t.tm_min=rlt.Minute;
- t.tm_hour=rlt.Hour;
- t.tm_mday=rlt.Day;
- t.tm_mon=rlt.Month-1;
- t.tm_year=rlt.Year-1900;
- t.tm_isdst=-1;
- return(mktime(&t));
+ uint64 ushift=INT32TO64(0x19DB1DE,0xD53E8000); // 116444736000000000.
+ time_t ut=(itime-ushift)/10000000;
+ return ut;
}
-#endif
-// Return the stored time as 64-bit number of 100-nanosecond intervals
-// since January 1, 1601 for Windows and since January 1, 1970 for Unix.
-// 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
-// returned by GetRaw() for time comparisons, for relative operations
-// like SetRaw(GetRaw()-C) and for compact time storage when necessary.
-int64 RarTime::GetRaw()
+
+void RarTime::GetLocal(RarLocalTime *lt)
{
- if (!IsSet())
- return(0);
#ifdef _WIN_ALL
FILETIME ft;
GetWin32(&ft);
- return(INT32TO64(ft.dwHighDateTime,ft.dwLowDateTime));
-#elif defined(_UNIX) || defined(_EMX)
- time_t ut=GetUnix();
- return(INT32TO64(0,ut)*10000000+rlt.Reminder);
-#else
- // We should never be here. It is better to use standard time functions.
-
- // Days since 1970. We do not care about leap years for code simplicity.
- // It should be acceptable for comprisons.
- int64 r=(rlt.Year-1970)*365; // Days since 1970.
+ FILETIME lft;
+ FileTimeToLocalFileTime(&ft,&lft);
+ SYSTEMTIME st;
+ FileTimeToSystemTime(&lft,&st);
+ lt->Year=st.wYear;
+ lt->Month=st.wMonth;
+ lt->Day=st.wDay;
+ lt->Hour=st.wHour;
+ lt->Minute=st.wMinute;
+ lt->Second=st.wSecond;
+ lt->wDay=st.wDayOfWeek;
+ lt->yDay=lt->Day-1;
+
+ static int mdays[12]={31,28,31,30,31,30,31,31,30,31,30,31};
+ for (uint I=1;I<lt->Month && I<=ASIZE(mdays);I++)
+ lt->yDay+=mdays[I-1];
+
+ if (lt->Month>2 && IsLeapYear(lt->Year))
+ lt->yDay++;
- // Cumulative day value for beginning of every month.
- static int MonthToDay[12]={0,31,60,91,121,152,182,213,244,274,305,335};
+ st.wMilliseconds=0;
+ FILETIME zft;
+ SystemTimeToFileTime(&st,&zft);
- r+=MonthToDay[rlt.Month-1]+(rlt.Day-1); // Add days since beginning of year.
- r=r*24+rlt.Hour; // Hours.
- r=r*60+rlt.Minute; // Minutes.
- r=r*60+rlt.Second; // Seconds.
- r=r*10000000+rlt.Reminder; // 100-nanosecond intervals.
+ // Calculate the time reminder, which is the part of time smaller
+ // than 1 second, represented in 100-nanosecond intervals.
+ lt->Reminder=INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime)-
+ INT32TO64(zft.dwHighDateTime,zft.dwLowDateTime);
+#else
+ time_t ut=GetUnix();
+ struct tm *t;
+ t=localtime(&ut);
- return(r);
+ lt->Year=t->tm_year+1900;
+ lt->Month=t->tm_mon+1;
+ lt->Day=t->tm_mday;
+ lt->Hour=t->tm_hour;
+ lt->Minute=t->tm_min;
+ lt->Second=t->tm_sec;
+ lt->Reminder=0;
+ lt->wDay=t->tm_wday;
+ lt->yDay=t->tm_yday;
#endif
}
-#ifndef SFX_MODULE
-void RarTime::SetRaw(int64 RawTime)
+void RarTime::SetLocal(RarLocalTime *lt)
{
#ifdef _WIN_ALL
- FILETIME ft;
- ft.dwHighDateTime=(DWORD)(RawTime>>32);
- ft.dwLowDateTime=(DWORD)RawTime;
- *this=ft;
-#elif defined(_UNIX) || defined(_EMX)
- time_t ut=(time_t)(RawTime/10000000);
- *this=ut;
- rlt.Reminder=(uint)(RawTime%10000000);
+ 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;
+ FILETIME lft;
+ if (SystemTimeToFileTime(&st,&lft))
+ {
+ lft.dwLowDateTime+=lt->Reminder;
+ if (lft.dwLowDateTime<lt->Reminder)
+ lft.dwHighDateTime++;
+ FILETIME ft;
+ LocalFileTimeToFileTime(&lft,&ft);
+ *this=ft;
+ }
+ else
+ Reset();
#else
- // We should never be here. It is better to use standard time functions.
- rlt.Reminder=RawTime%10000000;
- RawTime/=10000000; // Seconds.
- rlt.Second=uint(RawTime%60);
- RawTime/=60; // Minutes.
- rlt.Minute=uint(RawTime%60);
- RawTime/=60; // Hours.
- rlt.Hour=uint(RawTime%24);
- RawTime/=24; // Days since 1970.
- rlt.Year=uint(1970+RawTime/365);
- RawTime%=365; // Days since beginning of year.
-
- // Cumulative day value for beginning of every month.
- static int MonthToDay[12]={0,31,60,91,121,152,182,213,244,274,305,335};
-
- for (int I=0;I<12;I++)
- if (RawTime>=MonthToDay[I])
- {
- rlt.Day=uint(RawTime-MonthToDay[I]+1);
- rlt.Month=I+1;
- }
+ struct tm t;
- rlt.wDay=0;
- rlt.yDay=0;
+ 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;
+ *this=mktime(&t);
#endif
}
-#endif
-bool RarTime::operator == (RarTime &rt)
-{
- return(rlt.Year==rt.rlt.Year && rlt.Month==rt.rlt.Month &&
- rlt.Day==rt.rlt.Day && rlt.Hour==rt.rlt.Hour &&
- rlt.Minute==rt.rlt.Minute && rlt.Second==rt.rlt.Second &&
- rlt.Reminder==rt.rlt.Reminder);
-}
-
-
-bool RarTime::operator < (RarTime &rt)
-{
- return(GetRaw()<rt.GetRaw());
-}
-
-
-bool RarTime::operator <= (RarTime &rt)
-{
- return(*this<rt || *this==rt);
-}
-
-
-bool RarTime::operator > (RarTime &rt)
+// 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
+// returned by GetRaw() for time comparisons, for relative operations
+// like SetRaw(GetRaw()-C) and for compact time storage when necessary.
+uint64 RarTime::GetRaw()
{
- return(GetRaw()>rt.GetRaw());
+ return itime;
}
-bool RarTime::operator >= (RarTime &rt)
+void RarTime::SetRaw(uint64 RawTime)
{
- return(*this>rt || *this==rt);
+ itime=RawTime;
}
uint RarTime::GetDos()
{
- uint DosTime=(rlt.Second/2)|(rlt.Minute<<5)|(rlt.Hour<<11)|
- (rlt.Day<<16)|(rlt.Month<<21)|((rlt.Year-1980)<<25);
- return(DosTime);
+ RarLocalTime lt;
+ GetLocal(&lt);
+ uint DosTime=(lt.Second/2)|(lt.Minute<<5)|(lt.Hour<<11)|
+ (lt.Day<<16)|(lt.Month<<21)|((lt.Year-1980)<<25);
+ return DosTime;
}
void RarTime::SetDos(uint DosTime)
{
- rlt.Second=(DosTime & 0x1f)*2;
- rlt.Minute=(DosTime>>5) & 0x3f;
- rlt.Hour=(DosTime>>11) & 0x1f;
- rlt.Day=(DosTime>>16) & 0x1f;
- rlt.Month=(DosTime>>21) & 0x0f;
- rlt.Year=(DosTime>>25)+1980;
- rlt.Reminder=0;
+ RarLocalTime lt;
+ lt.Second=(DosTime & 0x1f)*2;
+ lt.Minute=(DosTime>>5) & 0x3f;
+ lt.Hour=(DosTime>>11) & 0x1f;
+ lt.Day=(DosTime>>16) & 0x1f;
+ lt.Month=(DosTime>>21) & 0x0f;
+ lt.Year=(DosTime>>25)+1980;
+ lt.Reminder=0;
+ SetLocal(&lt);
}
#if !defined(GUI) || !defined(SFX_MODULE)
-void RarTime::GetText(char *DateStr,bool FullYear)
+void RarTime::GetText(wchar *DateStr,size_t MaxSize,bool FullYear,bool FullMS)
{
- if (FullYear)
- sprintf(DateStr,"%02u-%02u-%u %02u:%02u",rlt.Day,rlt.Month,rlt.Year,rlt.Hour,rlt.Minute);
+ if (IsSet())
+ {
+ RarLocalTime lt;
+ GetLocal(&lt);
+ if (FullMS)
+ swprintf(DateStr,MaxSize,L"%u-%02u-%02u %02u:%02u,%03u",lt.Year,lt.Month,lt.Day,lt.Hour,lt.Minute,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);
+ }
else
- sprintf(DateStr,"%02u-%02u-%02u %02u:%02u",rlt.Day,rlt.Month,rlt.Year%100,rlt.Hour,rlt.Minute);
+ {
+ // We use escape before '?' to avoid weird C trigraph characters.
+ wcscpy(DateStr,FullYear ? L"\?\?-\?\?-\?\?\?\? \?\?:\?\?":L"\?\?-\?\?-\?\? \?\?:\?\?");
+ }
}
#endif
#ifndef SFX_MODULE
-void RarTime::SetIsoText(const char *TimeText)
+void RarTime::SetIsoText(const wchar *TimeText)
{
int Field[6];
memset(Field,0,sizeof(Field));
- for (int DigitCount=0;*TimeText!=0;TimeText++)
+ for (uint DigitCount=0;*TimeText!=0;TimeText++)
if (IsDigit(*TimeText))
{
int FieldPos=DigitCount<4 ? 0:(DigitCount-4)/2+1;
- if (FieldPos<sizeof(Field)/sizeof(Field[0]))
+ if (FieldPos<ASIZE(Field))
Field[FieldPos]=Field[FieldPos]*10+*TimeText-'0';
DigitCount++;
}
- rlt.Second=Field[5];
- rlt.Minute=Field[4];
- rlt.Hour=Field[3];
- rlt.Day=Field[2]==0 ? 1:Field[2];
- rlt.Month=Field[1]==0 ? 1:Field[1];
- rlt.Year=Field[0];
- rlt.Reminder=0;
+ RarLocalTime lt;
+ lt.Second=Field[5];
+ lt.Minute=Field[4];
+ lt.Hour=Field[3];
+ lt.Day=Field[2]==0 ? 1:Field[2];
+ lt.Month=Field[1]==0 ? 1:Field[1];
+ lt.Year=Field[0];
+ lt.Reminder=0;
+ SetLocal(&lt);
}
#endif
#ifndef SFX_MODULE
-void RarTime::SetAgeText(const char *TimeText)
+void RarTime::SetAgeText(const wchar *TimeText)
{
uint Seconds=0,Value=0;
for (int I=0;TimeText[I]!=0;I++)
@@ -293,7 +251,7 @@ void RarTime::SetAgeText(const char *TimeText)
}
SetCurrentTime();
int64 RawTime=GetRaw();
- SetRaw(RawTime-INT32TO64(0,Seconds)*10000000);
+ SetRaw(itime-uint64(Seconds)*10000000);
}
#endif
@@ -315,10 +273,10 @@ void RarTime::SetCurrentTime()
#if !defined(SFX_MODULE) && !defined(_WIN_CE)
-const char *GetMonthName(int Month)
+const wchar *GetMonthName(int Month)
{
#ifdef SILENT
- return("");
+ return(L"");
#else
static MSGID MonthID[]={
MMonthJan,MMonthFeb,MMonthMar,MMonthApr,MMonthMay,MMonthJun,
diff --git a/src/thirdparty/unrar/timefn.hpp b/src/thirdparty/unrar/timefn.hpp
index 7dc55a7b4..005a72445 100644
--- a/src/thirdparty/unrar/timefn.hpp
+++ b/src/thirdparty/unrar/timefn.hpp
@@ -18,37 +18,37 @@ struct RarLocalTime
class RarTime
{
private:
- RarLocalTime rlt;
+ // Internal FILETIME like time representation in 100 nanoseconds
+ // since 01.01.1601.
+ uint64 itime;
public:
RarTime();
#ifdef _WIN_ALL
RarTime& operator =(FILETIME &ft);
void GetWin32(FILETIME *ft);
#endif
-#if defined(_UNIX) || defined(_EMX)
RarTime& operator =(time_t ut);
time_t GetUnix();
-#endif
- bool operator == (RarTime &rt);
- bool operator < (RarTime &rt);
- bool operator <= (RarTime &rt);
- bool operator > (RarTime &rt);
- bool operator >= (RarTime &rt);
- void GetLocal(RarLocalTime *lt) {*lt=rlt;}
- void SetLocal(RarLocalTime *lt) {rlt=*lt;}
- int64 GetRaw();
- void SetRaw(int64 RawTime);
+ bool operator == (RarTime &rt) {return itime==rt.itime;}
+ bool operator < (RarTime &rt) {return itime<rt.itime;}
+ bool operator <= (RarTime &rt) {return itime<rt.itime || itime==rt.itime;}
+ bool operator > (RarTime &rt) {return itime>rt.itime;}
+ bool operator >= (RarTime &rt) {return itime>rt.itime || itime==rt.itime;}
+ void GetLocal(RarLocalTime *lt);
+ void SetLocal(RarLocalTime *lt);
+ uint64 GetRaw();
+ void SetRaw(uint64 RawTime);
uint GetDos();
void SetDos(uint DosTime);
- void GetText(char *DateStr,bool FullYear);
- void SetIsoText(const char *TimeText);
- void SetAgeText(const char *TimeText);
+ void GetText(wchar *DateStr,size_t MaxSize,bool FullYear,bool FullMS);
+ void SetIsoText(const wchar *TimeText);
+ void SetAgeText(const wchar *TimeText);
void SetCurrentTime();
- void Reset() {rlt.Year=0;}
- bool IsSet() {return(rlt.Year!=0);}
+ void Reset() {itime=0;}
+ bool IsSet() {return(itime!=0);}
};
-const char *GetMonthName(int Month);
+const wchar *GetMonthName(int Month);
bool IsLeapYear(int Year);
#endif
diff --git a/src/thirdparty/unrar/ulinks.cpp b/src/thirdparty/unrar/ulinks.cpp
index c3c828d2c..7a309eedc 100644
--- a/src/thirdparty/unrar/ulinks.cpp
+++ b/src/thirdparty/unrar/ulinks.cpp
@@ -1,35 +1,65 @@
-#include "rar.hpp"
-
-bool ExtractLink(ComprDataIO &DataIO,Archive &Arc,const char *LinkName,uint &LinkCRC,bool Create)
+static bool UnixSymlink(const char *Target,const wchar *LinkName)
{
-#if defined(SAVE_LINKS) && defined(_UNIX)
- char LinkTarget[NM];
- if (IsLink(Arc.NewLhd.FileAttr))
+ CreatePath(LinkName,true);
+ DelFile(LinkName);
+ char LinkNameA[NM];
+ WideToChar(LinkName,LinkNameA,ASIZE(LinkNameA));
+ if (symlink(Target,LinkNameA)==-1) // Error.
{
- int DataSize=Min(Arc.NewLhd.PackSize,sizeof(LinkTarget)-1);
- DataIO.UnpRead((byte *)LinkTarget,DataSize);
- LinkTarget[DataSize]=0;
- if (Create)
+ if (errno==EEXIST)
+ Log(NULL,St(MSymLinkExists),LinkName);
+ else
{
- CreatePath(LinkName,NULL,true);
- if (symlink(LinkTarget,LinkName)==-1) // Error.
- if (errno==EEXIST)
- Log(Arc.FileName,St(MSymLinkExists),LinkName);
- else
- {
- Log(Arc.FileName,St(MErrCreateLnk),LinkName);
- ErrHandler.SetErrorCode(RARX_WARNING);
- }
- // We do not set time of created symlink, because utime changes
- // time of link target and lutimes is not available on all Linux
- // systems at the moment of writing this code.
+ Log(NULL,St(MErrCreateLnk),LinkName);
+ ErrHandler.SetErrorCode(RARX_WARNING);
}
- int NameSize=Min(DataSize,strlen(LinkTarget));
- LinkCRC=CRC(0xffffffff,LinkTarget,NameSize);
- return(true);
+ mprintf(L" "); // Provide space for "OK" message.
+ return false;
+ }
+ // We do not set time of created symlink, because utime changes
+ // time of link target and lutimes is not available on all Linux
+ // systems at the moment of writing this code.
+ return true;
+}
+
+
+bool ExtractUnixLink30(ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName)
+{
+ char Target[NM];
+ if (IsLink(Arc.FileHead.FileAttr))
+ {
+ size_t DataSize=Min(Arc.FileHead.PackSize,ASIZE(Target)-1);
+ DataIO.UnpRead((byte *)Target,DataSize);
+ Target[DataSize]=0;
+
+ DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,1);
+ DataIO.UnpHash.Update(Target,strlen(Target));
+ DataIO.UnpHash.Result(&Arc.FileHead.FileHash);
+
+ // Return true in case of bad checksum, so link will be processed further
+ // and extraction routine will report the checksum error.
+ if (!DataIO.UnpHash.Cmp(&Arc.FileHead.FileHash,Arc.FileHead.UseHashKey ? Arc.FileHead.HashKey:NULL))
+ return true;
+
+ return UnixSymlink(Target,LinkName);
+ }
+ return false;
+}
+
+
+bool ExtractUnixLink50(const wchar *Name,FileHeader *hd)
+{
+ char Target[NM];
+ WideToChar(hd->RedirName,Target,ASIZE(Target));
+ if (hd->RedirType==FSREDIR_WINSYMLINK || hd->RedirType==FSREDIR_JUNCTION)
+ {
+ // Cannot create Windows absolute path symlinks in Unix. Only relative path
+ // Windows symlinks can be created here.
+ if (strncmp(Target,"\\??\\",4)==0)
+ return false;
+ DosSlashToUnix(Target,Target,ASIZE(Target));
}
-#endif
- return(false);
+ return UnixSymlink(Target,Name);
}
diff --git a/src/thirdparty/unrar/unicode.cpp b/src/thirdparty/unrar/unicode.cpp
index a3022d233..8af88d804 100644
--- a/src/thirdparty/unrar/unicode.cpp
+++ b/src/thirdparty/unrar/unicode.cpp
@@ -1,7 +1,20 @@
#include "rar.hpp"
+#define MBFUNCTIONS
+
+#if defined(_UNIX) && defined(MBFUNCTIONS)
+
+static bool WideToCharMap(const wchar *Src,char *Dest,size_t DestSize,bool &Success);
+static void CharToWideMap(const char *Src,wchar *Dest,size_t DestSize,bool &Success);
+
+// In Unix we map high ASCII characters which cannot be converted to Unicode
+// to 0xE000 - 0xE0FF private use Unicode area.
+static const uint MapAreaStart=0xE000;
+
+// Mapped string marker. Initially we used 0xFFFF for this purpose,
+// but it causes MSVC2008 swprintf to fail (it treats 0xFFFF as error marker).
+// While we could workaround it, it is safer to use another character.
+static const uint MappedStringMark=0xFFFE;
-#if defined(_EMX) && !defined(_DJGPP)
-#include "unios2.cpp"
#endif
bool WideToChar(const wchar *Src,char *Dest,size_t DestSize)
@@ -17,42 +30,25 @@ bool WideToChar(const wchar *Src,char *Dest,size_t DestSize)
WideToUtf(Src,Dest,DestSize);
#elif defined(MBFUNCTIONS)
- size_t ResultingSize=wcstombs(Dest,Src,DestSize);
- if (ResultingSize==(size_t)-1)
- RetCode=false;
- if (ResultingSize==0 && *Src!=0)
- RetCode=false;
-
- if ((!RetCode || *Dest==0 && *Src!=0) && DestSize>NM && wcslen(Src)<NM)
+ if (!WideToCharMap(Src,Dest,DestSize,RetCode))
{
- /* Workaround for strange Linux Unicode functions bug.
- Some of wcstombs and mbstowcs implementations in some situations
- (we are yet to find out what it depends on) can return an empty
- string and success code if buffer size value is too large.
- */
- return(WideToChar(Src,Dest,NM));
+ size_t ResultingSize=wcstombs(Dest,Src,DestSize);
+ if (ResultingSize==(size_t)-1)
+ RetCode=false;
+ if (ResultingSize==0 && *Src!=0)
+ RetCode=false;
}
-
#else
- if (UnicodeEnabled())
+ for (int I=0;I<DestSize;I++)
{
-#if defined(_EMX) && !defined(_DJGPP)
- int len=Min(wcslen(Src)+1,DestSize-1);
- if (uni_fromucs((UniChar*)Src,len,Dest,(size_t*)&DestSize)==-1 ||
- DestSize>len*2)
- RetCode=false;
- Dest[DestSize]=0;
-#endif
+ Dest[I]=(char)Src[I];
+ if (Src[I]==0)
+ break;
}
- else
- for (int I=0;I<DestSize;I++)
- {
- Dest[I]=(char)Src[I];
- if (Src[I]==0)
- break;
- }
#endif
-
+ if (DestSize>0)
+ Dest[DestSize-1]=0;
+
// We tried to return the empty string if conversion is failed,
// but it does not work well. WideCharToMultiByte returns 'failed' code
// and partially converted string even if we wanted to convert only a part
@@ -60,7 +56,7 @@ bool WideToChar(const wchar *Src,char *Dest,size_t DestSize)
// string. Such call is the valid behavior in RAR code and we do not expect
// the empty string in this case.
- return(RetCode);
+ return RetCode;
}
@@ -83,34 +79,19 @@ bool CharToWide(const char *Src,wchar *Dest,size_t DestSize)
if (ResultingSize==0 && *Src!=0)
RetCode=false;
- if ((!RetCode || *Dest==0 && *Src!=0) && DestSize>NM && strlen(Src)<NM)
- {
- /* Workaround for strange Linux Unicode functions bug.
- Some of wcstombs and mbstowcs implementations in some situations
- (we are yet to find out what it depends on) can return an empty
- string and success code if buffer size value is too large.
- */
- return(CharToWide(Src,Dest,NM));
- }
+ if (RetCode==false && DestSize>1)
+ CharToWideMap(Src,Dest,DestSize,RetCode);
+
#else
- if (UnicodeEnabled())
+ for (int I=0;I<DestSize;I++)
{
-#if defined(_EMX) && !defined(_DJGPP)
- int len=Min(strlen(Src)+1,DestSize-1);
- if (uni_toucs((char*)Src,len,(UniChar*)Dest,(size_t*)&DestSize)==-1 ||
- DestSize>len)
- DestSize=0;
- RetCode=false;
-#endif
+ Dest[I]=(wchar_t)Src[I];
+ if (Src[I]==0)
+ break;
}
- else
- for (int I=0;I<DestSize;I++)
- {
- Dest[I]=(wchar_t)Src[I];
- if (Src[I]==0)
- break;
- }
#endif
+ if (DestSize>0)
+ Dest[DestSize-1]=0;
// We tried to return the empty string if conversion is failed,
// but it does not work well. MultiByteToWideChar returns 'failed' code
@@ -118,8 +99,102 @@ bool CharToWide(const char *Src,wchar *Dest,size_t DestSize)
// smaller than required for fully converted string. Such call is the valid
// behavior in RAR code and we do not expect the empty string in this case.
- return(RetCode);
+ return RetCode;
+}
+
+
+#if defined(_UNIX) && defined(MBFUNCTIONS)
+// Convert and restore mapped inconvertible Unicode characters.
+// We use it for extended ASCII names in Unix.
+bool WideToCharMap(const wchar *Src,char *Dest,size_t DestSize,bool &Success)
+{
+ // String with inconvertible characters mapped to private use Unicode area
+ // must have the mark code somewhere.
+ if (wcschr(Src,(wchar)MappedStringMark)==NULL)
+ return false;
+
+ Success=true;
+ uint SrcPos=0,DestPos=0;
+ while (DestPos<DestSize-MB_CUR_MAX)
+ {
+ if (Src[SrcPos]==0)
+ {
+ Dest[DestPos]=0;
+ break;
+ }
+ if (uint(Src[SrcPos])==MappedStringMark)
+ {
+ SrcPos++;
+ continue;
+ }
+ // For security reasons do not retore low ASCII codes, so mapping cannot
+ // be used to hide control codes like path separators.
+ if (uint(Src[SrcPos])>=MapAreaStart+0x80 && uint(Src[SrcPos])<MapAreaStart+0x100)
+ Dest[DestPos++]=char(uint(Src[SrcPos++])-MapAreaStart);
+ else
+ {
+ ignore_result( wctomb(NULL,0) ); // Reset shift state.
+ if (wctomb(Dest+DestPos,Src[SrcPos])==-1)
+ Success=false;
+ SrcPos++;
+ ignore_result( mblen(NULL,0) ); // Reset shift state.
+ int Length=mblen(Dest+DestPos,MB_CUR_MAX);
+ DestPos+=Max(Length,1);
+ }
+ }
+ return true;
+}
+#endif
+
+
+#if defined(_UNIX) && defined(MBFUNCTIONS)
+// Convert and map inconvertible Unicode characters.
+// We use it for extended ASCII names in Unix.
+void CharToWideMap(const char *Src,wchar *Dest,size_t DestSize,bool &Success)
+{
+ // Map inconvertible characters to private use Unicode area 0xE000.
+ // Mark such string by placing special non-character code before
+ // first inconvertible character.
+ Success=false;
+ bool MarkAdded=false;
+ uint SrcPos=0,DestPos=0;
+ while (DestPos<DestSize)
+ {
+ if (Src[SrcPos]==0)
+ {
+ Dest[DestPos]=0;
+ Success=true;
+ break;
+ }
+ ignore_result( mbtowc(NULL,NULL,0) ); // Reset shift state.
+ if (mbtowc(Dest+DestPos,Src+SrcPos,MB_CUR_MAX)==-1)
+ {
+ // For security reasons we do not want to map low ASCII characters,
+ // so we do not have additional .. and path separator codes.
+ if (byte(Src[SrcPos])>=0x80)
+ {
+ if (!MarkAdded)
+ {
+ Dest[DestPos++]=MappedStringMark;
+ MarkAdded=true;
+ if (DestPos>=DestSize)
+ break;
+ }
+ Dest[DestPos++]=byte(Src[SrcPos++])+MapAreaStart;
+ }
+ else
+ break;
+ }
+ else
+ {
+ ignore_result( mblen(NULL,0) ); // Reset shift state.
+ int Length=mblen(Src+SrcPos,MB_CUR_MAX);
+ SrcPos+=Max(Length,1);
+ DestPos++;
+ }
+ }
}
+#endif
// SrcSize is in wide characters, not in bytes.
@@ -161,6 +236,12 @@ void WideToUtf(const wchar *Src,char *Dest,size_t DestSize)
*(Dest++)=(0x80|(c&0x3f));
}
else
+ {
+ if (c>=0xd800 && c<=0xdbff && *Src>=0xdc00 && *Src<=0xdfff) // Surrogate pair.
+ {
+ c=((c-0xd800)<<10)+(*Src-0xdc00)+0x10000;
+ Src++;
+ }
if (c<0x10000 && (dsize-=2)>=0)
{
*(Dest++)=(0xe0|(c>>12));
@@ -175,11 +256,39 @@ void WideToUtf(const wchar *Src,char *Dest,size_t DestSize)
*(Dest++)=(0x80|((c>>6)&0x3f));
*(Dest++)=(0x80|(c&0x3f));
}
+ }
}
*Dest=0;
}
+size_t WideToUtfSize(const wchar *Src)
+{
+ size_t Size=0;
+ for (;*Src!=0;Src++)
+ if (*Src<0x80)
+ Size++;
+ else
+ if (*Src<0x800)
+ Size+=2;
+ else
+ if (*Src<0x10000)
+ {
+ if (Src[0]>=0xd800 && Src[0]<=0xdbff && Src[1]>=0xdc00 && Src[1]<=0xdfff)
+ {
+ Size+=4; // 4 output bytes for Unicode surrogate pair.
+ Src++;
+ }
+ else
+ Size+=3;
+ }
+ else
+ if (*Src<0x200000)
+ Size+=4;
+ return Size+1; // Include terminating zero.
+}
+
+
// Dest can be NULL if we only need to check validity of Src.
bool UtfToWide(const char *Src,wchar *Dest,size_t DestSize)
{
@@ -188,14 +297,17 @@ bool UtfToWide(const char *Src,wchar *Dest,size_t DestSize)
dsize--;
while (*Src!=0)
{
- uint c=(byte)*(Src++),d;
+ uint c=byte(*(Src++)),d;
if (c<0x80)
d=c;
else
if ((c>>5)==6)
{
if ((*Src&0xc0)!=0x80)
+ {
+ Success=false;
break;
+ }
d=((c&0x1f)<<6)|(*Src&0x3f);
Src++;
}
@@ -203,7 +315,10 @@ bool UtfToWide(const char *Src,wchar *Dest,size_t DestSize)
if ((c>>4)==14)
{
if ((Src[0]&0xc0)!=0x80 || (Src[1]&0xc0)!=0x80)
+ {
+ Success=false;
break;
+ }
d=((c&0xf)<<12)|((Src[0]&0x3f)<<6)|(Src[1]&0x3f);
Src+=2;
}
@@ -211,16 +326,17 @@ bool UtfToWide(const char *Src,wchar *Dest,size_t DestSize)
if ((c>>3)==30)
{
if ((Src[0]&0xc0)!=0x80 || (Src[1]&0xc0)!=0x80 || (Src[2]&0xc0)!=0x80)
+ {
+ Success=false;
break;
+ }
d=((c&7)<<18)|((Src[0]&0x3f)<<12)|((Src[1]&0x3f)<<6)|(Src[2]&0x3f);
Src+=3;
}
else
{
- // Skip bad character, but continue processing, so we can handle
- // archived UTF-8 file names even if one of characters is corrupt.
Success=false;
- continue;
+ break;
}
if (Dest!=NULL && --dsize<0)
break;
@@ -228,17 +344,19 @@ bool UtfToWide(const char *Src,wchar *Dest,size_t DestSize)
{
if (Dest!=NULL && --dsize<0)
break;
- if (d>0x10ffff)
+ if (d>0x10ffff) // UTF-8 must end at 0x10ffff according to RFC 3629.
{
- // UTF-8 is restricted by RFC 3629 to end at 0x10ffff.
Success=false;
continue;
}
if (Dest!=NULL)
- {
- *(Dest++)=((d-0x10000)>>10)+0xd800;
- *(Dest++)=(d&0x3ff)+0xdc00;
- }
+ if (sizeof(*Dest)==2) // Use the surrogate pair for 2 byte Unicode.
+ {
+ *(Dest++)=((d-0x10000)>>10)+0xd800;
+ *(Dest++)=(d&0x3ff)+0xdc00;
+ }
+ else
+ *(Dest++)=d;
}
else
if (Dest!=NULL)
@@ -250,91 +368,110 @@ bool UtfToWide(const char *Src,wchar *Dest,size_t DestSize)
}
-bool UnicodeEnabled()
+int wcsicomp(const wchar *s1,const wchar *s2)
{
-#ifdef UNICODE_SUPPORTED
- #ifdef _EMX
- return(uni_ready);
- #else
- return(true);
- #endif
+#ifdef _WIN_ALL
+ return CompareStringW(LOCALE_USER_DEFAULT,NORM_IGNORECASE|SORT_STRINGSORT,s1,-1,s2,-1)-2;
#else
- return(false);
+ while (towupper(*s1)==towupper(*s2))
+ {
+ if (*s1==0)
+ return 0;
+ s1++;
+ s2++;
+ }
+ return s1 < s2 ? -1 : 1;
#endif
}
-int wcsicomp(const wchar *s1,const wchar *s2)
-{
- char Ansi1[NM*sizeof(wchar)],Ansi2[NM*sizeof(wchar)];
- WideToChar(s1,Ansi1,sizeof(Ansi1));
- WideToChar(s2,Ansi2,sizeof(Ansi2));
- return(stricomp(Ansi1,Ansi2));
-}
-
-
-static int wcsnicomp_w2c(const wchar *s1,const wchar *s2,size_t n)
-{
- char Ansi1[NM*2],Ansi2[NM*2];
- GetAsciiName(s1,Ansi1,ASIZE(Ansi1));
- GetAsciiName(s2,Ansi2,ASIZE(Ansi2));
- return(stricomp(Ansi1,Ansi2));
-}
-
-
int wcsnicomp(const wchar *s1,const wchar *s2,size_t n)
{
- return(wcsnicomp_w2c(s1,s2,n));
+#ifdef _WIN_ALL
+ // If we specify 'n' exceeding the actual string length, CompareString goes
+ // beyond the trailing zero and compares garbage. So we need to limit 'n'
+ // to real string length.
+ size_t l1=Min(wcslen(s1)+1,n);
+ size_t l2=Min(wcslen(s2)+1,n);
+ return(CompareStringW(LOCALE_USER_DEFAULT,NORM_IGNORECASE|SORT_STRINGSORT,s1,(int)l1,s2,(int)l2)-2);
+#else
+ if (n==0)
+ return 0;
+ while (towupper(*s1)==towupper(*s2))
+ {
+ if (*s1==0 || --n==0)
+ return 0;
+ s1++;
+ s2++;
+ }
+ return s1 < s2 ? -1 : 1;
+#endif
}
#ifndef SFX_MODULE
-wchar* wcslower(wchar *Str)
+wchar* wcslower(wchar *s)
{
- for (wchar *ChPtr=Str;*ChPtr;ChPtr++)
- if (*ChPtr<128)
- *ChPtr=loctolower((byte)*ChPtr);
- return(Str);
+#ifdef _WIN_ALL
+ CharLowerW(s);
+#else
+ for (wchar *c=s;*c!=0;c++)
+ *c=towlower(*c);
+#endif
+ return s;
}
#endif
#ifndef SFX_MODULE
-wchar* wcsupper(wchar *Str)
+wchar* wcsupper(wchar *s)
{
- for (wchar *ChPtr=Str;*ChPtr;ChPtr++)
- if (*ChPtr<128)
- *ChPtr=loctoupper((byte)*ChPtr);
- return(Str);
+#ifdef _WIN_ALL
+ CharUpperW(s);
+#else
+ for (wchar *c=s;*c!=0;c++)
+ *c=towupper(*c);
+#endif
+ return s;
}
#endif
int toupperw(int ch)
{
- return((ch<128) ? loctoupper(ch):ch);
+#ifdef _WIN_ALL
+ return (int)CharUpperW((wchar *)ch);
+#else
+ return towupper(ch);
+#endif
}
int tolowerw(int ch)
{
#ifdef _WIN_ALL
- return((int)(LPARAM)CharLowerW((wchar *)(uint)ch));
+ return (int)CharLowerW((wchar *)ch);
#else
- return((ch<128) ? loctolower(ch):ch);
+ return towlower(ch);
#endif
}
-int atoiw(const wchar *s)
+uint atoiw(const wchar *s)
+{
+ return (uint)atoilw(s);
+}
+
+
+uint64 atoilw(const wchar *s)
{
- int n=0;
+ uint64 n=0;
while (*s>='0' && *s<='9')
{
n=n*10+(*s-'0');
s++;
}
- return(n);
+ return n;
}
diff --git a/src/thirdparty/unrar/unicode.hpp b/src/thirdparty/unrar/unicode.hpp
index 6e4b62289..0e0bf963c 100644
--- a/src/thirdparty/unrar/unicode.hpp
+++ b/src/thirdparty/unrar/unicode.hpp
@@ -1,55 +1,26 @@
#ifndef _RAR_UNICODE_
#define _RAR_UNICODE_
-#ifndef _EMX
-#define MBFUNCTIONS
-#endif
-
-#if defined(MBFUNCTIONS) || defined(_WIN_ALL) || defined(_EMX) && !defined(_DJGPP)
-#define UNICODE_SUPPORTED
-#endif
-
-#if !defined(SFX_MODULE) && (defined(_MSC_VER) || defined(__BORLANDC__))
-// If C_UNICODE_RTL is defined, we can use library Unicode functions like
-// wcscpy. Otherwise, for compatibility with old compilers or for removing
-// RTL to reduce SFX module size, we need need to use our own implementations.
-#define C_UNICODE_RTL
-#endif
-
#ifdef _WIN_ALL
#define DBCS_SUPPORTED
#endif
-#ifdef _EMX
-int uni_init(int codepage);
-int uni_done();
-#endif
-
-#ifdef __BORLANDC__
-// Borland C++ Builder 5 uses the old style swprintf without the buffer size,
-// so we replace it with snwprintf in our custom sprintfw definition.
-#define sprintfw snwprintf
-#elif defined (__OpenBSD__)
-#define sprintfw(s,...) *(s)=0
-#else
-#define sprintfw swprintf
-#endif
-
-bool WideToChar(const wchar *Src,char *Dest,size_t DestSize=0x1000000);
-bool CharToWide(const char *Src,wchar *Dest,size_t DestSize=0x1000000);
-byte* WideToRaw(const wchar *Src,byte *Dest,size_t SrcSize=0x1000000);
-wchar* RawToWide(const byte *Src,wchar *Dest,size_t DestSize=0x1000000);
+bool WideToChar(const wchar *Src,char *Dest,size_t DestSize);
+bool CharToWide(const char *Src,wchar *Dest,size_t DestSize);
+byte* WideToRaw(const wchar *Src,byte *Dest,size_t SrcSize);
+wchar* RawToWide(const byte *Src,wchar *Dest,size_t DestSize);
void WideToUtf(const wchar *Src,char *Dest,size_t DestSize);
+size_t WideToUtfSize(const wchar *Src);
bool UtfToWide(const char *Src,wchar *Dest,size_t DestSize);
-bool UnicodeEnabled();
int wcsicomp(const wchar *s1,const wchar *s2);
int wcsnicomp(const wchar *s1,const wchar *s2,size_t n);
-wchar* wcslower(wchar *Str);
-wchar* wcsupper(wchar *Str);
+wchar* wcslower(wchar *s);
+wchar* wcsupper(wchar *s);
int toupperw(int ch);
int tolowerw(int ch);
-int atoiw(const wchar *s);
+uint atoiw(const wchar *s);
+uint64 atoilw(const wchar *s);
#ifdef DBCS_SUPPORTED
class SupportDBCS
diff --git a/src/thirdparty/unrar/unios2.cpp b/src/thirdparty/unrar/unios2.cpp
deleted file mode 100644
index 1261473ba..000000000
--- a/src/thirdparty/unrar/unios2.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-// (c) 2001,2004 by Max Alekseyev
-// ver. 2.1
-
-#include <stddef.h>
-
-#define INCL_DOSMODULEMGR
-#include <os2.h>
-
-typedef void* UconvObject;
-typedef unsigned short UniChar;
-
-int uni_init(int codepage);
-
-int uni_done();
-
-int uni_toucs( /* translate to Unicode */
- char*, /* I - input string */
- size_t, /* I - length of input string (chars) */
- UniChar*, /* O - output Unicode string */
- size_t* ); /* O - length of output string (UniChars) */
-
-int uni_fromucs( /* translate from Unicode */
- UniChar*, /* I - input Unicode string */
- size_t, /* I - length of input string (UniChars) */
- char*, /* O - output string */
- size_t* ); /* O - length of output string (chars) */
-
-/* IMPLEMENTATION */
-
-static int (*uniMapCpToUcsCp) (
- unsigned long, /* I - Codepage to convert */
- UniChar*, /* O - Output buffer */
- size_t ); /* I - UniChars in output buffer */
-
-static int (*uniCreateUconvObject) (
- UniChar*, /* I - Unicode name of uconv table */
- UconvObject* );/* O - Uconv object handle */
-
-static int (*uniFreeUconvObject) (
- UconvObject ); /* I - Uconv object handle */
-
-static int (*uniUconvToUcs) (
- UconvObject, /* I - Uconv object handle */
- void**, /* IO - Input buffer */
- size_t*, /* IO - Input buffer size (bytes) */
- UniChar**, /* IO - Output buffer size */
- size_t*, /* IO - Output size (chars) */
- size_t* ); /* IO - Substitution count */
-
-static int (*uniUconvFromUcs) (
- UconvObject, /* I - Uconv object handle */
- UniChar**, /* IO - Input buffer */
- size_t*, /* IO - Input buffer size (bytes) */
- void**, /* IO - Output buffer size */
- size_t*, /* IO - Output size (chars) */
- size_t* ); /* IO - Substitution count */
-
-static int uni_ready = 0;
-static HMODULE uni_UCONV;
-static UconvObject uni_obj;
-
-int uni_init(int codepage) {
- UniChar unistr[256];
-
- uni_ready = 0;
-
- if(!&DosLoadModule) {
- /* DOS enviroment detected */
- return -1;
- }
-
- if( DosLoadModule(0,0,(PCSZ)"UCONV",&uni_UCONV) ) {
- /* no Unicode API found (obsolete OS/2 version) */
- return -2;
- }
-
- if( !DosQueryProcAddr(uni_UCONV,0,(PCSZ)"UniMapCpToUcsCp", (PPFN)&uniMapCpToUcsCp ) &&
- !DosQueryProcAddr(uni_UCONV,0,(PCSZ)"UniUconvToUcs", (PPFN)&uniUconvToUcs ) &&
- !DosQueryProcAddr(uni_UCONV,0,(PCSZ)"UniUconvFromUcs", (PPFN)&uniUconvFromUcs ) &&
- !DosQueryProcAddr(uni_UCONV,0,(PCSZ)"UniCreateUconvObject",(PPFN)&uniCreateUconvObject) &&
- !DosQueryProcAddr(uni_UCONV,0,(PCSZ)"UniFreeUconvObject", (PPFN)&uniFreeUconvObject )
- ) {
- unistr[0] = 0;
- if( (!codepage || !uniMapCpToUcsCp(codepage, unistr, 256)) && !uniCreateUconvObject(unistr,&uni_obj) ) {
- uni_ready = 1;
- return 0;
- }
- }
- DosFreeModule(uni_UCONV);
- return -2;
-}
-
-int uni_toucs(char* src, size_t srclen, UniChar* dst, size_t* dstlen) {
- size_t srcbytes, srcsize, dstsize, subsc=0;
-
- if(!uni_ready) return -1;
-
- dstsize = srcbytes = srclen * sizeof(UniChar);
-
- if( uniUconvToUcs(uni_obj,(void**)&src,&srclen,&dst,&dstsize,&subsc) ) {
- return -1;
- }
- *dstlen = srcbytes - dstsize;
- return 0;
-}
-
-int uni_fromucs(UniChar* src, size_t srclen, char* dst, size_t* dstlen) {
- size_t srcbytes, srcsize, dstsize, subsc=0;
-
- if(!uni_ready) return -1;
-
- dstsize = srcbytes = *dstlen;
-
- if( uniUconvFromUcs(uni_obj,&src,&srclen,(void**)&dst,&dstsize,&subsc) ) {
- return -1;
- }
- *dstlen = srcbytes - dstsize;
- return 0;
-}
-
-int uni_done() {
- if( uni_ready ) {
- uniFreeUconvObject(uni_obj);
- DosFreeModule(uni_UCONV);
- uni_ready = 0;
- }
- return 0;
-}
diff --git a/src/thirdparty/unrar/unpack.cpp b/src/thirdparty/unrar/unpack.cpp
index 350d8951f..a20d37f9e 100644
--- a/src/thirdparty/unrar/unpack.cpp
+++ b/src/thirdparty/unrar/unpack.cpp
@@ -3,48 +3,106 @@
#include "coder.cpp"
#include "suballoc.cpp"
#include "model.cpp"
+#include "unpackinline.cpp"
+#ifdef RAR_SMP
+#include "unpack50mt.cpp"
+#endif
#ifndef SFX_MODULE
#include "unpack15.cpp"
#include "unpack20.cpp"
#endif
+#include "unpack30.cpp"
+#include "unpack50.cpp"
Unpack::Unpack(ComprDataIO *DataIO)
+:Inp(true),VMCodeInp(true)
{
UnpIO=DataIO;
Window=NULL;
Suspended=false;
UnpAllBuf=false;
UnpSomeRead=false;
+#ifdef RAR_SMP
+ MaxUserThreads=1;
+ UnpThreadPool=CreateThreadPool();
+ ReadBufMT=NULL;
+ UnpThreadData=NULL;
+#endif
+ MaxWinSize=0;
+ MaxWinMask=0;
}
Unpack::~Unpack()
{
+ InitFilters30();
+
delete[] Window;
- InitFilters();
+#ifdef RAR_SMP
+ DestroyThreadPool(UnpThreadPool);
+ delete[] ReadBufMT;
+ delete[] UnpThreadData;
+#endif
}
-void Unpack::Init()
+void Unpack::Init(size_t WinSize,bool Solid)
{
- Window=new byte[MAXWINSIZE];
+ if (Window==NULL) // Perform initialization, which should be done only once for all files.
+ {
+ // Prevent crash if DoUnpack is later called with wrong 'Solid' value.
+ UnpInitData(false);
+#ifndef SFX_MODULE
+ // RAR 1.5 decompression initialization
+ UnpInitData15(false);
+ InitHuff();
+#endif
+ }
-#ifndef ALLOW_EXCEPTIONS
- if (Window==NULL)
+ // If 32-bit RAR unpacks an archive with 4 GB dictionary, the window size
+ // will be 0 because of size_t overflow. Let's issue the memory error.
+ if (WinSize==0)
ErrHandler.MemoryError();
-#endif
+
+ // Minimum window size must be at least twice more than maximum possible
+ // size of filter block, which is 0x10000 in RAR now. If window size is
+ // smaller, we can have a block with never cleared flt->NextWindow flag
+ // in UnpWriteBuf(). Minimum window size 0x20000 would be enough, but let's
+ // use 0x40000 for extra safety and possible filter area size expansion.
+ const size_t MinAllocSize=0x40000;
+ if (WinSize<MinAllocSize)
+ WinSize=MinAllocSize;
+
+ if (WinSize<=MaxWinSize) // Use the already allocated window.
+ return;
+ if ((WinSize>>16)>0x10000) // Window size must not exceed 4 GB.
+ return;
+
+ // Archiving code guarantees that window size does not grow in the same
+ // solid stream. So if we are here, we are either creating a new window
+ // or increasing the size of non-solid window. So we could safely reject
+ // current window data without copying them to a new window, though being
+ // extra cautious, we still handle the solid window grow case below.
+
+ byte *NewWindow=new byte[WinSize];
// Clean the window to generate the same output when unpacking corrupt
// RAR files, which may access to unused areas of sliding dictionary.
- memset(Window,0,MAXWINSIZE);
+ memset(NewWindow,0,WinSize);
- UnpInitData(false);
+ // If Window is not NULL, it means that window size has grown.
+ // In solid streams we need to copy data to a new window in such case.
+ // 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 (Solid && Window!=NULL)
+ for (size_t I=1;I<MaxWinSize;I++)
+ NewWindow[(UnpPtr-I)&(WinSize-1)]=Window[(UnpPtr-I)&(MaxWinSize-1)];
-#ifndef SFX_MODULE
- // RAR 1.5 decompression initialization
- OldUnpInitData(false);
- InitHuff();
-#endif
+ delete Window;
+ Window=NewWindow;
+
+ MaxWinSize=WinSize;
+ MaxWinMask=MaxWinSize-1;
}
@@ -62,988 +120,47 @@ void Unpack::DoUnpack(int Method,bool Solid)
break;
#endif
case 29: // rar 3.x compression
- case 36: // alternative hash
Unpack29(Solid);
break;
- }
-}
-
-
-inline void Unpack::InsertOldDist(unsigned int Distance)
-{
- OldDist[3]=OldDist[2];
- OldDist[2]=OldDist[1];
- OldDist[1]=OldDist[0];
- OldDist[0]=Distance;
-}
-
-
-_forceinline void Unpack::CopyString(uint Length,uint Distance)
-{
- uint SrcPtr=UnpPtr-Distance;
- if (SrcPtr<MAXWINSIZE-MAX_LZ_MATCH && UnpPtr<MAXWINSIZE-MAX_LZ_MATCH)
- {
- // If we are not close to end of window, we do not need to waste time
- // to "& MAXWINMASK" pointer protection.
-
- byte *Src=Window+SrcPtr;
- byte *Dest=Window+UnpPtr;
- UnpPtr+=Length;
-
- while (Length>=8)
- {
- // Unroll the loop for 8 byte and longer strings.
- Dest[0]=Src[0];
- Dest[1]=Src[1];
- Dest[2]=Src[2];
- Dest[3]=Src[3];
- Dest[4]=Src[4];
- Dest[5]=Src[5];
- Dest[6]=Src[6];
- Dest[7]=Src[7];
- Src+=8;
- Dest+=8;
- Length-=8;
- }
-
- // Unroll the loop for 0 - 7 bytes left. Note that we use nested "if"s.
- if (Length>0) { Dest[0]=Src[0];
- if (Length>1) { Dest[1]=Src[1];
- if (Length>2) { Dest[2]=Src[2];
- if (Length>3) { Dest[3]=Src[3];
- if (Length>4) { Dest[4]=Src[4];
- if (Length>5) { Dest[5]=Src[5];
- if (Length>6) { Dest[6]=Src[6]; } } } } } } } // Close all nested "if"s.
- }
- else
- while (Length--) // Slow copying with all possible precautions.
- {
- Window[UnpPtr]=Window[SrcPtr++ & MAXWINMASK];
- UnpPtr=(UnpPtr+1) & MAXWINMASK;
- }
-}
-
-
-_forceinline uint Unpack::DecodeNumber(DecodeTable *Dec)
-{
- // Left aligned 15 bit length raw bit field.
- uint BitField=getbits() & 0xfffe;
-
- if (BitField<Dec->DecodeLen[Dec->QuickBits])
- {
- uint Code=BitField>>(16-Dec->QuickBits);
- addbits(Dec->QuickLen[Code]);
- return Dec->QuickNum[Code];
- }
-
- // Detect the real bit length for current code.
- uint Bits=15;
- for (uint I=Dec->QuickBits+1;I<15;I++)
- if (BitField<Dec->DecodeLen[I])
- {
- Bits=I;
- break;
- }
-
- addbits(Bits);
-
- // Calculate the distance from the start code for current bit length.
- uint Dist=BitField-Dec->DecodeLen[Bits-1];
-
- // Start codes are left aligned, but we need the normal right aligned
- // number. So we shift the distance to the right.
- Dist>>=(16-Bits);
-
- // Now we can calculate the position in the code list. It is the sum
- // of first position for current bit length and right aligned distance
- // between our bit field and start code for current bit length.
- uint Pos=Dec->DecodePos[Bits]+Dist;
-
- // Out of bounds safety check required for damaged archives.
- if (Pos>=Dec->MaxNum)
- Pos=0;
-
- // Convert the position in the code list to position in alphabet
- // and return it.
- return(Dec->DecodeNum[Pos]);
-}
-
-
-// We use it instead of direct PPM.DecodeChar call to be sure that
-// we reset PPM structures in case of corrupt data. It is important,
-// because these structures can be invalid after PPM.DecodeChar returned -1.
-inline int Unpack::SafePPMDecodeChar()
-{
- int Ch=PPM.DecodeChar();
- if (Ch==-1) // Corrupt PPM data found.
- {
- PPM.CleanUp(); // Reset possibly corrupt PPM data structures.
- UnpBlockType=BLOCK_LZ; // Set faster and more fail proof LZ mode.
- }
- return(Ch);
-}
-
-
-void Unpack::Unpack29(bool Solid)
-{
- static unsigned char LDecode[]={0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224};
- static unsigned char LBits[]= {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5};
- static int DDecode[DC];
- static byte DBits[DC];
- static int DBitLengthCounts[]= {4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,14,0,12};
- static unsigned char SDDecode[]={0,4,8,16,32,64,128,192};
- static unsigned char SDBits[]= {2,2,3, 4, 5, 6, 6, 6};
- unsigned int Bits;
-
- if (DDecode[1]==0)
- {
- int Dist=0,BitLength=0,Slot=0;
- for (int I=0;I<ASIZE(DBitLengthCounts);I++,BitLength++)
- for (int J=0;J<DBitLengthCounts[I];J++,Slot++,Dist+=(1<<BitLength))
- {
- DDecode[Slot]=Dist;
- DBits[Slot]=BitLength;
- }
- }
-
- FileExtracted=true;
-
- if (!Suspended)
- {
- UnpInitData(Solid);
- if (!UnpReadBuf())
- return;
- if ((!Solid || !TablesRead) && !ReadTables())
- return;
- }
-
- while (true)
- {
- UnpPtr&=MAXWINMASK;
-
- if (InAddr>ReadBorder)
- {
- if (!UnpReadBuf())
- break;
- }
- if (((WrPtr-UnpPtr) & MAXWINMASK)<260 && WrPtr!=UnpPtr)
- {
- UnpWriteBuf();
- if (WrittenFileSize>DestUnpSize)
- return;
- if (Suspended)
- {
- FileExtracted=false;
- return;
- }
- }
- if (UnpBlockType==BLOCK_PPM)
- {
- // Here speed is critical, so we do not use SafePPMDecodeChar,
- // because sometimes even the inline function can introduce
- // some additional penalty.
- int Ch=PPM.DecodeChar();
- if (Ch==-1) // Corrupt PPM data found.
- {
- PPM.CleanUp(); // Reset possibly corrupt PPM data structures.
- UnpBlockType=BLOCK_LZ; // Set faster and more fail proof LZ mode.
- break;
- }
- if (Ch==PPMEscChar)
- {
- int NextCh=SafePPMDecodeChar();
- if (NextCh==0) // End of PPM encoding.
+ case 0: // RAR 5.0 compression algorithm 0.
+#ifdef RAR_SMP
+ if (MaxUserThreads>1)
{
- if (!ReadTables())
- break;
- continue;
- }
- if (NextCh==-1) // Corrupt PPM data found.
+ Unpack5MT(Solid);
break;
- if (NextCh==2) // End of file in PPM mode.
- break;
- if (NextCh==3) // Read VM code.
- {
- if (!ReadVMCodePPM())
- break;
- continue;
- }
- if (NextCh==4) // LZ inside of PPM.
- {
- unsigned int Distance=0,Length;
- bool Failed=false;
- for (int I=0;I<4 && !Failed;I++)
- {
- int Ch=SafePPMDecodeChar();
- if (Ch==-1)
- Failed=true;
- else
- if (I==3)
- Length=(byte)Ch;
- else
- Distance=(Distance<<8)+(byte)Ch;
- }
- if (Failed)
- break;
-
- CopyString(Length+32,Distance+2);
- continue;
- }
- if (NextCh==5) // One byte distance match (RLE) inside of PPM.
- {
- int Length=SafePPMDecodeChar();
- if (Length==-1)
- break;
- CopyString(Length+4,1);
- continue;
- }
- // If we are here, NextCh must be 1, what means that current byte
- // is equal to our 'escape' byte, so we just store it to Window.
- }
- Window[UnpPtr++]=Ch;
- continue;
- }
-
- int Number=DecodeNumber(&LD);
- if (Number<256)
- {
- Window[UnpPtr++]=(byte)Number;
- continue;
- }
- if (Number>=271)
- {
- int Length=LDecode[Number-=271]+3;
- if ((Bits=LBits[Number])>0)
- {
- Length+=getbits()>>(16-Bits);
- addbits(Bits);
- }
-
- int DistNumber=DecodeNumber(&DD);
- unsigned int Distance=DDecode[DistNumber]+1;
- if ((Bits=DBits[DistNumber])>0)
- {
- if (DistNumber>9)
- {
- if (Bits>4)
- {
- Distance+=((getbits()>>(20-Bits))<<4);
- addbits(Bits-4);
- }
- if (LowDistRepCount>0)
- {
- LowDistRepCount--;
- Distance+=PrevLowDist;
- }
- else
- {
- int LowDist=DecodeNumber(&LDD);
- if (LowDist==16)
- {
- LowDistRepCount=LOW_DIST_REP_COUNT-1;
- Distance+=PrevLowDist;
- }
- else
- {
- Distance+=LowDist;
- PrevLowDist=LowDist;
- }
- }
}
- else
- {
- Distance+=getbits()>>(16-Bits);
- addbits(Bits);
- }
- }
-
- if (Distance>=0x2000)
- {
- Length++;
- if (Distance>=0x40000L)
- Length++;
- }
-
- InsertOldDist(Distance);
- LastLength=Length;
- CopyString(Length,Distance);
- continue;
- }
- if (Number==256)
- {
- if (!ReadEndOfBlock())
- break;
- continue;
- }
- if (Number==257)
- {
- if (!ReadVMCode())
- break;
- continue;
- }
- if (Number==258)
- {
- if (LastLength!=0)
- CopyString(LastLength,OldDist[0]);
- continue;
- }
- if (Number<263)
- {
- int DistNum=Number-259;
- unsigned int Distance=OldDist[DistNum];
- for (int I=DistNum;I>0;I--)
- OldDist[I]=OldDist[I-1];
- OldDist[0]=Distance;
-
- int LengthNumber=DecodeNumber(&RD);
- int Length=LDecode[LengthNumber]+2;
- if ((Bits=LBits[LengthNumber])>0)
- {
- Length+=getbits()>>(16-Bits);
- addbits(Bits);
- }
- LastLength=Length;
- CopyString(Length,Distance);
- continue;
- }
- if (Number<272)
- {
- unsigned int Distance=SDDecode[Number-=263]+1;
- if ((Bits=SDBits[Number])>0)
- {
- Distance+=getbits()>>(16-Bits);
- addbits(Bits);
- }
- InsertOldDist(Distance);
- LastLength=2;
- CopyString(2,Distance);
- continue;
- }
- }
- UnpWriteBuf();
-}
-
-
-// Return 'false' to quit unpacking the current file or 'true' to continue.
-bool Unpack::ReadEndOfBlock()
-{
- unsigned int BitField=getbits();
- bool NewTable,NewFile=false;
-
- // "1" - no new file, new table just here.
- // "00" - new file, no new table.
- // "01" - new file, new table (in beginning of next file).
-
- if ((BitField & 0x8000)!=0)
- {
- NewTable=true;
- addbits(1);
- }
- else
- {
- NewFile=true;
- NewTable=(BitField & 0x4000)!=0;
- addbits(2);
- }
- TablesRead=!NewTable;
-
- // Quit immediately if "new file" flag is set. If "new table" flag
- // is present, we'll read the table in beginning of next file
- // based on 'TablesRead' 'false' value.
- if (NewFile)
- return false;
- return ReadTables(); // Quit only if we failed to read tables.
-}
-
-
-bool Unpack::ReadVMCode()
-{
- // Entire VM code is guaranteed to fully present in block defined
- // by current Huffman table. Compressor checks that VM code does not cross
- // Huffman block boundaries.
- unsigned int FirstByte=getbits()>>8;
- addbits(8);
- int Length=(FirstByte & 7)+1;
- if (Length==7)
- {
- Length=(getbits()>>8)+7;
- addbits(8);
- }
- else
- if (Length==8)
- {
- Length=getbits();
- addbits(16);
- }
- Array<byte> VMCode(Length);
- for (int I=0;I<Length;I++)
- {
- // 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 (InAddr>=ReadTop-1 && !UnpReadBuf() && I<Length-1)
- return(false);
- VMCode[I]=getbits()>>8;
- addbits(8);
- }
- return(AddVMCode(FirstByte,&VMCode[0],Length));
-}
-
-
-bool Unpack::ReadVMCodePPM()
-{
- unsigned int FirstByte=SafePPMDecodeChar();
- if ((int)FirstByte==-1)
- return(false);
- int Length=(FirstByte & 7)+1;
- if (Length==7)
- {
- int B1=SafePPMDecodeChar();
- if (B1==-1)
- return(false);
- Length=B1+7;
- }
- else
- if (Length==8)
- {
- int B1=SafePPMDecodeChar();
- if (B1==-1)
- return(false);
- int B2=SafePPMDecodeChar();
- if (B2==-1)
- return(false);
- Length=B1*256+B2;
- }
- Array<byte> VMCode(Length);
- for (int I=0;I<Length;I++)
- {
- int Ch=SafePPMDecodeChar();
- if (Ch==-1)
- return(false);
- VMCode[I]=Ch;
- }
- return(AddVMCode(FirstByte,&VMCode[0],Length));
-}
-
-
-bool Unpack::AddVMCode(unsigned int FirstByte,byte *Code,int CodeSize)
-{
- VMCodeInp.InitBitInput();
- memcpy(VMCodeInp.InBuf,Code,Min(BitInput::MAX_SIZE,CodeSize));
- VM.Init();
-
- uint FiltPos;
- if (FirstByte & 0x80)
- {
- FiltPos=RarVM::ReadData(VMCodeInp);
- if (FiltPos==0)
- InitFilters();
- else
- FiltPos--;
- }
- else
- FiltPos=LastFilter; // Use the same filter as last time.
-
- if (FiltPos>Filters.Size() || FiltPos>OldFilterLengths.Size())
- return(false);
- LastFilter=FiltPos;
- bool NewFilter=(FiltPos==Filters.Size());
-
- UnpackFilter *StackFilter=new UnpackFilter; // New filter for PrgStack.
-
- UnpackFilter *Filter;
- if (NewFilter) // New filter code, never used before since VM reset.
- {
- // Too many different filters, corrupt archive.
- if (FiltPos>MAX_FILTERS)
- {
- delete StackFilter;
- return false;
- }
-
- Filters.Add(1);
- Filters[Filters.Size()-1]=Filter=new UnpackFilter;
- StackFilter->ParentFilter=(uint)(Filters.Size()-1);
-
- // Reserve one item, where we store the data block length of our new
- // filter entry. We'll set it to real block length below, after reading
- // it. But we need to initialize it now, because when processing corrupt
- // data, we can access this item even before we set it to real value.
- OldFilterLengths.Push(0);
- Filter->ExecCount=0;
- }
- else // Filter was used in the past.
- {
- Filter=Filters[FiltPos];
- StackFilter->ParentFilter=FiltPos;
- Filter->ExecCount++;
- }
-
- int EmptyCount=0;
- for (uint I=0;I<PrgStack.Size();I++)
- {
- PrgStack[I-EmptyCount]=PrgStack[I];
- if (PrgStack[I]==NULL)
- EmptyCount++;
- if (EmptyCount>0)
- PrgStack[I]=NULL;
- }
- if (EmptyCount==0)
- {
- PrgStack.Add(1);
- EmptyCount=1;
- }
- int StackPos=(int)(PrgStack.Size()-EmptyCount);
- PrgStack[StackPos]=StackFilter;
- StackFilter->ExecCount=Filter->ExecCount;
-
- uint BlockStart=RarVM::ReadData(VMCodeInp);
- if (FirstByte & 0x40)
- BlockStart+=258;
- StackFilter->BlockStart=(BlockStart+UnpPtr)&MAXWINMASK;
- if (FirstByte & 0x20)
- {
- StackFilter->BlockLength=RarVM::ReadData(VMCodeInp);
-
- // Store the last data block length for current filter.
- OldFilterLengths[FiltPos]=StackFilter->BlockLength;
- }
- else
- {
- // Set the data block size to same value as the previous block size
- // for same filter. It is possible on corrupt data to access here a new
- // and not filled yet item of OldFilterLengths array. This is why above
- // we set new OldFilterLengths items to zero.
- StackFilter->BlockLength=FiltPos<OldFilterLengths.Size() ? OldFilterLengths[FiltPos]:0;
- }
-
- StackFilter->NextWindow=WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MAXWINMASK)<=BlockStart;
-
-// DebugLog("\nNextWindow: UnpPtr=%08x WrPtr=%08x BlockStart=%08x",UnpPtr,WrPtr,BlockStart);
-
- memset(StackFilter->Prg.InitR,0,sizeof(StackFilter->Prg.InitR));
- StackFilter->Prg.InitR[3]=VM_GLOBALMEMADDR;
- StackFilter->Prg.InitR[4]=StackFilter->BlockLength;
- StackFilter->Prg.InitR[5]=StackFilter->ExecCount;
-
- if (FirstByte & 0x10) // set registers to optional parameters if any
- {
- unsigned int InitMask=VMCodeInp.fgetbits()>>9;
- VMCodeInp.faddbits(7);
- for (int I=0;I<7;I++)
- if (InitMask & (1<<I))
- StackFilter->Prg.InitR[I]=RarVM::ReadData(VMCodeInp);
- }
-
- if (NewFilter)
- {
- uint VMCodeSize=RarVM::ReadData(VMCodeInp);
- if (VMCodeSize>=0x10000 || VMCodeSize==0)
- return(false);
- Array<byte> VMCode(VMCodeSize);
- for (uint I=0;I<VMCodeSize;I++)
- {
- if (VMCodeInp.Overflow(3))
- return(false);
- VMCode[I]=VMCodeInp.fgetbits()>>8;
- VMCodeInp.faddbits(8);
- }
- VM.Prepare(&VMCode[0],VMCodeSize,&Filter->Prg);
- }
- StackFilter->Prg.AltCmd=&Filter->Prg.Cmd[0];
- StackFilter->Prg.CmdCount=Filter->Prg.CmdCount;
-
- size_t StaticDataSize=Filter->Prg.StaticData.Size();
- if (StaticDataSize>0 && StaticDataSize<VM_GLOBALMEMSIZE)
- {
- // read statically defined data contained in DB commands
- StackFilter->Prg.StaticData.Add(StaticDataSize);
- memcpy(&StackFilter->Prg.StaticData[0],&Filter->Prg.StaticData[0],StaticDataSize);
- }
-
- if (StackFilter->Prg.GlobalData.Size()<VM_FIXEDGLOBALSIZE)
- {
- StackFilter->Prg.GlobalData.Reset();
- StackFilter->Prg.GlobalData.Add(VM_FIXEDGLOBALSIZE);
- }
- byte *GlobalData=&StackFilter->Prg.GlobalData[0];
- for (int I=0;I<7;I++)
- VM.SetLowEndianValue((uint *)&GlobalData[I*4],StackFilter->Prg.InitR[I]);
- VM.SetLowEndianValue((uint *)&GlobalData[0x1c],StackFilter->BlockLength);
- VM.SetLowEndianValue((uint *)&GlobalData[0x20],0);
- VM.SetLowEndianValue((uint *)&GlobalData[0x2c],StackFilter->ExecCount);
- memset(&GlobalData[0x30],0,16);
-
- if (FirstByte & 8) // Put the data block passed as parameter if any.
- {
- if (VMCodeInp.Overflow(3))
- return(false);
- uint DataSize=RarVM::ReadData(VMCodeInp);
- if (DataSize>VM_GLOBALMEMSIZE-VM_FIXEDGLOBALSIZE)
- return(false);
- size_t CurSize=StackFilter->Prg.GlobalData.Size();
- if (CurSize<DataSize+VM_FIXEDGLOBALSIZE)
- StackFilter->Prg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize);
- byte *GlobalData=&StackFilter->Prg.GlobalData[VM_FIXEDGLOBALSIZE];
- for (uint I=0;I<DataSize;I++)
- {
- if (VMCodeInp.Overflow(3))
- return(false);
- GlobalData[I]=VMCodeInp.fgetbits()>>8;
- VMCodeInp.faddbits(8);
- }
- }
- return(true);
-}
-
-
-bool Unpack::UnpReadBuf()
-{
- int DataSize=ReadTop-InAddr; // Data left to process.
- if (DataSize<0)
- return(false);
- if (InAddr>BitInput::MAX_SIZE/2)
- {
- // If we already processed more than half of buffer, let's move
- // remaining data into beginning to free more space for new data.
- if (DataSize>0)
- memmove(InBuf,InBuf+InAddr,DataSize);
- InAddr=0;
- ReadTop=DataSize;
- }
- else
- DataSize=ReadTop;
- int ReadCode=UnpIO->UnpRead(InBuf+DataSize,(BitInput::MAX_SIZE-DataSize)&~0xf);
- if (ReadCode>0)
- ReadTop+=ReadCode;
- ReadBorder=ReadTop-30;
- return(ReadCode!=-1);
-}
-
-
-void Unpack::UnpWriteBuf()
-{
- unsigned int WrittenBorder=WrPtr;
- unsigned int WriteSize=(UnpPtr-WrittenBorder)&MAXWINMASK;
- for (size_t I=0;I<PrgStack.Size();I++)
- {
- // Here we apply filters to data which we need to write.
- // We always copy data to virtual machine memory 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.
-
- UnpackFilter *flt=PrgStack[I];
- if (flt==NULL)
- continue;
- if (flt->NextWindow)
- {
- flt->NextWindow=false;
- continue;
- }
- unsigned int BlockStart=flt->BlockStart;
- unsigned int BlockLength=flt->BlockLength;
- if (((BlockStart-WrittenBorder)&MAXWINMASK)<WriteSize)
- {
- if (WrittenBorder!=BlockStart)
- {
- UnpWriteArea(WrittenBorder,BlockStart);
- WrittenBorder=BlockStart;
- WriteSize=(UnpPtr-WrittenBorder)&MAXWINMASK;
- }
- if (BlockLength<=WriteSize)
- {
- unsigned int BlockEnd=(BlockStart+BlockLength)&MAXWINMASK;
- if (BlockStart<BlockEnd || BlockEnd==0)
- VM.SetMemory(0,Window+BlockStart,BlockLength);
- else
- {
- unsigned int FirstPartLength=MAXWINSIZE-BlockStart;
- VM.SetMemory(0,Window+BlockStart,FirstPartLength);
- VM.SetMemory(FirstPartLength,Window,BlockEnd);
- }
-
- VM_PreparedProgram *ParentPrg=&Filters[flt->ParentFilter]->Prg;
- VM_PreparedProgram *Prg=&flt->Prg;
-
- if (ParentPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE)
- {
- // Copy global data from previous script execution if any.
- Prg->GlobalData.Alloc(ParentPrg->GlobalData.Size());
- memcpy(&Prg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE);
- }
-
- ExecuteCode(Prg);
-
- if (Prg->GlobalData.Size()>VM_FIXEDGLOBALSIZE)
- {
- // Save global data for next script execution.
- if (ParentPrg->GlobalData.Size()<Prg->GlobalData.Size())
- ParentPrg->GlobalData.Alloc(Prg->GlobalData.Size());
- memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&Prg->GlobalData[VM_FIXEDGLOBALSIZE],Prg->GlobalData.Size()-VM_FIXEDGLOBALSIZE);
- }
- else
- ParentPrg->GlobalData.Reset();
-
- byte *FilteredData=Prg->FilteredData;
- unsigned int FilteredDataSize=Prg->FilteredDataSize;
-
- delete PrgStack[I];
- PrgStack[I]=NULL;
- while (I+1<PrgStack.Size())
- {
- UnpackFilter *NextFilter=PrgStack[I+1];
- if (NextFilter==NULL || NextFilter->BlockStart!=BlockStart ||
- NextFilter->BlockLength!=FilteredDataSize || NextFilter->NextWindow)
- break;
-
- // Apply several filters to same data block.
-
- VM.SetMemory(0,FilteredData,FilteredDataSize);
-
- VM_PreparedProgram *ParentPrg=&Filters[NextFilter->ParentFilter]->Prg;
- VM_PreparedProgram *NextPrg=&NextFilter->Prg;
-
- if (ParentPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE)
- {
- // Copy global data from previous script execution if any.
- NextPrg->GlobalData.Alloc(ParentPrg->GlobalData.Size());
- memcpy(&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE);
- }
-
- ExecuteCode(NextPrg);
-
- if (NextPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE)
- {
- // Save global data for next script execution.
- if (ParentPrg->GlobalData.Size()<NextPrg->GlobalData.Size())
- ParentPrg->GlobalData.Alloc(NextPrg->GlobalData.Size());
- memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],NextPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE);
- }
- else
- ParentPrg->GlobalData.Reset();
-
- FilteredData=NextPrg->FilteredData;
- FilteredDataSize=NextPrg->FilteredDataSize;
- I++;
- delete PrgStack[I];
- PrgStack[I]=NULL;
- }
- UnpIO->UnpWrite(FilteredData,FilteredDataSize);
- UnpSomeRead=true;
- WrittenFileSize+=FilteredDataSize;
- WrittenBorder=BlockEnd;
- WriteSize=(UnpPtr-WrittenBorder)&MAXWINMASK;
- }
- else
- {
- // Current filter intersects the window write border, so we adjust
- // the window border to process this filter next time, not now.
- for (size_t J=I;J<PrgStack.Size();J++)
- {
- UnpackFilter *flt=PrgStack[J];
- if (flt!=NULL && flt->NextWindow)
- flt->NextWindow=false;
- }
- WrPtr=WrittenBorder;
- return;
- }
- }
- }
-
- UnpWriteArea(WrittenBorder,UnpPtr);
- WrPtr=UnpPtr;
-}
-
-
-void Unpack::ExecuteCode(VM_PreparedProgram *Prg)
-{
- if (Prg->GlobalData.Size()>0)
- {
- Prg->InitR[6]=(uint)WrittenFileSize;
- VM.SetLowEndianValue((uint *)&Prg->GlobalData[0x24],(uint)WrittenFileSize);
- VM.SetLowEndianValue((uint *)&Prg->GlobalData[0x28],(uint)(WrittenFileSize>>32));
- VM.Execute(Prg);
- }
-}
-
-
-void Unpack::UnpWriteArea(unsigned int StartPtr,unsigned int EndPtr)
-{
- if (EndPtr!=StartPtr)
- UnpSomeRead=true;
- if (EndPtr<StartPtr)
- {
- UnpWriteData(&Window[StartPtr],-(int)StartPtr & MAXWINMASK);
- UnpWriteData(Window,EndPtr);
- UnpAllBuf=true;
- }
- else
- UnpWriteData(&Window[StartPtr],EndPtr-StartPtr);
-}
-
-
-void Unpack::UnpWriteData(byte *Data,size_t Size)
-{
- if (WrittenFileSize>=DestUnpSize)
- return;
- size_t WriteSize=Size;
- int64 LeftToWrite=DestUnpSize-WrittenFileSize;
- if ((int64)WriteSize>LeftToWrite)
- WriteSize=(size_t)LeftToWrite;
- UnpIO->UnpWrite(Data,WriteSize);
- WrittenFileSize+=Size;
-}
-
-
-bool Unpack::ReadTables()
-{
- byte BitLength[BC];
- byte Table[HUFF_TABLE_SIZE];
- if (InAddr>ReadTop-25)
- if (!UnpReadBuf())
- return(false);
- faddbits((8-InBit)&7);
- uint BitField=fgetbits();
- if (BitField & 0x8000)
- {
- UnpBlockType=BLOCK_PPM;
- return(PPM.DecodeInit(this,PPMEscChar));
- }
- UnpBlockType=BLOCK_LZ;
-
- PrevLowDist=0;
- LowDistRepCount=0;
-
- if (!(BitField & 0x4000))
- memset(UnpOldTable,0,sizeof(UnpOldTable));
- faddbits(2);
-
- for (int I=0;I<BC;I++)
- {
- int Length=(byte)(fgetbits() >> 12);
- faddbits(4);
- if (Length==15)
- {
- int ZeroCount=(byte)(fgetbits() >> 12);
- faddbits(4);
- if (ZeroCount==0)
- BitLength[I]=15;
- else
- {
- ZeroCount+=2;
- while (ZeroCount-- > 0 && I<sizeof(BitLength)/sizeof(BitLength[0]))
- BitLength[I++]=0;
- I--;
- }
- }
- else
- BitLength[I]=Length;
- }
- MakeDecodeTables(BitLength,&BD,BC);
-
- const int TableSize=HUFF_TABLE_SIZE;
- for (int I=0;I<TableSize;)
- {
- if (InAddr>ReadTop-5)
- if (!UnpReadBuf())
- return(false);
- int Number=DecodeNumber(&BD);
- if (Number<16)
- {
- Table[I]=(Number+UnpOldTable[I]) & 0xf;
- I++;
- }
- else
- if (Number<18)
- {
- int N;
- if (Number==16)
- {
- N=(fgetbits() >> 13)+3;
- faddbits(3);
- }
- else
- {
- N=(fgetbits() >> 9)+11;
- faddbits(7);
- }
- while (N-- > 0 && I<TableSize)
- {
- Table[I]=Table[I-1];
- I++;
- }
- }
- else
- {
- int N;
- if (Number==18)
- {
- N=(fgetbits() >> 13)+3;
- faddbits(3);
- }
- else
- {
- N=(fgetbits() >> 9)+11;
- faddbits(7);
- }
- while (N-- > 0 && I<TableSize)
- Table[I++]=0;
- }
+#endif
+ Unpack5(Solid);
+ break;
}
- TablesRead=true;
- if (InAddr>ReadTop)
- return(false);
- MakeDecodeTables(&Table[0],&LD,NC);
- MakeDecodeTables(&Table[NC],&DD,DC);
- MakeDecodeTables(&Table[NC+DC],&LDD,LDC);
- MakeDecodeTables(&Table[NC+DC+LDC],&RD,RC);
- memcpy(UnpOldTable,Table,sizeof(UnpOldTable));
- return(true);
}
-void Unpack::UnpInitData(int Solid)
+void Unpack::UnpInitData(bool Solid)
{
if (!Solid)
{
- TablesRead=false;
memset(OldDist,0,sizeof(OldDist));
OldDistPtr=0;
LastDist=LastLength=0;
-// memset(Window,0,MAXWINSIZE);
- memset(UnpOldTable,0,sizeof(UnpOldTable));
- memset(&LD,0,sizeof(LD));
- memset(&DD,0,sizeof(DD));
- memset(&LDD,0,sizeof(LDD));
- memset(&RD,0,sizeof(RD));
- memset(&BD,0,sizeof(BD));
+// memset(Window,0,MaxWinSize);
+ memset(&BlockTables,0,sizeof(BlockTables));
UnpPtr=WrPtr=0;
- PPMEscChar=2;
- UnpBlockType=BLOCK_LZ;
+ WriteBorder=Min(MaxWinSize,UNPACK_MAX_WRITE)&MaxWinMask;
InitFilters();
}
- InitBitInput();
+ Inp.InitBitInput();
WrittenFileSize=0;
ReadTop=0;
ReadBorder=0;
+
+ memset(&BlockHeader,0,sizeof(BlockHeader));
+ BlockHeader.BlockSize=-1; // '-1' means not defined yet.
#ifndef SFX_MODULE
UnpInitData20(Solid);
#endif
-}
-
-
-void Unpack::InitFilters()
-{
- OldFilterLengths.Reset();
- LastFilter=0;
-
- for (size_t I=0;I<Filters.Size();I++)
- delete Filters[I];
- Filters.Reset();
- for (size_t I=0;I<PrgStack.Size();I++)
- delete PrgStack[I];
- PrgStack.Reset();
+ UnpInitData30(Solid);
}
@@ -1131,6 +248,7 @@ void Unpack::MakeDecodeTables(byte *LengthTable,DecodeTable *Dec,uint Size)
{
case NC:
case NC20:
+ case NC30:
Dec->QuickBits=MAX_QUICK_DECODE_BITS;
break;
default:
diff --git a/src/thirdparty/unrar/unpack.hpp b/src/thirdparty/unrar/unpack.hpp
index d5779a9f9..87dfee2b4 100644
--- a/src/thirdparty/unrar/unpack.hpp
+++ b/src/thirdparty/unrar/unpack.hpp
@@ -1,13 +1,17 @@
#ifndef _RAR_UNPACK_
#define _RAR_UNPACK_
-enum BLOCK_TYPES {BLOCK_LZ,BLOCK_PPM};
-
// Maximum allowed number of compressed bits processed in quick mode.
-#define MAX_QUICK_DECODE_BITS 10
+#define MAX_QUICK_DECODE_BITS 10
// Maximum number of filters per entire data block.
-#define MAX_FILTERS 1024
+#define MAX_UNPACK_FILTERS 8192
+
+// Maximum number of filters per entire data block for RAR3 unpack.
+#define MAX3_FILTERS 1024
+
+// Write data in 4 MB or smaller blocks.
+#define UNPACK_MAX_WRITE 0x400000
// Decode compressed bit fields to alphabet numbers.
struct DecodeTable
@@ -51,8 +55,92 @@ struct DecodeTable
ushort DecodeNum[LARGEST_TABLE_SIZE];
};
+
+struct UnpackBlockHeader
+{
+ int BlockSize;
+ int BlockBitSize;
+ int BlockStart;
+ int HeaderSize;
+ bool LastBlockInFile;
+ bool TablePresent;
+};
+
+
+struct UnpackBlockTables
+{
+ DecodeTable LD; // Decode literals.
+ DecodeTable DD; // Decode distances.
+ DecodeTable LDD; // Decode lower bits of distances.
+ DecodeTable RD; // Decode repeating distances.
+ DecodeTable BD; // Decode bit lengths in Huffman table.
+};
+
+
+#ifdef RAR_SMP
+enum UNP_DEC_TYPE {
+ UNPDT_LITERAL,UNPDT_MATCH,UNPDT_FULLREP,UNPDT_REP,UNPDT_FILTER
+};
+
+struct UnpackDecodedItem
+{
+ UNP_DEC_TYPE Type;
+ ushort Length;
+ union
+ {
+ uint Distance;
+ byte Literal[4];
+ };
+};
+
+
+struct UnpackThreadData
+{
+ Unpack *UnpackPtr;
+ BitInput Inp;
+ bool HeaderRead;
+ UnpackBlockHeader BlockHeader;
+ bool TableRead;
+ UnpackBlockTables BlockTables;
+ int DataSize; // Data left in buffer. Can be less than block size.
+ bool DamagedData;
+ bool LargeBlock;
+ bool NoDataLeft; // 'true' if file is read completely.
+ bool Incomplete; // Not entire block was processed, need to read more data.
+
+ UnpackDecodedItem *Decoded;
+ uint DecodedSize;
+ uint DecodedAllocated;
+ uint ThreadNumber; // For debugging.
+
+ UnpackThreadData()
+ :Inp(false)
+ {
+ Decoded=NULL;
+ }
+ ~UnpackThreadData()
+ {
+ if (Decoded!=NULL)
+ free(Decoded);
+ }
+};
+#endif
+
+
struct UnpackFilter
{
+ byte Type;
+ uint BlockStart;
+ uint BlockLength;
+ byte Channels;
+ uint Width;
+ byte PosR;
+ bool NextWindow;
+};
+
+
+struct UnpackFilter30
+{
unsigned int BlockStart;
unsigned int BlockLength;
unsigned int ExecCount;
@@ -77,70 +165,62 @@ struct AudioVariables // For RAR 2.0 archives only.
};
-class Unpack:private BitInput
+class Unpack
{
private:
- void Unpack29(bool Solid);
+ void Unpack5(bool Solid);
+ void Unpack5MT(bool Solid);
bool UnpReadBuf();
void UnpWriteBuf();
- void ExecuteCode(VM_PreparedProgram *Prg);
- void UnpWriteArea(unsigned int StartPtr,unsigned int EndPtr);
+ uint FilterItanium_GetBits(byte *Data,int BitPos,int BitCount);
+ void FilterItanium_SetBits(byte *Data,uint BitField,int BitPos,int BitCount);
+ byte* ApplyFilter(byte *Data,uint DataSize,UnpackFilter *Flt);
+ void UnpWriteArea(size_t StartPtr,size_t EndPtr);
void UnpWriteData(byte *Data,size_t Size);
- bool ReadTables();
+ _forceinline uint SlotToLength(BitInput &Inp,uint Slot);
+ bool ReadBlockHeader(BitInput &Inp,UnpackBlockHeader &Header);
+ bool ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTables &Tables);
void MakeDecodeTables(byte *LengthTable,DecodeTable *Dec,uint Size);
- _forceinline uint DecodeNumber(DecodeTable *Dec);
- inline int SafePPMDecodeChar();
+ _forceinline uint DecodeNumber(BitInput &Inp,DecodeTable *Dec);
void CopyString();
inline void InsertOldDist(unsigned int Distance);
- void UnpInitData(int Solid);
+ void UnpInitData(bool Solid);
_forceinline void CopyString(uint Length,uint Distance);
- bool ReadEndOfBlock();
- bool ReadVMCode();
- bool ReadVMCodePPM();
- bool AddVMCode(unsigned int FirstByte,byte *Code,int CodeSize);
+ uint ReadFilterData(BitInput &Inp);
+ bool ReadFilter(BitInput &Inp,UnpackFilter &Filter);
+ bool AddFilter(UnpackFilter &Filter);
+ bool AddFilter();
void InitFilters();
ComprDataIO *UnpIO;
- ModelPPM PPM;
- int PPMEscChar;
-
- // Virtual machine to execute filters code.
- RarVM VM;
-
- // Buffer to read VM filters code. We moved it here from AddVMCode
- // function to reduce time spent in BitInput constructor.
- BitInput VMCodeInp;
+ BitInput Inp;
- // Filters code, one entry per filter.
- Array<UnpackFilter*> Filters;
-
- // Filters stack, several entrances of same filter are possible.
- Array<UnpackFilter*> PrgStack;
-
- // Lengths of preceding data blocks, one length of one last block
- // for every filter. Used to reduce the size required to write
- // the data block length if lengths are repeating.
- Array<int> OldFilterLengths;
+#ifdef RAR_SMP
+ void InitMT();
+ bool UnpackLargeBlock(UnpackThreadData &D);
+ bool ProcessDecoded(UnpackThreadData &D);
- int LastFilter;
+ ThreadPool *UnpThreadPool;
+ UnpackThreadData *UnpThreadData;
+ uint MaxUserThreads;
+ byte *ReadBufMT;
+#endif
- bool TablesRead;
+ Array<byte> FilterSrcMemory;
+ Array<byte> FilterDstMemory;
- DecodeTable LD; // Decode literals.
- DecodeTable DD; // Decode distances.
- DecodeTable LDD; // Decode lower bits of distances.
- DecodeTable RD; // Decode repeating distances.
- DecodeTable BD; // Decode bit lengths in Huffman table.
+ // Filters code, one entry per filter.
+ Array<UnpackFilter> Filters;
- unsigned int OldDist[4],OldDistPtr;
- unsigned int LastLength;
+ uint OldDist[4],OldDistPtr;
+ uint LastLength;
// LastDist is necessary only for RAR2 and older with circular OldDist
// array. In RAR3 last distance is always stored in OldDist[0].
- unsigned int LastDist;
+ uint LastDist;
- unsigned int UnpPtr,WrPtr;
+ size_t UnpPtr,WrPtr;
// Top border of read packed data.
int ReadTop;
@@ -150,9 +230,10 @@ class Unpack:private BitInput
// unless we are at the end of file.
int ReadBorder;
- byte UnpOldTable[HUFF_TABLE_SIZE];
+ UnpackBlockHeader BlockHeader;
+ UnpackBlockTables BlockTables;
- int UnpBlockType;
+ size_t WriteBorder;
byte *Window;
@@ -165,7 +246,6 @@ class Unpack:private BitInput
int64 WrittenFileSize;
bool FileExtracted;
- int PrevLowDist,LowDistRepCount;
/***************************** Unpack v 1.5 *********************************/
void Unpack15(bool Solid);
@@ -173,18 +253,17 @@ class Unpack:private BitInput
void LongLZ();
void HuffDecode();
void GetFlagsBuf();
- void OldUnpInitData(int Solid);
+ void UnpInitData15(int Solid);
void InitHuff();
void CorrHuff(ushort *CharSet,byte *NumToPlace);
- void OldCopyString(unsigned int Distance,unsigned int Length);
+ void CopyString15(uint Distance,uint Length);
uint DecodeNum(uint Num,uint StartPos,uint *DecTab,uint *PosTab);
- void OldUnpWriteBuf();
ushort ChSet[256],ChSetA[256],ChSetB[256],ChSetC[256];
byte NToPl[256],NToPlB[256],NToPlC[256];
- unsigned int FlagBuf,AvrPlc,AvrPlcB,AvrLn1,AvrLn2,AvrLn3;
+ uint FlagBuf,AvrPlc,AvrPlcB,AvrLn1,AvrLn2,AvrLn3;
int Buf60,NumHuf,StMode,LCount,FlagsCnt;
- unsigned int Nhfb,Nlzb,MaxDist3;
+ uint Nhfb,Nlzb,MaxDist3;
/***************************** Unpack v 1.5 *********************************/
/***************************** Unpack v 2.0 *********************************/
@@ -194,28 +273,87 @@ class Unpack:private BitInput
unsigned char UnpOldTable20[MC20*4];
int UnpAudioBlock,UnpChannels,UnpCurChannel,UnpChannelDelta;
- void CopyString20(unsigned int Length,unsigned int Distance);
+ void CopyString20(uint Length,uint Distance);
bool ReadTables20();
+ void UnpWriteBuf20();
void UnpInitData20(int Solid);
void ReadLastTables();
byte DecodeAudio(int Delta);
struct AudioVariables AudV[4];
/***************************** Unpack v 2.0 *********************************/
+/***************************** Unpack v 3.0 *********************************/
+ enum BLOCK_TYPES {BLOCK_LZ,BLOCK_PPM};
+
+ void UnpInitData30(bool Solid);
+ void Unpack29(bool Solid);
+ void InitFilters30();
+ bool ReadEndOfBlock();
+ bool ReadVMCode();
+ bool ReadVMCodePPM();
+ bool AddVMCode(uint FirstByte,byte *Code,int CodeSize);
+ int SafePPMDecodeChar();
+ bool ReadTables30();
+ bool UnpReadBuf30();
+ void UnpWriteBuf30();
+ void ExecuteCode(VM_PreparedProgram *Prg);
+
+ int PrevLowDist,LowDistRepCount;
+
+ ModelPPM PPM;
+ int PPMEscChar;
+
+ byte UnpOldTable[HUFF_TABLE_SIZE];
+ int UnpBlockType;
+
+ bool TablesRead;
+
+ // Virtual machine to execute filters code.
+ RarVM VM;
+
+ // Buffer to read VM filters code. We moved it here from AddVMCode
+ // function to reduce time spent in BitInput constructor.
+ BitInput VMCodeInp;
+
+ // Filters code, one entry per filter.
+ Array<UnpackFilter30 *> Filters30;
+
+ // Filters stack, several entrances of same filter are possible.
+ Array<UnpackFilter30 *> PrgStack;
+
+ // Lengths of preceding data blocks, one length of one last block
+ // for every filter. Used to reduce the size required to write
+ // the data block length if lengths are repeating.
+ Array<int> OldFilterLengths;
+
+ int LastFilter;
+/***************************** Unpack v 3.0 *********************************/
+
public:
Unpack(ComprDataIO *DataIO);
~Unpack();
- void Init();
+ void Init(size_t WinSize,bool Solid);
void DoUnpack(int Method,bool Solid);
bool IsFileExtracted() {return(FileExtracted);}
void SetDestSize(int64 DestSize) {DestUnpSize=DestSize;FileExtracted=false;}
void SetSuspended(bool Suspended) {Unpack::Suspended=Suspended;}
- unsigned int GetChar()
+#ifdef RAR_SMP
+ // More than 8 threads are unlikely to provide a noticeable gain
+ // for unpacking, but would use the additional memory.
+ void SetThreads(uint Threads) {MaxUserThreads=Min(Threads,8);}
+
+ void UnpackDecode(UnpackThreadData &D);
+#endif
+
+ size_t MaxWinSize;
+ size_t MaxWinMask;
+
+ uint GetChar()
{
- if (InAddr>BitInput::MAX_SIZE-30)
+ if (Inp.InAddr>BitInput::MAX_SIZE-30)
UnpReadBuf();
- return(InBuf[InAddr++]);
+ return(Inp.InBuf[Inp.InAddr++]);
}
};
diff --git a/src/thirdparty/unrar/unpack15.cpp b/src/thirdparty/unrar/unpack15.cpp
index c9faf01a6..131d2665c 100644
--- a/src/thirdparty/unrar/unpack15.cpp
+++ b/src/thirdparty/unrar/unpack15.cpp
@@ -39,22 +39,17 @@ static unsigned int PosHf4[]={0,0,0,0,0,0,0,0,0,255,0,0,0};
void Unpack::Unpack15(bool Solid)
{
- if (Suspended)
- UnpPtr=WrPtr;
- else
+ UnpInitData(Solid);
+ UnpInitData15(Solid);
+ UnpReadBuf();
+ if (!Solid)
{
- UnpInitData(Solid);
- OldUnpInitData(Solid);
- UnpReadBuf();
- if (!Solid)
- {
- InitHuff();
- UnpPtr=0;
- }
- else
- UnpPtr=WrPtr;
- --DestUnpSize;
+ InitHuff();
+ UnpPtr=0;
}
+ else
+ UnpPtr=WrPtr;
+ --DestUnpSize;
if (DestUnpSize>=0)
{
GetFlagsBuf();
@@ -63,16 +58,12 @@ void Unpack::Unpack15(bool Solid)
while (DestUnpSize>=0)
{
- UnpPtr&=MAXWINMASK;
+ UnpPtr&=MaxWinMask;
- if (InAddr>ReadTop-30 && !UnpReadBuf())
+ if (Inp.InAddr>ReadTop-30 && !UnpReadBuf())
break;
- if (((WrPtr-UnpPtr) & MAXWINMASK)<270 && WrPtr!=UnpPtr)
- {
- OldUnpWriteBuf();
- if (Suspended)
- return;
- }
+ if (((WrPtr-UnpPtr) & MaxWinMask)<270 && WrPtr!=UnpPtr)
+ UnpWriteBuf20();
if (StMode)
{
HuffDecode();
@@ -116,23 +107,7 @@ void Unpack::Unpack15(bool Solid)
}
}
}
- OldUnpWriteBuf();
-}
-
-
-void Unpack::OldUnpWriteBuf()
-{
- if (UnpPtr!=WrPtr)
- UnpSomeRead=true;
- if (UnpPtr<WrPtr)
- {
- UnpIO->UnpWrite(&Window[WrPtr],-(int)WrPtr & MAXWINMASK);
- UnpIO->UnpWrite(Window,UnpPtr);
- UnpAllBuf=true;
- }
- else
- UnpIO->UnpWrite(&Window[WrPtr],UnpPtr-WrPtr);
- WrPtr=UnpPtr;
+ UnpWriteBuf20();
}
@@ -155,13 +130,13 @@ void Unpack::ShortLZ()
int DistancePlace;
NumHuf=0;
- unsigned int BitField=fgetbits();
+ unsigned int BitField=Inp.fgetbits();
if (LCount==2)
{
- faddbits(1);
+ Inp.faddbits(1);
if (BitField >= 0x8000)
{
- OldCopyString((unsigned int)LastDist,LastLength);
+ CopyString15((unsigned int)LastDist,LastLength);
return;
}
BitField <<= 1;
@@ -178,14 +153,14 @@ void Unpack::ShortLZ()
for (Length=0;;Length++)
if (((BitField^ShortXor1[Length]) & (~(0xff>>GetShortLen1(Length))))==0)
break;
- faddbits(GetShortLen1(Length));
+ Inp.faddbits(GetShortLen1(Length));
}
else
{
for (Length=0;;Length++)
if (((BitField^ShortXor2[Length]) & (~(0xff>>GetShortLen2(Length))))==0)
break;
- faddbits(GetShortLen2(Length));
+ Inp.faddbits(GetShortLen2(Length));
}
if (Length >= 9)
@@ -193,25 +168,25 @@ void Unpack::ShortLZ()
if (Length == 9)
{
LCount++;
- OldCopyString((unsigned int)LastDist,LastLength);
+ CopyString15((unsigned int)LastDist,LastLength);
return;
}
if (Length == 14)
{
LCount=0;
- Length=DecodeNum(fgetbits(),STARTL2,DecL2,PosL2)+5;
- Distance=(fgetbits()>>1) | 0x8000;
- faddbits(15);
+ Length=DecodeNum(Inp.fgetbits(),STARTL2,DecL2,PosL2)+5;
+ Distance=(Inp.fgetbits()>>1) | 0x8000;
+ Inp.faddbits(15);
LastLength=Length;
LastDist=Distance;
- OldCopyString(Distance,Length);
+ CopyString15(Distance,Length);
return;
}
LCount=0;
SaveLength=Length;
Distance=OldDist[(OldDistPtr-(Length-9)) & 3];
- Length=DecodeNum(fgetbits(),STARTL1,DecL1,PosL1)+2;
+ Length=DecodeNum(Inp.fgetbits(),STARTL1,DecL1,PosL1)+2;
if (Length==0x101 && SaveLength==10)
{
Buf60 ^= 1;
@@ -226,7 +201,7 @@ void Unpack::ShortLZ()
OldDistPtr = OldDistPtr & 3;
LastLength=Length;
LastDist=Distance;
- OldCopyString(Distance,Length);
+ CopyString15(Distance,Length);
return;
}
@@ -234,7 +209,7 @@ void Unpack::ShortLZ()
AvrLn1 += Length;
AvrLn1 -= AvrLn1 >> 4;
- DistancePlace=DecodeNum(fgetbits(),STARTHF2,DecHf2,PosHf2) & 0xff;
+ DistancePlace=DecodeNum(Inp.fgetbits(),STARTHF2,DecHf2,PosHf2) & 0xff;
Distance=ChSetA[DistancePlace];
if (--DistancePlace != -1)
{
@@ -247,7 +222,7 @@ void Unpack::ShortLZ()
OldDistPtr = OldDistPtr & 3;
LastLength=Length;
LastDist=Distance;
- OldCopyString(Distance,Length);
+ CopyString15(Distance,Length);
}
@@ -267,7 +242,7 @@ void Unpack::LongLZ()
}
OldAvr2=AvrLn2;
- unsigned int BitField=fgetbits();
+ unsigned int BitField=Inp.fgetbits();
if (AvrLn2 >= 122)
Length=DecodeNum(BitField,STARTL2,DecL2,PosL2);
else
@@ -277,19 +252,19 @@ void Unpack::LongLZ()
if (BitField < 0x100)
{
Length=BitField;
- faddbits(16);
+ Inp.faddbits(16);
}
else
{
for (Length=0;((BitField<<Length)&0x8000)==0;Length++)
;
- faddbits(Length+1);
+ Inp.faddbits(Length+1);
}
AvrLn2 += Length;
AvrLn2 -= AvrLn2 >> 5;
- BitField=fgetbits();
+ BitField=Inp.fgetbits();
if (AvrPlcB > 0x28ff)
DistancePlace=DecodeNum(BitField,STARTHF2,DecHf2,PosHf2);
else
@@ -313,8 +288,8 @@ void Unpack::LongLZ()
ChSetB[DistancePlace]=ChSetB[NewDistancePlace];
ChSetB[NewDistancePlace]=Distance;
- Distance=((Distance & 0xff00) | (fgetbits() >> 8)) >> 1;
- faddbits(7);
+ Distance=((Distance & 0xff00) | (Inp.fgetbits() >> 8)) >> 1;
+ Inp.faddbits(7);
OldAvr3=AvrLn3;
if (Length!=1 && Length!=4)
@@ -339,7 +314,7 @@ void Unpack::LongLZ()
OldDistPtr = OldDistPtr & 3;
LastLength=Length;
LastDist=Distance;
- OldCopyString(Distance,Length);
+ CopyString15(Distance,Length);
}
@@ -350,7 +325,7 @@ void Unpack::HuffDecode()
unsigned int Distance;
int BytePlace;
- unsigned int BitField=fgetbits();
+ unsigned int BitField=Inp.fgetbits();
if (AvrPlc > 0x75ff)
BytePlace=DecodeNum(BitField,STARTHF4,DecHf4,PosHf4);
@@ -372,8 +347,8 @@ void Unpack::HuffDecode()
BytePlace=0x100;
if (--BytePlace==-1)
{
- BitField=fgetbits();
- faddbits(1);
+ BitField=Inp.fgetbits();
+ Inp.faddbits(1);
if (BitField & 0x8000)
{
NumHuf=StMode=0;
@@ -382,11 +357,11 @@ void Unpack::HuffDecode()
else
{
Length = (BitField & 0x4000) ? 4 : 3;
- faddbits(1);
- Distance=DecodeNum(fgetbits(),STARTHF2,DecHf2,PosHf2);
- Distance = (Distance << 5) | (fgetbits() >> 11);
- faddbits(5);
- OldCopyString(Distance,Length);
+ Inp.faddbits(1);
+ Distance=DecodeNum(Inp.fgetbits(),STARTHF2,DecHf2,PosHf2);
+ Distance = (Distance << 5) | (Inp.fgetbits() >> 11);
+ Inp.faddbits(5);
+ CopyString15(Distance,Length);
return;
}
}
@@ -424,7 +399,7 @@ void Unpack::HuffDecode()
void Unpack::GetFlagsBuf()
{
unsigned int Flags,NewFlagsPlace;
- unsigned int FlagsPlace=DecodeNum(fgetbits(),STARTHF2,DecHf2,PosHf2);
+ unsigned int FlagsPlace=DecodeNum(Inp.fgetbits(),STARTHF2,DecHf2,PosHf2);
while (1)
{
@@ -441,7 +416,7 @@ void Unpack::GetFlagsBuf()
}
-void Unpack::OldUnpInitData(int Solid)
+void Unpack::UnpInitData15(int Solid)
{
if (!Solid)
{
@@ -485,13 +460,13 @@ void Unpack::CorrHuff(ushort *CharSet,byte *NumToPlace)
}
-void Unpack::OldCopyString(unsigned int Distance,unsigned int Length)
+void Unpack::CopyString15(uint Distance,uint Length)
{
DestUnpSize-=Length;
while (Length--)
{
- Window[UnpPtr]=Window[(UnpPtr-Distance) & MAXWINMASK];
- UnpPtr=(UnpPtr+1) & MAXWINMASK;
+ Window[UnpPtr]=Window[(UnpPtr-Distance) & MaxWinMask];
+ UnpPtr=(UnpPtr+1) & MaxWinMask;
}
}
@@ -501,6 +476,6 @@ uint Unpack::DecodeNum(uint Num,uint StartPos,uint *DecTab,uint *PosTab)
int I;
for (Num&=0xfff0,I=0;DecTab[I]<=Num;I++)
StartPos++;
- faddbits(StartPos);
+ Inp.faddbits(StartPos);
return(((Num-(I ? DecTab[I-1]:0))>>(16-StartPos))+PosTab[StartPos]);
}
diff --git a/src/thirdparty/unrar/unpack20.cpp b/src/thirdparty/unrar/unpack20.cpp
index 300ee3407..aca520935 100644
--- a/src/thirdparty/unrar/unpack20.cpp
+++ b/src/thirdparty/unrar/unpack20.cpp
@@ -1,28 +1,11 @@
#include "rar.hpp"
-void Unpack::CopyString20(unsigned int Length,unsigned int Distance)
+void Unpack::CopyString20(uint Length,uint Distance)
{
LastDist=OldDist[OldDistPtr++ & 3]=Distance;
LastLength=Length;
DestUnpSize-=Length;
-
- unsigned int DestPtr=UnpPtr-Distance;
- if (DestPtr<MAXWINSIZE-300 && UnpPtr<MAXWINSIZE-300)
- {
- Window[UnpPtr++]=Window[DestPtr++];
- Window[UnpPtr++]=Window[DestPtr++];
- while (Length>2)
- {
- Length--;
- Window[UnpPtr++]=Window[DestPtr++];
- }
- }
- else
- while (Length--)
- {
- Window[UnpPtr]=Window[DestPtr++ & MAXWINMASK];
- UnpPtr=(UnpPtr+1) & MAXWINMASK;
- }
+ CopyString(Length,Distance);
}
@@ -51,20 +34,20 @@ void Unpack::Unpack20(bool Solid)
while (DestUnpSize>=0)
{
- UnpPtr&=MAXWINMASK;
+ UnpPtr&=MaxWinMask;
- if (InAddr>ReadTop-30)
+ if (Inp.InAddr>ReadTop-30)
if (!UnpReadBuf())
break;
- if (((WrPtr-UnpPtr) & MAXWINMASK)<270 && WrPtr!=UnpPtr)
+ if (((WrPtr-UnpPtr) & MaxWinMask)<270 && WrPtr!=UnpPtr)
{
- OldUnpWriteBuf();
+ UnpWriteBuf20();
if (Suspended)
return;
}
if (UnpAudioBlock)
{
- int AudioNumber=DecodeNumber(&MD[UnpCurChannel]);
+ int AudioNumber=DecodeNumber(Inp,&MD[UnpCurChannel]);
if (AudioNumber==256)
{
@@ -79,7 +62,7 @@ void Unpack::Unpack20(bool Solid)
continue;
}
- int Number=DecodeNumber(&LD);
+ int Number=DecodeNumber(Inp,&BlockTables.LD);
if (Number<256)
{
Window[UnpPtr++]=(byte)Number;
@@ -91,16 +74,16 @@ void Unpack::Unpack20(bool Solid)
int Length=LDecode[Number-=270]+3;
if ((Bits=LBits[Number])>0)
{
- Length+=getbits()>>(16-Bits);
- addbits(Bits);
+ Length+=Inp.getbits()>>(16-Bits);
+ Inp.addbits(Bits);
}
- int DistNumber=DecodeNumber(&DD);
+ int DistNumber=DecodeNumber(Inp,&BlockTables.DD);
unsigned int Distance=DDecode[DistNumber]+1;
if ((Bits=DBits[DistNumber])>0)
{
- Distance+=getbits()>>(16-Bits);
- addbits(Bits);
+ Distance+=Inp.getbits()>>(16-Bits);
+ Inp.addbits(Bits);
}
if (Distance>=0x2000)
@@ -127,12 +110,12 @@ void Unpack::Unpack20(bool Solid)
if (Number<261)
{
unsigned int Distance=OldDist[(OldDistPtr-(Number-256)) & 3];
- int LengthNumber=DecodeNumber(&RD);
+ int LengthNumber=DecodeNumber(Inp,&BlockTables.RD);
int Length=LDecode[LengthNumber]+2;
if ((Bits=LBits[LengthNumber])>0)
{
- Length+=getbits()>>(16-Bits);
- addbits(Bits);
+ Length+=Inp.getbits()>>(16-Bits);
+ Inp.addbits(Bits);
}
if (Distance>=0x101)
{
@@ -152,39 +135,55 @@ void Unpack::Unpack20(bool Solid)
unsigned int Distance=SDDecode[Number-=261]+1;
if ((Bits=SDBits[Number])>0)
{
- Distance+=getbits()>>(16-Bits);
- addbits(Bits);
+ Distance+=Inp.getbits()>>(16-Bits);
+ Inp.addbits(Bits);
}
CopyString20(2,Distance);
continue;
}
}
ReadLastTables();
- OldUnpWriteBuf();
+ UnpWriteBuf20();
+}
+
+
+void Unpack::UnpWriteBuf20()
+{
+ if (UnpPtr!=WrPtr)
+ UnpSomeRead=true;
+ if (UnpPtr<WrPtr)
+ {
+ UnpIO->UnpWrite(&Window[WrPtr],-(int)WrPtr & MaxWinMask);
+ UnpIO->UnpWrite(Window,UnpPtr);
+ UnpAllBuf=true;
+ }
+ else
+ UnpIO->UnpWrite(&Window[WrPtr],UnpPtr-WrPtr);
+ WrPtr=UnpPtr;
}
bool Unpack::ReadTables20()
{
byte BitLength[BC20];
- unsigned char Table[MC20*4];
+ byte Table[MC20*4];
int TableSize,N,I;
- if (InAddr>ReadTop-25)
+ if (Inp.InAddr>ReadTop-25)
if (!UnpReadBuf())
return(false);
- unsigned int BitField=getbits();
+ uint BitField=Inp.getbits();
UnpAudioBlock=(BitField & 0x8000);
if (!(BitField & 0x4000))
memset(UnpOldTable20,0,sizeof(UnpOldTable20));
- addbits(2);
+ Inp.addbits(2);
if (UnpAudioBlock)
{
UnpChannels=((BitField>>12) & 3)+1;
if (UnpCurChannel>=UnpChannels)
UnpCurChannel=0;
- addbits(2);
+ Inp.addbits(2);
TableSize=MC20*UnpChannels;
}
else
@@ -192,17 +191,17 @@ bool Unpack::ReadTables20()
for (I=0;I<BC20;I++)
{
- BitLength[I]=(byte)(getbits() >> 12);
- addbits(4);
+ BitLength[I]=(byte)(Inp.getbits() >> 12);
+ Inp.addbits(4);
}
- MakeDecodeTables(BitLength,&BD,BC20);
+ MakeDecodeTables(BitLength,&BlockTables.BD,BC20);
I=0;
while (I<TableSize)
{
- if (InAddr>ReadTop-5)
+ if (Inp.InAddr>ReadTop-5)
if (!UnpReadBuf())
- return(false);
- int Number=DecodeNumber(&BD);
+ return false;
+ int Number=DecodeNumber(Inp,&BlockTables.BD);
if (Number<16)
{
Table[I]=(Number+UnpOldTable20[I]) & 0xf;
@@ -211,40 +210,41 @@ bool Unpack::ReadTables20()
else
if (Number==16)
{
- N=(getbits() >> 14)+3;
- addbits(2);
- while (N-- > 0 && I<TableSize)
- {
- Table[I]=Table[I-1];
- I++;
- }
+ N=(Inp.getbits() >> 14)+3;
+ Inp.addbits(2);
+ if (I>0)
+ while (N-- > 0 && I<TableSize)
+ {
+ Table[I]=Table[I-1];
+ I++;
+ }
}
else
{
if (Number==17)
{
- N=(getbits() >> 13)+3;
- addbits(3);
+ N=(Inp.getbits() >> 13)+3;
+ Inp.addbits(3);
}
else
{
- N=(getbits() >> 9)+11;
- addbits(7);
+ N=(Inp.getbits() >> 9)+11;
+ Inp.addbits(7);
}
while (N-- > 0 && I<TableSize)
Table[I++]=0;
}
}
- if (InAddr>ReadTop)
+ if (Inp.InAddr>ReadTop)
return(true);
if (UnpAudioBlock)
for (I=0;I<UnpChannels;I++)
MakeDecodeTables(&Table[I*MC20],&MD[I],MC20);
else
{
- MakeDecodeTables(&Table[0],&LD,NC20);
- MakeDecodeTables(&Table[NC20],&DD,DC20);
- MakeDecodeTables(&Table[NC20+DC20],&RD,RC20);
+ MakeDecodeTables(&Table[0],&BlockTables.LD,NC20);
+ MakeDecodeTables(&Table[NC20],&BlockTables.DD,DC20);
+ MakeDecodeTables(&Table[NC20+DC20],&BlockTables.RD,RC20);
}
memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20));
return(true);
@@ -253,14 +253,14 @@ bool Unpack::ReadTables20()
void Unpack::ReadLastTables()
{
- if (ReadTop>=InAddr+5)
+ if (ReadTop>=Inp.InAddr+5)
if (UnpAudioBlock)
{
- if (DecodeNumber(&MD[UnpCurChannel])==256)
+ if (DecodeNumber(Inp,&MD[UnpCurChannel])==256)
ReadTables20();
}
else
- if (DecodeNumber(&LD)==269)
+ if (DecodeNumber(Inp,&BlockTables.LD)==269)
ReadTables20();
}
diff --git a/src/thirdparty/unrar/unpack30.cpp b/src/thirdparty/unrar/unpack30.cpp
new file mode 100644
index 000000000..33fb27aa4
--- /dev/null
+++ b/src/thirdparty/unrar/unpack30.cpp
@@ -0,0 +1,836 @@
+// We use it instead of direct PPM.DecodeChar call to be sure that
+// we reset PPM structures in case of corrupt data. It is important,
+// because these structures can be invalid after PPM.DecodeChar returned -1.
+inline int Unpack::SafePPMDecodeChar()
+{
+ int Ch=PPM.DecodeChar();
+ if (Ch==-1) // Corrupt PPM data found.
+ {
+ PPM.CleanUp(); // Reset possibly corrupt PPM data structures.
+ UnpBlockType=BLOCK_LZ; // Set faster and more fail proof LZ mode.
+ }
+ return(Ch);
+}
+
+
+void Unpack::Unpack29(bool Solid)
+{
+ static unsigned char LDecode[]={0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224};
+ static unsigned char LBits[]= {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5};
+ static int DDecode[DC];
+ static byte DBits[DC];
+ static int DBitLengthCounts[]= {4,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,14,0,12};
+ static unsigned char SDDecode[]={0,4,8,16,32,64,128,192};
+ static unsigned char SDBits[]= {2,2,3, 4, 5, 6, 6, 6};
+ unsigned int Bits;
+
+ if (DDecode[1]==0)
+ {
+ int Dist=0,BitLength=0,Slot=0;
+ for (int I=0;I<ASIZE(DBitLengthCounts);I++,BitLength++)
+ for (int J=0;J<DBitLengthCounts[I];J++,Slot++,Dist+=(1<<BitLength))
+ {
+ DDecode[Slot]=Dist;
+ DBits[Slot]=BitLength;
+ }
+ }
+
+ FileExtracted=true;
+
+ if (!Suspended)
+ {
+ UnpInitData(Solid);
+ if (!UnpReadBuf30())
+ return;
+ if ((!Solid || !TablesRead) && !ReadTables30())
+ return;
+ }
+
+ while (true)
+ {
+ UnpPtr&=MaxWinMask;
+
+ if (Inp.InAddr>ReadBorder)
+ {
+ if (!UnpReadBuf30())
+ break;
+ }
+ if (((WrPtr-UnpPtr) & MaxWinMask)<260 && WrPtr!=UnpPtr)
+ {
+ UnpWriteBuf30();
+ if (WrittenFileSize>DestUnpSize)
+ return;
+ if (Suspended)
+ {
+ FileExtracted=false;
+ return;
+ }
+ }
+ if (UnpBlockType==BLOCK_PPM)
+ {
+ // Here speed is critical, so we do not use SafePPMDecodeChar,
+ // because sometimes even the inline function can introduce
+ // some additional penalty.
+ int Ch=PPM.DecodeChar();
+ if (Ch==-1) // Corrupt PPM data found.
+ {
+ PPM.CleanUp(); // Reset possibly corrupt PPM data structures.
+ UnpBlockType=BLOCK_LZ; // Set faster and more fail proof LZ mode.
+ break;
+ }
+ if (Ch==PPMEscChar)
+ {
+ int NextCh=SafePPMDecodeChar();
+ if (NextCh==0) // End of PPM encoding.
+ {
+ if (!ReadTables30())
+ break;
+ continue;
+ }
+ if (NextCh==-1) // Corrupt PPM data found.
+ break;
+ if (NextCh==2) // End of file in PPM mode.
+ break;
+ if (NextCh==3) // Read VM code.
+ {
+ if (!ReadVMCodePPM())
+ break;
+ continue;
+ }
+ if (NextCh==4) // LZ inside of PPM.
+ {
+ unsigned int Distance=0,Length;
+ bool Failed=false;
+ for (int I=0;I<4 && !Failed;I++)
+ {
+ int Ch=SafePPMDecodeChar();
+ if (Ch==-1)
+ Failed=true;
+ else
+ if (I==3)
+ Length=(byte)Ch;
+ else
+ Distance=(Distance<<8)+(byte)Ch;
+ }
+ if (Failed)
+ break;
+
+ CopyString(Length+32,Distance+2);
+ continue;
+ }
+ if (NextCh==5) // One byte distance match (RLE) inside of PPM.
+ {
+ int Length=SafePPMDecodeChar();
+ if (Length==-1)
+ break;
+ CopyString(Length+4,1);
+ continue;
+ }
+ // If we are here, NextCh must be 1, what means that current byte
+ // is equal to our 'escape' byte, so we just store it to Window.
+ }
+ Window[UnpPtr++]=Ch;
+ continue;
+ }
+
+ int Number=DecodeNumber(Inp,&BlockTables.LD);
+ if (Number<256)
+ {
+ Window[UnpPtr++]=(byte)Number;
+ continue;
+ }
+ if (Number>=271)
+ {
+ int Length=LDecode[Number-=271]+3;
+ if ((Bits=LBits[Number])>0)
+ {
+ Length+=Inp.getbits()>>(16-Bits);
+ Inp.addbits(Bits);
+ }
+
+ int DistNumber=DecodeNumber(Inp,&BlockTables.DD);
+ unsigned int Distance=DDecode[DistNumber]+1;
+ if ((Bits=DBits[DistNumber])>0)
+ {
+ if (DistNumber>9)
+ {
+ if (Bits>4)
+ {
+ Distance+=((Inp.getbits()>>(20-Bits))<<4);
+ Inp.addbits(Bits-4);
+ }
+ if (LowDistRepCount>0)
+ {
+ LowDistRepCount--;
+ Distance+=PrevLowDist;
+ }
+ else
+ {
+ int LowDist=DecodeNumber(Inp,&BlockTables.LDD);
+ if (LowDist==16)
+ {
+ LowDistRepCount=LOW_DIST_REP_COUNT-1;
+ Distance+=PrevLowDist;
+ }
+ else
+ {
+ Distance+=LowDist;
+ PrevLowDist=LowDist;
+ }
+ }
+ }
+ else
+ {
+ Distance+=Inp.getbits()>>(16-Bits);
+ Inp.addbits(Bits);
+ }
+ }
+
+ if (Distance>=0x2000)
+ {
+ Length++;
+ if (Distance>=0x40000L)
+ Length++;
+ }
+
+ InsertOldDist(Distance);
+ LastLength=Length;
+ CopyString(Length,Distance);
+ continue;
+ }
+ if (Number==256)
+ {
+ if (!ReadEndOfBlock())
+ break;
+ continue;
+ }
+ if (Number==257)
+ {
+ if (!ReadVMCode())
+ break;
+ continue;
+ }
+ if (Number==258)
+ {
+ if (LastLength!=0)
+ CopyString(LastLength,OldDist[0]);
+ continue;
+ }
+ if (Number<263)
+ {
+ int DistNum=Number-259;
+ unsigned int Distance=OldDist[DistNum];
+ for (int I=DistNum;I>0;I--)
+ OldDist[I]=OldDist[I-1];
+ OldDist[0]=Distance;
+
+ int LengthNumber=DecodeNumber(Inp,&BlockTables.RD);
+ int Length=LDecode[LengthNumber]+2;
+ if ((Bits=LBits[LengthNumber])>0)
+ {
+ Length+=Inp.getbits()>>(16-Bits);
+ Inp.addbits(Bits);
+ }
+ LastLength=Length;
+ CopyString(Length,Distance);
+ continue;
+ }
+ if (Number<272)
+ {
+ unsigned int Distance=SDDecode[Number-=263]+1;
+ if ((Bits=SDBits[Number])>0)
+ {
+ Distance+=Inp.getbits()>>(16-Bits);
+ Inp.addbits(Bits);
+ }
+ InsertOldDist(Distance);
+ LastLength=2;
+ CopyString(2,Distance);
+ continue;
+ }
+ }
+ UnpWriteBuf30();
+}
+
+
+// Return 'false' to quit unpacking the current file or 'true' to continue.
+bool Unpack::ReadEndOfBlock()
+{
+ uint BitField=Inp.getbits();
+ bool NewTable,NewFile=false;
+
+ // "1" - no new file, new table just here.
+ // "00" - new file, no new table.
+ // "01" - new file, new table (in beginning of next file).
+
+ if ((BitField & 0x8000)!=0)
+ {
+ NewTable=true;
+ Inp.addbits(1);
+ }
+ else
+ {
+ NewFile=true;
+ NewTable=(BitField & 0x4000)!=0;
+ Inp.addbits(2);
+ }
+ TablesRead=!NewTable;
+
+ // Quit immediately if "new file" flag is set. If "new table" flag
+ // is present, we'll read the table in beginning of next file
+ // based on 'TablesRead' 'false' value.
+ if (NewFile)
+ return false;
+ return ReadTables30(); // Quit only if we failed to read tables.
+}
+
+
+bool Unpack::ReadVMCode()
+{
+ // Entire VM code is guaranteed to fully present in block defined
+ // by current Huffman table. Compressor checks that VM code does not cross
+ // Huffman block boundaries.
+ unsigned int FirstByte=Inp.getbits()>>8;
+ Inp.addbits(8);
+ int Length=(FirstByte & 7)+1;
+ if (Length==7)
+ {
+ Length=(Inp.getbits()>>8)+7;
+ Inp.addbits(8);
+ }
+ else
+ if (Length==8)
+ {
+ Length=Inp.getbits();
+ Inp.addbits(16);
+ }
+ Array<byte> VMCode(Length);
+ for (int I=0;I<Length;I++)
+ {
+ // 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);
+ VMCode[I]=Inp.getbits()>>8;
+ Inp.addbits(8);
+ }
+ return(AddVMCode(FirstByte,&VMCode[0],Length));
+}
+
+
+bool Unpack::ReadVMCodePPM()
+{
+ unsigned int FirstByte=SafePPMDecodeChar();
+ if ((int)FirstByte==-1)
+ return(false);
+ int Length=(FirstByte & 7)+1;
+ if (Length==7)
+ {
+ int B1=SafePPMDecodeChar();
+ if (B1==-1)
+ return(false);
+ Length=B1+7;
+ }
+ else
+ if (Length==8)
+ {
+ int B1=SafePPMDecodeChar();
+ if (B1==-1)
+ return(false);
+ int B2=SafePPMDecodeChar();
+ if (B2==-1)
+ return(false);
+ Length=B1*256+B2;
+ }
+ Array<byte> VMCode(Length);
+ for (int I=0;I<Length;I++)
+ {
+ int Ch=SafePPMDecodeChar();
+ if (Ch==-1)
+ return(false);
+ VMCode[I]=Ch;
+ }
+ return(AddVMCode(FirstByte,&VMCode[0],Length));
+}
+
+
+bool Unpack::AddVMCode(uint FirstByte,byte *Code,int CodeSize)
+{
+ VMCodeInp.InitBitInput();
+ memcpy(VMCodeInp.InBuf,Code,Min(BitInput::MAX_SIZE,CodeSize));
+ VM.Init();
+
+ uint FiltPos;
+ if (FirstByte & 0x80)
+ {
+ FiltPos=RarVM::ReadData(VMCodeInp);
+ if (FiltPos==0)
+ InitFilters30();
+ else
+ FiltPos--;
+ }
+ else
+ FiltPos=LastFilter; // Use the same filter as last time.
+
+ if (FiltPos>Filters30.Size() || FiltPos>OldFilterLengths.Size())
+ return(false);
+ LastFilter=FiltPos;
+ bool NewFilter=(FiltPos==Filters30.Size());
+
+ UnpackFilter30 *StackFilter=new UnpackFilter30; // New filter for PrgStack.
+
+ UnpackFilter30 *Filter;
+ if (NewFilter) // New filter code, never used before since VM reset.
+ {
+ if (FiltPos>MAX3_FILTERS)
+ {
+ // Too many different filters, corrupt archive.
+ delete StackFilter;
+ return false;
+ }
+
+ Filters30.Add(1);
+ Filters30[Filters30.Size()-1]=Filter=new UnpackFilter30;
+ StackFilter->ParentFilter=(uint)(Filters30.Size()-1);
+
+ // Reserve one item, where we store the data block length of our new
+ // filter entry. We'll set it to real block length below, after reading
+ // it. But we need to initialize it now, because when processing corrupt
+ // data, we can access this item even before we set it to real value.
+ OldFilterLengths.Push(0);
+ Filter->ExecCount=0;
+ }
+ else // Filter was used in the past.
+ {
+ Filter=Filters30[FiltPos];
+ StackFilter->ParentFilter=FiltPos;
+ Filter->ExecCount++;
+ }
+
+ int EmptyCount=0;
+ for (uint I=0;I<PrgStack.Size();I++)
+ {
+ PrgStack[I-EmptyCount]=PrgStack[I];
+ if (PrgStack[I]==NULL)
+ EmptyCount++;
+ if (EmptyCount>0)
+ PrgStack[I]=NULL;
+ }
+ if (EmptyCount==0)
+ {
+ PrgStack.Add(1);
+ EmptyCount=1;
+ }
+ int StackPos=(int)(PrgStack.Size()-EmptyCount);
+ PrgStack[StackPos]=StackFilter;
+ StackFilter->ExecCount=Filter->ExecCount;
+
+ uint BlockStart=RarVM::ReadData(VMCodeInp);
+ if (FirstByte & 0x40)
+ BlockStart+=258;
+ StackFilter->BlockStart=(uint)((BlockStart+UnpPtr)&MaxWinMask);
+ if (FirstByte & 0x20)
+ {
+ StackFilter->BlockLength=RarVM::ReadData(VMCodeInp);
+
+ // Store the last data block length for current filter.
+ OldFilterLengths[FiltPos]=StackFilter->BlockLength;
+ }
+ else
+ {
+ // Set the data block size to same value as the previous block size
+ // for same filter. It is possible on corrupt data to access here a new
+ // and not filled yet item of OldFilterLengths array. This is why above
+ // we set new OldFilterLengths items to zero.
+ StackFilter->BlockLength=FiltPos<OldFilterLengths.Size() ? OldFilterLengths[FiltPos]:0;
+ }
+
+ StackFilter->NextWindow=WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MaxWinMask)<=BlockStart;
+
+// DebugLog("\nNextWindow: UnpPtr=%08x WrPtr=%08x BlockStart=%08x",UnpPtr,WrPtr,BlockStart);
+
+ memset(StackFilter->Prg.InitR,0,sizeof(StackFilter->Prg.InitR));
+ StackFilter->Prg.InitR[3]=VM_GLOBALMEMADDR;
+ StackFilter->Prg.InitR[4]=StackFilter->BlockLength;
+ StackFilter->Prg.InitR[5]=StackFilter->ExecCount;
+
+ if (FirstByte & 0x10) // set registers to optional parameters if any
+ {
+ unsigned int InitMask=VMCodeInp.fgetbits()>>9;
+ VMCodeInp.faddbits(7);
+ for (int I=0;I<7;I++)
+ if (InitMask & (1<<I))
+ StackFilter->Prg.InitR[I]=RarVM::ReadData(VMCodeInp);
+ }
+
+ if (NewFilter)
+ {
+ uint VMCodeSize=RarVM::ReadData(VMCodeInp);
+ if (VMCodeSize>=0x10000 || VMCodeSize==0)
+ return(false);
+ Array<byte> VMCode(VMCodeSize);
+ for (uint I=0;I<VMCodeSize;I++)
+ {
+ if (VMCodeInp.Overflow(3))
+ return(false);
+ VMCode[I]=VMCodeInp.fgetbits()>>8;
+ VMCodeInp.faddbits(8);
+ }
+ VM.Prepare(&VMCode[0],VMCodeSize,&Filter->Prg);
+ }
+ StackFilter->Prg.AltCmd=&Filter->Prg.Cmd[0];
+ StackFilter->Prg.CmdCount=Filter->Prg.CmdCount;
+
+ size_t StaticDataSize=Filter->Prg.StaticData.Size();
+ if (StaticDataSize>0 && StaticDataSize<VM_GLOBALMEMSIZE)
+ {
+ // read statically defined data contained in DB commands
+ StackFilter->Prg.StaticData.Add(StaticDataSize);
+ memcpy(&StackFilter->Prg.StaticData[0],&Filter->Prg.StaticData[0],StaticDataSize);
+ }
+
+ if (StackFilter->Prg.GlobalData.Size()<VM_FIXEDGLOBALSIZE)
+ {
+ StackFilter->Prg.GlobalData.Reset();
+ StackFilter->Prg.GlobalData.Add(VM_FIXEDGLOBALSIZE);
+ }
+ byte *GlobalData=&StackFilter->Prg.GlobalData[0];
+ for (int I=0;I<7;I++)
+ VM.SetLowEndianValue((uint *)&GlobalData[I*4],StackFilter->Prg.InitR[I]);
+ VM.SetLowEndianValue((uint *)&GlobalData[0x1c],StackFilter->BlockLength);
+ VM.SetLowEndianValue((uint *)&GlobalData[0x20],0);
+ VM.SetLowEndianValue((uint *)&GlobalData[0x2c],StackFilter->ExecCount);
+ memset(&GlobalData[0x30],0,16);
+
+ if (FirstByte & 8) // Put the data block passed as parameter if any.
+ {
+ if (VMCodeInp.Overflow(3))
+ return(false);
+ uint DataSize=RarVM::ReadData(VMCodeInp);
+ if (DataSize>VM_GLOBALMEMSIZE-VM_FIXEDGLOBALSIZE)
+ return(false);
+ size_t CurSize=StackFilter->Prg.GlobalData.Size();
+ if (CurSize<DataSize+VM_FIXEDGLOBALSIZE)
+ StackFilter->Prg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize);
+ byte *GlobalData=&StackFilter->Prg.GlobalData[VM_FIXEDGLOBALSIZE];
+ for (uint I=0;I<DataSize;I++)
+ {
+ if (VMCodeInp.Overflow(3))
+ return(false);
+ GlobalData[I]=VMCodeInp.fgetbits()>>8;
+ VMCodeInp.faddbits(8);
+ }
+ }
+ return(true);
+}
+
+
+bool Unpack::UnpReadBuf30()
+{
+ int DataSize=ReadTop-Inp.InAddr; // Data left to process.
+ if (DataSize<0)
+ return(false);
+ if (Inp.InAddr>BitInput::MAX_SIZE/2)
+ {
+ // If we already processed more than half of buffer, let's move
+ // remaining data into beginning to free more space for new data
+ // and ensure that calling function does not cross the buffer border
+ // even if we did not read anything here. Also it ensures that read size
+ // is not less than CRYPT_BLOCK_SIZE, so we can align it without risk
+ // to make it zero.
+ if (DataSize>0)
+ memmove(Inp.InBuf,Inp.InBuf+Inp.InAddr,DataSize);
+ Inp.InAddr=0;
+ ReadTop=DataSize;
+ }
+ else
+ DataSize=ReadTop;
+ int ReadCode=UnpIO->UnpRead(Inp.InBuf+DataSize,BitInput::MAX_SIZE-DataSize);
+ if (ReadCode>0)
+ ReadTop+=ReadCode;
+ ReadBorder=ReadTop-30;
+ return(ReadCode!=-1);
+}
+
+
+void Unpack::UnpWriteBuf30()
+{
+ uint WrittenBorder=(uint)WrPtr;
+ uint WriteSize=(uint)((UnpPtr-WrittenBorder)&MaxWinMask);
+ for (size_t I=0;I<PrgStack.Size();I++)
+ {
+ // Here we apply filters to data which we need to write.
+ // We always copy data to virtual machine memory 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.
+
+ UnpackFilter30 *flt=PrgStack[I];
+ if (flt==NULL)
+ continue;
+ if (flt->NextWindow)
+ {
+ flt->NextWindow=false;
+ continue;
+ }
+ unsigned int BlockStart=flt->BlockStart;
+ unsigned int BlockLength=flt->BlockLength;
+ if (((BlockStart-WrittenBorder)&MaxWinMask)<WriteSize)
+ {
+ if (WrittenBorder!=BlockStart)
+ {
+ UnpWriteArea(WrittenBorder,BlockStart);
+ WrittenBorder=BlockStart;
+ WriteSize=(uint)((UnpPtr-WrittenBorder)&MaxWinMask);
+ }
+ if (BlockLength<=WriteSize)
+ {
+ uint BlockEnd=(BlockStart+BlockLength)&MaxWinMask;
+ if (BlockStart<BlockEnd || BlockEnd==0)
+ VM.SetMemory(0,Window+BlockStart,BlockLength);
+ else
+ {
+ uint FirstPartLength=uint(MaxWinSize-BlockStart);
+ VM.SetMemory(0,Window+BlockStart,FirstPartLength);
+ VM.SetMemory(FirstPartLength,Window,BlockEnd);
+ }
+
+ VM_PreparedProgram *ParentPrg=&Filters30[flt->ParentFilter]->Prg;
+ VM_PreparedProgram *Prg=&flt->Prg;
+
+ if (ParentPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE)
+ {
+ // Copy global data from previous script execution if any.
+ Prg->GlobalData.Alloc(ParentPrg->GlobalData.Size());
+ memcpy(&Prg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE);
+ }
+
+ ExecuteCode(Prg);
+
+ if (Prg->GlobalData.Size()>VM_FIXEDGLOBALSIZE)
+ {
+ // Save global data for next script execution.
+ if (ParentPrg->GlobalData.Size()<Prg->GlobalData.Size())
+ ParentPrg->GlobalData.Alloc(Prg->GlobalData.Size());
+ memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&Prg->GlobalData[VM_FIXEDGLOBALSIZE],Prg->GlobalData.Size()-VM_FIXEDGLOBALSIZE);
+ }
+ else
+ ParentPrg->GlobalData.Reset();
+
+ byte *FilteredData=Prg->FilteredData;
+ unsigned int FilteredDataSize=Prg->FilteredDataSize;
+
+ delete PrgStack[I];
+ PrgStack[I]=NULL;
+ while (I+1<PrgStack.Size())
+ {
+ UnpackFilter30 *NextFilter=PrgStack[I+1];
+ if (NextFilter==NULL || NextFilter->BlockStart!=BlockStart ||
+ NextFilter->BlockLength!=FilteredDataSize || NextFilter->NextWindow)
+ break;
+
+ // Apply several filters to same data block.
+
+ VM.SetMemory(0,FilteredData,FilteredDataSize);
+
+ VM_PreparedProgram *ParentPrg=&Filters30[NextFilter->ParentFilter]->Prg;
+ VM_PreparedProgram *NextPrg=&NextFilter->Prg;
+
+ if (ParentPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE)
+ {
+ // Copy global data from previous script execution if any.
+ NextPrg->GlobalData.Alloc(ParentPrg->GlobalData.Size());
+ memcpy(&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE);
+ }
+
+ ExecuteCode(NextPrg);
+
+ if (NextPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE)
+ {
+ // Save global data for next script execution.
+ if (ParentPrg->GlobalData.Size()<NextPrg->GlobalData.Size())
+ ParentPrg->GlobalData.Alloc(NextPrg->GlobalData.Size());
+ memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],NextPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE);
+ }
+ else
+ ParentPrg->GlobalData.Reset();
+
+ FilteredData=NextPrg->FilteredData;
+ FilteredDataSize=NextPrg->FilteredDataSize;
+ I++;
+ delete PrgStack[I];
+ PrgStack[I]=NULL;
+ }
+ UnpIO->UnpWrite(FilteredData,FilteredDataSize);
+ UnpSomeRead=true;
+ WrittenFileSize+=FilteredDataSize;
+ WrittenBorder=BlockEnd;
+ WriteSize=uint((UnpPtr-WrittenBorder)&MaxWinMask);
+ }
+ else
+ {
+ // Current filter intersects the window write border, so we adjust
+ // the window border to process this filter next time, not now.
+ for (size_t J=I;J<PrgStack.Size();J++)
+ {
+ UnpackFilter30 *flt=PrgStack[J];
+ if (flt!=NULL && flt->NextWindow)
+ flt->NextWindow=false;
+ }
+ WrPtr=WrittenBorder;
+ return;
+ }
+ }
+ }
+
+ UnpWriteArea(WrittenBorder,UnpPtr);
+ WrPtr=UnpPtr;
+}
+
+
+void Unpack::ExecuteCode(VM_PreparedProgram *Prg)
+{
+ if (Prg->GlobalData.Size()>0)
+ {
+ Prg->InitR[6]=(uint)WrittenFileSize;
+ VM.SetLowEndianValue((uint *)&Prg->GlobalData[0x24],(uint)WrittenFileSize);
+ VM.SetLowEndianValue((uint *)&Prg->GlobalData[0x28],(uint)(WrittenFileSize>>32));
+ VM.Execute(Prg);
+ }
+}
+
+
+bool Unpack::ReadTables30()
+{
+ byte BitLength[BC];
+ byte Table[HUFF_TABLE_SIZE30];
+ if (Inp.InAddr>ReadTop-25)
+ if (!UnpReadBuf30())
+ return(false);
+ Inp.faddbits((8-Inp.InBit)&7);
+ uint BitField=Inp.fgetbits();
+ if (BitField & 0x8000)
+ {
+ UnpBlockType=BLOCK_PPM;
+ return(PPM.DecodeInit(this,PPMEscChar));
+ }
+ UnpBlockType=BLOCK_LZ;
+
+ PrevLowDist=0;
+ LowDistRepCount=0;
+
+ if (!(BitField & 0x4000))
+ memset(UnpOldTable,0,sizeof(UnpOldTable));
+ Inp.faddbits(2);
+
+ for (int I=0;I<BC;I++)
+ {
+ int Length=(byte)(Inp.fgetbits() >> 12);
+ Inp.faddbits(4);
+ if (Length==15)
+ {
+ int ZeroCount=(byte)(Inp.fgetbits() >> 12);
+ Inp.faddbits(4);
+ if (ZeroCount==0)
+ BitLength[I]=15;
+ else
+ {
+ ZeroCount+=2;
+ while (ZeroCount-- > 0 && I<ASIZE(BitLength))
+ BitLength[I++]=0;
+ I--;
+ }
+ }
+ else
+ BitLength[I]=Length;
+ }
+ MakeDecodeTables(BitLength,&BlockTables.BD,BC30);
+
+ const int TableSize=HUFF_TABLE_SIZE30;
+ for (int I=0;I<TableSize;)
+ {
+ if (Inp.InAddr>ReadTop-5)
+ if (!UnpReadBuf30())
+ return(false);
+ int Number=DecodeNumber(Inp,&BlockTables.BD);
+ if (Number<16)
+ {
+ Table[I]=(Number+UnpOldTable[I]) & 0xf;
+ I++;
+ }
+ else
+ if (Number<18)
+ {
+ int N;
+ if (Number==16)
+ {
+ N=(Inp.fgetbits() >> 13)+3;
+ Inp.faddbits(3);
+ }
+ else
+ {
+ N=(Inp.fgetbits() >> 9)+11;
+ Inp.faddbits(7);
+ }
+ if (I>0)
+ while (N-- > 0 && I<TableSize)
+ {
+ Table[I]=Table[I-1];
+ I++;
+ }
+ }
+ else
+ {
+ int N;
+ if (Number==18)
+ {
+ N=(Inp.fgetbits() >> 13)+3;
+ Inp.faddbits(3);
+ }
+ else
+ {
+ N=(Inp.fgetbits() >> 9)+11;
+ Inp.faddbits(7);
+ }
+ while (N-- > 0 && I<TableSize)
+ Table[I++]=0;
+ }
+ }
+ TablesRead=true;
+ if (Inp.InAddr>ReadTop)
+ return(false);
+ MakeDecodeTables(&Table[0],&BlockTables.LD,NC30);
+ MakeDecodeTables(&Table[NC30],&BlockTables.DD,DC30);
+ MakeDecodeTables(&Table[NC30+DC30],&BlockTables.LDD,LDC30);
+ MakeDecodeTables(&Table[NC30+DC30+LDC30],&BlockTables.RD,RC30);
+ memcpy(UnpOldTable,Table,sizeof(UnpOldTable));
+ return(true);
+}
+
+
+void Unpack::UnpInitData30(bool Solid)
+{
+ if (!Solid)
+ {
+ TablesRead=false;
+ memset(UnpOldTable,0,sizeof(UnpOldTable));
+ PPMEscChar=2;
+ UnpBlockType=BLOCK_LZ;
+
+ InitFilters30();
+ }
+}
+
+
+void Unpack::InitFilters30()
+{
+ OldFilterLengths.Reset();
+ LastFilter=0;
+
+ for (size_t I=0;I<Filters30.Size();I++)
+ delete Filters30[I];
+ Filters30.Reset();
+ for (size_t I=0;I<PrgStack.Size();I++)
+ delete PrgStack[I];
+ PrgStack.Reset();
+}
diff --git a/src/thirdparty/unrar/unpack50.cpp b/src/thirdparty/unrar/unpack50.cpp
new file mode 100644
index 000000000..989d15bd1
--- /dev/null
+++ b/src/thirdparty/unrar/unpack50.cpp
@@ -0,0 +1,820 @@
+void Unpack::Unpack5(bool Solid)
+{
+ FileExtracted=true;
+
+ if (!Suspended)
+ {
+ UnpInitData(Solid);
+ if (!UnpReadBuf())
+ return;
+ if (!ReadBlockHeader(Inp,BlockHeader) || !ReadTables(Inp,BlockHeader,BlockTables))
+ return;
+ }
+
+ while (true)
+ {
+ UnpPtr&=MaxWinMask;
+
+ if (Inp.InAddr>=ReadBorder)
+ {
+ bool FileDone=false;
+
+ // We use 'while', because for empty block containing only Huffman table,
+ // we'll be on the block border once again just after reading the table.
+ while (Inp.InAddr>BlockHeader.BlockStart+BlockHeader.BlockSize-1 ||
+ Inp.InAddr==BlockHeader.BlockStart+BlockHeader.BlockSize-1 &&
+ Inp.InBit>=BlockHeader.BlockBitSize)
+ {
+ if (BlockHeader.LastBlockInFile)
+ {
+ FileDone=true;
+ break;
+ }
+ if (!ReadBlockHeader(Inp,BlockHeader) || !ReadTables(Inp,BlockHeader,BlockTables))
+ return;
+ }
+ if (FileDone || !UnpReadBuf())
+ break;
+ }
+
+ if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_LZ_MATCH+3 && WriteBorder!=UnpPtr)
+ {
+ UnpWriteBuf();
+ if (WrittenFileSize>DestUnpSize)
+ return;
+ if (Suspended)
+ {
+ FileExtracted=false;
+ return;
+ }
+ }
+
+ uint MainSlot=DecodeNumber(Inp,&BlockTables.LD);
+ if (MainSlot<256)
+ {
+ Window[UnpPtr++]=(byte)MainSlot;
+ continue;
+ }
+ if (MainSlot>=262)
+ {
+ uint Length=SlotToLength(Inp,MainSlot-262);
+
+ uint DBits,Distance=1,DistSlot=DecodeNumber(Inp,&BlockTables.DD);
+ if (DistSlot<4)
+ {
+ DBits=0;
+ Distance+=DistSlot;
+ }
+ else
+ {
+ DBits=DistSlot/2 - 1;
+ Distance+=(2 | (DistSlot & 1)) << DBits;
+ }
+
+ if (DBits>0)
+ {
+ if (DBits>=4)
+ {
+ if (DBits>4)
+ {
+ Distance+=((Inp.getbits32()>>(36-DBits))<<4);
+ Inp.addbits(DBits-4);
+ }
+ uint LowDist=DecodeNumber(Inp,&BlockTables.LDD);
+ Distance+=LowDist;
+ }
+ else
+ {
+ Distance+=Inp.getbits32()>>(32-DBits);
+ Inp.addbits(DBits);
+ }
+ }
+
+ if (Distance>0x100)
+ {
+ Length++;
+ if (Distance>0x2000)
+ {
+ Length++;
+ if (Distance>0x40000)
+ Length++;
+ }
+ }
+
+ InsertOldDist(Distance);
+ LastLength=Length;
+ CopyString(Length,Distance);
+ continue;
+ }
+ if (MainSlot==256)
+ {
+ UnpackFilter Filter;
+ if (!ReadFilter(Inp,Filter) || !AddFilter(Filter))
+ break;
+ continue;
+ }
+ if (MainSlot==257)
+ {
+ if (LastLength!=0)
+ CopyString(LastLength,OldDist[0]);
+ continue;
+ }
+ if (MainSlot<262)
+ {
+ uint DistNum=MainSlot-258;
+ uint Distance=OldDist[DistNum];
+ for (uint I=DistNum;I>0;I--)
+ OldDist[I]=OldDist[I-1];
+ OldDist[0]=Distance;
+
+ uint LengthSlot=DecodeNumber(Inp,&BlockTables.RD);
+ uint Length=SlotToLength(Inp,LengthSlot);
+ LastLength=Length;
+ CopyString(Length,Distance);
+ continue;
+ }
+ }
+ UnpWriteBuf();
+}
+
+
+uint Unpack::ReadFilterData(BitInput &Inp)
+{
+ uint ByteCount=(Inp.fgetbits()>>14)+1;
+ Inp.addbits(2);
+
+ uint Data=0;
+ for (uint I=0;I<ByteCount;I++)
+ {
+ Data+=(Inp.fgetbits()>>8)<<(I*8);
+ Inp.addbits(8);
+ }
+ return Data;
+}
+
+
+bool Unpack::ReadFilter(BitInput &Inp,UnpackFilter &Filter)
+{
+ if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-16)
+ if (!UnpReadBuf())
+ return false;
+
+ Filter.BlockStart=ReadFilterData(Inp);
+ Filter.BlockLength=ReadFilterData(Inp);
+
+ Filter.Type=Inp.fgetbits()>>13;
+ Inp.faddbits(3);
+
+ if (Filter.Type==FILTER_DELTA || Filter.Type==FILTER_AUDIO)
+ {
+ Filter.Channels=(Inp.fgetbits()>>11)+1;
+ Inp.faddbits(5);
+ }
+
+ if (Filter.Type==FILTER_RGB)
+ {
+ Filter.Channels=3;
+ Filter.Width=Inp.fgetbits()+1;
+ Inp.faddbits(16);
+ Filter.PosR=Inp.fgetbits()>>14;
+ Inp.faddbits(2);
+ }
+
+ return true;
+}
+
+
+bool Unpack::AddFilter(UnpackFilter &Filter)
+{
+ if (Filters.Size()>=MAX_UNPACK_FILTERS-1)
+ UnpWriteBuf(); // Write data, apply and flush filters.
+
+ // 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'
+ // flag and process this filter only after processing that older data.
+ Filter.NextWindow=WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MaxWinMask)<=Filter.BlockStart;
+
+ Filter.BlockStart=uint((Filter.BlockStart+UnpPtr)&MaxWinMask);
+ Filters.Push(Filter);
+ return true;
+}
+
+
+bool Unpack::UnpReadBuf()
+{
+ int DataSize=ReadTop-Inp.InAddr; // Data left to process.
+ if (DataSize<0)
+ return false;
+ BlockHeader.BlockSize-=Inp.InAddr-BlockHeader.BlockStart;
+ if (Inp.InAddr>BitInput::MAX_SIZE/2)
+ {
+ // If we already processed more than half of buffer, let's move
+ // remaining data into beginning to free more space for new data
+ // and ensure that calling function does not cross the buffer border
+ // even if we did not read anything here. Also it ensures that read size
+ // is not less than CRYPT_BLOCK_SIZE, so we can align it without risk
+ // to make it zero.
+ if (DataSize>0)
+ memmove(Inp.InBuf,Inp.InBuf+Inp.InAddr,DataSize);
+ Inp.InAddr=0;
+ ReadTop=DataSize;
+ }
+ else
+ DataSize=ReadTop;
+ int ReadCode=UnpIO->UnpRead(Inp.InBuf+DataSize,BitInput::MAX_SIZE-DataSize);
+ if (ReadCode>0)
+ ReadTop+=ReadCode;
+ ReadBorder=ReadTop-30;
+ BlockHeader.BlockStart=Inp.InAddr;
+ if (BlockHeader.BlockSize!=-1) // '-1' means not defined yet.
+ ReadBorder=Min(ReadBorder,BlockHeader.BlockStart+BlockHeader.BlockSize-1);
+ return ReadCode!=-1;
+}
+
+
+void Unpack::UnpWriteBuf()
+{
+ size_t WrittenBorder=WrPtr;
+ size_t FullWriteSize=(UnpPtr-WrittenBorder)&MaxWinMask;
+ size_t WriteSizeLeft=FullWriteSize;
+ bool NotAllFiltersProcessed=false;
+ 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 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.
+
+ UnpackFilter *flt=&Filters[I];
+ if (flt->Type==FILTER_NONE)
+ continue;
+ 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
+ // 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
+ // implementation seems to guarantee 'NextWindow' flag reset after
+ // buffer writing for all existing filters. But let's keep this check
+ // just in case. Compressor guarantees that distance between
+ // filter block start and filter storing position cannot exceed
+ // the dictionary size. So if we covered the filter block start with
+ // our write here, we can safely assume that filter is applicable
+ // to next block on no further wrap arounds is possible.
+ if (((flt->BlockStart-WrPtr)&MaxWinMask)<=FullWriteSize)
+ flt->NextWindow=false;
+ continue;
+ }
+ uint BlockStart=flt->BlockStart;
+ uint BlockLength=flt->BlockLength;
+ if (((BlockStart-WrittenBorder)&MaxWinMask)<WriteSizeLeft)
+ {
+ if (WrittenBorder!=BlockStart)
+ {
+ UnpWriteArea(WrittenBorder,BlockStart);
+ WrittenBorder=BlockStart;
+ WriteSizeLeft=(UnpPtr-WrittenBorder)&MaxWinMask;
+ }
+ if (BlockLength<=WriteSizeLeft)
+ {
+ if (BlockLength>0)
+ {
+ uint BlockEnd=(BlockStart+BlockLength)&MaxWinMask;
+
+ FilterSrcMemory.Alloc(BlockLength);
+ byte *Mem=&FilterSrcMemory[0];
+ if (BlockStart<BlockEnd || BlockEnd==0)
+ memcpy(Mem,Window+BlockStart,BlockLength);
+ else
+ {
+ size_t FirstPartLength=size_t(MaxWinSize-BlockStart);
+ memcpy(Mem,Window+BlockStart,FirstPartLength);
+ memcpy(Mem+FirstPartLength,Window,BlockEnd);
+ }
+
+ byte *OutMem=ApplyFilter(Mem,BlockLength,flt);
+
+ Filters[I].Type=FILTER_NONE;
+
+ if (OutMem!=NULL)
+ UnpIO->UnpWrite(OutMem,BlockLength);
+
+ UnpSomeRead=true;
+ WrittenFileSize+=BlockLength;
+ WrittenBorder=BlockEnd;
+ WriteSizeLeft=(UnpPtr-WrittenBorder)&MaxWinMask;
+ }
+ }
+ else
+ {
+ // Current filter intersects the window write border, so we adjust
+ // the window border to process this filter next time, not now.
+ WrPtr=WrittenBorder;
+
+ // Since Filter start position can only increase, we quit processing
+ // all following filters for this data block and reset 'NextWindow'
+ // flag for them.
+ for (size_t J=I;J<Filters.Size();J++)
+ {
+ UnpackFilter *flt=&Filters[J];
+ if (flt->Type!=FILTER_NONE)
+ flt->NextWindow=false;
+ }
+
+ // Do not write data left after current filter now.
+ NotAllFiltersProcessed=true;
+ break;
+ }
+ }
+ }
+
+ // Remove processed filters from queue.
+ size_t EmptyCount=0;
+ for (size_t I=0;I<Filters.Size();I++)
+ {
+ if (EmptyCount>0)
+ Filters[I-EmptyCount]=Filters[I];
+ if (Filters[I].Type==FILTER_NONE)
+ EmptyCount++;
+ }
+ if (EmptyCount>0)
+ Filters.Alloc(Filters.Size()-EmptyCount);
+
+ if (!NotAllFiltersProcessed) // Only if all filters are processed.
+ {
+ // Write data left after last filter.
+ UnpWriteArea(WrittenBorder,UnpPtr);
+ WrPtr=UnpPtr;
+ }
+
+ // We prefer to write data in blocks not exceeding UNPACK_MAX_WRITE
+ // instead of potentially huge MaxWinSize blocks.
+ WriteBorder=(UnpPtr+Min(MaxWinSize,UNPACK_MAX_WRITE))&MaxWinMask;
+
+ // Choose the nearest among WriteBorder and WrPtr actual written border.
+ // If border is equal to UnpPtr, it means that we have MaxWinSize data ahead.
+ if (WriteBorder==UnpPtr ||
+ WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MaxWinMask)<((WriteBorder-UnpPtr)&MaxWinMask))
+ WriteBorder=WrPtr;
+}
+
+
+uint Unpack::FilterItanium_GetBits(byte *Data,int BitPos,int BitCount)
+{
+ int InAddr=BitPos/8;
+ int InBit=BitPos&7;
+ uint BitField=(uint)Data[InAddr++];
+ BitField|=(uint)Data[InAddr++] << 8;
+ BitField|=(uint)Data[InAddr++] << 16;
+ BitField|=(uint)Data[InAddr] << 24;
+ BitField >>= InBit;
+ return(BitField & (0xffffffff>>(32-BitCount)));
+}
+
+
+void Unpack::FilterItanium_SetBits(byte *Data,uint BitField,int BitPos,int BitCount)
+{
+ int InAddr=BitPos/8;
+ int InBit=BitPos&7;
+ uint AndMask=0xffffffff>>(32-BitCount);
+ AndMask=~(AndMask<<InBit);
+
+ BitField<<=InBit;
+
+ for (uint I=0;I<4;I++)
+ {
+ Data[InAddr+I]&=AndMask;
+ Data[InAddr+I]|=BitField;
+ AndMask=(AndMask>>8)|0xff000000;
+ BitField>>=8;
+ }
+}
+
+
+inline uint GetFiltData32(byte *Data)
+{
+#if defined(BIG_ENDIAN) || !defined(ALLOW_NOT_ALIGNED_INT) || !defined(PRESENT_INT32)
+ uint Value=GET_UINT32((uint)Data[0]|((uint)Data[1]<<8)|((uint)Data[2]<<16)|((uint)Data[3]<<24));
+#else
+ uint Value=GET_UINT32(*(uint32 *)Data);
+#endif
+ return Value;
+}
+
+
+inline void SetFiltData32(byte *Data,uint Value)
+{
+#if defined(BIG_ENDIAN) || !defined(ALLOW_NOT_ALIGNED_INT) || !defined(PRESENT_INT32)
+ Data[0]=(byte)Value;
+ Data[1]=(byte)(Value>>8);
+ Data[2]=(byte)(Value>>16);
+ Data[3]=(byte)(Value>>24);
+#else
+ *(int32 *)Data=Value;
+#endif
+}
+
+
+byte* Unpack::ApplyFilter(byte *Data,uint DataSize,UnpackFilter *Flt)
+{
+ byte *SrcData=Data;
+ switch(Flt->Type)
+ {
+ case FILTER_E8:
+ case FILTER_E8E9:
+ {
+ uint FileOffset=(uint)WrittenFileSize;
+
+ const int FileSize=0x1000000;
+ byte CmpByte2=Flt->Type==FILTER_E8E9 ? 0xe9:0xe8;
+ for (uint CurPos=0;(int)CurPos<(int)DataSize-4;)
+ {
+ byte CurByte=*(Data++);
+ CurPos++;
+ if (CurByte==0xe8 || CurByte==CmpByte2)
+ {
+ uint Offset=(CurPos+FileOffset)%FileSize;
+ uint Addr=GetFiltData32(Data);
+
+ // We check 0x80000000 bit instead of '< 0' comparison
+ // not assuming int32 presence or uint size and endianness.
+ if ((Addr & 0x80000000)!=0) // Addr<0
+ {
+ if (((Addr+Offset) & 0x80000000)==0) // Addr+Offset>=0
+ SetFiltData32(Data,Addr+FileSize);
+ }
+ else
+ if (((Addr-FileSize) & 0x80000000)!=0) // Addr<FileSize
+ SetFiltData32(Data,Addr-Offset);
+
+ Data+=4;
+ CurPos+=4;
+ }
+ }
+ }
+ return SrcData;
+ case FILTER_ARM:
+ {
+ uint FileOffset=(uint)WrittenFileSize;
+ for (uint CurPos=0;(int)CurPos<(int)DataSize-3;CurPos+=4)
+ {
+ byte *D=Data+CurPos;
+ if (D[3]==0xeb) // BL command with '1110' (Always) condition.
+ {
+ uint Offset=D[0]+uint(D[1])*0x100+uint(D[2])*0x10000;
+ Offset-=(FileOffset+CurPos)/4;
+ D[0]=(byte)Offset;
+ D[1]=(byte)(Offset>>8);
+ D[2]=(byte)(Offset>>16);
+ }
+ }
+ }
+ return SrcData;
+ case FILTER_ITANIUM:
+ {
+ uint FileOffset=(uint)WrittenFileSize;
+
+ uint CurPos=0;
+
+ FileOffset>>=4;
+
+ while ((int)CurPos<(int)DataSize-21)
+ {
+ int Byte=(Data[0]&0x1f)-0x10;
+ if (Byte>=0)
+ {
+ static byte Masks[16]={4,4,6,6,0,0,7,7,4,4,0,0,4,4,0,0};
+ byte CmdMask=Masks[Byte];
+ if (CmdMask!=0)
+ for (int I=0;I<=2;I++)
+ if (CmdMask & (1<<I))
+ {
+ int StartPos=I*41+5;
+ int OpType=FilterItanium_GetBits(Data,StartPos+37,4);
+ if (OpType==5)
+ {
+ int Offset=FilterItanium_GetBits(Data,StartPos+13,20);
+ FilterItanium_SetBits(Data,(Offset-FileOffset)&0xfffff,StartPos+13,20);
+ }
+ }
+ }
+ Data+=16;
+ CurPos+=16;
+ FileOffset++;
+ }
+ }
+ return SrcData;
+ case FILTER_AUDIO:
+ {
+ uint Channels=Flt->Channels;
+
+ byte *SrcData=Data;
+
+ FilterDstMemory.Alloc(DataSize);
+ byte *DstData=&FilterDstMemory[0];
+
+ for (uint CurChannel=0;CurChannel<Channels;CurChannel++)
+ {
+ uint PrevByte=0,PrevDelta=0,Dif[7];
+ int D1=0,D2=0,D3;
+ int K1=0,K2=0,K3=0;
+ memset(Dif,0,sizeof(Dif));
+
+ for (uint I=CurChannel,ByteCount=0;I<DataSize;I+=Channels,ByteCount++)
+ {
+ D3=D2;
+ D2=PrevDelta-D1;
+ D1=PrevDelta;
+
+ uint Predicted=8*PrevByte+K1*D1+K2*D2+K3*D3;
+ Predicted=(Predicted>>3) & 0xff;
+
+ uint CurByte=*(SrcData++);
+
+ Predicted-=CurByte;
+ DstData[I]=Predicted;
+ PrevDelta=(signed char)(Predicted-PrevByte);
+ PrevByte=Predicted;
+
+ int D=((signed char)CurByte)<<3;
+
+ Dif[0]+=abs(D);
+ Dif[1]+=abs(D-D1);
+ Dif[2]+=abs(D+D1);
+ Dif[3]+=abs(D-D2);
+ Dif[4]+=abs(D+D2);
+ Dif[5]+=abs(D-D3);
+ Dif[6]+=abs(D+D3);
+
+ if ((ByteCount & 0x1f)==0)
+ {
+ uint MinDif=Dif[0],NumMinDif=0;
+ Dif[0]=0;
+ for (uint J=1;J<ASIZE(Dif);J++)
+ {
+ if (Dif[J]<MinDif)
+ {
+ MinDif=Dif[J];
+ NumMinDif=J;
+ }
+ Dif[J]=0;
+ }
+ switch(NumMinDif)
+ {
+ case 1: if (K1>=-16) K1--; break;
+ case 2: if (K1 < 16) K1++; break;
+ case 3: if (K2>=-16) K2--; break;
+ case 4: if (K2 < 16) K2++; break;
+ case 5: if (K3>=-16) K3--; break;
+ case 6: if (K3 < 16) K3++; break;
+ }
+ }
+ }
+ }
+ return DstData;
+ }
+ case FILTER_DELTA:
+ {
+ uint Channels=Flt->Channels,SrcPos=0;
+
+ FilterDstMemory.Alloc(DataSize);
+ byte *DstData=&FilterDstMemory[0];
+
+ // Bytes from same channels are grouped to continual data blocks,
+ // so we need to place them back to their interleaving positions.
+ for (uint CurChannel=0;CurChannel<Channels;CurChannel++)
+ {
+ byte PrevByte=0;
+ for (uint DestPos=CurChannel;DestPos<DataSize;DestPos+=Channels)
+ DstData[DestPos]=(PrevByte-=Data[SrcPos++]);
+ }
+ return DstData;
+ }
+ case FILTER_RGB:
+ {
+ uint Width=Flt->Width,PosR=Flt->PosR;
+
+ byte *SrcData=Data;
+
+ FilterDstMemory.Alloc(DataSize);
+ byte *DstData=&FilterDstMemory[0];
+
+ const int Channels=3;
+
+ for (uint CurChannel=0;CurChannel<Channels;CurChannel++)
+ {
+ uint PrevByte=0;
+
+ for (uint I=CurChannel;I<DataSize;I+=Channels)
+ {
+ uint Predicted;
+ int UpperPos=I-Width;
+ if (UpperPos>=3)
+ {
+ byte *UpperData=DstData+UpperPos;
+ uint UpperByte=*UpperData;
+ uint UpperLeftByte=*(UpperData-3);
+ Predicted=PrevByte+UpperByte-UpperLeftByte;
+ int pa=abs((int)(Predicted-PrevByte));
+ int pb=abs((int)(Predicted-UpperByte));
+ int pc=abs((int)(Predicted-UpperLeftByte));
+ if (pa<=pb && pa<=pc)
+ Predicted=PrevByte;
+ else
+ if (pb<=pc)
+ Predicted=UpperByte;
+ else
+ Predicted=UpperLeftByte;
+ }
+ else
+ Predicted=PrevByte;
+ DstData[I]=PrevByte=(byte)(Predicted-*(SrcData++));
+ }
+ }
+ for (uint I=PosR,Border=DataSize-2;I<Border;I+=3)
+ {
+ byte G=DstData[I+1];
+ DstData[I]+=G;
+ DstData[I+2]+=G;
+ }
+ return DstData;
+ }
+
+ }
+ return NULL;
+}
+
+
+void Unpack::UnpWriteArea(size_t StartPtr,size_t EndPtr)
+{
+ if (EndPtr!=StartPtr)
+ UnpSomeRead=true;
+ if (EndPtr<StartPtr)
+ {
+ UnpWriteData(&Window[StartPtr],-(int)StartPtr & MaxWinMask);
+ UnpWriteData(Window,EndPtr);
+ UnpAllBuf=true;
+ }
+ else
+ UnpWriteData(&Window[StartPtr],EndPtr-StartPtr);
+}
+
+
+void Unpack::UnpWriteData(byte *Data,size_t Size)
+{
+ if (WrittenFileSize>=DestUnpSize)
+ return;
+ size_t WriteSize=Size;
+ int64 LeftToWrite=DestUnpSize-WrittenFileSize;
+ if ((int64)WriteSize>LeftToWrite)
+ WriteSize=(size_t)LeftToWrite;
+ UnpIO->UnpWrite(Data,WriteSize);
+ WrittenFileSize+=Size;
+}
+
+
+bool Unpack::ReadBlockHeader(BitInput &Inp,UnpackBlockHeader &Header)
+{
+ Header.HeaderSize=0;
+
+ if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-7)
+ if (!UnpReadBuf())
+ return false;
+ Inp.faddbits((8-Inp.InBit)&7);
+
+ byte BlockFlags=Inp.fgetbits()>>8;
+ Inp.faddbits(8);
+ uint ByteCount=((BlockFlags>>3)&3)+1; // Block size byte count.
+
+ if (ByteCount==4)
+ return false;
+
+ Header.HeaderSize=2+ByteCount;
+
+ Header.BlockBitSize=(BlockFlags&7)+1;
+
+ byte SavedCheckSum=Inp.fgetbits()>>8;
+ Inp.faddbits(8);
+
+ int BlockSize=0;
+ for (uint I=0;I<ByteCount;I++)
+ {
+ BlockSize+=(Inp.fgetbits()>>8)<<(I*8);
+ Inp.addbits(8);
+ }
+
+ Header.BlockSize=BlockSize;
+ byte CheckSum=byte(0x5a^BlockFlags^BlockSize^(BlockSize>>8)^(BlockSize>>16));
+ if (CheckSum!=SavedCheckSum)
+ return false;
+
+ Header.BlockStart=Inp.InAddr;
+ ReadBorder=Min(ReadBorder,Header.BlockStart+Header.BlockSize-1);
+
+ Header.LastBlockInFile=(BlockFlags & 0x40)!=0;
+ Header.TablePresent=(BlockFlags & 0x80)!=0;
+ return true;
+}
+
+
+bool Unpack::ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTables &Tables)
+{
+ if (!Header.TablePresent)
+ return true;
+
+ if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-25)
+ if (!UnpReadBuf())
+ return false;
+
+ byte BitLength[BC];
+ for (int I=0;I<BC;I++)
+ {
+ int Length=(byte)(Inp.fgetbits() >> 12);
+ Inp.faddbits(4);
+ if (Length==15)
+ {
+ int ZeroCount=(byte)(Inp.fgetbits() >> 12);
+ Inp.faddbits(4);
+ if (ZeroCount==0)
+ BitLength[I]=15;
+ else
+ {
+ ZeroCount+=2;
+ while (ZeroCount-- > 0 && I<sizeof(BitLength)/sizeof(BitLength[0]))
+ BitLength[I++]=0;
+ I--;
+ }
+ }
+ else
+ BitLength[I]=Length;
+ }
+
+ MakeDecodeTables(BitLength,&Tables.BD,BC);
+
+ byte Table[HUFF_TABLE_SIZE];
+ const int TableSize=HUFF_TABLE_SIZE;
+ for (int I=0;I<TableSize;)
+ {
+ if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-5)
+ if (!UnpReadBuf())
+ return(false);
+ int Number=DecodeNumber(Inp,&Tables.BD);
+ if (Number<16)
+ {
+ Table[I]=Number;
+ I++;
+ }
+ else
+ if (Number<18)
+ {
+ int N;
+ if (Number==16)
+ {
+ N=(Inp.fgetbits() >> 13)+3;
+ Inp.faddbits(3);
+ }
+ else
+ {
+ N=(Inp.fgetbits() >> 9)+11;
+ Inp.faddbits(7);
+ }
+ if (I>0)
+ while (N-- > 0 && I<TableSize)
+ {
+ Table[I]=Table[I-1];
+ I++;
+ }
+ }
+ else
+ {
+ int N;
+ if (Number==18)
+ {
+ N=(Inp.fgetbits() >> 13)+3;
+ Inp.faddbits(3);
+ }
+ else
+ {
+ N=(Inp.fgetbits() >> 9)+11;
+ Inp.faddbits(7);
+ }
+ while (N-- > 0 && I<TableSize)
+ Table[I++]=0;
+ }
+ }
+ if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop)
+ return(false);
+ MakeDecodeTables(&Table[0],&Tables.LD,NC);
+ MakeDecodeTables(&Table[NC],&Tables.DD,DC);
+ MakeDecodeTables(&Table[NC+DC],&Tables.LDD,LDC);
+ MakeDecodeTables(&Table[NC+DC+LDC],&Tables.RD,RC);
+ return(true);
+}
+
+
+void Unpack::InitFilters()
+{
+ Filters.Reset();
+}
diff --git a/src/thirdparty/unrar/unpack50mt.cpp b/src/thirdparty/unrar/unpack50mt.cpp
new file mode 100644
index 000000000..5a0d7d2a1
--- /dev/null
+++ b/src/thirdparty/unrar/unpack50mt.cpp
@@ -0,0 +1,657 @@
+#define UNP_READ_SIZE_MT 0x400000
+#define UNP_BLOCKS_PER_THREAD 2
+
+
+struct UnpackThreadDataList
+{
+ UnpackThreadData *D;
+ uint BlockCount;
+};
+
+
+THREAD_PROC(UnpackDecodeThread)
+{
+ UnpackThreadDataList *DL=(UnpackThreadDataList *)Data;
+ for (uint I=0;I<DL->BlockCount;I++)
+ DL->D->UnpackPtr->UnpackDecode(DL->D[I]);
+}
+
+
+void Unpack::InitMT()
+{
+ if (ReadBufMT==NULL)
+ {
+ // Even getbits32 can read up to 3 additional bytes after current
+ // and our block header and table reading code can look much further.
+ // Let's allocate the additional space here, so we do not need to check
+ // bounds for every bit field access.
+ const size_t Overflow=1024;
+
+ ReadBufMT=new byte[UNP_READ_SIZE_MT+Overflow];
+ memset(ReadBufMT,0,UNP_READ_SIZE_MT+Overflow);
+ }
+ if (UnpThreadData==NULL)
+ {
+ uint MaxItems=MaxUserThreads*UNP_BLOCKS_PER_THREAD;
+ UnpThreadData=new UnpackThreadData[MaxItems];
+ memset(UnpThreadData,0,sizeof(UnpackThreadData)*MaxItems);
+
+ for (uint I=0;I<MaxItems;I++)
+ {
+ UnpackThreadData *CurData=UnpThreadData+I;
+ if (CurData->Decoded==NULL)
+ {
+ // Typical number of items in RAR blocks does not exceed 0x4000.
+ CurData->DecodedAllocated=0x4100;
+ CurData->Decoded=(UnpackDecodedItem *)malloc(CurData->DecodedAllocated*sizeof(UnpackDecodedItem));
+ if (CurData->Decoded==NULL)
+ ErrHandler.MemoryError();
+ }
+ }
+ }
+}
+
+
+void Unpack::Unpack5MT(bool Solid)
+{
+ InitMT();
+ UnpInitData(Solid);
+
+ for (uint I=0;I<MaxUserThreads*UNP_BLOCKS_PER_THREAD;I++)
+ {
+ UnpackThreadData *CurData=UnpThreadData+I;
+ CurData->LargeBlock=false;
+ CurData->Incomplete=false;
+ }
+
+ UnpThreadData[0].BlockHeader=BlockHeader;
+ UnpThreadData[0].BlockTables=BlockTables;
+ uint LastBlockNum=0;
+
+ int DataSize=0;
+ int BlockStart=0;
+
+
+ // 'true' if we found a block too large for multithreaded extraction,
+ // so we switched to single threaded mode until the end of file.
+ // Large blocks could cause too high memory use in multithreaded mode.
+ bool LargeBlock=false;
+
+ bool Done=false;
+ while (!Done)
+ {
+ int ReadSize=UnpIO->UnpRead(ReadBufMT+DataSize,(UNP_READ_SIZE_MT-DataSize)&~0xf);
+ if (ReadSize<0)
+ break;
+ DataSize+=ReadSize;
+ if (DataSize==0)
+ break;
+
+ bool BufferProcessed=false;
+ while (BlockStart<DataSize && !Done)
+ {
+ // Data amount, which is guaranteed to fit block header and tables,
+ // so we can safely read them without additional checks.
+ const int TooSmallToProcess=1024;
+
+ uint BlockNumber=0,BlockNumberMT=0;
+ while (BlockNumber<MaxUserThreads*UNP_BLOCKS_PER_THREAD)
+ {
+ UnpackThreadData *CurData=UnpThreadData+BlockNumber;
+ LastBlockNum=BlockNumber;
+ CurData->UnpackPtr=this;
+
+ // 'Incomplete' thread is present. This is a thread processing block
+ // in the end of buffer, split between two read operations.
+ if (CurData->Incomplete)
+ CurData->DataSize=DataSize;
+ else
+ {
+ CurData->Inp.SetExternalBuffer(ReadBufMT+BlockStart);
+ CurData->Inp.InitBitInput();
+ CurData->DataSize=DataSize-BlockStart;
+ if (CurData->DataSize==0)
+ break;
+ CurData->DamagedData=false;
+ CurData->HeaderRead=false;
+ CurData->TableRead=false;
+ }
+
+ // We should not use 'last block in file' block flag here unless
+ // we'll check the block size, because even if block is last in file,
+ // it can exceed the current buffer and require more reading.
+ CurData->NoDataLeft=(ReadSize==0);
+
+ CurData->Incomplete=false;
+ CurData->ThreadNumber=BlockNumber;
+
+ if (!CurData->HeaderRead)
+ {
+ CurData->HeaderRead=true;
+ if (!ReadBlockHeader(CurData->Inp,CurData->BlockHeader))
+ {
+ Done=true;
+ break;
+ }
+ }
+
+ // To prevent too high memory use we switch to single threaded mode
+ // if block exceeds this size. Typically RAR blocks do not exceed
+ // 64 KB, so this protection should not affect most of valid archives.
+ const int LargeBlockSize=0x20000;
+ if (LargeBlock || CurData->BlockHeader.BlockSize>LargeBlockSize)
+ LargeBlock=CurData->LargeBlock=true;
+ else
+ BlockNumberMT++; // Number of normal blocks processed in MT mode.
+
+ BlockStart+=CurData->BlockHeader.HeaderSize+CurData->BlockHeader.BlockSize;
+
+ BlockNumber++;
+
+ int DataLeft=DataSize-BlockStart;
+ if (DataLeft>=0 && CurData->BlockHeader.LastBlockInFile)
+ break;
+
+ // For second and following threads we move smaller blocks to buffer
+ // start to ensure that we have enough data to fit block header
+ // and tables.
+ if (DataLeft<TooSmallToProcess)
+ break;
+ }
+
+//#undef USE_THREADS
+ UnpackThreadDataList UTDArray[MaxPoolThreads];
+ uint UTDArrayPos=0;
+
+ uint MaxBlockPerThread=BlockNumberMT/MaxUserThreads;
+ if (BlockNumberMT%MaxUserThreads!=0)
+ MaxBlockPerThread++;
+
+ // Decode all normal blocks until the first 'large' if any.
+ for (uint CurBlock=0;CurBlock<BlockNumberMT;CurBlock+=MaxBlockPerThread)
+ {
+ UnpackThreadDataList *UTD=UTDArray+UTDArrayPos++;
+ UTD->D=UnpThreadData+CurBlock;
+ UTD->BlockCount=Min(MaxBlockPerThread,BlockNumberMT-CurBlock);
+
+#ifdef USE_THREADS
+ if (BlockNumber==1)
+ UnpackDecode(*UTD->D);
+ else
+ UnpThreadPool->AddTask(UnpackDecodeThread,(void*)UTD);
+#else
+ for (uint I=0;I<UTD->BlockCount;I++)
+ UnpackDecode(UTD->D[I]);
+#endif
+ }
+
+ if (BlockNumber==0)
+ break;
+
+#ifdef USE_THREADS
+ UnpThreadPool->WaitDone();
+#endif
+
+ bool IncompleteThread=false;
+
+ for (uint Block=0;Block<BlockNumber;Block++)
+ {
+ UnpackThreadData *CurData=UnpThreadData+Block;
+ if (!CurData->LargeBlock && !ProcessDecoded(*CurData) ||
+ CurData->LargeBlock && !UnpackLargeBlock(*CurData) ||
+ CurData->DamagedData)
+ {
+ Done=true;
+ break;
+ }
+ if (CurData->Incomplete)
+ {
+ int BufPos=int(CurData->Inp.InBuf+CurData->Inp.InAddr-ReadBufMT);
+ if (DataSize<=BufPos) // Thread exceeded input buffer boundary.
+ {
+ Done=true;
+ break;
+ }
+ IncompleteThread=true;
+ memmove(ReadBufMT,ReadBufMT+BufPos,DataSize-BufPos);
+ CurData->BlockHeader.BlockSize-=CurData->Inp.InAddr-CurData->BlockHeader.BlockStart;
+ CurData->BlockHeader.HeaderSize=0;
+ CurData->BlockHeader.BlockStart=0;
+ CurData->Inp.InBuf=ReadBufMT;
+ CurData->Inp.InAddr=0;
+
+ if (Block!=0)
+ {
+ // Move the incomplete thread entry to the first position,
+ // so we'll start processing from it. Preserve the original
+ // buffer for decoded data.
+ UnpackDecodedItem *Decoded=UnpThreadData[0].Decoded;
+ uint DecodedAllocated=UnpThreadData[0].DecodedAllocated;
+ UnpThreadData[0]=*CurData;
+ UnpThreadData[0].Decoded=Decoded;
+ UnpThreadData[0].DecodedAllocated=DecodedAllocated;
+ CurData->Incomplete=false;
+ }
+
+ BlockStart=0;
+ DataSize-=BufPos;
+ break;
+ }
+ else
+ if (CurData->BlockHeader.LastBlockInFile)
+ {
+ Done=true;
+ break;
+ }
+ }
+
+ if (IncompleteThread || Done)
+ break; // Current buffer is done, read more data or quit.
+ else
+ {
+ int DataLeft=DataSize-BlockStart;
+ if (DataLeft<TooSmallToProcess)
+ {
+ if (DataLeft<0) // Invalid data, must not happen in valid archive.
+ {
+ Done=true;
+ break;
+ }
+
+ // If we do not have incomplete thread and have some data
+ // in the end of buffer, too small for single thread,
+ // let's move it to beginning of next buffer.
+ if (DataLeft>0)
+ memmove(ReadBufMT,ReadBufMT+BlockStart,DataLeft);
+ DataSize=DataLeft;
+ BlockStart=0;
+ break; // Current buffer is done, try to read more data.
+ }
+ }
+ }
+ }
+ UnpWriteBuf();
+
+ BlockHeader=UnpThreadData[LastBlockNum].BlockHeader;
+ BlockTables=UnpThreadData[LastBlockNum].BlockTables;
+}
+
+
+// Decode Huffman block and save decoded data to memory.
+void Unpack::UnpackDecode(UnpackThreadData &D)
+{
+ if (!D.TableRead)
+ {
+ D.TableRead=true;
+ if (!ReadTables(D.Inp,D.BlockHeader,D.BlockTables))
+ {
+ D.DamagedData=true;
+ return;
+ }
+ }
+
+ if (D.Inp.InAddr>D.BlockHeader.HeaderSize+D.BlockHeader.BlockSize)
+ {
+ D.DamagedData=true;
+ return;
+ }
+
+ D.DecodedSize=0;
+ int BlockBorder=D.BlockHeader.BlockStart+D.BlockHeader.BlockSize-1;
+
+ // Reserve enough space even for filter entry.
+ int DataBorder=D.DataSize-16;
+ int ReadBorder=Min(BlockBorder,DataBorder);
+
+ while (true)
+ {
+ if (D.Inp.InAddr>=ReadBorder)
+ {
+ if (D.Inp.InAddr>BlockBorder || D.Inp.InAddr==BlockBorder &&
+ D.Inp.InBit>=D.BlockHeader.BlockBitSize)
+ break;
+
+ // If we do not have any more data in file to read, we must process
+ // what we have until last byte. Otherwise we can return and append
+ // more data to unprocessed few bytes.
+ if ((D.Inp.InAddr>=DataBorder) && !D.NoDataLeft || D.Inp.InAddr>=D.DataSize)
+ {
+ D.Incomplete=true;
+ break;
+ }
+ }
+ 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();
+ }
+
+ UnpackDecodedItem *CurItem=D.Decoded+D.DecodedSize++;
+
+ uint MainSlot=DecodeNumber(D.Inp,&D.BlockTables.LD);
+ if (MainSlot<256)
+ {
+ if (D.DecodedSize>1)
+ {
+ UnpackDecodedItem *PrevItem=CurItem-1;
+ if (PrevItem->Type==UNPDT_LITERAL && PrevItem->Length<3)
+ {
+ PrevItem->Length++;
+ PrevItem->Literal[PrevItem->Length]=(byte)MainSlot;
+ D.DecodedSize--;
+ continue;
+ }
+ }
+ CurItem->Type=UNPDT_LITERAL;
+ CurItem->Literal[0]=(byte)MainSlot;
+ CurItem->Length=0;
+ continue;
+ }
+ if (MainSlot>=262)
+ {
+ uint Length=SlotToLength(D.Inp,MainSlot-262);
+
+ uint DBits,Distance=1,DistSlot=DecodeNumber(D.Inp,&D.BlockTables.DD);
+ if (DistSlot<4)
+ {
+ DBits=0;
+ Distance+=DistSlot;
+ }
+ else
+ {
+ DBits=DistSlot/2 - 1;
+ Distance+=(2 | (DistSlot & 1)) << DBits;
+ }
+
+ if (DBits>0)
+ {
+ if (DBits>=4)
+ {
+ if (DBits>4)
+ {
+ Distance+=((D.Inp.getbits32()>>(36-DBits))<<4);
+ D.Inp.addbits(DBits-4);
+ }
+ uint LowDist=DecodeNumber(D.Inp,&D.BlockTables.LDD);
+ Distance+=LowDist;
+ }
+ else
+ {
+ Distance+=D.Inp.getbits32()>>(32-DBits);
+ D.Inp.addbits(DBits);
+ }
+ }
+
+ if (Distance>0x100)
+ {
+ Length++;
+ if (Distance>0x2000)
+ {
+ Length++;
+ if (Distance>0x40000)
+ Length++;
+ }
+ }
+
+ CurItem->Type=UNPDT_MATCH;
+ CurItem->Length=(ushort)Length;
+ CurItem->Distance=Distance;
+ continue;
+ }
+ if (MainSlot==256)
+ {
+ UnpackFilter Filter;
+ ReadFilter(D.Inp,Filter);
+
+ CurItem->Type=UNPDT_FILTER;
+ CurItem->Length=Filter.Type;
+ CurItem->Distance=Filter.BlockStart;
+
+ CurItem=D.Decoded+D.DecodedSize++;
+
+ CurItem->Type=UNPDT_FILTER;
+ CurItem->Length=Filter.Channels;
+ CurItem->Distance=Filter.BlockLength;
+
+ CurItem=D.Decoded+D.DecodedSize++;
+
+ CurItem->Type=UNPDT_FILTER;
+ CurItem->Length=Filter.PosR;
+ CurItem->Distance=Filter.Width;
+
+ continue;
+ }
+ if (MainSlot==257)
+ {
+ CurItem->Type=UNPDT_FULLREP;
+ continue;
+ }
+ if (MainSlot<262)
+ {
+ CurItem->Type=UNPDT_REP;
+ CurItem->Distance=MainSlot-258;
+ uint LengthSlot=DecodeNumber(D.Inp,&D.BlockTables.RD);
+ uint Length=SlotToLength(D.Inp,LengthSlot);
+ CurItem->Length=(ushort)Length;
+ continue;
+ }
+ }
+}
+
+
+// Process decoded Huffman block data.
+bool Unpack::ProcessDecoded(UnpackThreadData &D)
+{
+ UnpackDecodedItem *Item=D.Decoded,*Border=D.Decoded+D.DecodedSize;
+ while (Item<Border)
+ {
+ UnpPtr&=MaxWinMask;
+ if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_LZ_MATCH+3 && WriteBorder!=UnpPtr)
+ {
+ UnpWriteBuf();
+ if (WrittenFileSize>DestUnpSize)
+ return false;
+ }
+
+ if (Item->Type==UNPDT_LITERAL)
+ {
+#if defined(LITTLE_ENDIAN) && defined(PRESENT_INT32) && defined(ALLOW_NOT_ALIGNED_INT)
+ if (Item->Length==3 && UnpPtr<MaxWinSize-4)
+ {
+ *(uint32 *)(Window+UnpPtr)=*(uint32 *)Item->Literal;
+ UnpPtr+=4;
+ }
+ else
+#endif
+ for (uint I=0;I<=Item->Length;I++)
+ Window[UnpPtr++ & MaxWinMask]=Item->Literal[I];
+ }
+ else
+ if (Item->Type==UNPDT_MATCH)
+ {
+ InsertOldDist(Item->Distance);
+ LastLength=Item->Length;
+ CopyString(Item->Length,Item->Distance);
+ }
+ else
+ if (Item->Type==UNPDT_REP)
+ {
+ uint Distance=OldDist[Item->Distance];
+ for (uint I=Item->Distance;I>0;I--)
+ OldDist[I]=OldDist[I-1];
+ OldDist[0]=Distance;
+ LastLength=Item->Length;
+ CopyString(Item->Length,Distance);
+ }
+ else
+ if (Item->Type==UNPDT_FULLREP)
+ {
+ if (LastLength!=0)
+ CopyString(LastLength,OldDist[0]);
+ }
+ else
+ if (Item->Type==UNPDT_FILTER)
+ {
+ UnpackFilter Filter;
+
+ Filter.Type=(byte)Item->Length;
+ Filter.BlockStart=Item->Distance;
+
+ Item++;
+
+ Filter.Channels=(byte)Item->Length;
+ Filter.BlockLength=Item->Distance;
+
+ Item++;
+
+ Filter.PosR=(byte)Item->Length;
+ Filter.Width=Item->Distance;
+
+ AddFilter(Filter);
+ }
+ Item++;
+ }
+ return true;
+}
+
+
+// For large blocks we decode and process in same function in single threaded
+// mode, so we do not need to store intermediate data in memory.
+bool Unpack::UnpackLargeBlock(UnpackThreadData &D)
+{
+ if (!D.TableRead)
+ {
+ D.TableRead=true;
+ if (!ReadTables(D.Inp,D.BlockHeader,D.BlockTables))
+ {
+ D.DamagedData=true;
+ return false;
+ }
+ }
+
+ if (D.Inp.InAddr>D.BlockHeader.HeaderSize+D.BlockHeader.BlockSize)
+ {
+ D.DamagedData=true;
+ return false;
+ }
+
+ int BlockBorder=D.BlockHeader.BlockStart+D.BlockHeader.BlockSize-1;
+
+ // Reserve enough space even for filter entry.
+ int DataBorder=D.DataSize-16;
+ int ReadBorder=Min(BlockBorder,DataBorder);
+
+ while (true)
+ {
+ UnpPtr&=MaxWinMask;
+ if (D.Inp.InAddr>=ReadBorder)
+ {
+ if (D.Inp.InAddr>BlockBorder || D.Inp.InAddr==BlockBorder &&
+ D.Inp.InBit>=D.BlockHeader.BlockBitSize)
+ break;
+
+ // If we do not have any more data in file to read, we must process
+ // what we have until last byte. Otherwise we can return and append
+ // more data to unprocessed few bytes.
+ if ((D.Inp.InAddr>=DataBorder) && !D.NoDataLeft || D.Inp.InAddr>=D.DataSize)
+ {
+ D.Incomplete=true;
+ break;
+ }
+ }
+ if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_LZ_MATCH+3 && WriteBorder!=UnpPtr)
+ {
+ UnpWriteBuf();
+ if (WrittenFileSize>DestUnpSize)
+ return false;
+ }
+
+ uint MainSlot=DecodeNumber(D.Inp,&D.BlockTables.LD);
+ if (MainSlot<256)
+ {
+ Window[UnpPtr++]=(byte)MainSlot;
+ continue;
+ }
+ if (MainSlot>=262)
+ {
+ uint Length=SlotToLength(D.Inp,MainSlot-262);
+
+ uint DBits,Distance=1,DistSlot=DecodeNumber(D.Inp,&D.BlockTables.DD);
+ if (DistSlot<4)
+ {
+ DBits=0;
+ Distance+=DistSlot;
+ }
+ else
+ {
+ DBits=DistSlot/2 - 1;
+ Distance+=(2 | (DistSlot & 1)) << DBits;
+ }
+
+ if (DBits>0)
+ {
+ if (DBits>=4)
+ {
+ if (DBits>4)
+ {
+ Distance+=((D.Inp.getbits32()>>(36-DBits))<<4);
+ D.Inp.addbits(DBits-4);
+ }
+ uint LowDist=DecodeNumber(D.Inp,&D.BlockTables.LDD);
+ Distance+=LowDist;
+ }
+ else
+ {
+ Distance+=D.Inp.getbits32()>>(32-DBits);
+ D.Inp.addbits(DBits);
+ }
+ }
+
+ if (Distance>0x100)
+ {
+ Length++;
+ if (Distance>0x2000)
+ {
+ Length++;
+ if (Distance>0x40000)
+ Length++;
+ }
+ }
+
+ InsertOldDist(Distance);
+ LastLength=Length;
+ CopyString(Length,Distance);
+ continue;
+ }
+ if (MainSlot==256)
+ {
+ UnpackFilter Filter;
+ if (!ReadFilter(D.Inp,Filter) || !AddFilter(Filter))
+ break;
+ continue;
+ }
+ if (MainSlot==257)
+ {
+ if (LastLength!=0)
+ CopyString(LastLength,OldDist[0]);
+ continue;
+ }
+ if (MainSlot<262)
+ {
+ uint DistNum=MainSlot-258;
+ uint Distance=OldDist[DistNum];
+ for (uint I=DistNum;I>0;I--)
+ OldDist[I]=OldDist[I-1];
+ OldDist[0]=Distance;
+
+ uint LengthSlot=DecodeNumber(D.Inp,&D.BlockTables.RD);
+ uint Length=SlotToLength(D.Inp,LengthSlot);
+ LastLength=Length;
+ CopyString(Length,Distance);
+ continue;
+ }
+ }
+ return true;
+}
diff --git a/src/thirdparty/unrar/unpackinline.cpp b/src/thirdparty/unrar/unpackinline.cpp
new file mode 100644
index 000000000..807c24ded
--- /dev/null
+++ b/src/thirdparty/unrar/unpackinline.cpp
@@ -0,0 +1,140 @@
+_forceinline void Unpack::InsertOldDist(uint Distance)
+{
+ OldDist[3]=OldDist[2];
+ OldDist[2]=OldDist[1];
+ OldDist[1]=OldDist[0];
+ OldDist[0]=Distance;
+}
+
+#ifdef _MSC_VER
+#define FAST_MEMCPY
+#endif
+
+_forceinline void Unpack::CopyString(uint Length,uint Distance)
+{
+ size_t SrcPtr=UnpPtr-Distance;
+ if (SrcPtr<MaxWinSize-MAX_LZ_MATCH && UnpPtr<MaxWinSize-MAX_LZ_MATCH)
+ {
+ // If we are not close to end of window, we do not need to waste time
+ // to "& MaxWinMask" pointer protection.
+
+ byte *Src=Window+SrcPtr;
+ byte *Dest=Window+UnpPtr;
+ UnpPtr+=Length;
+
+#ifdef FAST_MEMCPY
+ if (Distance<Length) // Overlapping strings
+#endif
+ while (Length>=8)
+ {
+ Dest[0]=Src[0];
+ Dest[1]=Src[1];
+ Dest[2]=Src[2];
+ Dest[3]=Src[3];
+ Dest[4]=Src[4];
+ Dest[5]=Src[5];
+ Dest[6]=Src[6];
+ Dest[7]=Src[7];
+
+ Src+=8;
+ Dest+=8;
+ Length-=8;
+ }
+#ifdef FAST_MEMCPY
+ else
+ while (Length>=8)
+ {
+ // This memcpy expanded inline by MSVC. We could also use uint64
+ // assignment, which seems to provide about the same speed.
+ memcpy(Dest,Src,8);
+
+ Src+=8;
+ Dest+=8;
+ Length-=8;
+ }
+#endif
+
+ // Unroll the loop for 0 - 7 bytes left. Note that we use nested "if"s.
+ if (Length>0) { Dest[0]=Src[0];
+ if (Length>1) { Dest[1]=Src[1];
+ if (Length>2) { Dest[2]=Src[2];
+ if (Length>3) { Dest[3]=Src[3];
+ if (Length>4) { Dest[4]=Src[4];
+ if (Length>5) { Dest[5]=Src[5];
+ if (Length>6) { Dest[6]=Src[6]; } } } } } } } // Close all nested "if"s.
+ }
+ else
+ while (Length--) // Slow copying with all possible precautions.
+ {
+ Window[UnpPtr]=Window[SrcPtr++ & MaxWinMask];
+ UnpPtr=(UnpPtr+1) & MaxWinMask;
+ }
+}
+
+
+_forceinline uint Unpack::DecodeNumber(BitInput &Inp,DecodeTable *Dec)
+{
+ // Left aligned 15 bit length raw bit field.
+ uint BitField=Inp.getbits() & 0xfffe;
+
+ if (BitField<Dec->DecodeLen[Dec->QuickBits])
+ {
+ uint Code=BitField>>(16-Dec->QuickBits);
+ Inp.addbits(Dec->QuickLen[Code]);
+ return Dec->QuickNum[Code];
+ }
+
+ // Detect the real bit length for current code.
+ uint Bits=15;
+ for (uint I=Dec->QuickBits+1;I<15;I++)
+ if (BitField<Dec->DecodeLen[I])
+ {
+ Bits=I;
+ break;
+ }
+
+ Inp.addbits(Bits);
+
+ // Calculate the distance from the start code for current bit length.
+ uint Dist=BitField-Dec->DecodeLen[Bits-1];
+
+ // Start codes are left aligned, but we need the normal right aligned
+ // number. So we shift the distance to the right.
+ Dist>>=(16-Bits);
+
+ // Now we can calculate the position in the code list. It is the sum
+ // of first position for current bit length and right aligned distance
+ // between our bit field and start code for current bit length.
+ uint Pos=Dec->DecodePos[Bits]+Dist;
+
+ // Out of bounds safety check required for damaged archives.
+ if (Pos>=Dec->MaxNum)
+ Pos=0;
+
+ // Convert the position in the code list to position in alphabet
+ // and return it.
+ return(Dec->DecodeNum[Pos]);
+}
+
+
+_forceinline uint Unpack::SlotToLength(BitInput &Inp,uint Slot)
+{
+ uint LBits,Length=2;
+ if (Slot<8)
+ {
+ LBits=0;
+ Length+=Slot;
+ }
+ else
+ {
+ LBits=Slot/4-1;
+ Length+=(4 | (Slot & 3)) << LBits;
+ }
+
+ if (LBits>0)
+ {
+ Length+=Inp.getbits()>>(16-LBits);
+ Inp.addbits(LBits);
+ }
+ return Length;
+}
diff --git a/src/thirdparty/unrar/unrar.vcxproj b/src/thirdparty/unrar/unrar.vcxproj
index 405c899a0..1927883d1 100644
--- a/src/thirdparty/unrar/unrar.vcxproj
+++ b/src/thirdparty/unrar/unrar.vcxproj
@@ -97,6 +97,7 @@
<ItemGroup>
<ClCompile Include="archive.cpp" />
<ClCompile Include="arcread.cpp" />
+ <ClCompile Include="blake2s.cpp" />
<ClCompile Include="cmddata.cpp" />
<ClCompile Include="consio.cpp" />
<ClCompile Include="crc.cpp" />
@@ -115,11 +116,13 @@
<ClCompile Include="global.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
+ <ClCompile Include="hash.cpp" />
+ <ClCompile Include="headers.cpp" />
<ClCompile Include="isnt.cpp" />
- <ClCompile Include="list.cpp" />
<ClCompile Include="match.cpp" />
<ClCompile Include="options.cpp" />
<ClCompile Include="pathfn.cpp" />
+ <ClCompile Include="qopen.cpp" />
<ClCompile Include="rar.cpp" />
<ClCompile Include="rarpch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
@@ -128,19 +131,19 @@
<ClCompile Include="rawread.cpp" />
<ClCompile Include="rdwrfn.cpp" />
<ClCompile Include="recvol.cpp" />
- <ClCompile Include="resource.cpp" />
<ClCompile Include="rijndael.cpp" />
<ClCompile Include="rs.cpp" />
- <ClCompile Include="savepos.cpp" />
+ <ClCompile Include="rs16.cpp" />
<ClCompile Include="scantree.cpp" />
<ClCompile Include="secpassword.cpp" />
<ClCompile Include="sha1.cpp" />
+ <ClCompile Include="sha256.cpp" />
<ClCompile Include="smallfn.cpp" />
<ClCompile Include="strfn.cpp" />
<ClCompile Include="strlist.cpp" />
<ClCompile Include="system.cpp" />
+ <ClCompile Include="threadpool.cpp" />
<ClCompile Include="timefn.cpp" />
- <ClCompile Include="ulinks.cpp" />
<ClCompile Include="unicode.cpp" />
<ClCompile Include="unpack.cpp" />
<ClCompile Include="volume.cpp" />
@@ -148,6 +151,7 @@
<ItemGroup>
<ClInclude Include="archive.hpp" />
<ClInclude Include="array.hpp" />
+ <ClInclude Include="blake2s.hpp" />
<ClInclude Include="cmddata.hpp" />
<ClInclude Include="coder.hpp" />
<ClInclude Include="compress.hpp" />
@@ -166,7 +170,9 @@
<ClInclude Include="find.hpp" />
<ClInclude Include="getbits.hpp" />
<ClInclude Include="global.hpp" />
+ <ClInclude Include="hash.hpp" />
<ClInclude Include="headers.hpp" />
+ <ClInclude Include="headers5.hpp" />
<ClInclude Include="isnt.hpp" />
<ClInclude Include="list.hpp" />
<ClInclude Include="loclang.hpp" />
@@ -176,6 +182,7 @@
<ClInclude Include="options.hpp" />
<ClInclude Include="os.hpp" />
<ClInclude Include="pathfn.hpp" />
+ <ClInclude Include="qopen.hpp" />
<ClInclude Include="rar.hpp" />
<ClInclude Include="rardefs.hpp" />
<ClInclude Include="rarlang.hpp" />
@@ -188,15 +195,18 @@
<ClInclude Include="resource.hpp" />
<ClInclude Include="rijndael.hpp" />
<ClInclude Include="rs.hpp" />
+ <ClInclude Include="rs16.hpp" />
<ClInclude Include="savepos.hpp" />
<ClInclude Include="scantree.hpp" />
<ClInclude Include="secpassword.hpp" />
<ClInclude Include="sha1.hpp" />
+ <ClInclude Include="sha256.hpp" />
<ClInclude Include="smallfn.hpp" />
<ClInclude Include="strfn.hpp" />
<ClInclude Include="strlist.hpp" />
<ClInclude Include="suballoc.hpp" />
<ClInclude Include="system.hpp" />
+ <ClInclude Include="threadpool.hpp" />
<ClInclude Include="timefn.hpp" />
<ClInclude Include="ulinks.hpp" />
<ClInclude Include="unicode.hpp" />
diff --git a/src/thirdparty/unrar/unrar.vcxproj.filters b/src/thirdparty/unrar/unrar.vcxproj.filters
index 68850095e..c3e2710d8 100644
--- a/src/thirdparty/unrar/unrar.vcxproj.filters
+++ b/src/thirdparty/unrar/unrar.vcxproj.filters
@@ -17,12 +17,24 @@
<ClCompile Include="arcread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="blake2s.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="cmddata.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="consio.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="crc.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="crypt.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dll.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="encname.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -53,6 +65,15 @@
<ClCompile Include="getbits.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="global.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="hash.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="headers.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="isnt.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -65,6 +86,9 @@
<ClCompile Include="pathfn.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="qopen.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="rar.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@@ -83,80 +107,65 @@
<ClCompile Include="recvol.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="rs.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="savepos.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="scantree.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="strfn.cpp">
+ <ClCompile Include="rijndael.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="strlist.cpp">
+ <ClCompile Include="rs.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="system.cpp">
+ <ClCompile Include="rs16.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="timefn.cpp">
+ <ClCompile Include="scantree.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="unicode.cpp">
+ <ClCompile Include="secpassword.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="unpack.cpp">
+ <ClCompile Include="sha1.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="volume.cpp">
+ <ClCompile Include="sha256.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="smallfn.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="consio.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="ulinks.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="global.cpp">
+ <ClCompile Include="strfn.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="secpassword.cpp">
+ <ClCompile Include="strlist.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="crypt.cpp">
+ <ClCompile Include="system.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="list.cpp">
+ <ClCompile Include="threadpool.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="resource.cpp">
+ <ClCompile Include="timefn.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="rijndael.cpp">
+ <ClCompile Include="unicode.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="sha1.cpp">
+ <ClCompile Include="unpack.cpp">
<Filter>Source Files</Filter>
</ClCompile>
- <ClCompile Include="dll.cpp">
+ <ClCompile Include="volume.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
- <ClInclude Include="rar.hpp">
- <Filter>Header Files</Filter>
- </ClInclude>
<ClInclude Include="archive.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="array.hpp">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="blake2s.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="cmddata.hpp">
<Filter>Header Files</Filter>
</ClInclude>
@@ -211,9 +220,15 @@
<ClInclude Include="global.hpp">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="hash.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="headers.hpp">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="headers5.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="isnt.hpp">
<Filter>Header Files</Filter>
</ClInclude>
@@ -241,6 +256,12 @@
<ClInclude Include="pathfn.hpp">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="qopen.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="rar.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="rardefs.hpp">
<Filter>Header Files</Filter>
</ClInclude>
@@ -274,6 +295,9 @@
<ClInclude Include="rs.hpp">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="rs16.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="savepos.hpp">
<Filter>Header Files</Filter>
</ClInclude>
@@ -286,6 +310,9 @@
<ClInclude Include="sha1.hpp">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="sha256.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="smallfn.hpp">
<Filter>Header Files</Filter>
</ClInclude>
@@ -301,6 +328,9 @@
<ClInclude Include="system.hpp">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="threadpool.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="timefn.hpp">
<Filter>Header Files</Filter>
</ClInclude>
diff --git a/src/thirdparty/unrar/uowners.cpp b/src/thirdparty/unrar/uowners.cpp
index 913aaef3b..979b60b44 100644
--- a/src/thirdparty/unrar/uowners.cpp
+++ b/src/thirdparty/unrar/uowners.cpp
@@ -1,8 +1,11 @@
-void ExtractUnixOwner(Archive &Arc,char *FileName)
+void ExtractUnixOwner20(Archive &Arc,const wchar *FileName)
{
- if (Arc.HeaderCRC!=Arc.UOHead.HeadCRC)
+ char NameA[NM];
+ WideToChar(FileName,NameA,ASIZE(NameA));
+
+ if (Arc.BrokenHeader)
{
Log(Arc.FileName,St(MOwnersBroken),FileName);
ErrHandler.SetErrorCode(RARX_CRC);
@@ -13,7 +16,7 @@ void ExtractUnixOwner(Archive &Arc,char *FileName)
errno=0; // Required by getpwnam specification if we need to check errno.
if ((pw=getpwnam(Arc.UOHead.OwnerName))==NULL)
{
- Log(Arc.FileName,St(MErrGetOwnerID),Arc.UOHead.OwnerName);
+ Log(Arc.FileName,St(MErrGetOwnerID),GetWide(Arc.UOHead.OwnerName));
ErrHandler.SysErrMsg();
ErrHandler.SetErrorCode(RARX_WARNING);
return;
@@ -24,28 +27,31 @@ void ExtractUnixOwner(Archive &Arc,char *FileName)
errno=0; // Required by getgrnam specification if we need to check errno.
if ((gr=getgrnam(Arc.UOHead.GroupName))==NULL)
{
- Log(Arc.FileName,St(MErrGetGroupID),Arc.UOHead.GroupName);
+ Log(Arc.FileName,St(MErrGetGroupID),GetWide(Arc.UOHead.GroupName));
ErrHandler.SysErrMsg();
ErrHandler.SetErrorCode(RARX_CRC);
return;
}
- uint Attr=GetFileAttr(FileName,NULL);
+ uint Attr=GetFileAttr(FileName);
gid_t GroupID=gr->gr_gid;
#if defined(SAVE_LINKS) && !defined(_APPLE)
- if (lchown(FileName,OwnerID,GroupID)!=0)
+ if (lchown(NameA,OwnerID,GroupID)!=0)
#else
- if (chown(FileName,OwnerID,GroupID)!=0)
+ if (chown(NameA,OwnerID,GroupID)!=0)
#endif
{
Log(Arc.FileName,St(MSetOwnersError),FileName);
ErrHandler.SetErrorCode(RARX_CREATE);
}
- SetFileAttr(FileName,NULL,Attr);
+ SetFileAttr(FileName,Attr);
}
-void ExtractUnixOwnerNew(Archive &Arc,char *FileName)
+void ExtractUnixOwner30(Archive &Arc,const wchar *FileName)
{
+ char NameA[NM];
+ WideToChar(FileName,NameA,ASIZE(NameA));
+
char *OwnerName=(char *)&Arc.SubHead.SubData[0];
int OwnerSize=strlen(OwnerName)+1;
int GroupSize=Arc.SubHead.SubData.Size()-OwnerSize;
@@ -56,7 +62,7 @@ void ExtractUnixOwnerNew(Archive &Arc,char *FileName)
struct passwd *pw;
if ((pw=getpwnam(OwnerName))==NULL)
{
- Log(Arc.FileName,St(MErrGetOwnerID),OwnerName);
+ Log(Arc.FileName,St(MErrGetOwnerID),GetWide(OwnerName));
ErrHandler.SetErrorCode(RARX_WARNING);
return;
}
@@ -65,20 +71,71 @@ void ExtractUnixOwnerNew(Archive &Arc,char *FileName)
struct group *gr;
if ((gr=getgrnam(GroupName))==NULL)
{
- Log(Arc.FileName,St(MErrGetGroupID),GroupName);
- ErrHandler.SetErrorCode(RARX_CRC);
+ Log(Arc.FileName,St(MErrGetGroupID),GetWide(GroupName));
+ ErrHandler.SetErrorCode(RARX_WARNING);
return;
}
- uint Attr=GetFileAttr(FileName,NULL);
+ uint Attr=GetFileAttr(FileName);
gid_t GroupID=gr->gr_gid;
#if defined(SAVE_LINKS) && !defined(_APPLE)
- if (lchown(FileName,OwnerID,GroupID)!=0)
+ if (lchown(NameA,OwnerID,GroupID)!=0)
+#else
+ if (chown(NameA,OwnerID,GroupID)!=0)
+#endif
+ {
+ Log(Arc.FileName,St(MSetOwnersError),FileName);
+ ErrHandler.SetErrorCode(RARX_CREATE);
+ }
+ SetFileAttr(FileName,Attr);
+}
+
+
+void SetUnixOwner(Archive &Arc,const wchar *FileName)
+{
+ char NameA[NM];
+ WideToChar(FileName,NameA,ASIZE(NameA));
+
+ // First, we try to resolve symbolic names. If they are missing or cannot
+ // be resolved, we try to use numeric values if any. If numeric values
+ // are missing too, function fails.
+ FileHeader &hd=Arc.FileHead;
+ if (*hd.UnixOwnerName!=0)
+ {
+ struct passwd *pw;
+ if ((pw=getpwnam(hd.UnixOwnerName))==NULL)
+ {
+ if (!hd.UnixOwnerNumeric)
+ {
+ Log(Arc.FileName,St(MErrGetOwnerID),GetWide(hd.UnixOwnerName));
+ ErrHandler.SetErrorCode(RARX_WARNING);
+ return;
+ }
+ }
+ else
+ hd.UnixOwnerID=pw->pw_uid;
+ }
+ if (*hd.UnixGroupName!=0)
+ {
+ struct group *gr;
+ if ((gr=getgrnam(hd.UnixGroupName))==NULL)
+ {
+ if (!hd.UnixGroupNumeric)
+ {
+ Log(Arc.FileName,St(MErrGetGroupID),GetWide(hd.UnixGroupName));
+ ErrHandler.SetErrorCode(RARX_WARNING);
+ return;
+ }
+ }
+ else
+ hd.UnixGroupID=gr->gr_gid;
+ }
+#if defined(SAVE_LINKS) && !defined(_APPLE)
+ if (lchown(NameA,hd.UnixOwnerID,hd.UnixGroupID)!=0)
#else
- if (chown(FileName,OwnerID,GroupID)!=0)
+ if (chown(NameA,hd.UnixOwnerID,hd.UnixGroupID)!=0)
#endif
{
Log(Arc.FileName,St(MSetOwnersError),FileName);
ErrHandler.SetErrorCode(RARX_CREATE);
}
- SetFileAttr(FileName,NULL,Attr);
}
diff --git a/src/thirdparty/unrar/version.hpp b/src/thirdparty/unrar/version.hpp
index 3031b3a5d..4687491c1 100644
--- a/src/thirdparty/unrar/version.hpp
+++ b/src/thirdparty/unrar/version.hpp
@@ -1,6 +1,6 @@
-#define RARVER_MAJOR 4
-#define RARVER_MINOR 20
-#define RARVER_BETA 0
-#define RARVER_DAY 9
-#define RARVER_MONTH 6
-#define RARVER_YEAR 2012
+#define RARVER_MAJOR 5
+#define RARVER_MINOR 0
+#define RARVER_BETA 2
+#define RARVER_DAY 30
+#define RARVER_MONTH 4
+#define RARVER_YEAR 2013
diff --git a/src/thirdparty/unrar/volume.cpp b/src/thirdparty/unrar/volume.cpp
index 073edb8ae..dd3811231 100644
--- a/src/thirdparty/unrar/volume.cpp
+++ b/src/thirdparty/unrar/volume.cpp
@@ -1,28 +1,30 @@
#include "rar.hpp"
+#ifdef RARDLL
+static bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize);
+static bool DllVolNotify(RAROptions *Cmd,wchar *NextName);
+#endif
-#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
-// Disable the run time stack check for unrar.dll, so we can manipulate
-// with ChangeVolProc call type below. Run time check would intercept
-// a wrong ESP before we restore it.
-#pragma runtime_checks( "s", off )
-#endif
-
-bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,char Command)
+bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Command)
{
RAROptions *Cmd=Arc.GetRAROptions();
- int HeaderType=Arc.GetHeaderType();
- FileHeader *hd=HeaderType==NEWSUB_HEAD ? &Arc.SubHead:&Arc.NewLhd;
- bool SplitHeader=(HeaderType==FILE_HEAD || HeaderType==NEWSUB_HEAD) &&
- (hd->Flags & LHD_SPLIT_AFTER)!=0;
+ HEADER_TYPE HeaderType=Arc.GetHeaderType();
+ FileHeader *hd=HeaderType==HEAD_SERVICE ? &Arc.SubHead:&Arc.FileHead;
+ bool SplitHeader=(HeaderType==HEAD_FILE || HeaderType==HEAD_SERVICE) &&
+ hd->SplitAfter;
- if (DataIO!=NULL && SplitHeader && hd->UnpVer>=20 &&
- hd->FileCRC!=0xffffffff && DataIO->PackedCRC!=~hd->FileCRC)
+ if (DataIO!=NULL && SplitHeader)
{
- Log(Arc.FileName,St(MDataBadCRC),hd->FileName,Arc.FileName);
+ bool PackedHashPresent=Arc.Format==RARFMT50 ||
+ hd->UnpVer>=20 && hd->FileHash.CRC32!=0xffffffff;
+ if (PackedHashPresent &&
+ !DataIO->PackedDataHash.Cmp(&hd->FileHash,hd->UseHashKey ? hd->HashKey:NULL))
+ {
+ Log(Arc.FileName,St(MDataBadCRC),hd->FileName,Arc.FileName);
+ }
}
int64 PosBeforeClose=Arc.Tell();
@@ -32,11 +34,9 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,char Comman
Arc.Close();
- char NextName[NM];
- wchar NextNameW[NM];
- strcpy(NextName,Arc.FileName);
- wcscpy(NextNameW,Arc.FileNameW);
- NextVolumeName(NextName,NextNameW,ASIZE(NextName),(Arc.NewMhd.Flags & MHD_NEWNUMBERING)==0 || Arc.OldFormat);
+ wchar NextName[NM];
+ wcscpy(NextName,Arc.FileName);
+ NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering);
#if !defined(SFX_MODULE) && !defined(RARDLL)
bool RecoveryDone=false;
@@ -47,12 +47,12 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,char Comman
// In -vp mode we force the pause before next volume even if it is present
// and even if we are on the hard disk. It is important when user does not
// want to process partially downloaded volumes preliminary.
- if (Cmd->VolumePause && !AskNextVol(NextName,NextNameW))
+ if (Cmd->VolumePause && !AskNextVol(NextName))
FailedOpen=true;
#endif
if (!FailedOpen)
- while (!Arc.Open(NextName,NextNameW,0))
+ while (!Arc.Open(NextName,0))
{
// We need to open a new volume which size was not calculated
// in total size before, so we cannot calculate the total progress
@@ -65,86 +65,28 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,char Comman
{
// Checking for new style volumes renamed by user to old style
// name format. Some users did it for unknown reason.
- char AltNextName[NM];
- wchar AltNextNameW[NM];
- strcpy(AltNextName,Arc.FileName);
- wcscpy(AltNextNameW,Arc.FileNameW);
- NextVolumeName(AltNextName,AltNextNameW,ASIZE(AltNextName),true);
+ wchar AltNextName[NM];
+ wcscpy(AltNextName,Arc.FileName);
+ NextVolumeName(AltNextName,ASIZE(AltNextName),true);
OldSchemeTested=true;
- if (Arc.Open(AltNextName,AltNextNameW,0))
+ if (Arc.Open(AltNextName,0))
{
- strcpy(NextName,AltNextName);
- wcscpy(NextNameW,AltNextNameW);
+ wcscpy(NextName,AltNextName);
break;
}
}
#ifdef RARDLL
- bool DllVolChanged=false;
-
- if (Cmd->Callback!=NULL)
- {
- GetWideName(NextName,NextNameW,NextNameW,ASIZE(NextNameW));
- char CurName[ASIZE(NextName)];
- strcpy(CurName,NextName);
- wchar CurNameW[ASIZE(NextNameW)];
- wcscpy(CurNameW,NextNameW);
- if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextNameW,RAR_VOL_ASK)!=-1 &&
- wcscmp(CurNameW,NextNameW)!=0)
- {
- *NextName=0;
- DllVolChanged=true;
- }
- else
- if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextName,RAR_VOL_ASK)!=-1 &&
- strcmp(CurName,NextName)!=0)
- {
- *NextNameW=0;
- DllVolChanged=true;
- }
- }
- if (!DllVolChanged && Cmd->ChangeVolProc!=NULL)
+ if (!DllVolChange(Cmd,NextName,ASIZE(NextName)))
{
- // Here we preserve ESP value. It is necessary for those developers,
- // who still define ChangeVolProc callback as "C" type function,
- // even though in year 2001 we announced in unrar.dll whatsnew.txt
- // that it will be PASCAL type (for compatibility with Visual Basic).
-#if defined(_MSC_VER)
-#ifndef _WIN_64
- __asm mov ebx,esp
-#endif
-#elif defined(_WIN_ALL) && defined(__BORLANDC__)
- _EBX=_ESP;
-#endif
- int RetCode=Cmd->ChangeVolProc(NextName,RAR_VOL_ASK);
-
- // Restore ESP after ChangeVolProc with wrongly defined calling
- // convention broken it.
-#if defined(_MSC_VER)
-#ifndef _WIN_64
- __asm mov esp,ebx
-#endif
-#elif defined(_WIN_ALL) && defined(__BORLANDC__)
- _ESP=_EBX;
-#endif
- if (RetCode!=0)
- {
- *NextNameW=0;
- DllVolChanged=true;
+ FailedOpen=true;
+ break;
}
- }
- if (!DllVolChanged)
- {
- Cmd->DllError=ERAR_EOPEN;
- FailedOpen=true;
- break;
- }
#else // !RARDLL
#if !defined(SFX_MODULE) && !defined(_WIN_CE)
if (!RecoveryDone)
{
- RecVolumes RecVol;
- RecVol.Restore(Cmd,Arc.FileName,Arc.FileNameW,true);
+ RecVolumesRestore(Cmd,Arc.FileName,true);
RecoveryDone=true;
continue;
}
@@ -158,7 +100,7 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,char Comman
}
#endif
#ifndef SILENT
- if (Cmd->AllYes || !AskNextVol(NextName,NextNameW))
+ if (Cmd->AllYes || !AskNextVol(NextName))
#endif
{
FailedOpen=true;
@@ -173,76 +115,46 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,char Comman
#if !defined(SILENT) && !defined(_WIN_CE)
Log(Arc.FileName,St(MAbsNextVol),NextName);
#endif
- Arc.Open(Arc.FileName,Arc.FileNameW,0);
+ Arc.Open(Arc.FileName,0);
Arc.Seek(PosBeforeClose,SEEK_SET);
- return(false);
- }
- Arc.CheckArc(true);
-#ifdef RARDLL
- if (Cmd->Callback!=NULL)
- {
- GetWideName(NextName,NextNameW,NextNameW,ASIZE(NextNameW));
- if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextNameW,RAR_VOL_NOTIFY)==-1)
- return(false);
- if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextName,RAR_VOL_NOTIFY)==-1)
- return(false);
- }
- if (Cmd->ChangeVolProc!=NULL)
- {
-#if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__)
- _EBX=_ESP;
-#endif
- int RetCode=Cmd->ChangeVolProc(NextName,RAR_VOL_NOTIFY);
-#if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__)
- _ESP=_EBX;
-#endif
- if (RetCode==0)
- return(false);
+ return false;
}
-#endif
if (Command=='T' || Command=='X' || Command=='E')
mprintf(St(Command=='T' ? MTestVol:MExtrVol),Arc.FileName);
+ Arc.CheckArc(true);
+#ifdef RARDLL
+ if (!DllVolNotify(Cmd,NextName))
+ return false;
+#endif
+
if (SplitHeader)
Arc.SearchBlock(HeaderType);
else
Arc.ReadHeader();
- if (Arc.GetHeaderType()==FILE_HEAD)
+ if (Arc.GetHeaderType()==HEAD_FILE)
{
Arc.ConvertAttributes();
- Arc.Seek(Arc.NextBlockPos-Arc.NewLhd.FullPackSize,SEEK_SET);
+ Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET);
}
#ifndef GUI
if (ShowFileName)
{
- char OutName[NM];
- IntToExt(Arc.NewLhd.FileName,OutName);
-#ifdef UNICODE_SUPPORTED
- bool WideName=(Arc.NewLhd.Flags & LHD_UNICODE) && UnicodeEnabled();
- if (WideName)
- {
- wchar NameW[NM];
- ConvertPath(Arc.NewLhd.FileNameW,NameW);
- char Name[NM];
- if (WideToChar(NameW,Name) && IsNameUsable(Name))
- strcpy(OutName,Name);
- }
-#endif
- mprintf(St(MExtrPoints),OutName);
+ mprintf(St(MExtrPoints),Arc.FileHead.FileName);
if (!Cmd->DisablePercentage)
- mprintf(" ");
+ mprintf(L" ");
}
#endif
if (DataIO!=NULL)
{
- if (HeaderType==ENDARC_HEAD)
+ if (HeaderType==HEAD_ENDARC)
DataIO->UnpVolume=false;
else
{
- DataIO->UnpVolume=(hd->Flags & LHD_SPLIT_AFTER)!=0;
- DataIO->SetPackedSizeToRead(hd->FullPackSize);
+ DataIO->UnpVolume=hd->SplitAfter;
+ DataIO->SetPackedSizeToRead(hd->PackSize);
}
#ifdef SFX_MODULE
DataIO->UnpArcSize=Arc.FileLength();
@@ -253,28 +165,136 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,char Comman
// compensated with ProcessedArcSize, so we need to reset this variable.
DataIO->CurUnpRead=0;
- DataIO->PackedCRC=0xffffffff;
-// DataIO->SetFiles(&Arc,NULL);
+ DataIO->PackedDataHash.Init(hd->FileHash.Type,Cmd->Threads);
}
- return(true);
+ return true;
}
-#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
-// Restore the run time stack check for unrar.dll.
-#pragma runtime_checks( "s", restore )
-#endif
-
#ifndef SILENT
-bool AskNextVol(char *ArcName,wchar *ArcNameW)
+bool AskNextVol(wchar *ArcName)
{
eprintf(St(MAskNextVol),ArcName);
if (Ask(St(MContinueQuit))==2)
- return(false);
- return(true);
+ return false;
+ return true;
}
#endif
+
+
+#ifdef RARDLL
+#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
+// Disable the run time stack check for unrar.dll, so we can manipulate
+// with ChangeVolProc call type below. Run time check would intercept
+// a wrong ESP before we restore it.
+#pragma runtime_checks( "s", off )
+#endif
+
+bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize)
+{
+ bool DllVolChanged=false,DllVolAborted=false;
+
+ if (Cmd->Callback!=NULL)
+ {
+ wchar CurName[NM];
+ wcscpy(CurName,NextName);
+ if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextName,RAR_VOL_ASK)==-1)
+ DllVolAborted=true;
+ else
+ if (wcscmp(CurName,NextName)!=0)
+ DllVolChanged=true;
+ else
+ {
+ char NextNameA[NM];
+ WideToChar(NextName,NextNameA,ASIZE(NextNameA));
+ if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextNameA,RAR_VOL_ASK)==-1)
+ DllVolAborted=true;
+ else
+ {
+ CharToWide(NextNameA,NextName,NameSize);
+ if (wcscmp(CurName,NextName)!=0)
+ DllVolChanged=true;
+ }
+ }
+ }
+ if (!DllVolChanged && Cmd->ChangeVolProc!=NULL)
+ {
+ char NextNameA[NM];
+ WideToChar(NextName,NextNameA,ASIZE(NextNameA));
+ // Here we preserve ESP value. It is necessary for those developers,
+ // who still define ChangeVolProc callback as "C" type function,
+ // even though in year 2001 we announced in unrar.dll whatsnew.txt
+ // that it will be PASCAL type (for compatibility with Visual Basic).
+#if defined(_MSC_VER)
+#ifndef _WIN_64
+ __asm mov ebx,esp
+#endif
+#elif defined(_WIN_ALL) && defined(__BORLANDC__)
+ _EBX=_ESP;
+#endif
+ int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_ASK);
+
+ // Restore ESP after ChangeVolProc with wrongly defined calling
+ // convention broken it.
+#if defined(_MSC_VER)
+#ifndef _WIN_64
+ __asm mov esp,ebx
+#endif
+#elif defined(_WIN_ALL) && defined(__BORLANDC__)
+ _ESP=_EBX;
+#endif
+ if (RetCode==0)
+ DllVolAborted=true;
+ else
+ CharToWide(NextNameA,NextName,ASIZE(NextName));
+ }
+
+ // 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)
+ {
+ Cmd->DllError=ERAR_EOPEN;
+ return false;
+ }
+ return true;
+}
+#endif
+
+
+#ifdef RARDLL
+bool DllVolNotify(RAROptions *Cmd,wchar *NextName)
+{
+ char NextNameA[NM];
+ WideToChar(NextName,NextNameA,ASIZE(NextNameA));
+ if (Cmd->Callback!=NULL)
+ {
+ if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextName,RAR_VOL_NOTIFY)==-1)
+ return false;
+ if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextNameA,RAR_VOL_NOTIFY)==-1)
+ return false;
+ }
+ if (Cmd->ChangeVolProc!=NULL)
+ {
+#if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__)
+ _EBX=_ESP;
+#endif
+ int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_NOTIFY);
+#if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__)
+ _ESP=_EBX;
+#endif
+ if (RetCode==0)
+ return false;
+ }
+ return true;
+}
+
+#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
+// Restore the run time stack check for unrar.dll.
+#pragma runtime_checks( "s", restore )
+#endif
+#endif
diff --git a/src/thirdparty/unrar/volume.hpp b/src/thirdparty/unrar/volume.hpp
index 22dd5bae0..4d9a2ee98 100644
--- a/src/thirdparty/unrar/volume.hpp
+++ b/src/thirdparty/unrar/volume.hpp
@@ -4,8 +4,8 @@
void SplitArchive(Archive &Arc,FileHeader *fh,int64 *HeaderPos,
ComprDataIO *DataIO);
bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,
- char Command);
+ wchar Command);
void SetVolWrite(Archive &Dest,int64 VolSize);
-bool AskNextVol(char *ArcName,wchar *ArcNameW);
+bool AskNextVol(wchar *ArcName);
#endif
diff --git a/src/thirdparty/unrar/win32acl.cpp b/src/thirdparty/unrar/win32acl.cpp
index 4843ce881..966542006 100644
--- a/src/thirdparty/unrar/win32acl.cpp
+++ b/src/thirdparty/unrar/win32acl.cpp
@@ -1,25 +1,22 @@
-static void SetPrivileges();
+static void SetACLPrivileges();
static bool ReadSacl=false;
#ifndef SFX_MODULE
-void ExtractACL(Archive &Arc,char *FileName,wchar *FileNameW)
+void ExtractACL20(Archive &Arc,const wchar *FileName)
{
- if (!WinNT())
- return;
-
- SetPrivileges();
+ SetACLPrivileges();
- if (Arc.HeaderCRC!=Arc.EAHead.HeadCRC)
+ if (Arc.BrokenHeader)
{
Log(Arc.FileName,St(MACLBroken),FileName);
ErrHandler.SetErrorCode(RARX_CRC);
return;
}
- if (Arc.EAHead.Method<0x31 || Arc.EAHead.Method>0x35 || Arc.EAHead.UnpVer>PACK_VER)
+ if (Arc.EAHead.Method<0x31 || Arc.EAHead.Method>0x35 || Arc.EAHead.UnpVer>VER_PACK)
{
Log(Arc.FileName,St(MACLUnknown),FileName);
ErrHandler.SetErrorCode(RARX_WARNING);
@@ -28,17 +25,18 @@ void ExtractACL(Archive &Arc,char *FileName,wchar *FileNameW)
ComprDataIO DataIO;
Unpack Unpack(&DataIO);
- Unpack.Init();
+ Unpack.Init(0x10000,false);
Array<byte> UnpData(Arc.EAHead.UnpSize);
DataIO.SetUnpackToMemory(&UnpData[0],Arc.EAHead.UnpSize);
DataIO.SetPackedSizeToRead(Arc.EAHead.DataSize);
DataIO.EnableShowProgress(false);
DataIO.SetFiles(&Arc,NULL);
+ DataIO.UnpHash.Init(HASH_CRC32,1);
Unpack.SetDestSize(Arc.EAHead.UnpSize);
Unpack.DoUnpack(Arc.EAHead.UnpVer,false);
- if (Arc.EAHead.EACRC!=~DataIO.UnpFileCRC)
+ if (Arc.EAHead.EACRC!=DataIO.UnpHash.GetCRC32())
{
Log(Arc.FileName,St(MACLBroken),FileName);
ErrHandler.SetErrorCode(RARX_CRC);
@@ -51,11 +49,7 @@ void ExtractACL(Archive &Arc,char *FileName,wchar *FileNameW)
si|=SACL_SECURITY_INFORMATION;
SECURITY_DESCRIPTOR *sd=(SECURITY_DESCRIPTOR *)&UnpData[0];
- int SetCode;
- if (FileNameW!=NULL)
- SetCode=SetFileSecurityW(FileNameW,si,sd);
- else
- SetCode=SetFileSecurityA(FileName,si,sd);
+ int SetCode=SetFileSecurityW(FileName,si,sd);
if (!SetCode)
{
@@ -67,16 +61,13 @@ void ExtractACL(Archive &Arc,char *FileName,wchar *FileNameW)
#endif
-void ExtractACLNew(Archive &Arc,char *FileName,wchar *FileNameW)
+void ExtractACL(Archive &Arc,const wchar *FileName)
{
- if (!WinNT())
- return;
-
Array<byte> SubData;
if (!Arc.ReadSubData(&SubData,NULL))
return;
- SetPrivileges();
+ SetACLPrivileges();
SECURITY_INFORMATION si=OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|
DACL_SECURITY_INFORMATION;
@@ -84,11 +75,7 @@ void ExtractACLNew(Archive &Arc,char *FileName,wchar *FileNameW)
si|=SACL_SECURITY_INFORMATION;
SECURITY_DESCRIPTOR *sd=(SECURITY_DESCRIPTOR *)&SubData[0];
- int SetCode;
- if (FileNameW!=NULL)
- SetCode=SetFileSecurityW(FileNameW,si,sd);
- else
- SetCode=SetFileSecurityA(FileName,si,sd);
+ int SetCode=SetFileSecurityW(FileName,si,sd);
if (!SetCode)
{
@@ -99,29 +86,38 @@ void ExtractACLNew(Archive &Arc,char *FileName,wchar *FileNameW)
}
-void SetPrivileges()
+void SetACLPrivileges()
{
static bool InitDone=false;
if (InitDone)
return;
+
+ if (SetPrivilege(SE_SECURITY_NAME))
+ ReadSacl=true;
+ SetPrivilege(SE_RESTORE_NAME);
+
InitDone=true;
+}
- HANDLE hToken;
- if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
- return;
+bool SetPrivilege(LPCTSTR PrivName)
+{
+ bool Success=false;
- TOKEN_PRIVILEGES tp;
- tp.PrivilegeCount = 1;
- tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ HANDLE hToken;
+ if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
+ {
+ TOKEN_PRIVILEGES tp;
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- if (LookupPrivilegeValue(NULL,SE_SECURITY_NAME,&tp.Privileges[0].Luid))
- if (AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL) &&
+ if (LookupPrivilegeValue(NULL,PrivName,&tp.Privileges[0].Luid) &&
+ AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL) &&
GetLastError() == ERROR_SUCCESS)
- ReadSacl=true;
+ Success=true;
- if (LookupPrivilegeValue(NULL,SE_RESTORE_NAME,&tp.Privileges[0].Luid))
- AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL);
+ CloseHandle(hToken);
+ }
- CloseHandle(hToken);
+ return Success;
}
diff --git a/src/thirdparty/unrar/win32lnk.cpp b/src/thirdparty/unrar/win32lnk.cpp
new file mode 100644
index 000000000..cfb552f7e
--- /dev/null
+++ b/src/thirdparty/unrar/win32lnk.cpp
@@ -0,0 +1,232 @@
+#define SYMLINK_FLAG_RELATIVE 1
+
+typedef struct _REPARSE_DATA_BUFFER {
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ union {
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ ULONG Flags;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ };
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+
+
+void GetReparsePoint(const wchar *Name,FileHeader *hd)
+{
+ static bool PrivSet=false;
+ if (!PrivSet)
+ {
+ SetPrivilege(SE_BACKUP_NAME);
+ PrivSet=true;
+ }
+
+ WIN32_FIND_DATAW FindData;
+ HANDLE hFind=FindFirstFileW(Name,&FindData);
+ if (hFind==INVALID_HANDLE_VALUE)
+ return;
+ FindClose(hFind);
+
+ if ((FindData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)==0 ||
+ FindData.dwReserved0!=IO_REPARSE_TAG_MOUNT_POINT &&
+ FindData.dwReserved0!=IO_REPARSE_TAG_SYMLINK)
+ return;
+
+ HANDLE hFile=CreateFileW(
+ Name,FILE_READ_EA,FILE_SHARE_READ,NULL,OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_POINT,NULL);
+ if (hFile==INVALID_HANDLE_VALUE)
+ {
+ ErrHandler.OpenErrorMsg(NULL,Name);
+ ErrHandler.SysErrMsg();
+ ErrHandler.SetErrorCode(RARX_OPEN);
+ return;
+ }
+
+ const DWORD BufSize=MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
+ Array<byte> Buf(BufSize);
+ REPARSE_DATA_BUFFER *rdb=(REPARSE_DATA_BUFFER *)&Buf[0];
+
+ DWORD BytesReturned;
+ BOOL DevResult=DeviceIoControl(hFile,FSCTL_GET_REPARSE_POINT,NULL,0,rdb,BufSize,&BytesReturned,NULL);
+ CloseHandle(hFile);
+ if (!DevResult)
+ {
+ ErrHandler.ReadErrorMsg(Name);
+ return;
+ }
+
+ wchar TargetName[NM];
+ if (rdb->ReparseTag==IO_REPARSE_TAG_MOUNT_POINT)
+ {
+ uint SubstOffset=rdb->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR);
+ uint SubstLength=rdb->MountPointReparseBuffer.SubstituteNameLength/sizeof(WCHAR);
+ wchar *SubstName=rdb->MountPointReparseBuffer.PathBuffer+SubstOffset;
+
+ if (SubstLength>=ASIZE(TargetName))
+ return;
+ wcsncpy(TargetName,SubstName,SubstLength);
+ TargetName[SubstLength]=0;
+ hd->RedirType=FSREDIR_JUNCTION;
+ }
+ if (rdb->ReparseTag==IO_REPARSE_TAG_SYMLINK)
+ {
+ uint SubstOffset=rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof(WCHAR);
+ uint SubstLength=rdb->SymbolicLinkReparseBuffer.SubstituteNameLength/sizeof(WCHAR);
+ wchar *SubstName=rdb->SymbolicLinkReparseBuffer.PathBuffer+SubstOffset;
+
+ if (SubstLength>=ASIZE(TargetName))
+ return;
+ wcsncpy(TargetName,SubstName,SubstLength);
+ TargetName[SubstLength]=0;
+ hd->RedirType=FSREDIR_WINSYMLINK;
+ }
+ if (hd->RedirType==FSREDIR_NONE)
+ return;
+ wcsncpyz(hd->RedirName,TargetName,ASIZE(hd->RedirName));
+ hd->DirTarget=(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!=0;
+}
+
+
+bool CreateReparsePoint(CommandData *Cmd,const wchar *Name,FileHeader *hd)
+{
+ static bool PrivSet=false;
+ if (!PrivSet)
+ {
+ SetPrivilege(SE_RESTORE_NAME);
+ PrivSet=true;
+ }
+
+ CreatePath(Name,true);
+
+ // 'DirTarget' check is important for Unix symlinks to directories.
+ // Unix symlinks do not have their own 'directory' attribute.
+ if (hd->Dir || hd->DirTarget)
+ {
+ if (!CreateDirectoryW(Name,NULL))
+ return false;
+ }
+ else
+ {
+ HANDLE hFile=CreateFileW(Name,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return false;
+ CloseHandle(hFile);
+ }
+
+ const DWORD BufSize=sizeof(REPARSE_DATA_BUFFER)+2*NM+1024;
+ Array<byte> Buf(BufSize);
+ REPARSE_DATA_BUFFER *rdb=(REPARSE_DATA_BUFFER *)&Buf[0];
+
+ wchar SubstName[NM];
+ wcsncpyz(SubstName,hd->RedirName,ASIZE(SubstName));
+ size_t SubstLength=wcslen(SubstName);
+
+ wchar PrintName[NM],*PrintNameSrc=SubstName,*PrintNameDst=PrintName;
+ bool WinPrefix=wcsncmp(PrintNameSrc,L"\\??\\",4)==0;
+ if (WinPrefix)
+ PrintNameSrc+=4;
+ if (WinPrefix && wcsncmp(PrintNameSrc,L"UNC\\",4)==0)
+ {
+ *(PrintNameDst++)='\\'; // Insert second \ in beginning of share name.
+ PrintNameSrc+=3;
+ }
+ wcscpy(PrintNameDst,PrintNameSrc);
+
+ size_t PrintLength=wcslen(PrintName);
+
+ bool AbsPath=WinPrefix;
+
+ if (hd->RedirType==FSREDIR_JUNCTION)
+ {
+ rdb->ReparseTag=IO_REPARSE_TAG_MOUNT_POINT;
+ rdb->ReparseDataLength=USHORT(
+ sizeof(rdb->MountPointReparseBuffer.SubstituteNameOffset)+
+ sizeof(rdb->MountPointReparseBuffer.SubstituteNameLength)+
+ sizeof(rdb->MountPointReparseBuffer.PrintNameOffset)+
+ sizeof(rdb->MountPointReparseBuffer.PrintNameLength)+
+ (SubstLength+1)*sizeof(WCHAR)+(PrintLength+1)*sizeof(WCHAR));
+ rdb->Reserved=0;
+
+ rdb->MountPointReparseBuffer.SubstituteNameOffset=0;
+ rdb->MountPointReparseBuffer.SubstituteNameLength=USHORT(SubstLength*sizeof(WCHAR));
+ wcscpy(rdb->MountPointReparseBuffer.PathBuffer,SubstName);
+
+ rdb->MountPointReparseBuffer.PrintNameOffset=USHORT((SubstLength+1)*sizeof(WCHAR));
+ rdb->MountPointReparseBuffer.PrintNameLength=USHORT(PrintLength*sizeof(WCHAR));
+ wcscpy(rdb->MountPointReparseBuffer.PathBuffer+SubstLength+1,PrintName);
+ }
+ else
+ if (hd->RedirType==FSREDIR_WINSYMLINK || hd->RedirType==FSREDIR_UNIXSYMLINK)
+ {
+ rdb->ReparseTag=IO_REPARSE_TAG_SYMLINK;
+ rdb->ReparseDataLength=USHORT(
+ sizeof(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset)+
+ sizeof(rdb->SymbolicLinkReparseBuffer.SubstituteNameLength)+
+ sizeof(rdb->SymbolicLinkReparseBuffer.PrintNameOffset)+
+ sizeof(rdb->SymbolicLinkReparseBuffer.PrintNameLength)+
+ sizeof(rdb->SymbolicLinkReparseBuffer.Flags)+
+ (SubstLength+1)*sizeof(WCHAR)+(PrintLength+1)*sizeof(WCHAR));
+ rdb->Reserved=0;
+
+ rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset=0;
+ rdb->SymbolicLinkReparseBuffer.SubstituteNameLength=USHORT(SubstLength*sizeof(WCHAR));
+ wcscpy(rdb->SymbolicLinkReparseBuffer.PathBuffer,SubstName);
+
+ rdb->SymbolicLinkReparseBuffer.PrintNameOffset=USHORT((SubstLength+1)*sizeof(WCHAR));
+ rdb->SymbolicLinkReparseBuffer.PrintNameLength=USHORT(PrintLength*sizeof(WCHAR));
+ wcscpy(rdb->SymbolicLinkReparseBuffer.PathBuffer+SubstLength+1,PrintName);
+
+ rdb->SymbolicLinkReparseBuffer.Flags=AbsPath ? 0:SYMLINK_FLAG_RELATIVE;
+ }
+ else
+ return false;
+
+ HANDLE hFile=CreateFile(Name,GENERIC_READ|GENERIC_WRITE,0,NULL,
+ OPEN_EXISTING,FILE_FLAG_OPEN_REPARSE_POINT|
+ FILE_FLAG_BACKUP_SEMANTICS,NULL);
+ if (hFile==INVALID_HANDLE_VALUE)
+ return false;
+
+ DWORD Returned;
+ if (!DeviceIoControl(hFile,FSCTL_SET_REPARSE_POINT,rdb,
+ FIELD_OFFSET(REPARSE_DATA_BUFFER,GenericReparseBuffer)+
+ rdb->ReparseDataLength,NULL,0,&Returned,NULL))
+ {
+ CloseHandle(hFile);
+ ErrHandler.CreateErrorMsg(Name);
+ ErrHandler.SysErrMsg();
+ ErrHandler.SetErrorCode(RARX_CREATE);
+
+ if (hd->Dir)
+ RemoveDirectoryW(Name);
+ else
+ DeleteFileW(Name);
+ return false;
+ }
+ File LinkFile;
+ LinkFile.SetHandle(hFile);
+ LinkFile.SetOpenFileTime(
+ Cmd->xmtime==EXTTIME_NONE ? NULL:&hd->mtime,
+ Cmd->xctime==EXTTIME_NONE ? NULL:&hd->ctime,
+ Cmd->xatime==EXTTIME_NONE ? NULL:&hd->atime);
+ LinkFile.Close();
+ if (!Cmd->IgnoreGeneralAttr)
+ SetFileAttr(Name,hd->FileAttr);
+ return true;
+}
diff --git a/src/thirdparty/unrar/win32stm.cpp b/src/thirdparty/unrar/win32stm.cpp
index 3a8aea032..ecbef7a07 100644
--- a/src/thirdparty/unrar/win32stm.cpp
+++ b/src/thirdparty/unrar/win32stm.cpp
@@ -1,13 +1,9 @@
-
-#ifndef SFX_MODULE
-void ExtractStreams(Archive &Arc,char *FileName,wchar *FileNameW)
+#if !defined(SFX_MODULE) && defined(_WIN_ALL)
+void ExtractStreams20(Archive &Arc,const wchar *FileName)
{
- if (!WinNT())
- return;
-
- if (Arc.HeaderCRC!=Arc.StreamHead.HeadCRC)
+ if (Arc.BrokenHeader)
{
#ifndef SILENT
Log(Arc.FileName,St(MStreamBroken),FileName);
@@ -16,7 +12,7 @@ void ExtractStreams(Archive &Arc,char *FileName,wchar *FileNameW)
return;
}
- if (Arc.StreamHead.Method<0x31 || Arc.StreamHead.Method>0x35 || Arc.StreamHead.UnpVer>PACK_VER)
+ if (Arc.StreamHead.Method<0x31 || Arc.StreamHead.Method>0x35 || Arc.StreamHead.UnpVer>VER_PACK)
{
#ifndef SILENT
Log(Arc.FileName,St(MStreamUnknown),FileName);
@@ -25,15 +21,15 @@ void ExtractStreams(Archive &Arc,char *FileName,wchar *FileNameW)
return;
}
- char StreamName[NM+2];
+ wchar StreamName[NM+2];
if (FileName[0]!=0 && FileName[1]==0)
{
- strcpy(StreamName,".\\");
- strcpy(StreamName+2,FileName);
+ wcscpy(StreamName,L".\\");
+ wcscpy(StreamName+2,FileName);
}
else
- strcpy(StreamName,FileName);
- if (strlen(StreamName)+strlen((char *)Arc.StreamHead.StreamName)>=sizeof(StreamName) ||
+ wcscpy(StreamName,FileName);
+ if (wcslen(StreamName)+strlen(Arc.StreamHead.StreamName)>=ASIZE(StreamName) ||
Arc.StreamHead.StreamName[0]!=':')
{
#ifndef SILENT
@@ -43,31 +39,33 @@ void ExtractStreams(Archive &Arc,char *FileName,wchar *FileNameW)
return;
}
- ConvertPath((char *)Arc.StreamHead.StreamName+1,(char *)Arc.StreamHead.StreamName+1);
+ wchar StoredName[NM];
+ CharToWide(Arc.StreamHead.StreamName,StoredName,ASIZE(StoredName));
+ ConvertPath(StoredName+1,StoredName+1);
- strcat(StreamName,(char *)Arc.StreamHead.StreamName);
+ wcsncatz(StreamName,StoredName,ASIZE(StreamName));
FindData fd;
- bool Found=FindFile::FastFind(FileName,FileNameW,&fd);
+ bool Found=FindFile::FastFind(FileName,&fd);
- if (fd.FileAttr & FILE_ATTRIBUTE_READONLY)
- SetFileAttr(FileName,FileNameW,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY);
+ if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0)
+ SetFileAttr(FileName,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY);
File CurFile;
if (CurFile.WCreate(StreamName))
{
ComprDataIO DataIO;
Unpack Unpack(&DataIO);
- Unpack.Init();
+ Unpack.Init(0x10000,false);
- Array<unsigned char> UnpData(Arc.StreamHead.UnpSize);
DataIO.SetPackedSizeToRead(Arc.StreamHead.DataSize);
DataIO.EnableShowProgress(false);
DataIO.SetFiles(&Arc,&CurFile);
+ DataIO.UnpHash.Init(HASH_CRC32,1);
Unpack.SetDestSize(Arc.StreamHead.UnpSize);
Unpack.DoUnpack(Arc.StreamHead.UnpVer,false);
- if (Arc.StreamHead.StreamCRC!=~DataIO.UnpFileCRC)
+ if (Arc.StreamHead.StreamCRC!=DataIO.UnpHash.GetCRC32())
{
#ifndef SILENT
Log(Arc.FileName,St(MStreamBroken),StreamName);
@@ -78,51 +76,33 @@ void ExtractStreams(Archive &Arc,char *FileName,wchar *FileNameW)
CurFile.Close();
}
File HostFile;
- if (Found && HostFile.Open(FileName,FileNameW,FMF_OPENSHARED|FMF_UPDATE))
+ if (Found && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE))
SetFileTime(HostFile.GetHandle(),&fd.ftCreationTime,&fd.ftLastAccessTime,
&fd.ftLastWriteTime);
- if (fd.FileAttr & FILE_ATTRIBUTE_READONLY)
- SetFileAttr(FileName,FileNameW,fd.FileAttr);
+ if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0)
+ SetFileAttr(FileName,fd.FileAttr);
}
#endif
-void ExtractStreamsNew(Archive &Arc,char *FileName,wchar *FileNameW)
+#ifdef _WIN_ALL
+void ExtractStreams(Archive &Arc,const wchar *FileName)
{
- if (!WinNT())
- return;
-
- wchar NameW[NM];
- if (FileNameW!=NULL && *FileNameW!=0)
- wcscpy(NameW,FileNameW);
- else
- CharToWide(FileName,NameW);
- wchar StreamNameW[NM+2];
- if (NameW[0]!=0 && NameW[1]==0)
+ wchar FullName[NM+2];
+ if (FileName[0]!=0 && FileName[1]==0)
{
- wcscpy(StreamNameW,L".\\");
- wcscpy(StreamNameW+2,NameW);
+ wcscpy(FullName,L".\\");
+ wcsncpyz(FullName+2,FileName,ASIZE(FullName)-2);
}
else
- wcscpy(StreamNameW,NameW);
-
- wchar *DestName=StreamNameW+wcslen(StreamNameW);
- byte *SrcName=&Arc.SubHead.SubData[0];
- size_t DestSize=Arc.SubHead.SubData.Size()/2;
-
- if (wcslen(StreamNameW)+DestSize>=ASIZE(StreamNameW))
- {
-#if !defined(SILENT) && !defined(SFX_MODULE)
- Log(Arc.FileName,St(MStreamBroken),FileName);
-#endif
- ErrHandler.SetErrorCode(RARX_CRC);
- return;
- }
+ wcsncpyz(FullName,FileName,ASIZE(FullName));
- RawToWide(SrcName,DestName,DestSize);
- DestName[DestSize]=0;
+ byte *Data=&Arc.SubHead.SubData[0];
+ size_t DataSize=Arc.SubHead.SubData.Size();
- if (*DestName!=':')
+ wchar StreamName[NM];
+ GetStreamNameNTFS(Arc,StreamName,ASIZE(StreamName));
+ if (*StreamName!=':')
{
#if !defined(SILENT) && !defined(SFX_MODULE)
Log(Arc.FileName,St(MStreamBroken),FileName);
@@ -131,24 +111,44 @@ void ExtractStreamsNew(Archive &Arc,char *FileName,wchar *FileNameW)
return;
}
- ConvertPath(DestName+1,DestName+1);
+ wcsncatz(FullName,StreamName,ASIZE(FullName));
FindData fd;
- bool Found=FindFile::FastFind(FileName,FileNameW,&fd);
+ bool Found=FindFile::FastFind(FileName,&fd);
- if (fd.FileAttr & FILE_ATTRIBUTE_READONLY)
- SetFileAttr(FileName,FileNameW,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY);
- char StreamName[NM];
- WideToChar(StreamNameW,StreamName);
+ if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0)
+ SetFileAttr(FileName,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY);
File CurFile;
- if (CurFile.WCreate(StreamName,StreamNameW) && Arc.ReadSubData(NULL,&CurFile))
+ if (CurFile.WCreate(FullName) && Arc.ReadSubData(NULL,&CurFile))
CurFile.Close();
File HostFile;
- if (Found && HostFile.Open(FileName,FileNameW,FMF_OPENSHARED|FMF_UPDATE))
+ if (Found && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE))
SetFileTime(HostFile.GetHandle(),&fd.ftCreationTime,&fd.ftLastAccessTime,
&fd.ftLastWriteTime);
// Restoring original file attributes. Important if file was read only
// or did not have "Archive" attribute
- SetFileAttr(FileName,FileNameW,fd.FileAttr);
+ SetFileAttr(FileName,fd.FileAttr);
+}
+#endif
+
+
+void GetStreamNameNTFS(Archive &Arc,wchar *StreamName,size_t MaxSize)
+{
+ byte *Data=&Arc.SubHead.SubData[0];
+ size_t DataSize=Arc.SubHead.SubData.Size();
+ if (Arc.Format==RARFMT15)
+ {
+ size_t DestSize=Min(DataSize/2,MaxSize-1);
+ RawToWide(Data,StreamName,DestSize);
+ StreamName[DestSize]=0;
+ }
+ else
+ {
+ char UtfString[NM*4];
+ size_t DestSize=Min(DataSize,ASIZE(UtfString)-1);
+ memcpy(UtfString,Data,DestSize);
+ UtfString[DestSize]=0;
+ UtfToWide(UtfString,StreamName,MaxSize);
+ }
}