diff options
author | XhmikosR <xhmikosr@users.sourceforge.net> | 2013-05-05 11:39:47 +0400 |
---|---|---|
committer | XhmikosR <xhmikosr@users.sourceforge.net> | 2013-05-06 02:56:22 +0400 |
commit | 00f8520475b119d50d40b8a4b2298f04afa821b9 (patch) | |
tree | e389319284c45b5305bb5156e1d8f8310849902a | |
parent | b18faab4208d8368d28c7b51afe5a73bbc90b05e (diff) |
update unrar to v5.0.2
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(®s,0,sizeof(regs)); - regs.h.ah=0x36; - regs.h.dl=Drive; -#ifdef _DJGPP - int86 (0x21,®s,&outregs); -#else - _int86 (0x21,®s,&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(<); + 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(<); } #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(<); + 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(<); } #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); + } } |