unrar/arccmt.cpp0100666000000000000000000000776012176732143011267 0ustar zstatic bool IsAnsiEscComment(const wchar *Data,size_t Size); bool Archive::GetComment(Array *CmtData) { if (!MainComment) return false; SaveFilePos SavePos(*this); #ifndef SFX_MODULE ushort CmtLength; if (Format==RARFMT14) { Seek(SFXSize+SIZEOF_MAINHEAD14,SEEK_SET); CmtLength=GetByte(); CmtLength+=(GetByte()<<8); } else #endif { if (MainHead.CommentInHeader) { // Old style (RAR 2.9) archive comment embedded into the main // archive header. Seek(SFXSize+SIZEOF_MARKHEAD3+SIZEOF_MAINHEAD3,SEEK_SET); ReadHeader(); } else { // Current (RAR 3.0+) version of archive comment. Seek(GetStartPos(),SEEK_SET); return(SearchSubBlock(SUBHEAD_TYPE_CMT)!=0 && ReadCommentData(CmtData)); } #ifndef SFX_MODULE // Old style (RAR 2.9) comment header embedded into the main // archive header. if (BrokenHeader) { Log(FileName,St(MLogCommHead)); return false; } CmtLength=CommHead.HeadSize-SIZEOF_COMMHEAD; #endif } #ifndef SFX_MODULE if (Format==RARFMT14 && MainHead.PackComment || Format!=RARFMT14 && CommHead.Method!=0x30) { if (Format!=RARFMT14 && (CommHead.UnpVer < 15 || CommHead.UnpVer > VER_UNPACK || CommHead.Method > 0x35)) return(false); ComprDataIO DataIO; DataIO.SetTestMode(true); uint UnpCmtLength; if (Format==RARFMT14) { #ifdef RAR_NOCRYPT return(false); #else UnpCmtLength=GetByte(); UnpCmtLength+=(GetByte()<<8); CmtLength-=2; DataIO.SetCmt13Encryption(); CommHead.UnpVer=15; #endif } else UnpCmtLength=CommHead.UnpSize; DataIO.SetFiles(this,NULL); DataIO.EnableShowProgress(false); DataIO.SetPackedSizeToRead(CmtLength); DataIO.UnpHash.Init(HASH_CRC32,1); Unpack CmtUnpack(&DataIO); CmtUnpack.Init(0x10000,false); CmtUnpack.SetDestSize(UnpCmtLength); CmtUnpack.DoUnpack(CommHead.UnpVer,false); if (Format!=RARFMT14 && (DataIO.UnpHash.GetCRC32()&0xffff)!=CommHead.CommCRC) { Log(FileName,St(MLogCommBrk)); return false; } else { byte *UnpData; size_t UnpDataSize; DataIO.GetUnpackedData(&UnpData,&UnpDataSize); #ifdef _WIN_ALL OemToCharBuffA((char *)UnpData,(char *)UnpData,(DWORD)UnpDataSize); #endif CmtData->Alloc(UnpDataSize+1); memset(CmtData->Addr(0),0,CmtData->Size()*sizeof(wchar)); CharToWide((char *)UnpData,CmtData->Addr(0),UnpDataSize); CmtData->Alloc(wcslen(CmtData->Addr(0))); } } else { Array CmtRaw(CmtLength); Read(&CmtRaw[0],CmtLength); if (Format!=RARFMT14 && CommHead.CommCRC!=(~CRC32(0xffffffff,&CmtRaw[0],CmtLength)&0xffff)) { Log(FileName,St(MLogCommBrk)); return false; } CmtData->Alloc(CmtLength+1); CmtRaw.Push(0); #ifdef _WIN_ALL OemToCharA((char *)&CmtRaw[0],(char *)&CmtRaw[0]); #endif CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtLength); CmtData->Alloc(wcslen(CmtData->Addr(0))); } #endif return CmtData->Size() > 0; } bool Archive::ReadCommentData(Array *CmtData) { Array CmtRaw; if (!ReadSubData(&CmtRaw,NULL)) return false; size_t CmtSize=CmtRaw.Size(); CmtRaw.Push(0); CmtData->Alloc(CmtSize+1); if (Format==RARFMT50) UtfToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size()); else if ((SubHead.SubFlags & SUBHEAD_FLAGS_CMT_UNICODE)!=0) { RawToWide(&CmtRaw[0],CmtData->Addr(0),CmtSize/2); (*CmtData)[CmtSize/2]=0; } else { CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size()); } CmtData->Alloc(wcslen(CmtData->Addr(0))); // Set buffer size to actual comment length. return true; } void Archive::ViewComment() { #ifndef GUI if (Cmd->DisableComment) return; Array CmtBuf; if (GetComment(&CmtBuf)) { size_t CmtSize=CmtBuf.Size(); wchar *ChPtr=wcschr(&CmtBuf[0],0x1A); if (ChPtr!=NULL) CmtSize=ChPtr-&CmtBuf[0]; mprintf(L"\n"); OutComment(&CmtBuf[0],CmtSize); } #endif } unrar/archive.cpp0100666000000000000000000001645412176732143011437 0ustar z#include "rar.hpp" #ifndef SHELL_EXT #include "arccmt.cpp" #endif Archive::Archive(RAROptions *InitCmd) { Cmd=NULL; // Just in case we'll have an exception in 'new' below. DummyCmd=(InitCmd==NULL); Cmd=DummyCmd ? (new RAROptions):InitCmd; OpenShared=Cmd->OpenShared; Format=RARFMT15; Solid=false; Volume=false; MainComment=false; Locked=false; Signed=false; FirstVolume=false; NewNumbering=false; SFXSize=0; LatestTime.Reset(); Protected=false; Encrypted=false; FailedHeaderDecryption=false; BrokenHeader=false; LastReadBlock=0; CurBlockPos=0; NextBlockPos=0; RecoverySize=-1; RecoveryPercent=-1; memset(&MainHead,0,sizeof(MainHead)); memset(&CryptHead,0,sizeof(CryptHead)); memset(&EndArcHead,0,sizeof(EndArcHead)); VolNumber=0; VolWrite=0; AddingFilesSize=0; AddingHeadersSize=0; *FirstVolumeName=0; Splitting=false; NewArchive=false; SilentOpen=false; } Archive::~Archive() { if (DummyCmd) delete Cmd; } #ifndef SHELL_EXT void Archive::CheckArc(bool EnableBroken) { if (!IsArchive(EnableBroken)) { // If FailedHeaderDecryption is set, we already reported that archive // password is incorrect. if (!FailedHeaderDecryption) { Log(FileName,St(MBadArc),FileName); } ErrHandler.Exit(RARX_FATAL); } } #endif #if !defined(SHELL_EXT) && !defined(SFX_MODULE) void Archive::CheckOpen(const wchar *Name) { TOpen(Name); CheckArc(false); } #endif bool Archive::WCheckOpen(const wchar *Name) { if (!WOpen(Name)) return false; if (!IsArchive(false)) { #ifndef SHELL_EXT Log(FileName,St(MNotRAR),FileName); #endif Close(); return false; } return true; } RARFORMAT Archive::IsSignature(const byte *D,size_t Size) { RARFORMAT Type=RARFMT_NONE; if (Size>=1 && D[0]==0x52) #ifndef SFX_MODULE if (Size>=4 && D[1]==0x45 && D[2]==0x7e && D[3]==0x5e) Type=RARFMT14; 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. if (D[6]==0) Type=RARFMT15; else if (D[6]==1) Type=RARFMT50; else if (D[6]==2) Type=RARFMT_FUTURE; } return Type; } bool Archive::IsArchive(bool EnableBroken) { Encrypted=false; #ifdef USE_QOPEN QOpen.Unload(); #endif // Important if we reuse Archive object and it has virtual QOpen // file position not matching real. For example, for 'l -v volname'. Seek(0,SEEK_SET); #ifndef SFX_MODULE if (IsDevice()) { #ifndef SHELL_EXT Log(FileName,St(MInvalidName),FileName); #endif return false; } #endif if (Read(MarkHead.Mark,SIZEOF_MARKHEAD3)!=SIZEOF_MARKHEAD3) return(false); SFXSize=0; RARFORMAT Type; if ((Type=IsSignature(MarkHead.Mark,SIZEOF_MARKHEAD3))!=RARFMT_NONE) { Format=Type; if (Format==RARFMT14) Seek(0,SEEK_SET); } else { Array Buffer(MAXSFXSIZE); long CurPos=(long)Tell(); int ReadSize=Read(&Buffer[0],Buffer.Size()-16); for (int I=0;I0 && 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 (Format==RARFMT15 || Format==RARFMT50) Read(MarkHead.Mark,SIZEOF_MARKHEAD3); break; } if (SFXSize==0) return false; } if (Format==RARFMT_FUTURE) { #if !defined(SHELL_EXT) && !defined(SFX_MODULE) Log(FileName,St(MNewRarFormat)); #endif return false; } if (Format==RARFMT50) // RAR 5.0 signature is by one byte longer. { Read(MarkHead.Mark+SIZEOF_MARKHEAD3,1); if (MarkHead.Mark[SIZEOF_MARKHEAD3]!=0) return false; MarkHead.HeadSize=SIZEOF_MARKHEAD5; } else MarkHead.HeadSize=SIZEOF_MARKHEAD3; // Skip the archive encryption header if any and read the main header. while (ReadHeader()!=0 && GetHeaderType()!=HEAD_MAIN) SeekToNext(); // This check allows to make RS based recovery even if password is incorrect. // But we should not do it for EnableBroken or we'll get 'not RAR archive' // messages when extracting encrypted archives with wrong password. if (FailedHeaderDecryption && !EnableBroken) return false; SeekToNext(); if (BrokenHeader) { #ifndef SHELL_EXT Log(FileName,St(MMainHeaderBroken)); #endif if (!EnableBroken) return false; } /* if (MainHead.EncryptVer>VER_UNPACK) { #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),MainHead.EncryptVer/10,MainHead.EncryptVer%10); #endif #endif return(false); } */ #ifdef RARDLL // If callback function is not set, we cannot get the password, // so we skip the initial header processing for encrypted header archive. // It leads to skipped archive comment, but the rest of archive data // is processed correctly. if (Cmd->Callback==NULL) SilentOpen=true; #endif MainComment=MainHead.CommentInHeader; #ifdef USE_QOPEN if (MainHead.Locator && MainHead.QOpenOffset>0 && Cmd->QOpenMode!=QOPEN_NONE) { QOpen.Init(this,false); QOpen.Load(MainHead.QOpenOffset); } #endif // If we process non-encrypted archive or can request a password, // we set 'first volume' flag based on file attributes below. // It is necessary for RAR 2.x archives, which did not have 'first volume' // flag in main header. if (!SilentOpen || !Encrypted) { SaveFilePos SavePos(*this); int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos; while (ReadHeader()!=0) { HEADER_TYPE HeaderType=GetHeaderType(); if (HeaderType==HEAD_SERVICE) { if (SubHead.CmpName(SUBHEAD_TYPE_CMT)) MainComment=true; FirstVolume=!SubHead.SplitBefore; } else { FirstVolume=HeaderType==HEAD_FILE && !FileHead.SplitBefore; break; } SeekToNext(); } CurBlockPos=SaveCurBlockPos; NextBlockPos=SaveNextBlockPos; } if (!Volume || FirstVolume) wcscpy(FirstVolumeName,FileName); return true; } void Archive::SeekToNext() { Seek(NextBlockPos,SEEK_SET); } // Calculate the block size including encryption fields and padding if any. uint Archive::FullHeaderSize(size_t Size) { if (Encrypted) { Size = ALIGN_VALUE(Size, CRYPT_BLOCK_SIZE); // Align to encryption block size. if (Format == RARFMT50) Size += SIZE_INITV; else Size += SIZE_SALT30; } return uint(Size); } #ifdef USE_QOPEN int Archive::Read(void *Data,size_t Size) { size_t Result; if (QOpen.Read(Data,Size,Result)) return (int)Result; return File::Read(Data,Size); } void Archive::Seek(int64 Offset,int Method) { if (!QOpen.Seek(Offset,Method)) File::Seek(Offset,Method); } int64 Archive::Tell() { int64 QPos; if (QOpen.Tell(&QPos)) return QPos; return File::Tell(); } #endif unrar/arcread.cpp0100666000000000000000000011704512176732144011416 0ustar z#include "rar.hpp" size_t Archive::ReadHeader() { // Once we failed to decrypt an encrypted block, there is no reason to // attempt to do it further. We'll never be successful and only generate // endless errors. if (FailedHeaderDecryption) return 0; CurBlockPos=Tell(); size_t ReadSize; switch(Format) { #ifndef SFX_MODULE case RARFMT14: ReadSize=ReadHeader14(); break; #endif case RARFMT15: ReadSize=ReadHeader15(); break; case RARFMT50: ReadSize=ReadHeader50(); break; } if (ReadSize>0 && NextBlockPos<=CurBlockPos) { BrokenHeaderMsg(); return 0; } return ReadSize; } size_t Archive::SearchBlock(HEADER_TYPE HeaderType) { size_t Size,Count=0; while ((Size=ReadHeader())!=0 && (HeaderType==HEAD_ENDARC || GetHeaderType()!=HEAD_ENDARC)) { if ((++Count & 127)==0) Wait(); if (GetHeaderType()==HeaderType) return(Size); SeekToNext(); } return(0); } size_t Archive::SearchSubBlock(const wchar *Type) { size_t Size; while ((Size=ReadHeader())!=0 && GetHeaderType()!=HEAD_ENDARC) { if (GetHeaderType()==HEAD_SERVICE && SubHead.CmpName(Type)) return Size; SeekToNext(); } return 0; } size_t Archive::SearchRR() { // If locator extra field is available for recovery record, let's utilize it. if (MainHead.Locator && MainHead.RROffset!=0) { uint64 CurPos=Tell(); Seek(MainHead.RROffset,SEEK_SET); size_t Size=ReadHeader(); if (Size!=0 && !BrokenHeader && GetHeaderType()==HEAD_SERVICE && SubHead.CmpName(SUBHEAD_TYPE_RR)) return Size; Seek(CurPos,SEEK_SET); } // Otherwise scan the entire archive to find the recovery record. return SearchSubBlock(SUBHEAD_TYPE_RR); } void Archive::UnexpEndArcMsg() { int64 ArcSize=FileLength(); // If block positions are equal to file size, this is not an error. // It can happen when we reached the end of older RAR 1.5 archive, // which did not have the end of archive block. if (CurBlockPos>ArcSize || NextBlockPos>ArcSize) { #ifndef SHELL_EXT Log(FileName,St(MLogUnexpEOF)); #endif ErrHandler.SetErrorCode(RARX_WARNING); } } void Archive::BrokenHeaderMsg() { #ifndef SHELL_EXT Log(FileName,St(MHeaderBroken)); #endif BrokenHeader=true; ErrHandler.SetErrorCode(RARX_CRC); } void Archive::UnkEncVerMsg(const wchar *Name) { #ifndef SHELL_EXT Log(FileName,St(MUnkEncMethod),Name); #endif ErrHandler.SetErrorCode(RARX_WARNING); } size_t Archive::ReadHeader15() { RawRead Raw(this); bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD3; if (Decrypt) { #ifdef RAR_NOCRYPT // For rarext.dll and unrar_nocrypt.dll. return 0; #else RequestArcPassword(); byte Salt[SIZE_SALT30]; if (Read(Salt,SIZE_SALT30)!=SIZE_SALT30) { UnexpEndArcMsg(); return(0); } HeadersCrypt.SetCryptKeys(false,CRYPT_RAR30,&Cmd->Password,Salt,NULL,0,NULL,NULL); Raw.SetCrypt(&HeadersCrypt); #endif } Raw.Read(SIZEOF_SHORTBLOCKHEAD); if (Raw.Size()==0) { UnexpEndArcMsg(); return 0; } ShortBlock.HeadCRC=Raw.Get2(); ShortBlock.Reset(); uint HeaderType=Raw.Get1(); ShortBlock.Flags=Raw.Get2(); ShortBlock.SkipIfUnknown=(ShortBlock.Flags & SKIP_IF_UNKNOWN)!=0; ShortBlock.HeadSize=Raw.Get2(); ShortBlock.HeaderType=(HEADER_TYPE)HeaderType; if (ShortBlock.HeadSizeReset(); *(BaseBlock *)hd=ShortBlock; hd->SplitBefore=(hd->Flags & LHD_SPLIT_BEFORE)!=0; hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0; hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0; hd->SaltSet=(hd->Flags & LHD_SALT)!=0; hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0; hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0; hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY; hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5); hd->CommentInHeader=(hd->Flags & LHD_COMMENT)!=0; hd->Version=(hd->Flags & LHD_VERSION)!=0; hd->DataSize=Raw.Get4(); uint LowUnpSize=Raw.Get4(); hd->HostOS=Raw.Get1(); hd->FileHash.Type=HASH_CRC32; hd->FileHash.CRC32=Raw.Get4(); uint FileTime=Raw.Get4(); hd->UnpVer=Raw.Get1(); hd->Method=Raw.Get1()-0x30; size_t NameSize=Raw.Get2(); hd->FileAttr=Raw.Get4(); hd->CryptMethod=CRYPT_NONE; if (hd->Encrypted) switch(hd->UnpVer) { case 13: hd->CryptMethod=CRYPT_RAR13; break; case 15: hd->CryptMethod=CRYPT_RAR15; break; case 20: case 26: hd->CryptMethod=CRYPT_RAR20; break; default: hd->CryptMethod=CRYPT_RAR30; break; } hd->HSType=HSYS_UNKNOWN; if (hd->HostOS==HOST_UNIX || hd->HostOS==HOST_BEOS) hd->HSType=HSYS_UNIX; else if (hd->HostOSHSType=HSYS_WINDOWS; hd->RedirType=FSREDIR_NONE; // RAR 4.x Unix symlink. if (hd->HostOS==HOST_UNIX && (hd->FileAttr & 0xF000)==0xA000) { hd->RedirType=FSREDIR_UNIXSYMLINK; *hd->RedirName=0; } hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0; hd->LargeFile=(hd->Flags & LHD_LARGE)!=0; uint HighPackSize,HighUnpSize; if (hd->LargeFile) { HighPackSize=Raw.Get4(); HighUnpSize=Raw.Get4(); hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff); } else { HighPackSize=HighUnpSize=0; // UnpSize equal to 0xffffffff without LHD_LARGE flag indicates // that we do not know the unpacked file size and must unpack it // until we find the end of file marker in compressed data. hd->UnknownUnpSize=(LowUnpSize==0xffffffff); } hd->PackSize=INT32TO64(HighPackSize,hd->DataSize); hd->UnpSize=INT32TO64(HighUnpSize,LowUnpSize); if (hd->UnknownUnpSize) hd->UnpSize=INT64NDF; char FileName[NM*4]; size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1); Raw.GetB((byte *)FileName,ReadNameSize); FileName[ReadNameSize]=0; if (FileBlock) { if ((hd->Flags & LHD_UNICODE)!=0) { EncodeFileName NameCoder; size_t Length=strlen(FileName); if (Length==NameSize) UtfToWide(FileName,hd->FileName,ASIZE(hd->FileName)-1); else { Length++; NameCoder.Decode(FileName,(byte *)FileName+Length, NameSize-Length,hd->FileName, ASIZE(hd->FileName)); } } else *hd->FileName=0; char AnsiName[NM]; IntToExt(FileName,AnsiName,ASIZE(AnsiName)); GetWideName(AnsiName,hd->FileName,hd->FileName,ASIZE(hd->FileName)); #ifndef SFX_MODULE ConvertNameCase(hd->FileName); #endif ConvertFileHeader(hd); } else { CharToWide(FileName,hd->FileName,ASIZE(hd->FileName)); // Calculate the size of optional data. int DataSize=int(hd->HeadSize-NameSize-SIZEOF_FILEHEAD3); if ((hd->Flags & LHD_SALT)!=0) DataSize-=SIZE_SALT30; if (DataSize>0) { // Here we read optional additional fields for subheaders. // They are stored after the file name and before salt. hd->SubData.Alloc(DataSize); Raw.GetB(&hd->SubData[0],DataSize); if (hd->CmpName(SUBHEAD_TYPE_RR)) { byte *D=&hd->SubData[8]; RecoverySize=D[0]+((uint)D[1]<<8)+((uint)D[2]<<16)+((uint)D[3]<<24); RecoverySize*=512; // Sectors to size. int64 CurPos=Tell(); RecoveryPercent=ToPercent(RecoverySize,CurPos); // Round fractional percent exceeding .5 to upper value. if (ToPercent(RecoverySize+CurPos/200,CurPos)>RecoveryPercent) RecoveryPercent++; } } } if ((hd->Flags & LHD_SALT)!=0) Raw.GetB(hd->Salt,SIZE_SALT30); hd->mtime.SetDos(FileTime); if ((hd->Flags & LHD_EXTTIME)!=0) { ushort Flags=Raw.Get2(); RarTime *tbl[4]; tbl[0]=&FileHead.mtime; tbl[1]=&FileHead.ctime; tbl[2]=&FileHead.atime; tbl[3]=NULL; // Archive time is not used now. for (int I=0;I<4;I++) { RarTime *CurTime=tbl[I]; uint rmode=Flags>>(3-I)*4; if ((rmode & 8)==0 || CurTime==NULL) continue; if (I!=0) { uint DosTime=Raw.Get4(); CurTime->SetDos(DosTime); } RarLocalTime rlt; CurTime->GetLocal(&rlt); if (rmode & 4) rlt.Second++; rlt.Reminder=0; int count=rmode&3; for (int J=0;JSetLocal(&rlt); } } NextBlockPos+=hd->PackSize; bool CRCProcessedOnly=hd->CommentInHeader; ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly); if (hd->HeadCRC!=HeaderCRC) { BrokenHeader=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. if (!Decrypt) { #ifndef SHELL_EXT Log(Archive::FileName,St(MLogFileHead),hd->FileName); #endif } } } break; case HEAD_ENDARC: *(BaseBlock *)&EndArcHead=ShortBlock; EndArcHead.NextVolume=(EndArcHead.Flags & EARC_NEXT_VOLUME)!=0; EndArcHead.DataCRC=(EndArcHead.Flags & EARC_DATACRC)!=0; EndArcHead.RevSpace=(EndArcHead.Flags & EARC_REVSPACE)!=0; EndArcHead.StoreVolNumber=(EndArcHead.Flags & EARC_VOLNUMBER)!=0; if (EndArcHead.DataCRC) EndArcHead.ArcDataCRC=Raw.Get4(); if (EndArcHead.StoreVolNumber) VolNumber=EndArcHead.VolNumber=Raw.Get2(); break; #ifndef SFX_MODULE case HEAD3_CMT: *(BaseBlock *)&CommHead=ShortBlock; CommHead.UnpSize=Raw.Get2(); CommHead.UnpVer=Raw.Get1(); CommHead.Method=Raw.Get1(); CommHead.CommCRC=Raw.Get2(); break; case HEAD3_SIGN: *(BaseBlock *)&SignHead=ShortBlock; SignHead.CreationTime=Raw.Get4(); SignHead.ArcNameSize=Raw.Get2(); SignHead.UserNameSize=Raw.Get2(); break; case HEAD3_AV: *(BaseBlock *)&AVHead=ShortBlock; AVHead.UnpVer=Raw.Get1(); AVHead.Method=Raw.Get1(); AVHead.AVVer=Raw.Get1(); AVHead.AVInfoCRC=Raw.Get4(); break; case HEAD3_PROTECT: *(BaseBlock *)&ProtectHead=ShortBlock; ProtectHead.DataSize=Raw.Get4(); ProtectHead.Version=Raw.Get1(); ProtectHead.RecSectors=Raw.Get2(); ProtectHead.TotalBlocks=Raw.Get4(); Raw.GetB(ProtectHead.Mark,8); NextBlockPos+=ProtectHead.DataSize; RecoverySize=ProtectHead.RecSectors*512; break; case HEAD3_OLDSERVICE: *(BaseBlock *)&SubBlockHead=ShortBlock; SubBlockHead.DataSize=Raw.Get4(); NextBlockPos+=SubBlockHead.DataSize; SubBlockHead.SubType=Raw.Get2(); SubBlockHead.Level=Raw.Get1(); switch(SubBlockHead.SubType) { case UO_HEAD: *(SubBlockHeader *)&UOHead=SubBlockHead; UOHead.OwnerNameSize=Raw.Get2(); UOHead.GroupNameSize=Raw.Get2(); if (UOHead.OwnerNameSize>=ASIZE(UOHead.OwnerName)) UOHead.OwnerNameSize=ASIZE(UOHead.OwnerName)-1; if (UOHead.GroupNameSize>=ASIZE(UOHead.GroupName)) UOHead.GroupNameSize=ASIZE(UOHead.GroupName)-1; Raw.GetB(UOHead.OwnerName,UOHead.OwnerNameSize); Raw.GetB(UOHead.GroupName,UOHead.GroupNameSize); UOHead.OwnerName[UOHead.OwnerNameSize]=0; UOHead.GroupName[UOHead.GroupNameSize]=0; break; case MAC_HEAD: *(SubBlockHeader *)&MACHead=SubBlockHead; MACHead.fileType=Raw.Get4(); MACHead.fileCreator=Raw.Get4(); break; case EA_HEAD: case BEEA_HEAD: case NTACL_HEAD: *(SubBlockHeader *)&EAHead=SubBlockHead; EAHead.UnpSize=Raw.Get4(); EAHead.UnpVer=Raw.Get1(); EAHead.Method=Raw.Get1(); EAHead.EACRC=Raw.Get4(); break; case STREAM_HEAD: *(SubBlockHeader *)&StreamHead=SubBlockHead; StreamHead.UnpSize=Raw.Get4(); StreamHead.UnpVer=Raw.Get1(); StreamHead.Method=Raw.Get1(); StreamHead.StreamCRC=Raw.Get4(); StreamHead.StreamNameSize=Raw.Get2(); if (StreamHead.StreamNameSize>=ASIZE(StreamHead.StreamName)) StreamHead.StreamNameSize=ASIZE(StreamHead.StreamName)-1; Raw.GetB(StreamHead.StreamName,StreamHead.StreamNameSize); StreamHead.StreamName[StreamHead.StreamNameSize]=0; break; } break; #endif default: if (ShortBlock.Flags & LONG_BLOCK) NextBlockPos+=Raw.Get4(); break; } ushort HeaderCRC=Raw.GetCRC15(false); // Old AV header does not have header CRC properly set. if (ShortBlock.HeadCRC!=HeaderCRC && ShortBlock.HeaderType!=HEAD3_SIGN && ShortBlock.HeaderType!=HEAD3_AV) { bool Recovered=false; if (ShortBlock.HeaderType==HEAD_ENDARC && EndArcHead.RevSpace) { // Last 7 bytes of recovered volume can contain zeroes, because // REV files store its own information (volume number, etc.) here. SaveFilePos SavePos(*this); int64 Length=Tell(); Seek(Length-7,SEEK_SET); Recovered=true; for (int J=0;J<7;J++) if (GetByte()!=0) Recovered=false; } if (!Recovered) { BrokenHeader=true; ErrHandler.SetErrorCode(RARX_CRC); if (Decrypt) { #ifndef SILENT Log(FileName,St(MEncrBadCRC),FileName); #endif FailedHeaderDecryption=true; return 0; } } } if (NextBlockPos<=CurBlockPos) { BrokenHeaderMsg(); return 0; } return Raw.Size(); } size_t Archive::ReadHeader50() { RawRead Raw(this); bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD5; if (Decrypt) { #if defined(SHELL_EXT) || defined(RAR_NOCRYPT) return(0); #else RequestArcPassword(); byte HeadersInitV[SIZE_INITV]; if (Read(HeadersInitV,SIZE_INITV)!=SIZE_INITV) { UnexpEndArcMsg(); return(0); } byte PswCheck[SIZE_PSWCHECK]; HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck); // Verify password validity. if (CryptHead.UsePswCheck && memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0) { Log(FileName,St(MWrongPassword)); FailedHeaderDecryption=true; ErrHandler.SetErrorCode(RARX_BADPWD); return 0; } Raw.SetCrypt(&HeadersCrypt); #endif } // Header size must not occupy more than 3 variable length integer bytes // resulting in 2 MB maximum header size, so here we read 4 byte CRC32 // followed by 3 bytes or less of header size. const size_t FirstReadSize=7; Raw.Read(FirstReadSize); ShortBlock.Reset(); ShortBlock.HeadCRC=Raw.Get4(); uint SizeBytes=Raw.GetVSize(4); uint64 BlockSize=Raw.GetV(); if (BlockSize==0 || SizeBytes==0) { UnexpEndArcMsg(); // Incomplete or broken block size field. return 0; } int SizeToRead=int(BlockSize); SizeToRead-=FirstReadSize-SizeBytes-4; // Adjust overread size bytes if any. uint HeaderSize=4+SizeBytes+(uint)BlockSize; if (SizeToRead<0 || HeaderSize=ShortBlock.HeadSize) { BrokenHeaderMsg(); return 0; } } uint64 DataSize=0; if ((ShortBlock.Flags & HFL_DATA)!=0) DataSize=Raw.GetV(); NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize)+DataSize; switch(ShortBlock.HeaderType) { case HEAD_CRYPT: { *(BaseBlock *)&CryptHead=ShortBlock; uint CryptVersion=(uint)Raw.GetV(); if (CryptVersion>CRYPT_VERSION) { UnkEncVerMsg(FileName); return 0; } uint EncFlags=(uint)Raw.GetV(); CryptHead.UsePswCheck=(EncFlags & CHFL_CRYPT_PSWCHECK)!=0; CryptHead.Lg2Count=Raw.Get1(); if (CryptHead.Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX) { UnkEncVerMsg(FileName); return 0; } Raw.GetB(CryptHead.Salt,SIZE_SALT50); if (CryptHead.UsePswCheck) { Raw.GetB(CryptHead.PswCheck,SIZE_PSWCHECK); byte csum[SIZE_PSWCHECK_CSUM]; Raw.GetB(csum,SIZE_PSWCHECK_CSUM); sha256_context ctx; sha256_init(&ctx); sha256_process(&ctx, CryptHead.PswCheck, SIZE_PSWCHECK); byte Digest[SHA256_DIGEST_SIZE]; sha256_done(&ctx, Digest); CryptHead.UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0; } Encrypted=true; } break; case HEAD_MAIN: { MainHead.Reset(); *(BaseBlock *)&MainHead=ShortBlock; uint ArcFlags=(uint)Raw.GetV(); Volume=(ArcFlags & MHFL_VOLUME)!=0; Solid=(ArcFlags & MHFL_SOLID)!=0; Locked=(ArcFlags & MHFL_LOCK)!=0; Protected=(ArcFlags & MHFL_PROTECT)!=0; Signed=false; NewNumbering=true; if ((ArcFlags & MHFL_VOLNUMBER)!=0) VolNumber=(uint)Raw.GetV(); else VolNumber=0; FirstVolume=Volume && VolNumber==0; if (ExtraSize!=0) ProcessExtra50(&Raw,(size_t)ExtraSize,&MainHead); } break; case HEAD_FILE: case HEAD_SERVICE: { FileHeader *hd=ShortBlock.HeaderType==HEAD_FILE ? &FileHead:&SubHead; hd->Reset(); *(BaseBlock *)hd=ShortBlock; bool FileBlock=ShortBlock.HeaderType==HEAD_FILE; hd->LargeFile=true; hd->PackSize=DataSize; hd->FileFlags=(uint)Raw.GetV(); hd->UnpSize=Raw.GetV(); hd->UnknownUnpSize=(hd->FileFlags & FHFL_UNPUNKNOWN)!=0; if (hd->UnknownUnpSize) hd->UnpSize=INT64NDF; hd->MaxSize=Max(hd->PackSize,hd->UnpSize); hd->FileAttr=(uint)Raw.GetV(); if ((hd->FileFlags & FHFL_UTIME)!=0) hd->mtime=(time_t)Raw.Get4(); hd->FileHash.Type=HASH_NONE; if ((hd->FileFlags & FHFL_CRC32)!=0) { hd->FileHash.Type=HASH_CRC32; hd->FileHash.CRC32=Raw.Get4(); } hd->RedirType=FSREDIR_NONE; uint CompInfo=(uint)Raw.GetV(); hd->Method=(CompInfo>>7) & 7; hd->UnpVer=CompInfo & 0x3f; hd->HostOS=(byte)Raw.GetV(); size_t NameSize=(size_t)Raw.GetV(); hd->Inherited=(ShortBlock.Flags & HFL_INHERITED)!=0; hd->HSType=HSYS_UNKNOWN; if (hd->HostOS==HOST5_UNIX) hd->HSType=HSYS_UNIX; else if (hd->HostOS==HOST5_WINDOWS) hd->HSType=HSYS_WINDOWS; hd->SplitBefore=(hd->Flags & HFL_SPLITBEFORE)!=0; hd->SplitAfter=(hd->Flags & HFL_SPLITAFTER)!=0; hd->SubBlock=(hd->Flags & HFL_CHILD)!=0; hd->Solid=FileBlock && (CompInfo & FCI_SOLID)!=0; hd->Dir=(hd->FileFlags & FHFL_DIRECTORY)!=0; hd->WinSize=hd->Dir ? 0:size_t(0x20000)<<((CompInfo>>10)&0xf); hd->CryptMethod=hd->Encrypted ? CRYPT_RAR50:CRYPT_NONE; char FileName[NM*4]; size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1); Raw.GetB((byte *)FileName,ReadNameSize); FileName[ReadNameSize]=0; UtfToWide(FileName,hd->FileName,ASIZE(hd->FileName)-1); // Should do it before converting names, because extra fields can // affect name processing, like in case of NTFS streams. if (ExtraSize!=0) ProcessExtra50(&Raw,(size_t)ExtraSize,hd); if (FileBlock) { #ifndef SFX_MODULE ConvertNameCase(hd->FileName); #endif ConvertFileHeader(hd); } if (BadCRC) { // Add the file name to broken header message displayed above. #ifndef SHELL_EXT Log(Archive::FileName,St(MLogFileHead),hd->FileName); #endif } } break; case HEAD_ENDARC: { *(BaseBlock *)&EndArcHead=ShortBlock; uint ArcFlags=(uint)Raw.GetV(); EndArcHead.NextVolume=(ArcFlags & EHFL_NEXTVOLUME)!=0; EndArcHead.StoreVolNumber=false; EndArcHead.DataCRC=false; EndArcHead.RevSpace=false; } break; } if (NextBlockPos<=CurBlockPos) { BrokenHeaderMsg(); return 0; } return Raw.Size(); } #if !defined(SHELL_EXT) && !defined(RAR_NOCRYPT) void Archive::RequestArcPassword() { if (!Cmd->Password.IsSet()) { #ifdef RARDLL if (Cmd->Callback!=NULL) { wchar PasswordW[MAXPASSWORD]; *PasswordW=0; if (Cmd->Callback(UCM_NEEDPASSWORDW,Cmd->UserData,(LPARAM)PasswordW,ASIZE(PasswordW))==-1) *PasswordW=0; if (*PasswordW==0) { char PasswordA[MAXPASSWORD]; *PasswordA=0; if (Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1) *PasswordA=0; GetWideName(PasswordA,NULL,PasswordW,ASIZE(PasswordW)); cleandata(PasswordA,sizeof(PasswordA)); } Cmd->Password.Set(PasswordW); cleandata(PasswordW,sizeof(PasswordW)); } if (!Cmd->Password.IsSet()) { Close(); Cmd->DllError=ERAR_MISSING_PASSWORD; ErrHandler.Exit(RARX_USERBREAK); } #else if (!GetPassword(PASSWORD_ARCHIVE,FileName,&Cmd->Password)) { Close(); ErrHandler.Exit(RARX_USERBREAK); } #endif } } #endif void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb) { // Read extra data from the end of block skipping any fields before it. size_t ExtraStart=Raw->Size()-ExtraSize; if (ExtraStartGetPos()) return; Raw->SetPos(ExtraStart); while (Raw->DataLeft()>=2) { int64 FieldSize=Raw->GetV(); if (FieldSize==0 || Raw->DataLeft()==0 || FieldSize>(int64)Raw->DataLeft()) break; size_t NextPos=size_t(Raw->GetPos()+FieldSize); uint64 FieldType=Raw->GetV(); FieldSize=Raw->DataLeft(); // Field size without size and type fields. if (bb->HeaderType==HEAD_MAIN) { MainHeader *hd=(MainHeader *)bb; if (FieldType==MHEXTRA_LOCATOR) { hd->Locator=true; uint Flags=(uint)Raw->GetV(); if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0) { uint64 Offset=Raw->GetV(); if (Offset!=0) // 0 means that reserved space was not enough to write the offset. hd->QOpenOffset=Offset+CurBlockPos; } if ((Flags & MHEXTRA_LOCATOR_RR)!=0) { uint64 Offset=Raw->GetV(); if (Offset!=0) // 0 means that reserved space was not enough to write the offset. hd->RROffset=Offset+CurBlockPos; } } } if (bb->HeaderType==HEAD_FILE || bb->HeaderType==HEAD_SERVICE) { FileHeader *hd=(FileHeader *)bb; switch(FieldType) { case FHEXTRA_CRYPT: { FileHeader *hd=(FileHeader *)bb; uint EncVersion=(uint)Raw->GetV(); if (EncVersion > CRYPT_VERSION) UnkEncVerMsg(hd->FileName); else { uint Flags=(uint)Raw->GetV(); hd->UsePswCheck=(Flags & FHEXTRA_CRYPT_PSWCHECK)!=0; hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0; hd->Lg2Count=Raw->Get1(); if (hd->Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX) UnkEncVerMsg(hd->FileName); Raw->GetB(hd->Salt,SIZE_SALT50); Raw->GetB(hd->InitV,SIZE_INITV); if (hd->UsePswCheck) { Raw->GetB(hd->PswCheck,SIZE_PSWCHECK); // It is important to know if password check data is valid. // If it is damaged and header CRC32 fails to detect it, // archiver would refuse to decompress a possibly valid file. // Since we want to be sure distinguishing a wrong password // or corrupt file data, we use 64-bit password check data // and to control its validity we use 32 bits of password // check data SHA-256 additionally to 32-bit header CRC32. byte csum[SIZE_PSWCHECK_CSUM]; Raw->GetB(csum,SIZE_PSWCHECK_CSUM); sha256_context ctx; sha256_init(&ctx); sha256_process(&ctx, hd->PswCheck, SIZE_PSWCHECK); byte Digest[SHA256_DIGEST_SIZE]; sha256_done(&ctx, Digest); hd->UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0; } hd->SaltSet=true; hd->CryptMethod=CRYPT_RAR50; hd->Encrypted=true; } } break; case FHEXTRA_HASH: { FileHeader *hd=(FileHeader *)bb; uint Type=(uint)Raw->GetV(); if (Type==FHEXTRA_HASH_BLAKE2) { hd->FileHash.Type=HASH_BLAKE2; Raw->GetB(hd->FileHash.Digest,BLAKE2_DIGEST_SIZE); } } break; case FHEXTRA_HTIME: if (FieldSize>=9) { byte Flags=(byte)Raw->GetV(); bool UnixTime=(Flags & FHEXTRA_HTIME_UNIXTIME)!=0; if ((Flags & FHEXTRA_HTIME_MTIME)!=0) if (UnixTime) hd->mtime=(time_t)Raw->Get4(); else hd->mtime.SetRaw(Raw->Get8()); if ((Flags & FHEXTRA_HTIME_CTIME)!=0) if (UnixTime) hd->ctime=(time_t)Raw->Get4(); else hd->ctime.SetRaw(Raw->Get8()); if ((Flags & FHEXTRA_HTIME_ATIME)!=0) if (UnixTime) hd->atime=(time_t)Raw->Get4(); else hd->atime.SetRaw(Raw->Get8()); } break; case FHEXTRA_VERSION: if (FieldSize>=1) { Raw->GetV(); // Skip flags field. uint Version=(uint)Raw->GetV(); if (Version!=0) { hd->Version=true; wchar VerText[20]; swprintf(VerText,ASIZE(VerText),L";%u",Version); wcsncatz(FileHead.FileName,VerText,ASIZE(FileHead.FileName)); } } break; case FHEXTRA_REDIR: { hd->RedirType=(FILE_SYSTEM_REDIRECT)Raw->GetV(); uint Flags=(uint)Raw->GetV(); hd->DirTarget=(Flags & FHEXTRA_REDIR_DIR)!=0; size_t NameSize=(size_t)Raw->GetV(); char UtfName[NM*4]; *UtfName=0; if (NameSizeGetB(UtfName,NameSize); UtfName[NameSize]=0; } UtfToWide(UtfName,hd->RedirName,ASIZE(hd->RedirName)); } break; case FHEXTRA_UOWNER: { uint Flags=(uint)Raw->GetV(); hd->UnixOwnerNumeric=(Flags & FHEXTRA_UOWNER_NUMUID)!=0; hd->UnixGroupNumeric=(Flags & FHEXTRA_UOWNER_NUMGID)!=0; *hd->UnixOwnerName=*hd->UnixGroupName=0; if ((Flags & FHEXTRA_UOWNER_UNAME)!=0) { size_t Length=(size_t)Raw->GetV(); Length=Min(Length,ASIZE(hd->UnixOwnerName)-1); Raw->GetB(hd->UnixOwnerName,Length); hd->UnixOwnerName[Length]=0; } if ((Flags & FHEXTRA_UOWNER_GNAME)!=0) { size_t Length=(size_t)Raw->GetV(); Length=Min(Length,ASIZE(hd->UnixGroupName)-1); Raw->GetB(hd->UnixGroupName,Length); hd->UnixGroupName[Length]=0; } #ifdef _UNIX if (hd->UnixOwnerNumeric) hd->UnixOwnerID=(uid_t)Raw->GetV(); if (hd->UnixGroupNumeric) hd->UnixGroupID=(gid_t)Raw->GetV(); #else // Need these fields in Windows too for 'list' command, // but uid_t and gid_t are not defined. if (hd->UnixOwnerNumeric) hd->UnixOwnerID=(uint)Raw->GetV(); if (hd->UnixGroupNumeric) hd->UnixGroupID=(uint)Raw->GetV(); #endif hd->UnixOwnerSet=true; } break; case FHEXTRA_SUBDATA: { hd->SubData.Alloc((size_t)FieldSize); Raw->GetB(hd->SubData.Addr(0),(size_t)FieldSize); } break; } } Raw->SetPos(NextPos); } } #ifndef SFX_MODULE size_t Archive::ReadHeader14() { RawRead Raw(this); if (CurBlockPos<=(int64)SFXSize) { Raw.Read(SIZEOF_MAINHEAD14); MainHead.Reset(); byte Mark[4]; Raw.GetB(Mark,4); uint HeadSize=Raw.Get2(); byte Flags=Raw.Get1(); NextBlockPos=CurBlockPos+HeadSize; CurHeaderType=HEAD_MAIN; Volume=(Flags & MHD_VOLUME)!=0; Solid=(Flags & MHD_SOLID)!=0; Locked=(Flags & MHD_LOCK)!=0; MainHead.CommentInHeader=(Flags & MHD_COMMENT)!=0; MainHead.PackComment=(Flags & MHD_PACK_COMMENT)!=0; } else { Raw.Read(SIZEOF_FILEHEAD14); FileHead.Reset(); FileHead.HeaderType=HEAD_FILE; FileHead.DataSize=Raw.Get4(); FileHead.UnpSize=Raw.Get4(); FileHead.FileHash.Type=HASH_RAR14; FileHead.FileHash.CRC32=Raw.Get2(); FileHead.HeadSize=Raw.Get2(); uint FileTime=Raw.Get4(); FileHead.FileAttr=Raw.Get1(); FileHead.Flags=Raw.Get1()|LONG_BLOCK; FileHead.UnpVer=(Raw.Get1()==2) ? 13 : 10; size_t NameSize=Raw.Get1(); FileHead.Method=Raw.Get1(); FileHead.SplitBefore=(FileHead.Flags & LHD_SPLIT_BEFORE)!=0; FileHead.SplitAfter=(FileHead.Flags & LHD_SPLIT_AFTER)!=0; FileHead.Encrypted=(FileHead.Flags & LHD_PASSWORD)!=0; FileHead.CryptMethod=FileHead.Encrypted ? CRYPT_RAR13:CRYPT_NONE; FileHead.PackSize=FileHead.DataSize; FileHead.WinSize=0x10000; FileHead.mtime.SetDos(FileTime); Raw.Read(NameSize); char FileName[NM]; Raw.GetB((byte *)FileName,Min(NameSize,ASIZE(FileName))); FileName[NameSize]=0; CharToWide(FileName,FileHead.FileName,ASIZE(FileHead.FileName)); ConvertNameCase(FileHead.FileName); if (Raw.Size()!=0) NextBlockPos=CurBlockPos+FileHead.HeadSize+FileHead.PackSize; CurHeaderType=HEAD_FILE; } return(NextBlockPos>CurBlockPos ? Raw.Size():0); } #endif #ifndef SFX_MODULE void Archive::ConvertNameCase(wchar *Name) { if (Cmd->ConvertNames==NAMES_UPPERCASE) wcsupper(Name); if (Cmd->ConvertNames==NAMES_LOWERCASE) wcslower(Name); } #endif bool Archive::IsArcDir() { return FileHead.Dir; } void Archive::ConvertAttributes() { #if defined(_WIN_ALL) || defined(_EMX) if (FileHead.HSType!=HSYS_WINDOWS) FileHead.FileAttr=FileHead.Dir ? 0x10 : 0x20; #endif #ifdef _UNIX // umask defines which permission bits must not be set by default // 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(FileHead.HSType) { case HSYS_WINDOWS: { // Mapping MSDOS, OS/2 and Windows file attributes to Unix. if (FileHead.FileAttr & 0x10) // FILE_ATTRIBUTE_DIRECTORY { // For directories we use 0777 mask. FileHead.FileAttr=0777 & ~mask; } else if (FileHead.FileAttr & 1) // FILE_ATTRIBUTE_READONLY { // For read only files we use 0444 mask with 'w' bits turned off. FileHead.FileAttr=0444 & ~mask; } else { // umask does not set +x for regular files, so we use 0666 // instead of 0777 as for directories. FileHead.FileAttr=0666 & ~mask; } } break; case HSYS_UNIX: break; default: if (FileHead.Dir) FileHead.FileAttr=0x41ff & ~mask; else FileHead.FileAttr=0x81b6 & ~mask; break; } #endif } void Archive::ConvertFileHeader(FileHeader *hd) { if (Format==RARFMT15 && hd->UnpVer<20 && (hd->FileAttr & 0x10)) hd->Dir=true; if (hd->HSType==HSYS_UNKNOWN) if (hd->Dir) hd->FileAttr=0x10; else hd->FileAttr=0x20; for (wchar *s=hd->FileName;*s!=0;s++) { #ifdef _UNIX // Backslash is the invalid character for Windows file headers, // but it can present in Unix file names extracted in Unix. if (*s=='\\' && Format==RARFMT50 && hd->HSType==HSYS_WINDOWS) *s='_'; #endif #if defined(_WIN_ALL) || defined(_EMX) // RAR 5.0 archives do not use '\' as path separator, so if we see it, // it means that it is a part of Unix file name, which we cannot // extract in Windows. if (*s=='\\' && Format==RARFMT50) *s='_'; // ':' in file names is allowed in Unix, but not in Windows. // Even worse, file data will be written to NTFS stream on NTFS, // so automatic name correction on file create error in extraction // routine does not work. In Windows and DOS versions we better // replace ':' now. if (*s==':') *s='_'; #endif // This code must be performed only after other path separator checks, // because it produces backslashes illegal for some of checks above. // Backslash is allowed in file names in Unix, but not in Windows. // Still, RAR 4.x uses backslashes as path separator even in Unix. // Forward slash is not allowed in both systems. In RAR 5.0 we use // the forward slash as universal path separator. if (*s=='/' || *s=='\\' && Format!=RARFMT50) *s=CPATHDIVIDER; } } int64 Archive::GetStartPos() { int64 StartPos=SFXSize+MarkHead.HeadSize; if (Format==RARFMT15) StartPos+=MainHead.HeadSize; else // RAR 5.0. StartPos+=CryptHead.HeadSize+FullHeaderSize(MainHead.HeadSize); return StartPos; } #ifndef SHELL_EXT bool Archive::ReadSubData(Array *UnpData,File *DestFile) { if (BrokenHeader) { #ifndef SHELL_EXT Log(FileName,St(MSubHeadCorrupt)); #endif ErrHandler.SetErrorCode(RARX_CRC); return false; } if (SubHead.Method>5 || SubHead.UnpVer>(Format==RARFMT50 ? VER_UNPACK5:VER_UNPACK)) { #ifndef SHELL_EXT Log(FileName,St(MSubHeadUnknown)); #endif return false; } if (SubHead.PackSize==0 && !SubHead.SplitAfter) return true; SubDataIO.Init(); Unpack Unpack(&SubDataIO); Unpack.Init(SubHead.WinSize,false); if (DestFile==NULL) { if (SubHead.UnpSize>0x1000000) { // So huge allocation must never happen in valid archives. #ifndef SHELL_EXT Log(FileName,St(MSubHeadUnknown)); #endif return false; } UnpData->Alloc((size_t)SubHead.UnpSize); SubDataIO.SetUnpackToMemory(&(*UnpData)[0],(uint)SubHead.UnpSize); } if (SubHead.Encrypted) if (Cmd->Password.IsSet()) SubDataIO.SetEncryption(false,SubHead.CryptMethod,&Cmd->Password, SubHead.SaltSet ? SubHead.Salt:NULL,SubHead.InitV, SubHead.Lg2Count,SubHead.PswCheck,SubHead.HashKey); else return false; SubDataIO.UnpHash.Init(SubHead.FileHash.Type,1); SubDataIO.SetPackedSizeToRead(SubHead.PackSize); SubDataIO.EnableShowProgress(false); SubDataIO.SetFiles(this,DestFile); SubDataIO.UnpVolume=SubHead.SplitAfter; SubDataIO.SetSubHeader(&SubHead,NULL); Unpack.SetDestSize(SubHead.UnpSize); if (SubHead.Method==0) CmdExtract::UnstoreFile(SubDataIO,SubHead.UnpSize); else Unpack.DoUnpack(SubHead.UnpVer,false); if (!SubDataIO.UnpHash.Cmp(&SubHead.FileHash,SubHead.UseHashKey ? SubHead.HashKey:NULL)) { #ifndef SHELL_EXT Log(FileName,St(MSubHeadDataCRC),SubHead.FileName); #endif ErrHandler.SetErrorCode(RARX_CRC); if (UnpData!=NULL) UnpData->Reset(); return false; } return true; } #endif unrar/blake2s.cpp0100666000000000000000000001170012176732144011327 0ustar z// Based on public domain code written in 2012 by Samuel Neves #include "rar.hpp" #ifdef USE_SSE #include "blake2s_sse.cpp" #endif static void blake2s_init_param( blake2s_state *S, uint32 node_offset, uint32 node_depth); static void blake2s_update( blake2s_state *S, const byte *in, size_t inlen ); static void blake2s_final( blake2s_state *S, byte *digest ); #include "blake2sp.cpp" static const uint32 blake2s_IV[8] = { 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL }; static const byte blake2s_sigma[10][16] = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , }; static inline void blake2s_set_lastnode( blake2s_state *S ) { S->f[1] = ~0U; } /* Some helper functions, not necessarily useful */ static inline void blake2s_set_lastblock( blake2s_state *S ) { if( S->last_node ) blake2s_set_lastnode( S ); S->f[0] = ~0U; } static inline void blake2s_increment_counter( blake2s_state *S, const uint32 inc ) { S->t[0] += inc; S->t[1] += ( S->t[0] < inc ); } /* init2 xors IV with input parameter block */ void blake2s_init_param( blake2s_state *S, uint32 node_offset, uint32 node_depth) { S->init(); // Clean data. for( int i = 0; i < 8; ++i ) S->h[i] = blake2s_IV[i]; S->h[0] ^= 0x02080020; // We use BLAKE2sp parameters block. S->h[2] ^= node_offset; S->h[3] ^= (node_depth<<16)|0x20000000; } static _forceinline uint32 rotr32( const uint32 w, const unsigned c ) { return ( w >> c ) | ( w << ( 32 - c ) ); } #define G(r,i,m,a,b,c,d) \ a = a + b + m[blake2s_sigma[r][2*i+0]]; \ d = rotr32(d ^ a, 16); \ c = c + d; \ b = rotr32(b ^ c, 12); \ a = a + b + m[blake2s_sigma[r][2*i+1]]; \ d = rotr32(d ^ a, 8); \ c = c + d; \ b = rotr32(b ^ c, 7); static void blake2s_compress( blake2s_state *S, const byte block[BLAKE2S_BLOCKBYTES] ) { uint32 m[16]; uint32 v[16]; for( size_t i = 0; i < 16; ++i ) m[i] = RawGet4( block + i * 4 ); for( size_t i = 0; i < 8; ++i ) v[i] = S->h[i]; v[ 8] = blake2s_IV[0]; v[ 9] = blake2s_IV[1]; v[10] = blake2s_IV[2]; v[11] = blake2s_IV[3]; v[12] = S->t[0] ^ blake2s_IV[4]; v[13] = S->t[1] ^ blake2s_IV[5]; v[14] = S->f[0] ^ blake2s_IV[6]; v[15] = S->f[1] ^ blake2s_IV[7]; for ( uint r = 0; r <= 9; ++r ) // No gain on i7 if unrolled, but exe size grows. { G(r,0,m,v[ 0],v[ 4],v[ 8],v[12]); G(r,1,m,v[ 1],v[ 5],v[ 9],v[13]); G(r,2,m,v[ 2],v[ 6],v[10],v[14]); G(r,3,m,v[ 3],v[ 7],v[11],v[15]); G(r,4,m,v[ 0],v[ 5],v[10],v[15]); G(r,5,m,v[ 1],v[ 6],v[11],v[12]); G(r,6,m,v[ 2],v[ 7],v[ 8],v[13]); G(r,7,m,v[ 3],v[ 4],v[ 9],v[14]); } for( size_t i = 0; i < 8; ++i ) S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; } void blake2s_update( blake2s_state *S, const byte *in, size_t inlen ) { while( inlen > 0 ) { size_t left = S->buflen; size_t fill = 2 * BLAKE2S_BLOCKBYTES - left; if( inlen > fill ) { memcpy( S->buf + left, in, fill ); // Fill buffer S->buflen += fill; blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); #ifdef USE_SSE #ifdef _WIN_32 // We use SSSE3 _mm_shuffle_epi8 only in x64 mode. if (_SSE_Version>=SSE_SSE2) #else if (_SSE_Version>=SSE_SSSE3) #endif blake2s_compress_sse( S, S->buf ); else blake2s_compress( S, S->buf ); // Compress #else blake2s_compress( S, S->buf ); // Compress #endif memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); // Shift buffer left S->buflen -= BLAKE2S_BLOCKBYTES; in += fill; inlen -= fill; } else // inlen <= fill { memcpy( S->buf + left, in, (size_t)inlen ); S->buflen += (size_t)inlen; // Be lazy, do not compress in += inlen; inlen -= inlen; } } } void blake2s_final( blake2s_state *S, byte *digest ) { if( S->buflen > BLAKE2S_BLOCKBYTES ) { blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); blake2s_compress( S, S->buf ); S->buflen -= BLAKE2S_BLOCKBYTES; memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, S->buflen ); } blake2s_increment_counter( S, ( uint32 )S->buflen ); blake2s_set_lastblock( S ); memset( S->buf + S->buflen, 0, 2 * BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */ blake2s_compress( S, S->buf ); for( int i = 0; i < 8; ++i ) /* Output full hash */ RawPut4( S->h[i], digest + 4 * i ); } unrar/blake2s_sse.cpp0100666000000000000000000001025612176732144012206 0ustar z// Based on public domain code written in 2012 by Samuel Neves extern const byte blake2s_sigma[10][16]; #define LOAD(p) _mm_load_si128( (__m128i *)(p) ) #define STORE(p,r) _mm_store_si128((__m128i *)(p), r) #ifdef _WIN_32 // 32-bit mode has less SSE2 registers and in MSVC2008 it is more efficient // to not use _mm_shuffle_epi8 here. #define mm_rotr_epi32(r, c) ( \ _mm_xor_si128(_mm_srli_epi32( (r), c ),_mm_slli_epi32( (r), 32-c )) ) #else // Constants for cyclic rotation. static const __m128i crotr8 = _mm_set_epi8( 12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1 ); static const __m128i crotr16 = _mm_set_epi8( 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2 ); #define mm_rotr_epi32(r, c) ( \ c==8 ? _mm_shuffle_epi8(r,crotr8) \ : c==16 ? _mm_shuffle_epi8(r,crotr16) \ : _mm_xor_si128(_mm_srli_epi32( (r), c ),_mm_slli_epi32( (r), 32-c )) ) #endif #define G1(row1,row2,row3,row4,buf) \ row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \ row4 = _mm_xor_si128( row4, row1 ); \ row4 = mm_rotr_epi32(row4, 16); \ row3 = _mm_add_epi32( row3, row4 ); \ row2 = _mm_xor_si128( row2, row3 ); \ row2 = mm_rotr_epi32(row2, 12); #define G2(row1,row2,row3,row4,buf) \ row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \ row4 = _mm_xor_si128( row4, row1 ); \ row4 = mm_rotr_epi32(row4, 8); \ row3 = _mm_add_epi32( row3, row4 ); \ row2 = _mm_xor_si128( row2, row3 ); \ row2 = mm_rotr_epi32(row2, 7); #define DIAGONALIZE(row1,row2,row3,row4) \ row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(2,1,0,3) ); \ row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(1,0,3,2) ); \ row2 = _mm_shuffle_epi32( row2, _MM_SHUFFLE(0,3,2,1) ); #define UNDIAGONALIZE(row1,row2,row3,row4) \ row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(0,3,2,1) ); \ row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(1,0,3,2) ); \ row2 = _mm_shuffle_epi32( row2, _MM_SHUFFLE(2,1,0,3) ); #ifdef _WIN_64 // MSVC 2008 in x64 mode expands _mm_set_epi32 to store to stack and load // from stack operations, which are slower than this code. #define _mm_set_epi32(i3,i2,i1,i0) \ _mm_unpacklo_epi32(_mm_unpacklo_epi32(_mm_cvtsi32_si128(i0),_mm_cvtsi32_si128(i2)), \ _mm_unpacklo_epi32(_mm_cvtsi32_si128(i1),_mm_cvtsi32_si128(i3))) #endif // Original BLAKE2 SSE4.1 message loading code was a little slower in x86 mode // and about the same in x64 mode in our test. Perhaps depends on compiler. #define SSE_ROUND(m,row,r) \ { \ __m128i buf; \ buf=_mm_set_epi32(m[blake2s_sigma[r][6]],m[blake2s_sigma[r][4]],m[blake2s_sigma[r][2]],m[blake2s_sigma[r][0]]); \ G1(row[0],row[1],row[2],row[3],buf); \ buf=_mm_set_epi32(m[blake2s_sigma[r][7]],m[blake2s_sigma[r][5]],m[blake2s_sigma[r][3]],m[blake2s_sigma[r][1]]); \ G2(row[0],row[1],row[2],row[3],buf); \ DIAGONALIZE(row[0],row[1],row[2],row[3]); \ buf=_mm_set_epi32(m[blake2s_sigma[r][14]],m[blake2s_sigma[r][12]],m[blake2s_sigma[r][10]],m[blake2s_sigma[r][8]]); \ G1(row[0],row[1],row[2],row[3],buf); \ buf=_mm_set_epi32(m[blake2s_sigma[r][15]],m[blake2s_sigma[r][13]],m[blake2s_sigma[r][11]],m[blake2s_sigma[r][9]]); \ G2(row[0],row[1],row[2],row[3],buf); \ UNDIAGONALIZE(row[0],row[1],row[2],row[3]); \ } // Initialization vector. static const __m128i blake2s_IV_0_3 = _mm_setr_epi32( 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A ); static const __m128i blake2s_IV_4_7 = _mm_setr_epi32( 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 ); static int blake2s_compress_sse( blake2s_state *S, const byte block[BLAKE2S_BLOCKBYTES] ) { __m128i row[4]; __m128i ff0, ff1; const uint32 *m = ( uint32 * )block; row[0] = ff0 = LOAD( &S->h[0] ); row[1] = ff1 = LOAD( &S->h[4] ); row[2] = blake2s_IV_0_3; row[3] = _mm_xor_si128( blake2s_IV_4_7, LOAD( &S->t[0] ) ); SSE_ROUND( m, row, 0 ); SSE_ROUND( m, row, 1 ); SSE_ROUND( m, row, 2 ); SSE_ROUND( m, row, 3 ); SSE_ROUND( m, row, 4 ); SSE_ROUND( m, row, 5 ); SSE_ROUND( m, row, 6 ); SSE_ROUND( m, row, 7 ); SSE_ROUND( m, row, 8 ); SSE_ROUND( m, row, 9 ); STORE( &S->h[0], _mm_xor_si128( ff0, _mm_xor_si128( row[0], row[2] ) ) ); STORE( &S->h[4], _mm_xor_si128( ff1, _mm_xor_si128( row[1], row[3] ) ) ); return 0; } unrar/blake2sp.cpp0100666000000000000000000000734612176732144011522 0ustar z/* BLAKE2 reference source code package - reference C implementations Written in 2012 by Samuel Neves To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. This software is distributed without any warranty. You should have received a copy of the CC0 Public Domain Dedication along with this software. If not, see . */ #define PARALLELISM_DEGREE 8 void blake2sp_init( blake2sp_state *S ) { memset( S->buf, 0, sizeof( S->buf ) ); S->buflen = 0; blake2s_init_param( &S->R, 0, 1 ); // Init root. for( uint i = 0; i < PARALLELISM_DEGREE; ++i ) blake2s_init_param( &S->S[i], i, 0 ); // Init leaf. S->R.last_node = 1; S->S[PARALLELISM_DEGREE - 1].last_node = 1; } struct Blake2ThreadData { void Update(); blake2s_state *S; const byte *in; size_t inlen; }; void Blake2ThreadData::Update() { size_t inlen__ = inlen; const byte *in__ = ( const byte * )in; while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES ) { #ifdef USE_SSE // We gain 5% in i7 SSE mode by prefetching next data block. if (_SSE_Version>=SSE_SSE && inlen__ >= 2 * PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES) _mm_prefetch((char*)(in__ + PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES), _MM_HINT_T0); #endif blake2s_update( S, in__, BLAKE2S_BLOCKBYTES ); in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; } } #ifdef RAR_SMP THREAD_PROC(Blake2Thread) { Blake2ThreadData *td=(Blake2ThreadData *)Data; td->Update(); } #endif void blake2sp_update( blake2sp_state *S, const byte *in, size_t inlen ) { size_t left = S->buflen; size_t fill = sizeof( S->buf ) - left; if( left && inlen >= fill ) { memcpy( S->buf + left, in, fill ); for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) blake2s_update( &S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); in += fill; inlen -= fill; left = 0; } Blake2ThreadData btd_array[PARALLELISM_DEGREE]; #ifdef RAR_SMP uint ThreadNumber = inlen < 0x1000 ? 1 : S->MaxThreads; if (ThreadNumber==6 || ThreadNumber==7) // 6 and 7 threads work slower than 4 here. ThreadNumber=4; #else uint ThreadNumber=1; #endif for (size_t id__=0;id__inlen = inlen; btd->in = in + id__ * BLAKE2S_BLOCKBYTES; btd->S = &S->S[id__]; #ifdef RAR_SMP if (ThreadNumber>1) S->ThPool->AddTask(Blake2Thread,(void*)btd); else btd->Update(); #else btd->Update(); #endif id__++; } #ifdef RAR_SMP if (S->ThPool!=NULL) // Can be NULL in -mt1 mode. S->ThPool->WaitDone(); #endif // RAR_SMP } in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES ); inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; if( inlen > 0 ) memcpy( S->buf + left, in, (size_t)inlen ); S->buflen = left + (size_t)inlen; } void blake2sp_final( blake2sp_state *S, byte *digest ) { byte hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES]; for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) { if( S->buflen > i * BLAKE2S_BLOCKBYTES ) { size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES; if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES; blake2s_update( &S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left ); } blake2s_final( &S->S[i], hash[i] ); } for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) blake2s_update( &S->R, hash[i], BLAKE2S_OUTBYTES ); blake2s_final( &S->R, digest ); } unrar/cmddata.cpp0100666000000000000000000010146412176732144011410 0ustar z#include "rar.hpp" CommandData::CommandData() { Init(); } void CommandData::Init() { RAROptions::Init(); *Command=0; *ArcName=0; FileLists=false; NoMoreSwitches=false; ListMode=RCLM_AUTO; BareOutput=false; FileArgs.Reset(); ExclArgs.Reset(); InclArgs.Reset(); StoreArgs.Reset(); ArcNames.Reset(); NextVolSizes.Reset(); } // Return the pointer to next position in the string and store dynamically // allocated command line parameter in Par. static const wchar *AllocCmdParam(const wchar *CmdLine,wchar **Par) { const wchar *NextCmd=GetCmdParam(CmdLine,NULL,0); if (NextCmd==NULL) return NULL; size_t ParSize=NextCmd-CmdLine+2; // Parameter size including the trailing zero. *Par=(wchar *)malloc(ParSize*sizeof(wchar)); if (*Par==NULL) return NULL; return GetCmdParam(CmdLine,*Par,ParSize); } #ifndef SFX_MODULE void CommandData::ParseCommandLine(bool Preprocess,int argc, char *argv[]) { #ifdef CUSTOM_CMDLINE_PARSER // In Windows we may prefer to implement our own command line parser // to avoid replacing \" by " in standard parser. Such replacing corrupts // destination paths like "dest path\" in extraction commands. const wchar *CmdLine=GetCommandLine(); wchar *Par; for (bool FirstParam=true;;FirstParam=false) { if ((CmdLine=AllocCmdParam(CmdLine,&Par))==NULL) break; bool Code=true; if (!FirstParam) // First parameter is the executable name. if (Preprocess) Code=PreprocessSwitch(Par); else ParseArg(Par); free(Par); if (Preprocess && !Code) break; } #else Array Arg; for (int I=1;I EnvStrW(strlen(EnvStr)+1); CharToWide(EnvStr,&EnvStrW[0],EnvStrW.Size()); ProcessSwitchesString(&EnvStrW[0]); } } #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 wchar *Switch) { if (IsSwitch(Switch[0])) { Switch++; char SwitchA[1024]; WideToChar(Switch,SwitchA,ASIZE(SwitchA)); if (wcsicomp(Switch,L"-")==0) // Switch "--". return false; if (wcsicomp(Switch,L"cfg-")==0) ConfigDisabled=true; #ifndef GUI if (wcsnicomp(Switch,L"ilog",4)==0) { // Ensure that correct log file name is already set // if we need to report an error when processing the command line. ProcessSwitch(Switch); InitLogOptions(LogName,ErrlogCharset); } #endif if (wcsnicomp(Switch,L"sc",2)==0) { // Process -sc before reading any file lists. ProcessSwitch(Switch); #ifndef GUI if (*LogName!=0) InitLogOptions(LogName,ErrlogCharset); #endif } } return true; } #endif #if !defined(GUI) && !defined(SFX_MODULE) void CommandData::ReadConfig() { StringList List; if (ReadTextFile(DefConfigName,&List,true)) { wchar *Str; while ((Str=List.GetString())!=NULL) { while (IsSpace(*Str)) Str++; if (wcsnicomp(Str,L"switches=",9)==0) ProcessSwitchesString(Str+9); } } } #endif #ifndef SFX_MODULE void CommandData::ProcessSwitchesString(const wchar *Str) { wchar *Par; while ((Str=AllocCmdParam(Str,&Par))!=NULL) { if (IsSwitch(*Par)) ProcessSwitch(Par+1); free(Par); } } #endif #if !defined(SFX_MODULE) void CommandData::ProcessSwitch(const wchar *Switch) { switch(toupperw(Switch[0])) { case '@': ListMode=Switch[1]=='+' ? RCLM_ACCEPT_LISTS:RCLM_REJECT_LISTS; break; case 'A': switch(toupperw(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; wcsncpyz(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': wcscpy(ArcPath,Switch+2); break; case 'S': SyncFiles=true; break; default: BadSwitch(Switch); break; } break; case 'C': if (Switch[2]==0) switch(toupperw(Switch[1])) { case '-': DisableComment=true; break; case 'U': ConvertNames=NAMES_UPPERCASE; break; case 'L': ConvertNames=NAMES_LOWERCASE; break; } break; case 'D': if (Switch[2]==0) switch(toupperw(Switch[1])) { case 'S': DisableSortSolid=true; break; case 'H': OpenShared=true; break; case 'F': DeleteFiles=true; break; } break; case 'E': switch(toupperw(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; default: if (Switch[1]=='+') { InclFileAttr=GetExclAttr(Switch+2); InclAttrSet=true; } else ExclFileAttr=GetExclAttr(Switch+1); break; } break; case 'F': if (Switch[1]==0) FreshFiles=true; else BadSwitch(Switch); break; case 'H': switch (toupperw(Switch[1])) { case 'P': EncryptHeaders=true; if (Switch[2]!=0) { Password.Set(Switch+2); cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0])); } else if (!Password.IsSet()) { GetPassword(PASSWORD_GLOBAL,NULL,&Password); eprintf(L"\n"); } break; default : BadSwitch(Switch); break; } break; case 'I': if (wcsnicomp(Switch+1,L"LOG",3)==0) { wcsncpyz(LogName,Switch[4]!=0 ? Switch+4:DefLogName,ASIZE(LogName)); break; } if (wcsicomp(Switch+1,L"SND")==0) { Sound=true; break; } if (wcsicomp(Switch+1,L"ERR")==0) { MsgStream=MSG_STDERR; break; } if (wcsnicomp(Switch+1,L"EML",3)==0) { wcsncpyz(EmailTo,Switch[4]!=0 ? Switch+4:L"@",ASIZE(EmailTo)); break; } if (wcsicomp(Switch+1,L"NUL")==0) { MsgStream=MSG_NULL; break; } if (toupperw(Switch[1])=='D') { for (uint I=2;Switch[I]!=0;I++) switch(toupperw(Switch[I])) { case 'Q': MsgStream=MSG_ERRONLY; break; case 'C': DisableCopyright=true; break; case 'D': DisableDone=true; break; case 'P': DisablePercentage=true; break; } break; } if (wcsicomp(Switch+1,L"OFF")==0) { Shutdown=true; break; } break; case 'K': switch(toupperw(Switch[1])) { case 'B': KeepBroken=true; break; case 0: Lock=true; break; } break; case 'M': switch(toupperw(Switch[1])) { case 'C': { const wchar *Str=Switch+2; if (*Str=='-') for (uint I=0;IMaxPoolThreads || Threads<1) BadSwitch(Switch); else { } break; #endif default: Method=Switch[1]-'0'; if (Method>5 || Method<0) BadSwitch(Switch); break; } break; case 'N': case 'X': if (Switch[1]!=0) { StringList *Args=toupperw(Switch[0])=='N' ? &InclArgs:&ExclArgs; if (Switch[1]=='@' && !IsWildcard(Switch)) { RAR_CHARSET Charset=FilelistCharset; #if defined(_WIN_ALL) && !defined(GUI) // for compatibility reasons we use OEM encoding // in Win32 console version by default // if (Charset==RCH_DEFAULT) // Charset=RCH_OEM; #endif ReadTextFile(Switch+2,Args,false,true,Charset,true,true,true); } else Args->AddString(Switch+1); } break; case 'O': switch(toupperw(Switch[1])) { case '+': Overwrite=OVERWRITE_ALL; break; case '-': Overwrite=OVERWRITE_NONE; break; case 0: Overwrite=OVERWRITE_FORCE_ASK; break; #ifdef _WIN_ALL case 'C': SetCompressedAttr=true; break; #endif case 'H': SaveHardLinks=true; break; #ifdef SAVE_LINKS case 'L': SaveSymLinks=true; break; #endif case 'R': Overwrite=OVERWRITE_AUTORENAME; break; #ifdef _WIN_ALL case 'S': SaveStreams=true; break; #endif case 'W': ProcessOwners=true; break; default : BadSwitch(Switch); break; } break; case 'P': if (Switch[1]==0) { GetPassword(PASSWORD_GLOBAL,NULL,&Password); eprintf(L"\n"); } else { Password.Set(Switch+1); cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0])); } break; #ifndef SFX_MODULE case 'Q': if (toupperw(Switch[1])=='O') switch(toupperw(Switch[2])) { case 0: QOpenMode=QOPEN_AUTO; break; case '-': QOpenMode=QOPEN_NONE; break; case '+': QOpenMode=QOPEN_ALWAYS; break; default: BadSwitch(Switch); break; } else BadSwitch(Switch); break; #endif case 'R': switch(toupperw(Switch[1])) { case 0: Recurse=RECURSE_ALWAYS; break; case '-': Recurse=RECURSE_DISABLE; break; case '0': Recurse=RECURSE_WILDCARDS; break; case 'I': { Priority=atoiw(Switch+2); if (Priority<0 || Priority>15) BadSwitch(Switch); const wchar *ChPtr=wcschr(Switch+2,':'); if (ChPtr!=NULL) { SleepTime=atoiw(ChPtr+1); if (SleepTime>1000) BadSwitch(Switch); InitSystemOptions(SleepTime); } SetPriority(Priority); } break; } break; case 'S': if (IsDigit(Switch[1])) { Solid|=SOLID_COUNT; SolidCount=atoiw(&Switch[1]); } else switch(toupperw(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=atoilw(Switch+2); break; case 'M': if (IsDigit(Switch[2])) FileSizeMore=atoilw(Switch+2); break; case 'C': { bool AlreadyBad=false; // Avoid reporting "bad switch" several times. RAR_CHARSET rch=RCH_DEFAULT; switch(toupperw(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=ErrlogCharset=rch; else for (uint I=3;Switch[I]!=0 && !AlreadyBad;I++) switch(toupperw(Switch[I])) { case 'C': CommentCharset=rch; break; case 'L': FilelistCharset=rch; break; default: BadSwitch(Switch); AlreadyBad=true; break; } } break; } break; case 'T': switch(toupperw(Switch[1])) { case 'K': ArcTime=ARCTIME_KEEP; break; case 'L': ArcTime=ARCTIME_LATEST; break; case 'O': FileTimeBefore.SetAgeText(Switch+2); break; case 'N': FileTimeAfter.SetAgeText(Switch+2); break; case 'B': FileTimeBefore.SetIsoText(Switch+2); break; case 'A': FileTimeAfter.SetIsoText(Switch+2); break; case 'S': { EXTTIME_MODE Mode=EXTTIME_HIGH3; bool CommonMode=Switch[2]>='0' && Switch[2]<='4'; if (CommonMode) Mode=(EXTTIME_MODE)(Switch[2]-'0'); if (Switch[2]=='-') Mode=EXTTIME_NONE; if (CommonMode || Switch[2]=='-' || Switch[2]=='+' || Switch[2]==0) xmtime=xctime=xatime=Mode; else { if (Switch[3]>='0' && Switch[3]<='4') Mode=(EXTTIME_MODE)(Switch[3]-'0'); if (Switch[3]=='-') Mode=EXTTIME_NONE; switch(toupperw(Switch[2])) { case 'M': xmtime=Mode; break; case 'C': xctime=Mode; break; case 'A': xatime=Mode; break; } } } break; case '-': Test=false; break; case 0: Test=true; break; default: BadSwitch(Switch); break; } break; case 'U': if (Switch[1]==0) UpdateFiles=true; else BadSwitch(Switch); break; case 'V': switch(toupperw(Switch[1])) { case 'P': VolumePause=true; break; case 'E': if (toupperw(Switch[2])=='R') VersionControl=atoiw(Switch+3)+1; break; case '-': VolSize=0; break; default: VolSize=VOLSIZE_AUTO; // UnRAR -v switch for list command. break; } break; case 'W': wcsncpyz(TempPath,Switch+1,ASIZE(TempPath)); AddEndSlash(TempPath,ASIZE(TempPath)); break; case 'Y': AllYes=true; break; case 'Z': if (Switch[1]==0) { #ifndef GUI // stdin is not supported by WinRAR. // If comment file is not specified, we read data from stdin. wcscpy(CommentFile,L"stdin"); #endif } else wcsncpyz(CommentFile,Switch+1,ASIZE(CommentFile)); break; #ifndef GUI case '?' : OutHelp(RARX_SUCCESS); break; #endif default : BadSwitch(Switch); break; } } #endif #ifndef SFX_MODULE void CommandData::BadSwitch(const wchar *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; wchar Version[50]; int Beta=RARVER_BETA; if (Beta!=0) swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA); else swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR); #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 string 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 (uint I=0;IRewind(); while (Args->GetString(CurMask,ASIZE(CurMask)-1)) { wchar *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) wcscat(CurMask,L"*"); } #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,ASIZE(FullName)); if (CmpName(CurMask,FullName,MatchMode)) return true; } else #endif { wchar 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; wcsncpyz(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 &FileHead,bool *ExactMatch,int MatchType) { if (wcslen(FileHead.FileName)>=NM) return 0; bool Dir=FileHead.Dir; if (ExclCheck(FileHead.FileName,Dir,false,true)) return 0; #ifndef SFX_MODULE if (TimeCheck(FileHead.mtime)) return 0; if ((FileHead.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0) return 0; if (!Dir && SizeCheck(FileHead.UnpSize)) return 0; #endif wchar *ArgName; FileArgs.Rewind(); for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++) if (CmpName(ArgName,FileHead.FileName,MatchType)) { if (ExactMatch!=NULL) *ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0; return StringCount; } return 0; } #ifndef GUI void CommandData::ProcessCommand() { #ifndef SFX_MODULE const wchar *SingleCharCommands=L"FUADPXETK"; if (Command[0]!=0 && Command[1]!=0 && wcschr(SingleCharCommands,Command[0])!=NULL || *ArcName==0) OutHelp(*Command==0 ? RARX_SUCCESS:RARX_USERERROR); // Return 'success' for 'rar' without parameters. #ifdef _UNIX if (GetExt(ArcName)==NULL && (!FileExist(ArcName) || IsDir(GetFileAttr(ArcName)))) wcsncatz(ArcName,L".rar",ASIZE(ArcName)); #else if (GetExt(ArcName)==NULL) wcsncatz(ArcName,L".rar",ASIZE(ArcName)); #endif if (wcschr(L"AFUMD",*Command)==NULL) { if (GenerateArcName) GenerateArchiveName(ArcName,ASIZE(ArcName),GenerateMask,false); StringList ArcMasks; ArcMasks.AddString(ArcName); ScanTree Scan(&ArcMasks,Recurse,SaveSymLinks,SCAN_SKIPDIRS); FindData FindData; while (Scan.GetNext(&FindData)==SCAN_SUCCESS) AddArcName(FindData.Name); } else AddArcName(ArcName); #endif switch(Command[0]) { case 'P': case 'X': case 'E': case 'T': case 'I': { CmdExtract Extract(this); Extract.DoExtract(this); } break; #ifndef SILENT case 'V': case 'L': ListArchive(this); break; default: OutHelp(RARX_USERERROR); #endif } if (!BareOutput) mprintf(L"\n"); } #endif void CommandData::AddArcName(const wchar *Name) { ArcNames.AddString(Name); } bool CommandData::GetArcName(wchar *Name,int MaxSize) { return ArcNames.GetString(Name,MaxSize); } 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 wchar *Str) { if (IsDigit(*Str)) return(wcstol(Str,NULL,0)); uint Attr=0; while (*Str!=0) { switch(toupperw(*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 } Str++; } return Attr; } #endif #ifndef SFX_MODULE bool CommandData::CheckWinSize() { // Define 0x100000000 as macro to avoid troubles with older compilers. const uint64 MaxDictSize=INT32TO64(1,0); // Limit the dictionary size to 4 GB. for (uint64 I=0x10000;I<=MaxDictSize;I*=2) if (WinSize==I) return true; WinSize=0x400000; return false; } #endif #ifndef SFX_MODULE void CommandData::ReportWrongSwitches(RARFORMAT Format) { if (Format==RARFMT15) { if (HashType!=HASH_CRC32) { mprintf(St(MIncompatSwitch),L"-ht",4); } #ifdef _WIN_ALL if (SaveSymLinks) { mprintf(St(MIncompatSwitch),L"-ol",4); } #endif if (SaveHardLinks) { mprintf(St(MIncompatSwitch),L"-oh",4); } #ifdef _WIN_ALL #endif if (QOpenMode!=QOPEN_AUTO) { mprintf(St(MIncompatSwitch),L"-qo",4); } /* // We use 64 MB for both formats and reduce it for RAR 4.x later. if (WinSize>0x400000) { wchar SwMD[10]; swprintf(SwMD,ASIZE(SwMD),L"-md%dm",WinSize/0x100000); mprintf(St(MIncompatSwitch),SwMD,4); } */ } if (Format==RARFMT50) { } } #endif unrar/coder.cpp0100666000000000000000000000236012176732144011102 0ustar z 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))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; } unrar/consio.cpp0100666000000000000000000002104212176732144011276 0ustar z#include "rar.hpp" #include "log.cpp" static MESSAGE_TYPE MsgStream=MSG_STDOUT; static bool Sound=false; const int MaxMsgSize=2*NM+2048; #ifdef _WIN_ALL static bool StdoutRedirected=false,StderrRedirected=false,StdinRedirected=false; #endif #ifdef _WIN_ALL static bool IsRedirected(DWORD nStdHandle) { HANDLE hStd=GetStdHandle(nStdHandle); DWORD Mode; return GetFileType(hStd)!=FILE_TYPE_CHAR || GetConsoleMode(hStd,&Mode)==0; } #endif void InitConsole() { #ifdef _WIN_ALL // We want messages like file names or progress percent to be printed // immediately. Use only in Windows, in Unix they can cause wprintf %ls // to fail with non-English strings. setbuf(stdout,NULL); setbuf(stderr,NULL); // Detect if output is redirected and set output mode properly. // We do not want to send Unicode output to files and especially to pipes // like '|more', which cannot handle them correctly in Windows. // In Unix console output is UTF-8 and it is handled correctly // when redirecting, so no need to perform any adjustments. StdoutRedirected=IsRedirected(STD_OUTPUT_HANDLE); StderrRedirected=IsRedirected(STD_ERROR_HANDLE); StdinRedirected=IsRedirected(STD_INPUT_HANDLE); #ifdef _MSC_VER if (!StdoutRedirected) _setmode(_fileno(stdout), _O_U16TEXT); if (!StderrRedirected) _setmode(_fileno(stderr), _O_U16TEXT); #endif #endif } void InitConsoleOptions(MESSAGE_TYPE MsgStream,bool Sound) { ::MsgStream=MsgStream; ::Sound=Sound; } #ifndef SILENT static void cvt_wprintf(FILE *dest,const wchar *fmt,va_list arglist) { // This buffer is for format string only, not for entire output, // so it can be short enough. wchar fmtw[1024]; PrintfPrepareFmt(fmt,fmtw,ASIZE(fmtw)); #ifdef _WIN_ALL safebuf wchar Msg[MaxMsgSize]; if (dest==stdout && StdoutRedirected || dest==stderr && StderrRedirected) { // Avoid Unicode for redirect in Windows, it does not work with pipes. vswprintf(Msg,ASIZE(Msg),fmtw,arglist); safebuf char MsgA[MaxMsgSize]; WideToChar(Msg,MsgA,ASIZE(MsgA)); CharToOemA(MsgA,MsgA); // Console tools like 'more' expect OEM encoding. // We already converted \n to \r\n above, so we use WriteFile instead // of C library to avoid unnecessary additional conversion. HANDLE hOut=GetStdHandle(dest==stdout ? STD_OUTPUT_HANDLE:STD_ERROR_HANDLE); DWORD Written; WriteFile(hOut,MsgA,(DWORD)strlen(MsgA),&Written,NULL); return; } // MSVC2008 vfwprintf writes every character to console separately // and it is too slow. We use direct WriteConsole call instead. vswprintf(Msg,ASIZE(Msg),fmtw,arglist); HANDLE hOut=GetStdHandle(dest==stderr ? STD_ERROR_HANDLE:STD_OUTPUT_HANDLE); DWORD Written; WriteConsole(hOut,Msg,(DWORD)wcslen(Msg),&Written,NULL); #else vfwprintf(dest,fmtw,arglist); // We do not use setbuf(NULL) in Unix (see comments in InitConsole). fflush(dest); #endif } void mprintf(const wchar *fmt,...) { if (MsgStream==MSG_NULL || MsgStream==MSG_ERRONLY) return; fflush(stderr); // Ensure proper message order. va_list arglist; va_start(arglist,fmt); FILE *dest=MsgStream==MSG_STDERR ? stderr:stdout; cvt_wprintf(dest,fmt,arglist); va_end(arglist); } #endif #ifndef SILENT void eprintf(const wchar *fmt,...) { if (MsgStream==MSG_NULL) return; fflush(stdout); // Ensure proper message order. va_list arglist; va_start(arglist,fmt); cvt_wprintf(stderr,fmt,arglist); va_end(arglist); } #endif #ifndef SILENT void Alarm() { if (Sound) { static clock_t LastTime=clock(); if ((clock()-LastTime)/CLOCKS_PER_SEC>5) { #ifdef _WIN_ALL MessageBeep(-1); #else putwchar('\007'); #endif } } } #endif #ifndef SILENT static 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); ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL); Str[Read]=0; SetConsoleMode(hConIn,ConInMode); SetConsoleMode(hConOut,ConOutMode); #else char StrA[MAXPASSWORD]; #if defined(_EMX) || defined (__VMS) fgets(StrA,ASIZE(StrA)-1,stdin); #elif defined(__sun) strncpyz(StrA,getpassphrase(""),ASIZE(StrA)); #else strncpyz(StrA,getpass(""),ASIZE(StrA)); #endif CharToWide(StrA,Str,MaxLength); cleandata(StrA,sizeof(StrA)); #endif Str[MaxLength-1]=0; RemoveLF(Str); } #endif #ifndef SILENT bool GetConsolePassword(PASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password) { Alarm(); while (true) { if (Type==PASSWORD_GLOBAL) eprintf(L"\n%s: ",St(MAskPsw)); else eprintf(St(MAskPswFor),FileName); wchar PlainPsw[MAXPASSWORD]; GetPasswordText(PlainPsw,ASIZE(PlainPsw)); if (*PlainPsw==0 && Type==PASSWORD_GLOBAL) return false; 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 #ifndef SILENT bool getwstr(wchar *str,size_t n) { // Print buffered prompt title function before waiting for input. fflush(stderr); *str=0; #if defined(_WIN_ALL) // fgetws does not work well with non-English text in Windows, // so we do not use it. if (StdinRedirected) // ReadConsole does not work if redirected. { // fgets does not work well with pipes in Windows in our test. // Let's use files. Array StrA(n*4); // Up to 4 UTF-8 characters per wchar_t. File SrcFile; SrcFile.SetHandleType(FILE_HANDLESTD); int ReadSize=SrcFile.Read(&StrA[0],StrA.Size()-1); if (ReadSize<=0) { // Looks like stdin is a null device. We can enter to infinite loop // calling Ask(), so let's better exit. ErrHandler.Exit(RARX_USERBREAK); } StrA[ReadSize-1]=0; CharToWide(&StrA[0],str,n); } else { DWORD ReadSize=0; if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE),str,DWORD(n-1),&ReadSize,NULL)==0) return false; str[ReadSize]=0; } #else if (fgetws(str,n,stdin)==NULL) ErrHandler.Exit(RARX_USERBREAK); // Avoid infinite Ask() loop. #endif RemoveLF(str); return true; } #endif #ifndef SILENT int Ask(const wchar *AskStr) { Alarm(); const int MaxItems=10; wchar Item[MaxItems][40]; int ItemKeyPos[MaxItems],NumItems=0; for (const wchar *NextItem=AskStr;NextItem!=NULL;NextItem=wcschr(NextItem+1,'_')) { wchar *CurItem=Item[NumItems]; wcsncpyz(CurItem,NextItem+1,ASIZE(Item[0])); wchar *EndItem=wcschr(CurItem,'_'); if (EndItem!=NULL) *EndItem=0; int KeyPos=0,CurKey; while ((CurKey=CurItem[KeyPos])!=0) { bool Found=false; for (int I=0;I4 ? L"\n":L" "):L", "); int KeyPos=ItemKeyPos[I]; for (int J=0;J[{key};"{string}"p used to redefine // a keyboard key on some terminals. if (Data[J]=='\"') return true; if (!IsDigit(Data[J]) && Data[J]!=';') break; } return false; } void OutComment(const wchar *Comment,size_t Size) { if (IsCommentUnsafe(Comment,Size)) return; const size_t MaxOutSize=0x400; for (size_t I=0;I>1)^0xEDB88320 : (C>>1); CRCTab[I]=C; } } static void InitTables() { InitCRC32(crc_tables[0]); for (uint I=0;I<256;I++) // Build additional lookup tables. { uint C=crc_tables[0][I]; for (uint J=1;J<8;J++) { C=crc_tables[0][(byte)C]^(C>>8); crc_tables[J][I]=C; } } } struct CallInitCRC {CallInitCRC() {InitTables();}} static CallInit32; uint CRC32(uint StartCRC,const void *Addr,size_t Size) { 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); uint NextData = Data[4]|(Data[5] << 8)|(Data[6] << 16)|(Data[7] << 24); #else StartCRC ^= *(uint32 *) Data; uint NextData = *(uint32 *) (Data +4); #endif StartCRC = crc_tables[7][(byte) StartCRC ] ^ crc_tables[6][(byte)(StartCRC >> 8) ] ^ crc_tables[5][(byte)(StartCRC >> 16)] ^ crc_tables[4][(byte)(StartCRC >> 24)] ^ crc_tables[3][(byte) NextData ] ^ crc_tables[2][(byte)(NextData >>8 ) ] ^ crc_tables[1][(byte)(NextData >> 16)] ^ crc_tables[0][(byte)(NextData >> 24)]; } for (;Size>0;Size--,Data++) // Process left data. StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8); return StartCRC; } #ifndef SFX_MODULE // For RAR 1.4 archives in case somebody still has them. ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size) { byte *Data=(byte *)Addr; for (size_t I=0;I>15))&0xffff; } return StartCRC; } #endif unrar/crypt.cpp0100666000000000000000000000502112176732144011144 0ustar z#include "rar.hpp" #ifndef SFX_MODULE #include "crypt1.cpp" #include "crypt2.cpp" #endif #include "crypt3.cpp" #include "crypt5.cpp" CryptData::CryptData() { Method=CRYPT_NONE; memset(KDFCache,0,sizeof(KDFCache)); KDFCachePos=0; memset(CRCTab,0,sizeof(CRCTab)); } CryptData::~CryptData() { cleandata(KDFCache,sizeof(KDFCache)); } void CryptData::DecryptBlock(byte *Buf,size_t Size) { switch(Method) { #ifndef SFX_MODULE case CRYPT_RAR13: Decrypt13(Buf,Size); break; case CRYPT_RAR15: Crypt15(Buf,Size); break; case CRYPT_RAR20: for (size_t I=0;IIsSet() || Method==CRYPT_NONE) return false; CryptData::Method=Method; wchar PwdW[MAXPASSWORD]; Password->Get(PwdW,ASIZE(PwdW)); char PwdA[MAXPASSWORD]; WideToChar(PwdW,PwdA,ASIZE(PwdA)); switch(Method) { #ifndef SFX_MODULE case CRYPT_RAR13: SetKey13(PwdA); break; case CRYPT_RAR15: SetKey15(PwdA); break; case CRYPT_RAR20: SetKey20(PwdA); break; #endif case CRYPT_RAR30: SetKey30(Encrypt,Password,PwdW,Salt); break; case CRYPT_RAR50: SetKey50(Encrypt,Password,PwdW,Salt,InitV,Lg2Cnt,HashKey,PswCheck); break; } cleandata(PwdA,sizeof(PwdA)); cleandata(PwdW,sizeof(PwdW)); return true; } // Fill buffer with random data. void GetRnd(byte *RndBuf,size_t BufSize) { bool Success=false; #if defined(_WIN_ALL) HCRYPTPROV hProvider = 0; if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { Success=CryptGenRandom(hProvider, (DWORD)BufSize, RndBuf) == TRUE; CryptReleaseContext(hProvider, 0); } #elif defined(_UNIX) FILE *rndf = fopen("/dev/urandom", "r"); if (rndf!=NULL) { Success=fread(RndBuf, BufSize, 1, rndf) == BufSize; fclose(rndf); } #endif // We use this code only as the last resort if code above failed. if (!Success) { static uint Count=0; RarTime CurTime; CurTime.SetCurrentTime(); uint64 Random=CurTime.GetRaw()+clock(); for (size_t I=0;I> ( (I & 7) * 8 )); RndBuf[I]=byte( (RndByte ^ I) + Count++); } } } unrar/crypt1.cpp0100666000000000000000000000300612176732144011226 0ustar zextern uint CRCTab[256]; #define rol(x,n,xsize) (((x)<<(n)) | ((x)>>(xsize-(n)))) #define ror(x,n,xsize) (((x)>>(n)) | ((x)<<(xsize-(n)))) void CryptData::SetKey13(const char *Password) { Key13[0]=Key13[1]=Key13[2]=0; for (size_t I=0;Password[I]!=0;I++) { byte P=Password[I]; Key13[0]+=P; Key13[1]^=P; Key13[2]+=P; Key13[2]=(byte)rol(Key13[2],1,8); } } void CryptData::SetKey15(const char *Password) { InitCRC32(CRCTab); uint PswCRC=CRC32(0xffffffff,Password,strlen(Password)); Key15[0]=PswCRC&0xffff; Key15[1]=(PswCRC>>16)&0xffff; Key15[2]=Key15[3]=0; for (size_t I=0;Password[I]!=0;I++) { byte P=Password[I]; Key15[2]^=P^CRCTab[P]; Key15[3]+=P+(CRCTab[P]>>16); } } void CryptData::SetAV15Encryption() { InitCRC32(CRCTab); Method=CRYPT_RAR15; Key15[0]=0x4765; Key15[1]=0x9021; Key15[2]=0x7382; Key15[3]=0x5215; } void CryptData::SetCmt13Encryption() { Method=CRYPT_RAR13; Key13[0]=0; Key13[1]=7; Key13[2]=77; } void CryptData::Decrypt13(byte *Data,size_t Count) { while (Count--) { Key13[1]+=Key13[2]; Key13[0]+=Key13[1]; *Data-=Key13[0]; Data++; } } void CryptData::Crypt15(byte *Data,size_t Count) { while (Count--) { Key15[0]+=0x1234; Key15[1]^=CRCTab[(Key15[0] & 0x1fe)>>1]; Key15[2]-=CRCTab[(Key15[0] & 0x1fe)>>1]>>16; Key15[0]^=Key15[2]; Key15[3]=ror(Key15[3]&0xffff,1,16)^Key15[1]; Key15[3]=ror(Key15[3]&0xffff,1,16); Key15[0]^=Key15[3]; *Data^=(byte)(Key15[0]>>8); Data++; } } unrar/crypt2.cpp0100666000000000000000000001275412176732144011241 0ustar z#define NROUNDS 32 #define substLong(t) ( (uint)SubstTable20[(uint)t&255] | \ ((uint)SubstTable20[(int)(t>> 8)&255]<< 8) | \ ((uint)SubstTable20[(int)(t>>16)&255]<<16) | \ ((uint)SubstTable20[(int)(t>>24)&255]<<24) ) static byte InitSubstTable20[256]={ 215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221, 2, 42, 232, 1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137, 255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86, 6, 71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235, 107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36, 158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251, 97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11, 164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51, 207,120,189,210, 8,226, 41, 72,183,203,135,165,166, 60, 98, 7, 122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80, 131, 3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129, 224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10, 118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45, 4,148,108, 161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225, 0, 46,169,186, 68, 95,237, 65, 53,208,253,168, 9, 18,100, 52, 116,184,160, 96,109, 37, 30,106,140,104,150, 5,204,117,112, 84 }; void CryptData::SetKey20(const char *Password) { InitCRC32(CRCTab); char Psw[MAXPASSWORD]; strncpyz(Psw,Password,ASIZE(Psw)); // We'll need to modify it below. size_t PswLength=strlen(Psw); Key20[0]=0xD3A3B879L; Key20[1]=0x3F6D12F7L; Key20[2]=0x7515A235L; Key20[3]=0xA4E7F123L; memcpy(SubstTable20,InitSubstTable20,sizeof(SubstTable20)); for (int J=0;J<256;J++) for (size_t I=0;I>8); Buf[2]=(byte)(C>>16); Buf[3]=(byte)(C>>24); D^=Key20[1]; Buf[4]=(byte)D; Buf[5]=(byte)(D>>8); Buf[6]=(byte)(D>>16); Buf[7]=(byte)(D>>24); A^=Key20[2]; Buf[8]=(byte)A; Buf[9]=(byte)(A>>8); Buf[10]=(byte)(A>>16); Buf[11]=(byte)(A>>24); B^=Key20[3]; Buf[12]=(byte)B; Buf[13]=(byte)(B>>8); Buf[14]=(byte)(B>>16); Buf[15]=(byte)(B>>24); #else BufPtr[0]=C^Key20[0]; BufPtr[1]=D^Key20[1]; BufPtr[2]=A^Key20[2]; BufPtr[3]=B^Key20[3]; #endif UpdKeys20(Buf); } void CryptData::DecryptBlock20(byte *Buf) { byte InBuf[16]; uint A,B,C,D,T,TA,TB; #if defined(BIG_ENDIAN) || !defined(PRESENT_INT32) || !defined(ALLOW_NOT_ALIGNED_INT) A=((uint)Buf[0]|((uint)Buf[1]<<8)|((uint)Buf[2]<<16)|((uint)Buf[3]<<24))^Key20[0]; B=((uint)Buf[4]|((uint)Buf[5]<<8)|((uint)Buf[6]<<16)|((uint)Buf[7]<<24))^Key20[1]; C=((uint)Buf[8]|((uint)Buf[9]<<8)|((uint)Buf[10]<<16)|((uint)Buf[11]<<24))^Key20[2]; D=((uint)Buf[12]|((uint)Buf[13]<<8)|((uint)Buf[14]<<16)|((uint)Buf[15]<<24))^Key20[3]; #else uint32 *BufPtr=(uint32 *)Buf; A=BufPtr[0]^Key20[0]; B=BufPtr[1]^Key20[1]; C=BufPtr[2]^Key20[2]; D=BufPtr[3]^Key20[3]; #endif memcpy(InBuf,Buf,sizeof(InBuf)); for(int I=NROUNDS-1;I>=0;I--) { T=((C+rol(D,11,32))^Key20[I&3]); TA=A^substLong(T); T=((D^rol(C,17,32))+Key20[I&3]); TB=B^substLong(T); A=C; B=D; C=TA; D=TB; } #if defined(BIG_ENDIAN) || !defined(PRESENT_INT32) || !defined(ALLOW_NOT_ALIGNED_INT) C^=Key20[0]; Buf[0]=(byte)C; Buf[1]=(byte)(C>>8); Buf[2]=(byte)(C>>16); Buf[3]=(byte)(C>>24); D^=Key20[1]; Buf[4]=(byte)D; Buf[5]=(byte)(D>>8); Buf[6]=(byte)(D>>16); Buf[7]=(byte)(D>>24); A^=Key20[2]; Buf[8]=(byte)A; Buf[9]=(byte)(A>>8); Buf[10]=(byte)(A>>16); Buf[11]=(byte)(A>>24); B^=Key20[3]; Buf[12]=(byte)B; Buf[13]=(byte)(B>>8); Buf[14]=(byte)(B>>16); Buf[15]=(byte)(B>>24); #else BufPtr[0]=C^Key20[0]; BufPtr[1]=D^Key20[1]; BufPtr[2]=A^Key20[2]; BufPtr[3]=B^Key20[3]; #endif UpdKeys20(InBuf); } void CryptData::UpdKeys20(byte *Buf) { for (int I=0;I<16;I+=4) { Key20[0]^=CRCTab[Buf[I]]; Key20[1]^=CRCTab[Buf[I+1]]; Key20[2]^=CRCTab[Buf[I+2]]; Key20[3]^=CRCTab[Buf[I+3]]; } } void CryptData::Swap20(byte *Ch1,byte *Ch2) { byte Ch=*Ch1; *Ch1=*Ch2; *Ch2=Ch; } unrar/crypt3.cpp0100666000000000000000000000443212176732144011234 0ustar zstruct CryptKeyCacheItem { CryptKeyCacheItem() { Password.Set(L""); } ~CryptKeyCacheItem() { cleandata(AESKey,sizeof(AESKey)); cleandata(AESInit,sizeof(AESInit)); cleandata(&Password,sizeof(Password)); } byte AESKey[16],AESInit[16]; SecPassword Password; bool SaltPresent; byte Salt[SIZE_SALT30]; }; static CryptKeyCacheItem Cache[4]; static int CachePos=0; void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt) { byte AESKey[16],AESInit[16]; bool Cached=false; for (uint I=0;I>8); PswNum[2]=(byte)(I>>16); hash_process( &c, PswNum, 3, false); if (I%(HashRounds/16)==0) { hash_context tempc=c; uint32 digest[5]; hash_final( &tempc, digest, false); AESInit[I/(HashRounds/16)]=(byte)digest[4]; } } uint32 digest[5]; hash_final( &c, digest, false); for (int I=0;I<4;I++) for (int J=0;J<4;J++) AESKey[I*4+J]=(byte)(digest[I]>>(J*8)); Cache[CachePos].Password=*Password; if ((Cache[CachePos].SaltPresent=(Salt!=NULL))==true) memcpy(Cache[CachePos].Salt,Salt,SIZE_SALT30); memcpy(Cache[CachePos].AESKey,AESKey,sizeof(AESKey)); memcpy(Cache[CachePos].AESInit,AESInit,sizeof(AESInit)); CachePos=(CachePos+1)%ASIZE(Cache); cleandata(RawPsw,sizeof(RawPsw)); } rin.Init(Encrypt, AESKey, 128, AESInit); cleandata(AESKey,sizeof(AESKey)); cleandata(AESInit,sizeof(AESInit)); } unrar/crypt5.cpp0100666000000000000000000001526312176732144011242 0ustar zvoid hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data, size_t DataLength,byte *ResDigest) { const size_t Sha256BlockSize=64; // As defined in RFC 4868. byte KeyHash[SHA256_DIGEST_SIZE]; if (KeyLength > Sha256BlockSize) // Convert longer keys to key hash. { sha256_context KCtx; sha256_init(&KCtx); sha256_process(&KCtx, Key, KeyLength); sha256_done(&KCtx, KeyHash); Key = KeyHash; KeyLength = SHA256_DIGEST_SIZE; } byte KeyBuf[Sha256BlockSize]; // Store the padded key here. for (size_t I = 0; I < KeyLength; I++) // Use 0x36 padding for inner digest. KeyBuf[I] = Key[I] ^ 0x36; for (size_t I = KeyLength; I < Sha256BlockSize; I++) KeyBuf[I] = 0x36; sha256_context ICtx; sha256_init(&ICtx); sha256_process(&ICtx, KeyBuf, Sha256BlockSize); // Hash padded key. sha256_process(&ICtx, Data, DataLength); // Hash data. byte IDig[SHA256_DIGEST_SIZE]; // Internal digest for padded key and data. sha256_done(&ICtx, IDig); sha256_context RCtx; sha256_init(&RCtx); for (size_t I = 0; I < KeyLength; I++) // Use 0x5c for outer key padding. KeyBuf[I] = Key[I] ^ 0x5c; for (size_t I = KeyLength; I < Sha256BlockSize; I++) KeyBuf[I] = 0x5c; sha256_process(&RCtx, KeyBuf, Sha256BlockSize); // Hash padded key. sha256_process(&RCtx, IDig, SHA256_DIGEST_SIZE); // Hash internal digest. sha256_done(&RCtx, ResDigest); } // PBKDF2 for 32 byte key length. We generate the key for specified number // of iteration count also as two supplementary values (key for checksums // and password verification) for iterations+16 and iterations+32. void pbkdf2(const byte *Pwd, size_t PwdLength, const byte *Salt, size_t SaltLength, byte *Key, byte *V1, byte *V2, uint Count) { const size_t MaxSalt=64; byte SaltData[MaxSalt+4]; memcpy(SaltData, Salt, Min(SaltLength,MaxSalt)); SaltData[SaltLength + 0] = 0; // Salt concatenated to 1. SaltData[SaltLength + 1] = 0; SaltData[SaltLength + 2] = 0; SaltData[SaltLength + 3] = 1; // First iteration: HMAC of password, salt and block index (1). byte U1[SHA256_DIGEST_SIZE]; hmac_sha256(Pwd, PwdLength, SaltData, SaltLength + 4, U1); byte Fn[SHA256_DIGEST_SIZE]; // Current function value. memcpy(Fn, U1, sizeof(Fn)); // Function at first iteration. uint CurCount[] = { Count-1, 16, 16 }; byte *CurValue[] = { Key , V1, V2 }; byte U2[SHA256_DIGEST_SIZE]; for (uint I = 0; I < 3; I++) // For output key and 2 supplementary values. { for (uint J = 0; J < CurCount[I]; J++) { hmac_sha256(Pwd, PwdLength, U1, sizeof(U1), U2); // U2 = PRF (P, U1). memcpy(U1, U2, sizeof(U1)); for (uint K = 0; K < sizeof(Fn); K++) // Function ^= U. Fn[K] ^= U1[K]; } memcpy(CurValue[I], Fn, SHA256_DIGEST_SIZE); } cleandata(SaltData, sizeof(SaltData)); cleandata(Fn, sizeof(Fn)); cleandata(U1, sizeof(U1)); cleandata(U2, sizeof(U2)); } void CryptData::SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW, const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey, byte *PswCheck) { if (Lg2Cnt>CRYPT5_KDF_LG2_COUNT_MAX) return; byte Key[32],PswCheckValue[SHA256_DIGEST_SIZE],HashKeyValue[SHA256_DIGEST_SIZE]; bool Found=false; for (uint I=0;ILg2Count==Lg2Cnt && Item->Pwd==*Password && memcmp(Item->Salt,Salt,SIZE_SALT50)==0) { SecHideData(Item->Key,sizeof(Item->Key),false); memcpy(Key,Item->Key,sizeof(Key)); SecHideData(Item->Key,sizeof(Item->Key),true); memcpy(PswCheckValue,Item->PswCheckValue,sizeof(PswCheckValue)); memcpy(HashKeyValue,Item->HashKeyValue,sizeof(HashKeyValue)); Found=true; break; } } if (!Found) { char PwdUtf[MAXPASSWORD*4]; WideToUtf(PwdW,PwdUtf,ASIZE(PwdUtf)); pbkdf2((byte *)PwdUtf,strlen(PwdUtf),Salt,SIZE_SALT50,Key,HashKeyValue,PswCheckValue,(1<Lg2Count=Lg2Cnt; Item->Pwd=*Password; memcpy(Item->Salt,Salt,SIZE_SALT50); memcpy(Item->Key,Key,sizeof(Key)); memcpy(Item->PswCheckValue,PswCheckValue,sizeof(PswCheckValue)); memcpy(Item->HashKeyValue,HashKeyValue,sizeof(HashKeyValue)); SecHideData(Item->Key,sizeof(Key),true); } if (HashKey!=NULL) memcpy(HashKey,HashKeyValue,SHA256_DIGEST_SIZE); if (PswCheck!=NULL) { memset(PswCheck,0,SIZE_PSWCHECK); for (uint I=0;IType==HASH_CRC32) { byte RawCRC[4]; RawPut4(Value->CRC32,RawCRC); byte Digest[SHA256_DIGEST_SIZE]; hmac_sha256(Key,SHA256_DIGEST_SIZE,RawCRC,sizeof(RawCRC),Digest); Value->CRC32=0; for (uint I=0;ICRC32^=Digest[I] << ((I & 3) * 8); } if (Value->Type==HASH_BLAKE2) { byte Digest[BLAKE2_DIGEST_SIZE]; hmac_sha256(Key,BLAKE2_DIGEST_SIZE,Value->Digest,sizeof(Value->Digest),Digest); memcpy(Value->Digest,Digest,sizeof(Value->Digest)); } } #if 0 static void TestPBKDF2(); struct TestKDF {TestKDF() {TestPBKDF2();exit(0);}} GlobalTestKDF; void TestPBKDF2() // Test PBKDF2 HMAC-SHA256 { byte Key[32],V1[32],V2[32]; pbkdf2((byte *)"password", 8, (byte *)"salt", 4, Key, V1, V2, 1); byte Res1[32]={0x12, 0x0f, 0xb6, 0xcf, 0xfc, 0xf8, 0xb3, 0x2c, 0x43, 0xe7, 0x22, 0x52, 0x56, 0xc4, 0xf8, 0x37, 0xa8, 0x65, 0x48, 0xc9, 0x2c, 0xcc, 0x35, 0x48, 0x08, 0x05, 0x98, 0x7c, 0xb7, 0x0b, 0xe1, 0x7b }; mprintf(L"\nPBKDF2 test1: %s", memcmp(Key,Res1,32)==0 ? L"OK":L"Failed"); pbkdf2((byte *)"password", 8, (byte *)"salt", 4, Key, V1, V2, 4096); byte Res2[32]={0xc5, 0xe4, 0x78, 0xd5, 0x92, 0x88, 0xc8, 0x41, 0xaa, 0x53, 0x0d, 0xb6, 0x84, 0x5c, 0x4c, 0x8d, 0x96, 0x28, 0x93, 0xa0, 0x01, 0xce, 0x4e, 0x11, 0xa4, 0x96, 0x38, 0x73, 0xaa, 0x98, 0x13, 0x4a }; mprintf(L"\nPBKDF2 test2: %s", memcmp(Key,Res2,32)==0 ? L"OK":L"Failed"); pbkdf2((byte *)"just some long string pretending to be a password", 49, (byte *)"salt, salt, salt, a lot of salt", 31, Key, V1, V2, 65536); byte Res3[32]={0x08, 0x0f, 0xa3, 0x1d, 0x42, 0x2d, 0xb0, 0x47, 0x83, 0x9b, 0xce, 0x3a, 0x3b, 0xce, 0x49, 0x51, 0xe2, 0x62, 0xb9, 0xff, 0x76, 0x2f, 0x57, 0xe9, 0xc4, 0x71, 0x96, 0xce, 0x4b, 0x6b, 0x6e, 0xbf}; mprintf(L"\nPBKDF2 test3: %s", memcmp(Key,Res3,32)==0 ? L"OK":L"Failed"); } #endif unrar/dll.cpp0100666000000000000000000002551112176732144010564 0ustar z#include "rar.hpp" #include "dll.hpp" static int RarErrorToDll(RAR_EXIT ErrCode); struct DataSet { CommandData Cmd; Archive Arc; CmdExtract Extract; int OpenMode; int HeaderSize; DataSet():Arc(&Cmd),Extract(&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(L"*"); char AnsiArcName[NM]; *AnsiArcName=0; if (r->ArcName!=NULL) { strncpyz(AnsiArcName,r->ArcName,ASIZE(AnsiArcName)); #ifdef _WIN_ALL if (!AreFileApisANSI()) { OemToCharBuffA(r->ArcName,AnsiArcName,ASIZE(AnsiArcName)); AnsiArcName[ASIZE(AnsiArcName)-1]=0; } #endif } wchar ArcName[NM]; GetWideName(AnsiArcName,r->ArcNameW,ArcName,ASIZE(ArcName)); Data->Cmd.AddArcName(ArcName); Data->Cmd.Overwrite=OVERWRITE_ALL; Data->Cmd.VersionControl=1; Data->Cmd.Callback=r->Callback; Data->Cmd.UserData=r->UserData; if (!Data->Arc.Open(ArcName,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=0; if (Data->Arc.Volume) r->Flags|=0x01; if (Data->Arc.Locked) r->Flags|=0x04; if (Data->Arc.Solid) r->Flags|=0x08; if (Data->Arc.NewNumbering) r->Flags|=0x10; if (Data->Arc.Signed) r->Flags|=0x20; if (Data->Arc.Protected) r->Flags|=0x40; if (Data->Arc.Encrypted) r->Flags|=0x80; if (Data->Arc.FirstVolume) r->Flags|=0x100; Array CmtDataW; if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtDataW)) { Array CmtData(CmtDataW.Size()*4+1); memset(&CmtData[0],0,CmtData.Size()); WideToChar(&CmtDataW[0],&CmtData[0],CmtData.Size()-1); size_t Size=strlen(&CmtData[0])+1; r->Flags|=2; 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; 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; } return NULL; // To make compilers happy. } int PASCAL RARCloseArchive(HANDLE hArcData) { DataSet *Data=(DataSet *)hArcData; bool Success=Data==NULL ? false:Data->Arc.Close(); delete Data; return Success ? ERAR_SUCCESS : 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(HEAD_FILE))<=0) { if (Data->Arc.Volume && Data->Arc.GetHeaderType()==HEAD_ENDARC && Data->Arc.EndArcHead.NextVolume) if (MergeArchive(Data->Arc,NULL,false,'L')) { Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET); return RARReadHeaderEx(hArcData,D); } else return ERAR_EOPEN; return(Data->Arc.BrokenHeader ? ERAR_BAD_DATA:ERAR_END_ARCHIVE); } FileHeader *hd=&Data->Arc.FileHead; if (Data->OpenMode==RAR_OM_LIST && hd->SplitBefore) { int Code=RARProcessFile(hArcData,RAR_SKIP,NULL,NULL); if (Code==0) return RARReadHeaderEx(hArcData,D); else return Code; } wcsncpy(D->ArcNameW,hd->FileName,ASIZE(D->ArcNameW)); WideToChar(D->ArcNameW,D->ArcName,ASIZE(D->ArcName)); wcsncpy(D->FileNameW,hd->FileName,ASIZE(D->FileNameW)); WideToChar(D->FileNameW,D->FileName,ASIZE(D->FileName)); #ifdef _WIN_ALL CharToOemA(D->FileName,D->FileName); #endif D->Flags=0; if (hd->SplitBefore) D->Flags|=RHDF_SPLITBEFORE; if (hd->SplitAfter) D->Flags|=RHDF_SPLITAFTER; if (hd->Encrypted) D->Flags|=RHDF_ENCRYPTED; if (hd->Solid) D->Flags|=RHDF_SOLID; if (hd->Dir) D->Flags|=RHDF_DIRECTORY; D->PackSize=uint(hd->PackSize & 0xffffffff); D->PackSizeHigh=uint(hd->PackSize>>32); D->UnpSize=uint(hd->UnpSize & 0xffffffff); D->UnpSizeHigh=uint(hd->UnpSize>>32); D->HostOS=hd->HSType==HSYS_WINDOWS ? HOST_WIN32:HOST_UNIX; if (Data->Arc.Format==RARFMT50) D->UnpVer=Data->Arc.FileHead.UnpVer==0 ? 50 : 200; // If it is not 0, just set it to something big. else D->UnpVer=Data->Arc.FileHead.UnpVer; D->FileCRC=hd->FileHash.CRC32; D->FileTime=hd->mtime.GetDos(); D->Method=hd->Method+0x30; D->FileAttr=hd->FileAttr; D->CmtSize=0; D->CmtState=0; D->DictSize=uint(hd->WinSize/1024); switch (hd->FileHash.Type) { case HASH_RAR14: case HASH_CRC32: D->HashType=RAR_HASH_CRC32; break; case HASH_BLAKE2: D->HashType=RAR_HASH_BLAKE2; memcpy(D->Hash,hd->FileHash.Digest,BLAKE2_DIGEST_SIZE); break; default: D->HashType=RAR_HASH_NONE; break; } } catch (RAR_EXIT ErrCode) { return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode); } return ERAR_SUCCESS; } 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()==HEAD_FILE && Data->Arc.FileHead.SplitAfter) if (MergeArchive(Data->Arc,NULL,false,'L')) { Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET); return ERAR_SUCCESS; } else return ERAR_EOPEN; Data->Arc.SeekToNext(); } else { Data->Cmd.DllOpMode=Operation; *Data->Cmd.ExtrPath=0; *Data->Cmd.DllDestName=0; if (DestPath!=NULL) { char ExtrPathA[NM]; #ifdef _WIN_ALL OemToCharBuffA(DestPath,ExtrPathA,ASIZE(ExtrPathA)-2); #else strncpyz(ExtrPathA,DestPath,ASIZE(ExtrPathA)-2); #endif CharToWide(ExtrPathA,Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath)); AddEndSlash(Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath)); } if (DestName!=NULL) { char DestNameA[NM]; #ifdef _WIN_ALL OemToCharBuffA(DestName,DestNameA,ASIZE(DestNameA)-2); #else strncpyz(DestNameA,DestName,ASIZE(DestNameA)-2); #endif CharToWide(DestNameA,Data->Cmd.DllDestName,ASIZE(Data->Cmd.DllDestName)); } if (DestPathW!=NULL) { wcsncpy(Data->Cmd.ExtrPath,DestPathW,ASIZE(Data->Cmd.ExtrPath)); AddEndSlash(Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath)); } if (DestNameW!=NULL) wcsncpyz(Data->Cmd.DllDestName,DestNameW,ASIZE(Data->Cmd.DllDestName)); wcscpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T"); Data->Cmd.Test=Operation!=RAR_EXTRACT; bool Repeat=false; Data->Extract.ExtractCurrentFile(&Data->Cmd,Data->Arc,Data->HeaderSize,Repeat); // 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()==HEAD_SERVICE) { 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 ERAR_SUCCESS; // 0. default: return ERAR_UNKNOWN; } } unrar/encname.cpp0100666000000000000000000000245012176732144011414 0ustar z#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>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 && DecPos0 && DecPosMAX_PATH) { Log(NULL,St(MMaxPathLimit),MAX_PATH); } } #endif } void ErrorHandler::ReadErrorMsg(const wchar *FileName) { ReadErrorMsg(NULL,FileName); } void ErrorHandler::ReadErrorMsg(const wchar *ArcName,const wchar *FileName) { #ifndef SILENT Log(ArcName,St(MErrRead),FileName); SysErrMsg(); #endif } void ErrorHandler::WriteErrorMsg(const wchar *ArcName,const wchar *FileName) { #ifndef SILENT Log(ArcName,St(MErrWrite),FileName); SysErrMsg(); #endif } void ErrorHandler::Exit(RAR_EXIT ExitCode) { #ifndef GUI Alarm(); #endif Throw(ExitCode); } 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++; } #ifndef GUI #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 ErrHandler.UserBreak=true; mprintf(St(MBreak)); #ifdef _WIN_ALL // Let the main thread to handle 'throw' and destroy file objects. for (uint I=0;!ErrHandler.MainExit && I<50;I++) Sleep(100); #if defined(USE_RC) && !defined(SFX_MODULE) && !defined(RARDLL) ExtRes.UnloadDLL(); #endif exit(RARX_USERBREAK); #endif #ifdef _UNIX static uint BreakCount=0; // User continues to press Ctrl+C, exit immediately without cleanup. if (++BreakCount>1) exit(RARX_USERBREAK); // Otherwise return from signal handler and let Wait() function to close // files and quit. We cannot use the same approach as in Windows, // because Unix signal handler can block execution of our main code. #endif #if defined(_WIN_ALL) && !defined(_MSC_VER) // never reached, just to avoid a compiler warning return TRUE; #endif } #endif void ErrorHandler::SetSignalHandlers(bool Enable) { EnableBreak=Enable; #ifndef GUI #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; #if !defined(GUI) && !defined(SILENT) // Do not write "aborted" when just displaying online help. if (Code!=RARX_SUCCESS && Code!=RARX_USERERROR) mprintf(L"\n%s\n",St(MProgAborted)); #endif ErrHandler.SetErrorCode(Code); throw Code; } 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++; } Log(NULL,L"\n%ls",CurMsg); CurMsg=EndMsg; } } LocalFree( lpMsgBuf ); #endif #if defined(_UNIX) || defined(_EMX) if (errno!=0) { char *err=strerror(errno); if (err!=NULL) { wchar MsgW[1024]; CharToWide(err,MsgW,ASIZE(MsgW)); Log(NULL,L"\n%s",MsgW); } } #endif #endif } int ErrorHandler::GetSystemErrorCode() { #ifdef _WIN_ALL return GetLastError(); #else return errno; #endif } void ErrorHandler::SetSystemErrorCode(int Code) { #ifdef _WIN_ALL SetLastError(Code); #else errno=Code; #endif } unrar/extinfo.cpp0100666000000000000000000000332412176732144011463 0ustar z#include "rar.hpp" #include "hardlinks.cpp" #include "win32stm.cpp" #ifdef _WIN_ALL #include "win32acl.cpp" #include "win32lnk.cpp" #endif #ifdef _UNIX #include "uowners.cpp" #ifdef SAVE_LINKS #include "ulinks.cpp" #endif #endif #ifndef SFX_MODULE void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name) { switch(Arc.SubBlockHead.SubType) { #ifdef _UNIX case UO_HEAD: if (Cmd->ProcessOwners) ExtractUnixOwner20(Arc,Name); break; #endif #ifdef _WIN_ALL case NTACL_HEAD: if (Cmd->ProcessOwners) ExtractACL20(Arc,Name); break; case STREAM_HEAD: ExtractStreams20(Arc,Name); break; #endif } } #endif void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name) { #ifdef _UNIX if (Cmd->ProcessOwners && Arc.Format==RARFMT15 && Arc.SubHead.CmpName(SUBHEAD_TYPE_UOWNER)) ExtractUnixOwner30(Arc,Name); #endif #ifdef _WIN_ALL if (Cmd->ProcessOwners && Arc.SubHead.CmpName(SUBHEAD_TYPE_ACL)) ExtractACL(Arc,Name); if (Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM)) ExtractStreams(Arc,Name); #endif } bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName) { #if defined(SAVE_LINKS) && defined(_UNIX) // For RAR 3.x archives we process links even in test mode to skip link data. if (Arc.Format==RARFMT15) return ExtractUnixLink30(DataIO,Arc,LinkName); if (Arc.Format==RARFMT50) return ExtractUnixLink50(LinkName,&Arc.FileHead); #elif defined _WIN_ALL // RAR 5.0 archives store link information in file header, so there is // no need to additionally test it if we do not create a file. if (Arc.Format==RARFMT50) return CreateReparsePoint(Cmd,LinkName,&Arc.FileHead); #endif return false; } unrar/extract.cpp0100666000000000000000000007116412176732144011470 0ustar z#include "rar.hpp" CmdExtract::CmdExtract(CommandData *Cmd) { *ArcName=0; *DestFileName=0; TotalFileCount=0; Password.Set(L""); Unp=new Unpack(&DataIO); #ifdef RAR_SMP Unp->SetThreads(Cmd->Threads); #endif } CmdExtract::~CmdExtract() { delete Unp; } void CmdExtract::DoExtract(CommandData *Cmd) { PasswordCancelled=false; DataIO.SetCurrentCommand(Cmd->Command[0]); FindData FD; while (Cmd->GetArcName(ArcName,ASIZE(ArcName))) if (FindFile::FastFind(ArcName,&FD)) DataIO.TotalArcSize+=FD.Size; Cmd->ArcNames.Rewind(); while (Cmd->GetArcName(ArcName,ASIZE(ArcName))) { while (true) { SecPassword PrevCmdPassword; PrevCmdPassword=Cmd->Password; EXTRACT_ARC_CODE Code=ExtractArchive(Cmd); // Restore Cmd->Password, which could be changed in IsArchive() call // for next header encrypted archive. Cmd->Password=PrevCmdPassword; if (Code!=EXTRACT_ARC_REPEAT) break; } if (FindFile::FastFind(ArcName,&FD)) DataIO.ProcessedArcSize+=FD.Size; } if (TotalFileCount==0 && Cmd->Command[0]!='I' && ErrHandler.GetErrorCode()!=RARX_BADPWD) // Not in case of wrong archive password. { if (!PasswordCancelled) { mprintf(St(MExtrNoFiles)); } ErrHandler.SetErrorCode(RARX_NOFILES); } #ifndef GUI else if (!Cmd->DisableDone) if (Cmd->Command[0]=='I') mprintf(St(MDone)); else if (ErrHandler.GetErrorCount()==0) mprintf(St(MExtrAllOk)); else mprintf(St(MExtrTotalErr),ErrHandler.GetErrorCount()); #endif } void CmdExtract::ExtractArchiveInit(CommandData *Cmd,Archive &Arc) { DataIO.UnpArcSize=Arc.FileLength(); FileCount=0; MatchedArgs=0; #ifndef SFX_MODULE FirstFile=true; #endif PasswordAll=(Cmd->Password.IsSet()); if (PasswordAll) Password=Cmd->Password; DataIO.UnpVolume=false; PrevExtracted=false; AllMatchesExact=true; ReconstructDone=false; AnySolidDataUnpackedWell=false; StartTime.SetCurrentTime(); } EXTRACT_ARC_CODE CmdExtract::ExtractArchive(CommandData *Cmd) { Archive Arc(Cmd); if (!Arc.WOpen(ArcName)) { ErrHandler.SetErrorCode(RARX_OPEN); return EXTRACT_ARC_NEXT; } if (!Arc.IsArchive(true)) { #ifndef GUI mprintf(St(MNotRAR),ArcName); #endif if (CmpExt(ArcName,L"rar")) ErrHandler.SetErrorCode(RARX_WARNING); return EXTRACT_ARC_NEXT; } if (Arc.FailedHeaderDecryption) // Bad archive password. return EXTRACT_ARC_NEXT; #ifndef SFX_MODULE if (Arc.Volume && !Arc.FirstVolume) { wchar FirstVolName[NM]; VolNameToFirstName(ArcName,FirstVolName,Arc.NewNumbering); // If several volume names from same volume set are specified // and current volume is not first in set and first volume is present // and specified too, let's skip the current volume. if (wcsicomp(ArcName,FirstVolName)!=0 && FileExist(FirstVolName) && Cmd->ArcNames.Search(FirstVolName,false)) return EXTRACT_ARC_NEXT; } #endif int64 VolumeSetSize=0; // Total size of volumes after the current volume. if (Arc.Volume) { // Calculate the total size of all accessible volumes. // This size is necessary to display the correct total progress indicator. wchar NextName[NM]; wcscpy(NextName,Arc.FileName); while (true) { // First volume is already added to DataIO.TotalArcSize // in initial TotalArcSize calculation in DoExtract. // So we skip it and start from second volume. NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering); FindData FD; if (FindFile::FastFind(NextName,&FD)) VolumeSetSize+=FD.Size; else break; } DataIO.TotalArcSize+=VolumeSetSize; } ExtractArchiveInit(Cmd,Arc); if (*Cmd->Command=='T' || *Cmd->Command=='I') Cmd->Test=true; #ifndef GUI if (*Cmd->Command=='I') Cmd->DisablePercentage=true; else if (Cmd->Test) mprintf(St(MExtrTest),ArcName); else mprintf(St(MExtracting),ArcName); #endif Arc.ViewComment(); while (1) { size_t Size=Arc.ReadHeader(); bool Repeat=false; if (!ExtractCurrentFile(Cmd,Arc,Size,Repeat)) if (Repeat) { // If we started extraction from not first volume and need to // restart it from first, we must correct DataIO.TotalArcSize // for correct total progress display. We subtract the size // of current volume and all volumes after it and add the size // of new (first) volume. FindData OldArc,NewArc; if (FindFile::FastFind(Arc.FileName,&OldArc) && FindFile::FastFind(ArcName,&NewArc)) DataIO.TotalArcSize-=VolumeSetSize+OldArc.Size-NewArc.Size; return EXTRACT_ARC_REPEAT; } else break; } return EXTRACT_ARC_NEXT; } bool CmdExtract::ExtractCurrentFile(CommandData *Cmd,Archive &Arc,size_t HeaderSize,bool &Repeat) { wchar Command=Cmd->Command[0]; if (HeaderSize==0) if (DataIO.UnpVolume) { #ifdef NOVOLUME return false; #else if (!MergeArchive(Arc,&DataIO,false,Command)) { ErrHandler.SetErrorCode(RARX_WARNING); return false; } #endif } else return false; HEADER_TYPE HeaderType=Arc.GetHeaderType(); if (HeaderType!=HEAD_FILE) { #ifndef SFX_MODULE if (HeaderType==HEAD3_OLDSERVICE && PrevExtracted) SetExtraInfo20(Cmd,Arc,DestFileName); #endif if (HeaderType==HEAD_SERVICE && PrevExtracted) SetExtraInfo(Cmd,Arc,DestFileName); if (HeaderType==HEAD_ENDARC) if (Arc.EndArcHead.NextVolume) { #ifndef NOVOLUME if (!MergeArchive(Arc,&DataIO,false,Command)) { ErrHandler.SetErrorCode(RARX_WARNING); return false; } #endif Arc.Seek(Arc.CurBlockPos,SEEK_SET); return true; } else return false; Arc.SeekToNext(); return true; } PrevExtracted=false; if (!Cmd->Recurse && MatchedArgs>=Cmd->FileArgs.ItemsCount() && AllMatchesExact) return false; int MatchType=MATCH_WILDSUBPATH; bool EqualNames=false; int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType); bool ExactMatch=MatchNumber!=0; #ifndef SFX_MODULE if (Cmd->ExclPath==EXCL_BASEPATH) { *Cmd->ArcPath=0; if (ExactMatch) { Cmd->FileArgs.Rewind(); if (Cmd->FileArgs.GetString(Cmd->ArcPath,ASIZE(Cmd->ArcPath),MatchNumber-1)) *PointToName(Cmd->ArcPath)=0; } } #endif if (ExactMatch && !EqualNames) AllMatchesExact=false; Arc.ConvertAttributes(); #if !defined(SFX_MODULE) && !defined(RARDLL) if (Arc.FileHead.SplitBefore && FirstFile) { wchar CurVolName[NM]; wcsncpyz(CurVolName,ArcName,ASIZE(CurVolName)); VolNameToFirstName(ArcName,ArcName,Arc.NewNumbering); if (wcsicomp(ArcName,CurVolName)!=0 && FileExist(ArcName)) { // If first volume name does not match the current name and if such // volume name really exists, let's unpack from this first volume. Repeat=true; return false; } #ifndef RARDLL if (!ReconstructDone) { ReconstructDone=true; if (RecVolumesRestore(Cmd,Arc.FileName,true)) { Repeat=true; return false; } } #endif wcsncpyz(ArcName,CurVolName,ASIZE(ArcName)); } #endif wchar ArcFileName[NM]; ConvertPath(Arc.FileHead.FileName,ArcFileName); if (Arc.FileHead.Version) { if (Cmd->VersionControl!=1 && !EqualNames) { if (Cmd->VersionControl==0) ExactMatch=false; int Version=ParseVersionFileName(ArcFileName,false); if (Cmd->VersionControl-1==Version) ParseVersionFileName(ArcFileName,true); else ExactMatch=false; } } else if (!Arc.IsArcDir() && Cmd->VersionControl>1) ExactMatch=false; DataIO.UnpVolume=Arc.FileHead.SplitAfter; DataIO.NextVolumeMissing=false; Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET); bool ExtrFile=false; bool SkipSolid=false; #ifndef SFX_MODULE if (FirstFile && (ExactMatch || Arc.Solid) && Arc.FileHead.SplitBefore) { if (ExactMatch) { Log(Arc.FileName,St(MUnpCannotMerge),ArcFileName); #ifdef RARDLL Cmd->DllError=ERAR_BAD_DATA; #endif ErrHandler.SetErrorCode(RARX_OPEN); } ExactMatch=false; } FirstFile=false; #endif if (ExactMatch || (SkipSolid=Arc.Solid)!=0) { ExtrPrepareName(Cmd,Arc,ArcFileName,DestFileName,ASIZE(DestFileName)); // DestFileName can be set empty in case of excessive -ap switch. ExtrFile=!SkipSolid && *DestFileName!=0 && !Arc.FileHead.SplitBefore; if ((Cmd->FreshFiles || Cmd->UpdateFiles) && (Command=='E' || Command=='X')) { FindData FD; if (FindFile::FastFind(DestFileName,&FD)) { if (FD.mtime >= Arc.FileHead.mtime) { // If directory already exists and its modification time is newer // than start of extraction, it is likely it was created // when creating a path to one of already extracted items. // In such case we'll better update its time even if archived // directory is older. if (!FD.IsDir || FD.mtimeFreshFiles) ExtrFile=false; } if (Arc.FileHead.Encrypted) { #ifdef RARDLL if (!ExtrDllGetPassword(Cmd)) return false; #else if (!ExtrGetPassword(Cmd,Arc,ArcFileName)) { PasswordCancelled=true; return false; } #endif // Skip only the current encrypted file if empty password is entered. if (!Password.IsSet()) { ErrHandler.SetErrorCode(RARX_WARNING); #ifdef RARDLL Cmd->DllError=ERAR_MISSING_PASSWORD; #endif ExtrFile=false; } } #ifdef RARDLL if (*Cmd->DllDestName!=0) { wcsncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName)); // Do we need this code? // if (Cmd->DllOpMode!=RAR_EXTRACT) // ExtrFile=false; } #endif if (!CheckUnpVer(Arc,ArcFileName)) { ExtrFile=false; ErrHandler.SetErrorCode(RARX_WARNING); #ifdef RARDLL Cmd->DllError=ERAR_UNKNOWN_FORMAT; #endif } File CurFile; bool LinkEntry=Arc.FileHead.RedirType!=FSREDIR_NONE; if (LinkEntry && Arc.FileHead.RedirType!=FSREDIR_FILECOPY) { if (ExtrFile && Command!='P' && !Cmd->Test) { // Overwrite prompt for symbolic and hard links. bool UserReject=false; if (FileExist(DestFileName) && !UserReject) FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),Cmd->Overwrite,&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime); if (UserReject) ExtrFile=false; } } else if (Arc.IsArcDir()) { if (!ExtrFile || Command=='P' || Command=='I' || Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH) return true; TotalFileCount++; ExtrCreateDir(Cmd,Arc,ArcFileName); return true; } else if (ExtrFile) // Create files and file copies (FSREDIR_FILECOPY). ExtrFile=ExtrCreateFile(Cmd,Arc,CurFile); if (!ExtrFile && Arc.Solid) { SkipSolid=true; ExtrFile=true; } if (ExtrFile) { bool TestMode=Cmd->Test || SkipSolid; // Unpack to memory, not to disk. if (!SkipSolid) { if (!TestMode && Command!='P' && CurFile.IsDevice()) { Log(Arc.FileName,St(MInvalidName),DestFileName); ErrHandler.WriteError(Arc.FileName,DestFileName); } TotalFileCount++; } FileCount++; #ifndef GUI if (Command!='I') if (SkipSolid) mprintf(St(MExtrSkipFile),ArcFileName); else switch(Cmd->Test ? 'T':Command) // "Test" can be also enabled by -t switch. { case 'T': mprintf(St(MExtrTestFile),ArcFileName); break; #ifndef SFX_MODULE case 'P': mprintf(St(MExtrPrinting),ArcFileName); break; #endif case 'X': case 'E': mprintf(St(MExtrFile),DestFileName); break; } if (!Cmd->DisablePercentage) mprintf(L" "); #endif SecPassword FilePassword=Password; #if defined(_WIN_ALL) && !defined(SFX_MODULE) ConvertDosPassword(Arc,FilePassword); #endif byte PswCheck[SIZE_PSWCHECK]; DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword, Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL, Arc.FileHead.InitV,Arc.FileHead.Lg2Count, PswCheck,Arc.FileHead.HashKey); bool WrongPassword=false; // If header is damaged, we cannot rely on password check value, // because it can be damaged too. if (Arc.FileHead.Encrypted && Arc.FileHead.UsePswCheck && memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 && !Arc.BrokenHeader) { Log(Arc.FileName,St(MWrongPassword)); ErrHandler.SetErrorCode(RARX_BADPWD); WrongPassword=true; } DataIO.CurUnpRead=0; DataIO.CurUnpWrite=0; DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads); DataIO.PackedDataHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads); DataIO.SetPackedSizeToRead(Arc.FileHead.PackSize); DataIO.SetFiles(&Arc,&CurFile); DataIO.SetTestMode(TestMode); DataIO.SetSkipUnpCRC(SkipSolid); if (!TestMode && !WrongPassword && !Arc.BrokenHeader && (Arc.FileHead.PackSize<<11)>Arc.FileHead.UnpSize && (Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize)) CurFile.Prealloc(Arc.FileHead.UnpSize); CurFile.SetAllowDelete(!Cmd->KeepBroken); bool FileCreateMode=!TestMode && !SkipSolid && Command!='P'; bool ShowChecksum=true; // Display checksum verification result. if (LinkEntry) { FILE_SYSTEM_REDIRECT Type=Arc.FileHead.RedirType; bool LinkSuccess=true; // Assume success for test mode. if (Type==FSREDIR_HARDLINK || Type==FSREDIR_FILECOPY) { wchar NameExisting[NM]; ExtrPrepareName(Cmd,Arc,Arc.FileHead.RedirName,NameExisting,ASIZE(NameExisting)); if (FileCreateMode && *NameExisting!=0) // *NameExisting can be 0 in case of excessive -ap switch. if (Type==FSREDIR_HARDLINK) LinkSuccess=ExtractHardlink(DestFileName,NameExisting,ASIZE(NameExisting)); else LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,DestFileName,NameExisting,ASIZE(NameExisting)); } else if (Type==FSREDIR_UNIXSYMLINK || Type==FSREDIR_WINSYMLINK || Type==FSREDIR_JUNCTION) { if (FileCreateMode) LinkSuccess=ExtractSymlink(Cmd,DataIO,Arc,DestFileName); } else { #ifndef SFX_MODULE Log(Arc.FileName,St(MUnknownExtra),DestFileName); #endif LinkSuccess=false; } if (!LinkSuccess || Arc.Format==RARFMT15 && !FileCreateMode) { // RAR 5.x links have a valid data checksum even in case of // failure, because they do not store any data. // We do not want to display "OK" in this case. // For 4.x symlinks we verify the checksum only when extracting, // but not when testing an archive. ShowChecksum=false; } PrevExtracted=FileCreateMode && LinkSuccess; } else if (!Arc.FileHead.SplitBefore && !WrongPassword) if (Arc.FileHead.Method==0) UnstoreFile(DataIO,Arc.FileHead.UnpSize); else { Unp->Init(Arc.FileHead.WinSize,Arc.FileHead.Solid); Unp->SetDestSize(Arc.FileHead.UnpSize); #ifndef SFX_MODULE if (Arc.Format!=RARFMT50 && Arc.FileHead.UnpVer<=15) Unp->DoUnpack(15,FileCount>1 && Arc.Solid); else #endif Unp->DoUnpack(Arc.FileHead.UnpVer,Arc.FileHead.Solid); } Arc.SeekToNext(); bool ValidCRC=DataIO.UnpHash.Cmp(&Arc.FileHead.FileHash,Arc.FileHead.UseHashKey ? Arc.FileHead.HashKey:NULL); // We set AnySolidDataUnpackedWell to true if we found at least one // valid non-zero solid file in preceding solid stream. If it is true // and if current encrypted file is broken, we do not need to hint // about a wrong password and can report CRC error only. if (!Arc.FileHead.Solid) AnySolidDataUnpackedWell=false; // Reset the flag, because non-solid file is found. else if (Arc.FileHead.Method!=0 && Arc.FileHead.UnpSize>0 && ValidCRC) AnySolidDataUnpackedWell=true; bool BrokenFile=false; // Checksum is not calculated in skip solid mode for performance reason. if (!SkipSolid) { if (!WrongPassword && ValidCRC) { #ifndef GUI if (Command!='P' && Command!='I' && ShowChecksum) mprintf(L"%s%s ",Cmd->DisablePercentage ? L" ":L"\b\b\b\b\b ", Arc.FileHead.FileHash.Type==HASH_NONE ? L" ?":St(MOk)); #endif } else { if (!WrongPassword) if (Arc.FileHead.Encrypted && (!Arc.FileHead.UsePswCheck || Arc.BrokenHeader) && !AnySolidDataUnpackedWell) { Log(Arc.FileName,St(MEncrBadCRC),ArcFileName); } else { Log(Arc.FileName,St(MCRCFailed),ArcFileName); } BrokenFile=true; ErrHandler.SetErrorCode(RARX_CRC); #ifdef RARDLL // If we already have ERAR_EOPEN as result of missing volume, // we should not replace it with less precise ERAR_BAD_DATA. if (Cmd->DllError!=ERAR_EOPEN) Cmd->DllError=ERAR_BAD_DATA; #endif } } #ifndef GUI else mprintf(L"\b\b\b\b\b "); #endif if (!TestMode && !WrongPassword && (Command=='X' || Command=='E') && (!LinkEntry || Arc.FileHead.RedirType==FSREDIR_FILECOPY) && (!BrokenFile || Cmd->KeepBroken)) { // We could preallocate more space that really written to broken file. if (BrokenFile) CurFile.Truncate(); #if defined(_WIN_ALL) || defined(_EMX) if (Cmd->ClearArc) Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE; #endif CurFile.SetOpenFileTime( Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime, Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime, Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime); CurFile.Close(); #if defined(_WIN_ALL) && !defined(SFX_MODULE) if (Cmd->SetCompressedAttr && (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0) SetFileCompression(CurFile.FileName,true); #endif #ifdef _UNIX if (Cmd->ProcessOwners && Arc.Format==RARFMT50 && Arc.FileHead.UnixOwnerSet) SetUnixOwner(Arc,CurFile.FileName); #endif CurFile.SetCloseFileTime( Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime, Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime); if (!Cmd->IgnoreGeneralAttr) SetFileAttr(CurFile.FileName,Arc.FileHead.FileAttr); PrevExtracted=true; } } } if (ExactMatch) MatchedArgs++; if (DataIO.NextVolumeMissing) return false; if (!ExtrFile) if (!Arc.Solid) Arc.SeekToNext(); else if (!SkipSolid) return false; return true; } void CmdExtract::UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize) { Array Buffer(0x100000); while (1) { uint Code=DataIO.UnpRead(&Buffer[0],Buffer.Size()); if (Code==0 || (int)Code==-1) break; Code=Code=0) DestUnpSize-=Code; } } bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize) { #ifdef _WIN_ALL UnixSlashToDos(NameExisting,NameExisting,NameExistingSize); #elif defined(_UNIX) DosSlashToUnix(NameExisting,NameExisting,NameExistingSize); #endif File Existing; if (!Existing.Open(NameExisting)) { ErrHandler.OpenErrorMsg(ArcName,NameExisting); Log(ArcName,St(MCopyError),NameExisting,NameNew); Log(ArcName,St(MCopyErrorHint)); return false; } Array Buffer(0x100000); int64 CopySize=0; while (true) { Wait(); int ReadSize=Existing.Read(&Buffer[0],Buffer.Size()); if (ReadSize==0) break; New.Write(&Buffer[0],ReadSize); CopySize+=ReadSize; } return true; } void CmdExtract::ExtrPrepareName(CommandData *Cmd,Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize) { wcsncpyz(DestName,Cmd->ExtrPath,DestSize); // We need IsPathDiv check here to correctly handle Unix forward slash // in the end of destination path in Windows: rar x arc dest/ if (*Cmd->ExtrPath!=0 && !IsPathDiv(*PointToLastChar(Cmd->ExtrPath))) { // Destination path can be without trailing slash if it come from GUI shell. AddEndSlash(DestName,DestSize); } #ifndef SFX_MODULE if (Cmd->AppendArcNameToPath) { wcsncatz(DestName,PointToName(Arc.FirstVolumeName),DestSize); SetExt(DestName,NULL); AddEndSlash(DestName,DestSize); } #endif #ifndef SFX_MODULE size_t ArcPathLength=wcslen(Cmd->ArcPath); if (ArcPathLength>0) { size_t NameLength=wcslen(ArcFileName); ArcFileName+=Min(ArcPathLength,NameLength); while (*ArcFileName==CPATHDIVIDER) ArcFileName++; if (*ArcFileName==0) // Excessive -ap switch. { *DestName=0; return; } } #endif wchar Command=Cmd->Command[0]; // Use -ep3 only in systems, where disk letters are exist, not in Unix. bool AbsPaths=Cmd->ExclPath==EXCL_ABSPATH && Command=='X' && IsDriveDiv(':'); // We do not use any user specified destination paths when extracting // absolute paths in -ep3 mode. if (AbsPaths) *DestName=0; if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH) wcsncatz(DestName,PointToName(ArcFileName),DestSize); else wcsncatz(DestName,ArcFileName,DestSize); wchar DiskLetter=toupperw(DestName[0]); if (AbsPaths) { if (DestName[1]=='_' && IsPathDiv(DestName[2]) && DiskLetter>='A' && DiskLetter<='Z') DestName[1]=':'; else if (DestName[0]=='_' && DestName[1]=='_') { // Convert __server\share to \\server\share. DestName[0]=CPATHDIVIDER; DestName[1]=CPATHDIVIDER; } } } #ifdef RARDLL bool CmdExtract::ExtrDllGetPassword(CommandData *Cmd) { if (!Cmd->Password.IsSet()) { if (Cmd->Callback!=NULL) { wchar PasswordW[MAXPASSWORD]; *PasswordW=0; if (Cmd->Callback(UCM_NEEDPASSWORDW,Cmd->UserData,(LPARAM)PasswordW,ASIZE(PasswordW))==-1) *PasswordW=0; if (*PasswordW==0) { char PasswordA[MAXPASSWORD]; *PasswordA=0; if (Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1) *PasswordA=0; GetWideName(PasswordA,NULL,PasswordW,ASIZE(PasswordW)); cleandata(PasswordA,sizeof(PasswordA)); } Cmd->Password.Set(PasswordW); cleandata(PasswordW,sizeof(PasswordW)); } if (!Cmd->Password.IsSet()) return false; } Password=Cmd->Password; return true; } #endif #ifndef RARDLL bool CmdExtract::ExtrGetPassword(CommandData *Cmd,Archive &Arc,const wchar *ArcFileName) { if (!Password.IsSet()) { if (!GetPassword(PASSWORD_FILE,ArcFileName,&Password)) { return false; } } #if !defined(GUI) && !defined(SILENT) else if (!PasswordAll && !Arc.FileHead.Solid) { eprintf(St(MUseCurPsw),ArcFileName); switch(Cmd->AllYes ? 1:Ask(St(MYesNoAll))) { case -1: ErrHandler.Exit(RARX_USERBREAK); case 2: if (!GetPassword(PASSWORD_FILE,ArcFileName,&Password)) return false; break; case 3: PasswordAll=true; break; } } #endif return true; } #endif #if defined(_WIN_ALL) && !defined(SFX_MODULE) void CmdExtract::ConvertDosPassword(Archive &Arc,SecPassword &DestPwd) { if (Arc.Format==RARFMT15 && Arc.FileHead.HostOS==HOST_MSDOS) { // We need the password in OEM encoding if file was encrypted by // native RAR/DOS (not extender based). Let's make the conversion. wchar PlainPsw[MAXPASSWORD]; Password.Get(PlainPsw,ASIZE(PlainPsw)); char PswA[MAXPASSWORD]; CharToOemBuffW(PlainPsw,PswA,ASIZE(PswA)); PswA[ASIZE(PswA)-1]=0; CharToWide(PswA,PlainPsw,ASIZE(PlainPsw)); DestPwd.Set(PlainPsw); cleandata(PlainPsw,sizeof(PlainPsw)); cleandata(PswA,sizeof(PswA)); } } #endif void CmdExtract::ExtrCreateDir(CommandData *Cmd,Archive &Arc,const wchar *ArcFileName) { if (Cmd->Test) { #ifndef GUI mprintf(St(MExtrTestFile),ArcFileName); mprintf(L" %s",St(MOk)); #endif return; } MKDIR_CODE MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr); bool DirExist=false; if (MDCode!=MKDIR_SUCCESS) { DirExist=FileExist(DestFileName); if (DirExist && !IsDir(GetFileAttr(DestFileName))) { // File with name same as this directory exists. Propose user // to overwrite it. bool UserReject; FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),Cmd->Overwrite,&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime); DirExist=false; } if (!DirExist) { CreatePath(DestFileName,true); MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr); } } if (MDCode==MKDIR_SUCCESS) { #ifndef GUI mprintf(St(MCreatDir),DestFileName); mprintf(L" %s",St(MOk)); #endif PrevExtracted=true; } else if (DirExist) { if (!Cmd->IgnoreGeneralAttr) SetFileAttr(DestFileName,Arc.FileHead.FileAttr); PrevExtracted=true; } else { Log(Arc.FileName,St(MExtrErrMkDir),DestFileName); ErrHandler.CheckLongPathErrMsg(DestFileName); ErrHandler.SysErrMsg(); #ifdef RARDLL Cmd->DllError=ERAR_ECREATE; #endif ErrHandler.SetErrorCode(RARX_CREATE); } if (PrevExtracted) { #if defined(_WIN_ALL) && !defined(SFX_MODULE) if (Cmd->SetCompressedAttr && (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT()) SetFileCompression(DestFileName,true); #endif SetDirTime(DestFileName, Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime, Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime, Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime); } } bool CmdExtract::ExtrCreateFile(CommandData *Cmd,Archive &Arc,File &CurFile) { bool Success=true; wchar Command=Cmd->Command[0]; #if !defined(GUI) && !defined(SFX_MODULE) if (Command=='P') CurFile.SetHandleType(FILE_HANDLESTD); #endif if ((Command=='E' || Command=='X') && !Cmd->Test) { bool UserReject; // Specify "write only" mode to avoid OpenIndiana NAS problems // with SetFileTime and read+write files. if (!FileCreate(Cmd,&CurFile,DestFileName,ASIZE(DestFileName),Cmd->Overwrite,&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,true)) { Success=false; if (!UserReject) { ErrHandler.CreateErrorMsg(Arc.FileName,DestFileName); ErrHandler.SetErrorCode(RARX_CREATE); #ifdef RARDLL Cmd->DllError=ERAR_ECREATE; #endif if (!IsNameUsable(DestFileName)) { Log(Arc.FileName,St(MCorrectingName)); wchar OrigName[ASIZE(DestFileName)]; wcsncpyz(OrigName,DestFileName,ASIZE(OrigName)); MakeNameUsable(DestFileName,true); CreatePath(DestFileName,true); if (FileCreate(Cmd,&CurFile,DestFileName,ASIZE(DestFileName),Cmd->Overwrite,&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,true)) { #ifndef SFX_MODULE Log(Arc.FileName,St(MRenaming),OrigName,DestFileName); #endif Success=true; } else ErrHandler.CreateErrorMsg(Arc.FileName,DestFileName); } } } } return Success; } bool CmdExtract::CheckUnpVer(Archive &Arc,const wchar *ArcFileName) { bool WrongVer; if (Arc.Format==RARFMT50) // Both SFX and RAR can unpack RAR 5.0 archives. WrongVer=Arc.FileHead.UnpVer>VER_UNPACK5; else { #ifdef SFX_MODULE // SFX can unpack only RAR 2.9 archives. WrongVer=Arc.FileHead.UnpVer!=VER_UNPACK; #else // All formats since 1.3 for RAR. WrongVer=Arc.FileHead.UnpVer<13 || Arc.FileHead.UnpVer>VER_UNPACK; #endif } // We can unpack stored files regardless of compression version field. if (Arc.FileHead.Method==0) WrongVer=false; if (WrongVer) { #ifndef SILENT Log(Arc.FileName,St(MUnknownMeth),ArcFileName); #ifndef SFX_MODULE // Log(Arc.FileName,St(MVerRequired),Arc.FileHead.UnpVer/10,Arc.FileHead.UnpVer%10); Log(Arc.FileName,St(MNewerRAR)); #endif #endif } return !WrongVer; } unrar/filcreat.cpp0100666000000000000000000001503412176732144011601 0ustar z#include "rar.hpp" // If NewFile==NULL, we delete created file after user confirmation. // It is useful we we need to overwrite an existing folder or file, // but need user confirmation for that. bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize, OVERWRITE_MODE Mode,bool *UserReject,int64 FileSize, RarTime *FileTime,bool WriteOnly) { if (UserReject!=NULL) *UserReject=false; #ifdef _WIN_ALL bool ShortNameChanged=false; #endif while (FileExist(Name)) { #ifdef _WIN_ALL 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. if (UpdateExistingShortName(Name)) continue; } // Allow short name check again. It is necessary, because rename and // autorename below can change the name, so we need to check it again. 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,MaxNameSize)) 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) { wchar NewName[NM]; *NewName=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)); if (!getwstr(NewName,ASIZE(NewName))) { // Process fwgets failure as if user answered 'No'. if (UserReject!=NULL) *UserReject=true; return false; } #endif if (PointToName(NewName)==NewName) SetName(Name,NewName,MaxNameSize); else wcsncpyz(Name,NewName,MaxNameSize); 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,FileMode)) return true; PrepareToDelete(Name); CreatePath(Name,true); return NewFile!=NULL ? NewFile->Create(Name,FileMode):DelFile(Name); } bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize) { wchar NewName[NM]; if (wcslen(Name)>ASIZE(NewName)-10) return false; wchar *Ext=GetExt(Name); if (Ext==NULL) Ext=Name+wcslen(Name); *NewName=0; for (uint FileVer=1;;FileVer++) { swprintf(NewName,ASIZE(NewName),L"%.*ls(%u)%ls",uint(Ext-Name),Name,FileVer,Ext); if (!FileExist(NewName)) { wcsncpyz(Name,NewName,MaxNameSize); break; } if (FileVer>=1000000) return false; } return true; } #ifdef _WIN_ALL // If we find a file, which short name is equal to 'Name', we try to change // its short name, while preserving the long name. It helps when unpacking // an archived file, which long name is equal to short name of already // existing file. Otherwise we would overwrite the already existing file, // even though its long name does not match the name of unpacking file. bool UpdateExistingShortName(const wchar *Name) { wchar LongPathName[NM]; DWORD Res=GetLongPathName(Name,LongPathName,ASIZE(LongPathName)); if (Res==0 || Res>=ASIZE(LongPathName)) return false; wchar ShortPathName[NM]; Res=GetShortPathName(Name,ShortPathName,ASIZE(ShortPathName)); if (Res==0 || Res>=ASIZE(ShortPathName)) return false; wchar *LongName=PointToName(LongPathName); wchar *ShortName=PointToName(ShortPathName); // We continue only if file has a short name, which does not match its // long name, and this short name is equal to name of file which we need // to create. if (*ShortName==0 || wcsicomp(LongName,ShortName)==0 || wcsicomp(PointToName(Name),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. swprintf(PointToName(NewName),ASIZE(NewName),L"rtmp%d",I); // If such file is already exist, try next random name. if (FileExist(NewName)) *NewName=0; } // If we could not generate the name not used by any other file, we return. if (*NewName==0) return false; // 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)); SetName(FullName,LongName,ASIZE(FullName)); // Rename the existing file to randomly generated name. Normally it changes // the short name too. if (!MoveFile(FullName,NewName)) return false; // Now we need to create the temporary empty file with same name as // short name of our already existing file. We do it to occupy its previous // 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(Name)) Created=KeepShortFile.Create(Name); // Now we rename the existing file from temporary name to original long name. // Since its previous short name is occupied by another file, it should // get another short name. MoveFile(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 unrar/file.cpp0100666000000000000000000003275612176732144010741 0ustar z#include "rar.hpp" File::File() { hFile=BAD_HANDLE; *FileName=0; NewFile=false; LastWrite=false; HandleType=FILE_HANDLENORMAL; SkipClose=false; IgnoreReadErrors=false; ErrorType=FILE_SUCCESS; OpenShared=false; AllowDelete=true; 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; NewFile=SrcFile.NewFile; LastWrite=SrcFile.LastWrite; HandleType=SrcFile.HandleType; SrcFile.SkipClose=true; } bool File::Open(const wchar *Name,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; hNewFile=CreateFile(Name,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL); DWORD LastError; if (hNewFile==BAD_HANDLE) { // Following CreateFile("\\?\path") call can change the last error code // from "not found" to "access denied" for relative paths like "..\path". // But we need the correct "not found" code to create a new archive // if existing one is not found. So we preserve the code here. LastError=GetLastError(); wchar LongName[NM]; if (GetWinLongPath(Name,LongName,ASIZE(LongName))) hNewFile=CreateFile(LongName,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL); } if (hNewFile==BAD_HANDLE && LastError==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 char NameA[NM]; WideToChar(Name,NameA,ASIZE(NameA)); int handle=open(NameA,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 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; wcsncpyz(FileName,Name,ASIZE(FileName)); } return Success; } #if !defined(SHELL_EXT) && !defined(SFX_MODULE) void File::TOpen(const wchar *Name) { if (!WOpen(Name)) ErrHandler.Exit(RARX_OPEN); } #endif bool File::WOpen(const wchar *Name) { if (Open(Name)) return true; ErrHandler.OpenErrorMsg(Name); return false; } bool File::Create(const wchar *Name,uint Mode) { // OpenIndiana based NAS and CIFS shares fail to set the file time if file // was created in read+write mode and some data was written and not flushed // 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; hFile=CreateFile(Name,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL); if (hFile==BAD_HANDLE) { wchar LongName[NM]; if (GetWinLongPath(Name,LongName,ASIZE(LongName))) hFile=CreateFile(LongName,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL); } #else char NameA[NM]; WideToChar(Name,NameA,ASIZE(NameA)); hFile=fopen(NameA,WriteMode ? WRITEBINARY:CREATEBINARY); #endif NewFile=true; HandleType=FILE_HANDLENORMAL; SkipClose=false; wcsncpyz(FileName,Name,ASIZE(FileName)); return hFile!=BAD_HANDLE; } #if !defined(SHELL_EXT) && !defined(SFX_MODULE) void File::TCreate(const wchar *Name,uint Mode) { if (!WCreate(Name,Mode)) ErrHandler.Exit(RARX_FATAL); } #endif bool File::WCreate(const wchar *Name,uint Mode) { if (Create(Name,Mode)) return true; ErrHandler.SetErrorCode(RARX_CREATE); ErrHandler.CreateErrorMsg(Name); 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 } hFile=BAD_HANDLE; if (!Success && AllowExceptions) ErrHandler.CloseError(FileName); } 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); } bool File::Rename(const wchar *NewName) { // No need to rename if names are already same. bool Success=wcscmp(FileName,NewName)==0; if (!Success) Success=RenameFile(FileName,NewName); if (Success) wcscpy(FileName,NewName); return Success; } void File::Write(const void *Data,size_t Size) { if (Size==0) return; 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; } 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;ISize && FilePos-Size<=0xffffffff && FilePos+Size>0xffffffff) ErrHandler.WriteErrorFAT(FileName); #endif if (ErrHandler.AskRepeatWrite(FileName,false)) { #ifndef _WIN_ALL clearerr(hFile); #endif if (Written0) Seek(Tell()-Written,SEEK_SET); continue; } ErrHandler.WriteError(NULL,FileName); } 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;IMaxDeviceRead) Size=MaxDeviceRead; hFile=GetStdHandle(STD_INPUT_HANDLE); #else hFile=stdin; #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; // We had a bug report about failure to archive 1C database lock file // 1Cv8tmp.1CL, which is a zero length file with a region above 200 KB // permanently locked. If our first read request uses too large buffer // and if we are in -dh mode, so we were able to open the file, // we'll fail with "Read error". So now we use try a smaller buffer size // in case of lock error. if (HandleType==FILE_HANDLENORMAL && Size>MaxLockedRead && GetLastError()==ERROR_LOCK_VIOLATION) return DirectRead(Data,MaxLockedRead); return -1; } return Read; #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); } 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); 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); 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) { #ifdef _UNIX SetCloseFileTimeByName(FileName,ftm,fta); #endif } void File::SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta) { #ifdef _UNIX 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; char NameA[NM]; WideToChar(Name,NameA,ASIZE(NameA)); utime(NameA,&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(); } 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 int64 File::Copy(File &Dest,int64 Length) { Array 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 unrar/filefn.cpp0100666000000000000000000002371212176732144011255 0ustar z#include "rar.hpp" MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr) { #ifdef _WIN_ALL BOOL RetCode=CreateDirectory(Name,NULL); if (RetCode==0 && !FileExist(Name)) { wchar LongName[NM]; if (GetWinLongPath(Name,LongName,ASIZE(LongName))) RetCode=CreateDirectory(LongName,NULL); } if (RetCode!=0) // Non-zero return code means success for CreateDirectory. { if (SetAttr) SetFileAttr(Name,Attr); return MKDIR_SUCCESS; } int ErrCode=GetLastError(); if (ErrCode==ERROR_FILE_NOT_FOUND || ErrCode==ERROR_PATH_NOT_FOUND) return MKDIR_BADPATH; return MKDIR_ERROR; #elif defined(_UNIX) char NameA[NM]; WideToChar(Name,NameA,ASIZE(NameA)); mode_t uattr=SetAttr ? (mode_t)Attr:0777; int ErrCode=mkdir(NameA,uattr); if (ErrCode==-1) return errno==ENOENT ? MKDIR_BADPATH:MKDIR_ERROR; return MKDIR_SUCCESS; #else return MKDIR_ERROR; #endif } 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++) { wchar DirName[NM]; if (s-Path>=ASIZE(DirName)) break; // Process all kinds of path separators, so user can enter Unix style // path in Windows or Windows in Unix. if (IsPathDiv(*s)) { #ifdef _WIN_ALL // We must not attempt to create "D:" directory, because first // CreateDirectory will fail, so we'll use \\?\D:, which forces Wine // to create "D:" directory. if (s==Path+2 && Path[1]==':') continue; #endif wcsncpy(DirName,Path,s-Path); DirName[s-Path]=0; Success=MakeDir(DirName,true,DirAttr)==MKDIR_SUCCESS; #ifndef GUI if (Success) { mprintf(St(MCreatDir),DirName); mprintf(L" %s",St(MOk)); } #endif } } if (!SkipLastName && !IsPathDiv(*PointToLastChar(Path))) Success=MakeDir(Path,true,DirAttr)==MKDIR_SUCCESS; return Success; } void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta) { #ifdef _WIN_ALL bool sm=ftm!=NULL && ftm->IsSet(); bool sc=ftc!=NULL && ftc->IsSet(); bool sa=fta!=NULL && fta->IsSet(); uint DirAttr=GetFileAttr(Name); bool ResetAttr=(DirAttr!=0xffffffff && (DirAttr & FILE_ATTRIBUTE_READONLY)!=0); if (ResetAttr) SetFileAttr(Name,0); HANDLE hFile=CreateFile(Name,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL); if (hFile==INVALID_HANDLE_VALUE) { wchar LongName[NM]; if (GetWinLongPath(Name,LongName,ASIZE(LongName))) hFile=CreateFile(LongName,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL); } if (hFile==INVALID_HANDLE_VALUE) return; FILETIME fm,fc,fa; if (sm) 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,DirAttr); #endif #if defined(_UNIX) || defined(_EMX) File::SetCloseFileTimeByName(Name,ftm,fta); #endif } bool IsRemovable(const wchar *Name) { #ifdef _WIN_ALL wchar Root[NM]; GetPathRoot(Name,Root,ASIZE(Root)); int Type=GetDriveType(*Root!=0 ? Root:NULL); return Type==DRIVE_REMOVABLE || Type==DRIVE_CDROM; #else return false; #endif } #ifndef SFX_MODULE int64 GetFreeDisk(const wchar *Name) { #ifdef _WIN_ALL wchar Root[NM]; GetFilePath(Name,Root,ASIZE(Root)); ULARGE_INTEGER uiTotalSize,uiTotalFree,uiUserFree; uiUserFree.u.LowPart=uiUserFree.u.HighPart=0; if (GetDiskFreeSpaceEx(*Root!=0 ? Root:NULL,&uiUserFree,&uiTotalSize,&uiTotalFree) && uiUserFree.u.HighPart<=uiTotalFree.u.HighPart) return INT32TO64(uiUserFree.u.HighPart,uiUserFree.u.LowPart); return 0; #elif defined(_UNIX) wchar Root[NM]; GetFilePath(Name,Root,ASIZE(Root)); char RootA[NM]; WideToChar(Root,RootA,ASIZE(RootA)); struct statvfs sfs; if (statvfs(*RootA!=0 ? RootA:".",&sfs)!=0) return 0; int64 FreeSize=sfs.f_bsize; FreeSize=FreeSize*sfs.f_bavail; return FreeSize; #else return 0; #endif } #endif bool FileExist(const wchar *Name) { #ifdef _WIN_ALL return GetFileAttr(Name)!=0xffffffff; #elif defined(ENABLE_ACCESS) char NameA[NM]; WideToChar(Name,NameA,ASIZE(NameA)); return access(NameA,0)==0; #else FindData FD; return FindFile::FastFind(Name,&FD); #endif } bool WildFileExist(const wchar *Name) { if (IsWildcard(Name)) { FindFile Find; Find.SetMask(Name); FindData fd; return Find.Next(&fd); } return FileExist(Name); } bool IsDir(uint Attr) { #ifdef _WIN_ALL return Attr!=0xffffffff && (Attr & FILE_ATTRIBUTE_DIRECTORY)!=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 IsLink(uint Attr) { #ifdef _UNIX return (Attr & 0xF000)==0xA000; #elif defined(_WIN_ALL) return (Attr & FILE_ATTRIBUTE_REPARSE_POINT)!=0; #else return false; #endif } bool IsDeleteAllowed(uint FileAttr) { #ifdef _WIN_ALL return (FileAttr & (FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN))==0; #else return (FileAttr & (S_IRUSR|S_IWUSR))==(S_IRUSR|S_IWUSR); #endif } void PrepareToDelete(const wchar *Name) { #if defined(_WIN_ALL) || defined(_EMX) SetFileAttr(Name,0); #endif #ifdef _UNIX if (Name!=NULL) { char NameA[NM]; WideToChar(Name,NameA,ASIZE(NameA)); chmod(NameA,S_IRUSR|S_IWUSR|S_IXUSR); } #endif } uint GetFileAttr(const wchar *Name) { #ifdef _WIN_ALL DWORD Attr=GetFileAttributes(Name); if (Attr==0xffffffff) { wchar LongName[NM]; if (GetWinLongPath(Name,LongName,ASIZE(LongName))) Attr=GetFileAttributes(LongName); } return Attr; #else char NameA[NM]; WideToChar(Name,NameA,ASIZE(NameA)); struct stat st; if (stat(NameA,&st)!=0) return 0; return st.st_mode; #endif } bool SetFileAttr(const wchar *Name,uint Attr) { #ifdef _WIN_ALL bool Success=SetFileAttributes(Name,Attr)!=0; if (!Success) { wchar LongName[NM]; if (GetWinLongPath(Name,LongName,ASIZE(LongName))) Success=SetFileAttributes(LongName,Attr)!=0; } return Success; #elif defined(_UNIX) char NameA[NM]; WideToChar(Name,NameA,ASIZE(NameA)); return chmod(NameA,(mode_t)Attr)==0; #else return false; #endif } #if !defined(SFX_MODULE) && !defined(SHELL_EXT) && !defined(SETUP) void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,uint Flags) { SaveFilePos SavePos(*SrcFile); #ifndef SILENT int64 FileLength=SrcFile->FileLength(); if ((Flags & (CALCFSUM_SHOWTEXT|CALCFSUM_SHOWALL))!=0) { mprintf(St(MCalcCRC)); mprintf(L" "); } #endif if ((Flags & CALCFSUM_CURPOS)==0) SrcFile->Seek(0,SEEK_SET); const size_t BufSize=0x100000; Array Data(BufSize); DataHash HashCRC,HashBlake2; HashCRC.Init(HASH_CRC32,Threads); HashBlake2.Init(HASH_BLAKE2,Threads); int64 BlockCount=0; 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; if ((++BlockCount & 0xf)==0) { #ifndef SILENT if ((Flags & CALCFSUM_SHOWALL)!=0) mprintf(L"\b\b\b\b%3d%%",ToPercent(BlockCount*int64(BufSize),FileLength)); #endif Wait(); } if (CRC32!=NULL) HashCRC.Update(&Data[0],ReadSize); if (Blake2!=NULL) HashBlake2.Update(&Data[0],ReadSize); if (Size!=INT64NDF) Size-=ReadSize; } #ifndef SILENT if ((Flags & CALCFSUM_SHOWALL)!=0) mprintf(L"\b\b\b\b "); #endif if (CRC32!=NULL) *CRC32=HashCRC.GetCRC32(); if (Blake2!=NULL) { HashValue Result; HashBlake2.Result(&Result); memcpy(Blake2,Result.Digest,sizeof(Result.Digest)); } } #endif bool RenameFile(const wchar *SrcName,const wchar *DestName) { #ifdef _WIN_ALL bool Success=MoveFile(SrcName,DestName)!=0; if (!Success) { wchar LongName1[NM],LongName2[NM]; if (GetWinLongPath(SrcName,LongName1,ASIZE(LongName1)) && GetWinLongPath(DestName,LongName2,ASIZE(LongName2))) Success=MoveFile(LongName1,LongName2)!=0; } return Success; #else char SrcNameA[NM],DestNameA[NM]; WideToChar(SrcName,SrcNameA,ASIZE(SrcNameA)); WideToChar(DestName,DestNameA,ASIZE(DestNameA)); return rename(SrcNameA,DestNameA)==0; #endif } bool DelFile(const wchar *Name) { #ifdef _WIN_ALL bool Success=DeleteFile(Name)!=0; if (!Success) { wchar LongName[NM]; if (GetWinLongPath(Name,LongName,ASIZE(LongName))) Success=DeleteFile(LongName)!=0; } return Success; #else char NameA[NM]; WideToChar(Name,NameA,ASIZE(NameA)); return remove(NameA)==0; #endif } #if defined(_WIN_ALL) && !defined(SFX_MODULE) bool SetFileCompression(const wchar *Name,bool State) { HANDLE hFile=CreateFile(Name,FILE_READ_DATA|FILE_WRITE_DATA, FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL); if (hFile==INVALID_HANDLE_VALUE) { wchar LongName[NM]; if (GetWinLongPath(Name,LongName,ASIZE(LongName))) hFile=CreateFile(LongName,FILE_READ_DATA|FILE_WRITE_DATA, FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL); } if (hFile==INVALID_HANDLE_VALUE) return false; SHORT NewState=State ? COMPRESSION_FORMAT_DEFAULT:COMPRESSION_FORMAT_NONE; DWORD Result; int RetCode=DeviceIoControl(hFile,FSCTL_SET_COMPRESSION,&NewState, sizeof(NewState),NULL,0,&Result,NULL); CloseHandle(hFile); return RetCode!=0; } #endif unrar/filestr.cpp0100666000000000000000000001077712176732144011471 0ustar z#include "rar.hpp" static bool IsUnicode(byte *Data,int Size); bool ReadTextFile( const wchar *Name, StringList *List, bool Config, bool AbortOnError, RAR_CHARSET SrcCharset, bool Unquote, bool SkipComments, bool ExpandEnvStr) { wchar FileName[NM]; *FileName=0; if (Name!=NULL) if (Config) GetConfigName(Name,FileName,ASIZE(FileName),true,false); else wcsncpyz(FileName,Name,ASIZE(FileName)); File SrcFile; if (FileName!=NULL && *FileName!=0) { bool OpenCode=AbortOnError ? SrcFile.WOpen(FileName):SrcFile.Open(FileName,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 Data(ReadBlock+5); while ((ReadSize=SrcFile.Read(&Data[DataSize],ReadBlock))!=0) { DataSize+=ReadSize; Data.Add(ReadSize); } memset(&Data[DataSize],0,5); Array WideStr; 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 DataW(Data.Size()/2+1); for (size_t I=2;I=CurStr;SpacePtr--) { if (*SpacePtr!=' ' && *SpacePtr!='\t') break; *SpacePtr=0; } if (*CurStr!=0) { size_t Length=wcslen(CurStr); if (Unquote && *CurStr=='\"' && CurStr[Length-1]=='\"') { CurStr[Length-1]=0; CurStr++; } bool Expanded=false; #ifdef _WIN_ALL if (ExpandEnvStr && *CurStr=='%') { // Expanding environment variables in Windows version. wchar ExpName[NM]; *ExpName=0; DWORD Result=ExpandEnvironmentStrings(CurStr,ExpName,ASIZE(ExpName)); Expanded=Result!=0 && ResultAddString(ExpName); } #endif if (!Expanded) List->AddString(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; WideStr.Alloc(strlen(CurStr)+1); CharToWide(CurStr,&WideStr[0],WideStr.Size()); #ifdef _WIN_ALL if (ExpandEnvStr && *CurStr=='%') { // Expanding environment variables in Windows version. wchar ExpName[NM]; DWORD Result=ExpandEnvironmentStringsW(&WideStr[0],ExpName,ASIZE(ExpName)); Expanded=Result!=0 && ResultAddString(ExpName); } #endif if (!Expanded) List->AddString(&WideStr[0]); } 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;IError=false; if (*FindMask==0) return false; #ifdef _WIN_ALL if (FirstCall) { if ((hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,fd))==INVALID_HANDLE_VALUE) return false; } else if (Win32Find(hFind,FindMask,fd)==INVALID_HANDLE_VALUE) return false; #else if (FirstCall) { wchar DirName[NM]; wcsncpyz(DirName,FindMask,ASIZE(DirName)); RemoveNameFromPath(DirName); if (*DirName==0) wcscpy(DirName,L"."); char DirNameA[NM]; WideToChar(DirName,DirNameA,ASIZE(DirNameA)); if ((dirp=opendir(DirNameA))==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; wchar Name[NM]; if (!CharToWide(ent->d_name,Name,ASIZE(Name))) Log(NULL,St(MInvalidName),Name); if (CmpName(FindMask,Name,MATCH_NAMES)) { wchar FullName[NM]; wcscpy(FullName,FindMask); *PointToName(FullName)=0; if (wcslen(FullName)+wcslen(Name)>=ASIZE(FullName)-1) { #ifndef SILENT Log(NULL,L"\n%ls%ls",FullName,Name); Log(NULL,St(MPathTooLong)); #endif return false; } wcscat(FullName,Name); if (!FastFind(FullName,fd,GetSymLink)) { ErrHandler.OpenErrorMsg(NULL,FullName); continue; } wcscpy(fd->Name,FullName); break; } } #endif fd->Flags=0; fd->IsDir=IsDir(fd->FileAttr); fd->IsLink=IsLink(fd->FileAttr); FirstCall=false; wchar *NameOnly=PointToName(fd->Name); if (wcscmp(NameOnly,L".")==0 || wcscmp(NameOnly,L"..")==0) return Next(fd); return true; } bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink) { fd->Error=false; #ifndef _UNIX if (IsWildcard(FindMask)) return false; #endif #ifdef _WIN_ALL HANDLE hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,fd); if (hFind==INVALID_HANDLE_VALUE) return false; FindClose(hFind); #else char FindMaskA[NM]; WideToChar(FindMask,FindMaskA,ASIZE(FindMaskA)); struct stat st; if (GetSymLink) { #ifdef SAVE_LINKS if (lstat(FindMaskA,&st)!=0) #else if (stat(FindMaskA,&st)!=0) #endif { fd->Error=(errno!=ENOENT); return false; } } else if (stat(FindMaskA,&st)!=0) { fd->Error=(errno!=ENOENT); return false; } fd->FileAttr=st.st_mode; fd->Size=st.st_size; fd->mtime=st.st_mtime; fd->atime=st.st_atime; fd->ctime=st.st_ctime; wcsncpyz(fd->Name,FindMask,ASIZE(fd->Name)); #endif fd->Flags=0; fd->IsDir=IsDir(fd->FileAttr); fd->IsLink=IsLink(fd->FileAttr); return true; } #ifdef _WIN_ALL HANDLE FindFile::Win32Find(HANDLE hFind,const wchar *Mask,FindData *fd) { WIN32_FIND_DATA FindData; if (hFind==INVALID_HANDLE_VALUE) { hFind=FindFirstFile(Mask,&FindData); if (hFind==INVALID_HANDLE_VALUE) { wchar LongMask[NM]; if (GetWinLongPath(Mask,LongMask,ASIZE(LongMask))) hFind=FindFirstFile(LongMask,&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 (!FindNextFile(hFind,&FindData)) { hFind=INVALID_HANDLE_VALUE; fd->Error=GetLastError()!=ERROR_NO_MORE_FILES; } if (hFind!=INVALID_HANDLE_VALUE) { wcsncpyz(fd->Name,Mask,ASIZE(fd->Name)); SetName(fd->Name,FindData.cFileName,ASIZE(fd->Name)); fd->Size=INT32TO64(FindData.nFileSizeHigh,FindData.nFileSizeLow); fd->FileAttr=FindData.dwFileAttributes; fd->ftCreationTime=FindData.ftCreationTime; fd->ftLastAccessTime=FindData.ftLastAccessTime; fd->ftLastWriteTime=FindData.ftLastWriteTime; fd->mtime=FindData.ftLastWriteTime; fd->ctime=FindData.ftCreationTime; fd->atime=FindData.ftLastAccessTime; } fd->Flags=0; return hFind; } #endif unrar/getbits.cpp0100666000000000000000000000210012176732144011437 0ustar z#include "rar.hpp" BitInput::BitInput(bool AllocBuffer) { ExternalBuffer=false; if (AllocBuffer) { // getbits32 attempts to read data from InAddr, ... InAddr+3 positions. // So let's allocate 3 additional bytes for situation, when we need to // read only 1 byte from the last position of buffer and avoid a crash // from access to next 3 bytes, which contents we do not need. size_t BufSize=MAX_SIZE+3; InBuf=new byte[BufSize]; // Ensure that we get predictable results when accessing bytes in area // not filled with read data. memset(InBuf,0,BufSize); } else InBuf=NULL; } BitInput::~BitInput() { if (!ExternalBuffer) 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()); } void BitInput::SetExternalBuffer(byte *Buf) { if (InBuf!=NULL && !ExternalBuffer) delete[] InBuf; InBuf=Buf; ExternalBuffer=true; } unrar/global.cpp0100666000000000000000000000016112176732144011243 0ustar z#define INCLUDEGLOBAL #if defined(__BORLANDC__) || defined(_MSC_VER) #pragma hdrstop #endif #include "rar.hpp" unrar/hardlinks.cpp0100666000000000000000000000163412176732144011770 0ustar zbool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize) { if (!FileExist(NameExisting)) return false; CreatePath(NameNew,true); #ifdef _WIN_ALL UnixSlashToDos(NameExisting,NameExisting,NameExistingSize); bool Success=CreateHardLink(NameNew,NameExisting,NULL)!=0; if (!Success) { Log(NULL,St(MErrCreateLnkH),NameNew); ErrHandler.SysErrMsg(); ErrHandler.SetErrorCode(RARX_CREATE); } return Success; #elif defined(_UNIX) DosSlashToUnix(NameExisting,NameExisting,NameExistingSize); char NameExistingA[NM],NameNewA[NM]; WideToChar(NameExisting,NameExistingA,ASIZE(NameExistingA)); WideToChar(NameNew,NameNewA,ASIZE(NameNewA)); bool Success=link(NameExistingA,NameNewA)==0; if (!Success) { Log(NULL,St(MErrCreateLnkH),NameNew); ErrHandler.SysErrMsg(); ErrHandler.SetErrorCode(RARX_CREATE); } return Success; #else return false; #endif } unrar/hash.cpp0100666000000000000000000000602012176732144010726 0ustar z#include "rar.hpp" void HashValue::Init(HASH_TYPE Type) { HashValue::Type=Type; // Zero length data CRC32 is 0. It is important to set it when creating // headers with no following data like directories or symlinks. if (Type==HASH_RAR14 || Type==HASH_CRC32) CRC32=0; if (Type==HASH_BLAKE2) { // dd0e891776933f43c7d032b08a917e25741f8aa9a12c12e1cac8801500f2ca4f // is BLAKE2sp hash of empty data. We init the structure to this value, // so if we create a file or service header with no following data like // "file copy" or "symlink", we set the checksum to proper value avoiding // additional header type or size checks when extracting. static byte EmptyHash[32]={ 0xdd, 0x0e, 0x89, 0x17, 0x76, 0x93, 0x3f, 0x43, 0xc7, 0xd0, 0x32, 0xb0, 0x8a, 0x91, 0x7e, 0x25, 0x74, 0x1f, 0x8a, 0xa9, 0xa1, 0x2c, 0x12, 0xe1, 0xca, 0xc8, 0x80, 0x15, 0x00, 0xf2, 0xca, 0x4f }; memcpy(Digest,EmptyHash,sizeof(Digest)); } } bool HashValue::operator == (const HashValue &cmp) { if (Type==HASH_NONE || cmp.Type==HASH_NONE) return true; if (Type==HASH_RAR14 && cmp.Type==HASH_RAR14 || Type==HASH_CRC32 && cmp.Type==HASH_CRC32) return CRC32==cmp.CRC32; if (Type==HASH_BLAKE2 && cmp.Type==HASH_BLAKE2) return memcmp(Digest,cmp.Digest,sizeof(Digest))==0; return false; } DataHash::DataHash() { HashType=HASH_NONE; #ifdef RAR_SMP ThPool=NULL; MaxThreads=0; #endif } DataHash::~DataHash() { #ifdef RAR_SMP DestroyThreadPool(ThPool); #endif cleandata(&blake2ctx, sizeof(blake2ctx)); cleandata(&CurCRC32, sizeof(CurCRC32)); } void DataHash::Init(HASH_TYPE Type,uint MaxThreads) { HashType=Type; if (Type==HASH_RAR14) CurCRC32=0; if (Type==HASH_CRC32) CurCRC32=0xffffffff; // Initial CRC32 value. if (Type==HASH_BLAKE2) blake2sp_init( &blake2ctx ); #ifdef RAR_SMP DataHash::MaxThreads=Min(MaxThreads,MaxHashThreads); #endif } void DataHash::Update(const void *Data,size_t DataSize) { #ifndef SFX_MODULE if (HashType==HASH_RAR14) CurCRC32=Checksum14((ushort)CurCRC32,Data,DataSize); #endif if (HashType==HASH_CRC32) CurCRC32=CRC32(CurCRC32,Data,DataSize); if (HashType==HASH_BLAKE2) { #ifdef RAR_SMP if (MaxThreads>1 && ThPool==NULL) ThPool=CreateThreadPool(); blake2ctx.ThPool=ThPool; blake2ctx.MaxThreads=MaxThreads; #endif blake2sp_update( &blake2ctx, (byte *)Data, DataSize); } } void DataHash::Result(HashValue *Result) { Result->Type=HashType; if (HashType==HASH_RAR14) Result->CRC32=CurCRC32; if (HashType==HASH_CRC32) Result->CRC32=CurCRC32^0xffffffff; if (HashType==HASH_BLAKE2) { // Preserve the original context, so we can continue hashing if necessary. blake2sp_state res=blake2ctx; blake2sp_final( &res, Result->Digest ); } } uint DataHash::GetCRC32() { return HashType==HASH_CRC32 ? CurCRC32^0xffffffff : 0; } bool DataHash::Cmp(HashValue *CmpValue,byte *Key) { HashValue Final; Result(&Final); if (Key!=NULL) ConvertHashToMAC(&Final,Key); return Final==*CmpValue; } unrar/headers.cpp0100666000000000000000000000174712176732144011431 0ustar z#include "rar.hpp" void FileHeader::Reset(size_t SubDataSize) { SubData.Alloc(SubDataSize); BaseBlock::Reset(); #ifndef SHELL_EXT FileHash.Init(HASH_NONE); #endif mtime.Reset(); atime.Reset(); ctime.Reset(); SplitBefore=false; SplitAfter=false; UnknownUnpSize=0; SubFlags=0; // Important for RAR 3.0 subhead. CryptMethod=CRYPT_NONE; Encrypted=false; SaltSet=false; UsePswCheck=false; UseHashKey=false; Lg2Count=0; Solid=false; Dir=false; WinSize=0; Inherited=false; SubBlock=false; CommentInHeader=false; Version=false; LargeFile=false; RedirType=FSREDIR_NONE; UnixOwnerSet=false; } FileHeader& FileHeader::operator = (FileHeader &hd) { SubData.Reset(); memcpy(this,&hd,sizeof(*this)); SubData.CleanData(); SubData=hd.SubData; return *this; } void MainHeader::Reset() { HighPosAV=0; PosAV=0; CommentInHeader=false; PackComment=false; Locator=false; QOpenOffset=0; QOpenMaxSize=0; RROffset=0; RRMaxSize=0; } unrar/isnt.cpp0100666000000000000000000000101012176732144010752 0ustar z#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 unrar/list.cpp0100666000000000000000000003262512176732144010770 0ustar z#include "rar.hpp" static void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare); static void ListSymLink(Archive &Arc); static void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize); static void ListOldSubHeader(Archive &Arc); static void ListNewSubHeader(CommandData *Cmd,Archive &Arc); void ListArchive(CommandData *Cmd) { int64 SumPackSize=0,SumUnpSize=0; uint ArcCount=0,SumFileCount=0; bool Technical=(Cmd->Command[1]=='T'); bool ShowService=Technical && Cmd->Command[2]=='A'; bool Bare=(Cmd->Command[1]=='B'); bool Verbose=(Cmd->Command[0]=='V'); wchar ArcName[NM]; while (Cmd->GetArcName(ArcName,ASIZE(ArcName))) { Archive Arc(Cmd); #ifdef _WIN_ALL Arc.RemoveSequentialFlag(); #endif if (!Arc.WOpen(ArcName)) continue; bool FileMatched=true; while (1) { int64 TotalPackSize=0,TotalUnpSize=0; uint FileCount=0; if (Arc.IsArchive(true)) { bool TitleShown=false; if (!Bare) { Arc.ViewComment(); mprintf(L"\n%s: %s",St(MListArchive),Arc.FileName); mprintf(L"\n%s: ",St(MListDetails)); uint SetCount=0; const wchar *Fmt=Arc.Format==RARFMT14 ? L"RAR 1.4":(Arc.Format==RARFMT15 ? L"RAR 4":L"RAR 5"); mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", Fmt); if (Arc.Solid) mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSolid)); if (Arc.SFXSize>0) mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSFX)); if (Arc.Volume) if (Arc.Format==RARFMT50) { // RAR 5.0 archives store the volume number in main header, // so it is already available now. if (SetCount++ > 0) mprintf(L", "); mprintf(St(MVolumeNumber),Arc.VolNumber+1); } else mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListVolume)); if (Arc.Protected) mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListRR)); if (Arc.Locked) mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListLock)); if (Arc.Encrypted) mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListEncHead)); mprintf(L"\n"); } wchar VolNumText[50]; *VolNumText=0; while(Arc.ReadHeader()>0) { HEADER_TYPE HeaderType=Arc.GetHeaderType(); if (HeaderType==HEAD_ENDARC) { #ifndef SFX_MODULE // Only RAR 1.5 archives store the volume number in end record. if (Arc.EndArcHead.StoreVolNumber && Arc.Format==RARFMT15) swprintf(VolNumText,ASIZE(VolNumText),L"%.10ls %d",St(MListVolume),Arc.VolNumber+1); #endif if (Technical && ShowService) { mprintf(L"\n%12ls: %ls",St(MListService),L"EOF"); if (*VolNumText!=0) mprintf(L"\n%12ls: %ls",St(MListFlags),VolNumText); mprintf(L"\n"); } break; } switch(HeaderType) { case HEAD_FILE: FileMatched=Cmd->IsProcessFile(Arc.FileHead)!=0; if (FileMatched) { ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare); if (!Arc.FileHead.SplitBefore) { TotalUnpSize+=Arc.FileHead.UnpSize; FileCount++; } TotalPackSize+=Arc.FileHead.PackSize; } break; case HEAD_SERVICE: if (FileMatched && !Bare) { if (Technical && ShowService) ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false); } break; } Arc.SeekToNext(); } if (!Bare && !Technical) if (TitleShown) { wchar UnpSizeText[20]; itoa(TotalUnpSize,UnpSizeText); wchar PackSizeText[20]; itoa(TotalPackSize,PackSizeText); if (Verbose) { mprintf(L"\n----------- --------- -------- ----- -------- ----- -------- ----"); mprintf(L"\n%21ls %9ls %3d%% %-25ls %u",UnpSizeText, PackSizeText,ToPercentUnlim(TotalPackSize,TotalUnpSize), VolNumText,FileCount); } else { mprintf(L"\n----------- --------- -------- ----- ----"); mprintf(L"\n%21ls %-14ls %u",UnpSizeText,VolNumText,FileCount); } SumFileCount+=FileCount; SumUnpSize+=TotalUnpSize; SumPackSize+=TotalPackSize; mprintf(L"\n"); } else mprintf(St(MListNoFiles)); ArcCount++; #ifndef NOVOLUME if (Cmd->VolSize!=0 && (Arc.FileHead.SplitAfter || Arc.GetHeaderType()==HEAD_ENDARC && Arc.EndArcHead.NextVolume) && MergeArchive(Arc,NULL,false,Cmd->Command[0])) { Arc.Seek(0,SEEK_SET); } else #endif break; } else { if (Cmd->ArcNames.ItemsCount()<2 && !Bare) mprintf(St(MNotRAR),Arc.FileName); break; } } } if (ArcCount>1 && !Bare && !Technical) { wchar UnpSizeText[20],PackSizeText[20]; itoa(SumUnpSize,UnpSizeText); itoa(SumPackSize,PackSizeText); if (Verbose) mprintf(L"%21ls %9ls %3d%% %26ls %u",UnpSizeText,PackSizeText, ToPercentUnlim(SumPackSize,SumUnpSize),L"",SumFileCount); else mprintf(L"%21ls %16s %lu",UnpSizeText,L"",SumFileCount); } } enum LISTCOL_TYPE { LCOL_NAME,LCOL_ATTR,LCOL_SIZE,LCOL_PACKED,LCOL_RATIO,LCOL_CSUM,LCOL_ENCR }; void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare) { wchar *Name=hd.FileName; RARFORMAT Format=Arc.Format; if (Bare) { mprintf(L"%s\n",Name); return; } if (!TitleShown && !Technical) { if (Verbose) { mprintf(L"\n%ls",St(MListTitleV)); mprintf(L"\n----------- --------- -------- ----- -------- ----- -------- ----"); } else { mprintf(L"\n%ls",St(MListTitleL)); mprintf(L"\n----------- --------- -------- ----- ----"); } TitleShown=true; } wchar UnpSizeText[20],PackSizeText[20]; if (hd.UnpSize==INT64NDF) wcscpy(UnpSizeText,L"?"); else itoa(hd.UnpSize,UnpSizeText); itoa(hd.PackSize,PackSizeText); wchar AttrStr[30]; if (hd.HeaderType==HEAD_SERVICE) swprintf(AttrStr,ASIZE(AttrStr),L"%cB",hd.Inherited ? 'I' : '.'); else ListFileAttr(hd.FileAttr,hd.HSType,AttrStr,ASIZE(AttrStr)); wchar RatioStr[10]; if (hd.SplitBefore && hd.SplitAfter) wcscpy(RatioStr,L"<->"); else if (hd.SplitBefore) wcscpy(RatioStr,L"<--"); else if (hd.SplitAfter) wcscpy(RatioStr,L"-->"); else swprintf(RatioStr,ASIZE(RatioStr),L"%d%%",ToPercentUnlim(hd.PackSize,hd.UnpSize)); wchar DateStr[50]; hd.mtime.GetText(DateStr,ASIZE(DateStr),Technical,Technical); if (Technical) { mprintf(L"\n%12s: %s",St(MListName),Name); bool FileBlock=hd.HeaderType==HEAD_FILE; if (!FileBlock && Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM)) { mprintf(L"\n%12ls: %ls",St(MListType),St(MListStream)); wchar StreamName[NM]; GetStreamNameNTFS(Arc,StreamName,ASIZE(StreamName)); mprintf(L"\n%12ls: %ls",St(MListTarget),StreamName); } else { const wchar *Type=St(FileBlock ? (hd.Dir ? MListDir:MListFile):MListService); if (hd.RedirType!=FSREDIR_NONE) switch(hd.RedirType) { case FSREDIR_UNIXSYMLINK: Type=St(MListUSymlink); break; case FSREDIR_WINSYMLINK: Type=St(MListWSymlink); break; case FSREDIR_JUNCTION: Type=St(MListJunction); break; case FSREDIR_HARDLINK: Type=St(MListHardlink); break; case FSREDIR_FILECOPY: Type=St(MListCopy); break; } mprintf(L"\n%12ls: %ls",St(MListType),Type); if (hd.RedirType!=FSREDIR_NONE) mprintf(L"\n%12ls: %ls",St(MListTarget),hd.RedirName); } if (!hd.Dir) { mprintf(L"\n%12ls: %ls",St(MListSize),UnpSizeText); mprintf(L"\n%12ls: %ls",St(MListPacked),PackSizeText); mprintf(L"\n%12ls: %ls",St(MListRatio),RatioStr); } if (hd.mtime.IsSet()) mprintf(L"\n%12ls: %ls",St(MListMtime),DateStr); if (hd.ctime.IsSet()) { hd.ctime.GetText(DateStr,ASIZE(DateStr),true,true); mprintf(L"\n%12ls: %ls",St(MListCtime),DateStr); } if (hd.atime.IsSet()) { hd.atime.GetText(DateStr,ASIZE(DateStr),true,true); mprintf(L"\n%12ls: %ls",St(MListAtime),DateStr); } mprintf(L"\n%12ls: %ls",St(MListAttr),AttrStr); if (hd.FileHash.Type==HASH_CRC32) mprintf(L"\n%12ls: %8.8X", hd.UseHashKey ? L"CRC32 MAC":hd.SplitAfter ? L"Pack-CRC32":L"CRC32", hd.FileHash.CRC32); if (hd.FileHash.Type==HASH_BLAKE2) { wchar BlakeStr[BLAKE2_DIGEST_SIZE*2+1]; BinToHex(hd.FileHash.Digest,BLAKE2_DIGEST_SIZE,NULL,BlakeStr,ASIZE(BlakeStr)); mprintf(L"\n%12ls: %ls", hd.UseHashKey ? L"BLAKE2 MAC":hd.SplitAfter ? L"Pack-BLAKE2":L"BLAKE2", BlakeStr); } const wchar *HostOS=L""; if (Format==RARFMT50 && hd.HSType!=HSYS_UNKNOWN) HostOS=hd.HSType==HSYS_WINDOWS ? L"Windows":L"Unix"; if (Format==RARFMT15) { static const wchar *RarOS[]={ L"DOS",L"OS/2",L"Windows",L"Unix",L"Mac OS",L"BeOS",L"WinCE",L"",L"",L"" }; if (hd.HostOS=0x100000 ? hd.WinSize/0x100000:hd.WinSize/0x400, hd.WinSize>=0x100000 ? L"M":L"K"); if (hd.Solid || hd.Encrypted) { mprintf(L"\n%12ls: ",St(MListFlags)); if (hd.Solid) mprintf(L"%ls ",St(MListSolid)); if (hd.Encrypted) mprintf(L"%ls ",St(MListEnc)); } if (hd.Version) { uint Version=ParseVersionFileName(Name,false); if (Version!=0) mprintf(L"\n%12ls: %u",St(MListFileVer),Version); } if (hd.UnixOwnerSet) { mprintf(L"\n%12ls: ",L"Unix owner"); if (*hd.UnixOwnerName!=0) mprintf(L"%ls:",GetWide(hd.UnixOwnerName)); if (*hd.UnixGroupName!=0) mprintf(L"%ls",GetWide(hd.UnixGroupName)); if ((*hd.UnixOwnerName!=0 || *hd.UnixGroupName!=0) && (hd.UnixOwnerNumeric || hd.UnixGroupNumeric)) mprintf(L" "); if (hd.UnixOwnerNumeric) mprintf(L"#%d:",hd.UnixOwnerID); if (hd.UnixGroupNumeric) mprintf(L"#%d:",hd.UnixGroupID); } mprintf(L"\n"); return; } mprintf(L"\n%c%10ls %9ls ",hd.Encrypted ? '*' : ' ',AttrStr,UnpSizeText); if (Verbose) mprintf(L"%9ls %4ls ",PackSizeText,RatioStr); mprintf(L" %ls ",DateStr); if (Verbose) { if (hd.FileHash.Type==HASH_CRC32) mprintf(L"%8.8X ",hd.FileHash.CRC32); else if (hd.FileHash.Type==HASH_BLAKE2) { byte *S=hd.FileHash.Digest; mprintf(L"%02x%02x..%02x ",S[0],S[1],S[31]); } else mprintf(L"???????? "); } mprintf(L"%-12ls",Name); } /* void ListSymLink(Archive &Arc) { if (Arc.FileHead.HSType==HSYS_UNIX && (Arc.FileHead.FileAttr & 0xF000)==0xA000) if (Arc.FileHead.Encrypted) { // Link data are encrypted. We would need to ask for password // and initialize decryption routine to display the link target. mprintf(L"\n%22ls %ls",L"-->",L"*<-?->"); } else { char FileName[NM]; uint DataSize=(uint)Min(Arc.FileHead.PackSize,sizeof(FileName)-1); Arc.Read(FileName,DataSize); FileName[DataSize]=0; mprintf(L"\n%22ls %ls",L"-->",GetWide(FileName)); } } */ void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize) { switch(HostType) { case HSYS_WINDOWS: swprintf(AttrStr,AttrSize,L"%c%c%c%c%c%c%c", (A & 0x2000) ? 'I' : '.', // Not content indexed. (A & 0x0800) ? 'C' : '.', // Compressed. (A & 0x0020) ? 'A' : '.', // Archive. (A & 0x0010) ? 'D' : '.', // Directory. (A & 0x0004) ? 'S' : '.', // System. (A & 0x0002) ? 'H' : '.', // Hidden. (A & 0x0001) ? 'R' : '.'); // Read-only. break; case HSYS_UNIX: switch (A & 0xF000) { case 0x4000: AttrStr[0]='d'; break; case 0xA000: AttrStr[0]='l'; break; default: AttrStr[0]='-'; break; } swprintf(AttrStr+1,AttrSize-1,L"%c%c%c%c%c%c%c%c%c", (A & 0x0100) ? 'r' : '-', (A & 0x0080) ? 'w' : '-', (A & 0x0040) ? ((A & 0x0800) ? 's':'x'):((A & 0x0800) ? 'S':'-'), (A & 0x0020) ? 'r' : '-', (A & 0x0010) ? 'w' : '-', (A & 0x0008) ? ((A & 0x0400) ? 's':'x'):((A & 0x0400) ? 'S':'-'), (A & 0x0004) ? 'r' : '-', (A & 0x0002) ? 'w' : '-', (A & 0x0001) ? 'x' : '-'); break; case HSYS_UNKNOWN: wcscpy(AttrStr,L"?"); break; } } unrar/log.cpp0100666000000000000000000000143712176732144010573 0ustar z#include "rar.hpp" static wchar LogName[NM]; static RAR_CHARSET LogCharset=RCH_DEFAULT; void InitLogOptions(const wchar *LogFileName,RAR_CHARSET CSet) { wcsncpyz(LogName,LogFileName,ASIZE(LogName)); LogCharset=CSet; } #ifndef SILENT void Log(const wchar *ArcName,const wchar *fmt,...) { // Preserve the error code for possible following system error message. int Code=ErrHandler.GetSystemErrorCode(); Alarm(); // This buffer is for format string only, not for entire output, // so it can be short enough. wchar fmtw[1024]; PrintfPrepareFmt(fmt,fmtw,ASIZE(fmtw)); safebuf wchar Msg[2*NM+1024]; va_list arglist; va_start(arglist,fmt); vswprintf(Msg,ASIZE(Msg),fmtw,arglist); va_end(arglist); eprintf(L"%ls",Msg); ErrHandler.SetSystemErrorCode(Code); } #endif unrar/match.cpp0100666000000000000000000000747712176732144011120 0ustar z#include "rar.hpp" static bool match(const wchar *pattern,const wchar *string,bool ForceCase); static int mwcsicompc(const wchar *Str1,const wchar *Str2,bool ForceCase); static int mwcsnicompc(const wchar *Str1,const wchar *Str2,size_t N,bool ForceCase); inline uint touppercw(uint ch,bool ForceCase) { if (ForceCase) return ch; #if defined(_UNIX) return ch; #else return toupperw(ch); #endif } 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(Path1)) return(match(Wildcard,Name,ForceCase)); else if (CmpMode==MATCH_SUBPATH || IsWildcard(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)); } 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; } } } int mwcsicompc(const wchar *Str1,const wchar *Str2,bool ForceCase) { if (ForceCase) return(wcscmp(Str1,Str2)); return(wcsicompc(Str1,Str2)); } 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 } unrar/model.cpp0100666000000000000000000003510212176732144011106 0ustar z/**************************************************************************** * 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); } unrar/options.cpp0100666000000000000000000000120712176732144011500 0ustar z#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=0x2000000; Overwrite=OVERWRITE_DEFAULT; Method=3; MsgStream=MSG_STDOUT; ConvertNames=NAMES_ORIGINALCASE; ProcessEA=true; xmtime=EXTTIME_HIGH3; FileSizeLess=INT64NDF; FileSizeMore=INT64NDF; HashType=HASH_CRC32; #ifdef RAR_SMP Threads=GetNumberOfThreads(); #endif #ifdef USE_QOPEN QOpenMode=QOPEN_AUTO; #endif } unrar/pathfn.cpp0100666000000000000000000005426312176732144011277 0ustar z#include "rar.hpp" 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); } wchar* PointToLastChar(const wchar *Path) { size_t Length=wcslen(Path); return (wchar*)(Length>0 ? Path+Length-1:Path); } 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 :\ 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 SetName(wchar *FullName,const wchar *Name,size_t MaxSize) { wchar *NamePtr=PointToName(FullName); wcsncpyz(NamePtr,Name,MaxSize-(NamePtr-FullName)); } 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(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 wchar *GetExt(const wchar *Name) { return Name==NULL ? NULL:wcsrchr(PointToName(Name),'.'); } // '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 wchar *Str) { return Str==NULL ? false:wcspbrk(Str,L"*?")!=NULL; } bool IsPathDiv(int Ch) { #ifdef _WIN_ALL return Ch=='\\' || Ch=='/'; #else return Ch==CPATHDIVIDER; #endif } bool IsDriveDiv(int Ch) { #ifdef _UNIX return false; #else return Ch==':'; #endif } int GetPathDisk(const wchar *Path) { if (IsDiskLetter(Path)) return etoupperw(*Path)-'A'; else return -1; } void AddEndSlash(wchar *Path,size_t MaxLength) { size_t Length=wcslen(Path); if (Length>0 && Path[Length-1]!=CPATHDIVIDER && Length+1=Path+2 && (!IsDriveDiv(Path[1]) || Name>=Path+4)) Name--; *Name=0; } #if defined(_WIN_ALL) && !defined(SFX_MODULE) static void GetAppDataPath(wchar *Path,size_t MaxSize,bool Create) { LPMALLOC g_pMalloc; SHGetMalloc(&g_pMalloc); LPITEMIDLIST ppidl; *Path=0; bool Success=false; if (SHGetSpecialFolderLocation(NULL,CSIDL_APPDATA,&ppidl)==NOERROR && SHGetPathFromIDList(ppidl,Path) && *Path!=0) { AddEndSlash(Path,MaxSize); wcsncatz(Path,L"WinRAR",MaxSize); Success=FileExist(Path); if (!Success && Create) Success=MakeDir(Path,false,0)==MKDIR_SUCCESS; } if (!Success) { GetModuleFileName(NULL,Path,(DWORD)MaxSize); RemoveNameFromPath(Path); } g_pMalloc->Free(ppidl); } #endif #if defined(_WIN_ALL) && !defined(SFX_MODULE) void GetRarDataPath(wchar *Path,size_t MaxSize,bool Create) { *Path=0; HKEY hKey; if (RegOpenKeyEx(HKEY_CURRENT_USER,L"Software\\WinRAR\\Paths",0, KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS) { DWORD DataSize=(DWORD)MaxSize,Type; RegQueryValueEx(hKey,L"AppData",0,&Type,(BYTE *)Path,&DataSize); RegCloseKey(hKey); } if (*Path==0 || !FileExist(Path)) GetAppDataPath(Path,MaxSize,Create); } #endif #ifndef SFX_MODULE bool EnumConfigPaths(uint Number,wchar *Path,size_t MaxSize,bool Create) { #ifdef _UNIX static const wchar *ConfPath[]={ L"/etc", L"/etc/rar", L"/usr/lib", L"/usr/local/lib", L"/usr/local/etc" }; if (Number==0) { char *EnvStr=getenv("HOME"); if (EnvStr!=NULL) GetWideName(EnvStr,NULL,Path,MaxSize); else wcsncpyz(Path, ConfPath[0], MaxSize); return true; } Number--; if (Number>=ASIZE(ConfPath)) return false; wcsncpyz(Path,ConfPath[Number], MaxSize); return true; #elif defined(_WIN_ALL) if (Number>1) return false; if (Number==0) GetRarDataPath(Path,MaxSize,Create); else { GetModuleFileName(NULL,Path,(DWORD)MaxSize); RemoveNameFromPath(Path); } return true; #else return false; #endif } #endif #ifndef SFX_MODULE void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckExist,bool Create) { *FullName=0; for (uint I=0;EnumConfigPaths(I,FullName,MaxSize,Create);I++) { AddEndSlash(FullName,MaxSize); wcsncatz(FullName,Name,MaxSize); if (!CheckExist || WildFileExist(FullName)) break; } } #endif // Returns a pointer to rightmost digit of volume number. wchar* GetVolNumPart(const wchar *ArcName) { // Pointing to last name character. const wchar *ChPtr=ArcName+wcslen(ArcName)-1; // Skipping the archive extension. while (!IsDigit(*ChPtr) && ChPtr>ArcName) ChPtr--; // Skipping the numeric part of name. const 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|\"")==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==' ' || *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==' ' || *s=='.') && IsPathDiv(s[1])) *s='_'; #endif } } char* UnixSlashToDos(char *SrcName,char *DestName,size_t 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,size_t 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,size_t 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,size_t 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 wchar *Src,wchar *Dest,size_t MaxSize) { if (Src==NULL || *Src==0) { if (MaxSize>0) *Dest=0; return; } #ifdef _WIN_ALL { wchar FullName[NM],*NamePtr; DWORD Code=GetFullPathName(Src,ASIZE(FullName),FullName,&NamePtr); if (Code==0 || Code>ASIZE(FullName)) { wchar LongName[NM]; if (GetWinLongPath(Src,LongName,ASIZE(LongName))) Code=GetFullPathName(LongName,ASIZE(FullName),FullName,&NamePtr); } if (Code!=0 && Code='A' && Letter<='Z' && IsDriveDiv(Path[1]); } void GetPathRoot(const wchar *Path,wchar *Root,size_t MaxSize) { *Root=0; if (IsDiskLetter(Path)) swprintf(Root,MaxSize,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); if (Length>=MaxSize) Length=0; wcsncpy(Root,Path,Length); Root[Length]=0; } } } int ParseVersionFileName(wchar *Name,bool Truncate) { int Version=0; wchar *VerText=wcsrchr(Name,';'); if (VerText!=NULL) { if (Version==0) Version=atoiw(VerText+1); if (Truncate) *VerText=0; } return Version; } #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(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.SetMask(Mask); FindData FD; while (Find.Next(&FD)) { Archive Arc; if (Arc.Open(FD.Name,0) && Arc.IsArchive(true) && Arc.FirstVolume) { wcscpy(FirstName,FD.Name); break; } } } return VolNumStart; } #endif #ifndef SFX_MODULE static void GenArcName(wchar *ArcName,wchar *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. } wchar Mask[MAX_GENERATE_MASK]; wcsncpyz(Mask,*GenerateMask!=0 ? GenerateMask:L"yyyymmddhhmmss",ASIZE(Mask)); bool QuoteMode=false,Hours=false; for (uint I=0;Mask[I]!=0;I++) { if (Mask[I]=='{' || Mask[I]=='}') { QuoteMode=(Mask[I]=='{'); continue; } if (QuoteMode) continue; int CurChar=toupperw(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 (toupperw(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=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 wchar *MaskChars=L"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 wchar *ChPtr=wcschr(MaskChars,toupperw(Mask[I])); if (ChPtr!=NULL) CField[ChPtr-MaskChars]++; } wchar DateText[MAX_GENERATE_MASK]; *DateText=0; QuoteMode=false; for (size_t I=0,J=0;Mask[I]!=0 && J1) { // If we perform non-archiving operation, we need to use the last // existing archive before the first unused name. So we generate // the name for (ArcNumber-1) below. wcsncpyz(NewName,NullToEmpty(ArcName),ASIZE(NewName)); GenArcName(NewName,GenerateMask,ArcNumber-1,ArcNumPresent); } break; } ArcNumber++; } wcsncpyz(ArcName,NewName,MaxSize); } #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); } #ifdef _WIN_ALL // We should return 'true' even if resulting path is shorter than MAX_PATH, // because we can also use this function to open files with non-standard // characters, even if their path length is normal. bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize) { if (*Src==0) return false; const wchar *Prefix=L"\\\\?\\"; const size_t PrefixLength=4; bool FullPath=IsDiskLetter(Src) && IsPathDiv(Src[2]); size_t SrcLength=wcslen(Src); if (IsFullPath(Src)) // Paths in d:\path\name format. { if (IsDiskLetter(Src)) { if (MaxSize<=PrefixLength+SrcLength) return false; wcsncpy(Dest,Prefix,PrefixLength); wcscpy(Dest+PrefixLength,Src); return true; } else if (Src[0]=='\\' && Src[1]=='\\') { if (MaxSize<=PrefixLength+SrcLength+2) return false; wcsncpy(Dest,Prefix,PrefixLength); wcscpy(Dest+PrefixLength,L"UNC"); wcscpy(Dest+PrefixLength+3,Src+1); return true; } // We may be here only if we modify IsFullPath in the future. return false; } else { wchar CurDir[NM]; DWORD DirCode=GetCurrentDirectory(ASIZE(CurDir)-1,CurDir); if (DirCode==0 || DirCode>ASIZE(CurDir)-1) return false; if (IsPathDiv(Src[0])) // Paths in \path\name format. { if (MaxSize<=PrefixLength+SrcLength+2) return false; wcsncpy(Dest,Prefix,PrefixLength); wcsncpy(Dest+PrefixLength,CurDir,2); // Copy drive letter 'd:'. wcscpy(Dest+PrefixLength+2,Src); return true; } else // Paths in path\name format. { AddEndSlash(CurDir,ASIZE(CurDir)); if (MaxSize<=PrefixLength+wcslen(CurDir)+SrcLength) return false; wcsncpy(Dest,Prefix,PrefixLength); wcscpy(Dest+PrefixLength,CurDir); wcsncatz(Dest,Src,MaxSize); return true; } } return false; } #endif unrar/qopen.cpp0100666000000000000000000001361312176732144011133 0ustar z#include "rar.hpp" QuickOpen::QuickOpen() { Buf=NULL; Init(NULL,false); } QuickOpen::~QuickOpen() { Close(); delete[] Buf; } void QuickOpen::Init(Archive *Arc,bool WriteMode) { if (Arc!=NULL) // Unless called from constructor. Close(); QuickOpen::Arc=Arc; QuickOpen::WriteMode=WriteMode; ListStart=NULL; ListEnd=NULL; if (Buf==NULL) Buf=new byte[MaxBufSize]; CurBufSize=0; // Current size of buffered data in write mode. Loaded=false; } void QuickOpen::Close() { QuickOpenItem *Item=ListStart; while (Item!=NULL) { QuickOpenItem *Next=Item->Next; delete[] Item->Header; delete Item; Item=Next; } } void QuickOpen::Load(uint64 BlockPos) { if (!Loaded) // If loading the first time, perform additional intialization. { SeekPos=Arc->Tell(); UnsyncSeekPos=false; SaveFilePos SavePos(*Arc); Arc->Seek(BlockPos,SEEK_SET); if (Arc->ReadHeader()==0 || Arc->GetHeaderType()!=HEAD_SERVICE || !Arc->SubHead.CmpName(SUBHEAD_TYPE_QOPEN)) return; QLHeaderPos=Arc->CurBlockPos; RawDataStart=Arc->Tell(); RawDataSize=Arc->SubHead.UnpSize; Loaded=true; // Set only after all file processing calls like Tell, Seek, ReadHeader. } if (Arc->SubHead.Encrypted) { RAROptions *Cmd=Arc->GetRAROptions(); #ifndef RAR_NOCRYPT if (Cmd->Password.IsSet()) Crypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,Arc->SubHead.Salt, Arc->SubHead.InitV,Arc->SubHead.Lg2Count, Arc->SubHead.HashKey,Arc->SubHead.PswCheck); else #endif return; } RawDataPos=0; ReadBufSize=0; ReadBufPos=0; LastReadHeader.Reset(); LastReadHeaderPos=0; ReadBuffer(); } bool QuickOpen::Read(void *Data,size_t Size,size_t &Result) { if (!Loaded) return false; // Find next suitable cached block. while (LastReadHeaderPos+LastReadHeader.Size()<=SeekPos) if (!ReadNext()) break; if (!Loaded) { // If something wrong happened, let's set the correct file pointer // and stop further quick open processing. if (UnsyncSeekPos) Arc->File::Seek(SeekPos,SEEK_SET); return false; } if (SeekPos>=LastReadHeaderPos && SeekPos+Size<=LastReadHeaderPos+LastReadHeader.Size()) { memcpy(Data,LastReadHeader+size_t(SeekPos-LastReadHeaderPos),Size); Result=Size; SeekPos+=Size; UnsyncSeekPos=true; } else { if (UnsyncSeekPos) { Arc->File::Seek(SeekPos,SEEK_SET); UnsyncSeekPos=false; } int ReadSize=Arc->File::Read(Data,Size); if (ReadSize<0) { Loaded=false; return false; } Result=ReadSize; SeekPos+=ReadSize; } return true; } bool QuickOpen::Seek(int64 Offset,int Method) { if (!Loaded) return false; // Normally we process an archive sequentially from beginning to end, // so we read quick open data sequentially. But some operations like // archive updating involve several passes. So if we detect that file // pointer is moved back, we reload quick open data from beginning. if (Method==SEEK_SET && (uint64)OffsetFile::Seek(Offset,SEEK_END); SeekPos=Arc->File::Tell(); UnsyncSeekPos=false; } return true; } bool QuickOpen::Tell(int64 *Pos) { if (!Loaded) return false; *Pos=SeekPos; return true; } uint QuickOpen::ReadBuffer() { SaveFilePos SavePos(*Arc); Arc->File::Seek(RawDataStart+RawDataPos,SEEK_SET); size_t SizeToRead=(size_t)Min(RawDataSize-RawDataPos,MaxBufSize-ReadBufSize); if (Arc->SubHead.Encrypted) SizeToRead &= ~CRYPT_BLOCK_MASK; if (SizeToRead==0) return 0; int ReadSize=Arc->File::Read(Buf+ReadBufSize,SizeToRead); if (ReadSize<=0) return 0; #ifndef RAR_NOCRYPT if (Arc->SubHead.Encrypted) Crypt.DecryptBlock(Buf+ReadBufSize,ReadSize & ~CRYPT_BLOCK_MASK); #endif RawDataPos+=ReadSize; ReadBufSize+=ReadSize; return ReadSize; } // Fill RawRead object from buffer. bool QuickOpen::ReadRaw(RawRead &Raw) { if (MaxBufSize-ReadBufPos<0x100) // We are close to end of buffer. { // Ensure that we have enough data to read CRC and header size. size_t DataLeft=ReadBufSize-ReadBufPos; memcpy(Buf,Buf+ReadBufPos,DataLeft); ReadBufPos=0; ReadBufSize=DataLeft; ReadBuffer(); } const size_t FirstReadSize=7; if (ReadBufPos+FirstReadSize>ReadBufSize) return false; Raw.Read(Buf+ReadBufPos,FirstReadSize); ReadBufPos+=FirstReadSize; uint SavedCRC=Raw.Get4(); uint SizeBytes=Raw.GetVSize(4); uint64 BlockSize=Raw.GetV(); int SizeToRead=int(BlockSize); SizeToRead-=FirstReadSize-SizeBytes-4; // Adjust overread size bytes if any. if (SizeToRead<0 || SizeBytes==0 || BlockSize==0) { Loaded=false; // Invalid data. return false; } // If rest of block data crosses buffer boundary, read it in loop. size_t DataLeft=ReadBufSize-ReadBufPos; while (SizeToRead>0) { size_t CurSizeToRead=Min(DataLeft,(size_t)SizeToRead); Raw.Read(Buf+ReadBufPos,CurSizeToRead); ReadBufPos+=CurSizeToRead; SizeToRead-=int(CurSizeToRead); if (SizeToRead>0) // We read the entire buffer and still need more data. { ReadBufPos=0; ReadBufSize=0; if (ReadBuffer()==0) return false; } } return SavedCRC==Raw.GetCRC50(); } // Read next cached header. bool QuickOpen::ReadNext() { RawRead Raw(NULL); if (!ReadRaw(Raw)) // Read internal quick open header preceding stored block. return false; uint Flags=(uint)Raw.GetV(); uint64 Offset=Raw.GetV(); size_t HeaderSize=(size_t)Raw.GetV(); LastReadHeader.Alloc(HeaderSize); Raw.GetB(&LastReadHeader[0],HeaderSize); // Calculate the absolute position as offset from quick open service header. LastReadHeaderPos=QLHeaderPos-Offset; return true; } unrar/rar.cpp0100666000000000000000000000427112176732144010575 0ustar z#include "rar.hpp" #if !defined(GUI) && !defined(RARDLL) int main(int argc, char *argv[]) { #ifdef _UNIX setlocale(LC_ALL,""); #endif InitConsole(); ErrHandler.SetSignalHandlers(true); #ifdef SFX_MODULE wchar ModuleName[NM]; #ifdef _WIN_ALL GetModuleFileName(NULL,ModuleName,ASIZE(ModuleName)); #else CharToWide(argv[0],ModuleName,ASIZE(ModuleName)); #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 try { CommandData *Cmd=new CommandData; #ifdef SFX_MODULE wcscpy(Cmd->Command,L"X"); char *Switch=argc>1 ? argv[1]:NULL; 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(ModuleName); Cmd->ParseDone(); #else // !SFX_MODULE Cmd->ParseCommandLine(true,argc,argv); if (!Cmd->ConfigDisabled) { Cmd->ReadConfig(); Cmd->ParseEnvVar(); } Cmd->ParseCommandLine(false,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,Cmd->ErrlogCharset); ErrHandler.SetSilent(Cmd->AllYes || Cmd->MsgStream==MSG_NULL); ErrHandler.SetShutdown(Cmd->Shutdown); Cmd->OutTitle(); Cmd->ProcessCommand(); delete Cmd; } catch (RAR_EXIT ErrCode) { ErrHandler.SetErrorCode(ErrCode); } catch (std::bad_alloc) { ErrHandler.MemoryErrorMsg(); ErrHandler.SetErrorCode(RARX_MEMORY); } catch (...) { ErrHandler.SetErrorCode(RARX_FATAL); } #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SHELL_EXT) if (ShutdownOnClose) Shutdown(); #endif ErrHandler.MainExit=true; return ErrHandler.GetErrorCode(); } #endif unrar/rarpch.cpp0100666000000000000000000000013112176732144011257 0ustar z// We use rarpch.cpp to create precompiled headers for MS Visual C++. #include "rar.hpp" unrar/rarvm.cpp0100666000000000000000000007470612176732144011152 0ustar z#include "rar.hpp" #include "rarvmtbl.cpp" RarVM::RarVM() :BitInput(true) { 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)>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=(ResultByteMode,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<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;IByteMode,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=(ResultByteMode,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); return true; #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;ICmdCount=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; return; } #endif #ifndef NORARVM 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)InAddrStaticData.Add(1); Prg->StaticData[I]=fgetbits()>>8; faddbits(8); } } while ((uint)InAddrCmd.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++; } #endif } // 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;ICmdCount;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 } #ifndef NORARVM 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. } } } #endif 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(size_t Pos,byte *Data,size_t DataSize) { if (PosCmd[0]; uint CodeSize=Prg->CmdCount; for (uint I=0;IOpCode) { 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;JOpCode) { 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 }; uint CodeCRC=CRC32(0xffffffff,Code,CodeSize)^0xffffffff; for (uint I=0;I=VM_GLOBALMEMADDR || DataSize<4) break; const int FileSize=0x1000000; byte CmpByte2=FilterType==VMSF_E8E9 ? 0xe9:0xe8; for (int CurPos=0;CurPos=0) SET_VALUE(false,Data,Addr+FileSize); } else if (Addr=VM_GLOBALMEMADDR || DataSize<21) break; int CurPos=0; FileOffset>>=4; while (CurPos=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<=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=VM_GLOBALMEMADDR/2 || PosR<0) break; for (int CurChannel=0;CurChannel=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=VM_GLOBALMEMADDR/2) break; for (int CurChannel=0;CurChannel>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=-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; } } 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<>8)|0xff000000; BitField>>=8; } } #endif unrar/rarvmtbl.cpp0100666000000000000000000000627712176732144011652 0ustar z#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 }; unrar/rawread.cpp0100666000000000000000000000727612176732144011446 0ustar z#include "rar.hpp" RawRead::RawRead(File *SrcFile) { RawRead::SrcFile=SrcFile; Reset(); } void RawRead::Reset() { Data.SoftReset(); ReadPos=0; DataSize=0; #ifndef SHELL_EXT Crypt=NULL; #endif } size_t RawRead::Read(size_t Size) { size_t ReadSize=0; #if !defined(SHELL_EXT) && !defined(RAR_NOCRYPT) if (Crypt!=NULL) { // Full size of buffer with already read data including data read // for encryption block alignment. size_t FullSize=Data.Size(); // Data read for alignment and not processed yet. size_t DataLeft=FullSize-DataSize; if (Size>DataLeft) // Need to read more than we already have. { size_t SizeToRead=Size-DataLeft; size_t AlignedReadSize=SizeToRead+((~SizeToRead+1) & CRYPT_BLOCK_MASK); Data.Add(AlignedReadSize); ReadSize=SrcFile->Read(&Data[FullSize],AlignedReadSize); Crypt->DecryptBlock(&Data[FullSize],AlignedReadSize); DataSize+=ReadSize==0 ? 0:Size; } else // Use buffered data, no real read. { ReadSize=Size; DataSize+=Size; } } else #endif if (Size!=0) { Data.Add(Size); ReadSize=SrcFile->Read(&Data[DataSize],Size); DataSize+=ReadSize; } return ReadSize; } void RawRead::Read(byte *SrcData,size_t Size) { if (Size!=0) { Data.Add(Size); memcpy(&Data[DataSize],SrcData,Size); DataSize+=Size; } } byte RawRead::Get1() { return ReadPos0) memcpy(F,&Data[ReadPos],CopySize); if (Size>CopySize) memset(F+CopySize,0,Size-CopySize); ReadPos+=CopySize; return CopySize; } void RawRead::GetW(wchar *Field,size_t Size) { if (ReadPos+2*Size-1 0) { Archive *SrcArc=(Archive *)SrcFile; if (UnpackFromMemory) { memcpy(Addr,UnpackFromMemoryAddr,UnpackFromMemorySize); ReadSize=(int)UnpackFromMemorySize; UnpackFromMemorySize=0; } else { size_t SizeToRead=((int64)Count>UnpPackedSize) ? (size_t)UnpPackedSize:Count; if (SizeToRead==0) return 0; if (!SrcFile->IsOpened()) return(-1); ReadSize=SrcFile->Read(ReadAddr,SizeToRead); FileHeader *hd=SubHead!=NULL ? SubHead:&SrcArc->FileHead; if (hd->SplitAfter) PackedDataHash.Update(ReadAddr,ReadSize); } CurUnpRead+=ReadSize; TotalRead+=ReadSize; #ifndef NOVOLUME // These variable are not used in NOVOLUME mode, so it is better // to exclude commands below to avoid compiler warnings. ReadAddr+=ReadSize; Count-=ReadSize; #endif UnpPackedSize-=ReadSize; 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 (ReadSize!=-1) { ReadSize=TotalRead; #ifndef RAR_NOCRYPT if (Decryption) Decrypt.DecryptBlock(Addr,ReadSize); #endif } Wait(); return ReadSize; } #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) UnpHash.Update(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(L"\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(bool Encrypt,CRYPT_METHOD Method, SecPassword *Password,const byte *Salt,const byte *InitV, uint Lg2Cnt,byte *PswCheck,byte *HashKey) { #ifndef RAR_NOCRYPT if (Encrypt) Encryption=Crypt.SetCryptKeys(true,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck); else Decryption=Decrypt.SetCryptKeys(false,Method,Password,Salt,InitV,Lg2Cnt,HashKey,PswCheck); #endif } #if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT) void ComprDataIO::SetAV15Encryption() { Decryption=true; Decrypt.SetAV15Encryption(); } #endif #if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT) void ComprDataIO::SetCmt13Encryption() { Decryption=true; Decrypt.SetCmt13Encryption(); } #endif void ComprDataIO::SetUnpackToMemory(byte *Addr,uint Size) { UnpackToMemory=true; UnpackToMemoryAddr=Addr; UnpackToMemorySize=Size; } unrar/recvol.cpp0100666000000000000000000000155212176732144011302 0ustar z#include "rar.hpp" #include "recvol3.cpp" #include "recvol5.cpp" bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent) { Archive Arc(Cmd); if (!Arc.Open(Name)) { if (!Silent) ErrHandler.OpenErrorMsg(NULL,Name); return false; } RARFORMAT Fmt=RARFMT15; if (Arc.IsArchive(true)) Fmt=Arc.Format; else { byte Sign[REV5_SIGN_SIZE]; Arc.Seek(0,SEEK_SET); if (Arc.Read(Sign,REV5_SIGN_SIZE)==REV5_SIGN_SIZE && memcmp(Sign,REV5_SIGN,REV5_SIGN_SIZE)==0) Fmt=RARFMT50; } Arc.Close(); // We define RecVol as local variable for proper stack unwinding when // handling exceptions. So it can close and delete files on Cancel. if (Fmt==RARFMT15) { RecVolumes3 RecVol; return RecVol.Restore(Cmd,Name,Silent); } else { RecVolumes5 RecVol; return RecVol.Restore(Cmd,Name,Silent); } } unrar/recvol3.cpp0100666000000000000000000002720312176732144011366 0ustar z#include "rar.hpp" // Buffer size for all volumes involved. static const size_t TotalBufferSize=0x4000000; class RSEncode // Encode or decode data area, one object per one thread. { private: RSCoder RSC; public: void EncodeBuf(); void DecodeBuf(); void Init(int RecVolNumber) {RSC.Init(RecVolNumber);} byte *Buf; byte *OutBuf; int BufStart; int BufEnd; int FileNumber; int RecVolNumber; size_t RecBufferSize; int *Erasures; int EraSize; }; #ifdef RAR_SMP THREAD_PROC(RSEncodeThread) { RSEncode *rs=(RSEncode *)Data; rs->EncodeBuf(); } THREAD_PROC(RSDecodeThread) { RSEncode *rs=(RSEncode *)Data; rs->DecodeBuf(); } #endif RecVolumes3::RecVolumes3() { Buf.Alloc(TotalBufferSize); memset(SrcFile,0,sizeof(SrcFile)); #ifdef RAR_SMP RSThreadPool=CreateThreadPool(); #endif } RecVolumes3::~RecVolumes3() { for (size_t I=0;IArcName && DigitGroup<3;Ext--) if (!IsDigit(*Ext)) if (IsDigit(*(Ext-1)) && (*Ext=='_' || DigitGroup<2)) DigitGroup++; else if (DigitGroup<2) { NewStyle=true; break; } while (IsDigit(*Ext) && Ext>ArcName+1) Ext--; wcscpy(Ext,L"*.*"); FindFile Find; Find.SetMask(ArcName); FindData fd; while (Find.Next(&fd)) { Archive Arc(Cmd); if (Arc.WOpen(fd.Name) && Arc.IsArchive(true)) { wcscpy(ArcName,fd.Name); break; } } } Archive Arc(Cmd); if (!Arc.WCheckOpen(ArcName)) return false; if (!Arc.Volume) { #ifndef SILENT Log(ArcName,St(MNotVolume),ArcName); #endif return false; } bool NewNumbering=Arc.NewNumbering; Arc.Close(); wchar *VolNumStart=VolNameToFirstName(ArcName,ArcName,NewNumbering); wchar RecVolMask[NM]; wcscpy(RecVolMask,ArcName); size_t BaseNamePartLength=VolNumStart-ArcName; wcscpy(RecVolMask+BaseNamePartLength,L"*.rev"); #ifndef SILENT int64 RecFileSize=0; #endif // We cannot display "Calculating CRC..." message here, because we do not // know if we'll find any recovery volumes. We'll display it after finding // the first recovery volume. bool CalcCRCMessageDone=false; FindFile Find; Find.SetMask(RecVolMask); FindData RecData; int FileNumber=0,RecVolNumber=0,FoundRecVolumes=0,MissingVolumes=0; wchar PrevName[NM]; while (Find.Next(&RecData)) { wchar *CurName=RecData.Name; int P[3]; if (!RevName && !NewStyle) { NewStyle=true; wchar *Dot=GetExt(CurName); if (Dot!=NULL) { int LineCount=0; Dot--; while (Dot>CurName && *Dot!='.') { if (*Dot=='_') LineCount++; Dot--; } if (LineCount==2) NewStyle=false; } } if (NewStyle) { if (!CalcCRCMessageDone) { #ifndef SILENT mprintf(St(MCalcCRCAllVol)); #endif CalcCRCMessageDone=true; } #ifndef SILENT mprintf(L"\n%s",CurName); #endif File CurFile; CurFile.TOpen(CurName); CurFile.Seek(0,SEEK_END); int64 Length=CurFile.Tell(); CurFile.Seek(Length-7,SEEK_SET); for (int I=0;I<3;I++) P[2-I]=CurFile.GetByte()+1; uint FileCRC=0; for (int I=0;I<4;I++) FileCRC|=CurFile.GetByte()<<(I*8); uint CalcCRC; CalcFileSum(&CurFile,&CalcCRC,NULL,Cmd->Threads,Length-4); if (FileCRC!=CalcCRC) { #ifndef SILENT mprintf(St(MCRCFailed),CurName); #endif continue; } } else { wchar *Dot=GetExt(CurName); if (Dot==NULL) continue; bool WrongParam=false; for (size_t I=0;I=CurName+BaseNamePartLength); P[I]=atoiw(Dot+1); if (P[I]==0 || P[I]>255) WrongParam=true; } if (WrongParam) continue; } if (P[1]+P[2]>255) continue; if (RecVolNumber!=0 && RecVolNumber!=P[1] || FileNumber!=0 && FileNumber!=P[2]) { #ifndef SILENT Log(NULL,St(MRecVolDiffSets),CurName,PrevName); #endif return(false); } RecVolNumber=P[1]; FileNumber=P[2]; wcscpy(PrevName,CurName); File *NewFile=new File; NewFile->TOpen(CurName); SrcFile[FileNumber+P[0]-1]=NewFile; FoundRecVolumes++; #ifndef SILENT if (RecFileSize==0) RecFileSize=NewFile->FileLength(); #endif } #ifndef SILENT if (!Silent || FoundRecVolumes!=0) { mprintf(St(MRecVolFound),FoundRecVolumes); } #endif if (FoundRecVolumes==0) return(false); bool WriteFlags[256]; memset(WriteFlags,0,sizeof(WriteFlags)); wchar LastVolName[NM]; *LastVolName=0; for (int CurArcNum=0;CurArcNumTOpen(ArcName); ValidVolume=NewFile->IsArchive(false); if (ValidVolume) { while (NewFile->ReadHeader()!=0) { if (NewFile->GetHeaderType()==HEAD_ENDARC) { #ifndef SILENT mprintf(L"\n%s",ArcName); #endif if (NewFile->EndArcHead.DataCRC) { uint CalcCRC; CalcFileSum(NewFile,&CalcCRC,NULL,Cmd->Threads,NewFile->CurBlockPos); if (NewFile->EndArcHead.ArcDataCRC!=CalcCRC) { ValidVolume=false; #ifndef SILENT mprintf(St(MCRCFailed),ArcName); #endif } } break; } NewFile->SeekToNext(); } } if (!ValidVolume) { NewFile->Close(); wchar NewName[NM]; wcscpy(NewName,ArcName); wcscat(NewName,L".bad"); #ifndef SILENT mprintf(St(MBadArc),ArcName); mprintf(St(MRenaming),ArcName,NewName); #endif RenameFile(ArcName,NewName); } NewFile->Seek(0,SEEK_SET); } if (!ValidVolume) { // It is important to return 'false' instead of aborting here, // so if we are called from extraction, we will be able to continue // extracting. It may happen if .rar and .rev are on read-only disks // like CDs. if (!NewFile->Create(ArcName)) { // We need to display the title of operation before the error message, // to make clear for user that create error is related to recovery // volumes. This is why we cannot use WCreate call here. Title must be // before create error, not after that. #ifndef SILENT mprintf(St(MReconstructing)); #endif ErrHandler.CreateErrorMsg(NULL,ArcName); return false; } WriteFlags[CurArcNum]=true; MissingVolumes++; if (CurArcNum==FileNumber-1) wcscpy(LastVolName,ArcName); #ifndef SILENT mprintf(St(MAbsNextVol),ArcName); #endif } SrcFile[CurArcNum]=(File*)NewFile; NextVolumeName(ArcName,ASIZE(ArcName),!NewNumbering); } #ifndef SILENT mprintf(St(MRecVolMissing),MissingVolumes); #endif if (MissingVolumes==0) { #ifndef SILENT mprintf(St(MRecVolAllExist)); #endif return false; } if (MissingVolumes>FoundRecVolumes) { #ifndef SILENT mprintf(St(MRecVolCannotFix)); #endif return false; } #ifndef SILENT mprintf(St(MReconstructing)); #endif int TotalFiles=FileNumber+RecVolNumber; int Erasures[256],EraSize=0; for (int I=0;IThreads; RSEncode rse[MaxPoolThreads]; #else uint ThreadNumber=1; RSEncode rse[1]; #endif for (uint I=0;IRead(&Buf[I*RecBufferSize],RecBufferSize); if ((size_t)ReadSize!=RecBufferSize) memset(&Buf[I*RecBufferSize+ReadSize],0,RecBufferSize-ReadSize); if (ReadSize>MaxRead) MaxRead=ReadSize; } if (MaxRead==0) break; #ifndef SILENT int CurPercent=ToPercent(ProcessedSize,RecFileSize); if (!Cmd->DisablePercentage && CurPercent!=LastPercent) { mprintf(L"\b\b\b\b%3d%%",CurPercent); LastPercent=CurPercent; } ProcessedSize+=MaxRead; #endif int BlockStart=0; int BlockSize=MaxRead/ThreadNumber; if (BlockSize<0x100) BlockSize=MaxRead; for (uint CurThread=0;BlockStartBuf=&Buf[0]; curenc->BufStart=BlockStart; curenc->BufEnd=BlockStart+BlockSize; curenc->FileNumber=TotalFiles; curenc->RecBufferSize=RecBufferSize; curenc->Erasures=Erasures; curenc->EraSize=EraSize; #ifdef RAR_SMP if (ThreadNumber>1) RSThreadPool->AddTask(RSDecodeThread,(void*)curenc); else curenc->DecodeBuf(); #else curenc->DecodeBuf(); #endif BlockStart+=BlockSize; } #ifdef RAR_SMP RSThreadPool->WaitDone(); #endif // RAR_SMP for (int I=0;IWrite(&Buf[I*RecBufferSize],MaxRead); } for (int I=0;ITell(); CurFile->Seek(Length-7,SEEK_SET); for (int J=0;J<7;J++) CurFile->PutByte(0); } CurFile->Close(); SrcFile[I]=NULL; } if (*LastVolName!=0) { // Truncate the last volume to its real size. Archive Arc(Cmd); if (Arc.Open(LastVolName,FMF_UPDATE) && Arc.IsArchive(true) && Arc.SearchBlock(HEAD_ENDARC)) { Arc.Seek(Arc.NextBlockPos,SEEK_SET); char Buf[8192]; int ReadSize=Arc.Read(Buf,sizeof(Buf)); int ZeroCount=0; while (ZeroCountDisablePercentage) mprintf(L"\b\b\b\b100%%"); if (!Silent && !Cmd->DisableDone) mprintf(St(MDone)); #endif return true; } void RSEncode::DecodeBuf() { for (int BufPos=BufStart;BufPosRecRSPtr->ProcessAreaRS(td); } #endif void RecVolumes5::ProcessRS(RAROptions *Cmd,uint DataNum,const byte *Data,uint MaxRead,bool Encode) { /* RSCoder16 RS; RS.Init(DataCount,RecCount,Encode ? NULL:ValidFlags); uint Count=Encode ? RecCount : MissingVolumes; for (uint I=0;IThreads; #else uint ThreadNumber=1; #endif const uint MinThreadBlock=0x1000; ThreadNumber=Min(ThreadNumber,MaxRead/MinThreadBlock); if (ThreadNumber<1) ThreadNumber=1; uint ThreadDataSize=MaxRead/ThreadNumber; ThreadDataSize+=(ThreadDataSize&1); // Must be even for 16-bit RS coder. #ifdef USE_SSE ThreadDataSize=ALIGN_VALUE(ThreadDataSize,SSE_ALIGNMENT); // Alignment for SSE operations. #endif if (ThreadDataSizeRS==NULL) { td->RS=new RSCoder16; td->RS->Init(DataCount,RecCount,Encode ? NULL:ValidFlags); } td->DataNum=DataNum; td->Data=Data; td->Encode=Encode; td->StartPos=CurPos; size_t EndPos=CurPos+ThreadDataSize; if (EndPos>MaxRead || I==ThreadNumber-1) EndPos=MaxRead; td->Size=EndPos-CurPos; CurPos=EndPos; #ifdef RAR_SMP if (ThreadNumber>1) RecThreadPool->AddTask(RecThreadRS,(void*)td); else ProcessAreaRS(td); #else ProcessAreaRS(td); #endif } #ifdef RAR_SMP RecThreadPool->WaitDone(); #endif // RAR_SMP } void RecVolumes5::ProcessAreaRS(RecRSThreadData *td) { uint Count=td->Encode ? RecCount : MissingVolumes; for (uint I=0;IRS->UpdateECC(td->DataNum, I, td->Data+td->StartPos, Buf+I*RecBufferSize+td->StartPos, td->Size); } bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) { wchar ArcName[NM]; wcscpy(ArcName,Name); wchar *Num=GetVolNumPart(ArcName); while (Num>ArcName && IsDigit(*(Num-1))) Num--; wcsncpyz(Num,L"*.*",ASIZE(ArcName)-(Num-ArcName)); wchar FirstVolName[NM]; *FirstVolName=0; int64 RecFileSize=0; FindFile VolFind; VolFind.SetMask(ArcName); FindData fd; uint FoundRecVolumes=0; while (VolFind.Next(&fd)) { Wait(); Archive *Vol=new Archive(Cmd); int ItemPos=-1; if (Vol->WOpen(fd.Name)) { if (CmpExt(fd.Name,L"rev")) { uint RecNum=ReadHeader(Vol,FoundRecVolumes==0); if (RecNum!=0) { if (FoundRecVolumes==0) RecFileSize=Vol->FileLength(); ItemPos=RecNum; FoundRecVolumes++; } } else if (Vol->IsArchive(true) && (Vol->SFXSize>0 || CmpExt(fd.Name,L"rar"))) { if (!Vol->Volume && !Vol->BrokenHeader) { Log(ArcName,St(MNotVolume),ArcName); return false; } // We work with archive as with raw data file, so we do not want // to spend time to QOpen I/O redirection. Vol->QOpenUnload(); Vol->Seek(0,SEEK_SET); // RAR volume found. Get its number, store the handle in appropriate // array slot, clean slots in between if we had to grow the array. wchar *Num=GetVolNumPart(fd.Name); uint VolNum=0; for (uint K=1;Num>=fd.Name && IsDigit(*Num);K*=10,Num--) VolNum+=(*Num-'0')*K; if (VolNum==0 || VolNum>MaxVolumes) continue; size_t CurSize=RecItems.Size(); if (VolNum>CurSize) { RecItems.Alloc(VolNum); for (size_t I=CurSize;If=Vol; Item->New=false; wcsncpyz(Item->Name,fd.Name,ASIZE(Item->Name)); } } #ifndef SILENT if (!Silent || FoundRecVolumes!=0) { mprintf(St(MRecVolFound),FoundRecVolumes); } #endif if (FoundRecVolumes==0) return false; mprintf(St(MCalcCRCAllVol)); MissingVolumes=0; for (uint I=0;If!=NULL) { mprintf(L"\n%s",Item->Name); uint RevCRC; CalcFileSum(Item->f,&RevCRC,NULL,Cmd->Threads,INT64NDF,CALCFSUM_CURPOS); Item->Valid=RevCRC==Item->CRC; if (!Item->Valid) { mprintf(St(MCRCFailed),Item->Name); // Close only corrupt REV volumes here. We'll close and rename corrupt // RAR volumes later, if we'll know that recovery is possible. if (I>=DataCount) { Item->f->Close(); Item->f=NULL; FoundRecVolumes--; } } } if (If==NULL || !Item->Valid)) MissingVolumes++; } mprintf(St(MRecVolMissing),MissingVolumes); if (MissingVolumes==0) { mprintf(St(MRecVolAllExist)); return false; } if (MissingVolumes>FoundRecVolumes) { mprintf(St(MRecVolCannotFix)); return false; } mprintf(St(MReconstructing)); // Create missing and rename bad volumes. for (uint I=0;If!=NULL && !Item->Valid) { Item->f->Close(); wchar NewName[NM]; wcscpy(NewName,Item->Name); wcscat(NewName,L".bad"); #ifndef SILENT mprintf(St(MBadArc),Item->Name); mprintf(St(MRenaming),Item->Name,NewName); #endif RenameFile(Item->Name,NewName); delete Item->f; Item->f=NULL; } if (Item->New=(Item->f==NULL)) { wcsncpyz(Item->Name,FirstVolName,ASIZE(Item->Name)); mprintf(St(MCreating),Item->Name); File *NewVol=new File; bool UserReject; if (!FileCreate(Cmd,NewVol,Item->Name,ASIZE(Item->Name),Cmd->Overwrite,&UserReject)) { if (!UserReject) ErrHandler.CreateErrorMsg(NULL,Item->Name); ErrHandler.Exit(UserReject ? RARX_USERBREAK:RARX_CREATE); } NewVol->Prealloc(Item->FileSize); Item->f=NewVol; Item->New=true; } NextVolumeName(FirstVolName,ASIZE(FirstVolName),false); } int64 ProcessedSize=0; #ifndef GUI int LastPercent=-1; mprintf(L" "); #endif // Even though we already preliminary calculated missing volume number, // let's do it again now, when we have the final and exact information. MissingVolumes=0; ValidFlags=new bool[TotalCount]; for (uint I=0;If!=NULL && !Item->New) ReadSize=Item->f->Read(B,RecBufferSize); if (ReadSize!=RecBufferSize) memset(B+ReadSize,0,RecBufferSize-ReadSize); if (ReadSize>MaxRead) MaxRead=ReadSize; ProcessRS(Cmd,I,B,MaxRead,false); } if (MaxRead==0) break; for (uint I=0,J=0;IFileSize); Item->f->Write(Buf+(J++)*RecBufferSize,WriteSize); Item->FileSize-=WriteSize; } #ifndef SILENT int CurPercent=ToPercent(ProcessedSize,RecFileSize); if (!Cmd->DisablePercentage && CurPercent!=LastPercent) { mprintf(L"\b\b\b\b%3d%%",CurPercent); LastPercent=CurPercent; } ProcessedSize+=MaxRead; #endif } for (uint I=0;IClose(); delete[] ValidFlags; delete[] Data; #if !defined(GUI) && !defined(SILENT) if (!Cmd->DisablePercentage) mprintf(L"\b\b\b\b100%%"); if (!Silent && !Cmd->DisableDone) mprintf(St(MDone)); #endif return(true); } uint RecVolumes5::ReadHeader(File *RecFile,bool FirstRev) { const size_t FirstReadSize=REV5_SIGN_SIZE+8; byte ShortBuf[FirstReadSize]; if (RecFile->Read(ShortBuf,FirstReadSize)!=FirstReadSize) return 0; if (memcmp(ShortBuf,REV5_SIGN,REV5_SIGN_SIZE)!=0) return 0; uint HeaderSize=RawGet4(ShortBuf+REV5_SIGN_SIZE+4); if (HeaderSize>0x100000 || HeaderSize<=5) return 0; uint BlockCRC=RawGet4(ShortBuf+REV5_SIGN_SIZE); RawRead Raw(RecFile); if (Raw.Read(HeaderSize)!=HeaderSize) return 0; // Calculate CRC32 of entire header including 4 byte size field. uint CalcCRC=CRC32(0xffffffff,ShortBuf+REV5_SIGN_SIZE+4,4); if ((CRC32(CalcCRC,Raw.GetDataPtr(),HeaderSize)^0xffffffff)!=BlockCRC) return 0; if (Raw.Get1()!=1) // Version check. return 0; DataCount=Raw.Get2(); RecCount=Raw.Get2(); TotalCount=DataCount+RecCount; uint RecNum=Raw.Get2(); // Number of recovery volume. if (RecNum>=TotalCount || TotalCount>MaxVolumes) return 0; uint RevCRC=Raw.Get4(); // CRC of current REV volume. if (FirstRev) { // If we have read the first valid REV file, init data structures // using information from REV header. size_t CurSize=RecItems.Size(); RecItems.Alloc(TotalCount); for (size_t I=CurSize;I= sizeof(StrTable)/sizeof(StrTable[0])) StrNum=0; wchar *Str=StrTable[StrNum]; *Str=0; CharToWide(StringId,Str,ASIZE(StrTable[0])); return Str; } #endif unrar/rijndael.cpp0100666000000000000000000002542712176732144011607 0ustar z/*************************************************************************** * This code is based on public domain Szymon Stefanek AES implementation: * * http://www.pragmaware.net/software/rijndael/index.php * * * * Dynamic tables generation is based on the Brian Gladman work: * * http://fp.gladman.plus.com/cryptography_technology/rijndael * ***************************************************************************/ #include "rar.hpp" 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(bool Encrypt,const byte *key,uint keyLen,const byte * initVector) { uint uKeyLenInBytes; switch(keyLen) { case 128: uKeyLenInBytes = 16; m_uRounds = 10; break; case 192: uKeyLenInBytes = 24; m_uRounds = 12; break; case 256: uKeyLenInBytes = 32; m_uRounds = 14; break; } byte keyMatrix[_MAX_KEY_COLUMNS][4]; for(uint i = 0; i < uKeyLenInBytes; i++) keyMatrix[i >> 2][i & 3] = key[i]; for(int i = 0; i < MAX_IV_SIZE; i++) m_initVector[i] = initVector[i]; keySched(keyMatrix); if(!Encrypt) 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); } } #if 0 static void TestRijndael(); struct TestRij {TestRij() {TestRijndael();exit(0);}} GlobalTestRij; // Test CBC encryption according to NIST 800-38A. void TestRijndael() { byte IV[16]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; byte PT[64]={ 0x6b,0xc1,0xbe,0xe2,0x2e,0x40,0x9f,0x96,0xe9,0x3d,0x7e,0x11,0x73,0x93,0x17,0x2a, 0xae,0x2d,0x8a,0x57,0x1e,0x03,0xac,0x9c,0x9e,0xb7,0x6f,0xac,0x45,0xaf,0x8e,0x51, 0x30,0xc8,0x1c,0x46,0xa3,0x5c,0xe4,0x11,0xe5,0xfb,0xc1,0x19,0x1a,0x0a,0x52,0xef, 0xf6,0x9f,0x24,0x45,0xdf,0x4f,0x9b,0x17,0xad,0x2b,0x41,0x7b,0xe6,0x6c,0x37,0x10, }; byte Key128[16]={0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c}; byte Chk128[16]={0x3f,0xf1,0xca,0xa1,0x68,0x1f,0xac,0x09,0x12,0x0e,0xca,0x30,0x75,0x86,0xe1,0xa7}; byte Key192[24]={0x8e,0x73,0xb0,0xf7,0xda,0x0e,0x64,0x52,0xc8,0x10,0xf3,0x2b,0x80,0x90,0x79,0xe5,0x62,0xf8,0xea,0xd2,0x52,0x2c,0x6b,0x7b}; byte Chk192[16]={0x08,0xb0,0xe2,0x79,0x88,0x59,0x88,0x81,0xd9,0x20,0xa9,0xe6,0x4f,0x56,0x15,0xcd}; byte Key256[32]={0x60,0x3d,0xeb,0x10,0x15,0xca,0x71,0xbe,0x2b,0x73,0xae,0xf0,0x85,0x7d,0x77,0x81,0x1f,0x35,0x2c,0x07,0x3b,0x61,0x08,0xd7,0x2d,0x98,0x10,0xa3,0x09,0x14,0xdf,0xf4}; byte Chk256[16]={0xb2,0xeb,0x05,0xe2,0xc3,0x9b,0xe9,0xfc,0xda,0x6c,0x19,0x07,0x8c,0x6a,0x9d,0x1b}; byte *Key[3]={Key128,Key192,Key256}; byte *Chk[3]={Chk128,Chk192,Chk256}; Rijndael rij; // Declare outside of loop to test re-initialization. for (uint L=0;L<3;L++) { byte Out[16]; wchar Str[sizeof(Out)*2+1]; uint KeyLength=128+L*64; rij.Init(true,Key[L],KeyLength,IV); for (uint I=0;I MAXPAR) J^=0x11D; // 0x11D field-generator polynomial (x^8+x^4+x^3+x^2+1). } for (int I=MAXPAR;I0;J--) ShiftReg[J]=ShiftReg[J-1]^gfMult(GXPol[J],D); ShiftReg[0]=gfMult(GXPol[0],D); } for (int I=0;I0;I--) ELPol[I]^=gfMult(M,ELPol[I-1]); ErrCount=0; // Find roots of error locator polynomial. for (int Root=MAXPAR-DataSize;Root0) for (int I=0;I=0 && DataPosgfSize) E^=0x1100B; // Irreducible field-generator polynomial. } // log(0)+log(x) must be outside of usual log table, so we can set it // to 0 and avoid check for 0 in multiplication parameters. gfLog[0]= 2*gfSize; for (uint I=2*gfSize;I<=4*gfSize;I++) // Results for log(0)+log(x). gfExp[I]=0; } uint RSCoder16::gfAdd(uint a,uint b) // Addition in Galois field. { return a^b; } uint RSCoder16::gfMul(uint a,uint b) // Multiplication in Galois field. { return gfExp[gfLog[a]+gfLog[b]]; } uint RSCoder16::gfInv(uint a) // Inverse element in Galois field. { return a==0 ? 0:gfExp[gfSize-gfLog[a]]; } bool RSCoder16::Init(uint DataCount, uint RecCount, bool *ValidityFlags) { ND = DataCount; NR = RecCount; NE = 0; Decoding=ValidityFlags!=NULL; if (Decoding) { delete[] ValidFlags; ValidFlags=new bool[ND + NR]; for (uint I = 0; I < ND + NR; I++) ValidFlags[I]=ValidityFlags[I]; for (uint I = 0; I < ND; I++) if (!ValidFlags[I]) NE++; uint ValidECC=0; for (uint I = ND; I < ND + NR; I++) if (ValidFlags[I]) ValidECC++; if (NE > ValidECC || NE == 0 || ValidECC == 0) return false; } if (ND + NR > gfSize || NR > ND || ND == 0 || NR == 0) return false; delete[] MX; if (Decoding) { MX=new uint[NE * ND]; MakeDecoderMatrix(); InvertDecoderMatrix(); } else { MX=new uint[NR * ND]; MakeEncoderMatrix(); } return true; } void RSCoder16::MakeEncoderMatrix() { // Create Cauchy encoder generator matrix. Skip trivial "1" diagonal rows, // which would just copy source data to destination. for (uint I = 0; I < NR; I++) for (uint J = 0; J < ND; J++) MX[I * ND + J] = gfInv( gfAdd( (I+ND), J) ); } void RSCoder16::MakeDecoderMatrix() { // Create Cauchy decoder matrix. Skip trivial rows matching valid data // units and containing "1" on main diagonal. Such rows would just copy // source data to destination and they have no real value for us. // Include rows only for broken data units and replace them by first // available valid recovery code rows. for (uint Flag=0, R=ND, Dest=0; Flag < ND; Flag++) if (!ValidFlags[Flag]) // For every broken data unit. { while (!ValidFlags[R]) // Find a valid recovery unit. R++; for (uint J = 0; J < ND; J++) // And place its row to matrix. MX[Dest*ND + J] = gfInv( gfAdd(R,J) ); Dest++; R++; } } // Apply Gauss–Jordan elimination to find inverse of decoder matrix. // We have the square NDxND matrix, but we do not store its trivial // diagonal "1" rows matching valid data, so we work with NExND matrix. // Our original Cauchy matrix does not contain 0, so we skip search // for non-zero pivot. void RSCoder16::InvertDecoderMatrix() { uint *MI=new uint[NE * ND]; // We'll create inverse matrix here. memset(MI, 0, ND * NE * sizeof(*MI)); // Initialize to identity matrix. for (uint Kr = 0, Kf = 0; Kr < NE; Kr++, Kf++) { while (ValidFlags[Kf]) // Skip trivial rows. Kf++; MI[Kr * ND + Kf] = 1; // Set diagonal 1. } // Kr is the number of row in our actual reduced NE x ND matrix, // which does not contain trivial diagonal 1 rows. // Kf is the number of row in full ND x ND matrix with all trivial rows // included. for (uint Kr = 0, Kf = 0; Kf < ND; Kr++, Kf++) // Select pivot row. { while (ValidFlags[Kf] && Kf < ND) { // Here we process trivial diagonal 1 rows matching valid data units. // Their processing can be simplified comparing to usual rows. // In full version of elimination we would set MX[I * ND + Kf] to zero // after MI[..]^=, but we do not need it for matrix inversion. for (uint I = 0; I < NE; I++) MI[I * ND + Kf] ^= MX[I * ND + Kf]; Kf++; } if (Kf == ND) break; uint *MXk = MX + Kr * ND; // k-th row of main matrix. uint *MIk = MI + Kr * ND; // k-th row of inversion matrix. uint PInv = gfInv( MXk[Kf] ); // Pivot inverse. // Divide the pivot row by pivot, so pivot cell contains 1. for (uint I = 0; I < ND; I++) { MXk[I] = gfMul( MXk[I], PInv ); MIk[I] = gfMul( MIk[I], PInv ); } for (uint I = 0; I < NE; I++) if (I != Kr) // For all rows except containing the pivot cell. { // Apply Gaussian elimination Mij -= Mkj * Mik / pivot. // Since pivot is already 1, it is reduced to Mij -= Mkj * Mik. uint *MXi = MX + I * ND; // i-th row of main matrix. uint *MIi = MI + I * ND; // i-th row of inversion matrix. uint Mik = MXi[Kf]; // Cell in pivot position. for (uint J = 0; J < ND; J++) { MXi[J] ^= gfMul(MXk[J] , Mik); MIi[J] ^= gfMul(MIk[J] , Mik); } } } // Copy data to main matrix. for (uint I = 0; I < NE * ND; I++) MX[I] = MI[I]; delete[] MI; } // Multiply matrix to data vector. When encoding, it contains data in Data // and stores error correction codes in Out. When decoding it contains // broken data followed by ECC in Data and stores recovered data to Out. // We do not use this function now, everything is moved to UpdateECC. void RSCoder16::Process(const uint *Data, uint *Out) { uint ProcData[gfSize]; for (uint I = 0; I < ND; I++) ProcData[I]=Data[I]; if (Decoding) { // Replace broken data units with first available valid recovery codes. // 'Data' array must contain recovery codes after data. for (uint I=0, R=ND, Dest=0; I < ND; I++) if (!ValidFlags[I]) // For every broken data unit. { while (!ValidFlags[R]) // Find a valid recovery unit. R++; ProcData[I]=Data[R]; R++; } } uint H=Decoding ? NE : NR; for (uint I = 0; I < H; I++) { uint R = 0; // Result of matrix row multiplication to data. uint *MXi=MX + I * ND; for (uint J = 0; J < ND; J++) R ^= gfMul(MXi[J], ProcData[J]); Out[I] = R; } } // We update ECC in blocks by applying every data block to all ECC blocks. // This function applies one data block to one ECC block. void RSCoder16::UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte *ECC, size_t BlockSize) { if (DataNum==0) // Init ECC data. memset(ECC, 0, BlockSize); bool DirectAccess; #ifdef LITTLE_ENDIAN // We can access data and ECC directly if we have little endian 16 bit uint. DirectAccess=sizeof(ushort)==2; #else DirectAccess=false; #endif #ifdef USE_SSE if (DirectAccess && SSE_UpdateECC(DataNum,ECCNum,Data,ECC,BlockSize)) return; #endif if (ECCNum==0) { if (DataLogSize!=BlockSize) { delete[] DataLog; DataLog=new uint[BlockSize]; DataLogSize=BlockSize; } if (DirectAccess) for (size_t I=0; I>8; ((byte *)&T1L)[I]=gfMul(I<<4,M); ((byte *)&T1H)[I]=gfMul(I<<4,M)>>8; ((byte *)&T2L)[I]=gfMul(I<<8,M); ((byte *)&T2H)[I]=gfMul(I<<8,M)>>8; ((byte *)&T3L)[I]=gfMul(I<<12,M); ((byte *)&T3H)[I]=gfMul(I<<12,M)>>8; } size_t Pos=0; __m128i LowByteMask=_mm_set1_epi16(0xff); // 00ff00ff...00ff __m128i Low4Mask=_mm_set1_epi8(0xf); // 0f0f0f0f...0f0f __m128i High4Mask=_mm_slli_epi16(Low4Mask,4); // f0f0f0f0...f0f0 for (; Pos+2*sizeof(__m128i)<=BlockSize; Pos+=2*sizeof(__m128i)) { // We process two 128 bit chunks of source data at once. __m128i *D=(__m128i *)(Data+Pos); // Place high bytes of both chunks to one variable and low bytes to // another, so we can use the table lookup multiplication for 16 values // 4 bit length each at once. __m128i HighBytes0=_mm_srli_epi16(D[0],8); __m128i LowBytes0=_mm_and_si128(D[0],LowByteMask); __m128i HighBytes1=_mm_srli_epi16(D[1],8); __m128i LowBytes1=_mm_and_si128(D[1],LowByteMask); __m128i HighBytes=_mm_packus_epi16(HighBytes0,HighBytes1); __m128i LowBytes=_mm_packus_epi16(LowBytes0,LowBytes1); // Multiply bits 0..3 of low bytes. Store low and high product bytes // separately in cumulative sum variables. __m128i LowBytesLow4=_mm_and_si128(LowBytes,Low4Mask); __m128i LowBytesMultSum=_mm_shuffle_epi8(T0L,LowBytesLow4); __m128i HighBytesMultSum=_mm_shuffle_epi8(T0H,LowBytesLow4); // Multiply bits 4..7 of low bytes. Store low and high product bytes separately. __m128i LowBytesHigh4=_mm_and_si128(LowBytes,High4Mask); LowBytesHigh4=_mm_srli_epi16(LowBytesHigh4,4); __m128i LowBytesHigh4MultLow=_mm_shuffle_epi8(T1L,LowBytesHigh4); __m128i LowBytesHigh4MultHigh=_mm_shuffle_epi8(T1H,LowBytesHigh4); // Add new product to existing sum, low and high bytes separately. LowBytesMultSum=_mm_xor_si128(LowBytesMultSum,LowBytesHigh4MultLow); HighBytesMultSum=_mm_xor_si128(HighBytesMultSum,LowBytesHigh4MultHigh); // Multiply bits 0..3 of high bytes. Store low and high product bytes separately. __m128i HighBytesLow4=_mm_and_si128(HighBytes,Low4Mask); __m128i HighBytesLow4MultLow=_mm_shuffle_epi8(T2L,HighBytesLow4); __m128i HighBytesLow4MultHigh=_mm_shuffle_epi8(T2H,HighBytesLow4); // Add new product to existing sum, low and high bytes separately. LowBytesMultSum=_mm_xor_si128(LowBytesMultSum,HighBytesLow4MultLow); HighBytesMultSum=_mm_xor_si128(HighBytesMultSum,HighBytesLow4MultHigh); // Multiply bits 4..7 of high bytes. Store low and high product bytes separately. __m128i HighBytesHigh4=_mm_and_si128(HighBytes,High4Mask); HighBytesHigh4=_mm_srli_epi16(HighBytesHigh4,4); __m128i HighBytesHigh4MultLow=_mm_shuffle_epi8(T3L,HighBytesHigh4); __m128i HighBytesHigh4MultHigh=_mm_shuffle_epi8(T3H,HighBytesHigh4); // Add new product to existing sum, low and high bytes separately. LowBytesMultSum=_mm_xor_si128(LowBytesMultSum,HighBytesHigh4MultLow); HighBytesMultSum=_mm_xor_si128(HighBytesMultSum,HighBytesHigh4MultHigh); // Combine separate low and high cumulative sum bytes to 16-bit words. __m128i HighBytesHigh4Mult0=_mm_unpacklo_epi8(LowBytesMultSum,HighBytesMultSum); __m128i HighBytesHigh4Mult1=_mm_unpackhi_epi8(LowBytesMultSum,HighBytesMultSum); // Add result to ECC. __m128i *StoreECC=(__m128i *)(ECC+Pos); StoreECC[0]=_mm_xor_si128(StoreECC[0],HighBytesHigh4Mult0); StoreECC[1]=_mm_xor_si128(StoreECC[1],HighBytesHigh4Mult1); } // If we have non 128 bit aligned data in the end of block, process them // in a usual way. We cannot do the same in the beginning of block, // because Data and ECC can have different alignment offsets. for (; Pos=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,ASIZE(CurMask))) return false; CurMask[ASIZE(CurMask)-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; wchar *Name=PointToName(CurMask); if (*Name==0) wcsncatz(CurMask,MASKALL,ASIZE(CurMask)); if (Name[0]=='.' && (Name[1]==0 || Name[1]=='.' && Name[2]==0)) { AddEndSlash(CurMask,ASIZE(CurMask)); wcsncatz(CurMask,MASKALL,ASIZE(CurMask)); } SpecPathLength=Name-CurMask; Depth=0; wcscpy(OrigCurMask,CurMask); 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); // 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,FD,GetLinks); // Link check is important for NTFS, where links can have "Directory" // attribute, but we do not want to recurse to them in "get links" mode. bool IsDir=FindCode && FD->IsDir && (!GetLinks || !FD->IsLink); // SearchAll means that we'll use "*" mask for search, so we'll find // subdirectories and will be able to recurse into them. // 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; wchar SearchMask[NM]; wcsncpyz(SearchMask,CurMask,ASIZE(SearchMask)); if (SearchAll) SetName(SearchMask,MASKALL,ASIZE(SearchMask)); FindStack[Depth]->SetMask(SearchMask); } 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 || !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,CurMask); } // 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; 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; if (Error) ScanError(Error); wchar DirName[NM]; *DirName=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; } wchar *Slash=wcsrchr(CurMask,CPATHDIVIDER); if (Slash!=NULL) { wchar Mask[NM]; wcscpy(Mask,Slash); if (DepthIsDir) { FD->Flags|=FDDF_SECONDDIR; return Error ? SCAN_ERROR:SCAN_SUCCESS; } return Error ? SCAN_ERROR:SCAN_NEXT; } // Link check is required for NTFS links, not for Unix. if (FD->IsDir && (!GetLinks || !FD->IsLink)) { // If we found the directory in top (Depth==0) directory // and if we are not in "fast find" (directory name only as argument) // 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; } wchar Mask[NM]; wcscpy(Mask,FastFindFile ? MASKALL:PointToName(CurMask)); wcscpy(CurMask,FD->Name); if (wcslen(CurMask)+wcslen(Mask)+1>=NM || Depth>=MAXSCANDEPTH-1) { #ifndef SILENT Log(NULL,L"\n%ls%c%ls",CurMask,CPATHDIVIDER,Mask); Log(NULL,St(MPathTooLong)); #endif return SCAN_ERROR; } AddEndSlash(CurMask,ASIZE(CurMask)); wcsncatz(CurMask,Mask,ASIZE(CurMask)); 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; } void ScanTree::ScanError(bool &Error) { #ifdef _WIN_ALL if (Error) { // Get attributes of parent folder and do not display an error // if it is reparse point. We cannot scan contents of standard // Windows reparse points like "C:\Documents and Settings" // and we do not want to issue numerous useless errors for them. // We cannot just check FD->FileAttr here, it can be undefined // if we process "folder\*" mask or if we process "folder" mask, // but "folder" is inaccessible. wchar *Slash=PointToName(CurMask); if (Slash>CurMask) { *(Slash-1)=0; DWORD Attr=GetFileAttributes(CurMask); *(Slash-1)=CPATHDIVIDER; if (Attr!=0xffffffff && (Attr & FILE_ATTRIBUTE_REPARSE_POINT)!=0) Error=false; } // Do not display an error if we cannot scan contents of // "System Volume Information" folder. Normally it is not accessible. if (wcsstr(CurMask,L"System Volume Information\\")!=NULL) Error=false; } #endif if (Error && Cmd!=NULL && Cmd->ExclCheck(CurMask,false,true,true)) Error=false; #ifndef SILENT if (Error) { wchar FullName[NM]; // This conversion works for wildcard masks too. ConvertNameToFull(CurMask,FullName,ASIZE(FullName)); Log(NULL,St(MScanError),FullName); ErrHandler.SysErrMsg(); } #endif } unrar/secpassword.cpp0100666000000000000000000001221712176732144012345 0ustar z#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 parameter, so we need to take into account both sizes. memcpy(Dst,Src,Min(SrcSize,DstSize)*sizeof(*Dst)); SecHideData(Dst,DstSize*sizeof(*Dst),Encode); } void SecPassword::Get(wchar *Psw,size_t MaxSize) { if (PasswordSet) { Process(Password,ASIZE(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,wcslen(Psw)+1,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; } void SecHideData(void *Data,size_t DataSize,bool Encode) { #ifdef _WIN_ALL // Try to utilize the secure Crypt[Un]ProtectMemory if possible. if (GlobalCryptLoader.pCryptProtectMemory==NULL) GlobalCryptLoader.Load(); size_t Aligned=DataSize-DataSize%CRYPTPROTECTMEMORY_BLOCK_SIZE; if (Encode) { if (GlobalCryptLoader.pCryptProtectMemory!=NULL) { if (!GlobalCryptLoader.pCryptProtectMemory(Data,DWORD(Aligned),CRYPTPROTECTMEMORY_SAME_PROCESS)) { ErrHandler.GeneralErrMsg(L"CryptProtectMemory failed"); ErrHandler.SysErrMsg(); ErrHandler.Exit(RARX_FATAL); } return; } } else { if (GlobalCryptLoader.pCryptUnprotectMemory!=NULL) { if (!GlobalCryptLoader.pCryptUnprotectMemory(Data,DWORD(Aligned),CRYPTPROTECTMEMORY_SAME_PROCESS)) { ErrHandler.GeneralErrMsg(L"CryptUnprotectMemory failed"); ErrHandler.SysErrMsg(); ErrHandler.Exit(RARX_FATAL); } return; } } #endif // CryptProtectMemory is not available, so only slightly obfuscate data. uint Key; #ifdef _WIN_ALL Key=GetCurrentProcessId(); #elif defined(_UNIX) Key=getpid(); #else Key=0; // Just an arbitrary value. #endif for (size_t I=0;I 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;Istate[] 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 */ } unrar/sha256.cpp0100666000000000000000000001232012176732144011013 0ustar z#include "rar.hpp" #include "sha256.hpp" static const uint32 K[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; #define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) #define ROTR(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) // SHA-256 functions. We could optimize Ch and Maj a little, // but with no visible speed benefit. #define Ch(x, y, z) ((x & y) ^ (~x & z)) #define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) // Sigma functions. #define Sg0(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x, 22)) #define Sg1(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x, 25)) #define sg0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ (x >> 3)) #define sg1(x) (ROTR(x,17) ^ ROTR(x,19) ^ (x >> 10)) void sha256_init(sha256_context *ctx) { ctx->H[0] = 0x6a09e667; // Set the initial hash value. ctx->H[1] = 0xbb67ae85; ctx->H[2] = 0x3c6ef372; ctx->H[3] = 0xa54ff53a; ctx->H[4] = 0x510e527f; ctx->H[5] = 0x9b05688c; ctx->H[6] = 0x1f83d9ab; ctx->H[7] = 0x5be0cd19; ctx->Count = 0; // Processed data counter. } inline uint32 b2i(const byte *b) // Big endian bytes to integer. { #if defined(_MSC_VER)/* && defined(LITTLE_ENDIAN)*/ return _byteswap_ulong(*(uint32 *)b); #else return uint32(b[0]<<24) | uint32(b[1]<<16) | uint32(b[2]<<8) | b[3]; #endif } static void sha256_transform(sha256_context *ctx) { uint32 W[64]; // Words of message schedule. uint32 v[8]; // FIPS a, b, c, d, e, f, g, h working variables. if (ctx == NULL) // Clean variables and return. { cleandata(v,sizeof(v)); cleandata(W,sizeof(W)); return; } // Prepare message schedule. Loop unrolling provides some small gain here. W[0] = b2i(ctx->Data + 0 * 4 ); W[1] = b2i(ctx->Data + 1 * 4 ); W[2] = b2i(ctx->Data + 2 * 4 ); W[3] = b2i(ctx->Data + 3 * 4 ); W[4] = b2i(ctx->Data + 4 * 4 ); W[5] = b2i(ctx->Data + 5 * 4 ); W[6] = b2i(ctx->Data + 6 * 4 ); W[7] = b2i(ctx->Data + 7 * 4 ); W[8] = b2i(ctx->Data + 8 * 4 ); W[9] = b2i(ctx->Data + 9 * 4 ); W[10] = b2i(ctx->Data + 10 * 4 ); W[11] = b2i(ctx->Data + 11 * 4 ); W[12] = b2i(ctx->Data + 12 * 4 ); W[13] = b2i(ctx->Data + 13 * 4 ); W[14] = b2i(ctx->Data + 14 * 4 ); W[15] = b2i(ctx->Data + 15 * 4 ); for (uint I = 16; I < 64; I++) W[I] = sg1(W[I-2]) + W[I-7] + sg0(W[I-15]) + W[I-16]; uint32 *H=ctx->H; v[0]=H[0]; v[1]=H[1]; v[2]=H[2]; v[3]=H[3]; v[4]=H[4]; v[5]=H[5]; v[6]=H[6]; v[7]=H[7]; // MSVC -O2 partially unrolls this loop automatically. for (uint I = 0; I < 64; I++) { uint T1 = v[7] + Sg1(v[4]) + Ch(v[4], v[5], v[6]) + K[I] + W[I]; // It is possible to eliminate variable copying if we unroll loop // and rename variables every time. But my test did not show any speed // gain on i7 for such full or partial unrolling. v[7] = v[6]; v[6] = v[5]; v[5] = v[4]; v[4] = v[3] + T1; // It works a little faster when moved here from beginning of loop. uint T2 = Sg0(v[0]) + Maj(v[0], v[1], v[2]); v[3] = v[2]; v[2] = v[1]; v[1] = v[0]; v[0] = T1 + T2; } H[0]+=v[0]; H[1]+=v[1]; H[2]+=v[2]; H[3]+=v[3]; H[4]+=v[4]; H[5]+=v[5]; H[6]+=v[6]; H[7]+=v[7]; } void sha256_process(sha256_context *ctx, const void *Data, size_t Size) { const byte *Src=(const byte *)Data; size_t BufPos = (uint)ctx->Count & 0x3f; ctx->Count+=Size; while (Size > 0) { size_t BufSpace=sizeof(ctx->Buffer)-BufPos; size_t CopySize=Size>BufSpace ? BufSpace:Size; if (CopySize == 64) ctx->Data=Src; // Point to source data instead of copying it to buffer. else { ctx->Data=ctx->Buffer; memcpy(ctx->Buffer+BufPos,Src,CopySize); } Src+=CopySize; BufPos+=CopySize; Size-=CopySize; if (BufPos == 64) { BufPos = 0; sha256_transform(ctx); } } sha256_transform(NULL); } void sha256_done(sha256_context *ctx, byte *Digest) { ctx->Data = ctx->Buffer; uint64 BitLength = ctx->Count * 8; uint BufPos = (uint)ctx->Count & 0x3f; ctx->Buffer[BufPos++] = 0x80; // Padding the message with "1" bit. while (BufPos != 56) // We need 56 bytes block followed by 8 byte length. { BufPos &= 0x3f; if (BufPos == 0) sha256_transform(ctx); ctx->Buffer[BufPos++] = 0; } for (uint i = 0; i < 8; i++) // Store bit length of entire message. { ctx->Buffer[BufPos++] = (byte)(BitLength >> 56); BitLength <<= 8; } sha256_transform(ctx); for (uint i = 0; i < 32; i++) Digest[i] = byte(ctx->H[i / 4] >> ((3 - i % 4) * 8)); sha256_init(ctx); sha256_transform(NULL); cleandata(ctx->Buffer, sizeof(ctx->Buffer)); } unrar/smallfn.cpp0100666000000000000000000000040312176732144011436 0ustar z#include "rar.hpp" int ToPercent(int64 N1,int64 N2) { if (N2=0 && (Str[I]=='\r' || Str[I]=='\n' || Str[I]==' ' || Str[I]=='\t');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'); } void BinToHex(const byte *Bin,size_t BinSize,char *HexA,wchar *HexW,size_t HexSize) { uint A=0,W=0; // ASCII and Unicode hex output positions. for (uint I=0;I> 4; uint Low=Bin[I] & 0xf; uint HighHex=High>9 ? 'a'+High-10:'0'+High; uint LowHex=Low>9 ? 'a'+Low-10:'0'+Low; if (HexA!=NULL && A0) HexA[A]=0; if (HexW!=NULL && HexSize>0) HexW[W]=0; } #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 wcsicompc(const wchar *Str1,const wchar *Str2) { #if defined(_UNIX) return(wcscmp(Str1,Str2)); #else return(wcsicomp(Str1,Str2)); #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= ASIZE(StrTable)) StrNum=0; wchar *Str=StrTable[StrNum]; CharToWide(Src,Str,MaxLength); Str[MaxLength-1]=0; return(Str); } // 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 StrW(strlen(Str)); CharToWide(Str,&StrW[0],StrW.Size()); AddString(&StrW[0]); } void StringList::AddString(const wchar *Str) { if (Str==NULL) Str=L""; size_t PrevSize=StringData.Size(); StringData.Add(wcslen(Str)+1); wcscpy(&StringData[PrevSize],Str); StringsCount++; } bool StringList::GetStringA(char *Str,size_t MaxLength) { Array StrW(MaxLength); if (!GetString(&StrW[0],StrW.Size())) return false; WideToChar(&StrW[0],Str,MaxLength); return true; } bool StringList::GetString(wchar *Str,size_t MaxLength) { wchar *StrPtr; if (!GetString(&StrPtr)) return false; wcsncpyz(Str,StrPtr,MaxLength); return true; } #ifndef SFX_MODULE bool StringList::GetString(wchar *Str,size_t MaxLength,int StringNum) { SavePosition(); Rewind(); bool RetCode=true; while (StringNum-- >=0) if (!GetString(Str,MaxLength)) { RetCode=false; break; } RestorePosition(); return RetCode; } #endif wchar* StringList::GetString() { wchar *Str; GetString(&Str); return Str; } bool StringList::GetString(wchar **Str) { if (CurPos>=StringData.Size()) // No more strings left unprocessed. { if (Str!=NULL) *Str=NULL; return false; } wchar *CurStr=&StringData[CurPos]; CurPos+=wcslen(CurStr)+1; if (Str!=NULL) *Str=CurStr; return true; } void StringList::Rewind() { CurPos=0; } #ifndef SFX_MODULE bool StringList::Search(const wchar *Str,bool CaseSensitive) { SavePosition(); Rewind(); bool Found=false; wchar *CurStr; while (GetString(&CurStr)) { if (Str!=NULL && CurStr!=NULL) if ((CaseSensitive ? wcscmp(Str,CurStr):wcsicomp(Str,CurStr))!=0) continue; Found=true; break; } RestorePosition(); return Found; } #endif #ifndef SFX_MODULE void StringList::SavePosition() { if (SavePosNumber0) { SavePosNumber--; CurPos=SaveCurPos[SavePosNumber]; } } #endif unrar/suballoc.cpp0100666000000000000000000001712212176732144011614 0ustar z/**************************************************************************** * 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]); } unrar/system.cpp0100666000000000000000000000507112176732144011334 0ustar z#include "rar.hpp" static int SleepTime=0; void InitSystemOptions(int SleepTime) { ::SleepTime=SleepTime; } #if !defined(SFX_MODULE) && !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 (ErrHandler.UserBreak) ErrHandler.Exit(RARX_USERBREAK); #if defined(_WIN_ALL) && !defined(SFX_MODULE) if (SleepTime!=0) Sleep(SleepTime); #endif } #endif #if defined(_WIN_ALL) && !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 #ifdef USE_SSE SSE_VERSION _SSE_Version=GetSSEVersion(); SSE_VERSION GetSSEVersion() { int CPUInfo[4]; __cpuid(CPUInfo, 1); if ((CPUInfo[2] & 0x80000)!=0) return SSE_SSE41; if ((CPUInfo[2] & 0x200)!=0) return SSE_SSSE3; if ((CPUInfo[3] & 0x4000000)!=0) return SSE_SSE2; if ((CPUInfo[3] & 0x2000000)!=0) return SSE_SSE; return SSE_NONE; } #endif unrar/threadmisc.cpp0100666000000000000000000000577712176732144012150 0ustar z// Typically we use the same global thread pool for all RAR modules. static ThreadPool *GlobalPool=NULL; static uint GlobalPoolUseCount=0; ThreadPool* CreateThreadPool() { if (GlobalPoolUseCount++ == 0) GlobalPool=new ThreadPool(MaxPoolThreads); return GlobalPool; } void DestroyThreadPool(ThreadPool *Pool) { if (Pool!=NULL && Pool==GlobalPool && GlobalPoolUseCount > 0 && --GlobalPoolUseCount == 0) delete GlobalPool; } static THREAD_HANDLE ThreadCreate(NATIVE_THREAD_PTR Proc,void *Data) { #ifdef _UNIX pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); pthread_t pt; int Code=pthread_create(&pt,&attr,Proc,Data); if (Code!=0) { wchar Msg[100]; swprintf(Msg,ASIZE(Msg),L"\npthread_create failed, code %d\n",Code); ErrHandler.GeneralErrMsg(Msg); ErrHandler.SysErrMsg(); ErrHandler.Exit(RARX_FATAL); } return pt; #else DWORD ThreadId; HANDLE hThread=CreateThread(NULL,0x10000,Proc,Data,0,&ThreadId); if (hThread==NULL) { ErrHandler.GeneralErrMsg(L"CreateThread failed"); ErrHandler.SysErrMsg(); ErrHandler.Exit(RARX_FATAL); } return hThread; #endif } static void ThreadClose(THREAD_HANDLE hThread) { #ifdef _UNIX pthread_join(hThread,NULL); #else CloseHandle(hThread); #endif } static inline void CriticalSectionStart(CRITSECT_HANDLE *CritSection) { #ifdef _WIN_ALL EnterCriticalSection(CritSection); #elif defined(_UNIX) pthread_mutex_lock(CritSection); #endif } static inline void CriticalSectionEnd(CRITSECT_HANDLE *CritSection) { #ifdef _WIN_ALL LeaveCriticalSection(CritSection); #elif defined(_UNIX) pthread_mutex_unlock(CritSection); #endif } #ifdef _WIN_ALL static void CWaitForSingleObject(HANDLE hHandle) { DWORD rc=WaitForSingleObject(hHandle,INFINITE); if (rc==WAIT_FAILED) { ErrHandler.GeneralErrMsg(L"\nWaitForMultipleObjects error %d, GetLastError %d",rc,GetLastError()); ErrHandler.Exit(RARX_FATAL); } } #endif #ifdef _UNIX static void cpthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) { int rc=pthread_cond_wait(cond,mutex); if (rc!=0) { ErrHandler.GeneralErrMsg(L"\npthread_cond_wait error %d",rc); ErrHandler.Exit(RARX_FATAL); } } #endif uint GetNumberOfCPU() { #ifndef RAR_SMP return 1; #else #ifdef _UNIX #ifdef _SC_NPROCESSORS_ONLN uint Count=(uint)sysconf(_SC_NPROCESSORS_ONLN); return Count<1 ? 1:Count; #elif defined(_APPLE) uint Count; size_t Size=sizeof(Count); return sysctlbyname("hw.ncpu",&Count,&Size,NULL,0)==0 ? Count:1; #endif #else // !_UNIX DWORD_PTR ProcessMask; DWORD_PTR SystemMask; if (!GetProcessAffinityMask(GetCurrentProcess(),&ProcessMask,&SystemMask)) return 1; uint Count=0; for (DWORD_PTR Mask=1;Mask!=0;Mask<<=1) if ((ProcessMask & Mask)!=0) Count++; return Count<1 ? 1:Count; #endif #endif // RAR_SMP } uint GetNumberOfThreads() { uint NumCPU=GetNumberOfCPU(); if (NumCPU<1) return 1; if (NumCPU>MaxPoolThreads) return MaxPoolThreads; return NumCPU; } unrar/threadpool.cpp0100666000000000000000000001270112176732144012147 0ustar z#include "rar.hpp" #ifdef RAR_SMP #include "threadmisc.cpp" #ifdef _WIN_ALL int ThreadPool::ThreadPriority=THREAD_PRIORITY_NORMAL; #endif ThreadPool::ThreadPool(uint MaxThreads) { MaxAllowedThreads = MaxThreads; if (MaxAllowedThreads>MaxPoolThreads) MaxAllowedThreads=MaxPoolThreads; if (MaxAllowedThreads==0) MaxAllowedThreads=1; // If we have more threads than queue size, we'll hang on pool destroying, // not releasing all waiting threads. if (MaxAllowedThreads>ASIZE(TaskQueue)) MaxAllowedThreads=ASIZE(TaskQueue); Closing=false; bool Success; #ifdef _WIN_ALL QueuedTasksCnt=CreateSemaphore(NULL,0,ASIZE(TaskQueue),NULL); NoneActive=CreateEvent(NULL,TRUE,TRUE,NULL); InitializeCriticalSection(&CritSection); Success=QueuedTasksCnt!=NULL && NoneActive!=NULL; #elif defined(_UNIX) AnyActive = false; QueuedTasksCnt = 0; Success=pthread_mutex_init(&CritSection,NULL)==0 && pthread_cond_init(&AnyActiveCond,NULL)==0 && pthread_mutex_init(&AnyActiveMutex,NULL)==0 && pthread_cond_init(&QueuedTasksCntCond,NULL)==0 && pthread_mutex_init(&QueuedTasksCntMutex,NULL)==0; #endif if (!Success) { ErrHandler.GeneralErrMsg(L"\nThread pool initialization failed."); ErrHandler.Exit(RARX_FATAL); } for(uint I=0;IPoolThreadLoop(); return 0; } void ThreadPool::PoolThreadLoop() { QueueEntry Task; while (GetQueuedTask(&Task)) { Task.Proc(Task.Param); CriticalSectionStart(&CritSection); if (--ActiveThreads == 0) { #ifdef _WIN_ALL SetEvent(NoneActive); #elif defined(_UNIX) pthread_mutex_lock(&AnyActiveMutex); AnyActive=false; pthread_cond_signal(&AnyActiveCond); pthread_mutex_unlock(&AnyActiveMutex); #endif } CriticalSectionEnd(&CritSection); } } bool ThreadPool::GetQueuedTask(QueueEntry *Task) { #ifdef _WIN_ALL CWaitForSingleObject(QueuedTasksCnt); #elif defined(_UNIX) pthread_mutex_lock(&QueuedTasksCntMutex); while (QueuedTasksCnt==0) cpthread_cond_wait(&QueuedTasksCntCond,&QueuedTasksCntMutex); QueuedTasksCnt--; pthread_mutex_unlock(&QueuedTasksCntMutex); #endif if (Closing) return false; CriticalSectionStart(&CritSection); *Task = TaskQueue[QueueBottom]; QueueBottom = (QueueBottom + 1) % ASIZE(TaskQueue); CriticalSectionEnd(&CritSection); return true; } // Add task to queue. We assume that it is always called from main thread, // it allows to avoid any locks here. We process collected tasks only // when StartWait is called. void ThreadPool::AddTask(PTHREAD_PROC Proc,void *Data) { // If queue is full, wait until it is empty. if ((QueueTop + 1) % ASIZE(TaskQueue) == QueueBottom) WaitDone(); TaskQueue[QueueTop].Proc = Proc; TaskQueue[QueueTop].Param = Data; QueueTop = (QueueTop + 1) % ASIZE(TaskQueue); } // Start queued tasks and wait until all threads are inactive. // We assume that it is always called from main thread, when pool threads // are sleeping yet. void ThreadPool::WaitDone() { // We add ASIZE(TaskQueue) for case if TaskQueue array size is not // a power of two. Negative numbers would not suit our purpose here. ActiveThreads=(QueueTop+ASIZE(TaskQueue)-QueueBottom) % ASIZE(TaskQueue); if (ActiveThreads==0) return; #ifdef _WIN_ALL ResetEvent(NoneActive); ReleaseSemaphore(QueuedTasksCnt,ActiveThreads,NULL); CWaitForSingleObject(NoneActive); #elif defined(_UNIX) AnyActive=true; // Threads reset AnyActive before accessing QueuedTasksCnt and even // preceding WaitDone() call does not guarantee that some slow thread // is not accessing QueuedTasksCnt now. So lock is necessary. pthread_mutex_lock(&QueuedTasksCntMutex); QueuedTasksCnt+=ActiveThreads; pthread_mutex_unlock(&QueuedTasksCntMutex); pthread_cond_broadcast(&QueuedTasksCntCond); pthread_mutex_lock(&AnyActiveMutex); while (AnyActive) cpthread_cond_wait(&AnyActiveCond,&AnyActiveMutex); pthread_mutex_unlock(&AnyActiveMutex); #endif } #endif // RAR_SMP unrar/timefn.cpp0100666000000000000000000001404212176732144011270 0ustar z#include "rar.hpp" RarTime::RarTime() { Reset(); } #ifdef _WIN_ALL RarTime& RarTime::operator =(FILETIME &ft) { _ULARGE_INTEGER ul = {ft.dwLowDateTime, ft.dwHighDateTime}; itime=ul.QuadPart; return *this; } void RarTime::GetWin32(FILETIME *ft) { _ULARGE_INTEGER ul; ul.QuadPart=itime; ft->dwLowDateTime=ul.LowPart; ft->dwHighDateTime=ul.HighPart; } #endif RarTime& RarTime::operator =(time_t ut) { uint64 ushift=INT32TO64(0x19DB1DE,0xD53E8000); // 116444736000000000. itime=uint64(ut)*10000000+ushift; return *this; } time_t RarTime::GetUnix() { uint64 ushift=INT32TO64(0x19DB1DE,0xD53E8000); // 116444736000000000. time_t ut=(itime-ushift)/10000000; return ut; } void RarTime::GetLocal(RarLocalTime *lt) { #ifdef _WIN_ALL FILETIME ft; GetWin32(&ft); FILETIME lft; FileTimeToLocalFileTime(&ft,&lft); SYSTEMTIME st; FileTimeToSystemTime(&lft,&st); lt->Year=st.wYear; lt->Month=st.wMonth; lt->Day=st.wDay; lt->Hour=st.wHour; lt->Minute=st.wMinute; lt->Second=st.wSecond; lt->wDay=st.wDayOfWeek; lt->yDay=lt->Day-1; static int mdays[12]={31,28,31,30,31,30,31,31,30,31,30,31}; for (uint I=1;IMonth && I<=ASIZE(mdays);I++) lt->yDay+=mdays[I-1]; if (lt->Month>2 && IsLeapYear(lt->Year)) lt->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. lt->Reminder=INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime)- INT32TO64(zft.dwHighDateTime,zft.dwLowDateTime); #else time_t ut=GetUnix(); struct tm *t; t=localtime(&ut); lt->Year=t->tm_year+1900; lt->Month=t->tm_mon+1; lt->Day=t->tm_mday; lt->Hour=t->tm_hour; lt->Minute=t->tm_min; lt->Second=t->tm_sec; lt->Reminder=0; lt->wDay=t->tm_wday; lt->yDay=t->tm_yday; #endif } void RarTime::SetLocal(RarLocalTime *lt) { #ifdef _WIN_ALL SYSTEMTIME st; st.wYear=lt->Year; st.wMonth=lt->Month; st.wDay=lt->Day; st.wHour=lt->Hour; st.wMinute=lt->Minute; st.wSecond=lt->Second; st.wMilliseconds=0; FILETIME lft; if (SystemTimeToFileTime(&st,&lft)) { lft.dwLowDateTime+=lt->Reminder; if (lft.dwLowDateTimeReminder) lft.dwHighDateTime++; FILETIME ft; LocalFileTimeToFileTime(&lft,&ft); *this=ft; } else Reset(); #else struct tm t; t.tm_sec=lt->Second; t.tm_min=lt->Minute; t.tm_hour=lt->Hour; t.tm_mday=lt->Day; t.tm_mon=lt->Month-1; t.tm_year=lt->Year-1900; t.tm_isdst=-1; *this=mktime(&t); #endif } // Return the stored time as 64-bit number of 100-nanosecond intervals since // 01.01.1601. Actually we do not care since which date this time starts from // as long as this date is the same for GetRaw and SetRaw. We use the value // returned by GetRaw() for time comparisons, for relative operations // like SetRaw(GetRaw()-C) and for compact time storage when necessary. uint64 RarTime::GetRaw() { return itime; } void RarTime::SetRaw(uint64 RawTime) { itime=RawTime; } uint RarTime::GetDos() { RarLocalTime lt; GetLocal(<); uint DosTime=(lt.Second/2)|(lt.Minute<<5)|(lt.Hour<<11)| (lt.Day<<16)|(lt.Month<<21)|((lt.Year-1980)<<25); return DosTime; } void RarTime::SetDos(uint DosTime) { RarLocalTime lt; lt.Second=(DosTime & 0x1f)*2; lt.Minute=(DosTime>>5) & 0x3f; lt.Hour=(DosTime>>11) & 0x1f; lt.Day=(DosTime>>16) & 0x1f; lt.Month=(DosTime>>21) & 0x0f; lt.Year=(DosTime>>25)+1980; lt.Reminder=0; SetLocal(<); } #if !defined(GUI) || !defined(SFX_MODULE) void RarTime::GetText(wchar *DateStr,size_t MaxSize,bool FullYear,bool FullMS) { if (IsSet()) { RarLocalTime lt; GetLocal(<); if (FullMS) swprintf(DateStr,MaxSize,L"%u-%02u-%02u %02u:%02u,%03u",lt.Year,lt.Month,lt.Day,lt.Hour,lt.Minute,lt.Reminder/10000); else if (FullYear) swprintf(DateStr,MaxSize,L"%02u-%02u-%u %02u:%02u",lt.Day,lt.Month,lt.Year,lt.Hour,lt.Minute); else swprintf(DateStr,MaxSize,L"%02u-%02u-%02u %02u:%02u",lt.Day,lt.Month,lt.Year%100,lt.Hour,lt.Minute); } else { // We use escape before '?' to avoid weird C trigraph characters. wcscpy(DateStr,FullYear ? L"\?\?-\?\?-\?\?\?\? \?\?:\?\?":L"\?\?-\?\?-\?\? \?\?:\?\?"); } } #endif #ifndef SFX_MODULE void RarTime::SetIsoText(const wchar *TimeText) { int Field[6]; memset(Field,0,sizeof(Field)); for (uint DigitCount=0;*TimeText!=0;TimeText++) if (IsDigit(*TimeText)) { int FieldPos=DigitCount<4 ? 0:(DigitCount-4)/2+1; if (FieldPosRedirName,Target,ASIZE(Target)); if (hd->RedirType==FSREDIR_WINSYMLINK || hd->RedirType==FSREDIR_JUNCTION) { // Cannot create Windows absolute path symlinks in Unix. Only relative path // Windows symlinks can be created here. if (strncmp(Target,"\\??\\",4)==0) return false; DosSlashToUnix(Target,Target,ASIZE(Target)); } return UnixSymlink(Target,Name); } unrar/unicode.cpp0100666000000000000000000003003612176732144011435 0ustar z#include "rar.hpp" #define MBFUNCTIONS #if defined(_UNIX) && defined(MBFUNCTIONS) static bool WideToCharMap(const wchar *Src,char *Dest,size_t DestSize,bool &Success); static void CharToWideMap(const char *Src,wchar *Dest,size_t DestSize,bool &Success); // In Unix we map high ASCII characters which cannot be converted to Unicode // to 0xE000 - 0xE0FF private use Unicode area. static const uint MapAreaStart=0xE000; // Mapped string marker. Initially we used 0xFFFF for this purpose, // but it causes MSVC2008 swprintf to fail (it treats 0xFFFF as error marker). // While we could workaround it, it is safer to use another character. static const uint MappedStringMark=0xFFFE; #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) if (!WideToCharMap(Src,Dest,DestSize,RetCode)) { size_t ResultingSize=wcstombs(Dest,Src,DestSize); if (ResultingSize==(size_t)-1) RetCode=false; if (ResultingSize==0 && *Src!=0) RetCode=false; } #else for (int I=0;I0) Dest[DestSize-1]=0; // We tried to return the empty string if conversion is failed, // but it does not work well. WideCharToMultiByte returns 'failed' code // and partially converted string even if we wanted to convert only a part // 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==false && DestSize>1) CharToWideMap(Src,Dest,DestSize,RetCode); #else for (int I=0;I0) Dest[DestSize-1]=0; // We tried to return the empty string if conversion is failed, // but it does not work well. MultiByteToWideChar returns 'failed' code // 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; } #if defined(_UNIX) && defined(MBFUNCTIONS) // Convert and restore mapped inconvertible Unicode characters. // We use it for extended ASCII names in Unix. bool WideToCharMap(const wchar *Src,char *Dest,size_t DestSize,bool &Success) { // String with inconvertible characters mapped to private use Unicode area // must have the mark code somewhere. if (wcschr(Src,(wchar)MappedStringMark)==NULL) return false; Success=true; uint SrcPos=0,DestPos=0; while (DestPos=MapAreaStart+0x80 && uint(Src[SrcPos])=0x80) { if (!MarkAdded) { Dest[DestPos++]=MappedStringMark; MarkAdded=true; if (DestPos>=DestSize) break; } Dest[DestPos++]=byte(Src[SrcPos++])+MapAreaStart; } else break; } else { ignore_result( mblen(NULL,0) ); // Reset shift state. int Length=mblen(Src+SrcPos,MB_CUR_MAX); SrcPos+=Max(Length,1); DestPos++; } } } #endif // SrcSize is in wide characters, not in bytes. byte* WideToRaw(const wchar *Src,byte *Dest,size_t SrcSize) { for (size_t I=0;I>8); if (*Src==0) break; } return Dest; } wchar* RawToWide(const byte *Src,wchar *Dest,size_t DestSize) { for (size_t I=0;I=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>=0xd800 && c<=0xdbff && *Src>=0xdc00 && *Src<=0xdfff) // Surrogate pair. { c=((c-0xd800)<<10)+(*Src-0xdc00)+0x10000; Src++; } if (c<0x10000 && (dsize-=2)>=0) { *(Dest++)=(0xe0|(c>>12)); *(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; } size_t WideToUtfSize(const wchar *Src) { size_t Size=0; for (;*Src!=0;Src++) if (*Src<0x80) Size++; else if (*Src<0x800) Size+=2; else if (*Src<0x10000) { if (Src[0]>=0xd800 && Src[0]<=0xdbff && Src[1]>=0xdc00 && Src[1]<=0xdfff) { Size+=4; // 4 output bytes for Unicode surrogate pair. Src++; } else Size+=3; } else if (*Src<0x200000) Size+=4; return Size+1; // Include terminating zero. } // Dest can be NULL if we only need to check validity of Src. bool UtfToWide(const char *Src,wchar *Dest,size_t DestSize) { 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) { Success=false; break; } d=((c&0x1f)<<6)|(*Src&0x3f); Src++; } else if ((c>>4)==14) { if ((Src[0]&0xc0)!=0x80 || (Src[1]&0xc0)!=0x80) { Success=false; break; } d=((c&0xf)<<12)|((Src[0]&0x3f)<<6)|(Src[1]&0x3f); Src+=2; } else if ((c>>3)==30) { if ((Src[0]&0xc0)!=0x80 || (Src[1]&0xc0)!=0x80 || (Src[2]&0xc0)!=0x80) { Success=false; break; } d=((c&7)<<18)|((Src[0]&0x3f)<<12)|((Src[1]&0x3f)<<6)|(Src[2]&0x3f); Src+=3; } else { Success=false; break; } if (Dest!=NULL && --dsize<0) break; if (d>0xffff) { if (Dest!=NULL && --dsize<0) break; if (d>0x10ffff) // UTF-8 must end at 0x10ffff according to RFC 3629. { Success=false; continue; } if (Dest!=NULL) if (sizeof(*Dest)==2) // Use the surrogate pair for 2 byte Unicode. { *(Dest++)=((d-0x10000)>>10)+0xd800; *(Dest++)=(d&0x3ff)+0xdc00; } else *(Dest++)=d; } else if (Dest!=NULL) *(Dest++)=d; } if (Dest!=NULL) *Dest=0; return Success; } int wcsicomp(const wchar *s1,const wchar *s2) { #ifdef _WIN_ALL return CompareStringW(LOCALE_USER_DEFAULT,NORM_IGNORECASE|SORT_STRINGSORT,s1,-1,s2,-1)-2; #else while (towupper(*s1)==towupper(*s2)) { if (*s1==0) return 0; s1++; s2++; } return s1 < s2 ? -1 : 1; #endif } int wcsnicomp(const wchar *s1,const wchar *s2,size_t n) { #ifdef _WIN_ALL // If we specify 'n' exceeding the actual string length, CompareString goes // beyond the trailing zero and compares garbage. So we need to limit 'n' // to real string length. size_t l1=Min(wcslen(s1)+1,n); size_t l2=Min(wcslen(s2)+1,n); return(CompareStringW(LOCALE_USER_DEFAULT,NORM_IGNORECASE|SORT_STRINGSORT,s1,(int)l1,s2,(int)l2)-2); #else if (n==0) return 0; while (towupper(*s1)==towupper(*s2)) { if (*s1==0 || --n==0) return 0; s1++; s2++; } return s1 < s2 ? -1 : 1; #endif } #ifndef SFX_MODULE wchar* wcslower(wchar *s) { #ifdef _WIN_ALL CharLowerW(s); #else for (wchar *c=s;*c!=0;c++) *c=towlower(*c); #endif return s; } #endif #ifndef SFX_MODULE wchar* wcsupper(wchar *s) { #ifdef _WIN_ALL CharUpperW(s); #else for (wchar *c=s;*c!=0;c++) *c=towupper(*c); #endif return s; } #endif int toupperw(int ch) { #ifdef _WIN_ALL return (int)CharUpperW((wchar *)ch); #else return towupper(ch); #endif } int tolowerw(int ch) { #ifdef _WIN_ALL return (int)CharLowerW((wchar *)ch); #else return towlower(ch); #endif } uint atoiw(const wchar *s) { return (uint)atoilw(s); } uint64 atoilw(const wchar *s) { uint64 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;INextWindow flag // in UnpWriteBuf(). Minimum window size 0x20000 would be enough, but let's // use 0x40000 for extra safety and possible filter area size expansion. const size_t MinAllocSize=0x40000; if (WinSize>16)>0x10000) // Window size must not exceed 4 GB. return; // Archiving code guarantees that window size does not grow in the same // solid stream. So if we are here, we are either creating a new window // or increasing the size of non-solid window. So we could safely reject // current window data without copying them to a new window, though being // extra cautious, we still handle the solid window grow case below. bool Grow=Solid && (Window!=NULL || Fragmented); byte *NewWindow=(byte *)malloc(WinSize); // We do not handle growth for fragmented window now. if (Grow && (NewWindow==NULL || Fragmented)) throw std::bad_alloc(); if (NewWindow==NULL) if (WinSize<0x1000000) // Exclude RAR4 and small dictionaries. throw std::bad_alloc(); else { FragWindow.Init(WinSize); Fragmented=true; } if (!Fragmented) { // Clean the window to generate the same output when unpacking corrupt // RAR files, which may access to unused areas of sliding dictionary. memset(NewWindow,0,WinSize); // If Window is not NULL, it means that window size has grown. // In solid streams we need to copy data to a new window in such case. // RAR archiving code does not allow it in solid streams now, // but let's implement it anyway just in case we'll change it sometimes. if (Grow) for (size_t I=1;I1) { Unpack5MT(Solid); break; } #endif Unpack5(Solid); break; } } void Unpack::UnpInitData(bool Solid) { if (!Solid) { memset(OldDist,0,sizeof(OldDist)); OldDistPtr=0; LastDist=LastLength=0; // memset(Window,0,MaxWinSize); memset(&BlockTables,0,sizeof(BlockTables)); UnpPtr=WrPtr=0; WriteBorder=Min(MaxWinSize,UNPACK_MAX_WRITE)&MaxWinMask; InitFilters(); } Inp.InitBitInput(); WrittenFileSize=0; ReadTop=0; ReadBorder=0; memset(&BlockHeader,0,sizeof(BlockHeader)); BlockHeader.BlockSize=-1; // '-1' means not defined yet. #ifndef SFX_MODULE UnpInitData20(Solid); #endif UnpInitData30(Solid); } // 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;IDecodeNum,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;IDecodeNum[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: case NC30: 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<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;CodeQuickBits); // 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] && CurBitLengthDecodeLen)) 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 (PosQuickNum[Code]=Dec->DecodeNum[Pos]; } else Dec->QuickNum[Code]=0; } } unrar/unpack15.cpp0100666000000000000000000002462612176732144011446 0ustar z#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) { UnpInitData(Solid); UnpInitData15(Solid); UnpReadBuf(); if (!Solid) { InitHuff(); UnpPtr=0; } else UnpPtr=WrPtr; --DestUnpSize; if (DestUnpSize>=0) { GetFlagsBuf(); FlagsCnt=8; } while (DestUnpSize>=0) { UnpPtr&=MaxWinMask; if (Inp.InAddr>ReadTop-30 && !UnpReadBuf()) break; if (((WrPtr-UnpPtr) & MaxWinMask)<270 && WrPtr!=UnpPtr) UnpWriteBuf20(); 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(); } } } UnpWriteBuf20(); } #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=Inp.fgetbits(); if (LCount==2) { Inp.faddbits(1); if (BitField >= 0x8000) { CopyString15((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; Inp.faddbits(GetShortLen1(Length)); } else { for (Length=0;;Length++) if (((BitField^ShortXor2[Length]) & (~(0xff>>GetShortLen2(Length))))==0) break; Inp.faddbits(GetShortLen2(Length)); } if (Length >= 9) { if (Length == 9) { LCount++; CopyString15((unsigned int)LastDist,LastLength); return; } if (Length == 14) { LCount=0; Length=DecodeNum(Inp.fgetbits(),STARTL2,DecL2,PosL2)+5; Distance=(Inp.fgetbits()>>1) | 0x8000; Inp.faddbits(15); LastLength=Length; LastDist=Distance; CopyString15(Distance,Length); return; } LCount=0; SaveLength=Length; Distance=OldDist[(OldDistPtr-(Length-9)) & 3]; Length=DecodeNum(Inp.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; CopyString15(Distance,Length); return; } LCount=0; AvrLn1 += Length; AvrLn1 -= AvrLn1 >> 4; DistancePlace=DecodeNum(Inp.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; CopyString15(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=Inp.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; Inp.faddbits(16); } else { for (Length=0;((BitField<> 5; BitField=Inp.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) | (Inp.fgetbits() >> 8)) >> 1; Inp.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; CopyString15(Distance,Length); } void Unpack::HuffDecode() { unsigned int CurByte,NewBytePlace; unsigned int Length; unsigned int Distance; int BytePlace; unsigned int BitField=Inp.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=Inp.fgetbits(); Inp.faddbits(1); if (BitField & 0x8000) { NumHuf=StMode=0; return; } else { Length = (BitField & 0x4000) ? 4 : 3; Inp.faddbits(1); Distance=DecodeNum(Inp.fgetbits(),STARTHF2,DecHf2,PosHf2); Distance = (Distance << 5) | (Inp.fgetbits() >> 11); Inp.faddbits(5); CopyString15(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(Inp.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::UnpInitData15(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::CopyString15(uint Distance,uint 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++; Inp.faddbits(StartPos); return(((Num-(I ? DecTab[I-1]:0))>>(16-StartPos))+PosTab[StartPos]); } unrar/unpack20.cpp0100666000000000000000000002010612176732144011427 0ustar z#include "rar.hpp" void Unpack::CopyString20(uint Length,uint Distance) { LastDist=OldDist[OldDistPtr++ & 3]=Distance; LastLength=Length; DestUnpSize-=Length; CopyString(Length,Distance); } 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 (Inp.InAddr>ReadTop-30) if (!UnpReadBuf()) break; if (((WrPtr-UnpPtr) & MaxWinMask)<270 && WrPtr!=UnpPtr) { UnpWriteBuf20(); if (Suspended) return; } if (UnpAudioBlock) { int AudioNumber=DecodeNumber(Inp,&MD[UnpCurChannel]); if (AudioNumber==256) { if (!ReadTables20()) break; continue; } Window[UnpPtr++]=DecodeAudio(AudioNumber); if (++UnpCurChannel==UnpChannels) UnpCurChannel=0; --DestUnpSize; continue; } int Number=DecodeNumber(Inp,&BlockTables.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+=Inp.getbits()>>(16-Bits); Inp.addbits(Bits); } int DistNumber=DecodeNumber(Inp,&BlockTables.DD); unsigned int Distance=DDecode[DistNumber]+1; if ((Bits=DBits[DistNumber])>0) { Distance+=Inp.getbits()>>(16-Bits); Inp.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(Inp,&BlockTables.RD); int Length=LDecode[LengthNumber]+2; if ((Bits=LBits[LengthNumber])>0) { Length+=Inp.getbits()>>(16-Bits); Inp.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+=Inp.getbits()>>(16-Bits); Inp.addbits(Bits); } CopyString20(2,Distance); continue; } } ReadLastTables(); UnpWriteBuf20(); } void Unpack::UnpWriteBuf20() { if (UnpPtr!=WrPtr) UnpSomeRead=true; if (UnpPtrUnpWrite(&Window[WrPtr],-(int)WrPtr & MaxWinMask); UnpIO->UnpWrite(Window,UnpPtr); UnpAllBuf=true; } else UnpIO->UnpWrite(&Window[WrPtr],UnpPtr-WrPtr); WrPtr=UnpPtr; } bool Unpack::ReadTables20() { byte BitLength[BC20]; byte Table[MC20*4]; int TableSize,N,I; if (Inp.InAddr>ReadTop-25) if (!UnpReadBuf()) return(false); uint BitField=Inp.getbits(); UnpAudioBlock=(BitField & 0x8000); if (!(BitField & 0x4000)) memset(UnpOldTable20,0,sizeof(UnpOldTable20)); Inp.addbits(2); if (UnpAudioBlock) { UnpChannels=((BitField>>12) & 3)+1; if (UnpCurChannel>=UnpChannels) UnpCurChannel=0; Inp.addbits(2); TableSize=MC20*UnpChannels; } else TableSize=NC20+DC20+RC20; for (I=0;I> 12); Inp.addbits(4); } MakeDecodeTables(BitLength,&BlockTables.BD,BC20); I=0; while (IReadTop-5) if (!UnpReadBuf()) return false; int Number=DecodeNumber(Inp,&BlockTables.BD); if (Number<16) { Table[I]=(Number+UnpOldTable20[I]) & 0xf; I++; } else if (Number==16) { N=(Inp.getbits() >> 14)+3; Inp.addbits(2); if (I>0) while (N-- > 0 && I> 13)+3; Inp.addbits(3); } else { N=(Inp.getbits() >> 9)+11; Inp.addbits(7); } while (N-- > 0 && IReadTop) return(true); if (UnpAudioBlock) for (I=0;I=Inp.InAddr+5) if (UnpAudioBlock) { if (DecodeNumber(Inp,&MD[UnpCurChannel])==256) ReadTables20(); } else if (DecodeNumber(Inp,&BlockTables.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;IDif)/sizeof(V->Dif[0]);I++) { if (V->Dif[I]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); } unrar/unpack30.cpp0100666000000000000000000005477312176732144011451 0ustar z// 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;IReadBorder) { if (!UnpReadBuf30()) break; } if (((WrPtr-UnpPtr) & MaxWinMask)<260 && WrPtr!=UnpPtr) { UnpWriteBuf30(); if (WrittenFileSize>DestUnpSize) return; if (Suspended) { FileExtracted=false; return; } } if (UnpBlockType==BLOCK_PPM) { // Here speed is critical, so we do not use SafePPMDecodeChar, // because sometimes even the inline function can introduce // some additional penalty. int Ch=PPM.DecodeChar(); if (Ch==-1) // Corrupt PPM data found. { PPM.CleanUp(); // Reset possibly corrupt PPM data structures. UnpBlockType=BLOCK_LZ; // Set faster and more fail proof LZ mode. break; } if (Ch==PPMEscChar) { int NextCh=SafePPMDecodeChar(); if (NextCh==0) // End of PPM encoding. { if (!ReadTables30()) break; continue; } if (NextCh==-1) // Corrupt PPM data found. break; if (NextCh==2) // End of file in PPM mode. break; if (NextCh==3) // Read VM code. { if (!ReadVMCodePPM()) break; continue; } if (NextCh==4) // LZ inside of PPM. { unsigned int Distance=0,Length; bool Failed=false; for (int I=0;I<4 && !Failed;I++) { int Ch=SafePPMDecodeChar(); if (Ch==-1) Failed=true; else if (I==3) Length=(byte)Ch; else Distance=(Distance<<8)+(byte)Ch; } if (Failed) break; CopyString(Length+32,Distance+2); continue; } if (NextCh==5) // One byte distance match (RLE) inside of PPM. { int Length=SafePPMDecodeChar(); if (Length==-1) break; CopyString(Length+4,1); continue; } // If we are here, NextCh must be 1, what means that current byte // is equal to our 'escape' byte, so we just store it to Window. } Window[UnpPtr++]=Ch; continue; } int Number=DecodeNumber(Inp,&BlockTables.LD); if (Number<256) { Window[UnpPtr++]=(byte)Number; continue; } if (Number>=271) { int Length=LDecode[Number-=271]+3; if ((Bits=LBits[Number])>0) { Length+=Inp.getbits()>>(16-Bits); Inp.addbits(Bits); } int DistNumber=DecodeNumber(Inp,&BlockTables.DD); unsigned int Distance=DDecode[DistNumber]+1; if ((Bits=DBits[DistNumber])>0) { if (DistNumber>9) { if (Bits>4) { Distance+=((Inp.getbits()>>(20-Bits))<<4); Inp.addbits(Bits-4); } if (LowDistRepCount>0) { LowDistRepCount--; Distance+=PrevLowDist; } else { int LowDist=DecodeNumber(Inp,&BlockTables.LDD); if (LowDist==16) { LowDistRepCount=LOW_DIST_REP_COUNT-1; Distance+=PrevLowDist; } else { Distance+=LowDist; PrevLowDist=LowDist; } } } else { Distance+=Inp.getbits()>>(16-Bits); Inp.addbits(Bits); } } if (Distance>=0x2000) { Length++; if (Distance>=0x40000L) Length++; } InsertOldDist(Distance); LastLength=Length; CopyString(Length,Distance); continue; } if (Number==256) { if (!ReadEndOfBlock()) break; continue; } if (Number==257) { if (!ReadVMCode()) break; continue; } if (Number==258) { if (LastLength!=0) CopyString(LastLength,OldDist[0]); continue; } if (Number<263) { int DistNum=Number-259; unsigned int Distance=OldDist[DistNum]; for (int I=DistNum;I>0;I--) OldDist[I]=OldDist[I-1]; OldDist[0]=Distance; int LengthNumber=DecodeNumber(Inp,&BlockTables.RD); int Length=LDecode[LengthNumber]+2; if ((Bits=LBits[LengthNumber])>0) { Length+=Inp.getbits()>>(16-Bits); Inp.addbits(Bits); } LastLength=Length; CopyString(Length,Distance); continue; } if (Number<272) { unsigned int Distance=SDDecode[Number-=263]+1; if ((Bits=SDBits[Number])>0) { Distance+=Inp.getbits()>>(16-Bits); Inp.addbits(Bits); } InsertOldDist(Distance); LastLength=2; CopyString(2,Distance); continue; } } UnpWriteBuf30(); } // Return 'false' to quit unpacking the current file or 'true' to continue. bool Unpack::ReadEndOfBlock() { uint BitField=Inp.getbits(); bool NewTable,NewFile=false; // "1" - no new file, new table just here. // "00" - new file, no new table. // "01" - new file, new table (in beginning of next file). if ((BitField & 0x8000)!=0) { NewTable=true; Inp.addbits(1); } else { NewFile=true; NewTable=(BitField & 0x4000)!=0; Inp.addbits(2); } TablesRead=!NewTable; // Quit immediately if "new file" flag is set. If "new table" flag // is present, we'll read the table in beginning of next file // based on 'TablesRead' 'false' value. if (NewFile) return false; return ReadTables30(); // Quit only if we failed to read tables. } bool Unpack::ReadVMCode() { // Entire VM code is guaranteed to fully present in block defined // by current Huffman table. Compressor checks that VM code does not cross // Huffman block boundaries. unsigned int FirstByte=Inp.getbits()>>8; Inp.addbits(8); int Length=(FirstByte & 7)+1; if (Length==7) { Length=(Inp.getbits()>>8)+7; Inp.addbits(8); } else if (Length==8) { Length=Inp.getbits(); Inp.addbits(16); } Array VMCode(Length); for (int I=0;I=ReadTop-1 && !UnpReadBuf30() && I>8; Inp.addbits(8); } return(AddVMCode(FirstByte,&VMCode[0],Length)); } bool Unpack::ReadVMCodePPM() { unsigned int FirstByte=SafePPMDecodeChar(); if ((int)FirstByte==-1) return(false); int Length=(FirstByte & 7)+1; if (Length==7) { int B1=SafePPMDecodeChar(); if (B1==-1) return(false); Length=B1+7; } else if (Length==8) { int B1=SafePPMDecodeChar(); if (B1==-1) return(false); int B2=SafePPMDecodeChar(); if (B2==-1) return(false); Length=B1*256+B2; } Array VMCode(Length); for (int I=0;IFilters30.Size() || FiltPos>OldFilterLengths.Size()) return(false); LastFilter=FiltPos; bool NewFilter=(FiltPos==Filters30.Size()); UnpackFilter30 *StackFilter=new UnpackFilter30; // New filter for PrgStack. UnpackFilter30 *Filter; if (NewFilter) // New filter code, never used before since VM reset. { if (FiltPos>MAX3_FILTERS) { // Too many different filters, corrupt archive. delete StackFilter; return false; } Filters30.Add(1); Filters30[Filters30.Size()-1]=Filter=new UnpackFilter30; StackFilter->ParentFilter=(uint)(Filters30.Size()-1); // Reserve one item, where we store the data block length of our new // filter entry. We'll set it to real block length below, after reading // it. But we need to initialize it now, because when processing corrupt // data, we can access this item even before we set it to real value. OldFilterLengths.Push(0); Filter->ExecCount=0; } else // Filter was used in the past. { Filter=Filters30[FiltPos]; StackFilter->ParentFilter=FiltPos; Filter->ExecCount++; } int EmptyCount=0; for (uint I=0;I0) PrgStack[I]=NULL; } if (EmptyCount==0) { PrgStack.Add(1); EmptyCount=1; } int StackPos=(int)(PrgStack.Size()-EmptyCount); PrgStack[StackPos]=StackFilter; StackFilter->ExecCount=Filter->ExecCount; uint BlockStart=RarVM::ReadData(VMCodeInp); if (FirstByte & 0x40) BlockStart+=258; StackFilter->BlockStart=(uint)((BlockStart+UnpPtr)&MaxWinMask); if (FirstByte & 0x20) { StackFilter->BlockLength=RarVM::ReadData(VMCodeInp); // Store the last data block length for current filter. OldFilterLengths[FiltPos]=StackFilter->BlockLength; } else { // Set the data block size to same value as the previous block size // for same filter. It is possible on corrupt data to access here a new // and not filled yet item of OldFilterLengths array. This is why above // we set new OldFilterLengths items to zero. StackFilter->BlockLength=FiltPosNextWindow=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<Prg.InitR[I]=RarVM::ReadData(VMCodeInp); } if (NewFilter) { uint VMCodeSize=RarVM::ReadData(VMCodeInp); if (VMCodeSize>=0x10000 || VMCodeSize==0) return(false); Array VMCode(VMCodeSize); for (uint I=0;I>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 && StaticDataSizePrg.StaticData.Add(StaticDataSize); memcpy(&StackFilter->Prg.StaticData[0],&Filter->Prg.StaticData[0],StaticDataSize); } if (StackFilter->Prg.GlobalData.Size()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 (CurSizePrg.GlobalData.Add(DataSize+VM_FIXEDGLOBALSIZE-CurSize); byte *GlobalData=&StackFilter->Prg.GlobalData[VM_FIXEDGLOBALSIZE]; for (uint I=0;I>8; VMCodeInp.faddbits(8); } } return(true); } bool Unpack::UnpReadBuf30() { int DataSize=ReadTop-Inp.InAddr; // Data left to process. if (DataSize<0) return(false); if (Inp.InAddr>BitInput::MAX_SIZE/2) { // If we already processed more than half of buffer, let's move // remaining data into beginning to free more space for new data // and ensure that calling function does not cross the buffer border // even if we did not read anything here. Also it ensures that read size // is not less than CRYPT_BLOCK_SIZE, so we can align it without risk // to make it zero. if (DataSize>0) memmove(Inp.InBuf,Inp.InBuf+Inp.InAddr,DataSize); Inp.InAddr=0; ReadTop=DataSize; } else DataSize=ReadTop; int ReadCode=UnpIO->UnpRead(Inp.InBuf+DataSize,BitInput::MAX_SIZE-DataSize); if (ReadCode>0) ReadTop+=ReadCode; ReadBorder=ReadTop-30; return(ReadCode!=-1); } void Unpack::UnpWriteBuf30() { uint WrittenBorder=(uint)WrPtr; uint WriteSize=(uint)((UnpPtr-WrittenBorder)&MaxWinMask); for (size_t I=0;INextWindow) { flt->NextWindow=false; continue; } unsigned int BlockStart=flt->BlockStart; unsigned int BlockLength=flt->BlockLength; if (((BlockStart-WrittenBorder)&MaxWinMask)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()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+1BlockStart!=BlockStart || NextFilter->BlockLength!=FilteredDataSize || NextFilter->NextWindow) break; // Apply several filters to same data block. VM.SetMemory(0,FilteredData,FilteredDataSize); VM_PreparedProgram *ParentPrg=&Filters30[NextFilter->ParentFilter]->Prg; VM_PreparedProgram *NextPrg=&NextFilter->Prg; if (ParentPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE) { // Copy global data from previous script execution if any. NextPrg->GlobalData.Alloc(ParentPrg->GlobalData.Size()); memcpy(&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],ParentPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); } ExecuteCode(NextPrg); if (NextPrg->GlobalData.Size()>VM_FIXEDGLOBALSIZE) { // Save global data for next script execution. if (ParentPrg->GlobalData.Size()GlobalData.Size()) ParentPrg->GlobalData.Alloc(NextPrg->GlobalData.Size()); memcpy(&ParentPrg->GlobalData[VM_FIXEDGLOBALSIZE],&NextPrg->GlobalData[VM_FIXEDGLOBALSIZE],NextPrg->GlobalData.Size()-VM_FIXEDGLOBALSIZE); } else ParentPrg->GlobalData.Reset(); FilteredData=NextPrg->FilteredData; FilteredDataSize=NextPrg->FilteredDataSize; I++; delete PrgStack[I]; PrgStack[I]=NULL; } UnpIO->UnpWrite(FilteredData,FilteredDataSize); UnpSomeRead=true; WrittenFileSize+=FilteredDataSize; WrittenBorder=BlockEnd; WriteSize=uint((UnpPtr-WrittenBorder)&MaxWinMask); } else { // Current filter intersects the window write border, so we adjust // the window border to process this filter next time, not now. for (size_t J=I;JNextWindow) flt->NextWindow=false; } WrPtr=WrittenBorder; return; } } } UnpWriteArea(WrittenBorder,UnpPtr); WrPtr=UnpPtr; } void Unpack::ExecuteCode(VM_PreparedProgram *Prg) { if (Prg->GlobalData.Size()>0) { Prg->InitR[6]=(uint)WrittenFileSize; VM.SetLowEndianValue((uint *)&Prg->GlobalData[0x24],(uint)WrittenFileSize); VM.SetLowEndianValue((uint *)&Prg->GlobalData[0x28],(uint)(WrittenFileSize>>32)); VM.Execute(Prg); } } bool Unpack::ReadTables30() { byte BitLength[BC]; byte Table[HUFF_TABLE_SIZE30]; if (Inp.InAddr>ReadTop-25) if (!UnpReadBuf30()) return(false); Inp.faddbits((8-Inp.InBit)&7); uint BitField=Inp.fgetbits(); if (BitField & 0x8000) { UnpBlockType=BLOCK_PPM; return(PPM.DecodeInit(this,PPMEscChar)); } UnpBlockType=BLOCK_LZ; PrevLowDist=0; LowDistRepCount=0; if (!(BitField & 0x4000)) memset(UnpOldTable,0,sizeof(UnpOldTable)); Inp.faddbits(2); for (int I=0;I> 12); Inp.faddbits(4); if (Length==15) { int ZeroCount=(byte)(Inp.fgetbits() >> 12); Inp.faddbits(4); if (ZeroCount==0) BitLength[I]=15; else { ZeroCount+=2; while (ZeroCount-- > 0 && IReadTop-5) if (!UnpReadBuf30()) return(false); int Number=DecodeNumber(Inp,&BlockTables.BD); if (Number<16) { Table[I]=(Number+UnpOldTable[I]) & 0xf; I++; } else if (Number<18) { int N; if (Number==16) { N=(Inp.fgetbits() >> 13)+3; Inp.faddbits(3); } else { N=(Inp.fgetbits() >> 9)+11; Inp.faddbits(7); } if (I>0) while (N-- > 0 && I> 13)+3; Inp.faddbits(3); } else { N=(Inp.fgetbits() >> 9)+11; Inp.faddbits(7); } while (N-- > 0 && IReadTop) return(false); MakeDecodeTables(&Table[0],&BlockTables.LD,NC30); MakeDecodeTables(&Table[NC30],&BlockTables.DD,DC30); MakeDecodeTables(&Table[NC30+DC30],&BlockTables.LDD,LDC30); MakeDecodeTables(&Table[NC30+DC30+LDC30],&BlockTables.RD,RC30); memcpy(UnpOldTable,Table,sizeof(UnpOldTable)); return(true); } void Unpack::UnpInitData30(bool Solid) { if (!Solid) { TablesRead=false; memset(UnpOldTable,0,sizeof(UnpOldTable)); PPMEscChar=2; UnpBlockType=BLOCK_LZ; InitFilters30(); } } void Unpack::InitFilters30() { OldFilterLengths.Reset(); LastFilter=0; for (size_t I=0;I=ReadBorder) { bool FileDone=false; // We use 'while', because for empty block containing only Huffman table, // we'll be on the block border once again just after reading the table. while (Inp.InAddr>BlockHeader.BlockStart+BlockHeader.BlockSize-1 || Inp.InAddr==BlockHeader.BlockStart+BlockHeader.BlockSize-1 && Inp.InBit>=BlockHeader.BlockBitSize) { if (BlockHeader.LastBlockInFile) { FileDone=true; break; } if (!ReadBlockHeader(Inp,BlockHeader) || !ReadTables(Inp,BlockHeader,BlockTables)) return; } if (FileDone || !UnpReadBuf()) break; } if (((WriteBorder-UnpPtr) & MaxWinMask)DestUnpSize) return; if (Suspended) { FileExtracted=false; return; } } uint MainSlot=DecodeNumber(Inp,&BlockTables.LD); if (MainSlot<256) { if (Fragmented) FragWindow[UnpPtr++]=(byte)MainSlot; else Window[UnpPtr++]=(byte)MainSlot; continue; } if (MainSlot>=262) { uint Length=SlotToLength(Inp,MainSlot-262); uint DBits,Distance=1,DistSlot=DecodeNumber(Inp,&BlockTables.DD); if (DistSlot<4) { DBits=0; Distance+=DistSlot; } else { DBits=DistSlot/2 - 1; Distance+=(2 | (DistSlot & 1)) << DBits; } if (DBits>0) { if (DBits>=4) { if (DBits>4) { Distance+=((Inp.getbits32()>>(36-DBits))<<4); Inp.addbits(DBits-4); } uint LowDist=DecodeNumber(Inp,&BlockTables.LDD); Distance+=LowDist; } else { Distance+=Inp.getbits32()>>(32-DBits); Inp.addbits(DBits); } } if (Distance>0x100) { Length++; if (Distance>0x2000) { Length++; if (Distance>0x40000) Length++; } } InsertOldDist(Distance); LastLength=Length; if (Fragmented) FragWindow.CopyString(Length,Distance,UnpPtr,MaxWinMask); else CopyString(Length,Distance); continue; } if (MainSlot==256) { UnpackFilter Filter; if (!ReadFilter(Inp,Filter) || !AddFilter(Filter)) break; continue; } if (MainSlot==257) { if (LastLength!=0) if (Fragmented) FragWindow.CopyString(LastLength,OldDist[0],UnpPtr,MaxWinMask); else CopyString(LastLength,OldDist[0]); continue; } if (MainSlot<262) { uint DistNum=MainSlot-258; uint Distance=OldDist[DistNum]; for (uint I=DistNum;I>0;I--) OldDist[I]=OldDist[I-1]; OldDist[0]=Distance; uint LengthSlot=DecodeNumber(Inp,&BlockTables.RD); uint Length=SlotToLength(Inp,LengthSlot); LastLength=Length; if (Fragmented) FragWindow.CopyString(Length,Distance,UnpPtr,MaxWinMask); else CopyString(Length,Distance); continue; } } UnpWriteBuf(); } uint Unpack::ReadFilterData(BitInput &Inp) { uint ByteCount=(Inp.fgetbits()>>14)+1; Inp.addbits(2); uint Data=0; for (uint I=0;I>8)<<(I*8); Inp.addbits(8); } return Data; } bool Unpack::ReadFilter(BitInput &Inp,UnpackFilter &Filter) { if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-16) if (!UnpReadBuf()) return false; Filter.BlockStart=ReadFilterData(Inp); Filter.BlockLength=ReadFilterData(Inp); Filter.Type=Inp.fgetbits()>>13; Inp.faddbits(3); if (Filter.Type==FILTER_DELTA || Filter.Type==FILTER_AUDIO) { Filter.Channels=(Inp.fgetbits()>>11)+1; Inp.faddbits(5); } if (Filter.Type==FILTER_RGB) { Filter.Channels=3; Filter.Width=Inp.fgetbits()+1; Inp.faddbits(16); Filter.PosR=Inp.fgetbits()>>14; Inp.faddbits(2); } return true; } bool Unpack::AddFilter(UnpackFilter &Filter) { if (Filters.Size()>=MAX_UNPACK_FILTERS-1) UnpWriteBuf(); // Write data, apply and flush filters. // If distance to filter start is that large that due to circular dictionary // mode it points to old not written yet data, then we set 'NextWindow' // flag and process this filter only after processing that older data. Filter.NextWindow=WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MaxWinMask)<=Filter.BlockStart; Filter.BlockStart=uint((Filter.BlockStart+UnpPtr)&MaxWinMask); Filters.Push(Filter); return true; } bool Unpack::UnpReadBuf() { int DataSize=ReadTop-Inp.InAddr; // Data left to process. if (DataSize<0) return false; BlockHeader.BlockSize-=Inp.InAddr-BlockHeader.BlockStart; if (Inp.InAddr>BitInput::MAX_SIZE/2) { // If we already processed more than half of buffer, let's move // remaining data into beginning to free more space for new data // and ensure that calling function does not cross the buffer border // even if we did not read anything here. Also it ensures that read size // is not less than CRYPT_BLOCK_SIZE, so we can align it without risk // to make it zero. if (DataSize>0) memmove(Inp.InBuf,Inp.InBuf+Inp.InAddr,DataSize); Inp.InAddr=0; ReadTop=DataSize; } else DataSize=ReadTop; int ReadCode=UnpIO->UnpRead(Inp.InBuf+DataSize,BitInput::MAX_SIZE-DataSize); if (ReadCode>0) ReadTop+=ReadCode; ReadBorder=ReadTop-30; BlockHeader.BlockStart=Inp.InAddr; if (BlockHeader.BlockSize!=-1) // '-1' means not defined yet. ReadBorder=Min(ReadBorder,BlockHeader.BlockStart+BlockHeader.BlockSize-1); return ReadCode!=-1; } void Unpack::UnpWriteBuf() { size_t WrittenBorder=WrPtr; size_t FullWriteSize=(UnpPtr-WrittenBorder)&MaxWinMask; size_t WriteSizeLeft=FullWriteSize; bool NotAllFiltersProcessed=false; for (size_t I=0;IType==FILTER_NONE) continue; if (flt->NextWindow) { // Here we skip filters which have block start in current data range // due to address warp around in circular dictionary, but actually // belong to next dictionary block. If such filter start position // is included to current write range, then we reset 'NextWindow' flag. // In fact we can reset it even without such check, because current // implementation seems to guarantee 'NextWindow' flag reset after // buffer writing for all existing filters. But let's keep this check // just in case. Compressor guarantees that distance between // filter block start and filter storing position cannot exceed // the dictionary size. So if we covered the filter block start with // our write here, we can safely assume that filter is applicable // to next block on no further wrap arounds is possible. if (((flt->BlockStart-WrPtr)&MaxWinMask)<=FullWriteSize) flt->NextWindow=false; continue; } uint BlockStart=flt->BlockStart; uint BlockLength=flt->BlockLength; if (((BlockStart-WrittenBorder)&MaxWinMask)0) { uint BlockEnd=(BlockStart+BlockLength)&MaxWinMask; FilterSrcMemory.Alloc(BlockLength); byte *Mem=&FilterSrcMemory[0]; if (BlockStartUnpWrite(OutMem,BlockLength); UnpSomeRead=true; WrittenFileSize+=BlockLength; WrittenBorder=BlockEnd; WriteSizeLeft=(UnpPtr-WrittenBorder)&MaxWinMask; } } else { // Current filter intersects the window write border, so we adjust // the window border to process this filter next time, not now. WrPtr=WrittenBorder; // Since Filter start position can only increase, we quit processing // all following filters for this data block and reset 'NextWindow' // flag for them. for (size_t J=I;JType!=FILTER_NONE) flt->NextWindow=false; } // Do not write data left after current filter now. NotAllFiltersProcessed=true; break; } } } // Remove processed filters from queue. size_t EmptyCount=0; for (size_t I=0;I0) Filters[I-EmptyCount]=Filters[I]; if (Filters[I].Type==FILTER_NONE) EmptyCount++; } if (EmptyCount>0) Filters.Alloc(Filters.Size()-EmptyCount); if (!NotAllFiltersProcessed) // Only if all filters are processed. { // Write data left after last filter. UnpWriteArea(WrittenBorder,UnpPtr); WrPtr=UnpPtr; } // We prefer to write data in blocks not exceeding UNPACK_MAX_WRITE // instead of potentially huge MaxWinSize blocks. WriteBorder=(UnpPtr+Min(MaxWinSize,UNPACK_MAX_WRITE))&MaxWinMask; // Choose the nearest among WriteBorder and WrPtr actual written border. // If border is equal to UnpPtr, it means that we have MaxWinSize data ahead. if (WriteBorder==UnpPtr || WrPtr!=UnpPtr && ((WrPtr-UnpPtr)&MaxWinMask)<((WriteBorder-UnpPtr)&MaxWinMask)) WriteBorder=WrPtr; } uint Unpack::FilterItanium_GetBits(byte *Data,int BitPos,int BitCount) { int InAddr=BitPos/8; int InBit=BitPos&7; uint BitField=(uint)Data[InAddr++]; BitField|=(uint)Data[InAddr++] << 8; BitField|=(uint)Data[InAddr++] << 16; BitField|=(uint)Data[InAddr] << 24; BitField >>= InBit; return(BitField & (0xffffffff>>(32-BitCount))); } void Unpack::FilterItanium_SetBits(byte *Data,uint BitField,int BitPos,int BitCount) { int InAddr=BitPos/8; int InBit=BitPos&7; uint AndMask=0xffffffff>>(32-BitCount); AndMask=~(AndMask<>8)|0xff000000; BitField>>=8; } } inline uint GetFiltData32(byte *Data) { #if defined(BIG_ENDIAN) || !defined(ALLOW_NOT_ALIGNED_INT) || !defined(PRESENT_INT32) uint Value=GET_UINT32((uint)Data[0]|((uint)Data[1]<<8)|((uint)Data[2]<<16)|((uint)Data[3]<<24)); #else uint Value=GET_UINT32(*(uint32 *)Data); #endif return Value; } inline void SetFiltData32(byte *Data,uint Value) { #if defined(BIG_ENDIAN) || !defined(ALLOW_NOT_ALIGNED_INT) || !defined(PRESENT_INT32) Data[0]=(byte)Value; Data[1]=(byte)(Value>>8); Data[2]=(byte)(Value>>16); Data[3]=(byte)(Value>>24); #else *(int32 *)Data=Value; #endif } byte* Unpack::ApplyFilter(byte *Data,uint DataSize,UnpackFilter *Flt) { byte *SrcData=Data; switch(Flt->Type) { case FILTER_E8: case FILTER_E8E9: { uint FileOffset=(uint)WrittenFileSize; const int FileSize=0x1000000; byte CmpByte2=Flt->Type==FILTER_E8E9 ? 0xe9:0xe8; for (uint CurPos=0;(int)CurPos<(int)DataSize-4;) { byte CurByte=*(Data++); CurPos++; if (CurByte==0xe8 || CurByte==CmpByte2) { uint Offset=(CurPos+FileOffset)%FileSize; uint Addr=GetFiltData32(Data); // We check 0x80000000 bit instead of '< 0' comparison // not assuming int32 presence or uint size and endianness. if ((Addr & 0x80000000)!=0) // Addr<0 { if (((Addr+Offset) & 0x80000000)==0) // Addr+Offset>=0 SetFiltData32(Data,Addr+FileSize); } else if (((Addr-FileSize) & 0x80000000)!=0) // Addr>8); D[2]=(byte)(Offset>>16); } } } return SrcData; case FILTER_ITANIUM: { uint FileOffset=(uint)WrittenFileSize; uint CurPos=0; FileOffset>>=4; while ((int)CurPos<(int)DataSize-21) { int Byte=(Data[0]&0x1f)-0x10; if (Byte>=0) { static byte Masks[16]={4,4,6,6,0,0,7,7,4,4,0,0,4,4,0,0}; byte CmdMask=Masks[Byte]; if (CmdMask!=0) for (int I=0;I<=2;I++) if (CmdMask & (1<Channels; byte *SrcData=Data; FilterDstMemory.Alloc(DataSize); byte *DstData=&FilterDstMemory[0]; for (uint CurChannel=0;CurChannel>3) & 0xff; uint CurByte=*(SrcData++); Predicted-=CurByte; DstData[I]=Predicted; PrevDelta=(signed char)(Predicted-PrevByte); PrevByte=Predicted; int D=((signed char)CurByte)<<3; Dif[0]+=abs(D); Dif[1]+=abs(D-D1); Dif[2]+=abs(D+D1); Dif[3]+=abs(D-D2); Dif[4]+=abs(D+D2); Dif[5]+=abs(D-D3); Dif[6]+=abs(D+D3); if ((ByteCount & 0x1f)==0) { uint MinDif=Dif[0],NumMinDif=0; Dif[0]=0; for (uint J=1;J=-16) K1--; break; case 2: if (K1 < 16) K1++; break; case 3: if (K2>=-16) K2--; break; case 4: if (K2 < 16) K2++; break; case 5: if (K3>=-16) K3--; break; case 6: if (K3 < 16) K3++; break; } } } } return DstData; } case FILTER_DELTA: { uint Channels=Flt->Channels,SrcPos=0; FilterDstMemory.Alloc(DataSize); byte *DstData=&FilterDstMemory[0]; // Bytes from same channels are grouped to continual data blocks, // so we need to place them back to their interleaving positions. for (uint CurChannel=0;CurChannelWidth,PosR=Flt->PosR; byte *SrcData=Data; FilterDstMemory.Alloc(DataSize); byte *DstData=&FilterDstMemory[0]; const int Channels=3; for (uint CurChannel=0;CurChannel=3) { byte *UpperData=DstData+UpperPos; uint UpperByte=*UpperData; uint UpperLeftByte=*(UpperData-3); Predicted=PrevByte+UpperByte-UpperLeftByte; int pa=abs((int)(Predicted-PrevByte)); int pb=abs((int)(Predicted-UpperByte)); int pc=abs((int)(Predicted-UpperLeftByte)); if (pa<=pb && pa<=pc) Predicted=PrevByte; else if (pb<=pc) Predicted=UpperByte; else Predicted=UpperLeftByte; } else Predicted=PrevByte; DstData[I]=PrevByte=(byte)(Predicted-*(SrcData++)); } } for (uint I=PosR,Border=DataSize-2;I0) { size_t BlockSize=FragWindow.GetBlockSize(StartPtr,SizeToWrite); UnpWriteData(&FragWindow[StartPtr],BlockSize); SizeToWrite-=BlockSize; StartPtr=(StartPtr+BlockSize) & MaxWinMask; } } else if (EndPtr=DestUnpSize) return; size_t WriteSize=Size; int64 LeftToWrite=DestUnpSize-WrittenFileSize; if ((int64)WriteSize>LeftToWrite) WriteSize=(size_t)LeftToWrite; UnpIO->UnpWrite(Data,WriteSize); WrittenFileSize+=Size; } bool Unpack::ReadBlockHeader(BitInput &Inp,UnpackBlockHeader &Header) { Header.HeaderSize=0; if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-7) if (!UnpReadBuf()) return false; Inp.faddbits((8-Inp.InBit)&7); byte BlockFlags=Inp.fgetbits()>>8; Inp.faddbits(8); uint ByteCount=((BlockFlags>>3)&3)+1; // Block size byte count. if (ByteCount==4) return false; Header.HeaderSize=2+ByteCount; Header.BlockBitSize=(BlockFlags&7)+1; byte SavedCheckSum=Inp.fgetbits()>>8; Inp.faddbits(8); int BlockSize=0; for (uint I=0;I>8)<<(I*8); Inp.addbits(8); } Header.BlockSize=BlockSize; byte CheckSum=byte(0x5a^BlockFlags^BlockSize^(BlockSize>>8)^(BlockSize>>16)); if (CheckSum!=SavedCheckSum) return false; Header.BlockStart=Inp.InAddr; ReadBorder=Min(ReadBorder,Header.BlockStart+Header.BlockSize-1); Header.LastBlockInFile=(BlockFlags & 0x40)!=0; Header.TablePresent=(BlockFlags & 0x80)!=0; return true; } bool Unpack::ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTables &Tables) { if (!Header.TablePresent) return true; if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-25) if (!UnpReadBuf()) return false; byte BitLength[BC]; for (int I=0;I> 12); Inp.faddbits(4); if (Length==15) { int ZeroCount=(byte)(Inp.fgetbits() >> 12); Inp.faddbits(4); if (ZeroCount==0) BitLength[I]=15; else { ZeroCount+=2; while (ZeroCount-- > 0 && IReadTop-5) if (!UnpReadBuf()) return(false); int Number=DecodeNumber(Inp,&Tables.BD); if (Number<16) { Table[I]=Number; I++; } else if (Number<18) { int N; if (Number==16) { N=(Inp.fgetbits() >> 13)+3; Inp.faddbits(3); } else { N=(Inp.fgetbits() >> 9)+11; Inp.faddbits(7); } if (I>0) while (N-- > 0 && I> 13)+3; Inp.faddbits(3); } else { N=(Inp.fgetbits() >> 9)+11; Inp.faddbits(7); } while (N-- > 0 && IReadTop) return(false); MakeDecodeTables(&Table[0],&Tables.LD,NC); MakeDecodeTables(&Table[NC],&Tables.DD,DC); MakeDecodeTables(&Table[NC+DC],&Tables.LDD,LDC); MakeDecodeTables(&Table[NC+DC+LDC],&Tables.RD,RC); return(true); } void Unpack::InitFilters() { Filters.Reset(); } unrar/unpack50frag.cpp0100666000000000000000000000447712176732144012307 0ustar zFragmentedWindow::FragmentedWindow() { memset(Mem,0,sizeof(Mem)); memset(MemSize,0,sizeof(MemSize)); } FragmentedWindow::~FragmentedWindow() { for (uint I=0;I=MinSize) { NewMem=(byte *)malloc(Size); if (NewMem!=NULL) break; Size-=Size/32; } if (NewMem==NULL) throw std::bad_alloc(); // Clean the window to generate the same output when unpacking corrupt // RAR files, which may access to unused areas of sliding dictionary. memset(NewMem,0,Size); Mem[BlockNum]=NewMem; TotalSize+=Size; MemSize[BlockNum]=TotalSize; BlockNum++; } if (TotalSize 0) { (*this)[UnpPtr]=(*this)[SrcPtr++ & MaxWinMask]; // We need to have masked UnpPtr after quit from loop, so it must not // be replaced with '(*this)[UnpPtr++ & MaxWinMask]' UnpPtr=(UnpPtr+1) & MaxWinMask; } } void FragmentedWindow::CopyData(byte *Dest,size_t WinPos,size_t Size) { for (size_t I=0;IBlockCount;I++) DL->D->UnpackPtr->UnpackDecode(DL->D[I]); } void Unpack::InitMT() { if (ReadBufMT==NULL) { // Even getbits32 can read up to 3 additional bytes after current // and our block header and table reading code can look much further. // Let's allocate the additional space here, so we do not need to check // bounds for every bit field access. const size_t Overflow=1024; ReadBufMT=new byte[UNP_READ_SIZE_MT+Overflow]; memset(ReadBufMT,0,UNP_READ_SIZE_MT+Overflow); } if (UnpThreadData==NULL) { uint MaxItems=MaxUserThreads*UNP_BLOCKS_PER_THREAD; UnpThreadData=new UnpackThreadData[MaxItems]; memset(UnpThreadData,0,sizeof(UnpackThreadData)*MaxItems); for (uint I=0;IDecoded==NULL) { // Typical number of items in RAR blocks does not exceed 0x4000. CurData->DecodedAllocated=0x4100; CurData->Decoded=(UnpackDecodedItem *)malloc(CurData->DecodedAllocated*sizeof(UnpackDecodedItem)); if (CurData->Decoded==NULL) ErrHandler.MemoryError(); } } } } void Unpack::Unpack5MT(bool Solid) { InitMT(); UnpInitData(Solid); for (uint I=0;ILargeBlock=false; CurData->Incomplete=false; } UnpThreadData[0].BlockHeader=BlockHeader; UnpThreadData[0].BlockTables=BlockTables; uint LastBlockNum=0; int DataSize=0; int BlockStart=0; // 'true' if we found a block too large for multithreaded extraction, // so we switched to single threaded mode until the end of file. // Large blocks could cause too high memory use in multithreaded mode. bool LargeBlock=false; bool Done=false; while (!Done) { int ReadSize=UnpIO->UnpRead(ReadBufMT+DataSize,(UNP_READ_SIZE_MT-DataSize)&~0xf); if (ReadSize<0) break; DataSize+=ReadSize; if (DataSize==0) break; bool BufferProcessed=false; while (BlockStartUnpackPtr=this; // 'Incomplete' thread is present. This is a thread processing block // in the end of buffer, split between two read operations. if (CurData->Incomplete) CurData->DataSize=DataSize; else { CurData->Inp.SetExternalBuffer(ReadBufMT+BlockStart); CurData->Inp.InitBitInput(); CurData->DataSize=DataSize-BlockStart; if (CurData->DataSize==0) break; CurData->DamagedData=false; CurData->HeaderRead=false; CurData->TableRead=false; } // We should not use 'last block in file' block flag here unless // we'll check the block size, because even if block is last in file, // it can exceed the current buffer and require more reading. CurData->NoDataLeft=(ReadSize==0); CurData->Incomplete=false; CurData->ThreadNumber=BlockNumber; if (!CurData->HeaderRead) { CurData->HeaderRead=true; if (!ReadBlockHeader(CurData->Inp,CurData->BlockHeader)) { Done=true; break; } } // To prevent too high memory use we switch to single threaded mode // if block exceeds this size. Typically RAR blocks do not exceed // 64 KB, so this protection should not affect most of valid archives. const int LargeBlockSize=0x20000; if (LargeBlock || CurData->BlockHeader.BlockSize>LargeBlockSize) LargeBlock=CurData->LargeBlock=true; else BlockNumberMT++; // Number of normal blocks processed in MT mode. BlockStart+=CurData->BlockHeader.HeaderSize+CurData->BlockHeader.BlockSize; BlockNumber++; int DataLeft=DataSize-BlockStart; if (DataLeft>=0 && CurData->BlockHeader.LastBlockInFile) break; // For second and following threads we move smaller blocks to buffer // start to ensure that we have enough data to fit block header // and tables. if (DataLeftD=UnpThreadData+CurBlock; UTD->BlockCount=Min(MaxBlockPerThread,BlockNumberMT-CurBlock); #ifdef USE_THREADS if (BlockNumber==1) UnpackDecode(*UTD->D); else UnpThreadPool->AddTask(UnpackDecodeThread,(void*)UTD); #else for (uint I=0;IBlockCount;I++) UnpackDecode(UTD->D[I]); #endif } if (BlockNumber==0) break; #ifdef USE_THREADS UnpThreadPool->WaitDone(); #endif bool IncompleteThread=false; for (uint Block=0;BlockLargeBlock && !ProcessDecoded(*CurData) || CurData->LargeBlock && !UnpackLargeBlock(*CurData) || CurData->DamagedData) { Done=true; break; } if (CurData->Incomplete) { int BufPos=int(CurData->Inp.InBuf+CurData->Inp.InAddr-ReadBufMT); if (DataSize<=BufPos) // Thread exceeded input buffer boundary. { Done=true; break; } IncompleteThread=true; memmove(ReadBufMT,ReadBufMT+BufPos,DataSize-BufPos); CurData->BlockHeader.BlockSize-=CurData->Inp.InAddr-CurData->BlockHeader.BlockStart; CurData->BlockHeader.HeaderSize=0; CurData->BlockHeader.BlockStart=0; CurData->Inp.InBuf=ReadBufMT; CurData->Inp.InAddr=0; if (Block!=0) { // Move the incomplete thread entry to the first position, // so we'll start processing from it. Preserve the original // buffer for decoded data. UnpackDecodedItem *Decoded=UnpThreadData[0].Decoded; uint DecodedAllocated=UnpThreadData[0].DecodedAllocated; UnpThreadData[0]=*CurData; UnpThreadData[0].Decoded=Decoded; UnpThreadData[0].DecodedAllocated=DecodedAllocated; CurData->Incomplete=false; } BlockStart=0; DataSize-=BufPos; break; } else if (CurData->BlockHeader.LastBlockInFile) { Done=true; break; } } if (IncompleteThread || Done) break; // Current buffer is done, read more data or quit. else { int DataLeft=DataSize-BlockStart; if (DataLeft0) memmove(ReadBufMT,ReadBufMT+BlockStart,DataLeft); DataSize=DataLeft; BlockStart=0; break; // Current buffer is done, try to read more data. } } } } UnpWriteBuf(); BlockHeader=UnpThreadData[LastBlockNum].BlockHeader; BlockTables=UnpThreadData[LastBlockNum].BlockTables; } // Decode Huffman block and save decoded data to memory. void Unpack::UnpackDecode(UnpackThreadData &D) { if (!D.TableRead) { D.TableRead=true; if (!ReadTables(D.Inp,D.BlockHeader,D.BlockTables)) { D.DamagedData=true; return; } } if (D.Inp.InAddr>D.BlockHeader.HeaderSize+D.BlockHeader.BlockSize) { D.DamagedData=true; return; } D.DecodedSize=0; int BlockBorder=D.BlockHeader.BlockStart+D.BlockHeader.BlockSize-1; // Reserve enough space even for filter entry. int DataBorder=D.DataSize-16; int ReadBorder=Min(BlockBorder,DataBorder); while (true) { if (D.Inp.InAddr>=ReadBorder) { if (D.Inp.InAddr>BlockBorder || D.Inp.InAddr==BlockBorder && D.Inp.InBit>=D.BlockHeader.BlockBitSize) break; // If we do not have any more data in file to read, we must process // what we have until last byte. Otherwise we can return and append // more data to unprocessed few bytes. if ((D.Inp.InAddr>=DataBorder) && !D.NoDataLeft || D.Inp.InAddr>=D.DataSize) { D.Incomplete=true; break; } } if (D.DecodedSize>D.DecodedAllocated-8) // Filter can use several slots. { D.DecodedAllocated=D.DecodedAllocated*2; D.Decoded=(UnpackDecodedItem *)realloc(D.Decoded,D.DecodedAllocated*sizeof(UnpackDecodedItem)); if (D.Decoded==NULL) ErrHandler.MemoryError(); } UnpackDecodedItem *CurItem=D.Decoded+D.DecodedSize++; uint MainSlot=DecodeNumber(D.Inp,&D.BlockTables.LD); if (MainSlot<256) { if (D.DecodedSize>1) { UnpackDecodedItem *PrevItem=CurItem-1; if (PrevItem->Type==UNPDT_LITERAL && PrevItem->Length<3) { PrevItem->Length++; PrevItem->Literal[PrevItem->Length]=(byte)MainSlot; D.DecodedSize--; continue; } } CurItem->Type=UNPDT_LITERAL; CurItem->Literal[0]=(byte)MainSlot; CurItem->Length=0; continue; } if (MainSlot>=262) { uint Length=SlotToLength(D.Inp,MainSlot-262); uint DBits,Distance=1,DistSlot=DecodeNumber(D.Inp,&D.BlockTables.DD); if (DistSlot<4) { DBits=0; Distance+=DistSlot; } else { DBits=DistSlot/2 - 1; Distance+=(2 | (DistSlot & 1)) << DBits; } if (DBits>0) { if (DBits>=4) { if (DBits>4) { Distance+=((D.Inp.getbits32()>>(36-DBits))<<4); D.Inp.addbits(DBits-4); } uint LowDist=DecodeNumber(D.Inp,&D.BlockTables.LDD); Distance+=LowDist; } else { Distance+=D.Inp.getbits32()>>(32-DBits); D.Inp.addbits(DBits); } } if (Distance>0x100) { Length++; if (Distance>0x2000) { Length++; if (Distance>0x40000) Length++; } } CurItem->Type=UNPDT_MATCH; CurItem->Length=(ushort)Length; CurItem->Distance=Distance; continue; } if (MainSlot==256) { UnpackFilter Filter; ReadFilter(D.Inp,Filter); CurItem->Type=UNPDT_FILTER; CurItem->Length=Filter.Type; CurItem->Distance=Filter.BlockStart; CurItem=D.Decoded+D.DecodedSize++; CurItem->Type=UNPDT_FILTER; CurItem->Length=Filter.Channels; CurItem->Distance=Filter.BlockLength; CurItem=D.Decoded+D.DecodedSize++; CurItem->Type=UNPDT_FILTER; CurItem->Length=Filter.PosR; CurItem->Distance=Filter.Width; continue; } if (MainSlot==257) { CurItem->Type=UNPDT_FULLREP; continue; } if (MainSlot<262) { CurItem->Type=UNPDT_REP; CurItem->Distance=MainSlot-258; uint LengthSlot=DecodeNumber(D.Inp,&D.BlockTables.RD); uint Length=SlotToLength(D.Inp,LengthSlot); CurItem->Length=(ushort)Length; continue; } } } // Process decoded Huffman block data. bool Unpack::ProcessDecoded(UnpackThreadData &D) { UnpackDecodedItem *Item=D.Decoded,*Border=D.Decoded+D.DecodedSize; while (ItemDestUnpSize) return false; } if (Item->Type==UNPDT_LITERAL) { #if defined(LITTLE_ENDIAN) && defined(PRESENT_INT32) && defined(ALLOW_NOT_ALIGNED_INT) if (Item->Length==3 && UnpPtrLiteral; UnpPtr+=4; } else #endif for (uint I=0;I<=Item->Length;I++) Window[UnpPtr++ & MaxWinMask]=Item->Literal[I]; } else if (Item->Type==UNPDT_MATCH) { InsertOldDist(Item->Distance); LastLength=Item->Length; CopyString(Item->Length,Item->Distance); } else if (Item->Type==UNPDT_REP) { uint Distance=OldDist[Item->Distance]; for (uint I=Item->Distance;I>0;I--) OldDist[I]=OldDist[I-1]; OldDist[0]=Distance; LastLength=Item->Length; CopyString(Item->Length,Distance); } else if (Item->Type==UNPDT_FULLREP) { if (LastLength!=0) CopyString(LastLength,OldDist[0]); } else if (Item->Type==UNPDT_FILTER) { UnpackFilter Filter; Filter.Type=(byte)Item->Length; Filter.BlockStart=Item->Distance; Item++; Filter.Channels=(byte)Item->Length; Filter.BlockLength=Item->Distance; Item++; Filter.PosR=(byte)Item->Length; Filter.Width=Item->Distance; AddFilter(Filter); } Item++; } return true; } // For large blocks we decode and process in same function in single threaded // mode, so we do not need to store intermediate data in memory. bool Unpack::UnpackLargeBlock(UnpackThreadData &D) { if (!D.TableRead) { D.TableRead=true; if (!ReadTables(D.Inp,D.BlockHeader,D.BlockTables)) { D.DamagedData=true; return false; } } if (D.Inp.InAddr>D.BlockHeader.HeaderSize+D.BlockHeader.BlockSize) { D.DamagedData=true; return false; } int BlockBorder=D.BlockHeader.BlockStart+D.BlockHeader.BlockSize-1; // Reserve enough space even for filter entry. int DataBorder=D.DataSize-16; int ReadBorder=Min(BlockBorder,DataBorder); while (true) { UnpPtr&=MaxWinMask; if (D.Inp.InAddr>=ReadBorder) { if (D.Inp.InAddr>BlockBorder || D.Inp.InAddr==BlockBorder && D.Inp.InBit>=D.BlockHeader.BlockBitSize) break; // If we do not have any more data in file to read, we must process // what we have until last byte. Otherwise we can return and append // more data to unprocessed few bytes. if ((D.Inp.InAddr>=DataBorder) && !D.NoDataLeft || D.Inp.InAddr>=D.DataSize) { D.Incomplete=true; break; } } if (((WriteBorder-UnpPtr) & MaxWinMask)DestUnpSize) return false; } uint MainSlot=DecodeNumber(D.Inp,&D.BlockTables.LD); if (MainSlot<256) { Window[UnpPtr++]=(byte)MainSlot; continue; } if (MainSlot>=262) { uint Length=SlotToLength(D.Inp,MainSlot-262); uint DBits,Distance=1,DistSlot=DecodeNumber(D.Inp,&D.BlockTables.DD); if (DistSlot<4) { DBits=0; Distance+=DistSlot; } else { DBits=DistSlot/2 - 1; Distance+=(2 | (DistSlot & 1)) << DBits; } if (DBits>0) { if (DBits>=4) { if (DBits>4) { Distance+=((D.Inp.getbits32()>>(36-DBits))<<4); D.Inp.addbits(DBits-4); } uint LowDist=DecodeNumber(D.Inp,&D.BlockTables.LDD); Distance+=LowDist; } else { Distance+=D.Inp.getbits32()>>(32-DBits); D.Inp.addbits(DBits); } } if (Distance>0x100) { Length++; if (Distance>0x2000) { Length++; if (Distance>0x40000) Length++; } } InsertOldDist(Distance); LastLength=Length; CopyString(Length,Distance); continue; } if (MainSlot==256) { UnpackFilter Filter; if (!ReadFilter(D.Inp,Filter) || !AddFilter(Filter)) break; continue; } if (MainSlot==257) { if (LastLength!=0) CopyString(LastLength,OldDist[0]); continue; } if (MainSlot<262) { uint DistNum=MainSlot-258; uint Distance=OldDist[DistNum]; for (uint I=DistNum;I>0;I--) OldDist[I]=OldDist[I-1]; OldDist[0]=Distance; uint LengthSlot=DecodeNumber(D.Inp,&D.BlockTables.RD); uint Length=SlotToLength(D.Inp,LengthSlot); LastLength=Length; CopyString(Length,Distance); continue; } } return true; } unrar/unpackinline.cpp0100666000000000000000000000670112176732144012471 0ustar z_forceinline void Unpack::InsertOldDist(uint Distance) { OldDist[3]=OldDist[2]; OldDist[2]=OldDist[1]; OldDist[1]=OldDist[0]; OldDist[0]=Distance; } #ifdef _MSC_VER #define FAST_MEMCPY #endif _forceinline void Unpack::CopyString(uint Length,uint Distance) { size_t SrcPtr=UnpPtr-Distance; if (SrcPtr=8) { Dest[0]=Src[0]; Dest[1]=Src[1]; Dest[2]=Src[2]; Dest[3]=Src[3]; Dest[4]=Src[4]; Dest[5]=Src[5]; Dest[6]=Src[6]; Dest[7]=Src[7]; Src+=8; Dest+=8; Length-=8; } #ifdef FAST_MEMCPY else while (Length>=8) { // This memcpy expanded inline by MSVC. We could also use uint64 // assignment, which seems to provide about the same speed. memcpy(Dest,Src,8); Src+=8; Dest+=8; Length-=8; } #endif // Unroll the loop for 0 - 7 bytes left. Note that we use nested "if"s. if (Length>0) { Dest[0]=Src[0]; if (Length>1) { Dest[1]=Src[1]; if (Length>2) { Dest[2]=Src[2]; if (Length>3) { Dest[3]=Src[3]; if (Length>4) { Dest[4]=Src[4]; if (Length>5) { Dest[5]=Src[5]; if (Length>6) { Dest[6]=Src[6]; } } } } } } } // Close all nested "if"s. } else while (Length-- > 0) // Slow copying with all possible precautions. { Window[UnpPtr]=Window[SrcPtr++ & MaxWinMask]; // We need to have masked UnpPtr after quit from loop, so it must not // be replaced with 'Window[UnpPtr++ & MaxWinMask]' UnpPtr=(UnpPtr+1) & MaxWinMask; } } _forceinline uint Unpack::DecodeNumber(BitInput &Inp,DecodeTable *Dec) { // Left aligned 15 bit length raw bit field. uint BitField=Inp.getbits() & 0xfffe; if (BitFieldDecodeLen[Dec->QuickBits]) { uint Code=BitField>>(16-Dec->QuickBits); Inp.addbits(Dec->QuickLen[Code]); return Dec->QuickNum[Code]; } // Detect the real bit length for current code. uint Bits=15; for (uint I=Dec->QuickBits+1;I<15;I++) if (BitFieldDecodeLen[I]) { Bits=I; break; } Inp.addbits(Bits); // Calculate the distance from the start code for current bit length. uint Dist=BitField-Dec->DecodeLen[Bits-1]; // Start codes are left aligned, but we need the normal right aligned // number. So we shift the distance to the right. Dist>>=(16-Bits); // Now we can calculate the position in the code list. It is the sum // of first position for current bit length and right aligned distance // between our bit field and start code for current bit length. uint Pos=Dec->DecodePos[Bits]+Dist; // Out of bounds safety check required for damaged archives. if (Pos>=Dec->MaxNum) Pos=0; // Convert the position in the code list to position in alphabet // and return it. return(Dec->DecodeNum[Pos]); } _forceinline uint Unpack::SlotToLength(BitInput &Inp,uint Slot) { uint LBits,Length=2; if (Slot<8) { LBits=0; Length+=Slot; } else { LBits=Slot/4-1; Length+=(4 | (Slot & 3)) << LBits; } if (LBits>0) { Length+=Inp.getbits()>>(16-LBits); Inp.addbits(LBits); } return Length; } unrar/uowners.cpp0100666000000000000000000000707212176732144011515 0ustar z void ExtractUnixOwner20(Archive &Arc,const wchar *FileName) { char NameA[NM]; WideToChar(FileName,NameA,ASIZE(NameA)); if (Arc.BrokenHeader) { 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),GetWide(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),GetWide(Arc.UOHead.GroupName)); ErrHandler.SysErrMsg(); ErrHandler.SetErrorCode(RARX_CRC); return; } uint Attr=GetFileAttr(FileName); gid_t GroupID=gr->gr_gid; #if defined(SAVE_LINKS) && !defined(_APPLE) if (lchown(NameA,OwnerID,GroupID)!=0) #else if (chown(NameA,OwnerID,GroupID)!=0) #endif { Log(Arc.FileName,St(MSetOwnersError),FileName); ErrHandler.SetErrorCode(RARX_CREATE); } SetFileAttr(FileName,Attr); } void ExtractUnixOwner30(Archive &Arc,const wchar *FileName) { char NameA[NM]; WideToChar(FileName,NameA,ASIZE(NameA)); char *OwnerName=(char *)&Arc.SubHead.SubData[0]; int OwnerSize=strlen(OwnerName)+1; int GroupSize=Arc.SubHead.SubData.Size()-OwnerSize; 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),GetWide(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),GetWide(GroupName)); ErrHandler.SetErrorCode(RARX_WARNING); return; } uint Attr=GetFileAttr(FileName); gid_t GroupID=gr->gr_gid; #if defined(SAVE_LINKS) && !defined(_APPLE) if (lchown(NameA,OwnerID,GroupID)!=0) #else if (chown(NameA,OwnerID,GroupID)!=0) #endif { Log(Arc.FileName,St(MSetOwnersError),FileName); ErrHandler.SetErrorCode(RARX_CREATE); } SetFileAttr(FileName,Attr); } void SetUnixOwner(Archive &Arc,const wchar *FileName) { char NameA[NM]; WideToChar(FileName,NameA,ASIZE(NameA)); // First, we try to resolve symbolic names. If they are missing or cannot // be resolved, we try to use numeric values if any. If numeric values // are missing too, function fails. FileHeader &hd=Arc.FileHead; if (*hd.UnixOwnerName!=0) { struct passwd *pw; if ((pw=getpwnam(hd.UnixOwnerName))==NULL) { if (!hd.UnixOwnerNumeric) { Log(Arc.FileName,St(MErrGetOwnerID),GetWide(hd.UnixOwnerName)); ErrHandler.SetErrorCode(RARX_WARNING); return; } } else hd.UnixOwnerID=pw->pw_uid; } if (*hd.UnixGroupName!=0) { struct group *gr; if ((gr=getgrnam(hd.UnixGroupName))==NULL) { if (!hd.UnixGroupNumeric) { Log(Arc.FileName,St(MErrGetGroupID),GetWide(hd.UnixGroupName)); ErrHandler.SetErrorCode(RARX_WARNING); return; } } else hd.UnixGroupID=gr->gr_gid; } #if defined(SAVE_LINKS) && !defined(_APPLE) if (lchown(NameA,hd.UnixOwnerID,hd.UnixGroupID)!=0) #else if (chown(NameA,hd.UnixOwnerID,hd.UnixGroupID)!=0) #endif { Log(Arc.FileName,St(MSetOwnersError),FileName); ErrHandler.SetErrorCode(RARX_CREATE); } } unrar/volume.cpp0100666000000000000000000001713112176732144011317 0ustar z#include "rar.hpp" #ifdef RARDLL static bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize); static bool DllVolNotify(RAROptions *Cmd,wchar *NextName); #endif bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Command) { RAROptions *Cmd=Arc.GetRAROptions(); HEADER_TYPE HeaderType=Arc.GetHeaderType(); FileHeader *hd=HeaderType==HEAD_SERVICE ? &Arc.SubHead:&Arc.FileHead; bool SplitHeader=(HeaderType==HEAD_FILE || HeaderType==HEAD_SERVICE) && hd->SplitAfter; if (DataIO!=NULL && SplitHeader) { bool PackedHashPresent=Arc.Format==RARFMT50 || hd->UnpVer>=20 && hd->FileHash.CRC32!=0xffffffff; if (PackedHashPresent && !DataIO->PackedDataHash.Cmp(&hd->FileHash,hd->UseHashKey ? hd->HashKey:NULL)) { Log(Arc.FileName,St(MDataBadCRC),hd->FileName,Arc.FileName); } } int64 PosBeforeClose=Arc.Tell(); if (DataIO!=NULL) DataIO->ProcessedArcSize+=Arc.FileLength(); Arc.Close(); wchar NextName[NM]; wcscpy(NextName,Arc.FileName); NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering); #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)) FailedOpen=true; #endif if (!FailedOpen) while (!Arc.Open(NextName,0)) { // We need to open a new volume which size was not calculated // in total size before, so we cannot calculate the total progress // 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. wchar AltNextName[NM]; wcscpy(AltNextName,Arc.FileName); NextVolumeName(AltNextName,ASIZE(AltNextName),true); OldSchemeTested=true; if (Arc.Open(AltNextName,0)) { wcscpy(NextName,AltNextName); break; } } #ifdef RARDLL if (!DllVolChange(Cmd,NextName,ASIZE(NextName))) { FailedOpen=true; break; } #else // !RARDLL #ifndef SFX_MODULE if (!RecoveryDone) { RecVolumesRestore(Cmd,Arc.FileName,true); RecoveryDone=true; continue; } #endif #ifndef GUI if (!Cmd->VolumePause && !IsRemovable(NextName)) { FailedOpen=true; break; } #endif #ifndef SILENT if (Cmd->AllYes || !AskNextVol(NextName)) #endif { FailedOpen=true; break; } #endif // RARDLL } if (FailedOpen) { #ifndef SILENT Log(Arc.FileName,St(MAbsNextVol),NextName); #endif Arc.Open(Arc.FileName,0); Arc.Seek(PosBeforeClose,SEEK_SET); return false; } if (Command=='T' || Command=='X' || Command=='E') mprintf(St(Command=='T' ? MTestVol:MExtrVol),Arc.FileName); Arc.CheckArc(true); #ifdef RARDLL if (!DllVolNotify(Cmd,NextName)) return false; #endif if (SplitHeader) Arc.SearchBlock(HeaderType); else Arc.ReadHeader(); if (Arc.GetHeaderType()==HEAD_FILE) { Arc.ConvertAttributes(); Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET); } #ifndef GUI if (ShowFileName) { mprintf(St(MExtrPoints),Arc.FileHead.FileName); if (!Cmd->DisablePercentage) mprintf(L" "); } #endif if (DataIO!=NULL) { if (HeaderType==HEAD_ENDARC) DataIO->UnpVolume=false; else { DataIO->UnpVolume=hd->SplitAfter; DataIO->SetPackedSizeToRead(hd->PackSize); } #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->PackedDataHash.Init(hd->FileHash.Type,Cmd->Threads); } return true; } #ifndef SILENT bool AskNextVol(wchar *ArcName) { eprintf(St(MAskNextVol),ArcName); if (Ask(St(MContinueQuit))==2) return false; return true; } #endif #ifdef RARDLL #if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64) // Disable the run time stack check for unrar.dll, so we can manipulate // with ChangeVolProc call type below. Run time check would intercept // a wrong ESP before we restore it. #pragma runtime_checks( "s", off ) #endif bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize) { bool DllVolChanged=false,DllVolAborted=false; if (Cmd->Callback!=NULL) { wchar CurName[NM]; wcscpy(CurName,NextName); if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextName,RAR_VOL_ASK)==-1) DllVolAborted=true; else if (wcscmp(CurName,NextName)!=0) DllVolChanged=true; else { char NextNameA[NM]; WideToChar(NextName,NextNameA,ASIZE(NextNameA)); if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextNameA,RAR_VOL_ASK)==-1) DllVolAborted=true; else { CharToWide(NextNameA,NextName,NameSize); if (wcscmp(CurName,NextName)!=0) DllVolChanged=true; } } } if (!DllVolChanged && Cmd->ChangeVolProc!=NULL) { char NextNameA[NM]; WideToChar(NextName,NextNameA,ASIZE(NextNameA)); // Here we preserve ESP value. It is necessary for those developers, // who still define ChangeVolProc callback as "C" type function, // even though in year 2001 we announced in unrar.dll whatsnew.txt // that it will be PASCAL type (for compatibility with Visual Basic). #if defined(_MSC_VER) #ifndef _WIN_64 __asm mov ebx,esp #endif #elif defined(_WIN_ALL) && defined(__BORLANDC__) _EBX=_ESP; #endif int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_ASK); // Restore ESP after ChangeVolProc with wrongly defined calling // convention broken it. #if defined(_MSC_VER) #ifndef _WIN_64 __asm mov esp,ebx #endif #elif defined(_WIN_ALL) && defined(__BORLANDC__) _ESP=_EBX; #endif if (RetCode==0) DllVolAborted=true; else CharToWide(NextNameA,NextName,ASIZE(NextName)); } // We quit only on 'abort' condition, but not on 'name not changed'. // It is legitimate for program to return the same name when waiting // for currently non-existent volume. if (DllVolAborted) { Cmd->DllError=ERAR_EOPEN; return false; } return true; } #endif #ifdef RARDLL bool DllVolNotify(RAROptions *Cmd,wchar *NextName) { char NextNameA[NM]; WideToChar(NextName,NextNameA,ASIZE(NextNameA)); if (Cmd->Callback!=NULL) { if (Cmd->Callback(UCM_CHANGEVOLUMEW,Cmd->UserData,(LPARAM)NextName,RAR_VOL_NOTIFY)==-1) return false; if (Cmd->Callback(UCM_CHANGEVOLUME,Cmd->UserData,(LPARAM)NextNameA,RAR_VOL_NOTIFY)==-1) return false; } if (Cmd->ChangeVolProc!=NULL) { #if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__) _EBX=_ESP; #endif int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_NOTIFY); #if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__) _ESP=_EBX; #endif if (RetCode==0) return false; } return true; } #if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64) // Restore the run time stack check for unrar.dll. #pragma runtime_checks( "s", restore ) #endif #endif unrar/win32acl.cpp0100666000000000000000000000543012176732144011431 0ustar zstatic void SetACLPrivileges(); static bool ReadSacl=false; #ifndef SFX_MODULE void ExtractACL20(Archive &Arc,const wchar *FileName) { SetACLPrivileges(); if (Arc.BrokenHeader) { Log(Arc.FileName,St(MACLBroken),FileName); ErrHandler.SetErrorCode(RARX_CRC); return; } if (Arc.EAHead.Method<0x31 || Arc.EAHead.Method>0x35 || Arc.EAHead.UnpVer>VER_PACK) { Log(Arc.FileName,St(MACLUnknown),FileName); ErrHandler.SetErrorCode(RARX_WARNING); return; } ComprDataIO DataIO; Unpack Unpack(&DataIO); Unpack.Init(0x10000,false); Array UnpData(Arc.EAHead.UnpSize); DataIO.SetUnpackToMemory(&UnpData[0],Arc.EAHead.UnpSize); DataIO.SetPackedSizeToRead(Arc.EAHead.DataSize); DataIO.EnableShowProgress(false); DataIO.SetFiles(&Arc,NULL); DataIO.UnpHash.Init(HASH_CRC32,1); Unpack.SetDestSize(Arc.EAHead.UnpSize); Unpack.DoUnpack(Arc.EAHead.UnpVer,false); if (Arc.EAHead.EACRC!=DataIO.UnpHash.GetCRC32()) { 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=SetFileSecurityW(FileName,si,sd); if (!SetCode) { Log(Arc.FileName,St(MACLSetError),FileName); ErrHandler.SysErrMsg(); ErrHandler.SetErrorCode(RARX_WARNING); } } #endif void ExtractACL(Archive &Arc,const wchar *FileName) { Array SubData; if (!Arc.ReadSubData(&SubData,NULL)) return; SetACLPrivileges(); 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=SetFileSecurityW(FileName,si,sd); if (!SetCode) { Log(Arc.FileName,St(MACLSetError),FileName); ErrHandler.SysErrMsg(); ErrHandler.SetErrorCode(RARX_WARNING); } } void SetACLPrivileges() { static bool InitDone=false; if (InitDone) return; if (SetPrivilege(SE_SECURITY_NAME)) ReadSacl=true; SetPrivilege(SE_RESTORE_NAME); InitDone=true; } bool SetPrivilege(LPCTSTR PrivName) { bool Success=false; HANDLE hToken; if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (LookupPrivilegeValue(NULL,PrivName,&tp.Privileges[0].Luid) && AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL) && GetLastError() == ERROR_SUCCESS) Success=true; CloseHandle(hToken); } return Success; } unrar/win32lnk.cpp0100666000000000000000000001676512176732144011473 0ustar z#define SYMLINK_FLAG_RELATIVE 1 typedef struct _REPARSE_DATA_BUFFER { ULONG ReparseTag; USHORT ReparseDataLength; USHORT Reserved; union { struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; ULONG Flags; WCHAR PathBuffer[1]; } SymbolicLinkReparseBuffer; struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; WCHAR PathBuffer[1]; } MountPointReparseBuffer; struct { UCHAR DataBuffer[1]; } GenericReparseBuffer; }; } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; void GetReparsePoint(const wchar *Name,FileHeader *hd) { static bool PrivSet=false; if (!PrivSet) { SetPrivilege(SE_BACKUP_NAME); PrivSet=true; } WIN32_FIND_DATA FindData; HANDLE hFind=FindFirstFile(Name,&FindData); if (hFind==INVALID_HANDLE_VALUE) return; FindClose(hFind); if ((FindData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)==0 || FindData.dwReserved0!=IO_REPARSE_TAG_MOUNT_POINT && FindData.dwReserved0!=IO_REPARSE_TAG_SYMLINK) return; HANDLE hFile=CreateFile( Name,FILE_READ_EA,FILE_SHARE_READ,NULL,OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_POINT,NULL); if (hFile==INVALID_HANDLE_VALUE) { ErrHandler.OpenErrorMsg(NULL,Name); ErrHandler.SysErrMsg(); ErrHandler.SetErrorCode(RARX_OPEN); return; } const DWORD BufSize=MAXIMUM_REPARSE_DATA_BUFFER_SIZE; Array Buf(BufSize); REPARSE_DATA_BUFFER *rdb=(REPARSE_DATA_BUFFER *)&Buf[0]; DWORD BytesReturned; BOOL DevResult=DeviceIoControl(hFile,FSCTL_GET_REPARSE_POINT,NULL,0,rdb,BufSize,&BytesReturned,NULL); CloseHandle(hFile); if (!DevResult) { ErrHandler.ReadErrorMsg(Name); return; } wchar TargetName[NM]; if (rdb->ReparseTag==IO_REPARSE_TAG_MOUNT_POINT) { uint SubstOffset=rdb->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR); uint SubstLength=rdb->MountPointReparseBuffer.SubstituteNameLength/sizeof(WCHAR); wchar *SubstName=rdb->MountPointReparseBuffer.PathBuffer+SubstOffset; if (SubstLength>=ASIZE(TargetName)) return; wcsncpy(TargetName,SubstName,SubstLength); TargetName[SubstLength]=0; hd->RedirType=FSREDIR_JUNCTION; } if (rdb->ReparseTag==IO_REPARSE_TAG_SYMLINK) { uint SubstOffset=rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof(WCHAR); uint SubstLength=rdb->SymbolicLinkReparseBuffer.SubstituteNameLength/sizeof(WCHAR); wchar *SubstName=rdb->SymbolicLinkReparseBuffer.PathBuffer+SubstOffset; if (SubstLength>=ASIZE(TargetName)) return; wcsncpy(TargetName,SubstName,SubstLength); TargetName[SubstLength]=0; hd->RedirType=FSREDIR_WINSYMLINK; } if (hd->RedirType==FSREDIR_NONE) return; wcsncpyz(hd->RedirName,TargetName,ASIZE(hd->RedirName)); hd->DirTarget=(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!=0; } bool CreateReparsePoint(CommandData *Cmd,const wchar *Name,FileHeader *hd) { static bool PrivSet=false; if (!PrivSet) { SetPrivilege(SE_RESTORE_NAME); // Not sure if we really need it, but let's request anyway. SetPrivilege(SE_CREATE_SYMBOLIC_LINK_NAME); PrivSet=true; } CreatePath(Name,true); // 'DirTarget' check is important for Unix symlinks to directories. // Unix symlinks do not have their own 'directory' attribute. if (hd->Dir || hd->DirTarget) { if (!CreateDirectory(Name,NULL)) return false; } else { HANDLE hFile=CreateFile(Name,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL); if (hFile == INVALID_HANDLE_VALUE) return false; CloseHandle(hFile); } const DWORD BufSize=sizeof(REPARSE_DATA_BUFFER)+2*NM+1024; Array Buf(BufSize); REPARSE_DATA_BUFFER *rdb=(REPARSE_DATA_BUFFER *)&Buf[0]; wchar SubstName[NM]; wcsncpyz(SubstName,hd->RedirName,ASIZE(SubstName)); size_t SubstLength=wcslen(SubstName); wchar PrintName[NM],*PrintNameSrc=SubstName,*PrintNameDst=PrintName; bool WinPrefix=wcsncmp(PrintNameSrc,L"\\??\\",4)==0; if (WinPrefix) PrintNameSrc+=4; if (WinPrefix && wcsncmp(PrintNameSrc,L"UNC\\",4)==0) { *(PrintNameDst++)='\\'; // Insert second \ in beginning of share name. PrintNameSrc+=3; } wcscpy(PrintNameDst,PrintNameSrc); size_t PrintLength=wcslen(PrintName); bool AbsPath=WinPrefix; if (hd->RedirType==FSREDIR_JUNCTION) { rdb->ReparseTag=IO_REPARSE_TAG_MOUNT_POINT; rdb->ReparseDataLength=USHORT( sizeof(rdb->MountPointReparseBuffer.SubstituteNameOffset)+ sizeof(rdb->MountPointReparseBuffer.SubstituteNameLength)+ sizeof(rdb->MountPointReparseBuffer.PrintNameOffset)+ sizeof(rdb->MountPointReparseBuffer.PrintNameLength)+ (SubstLength+1)*sizeof(WCHAR)+(PrintLength+1)*sizeof(WCHAR)); rdb->Reserved=0; rdb->MountPointReparseBuffer.SubstituteNameOffset=0; rdb->MountPointReparseBuffer.SubstituteNameLength=USHORT(SubstLength*sizeof(WCHAR)); wcscpy(rdb->MountPointReparseBuffer.PathBuffer,SubstName); rdb->MountPointReparseBuffer.PrintNameOffset=USHORT((SubstLength+1)*sizeof(WCHAR)); rdb->MountPointReparseBuffer.PrintNameLength=USHORT(PrintLength*sizeof(WCHAR)); wcscpy(rdb->MountPointReparseBuffer.PathBuffer+SubstLength+1,PrintName); } else if (hd->RedirType==FSREDIR_WINSYMLINK || hd->RedirType==FSREDIR_UNIXSYMLINK) { rdb->ReparseTag=IO_REPARSE_TAG_SYMLINK; rdb->ReparseDataLength=USHORT( sizeof(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset)+ sizeof(rdb->SymbolicLinkReparseBuffer.SubstituteNameLength)+ sizeof(rdb->SymbolicLinkReparseBuffer.PrintNameOffset)+ sizeof(rdb->SymbolicLinkReparseBuffer.PrintNameLength)+ sizeof(rdb->SymbolicLinkReparseBuffer.Flags)+ (SubstLength+1)*sizeof(WCHAR)+(PrintLength+1)*sizeof(WCHAR)); rdb->Reserved=0; rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset=0; rdb->SymbolicLinkReparseBuffer.SubstituteNameLength=USHORT(SubstLength*sizeof(WCHAR)); wcscpy(rdb->SymbolicLinkReparseBuffer.PathBuffer,SubstName); rdb->SymbolicLinkReparseBuffer.PrintNameOffset=USHORT((SubstLength+1)*sizeof(WCHAR)); rdb->SymbolicLinkReparseBuffer.PrintNameLength=USHORT(PrintLength*sizeof(WCHAR)); wcscpy(rdb->SymbolicLinkReparseBuffer.PathBuffer+SubstLength+1,PrintName); rdb->SymbolicLinkReparseBuffer.Flags=AbsPath ? 0:SYMLINK_FLAG_RELATIVE; } else return false; HANDLE hFile=CreateFile(Name,GENERIC_READ|GENERIC_WRITE,0,NULL, OPEN_EXISTING,FILE_FLAG_OPEN_REPARSE_POINT| FILE_FLAG_BACKUP_SEMANTICS,NULL); if (hFile==INVALID_HANDLE_VALUE) return false; DWORD Returned; if (!DeviceIoControl(hFile,FSCTL_SET_REPARSE_POINT,rdb, FIELD_OFFSET(REPARSE_DATA_BUFFER,GenericReparseBuffer)+ rdb->ReparseDataLength,NULL,0,&Returned,NULL)) { CloseHandle(hFile); Log(NULL,St(MErrCreateLnkS),Name); if (GetLastError()==ERROR_PRIVILEGE_NOT_HELD) Log(NULL,St(MNeedAdmin)); ErrHandler.SysErrMsg(); ErrHandler.SetErrorCode(RARX_CREATE); if (hd->Dir) RemoveDirectory(Name); else DeleteFile(Name); return false; } File LinkFile; LinkFile.SetHandle(hFile); LinkFile.SetOpenFileTime( Cmd->xmtime==EXTTIME_NONE ? NULL:&hd->mtime, Cmd->xctime==EXTTIME_NONE ? NULL:&hd->ctime, Cmd->xatime==EXTTIME_NONE ? NULL:&hd->atime); LinkFile.Close(); if (!Cmd->IgnoreGeneralAttr) SetFileAttr(Name,hd->FileAttr); return true; } unrar/win32stm.cpp0100666000000000000000000000776212176732144011507 0ustar z #if !defined(SFX_MODULE) && defined(_WIN_ALL) void ExtractStreams20(Archive &Arc,const wchar *FileName) { if (Arc.BrokenHeader) { #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>VER_PACK) { #ifndef SILENT Log(Arc.FileName,St(MStreamUnknown),FileName); #endif ErrHandler.SetErrorCode(RARX_WARNING); return; } wchar StreamName[NM+2]; if (FileName[0]!=0 && FileName[1]==0) { wcscpy(StreamName,L".\\"); wcscpy(StreamName+2,FileName); } else wcscpy(StreamName,FileName); if (wcslen(StreamName)+strlen(Arc.StreamHead.StreamName)>=ASIZE(StreamName) || Arc.StreamHead.StreamName[0]!=':') { #ifndef SILENT Log(Arc.FileName,St(MStreamBroken),FileName); #endif ErrHandler.SetErrorCode(RARX_CRC); return; } wchar StoredName[NM]; CharToWide(Arc.StreamHead.StreamName,StoredName,ASIZE(StoredName)); ConvertPath(StoredName+1,StoredName+1); wcsncatz(StreamName,StoredName,ASIZE(StreamName)); FindData fd; bool Found=FindFile::FastFind(FileName,&fd); if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0) SetFileAttr(FileName,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY); File CurFile; if (CurFile.WCreate(StreamName)) { ComprDataIO DataIO; Unpack Unpack(&DataIO); Unpack.Init(0x10000,false); DataIO.SetPackedSizeToRead(Arc.StreamHead.DataSize); DataIO.EnableShowProgress(false); DataIO.SetFiles(&Arc,&CurFile); DataIO.UnpHash.Init(HASH_CRC32,1); Unpack.SetDestSize(Arc.StreamHead.UnpSize); Unpack.DoUnpack(Arc.StreamHead.UnpVer,false); if (Arc.StreamHead.StreamCRC!=DataIO.UnpHash.GetCRC32()) { #ifndef SILENT Log(Arc.FileName,St(MStreamBroken),StreamName); #endif ErrHandler.SetErrorCode(RARX_CRC); } else CurFile.Close(); } File HostFile; if (Found && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE)) SetFileTime(HostFile.GetHandle(),&fd.ftCreationTime,&fd.ftLastAccessTime, &fd.ftLastWriteTime); if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0) SetFileAttr(FileName,fd.FileAttr); } #endif #ifdef _WIN_ALL void ExtractStreams(Archive &Arc,const wchar *FileName) { wchar FullName[NM+2]; if (FileName[0]!=0 && FileName[1]==0) { wcscpy(FullName,L".\\"); wcsncpyz(FullName+2,FileName,ASIZE(FullName)-2); } else wcsncpyz(FullName,FileName,ASIZE(FullName)); byte *Data=&Arc.SubHead.SubData[0]; size_t DataSize=Arc.SubHead.SubData.Size(); wchar StreamName[NM]; GetStreamNameNTFS(Arc,StreamName,ASIZE(StreamName)); if (*StreamName!=':') { #if !defined(SILENT) && !defined(SFX_MODULE) Log(Arc.FileName,St(MStreamBroken),FileName); #endif ErrHandler.SetErrorCode(RARX_CRC); return; } wcsncatz(FullName,StreamName,ASIZE(FullName)); FindData fd; bool Found=FindFile::FastFind(FileName,&fd); if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0) SetFileAttr(FileName,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY); File CurFile; if (CurFile.WCreate(FullName) && Arc.ReadSubData(NULL,&CurFile)) CurFile.Close(); File HostFile; if (Found && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE)) SetFileTime(HostFile.GetHandle(),&fd.ftCreationTime,&fd.ftLastAccessTime, &fd.ftLastWriteTime); // Restoring original file attributes. Important if file was read only // or did not have "Archive" attribute SetFileAttr(FileName,fd.FileAttr); } #endif void GetStreamNameNTFS(Archive &Arc,wchar *StreamName,size_t MaxSize) { byte *Data=&Arc.SubHead.SubData[0]; size_t DataSize=Arc.SubHead.SubData.Size(); if (Arc.Format==RARFMT15) { size_t DestSize=Min(DataSize/2,MaxSize-1); RawToWide(Data,StreamName,DestSize); StreamName[DestSize]=0; } else { char UtfString[NM*4]; size_t DestSize=Min(DataSize,ASIZE(UtfString)-1); memcpy(UtfString,Data,DestSize); UtfString[DestSize]=0; UtfToWide(UtfString,StreamName,MaxSize); } } unrar/archive.hpp0100666000000000000000000001002412176732144011430 0ustar z#ifndef _RAR_ARCHIVE_ #define _RAR_ARCHIVE_ class PPack; class RawRead; class RawWrite; enum NOMODIFY_FLAGS { NMDF_ALLOWLOCK=1,NMDF_ALLOWANYVOLUME=2,NMDF_ALLOWFIRSTVOLUME=4 }; enum RARFORMAT {RARFMT_NONE,RARFMT14,RARFMT15,RARFMT50,RARFMT_FUTURE}; enum ADDSUBDATA_FLAGS { ASDF_SPLIT = 1, // Allow to split archive just before header if necessary. ASDF_COMPRESS = 2, // Allow to compress data following subheader. ASDF_CRYPT = 4, // Encrypt data after subheader if password is set. ASDF_CRYPTIFHEADERS = 8 // Encrypt data after subheader only in -hp mode. }; class Archive:public File { private: void UpdateLatestTime(FileHeader *CurBlock); void ConvertNameCase(wchar *Name); void ConvertFileHeader(FileHeader *hd); void WriteBlock50(HEADER_TYPE HeaderType,BaseBlock *wb,bool OnlySetSize,bool NonFinalWrite); size_t ReadHeader14(); size_t ReadHeader15(); size_t ReadHeader50(); void ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb); void RequestArcPassword(); void UnexpEndArcMsg(); void BrokenHeaderMsg(); void UnkEncVerMsg(const wchar *Name); void UnkEncVerMsg(); bool ReadCommentData(Array *CmtData); #if !defined(SHELL_EXT) && !defined(RAR_NOCRYPT) CryptData HeadersCrypt; #endif #ifndef SHELL_EXT ComprDataIO SubDataIO; #endif bool DummyCmd; RAROptions *Cmd; int64 RecoverySize; int RecoveryPercent; RarTime LatestTime; int LastReadBlock; HEADER_TYPE CurHeaderType; bool SilentOpen; #ifdef USE_QOPEN QuickOpen QOpen; #endif public: Archive(RAROptions *InitCmd=NULL); ~Archive(); RARFORMAT IsSignature(const byte *D,size_t Size); bool IsArchive(bool EnableBroken); size_t SearchBlock(HEADER_TYPE HeaderType); size_t SearchSubBlock(const wchar *Type); size_t SearchRR(); void WriteBlock(HEADER_TYPE HeaderType,BaseBlock *wb=NULL,bool OnlySetSize=false,bool NonFinalWrite=false); void SetBlockSize(HEADER_TYPE HeaderType,BaseBlock *wb=NULL) {WriteBlock(HeaderType,wb,true);} size_t ReadHeader(); void CheckArc(bool EnableBroken); void CheckOpen(const wchar *Name); bool WCheckOpen(const wchar *Name); bool GetComment(Array *CmtData); void ViewComment(); void SetLatestTime(RarTime *NewTime); void SeekToNext(); bool CheckAccess(); bool IsArcDir(); void ConvertAttributes(); void VolSubtractHeaderSize(size_t SubSize); uint FullHeaderSize(size_t Size); int64 GetStartPos(); void AddSubData(byte *SrcData,uint64 DataSize,File *SrcFile, const wchar *Name,uint Flags); bool ReadSubData(Array *UnpData,File *DestFile); HEADER_TYPE GetHeaderType() {return(CurHeaderType);}; void WriteCommentData(byte *Data,size_t DataSize,bool FileComment); RAROptions* GetRAROptions() {return(Cmd);} void SetSilentOpen(bool Mode) {SilentOpen=Mode;} #ifdef USE_QOPEN int Read(void *Data,size_t Size); void Seek(int64 Offset,int Method); int64 Tell(); void QOpenUnload() {QOpen.Unload();} #endif BaseBlock ShortBlock; MarkHeader MarkHead; MainHeader MainHead; CryptHeader CryptHead; FileHeader FileHead; 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; RARFORMAT Format; bool Solid; bool Volume; bool MainComment; bool Locked; bool Signed; bool FirstVolume; bool NewNumbering; bool Protected; bool Encrypted; size_t SFXSize; bool BrokenHeader; bool FailedHeaderDecryption; #if !defined(SHELL_EXT) && !defined(RAR_NOCRYPT) byte ArcSalt[SIZE_SALT50]; #endif bool Splitting; uint VolNumber; int64 VolWrite; uint64 AddingFilesSize; uint64 AddingHeadersSize; bool NewArchive; wchar FirstVolumeName[NM]; }; #endif unrar/array.hpp0100666000000000000000000000577212176732144011143 0ustar z#ifndef _RAR_ARRAY_ #define _RAR_ARRAY_ extern ErrorHandler ErrHandler; template class Array { private: T *Buffer; size_t BufSize; size_t AllocSize; size_t MaxSize; public: Array(); Array(size_t Size); Array(const Array &Src); // Copy constructor. ~Array(); inline void CleanData(); inline T& operator [](size_t Item) const; inline T* operator + (size_t Pos); inline size_t Size(); // Returns the size in items, not in bytes. void Add(size_t Items); void Alloc(size_t Items); void Reset(); void SoftReset(); void operator = (Array &Src); void Push(T Item); void Append(T *Item,size_t Count); T* Addr(size_t Item) {return Buffer+Item;} void SetMaxSize(size_t Size) {MaxSize=Size;} }; template void Array::CleanData() { Buffer=NULL; BufSize=0; AllocSize=0; MaxSize=0; } template Array::Array() { CleanData(); } template Array::Array(size_t Size) { CleanData(); Add(Size); } // Copy constructor in case we need to pass an object as value. template Array::Array(const Array &Src) { CleanData(); Alloc(Src.BufSize); if (Src.BufSize!=0) memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T)); } template Array::~Array() { if (Buffer!=NULL) free(Buffer); } template inline T& Array::operator [](size_t Item) const { return Buffer[Item]; } template inline T* Array::operator +(size_t Pos) { return Buffer+Pos; } template inline size_t Array::Size() { return BufSize; } template void Array::Add(size_t Items) { BufSize+=Items; if (BufSize>AllocSize) { if (MaxSize!=0 && BufSize>MaxSize) { ErrHandler.GeneralErrMsg(L"Maximum allowed array size (%u) is exceeded",MaxSize); ErrHandler.MemoryError(); } size_t Suggested=AllocSize+AllocSize/4+32; size_t NewSize=Max(BufSize,Suggested); T *NewBuffer=(T *)realloc(Buffer,NewSize*sizeof(T)); if (NewBuffer==NULL) ErrHandler.MemoryError(); Buffer=NewBuffer; AllocSize=NewSize; } } template void Array::Alloc(size_t Items) { if (Items>AllocSize) Add(Items-BufSize); else BufSize=Items; } template void Array::Reset() { if (Buffer!=NULL) { free(Buffer); Buffer=NULL; } BufSize=0; AllocSize=0; } // Reset buffer size, but preserve already allocated memory if any, // so we can reuse it without wasting time to allocation. template void Array::SoftReset() { BufSize=0; } template void Array::operator =(Array &Src) { Reset(); Alloc(Src.BufSize); if (Src.BufSize!=0) memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T)); } template void Array::Push(T Item) { Add(1); (*this)[Size()-1]=Item; } template void Array::Append(T *Items,size_t Count) { size_t CurSize=Size(); Add(Count); memcpy(Buffer+CurSize,Items,Count*sizeof(T)); } #endif unrar/blake2s.hpp0100666000000000000000000000436112176732144011341 0ustar z// Based on public domain code written in 2012 by Samuel Neves #ifndef _RAR_BLAKE2_ #define _RAR_BLAKE2_ #define BLAKE2_DIGEST_SIZE 32 enum blake2s_constant { BLAKE2S_BLOCKBYTES = 64, BLAKE2S_OUTBYTES = 32 }; // Alignment to 64 improves performance of both SSE and non-SSE versions. // Alignment to n*16 is required for SSE version, so we selected 64. // We use the custom alignment scheme instead of __declspec(align(x)), // because it is less compiler dependent. Also the compiler directive // does not help if structure is a member of class allocated through // 'new' operator. struct blake2s_state { enum { BLAKE_ALIGNMENT = 64 }; // buffer and uint32 h[8], t[2], f[2]; enum { BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES }; byte ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT]; byte *buf; // byte buf[2 * BLAKE2S_BLOCKBYTES]. uint32 *h, *t, *f; // uint32 h[8], t[2], f[2]. size_t buflen; byte last_node; blake2s_state() { set_pointers(); } // Required when we declare and assign in the same command. blake2s_state(blake2s_state &st) { set_pointers(); *this=st; } void set_pointers() { // Set aligned pointers. Must be done in constructor, not in Init(), // so assignments like 'blake2sp_state res=blake2ctx' work correctly // even if blake2sp_init is not called for 'res'. buf = (byte *) ALIGN_VALUE(ubuf, BLAKE_ALIGNMENT); h = (uint32 *) (buf + 2 * BLAKE2S_BLOCKBYTES); t = h + 8; f = t + 2; } void init() { memset( ubuf, 0, sizeof( ubuf ) ); buflen = 0; last_node = 0; } // Since we use pointers, the default = would work incorrectly. blake2s_state& operator = (blake2s_state &st) { if (this != &st) { memcpy(buf, st.buf, BLAKE_DATA_SIZE); buflen = st.buflen; last_node = st.last_node; } return *this; } }; #ifdef RAR_SMP class ThreadPool; #endif struct blake2sp_state { blake2s_state S[8]; blake2s_state R; byte buf[8 * BLAKE2S_BLOCKBYTES]; size_t buflen; #ifdef RAR_SMP ThreadPool *ThPool; uint MaxThreads; #endif }; void blake2sp_init( blake2sp_state *S ); void blake2sp_update( blake2sp_state *S, const byte *in, size_t inlen ); void blake2sp_final( blake2sp_state *S, byte *digest ); #endif unrar/cmddata.hpp0100666000000000000000000000335412176732144011414 0ustar z#ifndef _RAR_CMDDATA_ #define _RAR_CMDDATA_ #define DefaultStoreList L"7z;ace;arj;bz2;cab;gz;jpeg;jpg;lha;lzh;mp3;rar;taz;tgz;xz;z;zip" enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS}; class CommandData:public RAROptions { private: void ProcessSwitchesString(const wchar *Str); void ProcessSwitch(const wchar *Switch); void BadSwitch(const wchar *Switch); bool ExclCheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode); uint GetExclAttr(const wchar *Str); bool FileLists; bool NoMoreSwitches; RAR_CMD_LIST_MODE ListMode; bool BareOutput; public: CommandData(); void Init(); void ParseCommandLine(bool Preprocess,int argc, char *argv[]); void ParseArg(wchar *ArgW); void ParseDone(); void ParseEnvVar(); void ReadConfig(); bool PreprocessSwitch(const wchar *Switch); void OutTitle(); void OutHelp(RAR_EXIT ExitCode); bool IsSwitch(int Ch); bool ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList); bool ExclDirByAttr(uint FileAttr); bool TimeCheck(RarTime &ft); bool SizeCheck(int64 Size); bool AnyFiltersActive(); int IsProcessFile(FileHeader &FileHead,bool *ExactMatch=NULL,int MatchType=MATCH_WILDSUBPATH); void ProcessCommand(); void AddArcName(const wchar *Name); bool GetArcName(wchar *Name,int MaxSize); bool CheckWinSize(); int GetRecoverySize(const wchar *Str,int DefSize); #ifndef SFX_MODULE void ReportWrongSwitches(RARFORMAT Format); #endif wchar Command[NM+16]; wchar ArcName[NM]; StringList FileArgs; StringList ExclArgs; StringList InclArgs; StringList ArcNames; StringList StoreArgs; }; #endif unrar/coder.hpp0100666000000000000000000000123612176732144011110 0ustar z/**************************************************************************** * 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; }; unrar/compress.hpp0100666000000000000000000000214312176732144011645 0ustar z#ifndef _RAR_COMPRESS_ #define _RAR_COMPRESS_ #define MAX_LZ_MATCH 0x1001 #define MAX3_LZ_MATCH 0x101 // Maximum match length for RAR v3. #define LOW_DIST_REP_COUNT 16 #define NC 306 /* alphabet = {0, 1, 2, ..., NC - 1} */ #define DC 64 #define LDC 16 #define RC 44 #define HUFF_TABLE_SIZE (NC+DC+RC+LDC) #define BC 20 #define NC30 299 /* alphabet = {0, 1, 2, ..., NC - 1} */ #define DC30 60 #define LDC30 17 #define RC30 28 #define BC30 20 #define HUFF_TABLE_SIZE30 (NC30+DC30+RC30+LDC30) #define NC20 298 /* alphabet = {0, 1, 2, ..., NC - 1} */ #define DC20 48 #define RC20 28 #define BC20 19 #define MC20 257 // Largest alphabet size among all values listed above. #define LARGEST_TABLE_SIZE 306 enum {CODE_HUFFMAN,CODE_LZ,CODE_REPEATLZ,CODE_CACHELZ, CODE_STARTFILE,CODE_ENDFILE,CODE_FILTER,CODE_FILTERDATA}; enum FilterType { // These values must not be changed, because we use them directly // in RAR5 compression and decompression code. FILTER_DELTA=0, FILTER_E8, FILTER_E8E9, FILTER_ARM, FILTER_AUDIO, FILTER_RGB, FILTER_ITANIUM, FILTER_PPM, FILTER_NONE }; #endif unrar/consio.hpp0100666000000000000000000000130712176732144011305 0ustar z#ifndef _RAR_CONSIO_ #define _RAR_CONSIO_ void InitConsole(); void InitConsoleOptions(MESSAGE_TYPE MsgStream,bool Sound); void OutComment(const wchar *Comment,size_t Size); #ifndef SILENT bool GetConsolePassword(PASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password); #endif #ifdef SILENT inline void mprintf(const wchar *fmt,...) {} inline void eprintf(const wchar *fmt,...) {} inline void Alarm() {} inline int Ask(const wchar *AskStr) {return 0;} inline bool getwstr(wchar *str,size_t n) {return false;} #else void mprintf(const wchar *fmt,...); void eprintf(const wchar *fmt,...); void Alarm(); int Ask(const wchar *AskStr); bool getwstr(wchar *str,size_t n); #endif #endif unrar/crc.hpp0100666000000000000000000000052312176732144010561 0ustar z#ifndef _RAR_CRC_ #define _RAR_CRC_ // This function is only to intialize external CRC tables. We do not need to // call it before calculating CRC32. void InitCRC32(uint *CRCTab); uint CRC32(uint StartCRC,const void *Addr,size_t Size); #ifndef SFX_MODULE ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size); #endif #endif unrar/crypt.hpp0100666000000000000000000000477012176732144011163 0ustar z#ifndef _RAR_CRYPT_ #define _RAR_CRYPT_ enum CRYPT_METHOD { CRYPT_NONE,CRYPT_RAR13,CRYPT_RAR15,CRYPT_RAR20,CRYPT_RAR30,CRYPT_RAR50 }; #define SIZE_SALT50 16 #define SIZE_SALT30 8 #define SIZE_INITV 16 #define SIZE_PSWCHECK 8 #define SIZE_PSWCHECK_CSUM 4 #define CRYPT_BLOCK_SIZE 16 #define CRYPT_BLOCK_MASK (CRYPT_BLOCK_SIZE-1) // 0xf #define CRYPT5_KDF_LG2_COUNT 15 // LOG2 of PDKDF2 iteration count. #define CRYPT5_KDF_LG2_COUNT_MAX 24 // LOG2 of maximum accepted iteration count. #define CRYPT_VERSION 0 // Supported encryption version. struct KDFCacheItem { SecPassword Pwd; byte Salt[SIZE_SALT50]; uint Lg2Count; // Log2 of PBKDF2 repetition count. byte Key[32]; byte PswCheckValue[SHA256_DIGEST_SIZE]; byte HashKeyValue[SHA256_DIGEST_SIZE]; }; class CryptData { private: void SetKey13(const char *Password); void Decrypt13(byte *Data,size_t Count); void SetKey15(const char *Password); void Crypt15(byte *Data,size_t Count); void SetKey20(const char *Password); void Swap20(byte *Ch1,byte *Ch2); void UpdKeys20(byte *Buf); void EncryptBlock20(byte *Buf); void DecryptBlock20(byte *Buf); void SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt); void SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck); KDFCacheItem KDFCache[4]; uint KDFCachePos; CRYPT_METHOD Method; Rijndael rin; uint CRCTab[256]; // For RAR 1.5 and RAR 2.0 encryption. byte SubstTable20[256]; uint Key20[4]; byte Key13[3]; ushort Key15[4]; public: CryptData(); ~CryptData(); bool SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,SecPassword *Password, const byte *Salt,const byte *InitV,uint Lg2Cnt, byte *HashKey,byte *PswCheck); void SetAV15Encryption(); void SetCmt13Encryption(); void EncryptBlock(byte *Buf,size_t Size); void DecryptBlock(byte *Buf,size_t Size); static void SetSalt(byte *Salt,size_t SaltSize); }; void GetRnd(byte *RndBuf,size_t BufSize); void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data, size_t DataLength,byte *ResDigest); void pbkdf2(const byte *pass, size_t pass_len, const byte *salt, size_t salt_len,byte *key, byte *Value1, byte *Value2, uint rounds); void ConvertHashToMAC(HashValue *Value,byte *Key); #endif unrar/dll.hpp0100666000000000000000000001007112176732144010564 0ustar z#ifndef _UNRAR_DLL_ #define _UNRAR_DLL_ #pragma pack(1) #define ERAR_SUCCESS 0 #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 6 #define RAR_HASH_NONE 0 #define RAR_HASH_CRC32 1 #define RAR_HASH_BLAKE2 2 #ifdef _UNIX #define CALLBACK #define PASCAL #define LONG long #define HANDLE void * #define LPARAM long #define UINT unsigned int #endif #define RHDF_SPLITBEFORE 0x01 #define RHDF_SPLITAFTER 0x02 #define RHDF_ENCRYPTED 0x04 #define RHDF_SOLID 0x10 #define RHDF_DIRECTORY 0x20 struct RARHeaderData { char ArcName[260]; 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 DictSize; unsigned int HashType; char Hash[32]; unsigned int Reserved[1014]; }; 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 unrar/encname.hpp0100666000000000000000000000061412176732144011421 0ustar z#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 unrar/errhnd.hpp0100666000000000000000000000376612176732144011310 0ustar z#ifndef _RAR_ERRHANDLER_ #define _RAR_ERRHANDLER_ 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_BADPWD = 11, RARX_USERBREAK = 255 }; class ErrorHandler { private: RAR_EXIT ExitCode; uint ErrCount; bool EnableBreak; bool Silent; bool DoShutdown; public: ErrorHandler(); void Clean(); void MemoryError(); void OpenError(const wchar *FileName); void CloseError(const wchar *FileName); void ReadError(const wchar *FileName); bool AskRepeatRead(const wchar *FileName); void WriteError(const wchar *ArcName,const wchar *FileName); void WriteErrorFAT(const wchar *FileName); bool AskRepeatWrite(const wchar *FileName,bool DiskFull); void SeekError(const wchar *FileName); void GeneralErrMsg(const wchar *fmt,...); void MemoryErrorMsg(); void OpenErrorMsg(const wchar *FileName); void OpenErrorMsg(const wchar *ArcName,const wchar *FileName); void CreateErrorMsg(const wchar *FileName); void CreateErrorMsg(const wchar *ArcName,const wchar *FileName); void CheckLongPathErrMsg(const wchar *FileName); void ReadErrorMsg(const wchar *FileName); void ReadErrorMsg(const wchar *ArcName,const wchar *FileName); void WriteErrorMsg(const wchar *ArcName,const wchar *FileName); void Exit(RAR_EXIT ExitCode); void SetErrorCode(RAR_EXIT Code); RAR_EXIT GetErrorCode() {return(ExitCode);} uint GetErrorCount() {return ErrCount;} void SetSignalHandlers(bool Enable); void Throw(RAR_EXIT Code); void SetSilent(bool Mode) {Silent=Mode;}; void SetShutdown(bool Mode) {DoShutdown=Mode;}; void SysErrMsg(); int GetSystemErrorCode(); void SetSystemErrorCode(int Code); bool UserBreak; bool MainExit; // main() is completed. }; #endif unrar/extinfo.hpp0100666000000000000000000000106512176732144011470 0ustar z#ifndef _RAR_EXTINFO_ #define _RAR_EXTINFO_ bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName); #ifdef _UNIX void SetUnixOwner(Archive &Arc,const wchar *FileName); #endif bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize); void GetStreamNameNTFS(Archive &Arc,wchar *StreamName,size_t MaxSize); #ifdef _WIN_ALL bool SetPrivilege(LPCTSTR PrivName); #endif void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name); void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name); #endif unrar/extract.hpp0100666000000000000000000000364612176732144011475 0ustar z#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); bool ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize); void ExtrPrepareName(CommandData *Cmd,Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize); #ifdef RARDLL bool ExtrDllGetPassword(CommandData *Cmd); #else bool ExtrGetPassword(CommandData *Cmd,Archive &Arc,const wchar *ArcFileName); #endif #if defined(_WIN_ALL) && !defined(SFX_MODULE) void ConvertDosPassword(Archive &Arc,SecPassword &DestPwd); #endif void ExtrCreateDir(CommandData *Cmd,Archive &Arc,const wchar *ArcFileName); bool ExtrCreateFile(CommandData *Cmd,Archive &Arc,File &CurFile); bool CheckUnpVer(Archive &Arc,const wchar *ArcFileName); RarTime StartTime; // time when extraction started ComprDataIO DataIO; 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; wchar ArcName[NM]; SecPassword Password; bool PasswordAll; bool PrevExtracted; wchar DestFileName[NM]; bool PasswordCancelled; public: CmdExtract(CommandData *Cmd); ~CmdExtract(); void DoExtract(CommandData *Cmd); void ExtractArchiveInit(CommandData *Cmd,Archive &Arc); bool ExtractCurrentFile(CommandData *Cmd,Archive &Arc,size_t HeaderSize, bool &Repeat); static void UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize); }; #endif unrar/filcreat.hpp0100666000000000000000000000063012176732144011602 0ustar z#ifndef _RAR_FILECREATE_ #define _RAR_FILECREATE_ bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize, OVERWRITE_MODE Mode,bool *UserReject,int64 FileSize=INT64NDF, RarTime *FileTime=NULL,bool WriteOnly=false); bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize); #ifdef _WIN_ALL bool UpdateExistingShortName(const wchar *Name); #endif #endif unrar/file.hpp0100666000000000000000000000572112176732144010736 0ustar z#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}; 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: 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: wchar FileName[NM]; FILE_ERRORTYPE ErrorType; public: File(); virtual ~File(); void operator = (File &SrcFile); bool Open(const wchar *Name,uint Mode=FMF_READ); void TOpen(const wchar *Name); bool WOpen(const wchar *Name); bool Create(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD); void TCreate(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD); bool WCreate(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD); bool Close(); void Flush(); bool Delete(); bool Rename(const wchar *NewName); void Write(const void *Data,size_t Size); virtual int Read(void *Data,size_t Size); int DirectRead(void *Data,size_t Size); virtual void Seek(int64 Offset,int Method); bool RawSeek(int64 Offset,int Method); virtual int64 Tell(); void Prealloc(int64 Size); byte GetByte(); void PutByte(byte Byte); bool Truncate(); void SetOpenFileTime(RarTime *ftm,RarTime *ftc=NULL,RarTime *fta=NULL); void SetCloseFileTime(RarTime *ftm,RarTime *fta=NULL); static void SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta); void GetOpenFileTime(RarTime *ft); bool IsOpened() {return(hFile!=BAD_HANDLE);}; int64 FileLength(); void SetHandleType(FILE_HANDLETYPE Type) {HandleType=Type;} FILE_HANDLETYPE GetHandleType() {return HandleType;} bool IsDevice(); static bool RemoveCreated(); FileHandle GetHandle() {return hFile;} void SetHandle(FileHandle Handle) {Close();hFile=Handle;} void SetIgnoreReadErrors(bool Mode) {IgnoreReadErrors=Mode;} int64 Copy(File &Dest,int64 Length=INT64NDF); void SetAllowDelete(bool Allow) {AllowDelete=Allow;} void SetExceptions(bool Allow) {AllowExceptions=Allow;} #ifdef _WIN_ALL void RemoveSequentialFlag() {NoSequentialRead=true;} #endif }; #endif unrar/filefn.hpp0100666000000000000000000000232012176732144011252 0ustar z#ifndef _RAR_FILEFN_ #define _RAR_FILEFN_ enum MKDIR_CODE {MKDIR_SUCCESS,MKDIR_ERROR,MKDIR_BADPATH}; MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr); bool CreatePath(const wchar *Path,bool SkipLastName); void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta); bool IsRemovable(const wchar *Name); #ifndef SFX_MODULE int64 GetFreeDisk(const wchar *Name); #endif bool FileExist(const wchar *Name); bool WildFileExist(const wchar *Name); bool IsDir(uint Attr); bool IsUnreadable(uint Attr); bool IsLink(uint Attr); void SetSFXMode(const wchar *FileName); void EraseDiskContents(const wchar *FileName); bool IsDeleteAllowed(uint FileAttr); void PrepareToDelete(const wchar *Name); uint GetFileAttr(const wchar *Name); bool SetFileAttr(const wchar *Name,uint Attr); enum CALCFSUM_FLAGS {CALCFSUM_SHOWTEXT=1,CALCFSUM_SHOWALL=2,CALCFSUM_CURPOS=4}; void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size=INT64NDF,uint Flags=0); bool RenameFile(const wchar *SrcName,const wchar *DestName); bool DelFile(const wchar *Name); bool DelDir(const wchar *Name); #if defined(_WIN_ALL) && !defined(SFX_MODULE) bool SetFileCompression(const wchar *Name,bool State); #endif #endif unrar/filestr.hpp0100666000000000000000000000041712176732144011464 0ustar z#ifndef _RAR_FILESTR_ #define _RAR_FILESTR_ bool ReadTextFile( const wchar *Name, StringList *List, bool Config, bool AbortOnError=false, RAR_CHARSET SrcCharset=RCH_DEFAULT, bool Unquote=false, bool SkipComments=false, bool ExpandEnvStr=false ); #endif unrar/find.hpp0100666000000000000000000000162312176732144010734 0ustar z#ifndef _RAR_FINDDATA_ #define _RAR_FINDDATA_ enum FINDDATA_FLAGS { FDDF_SECONDDIR=1 // Second encounter of same directory in SCAN_GETDIRSTWICE ScanTree mode. }; struct FindData { wchar Name[NM]; uint64 Size; uint FileAttr; bool IsDir; bool IsLink; RarTime mtime; RarTime ctime; RarTime atime; #ifdef _WIN_ALL FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; #endif uint Flags; bool Error; }; class FindFile { private: #ifdef _WIN_ALL static HANDLE Win32Find(HANDLE hFind,const wchar *Mask,FindData *fd); #endif wchar FindMask[NM]; bool FirstCall; #ifdef _WIN_ALL HANDLE hFind; #else DIR *dirp; #endif public: FindFile(); ~FindFile(); void SetMask(const wchar *Mask); bool Next(FindData *fd,bool GetSymLink=false); static bool FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink=false); }; #endif unrar/getbits.hpp0100666000000000000000000000326512176732144011461 0ustar z#ifndef _RAR_GETBITS_ #define _RAR_GETBITS_ class BitInput { public: enum BufferSize {MAX_SIZE=0x8000}; // Size of input buffer. int InAddr; // Curent byte position in the buffer. int InBit; // Current bit position in the current byte. bool ExternalBuffer; public: BitInput(bool AllocBuffer); ~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); } // Return 32 bits from current position in the buffer. // Bit at (InAddr,InBit) has the highest position in returning data. uint getbits32() { uint BitField=(uint)InBuf[InAddr] << 24; BitField|=(uint)InBuf[InAddr+1] << 16; BitField|=(uint)InBuf[InAddr+2] << 8; BitField|=(uint)InBuf[InAddr+3]; BitField <<= InBit; BitField|=(uint)InBuf[InAddr+4] >> (8-InBit); return(BitField & 0xffffffff); } void faddbits(uint Bits); uint fgetbits(); // 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); } void SetExternalBuffer(byte *Buf); }; #endif unrar/global.hpp0100666000000000000000000000024112176732144011247 0ustar z#ifndef _RAR_GLOBAL_ #define _RAR_GLOBAL_ #ifdef INCLUDEGLOBAL #define EXTVAR #else #define EXTVAR extern #endif EXTVAR ErrorHandler ErrHandler; #endif unrar/hash.hpp0100666000000000000000000000174612176732144010745 0ustar z#ifndef _RAR_DATAHASH_ #define _RAR_DATAHASH_ enum HASH_TYPE {HASH_NONE,HASH_RAR14,HASH_CRC32,HASH_BLAKE2}; struct HashValue { void Init(HASH_TYPE Type); bool operator == (const HashValue &cmp); bool operator != (const HashValue &cmp) {return !(*this==cmp);} HASH_TYPE Type; union { uint CRC32; byte Digest[SHA256_DIGEST_SIZE]; }; }; #ifdef RAR_SMP class ThreadPool; class DataHash; #endif class DataHash { private: HASH_TYPE HashType; uint CurCRC32; blake2sp_state blake2ctx; #ifdef RAR_SMP ThreadPool *ThPool; uint MaxThreads; // Upper limit for maximum threads to prevent wasting threads in pool. static const uint MaxHashThreads=8; #endif public: DataHash(); ~DataHash(); void Init(HASH_TYPE Type,uint MaxThreads); void Update(const void *Data,size_t DataSize); void Result(HashValue *Result); uint GetCRC32(); bool Cmp(HashValue *CmpValue,byte *Key); HASH_TYPE Type() {return HashType;} }; #endif unrar/headers.hpp0100666000000000000000000002137412176732144011434 0ustar z#ifndef _RAR_HEADERS_ #define _RAR_HEADERS_ #define SIZEOF_MARKHEAD3 7 // Size of RAR 4.x archive mark header. #define SIZEOF_MAINHEAD14 7 // Size of RAR 1.4 main archive header. #define SIZEOF_MAINHEAD3 13 // Size of RAR 4.x main archive header. #define SIZEOF_FILEHEAD14 21 // Size of RAR 1.4 file header. #define SIZEOF_FILEHEAD3 32 // Size of RAR 3.0 file header. #define SIZEOF_SHORTBLOCKHEAD 7 #define SIZEOF_LONGBLOCKHEAD 11 #define SIZEOF_SUBBLOCKHEAD 14 #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 VER_PACK 29 #define VER_PACK5 0 #define VER_UNPACK 29 #define VER_UNPACK5 0 #define MHD_VOLUME 0x0001U // Old style main archive comment embed into main archive header. Must not // be used in new archives anymore. #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 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 // For non-file subheaders it denotes 'subblock having a parent file' flag. #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 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 { // RAR 5.0 header types. HEAD_MARK=0x00, HEAD_MAIN=0x01, HEAD_FILE=0x02, HEAD_SERVICE=0x03, HEAD_CRYPT=0x04, HEAD_ENDARC=0x05, HEAD_UNKNOWN=0xff, // RAR 1.5 - 4.x header types. HEAD3_MARK=0x72,HEAD3_MAIN=0x73,HEAD3_FILE=0x74,HEAD3_CMT=0x75, HEAD3_AV=0x76,HEAD3_OLDSERVICE=0x77,HEAD3_PROTECT=0x78,HEAD3_SIGN=0x79, HEAD3_SERVICE=0x7a,HEAD3_ENDARC=0x7b }; enum { EA_HEAD=0x100,UO_HEAD=0x101,MAC_HEAD=0x102,BEEA_HEAD=0x103, NTACL_HEAD=0x104,STREAM_HEAD=0x105 }; // Internal implementation, depends on archive format version. enum HOST_SYSTEM { // RAR 5.0 host OS HOST5_WINDOWS=0,HOST5_UNIX=1, // RAR 3.0 host OS. HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4, HOST_BEOS=5,HOST_MAX }; // Unified archive format independent implementation. enum HOST_SYSTEM_TYPE { HSYS_WINDOWS, HSYS_UNIX, HSYS_UNKNOWN }; // We also use these values in extra field, so do not modify them. enum FILE_SYSTEM_REDIRECT { FSREDIR_NONE=0, FSREDIR_UNIXSYMLINK, FSREDIR_WINSYMLINK, FSREDIR_JUNCTION, FSREDIR_HARDLINK, FSREDIR_FILECOPY }; #define SUBHEAD_TYPE_CMT L"CMT" #define SUBHEAD_TYPE_QOPEN L"QO" #define SUBHEAD_TYPE_ACL L"ACL" #define SUBHEAD_TYPE_STREAM L"STM" #define SUBHEAD_TYPE_UOWNER L"UOW" #define SUBHEAD_TYPE_AV L"AV" #define SUBHEAD_TYPE_RR L"RR" #define SUBHEAD_TYPE_OS2EA L"EA2" /* new file inherits a subblock when updating a host file */ #define SUBHEAD_FLAGS_INHERITED 0x80000000 #define SUBHEAD_FLAGS_CMT_UNICODE 0x00000001 struct MarkHeader { byte Mark[8]; // Following fields are virtual and not present in real blocks. uint HeadSize; }; struct BaseBlock { uint HeadCRC; // 'ushort' for RAR 1.5. HEADER_TYPE HeaderType; // 1 byte for RAR 1.5. uint Flags; // 'ushort' for RAR 1.5. uint HeadSize; // 'ushort' for RAR 1.5, up to 2 MB for RAR 5.0. bool SkipIfUnknown; void Reset() { SkipIfUnknown=false; } }; struct BlockHeader:BaseBlock { uint DataSize; }; struct MainHeader:BaseBlock { ushort HighPosAV; uint PosAV; bool CommentInHeader; bool PackComment; // For RAR 1.4 archive format only. bool Locator; uint64 QOpenOffset; // Offset of quick list record. uint64 QOpenMaxSize; // Maximum size of QOpen offset in locator extra field. uint64 RROffset; // Offset of recovery record. uint64 RRMaxSize; // Maximum size of RR offset in locator extra field. void Reset(); }; struct FileHeader:BlockHeader { byte HostOS; byte UnpVer; byte Method; union { uint FileAttr; uint SubFlags; }; wchar FileName[NM]; Array SubData; RarTime mtime; RarTime ctime; RarTime atime; int64 PackSize; int64 UnpSize; int64 MaxSize; // Reserve size bytes for vint of this size. HashValue FileHash; uint FileFlags; bool SplitBefore; bool SplitAfter; bool UnknownUnpSize; bool Encrypted; CRYPT_METHOD CryptMethod; bool SaltSet; byte Salt[SIZE_SALT50]; byte InitV[SIZE_INITV]; bool UsePswCheck; byte PswCheck[SIZE_PSWCHECK]; // Use HMAC calculated from HashKey and checksum instead of plain checksum. bool UseHashKey; // Key to convert checksum to HMAC. Derived from password with PBKDF2 // using additional iterations. byte HashKey[SHA256_DIGEST_SIZE]; uint Lg2Count; // Log2 of PBKDF2 repetition count. bool Solid; bool Dir; bool CommentInHeader; // RAR 2.0 file comment. bool Version; // name.ext;ver file name containing the version number. size_t WinSize; bool Inherited; // New file inherits a subblock when updating a host file (for subblocks only). // 'true' if file sizes use 8 bytes instead of 4. Not used in RAR 5.0. bool LargeFile; // 'true' for HEAD_SERVICE block, which is a child of preceding file block. // RAR 4.x uses 'solid' flag to indicate child subheader blocks in archives. bool SubBlock; HOST_SYSTEM_TYPE HSType; FILE_SYSTEM_REDIRECT RedirType; wchar RedirName[NM]; bool DirTarget; bool UnixOwnerSet,UnixOwnerNumeric,UnixGroupNumeric; char UnixOwnerName[256],UnixGroupName[256]; #ifdef _UNIX uid_t UnixOwnerID; gid_t UnixGroupID; #else // Need these Unix fields in Windows too for 'list' command. uint UnixOwnerID; uint UnixGroupID; #endif void Reset(size_t SubDataSize=0); bool CmpName(const wchar *Name) { return(wcscmp(FileName,Name)==0); } FileHeader& operator = (FileHeader &hd); }; struct EndArcHeader:BaseBlock { // Optional CRC32 of entire archive up to start of EndArcHeader block. // Present in RAR 4.x archives if EARC_DATACRC flag is set. uint ArcDataCRC; uint VolNumber; // Optional number of current volume. // 7 additional zero bytes can be stored here if EARC_REVSPACE is set. bool NextVolume; // Not last volume. bool DataCRC; bool RevSpace; bool StoreVolNumber; void Reset() { BaseBlock::Reset(); NextVolume=false; DataCRC=false; RevSpace=false; StoreVolNumber=false; } }; struct CryptHeader:BaseBlock { bool UsePswCheck; uint Lg2Count; // Log2 of PBKDF2 repetition count. byte Salt[SIZE_SALT50]; byte PswCheck[SIZE_PSWCHECK]; }; // SubBlockHeader and its successors were used in RAR 2.x format. // RAR 4.x uses FileHeader with HEAD_SERVICE HeaderType 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[256]; char GroupName[256]; }; struct EAHeader:SubBlockHeader { uint UnpSize; byte UnpVer; byte Method; uint EACRC; }; struct StreamHeader:SubBlockHeader { uint UnpSize; byte UnpVer; byte Method; uint StreamCRC; ushort StreamNameSize; char StreamName[260]; }; struct MacFInfoHeader:SubBlockHeader { uint fileType; uint fileCreator; }; #endif unrar/headers5.hpp0100666000000000000000000001010412176732144011506 0ustar z#ifndef _RAR_HEADERS5_ #define _RAR_HEADERS5_ #define SIZEOF_MARKHEAD5 8 // RAR 5.0 signature length. #define SIZEOF_SHORTBLOCKHEAD5 7 // Smallest RAR 5.0 block size. // RAR 5.0 block flags common for all blocks. // Additional extra area is present in the end of block header. #define HFL_EXTRA 0x0001 // Additional data area is present in the end of block header. #define HFL_DATA 0x0002 // Unknown blocks with this flag must be skipped when updating an archive. #define HFL_SKIPIFUNKNOWN 0x0004 // Data area of this block is continuing from previous volume. #define HFL_SPLITBEFORE 0x0008 // Data area of this block is continuing in next volume. #define HFL_SPLITAFTER 0x0010 // Block depends on preceding file block. #define HFL_CHILD 0x0020 // Preserve a child block if host is modified. #define HFL_INHERITED 0x0040 // RAR 5.0 main archive header specific flags. #define MHFL_VOLUME 0x0001 // Volume. #define MHFL_VOLNUMBER 0x0002 // Volume number field is present. True for all volumes except first. #define MHFL_SOLID 0x0004 // Solid archive. #define MHFL_PROTECT 0x0008 // Recovery record is present. #define MHFL_LOCK 0x0010 // Locked archive. // RAR 5.0 file header specific flags. #define FHFL_DIRECTORY 0x0001 // Directory. #define FHFL_UTIME 0x0002 // Time field in Unix format is present. #define FHFL_CRC32 0x0004 // CRC32 field is present. #define FHFL_UNPUNKNOWN 0x0008 // Unknown unpacked size. // RAR 5.0 end of archive header specific flags. #define EHFL_NEXTVOLUME 0x0001 // Not last volume. // RAR 5.0 archive encryption header specific flags. #define CHFL_CRYPT_PSWCHECK 0x0001 // Password check data is present. // RAR 5.0 file compression flags. #define FCI_ALGO_BIT0 0x0001 // Version of compression algorithm. #define FCI_ALGO_BIT1 0x0002 // 0 .. 63. #define FCI_ALGO_BIT2 0x0004 #define FCI_ALGO_BIT3 0x0008 #define FCI_ALGO_BIT4 0x0010 #define FCI_ALGO_BIT5 0x0020 #define FCI_SOLID 0x0040 // Solid flag. #define FCI_METHOD_BIT0 0x0080 // Compression method. #define FCI_METHOD_BIT1 0x0100 // 0 .. 5 (6 and 7 are not used). #define FCI_METHOD_BIT2 0x0200 #define FCI_DICT_BIT0 0x0400 // Dictionary size. #define FCI_DICT_BIT1 0x0800 // 128 KB .. 4 GB. #define FCI_DICT_BIT2 0x1000 #define FCI_DICT_BIT3 0x2000 // Main header extra field values. #define MHEXTRA_LOCATOR 0x01 // Position of quick list and other blocks. // Flags for MHEXTRA_LOCATOR. #define MHEXTRA_LOCATOR_QLIST 0x01 // Quick open offset is present. #define MHEXTRA_LOCATOR_RR 0x02 // Recovery record offset is present. // File and service header extra field values. #define FHEXTRA_CRYPT 0x01 // Encryption parameters. #define FHEXTRA_HASH 0x02 // File hash. #define FHEXTRA_HTIME 0x03 // High precision file time. #define FHEXTRA_VERSION 0x04 // File version information. #define FHEXTRA_REDIR 0x05 // File system redirection (links, etc.). #define FHEXTRA_UOWNER 0x06 // Unix owner and group information. #define FHEXTRA_SUBDATA 0x07 // Service header subdata array. // Hash type values for FHEXTRA_HASH. #define FHEXTRA_HASH_BLAKE2 0x00 // Flags for FHEXTRA_HTIME. #define FHEXTRA_HTIME_UNIXTIME 0x01 // Use Unix time_t format. #define FHEXTRA_HTIME_MTIME 0x02 // mtime is present. #define FHEXTRA_HTIME_CTIME 0x04 // ctime is present. #define FHEXTRA_HTIME_ATIME 0x08 // atime is present. // Flags for FHEXTRA_CRYPT. #define FHEXTRA_CRYPT_PSWCHECK 0x01 // Store password check data. #define FHEXTRA_CRYPT_HASHMAC 0x02 // Use MAC for unpacked data checksums. // Flags for FHEXTRA_REDIR. #define FHEXTRA_REDIR_DIR 0x01 // Link target is directory. // Flags for FHEXTRA_UOWNER. #define FHEXTRA_UOWNER_UNAME 0x01 // User name string is present. #define FHEXTRA_UOWNER_GNAME 0x02 // Group name string is present. #define FHEXTRA_UOWNER_NUMUID 0x04 // Numeric user ID is present. #define FHEXTRA_UOWNER_NUMGID 0x08 // Numeric group ID is present. #endif unrar/isnt.hpp0100666000000000000000000000032712176732144010771 0ustar z#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 unrar/list.hpp0100666000000000000000000000012312176732144010761 0ustar z#ifndef _RAR_LIST_ #define _RAR_LIST_ void ListArchive(CommandData *Cmd); #endif unrar/loclang.hpp0100666000000000000000000006111312176732144011433 0ustar z#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 - - " #define MUNRARTitle1 "\nUsage: unrar - - " #define MRARTitle2 "\n <@listfiles...> " #define MCHelpCmd "\n\n" #define MCHelpCmdA "\n a Add files to archive" #define MCHelpCmdC "\n c Add archive 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 without archived paths" #define MCHelpCmdF "\n f Freshen files in archive" #define MCHelpCmdI "\n i[par]= Find string in archives" #define MCHelpCmdK "\n k Lock archive" #define MCHelpCmdL "\n l[t[a],b] List archive contents [technical[all], bare]" #define MCHelpCmdM "\n m[f] Move to archive [files only]" #define MCHelpCmdP "\n p Print file to stdout" #define MCHelpCmdR "\n r Repair archive" #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[a],b] Verbosely list archive contents [technical[all],bare]" #define MCHelpCmdX "\n x Extract files with full path" #define MCHelpSw "\n\n" #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 Set path inside archive" #define MCHelpSwAS "\n as Synchronize archive contents" #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[+] 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 MCHelpSwHT "\n ht[b|c] Select hash type [BLAKE2,CRC32] for file checksum" #define MCHelpSwIDP "\n id[c,d,p,q] Disable messages" #define MCHelpSwIEML "\n ieml[addr] Send archive by email" #define MCHelpSwIERR "\n ierr Send all messages to stderr" #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 MCHelpSwMA "\n ma[4|5] Specify a version of archiving format" #define MCHelpSwMC "\n mc Set advanced compression parameters" #define MCHelpSwMD "\n md[k,m,g] Dictionary size in KB, MB or GB" #define MCHelpSwMS "\n ms[ext;ext] Specify file types to store" #define MCHelpSwMT "\n mt Set the number of threads" #define MCHelpSwN "\n n Additionally filter included files" #define MCHelpSwNa "\n n@ Read additional filter masks from stdin" #define MCHelpSwNal "\n n@ Read additional filter masks from list file" #define MCHelpSwO "\n o[+|-] Set the overwrite mode" #define MCHelpSwOC "\n oc Set NTFS Compressed attribute" #define MCHelpSwOH "\n oh Save hard links as the link instead of the file" #define MCHelpSwOI "\n oi[0-4][:min] Save identical files as references" #define MCHelpSwOL "\n ol Save symbolic links as the link instead of the file" #define MCHelpSwOR "\n or Rename files automatically" #define MCHelpSwOS "\n os Save NTFS streams" #define MCHelpSwOW "\n ow Save or restore file owner and group" #define MCHelpSwP "\n p[password] Set password" #define MCHelpSwPm "\n p- Do not query password" #define MCHelpSwQO "\n qo[-|+] Add quick open information [none|force]" #define MCHelpSwR "\n r Recurse subdirectories" #define MCHelpSwRm "\n r- Disable recursion" #define MCHelpSwR0 "\n r0 Recurse subdirectories for wildcard names only" #define MCHelpSwRI "\n ri

[:] 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[,v[-],e] Create solid archive" #define MCHelpSwSm "\n s- Disable solid archiving" #define MCHelpSwSC "\n sc[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 Process files with size less than specified" #define MCHelpSwSM "\n sm 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