diff options
author | XhmikosR <xhmikosr@users.sourceforge.net> | 2012-06-16 00:29:14 +0400 |
---|---|---|
committer | XhmikosR <xhmikosr@users.sourceforge.net> | 2012-06-16 00:29:14 +0400 |
commit | a3d79a0b72e55ddb2d252b9e321dcf8451fdc25e (patch) | |
tree | 68f98e7fc27fb96ccaab7ea3bf58d4fdee34e091 /src/thirdparty/unrar | |
parent | 9a444c24cfea2d07fec73dd84377c36588456902 (diff) |
add unrar and use it as a static lib
git-svn-id: https://mpc-hc.svn.sourceforge.net/svnroot/mpc-hc/trunk@5142 10f7b99b-c216-0410-bff0-8a66a9350fd8
Diffstat (limited to 'src/thirdparty/unrar')
123 files changed, 23512 insertions, 0 deletions
diff --git a/src/thirdparty/unrar/acknow.txt b/src/thirdparty/unrar/acknow.txt new file mode 100644 index 000000000..69bb0ba81 --- /dev/null +++ b/src/thirdparty/unrar/acknow.txt @@ -0,0 +1,81 @@ + ACKNOWLEDGMENTS
+
+* 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.
+
+* RAR encryption includes parts of code from Szymon Stefanek
+ and Brian Gladman AES implementations also as Steve Reid SHA-1 source.
+
+ ---------------------------------------------------------------------------
+ Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK.
+ All rights reserved.
+
+ LICENSE TERMS
+
+ The free distribution and use of this software in both source and binary
+ form is allowed (with or without changes) provided that:
+
+ 1. distributions of this source code include the above copyright
+ notice, this list of conditions and the following disclaimer;
+
+ 2. distributions in binary form include the above copyright
+ notice, this list of conditions and the following disclaimer
+ in the documentation and/or other associated materials;
+
+ 3. the copyright holder's name is not used to endorse products
+ built using this software without specific written permission.
+
+ ALTERNATIVELY, provided that this notice is retained in full, this product
+ may be distributed under the terms of the GNU General Public License (GPL),
+ in which case the provisions of the GPL apply INSTEAD OF those given above.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+
+ Source code of this package also as other cryptographic technology
+ and computing project related links are available on Brian Gladman's
+ web site: http://www.gladman.me.uk
+
+* RAR uses CRC32 function based on Intel Slicing-by-8 algorithm.
+ Original Intel Slicing-by-8 code is available here:
+
+ http://sourceforge.net/projects/slicing-by-8/
+
+ Original Intel Slicing-by-8 code is licensed under BSD License
+ available at http://www.opensource.org/licenses/bsd-license.html
+
+ Copyright (c) 2004-2006 Intel Corporation.
+ All Rights Reserved
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with
+ the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+* 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 new file mode 100644 index 000000000..189fc791e --- /dev/null +++ b/src/thirdparty/unrar/arccmt.cpp @@ -0,0 +1,235 @@ +bool IsAnsiComment(const char *Data,int Size); + +bool Archive::GetComment(Array<byte> *CmtData,Array<wchar> *CmtDataW) +{ + if (!MainComment) + return(false); + SaveFilePos SavePos(*this); + +#ifndef SFX_MODULE + ushort CmtLength; + if (OldFormat) + { + Seek(SFXSize+SIZEOF_OLDMHD,SEEK_SET); + CmtLength=GetByte(); + CmtLength+=(GetByte()<<8); + } + else +#endif + { + if ((NewMhd.Flags & MHD_COMMENT)!=0) + { + // Old style (RAR 2.9) archive comment embedded into the main + // archive header. + Seek(SFXSize+SIZEOF_MARKHEAD+SIZEOF_NEWMHD,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); + } +#ifndef SFX_MODULE + // Old style (RAR 2.9) comment header embedded into the main + // archive header. + if (CommHead.HeadCRC!=HeaderCRC) + { + Log(FileName,St(MLogCommHead)); + Alarm(); + return(false); + } + CmtLength=CommHead.HeadSize-SIZEOF_COMMHEAD; +#endif + } +#ifndef SFX_MODULE + if (OldFormat && (OldMhd.Flags & MHD_PACK_COMMENT)!=0 || !OldFormat && CommHead.Method!=0x30) + { + if (!OldFormat && (CommHead.UnpVer < 15 || CommHead.UnpVer > UNP_VER || CommHead.Method > 0x35)) + return(false); + ComprDataIO DataIO; + DataIO.SetTestMode(true); + uint UnpCmtLength; + if (OldFormat) + { +#ifdef RAR_NOCRYPT + return(false); +#else + UnpCmtLength=GetByte(); + UnpCmtLength+=(GetByte()<<8); + CmtLength-=2; + DataIO.SetCmt13Encryption(); +#endif + } + else + UnpCmtLength=CommHead.UnpSize; + DataIO.SetFiles(this,NULL); + DataIO.EnableShowProgress(false); + DataIO.SetPackedSizeToRead(CmtLength); + + Unpack Unpack(&DataIO); + Unpack.Init(); + Unpack.SetDestSize(UnpCmtLength); + Unpack.DoUnpack(CommHead.UnpVer,false); + + if (!OldFormat && ((~DataIO.UnpFileCRC)&0xffff)!=CommHead.CommCRC) + { + Log(FileName,St(MLogCommBrk)); + Alarm(); + return(false); + } + else + { + byte *UnpData; + size_t UnpDataSize; + DataIO.GetUnpackedData(&UnpData,&UnpDataSize); + CmtData->Alloc(UnpDataSize); + memcpy(&((*CmtData)[0]),UnpData,UnpDataSize); + } + } + else + { + CmtData->Alloc(CmtLength); + + Read(&((*CmtData)[0]),CmtLength); + if (!OldFormat && CommHead.CommCRC!=(~CRC(0xffffffff,&((*CmtData)[0]),CmtLength)&0xffff)) + { + Log(FileName,St(MLogCommBrk)); + Alarm(); + CmtData->Reset(); + return(false); + } + } +#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())); + } + } +#endif + return(CmtData->Size()>0); +} + + +size_t Archive::ReadCommentData(Array<byte> *CmtData,Array<wchar> *CmtDataW) +{ + 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) + { + *CmtDataW=DataW; + CmtDataW->Alloc(CmtSize); + } + } + else + if (CmtDataW!=NULL) + { + CmtData->Push(0); + CmtDataW->Alloc(CmtSize+1); + CharToWide((char *)CmtData->Addr(),CmtDataW->Addr(),CmtSize+1); + CmtData->Alloc(CmtSize); + CmtDataW->Alloc(wcslen(CmtDataW->Addr())); + } + return(CmtSize); +} + + +void Archive::ViewComment() +{ +#ifndef GUI + if (Cmd->DisableComment) + return; + Array<byte> CmtBuf; + if (GetComment(&CmtBuf,NULL)) + { + size_t CmtSize=CmtBuf.Size(); + char *ChPtr=(char *)memchr(&CmtBuf[0],0x1A,CmtSize); + if (ChPtr!=NULL) + CmtSize=ChPtr-(char *)&CmtBuf[0]; + mprintf("\n"); + OutComment((char *)&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 new file mode 100644 index 000000000..b061e540a --- /dev/null +++ b/src/thirdparty/unrar/archive.cpp @@ -0,0 +1,284 @@ +#include "rar.hpp" + +#ifndef SHELL_EXT +#include "arccmt.cpp" +#endif + + +Archive::Archive(RAROptions *InitCmd) +{ + Cmd=InitCmd==NULL ? &DummyCmd:InitCmd; + OpenShared=Cmd->OpenShared; + OldFormat=false; + Solid=false; + Volume=false; + MainComment=false; + Locked=false; + Signed=false; + NotFirstVolume=false; + SFXSize=0; + LatestTime.Reset(); + Protected=false; + Encrypted=false; + FailedHeaderDecryption=false; + BrokenFileHeader=false; + LastReadBlock=0; + + CurBlockPos=0; + NextBlockPos=0; + + RecoveryPos=SIZEOF_MARKHEAD; + RecoverySectors=-1; + + memset(&NewMhd,0,sizeof(NewMhd)); + NewMhd.HeadType=MAIN_HEAD; + NewMhd.HeadSize=SIZEOF_NEWMHD; + HeaderCRC=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; + +} + + + +#ifndef SHELL_EXT +void Archive::CheckArc(bool EnableBroken) +{ + if (!IsArchive(EnableBroken)) + { + Log(FileName,St(MBadArc),FileName); + ErrHandler.Exit(RARX_FATAL); + } +} +#endif + + +#if !defined(SHELL_EXT) && !defined(SFX_MODULE) +void Archive::CheckOpen(const char *Name,const wchar *NameW) +{ + TOpen(Name,NameW); + CheckArc(false); +} +#endif + + +bool Archive::WCheckOpen(const char *Name,const wchar *NameW) +{ + if (!WOpen(Name,NameW)) + return(false); + if (!IsArchive(false)) + { +#ifndef SHELL_EXT + Log(FileName,St(MNotRAR),FileName); +#endif + Close(); + return(false); + } + return(true); +} + + +ARCSIGN_TYPE Archive::IsSignature(const byte *D,size_t Size) +{ + ARCSIGN_TYPE Type=ARCSIGN_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; + else +#endif + if (Size>=7 && D[1]==0x61 && D[2]==0x72 && D[3]==0x21 && D[4]==0x1a && D[5]==0x07) + { + // We check for non-zero last signature byte, so we can return + // a sensible warning in case we'll want to change the archive + // format sometimes in the future. + Type=D[6]==0 ? ARCSIGN_CURRENT:ARCSIGN_FUTURE; + } + return Type; +} + + +bool Archive::IsArchive(bool EnableBroken) +{ + Encrypted=false; +#ifndef SFX_MODULE + if (IsDevice()) + { +#ifndef SHELL_EXT + Log(FileName,St(MInvalidName),FileName); +#endif + return(false); + } +#endif + if (Read(MarkHead.Mark,SIZEOF_MARKHEAD)!=SIZEOF_MARKHEAD) + return(false); + SFXSize=0; + + ARCSIGN_TYPE Type; + if ((Type=IsSignature(MarkHead.Mark,sizeof(MarkHead.Mark)))!=ARCSIGN_NONE) + { + OldFormat=(Type==ARCSIGN_OLD); + if (OldFormat) + Seek(0,SEEK_SET); + } + else + { + Array<char> Buffer(MAXSFXSIZE); + 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) + { + OldFormat=(Type==ARCSIGN_OLD); + if (OldFormat && I>0 && CurPos<28 && ReadSize>31) + { + char *D=&Buffer[28-CurPos]; + if (D[0]!=0x52 || D[1]!=0x53 || D[2]!=0x46 || D[3]!=0x58) + continue; + } + SFXSize=CurPos+I; + Seek(SFXSize,SEEK_SET); + if (!OldFormat) + Read(MarkHead.Mark,SIZEOF_MARKHEAD); + break; + } + if (SFXSize==0) + return false; + } + if (Type==ARCSIGN_FUTURE) + { +#if !defined(SHELL_EXT) && !defined(SFX_MODULE) + Log(FileName,St(MNewRarFormat)); +#endif + return false; + } + ReadHeader(); + SeekToNext(); +#ifndef SFX_MODULE + if (OldFormat) + { + NewMhd.Flags=OldMhd.Flags & 0x3f; + NewMhd.HeadSize=OldMhd.HeadSize; + } + else +#endif + { + if (HeaderCRC!=NewMhd.HeadCRC) + { +#ifndef SHELL_EXT + Log(FileName,St(MLogMainHead)); +#endif + Alarm(); + 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) + { +#ifdef RARDLL + Cmd->DllError=ERAR_UNKNOWN_FORMAT; +#else + 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); + #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. + // It leads to skipped archive comment, but the rest of archive data + // is processed correctly. + if (Cmd->Callback==NULL) + SilentOpen=true; +#endif + + // If not encrypted, we'll check it below. + NotFirstVolume=Encrypted && (NewMhd.Flags & MHD_FIRSTVOLUME)==0; + + if (!SilentOpen || !Encrypted) + { + SaveFilePos SavePos(*this); + int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos; + + NotFirstVolume=false; + while (ReadHeader()!=0) + { + int HeaderType=GetHeaderType(); + if (HeaderType==NEWSUB_HEAD) + { + if (SubHead.CmpName(SUBHEAD_TYPE_CMT)) + MainComment=true; + if ((SubHead.Flags & LHD_SPLIT_BEFORE) || + Volume && (NewMhd.Flags & MHD_FIRSTVOLUME)==0) + NotFirstVolume=true; + } + else + { + if (HeaderType==FILE_HEAD && ((NewLhd.Flags & LHD_SPLIT_BEFORE)!=0 || + Volume && NewLhd.UnpVer>=29 && (NewMhd.Flags & MHD_FIRSTVOLUME)==0)) + NotFirstVolume=true; + break; + } + SeekToNext(); + } + CurBlockPos=SaveCurBlockPos; + NextBlockPos=SaveNextBlockPos; + } + if (!Volume || !NotFirstVolume) + { + strcpy(FirstVolumeName,FileName); + wcscpy(FirstVolumeNameW,FileNameW); + } + + return(true); +} + + + + +void Archive::SeekToNext() +{ + Seek(NextBlockPos,SEEK_SET); +} + + +#ifndef SFX_MODULE +int Archive::GetRecoverySize(bool Required) +{ + if (!Protected) + return(0); + if (RecoverySectors!=-1 || !Required) + return(RecoverySectors); + SaveFilePos SavePos(*this); + Seek(SFXSize,SEEK_SET); + SearchSubBlock(SUBHEAD_TYPE_RR); + return(RecoverySectors); +} +#endif + + + + diff --git a/src/thirdparty/unrar/archive.hpp b/src/thirdparty/unrar/archive.hpp new file mode 100644 index 000000000..58b4cd3ef --- /dev/null +++ b/src/thirdparty/unrar/archive.hpp @@ -0,0 +1,121 @@ +#ifndef _RAR_ARCHIVE_ +#define _RAR_ARCHIVE_ + +class Pack; + +enum {EN_LOCK=1,EN_VOL=2,EN_FIRSTVOL=4}; + +enum ARCSIGN_TYPE {ARCSIGN_NONE,ARCSIGN_OLD,ARCSIGN_CURRENT,ARCSIGN_FUTURE}; + +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 UnexpEndArcMsg(); + +#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; + + MarkHeader MarkHead; + OldMainHeader OldMhd; + + int RecoverySectors; + int64 RecoveryPos; + + bool FailedHeaderDecryption; + + RarTime LatestTime; + int LastReadBlock; + int CurHeaderType; + + bool SilentOpen; + public: + Archive(RAROptions *InitCmd=NULL); + 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 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 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); + bool ReadSubData(Array<byte> *UnpData,File *DestFile); + int GetHeaderType() {return(CurHeaderType);}; + size_t ReadCommentData(Array<byte> *CmtData,Array<wchar> *CmtDataW); + void WriteCommentData(byte *Data,size_t DataSize,bool FileComment); + RAROptions* GetRAROptions() {return(Cmd);} + void SetSilentOpen(bool Mode) {SilentOpen=Mode;} + + BaseBlock ShortBlock; + MainHeader NewMhd; + FileHeader NewLhd; + EndArcHeader EndArcHead; + SubBlockHeader SubBlockHead; + FileHeader SubHead; + CommentHeader CommHead; + ProtectHeader ProtectHead; + AVHeader AVHead; + SignHeader SignHead; + UnixOwnersHeader UOHead; + MacFInfoHeader MACHead; + EAHeader EAHead; + StreamHeader StreamHead; + + int64 CurBlockPos; + int64 NextBlockPos; + + bool OldFormat; + bool Solid; + bool Volume; + bool MainComment; + bool Locked; + bool Signed; + bool NotFirstVolume; + bool Protected; + bool Encrypted; + size_t SFXSize; + bool BrokenFileHeader; + + bool Splitting; + + ushort HeaderCRC; + + int64 VolWrite; + int64 AddingFilesSize; + size_t AddingHeadersSize; + + bool NewArchive; + + char FirstVolumeName[NM]; + wchar FirstVolumeNameW[NM]; +}; + + +#endif diff --git a/src/thirdparty/unrar/arcread.cpp b/src/thirdparty/unrar/arcread.cpp new file mode 100644 index 000000000..a524a9612 --- /dev/null +++ b/src/thirdparty/unrar/arcread.cpp @@ -0,0 +1,765 @@ +#include "rar.hpp" + +size_t Archive::SearchBlock(int BlockType) +{ + size_t Size,Count=0; + while ((Size=ReadHeader())!=0 && + (BlockType==ENDARC_HEAD || GetHeaderType()!=ENDARC_HEAD)) + { + if ((++Count & 127)==0) + Wait(); + if (GetHeaderType()==BlockType) + return(Size); + SeekToNext(); + } + return(0); +} + + +size_t Archive::SearchSubBlock(const char *Type) +{ + size_t Size; + while ((Size=ReadHeader())!=0 && GetHeaderType()!=ENDARC_HEAD) + { + if (GetHeaderType()==NEWSUB_HEAD && SubHead.CmpName(Type)) + return(Size); + SeekToNext(); + } + return(0); +} + + +void Archive::UnexpEndArcMsg() +{ + int64 ArcSize=FileLength(); + if (CurBlockPos>ArcSize || NextBlockPos>ArcSize) + { +#ifndef SHELL_EXT + Log(FileName,St(MLogUnexpEOF)); +#endif + ErrHandler.SetErrorCode(RARX_WARNING); + } +} + + +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(); + +#ifndef SFX_MODULE + if (OldFormat) + return(ReadOldHeader()); +#endif + + RawRead Raw(this); + + bool Decrypt=Encrypted && CurBlockPos>=(int64)SFXSize+SIZEOF_MARKHEAD+SIZEOF_NEWMHD; + + if (Decrypt) + { +#if defined(SHELL_EXT) || defined(RAR_NOCRYPT) + return(0); +#else + if (Read(HeadersSalt,SALT_SIZE)!=SALT_SIZE) + { + 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); + Raw.SetCrypt(&HeadersCrypt); +#endif + } + + Raw.Read(SIZEOF_SHORTBLOCKHEAD); + if (Raw.Size()==0) + { + UnexpEndArcMsg(); + return(0); + } + + Raw.Get(ShortBlock.HeadCRC); + byte HeadType; + Raw.Get(HeadType); + ShortBlock.HeadType=(HEADER_TYPE)HeadType; + Raw.Get(ShortBlock.Flags); + Raw.Get(ShortBlock.HeadSize); + if (ShortBlock.HeadSize<SIZEOF_SHORTBLOCKHEAD) + { +#ifndef SHELL_EXT + Log(FileName,St(MLogFileHead),"???"); +#endif + BrokenFileHeader=true; + ErrHandler.SetErrorCode(RARX_CRC); + return(0); + } + + if (ShortBlock.HeadType==COMM_HEAD) + { + // Old style (up to RAR 2.9) comment header embedded into main + // or file header. We must not read the entire ShortBlock.HeadSize here + // to not break the comment processing logic later. + Raw.Read(SIZEOF_COMMHEAD-SIZEOF_SHORTBLOCKHEAD); + } + else + if (ShortBlock.HeadType==MAIN_HEAD && (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); + } + else + Raw.Read(ShortBlock.HeadSize-SIZEOF_SHORTBLOCKHEAD); + + NextBlockPos=CurBlockPos+ShortBlock.HeadSize; + + switch(ShortBlock.HeadType) + { + 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); + break; + case FILE_HEAD: + case NEWSUB_HEAD: + { + FileHeader *hd=ShortBlock.HeadType==FILE_HEAD ? &NewLhd:&SubHead; + *(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) + { + Raw.Get(hd->HighPackSize); + Raw.Get(hd->HighUnpSize); + } + 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); + } + } + hd->FullPackSize=INT32TO64(hd->HighPackSize,hd->PackSize); + hd->FullUnpSize=INT32TO64(hd->HighUnpSize,hd->UnpSize); + + char FileName[NM*4]; + size_t NameSize=Min(hd->NameSize,sizeof(FileName)-1); + Raw.Get((byte *)FileName,NameSize); + FileName[NameSize]=0; + + strncpyz(hd->FileName,FileName,ASIZE(hd->FileName)); + + if (hd->HeadType==NEWSUB_HEAD) + { + // Let's calculate the size of optional data. + int DataSize=hd->HeadSize-hd->NameSize-SIZEOF_NEWLHD; + if (hd->Flags & LHD_SALT) + DataSize-=SALT_SIZE; + + 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); + 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); + } + } + } + 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) + { + ushort Flags; + Raw.Get(Flags); + RarTime *tbl[4]; + tbl[0]=&NewLhd.mtime; + tbl[1]=&NewLhd.ctime; + tbl[2]=&NewLhd.atime; + tbl[3]=&NewLhd.arctime; + for (int I=0;I<4;I++) + { + RarTime *CurTime=tbl[I]; + uint rmode=Flags>>(3-I)*4; + if ((rmode & 8)==0) + continue; + if (I!=0) + { + uint DosTime; + Raw.Get(DosTime); + CurTime->SetDos(DosTime); + } + RarLocalTime rlt; + CurTime->GetLocal(&rlt); + if (rmode & 4) + rlt.Second++; + rlt.Reminder=0; + int count=rmode&3; + for (int J=0;J<count;J++) + { + byte CurByte; + Raw.Get(CurByte); + 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; + if (hd->HeadCRC!=HeaderCRC) + { + if (hd->HeadType==NEWSUB_HEAD && strlen(hd->FileName)<ASIZE(hd->FileName)-5) + strcat(hd->FileName,"- ???"); + BrokenFileHeader=true; + ErrHandler.SetErrorCode(RARX_WARNING); + + // If we have a broken encrypted header, we do not need to display + // the error message here, because it will be displayed for such + // 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) + { +#ifndef SHELL_EXT + Log(Archive::FileName,St(MLogFileHead),IntNameToExt(hd->FileName)); + Alarm(); +#endif + } + } + } + break; +#ifndef SFX_MODULE + case COMM_HEAD: + *(BaseBlock *)&CommHead=ShortBlock; + Raw.Get(CommHead.UnpSize); + Raw.Get(CommHead.UnpVer); + Raw.Get(CommHead.Method); + Raw.Get(CommHead.CommCRC); + break; + case SIGN_HEAD: + *(BaseBlock *)&SignHead=ShortBlock; + Raw.Get(SignHead.CreationTime); + Raw.Get(SignHead.ArcNameSize); + Raw.Get(SignHead.UserNameSize); + break; + case AV_HEAD: + *(BaseBlock *)&AVHead=ShortBlock; + Raw.Get(AVHead.UnpVer); + Raw.Get(AVHead.Method); + Raw.Get(AVHead.AVVer); + Raw.Get(AVHead.AVInfoCRC); + break; + case PROTECT_HEAD: + *(BaseBlock *)&ProtectHead=ShortBlock; + Raw.Get(ProtectHead.DataSize); + Raw.Get(ProtectHead.Version); + Raw.Get(ProtectHead.RecSectors); + Raw.Get(ProtectHead.TotalBlocks); + Raw.Get(ProtectHead.Mark,8); + NextBlockPos+=ProtectHead.DataSize; + RecoverySectors=ProtectHead.RecSectors; + break; + case SUB_HEAD: + *(BaseBlock *)&SubBlockHead=ShortBlock; + Raw.Get(SubBlockHead.DataSize); + NextBlockPos+=SubBlockHead.DataSize; + Raw.Get(SubBlockHead.SubType); + Raw.Get(SubBlockHead.Level); + 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.OwnerName[UOHead.OwnerNameSize]=0; + UOHead.GroupName[UOHead.GroupNameSize]=0; + break; + case MAC_HEAD: + *(SubBlockHeader *)&MACHead=SubBlockHead; + Raw.Get(MACHead.fileType); + Raw.Get(MACHead.fileCreator); + 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); + 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.StreamName[StreamHead.StreamNameSize]=0; + break; + } + break; +#endif + default: + if (ShortBlock.Flags & LONG_BLOCK) + { + uint DataSize; + Raw.Get(DataSize); + NextBlockPos+=DataSize; + } + break; + } + HeaderCRC=~Raw.GetCRC(false)&0xffff; + CurHeaderType=ShortBlock.HeadType; + if (Decrypt) + { + NextBlockPos+=Raw.PaddedSize()+SALT_SIZE; + + if (ShortBlock.HeadCRC!=HeaderCRC) + { + 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) + { +#ifndef SILENT + Log(FileName,St(MEncrBadCRC),FileName); +#endif +// Close(); + FailedHeaderDecryption=true; + BrokenFileHeader=true; + + ErrHandler.SetErrorCode(RARX_CRC); + return(0); + } + } + } + + if (NextBlockPos<=CurBlockPos) + { +#ifndef SHELL_EXT + Log(FileName,St(MLogFileHead),"???"); +#endif + BrokenFileHeader=true; + ErrHandler.SetErrorCode(RARX_CRC); + return(0); + } + return(Raw.Size()); +} + + +#ifndef SFX_MODULE +size_t Archive::ReadOldHeader() +{ + RawRead Raw(this); + if (CurBlockPos<=(int64)SFXSize) + { + Raw.Read(SIZEOF_OLDMHD); + Raw.Get(OldMhd.Mark,4); + Raw.Get(OldMhd.HeadSize); + Raw.Get(OldMhd.Flags); + NextBlockPos=CurBlockPos+OldMhd.HeadSize; + CurHeaderType=MAIN_HEAD; + } + else + { + 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; + + if (Raw.Size()!=0) + NextBlockPos=CurBlockPos+NewLhd.HeadSize+NewLhd.PackSize; + CurHeaderType=FILE_HEAD; + } + return(NextBlockPos>CurBlockPos ? Raw.Size():0); +} +#endif + + +void Archive::ConvertNameCase(char *Name) +{ + if (Cmd->ConvertNames==NAMES_UPPERCASE) + { + IntToExt(Name,Name); + strupper(Name); + ExtToInt(Name,Name); + } + if (Cmd->ConvertNames==NAMES_LOWERCASE) + { + IntToExt(Name,Name); + strlower(Name); + ExtToInt(Name,Name); + } +} + + +#ifndef SFX_MODULE +void Archive::ConvertNameCase(wchar *Name) +{ + if (Cmd->ConvertNames==NAMES_UPPERCASE) + wcsupper(Name); + if (Cmd->ConvertNames==NAMES_LOWERCASE) + wcslower(Name); +} +#endif + + +bool Archive::IsArcDir() +{ + return((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY); +} + + +bool Archive::IsArcLabel() +{ + return(NewLhd.HostOS<=HOST_WIN32 && (NewLhd.FileAttr & 8)); +} + + +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; + } +#endif +#ifdef _UNIX + // umask defines which permission bits must not be set by default + // when creating a file or directory. The typical default value + // for the process umask is S_IWGRP | S_IWOTH (octal 022), + // resulting in 0644 mode for new files. + static mode_t mask = (mode_t) -1; + + if (mask == (mode_t) -1) + { + // umask call returns the current umask value. Argument (022) is not + // really important here. + mask = umask(022); + + // Restore the original umask value, which was changed to 022 above. + umask(mask); + } + + switch(NewLhd.HostOS) + { + case HOST_MSDOS: + case HOST_OS2: + case HOST_WIN32: + { + // Mapping MSDOS, OS/2 and Windows file attributes to Unix. + + if (NewLhd.FileAttr & 0x10) // FILE_ATTRIBUTE_DIRECTORY + { + // For directories we use 0777 mask. + NewLhd.FileAttr=0777 & ~mask; + } + else + if (NewLhd.FileAttr & 1) // FILE_ATTRIBUTE_READONLY + { + // For read only files we use 0444 mask with 'w' bits turned off. + NewLhd.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; + } + } + break; + case HOST_UNIX: + case HOST_BEOS: + break; + default: + if ((NewLhd.Flags & LHD_WINDOWMASK)==LHD_DIRECTORY) + NewLhd.FileAttr=0x41ff & ~mask; + else + NewLhd.FileAttr=0x81b6 & ~mask; + break; + } +#endif +} + + +void Archive::ConvertUnknownHeader() +{ + 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; + else + NewLhd.FileAttr=0x20; + } + for (char *s=NewLhd.FileName;*s!=0;s=charnext(s)) + { + if (*s=='/' || *s=='\\') + *s=CPATHDIVIDER; +#if defined(_APPLE) && !defined(UNICODE_SUPPORTED) + if ((byte)*s<32 || (byte)*s>127) + *s='_'; +#endif + +#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 + + } + + 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 + } +} + + +#ifndef SHELL_EXT +bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile) +{ + if (HeaderCRC!=SubHead.HeadCRC) + { +#ifndef SHELL_EXT + Log(FileName,St(MSubHeadCorrupt)); +#endif + ErrHandler.SetErrorCode(RARX_CRC); + return(false); + } + if (SubHead.Method<0x30 || SubHead.Method>0x35 || SubHead.UnpVer>/*PACK_VER*/36) + { +#ifndef SHELL_EXT + Log(FileName,St(MSubHeadUnknown)); +#endif + return(false); + } + + if (SubHead.PackSize==0 && (SubHead.Flags & LHD_SPLIT_AFTER)==0) + return(true); + + SubDataIO.Init(); + Unpack Unpack(&SubDataIO); + Unpack.Init(); + + if (DestFile==NULL) + { + UnpData->Alloc(SubHead.UnpSize); + SubDataIO.SetUnpackToMemory(&(*UnpData)[0],SubHead.UnpSize); + } + if (SubHead.Flags & LHD_PASSWORD) + if (Cmd->Password.IsSet()) + SubDataIO.SetEncryption(SubHead.UnpVer,&Cmd->Password, + (SubHead.Flags & LHD_SALT) ? SubHead.Salt:NULL,false, + SubHead.UnpVer>=36); + else + return(false); + SubDataIO.SetPackedSizeToRead(SubHead.PackSize); + SubDataIO.EnableShowProgress(false); + SubDataIO.SetFiles(this,DestFile); + SubDataIO.UnpVolume=(SubHead.Flags & LHD_SPLIT_AFTER)!=0; + SubDataIO.SetSubHeader(&SubHead,NULL); + Unpack.SetDestSize(SubHead.UnpSize); + if (SubHead.Method==0x30) + CmdExtract::UnstoreFile(SubDataIO,SubHead.UnpSize); + else + Unpack.DoUnpack(SubHead.UnpVer,false); + + if (SubHead.FileCRC!=~SubDataIO.UnpFileCRC) + { +#ifndef SHELL_EXT + Log(FileName,St(MSubHeadDataCRC),SubHead.FileName); +#endif + ErrHandler.SetErrorCode(RARX_CRC); + if (UnpData!=NULL) + UnpData->Reset(); + return(false); + } + return(true); +} +#endif diff --git a/src/thirdparty/unrar/array.hpp b/src/thirdparty/unrar/array.hpp new file mode 100644 index 000000000..f3821bc47 --- /dev/null +++ b/src/thirdparty/unrar/array.hpp @@ -0,0 +1,131 @@ +#ifndef _RAR_ARRAY_ +#define _RAR_ARRAY_ + +extern ErrorHandler ErrHandler; + +template <class T> class Array +{ + private: + T *Buffer; + size_t BufSize; + size_t AllocSize; + public: + Array(); + Array(size_t Size); + ~Array(); + inline void CleanData(); + inline T& operator [](size_t Item); + inline size_t Size(); // Returns the size in items, not in bytes. + void Add(size_t Items); + void Alloc(size_t Items); + void Reset(); + void SoftReset(); + void operator = (Array<T> &Src); + void Push(T Item); + T* Addr() {return(Buffer);} +}; + +template <class T> void Array<T>::CleanData() +{ + Buffer=NULL; + BufSize=0; + AllocSize=0; +} + + +template <class T> Array<T>::Array() +{ + CleanData(); +} + + +template <class T> Array<T>::Array(size_t Size) +{ + Buffer=(T *)malloc(sizeof(T)*Size); + if (Buffer==NULL && Size!=0) + ErrHandler.MemoryError(); + + AllocSize=BufSize=Size; +} + + +template <class T> Array<T>::~Array() +{ + if (Buffer!=NULL) + free(Buffer); +} + + +template <class T> inline T& Array<T>::operator [](size_t Item) +{ + return(Buffer[Item]); +} + + +template <class T> inline size_t Array<T>::Size() +{ + return(BufSize); +} + + +template <class T> void Array<T>::Add(size_t Items) +{ + BufSize+=Items; + if (BufSize>AllocSize) + { + size_t Suggested=AllocSize+AllocSize/4+32; + size_t NewSize=Max(BufSize,Suggested); + + Buffer=(T *)realloc(Buffer,NewSize*sizeof(T)); + if (Buffer==NULL) + ErrHandler.MemoryError(); + AllocSize=NewSize; + } +} + + +template <class T> void Array<T>::Alloc(size_t Items) +{ + if (Items>AllocSize) + Add(Items-BufSize); + else + BufSize=Items; +} + + +template <class T> void Array<T>::Reset() +{ + if (Buffer!=NULL) + { + free(Buffer); + Buffer=NULL; + } + BufSize=0; + AllocSize=0; +} + + +// Reste 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() +{ + BufSize=0; +} + + +template <class T> void Array<T>::operator =(Array<T> &Src) +{ + Reset(); + Alloc(Src.BufSize); + if (Src.BufSize!=0) + memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T)); +} + + +template <class T> void Array<T>::Push(T Item) +{ + Add(1); + (*this)[Size()-1]=Item; +} + +#endif diff --git a/src/thirdparty/unrar/beosea.cpp b/src/thirdparty/unrar/beosea.cpp new file mode 100644 index 000000000..3b6e862e4 --- /dev/null +++ b/src/thirdparty/unrar/beosea.cpp @@ -0,0 +1,113 @@ + + +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/cmddata.cpp b/src/thirdparty/unrar/cmddata.cpp new file mode 100644 index 000000000..e17fa2061 --- /dev/null +++ b/src/thirdparty/unrar/cmddata.cpp @@ -0,0 +1,1431 @@ +#include "rar.hpp" + + +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; +} + + +void CommandData::Close() +{ + delete FileArgs; + delete ExclArgs; + delete InclArgs; + delete StoreArgs; + delete ArcNames; + FileArgs=ExclArgs=InclArgs=StoreArgs=ArcNames=NULL; + 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) +{ + 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); + return NULL; + } + GetAsciiName(*ParW,*ParA,ParSizeA); + return CmdLine; +} +#endif + + +#ifndef SFX_MODULE +void CommandData::PreprocessCommandLine(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; + bool Code=FirstParam ? true:PreprocessSwitch(ParA); + free(ParW); + free(ParA); + if (!Code) + break; + } +#else + 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); + } +#else + for (int I=1;I<argc;I++) + ParseArg(argv[I],NULL); +#endif + ParseDone(); +} +#endif + + +#ifndef SFX_MODULE +void CommandData::ParseArg(char *Arg,wchar *ArgW) +{ + if (IsSwitch(*Arg) && !NoMoreSwitches) + if (Arg[1]=='-') + NoMoreSwitches=true; + else + ProcessSwitch(Arg+1,(ArgW!=NULL && *ArgW!=0 ? ArgW+1:NULL)); + else + if (*Command==0) + { + strncpyz(Command,Arg,ASIZE(Command)); + if (ArgW!=NULL) + wcsncpy(CommandW,ArgW,ASIZE(CommandW)); + + +#ifndef GUI + *Command=etoupper(*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); +#endif + } + else + if (*ArcName==0 && *ArcNameW==0) + { + strncpyz(ArcName,Arg,ASIZE(ArcName)); + if (ArgW!=NULL) + wcsncpyz(ArcNameW,ArgW,ASIZE(ArcNameW)); + } + 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); + } + + char CmdChar=etoupper(*Command); + bool Add=strchr("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)); + } + else + if ((Add || CmdChar=='T') && (*Arg!='@' || ListMode==RCLM_REJECT_LISTS)) + FileArgs->AddString(Arg,ArgW); + else + { + FindData FileData; + bool Found=FindFile::FastFind(Arg,ArgW,&FileData); + if ((!Found || ListMode==RCLM_ACCEPT_LISTS) && + ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg,ArgW)) + { + FileLists=true; + + 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 + + wchar *WideArgName=(ArgW!=NULL && *ArgW!=0 ? ArgW+1:NULL); + ReadTextFile(Arg+1,WideArgName,FileArgs,false,true,Charset,true,true,true); + + } + else + if (Found && FileData.IsDir && Extract && *ExtrPath==0 && *ExtrPathW==0) + { + strncpyz(ExtrPath,Arg,ASIZE(ExtrPath)-1); + AddEndSlash(ExtrPath); + if (ArgW!=NULL) + { + wcsncpyz(ExtrPathW,ArgW,ASIZE(ExtrPathW)-1); + AddEndSlash(ExtrPathW); + } + } + else + FileArgs->AddString(Arg,ArgW); + } + } +} +#endif + + +void CommandData::ParseDone() +{ + if (FileArgs->ItemsCount()==0 && !FileLists) + FileArgs->AddString(MASKALL); + char CmdChar=etoupper(*Command); + 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'; +} + + +#if !defined(SFX_MODULE) && !defined(_WIN_CE) +void CommandData::ParseEnvVar() +{ + char *EnvStr=getenv("RAR"); + if (EnvStr!=NULL) + { + ProcessSwitchesString(EnvStr); + } +} +#endif + + + +#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) +{ + if (IsSwitch(Switch[0])) + { + Switch++; + if (stricomp(Switch,"-")==0) // Switch "--". + return false; + if (stricomp(Switch,"cfg-")==0) + ConfigDisabled=true; +#ifndef GUI + if (strnicomp(Switch,"ilog",4)==0) + { + // Ensure that correct log file name is already set + // if we need to report an error when processing the command line. + ProcessSwitch(Switch); + InitLogOptions(LogName); + } +#endif + if (strnicomp(Switch,"sc",2)==0) + { + // Process -sc before reading any file lists. + ProcessSwitch(Switch); + } + } + return true; +} +#endif + + +#if !defined(GUI) && !defined(SFX_MODULE) +void CommandData::ReadConfig() +{ + StringList List; + if (ReadTextFile(DefConfigName,NULL,&List,true)) + { + char *Str; + while ((Str=List.GetString())!=NULL) + { + while (IsSpace(*Str)) + Str++; + if (strnicomp(Str,"switches=",9)==0) + ProcessSwitchesString(Str+9); + } + } +} +#endif + + +#if !defined(SFX_MODULE) && !defined(_WIN_CE) +void CommandData::ProcessSwitchesString(char *Str) +{ + while (*Str) + { + 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; + } +} +#endif + + +#if !defined(SFX_MODULE) +void CommandData::ProcessSwitch(const char *Switch,const wchar *SwitchW) +{ + + bool WidePresent=SwitchW!=NULL && *SwitchW!=0; // If 'true', SwitchW is not empty. + + switch(etoupper(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])) + { + case 'C': + ClearArc=true; + break; + case 'D': + AppendArcNameToPath=true; + break; +#ifndef SFX_MODULE + case 'G': + if (Switch[2]=='-' && Switch[3]==0) + GenerateArcName=0; + else + { + GenerateArcName=true; + strncpyz(GenerateMask,Switch+2,ASIZE(GenerateMask)); + } + break; +#endif + case 'I': + IgnoreGeneralAttr=true; + break; + case 'N': // Reserved for archive name. + break; + case 'O': + AddArcOnly=true; + break; + case 'P': + strcpy(ArcPath,Switch+2); + if (WidePresent) + wcscpy(ArcPathW,SwitchW+2); + break; + case 'S': + SyncFiles=true; + break; + default: + BadSwitch(Switch); + break; + } + break; + case 'D': + if (Switch[2]==0) + switch(etoupper(Switch[1])) + { + case 'S': + DisableSortSolid=true; + break; + case 'H': + OpenShared=true; + break; + case 'F': + DeleteFiles=true; + 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])) + { + case 'P': + switch(Switch[2]) + { + case 0: + ExclPath=EXCL_SKIPWHOLEPATH; + break; + case '1': + ExclPath=EXCL_BASEPATH; + break; + case '2': + ExclPath=EXCL_SAVEFULLPATH; + break; + case '3': + ExclPath=EXCL_ABSPATH; + break; + } + break; + case 'E': + ProcessEA=false; + break; + case 'N': + NoEndBlock=true; + break; + default: + if (Switch[1]=='+') + { + InclFileAttr=GetExclAttr(&Switch[2]); + InclAttrSet=true; + } + else + ExclFileAttr=GetExclAttr(&Switch[1]); + break; + } + break; + case 'P': + if (Switch[1]==0) + { + GetPassword(PASSWORD_GLOBAL,NULL,NULL,&Password); + eprintf("\n"); + } + else + { + wchar PlainPsw[MAXPASSWORD]; + CharToWide(Switch+1,PlainPsw,ASIZE(PlainPsw)); + PlainPsw[ASIZE(PlainPsw)-1]=0; + Password.Set(PlainPsw); + cleandata(PlainPsw,ASIZE(PlainPsw)); + } + break; + case 'H': + if (etoupper(Switch[1])=='P') + { + 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()) + { + GetPassword(PASSWORD_GLOBAL,NULL,NULL,&Password); + eprintf("\n"); + } + } + break; + case 'Z': + if (Switch[1]==0 && (!WidePresent || SwitchW[1]==0)) + { +#ifndef GUI // stdin is not supported by WinRAR. + // If comment file is not specified, we read data from stdin. + strcpy(CommentFile,"stdin"); +#endif + } + else + { + strncpyz(CommentFile,Switch+1,ASIZE(CommentFile)); + if (WidePresent) + wcsncpyz(CommentFileW,SwitchW+1,ASIZE(CommentFileW)); + } + break; + case 'M': + switch(etoupper(Switch[1])) + { + case 'C': + { + const char *Str=Switch+2; + if (*Str=='-') + for (uint I=0;I<ASIZE(FilterModes);I++) + FilterModes[I].State=FILTER_DISABLE; + else + while (*Str) + { + int Param1=0,Param2=0; + FilterState State=FILTER_AUTO; + FilterType Type=FILTER_NONE; + if (IsDigit(*Str)) + { + Param1=atoi(Str); + while (IsDigit(*Str)) + Str++; + } + if (*Str==':' && IsDigit(Str[1])) + { + Param2=atoi(++Str); + while (IsDigit(*Str)) + Str++; + } + switch(etoupper(*(Str++))) + { + case 'T': Type=FILTER_PPM; break; + case 'E': Type=FILTER_E8; break; + case 'D': Type=FILTER_DELTA; break; + case 'A': Type=FILTER_AUDIO; break; + case 'C': Type=FILTER_RGB; break; + case 'I': Type=FILTER_ITANIUM; break; + case 'L': Type=FILTER_UPCASETOLOW; break; + } + if (*Str=='+' || *Str=='-') + State=*(Str++)=='+' ? FILTER_FORCE:FILTER_DISABLE; + FilterModes[Type].State=State; + FilterModes[Type].Param1=Param1; + FilterModes[Type].Param2=Param2; + } + } + break; + 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; + while (*Names!=0) + { + char *End=strchr(Names,';'); + if (End!=NULL) + *End=0; + if (*Names=='.') + Names++; + char Mask[NM]; + if (strpbrk(Names,"*?.")==NULL) + sprintf(Mask,"*.%s",Names); + else + strcpy(Mask,Names); + StoreArgs->AddString(Mask); + if (End==NULL) + break; + Names=End+1; + } + } + break; +#ifdef RAR_SMP + case 'T': + Threads=atoi(Switch+2); + if (Threads>MaxPoolThreads || Threads<1) + BadSwitch(Switch); + else + { + } + break; +#endif + default: + Method=Switch[1]-'0'; + if (Method>5 || Method<0) + BadSwitch(Switch); + break; + } + break; + case 'V': + switch(etoupper(Switch[1])) + { + case 'N': + OldNumbering=true; + break; + case 'P': + VolumePause=true; + break; + case 'E': + if (etoupper(Switch[2])=='R') + VersionControl=atoi(Switch+3)+1; + break; + case '-': + VolSize=0; + break; + default: + VolSize=VOLSIZE_AUTO; // UnRAR -v switch for list command. + break; + } + break; + case 'F': + if (Switch[1]==0) + FreshFiles=true; + else + BadSwitch(Switch); + break; + case 'U': + if (Switch[1]==0) + UpdateFiles=true; + else + BadSwitch(Switch); + break; + case 'W': + strncpyz(TempPath,&Switch[1],ASIZE(TempPath)); + AddEndSlash(TempPath); + break; + case 'S': + if (IsDigit(Switch[1])) + { + Solid|=SOLID_COUNT; + SolidCount=atoi(&Switch[1]); + } + else + switch(etoupper(Switch[1])) + { + case 0: + Solid|=SOLID_NORMAL; + break; + case '-': + Solid=SOLID_NONE; + break; + case 'E': + Solid|=SOLID_FILEEXT; + break; + case 'V': + Solid|=Switch[2]=='-' ? SOLID_VOLUME_DEPENDENT:SOLID_VOLUME_INDEPENDENT; + break; + case 'D': + Solid|=SOLID_VOLUME_DEPENDENT; + break; + case 'L': + if (IsDigit(Switch[2])) + FileSizeLess=atoil(Switch+2); + break; + case 'M': + if (IsDigit(Switch[2])) + FileSizeMore=atoil(Switch+2); + break; + case 'C': + { + // Switch is already found bad, avoid reporting it several times. + bool AlreadyBad=false; + + RAR_CHARSET rch=RCH_DEFAULT; + switch(etoupper(Switch[2])) + { + case 'A': + rch=RCH_ANSI; + break; + case 'O': + rch=RCH_OEM; + break; + case 'U': + rch=RCH_UNICODE; + break; + default : + BadSwitch(Switch); + AlreadyBad=true; + break; + }; + if (!AlreadyBad) + if (Switch[3]==0) + CommentCharset=FilelistCharset=rch; + else + for (int I=3;Switch[I]!=0 && !AlreadyBad;I++) + switch(etoupper(Switch[I])) + { + case 'C': + CommentCharset=rch; + break; + case 'L': + FilelistCharset=rch; + break; + default: + BadSwitch(Switch); + AlreadyBad=true; + break; + } + } + break; + + } + 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 'B': + KeepBroken=true; + break; + case 0: + Lock=true; + break; + } + break; +#ifndef GUI + case '?' : + OutHelp(RARX_SUCCESS); + break; +#endif + default : + BadSwitch(Switch); + break; + } +} +#endif + + +#ifndef SFX_MODULE +void CommandData::BadSwitch(const char *Switch) +{ + mprintf(St(MUnknownOption),Switch); + ErrHandler.Exit(RARX_USERERROR); +} +#endif + + +#ifndef GUI +void CommandData::OutTitle() +{ + if (BareOutput || DisableCopyright) + return; +#if defined(__GNUC__) && defined(SFX_MODULE) + mprintf(St(MCopyrightS)); +#else +#ifndef SILENT + static bool TitleShown=false; + if (TitleShown) + return; + TitleShown=true; + char Version[50]; + int Beta=RARVER_BETA; + if (Beta!=0) + sprintf(Version,"%d.%02d %s %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA); + else + sprintf(Version,"%d.%02d",RARVER_MAJOR,RARVER_MINOR); +#ifdef UNRAR + mprintf(St(MUCopyright),Version,RARVER_YEAR); +#else +#endif +#endif +#endif +} +#endif + + +inline bool CmpMSGID(MSGID i1,MSGID i2) +{ +#ifdef MSGID_INT + return(i1==i2); +#else + // If MSGID is const char*, we cannot compare pointers only. + // Pointers to different instances of same strings can differ, + // so we need to compare complete strings. + return(strcmp(i1,i2)==0); +#endif +} + +void CommandData::OutHelp(RAR_EXIT ExitCode) +{ +#if !defined(GUI) && !defined(SILENT) + OutTitle(); + static MSGID Help[]={ +#ifdef SFX_MODULE + // Console SFX switches definition. + MCHelpCmd,MSHelpCmdE,MSHelpCmdT,MSHelpCmdV +#elif defined(UNRAR) + // UnRAR switches definition. + MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL, + MCHelpCmdP,MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,MCHelpSwm, + MCHelpSwAT,MCHelpSwAC,MCHelpSwAD,MCHelpSwAG,MCHelpSwAI,MCHelpSwAP, + MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU, + MCHelpSwDH,MCHelpSwEP,MCHelpSwEP3,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR, + MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwN,MCHelpSwNa,MCHelpSwNal, + MCHelpSwO,MCHelpSwOC,MCHelpSwOR,MCHelpSwOW,MCHelpSwP, + MCHelpSwPm,MCHelpSwR,MCHelpSwRI,MCHelpSwSL,MCHelpSwSM,MCHelpSwTA, + MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU,MCHelpSwVUnr, + MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal,MCHelpSwY +#else +#endif + }; + + for (int I=0;I<sizeof(Help)/sizeof(Help[0]);I++) + { +#ifndef SFX_MODULE +#ifdef DISABLEAUTODETECT + if (Help[I]==MCHelpSwV) + continue; +#endif +#ifndef _WIN_ALL + static MSGID Win32Only[]={ + MCHelpSwIEML,MCHelpSwVD,MCHelpSwAO,MCHelpSwOS,MCHelpSwIOFF, + MCHelpSwEP2,MCHelpSwOC,MCHelpSwDR,MCHelpSwRI + }; + bool Found=false; + for (int J=0;J<sizeof(Win32Only)/sizeof(Win32Only[0]);J++) + if (CmpMSGID(Help[I],Win32Only[J])) + { + Found=true; + break; + } + if (Found) + continue; +#endif +#if !defined(_UNIX) && !defined(_WIN_ALL) + if (CmpMSGID(Help[I],MCHelpSwOW)) + continue; +#endif +#if !defined(_WIN_ALL) && !defined(_EMX) + if (CmpMSGID(Help[I],MCHelpSwAC)) + continue; +#endif +#ifndef SAVE_LINKS + if (CmpMSGID(Help[I],MCHelpSwOL)) + continue; +#endif +#ifndef RAR_SMP + if (CmpMSGID(Help[I],MCHelpSwMT)) + continue; +#endif +#ifndef _BEOS + if (CmpMSGID(Help[I],MCHelpSwEE)) + { +#if defined(_EMX) && !defined(_DJGPP) + if (_osmode != OS2_MODE) + continue; +#else + continue; +#endif + } +#endif +#endif + mprintf(St(Help[I])); + } + mprintf("\n"); + ErrHandler.Exit(ExitCode); +#endif +} + + +// 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) +{ + 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) +{ + char *Name=ConvertPath(CheckName,NULL); + char FullName[NM]; + char 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); + bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only. + + if (Dir) + { + // CheckName is a directory. + if (DirMask) + { + // We process the directory and have the directory exclusion mask. + // So let's convert "mask\" to "mask" and process it normally. + + *LastMaskChar=0; + } + else + { + // If mask has wildcards in name part and does not have the trailing + // '\' character, we cannot use it for directories. + + if (IsWildcard(PointToName(CurMask))) + continue; + } + } + else + { + // If we process a file inside of directory excluded by "dirmask\". + // we want to exclude such file too. So we convert "dirmask\" to + // "dirmask\*". It is important for operations other than archiving. + // When archiving, directory matched by "dirmask\" is excluded + // from further scanning. + + if (DirMask) + strcat(CurMask,"*"); + } + +#ifndef SFX_MODULE + if (CheckFullPath && IsFullPath(CurMask)) + { + // We do not need to do the special "*\" processing here, because + // unlike the "else" part of this "if", now we convert names to full + // format, so they all include the path, which is matched by "*\" + // correctly. Moreover, removing "*\" from mask would break + // the comparison, because now all names have the path. + + if (*FullName==0) + ConvertNameToFull(CheckName,FullName); + if (CmpName(CurMask,FullName,MatchMode)) + return(true); + } + else +#endif + { + char NewName[NM+2],*CurName=Name; + if (CurMask[0]=='*' && IsPathDiv(CurMask[1])) + { + // We want "*\name" to match 'name' not only in subdirectories, + // but also in the current directory. We convert the name + // from 'name' to '.\name' to be matched by "*\" part even if it is + // in current directory. + NewName[0]='.'; + NewName[1]=CPATHDIVIDER; + strncpyz(NewName+2,Name,ASIZE(NewName)-2); + CurName=NewName; + } + + if (CmpName(ConvertPath(CurMask,NULL),CurName,MatchMode)) + return(true); + } + } + return(false); +} + + +#ifndef SFX_MODULE +// Now this function performs only one task and only in Windows version: +// it skips symlinks to directories if -e1024 switch is specified. +// Symlinks are skipped in ScanTree class, so their entire contents +// is skipped too. Without this function we would check the attribute +// only directly before archiving, so we would skip the symlink record, +// but not the contents of symlinked directory. +bool CommandData::ExclDirByAttr(uint FileAttr) +{ +#ifdef _WIN_ALL + if ((FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0 && + (ExclFileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0) + return true; +#endif + return false; +} +#endif + + + + +#ifndef SFX_MODULE +// Return 'true' if we need to exclude the file from processing. +bool CommandData::TimeCheck(RarTime &ft) +{ + if (FileTimeBefore.IsSet() && ft>=FileTimeBefore) + return(true); + if (FileTimeAfter.IsSet() && ft<=FileTimeAfter) + return(true); + return(false); +} +#endif + + +#ifndef SFX_MODULE +// Return 'true' if we need to exclude the file from processing. +bool CommandData::SizeCheck(int64 Size) +{ + if (FileSizeLess!=INT64NDF && Size>=FileSizeLess) + return(true); + if (FileSizeMore!=INT64NDF && Size<=FileSizeMore) + return(true); + return(false); +} +#endif + + + + +int CommandData::IsProcessFile(FileHeader &NewLhd,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); +#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); +#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)) + { + if (ExactMatch!=NULL) + *ExactMatch=stricompc(ArgName,NewLhd.FileName)==0; + return(StringCount); + } + } + return(0); +} + + +#ifndef GUI +void CommandData::ProcessCommand() +{ +#ifndef SFX_MODULE + + const char *SingleCharCommands="FUADPXETK"; + if (Command[0]!=0 && Command[1]!=0 && strchr(SingleCharCommands,*Command)!=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)); +#else + if (GetExt(ArcName)==NULL) + strncatz(ArcName,".rar",ASIZE(ArcName)); +#endif + + if (strchr("AFUMD",*Command)==NULL) + { + if (GenerateArcName) + GenerateArchiveName(ArcName,ArcNameW,ASIZE(ArcName),GenerateMask,false); + + StringList ArcMasks; + ArcMasks.AddString(ArcName); + ScanTree Scan(&ArcMasks,Recurse,SaveLinks,SCAN_SKIPDIRS); + FindData FindData; + while (Scan.GetNext(&FindData)==SCAN_SUCCESS) + AddArcName(FindData.Name,FindData.NameW); + } + else + AddArcName(ArcName,NULL); +#endif + + switch(Command[0]) + { + case 'P': + case 'X': + case 'E': + case 'T': + case 'I': + { + CmdExtract Extract; + Extract.DoExtract(this); + } + break; +#ifndef SILENT + case 'V': + case 'L': + ListArchive(this); + break; + default: + OutHelp(RARX_USERERROR); +#endif + } + if (!BareOutput) + mprintf("\n"); +} +#endif + + +void CommandData::AddArcName(const char *Name,const wchar *NameW) +{ + ArcNames->AddString(Name,NameW); +} + + +bool CommandData::GetArcName(char *Name,wchar *NameW,int MaxSize) +{ + if (!ArcNames->GetString(Name,NameW,NM)) + return(false); + return(true); +} + + +bool CommandData::IsSwitch(int Ch) +{ +#if defined(_WIN_ALL) || defined(_EMX) + return(Ch=='-' || Ch=='/'); +#else + return(Ch=='-'); +#endif +} + + +#ifndef SFX_MODULE +uint CommandData::GetExclAttr(const char *Str) +{ + if (IsDigit(*Str)) + return(strtol(Str,NULL,0)); + else + { + uint Attr; + for (Attr=0;*Str;Str++) + switch(etoupper(*Str)) + { +#ifdef _UNIX + 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; +#endif + } + return(Attr); + } +} +#endif + + + + +#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); + WinSize=0x400000; + return(false); +} +#endif diff --git a/src/thirdparty/unrar/cmddata.hpp b/src/thirdparty/unrar/cmddata.hpp new file mode 100644 index 000000000..aef6deb3b --- /dev/null +++ b/src/thirdparty/unrar/cmddata.hpp @@ -0,0 +1,64 @@ +#ifndef _RAR_CMDDATA_ +#define _RAR_CMDDATA_ + + +#define DefaultStoreList "7z;ace;arj;bz2;cab;gz;jpeg;jpg;lha;lzh;mp3;rar;taz;tgz;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); + + bool FileLists; + bool NoMoreSwitches; + RAR_CMD_LIST_MODE ListMode; + 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 ParseDone(); + void ParseEnvVar(); + void ReadConfig(); + bool PreprocessSwitch(const char *Switch); + void OutTitle(); + void OutHelp(RAR_EXIT ExitCode); + bool IsSwitch(int Ch); + bool ExclCheck(char *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); + void ProcessCommand(); + void AddArcName(const char *Name,const wchar *NameW); + bool GetArcName(char *Name,wchar *NameW,int MaxSize); + bool CheckWinSize(); + + int GetRecoverySize(const char *Str,int DefSize); + + char Command[NM+16]; + wchar CommandW[NM+16]; + + char ArcName[NM]; + wchar ArcNameW[NM]; + + StringList *FileArgs; + StringList *ExclArgs; + StringList *InclArgs; + StringList *ArcNames; + StringList *StoreArgs; +}; + +#endif diff --git a/src/thirdparty/unrar/coder.cpp b/src/thirdparty/unrar/coder.cpp new file mode 100644 index 000000000..9d971a8ad --- /dev/null +++ b/src/thirdparty/unrar/coder.cpp @@ -0,0 +1,48 @@ + + +inline unsigned int RangeCoder::GetChar() +{ + return(UnpackRead->GetChar()); +} + + +void RangeCoder::InitDecoder(Unpack *UnpackRead) +{ + RangeCoder::UnpackRead=UnpackRead; + + low=code=0; + range=uint(-1); + for (int i=0;i < 4;i++) + code=(code << 8) | GetChar(); +} + + +// (int) cast before "low" added only to suppress compiler warnings. +#define ARI_DEC_NORMALIZE(code,low,range,read) \ +{ \ + while ((low^(low+range))<TOP || range<BOT && ((range=-(int)low&(BOT-1)),1)) \ + { \ + code=(code << 8) | read->GetChar(); \ + range <<= 8; \ + low <<= 8; \ + } \ +} + + +inline int RangeCoder::GetCurrentCount() +{ + return (code-low)/(range /= SubRange.scale); +} + + +inline uint RangeCoder::GetCurrentShiftCount(uint SHIFT) +{ + return (code-low)/(range >>= SHIFT); +} + + +inline void RangeCoder::Decode() +{ + low += range*SubRange.LowCount; + range *= SubRange.HighCount-SubRange.LowCount; +} diff --git a/src/thirdparty/unrar/coder.hpp b/src/thirdparty/unrar/coder.hpp new file mode 100644 index 000000000..0c8156c44 --- /dev/null +++ b/src/thirdparty/unrar/coder.hpp @@ -0,0 +1,25 @@ +/**************************************************************************** + * Contents: 'Carryless rangecoder' by Dmitry Subbotin * + ****************************************************************************/ + +const uint TOP=1 << 24, BOT=1 << 15; + + +class RangeCoder +{ + public: + void InitDecoder(Unpack *UnpackRead); + inline int GetCurrentCount(); + inline uint GetCurrentShiftCount(uint SHIFT); + inline void Decode(); + inline void PutChar(unsigned int c); + inline unsigned int GetChar(); + + uint low, code, range; + struct SUBRANGE + { + uint LowCount, HighCount, scale; + } SubRange; + + Unpack *UnpackRead; +}; diff --git a/src/thirdparty/unrar/compress.hpp b/src/thirdparty/unrar/compress.hpp new file mode 100644 index 000000000..3157e1a3b --- /dev/null +++ b/src/thirdparty/unrar/compress.hpp @@ -0,0 +1,40 @@ +#ifndef _RAR_COMPRESS_ +#define _RAR_COMPRESS_ + +class ComprDataIO; +class PackingFileTable; + +#define MAX_LZ_MATCH 0x101 + +#define MAXWINSIZE 0x400000 +#define MAXWINMASK (MAXWINSIZE-1) + +#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 HUFF_TABLE_SIZE (NC+DC+RC+LDC) +#define BC 20 + +#define NC20 298 /* alphabet = {0, 1, 2, ..., NC - 1} */ +#define DC20 48 +#define RC20 28 +#define BC20 19 +#define MC20 257 + +// Largest alphabet size among all values listed above. +#define LARGEST_TABLE_SIZE 299 + +enum {CODE_HUFFMAN,CODE_LZ,CODE_LZ2,CODE_REPEATLZ,CODE_CACHELZ, + CODE_STARTFILE,CODE_ENDFILE,CODE_VM,CODE_VMDATA}; + + +enum FilterType { + FILTER_NONE, FILTER_PPM /*dummy*/, FILTER_E8, FILTER_E8E9, + FILTER_UPCASETOLOW, FILTER_AUDIO, FILTER_RGB, FILTER_DELTA, + FILTER_ITANIUM, FILTER_E8E9V2 +}; + +#endif diff --git a/src/thirdparty/unrar/consio.cpp b/src/thirdparty/unrar/consio.cpp new file mode 100644 index 000000000..42b72a617 --- /dev/null +++ b/src/thirdparty/unrar/consio.cpp @@ -0,0 +1,319 @@ +#include "rar.hpp" + +#ifndef GUI +#include "log.cpp" +#endif + +static int KbdAnsi(char *Addr,int Size); + +#if !defined(GUI) && !defined(SILENT) +static void RawPrint(char *Msg,MESSAGE_TYPE MessageType); +static byte GetKey(); +#endif + +static MESSAGE_TYPE MsgStream=MSG_STDOUT; +static bool Sound=false; +const int MaxMsgSize=2*NM+2048; + +void InitConsoleOptions(MESSAGE_TYPE MsgStream,bool Sound) +{ + ::MsgStream=MsgStream; + ::Sound=Sound; +} + +#if !defined(GUI) && !defined(SILENT) +void mprintf(const char *fmt,...) +{ + if (MsgStream==MSG_NULL || MsgStream==MSG_ERRONLY) + 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); +} +#endif + + +#if !defined(GUI) && !defined(SILENT) +void eprintf(const char *fmt,...) +{ + if (MsgStream==MSG_NULL) + 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); +} +#endif + + +#if !defined(GUI) && !defined(SILENT) +void RawPrint(char *Msg,MESSAGE_TYPE MessageType) +{ + 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); + + 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 + + OutFile.Write(Msg,strlen(Msg)); +} +#endif + + +#ifndef SILENT +void Alarm() +{ +#ifndef SFX_MODULE + if (Sound) + putchar('\007'); +#endif +} +#endif + + +#ifndef SILENT +#ifndef GUI +void GetPasswordText(wchar *Str,uint MaxLength) +{ + if (MaxLength==0) + return; +#ifdef _WIN_ALL + HANDLE hConIn=GetStdHandle(STD_INPUT_HANDLE); + HANDLE hConOut=GetStdHandle(STD_OUTPUT_HANDLE); + DWORD ConInMode,ConOutMode; + DWORD Read=0; + GetConsoleMode(hConIn,&ConInMode); + GetConsoleMode(hConOut,&ConOutMode); + SetConsoleMode(hConIn,ENABLE_LINE_INPUT); + SetConsoleMode(hConOut,ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT); + + ReadConsoleW(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) + fgets(StrA,ASIZE(StrA)-1,stdin); +#else + strncpyz(StrA,getpass(""),ASIZE(StrA)); +#endif + CharToWide(StrA,Str,MaxLength); + cleandata(StrA,sizeof(StrA)); +#endif + Str[MaxLength-1]=0; + RemoveLF(Str); +} +#endif +#endif + + +#ifndef SILENT +bool GetPassword(PASSWORD_TYPE Type,const char *FileName,const wchar *FileNameW, + 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); + + wchar PlainPsw[MAXPASSWORD]; + GetPasswordText(PlainPsw,ASIZE(PlainPsw)); + if (*PlainPsw==0 && Type==PASSWORD_GLOBAL) + return(false); + if (Type==PASSWORD_GLOBAL) + { + eprintf(St(MReAskPsw)); + wchar CmpStr[MAXPASSWORD]; + GetPasswordText(CmpStr,ASIZE(CmpStr)); + if (*CmpStr==0 || wcscmp(PlainPsw,CmpStr)!=0) + { + eprintf(St(MNotMatchPsw)); + cleandata(PlainPsw,sizeof(PlainPsw)); + cleandata(CmpStr,sizeof(CmpStr)); + continue; + } + cleandata(CmpStr,sizeof(CmpStr)); + } + Password->Set(PlainPsw); + cleandata(PlainPsw,sizeof(PlainPsw)); + break; + } + return(true); +} +#endif + + +#if !defined(GUI) && !defined(SILENT) +byte GetKey() +{ + 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) + { + // Looks like stdin is a null device. We can enter to infinite loop + // calling Ask(), so let's better exit. + ErrHandler.Exit(RARX_USERBREAK); + } + return (byte)Str[0]; +} +#endif + + +#if !defined(GUI) && !defined(SILENT) +int Ask(const char *AskStr) +{ + const int MaxItems=10; + char Item[MaxItems][40]; + int ItemKeyPos[MaxItems],NumItems=0; + + for (const char *NextItem=AskStr;NextItem!=NULL;NextItem=strchr(NextItem+1,'_')) + { + char *CurItem=Item[NumItems]; + strncpyz(CurItem,NextItem+1,ASIZE(Item[0])); + char *EndItem=strchr(CurItem,'_'); + if (EndItem!=NULL) + *EndItem=0; + int KeyPos=0,CurKey; + while ((CurKey=CurItem[KeyPos])!=0) + { + bool Found=false; + for (int I=0;I<NumItems && !Found;I++) + if (loctoupper(Item[I][ItemKeyPos[I]])==loctoupper(CurKey)) + Found=true; + if (!Found && CurKey!=' ') + break; + KeyPos++; + } + ItemKeyPos[NumItems]=KeyPos; + NumItems++; + } + + for (int I=0;I<NumItems;I++) + { + eprintf(I==0 ? (NumItems>4 ? "\n":" "):", "); + 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(" "); + byte Ch=GetKey(); +#if defined(_WIN_ALL) + OemToCharBuffA((LPCSTR)&Ch,(LPSTR)&Ch,1); +#endif + Ch=loctoupper(Ch); + for (int I=0;I<NumItems;I++) + if (Ch==(byte)Item[I][ItemKeyPos[I]]) + return(I+1); + return(0); +} +#endif + + +int KbdAnsi(char *Addr,size_t Size) +{ + int RetCode=0; +#ifndef GUI + for (size_t I=0;I<Size;I++) + if (Addr[I]==27 && Addr[I+1]=='[') + { + for (size_t J=I+2;J<Size;J++) + { + if (Addr[J]=='\"') + return(2); + if (!IsDigit(Addr[J]) && Addr[J]!=';') + break; + } + RetCode=1; + } +#endif + return(RetCode); +} + + +void OutComment(char *Comment,size_t Size) +{ +#ifndef GUI + if (KbdAnsi(Comment,Size)==2) + return; + const size_t MaxOutSize=0x400; + for (size_t I=0;I<Size;I+=MaxOutSize) + { + char Msg[MaxOutSize+1]; + size_t CopySize=Min(MaxOutSize,Size-I); + strncpy(Msg,Comment+I,CopySize); + Msg[CopySize]=0; + mprintf("%s",Msg); + } + mprintf("\n"); +#endif +} diff --git a/src/thirdparty/unrar/consio.hpp b/src/thirdparty/unrar/consio.hpp new file mode 100644 index 000000000..45489c39f --- /dev/null +++ b/src/thirdparty/unrar/consio.hpp @@ -0,0 +1,37 @@ +#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 InitConsoleOptions(MESSAGE_TYPE MsgStream,bool Sound); + +#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); +#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 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);} +#endif + +#endif diff --git a/src/thirdparty/unrar/crc.cpp b/src/thirdparty/unrar/crc.cpp new file mode 100644 index 000000000..26590fda1 --- /dev/null +++ b/src/thirdparty/unrar/crc.cpp @@ -0,0 +1,91 @@ +// This CRC function is based on Intel Slicing-by-8 algorithm. +// +// Original Intel Slicing-by-8 code is available here: +// +// http://sourceforge.net/projects/slicing-by-8/ +// +// Original Intel Slicing-by-8 code is licensed as: +// +// Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved +// +// This software program is licensed subject to the BSD License, +// available at http://www.opensource.org/licenses/bsd-license.html + + +#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() +{ + for (uint I=0;I<256;I++) // Build the classic CRC32 lookup table. + { + 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; + } + + for (uint I=0;I<=256;I++) // Build additional lookup tables. + { + uint C=crc_tables[0][I]; + for (uint J=1;J<8;J++) + { + C=crc_tables[0][(byte)C]^(C>>8); + crc_tables[J][I]=C; + } + } +} + + +uint CRC(uint StartCRC,const void *Addr,size_t Size) +{ + if (CRCTab[1]==0) + InitCRC(); + byte *Data=(byte *)Addr; + + // Align Data to 8 for better performance. + for (;Size>0 && ((long)Data & 7);Size--,Data++) + StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8); + + for (;Size>=8;Size-=8,Data+=8) + { +#ifdef BIG_ENDIAN + StartCRC ^= Data[0]|(Data[1] << 8)|(Data[2] << 16)|(Data[3] << 24); +#else + StartCRC ^= *(uint32 *) Data; +#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]]; + } + + for (;Size>0;Size--,Data++) // Process left data. + StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8); + + 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) +{ + byte *Data=(byte *)Addr; + for (size_t I=0;I<Size;I++) + { + StartCRC=(StartCRC+Data[I])&0xffff; + StartCRC=((StartCRC<<1)|(StartCRC>>15))&0xffff; + } + return(StartCRC); +} +#endif diff --git a/src/thirdparty/unrar/crc.hpp b/src/thirdparty/unrar/crc.hpp new file mode 100644 index 000000000..196a7e6ab --- /dev/null +++ b/src/thirdparty/unrar/crc.hpp @@ -0,0 +1,8 @@ +#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); + +#endif diff --git a/src/thirdparty/unrar/crypt.cpp b/src/thirdparty/unrar/crypt.cpp new file mode 100644 index 000000000..5cc5aefbf --- /dev/null +++ b/src/thirdparty/unrar/crypt.cpp @@ -0,0 +1,387 @@ +#include "rar.hpp" + +#ifndef SFX_MODULE +extern uint CRCTab[256]; +#endif + +#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) +{ + rin.blockDecrypt(Buf,Size,Buf); +} + + +#ifndef SFX_MODULE +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))^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); +} + + +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) +{ + for (int I=0;I<16;I+=4) + { + Key[0]^=CRCTab[Buf[I]]; + Key[1]^=CRCTab[Buf[I+1]]; + Key[2]^=CRCTab[Buf[I+2]]; + Key[3]^=CRCTab[Buf[I+3]]; + } +} + + +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) +{ + if (!Password->IsSet()) + 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); + + 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; + } + + 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) + { + 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++; + } +} + + +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) +{ + 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--) + { + PN2+=PN3; + PN1+=PN2; + *Data+=PN1; + Data++; + } +} + + +void CryptData::Decode13(byte *Data,uint Count) +{ + while (Count--) + { + PN2+=PN3; + PN1+=PN2; + *Data-=PN1; + Data++; + } +} + + +void CryptData::Crypt15(byte *Data,uint Count) +{ + while (Count--) + { + 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++; + } +} +#endif + + diff --git a/src/thirdparty/unrar/crypt.hpp b/src/thirdparty/unrar/crypt.hpp new file mode 100644 index 000000000..96b8a27f1 --- /dev/null +++ b/src/thirdparty/unrar/crypt.hpp @@ -0,0 +1,62 @@ +#ifndef _RAR_CRYPT_ +#define _RAR_CRYPT_ + +enum { OLD_DECODE=0,OLD_ENCODE=1,NEW_CRYPT=2 }; + + +struct CryptKeyCacheItem +{ +#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; +}; + +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); + + Rijndael rin; + + byte SubstTable[256]; + uint Key[4]; + ushort OldKey[4]; + byte PN1,PN2,PN3; + + byte AESKey[16],AESInit[16]; + + static CryptKeyCacheItem Cache[4]; + static int CachePos; + public: + void SetCryptKeys(SecPassword *Password,const byte *Salt,bool Encrypt,bool OldOnly,bool HandsOffHash); + 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); +}; + +#endif diff --git a/src/thirdparty/unrar/dll.cpp b/src/thirdparty/unrar/dll.cpp new file mode 100644 index 000000000..535656caf --- /dev/null +++ b/src/thirdparty/unrar/dll.cpp @@ -0,0 +1,375 @@ +#include "rar.hpp" +#include "dll.hpp" + +static int RarErrorToDll(RAR_EXIT ErrCode); + +struct DataSet +{ + CommandData Cmd; + CmdExtract Extract; + Archive Arc; + int OpenMode; + int HeaderSize; + + DataSet():Arc(&Cmd) {}; +}; + + +HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *r) +{ + RAROpenArchiveDataEx rx; + memset(&rx,0,sizeof(rx)); + rx.ArcName=r->ArcName; + rx.OpenMode=r->OpenMode; + rx.CmtBuf=r->CmtBuf; + rx.CmtBufSize=r->CmtBufSize; + HANDLE hArc=RAROpenArchiveEx(&rx); + r->OpenResult=rx.OpenResult; + r->CmtSize=rx.CmtSize; + r->CmtState=rx.CmtState; + return(hArc); +} + + +HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r) +{ + DataSet *Data=NULL; + try + { + r->OpenResult=0; + Data=new DataSet; + Data->Cmd.DllError=0; + Data->OpenMode=r->OpenMode; + Data->Cmd.FileArgs->AddString("*"); + + char an[NM]; + if (r->ArcName==NULL && r->ArcNameW!=NULL) + { + WideToChar(r->ArcNameW,an,NM); + r->ArcName=an; + } + + Data->Cmd.AddArcName(r->ArcName,r->ArcNameW); + 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)) + { + r->OpenResult=ERAR_EOPEN; + delete Data; + return(NULL); + } + if (!Data->Arc.IsArchive(false)) + { + r->OpenResult=Data->Cmd.DllError!=0 ? Data->Cmd.DllError:ERAR_BAD_ARCHIVE; + delete Data; + return(NULL); + } + r->Flags=Data->Arc.NewMhd.Flags; + Array<byte> CmtData; + if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtData,NULL)) + { + 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); + if (Size<=r->CmtBufSize) + r->CmtBuf[r->CmtSize-1]=0; + } + else + r->CmtState=r->CmtSize=0; + if (Data->Arc.Signed) + r->Flags|=0x20; + Data->Extract.ExtractArchiveInit(&Data->Cmd,Data->Arc); + return((HANDLE)Data); + } + catch (RAR_EXIT ErrCode) + { + if (Data!=NULL && Data->Cmd.DllError!=0) + r->OpenResult=Data->Cmd.DllError; + else + r->OpenResult=RarErrorToDll(ErrCode); + if (Data != NULL) + delete Data; + return(NULL); + } + catch (std::bad_alloc) // Catch 'new' exception. + { + r->OpenResult=ERAR_NO_MEMORY; + if (Data != NULL) + delete Data; + } +} + + +int PASCAL RARCloseArchive(HANDLE hArcData) +{ + DataSet *Data=(DataSet *)hArcData; + bool Success=Data==NULL ? false:Data->Arc.Close(); + delete Data; + return(Success ? 0:ERAR_ECLOSE); +} + + +int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *D) +{ + struct RARHeaderDataEx X; + memset(&X,0,sizeof(X)); + + int Code=RARReadHeaderEx(hArcData,&X); + + strncpyz(D->ArcName,X.ArcName,ASIZE(D->ArcName)); + strncpyz(D->FileName,X.FileName,ASIZE(D->FileName)); + D->Flags=X.Flags; + D->PackSize=X.PackSize; + D->UnpSize=X.UnpSize; + D->HostOS=X.HostOS; + D->FileCRC=X.FileCRC; + D->FileTime=X.FileTime; + D->UnpVer=X.UnpVer; + D->Method=X.Method; + D->FileAttr=X.FileAttr; + D->CmtSize=0; + D->CmtState=0; + + return Code; +} + + +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->Arc.Volume && Data->Arc.GetHeaderType()==ENDARC_HEAD && + (Data->Arc.EndArcHead.Flags & EARC_NEXT_VOLUME)) + if (MergeArchive(Data->Arc,NULL,false,'L')) + { + Data->Extract.SignatureFound=false; + Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET); + return(RARReadHeaderEx(hArcData,D)); + } + else + return(ERAR_EOPEN); + return(Data->Arc.BrokenFileHeader ? ERAR_BAD_DATA:ERAR_END_ARCHIVE); + } + if (Data->OpenMode==RAR_OM_LIST && (Data->Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)!=0) + { + int Code=RARProcessFile(hArcData,RAR_SKIP,NULL,NULL); + if (Code==0) + return(RARReadHeaderEx(hArcData,D)); + else + 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 + { +#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; +#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->CmtSize=0; + D->CmtState=0; + } + catch (RAR_EXIT ErrCode) + { + return(Data->Cmd.DllError!=0 ? Data->Cmd.DllError:RarErrorToDll(ErrCode)); + } + return(0); +} + + +int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName,wchar *DestPathW,wchar *DestNameW) +{ + DataSet *Data=(DataSet *)hArcData; + try + { + Data->Cmd.DllError=0; + 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 (MergeArchive(Data->Arc,NULL,false,'L')) + { + Data->Extract.SignatureFound=false; + Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET); + return(0); + } + else + return(ERAR_EOPEN); + Data->Arc.SeekToNext(); + } + else + { + Data->Cmd.DllOpMode=Operation; + + if (DestPath!=NULL || DestName!=NULL) + { +#ifdef _WIN_ALL + OemToCharA(NullToEmpty(DestPath),Data->Cmd.ExtrPath); +#else + strcpy(Data->Cmd.ExtrPath,NullToEmpty(DestPath)); +#endif + AddEndSlash(Data->Cmd.ExtrPath); +#ifdef _WIN_ALL + OemToCharA(NullToEmpty(DestName),Data->Cmd.DllDestName); +#else + strcpy(Data->Cmd.DllDestName,NullToEmpty(DestName)); +#endif + } + 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 + { + *Data->Cmd.ExtrPathW=0; + *Data->Cmd.DllDestNameW=0; + } + + strcpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? "X":"T"); + Data->Cmd.Test=Operation!=RAR_EXTRACT; + bool Repeat=false; + Data->Extract.ExtractCurrentFile(&Data->Cmd,Data->Arc,Data->HeaderSize,Repeat); + + // Now we process extra file information if any. + // + // Archive can be closed if we process volumes, next volume is missing + // and current one is already removed or deleted. So we need to check + // if archive is still open to avoid calling file operations on + // 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->Extract.ExtractCurrentFile(&Data->Cmd,Data->Arc,Data->HeaderSize,Repeat); + Data->Arc.SeekToNext(); + } + Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET); + } + } + catch (RAR_EXIT ErrCode) + { + return(Data->Cmd.DllError!=0 ? Data->Cmd.DllError:RarErrorToDll(ErrCode)); + } + return(Data->Cmd.DllError); +} + + +int PASCAL RARProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName) +{ + return(ProcessFile(hArcData,Operation,DestPath,DestName,NULL,NULL)); +} + + +int PASCAL RARProcessFileW(HANDLE hArcData,int Operation,wchar *DestPath,wchar *DestName) +{ + return(ProcessFile(hArcData,Operation,NULL,NULL,DestPath,DestName)); +} + + +void PASCAL RARSetChangeVolProc(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc) +{ + DataSet *Data=(DataSet *)hArcData; + Data->Cmd.ChangeVolProc=ChangeVolProc; +} + + +void PASCAL RARSetCallback(HANDLE hArcData,UNRARCALLBACK Callback,LPARAM UserData) +{ + DataSet *Data=(DataSet *)hArcData; + Data->Cmd.Callback=Callback; + Data->Cmd.UserData=UserData; +} + + +void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc) +{ + DataSet *Data=(DataSet *)hArcData; + Data->Cmd.ProcessDataProc=ProcessDataProc; +} + + +#ifndef RAR_NOCRYPT +void PASCAL RARSetPassword(HANDLE hArcData,char *Password) +{ + DataSet *Data=(DataSet *)hArcData; + wchar PasswordW[MAXPASSWORD]; + GetWideName(Password,NULL,PasswordW,ASIZE(PasswordW)); + Data->Cmd.Password.Set(PasswordW); + cleandata(PasswordW,sizeof(PasswordW)); +} +#endif + + +int PASCAL RARGetDllVersion() +{ + return(RAR_DLL_VERSION); +} + + +static int RarErrorToDll(RAR_EXIT ErrCode) +{ + switch(ErrCode) + { + case RARX_FATAL: + return(ERAR_EREAD); + case RARX_CRC: + return(ERAR_BAD_DATA); + case RARX_WRITE: + return(ERAR_EWRITE); + case RARX_OPEN: + return(ERAR_EOPEN); + case RARX_CREATE: + return(ERAR_ECREATE); + case RARX_MEMORY: + return(ERAR_NO_MEMORY); + case RARX_SUCCESS: + return(0); + default: + return(ERAR_UNKNOWN); + } +} diff --git a/src/thirdparty/unrar/dll.def b/src/thirdparty/unrar/dll.def new file mode 100644 index 000000000..660f69bf6 --- /dev/null +++ b/src/thirdparty/unrar/dll.def @@ -0,0 +1,12 @@ +EXPORTS
+ RAROpenArchive
+ RAROpenArchiveEx
+ RARCloseArchive
+ RARReadHeader
+ RARReadHeaderEx
+ RARProcessFile
+ RARSetCallback
+ RARSetChangeVolProc
+ RARSetProcessDataProc
+ RARSetPassword
+ RARGetDllVersion
diff --git a/src/thirdparty/unrar/dll.hpp b/src/thirdparty/unrar/dll.hpp new file mode 100644 index 000000000..1d929bece --- /dev/null +++ b/src/thirdparty/unrar/dll.hpp @@ -0,0 +1,147 @@ +#ifndef _UNRAR_DLL_ +#define _UNRAR_DLL_ + +#pragma pack(1) + +#define ERAR_END_ARCHIVE 10 +#define ERAR_NO_MEMORY 11 +#define ERAR_BAD_DATA 12 +#define ERAR_BAD_ARCHIVE 13 +#define ERAR_UNKNOWN_FORMAT 14 +#define ERAR_EOPEN 15 +#define ERAR_ECREATE 16 +#define ERAR_ECLOSE 17 +#define ERAR_EREAD 18 +#define ERAR_EWRITE 19 +#define ERAR_SMALL_BUF 20 +#define ERAR_UNKNOWN 21 +#define ERAR_MISSING_PASSWORD 22 + +#define RAR_OM_LIST 0 +#define RAR_OM_EXTRACT 1 +#define RAR_OM_LIST_INCSPLIT 2 + +#define RAR_SKIP 0 +#define RAR_TEST 1 +#define RAR_EXTRACT 2 + +#define RAR_VOL_ASK 0 +#define RAR_VOL_NOTIFY 1 + +#define RAR_DLL_VERSION 5 + +#ifdef _UNIX +#define CALLBACK +#define PASCAL +#define LONG long +#define HANDLE void * +#define LPARAM long +#define UINT unsigned int +#endif + +struct RARHeaderData +{ + char ArcName[260]; + char FileName[260]; + unsigned int Flags; + unsigned int PackSize; + unsigned int UnpSize; + unsigned int HostOS; + unsigned int FileCRC; + unsigned int FileTime; + unsigned int UnpVer; + unsigned int Method; + unsigned int FileAttr; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; +}; + + +struct RARHeaderDataEx +{ + char ArcName[1024]; + wchar_t ArcNameW[1024]; + char FileName[1024]; + wchar_t FileNameW[1024]; + unsigned int Flags; + unsigned int PackSize; + unsigned int PackSizeHigh; + unsigned int UnpSize; + unsigned int UnpSizeHigh; + unsigned int HostOS; + unsigned int FileCRC; + unsigned int FileTime; + unsigned int UnpVer; + unsigned int Method; + unsigned int FileAttr; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; + unsigned int Reserved[1024]; +}; + + +struct RAROpenArchiveData +{ + char *ArcName; + unsigned int OpenMode; + unsigned int OpenResult; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; +}; + +typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2); + +struct RAROpenArchiveDataEx +{ + char *ArcName; + wchar_t *ArcNameW; + unsigned int OpenMode; + unsigned int OpenResult; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; + unsigned int Flags; + UNRARCALLBACK Callback; + LPARAM UserData; + unsigned int Reserved[28]; +}; + +enum UNRARCALLBACK_MESSAGES { + UCM_CHANGEVOLUME,UCM_PROCESSDATA,UCM_NEEDPASSWORD,UCM_CHANGEVOLUMEW, + UCM_NEEDPASSWORDW +}; + +typedef int (PASCAL *CHANGEVOLPROC)(char *ArcName,int Mode); +typedef int (PASCAL *PROCESSDATAPROC)(unsigned char *Addr,int Size); + +#ifdef __cplusplus +extern "C" { +#endif + +HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *ArchiveData); +HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *ArchiveData); +int PASCAL RARCloseArchive(HANDLE hArcData); +int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *HeaderData); +int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *HeaderData); +int PASCAL RARProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName); +int PASCAL RARProcessFileW(HANDLE hArcData,int Operation,wchar_t *DestPath,wchar_t *DestName); +void PASCAL RARSetCallback(HANDLE hArcData,UNRARCALLBACK Callback,LPARAM UserData); +void PASCAL RARSetChangeVolProc(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc); +void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc); +void PASCAL RARSetPassword(HANDLE hArcData,char *Password); +int PASCAL RARGetDllVersion(); + +#ifdef __cplusplus +} +#endif + +#pragma pack() + +#endif diff --git a/src/thirdparty/unrar/dll.rc b/src/thirdparty/unrar/dll.rc new file mode 100644 index 000000000..7a93039ad --- /dev/null +++ b/src/thirdparty/unrar/dll.rc @@ -0,0 +1,28 @@ +#include <windows.h>
+#include <commctrl.h>
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION 4, 20, 100, 526 +PRODUCTVERSION 4, 20, 100, 526 +FILEOS VOS__WINDOWS32
+FILETYPE VFT_APP
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904E4"
+ {
+ 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 "OriginalFilename", "Unrar.dll\0"
+ }
+ }
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0, 0
+ }
+}
+
diff --git a/src/thirdparty/unrar/encname.cpp b/src/thirdparty/unrar/encname.cpp new file mode 100644 index 000000000..4e42a759b --- /dev/null +++ b/src/thirdparty/unrar/encname.cpp @@ -0,0 +1,57 @@ +#include "rar.hpp" + +EncodeFileName::EncodeFileName() +{ + Flags=0; + FlagBits=0; + FlagsPos=0; + DestSize=0; +} + + + + +void EncodeFileName::Decode(char *Name,byte *EncName,size_t EncSize,wchar *NameW, + size_t MaxDecSize) +{ + size_t EncPos=0,DecPos=0; + byte HighByte=EncName[EncPos++]; + while (EncPos<EncSize && DecPos<MaxDecSize) + { + if (FlagBits==0) + { + Flags=EncName[EncPos++]; + FlagBits=8; + } + switch(Flags>>6) + { + case 0: + NameW[DecPos++]=EncName[EncPos++]; + break; + case 1: + NameW[DecPos++]=EncName[EncPos++]+(HighByte<<8); + break; + case 2: + NameW[DecPos++]=EncName[EncPos]+(EncName[EncPos+1]<<8); + EncPos+=2; + break; + case 3: + { + int Length=EncName[EncPos++]; + if (Length & 0x80) + { + byte Correction=EncName[EncPos++]; + for (Length=(Length&0x7f)+2;Length>0 && DecPos<MaxDecSize;Length--,DecPos++) + NameW[DecPos]=((Name[DecPos]+Correction)&0xff)+(HighByte<<8); + } + else + for (Length+=2;Length>0 && DecPos<MaxDecSize;Length--,DecPos++) + NameW[DecPos]=Name[DecPos]; + } + break; + } + Flags<<=2; + FlagBits-=2; + } + NameW[DecPos<MaxDecSize ? DecPos:MaxDecSize-1]=0; +} diff --git a/src/thirdparty/unrar/encname.hpp b/src/thirdparty/unrar/encname.hpp new file mode 100644 index 000000000..3e7786f54 --- /dev/null +++ b/src/thirdparty/unrar/encname.hpp @@ -0,0 +1,20 @@ +#ifndef _RAR_ENCNAME_ +#define _RAR_ENCNAME_ + +class EncodeFileName +{ + private: + void AddFlags(int Value); + + byte *EncName; + byte Flags; + uint FlagBits; + size_t FlagsPos; + size_t DestSize; + public: + EncodeFileName(); + size_t Encode(char *Name,wchar *NameW,byte *EncName); + void Decode(char *Name,byte *EncName,size_t EncSize,wchar *NameW,size_t MaxDecSize); +}; + +#endif diff --git a/src/thirdparty/unrar/errhnd.cpp b/src/thirdparty/unrar/errhnd.cpp new file mode 100644 index 000000000..9323518b8 --- /dev/null +++ b/src/thirdparty/unrar/errhnd.cpp @@ -0,0 +1,405 @@ +#include "rar.hpp" + + +static bool UserBreak; + +ErrorHandler::ErrorHandler() +{ + Clean(); +} + + +void ErrorHandler::Clean() +{ + ExitCode=RARX_SUCCESS; + ErrCount=0; + EnableBreak=true; + Silent=false; + DoShutdown=false; +} + + +void ErrorHandler::MemoryError() +{ + MemoryErrorMsg(); + Throw(RARX_MEMORY); +} + + +void ErrorHandler::OpenError(const char *FileName,const wchar *FileNameW) +{ +#ifndef SILENT + OpenErrorMsg(FileName); + Throw(RARX_OPEN); +#endif +} + + +void ErrorHandler::CloseError(const char *FileName,const wchar *FileNameW) +{ +#ifndef SILENT + if (!UserBreak) + { + ErrMsg(NULL,St(MErrFClose),FileName); + SysErrMsg(); + } +#endif +#if !defined(SILENT) || defined(RARDLL) + Throw(RARX_FATAL); +#endif +} + + +void ErrorHandler::ReadError(const char *FileName,const wchar *FileNameW) +{ +#ifndef SILENT + ReadErrorMsg(NULL,NULL,FileName,FileNameW); +#endif +#if !defined(SILENT) || defined(RARDLL) + Throw(RARX_FATAL); +#endif +} + + +bool ErrorHandler::AskRepeatRead(const char *FileName,const wchar *FileNameW) +{ +#if !defined(SILENT) && !defined(SFX_MODULE) && !defined(_WIN_CE) + if (!Silent) + { + SysErrMsg(); + mprintf("\n"); + Log(NULL,St(MErrRead),FileName); + return(Ask(St(MRetryAbort))==1); + } +#endif + return(false); +} + + +void ErrorHandler::WriteError(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW) +{ +#ifndef SILENT + WriteErrorMsg(ArcName,ArcNameW,FileName,FileNameW); +#endif +#if !defined(SILENT) || defined(RARDLL) + Throw(RARX_WRITE); +#endif +} + + +#ifdef _WIN_ALL +void ErrorHandler::WriteErrorFAT(const char *FileName,const wchar *FileNameW) +{ +#if !defined(SILENT) && !defined(SFX_MODULE) + SysErrMsg(); + ErrMsg(NULL,St(MNTFSRequired),FileName); +#endif +#if !defined(SILENT) && !defined(SFX_MODULE) || defined(RARDLL) + Throw(RARX_WRITE); +#endif +} +#endif + + +bool ErrorHandler::AskRepeatWrite(const char *FileName,const wchar *FileNameW,bool DiskFull) +{ +#if !defined(SILENT) && !defined(_WIN_CE) + if (!Silent) + { + SysErrMsg(); + mprintf("\n"); + Log(NULL,St(DiskFull ? MNotEnoughDisk:MErrWrite),FileName); + return(Ask(St(MRetryAbort))==1); + } +#endif + return(false); +} + + +void ErrorHandler::SeekError(const char *FileName,const wchar *FileNameW) +{ +#ifndef SILENT + if (!UserBreak) + { + ErrMsg(NULL,St(MErrSeek),FileName); + SysErrMsg(); + } +#endif +#if !defined(SILENT) || defined(RARDLL) + Throw(RARX_FATAL); +#endif +} + + +void ErrorHandler::GeneralErrMsg(const char *Msg) +{ +#ifndef SILENT + Log(NULL,"%s",Msg); + SysErrMsg(); +#endif +} + + +void ErrorHandler::MemoryErrorMsg() +{ +#ifndef SILENT + ErrMsg(NULL,St(MErrOutMem)); +#endif +} + + +void ErrorHandler::OpenErrorMsg(const char *FileName,const wchar *FileNameW) +{ + OpenErrorMsg(NULL,NULL,FileName,FileNameW); +} + + +void ErrorHandler::OpenErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW) +{ +#ifndef SILENT + if (FileName!=NULL) + Log(ArcName,St(MCannotOpen),FileName); + Alarm(); + SysErrMsg(); +#endif +} + + +void ErrorHandler::CreateErrorMsg(const char *FileName,const wchar *FileNameW) +{ + CreateErrorMsg(NULL,NULL,FileName,FileNameW); +} + + +void ErrorHandler::CreateErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW) +{ +#ifndef SILENT + if (FileName!=NULL) + Log(ArcName,St(MCannotCreate),FileName); + Alarm(); + +#if defined(_WIN_ALL) && !defined(_WIN_CE) && defined(MAX_PATH) + CheckLongPathErrMsg(FileName,FileNameW); +#endif + + SysErrMsg(); +#endif +} + + +// Check the path length and display the error message if it is too long. +void ErrorHandler::CheckLongPathErrMsg(const char *FileName,const wchar *FileNameW) +{ +#if defined(_WIN_ALL) && !defined(_WIN_CE) && !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)) + { + wchar CurDir[NM]; + GetCurrentDirectoryW(ASIZE(CurDir),CurDir); + NameLength+=wcslen(CurDir)+1; + } + if (NameLength>MAX_PATH) + { + Log(NULL,St(MMaxPathLimit),MAX_PATH); + } + } +#endif +} + + +void ErrorHandler::ReadErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW) +{ +#ifndef SILENT + ErrMsg(ArcName,St(MErrRead),FileName); + SysErrMsg(); +#endif +} + + +void ErrorHandler::WriteErrorMsg(const char *ArcName,const wchar *ArcNameW,const char *FileName,const wchar *FileNameW) +{ +#ifndef SILENT + ErrMsg(ArcName,St(MErrWrite),FileName); + SysErrMsg(); +#endif +} + + +void ErrorHandler::Exit(RAR_EXIT ExitCode) +{ +#ifndef SFX_MODULE + 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) + { + case RARX_WARNING: + case RARX_USERBREAK: + if (ExitCode==RARX_SUCCESS) + ExitCode=Code; + break; + case RARX_FATAL: + if (ExitCode==RARX_SUCCESS || ExitCode==RARX_WARNING) + ExitCode=RARX_FATAL; + break; + default: + ExitCode=Code; + break; + } + ErrCount++; +} + + +#if !defined(GUI) && !defined(_SFX_RTL_) +#ifdef _WIN_ALL +BOOL __stdcall ProcessSignal(DWORD SigType) +#else +#if defined(__sun) +extern "C" +#endif +void _stdfunction ProcessSignal(int SigType) +#endif +{ +#ifdef _WIN_ALL + // 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); +#endif + UserBreak=true; + mprintf(St(MBreak)); + for (int I=0;!File::RemoveCreated() && I<3;I++) + { +#ifdef _WIN_ALL + Sleep(100); +#endif + } +#if defined(USE_RC) && !defined(SFX_MODULE) && !defined(_WIN_CE) && !defined(RARDLL) + ExtRes.UnloadDLL(); +#endif + exit(RARX_USERBREAK); +#if defined(_WIN_ALL) && !defined(_MSC_VER) + // never reached, just to avoid a compiler warning + return(TRUE); +#endif +} +#endif + + +void ErrorHandler::SetSignalHandlers(bool Enable) +{ + EnableBreak=Enable; +#if !defined(GUI) && !defined(_SFX_RTL_) +#ifdef _WIN_ALL + SetConsoleCtrlHandler(Enable ? ProcessSignal:NULL,TRUE); +// signal(SIGBREAK,Enable ? ProcessSignal:SIG_IGN); +#else + signal(SIGINT,Enable ? ProcessSignal:SIG_IGN); + signal(SIGTERM,Enable ? ProcessSignal:SIG_IGN); +#endif +#endif +} + + +void ErrorHandler::Throw(RAR_EXIT Code) +{ + if (Code==RARX_USERBREAK && !EnableBreak) + return; + ErrHandler.SetErrorCode(Code); +#ifdef ALLOW_EXCEPTIONS + throw Code; +#else + File::RemoveCreated(); + exit(Code); +#endif +} + + +void ErrorHandler::SysErrMsg() +{ +#if !defined(SFX_MODULE) && !defined(SILENT) +#ifdef _WIN_ALL + wchar *lpMsgBuf=NULL; + int ErrType=GetLastError(); + if (ErrType!=0 && FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, + NULL,ErrType,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpMsgBuf,0,NULL)) + { + wchar *CurMsg=lpMsgBuf; + while (CurMsg!=NULL) + { + while (*CurMsg=='\r' || *CurMsg=='\n') + CurMsg++; + if (*CurMsg==0) + break; + wchar *EndMsg=wcschr(CurMsg,'\r'); + if (EndMsg==NULL) + EndMsg=wcschr(CurMsg,'\n'); + if (EndMsg!=NULL) + { + *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); + } + CurMsg=EndMsg; + } + } + LocalFree( lpMsgBuf ); +#endif + +#if defined(_UNIX) || defined(_EMX) + if (errno!=0) + { + char *err=strerror(errno); + if (err!=NULL) + Log(NULL,"\n%s",err); + } +#endif + +#endif +} + + + + diff --git a/src/thirdparty/unrar/errhnd.hpp b/src/thirdparty/unrar/errhnd.hpp new file mode 100644 index 000000000..ab84e0b54 --- /dev/null +++ b/src/thirdparty/unrar/errhnd.hpp @@ -0,0 +1,67 @@ +#ifndef _RAR_ERRHANDLER_ +#define _RAR_ERRHANDLER_ + +#ifndef SFX_MODULE +#define ALLOW_EXCEPTIONS +#endif + +enum RAR_EXIT // RAR exit code. +{ + RARX_SUCCESS = 0, + RARX_WARNING = 1, + RARX_FATAL = 2, + RARX_CRC = 3, + RARX_LOCK = 4, + RARX_WRITE = 5, + RARX_OPEN = 6, + RARX_USERERROR = 7, + RARX_MEMORY = 8, + RARX_CREATE = 9, + RARX_NOFILES = 10, + RARX_USERBREAK = 255 +}; + +class ErrorHandler +{ + private: + void ErrMsg(const char *ArcName,const char *fmt,...); + + RAR_EXIT ExitCode; + int ErrCount; + bool EnableBreak; + bool Silent; + bool DoShutdown; + public: + 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 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 Exit(RAR_EXIT ExitCode); + void SetErrorCode(RAR_EXIT Code); + RAR_EXIT GetErrorCode() {return(ExitCode);} + int 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(); +}; + + +#endif diff --git a/src/thirdparty/unrar/extinfo.cpp b/src/thirdparty/unrar/extinfo.cpp new file mode 100644 index 000000000..538f6a7f3 --- /dev/null +++ b/src/thirdparty/unrar/extinfo.cpp @@ -0,0 +1,76 @@ +#include "rar.hpp" + +#ifdef _WIN_ALL +#include "win32acl.cpp" +#include "win32stm.cpp" +#endif +#ifdef _BEOS +#include "beosea.cpp" +#endif +#if defined(_EMX) && !defined(_DJGPP) +#include "os2ea.cpp" +#endif +#ifdef _UNIX +#include "uowners.cpp" +#endif + + + +#ifndef SFX_MODULE +void SetExtraInfo(CommandData *Cmd,Archive &Arc,char *Name,wchar *NameW) +{ + 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); + break; +#endif +#ifdef _WIN_ALL + case NTACL_HEAD: + if (Cmd->ProcessOwners) + ExtractACL(Arc,Name,NameW); + break; + case STREAM_HEAD: + ExtractStreams(Arc,Name,NameW); + break; +#endif + } +} +#endif + + +void SetExtraInfoNew(CommandData *Cmd,Archive &Arc,char *Name,wchar *NameW) +{ +#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); +#endif +#ifdef _WIN_ALL + if (Cmd->ProcessOwners && Arc.SubHead.CmpName(SUBHEAD_TYPE_ACL)) + ExtractACLNew(Arc,Name,NameW); + if (Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM)) + ExtractStreamsNew(Arc,Name,NameW); +#endif +} diff --git a/src/thirdparty/unrar/extinfo.hpp b/src/thirdparty/unrar/extinfo.hpp new file mode 100644 index 000000000..db7cea53f --- /dev/null +++ b/src/thirdparty/unrar/extinfo.hpp @@ -0,0 +1,8 @@ +#ifndef _RAR_EXTINFO_ +#define _RAR_EXTINFO_ + + +void SetExtraInfo(CommandData *Cmd,Archive &Arc,char *Name,wchar *NameW); +void SetExtraInfoNew(CommandData *Cmd,Archive &Arc,char *Name,wchar *NameW); + +#endif diff --git a/src/thirdparty/unrar/extract.cpp b/src/thirdparty/unrar/extract.cpp new file mode 100644 index 000000000..ddd71a038 --- /dev/null +++ b/src/thirdparty/unrar/extract.cpp @@ -0,0 +1,1026 @@ +#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; + } +} + diff --git a/src/thirdparty/unrar/extract.hpp b/src/thirdparty/unrar/extract.hpp new file mode 100644 index 000000000..0995e8eda --- /dev/null +++ b/src/thirdparty/unrar/extract.hpp @@ -0,0 +1,49 @@ +#ifndef _RAR_EXTRACT_ +#define _RAR_EXTRACT_ + +enum EXTRACT_ARC_CODE {EXTRACT_ARC_NEXT,EXTRACT_ARC_REPEAT}; + +class CmdExtract +{ + private: + EXTRACT_ARC_CODE ExtractArchive(CommandData *Cmd); + RarTime StartTime; // time when extraction started + + ComprDataIO DataIO; + Unpack *Unp; + unsigned long TotalFileCount; + + unsigned long FileCount; + unsigned long MatchedArgs; + bool FirstFile; + bool AllMatchesExact; + bool ReconstructDone; + + // If any non-zero solid file was successfully unpacked before current. + // If true and if current encrypted file is broken, obviously + // the password is correct and we can report broken CRC without + // any wrong password hints. + bool AnySolidDataUnpackedWell; + + char ArcName[NM]; + wchar ArcNameW[NM]; + + SecPassword Password; + bool PasswordAll; + bool PrevExtracted; + char DestFileName[NM]; + wchar DestFileNameW[NM]; + bool PasswordCancelled; + public: + CmdExtract(); + ~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 new file mode 100644 index 000000000..2bd176f79 --- /dev/null +++ b/src/thirdparty/unrar/filcreat.cpp @@ -0,0 +1,260 @@ +#include "rar.hpp" + +bool FileCreate(RAROptions *Cmd,File *NewFile,char *Name,wchar *NameW, + OVERWRITE_MODE Mode,bool *UserReject,int64 FileSize, + uint FileTime,bool WriteOnly) +{ + if (UserReject!=NULL) + *UserReject=false; +#if defined(_WIN_ALL) && !defined(_WIN_CE) + bool ShortNameChanged=false; +#endif + while (FileExist(Name,NameW)) + { +#if defined(_WIN_ALL) && !defined(_WIN_CE) + if (!ShortNameChanged) + { + // Avoid the infinite loop if UpdateExistingShortName returns + // the same name. + ShortNameChanged=true; + + // 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); + 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. + ShortNameChanged=false; +#endif + if (Mode==OVERWRITE_NONE) + { + if (UserReject!=NULL) + *UserReject=true; + return(false); + } + + // Must be before Cmd->AllYes check or -y switch would override -or. + if (Mode==OVERWRITE_AUTORENAME) + { + if (!GetAutoRenamedName(Name,NameW)) + Mode=OVERWRITE_DEFAULT; + continue; + } + +#ifdef SILENT + Mode=OVERWRITE_ALL; +#endif + + // This check must be after OVERWRITE_AUTORENAME processing or -y switch + // would override -or. + if (Cmd->AllYes || Mode==OVERWRITE_ALL) + break; + + if (Mode==OVERWRITE_DEFAULT || Mode==OVERWRITE_FORCE_ASK) + { + char NewName[NM]; + wchar NewNameW[NM]; + *NewNameW=0; + eprintf(St(MFileExists),Name); + int Choice=Ask(St(MYesNoAllRenQ)); + if (Choice==1) + break; + if (Choice==2) + { + if (UserReject!=NULL) + *UserReject=true; + return(false); + } + if (Choice==3) + { + Cmd->Overwrite=OVERWRITE_ALL; + break; + } + if (Choice==4) + { + if (UserReject!=NULL) + *UserReject=true; + Cmd->Overwrite=OVERWRITE_NONE; + 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) + { + // Process fgets failure as if user answered 'No'. + if (UserReject!=NULL) + *UserReject=true; + return(false); + } +#endif + RemoveLF(NewName); +#endif + if (PointToName(NewName)==NewName) + strcpy(PointToName(Name),NewName); + else + strcpy(Name,NewName); + + if (NameW!=NULL) + if (PointToName(NewNameW)==NewNameW) + wcscpy(PointToName(NameW),NewNameW); + else + wcscpy(NameW,NewNameW); + continue; + } + if (Choice==6) + ErrHandler.Exit(RARX_USERBREAK); + } + } + 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)); +} + + +bool GetAutoRenamedName(char *Name,wchar *NameW) +{ + 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); + } + *NewName=0; + *NewNameW=0; + for (int 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)) + { + if (Name!=NULL && *Name!=0) + strcpy(Name,NewName); + if (NameW!=NULL && *NameW!=0) + wcscpy(NameW,NewNameW); + break; + } + if (FileVer>=1000000) + return(false); + } + return(true); +} + + +#if defined(_WIN_ALL) && !defined(_WIN_CE) +// 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) +{ + // '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); + + // 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); + + // Generate the temporary new name for existing file. + wchar NewName[NM]; + *NewName=0; + for (int I=0;I<10000 && *NewName==0;I+=123) + { + // Here we copy the path part of file to create. We'll make the temporary + // file in the same folder. + wcsncpyz(NewName,Name,ASIZE(NewName)); + + // Here we set the random name part. + sprintfw(PointToName(NewName),ASIZE(NewName),L"rtmp%d",I); + + // If such file is already exist, try next random name. + if (FileExist(NULL,NewName)) + *NewName=0; + } + + // If we could not generate the name not used by any other file, we return. + if (*NewName==0) + 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)); + + // Rename the existing file to randomly generated name. Normally it changes + // the short name too. + if (!MoveFileW(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 + // short name and not allow to use it again when renaming the file back to + // its original long name. + File KeepShortFile; + bool Created=false; + if (!FileExist(NULL,Name)) + Created=KeepShortFile.Create(NULL,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); + + if (Created) + { + // Delete the temporary zero length file occupying the short name, + KeepShortFile.Close(); + KeepShortFile.Delete(); + } + // 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); +} +#endif diff --git a/src/thirdparty/unrar/filcreat.hpp b/src/thirdparty/unrar/filcreat.hpp new file mode 100644 index 000000000..7e758bfc7 --- /dev/null +++ b/src/thirdparty/unrar/filcreat.hpp @@ -0,0 +1,13 @@ +#ifndef _RAR_FILECREATE_ +#define _RAR_FILECREATE_ + +bool FileCreate(RAROptions *Cmd,File *NewFile,char *Name,wchar *NameW, + OVERWRITE_MODE Mode,bool *UserReject,int64 FileSize=INT64NDF, + uint FileTime=0,bool WriteOnly=false); +bool GetAutoRenamedName(char *Name,wchar *NameW); + +#if defined(_WIN_ALL) && !defined(_WIN_CE) +bool UpdateExistingShortName(wchar *Name); +#endif + +#endif diff --git a/src/thirdparty/unrar/file.cpp b/src/thirdparty/unrar/file.cpp new file mode 100644 index 000000000..dcf4e612a --- /dev/null +++ b/src/thirdparty/unrar/file.cpp @@ -0,0 +1,710 @@ +#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; + SkipClose=false; + IgnoreReadErrors=false; + ErrorType=FILE_SUCCESS; + OpenShared=false; + AllowDelete=true; + CloseCount=0; + AllowExceptions=true; +#ifdef _WIN_ALL + NoSequentialRead=false; + CreateMode=FMF_UNDEFINED; +#endif +} + + +File::~File() +{ + if (hFile!=BAD_HANDLE && !SkipClose) + if (NewFile) + Delete(); + else + Close(); +} + + +void File::operator = (File &SrcFile) +{ + hFile=SrcFile.hFile; + strcpy(FileName,SrcFile.FileName); + NewFile=SrcFile.NewFile; + LastWrite=SrcFile.LastWrite; + HandleType=SrcFile.HandleType; + SrcFile.SkipClose=true; +} + + +bool File::Open(const char *Name,const wchar *NameW,uint Mode) +{ + ErrorType=FILE_SUCCESS; + FileHandle hNewFile; + bool OpenShared=File::OpenShared || (Mode & FMF_OPENSHARED)!=0; + bool UpdateMode=(Mode & FMF_UPDATE)!=0; + bool WriteMode=(Mode & FMF_WRITE)!=0; +#ifdef _WIN_ALL + uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ; + if (UpdateMode) + Access|=GENERIC_WRITE; + uint ShareMode=FILE_SHARE_READ; + 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); + + if (hNewFile==BAD_HANDLE && GetLastError()==ERROR_FILE_NOT_FOUND) + ErrorType=FILE_NOTFOUND; +#else + int flags=UpdateMode ? O_RDWR:(WriteMode ? O_WRONLY:O_RDONLY); +#ifdef O_BINARY + flags|=O_BINARY; +#if defined(_AIX) && defined(_LARGE_FILE_API) + 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); +#ifdef LOCK_EX + +#ifdef _OSF_SOURCE + extern "C" int flock(int, int); +#endif + + if (!OpenShared && UpdateMode && handle>=0 && flock(handle,LOCK_EX|LOCK_NB)==-1) + { + close(handle); + return(false); + } +#endif +#endif + hNewFile=handle==-1 ? BAD_HANDLE:fdopen(handle,UpdateMode ? UPDATEBINARY:READBINARY); + if (hNewFile==BAD_HANDLE && errno==ENOENT) + ErrorType=FILE_NOTFOUND; +#endif + NewFile=false; + HandleType=FILE_HANDLENORMAL; + SkipClose=false; + bool Success=hNewFile!=BAD_HANDLE; + 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); + } + return(Success); +} + + +#if !defined(SHELL_EXT) && !defined(SFX_MODULE) +void File::TOpen(const char *Name,const wchar *NameW) +{ + if (!WOpen(Name,NameW)) + ErrHandler.Exit(RARX_OPEN); +} +#endif + + +bool File::WOpen(const char *Name,const wchar *NameW) +{ + if (Open(Name,NameW)) + return(true); + ErrHandler.OpenErrorMsg(Name,NameW); + return(false); +} + + +bool File::Create(const char *Name,const wchar *NameW,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 + // before SetFileTime call. So we should use the write only mode if we plan + // SetFileTime call and do not need to read from file. + bool WriteMode=(Mode & FMF_WRITE)!=0; + bool ShareRead=(Mode & FMF_SHAREREAD)!=0 || File::OpenShared; +#ifdef _WIN_ALL + 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); +#else + hFile=fopen(Name,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; + } +} + + +#if !defined(SHELL_EXT) && !defined(SFX_MODULE) +void File::TCreate(const char *Name,const wchar *NameW,uint Mode) +{ + if (!WCreate(Name,NameW,Mode)) + ErrHandler.Exit(RARX_FATAL); +} +#endif + + +bool File::WCreate(const char *Name,const wchar *NameW,uint Mode) +{ + if (Create(Name,NameW,Mode)) + return(true); + ErrHandler.SetErrorCode(RARX_CREATE); + ErrHandler.CreateErrorMsg(Name,NameW); + return(false); +} + + +bool File::Close() +{ + bool Success=true; + if (HandleType!=FILE_HANDLENORMAL) + HandleType=FILE_HANDLENORMAL; + else + if (hFile!=BAD_HANDLE) + { + if (!SkipClose) + { +#ifdef _WIN_ALL + Success=CloseHandle(hFile)==TRUE; +#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); + } + CloseCount++; + return(Success); +} + + +void File::Flush() +{ +#ifdef _WIN_ALL + FlushFileBuffers(hFile); +#else + fflush(hFile); +#endif +} + + +bool File::Delete() +{ + if (HandleType!=FILE_HANDLENORMAL) + return(false); + if (hFile!=BAD_HANDLE) + Close(); + if (!AllowDelete) + return(false); + return(DelFile(FileName,FileNameW)); +} + + +bool File::Rename(const char *NewName,const wchar *NewNameW) +{ + // 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; + + if (!Success) + Success=RenameFile(FileName,FileNameW,NewName,NewNameW); + + if (Success) + { + // renamed successfully, storing the new name + strcpy(FileName,NewName); + wcscpy(FileNameW,NullToEmpty(NewNameW)); + } + return(Success); +} + + +void File::Write(const void *Data,size_t Size) +{ + if (Size==0) + return; +#ifndef _WIN_CE + if (HandleType!=FILE_HANDLENORMAL) + switch(HandleType) + { + case FILE_HANDLESTD: +#ifdef _WIN_ALL + hFile=GetStdHandle(STD_OUTPUT_HANDLE); +#else + hFile=stdout; +#endif + break; + case FILE_HANDLEERR: +#ifdef _WIN_ALL + hFile=GetStdHandle(STD_ERROR_HANDLE); +#else + hFile=stderr; +#endif + break; + } +#endif + while (1) + { + bool Success=false; +#ifdef _WIN_ALL + DWORD Written=0; + if (HandleType!=FILE_HANDLENORMAL) + { + // writing to stdout can fail in old Windows if data block is too large + const size_t MaxSize=0x4000; + for (size_t I=0;I<Size;I+=MaxSize) + { + Success=WriteFile(hFile,(byte *)Data+I,(DWORD)Min(Size-I,MaxSize),&Written,NULL)==TRUE; + if (!Success) + break; + } + } + else + Success=WriteFile(hFile,Data,(DWORD)Size,&Written,NULL)==TRUE; +#else + int Written=fwrite(Data,1,Size,hFile); + Success=Written==Size && !ferror(hFile); +#endif + if (!Success && AllowExceptions && HandleType==FILE_HANDLENORMAL) + { +#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(RARDLL) + int ErrCode=GetLastError(); + int64 FilePos=Tell(); + uint64 FreeSize=GetFreeDisk(FileName); + SetLastError(ErrCode); + if (FreeSize>Size && FilePos-Size<=0xffffffff && FilePos+Size>0xffffffff) + ErrHandler.WriteErrorFAT(FileName,FileNameW); +#endif + if (ErrHandler.AskRepeatWrite(FileName,FileNameW,false)) + { +#ifndef _WIN_ALL + clearerr(hFile); +#endif + if (Written<Size && Written>0) + Seek(Tell()-Written,SEEK_SET); + continue; + } + ErrHandler.WriteError(NULL,NULL,FileName,FileNameW); + } + break; + } + LastWrite=true; +} + + +int File::Read(void *Data,size_t Size) +{ + int64 FilePos=0; // Initialized only to suppress some compilers warning. + + if (IgnoreReadErrors) + FilePos=Tell(); + int ReadSize; + while (true) + { + ReadSize=DirectRead(Data,Size); + if (ReadSize==-1) + { + ErrorType=FILE_READERROR; + if (AllowExceptions) + if (IgnoreReadErrors) + { + ReadSize=0; + for (size_t I=0;I<Size;I+=512) + { + Seek(FilePos+I,SEEK_SET); + size_t SizeToRead=Min(Size-I,512); + int ReadCode=DirectRead(Data,SizeToRead); + ReadSize+=(ReadCode==-1) ? 512:ReadCode; + } + } + else + { + if (HandleType==FILE_HANDLENORMAL && ErrHandler.AskRepeatRead(FileName,FileNameW)) + continue; + ErrHandler.ReadError(FileName,FileNameW); + } + } + break; + } + return(ReadSize); +} + + +// Returns -1 in case of error. +int File::DirectRead(void *Data,size_t Size) +{ +#ifdef _WIN_ALL + const size_t MaxDeviceRead=20000; +#endif +#ifndef _WIN_CE + if (HandleType==FILE_HANDLESTD) + { +#ifdef _WIN_ALL + if (Size>MaxDeviceRead) + Size=MaxDeviceRead; + hFile=GetStdHandle(STD_INPUT_HANDLE); +#else + hFile=stdin; +#endif + } +#endif +#ifdef _WIN_ALL + DWORD Read; + if (!ReadFile(hFile,Data,(DWORD)Size,&Read,NULL)) + { + if (IsDevice() && Size>MaxDeviceRead) + return(DirectRead(Data,MaxDeviceRead)); + if (HandleType==FILE_HANDLESTD && GetLastError()==ERROR_BROKEN_PIPE) + return(0); + return(-1); + } + return(Read); +#else + if (LastWrite) + { + fflush(hFile); + LastWrite=false; + } + clearerr(hFile); + size_t ReadSize=fread(Data,1,Size,hFile); + if (ferror(hFile)) + return(-1); + return((int)ReadSize); +#endif +} + + +void File::Seek(int64 Offset,int Method) +{ + if (!RawSeek(Offset,Method) && AllowExceptions) + ErrHandler.SeekError(FileName,FileNameW); +} + + +bool File::RawSeek(int64 Offset,int Method) +{ + if (hFile==BAD_HANDLE) + return(true); + if (Offset<0 && Method!=SEEK_SET) + { + Offset=(Method==SEEK_CUR ? Tell():FileLength())+Offset; + Method=SEEK_SET; + } +#ifdef _WIN_ALL + LONG HighDist=(LONG)(Offset>>32); + if (SetFilePointer(hFile,(LONG)Offset,&HighDist,Method)==0xffffffff && + GetLastError()!=NO_ERROR) + return(false); +#else + LastWrite=false; +#if defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE) && !defined(__VMS) + if (fseeko(hFile,Offset,Method)!=0) +#else + if (fseek(hFile,(long)Offset,Method)!=0) +#endif + return(false); +#endif + return(true); +} + + +int64 File::Tell() +{ + if (hFile==BAD_HANDLE) + if (AllowExceptions) + ErrHandler.SeekError(FileName,FileNameW); + else + 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); + else + return(-1); + return(INT32TO64(HighDist,LowDist)); +#else +#if defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE) + return(ftello(hFile)); +#else + return(ftell(hFile)); +#endif +#endif +} + + +void File::Prealloc(int64 Size) +{ +#ifdef _WIN_ALL + if (RawSeek(Size,SEEK_SET)) + { + Truncate(); + Seek(0,SEEK_SET); + } +#endif + +#if defined(_UNIX) && defined(USE_FALLOCATE) + // fallocate is rather new call. Only latest kernels support it. + // So we are not using it by default yet. + int fd = fileno(hFile); + if (fd >= 0) + fallocate(fd, 0, 0, Size); +#endif +} + + +byte File::GetByte() +{ + byte Byte=0; + Read(&Byte,1); + return(Byte); +} + + +void File::PutByte(byte Byte) +{ + Write(&Byte,1); +} + + +bool File::Truncate() +{ +#ifdef _WIN_ALL + return(SetEndOfFile(hFile)==TRUE); +#else + return(false); +#endif +} + + +void File::SetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta) +{ +#ifdef _WIN_ALL + // Workaround for OpenIndiana NAS time bug. If we cannot create a file + // in write only mode, we need to flush the write buffer before calling + // SetFileTime or file time will not be changed. + if (CreateMode!=FMF_UNDEFINED && (CreateMode & FMF_WRITE)==0) + FlushFileBuffers(hFile); + + bool sm=ftm!=NULL && ftm->IsSet(); + bool sc=ftc!=NULL && ftc->IsSet(); + bool sa=fta!=NULL && fta->IsSet(); + FILETIME fm,fc,fa; + if (sm) + ftm->GetWin32(&fm); + if (sc) + ftc->GetWin32(&fc); + if (sa) + fta->GetWin32(&fa); + SetFileTime(hFile,sc ? &fc:NULL,sa ? &fa:NULL,sm ? &fm:NULL); +#endif +} + + +void File::SetCloseFileTime(RarTime *ftm,RarTime *fta) +{ +#if defined(_UNIX) || defined(_EMX) + SetCloseFileTimeByName(FileName,ftm,fta); +#endif +} + + +void File::SetCloseFileTimeByName(const char *Name,RarTime *ftm,RarTime *fta) +{ +#if defined(_UNIX) || defined(_EMX) + bool setm=ftm!=NULL && ftm->IsSet(); + bool seta=fta!=NULL && fta->IsSet(); + if (setm || seta) + { + utimbuf ut; + if (setm) + ut.modtime=ftm->GetUnix(); + else + ut.modtime=fta->GetUnix(); + if (seta) + ut.actime=fta->GetUnix(); + else + ut.actime=ut.modtime; + utime(Name,&ut); + } +#endif +} + + +void File::GetOpenFileTime(RarTime *ft) +{ +#ifdef _WIN_ALL + FILETIME FileTime; + GetFileTime(hFile,NULL,NULL,&FileTime); + *ft=FileTime; +#endif +#if defined(_UNIX) || defined(_EMX) + struct stat st; + fstat(fileno(hFile),&st); + *ft=st.st_mtime; +#endif +} + + +int64 File::FileLength() +{ + SaveFilePos SavePos(*this); + Seek(0,SEEK_END); + return(Tell()); +} + + +void File::SetHandleType(FILE_HANDLETYPE Type) +{ + HandleType=Type; +} + + +bool File::IsDevice() +{ + if (hFile==BAD_HANDLE) + return(false); +#ifdef _WIN_ALL + uint Type=GetFileType(hFile); + return(Type==FILE_TYPE_CHAR || Type==FILE_TYPE_PIPE); +#else + 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); + int64 CopySize=0; + bool CopyAll=(Length==INT64NDF); + + while (CopyAll || Length>0) + { + Wait(); + size_t SizeToRead=(!CopyAll && Length<(int64)Buffer.Size()) ? (size_t)Length:Buffer.Size(); + int ReadSize=Read(&Buffer[0],SizeToRead); + if (ReadSize==0) + break; + Dest.Write(&Buffer[0],ReadSize); + CopySize+=ReadSize; + if (!CopyAll) + Length-=ReadSize; + } + return(CopySize); +} +#endif diff --git a/src/thirdparty/unrar/file.hpp b/src/thirdparty/unrar/file.hpp new file mode 100644 index 000000000..666b5196e --- /dev/null +++ b/src/thirdparty/unrar/file.hpp @@ -0,0 +1,120 @@ +#ifndef _RAR_FILE_ +#define _RAR_FILE_ + +#ifdef _WIN_ALL +typedef HANDLE FileHandle; +#define BAD_HANDLE INVALID_HANDLE_VALUE +#else +typedef FILE* FileHandle; +#define BAD_HANDLE NULL +#endif + +class RAROptions; + +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, + + // Request both read and write access to file. Default for Create. + FMF_UPDATE=1, + + // Request write only access to file. + FMF_WRITE=2, + + // Open files which are already opened for write by other programs. + FMF_OPENSHARED=4, + + // Provide read access to created file for other programs. + FMF_SHAREREAD=8, + + // Mode flags are not defined yet. + FMF_UNDEFINED=256 +}; + + +class File +{ + private: + void AddFileToList(FileHandle hFile); + + FileHandle hFile; + bool LastWrite; + FILE_HANDLETYPE HandleType; + bool SkipClose; + bool IgnoreReadErrors; + bool NewFile; + bool AllowDelete; + bool AllowExceptions; +#ifdef _WIN_ALL + bool NoSequentialRead; + uint CreateMode; +#endif + protected: + bool OpenShared; // Set by 'Archive' class. + public: + char FileName[NM]; + wchar FileNameW[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 Close(); + void Flush(); + bool Delete(); + bool Rename(const char *NewName,const wchar *NewNameW=NULL); + void Write(const void *Data,size_t Size); + int Read(void *Data,size_t Size); + int DirectRead(void *Data,size_t Size); + void Seek(int64 Offset,int Method); + bool RawSeek(int64 Offset,int Method); + 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); + void GetOpenFileTime(RarTime *ft); + bool IsOpened() {return(hFile!=BAD_HANDLE);}; + int64 FileLength(); + void SetHandleType(FILE_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);} + int64 Copy(File &Dest,int64 Length=INT64NDF); + void SetAllowDelete(bool Allow) {AllowDelete=Allow;} + void SetExceptions(bool Allow) {AllowExceptions=Allow;} +#ifdef _WIN_ALL + void RemoveSequentialFlag() {NoSequentialRead=true;} +#endif +}; + +#endif diff --git a/src/thirdparty/unrar/filefn.cpp b/src/thirdparty/unrar/filefn.cpp new file mode 100644 index 000000000..e7cc8fd6b --- /dev/null +++ b/src/thirdparty/unrar/filefn.cpp @@ -0,0 +1,564 @@ +#include "rar.hpp" + +MKDIR_CODE MakeDir(const char *Name,const wchar *NameW,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); + if (RetCode!=0) // Non-zero return code means success for CreateDirectory. + { + if (SetAttr) + SetFileAttr(Name,NameW,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 + mode_t uattr=SetAttr ? (mode_t)Attr:0777; + int ErrCode=mkdir(Name,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; +#else + uint DirAttr=0777; +#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); + +#if defined(_WIN_ALL) || defined(_EMX) + uint DirAttr=0; +#else + uint DirAttr=0777; +#endif + + bool Success=true; + + for (const wchar *s=Path;*s!=0;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)) + { + wchar DirName[NM]; + wcsncpy(DirName,Path,s-Path); + DirName[s-Path]=0; + + if (MakeDir(NULL,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 + } + else + Success=false; + } + } + if (!SkipLastName) + if (!IsPathDiv(*PointToLastChar(Path))) + if (MakeDir(NULL,Path,true,DirAttr)!=MKDIR_SUCCESS) + Success=false; + return(Success); +} + + +bool CreatePath(const char *Path,const wchar *PathW,bool SkipLastName) +{ +#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); + if (ResetAttr) + SetFileAttr(Name,NameW,0); + + wchar DirNameW[NM]; + GetWideName(Name,NameW,DirNameW,ASIZE(DirNameW)); + HANDLE hFile=CreateFileW(DirNameW,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) + ftm->GetWin32(&fm); + if (sc) + ftc->GetWin32(&fc); + if (sa) + fta->GetWin32(&fa); + SetFileTime(hFile,sc ? &fc:NULL,sa ? &fa:NULL,sm ? &fm:NULL); + CloseHandle(hFile); + if (ResetAttr) + SetFileAttr(Name,NameW,DirAttr); +#endif +#if defined(_UNIX) || defined(_EMX) + File::SetCloseFileTimeByName(Name,ftm,fta); +#endif +} + + +bool IsRemovable(const char *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]==':'); +#else + return(false); +#endif +} + + + + +#ifndef SFX_MODULE +int64 GetFreeDisk(const char *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]; + 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); +#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); + } +#else + #define DISABLEAUTODETECT + return(1457664); +#endif +} +#endif + + + + + +bool FileExist(const char *Name,const wchar *NameW) +{ +#ifdef _WIN_ALL + if (WinNT() && NameW!=NULL && *NameW!=0) + return(GetFileAttributesW(NameW)!=0xffffffff); + else + return(Name!=NULL && GetFileAttributesA(Name)!=0xffffffff); +#elif defined(ENABLE_ACCESS) + return(access(Name,0)==0); +#else + FindData FD; + return(FindFile::FastFind(Name,NameW,&FD)); +#endif +} + + +bool FileExist(const wchar *Name) +{ + return FileExist(NULL,Name); +} + + +bool WildFileExist(const char *Name,const wchar *NameW) +{ + if (IsWildcard(Name,NameW)) + { + FindFile Find; + Find.SetMask(Name); + Find.SetMaskW(NameW); + FindData fd; + return(Find.Next(&fd)); + } + return(FileExist(Name,NameW)); +} + + +bool IsDir(uint Attr) +{ +#if defined (_WIN_ALL) || defined(_EMX) + return(Attr!=0xffffffff && (Attr & 0x10)!=0); +#endif +#if defined(_UNIX) + return((Attr & 0xF000)==0x4000); +#endif +} + + +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); +#endif +} + + +bool IsLink(uint Attr) +{ +#ifdef _UNIX + return((Attr & 0xF000)==0xA000); +#else + return(false); +#endif +} + + + + + + +bool IsDeleteAllowed(uint FileAttr) +{ +#if defined(_WIN_ALL) || defined(_EMX) + return((FileAttr & (FA_RDONLY|FA_SYSTEM|FA_HIDDEN))==0); +#else + return((FileAttr & (S_IRUSR|S_IWUSR))==(S_IRUSR|S_IWUSR)); +#endif +} + + +void PrepareToDelete(const char *Name,const wchar *NameW) +{ +#if defined(_WIN_ALL) || defined(_EMX) + SetFileAttr(Name,NameW,0); +#endif +#ifdef _UNIX + if (Name!=NULL) + chmod(Name,S_IRUSR|S_IWUSR|S_IXUSR); +#endif +} + + +uint GetFileAttr(const char *Name,const wchar *NameW) +{ +#ifdef _WIN_ALL + if (WinNT() && NameW!=NULL && *NameW!=0) + return(GetFileAttributesW(NameW)); + else + return(GetFileAttributesA(Name)); +#elif defined(_DJGPP) + return(_chmod(Name,0)); +#else + struct stat st; + if (stat(Name,&st)!=0) + return(0); +#ifdef _EMX + return(st.st_attr); +#else + return(st.st_mode); +#endif +#endif +} + + +bool SetFileAttr(const char *Name,const wchar *NameW,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; +#elif defined(_UNIX) + Success=chmod(Name,(mode_t)Attr)==0; +#else + Success=false; +#endif + return(Success); +} + + + + +#ifndef SFX_MODULE +uint CalcFileCRC(File *SrcFile,int64 Size,CALCCRC_SHOWMODE ShowMode) +{ + 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) + { + mprintf(St(MCalcCRC)); + mprintf(" "); + } + +#endif + + SrcFile->Seek(0,SEEK_SET); + while (true) + { + size_t SizeToRead; + if (Size==INT64NDF) // If we process the entire file. + SizeToRead=BufSize; // Then always attempt to read the entire buffer. + else + SizeToRead=(size_t)Min((int64)BufSize,Size); + int ReadSize=SrcFile->Read(&Data[0],SizeToRead); + if (ReadSize==0) + break; + + ++BlockCount; + if ((BlockCount & 15)==0) + { +#if !defined(SILENT) && !defined(_WIN_CE) + if (ShowMode==CALCCRC_SHOWALL) + mprintf("\b\b\b\b%3d%%",ToPercent(BlockCount*int64(BufSize),FileLength)); +#endif + Wait(); + } + DataCRC=CRC(DataCRC,&Data[0],ReadSize); + if (Size!=INT64NDF) + Size-=ReadSize; + } +#if !defined(SILENT) && !defined(_WIN_CE) + if (ShowMode==CALCCRC_SHOWALL) + mprintf("\b\b\b\b "); +#endif + return(DataCRC^0xffffffff); +} +#endif + + +bool RenameFile(const char *SrcName,const wchar *SrcNameW,const char *DestName,const wchar *DestNameW) +{ + return(rename(SrcName,DestName)==0); +} + + +bool DelFile(const char *Name) +{ + return(DelFile(Name,NULL)); +} + + + + +bool DelFile(const char *Name,const wchar *NameW) +{ + return(Name!=NULL && remove(Name)==0); +} + + + + + + + + +#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE) +bool SetFileCompression(char *Name,wchar *NameW,bool State) +{ + wchar FileNameW[NM]; + GetWideName(Name,NameW,FileNameW,ASIZE(FileNameW)); + HANDLE hFile=CreateFileW(FileNameW,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); +} +#endif + + + + + + + + + diff --git a/src/thirdparty/unrar/filefn.hpp b/src/thirdparty/unrar/filefn.hpp new file mode 100644 index 000000000..bdf193e80 --- /dev/null +++ b/src/thirdparty/unrar/filefn.hpp @@ -0,0 +1,48 @@ +#ifndef _RAR_FILEFN_ +#define _RAR_FILEFN_ + +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); +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); + +#ifndef SFX_MODULE +int64 GetFreeDisk(const char *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 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); +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); + +enum CALCCRC_SHOWMODE {CALCCRC_SHOWNONE,CALCCRC_SHOWTEXT,CALCCRC_SHOWALL}; +uint CalcFileCRC(File *SrcFile,int64 Size=INT64NDF,CALCCRC_SHOWMODE ShowMode=CALCCRC_SHOWNONE); + +bool RenameFile(const char *SrcName,const wchar *SrcNameW,const char *DestName,const wchar *DestNameW); +bool DelFile(const char *Name); +bool DelFile(const char *Name,const wchar *NameW); +bool DelDir(const char *Name); +bool DelDir(const char *Name,const wchar *NameW); + +#if defined(_WIN_ALL) && !defined(_WIN_CE) +bool SetFileCompression(char *Name,wchar *NameW,bool State); +#endif + + + + +#endif diff --git a/src/thirdparty/unrar/filestr.cpp b/src/thirdparty/unrar/filestr.cpp new file mode 100644 index 000000000..49e865b9a --- /dev/null +++ b/src/thirdparty/unrar/filestr.cpp @@ -0,0 +1,208 @@ +#include "rar.hpp" + +static bool IsUnicode(byte *Data,int Size); + +bool ReadTextFile( + const char *Name, + const wchar *NameW, + StringList *List, + bool Config, + bool AbortOnError, + RAR_CHARSET SrcCharset, + bool Unquote, + bool SkipComments, + bool ExpandEnvStr) +{ + char 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 (Config) + GetConfigName(NameW,FileNameW,true); + else + wcscpy(FileNameW,NameW); +#endif + + File SrcFile; + if (FileName!=NULL && *FileName!=0 || FileNameW!=NULL && *FileNameW!=0) + { + bool OpenCode=AbortOnError ? SrcFile.WOpen(FileName,FileNameW):SrcFile.Open(FileName,FileNameW,0); + + if (!OpenCode) + { + if (AbortOnError) + ErrHandler.Exit(RARX_OPEN); + return(false); + } + } + else + SrcFile.SetHandleType(FILE_HANDLESTD); + + unsigned int DataSize=0,ReadSize; + const int ReadBlock=1024; + Array<char> Data(ReadBlock+5); + while ((ReadSize=SrcFile.Read(&Data[DataSize],ReadBlock))!=0) + { + DataSize+=ReadSize; + Data.Add(ReadSize); + } + + memset(&Data[DataSize],0,5); + + if (SrcCharset==RCH_UNICODE || + SrcCharset==RCH_DEFAULT && IsUnicode((byte *)&Data[0],DataSize)) + { + // Unicode in native system format, can be more than 2 bytes per character. + Array<wchar> DataW(Data.Size()/2+1); + for (size_t I=2;I<Data.Size()-1;I+=2) + { + // Need to convert Data to (byte) first to prevent the sign extension + // to higher bytes. + DataW[(I-2)/2]=(wchar)((byte)Data[I])+(wchar)((byte)Data[I+1])*256; + } + + wchar *CurStr=&DataW[0]; + Array<char> AnsiName; + + while (*CurStr!=0) + { + wchar *NextStr=CurStr,*CmtPtr=NULL; + while (*NextStr!='\r' && *NextStr!='\n' && *NextStr!=0) + { + if (SkipComments && NextStr[0]=='/' && NextStr[1]=='/') + { + *NextStr=0; + CmtPtr=NextStr; + } + NextStr++; + } + *NextStr=0; + for (wchar *SpacePtr=(CmtPtr ? CmtPtr:NextStr)-1;SpacePtr>=CurStr;SpacePtr--) + { + if (*SpacePtr!=' ' && *SpacePtr!='\t') + break; + *SpacePtr=0; + } + if (*CurStr) + { + // 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); + + 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) + if (ExpandEnvStr && *CurStr=='%') + { + // 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); + if (Expanded) + List->AddString(ExpName,ExpNameW); + } +#endif + if (!Expanded) + List->AddString(&AnsiName[0],CurStr); + } + CurStr=NextStr+1; + while (*CurStr=='\r' || *CurStr=='\n') + CurStr++; + } + } + else + { + char *CurStr=&Data[0]; + while (*CurStr!=0) + { + char *NextStr=CurStr,*CmtPtr=NULL; + while (*NextStr!='\r' && *NextStr!='\n' && *NextStr!=0) + { + if (SkipComments && NextStr[0]=='/' && NextStr[1]=='/') + { + *NextStr=0; + CmtPtr=NextStr; + } + NextStr++; + } + *NextStr=0; + for (char *SpacePtr=(CmtPtr ? CmtPtr:NextStr)-1;SpacePtr>=CurStr;SpacePtr--) + { + if (*SpacePtr!=' ' && *SpacePtr!='\t') + break; + *SpacePtr=0; + } + if (*CurStr) + { + if (Unquote && *CurStr=='\"') + { + size_t Length=strlen(CurStr); + if (CurStr[Length-1]=='\"') + { + CurStr[Length-1]=0; + CurStr++; + } + } +#if defined(_WIN_ALL) + if (SrcCharset==RCH_OEM) + OemToCharA(CurStr,CurStr); +#endif + + bool Expanded=false; +#if defined(_WIN_ALL) && !defined(_WIN_CE) + 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); + if (Expanded) + List->AddString(ExpName); + } +#endif + if (!Expanded) + List->AddString(CurStr); + } + CurStr=NextStr+1; + while (*CurStr=='\r' || *CurStr=='\n') + CurStr++; + } + } + return(true); +} + + +bool IsUnicode(byte *Data,int Size) +{ + if (Size<4 || Data[0]!=0xff || Data[1]!=0xfe) + return(false); + for (int I=2;I<Size;I++) + if (Data[I]<32 && Data[I]!='\r' && Data[I]!='\n') + return(true); + return(false); +} diff --git a/src/thirdparty/unrar/filestr.hpp b/src/thirdparty/unrar/filestr.hpp new file mode 100644 index 000000000..3bdcfe737 --- /dev/null +++ b/src/thirdparty/unrar/filestr.hpp @@ -0,0 +1,16 @@ +#ifndef _RAR_FILESTR_ +#define _RAR_FILESTR_ + +bool ReadTextFile( + const char *Name, + const wchar *NameW, + StringList *List, + bool Config, + bool AbortOnError=false, + RAR_CHARSET SrcCharset=RCH_DEFAULT, + bool Unquote=false, + bool SkipComments=false, + bool ExpandEnvStr=false +); + +#endif diff --git a/src/thirdparty/unrar/find.cpp b/src/thirdparty/unrar/find.cpp new file mode 100644 index 000000000..7ba14c055 --- /dev/null +++ b/src/thirdparty/unrar/find.cpp @@ -0,0 +1,291 @@ +#include "rar.hpp" + +FindFile::FindFile() +{ + *FindMask=0; + *FindMaskW=0; + FirstCall=true; +#ifdef _WIN_ALL + hFind=INVALID_HANDLE_VALUE; +#else + dirp=NULL; +#endif +} + + +FindFile::~FindFile() +{ +#ifdef _WIN_ALL + if (hFind!=INVALID_HANDLE_VALUE) + FindClose(hFind); +#else + if (dirp!=NULL) + closedir(dirp); +#endif +} + + +void FindFile::SetMask(const char *FindMask) +{ + strcpy(FindFile::FindMask,NullToEmpty(FindMask)); + if (*FindMaskW==0) + CharToWide(FindMask,FindMaskW); + 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) +{ + fd->Error=false; + if (*FindMask==0) + return(false); +#ifdef _WIN_ALL + if (FirstCall) + { + if ((hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,FindMaskW,fd))==INVALID_HANDLE_VALUE) + return(false); + } + else + if (Win32Find(hFind,FindMask,FindMaskW,fd)==INVALID_HANDLE_VALUE) + return(false); +#else + if (FirstCall) + { + char DirName[NM]; + strcpy(DirName,FindMask); + RemoveNameFromPath(DirName); + if (*DirName==0) + strcpy(DirName,"."); + if ((dirp=opendir(DirName))==NULL) + { + fd->Error=(errno!=ENOENT); + return(false); + } + } + while (1) + { + struct dirent *ent=readdir(dirp); + if (ent==NULL) + return(false); + if (strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0) + continue; + if (CmpName(FindMask,ent->d_name,MATCH_NAMES)) + { + char FullName[NM]; + strcpy(FullName,FindMask); + *PointToName(FullName)=0; + if (strlen(FullName)+strlen(ent->d_name)>=ASIZE(FullName)-1) + { +#ifndef SILENT + Log(NULL,"\n%s%s",FullName,ent->d_name); + Log(NULL,St(MPathTooLong)); +#endif + return(false); + } + strcat(FullName,ent->d_name); + if (!FastFind(FullName,NULL,fd,GetSymLink)) + { + ErrHandler.OpenErrorMsg(FullName); + continue; + } + strcpy(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); + FirstCall=false; + char *Name=PointToName(fd->Name); + if (strcmp(Name,".")==0 || strcmp(Name,"..")==0) + return(Next(fd)); + return(true); +} + + +bool FindFile::FastFind(const char *FindMask,const wchar *FindMaskW,FindData *fd,bool GetSymLink) +{ + fd->Error=false; +#ifndef _UNIX + if (IsWildcard(FindMask,FindMaskW)) + return(false); +#endif +#ifdef _WIN_ALL + HANDLE hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,FindMaskW,fd); + if (hFind==INVALID_HANDLE_VALUE) + return(false); + FindClose(hFind); +#else + struct stat st; + if (GetSymLink) + { +#ifdef SAVE_LINKS + if (lstat(FindMask,&st)!=0) +#else + if (stat(FindMask,&st)!=0) +#endif + { + fd->Error=(errno!=ENOENT); + return(false); + } + } + else + if (stat(FindMask,&st)!=0) + { + fd->Error=(errno!=ENOENT); + 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 +#endif + fd->Flags=0; + fd->IsDir=IsDir(fd->FileAttr); + return(true); +} + + +#ifdef _WIN_ALL +HANDLE FindFile::Win32Find(HANDLE hFind,const char *Mask,const wchar *MaskW,FindData *fd) +{ +#ifndef _WIN_CE + if (WinNT()) +#endif + { + wchar WideMask[NM]; + if (MaskW!=NULL && *MaskW!=0) + wcscpy(WideMask,MaskW); + else + CharToWide(Mask,WideMask); + + WIN32_FIND_DATAW 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); + } + } + else + if (!FindNextFileW(hFind,&FindData)) + { + hFind=INVALID_HANDLE_VALUE; + fd->Error=GetLastError()!=ERROR_NO_MORE_FILES; + } + + 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 + } + } +#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) + { + hFind=FindFirstFileA(CharMask,&FindData); + if (hFind==INVALID_HANDLE_VALUE) + { + int SysErr=GetLastError(); + fd->Error=SysErr!=ERROR_FILE_NOT_FOUND && SysErr!=ERROR_PATH_NOT_FOUND; + } + } + 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; + } + } +#endif + fd->Flags=0; + return(hFind); +} +#endif + diff --git a/src/thirdparty/unrar/find.hpp b/src/thirdparty/unrar/find.hpp new file mode 100644 index 000000000..05f5d7f0e --- /dev/null +++ b/src/thirdparty/unrar/find.hpp @@ -0,0 +1,53 @@ +#ifndef _RAR_FINDDATA_ +#define _RAR_FINDDATA_ + +enum FINDDATA_FLAGS { + FDDF_SECONDDIR=1 // Second encounter of same directory in SCAN_GETDIRSTWICE ScanTree mode. +}; + +struct FindData +{ + char Name[NM]; + wchar NameW[NM]; + int64 Size; + uint FileAttr; + uint FileTime; + bool IsDir; + RarTime mtime; + RarTime ctime; + RarTime atime; +#ifdef _WIN_ALL + wchar ShortName[NM]; + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; +#endif + uint Flags; + bool Error; +}; + +class FindFile +{ + private: +#ifdef _WIN_ALL + static HANDLE Win32Find(HANDLE hFind,const char *Mask,const wchar *MaskW,struct FindData *fd); +#endif + + char FindMask[NM]; + wchar FindMaskW[NM]; + bool FirstCall; +#ifdef _WIN_ALL + HANDLE hFind; +#else + DIR *dirp; +#endif + public: + FindFile(); + ~FindFile(); + void SetMask(const char *FindMask); + void SetMaskW(const wchar *FindMaskW); + bool Next(FindData *fd,bool GetSymLink=false); + static bool FastFind(const char *FindMask,const wchar *FindMaskW,FindData *fd,bool GetSymLink=false); +}; + +#endif diff --git a/src/thirdparty/unrar/getbits.cpp b/src/thirdparty/unrar/getbits.cpp new file mode 100644 index 000000000..02b3a0b46 --- /dev/null +++ b/src/thirdparty/unrar/getbits.cpp @@ -0,0 +1,35 @@ +#include "rar.hpp" + +BitInput::BitInput() +{ + // 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); +} + + +BitInput::~BitInput() +{ + delete[] InBuf; +} + + +void BitInput::faddbits(uint Bits) +{ + // Function wrapped version of inline addbits to save code size. + addbits(Bits); +} + + +uint BitInput::fgetbits() +{ + // Function wrapped version of inline getbits to save code size. + return(getbits()); +} diff --git a/src/thirdparty/unrar/getbits.hpp b/src/thirdparty/unrar/getbits.hpp new file mode 100644 index 000000000..d44fb9f06 --- /dev/null +++ b/src/thirdparty/unrar/getbits.hpp @@ -0,0 +1,51 @@ +#ifndef _RAR_GETBITS_ +#define _RAR_GETBITS_ + +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. + public: + BitInput(); + ~BitInput(); + + byte *InBuf; // Dynamically allocated input buffer. + + void InitBitInput() + { + InAddr=InBit=0; + } + + // Move forward by 'Bits' bits. + void addbits(uint Bits) + { + Bits+=InBit; + InAddr+=Bits>>3; + InBit=Bits&7; + } + + // Return 16 bits from current position in the buffer. + // Bit at (InAddr,InBit) has the highest position in returning data. + uint getbits() + { + uint BitField=(uint)InBuf[InAddr] << 16; + BitField|=(uint)InBuf[InAddr+1] << 8; + BitField|=(uint)InBuf[InAddr+2]; + BitField >>= (8-InBit); + return(BitField & 0xffff); + } + + void faddbits(uint Bits); + uint fgetbits(); + + // Check if buffer has enough space for IncPtr bytes. Returns 'true' + // if buffer will be overflown. + bool Overflow(uint IncPtr) + { + return(InAddr+IncPtr>=MAX_SIZE); + } +}; +#endif diff --git a/src/thirdparty/unrar/global.cpp b/src/thirdparty/unrar/global.cpp new file mode 100644 index 000000000..593a057cb --- /dev/null +++ b/src/thirdparty/unrar/global.cpp @@ -0,0 +1,4 @@ +#define INCLUDEGLOBAL + + +#include "rar.hpp" diff --git a/src/thirdparty/unrar/global.hpp b/src/thirdparty/unrar/global.hpp new file mode 100644 index 000000000..30eff082a --- /dev/null +++ b/src/thirdparty/unrar/global.hpp @@ -0,0 +1,15 @@ +#ifndef _RAR_GLOBAL_ +#define _RAR_GLOBAL_ + +#ifdef INCLUDEGLOBAL + #define EXTVAR +#else + #define EXTVAR extern +#endif + +EXTVAR ErrorHandler ErrHandler; + + + + +#endif diff --git a/src/thirdparty/unrar/headers.hpp b/src/thirdparty/unrar/headers.hpp new file mode 100644 index 000000000..75343a258 --- /dev/null +++ b/src/thirdparty/unrar/headers.hpp @@ -0,0 +1,327 @@ +#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_SHORTBLOCKHEAD 7 +#define SIZEOF_LONGBLOCKHEAD 11 +#define SIZEOF_SUBBLOCKHEAD 14 +#define SIZEOF_COMMHEAD 13 +#define SIZEOF_PROTECTHEAD 26 +#define SIZEOF_AVHEAD 14 +#define SIZEOF_SIGNHEAD 15 +#define SIZEOF_UOHEAD 18 +#define SIZEOF_MACHEAD 22 +#define SIZEOF_EAHEAD 24 +#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 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. +#define MHD_COMMENT 0x0002U + +#define MHD_LOCK 0x0004U +#define MHD_SOLID 0x0008U +#define MHD_PACK_COMMENT 0x0010U +#define MHD_NEWNUMBERING 0x0010U +#define MHD_AV 0x0020U +#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 +#define LHD_PASSWORD 0x0004U + +// Old style file comment embed into file header. Must not be used +// in new archives anymore. +#define LHD_COMMENT 0x0008U + +#define LHD_SOLID 0x0010U + + +#define LHD_WINDOWMASK 0x00e0U +#define LHD_WINDOW64 0x0000U +#define LHD_WINDOW128 0x0020U +#define LHD_WINDOW256 0x0040U +#define LHD_WINDOW512 0x0060U +#define LHD_WINDOW1024 0x0080U +#define LHD_WINDOW2048 0x00a0U +#define LHD_WINDOW4096 0x00c0U +#define LHD_DIRECTORY 0x00e0U + +#define LHD_LARGE 0x0100U +#define LHD_UNICODE 0x0200U +#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 + +#define EARC_NEXT_VOLUME 0x0001U // Not last volume. +#define EARC_DATACRC 0x0002U // Store CRC32 of RAR archive (now is used only in volumes). +#define EARC_REVSPACE 0x0004U // Reserve space for end of REV file 7 byte record. +#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 +}; + +enum { EA_HEAD=0x100,UO_HEAD=0x101,MAC_HEAD=0x102,BEEA_HEAD=0x103, + NTACL_HEAD=0x104,STREAM_HEAD=0x105 }; + +enum HOST_SYSTEM { + 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 + +#define SUBHEAD_FLAGS_CMT_UNICODE 0x00000001 + +struct OldMainHeader +{ + byte Mark[4]; + ushort HeadSize; + byte Flags; +}; + + +struct OldFileHeader +{ + uint PackSize; + uint UnpSize; + ushort FileCRC; + ushort HeadSize; + uint FileTime; + byte FileAttr; + byte Flags; + byte UnpVer; + byte NameSize; + byte Method; +}; + + +struct MarkHeader +{ + byte Mark[7]; +}; + + +struct BaseBlock +{ + ushort HeadCRC; + HEADER_TYPE HeadType; // 1 byte. + ushort Flags; + ushort HeadSize; + + bool IsSubBlock() + { + if (HeadType==SUB_HEAD) + return(true); + if (HeadType==NEWSUB_HEAD && (Flags & LHD_SOLID)!=0) + return(true); + return(false); + } +}; + +struct BlockHeader:BaseBlock +{ + union { + uint DataSize; + uint PackSize; + }; +}; + + +struct MainHeader:BaseBlock +{ + ushort HighPosAV; + uint PosAV; + byte EncryptVer; +}; + + +#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 */ + 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; + } + + bool CmpName(const char *Name) + { + return(strcmp(FileName,Name)==0); + } + + FileHeader& operator = (FileHeader &hd) + { + SubData.Reset(); + memcpy(this,&hd,sizeof(*this)); + SubData.CleanData(); + SubData=hd.SubData; + return(*this); + } +}; + + +struct EndArcHeader:BaseBlock +{ + // Optional CRC32 of entire archive up to start of EndArcHeader block. + // Present if EARC_DATACRC flag is set. + uint ArcDataCRC; + + // Optional number of current volume. + // Present if EARC_VOLNUMBER flag is set. + ushort VolNumber; + + // 7 additional zero bytes can be stored here if EARC_REVSPACE is set. +}; + + +// SubBlockHeader and its successors were used in RAR 2.x format. +// RAR 3.x uses FileHeader with NEWSUB_HEAD HeadType for subblocks. +struct SubBlockHeader:BlockHeader +{ + ushort SubType; + byte Level; +}; + + +struct CommentHeader:BaseBlock +{ + ushort UnpSize; + byte UnpVer; + byte Method; + ushort CommCRC; +}; + + +struct ProtectHeader:BlockHeader +{ + byte Version; + ushort RecSectors; + uint TotalBlocks; + byte Mark[8]; +}; + + +struct AVHeader:BaseBlock +{ + byte UnpVer; + byte Method; + byte AVVer; + uint AVInfoCRC; +}; + + +struct SignHeader:BaseBlock +{ + uint CreationTime; + ushort ArcNameSize; + ushort UserNameSize; +}; + + +struct UnixOwnersHeader:SubBlockHeader +{ + ushort OwnerNameSize; + ushort GroupNameSize; +/* dummy */ + char OwnerName[NM]; + char GroupName[NM]; +}; + + +struct EAHeader:SubBlockHeader +{ + uint UnpSize; + byte UnpVer; + byte Method; + uint EACRC; +}; + + +struct StreamHeader:SubBlockHeader +{ + uint UnpSize; + byte UnpVer; + byte Method; + uint StreamCRC; + ushort StreamNameSize; +/* dummy */ + byte StreamName[NM]; +}; + + +struct MacFInfoHeader:SubBlockHeader +{ + uint fileType; + uint fileCreator; +}; + + +#endif diff --git a/src/thirdparty/unrar/isnt.cpp b/src/thirdparty/unrar/isnt.cpp new file mode 100644 index 000000000..53c722ab4 --- /dev/null +++ b/src/thirdparty/unrar/isnt.cpp @@ -0,0 +1,24 @@ +#include "rar.hpp" + +#ifdef _WIN_ALL +DWORD WinNT() +{ + static int dwPlatformId=-1; + static DWORD dwMajorVersion,dwMinorVersion; + if (dwPlatformId==-1) + { + OSVERSIONINFO WinVer; + WinVer.dwOSVersionInfoSize=sizeof(WinVer); + GetVersionEx(&WinVer); + dwPlatformId=WinVer.dwPlatformId; + dwMajorVersion=WinVer.dwMajorVersion; + dwMinorVersion=WinVer.dwMinorVersion; + } + DWORD Result=0; + if (dwPlatformId==VER_PLATFORM_WIN32_NT) + Result=dwMajorVersion*0x100+dwMinorVersion; + + + return(Result); +} +#endif diff --git a/src/thirdparty/unrar/isnt.hpp b/src/thirdparty/unrar/isnt.hpp new file mode 100644 index 000000000..520ac8ad7 --- /dev/null +++ b/src/thirdparty/unrar/isnt.hpp @@ -0,0 +1,11 @@ +#ifndef _RAR_ISNT_ +#define _RAR_ISNT_ + +enum WINNT_VERSION { + WNT_NONE=0,WNT_NT351=0x0333,WNT_NT4=0x0400,WNT_W2000=0x0500, + WNT_WXP=0x0501,WNT_W2003=0x0502,WNT_VISTA=0x0600,WNT_W7=0x0601 +}; + +DWORD WinNT(); + +#endif diff --git a/src/thirdparty/unrar/license.txt b/src/thirdparty/unrar/license.txt new file mode 100644 index 000000000..4fc82a7d7 --- /dev/null +++ b/src/thirdparty/unrar/license.txt @@ -0,0 +1,42 @@ + ****** ***** ****** UnRAR - free utility for RAR archives + ** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ****** ******* ****** License for use and distribution of + ** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ** ** ** ** ** ** FREE portable version + ~~~~~~~~~~~~~~~~~~~~~ + + The source code of UnRAR utility is freeware. This means: + + 1. All copyrights to RAR and the utility UnRAR are exclusively + owned by the author - Alexander Roshal. + + 2. UnRAR source code may be used in any software to handle + RAR archives without limitations free of charge, but cannot be + used to develop RAR (WinRAR) compatible archiver and to + re-create RAR compression algorithm, which is proprietary. + Distribution of modified UnRAR source code in separate form + or as a part of other software is permitted, provided that + full text of this paragraph, starting from "UnRAR source code" + words, is included in license, or in documentation if license + is not available, and in source code comments of resulting package. + + 3. The UnRAR utility may be freely distributed. It is allowed + 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, + DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING + OR MISUSING THIS SOFTWARE. + + 5. Installing and using the UnRAR utility signifies acceptance of + these terms and conditions of the license. + + 6. If you don't agree with terms of the license you must remove + UnRAR files from your storage devices and cease to use the + utility. + + Thank you for your interest in RAR and UnRAR. + + + Alexander L. Roshal diff --git a/src/thirdparty/unrar/list.cpp b/src/thirdparty/unrar/list.cpp new file mode 100644 index 000000000..000e92d3f --- /dev/null +++ b/src/thirdparty/unrar/list.cpp @@ -0,0 +1,391 @@ +#include "rar.hpp" + +static void ListFileHeader(FileHeader &hd,bool Verbose,bool Technical,bool &TitleShown,bool Bare); +static void ListSymLink(Archive &Arc); +static void ListFileAttr(uint A,int HostOS); +static void ListOldSubHeader(Archive &Arc); +static void ListNewSubHeader(CommandData *Cmd,Archive &Arc,bool Technical); + +void ListArchive(CommandData *Cmd) +{ + int64 SumPackSize=0,SumUnpSize=0; + uint ArcCount=0,SumFileCount=0; + bool Technical=(Cmd->Command[1]=='T'); + bool Bare=(Cmd->Command[1]=='B'); + bool Verbose=(*Cmd->Command=='V'); + + char ArcName[NM]; + wchar ArcNameW[NM]; + + while (Cmd->GetArcName(ArcName,ArcNameW,sizeof(ArcName))) + { + Archive Arc(Cmd); +#ifdef _WIN_ALL + Arc.RemoveSequentialFlag(); +#endif + if (!Arc.WOpen(ArcName,ArcNameW)) + continue; + bool FileMatched=true; + while (1) + { + int64 TotalPackSize=0,TotalUnpSize=0; + uint FileCount=0; + if (Arc.IsArchive(true)) + { +// if (!Arc.IsOpened()) +// break; + bool TitleShown=false; + if (!Bare) + { + Arc.ViewComment(); + mprintf("\n"); + if (Arc.Solid) + mprintf(St(MListSolid)); + if (Arc.SFXSize>0) + mprintf(St(MListSFX)); + if (Arc.Volume) + if (Arc.Solid) + mprintf(St(MListVol1)); + else + mprintf(St(MListVol2)); + else + if (Arc.Solid) + mprintf(St(MListArc1)); + else + mprintf(St(MListArc2)); + mprintf(" %s\n",Arc.FileName); + if (Technical) + { + if (Arc.Protected) + mprintf(St(MListRecRec)); + if (Arc.Locked) + mprintf(St(MListLock)); + } + } + while(Arc.ReadHeader()>0) + { + int HeaderType=Arc.GetHeaderType(); + if (HeaderType==ENDARC_HEAD) + break; + switch(HeaderType) + { + case FILE_HEAD: + IntToExt(Arc.NewLhd.FileName,Arc.NewLhd.FileName); + FileMatched=Cmd->IsProcessFile(Arc.NewLhd)!=0; + if (FileMatched) + { + ListFileHeader(Arc.NewLhd,Verbose,Technical,TitleShown,Bare); + if (!(Arc.NewLhd.Flags & LHD_SPLIT_BEFORE)) + { + TotalUnpSize+=Arc.NewLhd.FullUnpSize; + FileCount++; + } + TotalPackSize+=Arc.NewLhd.FullPackSize; + if (Technical) + ListSymLink(Arc); +#ifndef SFX_MODULE + if (Verbose) + Arc.ViewFileComment(); +#endif + } + break; +#ifndef SFX_MODULE + case SUB_HEAD: + if (Technical && FileMatched && !Bare) + ListOldSubHeader(Arc); + break; +#endif + case NEWSUB_HEAD: + if (FileMatched && !Bare) + { + if (Technical) + ListFileHeader(Arc.SubHead,Verbose,true,TitleShown,false); + ListNewSubHeader(Cmd,Arc,Technical); + } + break; + } + Arc.SeekToNext(); + } + if (!Bare) + if (TitleShown) + { + mprintf("\n"); + for (int I=0;I<79;I++) + mprintf("-"); + char UnpSizeText[20]; + itoa(TotalUnpSize,UnpSizeText); + + char PackSizeText[20]; + itoa(TotalPackSize,PackSizeText); + + mprintf("\n%5lu %16s %8s %3d%%",FileCount,UnpSizeText, + PackSizeText,ToPercentUnlim(TotalPackSize,TotalUnpSize)); + 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"); + } + else + mprintf(St(MListNoFiles)); + + 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)) + { + Arc.Seek(0,SEEK_SET); + } + else +#endif + break; + } + else + { + if (Cmd->ArcNames->ItemsCount()<2 && !Bare) + mprintf(St(MNotRAR),Arc.FileName); + break; + } + } + } + if (ArcCount>1 && !Bare) + { + char UnpSizeText[20],PackSizeText[20]; + itoa(SumUnpSize,UnpSizeText); + itoa(SumPackSize,PackSizeText); + mprintf("\n%5lu %16s %8s %3d%%\n",SumFileCount,UnpSizeText, + PackSizeText,ToPercentUnlim(SumPackSize,SumUnpSize)); + } +} + + +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; + } + + if (hd.HeadType==NEWSUB_HEAD) + mprintf(St(MSubHeadType),hd.FileName); + + mprintf("\n%c",(hd.Flags & LHD_PASSWORD) ? '*' : ' '); + } + + char *Name=hd.FileName; + +#ifdef UNICODE_SUPPORTED + char ConvertedName[NM]; + if ((hd.Flags & LHD_UNICODE)!=0 && *hd.FileNameW!=0 && UnicodeEnabled()) + { + if (WideToChar(hd.FileNameW,ConvertedName) && *ConvertedName!=0) + Name=ConvertedName; + } +#endif + + if (Bare) + { + mprintf("%s\n",Verbose ? Name:PointToName(Name)); + return; + } + + if (Verbose) + mprintf("%s\n%12s ",Name,""); + else + mprintf("%-12s",PointToName(Name)); + + char UnpSizeText[20],PackSizeText[20]; + if (hd.FullUnpSize==INT64NDF) + strcpy(UnpSizeText,"?"); + else + itoa(hd.FullUnpSize,UnpSizeText); + itoa(hd.FullPackSize,PackSizeText); + + mprintf(" %8s %8s ",UnpSizeText,PackSizeText); + + if ((hd.Flags & LHD_SPLIT_BEFORE) && (hd.Flags & LHD_SPLIT_AFTER)) + mprintf(" <->"); + else + if (hd.Flags & LHD_SPLIT_BEFORE) + mprintf(" <--"); + else + if (hd.Flags & LHD_SPLIT_AFTER) + mprintf(" -->"); + else + mprintf("%3d%%",ToPercentUnlim(hd.FullPackSize,hd.FullUnpSize)); + + char DateStr[50]; + hd.mtime.GetText(DateStr,false); + mprintf(" %s ",DateStr); + + if (hd.HeadType==NEWSUB_HEAD) + mprintf(" %c....B ",(hd.SubFlags & SUBHEAD_FLAGS_INHERITED) ? 'I' : '.'); + else + ListFileAttr(hd.FileAttr,hd.HostOS); + + 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); + + static const char *RarOS[]={ + "DOS","OS/2","Windows","Unix","Mac OS","BeOS","WinCE","","","" + }; + + 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)); +} + + +void ListSymLink(Archive &Arc) +{ + if (Arc.NewLhd.HostOS==HOST_UNIX && (Arc.NewLhd.FileAttr & 0xF000)==0xA000) + if ((Arc.NewLhd.Flags & LHD_PASSWORD)==0) + { + char FileName[NM]; + int DataSize=Min(Arc.NewLhd.PackSize,sizeof(FileName)-1); + Arc.Read(FileName,DataSize); + FileName[DataSize]=0; + mprintf("\n%22s %s","-->",FileName); + } + else + { + // Link data are encrypted. We would need to ask for password + // and initialize decryption routine to display the link target. + mprintf("\n%22s %s","-->","*<-?->"); + } +} + + +void ListFileAttr(uint A,int HostOS) +{ + switch(HostOS) + { + 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' : '.'); + break; + case HOST_UNIX: + case HOST_BEOS: + switch (A & 0xF000) + { + case 0x4000: + mprintf("d"); + break; + case 0xA000: + mprintf("l"); + break; + default: + mprintf("-"); + break; + } + mprintf("%c%c%c%c%c%c%c%c%c", + (A & 0x0100) ? 'r' : '-', + (A & 0x0080) ? 'w' : '-', + (A & 0x0040) ? ((A & 0x0800) ? 's':'x'):((A & 0x0800) ? 'S':'-'), + (A & 0x0020) ? 'r' : '-', + (A & 0x0010) ? 'w' : '-', + (A & 0x0008) ? ((A & 0x0400) ? 's':'x'):((A & 0x0400) ? 'S':'-'), + (A & 0x0004) ? 'r' : '-', + (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); + 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/list.hpp b/src/thirdparty/unrar/list.hpp new file mode 100644 index 000000000..7721ae521 --- /dev/null +++ b/src/thirdparty/unrar/list.hpp @@ -0,0 +1,6 @@ +#ifndef _RAR_LIST_ +#define _RAR_LIST_ + +void ListArchive(CommandData *Cmd); + +#endif diff --git a/src/thirdparty/unrar/loclang.hpp b/src/thirdparty/unrar/loclang.hpp new file mode 100644 index 000000000..2d69b3972 --- /dev/null +++ b/src/thirdparty/unrar/loclang.hpp @@ -0,0 +1,357 @@ +#define MYesNo "_Yes_No" +#define MYesNoAll "_Yes_No_All" +#define MYesNoAllQ "_Yes_No_All_nEver_Quit" +#define MYesNoAllRenQ "_Yes_No_All_nEver_Rename_Quit" +#define MContinueQuit "_Continue_Quit" +#define MRetryAbort "_Retry_Abort" +#define MCopyright "\nRAR %s Copyright (c) 1993-%d Alexander Roshal %d %s %d" +#define MRegTo "\nRegistered to %s\n" +#define MShare "\nTrial version Type RAR -? for help\n" +#define MUCopyright "\nUNRAR %s freeware Copyright (c) 1993-%d Alexander Roshal\n" +#define MBeta "beta" +#define MMonthJan "Jan" +#define MMonthFeb "Feb" +#define MMonthMar "Mar" +#define MMonthApr "Apr" +#define MMonthMay "May" +#define MMonthJun "Jun" +#define MMonthJul "Jul" +#define MMonthAug "Aug" +#define MMonthSep "Sep" +#define MMonthOct "Oct" +#define MMonthNov "Nov" +#define MMonthDec "Dec" +#define MRARTitle1 "\nUsage: rar <command> -<switch 1> -<switch N> <archive> <files...>" +#define MUNRARTitle1 "\nUsage: unrar <command> -<switch 1> -<switch N> <archive> <files...>" +#define MRARTitle2 "\n <@listfiles...> <path_to_extract\\>" +#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 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 MCHelpCmdM "\n m[f] Move to archive [files only]" +#define MCHelpCmdP "\n p Print file to stdout" +#define MCHelpCmdR "\n r Repair archive" +#define MCHelpCmdRC "\n rc Reconstruct missing volumes" +#define MCHelpCmdRN "\n rn Rename archived files" +#define MCHelpCmdRR "\n rr[N] Add data recovery record" +#define MCHelpCmdRV "\n rv[N] Create recovery volumes" +#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 MCHelpCmdX "\n x Extract files with full path" +#define MCHelpSw "\n\n<Switches>" +#define MCHelpSwm "\n - Stop switches scanning" +#define MCHelpSwAT "\n @[+] Disable [enable] file lists" +#define MCHelpSwAC "\n ac Clear Archive attribute after compression or extraction" +#define MCHelpSwAD "\n ad Append archive name to destination path" +#define MCHelpSwAG "\n ag[format] Generate archive name using the current date" +#define MCHelpSwAI "\n ai Ignore file attributes" +#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" +#define MCHelpSwCU "\n cu Convert names to upper case" +#define MCHelpSwDF "\n df Delete files after archiving" +#define MCHelpSwDH "\n dh Open shared files" +#define MCHelpSwDR "\n dr Delete files to Recycle Bin" +#define MCHelpSwDS "\n ds Disable name sort for solid archive" +#define MCHelpSwDW "\n dw Wipe files after archiving" +#define MCHelpSwEa "\n e[+]<attr> Set file exclude and include attributes" +#define MCHelpSwED "\n ed Do not add empty directories" +#define MCHelpSwEE "\n ee Do not save and extract extended attributes" +#define MCHelpSwEN "\n en Do not put 'end of archive' block" +#define MCHelpSwEP "\n ep Exclude paths from names" +#define MCHelpSwEP1 "\n ep1 Exclude base directory from names" +#define MCHelpSwEP2 "\n ep2 Expand paths to full" +#define MCHelpSwEP3 "\n ep3 Expand paths to full including the drive letter" +#define MCHelpSwF "\n f Freshen files" +#define MCHelpSwHP "\n hp[password] Encrypt both file data and headers" +#define MCHelpSwIDP "\n id[c,d,p,q] Disable messages" +#define MCHelpSwIEML "\n ieml[addr] Send archive by email" +#define MCHelpSwIERR "\n ierr Send all messages to stderr" +#define MCHelpSwILOG "\n ilog[name] Log errors to file (registered versions only)" +#define MCHelpSwINUL "\n inul Disable all messages" +#define MCHelpSwIOFF "\n ioff Turn PC off after completing an operation" +#define MCHelpSwISND "\n isnd Enable sound" +#define MCHelpSwK "\n k Lock archive" +#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 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 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 MCHelpSwO "\n o[+|-] Set the overwrite mode" +#define MCHelpSwOC "\n oc Set NTFS Compressed attribute" +#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 MCHelpSwR "\n r Recurse subdirectories" +#define MCHelpSwRm "\n r- Disable recursion" +#define MCHelpSwR0 "\n r0 Recurse subdirectories for wildcard names only" +#define MCHelpSwRI "\n ri<P>[:<S>] Set priority (0-default,1-min..15-max) and sleep time in ms" +#define MCHelpSwRR "\n rr[N] Add data recovery record" +#define MCHelpSwRV "\n rv[N] Create recovery volumes" +#define MCHelpSwS "\n s[<N>,v[-],e] Create solid archive" +#define MCHelpSwSm "\n s- Disable solid archiving" +#define MCHelpSwSC "\n sc<chr>[obj] Specify the character set" +#define MCHelpSwSFX "\n sfx[name] Create SFX archive" +#define MCHelpSwSI "\n si[name] Read data from standard input (stdin)" +#define MCHelpSwSL "\n sl<size> Process files with size less than specified" +#define MCHelpSwSM "\n sm<size> Process files with size more than specified" +#define MCHelpSwT "\n t Test files after archiving" +#define MCHelpSwTK "\n tk Keep original archive time" +#define MCHelpSwTL "\n tl Set archive time to latest file" +#define MCHelpSwTN "\n tn<time> Process files newer than <time>" +#define MCHelpSwTO "\n to<time> Process files older than <time>" +#define MCHelpSwTA "\n ta<date> Process files modified after <date> in YYYYMMDDHHMMSS format" +#define MCHelpSwTB "\n tb<date> Process files modified before <date> in YYYYMMDDHHMMSS format" +#define MCHelpSwTS "\n ts<m,c,a>[N] Save or restore file time (modification, creation, access)" +#define MCHelpSwU "\n u Update files" +#define MCHelpSwV "\n v Create volumes with size autodetection or list all volumes" +#define MCHelpSwVUnr "\n v List all volumes" +#define MCHelpSwVn "\n v<size>[k,b] Create volumes with size=<size>*1000 [*1024, *1]" +#define MCHelpSwVD "\n vd Erase disk contents before creating volume" +#define MCHelpSwVER "\n ver[n] File version control" +#define MCHelpSwVN "\n vn Use the old style volume naming scheme" +#define MCHelpSwVP "\n vp Pause before each volume" +#define MCHelpSwW "\n w<path> Assign work directory" +#define MCHelpSwX "\n x<file> Exclude specified file" +#define MCHelpSwXa "\n x@ Read file names to exclude from stdin" +#define MCHelpSwXal "\n x@<list> Exclude files listed in specified list file" +#define MCHelpSwY "\n y Assume Yes on all queries" +#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 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" +#define MErrSeek "Seek error in the file %s" +#define MErrFClose "Cannot close the file %s" +#define MErrOutMem "Not enough memory" +#define MErrBrokenArc "Corrupt archive - use 'Repair' command" +#define MProgAborted "Program aborted" +#define MErrRename "\nCannot rename %s to %s" +#define MAbsNextVol "\nCannot find volume %s" +#define MBreak "\nUser break\n" +#define MAskCreatVol "\nCreate next volume ?" +#define MAskNextDisk "\nDisk full. Insert next" +#define MCreatVol "\n\nCreating %sarchive %s\n" +#define MAskNextVol "\nInsert disk with %s" +#define MTestVol "\n\nTesting archive %s\n" +#define MExtrVol "\n\nExtracting from %s\n" +#define MConverting "\nConverting %s" +#define MCvtToSFX "\nConvert archives to SFX" +#define MCvtFromSFX "\nRemoving SFX module" +#define MNotSFX "\n%s is not SFX archive" +#define MNotRAR "\n%s is not RAR archive" +#define MNotFirstVol "\n%s is not the first volume" +#define MCvtOldFormat "\n%s - cannot convert to SFX archive with old format" +#define MCannotCreate "\nCannot create %s" +#define MCannotOpen "\nCannot open %s" +#define MUnknownMeth "\nUnknown method in %s" +#define MVerRequired "\nYou need RAR %d.%d to unpack it" +#define MNewRarFormat "\nUnsupported archive format. Please update RAR to a newer version." +#define MOk " OK" +#define MDone "\nDone" +#define MLockingArc "\nLocking archive" +#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" +#define MAddSolid "solid " +#define MAddFile "\nAdding %-58s " +#define MUpdFile "\nUpdating %-58s " +#define MAddPoints "\n... %-58s " +#define MCannotUpdPswSolid "\nERROR: Cannot update solid archives with password\n" +#define MMoveDelFiles "\n\nDeleting files %s..." +#define MMoveDelDirs "and directories" +#define MMoveDelFile "\nDeleting %-30s" +#define MMoveDeleted " deleted" +#define MMoveNotDeleted " NOT DELETED" +#define MClearAttrib "\n\nClearing attributes..." +#define MMoveDelDir "\nDeleting directory %-30s" +#define MWarErrFOpen "\nWARNING: Cannot open %d %s" +#define MErrOpenFiles "files" +#define MErrOpenFile "file" +#define MAddNoFiles "\nWARNING: No files" +#define MMdfEncrSol "\n%s: encrypted" +#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 MExtrTest "\n\nTesting archive %s\n" +#define MExtracting "\n\nExtracting from %s\n" +#define MUseCurPsw "\n%s - use current password ?" +#define MCreatDir "\nCreating %-56s" +#define MExtrSkipFile "\nSkipping %-56s" +#define MExtrTestFile "\nTesting %-56s" +#define MExtrFile "\nExtracting %-56s" +#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 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 MLogFileHead "\n%s - the file header is corrupt" +#define MLogCommHead "\nThe comment header is corrupt\n" +#define MLogProtectHead "The data recovery header is corrupt" +#define MReadStdinCmt "\nReading comment from stdin\n" +#define MReadCommFrom "\nReading comment from %s" +#define MDelComment "\nDeleting comment from %s" +#define MAddComment "\nAdding comment to %s" +#define MFCommAdd "\nAdding file comments" +#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" +#define MDeleting "\nDeleting %s" +#define MEraseArc "\nErasing empty archive %s" +#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 MListEAHead "\n OS/2 extended attributes" +#define MListUOHead "\n Unix Owner/Group data: %-14s %-14s" +#define MListBeEAHead "\n BeOS extended attributes" +#define MListNTACLHead "\n NTFS security data" +#define MListStrmHead "\n NTFS stream: %s" +#define MListUnkHead "\n Unknown subheader type: 0x%04x" +#define MFileComment "\nComment: " +#define MYes "Yes" +#define MNo "No" +#define MListNoFiles " 0 files\n" +#define MRprReconstr "\nReconstructing %s" +#define MRprBuild "\nBuilding %s" +#define MRprOldFormat "\nCannot repair archive with old format" +#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..." +#define MRecRNotFound "\nData recovery record not found" +#define MRecRFound "\nData recovery record found" +#define MRecSecDamage "\nSector %ld (offsets %lX...%lX) damaged" +#define MRecCorrected " - data recovered" +#define MRecFailed " - cannot recover data" +#define MAddRecRec "\nAdding data recovery record" +#define MEraseForVolume "\n\nErasing contents of drive %c:\n" +#define MGetOwnersError "\nWARNING: Cannot get %s owner and group\n" +#define MErrGetOwnerID "\nWARNING: Cannot get owner %s ID\n" +#define MErrGetGroupID "\nWARNING: Cannot get group %s ID\n" +#define MOwnersBroken "\nERROR: %s group and owner data are corrupt\n" +#define MSetOwnersError "\nWARNING: Cannot set %s owner and group\n" +#define MErrLnkRead "\nWARNING: Cannot read symbolic link %s" +#define MErrCreateLnk "\nWARNING: Cannot create link %s" +#define MSymLinkExists "\nWARNING: Symbolic link %s already exists" +#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 MFileRO "\n%s is read-only" +#define MACLGetError "\nWARNING: Cannot get %s security data\n" +#define MACLSetError "\nWARNING: Cannot set %s security data\n" +#define MACLBroken "\nERROR: %s security data are corrupt\n" +#define MACLUnknown "\nWARNING: Unknown format of %s security data\n" +#define MStreamBroken "\nERROR: %s stream data are corrupt\n" +#define MStreamUnknown "\nWARNING: Unknown format of %s stream data\n" +#define MInvalidName "\nERROR: Invalid file name %s" +#define MEABroken "\nERROR: %s extended attributes are corrupt\n" +#define MEAUnknHeader "\nWARNING: %s - unknown format of extended attributes\n" +#define MCannotSetEA "\nWARNING: cannot set extended attributes to %s\n" +#define MCannotGetEA "\nERROR: Cannot get extended attributes of %s\n" +#define MShowEA " (+EA)" +#define MSkipEA "\n...skipping extended attributes" +#define MProcessArc "\n\nProcessing archive %s" +#define MSyncScanError "\nFile search errors, cannot synchronize archive" +#define MCorrectingName "\nWARNING: Attempting to correct the invalid file name" +#define MUnpCannotMerge "\nWARNING: You need to start extraction from a previous volume to unpack %s" +#define MUnknownOption "\nERROR: Unknown option: %s" +#define MSubHeadCorrupt "\nERROR: Corrupt data header found, ignored" +#define MSubHeadUnknown "\nWARNING: Unknown data header format, ignored" +#define MSubHeadDataCRC "\nERROR: Corrupt %s data block" +#define MSubHeadType "\nData header type: %s" +#define MScanError "\nCannot read contents of %s" +#define MNotVolume "\n%s is not volume" +#define MRecVolDiffSets "\nERROR: %s and %s belong to different sets" +#define MRecVolMissing "\n%d volumes missing" +#define MRecVolFound "\n%d recovery volumes found" +#define MRecVolAllExist "\nNothing to reconstruct" +#define MRecVolCannotFix "\nReconstruction impossible" +#define MReconstructing "\nReconstructing..." +#define MCreating "\nCreating %s" +#define MRenaming "\nRenaming %s to %s" +#define MNTFSRequired "\nWrite error: only NTFS file system supports files larger than 4 GB" +#define MErrChangeAttr "\nWARNING: Cannot change attributes of %s" +#define MWrongSFXVer "\nERROR: default SFX module does not support RAR %d.%d archives" +#define MCannotEncName "\nCannot encrypt archive already contained encrypted files" +#define MCannotEmail "\nCannot email the file %s" +#define MCopyrightS "\nRAR SFX archive" +#define MSHelpCmd "\n\n<Commands>" +#define MSHelpCmdE "\n -x Extract from archive (default)" +#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 MVolumeNumber "volume %d" +#define MCannotDelete "\nCannot delete %s" +#define MCalcCRC "\nCalculating the control sum" +#define MTooLargeSFXArc "\nWARNING: Too large SFX archive. Windows cannot run the executable file exceeding 4 GB." +#define MCalcCRCAllVol "\nCalculating control sums of all volumes." +#define MNotEnoughDisk "\nERROR: Not enough disk space for %s." diff --git a/src/thirdparty/unrar/log.cpp b/src/thirdparty/unrar/log.cpp new file mode 100644 index 000000000..966e9de15 --- /dev/null +++ b/src/thirdparty/unrar/log.cpp @@ -0,0 +1,24 @@ +#include "rar.hpp" + + +static char LogName[NM]; + +void InitLogOptions(char *LogName) +{ + strcpy(::LogName,LogName); +} + + +#ifndef SILENT +void Log(const char *ArcName,const char *Format,...) +{ + safebuf char Msg[2*NM+1024]; + va_list ArgPtr; + va_start(ArgPtr,Format); + vsprintf(Msg,Format,ArgPtr); + va_end(ArgPtr); + eprintf("%s",Msg); +} +#endif + + diff --git a/src/thirdparty/unrar/log.hpp b/src/thirdparty/unrar/log.hpp new file mode 100644 index 000000000..52d6b8d56 --- /dev/null +++ b/src/thirdparty/unrar/log.hpp @@ -0,0 +1,18 @@ +#ifndef _RAR_LOG_ +#define _RAR_LOG_ + +void InitLogOptions(char *LogName); + +#ifndef SILENT +void Log(const char *ArcName,const char *Format,...); +#endif + +#ifdef SILENT +#ifdef __GNUC__ +#define Log(args...) +#else +inline void Log(const char *a,const char *b,const char *c=NULL,const char *d=NULL) {} +#endif +#endif + +#endif diff --git a/src/thirdparty/unrar/match.cpp b/src/thirdparty/unrar/match.cpp new file mode 100644 index 000000000..4d5a1d053 --- /dev/null +++ b/src/thirdparty/unrar/match.cpp @@ -0,0 +1,300 @@ +#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); +#if defined(_UNIX) + return(ch); +#else + 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; + + CmpMode&=MATCH_MODEMASK; + + if (CmpMode!=MATCH_NAMES) + { + size_t WildLength=wcslen(Wildcard); + if (CmpMode!=MATCH_EXACT && CmpMode!=MATCH_EXACTPATH && + mwcsnicompc(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. + wchar NextCh=Name[WildLength]; + if (NextCh==L'\\' || NextCh==L'/' || NextCh==0) + return(true); + } + + // Nothing more to compare for MATCH_SUBPATHONLY. + if (CmpMode==MATCH_SUBPATHONLY) + return(false); + + wchar Path1[NM],Path2[NM]; + GetFilePath(Wildcard,Path1,ASIZE(Path1)); + GetFilePath(Name,Path2,ASIZE(Path2)); + + if ((CmpMode==MATCH_EXACT || CmpMode==MATCH_EXACTPATH) && + mwcsicompc(Path1,Path2,ForceCase)!=0) + return(false); + if (CmpMode==MATCH_SUBPATH || CmpMode==MATCH_WILDSUBPATH) + if (IsWildcard(NULL,Path1)) + return(match(Wildcard,Name,ForceCase)); + else + if (CmpMode==MATCH_SUBPATH || IsWildcard(NULL,Wildcard)) + { + if (*Path1 && mwcsnicompc(Path1,Path2,wcslen(Path1),ForceCase)!=0) + return(false); + } + else + if (mwcsicompc(Path1,Path2,ForceCase)!=0) + return(false); + } + wchar *Name1=PointToName(Wildcard); + wchar *Name2=PointToName(Name); + + // Always return false for RAR temporary files to exclude them + // from archiving operations. + if (mwcsnicompc(L"__rar_",Name2,6,false)==0) + return(false); + + if (CmpMode==MATCH_EXACT) + return(mwcsicompc(Name1,Name2,ForceCase)==0); + + 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) + { + wchar stringc=touppercw(*string,ForceCase); + wchar patternc=touppercw(*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 wchar *dot=wcschr(string,'.'); + if (pattern[1]==0) + return (dot==NULL || dot[1]==0); + if (dot!=NULL) + { + string=dot; + if (wcspbrk(pattern,L"*?")==NULL && wcschr(string+1,'.')==NULL) + return(mwcsicompc(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; + } + } +} +#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) + return(wcsncmp(Str1,Str2,N)); +#if defined(_UNIX) + return(wcsncmp(Str1,Str2,N)); +#else + return(wcsnicomp(Str1,Str2,N)); +#endif +} +#endif diff --git a/src/thirdparty/unrar/match.hpp b/src/thirdparty/unrar/match.hpp new file mode 100644 index 000000000..697286d85 --- /dev/null +++ b/src/thirdparty/unrar/match.hpp @@ -0,0 +1,35 @@ +#ifndef _RAR_MATCH_ +#define _RAR_MATCH_ + +enum { + MATCH_NAMES, // Paths are ignored. + // Compares names only using wildcards. + + MATCH_SUBPATHONLY, // Paths must match either exactly or path in wildcard + // must be present in the beginning of file path. + // For example, "c:\path1\*" or "c:\path1" will match + // "c:\path1\path2\file". + // Names are not compared. + + MATCH_EXACT, // Paths must match exactly. + // Names must match exactly. + + MATCH_EXACTPATH, // Paths must match exactly. + // Names are compared using wildcards. + + MATCH_SUBPATH, // Names must be the same, but path in mask is allowed + // to be only a part of name path. In other words, + // we match all files matching the file mask + // in current folder and subfolders. + + MATCH_WILDSUBPATH // Works as MATCH_SUBPATH if file mask contains + // wildcards and as MATCH_EXACTPATH otherwise. +}; + +#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/model.cpp b/src/thirdparty/unrar/model.cpp new file mode 100644 index 000000000..fb28c0774 --- /dev/null +++ b/src/thirdparty/unrar/model.cpp @@ -0,0 +1,610 @@ +/**************************************************************************** + * This file is part of PPMd project * + * Written and distributed to public domain by Dmitry Shkarin 1997, * + * 1999-2000 * + * Contents: model description and encoding/decoding routines * + ****************************************************************************/ + +inline PPM_CONTEXT* PPM_CONTEXT::createChild(ModelPPM *Model,STATE* pStats, + STATE& FirstState) +{ + PPM_CONTEXT* pc = (PPM_CONTEXT*) Model->SubAlloc.AllocContext(); + if ( pc ) + { + pc->NumStats=1; + pc->OneState=FirstState; + pc->Suffix=this; + pStats->Successor=pc; + } + return pc; +} + + +ModelPPM::ModelPPM() +{ + MinContext=NULL; + MaxContext=NULL; + MedContext=NULL; +} + + +void ModelPPM::RestartModelRare() +{ + int i, k, m; + memset(CharMask,0,sizeof(CharMask)); + SubAlloc.InitSubAllocator(); + InitRL=-(MaxOrder < 12 ? MaxOrder:12)-1; + MinContext = MaxContext = (PPM_CONTEXT*) SubAlloc.AllocContext(); + MinContext->Suffix=NULL; + OrderFall=MaxOrder; + MinContext->U.SummFreq=(MinContext->NumStats=256)+1; + FoundState=MinContext->U.Stats=(STATE*)SubAlloc.AllocUnits(256/2); + for (RunLength=InitRL, PrevSuccess=i=0;i < 256;i++) + { + MinContext->U.Stats[i].Symbol=i; + MinContext->U.Stats[i].Freq=1; + MinContext->U.Stats[i].Successor=NULL; + } + + static const ushort InitBinEsc[]={ + 0x3CDD,0x1F3F,0x59BF,0x48F3,0x64A1,0x5ABC,0x6632,0x6051 + }; + + for (i=0;i < 128;i++) + for (k=0;k < 8;k++) + for (m=0;m < 64;m += 8) + BinSumm[i][k+m]=BIN_SCALE-InitBinEsc[k]/(i+2); + for (i=0;i < 25;i++) + for (k=0;k < 16;k++) + SEE2Cont[i][k].init(5*i+10); +} + + +void ModelPPM::StartModelRare(int MaxOrder) +{ + int i, k, m ,Step; + EscCount=1; +/* + if (MaxOrder < 2) + { + memset(CharMask,0,sizeof(CharMask)); + OrderFall=ModelPPM::MaxOrder; + MinContext=MaxContext; + while (MinContext->Suffix != NULL) + { + MinContext=MinContext->Suffix; + OrderFall--; + } + FoundState=MinContext->U.Stats; + MinContext=MaxContext; + } + else +*/ + { + ModelPPM::MaxOrder=MaxOrder; + RestartModelRare(); + NS2BSIndx[0]=2*0; + NS2BSIndx[1]=2*1; + memset(NS2BSIndx+2,2*2,9); + memset(NS2BSIndx+11,2*3,256-11); + for (i=0;i < 3;i++) + NS2Indx[i]=i; + for (m=i, k=Step=1;i < 256;i++) + { + NS2Indx[i]=m; + if ( !--k ) + { + k = ++Step; + m++; + } + } + memset(HB2Flag,0,0x40); + memset(HB2Flag+0x40,0x08,0x100-0x40); + DummySEE2Cont.Shift=PERIOD_BITS; + } +} + + +void PPM_CONTEXT::rescale(ModelPPM *Model) +{ + int OldNS=NumStats, i=NumStats-1, Adder, EscFreq; + STATE* p1, * p; + for (p=Model->FoundState;p != U.Stats;p--) + _PPMD_SWAP(p[0],p[-1]); + U.Stats->Freq += 4; + U.SummFreq += 4; + EscFreq=U.SummFreq-p->Freq; + Adder=(Model->OrderFall != 0); + U.SummFreq = (p->Freq=(p->Freq+Adder) >> 1); + do + { + EscFreq -= (++p)->Freq; + U.SummFreq += (p->Freq=(p->Freq+Adder) >> 1); + if (p[0].Freq > p[-1].Freq) + { + STATE tmp=*(p1=p); + do + { + p1[0]=p1[-1]; + } while (--p1 != U.Stats && tmp.Freq > p1[-1].Freq); + *p1=tmp; + } + } while ( --i ); + if (p->Freq == 0) + { + do + { + i++; + } while ((--p)->Freq == 0); + EscFreq += i; + if ((NumStats -= i) == 1) + { + STATE tmp=*U.Stats; + do + { + tmp.Freq-=(tmp.Freq >> 1); + EscFreq>>=1; + } while (EscFreq > 1); + Model->SubAlloc.FreeUnits(U.Stats,(OldNS+1) >> 1); + *(Model->FoundState=&OneState)=tmp; return; + } + } + U.SummFreq += (EscFreq -= (EscFreq >> 1)); + int n0=(OldNS+1) >> 1, n1=(NumStats+1) >> 1; + if (n0 != n1) + U.Stats = (STATE*) Model->SubAlloc.ShrinkUnits(U.Stats,n0,n1); + Model->FoundState=U.Stats; +} + + +inline PPM_CONTEXT* ModelPPM::CreateSuccessors(bool Skip,STATE* p1) +{ +#ifdef __ICL + static +#endif + STATE UpState; + PPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor; + STATE * p, * ps[MAX_O], ** pps=ps; + if ( !Skip ) + { + *pps++ = FoundState; + if ( !pc->Suffix ) + goto NO_LOOP; + } + if ( p1 ) + { + p=p1; + pc=pc->Suffix; + goto LOOP_ENTRY; + } + do + { + pc=pc->Suffix; + if (pc->NumStats != 1) + { + if ((p=pc->U.Stats)->Symbol != FoundState->Symbol) + do + { + p++; + } while (p->Symbol != FoundState->Symbol); + } + else + p=&(pc->OneState); +LOOP_ENTRY: + if (p->Successor != UpBranch) + { + pc=p->Successor; + break; + } + *pps++ = p; + } while ( pc->Suffix ); +NO_LOOP: + if (pps == ps) + return pc; + UpState.Symbol=*(byte*) UpBranch; + UpState.Successor=(PPM_CONTEXT*) (((byte*) UpBranch)+1); + if (pc->NumStats != 1) + { + if ((byte*) pc <= SubAlloc.pText) + return(NULL); + if ((p=pc->U.Stats)->Symbol != UpState.Symbol) + do + { + p++; + } while (p->Symbol != UpState.Symbol); + uint cf=p->Freq-1; + uint s0=pc->U.SummFreq-pc->NumStats-cf; + UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0))); + } + else + UpState.Freq=pc->OneState.Freq; + do + { + pc = pc->createChild(this,*--pps,UpState); + if ( !pc ) + return NULL; + } while (pps != ps); + return pc; +} + + +inline void ModelPPM::UpdateModel() +{ + STATE fs = *FoundState, *p = NULL; + PPM_CONTEXT *pc, *Successor; + uint ns1, ns, cf, sf, s0; + if (fs.Freq < MAX_FREQ/4 && (pc=MinContext->Suffix) != NULL) + { + if (pc->NumStats != 1) + { + if ((p=pc->U.Stats)->Symbol != fs.Symbol) + { + do + { + p++; + } while (p->Symbol != fs.Symbol); + if (p[0].Freq >= p[-1].Freq) + { + _PPMD_SWAP(p[0],p[-1]); + p--; + } + } + if (p->Freq < MAX_FREQ-9) + { + p->Freq += 2; + pc->U.SummFreq += 2; + } + } + else + { + p=&(pc->OneState); + p->Freq += (p->Freq < 32); + } + } + if ( !OrderFall ) + { + MinContext=MaxContext=FoundState->Successor=CreateSuccessors(TRUE,p); + if ( !MinContext ) + goto RESTART_MODEL; + return; + } + *SubAlloc.pText++ = fs.Symbol; + Successor = (PPM_CONTEXT*) SubAlloc.pText; + if (SubAlloc.pText >= SubAlloc.FakeUnitsStart) + goto RESTART_MODEL; + if ( fs.Successor ) + { + if ((byte*) fs.Successor <= SubAlloc.pText && + (fs.Successor=CreateSuccessors(FALSE,p)) == NULL) + goto RESTART_MODEL; + if ( !--OrderFall ) + { + Successor=fs.Successor; + SubAlloc.pText -= (MaxContext != MinContext); + } + } + else + { + FoundState->Successor=Successor; + fs.Successor=MinContext; + } + s0=MinContext->U.SummFreq-(ns=MinContext->NumStats)-(fs.Freq-1); + for (pc=MaxContext;pc != MinContext;pc=pc->Suffix) + { + if ((ns1=pc->NumStats) != 1) + { + if ((ns1 & 1) == 0) + { + pc->U.Stats=(STATE*) SubAlloc.ExpandUnits(pc->U.Stats,ns1 >> 1); + if ( !pc->U.Stats ) + goto RESTART_MODEL; + } + pc->U.SummFreq += (2*ns1 < ns)+2*((4*ns1 <= ns) & (pc->U.SummFreq <= 8*ns1)); + } + else + { + p=(STATE*) SubAlloc.AllocUnits(1); + if ( !p ) + goto RESTART_MODEL; + *p=pc->OneState; + pc->U.Stats=p; + if (p->Freq < MAX_FREQ/4-1) + p->Freq += p->Freq; + else + p->Freq = MAX_FREQ-4; + pc->U.SummFreq=p->Freq+InitEsc+(ns > 3); + } + cf=2*fs.Freq*(pc->U.SummFreq+6); + sf=s0+pc->U.SummFreq; + if (cf < 6*sf) + { + cf=1+(cf > sf)+(cf >= 4*sf); + pc->U.SummFreq += 3; + } + else + { + cf=4+(cf >= 9*sf)+(cf >= 12*sf)+(cf >= 15*sf); + pc->U.SummFreq += cf; + } + p=pc->U.Stats+ns1; + p->Successor=Successor; + p->Symbol = fs.Symbol; + p->Freq = cf; + pc->NumStats=++ns1; + } + MaxContext=MinContext=fs.Successor; + return; +RESTART_MODEL: + RestartModelRare(); + EscCount=0; +} + + +// Tabulated escapes for exponential symbol distribution +static const byte ExpEscape[16]={ 25,14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 }; +#define GET_MEAN(SUMM,SHIFT,ROUND) ((SUMM+(1 << (SHIFT-ROUND))) >> (SHIFT)) + + + +inline void PPM_CONTEXT::decodeBinSymbol(ModelPPM *Model) +{ + STATE& rs=OneState; + Model->HiBitsFlag=Model->HB2Flag[Model->FoundState->Symbol]; + ushort& bs=Model->BinSumm[rs.Freq-1][Model->PrevSuccess+ + Model->NS2BSIndx[Suffix->NumStats-1]+ + Model->HiBitsFlag+2*Model->HB2Flag[rs.Symbol]+ + ((Model->RunLength >> 26) & 0x20)]; + if (Model->Coder.GetCurrentShiftCount(TOT_BITS) < bs) + { + Model->FoundState=&rs; + rs.Freq += (rs.Freq < 128); + Model->Coder.SubRange.LowCount=0; + Model->Coder.SubRange.HighCount=bs; + bs = GET_SHORT16(bs+INTERVAL-GET_MEAN(bs,PERIOD_BITS,2)); + Model->PrevSuccess=1; + Model->RunLength++; + } + else + { + Model->Coder.SubRange.LowCount=bs; + bs = GET_SHORT16(bs-GET_MEAN(bs,PERIOD_BITS,2)); + Model->Coder.SubRange.HighCount=BIN_SCALE; + Model->InitEsc=ExpEscape[bs >> 10]; + Model->NumMasked=1; + Model->CharMask[rs.Symbol]=Model->EscCount; + Model->PrevSuccess=0; + Model->FoundState=NULL; + } +} + + +inline void PPM_CONTEXT::update1(ModelPPM *Model,STATE* p) +{ + (Model->FoundState=p)->Freq += 4; + U.SummFreq += 4; + if (p[0].Freq > p[-1].Freq) + { + _PPMD_SWAP(p[0],p[-1]); + Model->FoundState=--p; + if (p->Freq > MAX_FREQ) + rescale(Model); + } +} + + + + +inline bool PPM_CONTEXT::decodeSymbol1(ModelPPM *Model) +{ + Model->Coder.SubRange.scale=U.SummFreq; + STATE* p=U.Stats; + int i, HiCnt; + int count=Model->Coder.GetCurrentCount(); + if (count>=(int)Model->Coder.SubRange.scale) + return(false); + if (count < (HiCnt=p->Freq)) + { + Model->PrevSuccess=(2*(Model->Coder.SubRange.HighCount=HiCnt) > Model->Coder.SubRange.scale); + Model->RunLength += Model->PrevSuccess; + (Model->FoundState=p)->Freq=(HiCnt += 4); + U.SummFreq += 4; + if (HiCnt > MAX_FREQ) + rescale(Model); + Model->Coder.SubRange.LowCount=0; + return(true); + } + else + if (Model->FoundState==NULL) + return(false); + Model->PrevSuccess=0; + i=NumStats-1; + while ((HiCnt += (++p)->Freq) <= count) + if (--i == 0) + { + Model->HiBitsFlag=Model->HB2Flag[Model->FoundState->Symbol]; + Model->Coder.SubRange.LowCount=HiCnt; + Model->CharMask[p->Symbol]=Model->EscCount; + i=(Model->NumMasked=NumStats)-1; + Model->FoundState=NULL; + do + { + Model->CharMask[(--p)->Symbol]=Model->EscCount; + } while ( --i ); + Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale; + return(true); + } + Model->Coder.SubRange.LowCount=(Model->Coder.SubRange.HighCount=HiCnt)-p->Freq; + update1(Model,p); + return(true); +} + + +inline void PPM_CONTEXT::update2(ModelPPM *Model,STATE* p) +{ + (Model->FoundState=p)->Freq += 4; + U.SummFreq += 4; + if (p->Freq > MAX_FREQ) + rescale(Model); + Model->EscCount++; + Model->RunLength=Model->InitRL; +} + + +inline SEE2_CONTEXT* PPM_CONTEXT::makeEscFreq2(ModelPPM *Model,int Diff) +{ + SEE2_CONTEXT* psee2c; + if (NumStats != 256) + { + psee2c=Model->SEE2Cont[Model->NS2Indx[Diff-1]]+ + (Diff < Suffix->NumStats-NumStats)+ + 2*(U.SummFreq < 11*NumStats)+4*(Model->NumMasked > Diff)+ + Model->HiBitsFlag; + Model->Coder.SubRange.scale=psee2c->getMean(); + } + else + { + psee2c=&Model->DummySEE2Cont; + Model->Coder.SubRange.scale=1; + } + return psee2c; +} + + + + +inline bool PPM_CONTEXT::decodeSymbol2(ModelPPM *Model) +{ + int count, HiCnt, i=NumStats-Model->NumMasked; + SEE2_CONTEXT* psee2c=makeEscFreq2(Model,i); + STATE* ps[256], ** pps=ps, * p=U.Stats-1; + HiCnt=0; + do + { + do + { + p++; + } while (Model->CharMask[p->Symbol] == Model->EscCount); + HiCnt += p->Freq; + *pps++ = p; + } while ( --i ); + Model->Coder.SubRange.scale += HiCnt; + count=Model->Coder.GetCurrentCount(); + if (count>=(int)Model->Coder.SubRange.scale) + return(false); + p=*(pps=ps); + if (count < HiCnt) + { + HiCnt=0; + while ((HiCnt += p->Freq) <= count) + p=*++pps; + Model->Coder.SubRange.LowCount = (Model->Coder.SubRange.HighCount=HiCnt)-p->Freq; + psee2c->update(); + update2(Model,p); + } + else + { + Model->Coder.SubRange.LowCount=HiCnt; + Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale; + i=NumStats-Model->NumMasked; + pps--; + do + { + Model->CharMask[(*++pps)->Symbol]=Model->EscCount; + } while ( --i ); + psee2c->Summ += Model->Coder.SubRange.scale; + Model->NumMasked = NumStats; + } + return(true); +} + + +inline void ModelPPM::ClearMask() +{ + EscCount=1; + memset(CharMask,0,sizeof(CharMask)); +} + + + + +// reset PPM variables after data error allowing safe resuming +// of further data processing +void ModelPPM::CleanUp() +{ + SubAlloc.StopSubAllocator(); + SubAlloc.StartSubAllocator(1); + StartModelRare(2); +} + + +bool ModelPPM::DecodeInit(Unpack *UnpackRead,int &EscChar) +{ + int MaxOrder=UnpackRead->GetChar(); + bool Reset=(MaxOrder & 0x20)!=0; + + int MaxMB; + if (Reset) + MaxMB=UnpackRead->GetChar(); + else + if (SubAlloc.GetAllocatedMemory()==0) + return(false); + if (MaxOrder & 0x40) + EscChar=UnpackRead->GetChar(); + Coder.InitDecoder(UnpackRead); + if (Reset) + { + MaxOrder=(MaxOrder & 0x1f)+1; + if (MaxOrder>16) + MaxOrder=16+(MaxOrder-16)*3; + if (MaxOrder==1) + { + SubAlloc.StopSubAllocator(); + return(false); + } + SubAlloc.StartSubAllocator(MaxMB+1); + StartModelRare(MaxOrder); + } + return(MinContext!=NULL); +} + + +int ModelPPM::DecodeChar() +{ + if ((byte*)MinContext <= SubAlloc.pText || (byte*)MinContext>SubAlloc.HeapEnd) + return(-1); + if (MinContext->NumStats != 1) + { + if ((byte*)MinContext->U.Stats <= SubAlloc.pText || (byte*)MinContext->U.Stats>SubAlloc.HeapEnd) + return(-1); + if (!MinContext->decodeSymbol1(this)) + return(-1); + } + else + MinContext->decodeBinSymbol(this); + Coder.Decode(); + while ( !FoundState ) + { + ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead); + do + { + OrderFall++; + MinContext=MinContext->Suffix; + if ((byte*)MinContext <= SubAlloc.pText || (byte*)MinContext>SubAlloc.HeapEnd) + return(-1); + } while (MinContext->NumStats == NumMasked); + if (!MinContext->decodeSymbol2(this)) + return(-1); + Coder.Decode(); + } + int Symbol=FoundState->Symbol; + if (!OrderFall && (byte*) FoundState->Successor > SubAlloc.pText) + MinContext=MaxContext=FoundState->Successor; + else + { + UpdateModel(); + if (EscCount == 0) + ClearMask(); + } + ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead); + return(Symbol); +} diff --git a/src/thirdparty/unrar/model.hpp b/src/thirdparty/unrar/model.hpp new file mode 100644 index 000000000..077742170 --- /dev/null +++ b/src/thirdparty/unrar/model.hpp @@ -0,0 +1,132 @@ +#ifndef _RAR_PPMMODEL_ +#define _RAR_PPMMODEL_ + +#include "coder.hpp" +#include "suballoc.hpp" + +const int MAX_O=64; /* maximum allowed model order */ + +const int INT_BITS=7, PERIOD_BITS=7, TOT_BITS=INT_BITS+PERIOD_BITS, + INTERVAL=1 << INT_BITS, BIN_SCALE=1 << TOT_BITS, MAX_FREQ=124; + +#ifndef STRICT_ALIGNMENT_REQUIRED +#pragma pack(1) +#endif + +struct SEE2_CONTEXT +{ // SEE-contexts for PPM-contexts with masked symbols + ushort Summ; + byte Shift, Count; + void init(int InitVal) + { + Summ=InitVal << (Shift=PERIOD_BITS-4); + Count=4; + } + uint getMean() + { + uint RetVal=GET_SHORT16(Summ) >> Shift; + Summ -= RetVal; + return RetVal+(RetVal == 0); + } + void update() + { + if (Shift < PERIOD_BITS && --Count == 0) + { + Summ += Summ; + Count=3 << Shift++; + } + } +}; + + +class ModelPPM; +struct PPM_CONTEXT; + +struct STATE +{ + byte Symbol; + byte Freq; + PPM_CONTEXT* Successor; +}; + +struct FreqData +{ + ushort SummFreq; + STATE _PACK_ATTR * Stats; +}; + +struct PPM_CONTEXT +{ + ushort NumStats; + union + { + FreqData U; + STATE OneState; + }; + + PPM_CONTEXT* Suffix; + inline void encodeBinSymbol(ModelPPM *Model,int symbol); // MaxOrder: + inline void encodeSymbol1(ModelPPM *Model,int symbol); // ABCD context + inline void encodeSymbol2(ModelPPM *Model,int symbol); // BCD suffix + inline void decodeBinSymbol(ModelPPM *Model); // BCDE successor + inline bool decodeSymbol1(ModelPPM *Model); // other orders: + inline bool decodeSymbol2(ModelPPM *Model); // BCD context + inline void update1(ModelPPM *Model,STATE* p); // CD suffix + inline void update2(ModelPPM *Model,STATE* p); // BCDE successor + void rescale(ModelPPM *Model); + inline PPM_CONTEXT* createChild(ModelPPM *Model,STATE* pStats,STATE& FirstState); + inline SEE2_CONTEXT* makeEscFreq2(ModelPPM *Model,int Diff); +}; + +#ifndef STRICT_ALIGNMENT_REQUIRED +#ifdef _AIX +#pragma pack(pop) +#else +#pragma pack() +#endif +#endif + +const uint UNIT_SIZE=Max(sizeof(PPM_CONTEXT),sizeof(RAR_MEM_BLK)); +const uint FIXED_UNIT_SIZE=12; + +/* +inline PPM_CONTEXT::PPM_CONTEXT(STATE* pStats,PPM_CONTEXT* ShorterContext): + NumStats(1), Suffix(ShorterContext) { pStats->Successor=this; } +inline PPM_CONTEXT::PPM_CONTEXT(): NumStats(0) {} +*/ + +template <class T> +inline void _PPMD_SWAP(T& t1,T& t2) { T tmp=t1; t1=t2; t2=tmp; } + + +class ModelPPM +{ + private: + friend struct PPM_CONTEXT; + + SEE2_CONTEXT SEE2Cont[25][16], DummySEE2Cont; + + struct PPM_CONTEXT *MinContext, *MedContext, *MaxContext; + STATE* FoundState; // found next state transition + int NumMasked, InitEsc, OrderFall, MaxOrder, RunLength, InitRL; + byte CharMask[256], NS2Indx[256], NS2BSIndx[256], HB2Flag[256]; + byte EscCount, PrevSuccess, HiBitsFlag; + ushort BinSumm[128][64]; // binary SEE-contexts + + RangeCoder Coder; + SubAllocator SubAlloc; + + void RestartModelRare(); + void StartModelRare(int MaxOrder); + inline PPM_CONTEXT* CreateSuccessors(bool Skip,STATE* p1); + + inline void UpdateModel(); + inline void ClearMask(); + public: + ModelPPM(); + void CleanUp(); // reset PPM variables after data error + bool DecodeInit(Unpack *UnpackRead,int &EscChar); + int DecodeChar(); +}; + +#endif diff --git a/src/thirdparty/unrar/options.cpp b/src/thirdparty/unrar/options.cpp new file mode 100644 index 000000000..585ce5243 --- /dev/null +++ b/src/thirdparty/unrar/options.cpp @@ -0,0 +1,30 @@ +#include "rar.hpp" + +RAROptions::RAROptions() +{ + Init(); +} + + +RAROptions::~RAROptions() +{ + // It is important for security reasons, so we do not have the unnecessary + // password data left in memory. + memset(this,0,sizeof(RAROptions)); +} + + +void RAROptions::Init() +{ + memset(this,0,sizeof(RAROptions)); + WinSize=0x400000; + Overwrite=OVERWRITE_DEFAULT; + Method=3; + MsgStream=MSG_STDOUT; + ConvertNames=NAMES_ORIGINALCASE; + ProcessEA=true; + xmtime=EXTTIME_HIGH3; + CurVolNum=0; + FileSizeLess=INT64NDF; + FileSizeMore=INT64NDF; +} diff --git a/src/thirdparty/unrar/options.hpp b/src/thirdparty/unrar/options.hpp new file mode 100644 index 000000000..b01912967 --- /dev/null +++ b/src/thirdparty/unrar/options.hpp @@ -0,0 +1,175 @@ +#ifndef _RAR_OPTIONS_ +#define _RAR_OPTIONS_ + +#define DEFAULT_RECOVERY -1 + +#define DEFAULT_RECVOLUMES -10 + +#define VOLSIZE_AUTO INT64NDF // Automatically detect the volume size. + +enum PATH_EXCL_MODE { + EXCL_UNCHANGED=0, // Process paths as is (default). + EXCL_SKIPWHOLEPATH, // -ep (exclude the path completely) + EXCL_BASEPATH, // -ep1 (exclude the base part of path) + EXCL_SAVEFULLPATH, // -ep2 (the full path without the disk letter) + EXCL_ABSPATH, // -ep3 (the full path with the disk letter) + + EXCL_SKIPABSPATH // Works as EXCL_BASEPATH for fully qualified paths + // and as EXCL_UNCHANGED for relative paths. + // Used by WinRAR GUI only. +}; + +enum {SOLID_NONE=0,SOLID_NORMAL=1,SOLID_COUNT=2,SOLID_FILEEXT=4, + SOLID_VOLUME_DEPENDENT=8,SOLID_VOLUME_INDEPENDENT=16}; + +enum {ARCTIME_NONE=0,ARCTIME_KEEP,ARCTIME_LATEST}; + +enum EXTTIME_MODE { + EXTTIME_NONE=0,EXTTIME_1S,EXTTIME_HIGH1,EXTTIME_HIGH2,EXTTIME_HIGH3 +}; + +enum {NAMES_ORIGINALCASE=0,NAMES_UPPERCASE,NAMES_LOWERCASE}; + +enum MESSAGE_TYPE {MSG_STDOUT=0,MSG_STDERR,MSG_ERRONLY,MSG_NULL}; + +enum RECURSE_MODE +{ + RECURSE_NONE=0, // no recurse switches + RECURSE_DISABLE, // switch -r- + RECURSE_ALWAYS, // switch -r + RECURSE_WILDCARDS, // switch -r0 +}; + +enum OVERWRITE_MODE +{ + OVERWRITE_DEFAULT=0, // ask for extraction, silently overwrite for archiving + OVERWRITE_ALL, + OVERWRITE_NONE, + OVERWRITE_AUTORENAME, + OVERWRITE_FORCE_ASK +}; + +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}; + + +struct FilterMode +{ + FilterState State; + int Param1; + int Param2; +}; + +#define MAX_GENERATE_MASK 128 + + +class RAROptions +{ + public: + RAROptions(); + ~RAROptions(); + void Init(); + + uint ExclFileAttr; + uint InclFileAttr; + bool InclAttrSet; + uint WinSize; + char TempPath[NM]; + bool ConfigDisabled; // Switch -cfg-. + char ExtrPath[NM]; + wchar ExtrPathW[NM]; + char CommentFile[NM]; + wchar CommentFileW[NM]; + RAR_CHARSET CommentCharset; + RAR_CHARSET FilelistCharset; + char ArcPath[NM]; + wchar ArcPathW[NM]; + SecPassword Password; + bool EncryptHeaders; + char LogName[NM]; + MESSAGE_TYPE MsgStream; + bool Sound; + OVERWRITE_MODE Overwrite; + int Method; + int Recovery; + int RecVolNumber; + bool DisablePercentage; + bool DisableCopyright; + bool DisableDone; + int Solid; + int SolidCount; + bool ClearArc; + bool AddArcOnly; + bool AV; + bool DisableComment; + bool FreshFiles; + bool UpdateFiles; + PATH_EXCL_MODE ExclPath; + RECURSE_MODE Recurse; + int64 VolSize; + Array<int64> NextVolSizes; + uint CurVolNum; + bool AllYes; + bool DisableViewAV; + bool DisableSortSolid; + int ArcTime; + int ConvertNames; + bool ProcessOwners; + bool SaveLinks; + int Priority; + int SleepTime; + bool KeepBroken; + bool OpenShared; + bool DeleteFiles; +#ifndef SFX_MODULE + bool GenerateArcName; + char GenerateMask[MAX_GENERATE_MASK]; +#endif + bool SyncFiles; + bool ProcessEA; + bool SaveStreams; + bool SetCompressedAttr; + bool IgnoreGeneralAttr; + RarTime FileTimeBefore; + RarTime FileTimeAfter; + int64 FileSizeLess; + int64 FileSizeMore; + bool OldNumbering; + bool Lock; + bool Test; + bool VolumePause; + FilterMode FilterModes[MAX_FILTER_TYPES]; + char 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 + + + + + + +#ifdef RARDLL + char DllDestName[NM]; + wchar DllDestNameW[NM]; + int DllOpMode; + int DllError; + LPARAM UserData; + UNRARCALLBACK Callback; + CHANGEVOLPROC ChangeVolProc; + PROCESSDATAPROC ProcessDataProc; +#endif +}; +#endif diff --git a/src/thirdparty/unrar/os.hpp b/src/thirdparty/unrar/os.hpp new file mode 100644 index 000000000..21488a849 --- /dev/null +++ b/src/thirdparty/unrar/os.hpp @@ -0,0 +1,254 @@ +#ifndef _RAR_OS_ +#define _RAR_OS_ + +#define FALSE 0 +#define TRUE 1 + +#ifdef __EMX__ + #define INCL_BASE +#endif + +#if defined(RARDLL) && !defined(SILENT) +#define SILENT +#endif + +#define ENABLE_BAD_ALLOC // Undefine if std::bad_alloc is not supported. + +#ifdef ENABLE_BAD_ALLOC + #include <new> +#endif + + +#if defined(_WIN_ALL) || defined(_EMX) + +#define LITTLE_ENDIAN +#define NM 1024 + +#ifdef _WIN_ALL + +#define STRICT +#define UNICODE +#undef WINVER +#undef _WIN32_WINNT +#define WINVER 0x0501 +#define _WIN32_WINNT 0x0501 + + +#define WIN32_LEAN_AND_MEAN + +#include <windows.h> +#include <prsht.h> +#include <shlwapi.h> +#include <shellapi.h> +#include <shlobj.h> +#include <winioctl.h> + + + +#endif // _WIN_ALL + +#include <sys/types.h> +#include <sys/stat.h> +#include <dos.h> + +#if !defined(_EMX) && !defined(_MSC_VER) + #include <dir.h> +#endif +#ifdef _MSC_VER + #if _MSC_VER<1500 + #define for if (0) ; else for + #endif + #include <direct.h> +#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> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <dos.h> +#include <io.h> +#include <time.h> +#include <signal.h> + +#define ENABLE_ACCESS + +#define DefConfigName "rar.ini" +#define DefLogName "rar.log" + + +#define PATHDIVIDER "\\" +#define PATHDIVIDERW L"\\" +#define CPATHDIVIDER '\\' +#define MASKALL "*" +#define MASKALLW L"*" + +#define READBINARY "rb" +#define READTEXT "rt" +#define UPDATEBINARY "r+b" +#define CREATEBINARY "w+b" +#define WRITEBINARY "wb" +#define APPENDTEXT "at" + +#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 + + #else + #define _stdfunction _USERENTRY + #define _forceinline inline + #endif +#else + #define _stdfunction + #define _forceinline inline +#endif + +#endif + +#ifdef _UNIX + +#define NM 1024 + +#ifdef _BEOS +#include <be/kernel/fs_info.h> +#include <be/kernel/fs_attr.h> +#endif + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> +#if defined(__QNXNTO__) + #include <sys/param.h> +#endif +#if defined(RAR_SMP) && defined(__APPLE__) + #include <sys/sysctl.h> +#endif +#if defined(__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__) + #include <sys/param.h> + #include <sys/mount.h> +#else +#endif +#include <pwd.h> +#include <grp.h> +#include <wchar.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> +#include <fcntl.h> +#include <errno.h> +#include <dirent.h> +#include <time.h> +#include <signal.h> +#include <utime.h> +#include <locale.h> + +#ifdef S_IFLNK +#define SAVE_LINKS +#endif + +#define ENABLE_ACCESS + +#define DefConfigName ".rarrc" +#define DefLogName ".rarlog" + + +#define PATHDIVIDER "/" +#define PATHDIVIDERW L"/" +#define CPATHDIVIDER '/' +#define MASKALL "*" +#define MASKALLW L"*" + +#define READBINARY "r" +#define READTEXT "r" +#define UPDATEBINARY "r+" +#define CREATEBINARY "w+" +#define WRITEBINARY "w" +#define APPENDTEXT "a" + +#define _stdfunction +#define _forceinline inline + +#ifdef _APPLE + #if defined(__BIG_ENDIAN__) && !defined(BIG_ENDIAN) + #define BIG_ENDIAN + #undef LITTLE_ENDIAN + #endif + #if defined(__i386__) && !defined(LITTLE_ENDIAN) + #define LITTLE_ENDIAN + #undef BIG_ENDIAN + #endif +#endif + +#if defined(__sparc) || defined(sparc) || defined(__hpux) + #ifndef BIG_ENDIAN + #define BIG_ENDIAN + #endif +#endif + +#endif + + typedef const char* MSGID; + +#define safebuf static + +#if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN) + #if defined(__i386) || defined(i386) || defined(__i386__) + #define LITTLE_ENDIAN + #elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN + #define LITTLE_ENDIAN + #elif defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN + #define BIG_ENDIAN + #else + #error "Neither LITTLE_ENDIAN nor BIG_ENDIAN are defined. Define one of them." + #endif +#endif + +#if defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN) + #if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN + #undef LITTLE_ENDIAN + #elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN + #undef BIG_ENDIAN + #else + #error "Both LITTLE_ENDIAN and BIG_ENDIAN are defined. Undef one of them." + #endif +#endif + +#if !defined(BIG_ENDIAN) && !defined(_WIN_CE) && defined(_WIN_ALL) +// Allow not aligned integer access, increases speed in some operations. +#define ALLOW_NOT_ALIGNED_INT +#endif + +#if defined(__sparc) || defined(sparc) || defined(__sparcv9) +// Prohibit not aligned access to data structures in text compression +// algorithm, increases memory requirements +#define STRICT_ALIGNMENT_REQUIRED +#endif + +#endif // _RAR_OS_ diff --git a/src/thirdparty/unrar/os2ea.cpp b/src/thirdparty/unrar/os2ea.cpp new file mode 100644 index 000000000..fbb12dbdc --- /dev/null +++ b/src/thirdparty/unrar/os2ea.cpp @@ -0,0 +1,94 @@ +#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 new file mode 100644 index 000000000..b9244cdec --- /dev/null +++ b/src/thirdparty/unrar/pathfn.cpp @@ -0,0 +1,1457 @@ +#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--) + if (IsPathDiv(Path[I])) + return (wchar*)&Path[I+1]; + return (wchar*)((*Path && IsDriveDiv(Path[1])) ? Path+2: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); +} + + +wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath) +{ + const wchar *DestPtr=SrcPath; + + // Prevent \..\ in any part of path string. + for (const wchar *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 wchar *s=DestPtr; + if (s[0] && IsDriveDiv(s[1])) + s+=2; + if (s[0]=='\\' && s[1]=='\\') + { + const wchar *Slash=wcschr(s+2,'\\'); + if (Slash!=NULL && (Slash=wcschr(Slash+1,'\\'))!=NULL) + s=Slash+1; + } + for (const wchar *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. + wchar TmpStr[NM]; + wcsncpyz(TmpStr,DestPtr,ASIZE(TmpStr)); + wcscpy(DestPath,TmpStr); + } + return((wchar *)DestPtr); +} + + +void SetExt(char *Name,const char *NewExt) +{ + 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); +} + + +void SetExt(wchar *Name,const wchar *NewExt) +{ + if (Name==NULL || *Name==0) + return; + wchar *Dot=GetExt(Name); + if (NewExt==NULL) + { + if (Dot!=NULL) + *Dot=0; + } + else + if (Dot==NULL) + { + wcscat(Name,L"."); + wcscat(Name,NewExt); + } + else + wcscpy(Dot+1,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) + return; + +#ifdef _UNIX + SetExt(SFXName,L"sfx"); +#endif + +#if defined(_WIN_ALL) || defined(_EMX) + SetExt(SFXName,L"exe"); +#endif +} +#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); +} + + +// 'Ext' is an extension without the leading dot, like L"rar". +bool CmpExt(const wchar *Name,const wchar *Ext) +{ + wchar *NameExt=GetExt(Name); + return(NameExt!=NULL && wcsicomp(NameExt+1,Ext)==0); +} + + +bool IsWildcard(const char *Str,const wchar *StrW) +{ + if (StrW!=NULL && *StrW!=0) + return(wcspbrk(StrW,L"*?")!=NULL); + return(Str==NULL ? false:strpbrk(Str,"*?")!=NULL); +} + + +bool IsPathDiv(int Ch) +{ +#if defined(_WIN_ALL) || defined(_EMX) + return(Ch=='\\' || Ch=='/'); +#else + return(Ch==CPATHDIVIDER); +#endif +} + + +bool IsDriveDiv(int Ch) +{ +#ifdef _UNIX + return(false); +#else + 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'); + else + return(-1); +} + + +void AddEndSlash(char *Path) +{ + char *LastChar=PointToLastChar(Path); + if (*LastChar!=0 && *LastChar!=CPATHDIVIDER) + strcat(LastChar,PATHDIVIDER); +} + + +void AddEndSlash(wchar *Path) +{ + size_t Length=wcslen(Path); + if (Length>0 && Path[Length-1]!=CPATHDIVIDER) + wcscat(Path,PATHDIVIDERW); +} + + +// Returns file path including the trailing path separator symbol. +void GetFilePath(const char *FullName,char *Path,int MaxLength) +{ + size_t PathLength=Min(MaxLength-1,PointToName(FullName)-FullName); + strncpy(Path,FullName,PathLength); + Path[PathLength]=0; +} + + +// Returns file path including the trailing path separator symbol. +void GetFilePath(const wchar *FullName,wchar *Path,int MaxLength) +{ + size_t PathLength=Min(MaxLength-1,PointToName(FullName)-FullName); + wcsncpy(Path,FullName,PathLength); + Path[PathLength]=0; +} + + +// Removes name and returns file path without the trailing +// path separator symbol. +void RemoveNameFromPath(char *Path) +{ + char *Name=PointToName(Path); + 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); + if (Name>=Path+2 && (!IsDriveDiv(Path[1]) || Name>=Path+4)) + Name--; + *Name=0; +} + + +#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) +{ + LPMALLOC g_pMalloc; + SHGetMalloc(&g_pMalloc); + LPITEMIDLIST ppidl; + *Path=0; + bool Success=false; + if (SHGetSpecialFolderLocation(NULL,CSIDL_APPDATA,&ppidl)==NOERROR && + SHGetPathFromIDListW(ppidl,Path) && *Path!=0) + { + AddEndSlash(Path); + wcscat(Path,L"WinRAR"); + Success=FileExist(NULL,Path) || MakeDir(NULL,Path,false,0)==MKDIR_SUCCESS; + } + if (!Success) + { + GetModuleFileNameW(NULL,Path,NM); + RemoveNameFromPath(Path); + } + g_pMalloc->Free(ppidl); +} +#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) +{ + *Path=0; + + HKEY hKey; + if (RegOpenKeyExW(HKEY_CURRENT_USER,L"Software\\WinRAR\\Paths",0, + KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS) + { + DWORD DataSize=NM,Type; + RegQueryValueExW(hKey,L"AppData",0,&Type,(BYTE *)Path,&DataSize); + RegCloseKey(hKey); + } + + if (*Path==0 || !FileExist(NULL,Path)) + GetAppDataPath(Path); +} +#endif + + +#ifndef SFX_MODULE +bool EnumConfigPaths(char *Path,int Number) +{ +#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" + }; + if (Number==0) + { + char *EnvStr=getenv("HOME"); + strncpy(Path, (EnvStr==NULL) ? AltPath[0] : EnvStr, NM-1); + Path[NM-1]=0; + return(true); + } + Number--; + if (Number<0 || Number>=sizeof(AltPath)/sizeof(AltPath[0])) + return(false); + strcpy(Path,AltPath[Number]); + return(true); +#elif defined(_WIN_ALL) + + if (Number<0 || Number>1) + return(false); + if (Number==0) + GetRarDataPath(Path); + else + { + GetModuleFileNameA(NULL,Path,NM); + RemoveNameFromPath(Path); + } + return(true); + +#else + 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) +{ + *FullName=0; + for (int I=0;EnumConfigPaths(FullName,I);I++) + { + AddEndSlash(FullName); + strcat(FullName,Name); + if (!CheckExist || WildFileExist(FullName)) + break; + } +} +#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) +{ + // Pointing to last name character. + char *ChPtr=ArcName+strlen(ArcName)-1; + + // Skipping the archive extension. + while (!IsDigit(*ChPtr) && ChPtr>ArcName) + ChPtr--; + + // Skipping the numeric part of name. + char *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!='.') + { + if (IsDigit(*NumPtr)) + { + // Validate the first numeric part only if it has a dot somewhere + // before it. + char *Dot=strchrd(PointToName(ArcName),'.'); + if (Dot!=NULL && Dot<NumPtr) + ChPtr=NumPtr; + break; + } + NumPtr--; + } + return(ChPtr); +} + + +// Returns a pointer to rightmost digit of volume number. +wchar* GetVolNumPart(wchar *ArcName) +{ + // 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!='.') + { + 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--; + } + return(ChPtr); +} + + +void NextVolumeName(char *ArcName,wchar *ArcNameW,uint MaxLength,bool OldNumbering) +{ + if (ArcName!=NULL && *ArcName!=0) + { + 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); + + while ((++(*ChPtr))=='9'+1) + { + *ChPtr='0'; + ChPtr--; + if (ChPtr<ArcName || !IsDigit(*ChPtr)) + { + for (char *EndPtr=ArcName+strlen(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 (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); + + while ((++(*ChPtr))=='9'+1) + { + *ChPtr='0'; + ChPtr--; + if (ChPtr<ArcNameW || !IsDigit(*ChPtr)) + { + for (wchar *EndPtr=ArcNameW+wcslen(ArcNameW);EndPtr!=ChPtr;EndPtr--) + *(EndPtr+1)=*EndPtr; + *(ChPtr+1)='1'; + break; + } + } + } + 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); +} + + +bool IsNameUsable(const wchar *Name) +{ +#ifndef _UNIX + if (Name[0] && Name[1] && wcschr(Name+2,':')!=NULL) + return(false); + for (const wchar *s=Name;*s!=0;s++) + { + if ((uint)*s<32) + return(false); + if (*s==' ' && IsPathDiv(s[1])) + return(false); + } +#endif + return(*Name!=0 && wcspbrk(Name,L"?*<>|\"")==NULL); +} + + +void MakeNameUsable(char *Name,bool Extended) +{ +#ifdef _WIN_ALL + // In Windows we also need to convert characters not defined in current + // code page. This double conversion changes them to '?', which is + // catched by code below. + size_t NameLength=strlen(Name); + wchar NameW[NM]; + CharToWide(Name,NameW,ASIZE(NameW)); + WideToChar(NameW,Name,NameLength+1); + Name[NameLength]=0; +#endif + for (char *s=Name;*s!=0;s=charnext(s)) + { + if (strchr(Extended ? "?*<>|\"":"?*",*s)!=NULL || Extended && (byte)*s<32) + *s='_'; +#ifdef _EMX + if (*s=='=') + *s='_'; +#endif +#ifndef _UNIX + if (s-Name>1 && *s==':') + *s='_'; + if (*s==' ' && IsPathDiv(s[1])) + *s='_'; +#endif + } +} + + +void MakeNameUsable(wchar *Name,bool Extended) +{ + for (wchar *s=Name;*s!=0;s++) + { + if (wcschr(Extended ? L"?*<>|\"":L"?*",*s)!=NULL || Extended && (uint)*s<32) + *s='_'; +#ifndef _UNIX + if (s-Name>1 && *s==':') + *s='_'; + if (*s==' ' && IsPathDiv(s[1])) + *s='_'; +#endif + } +} + + +char* UnixSlashToDos(char *SrcName,char *DestName,uint MaxLength) +{ + if (DestName!=NULL && DestName!=SrcName) + if (strlen(SrcName)>=MaxLength) + { + *DestName=0; + return(DestName); + } + else + strcpy(DestName,SrcName); + for (char *s=SrcName;*s!=0;s=charnext(s)) + { + if (*s=='/') + if (DestName==NULL) + *s='\\'; + else + DestName[s-SrcName]='\\'; + } + return(DestName==NULL ? SrcName:DestName); +} + + +char* DosSlashToUnix(char *SrcName,char *DestName,uint MaxLength) +{ + if (DestName!=NULL && DestName!=SrcName) + if (strlen(SrcName)>=MaxLength) + { + *DestName=0; + return(DestName); + } + else + strcpy(DestName,SrcName); + for (char *s=SrcName;*s!=0;s=charnext(s)) + { + if (*s=='\\') + if (DestName==NULL) + *s='/'; + else + DestName[s-SrcName]='/'; + } + return(DestName==NULL ? SrcName:DestName); +} + + +wchar* UnixSlashToDos(wchar *SrcName,wchar *DestName,uint MaxLength) +{ + if (DestName!=NULL && DestName!=SrcName) + if (wcslen(SrcName)>=MaxLength) + { + *DestName=0; + return(DestName); + } + else + wcscpy(DestName,SrcName); + for (wchar *s=SrcName;*s!=0;s++) + { + if (*s=='/') + if (DestName==NULL) + *s='\\'; + else + DestName[s-SrcName]='\\'; + } + return(DestName==NULL ? SrcName:DestName); +} + + +wchar* DosSlashToUnix(wchar *SrcName,wchar *DestName,uint MaxLength) +{ + if (DestName!=NULL && DestName!=SrcName) + if (wcslen(SrcName)>=MaxLength) + { + *DestName=0; + return(DestName); + } + else + wcscpy(DestName,SrcName); + for (wchar *s=SrcName;*s!=0;s++) + { + if (*s=='\\') + if (DestName==NULL) + *s='/'; + 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 +} + + +void ConvertNameToFull(const wchar *Src,wchar *Dest) +{ + if (Src==NULL || *Src==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); + if (Code!=0 && Code<ASIZE(FullName)) + wcscpy(Dest,FullName); + else +#endif + if (Src!=Dest) + wcscpy(Dest,Src); + } +#ifndef _WIN_CE + else + { + char AnsiName[NM]; + WideToChar(Src,AnsiName); + ConvertNameToFull(AnsiName,AnsiName); + CharToWide(AnsiName,Dest); + } +#endif +#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])); +#endif +} + + +bool IsFullPath(const wchar *Path) +{ + wchar PathOnly[NM]; + GetFilePath(Path,PathOnly,ASIZE(PathOnly)); + if (IsWildcard(NULL,PathOnly)) + return(true); +#if defined(_WIN_ALL) || defined(_EMX) + return(Path[0]=='\\' && Path[1]=='\\' || + IsDiskLetter(Path) && IsPathDiv(Path[2])); +#else + 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]); + return(Letter>='A' && Letter<='Z' && IsDriveDiv(Path[1])); +} + + +void GetPathRoot(const char *Path,char *Root) +{ + *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); + else + if (Path[0]=='\\' && Path[1]=='\\') + { + const wchar *Slash=wcschr(Path+2,'\\'); + if (Slash!=NULL) + { + size_t Length; + if ((Slash=wcschr(Slash+1,'\\'))!=NULL) + Length=Slash-Path+1; + else + Length=wcslen(Path); + wcsncpy(Root,Path,Length); + Root[Length]=0; + } + } +} + + +int ParseVersionFileName(char *Name,wchar *NameW,bool Truncate) +{ + int Version=0; + char *VerText=strrchrd(Name,';'); + if (VerText!=NULL) + { + Version=atoi(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); +} + + +#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) + wcscpy(FirstName,VolName); + wchar *VolNumStart=FirstName; + if (NewNumbering) + { + wchar N='1'; + + // From the rightmost digit of volume number to the left. + for (wchar *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,L"rar"); + VolNumStart=GetExt(FirstName); + } + if (!FileExist(NULL,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. + wchar Mask[NM]; + wcscpy(Mask,FirstName); + SetExt(Mask,L"*"); + FindFile Find; + Find.SetMaskW(Mask); + FindData FD; + while (Find.Next(&FD)) + { + Archive Arc; + if (Arc.Open(FD.Name,FD.NameW,0) && Arc.IsArchive(true) && !Arc.NotFirstVolume) + { + wcscpy(FirstName,FD.NameW); + break; + } + } + } + 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) +{ + bool Prefix=false; + if (*GenerateMask=='+') + { + Prefix=true; // Add the time string before the archive name. + GenerateMask++; // Skip '+' in the beginning of time mask. + } + + char Mask[MAX_GENERATE_MASK]; + strncpyz(Mask,*GenerateMask ? GenerateMask:"yyyymmddhhmmss",ASIZE(Mask)); + + bool QuoteMode=false,Hours=false; + for (uint I=0;Mask[I]!=0;I++) + { + if (Mask[I]=='{' || Mask[I]=='}') + { + QuoteMode=(Mask[I]=='{'); + continue; + } + if (QuoteMode) + continue; + int CurChar=etoupper(Mask[I]); + if (CurChar=='H') + Hours=true; + + if (Hours && CurChar=='M') + { + // Replace minutes with 'I'. We use 'M' both for months and minutes, + // so we treat as minutes only those 'M' which are found after hours. + Mask[I]='I'; + } + if (CurChar=='N') + { + uint Digits=GetDigits(ArcNumber); + uint NCount=0; + while (etoupper(Mask[I+NCount])=='N') + NCount++; + + // Here we ensure that we have enough 'N' characters to fit all digits + // of archive number. We'll replace them by actual number later + // in this function. + if (NCount<Digits) + { + memmove(Mask+I+Digits,Mask+I+NCount,strlen(Mask+I+NCount)+1); + memset(Mask+I,'N',Digits); + } + I+=Max(Digits,NCount)-1; + ArcNumPresent=true; + continue; + } + } + + RarTime CurTime; + CurTime.SetCurrentTime(); + RarLocalTime rlt; + CurTime.GetLocal(&rlt); + + char Ext[NM]; + *Ext=0; + if (ArcName!=NULL && *ArcName!=0) + { + 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; + } + } + + int WeekDay=rlt.wDay==0 ? 6:rlt.wDay-1; + int StartWeekDay=rlt.yDay-WeekDay; + if (StartWeekDay<0) + if (StartWeekDay<=-4) + StartWeekDay+=IsLeapYear(rlt.Year-1) ? 366:365; + else + StartWeekDay=0; + int CurWeek=StartWeekDay/7+1; + if (StartWeekDay%7>=4) + CurWeek++; + + char Field[10][6]; + + sprintf(Field[0],"%04d",rlt.Year); + sprintf(Field[1],"%02d",rlt.Month); + sprintf(Field[2],"%02d",rlt.Day); + sprintf(Field[3],"%02d",rlt.Hour); + sprintf(Field[4],"%02d",rlt.Minute); + sprintf(Field[5],"%02d",rlt.Second); + sprintf(Field[6],"%02d",CurWeek); + sprintf(Field[7],"%d",WeekDay+1); + sprintf(Field[8],"%03d",rlt.yDay+1); + sprintf(Field[9],"%05d",ArcNumber); + + const char *MaskChars="YMDHISWAEN"; + + int CField[sizeof(Field)/sizeof(Field[0])]; + memset(CField,0,sizeof(CField)); + QuoteMode=false; + for (int I=0;Mask[I]!=0;I++) + { + if (Mask[I]=='{' || Mask[I]=='}') + { + QuoteMode=(Mask[I]=='{'); + continue; + } + if (QuoteMode) + continue; + const char *Ch=strchr(MaskChars,etoupper(Mask[I])); + if (Ch!=NULL) + CField[Ch-MaskChars]++; + } + + char DateText[MAX_GENERATE_MASK]; + *DateText=0; + QuoteMode=false; + for (size_t I=0,J=0;Mask[I]!=0 && J<ASIZE(DateText)-1;I++) + { + if (Mask[I]=='{' || Mask[I]=='}') + { + QuoteMode=(Mask[I]=='{'); + continue; + } + const char *Ch=strchr(MaskChars,etoupper(Mask[I])); + if (Ch==NULL || QuoteMode) + DateText[J]=Mask[I]; + else + { + size_t FieldPos=Ch-MaskChars; + int CharPos=(int)strlen(Field[FieldPos])-CField[FieldPos]--; + if (FieldPos==1 && etoupper(Mask[I+1])=='M' && etoupper(Mask[I+2])=='M') + { + strncpyz(DateText+J,GetMonthName(rlt.Month-1),ASIZE(DateText)-J); + J=strlen(DateText); + I+=2; + continue; + } + if (CharPos<0) + DateText[J]=Mask[I]; + else + DateText[J]=Field[FieldPos][CharPos]; + } + 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); + } + } + else + { + if (ArcName!=NULL && *ArcName!=0) + strcat(ArcName,DateText); + if (ArcNameW!=NULL && *ArcNameW!=0) + wcscat(ArcNameW,DateTextW); + } + if (ArcName!=NULL && *ArcName!=0) + strcat(ArcName,Ext); + if (ArcNameW!=NULL && *ArcNameW!=0) + wcscat(ArcNameW,ExtW); +} +#endif + + +wchar* GetWideName(const char *Name,const wchar *NameW,wchar *DestW,size_t DestSize) +{ + if (NameW!=NULL && *NameW!=0) + { + if (DestW!=NameW) + wcsncpy(DestW,NameW,DestSize); + } + else + if (Name!=NULL) + CharToWide(Name,DestW,DestSize); + else + *DestW=0; + + // Ensure that we return a zero terminate string for security reasons. + if (DestSize>0) + DestW[DestSize-1]=0; + + return(DestW); +} + + +// 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; + } + else + *Name=0; + return Name; +} diff --git a/src/thirdparty/unrar/pathfn.hpp b/src/thirdparty/unrar/pathfn.hpp new file mode 100644 index 000000000..5ee614696 --- /dev/null +++ b/src/thirdparty/unrar/pathfn.hpp @@ -0,0 +1,66 @@ +#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 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 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 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); +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); +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); +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); +#endif + +#endif diff --git a/src/thirdparty/unrar/rar.cpp b/src/thirdparty/unrar/rar.cpp new file mode 100644 index 000000000..e487cc639 --- /dev/null +++ b/src/thirdparty/unrar/rar.cpp @@ -0,0 +1,144 @@ +#include "rar.hpp" + +#if !defined(GUI) && !defined(RARDLL) +int main(int argc, char *argv[]) +{ + +#ifdef _UNIX + 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 + + ErrHandler.SetSignalHandlers(true); + + RARInitData(); + +#ifdef SFX_MODULE + char ModuleNameA[NM]; + wchar ModuleNameW[NM]; +#ifdef _WIN_ALL + GetModuleFileNameW(NULL,ModuleNameW,ASIZE(ModuleNameW)); + WideToChar(ModuleNameW,ModuleNameA); +#else + strcpy(ModuleNameA,argv[0]); + *ModuleNameW=0; +#endif +#endif + +#ifdef _WIN_ALL + SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT|SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + + +#endif + +#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SHELL_EXT) + // Must be initialized, normal initialization can be skipped in case of + // exception. + bool ShutdownOnClose=false; +#endif + +#ifdef ALLOW_EXCEPTIONS + try +#endif + { + + CommandData Cmd; +#ifdef SFX_MODULE + strcpy(Cmd.Command,"X"); + char *Switch=NULL; +#ifdef _SFX_RTL_ + char *CmdLine=GetCommandLineA(); + if (CmdLine!=NULL && *CmdLine=='\"') + CmdLine=strchr(CmdLine+1,'\"'); + if (CmdLine!=NULL && (CmdLine=strpbrk(CmdLine," /"))!=NULL) + { + while (IsSpace(*CmdLine)) + CmdLine++; + Switch=CmdLine; + } +#else + Switch=argc>1 ? argv[1]:NULL; +#endif + if (Switch!=NULL && Cmd.IsSwitch(Switch[0])) + { + int UpperCmd=etoupper(Switch[1]); + switch(UpperCmd) + { + case 'T': + case 'V': + Cmd.Command[0]=UpperCmd; + break; + case '?': + Cmd.OutHelp(RARX_SUCCESS); + break; + } + } + Cmd.AddArcName(ModuleNameA,ModuleNameW); + Cmd.ParseDone(); +#else // !SFX_MODULE + Cmd.PreprocessCommandLine(argc,argv); + if (!Cmd.ConfigDisabled) + { + Cmd.ReadConfig(); + Cmd.ParseEnvVar(); + } + Cmd.ParseCommandLine(argc,argv); +#endif + +#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SHELL_EXT) + ShutdownOnClose=Cmd.Shutdown; +#endif + + InitConsoleOptions(Cmd.MsgStream,Cmd.Sound); + InitLogOptions(Cmd.LogName); + ErrHandler.SetSilent(Cmd.AllYes || Cmd.MsgStream==MSG_NULL); + ErrHandler.SetShutdown(Cmd.Shutdown); + + Cmd.OutTitle(); + Cmd.ProcessCommand(); + } +#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()); +} +#endif + + diff --git a/src/thirdparty/unrar/rar.hpp b/src/thirdparty/unrar/rar.hpp new file mode 100644 index 000000000..73ebd2bc7 --- /dev/null +++ b/src/thirdparty/unrar/rar.hpp @@ -0,0 +1,79 @@ +#ifndef _RAR_RARCOMMON_ +#define _RAR_RARCOMMON_ + +#include "raros.hpp" +#include "os.hpp" + +#ifdef RARDLL +#include "dll.hpp" +#endif + + +#ifndef _WIN_CE +#include "version.hpp" +#endif +#include "rartypes.hpp" +#include "rardefs.hpp" +#include "rarlang.hpp" +#include "unicode.hpp" +#include "errhnd.hpp" +#include "array.hpp" +#include "timefn.hpp" +#include "secpassword.hpp" +#include "options.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" +#include "scantree.hpp" +#include "savepos.hpp" +#include "getbits.hpp" +#include "rdwrfn.hpp" +#include "archive.hpp" +#include "match.hpp" +#include "cmddata.hpp" +#include "filcreat.hpp" +#include "consio.hpp" +#include "system.hpp" +#ifdef _WIN_ALL +#include "isnt.hpp" +#endif +#include "log.hpp" +#include "rawread.hpp" +#include "encname.hpp" +#include "resource.hpp" +#include "compress.hpp" + +#include "rarvm.hpp" +#include "model.hpp" + +#include "unpack.hpp" + + + +#include "extinfo.hpp" +#include "extract.hpp" + + + +#include "list.hpp" + + +#include "rs.hpp" +#include "recvol.hpp" +#include "volume.hpp" +#include "smallfn.hpp" +#include "ulinks.hpp" + +#include "global.hpp" + + +#endif diff --git a/src/thirdparty/unrar/rardefs.hpp b/src/thirdparty/unrar/rardefs.hpp new file mode 100644 index 000000000..1e9788b38 --- /dev/null +++ b/src/thirdparty/unrar/rardefs.hpp @@ -0,0 +1,28 @@ +#ifndef _RAR_DEFS_ +#define _RAR_DEFS_ + +#define Min(x,y) (((x)<(y)) ? (x):(y)) +#define Max(x,y) (((x)>(y)) ? (x):(y)) + +#define ASIZE(x) (sizeof(x)/sizeof(x[0])) + +// MAXPASSWORD is expected to be multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE (16) +// for CryptProtectMemory in SecPassword. +#define MAXPASSWORD 128 + +#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 +#endif + + +#endif diff --git a/src/thirdparty/unrar/rarlang.hpp b/src/thirdparty/unrar/rarlang.hpp new file mode 100644 index 000000000..6151d15a9 --- /dev/null +++ b/src/thirdparty/unrar/rarlang.hpp @@ -0,0 +1,10 @@ +#ifndef _RAR_LANG_ +#define _RAR_LANG_ + + #ifdef USE_RC + #include "rarres.hpp" + #else + #include "loclang.hpp" + #endif + +#endif diff --git a/src/thirdparty/unrar/raros.hpp b/src/thirdparty/unrar/raros.hpp new file mode 100644 index 000000000..ce853bd7d --- /dev/null +++ b/src/thirdparty/unrar/raros.hpp @@ -0,0 +1,46 @@ +#ifndef _RAR_RAROS_ +#define _RAR_RAROS_ + +#ifdef __EMX__ + #define _EMX +#endif + +#ifdef __DJGPP__ + #define _DJGPP + #define _EMX +#endif + +#if defined(__WIN32__) || defined(_WIN32) + #define _WIN_ALL // Defined for all Windows platforms, 32 and 64 bit, mobile and desktop. + #ifdef _M_X64 + #define _WIN_64 + #else + #define _WIN_32 + #endif +#endif + +#ifdef _WIN32_WCE + #define _WIN_ALL + #define _WIN_CE + #ifdef WM_FILECHANGEINFO + #define PC2002 + #else + #undef PC2002 + #endif +#endif + +#ifdef __BEOS__ + #define _UNIX + #define _BEOS +#endif + +#ifdef __APPLE__ + #define _UNIX + #define _APPLE +#endif + +#if !defined(_EMX) && !defined(_WIN_ALL) && !defined(_BEOS) && !defined(_APPLE) + #define _UNIX +#endif + +#endif diff --git a/src/thirdparty/unrar/rarpch.cpp b/src/thirdparty/unrar/rarpch.cpp new file mode 100644 index 000000000..c070cf74b --- /dev/null +++ b/src/thirdparty/unrar/rarpch.cpp @@ -0,0 +1,2 @@ +// We use rarpch.cpp to create precompiled headers for MS Visual C++. +#include "rar.hpp" diff --git a/src/thirdparty/unrar/rartypes.hpp b/src/thirdparty/unrar/rartypes.hpp new file mode 100644 index 000000000..a2d8b44a0 --- /dev/null +++ b/src/thirdparty/unrar/rartypes.hpp @@ -0,0 +1,47 @@ +#ifndef _RAR_TYPES_ +#define _RAR_TYPES_ + +typedef unsigned char byte; // unsigned 8 bits +typedef unsigned short ushort; // preferably 16 bits, but can be more +typedef unsigned int uint; // 32 bits or more + +#define PRESENT_INT32 // undefine if signed 32 bits is not available + +typedef unsigned int uint32; // 32 bits exactly +typedef signed int int32; // signed 32 bits exactly + +// If compiler does not support 64 bit variables, we can define +// uint64 and int64 as 32 bit, but it will limit the maximum processed +// file size to 2 GB. +#if defined(__BORLANDC__) || defined(_MSC_VER) +typedef unsigned __int64 uint64; // unsigned 64 bits +typedef signed __int64 int64; // signed 64 bits +#else +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)) + +// Get lowest 32 bits. +#define GET_UINT32(x) (sizeof(uint32)==4 ? (uint32)(x):((x)&0xffffffff)) + +// Make 64 bit integer from two 32 bit. +#define INT32TO64(high,low) ((((uint64)(high))<<32)+((uint64)low)) + +// Special int64 value, large enough to never be found in real life. +// We use it in situations, when we need to indicate that parameter +// is not defined and probably should be calculated inside of function. +// Lower part is intentionally 0x7fffffff, not 0xffffffff, to make it +// compatible with 32 bit int64. +#define INT64NDF INT32TO64(0x7fffffff,0x7fffffff) + +#endif diff --git a/src/thirdparty/unrar/rarvm.cpp b/src/thirdparty/unrar/rarvm.cpp new file mode 100644 index 000000000..8b8580064 --- /dev/null +++ b/src/thirdparty/unrar/rarvm.cpp @@ -0,0 +1,1139 @@ +#include "rar.hpp" + +#include "rarvmtbl.cpp" + +RarVM::RarVM() +{ + Mem=NULL; +} + + +RarVM::~RarVM() +{ + delete[] Mem; +} + + +void RarVM::Init() +{ + if (Mem==NULL) + Mem=new byte[VM_MEMSIZE+4]; +} + +/********************************************************************* + IS_VM_MEM macro checks if address belongs to VM memory pool (Mem). + Only Mem data are always low endian regardless of machine architecture, + so we need to convert them to native format when reading or writing. + VM registers have endianness of host machine. +**********************************************************************/ +#define IS_VM_MEM(a) (((byte*)a)>=Mem && ((byte*)a)<Mem+VM_MEMSIZE) + +inline uint RarVM::GetValue(bool ByteMode,uint *Addr) +{ + if (ByteMode) + { +#ifdef BIG_ENDIAN + if (IS_VM_MEM(Addr)) + return(*(byte *)Addr); + else + return(*Addr & 0xff); +#else + return(*(byte *)Addr); +#endif + } + else + { +#if defined(BIG_ENDIAN) || !defined(ALLOW_NOT_ALIGNED_INT) + if (IS_VM_MEM(Addr)) + { + byte *B=(byte *)Addr; + return GET_UINT32((uint)B[0]|((uint)B[1]<<8)|((uint)B[2]<<16)|((uint)B[3]<<24)); + } + else + return GET_UINT32(*Addr); +#else + return GET_UINT32(*Addr); +#endif + } +} + +#if defined(BIG_ENDIAN) || !defined(ALLOW_NOT_ALIGNED_INT) + #define GET_VALUE(ByteMode,Addr) GetValue(ByteMode,(uint *)Addr) +#else + #define GET_VALUE(ByteMode,Addr) ((ByteMode) ? (*(byte *)(Addr)):GET_UINT32(*(uint *)(Addr))) +#endif + + +inline void RarVM::SetValue(bool ByteMode,uint *Addr,uint Value) +{ + if (ByteMode) + { +#ifdef BIG_ENDIAN + if (IS_VM_MEM(Addr)) + *(byte *)Addr=Value; + else + *Addr=(*Addr & ~0xff)|(Value & 0xff); +#else + *(byte *)Addr=Value; +#endif + } + else + { +#if defined(BIG_ENDIAN) || !defined(ALLOW_NOT_ALIGNED_INT) || !defined(PRESENT_INT32) + if (IS_VM_MEM(Addr)) + { + ((byte *)Addr)[0]=(byte)Value; + ((byte *)Addr)[1]=(byte)(Value>>8); + ((byte *)Addr)[2]=(byte)(Value>>16); + ((byte *)Addr)[3]=(byte)(Value>>24); + } + else + *(uint *)Addr=Value; +#else + *(uint32 *)Addr=Value; +#endif + } +} + +#if defined(BIG_ENDIAN) || !defined(ALLOW_NOT_ALIGNED_INT) || !defined(PRESENT_INT32) + #define SET_VALUE(ByteMode,Addr,Value) SetValue(ByteMode,(uint *)Addr,Value) +#else + #define SET_VALUE(ByteMode,Addr,Value) ((ByteMode) ? (*(byte *)(Addr)=((byte)(Value))):(*(uint32 *)(Addr)=((uint32)(Value)))) +#endif + + +void RarVM::SetLowEndianValue(uint *Addr,uint Value) +{ +#if defined(BIG_ENDIAN) || !defined(ALLOW_NOT_ALIGNED_INT) || !defined(PRESENT_INT32) + ((byte *)Addr)[0]=(byte)Value; + ((byte *)Addr)[1]=(byte)(Value>>8); + ((byte *)Addr)[2]=(byte)(Value>>16); + ((byte *)Addr)[3]=(byte)(Value>>24); +#else + *(uint32 *)Addr=Value; +#endif +} + + +inline uint* RarVM::GetOperand(VM_PreparedOperand *CmdOp) +{ + if (CmdOp->Type==VM_OPREGMEM) + return((uint *)&Mem[(*CmdOp->Addr+CmdOp->Base)&VM_MEMMASK]); + else + return(CmdOp->Addr); +} + + +void RarVM::Execute(VM_PreparedProgram *Prg) +{ + memcpy(R,Prg->InitR,sizeof(Prg->InitR)); + size_t GlobalSize=Min(Prg->GlobalData.Size(),VM_GLOBALMEMSIZE); + if (GlobalSize) + memcpy(Mem+VM_GLOBALMEMADDR,&Prg->GlobalData[0],GlobalSize); + size_t StaticSize=Min(Prg->StaticData.Size(),VM_GLOBALMEMSIZE-GlobalSize); + if (StaticSize) + memcpy(Mem+VM_GLOBALMEMADDR+GlobalSize,&Prg->StaticData[0],StaticSize); + + R[7]=VM_MEMSIZE; + Flags=0; + + VM_PreparedCommand *PreparedCode=Prg->AltCmd ? Prg->AltCmd:&Prg->Cmd[0]; + if (Prg->CmdCount>0 && !ExecuteCode(PreparedCode,Prg->CmdCount)) + { + // Invalid VM program. Let's replace it with 'return' command. + PreparedCode[0].OpCode=VM_RET; + } + uint NewBlockPos=GET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x20])&VM_MEMMASK; + uint NewBlockSize=GET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x1c])&VM_MEMMASK; + if (NewBlockPos+NewBlockSize>=VM_MEMSIZE) + NewBlockPos=NewBlockSize=0; + Prg->FilteredData=Mem+NewBlockPos; + Prg->FilteredDataSize=NewBlockSize; + + Prg->GlobalData.Reset(); + + uint DataSize=Min(GET_VALUE(false,(uint*)&Mem[VM_GLOBALMEMADDR+0x30]),VM_GLOBALMEMSIZE-VM_FIXEDGLOBALSIZE); + if (DataSize!=0) + { + Prg->GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE); + memcpy(&Prg->GlobalData[0],&Mem[VM_GLOBALMEMADDR],DataSize+VM_FIXEDGLOBALSIZE); + } +} + + +/* +Note: + Due to performance considerations RAR VM may set VM_FS, VM_FC, VM_FZ + incorrectly for byte operands. These flags are always valid only + for 32-bit operands. Check implementation of concrete VM command + to see if it sets flags right. +*/ + +#define SET_IP(IP) \ + if ((IP)>=CodeSize) \ + return(true); \ + if (--MaxOpCount<=0) \ + return(false); \ + Cmd=PreparedCode+(IP); + +bool RarVM::ExecuteCode(VM_PreparedCommand *PreparedCode,uint CodeSize) +{ + int MaxOpCount=25000000; + VM_PreparedCommand *Cmd=PreparedCode; + while (1) + { +#ifndef NORARVM + // Get addresses to quickly access operands. + uint *Op1=GetOperand(&Cmd->Op1); + uint *Op2=GetOperand(&Cmd->Op2); +#endif + switch(Cmd->OpCode) + { +#ifndef NORARVM + case VM_MOV: + SET_VALUE(Cmd->ByteMode,Op1,GET_VALUE(Cmd->ByteMode,Op2)); + break; +#ifdef VM_OPTIMIZE + case VM_MOVB: + SET_VALUE(true,Op1,GET_VALUE(true,Op2)); + break; + case VM_MOVD: + SET_VALUE(false,Op1,GET_VALUE(false,Op2)); + break; +#endif + case VM_CMP: + { + uint Value1=GET_VALUE(Cmd->ByteMode,Op1); + uint Result=GET_UINT32(Value1-GET_VALUE(Cmd->ByteMode,Op2)); + Flags=Result==0 ? VM_FZ:(Result>Value1)|(Result&VM_FS); + } + break; +#ifdef VM_OPTIMIZE + case VM_CMPB: + { + uint Value1=GET_VALUE(true,Op1); + uint Result=GET_UINT32(Value1-GET_VALUE(true,Op2)); + Flags=Result==0 ? VM_FZ:(Result>Value1)|(Result&VM_FS); + } + break; + case VM_CMPD: + { + uint Value1=GET_VALUE(false,Op1); + uint Result=GET_UINT32(Value1-GET_VALUE(false,Op2)); + Flags=Result==0 ? VM_FZ:(Result>Value1)|(Result&VM_FS); + } + break; +#endif + case VM_ADD: + { + uint Value1=GET_VALUE(Cmd->ByteMode,Op1); + uint Result=GET_UINT32(Value1+GET_VALUE(Cmd->ByteMode,Op2)); + if (Cmd->ByteMode) + { + Result&=0xff; + Flags=(Result<Value1)|(Result==0 ? VM_FZ:((Result&0x80) ? VM_FS:0)); + } + else + Flags=(Result<Value1)|(Result==0 ? VM_FZ:(Result&VM_FS)); + SET_VALUE(Cmd->ByteMode,Op1,Result); + } + break; +#ifdef VM_OPTIMIZE + case VM_ADDB: + SET_VALUE(true,Op1,GET_VALUE(true,Op1)+GET_VALUE(true,Op2)); + break; + case VM_ADDD: + SET_VALUE(false,Op1,GET_VALUE(false,Op1)+GET_VALUE(false,Op2)); + break; +#endif + case VM_SUB: + { + uint Value1=GET_VALUE(Cmd->ByteMode,Op1); + uint Result=GET_UINT32(Value1-GET_VALUE(Cmd->ByteMode,Op2)); + Flags=Result==0 ? VM_FZ:(Result>Value1)|(Result&VM_FS); + SET_VALUE(Cmd->ByteMode,Op1,Result); + } + break; +#ifdef VM_OPTIMIZE + case VM_SUBB: + SET_VALUE(true,Op1,GET_VALUE(true,Op1)-GET_VALUE(true,Op2)); + break; + case VM_SUBD: + SET_VALUE(false,Op1,GET_VALUE(false,Op1)-GET_VALUE(false,Op2)); + break; +#endif + case VM_JZ: + if ((Flags & VM_FZ)!=0) + { + SET_IP(GET_VALUE(false,Op1)); + continue; + } + break; + case VM_JNZ: + if ((Flags & VM_FZ)==0) + { + SET_IP(GET_VALUE(false,Op1)); + continue; + } + break; + case VM_INC: + { + uint Result=GET_UINT32(GET_VALUE(Cmd->ByteMode,Op1)+1); + if (Cmd->ByteMode) + Result&=0xff; + SET_VALUE(Cmd->ByteMode,Op1,Result); + Flags=Result==0 ? VM_FZ:Result&VM_FS; + } + break; +#ifdef VM_OPTIMIZE + case VM_INCB: + SET_VALUE(true,Op1,GET_VALUE(true,Op1)+1); + break; + case VM_INCD: + SET_VALUE(false,Op1,GET_VALUE(false,Op1)+1); + break; +#endif + case VM_DEC: + { + uint Result=GET_UINT32(GET_VALUE(Cmd->ByteMode,Op1)-1); + SET_VALUE(Cmd->ByteMode,Op1,Result); + Flags=Result==0 ? VM_FZ:Result&VM_FS; + } + break; +#ifdef VM_OPTIMIZE + case VM_DECB: + SET_VALUE(true,Op1,GET_VALUE(true,Op1)-1); + break; + case VM_DECD: + SET_VALUE(false,Op1,GET_VALUE(false,Op1)-1); + break; +#endif + case VM_JMP: + SET_IP(GET_VALUE(false,Op1)); + continue; + case VM_XOR: + { + uint Result=GET_UINT32(GET_VALUE(Cmd->ByteMode,Op1)^GET_VALUE(Cmd->ByteMode,Op2)); + Flags=Result==0 ? VM_FZ:Result&VM_FS; + SET_VALUE(Cmd->ByteMode,Op1,Result); + } + break; + case VM_AND: + { + uint Result=GET_UINT32(GET_VALUE(Cmd->ByteMode,Op1)&GET_VALUE(Cmd->ByteMode,Op2)); + Flags=Result==0 ? VM_FZ:Result&VM_FS; + SET_VALUE(Cmd->ByteMode,Op1,Result); + } + break; + case VM_OR: + { + uint Result=GET_UINT32(GET_VALUE(Cmd->ByteMode,Op1)|GET_VALUE(Cmd->ByteMode,Op2)); + Flags=Result==0 ? VM_FZ:Result&VM_FS; + SET_VALUE(Cmd->ByteMode,Op1,Result); + } + break; + case VM_TEST: + { + uint Result=GET_UINT32(GET_VALUE(Cmd->ByteMode,Op1)&GET_VALUE(Cmd->ByteMode,Op2)); + Flags=Result==0 ? VM_FZ:Result&VM_FS; + } + break; + case VM_JS: + if ((Flags & VM_FS)!=0) + { + SET_IP(GET_VALUE(false,Op1)); + continue; + } + break; + case VM_JNS: + if ((Flags & VM_FS)==0) + { + SET_IP(GET_VALUE(false,Op1)); + continue; + } + break; + case VM_JB: + if ((Flags & VM_FC)!=0) + { + SET_IP(GET_VALUE(false,Op1)); + continue; + } + break; + case VM_JBE: + if ((Flags & (VM_FC|VM_FZ))!=0) + { + SET_IP(GET_VALUE(false,Op1)); + continue; + } + break; + case VM_JA: + if ((Flags & (VM_FC|VM_FZ))==0) + { + SET_IP(GET_VALUE(false,Op1)); + continue; + } + break; + case VM_JAE: + if ((Flags & VM_FC)==0) + { + SET_IP(GET_VALUE(false,Op1)); + continue; + } + break; + case VM_PUSH: + R[7]-=4; + SET_VALUE(false,(uint *)&Mem[R[7]&VM_MEMMASK],GET_VALUE(false,Op1)); + break; + case VM_POP: + SET_VALUE(false,Op1,GET_VALUE(false,(uint *)&Mem[R[7] & VM_MEMMASK])); + R[7]+=4; + break; + case VM_CALL: + R[7]-=4; + SET_VALUE(false,(uint *)&Mem[R[7]&VM_MEMMASK],Cmd-PreparedCode+1); + SET_IP(GET_VALUE(false,Op1)); + continue; + case VM_NOT: + SET_VALUE(Cmd->ByteMode,Op1,~GET_VALUE(Cmd->ByteMode,Op1)); + break; + case VM_SHL: + { + uint Value1=GET_VALUE(Cmd->ByteMode,Op1); + uint Value2=GET_VALUE(Cmd->ByteMode,Op2); + uint Result=GET_UINT32(Value1<<Value2); + Flags=(Result==0 ? VM_FZ:(Result&VM_FS))|((Value1<<(Value2-1))&0x80000000 ? VM_FC:0); + SET_VALUE(Cmd->ByteMode,Op1,Result); + } + break; + case VM_SHR: + { + uint Value1=GET_VALUE(Cmd->ByteMode,Op1); + uint Value2=GET_VALUE(Cmd->ByteMode,Op2); + uint Result=GET_UINT32(Value1>>Value2); + Flags=(Result==0 ? VM_FZ:(Result&VM_FS))|((Value1>>(Value2-1))&VM_FC); + SET_VALUE(Cmd->ByteMode,Op1,Result); + } + break; + case VM_SAR: + { + uint Value1=GET_VALUE(Cmd->ByteMode,Op1); + uint Value2=GET_VALUE(Cmd->ByteMode,Op2); + uint Result=GET_UINT32(((int)Value1)>>Value2); + Flags=(Result==0 ? VM_FZ:(Result&VM_FS))|((Value1>>(Value2-1))&VM_FC); + SET_VALUE(Cmd->ByteMode,Op1,Result); + } + break; + case VM_NEG: + { + // We use "0-value" expression to suppress "unary minus to unsigned" + // compiler warning. + uint Result=GET_UINT32(0-GET_VALUE(Cmd->ByteMode,Op1)); + Flags=Result==0 ? VM_FZ:VM_FC|(Result&VM_FS); + SET_VALUE(Cmd->ByteMode,Op1,Result); + } + break; +#ifdef VM_OPTIMIZE + case VM_NEGB: + SET_VALUE(true,Op1,0-GET_VALUE(true,Op1)); + break; + case VM_NEGD: + SET_VALUE(false,Op1,0-GET_VALUE(false,Op1)); + break; +#endif + case VM_PUSHA: + { + const int RegCount=sizeof(R)/sizeof(R[0]); + for (int I=0,SP=R[7]-4;I<RegCount;I++,SP-=4) + SET_VALUE(false,(uint *)&Mem[SP & VM_MEMMASK],R[I]); + R[7]-=RegCount*4; + } + break; + case VM_POPA: + { + const int RegCount=sizeof(R)/sizeof(R[0]); + for (uint I=0,SP=R[7];I<RegCount;I++,SP+=4) + R[7-I]=GET_VALUE(false,(uint *)&Mem[SP & VM_MEMMASK]); + } + break; + case VM_PUSHF: + R[7]-=4; + SET_VALUE(false,(uint *)&Mem[R[7]&VM_MEMMASK],Flags); + break; + case VM_POPF: + Flags=GET_VALUE(false,(uint *)&Mem[R[7] & VM_MEMMASK]); + R[7]+=4; + break; + case VM_MOVZX: + SET_VALUE(false,Op1,GET_VALUE(true,Op2)); + break; + case VM_MOVSX: + SET_VALUE(false,Op1,(signed char)GET_VALUE(true,Op2)); + break; + case VM_XCHG: + { + uint Value1=GET_VALUE(Cmd->ByteMode,Op1); + SET_VALUE(Cmd->ByteMode,Op1,GET_VALUE(Cmd->ByteMode,Op2)); + SET_VALUE(Cmd->ByteMode,Op2,Value1); + } + break; + case VM_MUL: + { + uint Result=GET_VALUE(Cmd->ByteMode,Op1)*GET_VALUE(Cmd->ByteMode,Op2); + SET_VALUE(Cmd->ByteMode,Op1,Result); + } + break; + case VM_DIV: + { + uint Divider=GET_VALUE(Cmd->ByteMode,Op2); + if (Divider!=0) + { + uint Result=GET_VALUE(Cmd->ByteMode,Op1)/Divider; + SET_VALUE(Cmd->ByteMode,Op1,Result); + } + } + break; + case VM_ADC: + { + uint Value1=GET_VALUE(Cmd->ByteMode,Op1); + uint FC=(Flags&VM_FC); + uint Result=GET_UINT32(Value1+GET_VALUE(Cmd->ByteMode,Op2)+FC); + if (Cmd->ByteMode) + Result&=0xff; + Flags=(Result<Value1 || Result==Value1 && FC)|(Result==0 ? VM_FZ:(Result&VM_FS)); + SET_VALUE(Cmd->ByteMode,Op1,Result); + } + break; + case VM_SBB: + { + uint Value1=GET_VALUE(Cmd->ByteMode,Op1); + uint FC=(Flags&VM_FC); + uint Result=GET_UINT32(Value1-GET_VALUE(Cmd->ByteMode,Op2)-FC); + if (Cmd->ByteMode) + Result&=0xff; + Flags=(Result>Value1 || Result==Value1 && FC)|(Result==0 ? VM_FZ:(Result&VM_FS)); + SET_VALUE(Cmd->ByteMode,Op1,Result); + } + break; +#endif // for #ifndef NORARVM + case VM_RET: + if (R[7]>=VM_MEMSIZE) + return(true); + SET_IP(GET_VALUE(false,(uint *)&Mem[R[7] & VM_MEMMASK])); + R[7]+=4; + continue; +#ifdef VM_STANDARDFILTERS + case VM_STANDARD: + ExecuteStandardFilter((VM_StandardFilters)Cmd->Op1.Data); + break; +#endif + case VM_PRINT: + break; + } + Cmd++; + --MaxOpCount; + } +} + + + + +void RarVM::Prepare(byte *Code,uint CodeSize,VM_PreparedProgram *Prg) +{ + InitBitInput(); + memcpy(InBuf,Code,Min(CodeSize,BitInput::MAX_SIZE)); + + // Calculate the single byte XOR checksum to check validity of VM code. + byte XorSum=0; + for (uint I=1;I<CodeSize;I++) + XorSum^=Code[I]; + + faddbits(8); + + Prg->CmdCount=0; + if (XorSum==Code[0]) // VM code is valid if equal. + { +#ifdef VM_STANDARDFILTERS + VM_StandardFilters FilterType=IsStandardFilter(Code,CodeSize); + if (FilterType!=VMSF_NONE) + { + // VM code is found among standard filters. + Prg->Cmd.Add(1); + VM_PreparedCommand *CurCmd=&Prg->Cmd[Prg->CmdCount++]; + CurCmd->OpCode=VM_STANDARD; + CurCmd->Op1.Data=FilterType; + CurCmd->Op1.Addr=&CurCmd->Op1.Data; + CurCmd->Op2.Addr=&CurCmd->Op2.Data; + CurCmd->Op1.Type=CurCmd->Op2.Type=VM_OPNONE; + CodeSize=0; + } +#endif + uint DataFlag=fgetbits(); + faddbits(1); + + // Read static data contained in DB operators. This data cannot be + // changed, it is a part of VM code, not a filter parameter. + + if (DataFlag&0x8000) + { + uint DataSize=ReadData(*this)+1; + for (uint I=0;(uint)InAddr<CodeSize && I<DataSize;I++) + { + Prg->StaticData.Add(1); + Prg->StaticData[I]=fgetbits()>>8; + faddbits(8); + } + } + + while ((uint)InAddr<CodeSize) + { + Prg->Cmd.Add(1); + VM_PreparedCommand *CurCmd=&Prg->Cmd[Prg->CmdCount]; + uint Data=fgetbits(); + if ((Data&0x8000)==0) + { + CurCmd->OpCode=(VM_Commands)(Data>>12); + faddbits(4); + } + else + { + CurCmd->OpCode=(VM_Commands)((Data>>10)-24); + faddbits(6); + } + if (VM_CmdFlags[CurCmd->OpCode] & VMCF_BYTEMODE) + { + CurCmd->ByteMode=(fgetbits()>>15)!=0; + faddbits(1); + } + else + CurCmd->ByteMode=0; + CurCmd->Op1.Type=CurCmd->Op2.Type=VM_OPNONE; + int OpNum=(VM_CmdFlags[CurCmd->OpCode] & VMCF_OPMASK); + CurCmd->Op1.Addr=CurCmd->Op2.Addr=NULL; + if (OpNum>0) + { + DecodeArg(CurCmd->Op1,CurCmd->ByteMode); // reading the first operand + if (OpNum==2) + DecodeArg(CurCmd->Op2,CurCmd->ByteMode); // reading the second operand + else + { + if (CurCmd->Op1.Type==VM_OPINT && (VM_CmdFlags[CurCmd->OpCode]&(VMCF_JUMP|VMCF_PROC))) + { + // Calculating jump distance. + int Distance=CurCmd->Op1.Data; + if (Distance>=256) + Distance-=256; + else + { + if (Distance>=136) + Distance-=264; + else + if (Distance>=16) + Distance-=8; + else + if (Distance>=8) + Distance-=16; + Distance+=Prg->CmdCount; + } + CurCmd->Op1.Data=Distance; + } + } + } + Prg->CmdCount++; + } + } + + // Adding RET command at the end of program. + Prg->Cmd.Add(1); + VM_PreparedCommand *CurCmd=&Prg->Cmd[Prg->CmdCount++]; + CurCmd->OpCode=VM_RET; + CurCmd->Op1.Addr=&CurCmd->Op1.Data; + CurCmd->Op2.Addr=&CurCmd->Op2.Data; + CurCmd->Op1.Type=CurCmd->Op2.Type=VM_OPNONE; + + // If operand 'Addr' field has not been set by DecodeArg calls above, + // let's set it to point to operand 'Data' field. It is necessary for + // VM_OPINT type operands (usual integers) or maybe if something was + // not set properly for other operands. 'Addr' field is required + // for quicker addressing of operand data. + for (int I=0;I<Prg->CmdCount;I++) + { + VM_PreparedCommand *Cmd=&Prg->Cmd[I]; + if (Cmd->Op1.Addr==NULL) + Cmd->Op1.Addr=&Cmd->Op1.Data; + if (Cmd->Op2.Addr==NULL) + Cmd->Op2.Addr=&Cmd->Op2.Data; + } + +#ifdef VM_OPTIMIZE + if (CodeSize!=0) + Optimize(Prg); +#endif +} + + +void RarVM::DecodeArg(VM_PreparedOperand &Op,bool ByteMode) +{ + uint Data=fgetbits(); + if (Data & 0x8000) + { + Op.Type=VM_OPREG; // Operand is register (R[0]..R[7]) + Op.Data=(Data>>12)&7; // Register number + Op.Addr=&R[Op.Data]; // Register address + faddbits(4); // 1 flag bit and 3 register number bits + } + else + if ((Data & 0xc000)==0) + { + Op.Type=VM_OPINT; // Operand is integer + if (ByteMode) + { + Op.Data=(Data>>6) & 0xff; // Byte integer. + faddbits(10); + } + else + { + faddbits(2); + Op.Data=ReadData(*this); // 32 bit integer. + } + } + else + { + // Operand is data addressed by register data, base address or both. + Op.Type=VM_OPREGMEM; + if ((Data & 0x2000)==0) + { + // Base address is zero, just use the address from register. + Op.Data=(Data>>10)&7; + Op.Addr=&R[Op.Data]; + Op.Base=0; + faddbits(6); + } + else + { + if ((Data & 0x1000)==0) + { + // Use both register and base address. + Op.Data=(Data>>9)&7; + Op.Addr=&R[Op.Data]; + faddbits(7); + } + else + { + // Use base address only. Access memory by fixed address. + Op.Data=0; + faddbits(4); + } + Op.Base=ReadData(*this); // Read base address. + } + } +} + + +uint RarVM::ReadData(BitInput &Inp) +{ + uint Data=Inp.fgetbits(); + switch(Data&0xc000) + { + case 0: + Inp.faddbits(6); + return((Data>>10)&0xf); + case 0x4000: + if ((Data&0x3c00)==0) + { + Data=0xffffff00|((Data>>2)&0xff); + Inp.faddbits(14); + } + else + { + Data=(Data>>6)&0xff; + Inp.faddbits(10); + } + return(Data); + case 0x8000: + Inp.faddbits(2); + Data=Inp.fgetbits(); + Inp.faddbits(16); + return(Data); + default: + Inp.faddbits(2); + Data=(Inp.fgetbits()<<16); + Inp.faddbits(16); + Data|=Inp.fgetbits(); + Inp.faddbits(16); + return(Data); + } +} + + +void RarVM::SetMemory(uint Pos,byte *Data,uint DataSize) +{ + if (Pos<VM_MEMSIZE && Data!=Mem+Pos) + memmove(Mem+Pos,Data,Min(DataSize,VM_MEMSIZE-Pos)); +} + + +#ifdef VM_OPTIMIZE +void RarVM::Optimize(VM_PreparedProgram *Prg) +{ + VM_PreparedCommand *Code=&Prg->Cmd[0]; + uint CodeSize=Prg->CmdCount; + + for (uint I=0;I<CodeSize;I++) + { + VM_PreparedCommand *Cmd=Code+I; + + // Replace universal opcodes with faster byte or word only processing + // opcodes. + switch(Cmd->OpCode) + { + case VM_MOV: + Cmd->OpCode=Cmd->ByteMode ? VM_MOVB:VM_MOVD; + continue; + case VM_CMP: + Cmd->OpCode=Cmd->ByteMode ? VM_CMPB:VM_CMPD; + continue; + } + if ((VM_CmdFlags[Cmd->OpCode] & VMCF_CHFLAGS)==0) + continue; + + // If we do not have jump commands between the current operation + // and next command which will modify processor flags, we can replace + // the current command with faster version which does not need to + // modify flags. + bool FlagsRequired=false; + for (uint J=I+1;J<CodeSize;J++) + { + int Flags=VM_CmdFlags[Code[J].OpCode]; + if (Flags & (VMCF_JUMP|VMCF_PROC|VMCF_USEFLAGS)) + { + FlagsRequired=true; + break; + } + if (Flags & VMCF_CHFLAGS) + break; + } + + // Below we'll replace universal opcodes with faster byte or word only + // processing opcodes, which also do not modify processor flags to + // provide better performance. + if (FlagsRequired) + continue; + switch(Cmd->OpCode) + { + case VM_ADD: + Cmd->OpCode=Cmd->ByteMode ? VM_ADDB:VM_ADDD; + continue; + case VM_SUB: + Cmd->OpCode=Cmd->ByteMode ? VM_SUBB:VM_SUBD; + continue; + case VM_INC: + Cmd->OpCode=Cmd->ByteMode ? VM_INCB:VM_INCD; + continue; + case VM_DEC: + Cmd->OpCode=Cmd->ByteMode ? VM_DECB:VM_DECD; + continue; + case VM_NEG: + Cmd->OpCode=Cmd->ByteMode ? VM_NEGB:VM_NEGD; + continue; + } + } +} +#endif + + +#ifdef VM_STANDARDFILTERS +VM_StandardFilters RarVM::IsStandardFilter(byte *Code,uint CodeSize) +{ + struct StandardFilterSignature + { + int Length; + uint CRC; + VM_StandardFilters Type; + } static StdList[]={ + 53, 0xad576887, VMSF_E8, + 57, 0x3cd7e57e, VMSF_E8E9, + 120, 0x3769893f, VMSF_ITANIUM, + 29, 0x0e06077d, VMSF_DELTA, + 149, 0x1c2c5dc8, VMSF_RGB, + 216, 0xbc85e701, VMSF_AUDIO, + 40, 0x46b9c560, VMSF_UPCASE + }; + uint CodeCRC=CRC(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); + return(VMSF_NONE); +} + + +void RarVM::ExecuteStandardFilter(VM_StandardFilters FilterType) +{ + switch(FilterType) + { + case VMSF_E8: + case VMSF_E8E9: + { + byte *Data=Mem; + int DataSize=R[4]; + uint FileOffset=R[6]; + + if ((uint)DataSize>=VM_GLOBALMEMADDR || DataSize<4) + break; + + const int FileSize=0x1000000; + byte CmpByte2=FilterType==VMSF_E8E9 ? 0xe9:0xe8; + for (int CurPos=0;CurPos<DataSize-4;) + { + byte CurByte=*(Data++); + CurPos++; + if (CurByte==0xe8 || CurByte==CmpByte2) + { +#ifdef PRESENT_INT32 + int32 Offset=CurPos+FileOffset; + int32 Addr=GET_VALUE(false,Data); + if (Addr<0) + { + if (Addr+Offset>=0) + SET_VALUE(false,Data,Addr+FileSize); + } + else + if (Addr<FileSize) + SET_VALUE(false,Data,Addr-Offset); +#else + long Offset=CurPos+FileOffset; + long Addr=GET_VALUE(false,Data); + if ((Addr & 0x80000000)!=0) + { + if (((Addr+Offset) & 0x80000000)==0) + SET_VALUE(false,Data,Addr+FileSize); + } + else + if (((Addr-FileSize) & 0x80000000)!=0) + SET_VALUE(false,Data,Addr-Offset); +#endif + Data+=4; + CurPos+=4; + } + } + } + break; + case VMSF_ITANIUM: + { + byte *Data=Mem; + int DataSize=R[4]; + uint FileOffset=R[6]; + + if ((uint)DataSize>=VM_GLOBALMEMADDR || DataSize<21) + break; + + int CurPos=0; + + FileOffset>>=4; + + while (CurPos<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++; + } + } + break; + case VMSF_DELTA: + { + int DataSize=R[4],Channels=R[0],SrcPos=0,Border=DataSize*2; + SET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x20],DataSize); + if ((uint)DataSize>=VM_GLOBALMEMADDR/2) + break; + + // Bytes from same channels are grouped to continual data blocks, + // so we need to place them back to their interleaving positions. + for (int CurChannel=0;CurChannel<Channels;CurChannel++) + { + byte PrevByte=0; + for (int DestPos=DataSize+CurChannel;DestPos<Border;DestPos+=Channels) + Mem[DestPos]=(PrevByte-=Mem[SrcPos++]); + } + } + break; + case VMSF_RGB: + { + int DataSize=R[4],Width=R[0]-3,PosR=R[1]; + byte *SrcData=Mem,*DestData=SrcData+DataSize; + const int Channels=3; + SET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x20],DataSize); + if ((uint)DataSize>=VM_GLOBALMEMADDR/2 || PosR<0) + break; + for (int CurChannel=0;CurChannel<Channels;CurChannel++) + { + uint PrevByte=0; + + for (int I=CurChannel;I<DataSize;I+=Channels) + { + uint Predicted; + int UpperPos=I-Width; + if (UpperPos>=3) + { + byte *UpperData=DestData+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; + DestData[I]=PrevByte=(byte)(Predicted-*(SrcData++)); + } + } + for (int I=PosR,Border=DataSize-2;I<Border;I+=3) + { + byte G=DestData[I+1]; + DestData[I]+=G; + DestData[I+2]+=G; + } + } + break; + case VMSF_AUDIO: + { + int DataSize=R[4],Channels=R[0]; + byte *SrcData=Mem,*DestData=SrcData+DataSize; + SET_VALUE(false,&Mem[VM_GLOBALMEMADDR+0x20],DataSize); + if ((uint)DataSize>=VM_GLOBALMEMADDR/2) + break; + for (int 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 (int 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; + DestData[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 (int J=1;J<sizeof(Dif)/sizeof(Dif[0]);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; + } + } + } + } + } + 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; + } +} + + +uint RarVM::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 RarVM::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; + } +} +#endif diff --git a/src/thirdparty/unrar/rarvm.hpp b/src/thirdparty/unrar/rarvm.hpp new file mode 100644 index 000000000..96d42c233 --- /dev/null +++ b/src/thirdparty/unrar/rarvm.hpp @@ -0,0 +1,113 @@ +#ifndef _RAR_VM_ +#define _RAR_VM_ + +#define VM_STANDARDFILTERS + +#ifndef SFX_MODULE +#define VM_OPTIMIZE +#endif + + +#define VM_MEMSIZE 0x40000 +#define VM_MEMMASK (VM_MEMSIZE-1) +#define VM_GLOBALMEMADDR 0x3C000 +#define VM_GLOBALMEMSIZE 0x2000 +#define VM_FIXEDGLOBALSIZE 64 + +enum VM_Commands +{ + VM_MOV, VM_CMP, VM_ADD, VM_SUB, VM_JZ, VM_JNZ, VM_INC, VM_DEC, + VM_JMP, VM_XOR, VM_AND, VM_OR, VM_TEST, VM_JS, VM_JNS, VM_JB, + VM_JBE, VM_JA, VM_JAE, VM_PUSH, VM_POP, VM_CALL, VM_RET, VM_NOT, + VM_SHL, VM_SHR, VM_SAR, VM_NEG, VM_PUSHA,VM_POPA, VM_PUSHF,VM_POPF, + VM_MOVZX,VM_MOVSX,VM_XCHG, VM_MUL, VM_DIV, VM_ADC, VM_SBB, VM_PRINT, + +#ifdef VM_OPTIMIZE + VM_MOVB, VM_MOVD, VM_CMPB, VM_CMPD, + + VM_ADDB, VM_ADDD, VM_SUBB, VM_SUBD, VM_INCB, VM_INCD, VM_DECB, VM_DECD, + VM_NEGB, VM_NEGD, +#endif + + VM_STANDARD +}; + +enum VM_StandardFilters { + VMSF_NONE, VMSF_E8, VMSF_E8E9, VMSF_ITANIUM, VMSF_RGB, VMSF_AUDIO, + VMSF_DELTA, VMSF_UPCASE +}; + +enum VM_Flags {VM_FC=1,VM_FZ=2,VM_FS=0x80000000}; + +enum VM_OpType {VM_OPREG,VM_OPINT,VM_OPREGMEM,VM_OPNONE}; + +struct VM_PreparedOperand +{ + VM_OpType Type; + uint Data; + uint Base; + uint *Addr; +}; + +struct VM_PreparedCommand +{ + VM_Commands OpCode; + bool ByteMode; + VM_PreparedOperand Op1,Op2; +}; + + +struct VM_PreparedProgram +{ + VM_PreparedProgram() + { + AltCmd=NULL; + FilteredDataSize=0; + CmdCount=0; + } + + Array<VM_PreparedCommand> Cmd; + VM_PreparedCommand *AltCmd; + int CmdCount; + + Array<byte> GlobalData; + Array<byte> StaticData; // static data contained in DB operators + uint InitR[7]; + + byte *FilteredData; + uint FilteredDataSize; +}; + +class RarVM:private BitInput +{ + private: + inline uint GetValue(bool ByteMode,uint *Addr); + inline void SetValue(bool ByteMode,uint *Addr,uint Value); + inline uint* GetOperand(VM_PreparedOperand *CmdOp); + void DecodeArg(VM_PreparedOperand &Op,bool ByteMode); +#ifdef VM_OPTIMIZE + void Optimize(VM_PreparedProgram *Prg); +#endif + bool ExecuteCode(VM_PreparedCommand *PreparedCode,uint CodeSize); +#ifdef VM_STANDARDFILTERS + VM_StandardFilters IsStandardFilter(byte *Code,uint CodeSize); + void ExecuteStandardFilter(VM_StandardFilters FilterType); + uint FilterItanium_GetBits(byte *Data,int BitPos,int BitCount); + void FilterItanium_SetBits(byte *Data,uint BitField,int BitPos,int BitCount); +#endif + + byte *Mem; + uint R[8]; + uint Flags; + public: + RarVM(); + ~RarVM(); + void Init(); + 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); + static uint ReadData(BitInput &Inp); +}; + +#endif diff --git a/src/thirdparty/unrar/rarvmtbl.cpp b/src/thirdparty/unrar/rarvmtbl.cpp new file mode 100644 index 000000000..b5e6c7201 --- /dev/null +++ b/src/thirdparty/unrar/rarvmtbl.cpp @@ -0,0 +1,53 @@ +#define VMCF_OP0 0 +#define VMCF_OP1 1 +#define VMCF_OP2 2 +#define VMCF_OPMASK 3 +#define VMCF_BYTEMODE 4 +#define VMCF_JUMP 8 +#define VMCF_PROC 16 +#define VMCF_USEFLAGS 32 +#define VMCF_CHFLAGS 64 + +static byte VM_CmdFlags[]= +{ + /* VM_MOV */ VMCF_OP2 | VMCF_BYTEMODE , + /* VM_CMP */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_ADD */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_SUB */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_JZ */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JNZ */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_INC */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_DEC */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_JMP */ VMCF_OP1 | VMCF_JUMP , + /* VM_XOR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_AND */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_OR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_TEST */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_JS */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JNS */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JB */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JBE */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JA */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_JAE */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS , + /* VM_PUSH */ VMCF_OP1 , + /* VM_POP */ VMCF_OP1 , + /* VM_CALL */ VMCF_OP1 | VMCF_PROC , + /* VM_RET */ VMCF_OP0 | VMCF_PROC , + /* VM_NOT */ VMCF_OP1 | VMCF_BYTEMODE , + /* VM_SHL */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_SHR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_SAR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_NEG */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS , + /* VM_PUSHA */ VMCF_OP0 , + /* VM_POPA */ VMCF_OP0 , + /* VM_PUSHF */ VMCF_OP0 | VMCF_USEFLAGS , + /* VM_POPF */ VMCF_OP0 | VMCF_CHFLAGS , + /* VM_MOVZX */ VMCF_OP2 , + /* VM_MOVSX */ VMCF_OP2 , + /* VM_XCHG */ VMCF_OP2 | VMCF_BYTEMODE , + /* VM_MUL */ VMCF_OP2 | VMCF_BYTEMODE , + /* VM_DIV */ VMCF_OP2 | VMCF_BYTEMODE , + /* VM_ADC */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS , + /* VM_SBB */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS , + /* VM_PRINT */ VMCF_OP0 +}; diff --git a/src/thirdparty/unrar/rawread.cpp b/src/thirdparty/unrar/rawread.cpp new file mode 100644 index 000000000..df90171eb --- /dev/null +++ b/src/thirdparty/unrar/rawread.cpp @@ -0,0 +1,126 @@ +#include "rar.hpp" + +RawRead::RawRead(File *SrcFile) +{ + RawRead::SrcFile=SrcFile; + ReadPos=0; + DataSize=0; +#ifndef SHELL_EXT + Crypt=NULL; +#endif +} + + +void RawRead::Read(size_t Size) +{ +#if !defined(SHELL_EXT) && !defined(RAR_NOCRYPT) + if (Crypt!=NULL) + { + size_t CurSize=Data.Size(); + size_t SizeToRead=Size-(CurSize-DataSize); + if (SizeToRead>0) + { + size_t AlignedReadSize=SizeToRead+((~SizeToRead+1)&0xf); + Data.Add(AlignedReadSize); + size_t ReadSize=SrcFile->Read(&Data[CurSize],AlignedReadSize); + Crypt->DecryptBlock(&Data[CurSize],AlignedReadSize); + DataSize+=ReadSize==0 ? 0:Size; + } + else + DataSize+=Size; + } + else +#endif + if (Size!=0) + { + Data.Add(Size); + DataSize+=SrcFile->Read(&Data[DataSize],Size); + } +} + + +void RawRead::Read(byte *SrcData,size_t Size) +{ + if (Size!=0) + { + Data.Add(Size); + memcpy(&Data[DataSize],SrcData,Size); + DataSize+=Size; + } +} + + +void RawRead::Get(byte &Field) +{ + if (ReadPos<DataSize) + { + Field=Data[ReadPos]; + ReadPos++; + } + else + Field=0; +} + + +void RawRead::Get(ushort &Field) +{ + if (ReadPos+1<DataSize) + { + Field=Data[ReadPos]+(Data[ReadPos+1]<<8); + ReadPos+=2; + } + else + Field=0; +} + + +void RawRead::Get(uint &Field) +{ + if (ReadPos+3<DataSize) + { + Field=Data[ReadPos]+(Data[ReadPos+1]<<8)+(Data[ReadPos+2]<<16)+ + (Data[ReadPos+3]<<24); + ReadPos+=4; + } + else + Field=0; +} + + +void RawRead::Get8(int64 &Field) +{ + uint Low,High; + Get(Low); + Get(High); + Field=INT32TO64(High,Low); +} + + +void RawRead::Get(byte *Field,size_t Size) +{ + if (ReadPos+Size-1<DataSize) + { + memcpy(Field,&Data[ReadPos],Size); + ReadPos+=Size; + } + else + memset(Field,0,Size); +} + + +void RawRead::Get(wchar *Field,size_t Size) +{ + if (ReadPos+2*Size-1<DataSize) + { + RawToWide(&Data[ReadPos],Field,Size); + ReadPos+=sizeof(wchar)*Size; + } + else + memset(Field,0,sizeof(wchar)*Size); +} + + +uint RawRead::GetCRC(bool ProcessedOnly) +{ + return(DataSize>2 ? CRC(0xffffffff,&Data[2],(ProcessedOnly ? ReadPos:DataSize)-2):0xffffffff); +} diff --git a/src/thirdparty/unrar/rawread.hpp b/src/thirdparty/unrar/rawread.hpp new file mode 100644 index 000000000..39fefe6f7 --- /dev/null +++ b/src/thirdparty/unrar/rawread.hpp @@ -0,0 +1,32 @@ +#ifndef _RAR_RAWREAD_ +#define _RAR_RAWREAD_ + +class RawRead +{ + private: + Array<byte> Data; + File *SrcFile; + size_t DataSize; + size_t ReadPos; +#ifndef SHELL_EXT + CryptData *Crypt; +#endif + public: + RawRead(File *SrcFile); + void 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); + size_t Size() {return DataSize;} + size_t PaddedSize() {return Data.Size()-DataSize;} +#ifndef SHELL_EXT + void SetCrypt(CryptData *Crypt) {RawRead::Crypt=Crypt;} +#endif +}; + +#endif diff --git a/src/thirdparty/unrar/rdwrfn.cpp b/src/thirdparty/unrar/rdwrfn.cpp new file mode 100644 index 000000000..d7bacd478 --- /dev/null +++ b/src/thirdparty/unrar/rdwrfn.cpp @@ -0,0 +1,295 @@ +#include "rar.hpp" + +ComprDataIO::ComprDataIO() +{ + Init(); +} + + +void ComprDataIO::Init() +{ + UnpackFromMemory=false; + UnpackToMemory=false; + UnpPackedSize=0; + ShowProgress=true; + TestMode=false; + SkipUnpCRC=false; + PackVolume=false; + UnpVolume=false; + NextVolumeMissing=false; + SrcFile=NULL; + DestFile=NULL; + UnpWrSize=0; + Command=NULL; + Encryption=0; + Decryption=0; + TotalPackRead=0; + CurPackRead=CurPackWrite=CurUnpRead=CurUnpWrite=0; + PackFileCRC=UnpFileCRC=PackedCRC=0xffffffff; + LastPercent=-1; + SubHead=NULL; + SubHeadPos=NULL; + CurrentCommand=0; + ProcessedArcSize=TotalArcSize=0; +} + + + + +int ComprDataIO::UnpRead(byte *Addr,size_t Count) +{ + int RetCode=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; + UnpackFromMemorySize=0; + } + else + { + 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); + } + CurUnpRead+=RetCode; + TotalRead+=RetCode; +#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; +#endif + UnpPackedSize-=RetCode; + if (UnpPackedSize == 0 && UnpVolume) + { +#ifndef NOVOLUME + if (!MergeArchive(*SrcArc,this,true,CurrentCommand)) +#endif + { + NextVolumeMissing=true; + return(-1); + } + } + else + break; + } + Archive *SrcArc=(Archive *)SrcFile; + if (SrcArc!=NULL) + ShowUnpRead(SrcArc->CurBlockPos+CurUnpRead,UnpArcSize); + if (RetCode!=-1) + { + RetCode=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); + } +#endif + } + Wait(); + return(RetCode); +} + + +#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64) +// Disable the run time stack check for unrar.dll, so we can manipulate +// with ProcessDataProc call type below. Run time check would intercept +// a wrong ESP before we restore it. +#pragma runtime_checks( "s", off ) +#endif + +void ComprDataIO::UnpWrite(byte *Addr,size_t Count) +{ + +#ifdef RARDLL + RAROptions *Cmd=((Archive *)SrcFile)->GetRAROptions(); + if (Cmd->DllOpMode!=RAR_SKIP) + { + if (Cmd->Callback!=NULL && + Cmd->Callback(UCM_PROCESSDATA,Cmd->UserData,(LPARAM)Addr,Count)==-1) + ErrHandler.Exit(RARX_USERBREAK); + if (Cmd->ProcessDataProc!=NULL) + { + // Here we preserve ESP value. It is necessary for those developers, + // who still define ProcessDataProc 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->ProcessDataProc(Addr,(int)Count); + + // Restore ESP after ProcessDataProc 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) + ErrHandler.Exit(RARX_USERBREAK); + } + } +#endif // RARDLL + + UnpWrAddr=Addr; + UnpWrSize=Count; + if (UnpackToMemory) + { + if (Count <= UnpackToMemorySize) + { + memcpy(UnpackToMemoryAddr,Addr,Count); + UnpackToMemoryAddr+=Count; + UnpackToMemorySize-=Count; + } + } + else + if (!TestMode) + 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); + ShowUnpWrite(); + Wait(); +} + +#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64) +// Restore the run time stack check for unrar.dll. +#pragma runtime_checks( "s", restore ) +#endif + + + + + + +void ComprDataIO::ShowUnpRead(int64 ArcPos,int64 ArcSize) +{ + if (ShowProgress && SrcFile!=NULL) + { + if (TotalArcSize!=0) + { + // important when processing several archives or multivolume archive + ArcSize=TotalArcSize; + ArcPos+=ProcessedArcSize; + } + + Archive *SrcArc=(Archive *)SrcFile; + RAROptions *Cmd=SrcArc->GetRAROptions(); + + int CurPercent=ToPercent(ArcPos,ArcSize); + if (!Cmd->DisablePercentage && CurPercent!=LastPercent) + { + mprintf("\b\b\b\b%3d%%",CurPercent); + LastPercent=CurPercent; + } + } +} + + +void ComprDataIO::ShowUnpWrite() +{ +} + + + + + + + + +void ComprDataIO::SetFiles(File *SrcFile,File *DestFile) +{ + if (SrcFile!=NULL) + ComprDataIO::SrcFile=SrcFile; + if (DestFile!=NULL) + ComprDataIO::DestFile=DestFile; + LastPercent=-1; +} + + +void ComprDataIO::GetUnpackedData(byte **Data,size_t *Size) +{ + *Data=UnpWrAddr; + *Size=UnpWrSize; +} + + +void ComprDataIO::SetEncryption(int Method,SecPassword *Password,const byte *Salt,bool Encrypt,bool HandsOffHash) +{ + if (Encrypt) + { + Encryption=Password->IsSet() ? Method:0; +#ifndef RAR_NOCRYPT + Crypt.SetCryptKeys(Password,Salt,Encrypt,false,HandsOffHash); +#endif + } + else + { + Decryption=Password->IsSet() ? Method:0; +#ifndef RAR_NOCRYPT + Decrypt.SetCryptKeys(Password,Salt,Encrypt,Method<29,HandsOffHash); +#endif + } +} + + +#if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT) +void ComprDataIO::SetAV15Encryption() +{ + Decryption=15; + Decrypt.SetAV15Encryption(); +} +#endif + + +#if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT) +void ComprDataIO::SetCmt13Encryption() +{ + Decryption=13; + Decrypt.SetCmt13Encryption(); +} +#endif + + + + +void ComprDataIO::SetUnpackToMemory(byte *Addr,uint Size) +{ + UnpackToMemory=true; + UnpackToMemoryAddr=Addr; + UnpackToMemorySize=Size; +} + + diff --git a/src/thirdparty/unrar/rdwrfn.hpp b/src/thirdparty/unrar/rdwrfn.hpp new file mode 100644 index 000000000..0c6fd1dc5 --- /dev/null +++ b/src/thirdparty/unrar/rdwrfn.hpp @@ -0,0 +1,88 @@ +#ifndef _RAR_DATAIO_ +#define _RAR_DATAIO_ + +class CmdAdd; +class Unpack; + + +class ComprDataIO +{ + private: + void ShowUnpRead(int64 ArcPos,int64 ArcSize); + void ShowUnpWrite(); + + + bool UnpackFromMemory; + size_t UnpackFromMemorySize; + byte *UnpackFromMemoryAddr; + + bool UnpackToMemory; + size_t UnpackToMemorySize; + byte *UnpackToMemoryAddr; + + size_t UnpWrSize; + byte *UnpWrAddr; + + int64 UnpPackedSize; + + bool ShowProgress; + bool TestMode; + bool SkipUnpCRC; + + File *SrcFile; + File *DestFile; + + CmdAdd *Command; + + FileHeader *SubHead; + int64 *SubHeadPos; + +#ifndef RAR_NOCRYPT + CryptData Crypt; + CryptData Decrypt; +#endif + + + int LastPercent; + + char CurrentCommand; + + public: + ComprDataIO(); + void Init(); + int UnpRead(byte *Addr,size_t Count); + void UnpWrite(byte *Addr,size_t Count); + void EnableShowProgress(bool Show) {ShowProgress=Show;} + void GetUnpackedData(byte **Data,size_t *Size); + void SetPackedSizeToRead(int64 Size) {UnpPackedSize=Size;} + void SetTestMode(bool Mode) {TestMode=Mode;} + void SetSkipUnpCRC(bool Skip) {SkipUnpCRC=Skip;} + 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 SetAV15Encryption(); + void SetCmt13Encryption(); + void SetUnpackToMemory(byte *Addr,uint Size); + void SetCurrentCommand(char 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; + + int Encryption; + int Decryption; +}; + +#endif diff --git a/src/thirdparty/unrar/readme.txt b/src/thirdparty/unrar/readme.txt new file mode 100644 index 000000000..fd7137d95 --- /dev/null +++ b/src/thirdparty/unrar/readme.txt @@ -0,0 +1,66 @@ + + Portable UnRAR version + + + 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, + 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. + + 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 + in rartypes.hpp. + + 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. + + UnRAR.vcproj and UnRARDll.vcproj are projects for Microsoft Visual C++. + UnRARDll.vcproj lets to build unrar.dll library. + + + 2. Unrar binaries + + If you compiled Unrar for OS, which is not present in "Downloads" + and "RAR extras" on www.rarlab.com, we will appreciate if you send + us the compiled executable to place it to our site. + + + 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 + + + 4. Legal stuff + + Unrar source may be used in any software to handle RAR archives + without limitations free of charge, but cannot be used to re-create + the RAR compression algorithm, which is proprietary. Distribution + of modified Unrar source in separate form or as a part of other + software is permitted, provided that it is clearly stated in + the documentation and source comments that the code may not be used + to develop a RAR (WinRAR) compatible archiver. + + More detailed license text is available in license.txt. diff --git a/src/thirdparty/unrar/recvol.cpp b/src/thirdparty/unrar/recvol.cpp new file mode 100644 index 000000000..0d6162e17 --- /dev/null +++ b/src/thirdparty/unrar/recvol.cpp @@ -0,0 +1,572 @@ +#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 + +RecVolumes::RecVolumes() +{ + 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) + { + mprintf(St(MRecVolFound),FoundRecVolumes); + } +#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++) + { + 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); + } + +#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) + { + // 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(); + } + } + } +#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++) + { + 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/recvol.hpp b/src/thirdparty/unrar/recvol.hpp new file mode 100644 index 000000000..9a97465eb --- /dev/null +++ b/src/thirdparty/unrar/recvol.hpp @@ -0,0 +1,20 @@ +#ifndef _RAR_RECVOL_ +#define _RAR_RECVOL_ + +class RecVolumes +{ + private: + File *SrcFile[256]; + Array<byte> Buf; + +#ifdef RAR_SMP + 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); +}; + +#endif diff --git a/src/thirdparty/unrar/resource.cpp b/src/thirdparty/unrar/resource.cpp new file mode 100644 index 000000000..1c966ce88 --- /dev/null +++ b/src/thirdparty/unrar/resource.cpp @@ -0,0 +1,27 @@ +#include "rar.hpp" + + + +#ifndef RARDLL +const char *St(MSGID StringId) +{ + return(StringId); +} +#endif + + +#ifndef RARDLL +const wchar *StW(MSGID StringId) +{ + static wchar StrTable[8][512]; + static int StrNum=0; + if (++StrNum >= sizeof(StrTable)/sizeof(StrTable[0])) + StrNum=0; + wchar *Str=StrTable[StrNum]; + *Str=0; + CharToWide(StringId,Str,ASIZE(StrTable[0])); + return(Str); +} +#endif + + diff --git a/src/thirdparty/unrar/resource.hpp b/src/thirdparty/unrar/resource.hpp new file mode 100644 index 000000000..7df584438 --- /dev/null +++ b/src/thirdparty/unrar/resource.hpp @@ -0,0 +1,13 @@ +#ifndef _RAR_RESOURCE_ +#define _RAR_RESOURCE_ + +#ifdef RARDLL +#define St(x) ( "") +#define StW(x) (L"") +#else +const char *St (MSGID StringId); +const wchar *StW (MSGID StringId); +#endif + + +#endif diff --git a/src/thirdparty/unrar/rijndael.cpp b/src/thirdparty/unrar/rijndael.cpp new file mode 100644 index 000000000..67434ba20 --- /dev/null +++ b/src/thirdparty/unrar/rijndael.cpp @@ -0,0 +1,298 @@ +/************************************************************************** + * 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 * + **************************************************************************/ +#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]; +static byte U1[256][4],U2[256][4],U3[256][4],U4[256][4]; + + +inline void Xor128(byte *dest,const byte *arg1,const byte *arg2) +{ +#if defined(PRESENT_INT32) && defined(ALLOW_NOT_ALIGNED_INT) + ((uint32*)dest)[0]=((uint32*)arg1)[0]^((uint32*)arg2)[0]; + ((uint32*)dest)[1]=((uint32*)arg1)[1]^((uint32*)arg2)[1]; + ((uint32*)dest)[2]=((uint32*)arg1)[2]^((uint32*)arg2)[2]; + ((uint32*)dest)[3]=((uint32*)arg1)[3]^((uint32*)arg2)[3]; +#else + for (int I=0;I<16;I++) + dest[I]=arg1[I]^arg2[I]; +#endif +} + + +inline void Xor128(byte *dest,const byte *arg1,const byte *arg2, + const byte *arg3,const byte *arg4) +{ +#if defined(PRESENT_INT32) && defined(ALLOW_NOT_ALIGNED_INT) + (*(uint32*)dest)=(*(uint32*)arg1)^(*(uint32*)arg2)^(*(uint32*)arg3)^(*(uint32*)arg4); +#else + for (int I=0;I<4;I++) + dest[I]=arg1[I]^arg2[I]^arg3[I]^arg4[I]; +#endif +} + + +inline void Copy128(byte *dest,const byte *src) +{ +#if defined(PRESENT_INT32) && defined(ALLOW_NOT_ALIGNED_INT) + ((uint32*)dest)[0]=((uint32*)src)[0]; + ((uint32*)dest)[1]=((uint32*)src)[1]; + ((uint32*)dest)[2]=((uint32*)src)[2]; + ((uint32*)dest)[3]=((uint32*)src)[3]; +#else + for (int I=0;I<16;I++) + dest[I]=src[I]; +#endif +} + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// API +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +Rijndael::Rijndael() +{ + if (S[0]==0) + GenerateTables(); +} + + +void Rijndael::init(Direction dir,const byte * key,byte * initVector) +{ + m_direction = dir; + + byte keyMatrix[_MAX_KEY_COLUMNS][4]; + + for(uint i = 0;i < uKeyLenInBytes;i++) + keyMatrix[i >> 2][i & 3] = key[i]; + + for(int i = 0;i < MAX_IV_SIZE;i++) + m_initVector[i] = initVector[i]; + + keySched(keyMatrix); + + if(m_direction == Decrypt) + keyEncToDec(); +} + + + +size_t Rijndael::blockDecrypt(const byte *input, size_t inputLen, byte *outBuffer) +{ + if (input == 0 || inputLen <= 0) + return 0; + + byte block[16], iv[4][4]; + memcpy(iv,m_initVector,16); + + size_t numBlocks=inputLen/16; + for (size_t i = numBlocks; i > 0; i--) + { + decrypt(input, block); + Xor128(block,block,(byte*)iv); +#if STRICT_ALIGN + memcpy(iv, input, 16); + memcpy(outBuf, block, 16); +#else + Copy128((byte*)iv,input); + Copy128(outBuffer,block); +#endif + input += 16; + outBuffer += 16; + } + + memcpy(m_initVector,iv,16); + + return 16*numBlocks; +} + + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// ALGORITHM +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +void Rijndael::keySched(byte key[_MAX_KEY_COLUMNS][4]) +{ + int j,rconpointer = 0; + + // Calculate the necessary round keys + // The number of calculations depends on keyBits and blockBits + int uKeyColumns = m_uRounds - 6; + + byte tempKey[_MAX_KEY_COLUMNS][4]; + + // Copy the input key to the temporary key matrix + + memcpy(tempKey,key,sizeof(tempKey)); + + int r = 0; + int t = 0; + + // copy values into round key array + for(j = 0;(j < uKeyColumns) && (r <= m_uRounds); ) + { + for(;(j < uKeyColumns) && (t < 4); j++, t++) + for (int k=0;k<4;k++) + m_expandedKey[r][t][k]=tempKey[j][k]; + + if(t == 4) + { + r++; + t = 0; + } + } + + while(r <= m_uRounds) + { + tempKey[0][0] ^= S[tempKey[uKeyColumns-1][1]]; + tempKey[0][1] ^= S[tempKey[uKeyColumns-1][2]]; + tempKey[0][2] ^= S[tempKey[uKeyColumns-1][3]]; + tempKey[0][3] ^= S[tempKey[uKeyColumns-1][0]]; + tempKey[0][0] ^= rcon[rconpointer++]; + + if (uKeyColumns != 8) + for(j = 1; j < uKeyColumns; j++) + for (int k=0;k<4;k++) + tempKey[j][k] ^= tempKey[j-1][k]; + else + { + for(j = 1; j < uKeyColumns/2; j++) + for (int k=0;k<4;k++) + tempKey[j][k] ^= tempKey[j-1][k]; + + tempKey[uKeyColumns/2][0] ^= S[tempKey[uKeyColumns/2 - 1][0]]; + tempKey[uKeyColumns/2][1] ^= S[tempKey[uKeyColumns/2 - 1][1]]; + tempKey[uKeyColumns/2][2] ^= S[tempKey[uKeyColumns/2 - 1][2]]; + tempKey[uKeyColumns/2][3] ^= S[tempKey[uKeyColumns/2 - 1][3]]; + for(j = uKeyColumns/2 + 1; j < uKeyColumns; j++) + for (int k=0;k<4;k++) + tempKey[j][k] ^= tempKey[j-1][k]; + } + for(j = 0; (j < uKeyColumns) && (r <= m_uRounds); ) + { + for(; (j < uKeyColumns) && (t < 4); j++, t++) + for (int k=0;k<4;k++) + m_expandedKey[r][t][k] = tempKey[j][k]; + if(t == 4) + { + r++; + t = 0; + } + } + } +} + +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++) + { + 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]; + } + memcpy(m_expandedKey[r],n_expandedKey,sizeof(m_expandedKey[0])); + } +} + + +void Rijndael::decrypt(const byte a[16], byte b[16]) +{ + int r; + byte temp[4][4]; + + Xor128((byte*)temp,(byte*)a,(byte*)m_expandedKey[m_uRounds]); + + Xor128(b, T5[temp[0][0]],T6[temp[3][1]],T7[temp[2][2]],T8[temp[1][3]]); + Xor128(b+4, T5[temp[1][0]],T6[temp[0][1]],T7[temp[3][2]],T8[temp[2][3]]); + Xor128(b+8, T5[temp[2][0]],T6[temp[1][1]],T7[temp[0][2]],T8[temp[3][3]]); + Xor128(b+12,T5[temp[3][0]],T6[temp[2][1]],T7[temp[1][2]],T8[temp[0][3]]); + + for(r = m_uRounds-1; r > 1; r--) + { + Xor128((byte*)temp,(byte*)b,(byte*)m_expandedKey[r]); + Xor128(b, T5[temp[0][0]],T6[temp[3][1]],T7[temp[2][2]],T8[temp[1][3]]); + Xor128(b+4, T5[temp[1][0]],T6[temp[0][1]],T7[temp[3][2]],T8[temp[2][3]]); + Xor128(b+8, T5[temp[2][0]],T6[temp[1][1]],T7[temp[0][2]],T8[temp[3][3]]); + Xor128(b+12,T5[temp[3][0]],T6[temp[2][1]],T7[temp[1][2]],T8[temp[0][3]]); + } + + Xor128((byte*)temp,(byte*)b,(byte*)m_expandedKey[1]); + b[ 0] = S5[temp[0][0]]; + b[ 1] = S5[temp[3][1]]; + b[ 2] = S5[temp[2][2]]; + b[ 3] = S5[temp[1][3]]; + b[ 4] = S5[temp[1][0]]; + b[ 5] = S5[temp[0][1]]; + b[ 6] = S5[temp[3][2]]; + b[ 7] = S5[temp[2][3]]; + b[ 8] = S5[temp[2][0]]; + b[ 9] = S5[temp[1][1]]; + b[10] = S5[temp[0][2]]; + b[11] = S5[temp[3][3]]; + b[12] = S5[temp[3][0]]; + b[13] = S5[temp[2][1]]; + b[14] = S5[temp[1][2]]; + b[15] = S5[temp[0][3]]; + Xor128((byte*)b,(byte*)b,(byte*)m_expandedKey[0]); +} + +#define ff_poly 0x011b +#define ff_hi 0x80 + +#define FFinv(x) ((x) ? pow[255 - log[x]]: 0) + +#define FFmul02(x) (x ? pow[log[x] + 0x19] : 0) +#define FFmul03(x) (x ? pow[log[x] + 0x01] : 0) +#define FFmul09(x) (x ? pow[log[x] + 0xc7] : 0) +#define FFmul0b(x) (x ? pow[log[x] + 0x68] : 0) +#define FFmul0d(x) (x ? pow[log[x] + 0xee] : 0) +#define FFmul0e(x) (x ? pow[log[x] + 0xdf] : 0) +#define fwd_affine(x) \ + (w = (uint)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), (byte)(0x63^(w^(w>>8)))) + +#define inv_affine(x) \ + (w = (uint)x, w = (w<<1)^(w<<3)^(w<<6), (byte)(0x05^(w^(w>>8)))) + +void Rijndael::GenerateTables() +{ + unsigned char pow[512],log[256]; + int i = 0, w = 1; + do + { + pow[i] = (byte)w; + pow[i + 255] = (byte)w; + log[w] = (byte)i++; + w ^= (w << 1) ^ (w & ff_hi ? ff_poly : 0); + } while (w != 1); + + for (int i = 0,w = 1; i < sizeof(rcon)/sizeof(rcon[0]); i++) + { + rcon[i] = w; + w = (w << 1) ^ (w & ff_hi ? ff_poly : 0); + } + for(int i = 0; i < 256; ++i) + { + unsigned char b=S[i]=fwd_affine(FFinv((byte)i)); + T1[i][1]=T1[i][2]=T2[i][2]=T2[i][3]=T3[i][0]=T3[i][3]=T4[i][0]=T4[i][1]=b; + T1[i][0]=T2[i][1]=T3[i][2]=T4[i][3]=FFmul02(b); + T1[i][3]=T2[i][0]=T3[i][1]=T4[i][2]=FFmul03(b); + S5[i] = b = FFinv(inv_affine((byte)i)); + U1[b][3]=U2[b][0]=U3[b][1]=U4[b][2]=T5[i][3]=T6[i][0]=T7[i][1]=T8[i][2]=FFmul0b(b); + U1[b][1]=U2[b][2]=U3[b][3]=U4[b][0]=T5[i][1]=T6[i][2]=T7[i][3]=T8[i][0]=FFmul09(b); + U1[b][2]=U2[b][3]=U3[b][0]=U4[b][1]=T5[i][2]=T6[i][3]=T7[i][0]=T8[i][1]=FFmul0d(b); + 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); + } +} diff --git a/src/thirdparty/unrar/rijndael.hpp b/src/thirdparty/unrar/rijndael.hpp new file mode 100644 index 000000000..bb5bd881c --- /dev/null +++ b/src/thirdparty/unrar/rijndael.hpp @@ -0,0 +1,37 @@ +#ifndef _RIJNDAEL_H_ +#define _RIJNDAEL_H_ + +/************************************************************************** + * 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's work: * + * http://fp.gladman.plus.com/cryptography_technology/rijndael * + **************************************************************************/ + +#define _MAX_KEY_COLUMNS (256/32) +#define _MAX_ROUNDS 14 +#define MAX_IV_SIZE 16 + +class Rijndael +{ + public: + enum Direction { Encrypt , Decrypt }; + private: + void keySched(byte key[_MAX_KEY_COLUMNS][4]); + void keyEncToDec(); + void encrypt(const byte a[16], byte b[16]); + void decrypt(const byte a[16], byte b[16]); + void GenerateTables(); + + Direction m_direction; + 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); + 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 new file mode 100644 index 000000000..b7ce1db60 --- /dev/null +++ b/src/thirdparty/unrar/rs.cpp @@ -0,0 +1,172 @@ +#include "rar.hpp" + +#define Clean(D,S) {for (int I=0;I<(S);I++) (D)[I]=0;} + +void RSCoder::Init(int ParSize) +{ + RSCoder::ParSize=ParSize; // Store the number of recovery volumes. + FirstBlockDone=false; + gfInit(); + pnInit(); +} + + +// Initialize logarithms and exponents Galois field tables. +void RSCoder::gfInit() +{ + for (int I=0,J=1;I<MAXPAR;I++) + { + gfLog[J]=I; + gfExp[I]=J; + J<<=1; + if (J & 0x100) + J^=0x11D; // 0x11D field-generator polynomial (x^8+x^4+x^3+x^2+1). + } + for (int I=MAXPAR;I<MAXPOL;I++) + gfExp[I]=gfExp[I-MAXPAR]; +} + + +// Multiplication over Galois field. +inline int RSCoder::gfMult(int a,int b) +{ + return(a==0 || b == 0 ? 0:gfExp[gfLog[a]+gfLog[b]]); +} + + +// Create the generator polynomial g(x). +// g(x)=(x-a)(x-a^2)(x-a^3)..(x-a^N) +void RSCoder::pnInit() +{ + int p2[MAXPAR+1]; // Currently calculated part of g(x). + + Clean(p2,ParSize); + p2[0]=1; // Set p2 polynomial to 1. + + for (int I=1;I<=ParSize;I++) + { + int p1[MAXPAR+1]; // We use p1 as current (x+a^i) expression. + Clean(p1,ParSize); + p1[0]=gfExp[I]; + p1[1]=1; // Set p1 polynomial to x+a^i. + + // Multiply the already calucated part of g(x) to next (x+a^i). + pnMult(p1,p2,GXPol); + + // p2=g(x). + for (int J=0;J<ParSize;J++) + p2[J]=GXPol[J]; + } +} + + +// Multiply polynomial 'p1' to 'p2' and store the result in 'r'. +void RSCoder::pnMult(int *p1,int *p2,int *r) +{ + Clean(r,ParSize); + for (int I=0;I<ParSize;I++) + if (p1[I]!=0) + for(int J=0;J<ParSize-I;J++) + r[I+J]^=gfMult(p1[I],p2[J]); +} + + +void RSCoder::Encode(byte *Data,int DataSize,byte *DestData) +{ + int ShiftReg[MAXPAR+1]; // Linear Feedback Shift Register. + + Clean(ShiftReg,ParSize+1); + for (int I=0;I<DataSize;I++) + { + int D=Data[I]^ShiftReg[ParSize-1]; + + // Use g(x) to define feedback taps. + for (int J=ParSize-1;J>0;J--) + ShiftReg[J]=ShiftReg[J-1]^gfMult(GXPol[J],D); + ShiftReg[0]=gfMult(GXPol[0],D); + } + for (int I=0;I<ParSize;I++) + DestData[I]=ShiftReg[ParSize-I-1]; +} + + +bool RSCoder::Decode(byte *Data,int DataSize,int *EraLoc,int EraSize) +{ + int SynData[MAXPOL]; // Syndrome data. + + 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); + if ((SynData[I]=Sum)!=0) + AllZeroes=false; + } + + // If all syndrome numbers are zero, message does not have errors. + if (AllZeroes) + return(true); + + if (!FirstBlockDone) // Do things which we need to do once for all data. + { + FirstBlockDone=true; + + // Calculate the error locator polynomial. + Clean(ELPol,ParSize+1); + ELPol[0]=1; + + for (int EraPos=0;EraPos<EraSize;EraPos++) + for (int I=ParSize,M=gfExp[DataSize-EraLoc[EraPos]-1];I>0;I--) + ELPol[I]^=gfMult(M,ELPol[I-1]); + + ErrCount=0; + + // Find roots of error locator polynomial. + for (int Root=MAXPAR-DataSize;Root<MAXPAR+1;Root++) + { + int Sum=0; + for (int B=0;B<ParSize+1;B++) + Sum^=gfMult(gfExp[(B*Root)%MAXPAR],ELPol[B]); + if (Sum==0) // Root found. + { + ErrorLocs[ErrCount]=MAXPAR-Root; // Location of error. + + // Calculate the denominator for every error location. + Dnm[ErrCount]=0; + for (int I=1;I<ParSize+1;I+=2) + Dnm[ErrCount]^= gfMult(ELPol[I],gfExp[Root*(I-1)%MAXPAR]); + + ErrCount++; + } + } + } + + int EEPol[MAXPOL]; // Error Evaluator Polynomial. + pnMult(ELPol,SynData,EEPol); + // If errors are present and their number is correctable. + if ((ErrCount<=ParSize) && ErrCount>0) + for (int I=0;I<ErrCount;I++) + { + int Loc=ErrorLocs[I],DLoc=MAXPAR-Loc,N=0; + for (int J=0;J<ParSize;J++) + N^=gfMult(EEPol[J],gfExp[DLoc*J%MAXPAR]); + int DataPos=DataSize-Loc-1; + // Perform bounds check and correct the data error. + if (DataPos>=0 && DataPos<DataSize) + Data[DataPos]^=gfMult(N,gfExp[MAXPAR-gfLog[Dnm[I]]]); + } + return(ErrCount<=ParSize); // Return true if success. +} diff --git a/src/thirdparty/unrar/rs.hpp b/src/thirdparty/unrar/rs.hpp new file mode 100644 index 000000000..6ac80940e --- /dev/null +++ b/src/thirdparty/unrar/rs.hpp @@ -0,0 +1,32 @@ +#ifndef _RAR_RS_ +#define _RAR_RS_ + +#define MAXPAR 255 // Maximum parity data size. +#define MAXPOL 512 // Maximum polynomial degree. + +class RSCoder +{ + private: + void gfInit(); + int gfMult(int a,int b); + void pnInit(); + void pnMult(int *p1,int *p2,int *r); + + int gfExp[MAXPOL]; // Galois field exponents. + int gfLog[MAXPAR+1]; // Galois field logarithms. + + int GXPol[MAXPOL*2]; // Generator polynomial g(x). + + int ErrorLocs[MAXPAR+1],ErrCount; + int Dnm[MAXPAR+1]; + + int ParSize; // Parity bytes size and so the number of recovery volumes. + int ELPol[MAXPOL]; // Error locator polynomial. + bool FirstBlockDone; + public: + void Init(int ParSize); + void Encode(byte *Data,int DataSize,byte *DestData); + bool Decode(byte *Data,int DataSize,int *EraLoc,int EraSize); +}; + +#endif diff --git a/src/thirdparty/unrar/savepos.cpp b/src/thirdparty/unrar/savepos.cpp new file mode 100644 index 000000000..e46c4e666 --- /dev/null +++ b/src/thirdparty/unrar/savepos.cpp @@ -0,0 +1,15 @@ +#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 new file mode 100644 index 000000000..b3b237339 --- /dev/null +++ b/src/thirdparty/unrar/savepos.hpp @@ -0,0 +1,15 @@ +#ifndef _RAR_SAVEPOS_ +#define _RAR_SAVEPOS_ + +class SaveFilePos +{ + private: + File *SaveFile; + int64 SavePos; + uint CloseCount; + public: + SaveFilePos(File &SaveFile); + ~SaveFilePos(); +}; + +#endif diff --git a/src/thirdparty/unrar/scantree.cpp b/src/thirdparty/unrar/scantree.cpp new file mode 100644 index 000000000..9fbfd10cd --- /dev/null +++ b/src/thirdparty/unrar/scantree.cpp @@ -0,0 +1,413 @@ +#include "rar.hpp" + +ScanTree::ScanTree(StringList *FileMasks,RECURSE_MODE Recurse,bool GetLinks,SCAN_DIRS GetDirs) +{ + ScanTree::FileMasks=FileMasks; + ScanTree::Recurse=Recurse; + ScanTree::GetLinks=GetLinks; + ScanTree::GetDirs=GetDirs; + + ScanEntireDisk=false; + + SetAllMaskDepth=0; + *CurMask=0; + *CurMaskW=0; + memset(FindStack,0,sizeof(FindStack)); + Depth=0; + Errors=0; + *ErrArcName=0; + Cmd=NULL; +} + + +ScanTree::~ScanTree() +{ + for (int I=Depth;I>=0;I--) + if (FindStack[I]!=NULL) + delete FindStack[I]; +} + + +SCAN_CODE ScanTree::GetNext(FindData *FindData) +{ + if (Depth<0) + return(SCAN_DONE); + + + SCAN_CODE FindCode; + while (1) + { + if (*CurMask==0 && !GetNextMask()) + return(SCAN_DONE); + + + FindCode=FindProc(FindData); + if (FindCode==SCAN_ERROR) + { + Errors++; + continue; + } + if (FindCode==SCAN_NEXT) + continue; + if (FindCode==SCAN_SUCCESS && FindData->IsDir && GetDirs==SCAN_SKIPDIRS) + continue; + if (FindCode==SCAN_DONE && GetNextMask()) + continue; + break; + } + return(FindCode); +} + + +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)); + } + + CurMask[ASIZE(CurMask)-1]=0; + CurMaskW[ASIZE(CurMaskW)-1]=0; +#ifdef _WIN_ALL + UnixSlashToDos(CurMask); +#endif + + // We wish to scan entire disk if mask like c:\ is specified + // regardless of recursion mode. Use c:\*.* mask when need to scan only + // the root directory. + ScanEntireDisk=IsDiskLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0; + + char *Name=PointToName(CurMask); + if (*Name==0) + strcat(CurMask,MASKALL); + if (Name[0]=='.' && (Name[1]==0 || Name[1]=='.' && Name[2]==0)) + { + AddEndSlash(CurMask); + strcat(CurMask,MASKALL); + } + 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)); + + return(true); +} + + +SCAN_CODE ScanTree::FindProc(FindData *FD) +{ + if (*CurMask==0) + return(SCAN_NEXT); + bool FastFindFile=false; + + if (FindStack[Depth]==NULL) // No FindFile object for this depth yet. + { + bool Wildcards=IsWildcard(CurMask,CurMaskW); + + // 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 IsDir=FindCode && FD->IsDir; + + // SearchAll means that we'll use "*" mask for search, so we'll find + // subdirectories and will be able to recurse into them. + // We do not use "*" for directories at any level or for files + // at top level in recursion mode. + bool SearchAll=!IsDir && (Depth>0 || Recurse==RECURSE_ALWAYS || + Wildcards && Recurse==RECURSE_WILDCARDS || + ScanEntireDisk && Recurse!=RECURSE_DISABLE); + if (Depth==0) + SearchAllInRoot=SearchAll; + if (SearchAll || Wildcards) + { + // Create the new FindFile object for wildcard based search. + FindStack[Depth]=new FindFile; + char SearchMask[NM]; + strcpy(SearchMask,CurMask); + if (SearchAll) + strcpy(PointToName(SearchMask),MASKALL); + FindStack[Depth]->SetMask(SearchMask); + if (*CurMaskW!=0) + { + wchar SearchMaskW[NM]; + wcscpy(SearchMaskW,CurMaskW); + if (SearchAll) + wcscpy(PointToName(SearchMaskW),MASKALLW); + FindStack[Depth]->SetMaskW(SearchMaskW); + } + } + else + { + // Either we failed to fast find or we found a file or we found + // 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) + { + // Return SCAN_SUCCESS if we found a file. + SCAN_CODE RetCode=SCAN_SUCCESS; + + if (!FindCode) + { + // Return SCAN_ERROR if problem is more serious than just + // "file not found". + RetCode=FD->Error ? SCAN_ERROR:SCAN_NEXT; + + // If we failed to find an object, but our current mask is excluded, + // we skip this object and avoid indicating an error. + if (Cmd!=NULL && Cmd->ExclCheck(CurMask,false,true,true)) + RetCode=SCAN_NEXT; + else + ErrHandler.OpenErrorMsg(ErrArcName,NULL,CurMask,CurMaskW); + } + + // If we searched only for one file or directory in "fast find" + // (without a wildcard) mode, let's set masks to zero, + // so calling function will know that current mask is used + // and next one must be read from mask list for next call. + // It is not necessary for directories, because even in "fast find" + // mode, directory recursing will quit by (Depth < 0) condition, + // which returns SCAN_DONE to calling function. + *CurMask=0; + *CurMaskW=0; + + return(RetCode); + } + + // We found a directory using only FindFile::FastFind function. + FastFindFile=true; + } + } + + if (!FastFindFile && !FindStack[Depth]->Next(FD,GetLinks)) + { + // We cannot find anything more in directory either because of + // 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 + + char DirName[NM]; + wchar DirNameW[NM]; + *DirName=0; + *DirNameW=0; + + // Going to at least one directory level higher. + delete FindStack[Depth]; + FindStack[Depth--]=NULL; + while (Depth>=0 && FindStack[Depth]==NULL) + Depth--; + if (Depth < 0) + { + // Directories scanned both in normal and FastFindFile mode, + // finally exit from scan here, by (Depth < 0) condition. + + if (Error) + Errors++; + return(SCAN_DONE); + } + char *Slash=strrchrd(CurMask,CPATHDIVIDER); + if (Slash!=NULL) + { + char Mask[NM]; + strcpy(Mask,Slash); + if (Depth<SetAllMaskDepth) + strcpy(Mask+1,PointToName(OrigCurMask)); + *Slash=0; + strcpy(DirName,CurMask); + char *PrevSlash=strrchrd(CurMask,CPATHDIVIDER); + if (PrevSlash==NULL) + strcpy(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 + } + if (GetDirs==SCAN_GETDIRSTWICE && + FindFile::FastFind(DirName,DirNameW,FD,GetLinks) && FD->IsDir) + { + FD->Flags|=FDDF_SECONDDIR; + return(Error ? SCAN_ERROR:SCAN_SUCCESS); + } + return(Error ? SCAN_ERROR:SCAN_NEXT); + } + + if (FD->IsDir) + { + // If we found the directory in top (Depth==0) directory + // and if we are not in "fast find" (directory name only as argument) + // or in recurse (SearchAll was set when opening the top directory) mode, + // 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); + + // Let's check if directory name is excluded, so we do not waste + // time searching in directory, which will be excluded anyway. + if (Cmd!=NULL && (Cmd->ExclCheck(FD->Name,true,false,false) || + Cmd->ExclDirByAttr(FD->FileAttr))) + { + // If we are here in "fast find" mode, it means that entire directory + // specified in command line is excluded. Then we need to return + // SCAN_DONE to go to next mask and avoid the infinite loop + // 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); + } + + char Mask[NM]; + + strcpy(Mask,FastFindFile ? MASKALL:PointToName(CurMask)); + strcpy(CurMask,FD->Name); + + if (strlen(CurMask)+strlen(Mask)+1>=NM || Depth>=MAXSCANDEPTH-1) + { +#ifndef SILENT + Log(NULL,"\n%s%c%s",CurMask,CPATHDIVIDER,Mask); + Log(NULL,St(MPathTooLong)); +#endif + return(SCAN_ERROR); + } + + AddEndSlash(CurMask); + strcat(CurMask,Mask); + + 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 + // and "*" for depths equal or larger than SetAllMaskDepth. + // It is important when "fast finding" directories at Depth > 0. + // For example, if current directory is RootFolder and we compress + // the following directories structure: + // RootFolder + // +--Folder1 + // | +--Folder2 + // | +--Folder3 + // +--Folder4 + // with 'rar a -r arcname Folder2' command, rar could add not only + // Folder1\Folder2 contents, but also Folder1\Folder3 if we were using + // "*" mask at all levels. We need to use "*" mask inside of Folder2, + // but return to "Folder2" mask when completing scanning Folder2. + // We can rewrite SearchAll expression above to avoid fast finding + // directories at Depth > 0, but then 'rar a -r arcname Folder2' + // will add the empty Folder2 and do not add its contents. + + if (FastFindFile) + SetAllMaskDepth=Depth; + } + if (!FastFindFile && !CmpName(CurMask,FD->Name,MATCH_NAMES)) + return(SCAN_NEXT); + + return(SCAN_SUCCESS); +} diff --git a/src/thirdparty/unrar/scantree.hpp b/src/thirdparty/unrar/scantree.hpp new file mode 100644 index 000000000..33a6d4678 --- /dev/null +++ b/src/thirdparty/unrar/scantree.hpp @@ -0,0 +1,60 @@ +#ifndef _RAR_SCANTREE_ +#define _RAR_SCANTREE_ + +enum SCAN_DIRS +{ + SCAN_SKIPDIRS, // Skip directories, but recurse for files if recursion mode is enabled. + SCAN_GETDIRS, // Get subdirectories in recurse mode. + SCAN_GETDIRSTWICE, // Get the directory name both before and after the list of files it contains. + SCAN_GETCURDIRS // Get subdirectories in current directory even in RECURSE_NONE mode. +}; + +enum SCAN_CODE { SCAN_SUCCESS,SCAN_DONE,SCAN_ERROR,SCAN_NEXT }; + +#define MAXSCANDEPTH (NM/2) + +class CommandData; + +class ScanTree +{ + private: + bool GetNextMask(); + SCAN_CODE FindProc(FindData *FD); + + FindFile *FindStack[MAXSCANDEPTH]; + int Depth; + + int SetAllMaskDepth; + + StringList *FileMasks; + RECURSE_MODE Recurse; + bool GetLinks; + SCAN_DIRS GetDirs; + int Errors; + + // set when processing paths like c:\ (root directory without wildcards) + bool ScanEntireDisk; + + char CurMask[NM]; + wchar CurMaskW[NM]; + char OrigCurMask[NM]; + wchar OrigCurMaskW[NM]; + bool SearchAllInRoot; + size_t SpecPathLength; + size_t SpecPathLengthW; + + char 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);} + void SetCommandData(CommandData *Cmd) {ScanTree::Cmd=Cmd;} +}; + +#endif diff --git a/src/thirdparty/unrar/secpassword.cpp b/src/thirdparty/unrar/secpassword.cpp new file mode 100644 index 000000000..016e1360c --- /dev/null +++ b/src/thirdparty/unrar/secpassword.cpp @@ -0,0 +1,203 @@ +#include "rar.hpp" + +#ifdef _WIN_ALL +typedef BOOL (WINAPI *CRYPTPROTECTMEMORY)(LPVOID pData,DWORD cbData,DWORD dwFlags); +typedef BOOL (WINAPI *CRYPTUNPROTECTMEMORY)(LPVOID pData,DWORD cbData,DWORD dwFlags); + +#ifndef CRYPTPROTECTMEMORY_BLOCK_SIZE +#define CRYPTPROTECTMEMORY_BLOCK_SIZE 16 +#define CRYPTPROTECTMEMORY_SAME_PROCESS 0x00 +#endif + +class CryptLoader +{ + private: + HMODULE hCrypt; + bool LoadCalled; + public: + CryptLoader() + { + hCrypt=NULL; + pCryptProtectMemory=NULL; + pCryptUnprotectMemory=NULL; + LoadCalled=false; + } + ~CryptLoader() + { + if (hCrypt!=NULL) + FreeLibrary(hCrypt); + hCrypt=NULL; + pCryptProtectMemory=NULL; + pCryptUnprotectMemory=NULL; + }; + void Load() + { + if (!LoadCalled) + { + hCrypt = LoadLibraryW(L"Crypt32.dll"); + if (hCrypt != NULL) + { + pCryptProtectMemory = (CRYPTPROTECTMEMORY)GetProcAddress(hCrypt, "CryptProtectMemory"); + pCryptUnprotectMemory = (CRYPTUNPROTECTMEMORY)GetProcAddress(hCrypt, "CryptUnprotectMemory"); + } + LoadCalled=true; + } + } + + CRYPTPROTECTMEMORY pCryptProtectMemory; + CRYPTUNPROTECTMEMORY pCryptUnprotectMemory; +}; + +// We want to call FreeLibrary when RAR is exiting. +CryptLoader GlobalCryptLoader; +#endif + +SecPassword::SecPassword() +{ + Set(L""); +} + + +SecPassword::~SecPassword() +{ + Clean(); +} + + +void SecPassword::Clean() +{ + PasswordSet=false; + cleandata(Password,sizeof(Password)); +} + + +// When we call memset in end of function to clean local variables +// for security reason, compiler optimizer can remove such call. +// So we use our own function for this purpose. +void cleandata(void *data,size_t size) +{ +#if defined(_WIN_ALL) && defined(_MSC_VER) + SecureZeroMemory(data,size); +#else + // 'volatile' is required. Otherwise optimizers can remove this function + // if cleaning local variables, which are not used after that. + volatile byte *d = (volatile byte *)data; + for (size_t i=0;i<size;i++) + d[i]=0; +#endif +} + + +// We got a complain from user that it is possible to create WinRAR dump +// with "Create dump file" command in Windows Task Manager and then easily +// locate Unicode password string in the dump. It is unsecure if several +// 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) +{ +#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)); +} + + +void SecPassword::Get(wchar *Psw,size_t MaxSize) +{ + if (PasswordSet) + { + Process(Password,Psw,MaxSize,false); + Psw[MaxSize-1]=0; + } + else + *Psw=0; +} + + +void SecPassword::Set(const wchar *Psw) +{ + if (*Psw==0) + { + PasswordSet=false; + memset(Password,0,sizeof(Password)); + } + else + { + PasswordSet=true; + Process(Psw,Password,ASIZE(Password),true); + } +} + + +size_t SecPassword::Length() +{ + wchar Plain[MAXPASSWORD]; + Get(Plain,ASIZE(Plain)); + size_t Length=wcslen(Plain); + cleandata(Plain,ASIZE(Plain)); + return Length; +} + + +bool SecPassword::operator == (SecPassword &psw) +{ + // We cannot compare encoded data directly, because there is no guarantee + // than encryption function will always produce the same result for same + // data (salt?) and because we do not clean the rest of password buffer + // after trailing zero before encoding password. So we decode first. + wchar Plain1[MAXPASSWORD],Plain2[MAXPASSWORD]; + Get(Plain1,ASIZE(Plain1)); + psw.Get(Plain2,ASIZE(Plain2)); + bool Result=wcscmp(Plain1,Plain2)==0; + cleandata(Plain1,ASIZE(Plain1)); + cleandata(Plain2,ASIZE(Plain2)); + return Result; +} + diff --git a/src/thirdparty/unrar/secpassword.hpp b/src/thirdparty/unrar/secpassword.hpp new file mode 100644 index 000000000..b93d97bc3 --- /dev/null +++ b/src/thirdparty/unrar/secpassword.hpp @@ -0,0 +1,30 @@ +#ifndef _RAR_SECURE_PASSWORD_ +#define _RAR_SECURE_PASSWORD_ + +// Store a password securely (if data encryption is provided by OS) +// or obfuscated to make search for password in memory dump less trivial. +class SecPassword +{ + private: + void Process(const wchar *Src,wchar *Dst,size_t MaxSize,bool Encode); + + wchar Password[MAXPASSWORD]; + + // It is important to have this 'bool' value, so if our object is cleaned + // with memset as a part of larger structure, it is handled correctly. + bool PasswordSet; + public: + SecPassword(); + ~SecPassword(); + void Clean(); + void Get(wchar *Psw,size_t MaxSize); + void Set(const wchar *Psw); + bool IsSet() {return PasswordSet;} + size_t Length(); + bool operator == (SecPassword &psw); +}; + + +void cleandata(void *data,size_t size); + +#endif diff --git a/src/thirdparty/unrar/sha1.cpp b/src/thirdparty/unrar/sha1.cpp new file mode 100644 index 000000000..71045d856 --- /dev/null +++ b/src/thirdparty/unrar/sha1.cpp @@ -0,0 +1,248 @@ +#include "rar.hpp" + +/* +SHA-1 in C +By Steve Reid <steve@edmweb.com> +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +#if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN) + #if defined(_M_IX86) || defined(_M_I86) || defined(__alpha) + #define LITTLE_ENDIAN + #else + #error "LITTLE_ENDIAN or BIG_ENDIAN must be defined" + #endif +#endif + +/* #define SHA1HANDSOFF * Copies data before messing with it. */ + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#ifdef LITTLE_ENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) {z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);} +#define R1(v,w,x,y,z,i) {z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);} +#define R2(v,w,x,y,z,i) {z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);} +#define R3(v,w,x,y,z,i) {z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);} +#define R4(v,w,x,y,z,i) {z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);} + +#ifdef _MSC_VER +#pragma optimize( "", off ) +// We need to disable the optimization to really wipe these variables. +#endif +static void wipevars(uint32 &a,uint32 &b,uint32 &c,uint32 &d,uint32 &e) +{ + // Wipe used variables for safety reason. + a=b=c=d=e=0; +} +#ifdef _MSC_VER +#pragma optimize( "", on ) +#endif + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform(uint32 state[5], unsigned char workspace[64], unsigned char buffer[64], bool handsoff) +{ +#ifndef SFX_MODULE + uint32 a, b, c, d, e; +#endif + typedef union { + unsigned char c[64]; + uint32 l[16]; +} CHAR64LONG16; +CHAR64LONG16* block; + if (handsoff) + { + block = (CHAR64LONG16*)workspace; + memcpy(block, buffer, 64); + } + else + block = (CHAR64LONG16*)buffer; +#ifdef SFX_MODULE + static int pos[80][5]; + static bool pinit=false; + if (!pinit) + { + for (int I=0,P=0;I<80;I++,P=(P ? P-1:4)) + { + pos[I][0]=P; + pos[I][1]=(P+1)%5; + pos[I][2]=(P+2)%5; + pos[I][3]=(P+3)%5; + pos[I][4]=(P+4)%5; + } + pinit=true; + } + uint32 s[5]; + for (int I=0;I<sizeof(s)/sizeof(s[0]);I++) + s[I]=state[I]; + + for (int I=0;I<16;I++) + R0(s[pos[I][0]],s[pos[I][1]],s[pos[I][2]],s[pos[I][3]],s[pos[I][4]],I); + for (int I=16;I<20;I++) + R1(s[pos[I][0]],s[pos[I][1]],s[pos[I][2]],s[pos[I][3]],s[pos[I][4]],I); + for (int I=20;I<40;I++) + R2(s[pos[I][0]],s[pos[I][1]],s[pos[I][2]],s[pos[I][3]],s[pos[I][4]],I); + for (int I=40;I<60;I++) + R3(s[pos[I][0]],s[pos[I][1]],s[pos[I][2]],s[pos[I][3]],s[pos[I][4]],I); + for (int I=60;I<80;I++) + R4(s[pos[I][0]],s[pos[I][1]],s[pos[I][2]],s[pos[I][3]],s[pos[I][4]],I); + + for (int I=0;I<sizeof(s)/sizeof(s[0]);I++) + state[I]+=s[I]; +#else + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + /* Wipe variables */ +// Such wipe method does not work in optimizing compilers. +// a = b = c = d = e = 0; +// memset(&a,0,sizeof(a)); + + wipevars(a,b,c,d,e); +#endif +} + + +/* Initialize new context */ + +void hash_initial(hash_context* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ +void hash_process( hash_context * context, unsigned char * data, size_t len, + bool handsoff ) +{ +unsigned int i, j; +uint blen = ((uint)len)<<3; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += blen) < blen ) context->count[1]++; + context->count[1] += (uint32)(len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->workspace, context->buffer, handsoff); + for ( ; i + 63 < len; i += 64) { +#ifdef ALLOW_NOT_ALIGNED_INT + SHA1Transform(context->state, context->workspace, &data[i], handsoff); +#else + unsigned char buffer[64]; + memcpy(buffer,data+i,sizeof(buffer)); + SHA1Transform(context->state, context->workspace, buffer, handsoff); + memcpy(data+i,buffer,sizeof(buffer)); +#endif +#ifdef BIG_ENDIAN + if (!handsoff) + { + unsigned char *d=data+i; + for (int k=0;k<64;k+=4) + { + byte b0=d[k],b1=d[k+1]; + d[k]=d[k+3]; + d[k+1]=d[k+2]; + d[k+2]=b1; + d[k+3]=b0; + } + } +#endif + } + j = 0; + } + else i = 0; + if (len > i) + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +void hash_final( hash_context* context, uint32 digest[5], bool handsoff) +{ +uint i, j; +unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + unsigned char ch=(unsigned char)'\200'; + hash_process(context, &ch, 1, handsoff); + while ((context->count[0] & 504) != 448) { + ch=0; + hash_process(context, &ch, 1, handsoff); + } + hash_process(context, finalcount, 8, handsoff); /* Should cause a SHA1Transform() */ + for (i = 0; i < 5; i++) { + digest[i] = context->state[i] & 0xffffffff; + } + /* Wipe variables */ + cleandata(&i,sizeof(i)); + cleandata(&j,sizeof(j)); + cleandata(context->buffer, 64); + cleandata(context->state, 20); + cleandata(context->count, 8); + cleandata(&finalcount, 8); + if (handsoff) + memset(context->workspace,0,sizeof(context->workspace)); // Wipe the temporary buffer. +// SHA1Transform(context->state, context->workspace, context->buffer, true); /* make SHA1Transform overwrite it's own static vars */ +} + + diff --git a/src/thirdparty/unrar/sha1.hpp b/src/thirdparty/unrar/sha1.hpp new file mode 100644 index 000000000..f28403fd6 --- /dev/null +++ b/src/thirdparty/unrar/sha1.hpp @@ -0,0 +1,19 @@ +#ifndef _RAR_SHA1_ +#define _RAR_SHA1_ + +#define HW 5 + +typedef struct { + uint32 state[5]; + uint32 count[2]; + unsigned char buffer[64]; + + unsigned char workspace[64]; // Temporary buffer. +} hash_context; + +void hash_initial( hash_context * c ); +void hash_process( hash_context * c, unsigned char * data, size_t len, + bool handsoff); +void hash_final( hash_context * c, uint32[HW], bool handsoff); + +#endif diff --git a/src/thirdparty/unrar/smallfn.cpp b/src/thirdparty/unrar/smallfn.cpp new file mode 100644 index 000000000..f7d6fa162 --- /dev/null +++ b/src/thirdparty/unrar/smallfn.cpp @@ -0,0 +1,42 @@ +#include "rar.hpp" + +int ToPercent(int64 N1,int64 N2) +{ + if (N2<N1) + return(100); + return(ToPercentUnlim(N1,N2)); +} + + +// Allows the percent larger than 100. +int ToPercentUnlim(int64 N1,int64 N2) +{ + if (N2==0) + 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/smallfn.hpp b/src/thirdparty/unrar/smallfn.hpp new file mode 100644 index 000000000..f53daa8b5 --- /dev/null +++ b/src/thirdparty/unrar/smallfn.hpp @@ -0,0 +1,8 @@ +#ifndef _RAR_SMALLFN_ +#define _RAR_SMALLFN_ + +int ToPercent(int64 N1,int64 N2); +int ToPercentUnlim(int64 N1,int64 N2); +void RARInitData(); + +#endif diff --git a/src/thirdparty/unrar/strfn.cpp b/src/thirdparty/unrar/strfn.cpp new file mode 100644 index 000000000..faf48e8ed --- /dev/null +++ b/src/thirdparty/unrar/strfn.cpp @@ -0,0 +1,413 @@ +#include "rar.hpp" + +const char *NullToEmpty(const char *Str) +{ + return(Str==NULL ? "":Str); +} + + +const wchar *NullToEmpty(const wchar *Str) +{ + return(Str==NULL ? L"":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) +{ +#ifdef _WIN_ALL + OemToCharA(Src,Dest); +#else + if (Dest!=Src) + strcpy(Dest,Src); +#endif +} + + +char* strlower(char *Str) +{ +#ifdef _WIN_ALL + CharLowerA((LPSTR)Str); +#else + for (char *ChPtr=Str;*ChPtr;ChPtr++) + *ChPtr=(char)loctolower(*ChPtr); +#endif + return(Str); +} + + +char* strupper(char *Str) +{ +#ifdef _WIN_ALL + CharUpperA((LPSTR)Str); +#else + for (char *ChPtr=Str;*ChPtr;ChPtr++) + *ChPtr=(char)loctoupper(*ChPtr); +#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) +{ + 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--) + Str[I]=0; + return(Str); +} + + +wchar* RemoveLF(wchar *Str) +{ + for (int I=(int)wcslen(Str)-1;I>=0 && (Str[I]=='\r' || Str[I]=='\n');I--) + Str[I]=0; + return(Str); +} + + +unsigned char loctolower(unsigned char ch) +{ +#ifdef _WIN_ALL + // Convert to LPARAM first to avoid a warning in 64 bit mode. + return((int)(LPARAM)CharLowerA((LPSTR)ch)); +#else + return(tolower(ch)); +#endif +} + + +unsigned char loctoupper(unsigned char ch) +{ +#ifdef _WIN_ALL + // Convert to LPARAM first to avoid a warning in 64 bit mode. + return((int)(LPARAM)CharUpperA((LPSTR)ch)); +#else + return(toupper(ch)); +#endif +} + + +// toupper with English only results if English input is provided. +// It avoids Turkish (small i) -> (big I with dot) conversion problem. +// We do not define 'ch' as 'int' to avoid necessity to cast all +// signed chars passed to this function to unsigned char. +unsigned char etoupper(unsigned char ch) +{ + if (ch=='i') + return('I'); + return(toupper(ch)); +} + + +// Unicode version of etoupper. +wchar etoupperw(wchar ch) +{ + if (ch=='i') + return('I'); + return(toupperw(ch)); +} + + +// We do not want to cast every signed char to unsigned when passing to +// isdigit, so we implement the replacement. Shall work for Unicode too. +// If chars are signed, conversion from char to int could generate negative +// values, resulting in undefined behavior in standard isdigit. +bool IsDigit(int ch) +{ + return(ch>='0' && ch<='9'); +} + + +// We do not want to cast every signed char to unsigned when passing to +// isspace, so we implement the replacement. Shall work for Unicode too. +// If chars are signed, conversion from char to int could generate negative +// values, resulting in undefined behavior in standard isspace. +bool IsSpace(int ch) +{ + return(ch==' ' || ch=='\t'); +} + + +// We do not want to cast every signed char to unsigned when passing to +// isalpha, so we implement the replacement. Shall work for Unicode too. +// If chars are signed, conversion from char to int could generate negative +// values, resulting in undefined behavior in standard function. +bool IsAlpha(int ch) +{ + return(ch>='A' && ch<='Z' || ch>='a' && ch<='z'); +} + + + + +#ifndef SFX_MODULE +uint GetDigits(uint Number) +{ + uint Digits=1; + while (Number>=10) + { + Number/=10; + Digits++; + } + return(Digits); +} +#endif + + +bool LowAscii(const char *Str) +{ + for (int I=0;Str[I]!=0;I++) + if ((byte)Str[I]<32 || (byte)Str[I]>127) + return(false); + return(true); +} + + +bool LowAscii(const wchar *Str) +{ + for (int I=0;Str[I]!=0;I++) + { + // We convert wchar_t to uint just in case if some compiler + // uses the signed wchar_t. + if ((uint)Str[I]<32 || (uint)Str[I]>127) + return(false); + } + return(true); +} + + + + +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) + return(wcscmp(Str1,Str2)); +#else + return(wcsicomp(Str1,Str2)); +#endif +} +#endif + + +// safe strncpy: copies maxlen-1 max and always returns zero terminated dest +char* strncpyz(char *dest, const char *src, size_t maxlen) +{ + if (maxlen>0) + { + strncpy(dest,src,maxlen-1); + dest[maxlen-1]=0; + } + return(dest); +} + + +// Safe wcsncpy: copies maxlen-1 max and always returns zero terminated dest. +wchar* wcsncpyz(wchar *dest, const wchar *src, size_t maxlen) +{ + if (maxlen>0) + { + wcsncpy(dest,src,maxlen-1); + dest[maxlen-1]=0; + } + return(dest); +} + + +// Safe strncat: resulting dest length cannot exceed maxlen and dest +// is always zero terminated. Note that 'maxlen' parameter defines the entire +// dest buffer size and is not compatible with standard strncat. +char* strncatz(char* dest, const char* src, size_t maxlen) +{ + size_t Length = strlen(dest); + if (Length + 1 < maxlen) + strncat(dest, src, maxlen - Length - 1); + return dest; +} + + +// Safe wcsncat: resulting dest length cannot exceed maxlen and dest +// is always zero terminated. Note that 'maxlen' parameter defines the entire +// dest buffer size and is not compatible with standard wcsncat. +wchar* wcsncatz(wchar* dest, const wchar* src, size_t maxlen) +{ + size_t Length = wcslen(dest); + if (Length + 1 < maxlen) + wcsncat(dest, src, maxlen - Length - 1); + return dest; +} + + +void itoa(int64 n,char *Str) +{ + char NumStr[50]; + size_t Pos=0; + + do + { + NumStr[Pos++]=char(n%10)+'0'; + n=n/10; + } while (n!=0); + + for (size_t I=0;I<Pos;I++) + Str[I]=NumStr[Pos-I-1]; + Str[Pos]=0; +} + + + +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]; + size_t Pos=0; + + do + { + NumStr[Pos++]=wchar(n%10)+'0'; + n=n/10; + } while (n!=0); + + for (size_t I=0;I<Pos;I++) + Str[I]=NumStr[Pos-I-1]; + Str[Pos]=0; +} + + +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; + static wchar StrTable[4][MaxLength]; + static uint StrNum=0; + if (++StrNum >= ASIZE(StrTable)) + StrNum=0; + wchar *Str=StrTable[StrNum]; + CharToWide(Src,Str,MaxLength); + Str[MaxLength-1]=0; + return(Str); +} + + +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. +const wchar* GetCmdParam(const wchar *CmdLine,wchar *Param,size_t MaxSize) +{ + while (IsSpace(*CmdLine)) + CmdLine++; + if (*CmdLine==0) + return NULL; + + size_t ParamSize=0; + bool Quote=false; + while (*CmdLine!=0 && (Quote || !IsSpace(*CmdLine))) + { + if (*CmdLine=='\"') + { + if (CmdLine[1]=='\"') + { + // Insert the quote character instead of two adjoining quote characters. + if (Param!=NULL && ParamSize<MaxSize-1) + Param[ParamSize++]='\"'; + CmdLine++; + } + else + Quote=!Quote; + } + else + if (Param!=NULL && ParamSize<MaxSize-1) + Param[ParamSize++]=*CmdLine; + CmdLine++; + } + if (Param!=NULL) + Param[ParamSize]=0; + return CmdLine; +} +#endif diff --git a/src/thirdparty/unrar/strfn.hpp b/src/thirdparty/unrar/strfn.hpp new file mode 100644 index 000000000..9d7fee899 --- /dev/null +++ b/src/thirdparty/unrar/strfn.hpp @@ -0,0 +1,53 @@ +#ifndef _RAR_STRFN_ +#define _RAR_STRFN_ + +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); +wchar* RemoveLF(wchar *Str); +unsigned char loctolower(unsigned char ch); +unsigned char loctoupper(unsigned char ch); + +char* strncpyz(char *dest, const char *src, size_t maxlen); +wchar* wcsncpyz(wchar *dest, const wchar *src, size_t maxlen); +char* strncatz(char* dest, const char* src, size_t maxlen); +wchar* wcsncatz(wchar* dest, const wchar* src, size_t maxlen); + +unsigned char etoupper(unsigned char ch); +wchar etoupperw(wchar ch); + +bool IsDigit(int ch); +bool IsSpace(int ch); +bool IsAlpha(int ch); + + +#ifndef SFX_MODULE +uint GetDigits(uint Number); +#endif + +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); + +#endif diff --git a/src/thirdparty/unrar/strlist.cpp b/src/thirdparty/unrar/strlist.cpp new file mode 100644 index 000000000..5e5ace28b --- /dev/null +++ b/src/thirdparty/unrar/strlist.cpp @@ -0,0 +1,204 @@ +#include "rar.hpp" + +StringList::StringList() +{ + Reset(); +} + + +void StringList::Reset() +{ + Rewind(); + StringData.Reset(); + StringDataW.Reset(); + StringsCount=0; + SavePosNumber=0; +} + + +void StringList::AddString(const char *Str) +{ + AddString(Str,NULL); +} + + +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""; + + 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); + + StringsCount++; +} + + +bool StringList::GetString(char *Str,size_t MaxLength) +{ + return(GetString(Str,NULL,MaxLength)); +} + + +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); +} + + +#ifndef SFX_MODULE +bool StringList::GetString(char *Str,wchar *StrW,size_t MaxLength,int StringNum) +{ + SavePosition(); + Rewind(); + bool RetCode=true; + while (StringNum-- >=0) + if (!GetString(Str,StrW,MaxLength)) + { + RetCode=false; + break; + } + RestorePosition(); + return(RetCode); +} +#endif + + +char* StringList::GetString() +{ + char *Str; + GetString(&Str,NULL); + return(Str); +} + + +wchar* StringList::GetStringW() +{ + wchar *StrW; + GetString(NULL,&StrW); + return(StrW); +} + + +bool StringList::GetString(char **Str,wchar **StrW) +{ + // 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()) + { + // No more strings left unprocessed. + if (Str!=NULL) + *Str=NULL; + if (StrW!=NULL) + *StrW=NULL; + return(false); + } + + // We move ASCII and Unicode buffer pointers synchronously. + + char *CurStr=&StringData[CurPos]; + CurPos+=strlen(CurStr)+1; + if (Str!=NULL) + *Str=CurStr; + + wchar *CurStrW=&StringDataW[CurPosW]; + CurPosW+=wcslen(CurStrW)+1; + if (StrW!=NULL) + *StrW=CurStrW; + + 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) +{ + SavePosition(); + Rewind(); + bool Found=false; + char *CurStr; + wchar *CurStrW; + while (GetString(&CurStr,&CurStrW)) + { + 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) + continue; + Found=true; + break; + } + RestorePosition(); + return(Found); +} +#endif + + +#ifndef SFX_MODULE +void StringList::SavePosition() +{ + if (SavePosNumber<ASIZE(SaveCurPos)) + { + SaveCurPos[SavePosNumber]=CurPos; + SaveCurPosW[SavePosNumber]=CurPosW; + SavePosNumber++; + } +} +#endif + + +#ifndef SFX_MODULE +void StringList::RestorePosition() +{ + if (SavePosNumber>0) + { + SavePosNumber--; + CurPos=SaveCurPos[SavePosNumber]; + CurPosW=SaveCurPosW[SavePosNumber]; + } +} +#endif diff --git a/src/thirdparty/unrar/strlist.hpp b/src/thirdparty/unrar/strlist.hpp new file mode 100644 index 000000000..4c8985ef0 --- /dev/null +++ b/src/thirdparty/unrar/strlist.hpp @@ -0,0 +1,37 @@ +#ifndef _RAR_STRLIST_ +#define _RAR_STRLIST_ + +class StringList +{ + private: + Array<char> StringData; + size_t CurPos; + + Array<wchar> StringDataW; + size_t CurPosW; + + uint StringsCount; + + size_t SaveCurPos[16],SaveCurPosW[16],SavePosNumber; + public: + StringList(); + void Reset(); + void AddString(const char *Str); + void AddString(const wchar *Str); + void AddString(const char *Str,const wchar *StrW); + bool GetString(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); + void Rewind(); + uint ItemsCount() {return(StringsCount);}; + size_t GetCharCount(); + bool Search(char *Str,wchar *StrW,bool CaseSensitive); + void SavePosition(); + void RestorePosition(); +}; + +#endif diff --git a/src/thirdparty/unrar/suballoc.cpp b/src/thirdparty/unrar/suballoc.cpp new file mode 100644 index 000000000..4a5c22a2e --- /dev/null +++ b/src/thirdparty/unrar/suballoc.cpp @@ -0,0 +1,294 @@ +/**************************************************************************** + * This file is part of PPMd project * + * Written and distributed to public domain by Dmitry Shkarin 1997, * + * 1999-2000 * + * Contents: memory allocation routines * + ****************************************************************************/ + +SubAllocator::SubAllocator() +{ + Clean(); +} + + +void SubAllocator::Clean() +{ + SubAllocatorSize=0; +} + + +inline void SubAllocator::InsertNode(void* p,int indx) +{ + ((RAR_NODE*) p)->next=FreeList[indx].next; + FreeList[indx].next=(RAR_NODE*) p; +} + + +inline void* SubAllocator::RemoveNode(int indx) +{ + RAR_NODE* RetVal=FreeList[indx].next; + FreeList[indx].next=RetVal->next; + return RetVal; +} + + +inline uint SubAllocator::U2B(int NU) +{ + // We calculate the size of units in bytes based on real UNIT_SIZE. + // In original implementation it was 8*NU+4*NU. + return UNIT_SIZE*NU; +} + + + +// Calculate RAR_MEM_BLK+Items address. Real RAR_MEM_BLK size must be +// equal to UNIT_SIZE, so we cannot just add Items to RAR_MEM_BLK address. +inline RAR_MEM_BLK* SubAllocator::MBPtr(RAR_MEM_BLK *BasePtr,int Items) +{ + return((RAR_MEM_BLK*)( ((byte *)(BasePtr))+U2B(Items) )); +} + + +inline void SubAllocator::SplitBlock(void* pv,int OldIndx,int NewIndx) +{ + int i, UDiff=Indx2Units[OldIndx]-Indx2Units[NewIndx]; + byte* p=((byte*) pv)+U2B(Indx2Units[NewIndx]); + if (Indx2Units[i=Units2Indx[UDiff-1]] != UDiff) + { + InsertNode(p,--i); + p += U2B(i=Indx2Units[i]); + UDiff -= i; + } + InsertNode(p,Units2Indx[UDiff-1]); +} + + + + +void SubAllocator::StopSubAllocator() +{ + if ( SubAllocatorSize ) + { + SubAllocatorSize=0; + free(HeapStart); + } +} + + +bool SubAllocator::StartSubAllocator(int SASize) +{ + uint t=SASize << 20; + if (SubAllocatorSize == t) + return TRUE; + StopSubAllocator(); + + // Original algorithm expects FIXED_UNIT_SIZE, but actual structure size + // can be larger. So let's recalculate the allocated size and add two more + // units: one as reserve for HeapEnd overflow checks and another + // to provide the space to correctly align UnitsStart. + uint AllocSize=t/FIXED_UNIT_SIZE*UNIT_SIZE+2*UNIT_SIZE; + if ((HeapStart=(byte *)malloc(AllocSize)) == NULL) + { + ErrHandler.MemoryError(); + return FALSE; + } + + // HeapEnd did not present in original algorithm. We added it to control + // invalid memory access attempts when processing corrupt archived data. + HeapEnd=HeapStart+AllocSize-UNIT_SIZE; + + SubAllocatorSize=t; + return TRUE; +} + + +void SubAllocator::InitSubAllocator() +{ + int i, k; + memset(FreeList,0,sizeof(FreeList)); + pText=HeapStart; + + // Original algorithm operates with 12 byte FIXED_UNIT_SIZE, but actual + // size of RAR_MEM_BLK and PPM_CONTEXT structures can exceed this value + // because of alignment and larger pointer fields size. + // So we define UNIT_SIZE for this larger size and adjust memory + // pointers accordingly. + + // Size2 is (HiUnit-LoUnit) memory area size to allocate as originally + // supposed by compression algorithm. It is 7/8 of total allocated size. + uint Size2=FIXED_UNIT_SIZE*(SubAllocatorSize/8/FIXED_UNIT_SIZE*7); + + // RealSize2 is the real adjusted size of (HiUnit-LoUnit) memory taking + // into account that our UNIT_SIZE can be larger than FIXED_UNIT_SIZE. + uint RealSize2=Size2/FIXED_UNIT_SIZE*UNIT_SIZE; + + // Size1 is the size of memory area from HeapStart to FakeUnitsStart + // as originally supposed by compression algorithm. This area can contain + // different data types, both single symbols and structures. + uint Size1=SubAllocatorSize-Size2; + + // Real size of this area. We correct it according to UNIT_SIZE vs + // FIXED_UNIT_SIZE difference. Also we add one more UNIT_SIZE + // to compensate a possible reminder from Size1/FIXED_UNIT_SIZE, + // which would be lost otherwise. We add UNIT_SIZE instead of + // this Size1%FIXED_UNIT_SIZE reminder, because it allows to align + // UnitsStart easily and adding more than reminder is ok for algorithm. + uint RealSize1=Size1/FIXED_UNIT_SIZE*UNIT_SIZE+UNIT_SIZE; + + // RealSize1 must be divided by UNIT_SIZE without a reminder, so UnitsStart + // is aligned to UNIT_SIZE. It is important for those architectures, + // where a proper memory alignment is mandatory. Since we produce RealSize1 + // multiplying by UNIT_SIZE, this condition is always true. So LoUnit, + // UnitsStart, HeapStart are properly aligned, + LoUnit=UnitsStart=HeapStart+RealSize1; + + // When we reach FakeUnitsStart, we restart the model. It is where + // the original algorithm expected to see UnitsStart. Real UnitsStart + // can have a larger value. + FakeUnitsStart=HeapStart+Size1; + + HiUnit=LoUnit+RealSize2; + for (i=0,k=1;i < N1 ;i++,k += 1) + Indx2Units[i]=k; + for (k++;i < N1+N2 ;i++,k += 2) + Indx2Units[i]=k; + for (k++;i < N1+N2+N3 ;i++,k += 3) + Indx2Units[i]=k; + for (k++;i < N1+N2+N3+N4;i++,k += 4) + Indx2Units[i]=k; + for (GlueCount=k=i=0;k < 128;k++) + { + i += (Indx2Units[i] < k+1); + Units2Indx[k]=i; + } +} + + +inline void SubAllocator::GlueFreeBlocks() +{ + RAR_MEM_BLK s0, * p, * p1; + int i, k, sz; + if (LoUnit != HiUnit) + *LoUnit=0; + for (i=0, s0.next=s0.prev=&s0;i < N_INDEXES;i++) + while ( FreeList[i].next ) + { + p=(RAR_MEM_BLK*)RemoveNode(i); + p->insertAt(&s0); + p->Stamp=0xFFFF; + p->NU=Indx2Units[i]; + } + for (p=s0.next;p != &s0;p=p->next) + while ((p1=MBPtr(p,p->NU))->Stamp == 0xFFFF && int(p->NU)+p1->NU < 0x10000) + { + p1->remove(); + p->NU += p1->NU; + } + while ((p=s0.next) != &s0) + { + for (p->remove(), sz=p->NU;sz > 128;sz -= 128, p=MBPtr(p,128)) + InsertNode(p,N_INDEXES-1); + if (Indx2Units[i=Units2Indx[sz-1]] != sz) + { + k=sz-Indx2Units[--i]; + InsertNode(MBPtr(p,sz-k),k-1); + } + InsertNode(p,i); + } +} + +void* SubAllocator::AllocUnitsRare(int indx) +{ + if ( !GlueCount ) + { + GlueCount = 255; + GlueFreeBlocks(); + if ( FreeList[indx].next ) + return RemoveNode(indx); + } + int i=indx; + do + { + if (++i == N_INDEXES) + { + GlueCount--; + i=U2B(Indx2Units[indx]); + int j=FIXED_UNIT_SIZE*Indx2Units[indx]; + if (FakeUnitsStart-pText > j) + { + FakeUnitsStart-=j; + UnitsStart -= i; + return(UnitsStart); + } + return(NULL); + } + } while ( !FreeList[i].next ); + void* RetVal=RemoveNode(i); + SplitBlock(RetVal,i,indx); + return RetVal; +} + + +inline void* SubAllocator::AllocUnits(int NU) +{ + int indx=Units2Indx[NU-1]; + if ( FreeList[indx].next ) + return RemoveNode(indx); + void* RetVal=LoUnit; + LoUnit += U2B(Indx2Units[indx]); + if (LoUnit <= HiUnit) + return RetVal; + LoUnit -= U2B(Indx2Units[indx]); + return AllocUnitsRare(indx); +} + + +void* SubAllocator::AllocContext() +{ + if (HiUnit != LoUnit) + return (HiUnit -= UNIT_SIZE); + if ( FreeList->next ) + return RemoveNode(0); + return AllocUnitsRare(0); +} + + +void* SubAllocator::ExpandUnits(void* OldPtr,int OldNU) +{ + int i0=Units2Indx[OldNU-1], i1=Units2Indx[OldNU-1+1]; + if (i0 == i1) + return OldPtr; + void* ptr=AllocUnits(OldNU+1); + if ( ptr ) + { + memcpy(ptr,OldPtr,U2B(OldNU)); + InsertNode(OldPtr,i0); + } + return ptr; +} + + +void* SubAllocator::ShrinkUnits(void* OldPtr,int OldNU,int NewNU) +{ + int i0=Units2Indx[OldNU-1], i1=Units2Indx[NewNU-1]; + if (i0 == i1) + return OldPtr; + if ( FreeList[i1].next ) + { + void* ptr=RemoveNode(i1); + memcpy(ptr,OldPtr,U2B(NewNU)); + InsertNode(OldPtr,i0); + return ptr; + } + else + { + SplitBlock(OldPtr,i0,i1); + return OldPtr; + } +} + + +void SubAllocator::FreeUnits(void* ptr,int OldNU) +{ + InsertNode(ptr,Units2Indx[OldNU-1]); +} diff --git a/src/thirdparty/unrar/suballoc.hpp b/src/thirdparty/unrar/suballoc.hpp new file mode 100644 index 000000000..474ee5920 --- /dev/null +++ b/src/thirdparty/unrar/suballoc.hpp @@ -0,0 +1,87 @@ +/**************************************************************************** + * This file is part of PPMd project * + * Written and distributed to public domain by Dmitry Shkarin 1997, * + * 1999-2000 * + * Contents: interface to memory allocation routines * + ****************************************************************************/ +#if !defined(_SUBALLOC_H_) +#define _SUBALLOC_H_ + +const int N1=4, N2=4, N3=4, N4=(128+3-1*N1-2*N2-3*N3)/4; +const int N_INDEXES=N1+N2+N3+N4; + +#if defined(__GNUC__) && !defined(STRICT_ALIGNMENT_REQUIRED) +#define _PACK_ATTR __attribute__ ((packed)) +#else +#define _PACK_ATTR +#endif /* defined(__GNUC__) */ + +#ifndef STRICT_ALIGNMENT_REQUIRED +#pragma pack(1) +#endif + +struct RAR_MEM_BLK +{ + ushort Stamp, NU; + RAR_MEM_BLK* next, * prev; + void insertAt(RAR_MEM_BLK* p) + { + next=(prev=p)->next; + p->next=next->prev=this; + } + void remove() + { + prev->next=next; + next->prev=prev; + } +} _PACK_ATTR; + +#ifndef STRICT_ALIGNMENT_REQUIRED +#ifdef _AIX +#pragma pack(pop) +#else +#pragma pack() +#endif +#endif + + +struct RAR_NODE +{ + RAR_NODE* next; +}; + +class SubAllocator +{ + private: + inline void InsertNode(void* p,int indx); + inline void* RemoveNode(int indx); + inline uint U2B(int NU); + inline void SplitBlock(void* pv,int OldIndx,int NewIndx); + uint GetUsedMemory(); + inline void GlueFreeBlocks(); + void* AllocUnitsRare(int indx); + inline RAR_MEM_BLK* MBPtr(RAR_MEM_BLK *BasePtr,int Items); + + long SubAllocatorSize; + byte Indx2Units[N_INDEXES], Units2Indx[128], GlueCount; + byte *HeapStart,*LoUnit, *HiUnit; + struct RAR_NODE FreeList[N_INDEXES]; + public: + SubAllocator(); + ~SubAllocator() {StopSubAllocator();} + void Clean(); + bool StartSubAllocator(int SASize); + void StopSubAllocator(); + void InitSubAllocator(); + inline void* AllocContext(); + inline void* AllocUnits(int NU); + inline void* ExpandUnits(void* ptr,int OldNU); + inline void* ShrinkUnits(void* ptr,int OldNU,int NewNU); + inline void FreeUnits(void* ptr,int OldNU); + long GetAllocatedMemory() {return(SubAllocatorSize);}; + + byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart; +}; + + +#endif /* !defined(_SUBALLOC_H_) */ diff --git a/src/thirdparty/unrar/system.cpp b/src/thirdparty/unrar/system.cpp new file mode 100644 index 000000000..a3746aa12 --- /dev/null +++ b/src/thirdparty/unrar/system.cpp @@ -0,0 +1,102 @@ +#include "rar.hpp" + +#ifndef _WIN_CE +static int SleepTime=0; + +void InitSystemOptions(int SleepTime) +{ + ::SleepTime=SleepTime; +} +#endif + + +#if !defined(SFX_MODULE) && !defined(_WIN_CE) && !defined(SETUP) +void SetPriority(int Priority) +{ +#ifdef _WIN_ALL + uint PriorityClass; + int PriorityLevel; + if (Priority<1 || Priority>15) + return; + + if (Priority==1) + { + PriorityClass=IDLE_PRIORITY_CLASS; + PriorityLevel=THREAD_PRIORITY_IDLE; + } + else + if (Priority<7) + { + PriorityClass=IDLE_PRIORITY_CLASS; + PriorityLevel=Priority-4; + } + else + if (Priority==7) + { + PriorityClass=BELOW_NORMAL_PRIORITY_CLASS; + PriorityLevel=THREAD_PRIORITY_ABOVE_NORMAL; + } + else + if (Priority<10) + { + PriorityClass=NORMAL_PRIORITY_CLASS; + PriorityLevel=Priority-7; + } + else + if (Priority==10) + { + PriorityClass=ABOVE_NORMAL_PRIORITY_CLASS; + PriorityLevel=THREAD_PRIORITY_NORMAL; + } + else + { + PriorityClass=HIGH_PRIORITY_CLASS; + PriorityLevel=Priority-13; + } + SetPriorityClass(GetCurrentProcess(),PriorityClass); + SetThreadPriority(GetCurrentThread(),PriorityLevel); + +#ifdef RAR_SMP + ThreadPool::SetPriority(PriorityLevel); +#endif + +// Background mode for Vista, too slow for real life use. +// if (WinNT()>=WNT_VISTA && Priority==1) +// SetPriorityClass(GetCurrentProcess(),PROCESS_MODE_BACKGROUND_BEGIN); + +#endif +} +#endif + + +#ifndef SETUP +void Wait() +{ +#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE) + if (SleepTime!=0) + Sleep(SleepTime); +#endif +} +#endif + + + + +#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE) && !defined(SHELL_EXT) && !defined(SETUP) +void Shutdown() +{ + HANDLE hToken; + TOKEN_PRIVILEGES tkp; + if (OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken)) + { + LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid); + tkp.PrivilegeCount = 1; + tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + AdjustTokenPrivileges(hToken,FALSE,&tkp,0,(PTOKEN_PRIVILEGES)NULL,0); + } + ExitWindowsEx(EWX_SHUTDOWN|EWX_FORCE|EWX_POWEROFF,SHTDN_REASON_FLAG_PLANNED); +} +#endif + + diff --git a/src/thirdparty/unrar/system.hpp b/src/thirdparty/unrar/system.hpp new file mode 100644 index 000000000..a76556470 --- /dev/null +++ b/src/thirdparty/unrar/system.hpp @@ -0,0 +1,28 @@ +#ifndef _RAR_SYSTEM_ +#define _RAR_SYSTEM_ + +#ifdef _WIN_ALL +#ifndef BELOW_NORMAL_PRIORITY_CLASS +#define BELOW_NORMAL_PRIORITY_CLASS 0x00004000 +#define ABOVE_NORMAL_PRIORITY_CLASS 0x00008000 +#endif +#ifndef PROCESS_MODE_BACKGROUND_BEGIN +#define PROCESS_MODE_BACKGROUND_BEGIN 0x00100000 +#define PROCESS_MODE_BACKGROUND_END 0x00200000 +#endif +#ifndef SHTDN_REASON_MAJOR_APPLICATION +#define SHTDN_REASON_MAJOR_APPLICATION 0x00040000 +#define SHTDN_REASON_FLAG_PLANNED 0x80000000 +#define SHTDN_REASON_MINOR_MAINTENANCE 0x00000001 +#endif +#endif + +void InitSystemOptions(int SleepTime); +void SetPriority(int Priority); +void Wait(); +bool EmailFile(char *FileName,char *MailTo); +void Shutdown(); + + + +#endif diff --git a/src/thirdparty/unrar/timefn.cpp b/src/thirdparty/unrar/timefn.cpp new file mode 100644 index 000000000..ed2bd8861 --- /dev/null +++ b/src/thirdparty/unrar/timefn.cpp @@ -0,0 +1,336 @@ +#include "rar.hpp" + +RarTime::RarTime() +{ + Reset(); +} + +#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); +} + + +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); +} +#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); +} + + +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)); +} +#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() +{ + 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. + + // Cumulative day value for beginning of every month. + static int MonthToDay[12]={0,31,60,91,121,152,182,213,244,274,305,335}; + + 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. + + return(r); +#endif +} + + +#ifndef SFX_MODULE +void RarTime::SetRaw(int64 RawTime) +{ +#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); +#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; + } + + rlt.wDay=0; + rlt.yDay=0; +#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(GetRaw()>rt.GetRaw()); +} + + +bool RarTime::operator >= (RarTime &rt) +{ + return(*this>rt || *this==rt); +} + + +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); +} + + +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; +} + + +#if !defined(GUI) || !defined(SFX_MODULE) +void RarTime::GetText(char *DateStr,bool FullYear) +{ + if (FullYear) + sprintf(DateStr,"%02u-%02u-%u %02u:%02u",rlt.Day,rlt.Month,rlt.Year,rlt.Hour,rlt.Minute); + else + sprintf(DateStr,"%02u-%02u-%02u %02u:%02u",rlt.Day,rlt.Month,rlt.Year%100,rlt.Hour,rlt.Minute); +} +#endif + + +#ifndef SFX_MODULE +void RarTime::SetIsoText(const char *TimeText) +{ + int Field[6]; + memset(Field,0,sizeof(Field)); + for (int DigitCount=0;*TimeText!=0;TimeText++) + if (IsDigit(*TimeText)) + { + int FieldPos=DigitCount<4 ? 0:(DigitCount-4)/2+1; + if (FieldPos<sizeof(Field)/sizeof(Field[0])) + 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; +} +#endif + + +#ifndef SFX_MODULE +void RarTime::SetAgeText(const char *TimeText) +{ + uint Seconds=0,Value=0; + for (int I=0;TimeText[I]!=0;I++) + { + int Ch=TimeText[I]; + if (IsDigit(Ch)) + Value=Value*10+Ch-'0'; + else + { + switch(etoupper(Ch)) + { + case 'D': + Seconds+=Value*24*3600; + break; + case 'H': + Seconds+=Value*3600; + break; + case 'M': + Seconds+=Value*60; + break; + case 'S': + Seconds+=Value; + break; + } + Value=0; + } + } + SetCurrentTime(); + int64 RawTime=GetRaw(); + SetRaw(RawTime-INT32TO64(0,Seconds)*10000000); +} +#endif + + +void RarTime::SetCurrentTime() +{ +#ifdef _WIN_ALL + FILETIME ft; + SYSTEMTIME st; + GetSystemTime(&st); + SystemTimeToFileTime(&st,&ft); + *this=ft; +#else + time_t st; + time(&st); + *this=st; +#endif +} + + +#if !defined(SFX_MODULE) && !defined(_WIN_CE) +const char *GetMonthName(int Month) +{ +#ifdef SILENT + return(""); +#else + static MSGID MonthID[]={ + MMonthJan,MMonthFeb,MMonthMar,MMonthApr,MMonthMay,MMonthJun, + MMonthJul,MMonthAug,MMonthSep,MMonthOct,MMonthNov,MMonthDec + }; + return(St(MonthID[Month])); +#endif +} +#endif + + +bool IsLeapYear(int Year) +{ + return((Year&3)==0 && (Year%100!=0 || Year%400==0)); +} diff --git a/src/thirdparty/unrar/timefn.hpp b/src/thirdparty/unrar/timefn.hpp new file mode 100644 index 000000000..7dc55a7b4 --- /dev/null +++ b/src/thirdparty/unrar/timefn.hpp @@ -0,0 +1,54 @@ +#ifndef _RAR_TIMEFN_ +#define _RAR_TIMEFN_ + +struct RarLocalTime +{ + uint Year; + uint Month; + uint Day; + uint Hour; + uint Minute; + uint Second; + uint Reminder; // Part of time smaller than 1 second, represented in 100-nanosecond intervals. + uint wDay; + uint yDay; +}; + + +class RarTime +{ + private: + RarLocalTime rlt; + 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); + uint GetDos(); + void SetDos(uint DosTime); + void GetText(char *DateStr,bool FullYear); + void SetIsoText(const char *TimeText); + void SetAgeText(const char *TimeText); + void SetCurrentTime(); + void Reset() {rlt.Year=0;} + bool IsSet() {return(rlt.Year!=0);} +}; + +const char *GetMonthName(int Month); +bool IsLeapYear(int Year); + +#endif diff --git a/src/thirdparty/unrar/ulinks.cpp b/src/thirdparty/unrar/ulinks.cpp new file mode 100644 index 000000000..c3c828d2c --- /dev/null +++ b/src/thirdparty/unrar/ulinks.cpp @@ -0,0 +1,35 @@ +#include "rar.hpp" + + + +bool ExtractLink(ComprDataIO &DataIO,Archive &Arc,const char *LinkName,uint &LinkCRC,bool Create) +{ +#if defined(SAVE_LINKS) && defined(_UNIX) + char LinkTarget[NM]; + if (IsLink(Arc.NewLhd.FileAttr)) + { + int DataSize=Min(Arc.NewLhd.PackSize,sizeof(LinkTarget)-1); + DataIO.UnpRead((byte *)LinkTarget,DataSize); + LinkTarget[DataSize]=0; + if (Create) + { + 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. + } + int NameSize=Min(DataSize,strlen(LinkTarget)); + LinkCRC=CRC(0xffffffff,LinkTarget,NameSize); + return(true); + } +#endif + return(false); +} diff --git a/src/thirdparty/unrar/ulinks.hpp b/src/thirdparty/unrar/ulinks.hpp new file mode 100644 index 000000000..fdd831f25 --- /dev/null +++ b/src/thirdparty/unrar/ulinks.hpp @@ -0,0 +1,9 @@ +#ifndef _RAR_ULINKS_ +#define _RAR_ULINKS_ + +void SaveLinkData(ComprDataIO &DataIO,Archive &TempArc,FileHeader &hd, + const char *Name); +bool ExtractLink(ComprDataIO &DataIO,Archive &Arc,const char *LinkName, + uint &LinkCRC,bool Create); + +#endif diff --git a/src/thirdparty/unrar/unicode.cpp b/src/thirdparty/unrar/unicode.cpp new file mode 100644 index 000000000..a3022d233 --- /dev/null +++ b/src/thirdparty/unrar/unicode.cpp @@ -0,0 +1,420 @@ +#include "rar.hpp" + +#if defined(_EMX) && !defined(_DJGPP) +#include "unios2.cpp" +#endif + +bool WideToChar(const wchar *Src,char *Dest,size_t DestSize) +{ + bool RetCode=true; + *Dest=0; // Set 'Dest' to zero just in case the conversion will fail. + +#ifdef _WIN_ALL + if (WideCharToMultiByte(CP_ACP,0,Src,-1,Dest,(int)DestSize,NULL,NULL)==0) + RetCode=false; + +#elif defined(_APPLE) + 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) + { + /* 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)); + } + +#else + if (UnicodeEnabled()) + { +#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 + } + else + for (int I=0;I<DestSize;I++) + { + Dest[I]=(char)Src[I]; + if (Src[I]==0) + break; + } +#endif + + // 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 + // of string and passed 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); +} + + +bool CharToWide(const char *Src,wchar *Dest,size_t DestSize) +{ + bool RetCode=true; + *Dest=0; // Set 'Dest' to zero just in case the conversion will fail. + +#ifdef _WIN_ALL + if (MultiByteToWideChar(CP_ACP,0,Src,-1,Dest,(int)DestSize)==0) + RetCode=false; + +#elif defined(_APPLE) + UtfToWide(Src,Dest,DestSize); + +#elif defined(MBFUNCTIONS) + size_t ResultingSize=mbstowcs(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 && 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)); + } +#else + if (UnicodeEnabled()) + { +#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 + } + else + for (int I=0;I<DestSize;I++) + { + Dest[I]=(wchar_t)Src[I]; + if (Src[I]==0) + break; + } +#endif + + // We tried to return the empty string if conversion is failed, + // but it does not work well. MultiByteToWideChar returns 'failed' code + // even if we wanted to convert only a part of string and passed 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); +} + + +// SrcSize is in wide characters, not in bytes. +byte* WideToRaw(const wchar *Src,byte *Dest,size_t SrcSize) +{ + for (size_t I=0;I<SrcSize;I++,Src++) + { + Dest[I*2]=(byte)*Src; + Dest[I*2+1]=(byte)(*Src>>8); + if (*Src==0) + break; + } + return(Dest); +} + + +wchar* RawToWide(const byte *Src,wchar *Dest,size_t DestSize) +{ + for (size_t I=0;I<DestSize;I++) + if ((Dest[I]=Src[I*2]+(Src[I*2+1]<<8))==0) + break; + return(Dest); +} + + +void WideToUtf(const wchar *Src,char *Dest,size_t DestSize) +{ + long dsize=(long)DestSize; + dsize--; + while (*Src!=0 && --dsize>=0) + { + uint c=*(Src++); + if (c<0x80) + *(Dest++)=c; + else + if (c<0x800 && --dsize>=0) + { + *(Dest++)=(0xc0|(c>>6)); + *(Dest++)=(0x80|(c&0x3f)); + } + else + if (c<0x10000 && (dsize-=2)>=0) + { + *(Dest++)=(0xe0|(c>>12)); + *(Dest++)=(0x80|((c>>6)&0x3f)); + *(Dest++)=(0x80|(c&0x3f)); + } + else + if (c < 0x200000 && (dsize-=3)>=0) + { + *(Dest++)=(0xf0|(c>>18)); + *(Dest++)=(0x80|((c>>12)&0x3f)); + *(Dest++)=(0x80|((c>>6)&0x3f)); + *(Dest++)=(0x80|(c&0x3f)); + } + } + *Dest=0; +} + + +// Dest can be NULL if we only need to check validity of Src. +bool UtfToWide(const char *Src,wchar *Dest,size_t DestSize) +{ + bool Success=true; + long dsize=(long)DestSize; + dsize--; + while (*Src!=0) + { + uint c=(byte)*(Src++),d; + if (c<0x80) + d=c; + else + if ((c>>5)==6) + { + if ((*Src&0xc0)!=0x80) + break; + d=((c&0x1f)<<6)|(*Src&0x3f); + Src++; + } + else + if ((c>>4)==14) + { + if ((Src[0]&0xc0)!=0x80 || (Src[1]&0xc0)!=0x80) + break; + d=((c&0xf)<<12)|((Src[0]&0x3f)<<6)|(Src[1]&0x3f); + Src+=2; + } + else + if ((c>>3)==30) + { + if ((Src[0]&0xc0)!=0x80 || (Src[1]&0xc0)!=0x80 || (Src[2]&0xc0)!=0x80) + 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; + } + if (Dest!=NULL && --dsize<0) + break; + if (d>0xffff) + { + if (Dest!=NULL && --dsize<0) + break; + if (d>0x10ffff) + { + // 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; + } + } + else + if (Dest!=NULL) + *(Dest++)=d; + } + if (Dest!=NULL) + *Dest=0; + return Success; +} + + +bool UnicodeEnabled() +{ +#ifdef UNICODE_SUPPORTED + #ifdef _EMX + return(uni_ready); + #else + return(true); + #endif +#else + return(false); +#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)); +} + + +#ifndef SFX_MODULE +wchar* wcslower(wchar *Str) +{ + for (wchar *ChPtr=Str;*ChPtr;ChPtr++) + if (*ChPtr<128) + *ChPtr=loctolower((byte)*ChPtr); + return(Str); +} +#endif + + +#ifndef SFX_MODULE +wchar* wcsupper(wchar *Str) +{ + for (wchar *ChPtr=Str;*ChPtr;ChPtr++) + if (*ChPtr<128) + *ChPtr=loctoupper((byte)*ChPtr); + return(Str); +} +#endif + + +int toupperw(int ch) +{ + return((ch<128) ? loctoupper(ch):ch); +} + + +int tolowerw(int ch) +{ +#ifdef _WIN_ALL + return((int)(LPARAM)CharLowerW((wchar *)(uint)ch)); +#else + return((ch<128) ? loctolower(ch):ch); +#endif +} + + +int atoiw(const wchar *s) +{ + int n=0; + while (*s>='0' && *s<='9') + { + n=n*10+(*s-'0'); + s++; + } + return(n); +} + + +#ifdef DBCS_SUPPORTED +SupportDBCS gdbcs; + +SupportDBCS::SupportDBCS() +{ + Init(); +} + + +void SupportDBCS::Init() +{ + CPINFO CPInfo; + GetCPInfo(CP_ACP,&CPInfo); + DBCSMode=CPInfo.MaxCharSize > 1; + for (uint I=0;I<ASIZE(IsLeadByte);I++) + IsLeadByte[I]=IsDBCSLeadByte(I)!=0; +} + + +char* SupportDBCS::charnext(const char *s) +{ + // Zero cannot be the trail byte. So if next byte after the lead byte + // is 0, the string is corrupt and we'll better return the pointer to 0, + // to break string processing loops. + return (char *)(IsLeadByte[(byte)*s] && s[1]!=0 ? s+2:s+1); +} + + +size_t SupportDBCS::strlend(const char *s) +{ + size_t Length=0; + while (*s!=0) + { + if (IsLeadByte[(byte)*s]) + s+=2; + else + s++; + Length++; + } + return(Length); +} + + +char* SupportDBCS::strchrd(const char *s, int c) +{ + while (*s!=0) + if (IsLeadByte[(byte)*s]) + s+=2; + else + if (*s==c) + return((char *)s); + else + s++; + return(NULL); +} + + +void SupportDBCS::copychrd(char *dest,const char *src) +{ + dest[0]=src[0]; + if (IsLeadByte[(byte)src[0]]) + dest[1]=src[1]; +} + + +char* SupportDBCS::strrchrd(const char *s, int c) +{ + const char *found=NULL; + while (*s!=0) + if (IsLeadByte[(byte)*s]) + s+=2; + else + { + if (*s==c) + found=s; + s++; + } + return((char *)found); +} +#endif diff --git a/src/thirdparty/unrar/unicode.hpp b/src/thirdparty/unrar/unicode.hpp new file mode 100644 index 000000000..6e4b62289 --- /dev/null +++ b/src/thirdparty/unrar/unicode.hpp @@ -0,0 +1,90 @@ +#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); +void WideToUtf(const wchar *Src,char *Dest,size_t DestSize); +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); +int toupperw(int ch); +int tolowerw(int ch); +int atoiw(const wchar *s); + +#ifdef DBCS_SUPPORTED +class SupportDBCS +{ + public: + SupportDBCS(); + void Init(); + + char* charnext(const char *s); + size_t strlend(const char *s); + char *strchrd(const char *s, int c); + char *strrchrd(const char *s, int c); + void copychrd(char *dest,const char *src); + + bool IsLeadByte[256]; + bool DBCSMode; +}; + +extern SupportDBCS gdbcs; + +inline char* charnext(const char *s) {return (char *)(gdbcs.DBCSMode ? gdbcs.charnext(s):s+1);} +inline size_t strlend(const char *s) {return (uint)(gdbcs.DBCSMode ? gdbcs.strlend(s):strlen(s));} +inline char* strchrd(const char *s, int c) {return (char *)(gdbcs.DBCSMode ? gdbcs.strchrd(s,c):strchr(s,c));} +inline char* strrchrd(const char *s, int c) {return (char *)(gdbcs.DBCSMode ? gdbcs.strrchrd(s,c):strrchr(s,c));} +inline void copychrd(char *dest,const char *src) {if (gdbcs.DBCSMode) gdbcs.copychrd(dest,src); else *dest=*src;} +inline bool IsDBCSMode() {return(gdbcs.DBCSMode);} +inline void InitDBCS() {gdbcs.Init();} + +#else +#define charnext(s) ((s)+1) +#define strlend strlen +#define strchrd strchr +#define strrchrd strrchr +#define IsDBCSMode() (true) +inline void copychrd(char *dest,const char *src) {*dest=*src;} +#endif + +#endif diff --git a/src/thirdparty/unrar/unios2.cpp b/src/thirdparty/unrar/unios2.cpp new file mode 100644 index 000000000..1261473ba --- /dev/null +++ b/src/thirdparty/unrar/unios2.cpp @@ -0,0 +1,128 @@ +// (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 new file mode 100644 index 000000000..350d8951f --- /dev/null +++ b/src/thirdparty/unrar/unpack.cpp @@ -0,0 +1,1187 @@ +#include "rar.hpp" + +#include "coder.cpp" +#include "suballoc.cpp" +#include "model.cpp" +#ifndef SFX_MODULE +#include "unpack15.cpp" +#include "unpack20.cpp" +#endif + +Unpack::Unpack(ComprDataIO *DataIO) +{ + UnpIO=DataIO; + Window=NULL; + Suspended=false; + UnpAllBuf=false; + UnpSomeRead=false; +} + + +Unpack::~Unpack() +{ + delete[] Window; + InitFilters(); +} + + +void Unpack::Init() +{ + Window=new byte[MAXWINSIZE]; + +#ifndef ALLOW_EXCEPTIONS + if (Window==NULL) + ErrHandler.MemoryError(); +#endif + + // 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); + + UnpInitData(false); + +#ifndef SFX_MODULE + // RAR 1.5 decompression initialization + OldUnpInitData(false); + InitHuff(); +#endif +} + + +void Unpack::DoUnpack(int Method,bool Solid) +{ + switch(Method) + { +#ifndef SFX_MODULE + case 15: // rar 1.5 compression + Unpack15(Solid); + break; + case 20: // rar 2.x compression + case 26: // files larger than 2GB + Unpack20(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. + { + if (!ReadTables()) + 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(&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; + } + } + 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) +{ + 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)); + UnpPtr=WrPtr=0; + PPMEscChar=2; + UnpBlockType=BLOCK_LZ; + + InitFilters(); + } + InitBitInput(); + WrittenFileSize=0; + ReadTop=0; + ReadBorder=0; +#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(); +} + + +// LengthTable contains the length in bits for every element of alphabet. +// Dec is the structure to decode Huffman code/ +// Size is size of length table and DecodeNum field in Dec structure, +void Unpack::MakeDecodeTables(byte *LengthTable,DecodeTable *Dec,uint Size) +{ + // Size of alphabet and DecodePos array. + Dec->MaxNum=Size; + + // Calculate how many entries for every bit length in LengthTable we have. + uint LengthCount[16]; + memset(LengthCount,0,sizeof(LengthCount)); + for (size_t I=0;I<Size;I++) + LengthCount[LengthTable[I] & 0xf]++; + + // We must not calculate the number of zero length codes. + LengthCount[0]=0; + + // Set the entire DecodeNum to zero. + memset(Dec->DecodeNum,0,Size*sizeof(*Dec->DecodeNum)); + + // Initialize not really used entry for zero length code. + Dec->DecodePos[0]=0; + + // Start code for bit length 1 is 0. + Dec->DecodeLen[0]=0; + + // Right aligned upper limit code for current bit length. + uint UpperLimit=0; + + for (size_t I=1;I<16;I++) + { + // Adjust the upper limit code. + UpperLimit+=LengthCount[I]; + + // Left aligned upper limit code. + uint LeftAligned=UpperLimit<<(16-I); + + // Prepare the upper limit code for next bit length. + UpperLimit*=2; + + // Store the left aligned upper limit code. + Dec->DecodeLen[I]=(uint)LeftAligned; + + // Every item of this array contains the sum of all preceding items. + // So it contains the start position in code list for every bit length. + Dec->DecodePos[I]=Dec->DecodePos[I-1]+LengthCount[I-1]; + } + + // Prepare the copy of DecodePos. We'll modify this copy below, + // so we cannot use the original DecodePos. + uint CopyDecodePos[16]; + memcpy(CopyDecodePos,Dec->DecodePos,sizeof(CopyDecodePos)); + + // For every bit length in the bit length table and so for every item + // of alphabet. + for (uint I=0;I<Size;I++) + { + // Get the current bit length. + byte CurBitLength=LengthTable[I] & 0xf; + + if (CurBitLength!=0) + { + // Last position in code list for current bit length. + uint LastPos=CopyDecodePos[CurBitLength]; + + // Prepare the decode table, so this position in code list will be + // decoded to current alphabet item number. + Dec->DecodeNum[LastPos]=(ushort)I; + + // We'll use next position number for this bit length next time. + // So we pass through the entire range of positions available + // for every bit length. + CopyDecodePos[CurBitLength]++; + } + } + + // Define the number of bits to process in quick mode. We use more bits + // for larger alphabets. More bits means that more codes will be processed + // in quick mode, but also that more time will be spent to preparation + // of tables for quick decode. + switch (Size) + { + case NC: + case NC20: + Dec->QuickBits=MAX_QUICK_DECODE_BITS; + break; + default: + Dec->QuickBits=MAX_QUICK_DECODE_BITS-3; + break; + } + + // Size of tables for quick mode. + uint QuickDataSize=1<<Dec->QuickBits; + + // Bit length for current code, start from 1 bit codes. It is important + // to use 1 bit instead of 0 for minimum code length, so we are moving + // forward even when processing a corrupt archive. + uint CurBitLength=1; + + // For every right aligned bit string which supports the quick decoding. + for (uint Code=0;Code<QuickDataSize;Code++) + { + // Left align the current code, so it will be in usual bit field format. + uint BitField=Code<<(16-Dec->QuickBits); + + // Prepare the table for quick decoding of bit lengths. + + // Find the upper limit for current bit field and adjust the bit length + // accordingly if necessary. + while (BitField>=Dec->DecodeLen[CurBitLength] && CurBitLength<ASIZE(Dec->DecodeLen)) + CurBitLength++; + + // Translation of right aligned bit string to bit length. + Dec->QuickLen[Code]=CurBitLength; + + // Prepare the table for quick translation of position in code list + // to position in alphabet. + + // Calculate the distance from the start code for current bit length. + uint Dist=BitField-Dec->DecodeLen[CurBitLength-1]; + + // Right align the distance. + Dist>>=(16-CurBitLength); + + // 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[CurBitLength]+Dist; + + if (Pos<Size) // Safety check for damaged archives. + { + // Define the code to alphabet number translation. + Dec->QuickNum[Code]=Dec->DecodeNum[Pos]; + } + else + Dec->QuickNum[Code]=0; + } +} diff --git a/src/thirdparty/unrar/unpack.hpp b/src/thirdparty/unrar/unpack.hpp new file mode 100644 index 000000000..d5779a9f9 --- /dev/null +++ b/src/thirdparty/unrar/unpack.hpp @@ -0,0 +1,222 @@ +#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 + +// Maximum number of filters per entire data block. +#define MAX_FILTERS 1024 + +// Decode compressed bit fields to alphabet numbers. +struct DecodeTable +{ + // Real size of DecodeNum table. + uint MaxNum; + + // Left aligned start and upper limit codes defining code space + // ranges for bit lengths. DecodeLen[BitLength-1] defines the start of + // range for bit length and DecodeLen[BitLength] defines next code + // after the end of range or in other words the upper limit code + // for specified bit length. + uint DecodeLen[16]; + + // Every item of this array contains the sum of all preceding items. + // So it contains the start position in code list for every bit length. + uint DecodePos[16]; + + // Number of compressed bits processed in quick mode. + // Must not exceed MAX_QUICK_DECODE_BITS. + uint QuickBits; + + // Translates compressed bits (up to QuickBits length) + // to bit length in quick mode. + byte QuickLen[1<<MAX_QUICK_DECODE_BITS]; + + // Translates compressed bits (up to QuickBits length) + // to position in alphabet in quick mode. + // 'ushort' saves some memory and even provides a little speed gain + // comparting to 'uint' here. + ushort QuickNum[1<<MAX_QUICK_DECODE_BITS]; + + // Translate the position in code list to position in alphabet. + // We do not allocate it dynamically to avoid performance overhead + // introduced by pointer, so we use the largest possible table size + // as array dimension. Real size of this array is defined in MaxNum. + // We use this array if compressed bit field is too lengthy + // for QuickLen based translation. + // 'ushort' saves some memory and even provides a little speed gain + // comparting to 'uint' here. + ushort DecodeNum[LARGEST_TABLE_SIZE]; +}; + +struct UnpackFilter +{ + unsigned int BlockStart; + unsigned int BlockLength; + unsigned int ExecCount; + bool NextWindow; + + // position of parent filter in Filters array used as prototype for filter + // in PrgStack array. Not defined for filters in Filters array. + unsigned int ParentFilter; + + VM_PreparedProgram Prg; +}; + + +struct AudioVariables // For RAR 2.0 archives only. +{ + int K1,K2,K3,K4,K5; + int D1,D2,D3,D4; + int LastDelta; + unsigned int Dif[11]; + unsigned int ByteCount; + int LastChar; +}; + + +class Unpack:private BitInput +{ + private: + + void Unpack29(bool Solid); + bool UnpReadBuf(); + void UnpWriteBuf(); + void ExecuteCode(VM_PreparedProgram *Prg); + void UnpWriteArea(unsigned int StartPtr,unsigned int EndPtr); + void UnpWriteData(byte *Data,size_t Size); + bool ReadTables(); + void MakeDecodeTables(byte *LengthTable,DecodeTable *Dec,uint Size); + _forceinline uint DecodeNumber(DecodeTable *Dec); + inline int SafePPMDecodeChar(); + void CopyString(); + inline void InsertOldDist(unsigned int Distance); + void UnpInitData(int Solid); + _forceinline void CopyString(uint Length,uint Distance); + bool ReadEndOfBlock(); + bool ReadVMCode(); + bool ReadVMCodePPM(); + bool AddVMCode(unsigned int FirstByte,byte *Code,int CodeSize); + 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; + + // 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; + + int LastFilter; + + bool TablesRead; + + 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. + + unsigned int OldDist[4],OldDistPtr; + unsigned int 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; + + unsigned int UnpPtr,WrPtr; + + // Top border of read packed data. + int ReadTop; + + // Border to call UnpReadBuf. We use it instead of (ReadTop-C) + // for optimization reasons. Ensures that we have C bytes in buffer + // unless we are at the end of file. + int ReadBorder; + + byte UnpOldTable[HUFF_TABLE_SIZE]; + + int UnpBlockType; + + byte *Window; + + + int64 DestUnpSize; + + bool Suspended; + bool UnpAllBuf; + bool UnpSomeRead; + int64 WrittenFileSize; + bool FileExtracted; + + int PrevLowDist,LowDistRepCount; + +/***************************** Unpack v 1.5 *********************************/ + void Unpack15(bool Solid); + void ShortLZ(); + void LongLZ(); + void HuffDecode(); + void GetFlagsBuf(); + void OldUnpInitData(int Solid); + void InitHuff(); + void CorrHuff(ushort *CharSet,byte *NumToPlace); + void OldCopyString(unsigned int Distance,unsigned int 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; + int Buf60,NumHuf,StMode,LCount,FlagsCnt; + unsigned int Nhfb,Nlzb,MaxDist3; +/***************************** Unpack v 1.5 *********************************/ + +/***************************** Unpack v 2.0 *********************************/ + void Unpack20(bool Solid); + + DecodeTable MD[4]; // Decode multimedia data, up to 4 channels. + + unsigned char UnpOldTable20[MC20*4]; + int UnpAudioBlock,UnpChannels,UnpCurChannel,UnpChannelDelta; + void CopyString20(unsigned int Length,unsigned int Distance); + bool ReadTables20(); + void UnpInitData20(int Solid); + void ReadLastTables(); + byte DecodeAudio(int Delta); + struct AudioVariables AudV[4]; +/***************************** Unpack v 2.0 *********************************/ + + public: + Unpack(ComprDataIO *DataIO); + ~Unpack(); + void Init(); + 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() + { + if (InAddr>BitInput::MAX_SIZE-30) + UnpReadBuf(); + return(InBuf[InAddr++]); + } +}; + +#endif diff --git a/src/thirdparty/unrar/unpack15.cpp b/src/thirdparty/unrar/unpack15.cpp new file mode 100644 index 000000000..c9faf01a6 --- /dev/null +++ b/src/thirdparty/unrar/unpack15.cpp @@ -0,0 +1,506 @@ +#define STARTL1 2 +static unsigned int DecL1[]={0x8000,0xa000,0xc000,0xd000,0xe000,0xea00, + 0xee00,0xf000,0xf200,0xf200,0xffff}; +static unsigned int PosL1[]={0,0,0,2,3,5,7,11,16,20,24,32,32}; + +#define STARTL2 3 +static unsigned int DecL2[]={0xa000,0xc000,0xd000,0xe000,0xea00,0xee00, + 0xf000,0xf200,0xf240,0xffff}; +static unsigned int PosL2[]={0,0,0,0,5,7,9,13,18,22,26,34,36}; + +#define STARTHF0 4 +static unsigned int DecHf0[]={0x8000,0xc000,0xe000,0xf200,0xf200,0xf200, + 0xf200,0xf200,0xffff}; +static unsigned int PosHf0[]={0,0,0,0,0,8,16,24,33,33,33,33,33}; + + +#define STARTHF1 5 +static unsigned int DecHf1[]={0x2000,0xc000,0xe000,0xf000,0xf200,0xf200, + 0xf7e0,0xffff}; +static unsigned int PosHf1[]={0,0,0,0,0,0,4,44,60,76,80,80,127}; + + +#define STARTHF2 5 +static unsigned int DecHf2[]={0x1000,0x2400,0x8000,0xc000,0xfa00,0xffff, + 0xffff,0xffff}; +static unsigned int PosHf2[]={0,0,0,0,0,0,2,7,53,117,233,0,0}; + + +#define STARTHF3 6 +static unsigned int DecHf3[]={0x800,0x2400,0xee00,0xfe80,0xffff,0xffff, + 0xffff}; +static unsigned int PosHf3[]={0,0,0,0,0,0,0,2,16,218,251,0,0}; + + +#define STARTHF4 8 +static unsigned int DecHf4[]={0xff00,0xffff,0xffff,0xffff,0xffff,0xffff}; +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); + OldUnpInitData(Solid); + UnpReadBuf(); + if (!Solid) + { + InitHuff(); + UnpPtr=0; + } + else + UnpPtr=WrPtr; + --DestUnpSize; + } + if (DestUnpSize>=0) + { + GetFlagsBuf(); + FlagsCnt=8; + } + + while (DestUnpSize>=0) + { + UnpPtr&=MAXWINMASK; + + if (InAddr>ReadTop-30 && !UnpReadBuf()) + break; + if (((WrPtr-UnpPtr) & MAXWINMASK)<270 && WrPtr!=UnpPtr) + { + OldUnpWriteBuf(); + if (Suspended) + return; + } + if (StMode) + { + HuffDecode(); + continue; + } + + if (--FlagsCnt < 0) + { + GetFlagsBuf(); + FlagsCnt=7; + } + + if (FlagBuf & 0x80) + { + FlagBuf<<=1; + if (Nlzb > Nhfb) + LongLZ(); + else + HuffDecode(); + } + else + { + FlagBuf<<=1; + if (--FlagsCnt < 0) + { + GetFlagsBuf(); + FlagsCnt=7; + } + if (FlagBuf & 0x80) + { + FlagBuf<<=1; + if (Nlzb > Nhfb) + HuffDecode(); + else + LongLZ(); + } + else + { + FlagBuf<<=1; + ShortLZ(); + } + } + } + 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; +} + + +#define GetShortLen1(pos) ((pos)==1 ? Buf60+3:ShortLen1[pos]) +#define GetShortLen2(pos) ((pos)==3 ? Buf60+3:ShortLen2[pos]) + +void Unpack::ShortLZ() +{ + static unsigned int ShortLen1[]={1,3,4,4,5,6,7,8,8,4,4,5,6,6,4,0}; + static unsigned int ShortXor1[]={0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe, + 0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0}; + static unsigned int ShortLen2[]={2,3,3,3,4,4,5,6,6,4,4,5,6,6,4,0}; + static unsigned int ShortXor2[]={0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8, + 0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0}; + + + unsigned int Length,SaveLength; + unsigned int LastDistance; + unsigned int Distance; + int DistancePlace; + NumHuf=0; + + unsigned int BitField=fgetbits(); + if (LCount==2) + { + faddbits(1); + if (BitField >= 0x8000) + { + OldCopyString((unsigned int)LastDist,LastLength); + return; + } + BitField <<= 1; + LCount=0; + } + + BitField>>=8; + +// not thread safe, replaced by GetShortLen1 and GetShortLen2 macro +// ShortLen1[1]=ShortLen2[3]=Buf60+3; + + if (AvrLn1<37) + { + for (Length=0;;Length++) + if (((BitField^ShortXor1[Length]) & (~(0xff>>GetShortLen1(Length))))==0) + break; + faddbits(GetShortLen1(Length)); + } + else + { + for (Length=0;;Length++) + if (((BitField^ShortXor2[Length]) & (~(0xff>>GetShortLen2(Length))))==0) + break; + faddbits(GetShortLen2(Length)); + } + + if (Length >= 9) + { + if (Length == 9) + { + LCount++; + OldCopyString((unsigned int)LastDist,LastLength); + return; + } + if (Length == 14) + { + LCount=0; + Length=DecodeNum(fgetbits(),STARTL2,DecL2,PosL2)+5; + Distance=(fgetbits()>>1) | 0x8000; + faddbits(15); + LastLength=Length; + LastDist=Distance; + OldCopyString(Distance,Length); + return; + } + + LCount=0; + SaveLength=Length; + Distance=OldDist[(OldDistPtr-(Length-9)) & 3]; + Length=DecodeNum(fgetbits(),STARTL1,DecL1,PosL1)+2; + if (Length==0x101 && SaveLength==10) + { + Buf60 ^= 1; + return; + } + if (Distance > 256) + Length++; + if (Distance >= MaxDist3) + Length++; + + OldDist[OldDistPtr++]=Distance; + OldDistPtr = OldDistPtr & 3; + LastLength=Length; + LastDist=Distance; + OldCopyString(Distance,Length); + return; + } + + LCount=0; + AvrLn1 += Length; + AvrLn1 -= AvrLn1 >> 4; + + DistancePlace=DecodeNum(fgetbits(),STARTHF2,DecHf2,PosHf2) & 0xff; + Distance=ChSetA[DistancePlace]; + if (--DistancePlace != -1) + { + LastDistance=ChSetA[DistancePlace]; + ChSetA[DistancePlace+1]=LastDistance; + ChSetA[DistancePlace]=Distance; + } + Length+=2; + OldDist[OldDistPtr++] = ++Distance; + OldDistPtr = OldDistPtr & 3; + LastLength=Length; + LastDist=Distance; + OldCopyString(Distance,Length); +} + + +void Unpack::LongLZ() +{ + unsigned int Length; + unsigned int Distance; + unsigned int DistancePlace,NewDistancePlace; + unsigned int OldAvr2,OldAvr3; + + NumHuf=0; + Nlzb+=16; + if (Nlzb > 0xff) + { + Nlzb=0x90; + Nhfb >>= 1; + } + OldAvr2=AvrLn2; + + unsigned int BitField=fgetbits(); + if (AvrLn2 >= 122) + Length=DecodeNum(BitField,STARTL2,DecL2,PosL2); + else + if (AvrLn2 >= 64) + Length=DecodeNum(BitField,STARTL1,DecL1,PosL1); + else + if (BitField < 0x100) + { + Length=BitField; + faddbits(16); + } + else + { + for (Length=0;((BitField<<Length)&0x8000)==0;Length++) + ; + faddbits(Length+1); + } + + AvrLn2 += Length; + AvrLn2 -= AvrLn2 >> 5; + + BitField=fgetbits(); + if (AvrPlcB > 0x28ff) + DistancePlace=DecodeNum(BitField,STARTHF2,DecHf2,PosHf2); + else + if (AvrPlcB > 0x6ff) + DistancePlace=DecodeNum(BitField,STARTHF1,DecHf1,PosHf1); + else + DistancePlace=DecodeNum(BitField,STARTHF0,DecHf0,PosHf0); + + AvrPlcB += DistancePlace; + AvrPlcB -= AvrPlcB >> 8; + while (1) + { + Distance = ChSetB[DistancePlace & 0xff]; + NewDistancePlace = NToPlB[Distance++ & 0xff]++; + if (!(Distance & 0xff)) + CorrHuff(ChSetB,NToPlB); + else + break; + } + + ChSetB[DistancePlace]=ChSetB[NewDistancePlace]; + ChSetB[NewDistancePlace]=Distance; + + Distance=((Distance & 0xff00) | (fgetbits() >> 8)) >> 1; + faddbits(7); + + OldAvr3=AvrLn3; + if (Length!=1 && Length!=4) + if (Length==0 && Distance <= MaxDist3) + { + AvrLn3++; + AvrLn3 -= AvrLn3 >> 8; + } + else + if (AvrLn3 > 0) + AvrLn3--; + Length+=3; + if (Distance >= MaxDist3) + Length++; + if (Distance <= 256) + Length+=8; + if (OldAvr3 > 0xb0 || AvrPlc >= 0x2a00 && OldAvr2 < 0x40) + MaxDist3=0x7f00; + else + MaxDist3=0x2001; + OldDist[OldDistPtr++]=Distance; + OldDistPtr = OldDistPtr & 3; + LastLength=Length; + LastDist=Distance; + OldCopyString(Distance,Length); +} + + +void Unpack::HuffDecode() +{ + unsigned int CurByte,NewBytePlace; + unsigned int Length; + unsigned int Distance; + int BytePlace; + + unsigned int BitField=fgetbits(); + + if (AvrPlc > 0x75ff) + BytePlace=DecodeNum(BitField,STARTHF4,DecHf4,PosHf4); + else + if (AvrPlc > 0x5dff) + BytePlace=DecodeNum(BitField,STARTHF3,DecHf3,PosHf3); + else + if (AvrPlc > 0x35ff) + BytePlace=DecodeNum(BitField,STARTHF2,DecHf2,PosHf2); + else + if (AvrPlc > 0x0dff) + BytePlace=DecodeNum(BitField,STARTHF1,DecHf1,PosHf1); + else + BytePlace=DecodeNum(BitField,STARTHF0,DecHf0,PosHf0); + BytePlace&=0xff; + if (StMode) + { + if (BytePlace==0 && BitField > 0xfff) + BytePlace=0x100; + if (--BytePlace==-1) + { + BitField=fgetbits(); + faddbits(1); + if (BitField & 0x8000) + { + NumHuf=StMode=0; + return; + } + else + { + Length = (BitField & 0x4000) ? 4 : 3; + faddbits(1); + Distance=DecodeNum(fgetbits(),STARTHF2,DecHf2,PosHf2); + Distance = (Distance << 5) | (fgetbits() >> 11); + faddbits(5); + OldCopyString(Distance,Length); + return; + } + } + } + else + if (NumHuf++ >= 16 && FlagsCnt==0) + StMode=1; + AvrPlc += BytePlace; + AvrPlc -= AvrPlc >> 8; + Nhfb+=16; + if (Nhfb > 0xff) + { + Nhfb=0x90; + Nlzb >>= 1; + } + + Window[UnpPtr++]=(byte)(ChSet[BytePlace]>>8); + --DestUnpSize; + + while (1) + { + CurByte=ChSet[BytePlace]; + NewBytePlace=NToPl[CurByte++ & 0xff]++; + if ((CurByte & 0xff) > 0xa1) + CorrHuff(ChSet,NToPl); + else + break; + } + + ChSet[BytePlace]=ChSet[NewBytePlace]; + ChSet[NewBytePlace]=CurByte; +} + + +void Unpack::GetFlagsBuf() +{ + unsigned int Flags,NewFlagsPlace; + unsigned int FlagsPlace=DecodeNum(fgetbits(),STARTHF2,DecHf2,PosHf2); + + while (1) + { + Flags=ChSetC[FlagsPlace]; + FlagBuf=Flags>>8; + NewFlagsPlace=NToPlC[Flags++ & 0xff]++; + if ((Flags & 0xff) != 0) + break; + CorrHuff(ChSetC,NToPlC); + } + + ChSetC[FlagsPlace]=ChSetC[NewFlagsPlace]; + ChSetC[NewFlagsPlace]=Flags; +} + + +void Unpack::OldUnpInitData(int Solid) +{ + if (!Solid) + { + AvrPlcB=AvrLn1=AvrLn2=AvrLn3=NumHuf=Buf60=0; + AvrPlc=0x3500; + MaxDist3=0x2001; + Nhfb=Nlzb=0x80; + } + FlagsCnt=0; + FlagBuf=0; + StMode=0; + LCount=0; + ReadTop=0; +} + + +void Unpack::InitHuff() +{ + for (unsigned int I=0;I<256;I++) + { + ChSet[I]=ChSetB[I]=I<<8; + ChSetA[I]=I; + ChSetC[I]=((~I+1) & 0xff)<<8; + } + memset(NToPl,0,sizeof(NToPl)); + memset(NToPlB,0,sizeof(NToPlB)); + memset(NToPlC,0,sizeof(NToPlC)); + CorrHuff(ChSetB,NToPlB); +} + + +void Unpack::CorrHuff(ushort *CharSet,byte *NumToPlace) +{ + int I,J; + for (I=7;I>=0;I--) + for (J=0;J<32;J++,CharSet++) + *CharSet=(*CharSet & ~0xff) | I; + memset(NumToPlace,0,sizeof(NToPl)); + for (I=6;I>=0;I--) + NumToPlace[I]=(7-I)*32; +} + + +void Unpack::OldCopyString(unsigned int Distance,unsigned int Length) +{ + DestUnpSize-=Length; + while (Length--) + { + Window[UnpPtr]=Window[(UnpPtr-Distance) & MAXWINMASK]; + UnpPtr=(UnpPtr+1) & MAXWINMASK; + } +} + + +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); + 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 new file mode 100644 index 000000000..300ee3407 --- /dev/null +++ b/src/thirdparty/unrar/unpack20.cpp @@ -0,0 +1,370 @@ +#include "rar.hpp" + +void Unpack::CopyString20(unsigned int Length,unsigned int 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; + } +} + + +void Unpack::Unpack20(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[]={0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040}; + static unsigned char DBits[]= {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16}; + 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 (Suspended) + UnpPtr=WrPtr; + else + { + UnpInitData(Solid); + if (!UnpReadBuf()) + return; + if (!Solid) + if (!ReadTables20()) + return; + --DestUnpSize; + } + + while (DestUnpSize>=0) + { + UnpPtr&=MAXWINMASK; + + if (InAddr>ReadTop-30) + if (!UnpReadBuf()) + break; + if (((WrPtr-UnpPtr) & MAXWINMASK)<270 && WrPtr!=UnpPtr) + { + OldUnpWriteBuf(); + if (Suspended) + return; + } + if (UnpAudioBlock) + { + int AudioNumber=DecodeNumber(&MD[UnpCurChannel]); + + if (AudioNumber==256) + { + if (!ReadTables20()) + break; + continue; + } + Window[UnpPtr++]=DecodeAudio(AudioNumber); + if (++UnpCurChannel==UnpChannels) + UnpCurChannel=0; + --DestUnpSize; + continue; + } + + int Number=DecodeNumber(&LD); + if (Number<256) + { + Window[UnpPtr++]=(byte)Number; + --DestUnpSize; + continue; + } + if (Number>269) + { + int Length=LDecode[Number-=270]+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) + { + Distance+=getbits()>>(16-Bits); + addbits(Bits); + } + + if (Distance>=0x2000) + { + Length++; + if (Distance>=0x40000L) + Length++; + } + + CopyString20(Length,Distance); + continue; + } + if (Number==269) + { + if (!ReadTables20()) + break; + continue; + } + if (Number==256) + { + CopyString20(LastLength,LastDist); + continue; + } + if (Number<261) + { + unsigned int Distance=OldDist[(OldDistPtr-(Number-256)) & 3]; + int LengthNumber=DecodeNumber(&RD); + int Length=LDecode[LengthNumber]+2; + if ((Bits=LBits[LengthNumber])>0) + { + Length+=getbits()>>(16-Bits); + addbits(Bits); + } + if (Distance>=0x101) + { + Length++; + if (Distance>=0x2000) + { + Length++; + if (Distance>=0x40000) + Length++; + } + } + CopyString20(Length,Distance); + continue; + } + if (Number<270) + { + unsigned int Distance=SDDecode[Number-=261]+1; + if ((Bits=SDBits[Number])>0) + { + Distance+=getbits()>>(16-Bits); + addbits(Bits); + } + CopyString20(2,Distance); + continue; + } + } + ReadLastTables(); + OldUnpWriteBuf(); +} + + +bool Unpack::ReadTables20() +{ + byte BitLength[BC20]; + unsigned char Table[MC20*4]; + int TableSize,N,I; + if (InAddr>ReadTop-25) + if (!UnpReadBuf()) + return(false); + unsigned int BitField=getbits(); + UnpAudioBlock=(BitField & 0x8000); + + if (!(BitField & 0x4000)) + memset(UnpOldTable20,0,sizeof(UnpOldTable20)); + addbits(2); + + if (UnpAudioBlock) + { + UnpChannels=((BitField>>12) & 3)+1; + if (UnpCurChannel>=UnpChannels) + UnpCurChannel=0; + addbits(2); + TableSize=MC20*UnpChannels; + } + else + TableSize=NC20+DC20+RC20; + + for (I=0;I<BC20;I++) + { + BitLength[I]=(byte)(getbits() >> 12); + addbits(4); + } + MakeDecodeTables(BitLength,&BD,BC20); + I=0; + while (I<TableSize) + { + if (InAddr>ReadTop-5) + if (!UnpReadBuf()) + return(false); + int Number=DecodeNumber(&BD); + if (Number<16) + { + Table[I]=(Number+UnpOldTable20[I]) & 0xf; + I++; + } + else + if (Number==16) + { + N=(getbits() >> 14)+3; + addbits(2); + while (N-- > 0 && I<TableSize) + { + Table[I]=Table[I-1]; + I++; + } + } + else + { + if (Number==17) + { + N=(getbits() >> 13)+3; + addbits(3); + } + else + { + N=(getbits() >> 9)+11; + addbits(7); + } + while (N-- > 0 && I<TableSize) + Table[I++]=0; + } + } + if (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); + } + memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20)); + return(true); +} + + +void Unpack::ReadLastTables() +{ + if (ReadTop>=InAddr+5) + if (UnpAudioBlock) + { + if (DecodeNumber(&MD[UnpCurChannel])==256) + ReadTables20(); + } + else + if (DecodeNumber(&LD)==269) + ReadTables20(); +} + + +void Unpack::UnpInitData20(int Solid) +{ + if (!Solid) + { + UnpAudioBlock=UnpChannelDelta=UnpCurChannel=0; + UnpChannels=1; + + memset(AudV,0,sizeof(AudV)); + memset(UnpOldTable20,0,sizeof(UnpOldTable20)); + memset(MD,0,sizeof(MD)); + } +} + + +byte Unpack::DecodeAudio(int Delta) +{ + struct AudioVariables *V=&AudV[UnpCurChannel]; + V->ByteCount++; + V->D4=V->D3; + V->D3=V->D2; + V->D2=V->LastDelta-V->D1; + V->D1=V->LastDelta; + int PCh=8*V->LastChar+V->K1*V->D1+V->K2*V->D2+V->K3*V->D3+V->K4*V->D4+V->K5*UnpChannelDelta; + PCh=(PCh>>3) & 0xFF; + + unsigned int Ch=PCh-Delta; + + int D=((signed char)Delta)<<3; + + V->Dif[0]+=abs(D); + V->Dif[1]+=abs(D-V->D1); + V->Dif[2]+=abs(D+V->D1); + V->Dif[3]+=abs(D-V->D2); + V->Dif[4]+=abs(D+V->D2); + V->Dif[5]+=abs(D-V->D3); + V->Dif[6]+=abs(D+V->D3); + V->Dif[7]+=abs(D-V->D4); + V->Dif[8]+=abs(D+V->D4); + V->Dif[9]+=abs(D-UnpChannelDelta); + V->Dif[10]+=abs(D+UnpChannelDelta); + + UnpChannelDelta=V->LastDelta=(signed char)(Ch-V->LastChar); + V->LastChar=Ch; + + if ((V->ByteCount & 0x1F)==0) + { + unsigned int MinDif=V->Dif[0],NumMinDif=0; + V->Dif[0]=0; + for (int I=1;I<sizeof(V->Dif)/sizeof(V->Dif[0]);I++) + { + if (V->Dif[I]<MinDif) + { + MinDif=V->Dif[I]; + NumMinDif=I; + } + V->Dif[I]=0; + } + switch(NumMinDif) + { + case 1: + if (V->K1>=-16) + V->K1--; + break; + case 2: + if (V->K1<16) + V->K1++; + break; + case 3: + if (V->K2>=-16) + V->K2--; + break; + case 4: + if (V->K2<16) + V->K2++; + break; + case 5: + if (V->K3>=-16) + V->K3--; + break; + case 6: + if (V->K3<16) + V->K3++; + break; + case 7: + if (V->K4>=-16) + V->K4--; + break; + case 8: + if (V->K4<16) + V->K4++; + break; + case 9: + if (V->K5>=-16) + V->K5--; + break; + case 10: + if (V->K5<16) + V->K5++; + break; + } + } + return((byte)Ch); +} diff --git a/src/thirdparty/unrar/unrar.vcxproj b/src/thirdparty/unrar/unrar.vcxproj new file mode 100644 index 000000000..4f50bf426 --- /dev/null +++ b/src/thirdparty/unrar/unrar.vcxproj @@ -0,0 +1,207 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>unrar</ProjectName>
+ <ProjectGuid>{DA8461C4-7683-4360-9372-2A9E0F1795C2}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="..\..\common.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="..\..\common.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="..\..\common.props" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ <Import Project="..\..\common.props" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
+ <PreprocessorDefinitions>_LIB;RARDLL;SILENT;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <WarningLevel>Level3</WarningLevel>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
+ <WarningLevel>TurnOffAllWarnings</WarningLevel>
+ <PreprocessorDefinitions>_LIB;RARDLL;SILENT;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
+ <WarningLevel>TurnOffAllWarnings</WarningLevel>
+ <PreprocessorDefinitions>_LIB;RARDLL;SILENT;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
+ <WarningLevel>TurnOffAllWarnings</WarningLevel>
+ <PreprocessorDefinitions>_LIB;RARDLL;SILENT;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="archive.cpp" />
+ <ClCompile Include="arcread.cpp" />
+ <ClCompile Include="cmddata.cpp" />
+ <ClCompile Include="consio.cpp" />
+ <ClCompile Include="crc.cpp" />
+ <ClCompile Include="crypt.cpp" />
+ <ClCompile Include="dll.cpp" />
+ <ClCompile Include="encname.cpp" />
+ <ClCompile Include="errhnd.cpp" />
+ <ClCompile Include="extinfo.cpp" />
+ <ClCompile Include="extract.cpp" />
+ <ClCompile Include="filcreat.cpp" />
+ <ClCompile Include="file.cpp" />
+ <ClCompile Include="filefn.cpp" />
+ <ClCompile Include="filestr.cpp" />
+ <ClCompile Include="find.cpp" />
+ <ClCompile Include="getbits.cpp" />
+ <ClCompile Include="global.cpp">
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="isnt.cpp" />
+ <ClCompile Include="list.cpp" />
+ <ClCompile Include="match.cpp" />
+ <ClCompile Include="options.cpp" />
+ <ClCompile Include="pathfn.cpp" />
+ <ClCompile Include="rar.cpp" />
+ <ClCompile Include="rarpch.cpp">
+ <PrecompiledHeader>Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="rarvm.cpp" />
+ <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="scantree.cpp" />
+ <ClCompile Include="secpassword.cpp" />
+ <ClCompile Include="sha1.cpp" />
+ <ClCompile Include="smallfn.cpp" />
+ <ClCompile Include="strfn.cpp" />
+ <ClCompile Include="strlist.cpp" />
+ <ClCompile Include="system.cpp" />
+ <ClCompile Include="timefn.cpp" />
+ <ClCompile Include="ulinks.cpp" />
+ <ClCompile Include="unicode.cpp" />
+ <ClCompile Include="unpack.cpp" />
+ <ClCompile Include="volume.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="archive.hpp" />
+ <ClInclude Include="array.hpp" />
+ <ClInclude Include="cmddata.hpp" />
+ <ClInclude Include="coder.hpp" />
+ <ClInclude Include="compress.hpp" />
+ <ClInclude Include="consio.hpp" />
+ <ClInclude Include="crc.hpp" />
+ <ClInclude Include="crypt.hpp" />
+ <ClInclude Include="dll.hpp" />
+ <ClInclude Include="encname.hpp" />
+ <ClInclude Include="errhnd.hpp" />
+ <ClInclude Include="extinfo.hpp" />
+ <ClInclude Include="extract.hpp" />
+ <ClInclude Include="filcreat.hpp" />
+ <ClInclude Include="file.hpp" />
+ <ClInclude Include="filefn.hpp" />
+ <ClInclude Include="filestr.hpp" />
+ <ClInclude Include="find.hpp" />
+ <ClInclude Include="getbits.hpp" />
+ <ClInclude Include="global.hpp" />
+ <ClInclude Include="headers.hpp" />
+ <ClInclude Include="isnt.hpp" />
+ <ClInclude Include="list.hpp" />
+ <ClInclude Include="loclang.hpp" />
+ <ClInclude Include="log.hpp" />
+ <ClInclude Include="match.hpp" />
+ <ClInclude Include="model.hpp" />
+ <ClInclude Include="options.hpp" />
+ <ClInclude Include="os.hpp" />
+ <ClInclude Include="pathfn.hpp" />
+ <ClInclude Include="rar.hpp" />
+ <ClInclude Include="rardefs.hpp" />
+ <ClInclude Include="rarlang.hpp" />
+ <ClInclude Include="raros.hpp" />
+ <ClInclude Include="rartypes.hpp" />
+ <ClInclude Include="rarvm.hpp" />
+ <ClInclude Include="rawread.hpp" />
+ <ClInclude Include="rdwrfn.hpp" />
+ <ClInclude Include="recvol.hpp" />
+ <ClInclude Include="resource.hpp" />
+ <ClInclude Include="rijndael.hpp" />
+ <ClInclude Include="rs.hpp" />
+ <ClInclude Include="savepos.hpp" />
+ <ClInclude Include="scantree.hpp" />
+ <ClInclude Include="secpassword.hpp" />
+ <ClInclude Include="sha1.hpp" />
+ <ClInclude Include="smallfn.hpp" />
+ <ClInclude Include="strfn.hpp" />
+ <ClInclude Include="strlist.hpp" />
+ <ClInclude Include="suballoc.hpp" />
+ <ClInclude Include="system.hpp" />
+ <ClInclude Include="timefn.hpp" />
+ <ClInclude Include="ulinks.hpp" />
+ <ClInclude Include="unicode.hpp" />
+ <ClInclude Include="unpack.hpp" />
+ <ClInclude Include="version.hpp" />
+ <ClInclude Include="volume.hpp" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file diff --git a/src/thirdparty/unrar/unrar.vcxproj.filters b/src/thirdparty/unrar/unrar.vcxproj.filters new file mode 100644 index 000000000..68850095e --- /dev/null +++ b/src/thirdparty/unrar/unrar.vcxproj.filters @@ -0,0 +1,323 @@ +<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="archive.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="arcread.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="cmddata.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="crc.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="encname.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="errhnd.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="extinfo.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="extract.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="filcreat.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="file.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="filefn.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="filestr.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="find.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="getbits.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="isnt.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="match.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="options.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="pathfn.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rar.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rarpch.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rarvm.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rawread.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rdwrfn.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <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">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="strlist.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="system.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="timefn.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="unicode.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="unpack.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="volume.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">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="secpassword.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="crypt.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="list.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="resource.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="rijndael.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="sha1.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dll.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="cmddata.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="coder.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="compress.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="consio.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="crc.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="crypt.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="dll.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="encname.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="errhnd.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="extinfo.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="extract.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="filcreat.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="file.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="filefn.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="filestr.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="find.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="getbits.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="global.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="headers.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="isnt.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="list.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="loclang.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="log.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="match.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="model.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="options.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="os.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="pathfn.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="rardefs.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="rarlang.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="raros.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="rartypes.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="rarvm.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="rawread.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="rdwrfn.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="recvol.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="rijndael.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="rs.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="savepos.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="scantree.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="secpassword.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="sha1.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="smallfn.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="strfn.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="strlist.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="suballoc.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="system.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="timefn.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ulinks.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="unicode.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="unpack.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="version.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="volume.hpp">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project>
\ No newline at end of file diff --git a/src/thirdparty/unrar/uowners.cpp b/src/thirdparty/unrar/uowners.cpp new file mode 100644 index 000000000..913aaef3b --- /dev/null +++ b/src/thirdparty/unrar/uowners.cpp @@ -0,0 +1,84 @@ + + +void ExtractUnixOwner(Archive &Arc,char *FileName) +{ + if (Arc.HeaderCRC!=Arc.UOHead.HeadCRC) + { + Log(Arc.FileName,St(MOwnersBroken),FileName); + ErrHandler.SetErrorCode(RARX_CRC); + return; + } + + struct passwd *pw; + 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); + ErrHandler.SysErrMsg(); + ErrHandler.SetErrorCode(RARX_WARNING); + return; + } + uid_t OwnerID=pw->pw_uid; + + struct group *gr; + 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); + ErrHandler.SysErrMsg(); + ErrHandler.SetErrorCode(RARX_CRC); + return; + } + uint Attr=GetFileAttr(FileName,NULL); + gid_t GroupID=gr->gr_gid; +#if defined(SAVE_LINKS) && !defined(_APPLE) + if (lchown(FileName,OwnerID,GroupID)!=0) +#else + if (chown(FileName,OwnerID,GroupID)!=0) +#endif + { + Log(Arc.FileName,St(MSetOwnersError),FileName); + ErrHandler.SetErrorCode(RARX_CREATE); + } + SetFileAttr(FileName,NULL,Attr); +} + + +void ExtractUnixOwnerNew(Archive &Arc,char *FileName) +{ + char *OwnerName=(char *)&Arc.SubHead.SubData[0]; + int OwnerSize=strlen(OwnerName)+1; + int GroupSize=Arc.SubHead.SubData.Size()-OwnerSize; + char GroupName[NM]; + strncpy(GroupName,(char *)&Arc.SubHead.SubData[OwnerSize],GroupSize); + GroupName[GroupSize]=0; + + struct passwd *pw; + if ((pw=getpwnam(OwnerName))==NULL) + { + Log(Arc.FileName,St(MErrGetOwnerID),OwnerName); + ErrHandler.SetErrorCode(RARX_WARNING); + return; + } + uid_t OwnerID=pw->pw_uid; + + struct group *gr; + if ((gr=getgrnam(GroupName))==NULL) + { + Log(Arc.FileName,St(MErrGetGroupID),GroupName); + ErrHandler.SetErrorCode(RARX_CRC); + return; + } + uint Attr=GetFileAttr(FileName,NULL); + gid_t GroupID=gr->gr_gid; +#if defined(SAVE_LINKS) && !defined(_APPLE) + if (lchown(FileName,OwnerID,GroupID)!=0) +#else + if (chown(FileName,OwnerID,GroupID)!=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 new file mode 100644 index 000000000..3031b3a5d --- /dev/null +++ b/src/thirdparty/unrar/version.hpp @@ -0,0 +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 diff --git a/src/thirdparty/unrar/volume.cpp b/src/thirdparty/unrar/volume.cpp new file mode 100644 index 000000000..073edb8ae --- /dev/null +++ b/src/thirdparty/unrar/volume.cpp @@ -0,0 +1,280 @@ +#include "rar.hpp" + + + + +#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) +{ + 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; + + if (DataIO!=NULL && SplitHeader && hd->UnpVer>=20 && + hd->FileCRC!=0xffffffff && DataIO->PackedCRC!=~hd->FileCRC) + { + Log(Arc.FileName,St(MDataBadCRC),hd->FileName,Arc.FileName); + } + + int64 PosBeforeClose=Arc.Tell(); + + if (DataIO!=NULL) + DataIO->ProcessedArcSize+=Arc.FileLength(); + + 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); + +#if !defined(SFX_MODULE) && !defined(RARDLL) + bool RecoveryDone=false; +#endif + bool FailedOpen=false,OldSchemeTested=false; + +#if !defined(GUI) && !defined(SILENT) + // 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)) + FailedOpen=true; +#endif + + if (!FailedOpen) + while (!Arc.Open(NextName,NextNameW,0)) + { + // We need to open a new volume which size was not calculated + // in total size before, so we cannot calculate the total progress + // anymore. Let's reset the total size to zero and stop + // the total progress. + if (DataIO!=NULL) + DataIO->TotalArcSize=0; + + if (!OldSchemeTested) + { + // 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); + OldSchemeTested=true; + if (Arc.Open(AltNextName,AltNextNameW,0)) + { + strcpy(NextName,AltNextName); + wcscpy(NextNameW,AltNextNameW); + 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) + { + // 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; + } + } + 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); + RecoveryDone=true; + continue; + } +#endif + +#ifndef GUI + if (!Cmd->VolumePause && !IsRemovable(NextName)) + { + FailedOpen=true; + break; + } +#endif +#ifndef SILENT + if (Cmd->AllYes || !AskNextVol(NextName,NextNameW)) +#endif + { + FailedOpen=true; + break; + } + +#endif // RARDLL + } + + if (FailedOpen) + { +#if !defined(SILENT) && !defined(_WIN_CE) + Log(Arc.FileName,St(MAbsNextVol),NextName); +#endif + Arc.Open(Arc.FileName,Arc.FileNameW,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); + } +#endif + + if (Command=='T' || Command=='X' || Command=='E') + mprintf(St(Command=='T' ? MTestVol:MExtrVol),Arc.FileName); + + + if (SplitHeader) + Arc.SearchBlock(HeaderType); + else + Arc.ReadHeader(); + if (Arc.GetHeaderType()==FILE_HEAD) + { + Arc.ConvertAttributes(); + Arc.Seek(Arc.NextBlockPos-Arc.NewLhd.FullPackSize,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); + if (!Cmd->DisablePercentage) + mprintf(" "); + } +#endif + if (DataIO!=NULL) + { + if (HeaderType==ENDARC_HEAD) + DataIO->UnpVolume=false; + else + { + DataIO->UnpVolume=(hd->Flags & LHD_SPLIT_AFTER)!=0; + DataIO->SetPackedSizeToRead(hd->FullPackSize); + } +#ifdef SFX_MODULE + DataIO->UnpArcSize=Arc.FileLength(); +#endif + + // Reset the size of packed data read from current volume. It is used + // to display the total progress and preceding volumes are already + // compensated with ProcessedArcSize, so we need to reset this variable. + DataIO->CurUnpRead=0; + + DataIO->PackedCRC=0xffffffff; +// DataIO->SetFiles(&Arc,NULL); + } + 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) +{ + eprintf(St(MAskNextVol),ArcName); + if (Ask(St(MContinueQuit))==2) + return(false); + return(true); +} +#endif diff --git a/src/thirdparty/unrar/volume.hpp b/src/thirdparty/unrar/volume.hpp new file mode 100644 index 000000000..22dd5bae0 --- /dev/null +++ b/src/thirdparty/unrar/volume.hpp @@ -0,0 +1,11 @@ +#ifndef _RAR_VOLUME_ +#define _RAR_VOLUME_ + +void SplitArchive(Archive &Arc,FileHeader *fh,int64 *HeaderPos, + ComprDataIO *DataIO); +bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName, + char Command); +void SetVolWrite(Archive &Dest,int64 VolSize); +bool AskNextVol(char *ArcName,wchar *ArcNameW); + +#endif diff --git a/src/thirdparty/unrar/win32acl.cpp b/src/thirdparty/unrar/win32acl.cpp new file mode 100644 index 000000000..4843ce881 --- /dev/null +++ b/src/thirdparty/unrar/win32acl.cpp @@ -0,0 +1,127 @@ +static void SetPrivileges(); + +static bool ReadSacl=false; + + + +#ifndef SFX_MODULE +void ExtractACL(Archive &Arc,char *FileName,wchar *FileNameW) +{ + if (!WinNT()) + return; + + SetPrivileges(); + + if (Arc.HeaderCRC!=Arc.EAHead.HeadCRC) + { + 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) + { + Log(Arc.FileName,St(MACLUnknown),FileName); + ErrHandler.SetErrorCode(RARX_WARNING); + 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(MACLBroken),FileName); + ErrHandler.SetErrorCode(RARX_CRC); + return; + } + + SECURITY_INFORMATION si=OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION| + DACL_SECURITY_INFORMATION; + if (ReadSacl) + 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); + + if (!SetCode) + { + Log(Arc.FileName,St(MACLSetError),FileName); + ErrHandler.SysErrMsg(); + ErrHandler.SetErrorCode(RARX_WARNING); + } +} +#endif + + +void ExtractACLNew(Archive &Arc,char *FileName,wchar *FileNameW) +{ + if (!WinNT()) + return; + + Array<byte> SubData; + if (!Arc.ReadSubData(&SubData,NULL)) + return; + + SetPrivileges(); + + SECURITY_INFORMATION si=OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION| + DACL_SECURITY_INFORMATION; + if (ReadSacl) + 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); + + if (!SetCode) + { + Log(Arc.FileName,St(MACLSetError),FileName); + ErrHandler.SysErrMsg(); + ErrHandler.SetErrorCode(RARX_WARNING); + } +} + + +void SetPrivileges() +{ + static bool InitDone=false; + if (InitDone) + return; + InitDone=true; + + HANDLE hToken; + + if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) + return; + + 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) && + GetLastError() == ERROR_SUCCESS) + ReadSacl=true; + + if (LookupPrivilegeValue(NULL,SE_RESTORE_NAME,&tp.Privileges[0].Luid)) + AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL); + + CloseHandle(hToken); +} diff --git a/src/thirdparty/unrar/win32stm.cpp b/src/thirdparty/unrar/win32stm.cpp new file mode 100644 index 000000000..3a8aea032 --- /dev/null +++ b/src/thirdparty/unrar/win32stm.cpp @@ -0,0 +1,154 @@ + + + +#ifndef SFX_MODULE +void ExtractStreams(Archive &Arc,char *FileName,wchar *FileNameW) +{ + if (!WinNT()) + return; + + if (Arc.HeaderCRC!=Arc.StreamHead.HeadCRC) + { +#ifndef SILENT + Log(Arc.FileName,St(MStreamBroken),FileName); +#endif + ErrHandler.SetErrorCode(RARX_CRC); + return; + } + + if (Arc.StreamHead.Method<0x31 || Arc.StreamHead.Method>0x35 || Arc.StreamHead.UnpVer>PACK_VER) + { +#ifndef SILENT + Log(Arc.FileName,St(MStreamUnknown),FileName); +#endif + ErrHandler.SetErrorCode(RARX_WARNING); + return; + } + + char StreamName[NM+2]; + if (FileName[0]!=0 && FileName[1]==0) + { + strcpy(StreamName,".\\"); + strcpy(StreamName+2,FileName); + } + else + strcpy(StreamName,FileName); + if (strlen(StreamName)+strlen((char *)Arc.StreamHead.StreamName)>=sizeof(StreamName) || + Arc.StreamHead.StreamName[0]!=':') + { +#ifndef SILENT + Log(Arc.FileName,St(MStreamBroken),FileName); +#endif + ErrHandler.SetErrorCode(RARX_CRC); + return; + } + + ConvertPath((char *)Arc.StreamHead.StreamName+1,(char *)Arc.StreamHead.StreamName+1); + + strcat(StreamName,(char *)Arc.StreamHead.StreamName); + + FindData fd; + bool Found=FindFile::FastFind(FileName,FileNameW,&fd); + + if (fd.FileAttr & FILE_ATTRIBUTE_READONLY) + SetFileAttr(FileName,FileNameW,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY); + + File CurFile; + if (CurFile.WCreate(StreamName)) + { + ComprDataIO DataIO; + Unpack Unpack(&DataIO); + Unpack.Init(); + + Array<unsigned char> UnpData(Arc.StreamHead.UnpSize); + DataIO.SetPackedSizeToRead(Arc.StreamHead.DataSize); + DataIO.EnableShowProgress(false); + DataIO.SetFiles(&Arc,&CurFile); + Unpack.SetDestSize(Arc.StreamHead.UnpSize); + Unpack.DoUnpack(Arc.StreamHead.UnpVer,false); + + if (Arc.StreamHead.StreamCRC!=~DataIO.UnpFileCRC) + { +#ifndef SILENT + Log(Arc.FileName,St(MStreamBroken),StreamName); +#endif + ErrHandler.SetErrorCode(RARX_CRC); + } + else + CurFile.Close(); + } + File HostFile; + if (Found && HostFile.Open(FileName,FileNameW,FMF_OPENSHARED|FMF_UPDATE)) + SetFileTime(HostFile.GetHandle(),&fd.ftCreationTime,&fd.ftLastAccessTime, + &fd.ftLastWriteTime); + if (fd.FileAttr & FILE_ATTRIBUTE_READONLY) + SetFileAttr(FileName,FileNameW,fd.FileAttr); +} +#endif + + +void ExtractStreamsNew(Archive &Arc,char *FileName,wchar *FileNameW) +{ + 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) + { + wcscpy(StreamNameW,L".\\"); + wcscpy(StreamNameW+2,NameW); + } + 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; + } + + RawToWide(SrcName,DestName,DestSize); + DestName[DestSize]=0; + + if (*DestName!=':') + { +#if !defined(SILENT) && !defined(SFX_MODULE) + Log(Arc.FileName,St(MStreamBroken),FileName); +#endif + ErrHandler.SetErrorCode(RARX_CRC); + return; + } + + ConvertPath(DestName+1,DestName+1); + + FindData fd; + bool Found=FindFile::FastFind(FileName,FileNameW,&fd); + + if (fd.FileAttr & FILE_ATTRIBUTE_READONLY) + SetFileAttr(FileName,FileNameW,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY); + char StreamName[NM]; + WideToChar(StreamNameW,StreamName); + File CurFile; + if (CurFile.WCreate(StreamName,StreamNameW) && Arc.ReadSubData(NULL,&CurFile)) + CurFile.Close(); + File HostFile; + if (Found && HostFile.Open(FileName,FileNameW,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); +} |