diff --git a/arccmt.cpp b/arccmt.cpp index 032dbf4..92a3896 100644 --- a/arccmt.cpp +++ b/arccmt.cpp @@ -34,7 +34,7 @@ bool Archive::GetComment(Array *CmtData) #ifndef SFX_MODULE // Old style (RAR 2.9) comment header embedded into the main // archive header. - if (BrokenHeader) + if (BrokenHeader || CommHead.HeadSize *CmtData) #else UnpCmtLength=GetByte(); UnpCmtLength+=(GetByte()<<8); + if (CmtLength<2) + return false; CmtLength-=2; DataIO.SetCmt13Encryption(); CommHead.UnpVer=15; diff --git a/archive.hpp b/archive.hpp index 76c2430..4edb481 100644 --- a/archive.hpp +++ b/archive.hpp @@ -84,7 +84,7 @@ class Archive:public File void AddSubData(byte *SrcData,uint64 DataSize,File *SrcFile, const wchar *Name,uint Flags); bool ReadSubData(Array *UnpData,File *DestFile); - HEADER_TYPE GetHeaderType() {return CurHeaderType;}; + HEADER_TYPE GetHeaderType() {return CurHeaderType;} RAROptions* GetRAROptions() {return Cmd;} void SetSilentOpen(bool Mode) {SilentOpen=Mode;} #if 0 diff --git a/arcread.cpp b/arcread.cpp index 9be8455..c299d3d 100644 --- a/arcread.cpp +++ b/arcread.cpp @@ -204,7 +204,7 @@ size_t Archive::ReadHeader15() if (ShortBlock.HeaderType==HEAD_MAIN && (ShortBlock.Flags & MHD_COMMENT)!=0) { // Old style (up to RAR 2.9) main archive comment embedded into - // the main archive header found. While we can read the entire + // the main archive header found. While we can read the entire // ShortBlock.HeadSize here and remove this part of "if", it would be // waste of memory, because we'll read and process this comment data // in other function anyway and we do not need them here now. @@ -230,7 +230,7 @@ size_t Archive::ReadHeader15() Encrypted=(MainHead.Flags & MHD_PASSWORD)!=0; Signed=MainHead.PosAV!=0 || MainHead.HighPosAV!=0; MainHead.CommentInHeader=(MainHead.Flags & MHD_COMMENT)!=0; - + // Only for encrypted 3.0+ archives. 2.x archives did not have this // flag, so for non-encrypted archives, we'll set it later based on // file attributes. @@ -257,7 +257,7 @@ size_t Archive::ReadHeader15() 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(); @@ -282,7 +282,7 @@ size_t Archive::ReadHeader15() { case 13: hd->CryptMethod=CRYPT_RAR13; break; case 15: hd->CryptMethod=CRYPT_RAR15; break; - case 20: + case 20: case 26: hd->CryptMethod=CRYPT_RAR20; break; default: hd->CryptMethod=CRYPT_RAR30; break; } @@ -304,7 +304,7 @@ size_t Archive::ReadHeader15() } hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0; - + hd->LargeFile=(hd->Flags & LHD_LARGE)!=0; uint HighPackSize,HighUnpSize; @@ -314,7 +314,7 @@ size_t Archive::ReadHeader15() HighUnpSize=Raw.Get4(); hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff); } - else + else { HighPackSize=HighUnpSize=0; // UnpSize equal to 0xffffffff without LHD_LARGE flag indicates @@ -509,7 +509,7 @@ size_t Archive::ReadHeader15() NextBlockPos+=Raw.Get4(); break; } - + ushort HeaderCRC=Raw.GetCRC15(false); // Old AV header does not have header CRC properly set. @@ -644,7 +644,7 @@ size_t Archive::ReadHeader50() BrokenHeaderMsg(); return 0; } - + Raw.Read(SizeToRead); if (Raw.Size()PackSize=DataSize; hd->FileFlags=(uint)Raw.GetV(); hd->UnpSize=Raw.GetV(); - + hd->UnknownUnpSize=(hd->FileFlags & FHFL_UNPUNKNOWN)!=0; if (hd->UnknownUnpSize) hd->UnpSize=INT64NDF; @@ -882,7 +882,7 @@ size_t Archive::ReadHeader50() RecoverySize=Header.RecSectionSize*Header.RecCount; } #endif - + if (BadCRC) // Add the file name to broken header message displayed above. uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName); } @@ -1307,7 +1307,7 @@ void Archive::ConvertAttributes() if (mask == (mode_t) -1) { - // umask call returns the current umask value. Argument (022) is not + // umask call returns the current umask value. Argument (022) is not // really important here. mask = umask(022); @@ -1384,8 +1384,8 @@ void Archive::ConvertFileHeader(FileHeader *hd) // ':' 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 + // 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='_'; diff --git a/cmddata.cpp b/cmddata.cpp index 2ab5e3f..7b92686 100644 --- a/cmddata.cpp +++ b/cmddata.cpp @@ -1,5 +1,8 @@ #include "rar.hpp" +#include "cmdfilter.cpp" +#include "cmdmix.cpp" + CommandData::CommandData() { Init(); @@ -130,7 +133,7 @@ void CommandData::ParseArg(wchar *Arg) FindData FileData; bool Found=FindFile::FastFind(Arg,&FileData); if ((!Found || ListMode==RCLM_ACCEPT_LISTS) && - ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg)) + ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg+1)) { FileLists=true; @@ -411,9 +414,9 @@ void CommandData::ProcessSwitch(const wchar *Switch) wcsncpyz(LogName,Switch[4]!=0 ? Switch+4:DefLogName,ASIZE(LogName)); break; } - if (wcsicomp(Switch+1,L"SND")==0) + if (wcsnicomp(Switch+1,L"SND",3)==0) { - Sound=true; + Sound=Switch[4]=='-' ? SOUND_NOTIFY_OFF : SOUND_NOTIFY_ON; break; } if (wcsicomp(Switch+1,L"ERR")==0) @@ -809,40 +812,16 @@ void CommandData::ProcessSwitch(const wchar *Switch) ArcTime=ARCTIME_LATEST; break; case 'O': - switch(toupperw(Switch[2])) - { - case 'M': FileMtimeBefore.SetAgeText(Switch+3); break; - case 'C': FileCtimeBefore.SetAgeText(Switch+3); break; - case 'A': FileAtimeBefore.SetAgeText(Switch+3); break; - default: FileMtimeBefore.SetAgeText(Switch+2); break; - } + SetTimeFilters(Switch+2,true,true); break; case 'N': - switch(toupperw(Switch[2])) - { - case 'M': FileMtimeAfter.SetAgeText(Switch+3); break; - case 'C': FileCtimeAfter.SetAgeText(Switch+3); break; - case 'A': FileAtimeAfter.SetAgeText(Switch+3); break; - default: FileMtimeAfter.SetAgeText(Switch+2); break; - } + SetTimeFilters(Switch+2,false,true); break; case 'B': - switch(toupperw(Switch[2])) - { - case 'M': FileMtimeBefore.SetIsoText(Switch+3); break; - case 'C': FileCtimeBefore.SetIsoText(Switch+3); break; - case 'A': FileAtimeBefore.SetIsoText(Switch+3); break; - default: FileMtimeBefore.SetIsoText(Switch+2); break; - } + SetTimeFilters(Switch+2,true,false); break; case 'A': - switch(toupperw(Switch[2])) - { - case 'M': FileMtimeAfter.SetIsoText(Switch+3); break; - case 'C': FileCtimeAfter.SetIsoText(Switch+3); break; - case 'A': FileAtimeAfter.SetIsoText(Switch+3); break; - default: FileMtimeAfter.SetIsoText(Switch+2); break; - } + SetTimeFilters(Switch+2,false,false); break; case 'S': { @@ -950,317 +929,6 @@ void CommandData::BadSwitch(const wchar *Switch) #endif -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[80]; - if (RARVER_BETA!=0) - swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA); - else - swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR); -#if defined(_WIN_32) || defined(_WIN_64) - wcsncatz(Version,L" ",ASIZE(Version)); -#endif -#ifdef _WIN_32 - wcsncatz(Version,St(Mx86),ASIZE(Version)); -#endif -#ifdef _WIN_64 - wcsncatz(Version,St(Mx64),ASIZE(Version)); -#endif - if (PrintVersion) - { - mprintf(L"%s",Version); - exit(0); - } - mprintf(St(MUCopyright),Version,RARVER_YEAR); -#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 wcscmp(i1,i2)==0; -#endif -} - -void CommandData::OutHelp(RAR_EXIT ExitCode) -{ -#if !defined(SILENT) - OutTitle(); - static MSGID Help[]={ -#ifdef SFX_MODULE - // Console SFX switches definition. - MCHelpCmd,MSHelpCmdE,MSHelpCmdT,MSHelpCmdV -#else - // 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,MCHelpSwOL,MCHelpSwOR,MCHelpSwOW,MCHelpSwP, - MCHelpSwPm,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSL,MCHelpSwSM, - MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU, - MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal, - MCHelpSwY -#endif - }; - - for (uint I=0;IRewind(); - while (Args->GetString(CurMask,ASIZE(CurMask))) - { - 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 - { - // REMOVED, we want -npath\* to match empty folders too. - // If mask has wildcards in name part and does not have the trailing - // '\' character, we cannot use it for directories. - - // if (IsWildcard(PointToName(CurMask))) - // continue; - } - } - 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 - // with -x. When archiving with -x, directory matched by "dirmask\" - // is excluded from further scanning. - - if (DirMask) - wcsncatz(CurMask,L"*",ASIZE(CurMask)); - } - -#ifndef SFX_MODULE - if (CheckFullPath && IsFullPath(CurMask)) - { - // We do not need to do the special "*\" processing here, because - // unlike the "else" part of this "if", now we convert names to full - // format, so they all include the path, which is matched by "*\" - // correctly. Moreover, removing "*\" from mask would break - // the comparison, because now all names have the path. - - if (*FullName==0) - ConvertNameToFull(CheckName,FullName,ASIZE(FullName)); - if (CmpName(CurMask,FullName,MatchMode)) - return true; - } - else -#endif - { - wchar NewName[NM+2],*CurName=Name; - - // Important to convert before "*\" check below, so masks like - // d:*\something are processed properly. - wchar *CmpMask=ConvertPath(CurMask,NULL,0); - - if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1])) - { - // We want "*\name" to match 'name' not only in subdirectories, - // but also in the current directory. We convert the name - // 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(CmpMask,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 &ftm,RarTime &ftc,RarTime &fta) -{ - if (FileMtimeBefore.IsSet() && ftm>=FileMtimeBefore) - return true; - if (FileMtimeAfter.IsSet() && ftm<=FileMtimeAfter) - return true; - if (FileCtimeBefore.IsSet() && ftc>=FileCtimeBefore) - return true; - if (FileCtimeAfter.IsSet() && ftc<=FileCtimeAfter) - return true; - if (FileAtimeBefore.IsSet() && fta>=FileAtimeBefore) - return true; - if (FileAtimeAfter.IsSet() && fta<=FileAtimeAfter) - 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, - wchar *MatchedArg,uint MatchedArgSize) -{ - if (MatchedArg!=NULL && MatchedArgSize>0) - *MatchedArg=0; -// if (wcslen(FileHead.FileName)>=NM) -// return 0; - bool Dir=FileHead.Dir; - if (ExclCheck(FileHead.FileName,Dir,false,true)) - return 0; -#ifndef SFX_MODULE - if (TimeCheck(FileHead.mtime,FileHead.ctime,FileHead.atime)) - 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; - if (MatchedArg!=NULL) - wcsncpyz(MatchedArg,ArgName,MatchedArgSize); - return StringCount; - } - return 0; -} - - void CommandData::ProcessCommand() { #ifndef SFX_MODULE diff --git a/cmddata.hpp b/cmddata.hpp index 55853bc..bf0efa6 100644 --- a/cmddata.hpp +++ b/cmddata.hpp @@ -6,6 +6,8 @@ enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS}; +enum IS_PROCESS_FILE_FLAGS {IPFF_EXCLUDE_PARENT=1}; + class CommandData:public RAROptions { private: @@ -13,6 +15,9 @@ class CommandData:public RAROptions void ProcessSwitch(const wchar *Switch); void BadSwitch(const wchar *Switch); uint GetExclAttr(const wchar *Str); +#if !defined(SFX_MODULE) + void SetTimeFilters(const wchar *Mod,bool Before,bool Age); +#endif bool FileLists; bool NoMoreSwitches; @@ -37,8 +42,8 @@ class CommandData:public RAROptions bool TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta); bool SizeCheck(int64 Size); bool AnyFiltersActive(); - int IsProcessFile(FileHeader &FileHead,bool *ExactMatch=NULL,int MatchType=MATCH_WILDSUBPATH, - wchar *MatchedArg=NULL,uint MatchedArgSize=0); + int IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType, + bool Flags,wchar *MatchedArg,uint MatchedArgSize); void ProcessCommand(); void AddArcName(const wchar *Name); bool GetArcName(wchar *Name,int MaxSize); diff --git a/cmdfilter.cpp b/cmdfilter.cpp new file mode 100644 index 0000000..20660cb --- /dev/null +++ b/cmdfilter.cpp @@ -0,0 +1,299 @@ +// Return 'true' if we need to exclude the file from processing as result +// of -x switch. If CheckInclList is true, we also check the file against +// the include list created with -n switch. +bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList) +{ + if (CheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH)) + return true; + if (!CheckInclList || InclArgs.ItemsCount()==0) + return false; + if (CheckArgs(&InclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH)) + return false; + return true; +} + + +bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode) +{ + wchar *Name=ConvertPath(CheckName,NULL,0); + wchar FullName[NM]; + wchar CurMask[NM]; + *FullName=0; + Args->Rewind(); + while (Args->GetString(CurMask,ASIZE(CurMask))) + { + 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 + { + // REMOVED, we want -npath\* to match empty folders too. + // If mask has wildcards in name part and does not have the trailing + // '\' character, we cannot use it for directories. + + // if (IsWildcard(PointToName(CurMask))) + // continue; + } + } + 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 + // with -x. When archiving with -x, directory matched by "dirmask\" + // is excluded from further scanning. + + if (DirMask) + wcsncatz(CurMask,L"*",ASIZE(CurMask)); + } + +#ifndef SFX_MODULE + if (CheckFullPath && IsFullPath(CurMask)) + { + // We do not need to do the special "*\" processing here, because + // unlike the "else" part of this "if", now we convert names to full + // format, so they all include the path, which is matched by "*\" + // correctly. Moreover, removing "*\" from mask would break + // the comparison, because now all names have the path. + + if (*FullName==0) + ConvertNameToFull(CheckName,FullName,ASIZE(FullName)); + if (CmpName(CurMask,FullName,MatchMode)) + return true; + } + else +#endif + { + wchar NewName[NM+2],*CurName=Name; + + // Important to convert before "*\" check below, so masks like + // d:*\something are processed properly. + wchar *CmpMask=ConvertPath(CurMask,NULL,0); + + if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1])) + { + // We want "*\name" to match 'name' not only in subdirectories, + // but also in the current directory. We convert the name + // 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(CmpMask,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 + + + + +#if !defined(SFX_MODULE) +void CommandData::SetTimeFilters(const wchar *Mod,bool Before,bool Age) +{ + bool ModeOR=false,TimeMods=false; + const wchar *S=Mod; + for (;wcschr(L"MCAOmcao",*S)!=NULL;S++) + if (*S=='o' || *S=='O') + ModeOR=true; + else + TimeMods=true; + + if (!TimeMods) + Mod=L"m"; + + for (;wcschr(L"MCAOmcao",*Mod)!=NULL;Mod++) + switch(toupperw(*Mod)) + { + case 'M': + if (Before) + { + Age ? FileMtimeBefore.SetAgeText(S):FileMtimeBefore.SetIsoText(S); + FileMtimeBeforeOR=ModeOR; + } + else + { + Age ? FileMtimeAfter.SetAgeText(S):FileMtimeAfter.SetIsoText(S); + FileMtimeAfterOR=ModeOR; + } + break; + case 'C': + if (Before) + { + Age ? FileCtimeBefore.SetAgeText(S):FileCtimeBefore.SetIsoText(S); + FileCtimeBeforeOR=ModeOR; + } + else + { + Age ? FileCtimeAfter.SetAgeText(S):FileCtimeAfter.SetIsoText(S); + FileCtimeAfterOR=ModeOR; + } + break; + case 'A': + if (Before) + { + Age ? FileAtimeBefore.SetAgeText(S):FileAtimeBefore.SetIsoText(S); + FileAtimeBeforeOR=ModeOR; + } + else + { + Age ? FileAtimeAfter.SetAgeText(S):FileAtimeAfter.SetIsoText(S); + FileAtimeAfterOR=ModeOR; + } + break; + } +} +#endif + + +#ifndef SFX_MODULE +// Return 'true' if we need to exclude the file from processing. +bool CommandData::TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta) +{ + bool FilterOR=false; + + if (FileMtimeBefore.IsSet()) // Filter present. + if (ftm>=FileMtimeBefore) // Condition not matched. + if (FileMtimeBeforeOR) + FilterOR=true; // Not matched OR filter is present. + else + return true; // Exclude file in AND mode. + else // Condition matched. + if (FileMtimeBeforeOR) + return false; // Include file in OR mode. + + if (FileMtimeAfter.IsSet()) // Filter present. + if (ftm=FileCtimeBefore) // Condition not matched. + if (FileCtimeBeforeOR) + FilterOR=true; // Not matched OR filter is present. + else + return true; // Exclude file in AND mode. + else // Condition matched. + if (FileCtimeBeforeOR) + return false; // Include file in OR mode. + + if (FileCtimeAfter.IsSet()) // Filter present. + if (ftc=FileAtimeBefore) // Condition not matched. + if (FileAtimeBeforeOR) + FilterOR=true; // Not matched OR filter is present. + else + return true; // Exclude file in AND mode. + else // Condition matched. + if (FileAtimeBeforeOR) + return false; // Include file in OR mode. + + if (FileAtimeAfter.IsSet()) // Filter present. + if (fta=FileSizeLess) + return true; + if (FileSizeMore!=INT64NDF && Size<=FileSizeMore) + return true; + return false; +} +#endif + + + + +// Return 0 if file must not be processed or a number of matched parameter otherwise. +int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType, + bool Flags,wchar *MatchedArg,uint MatchedArgSize) +{ + if (MatchedArg!=NULL && MatchedArgSize>0) + *MatchedArg=0; + bool Dir=FileHead.Dir; + if (ExclCheck(FileHead.FileName,Dir,false,true)) + return 0; +#ifndef SFX_MODULE + if (TimeCheck(FileHead.mtime,FileHead.ctime,FileHead.atime)) + 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; + if (MatchedArg!=NULL) + wcsncpyz(MatchedArg,ArgName,MatchedArgSize); + return StringCount; + } + return 0; +} diff --git a/cmdmix.cpp b/cmdmix.cpp new file mode 100644 index 0000000..3990cc1 --- /dev/null +++ b/cmdmix.cpp @@ -0,0 +1,118 @@ +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[80]; + if (RARVER_BETA!=0) + swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA); + else + swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR); +#if defined(_WIN_32) || defined(_WIN_64) + wcsncatz(Version,L" ",ASIZE(Version)); +#endif +#ifdef _WIN_32 + wcsncatz(Version,St(Mx86),ASIZE(Version)); +#endif +#ifdef _WIN_64 + wcsncatz(Version,St(Mx64),ASIZE(Version)); +#endif + if (PrintVersion) + { + mprintf(L"%s",Version); + exit(0); + } + mprintf(St(MUCopyright),Version,RARVER_YEAR); +#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 wcscmp(i1,i2)==0; +#endif +} + +void CommandData::OutHelp(RAR_EXIT ExitCode) +{ +#if !defined(SILENT) + OutTitle(); + static MSGID Help[]={ +#ifdef SFX_MODULE + // Console SFX switches definition. + MCHelpCmd,MSHelpCmdE,MSHelpCmdT,MSHelpCmdV +#else + // 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,MCHelpSwOL,MCHelpSwOR,MCHelpSwOW,MCHelpSwP, + MCHelpSwPm,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSL,MCHelpSwSM, + MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU, + MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal, + MCHelpSwY +#endif + }; + + for (uint I=0;IArc.Volume) r->Flags|=0x01; + if (Data->Arc.MainComment) + r->Flags|=0x02; if (Data->Arc.Locked) r->Flags|=0x04; if (Data->Arc.Solid) @@ -114,17 +116,29 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r) 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; + if (r->CmtBufW!=NULL) + { + CmtDataW.Push(0); + size_t Size=wcslen(&CmtDataW[0])+1; + + r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1; + r->CmtSize=(uint)Min(Size,r->CmtBufSize); + memcpy(r->CmtBufW,&CmtDataW[0],(r->CmtSize-1)*sizeof(*r->CmtBufW)); + r->CmtBufW[r->CmtSize-1]=0; + } + else + if (r->CmtBuf!=NULL) + { + 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->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1; + r->CmtSize=(uint)Min(Size,r->CmtBufSize); + memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1); + r->CmtBuf[r->CmtSize-1]=0; + } } else r->CmtState=r->CmtSize=0; @@ -437,16 +451,16 @@ void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataPro } -#ifndef RAR_NOCRYPT void PASCAL RARSetPassword(HANDLE hArcData,char *Password) { +#ifndef RAR_NOCRYPT 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() diff --git a/dll.def b/dll.def index 660f69b..3c9a2c8 100644 --- a/dll.def +++ b/dll.def @@ -5,6 +5,7 @@ EXPORTS RARReadHeader RARReadHeaderEx RARProcessFile + RARProcessFileW RARSetCallback RARSetChangeVolProc RARSetProcessDataProc diff --git a/dll.hpp b/dll.hpp index 32c1c11..c785ff1 100644 --- a/dll.hpp +++ b/dll.hpp @@ -1,7 +1,7 @@ #ifndef _UNRAR_DLL_ #define _UNRAR_DLL_ -#pragma pack(1) +#pragma pack(push, 1) #define ERAR_SUCCESS 0 #define ERAR_END_ARCHIVE 10 @@ -151,7 +151,8 @@ struct RAROpenArchiveDataEx UNRARCALLBACK Callback; LPARAM UserData; unsigned int OpFlags; - unsigned int Reserved[27]; + wchar_t *CmtBufW; + unsigned int Reserved[25]; }; enum UNRARCALLBACK_MESSAGES { @@ -183,6 +184,6 @@ int PASCAL RARGetDllVersion(); } #endif -#pragma pack() +#pragma pack(pop) #endif diff --git a/dll.rc b/dll.rc index 1acd11d..6ce358b 100644 --- a/dll.rc +++ b/dll.rc @@ -1,28 +1,28 @@ -#include -#include - -VS_VERSION_INFO VERSIONINFO -FILEVERSION 5, 70, 1, 2955 -PRODUCTVERSION 5, 70, 1, 2955 -FILEOS VOS__WINDOWS32 -FILETYPE VFT_APP -{ - BLOCK "StringFileInfo" - { - BLOCK "040904E4" - { - VALUE "CompanyName", "Alexander Roshal\0" - VALUE "ProductName", "RAR decompression library\0" - VALUE "FileDescription", "RAR decompression library\0" - VALUE "FileVersion", "5.70.1\0" - VALUE "ProductVersion", "5.70.1\0" - VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2019\0" - VALUE "OriginalFilename", "Unrar.dll\0" - } - } - BLOCK "VarFileInfo" - { - VALUE "Translation", 0x0409, 0x04E4 - } -} - +#include +#include + +VS_VERSION_INFO VERSIONINFO +FILEVERSION 5, 70, 100, 2983 +PRODUCTVERSION 5, 70, 100, 2983 +FILEOS VOS__WINDOWS32 +FILETYPE VFT_APP +{ + BLOCK "StringFileInfo" + { + BLOCK "040904E4" + { + VALUE "CompanyName", "Alexander Roshal\0" + VALUE "ProductName", "RAR decompression library\0" + VALUE "FileDescription", "RAR decompression library\0" + VALUE "FileVersion", "5.70.0\0" + VALUE "ProductVersion", "5.70.0\0" + VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2019\0" + VALUE "OriginalFilename", "Unrar.dll\0" + } + } + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x0409, 0x04E4 + } +} + diff --git a/dll_nocrypt.def b/dll_nocrypt.def new file mode 100644 index 0000000..d473e97 --- /dev/null +++ b/dll_nocrypt.def @@ -0,0 +1,13 @@ +EXPORTS + RAROpenArchive + RAROpenArchiveEx + RARCloseArchive + RARReadHeader + RARReadHeaderEx + RARProcessFile + RARProcessFileW + RARSetCallback + RARSetChangeVolProc + RARSetProcessDataProc +; RARSetPassword + RARGetDllVersion diff --git a/errhnd.hpp b/errhnd.hpp index eae5914..3455dac 100644 --- a/errhnd.hpp +++ b/errhnd.hpp @@ -56,7 +56,7 @@ class ErrorHandler uint GetErrorCount() {return ErrCount;} void SetSignalHandlers(bool Enable); void Throw(RAR_EXIT Code); - void SetSilent(bool Mode) {Silent=Mode;}; + void SetSilent(bool Mode) {Silent=Mode;} bool GetSysErrMsg(wchar *Msg,size_t Size); void SysErrMsg(); int GetSystemErrorCode(); diff --git a/extract.cpp b/extract.cpp index bc9e86f..fe11d7f 100644 --- a/extract.cpp +++ b/extract.cpp @@ -87,7 +87,7 @@ void CmdExtract::ExtractArchiveInit(Archive &Arc) FirstFile=true; #endif - GlobalPassword=Cmd->Password.IsSet(); + GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet(); DataIO.UnpVolume=false; @@ -298,7 +298,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) bool EqualNames=false; wchar MatchedArg[NM]; - int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType,MatchedArg,ASIZE(MatchedArg)); + int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType,0,MatchedArg,ASIZE(MatchedArg)); bool MatchFound=MatchNumber!=0; #ifndef SFX_MODULE if (Cmd->ExclPath==EXCL_BASEPATH) @@ -473,7 +473,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 && !Arc.BrokenHeader) { - if (GlobalPassword) // For -p or Ctrl+P. + if (GlobalPassword) // For -p or Ctrl+P to avoid the infinite loop. { // This message is used by Android GUI to reset cached passwords. // Update appropriate code if changed. @@ -1085,7 +1085,7 @@ void CmdExtract::ExtrCreateDir(Archive &Arc,const wchar *ArcFileName) { #if defined(_WIN_ALL) && !defined(SFX_MODULE) if (Cmd->SetCompressedAttr && - (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT()) + (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT()!=WNT_NONE) SetFileCompression(DestFileName,true); #endif SetFileHeaderExtra(Cmd,Arc,DestFileName); diff --git a/file.hpp b/file.hpp index f99336a..794023a 100644 --- a/file.hpp +++ b/file.hpp @@ -99,7 +99,7 @@ class File void SetCloseFileTime(RarTime *ftm,RarTime *fta=NULL); static void SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta); void GetOpenFileTime(RarTime *ft); - virtual bool IsOpened() {return hFile!=FILE_BAD_HANDLE;}; // 'virtual' for MultiFile class. + virtual bool IsOpened() {return hFile!=FILE_BAD_HANDLE;} // 'virtual' for MultiFile class. int64 FileLength(); void SetHandleType(FILE_HANDLETYPE Type) {HandleType=Type;} FILE_HANDLETYPE GetHandleType() {return HandleType;} diff --git a/list.cpp b/list.cpp index 060c1e4..11c404e 100644 --- a/list.cpp +++ b/list.cpp @@ -91,7 +91,7 @@ void ListArchive(CommandData *Cmd) switch(HeaderType) { case HEAD_FILE: - FileMatched=Cmd->IsProcessFile(Arc.FileHead)!=0; + FileMatched=Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0; if (FileMatched) { ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare); diff --git a/loclang.hpp b/loclang.hpp index fa57356..181fcb4 100644 --- a/loclang.hpp +++ b/loclang.hpp @@ -85,7 +85,7 @@ #define MCHelpSwILOG L"\n ilog[name] Log errors to file" #define MCHelpSwINUL L"\n inul Disable all messages" #define MCHelpSwIOFF L"\n ioff[n] Turn PC off after completing an operation" -#define MCHelpSwISND L"\n isnd Enable sound" +#define MCHelpSwISND L"\n isnd Control notification sounds" #define MCHelpSwIVER L"\n iver Display the version number" #define MCHelpSwK L"\n k Lock archive" #define MCHelpSwKB L"\n kb Keep broken extracted files" @@ -127,10 +127,10 @@ #define MCHelpSwT L"\n t Test files after archiving" #define MCHelpSwTK L"\n tk Keep original archive time" #define MCHelpSwTL L"\n tl Set archive time to latest file" -#define MCHelpSwTN L"\n tn[m,c,a] Process files newer than time" -#define MCHelpSwTO L"\n to[m,c,a] Process files older than time" -#define MCHelpSwTA L"\n ta[m,c,a] Process files modified after YYYYMMDDHHMMSS date" -#define MCHelpSwTB L"\n tb[m,c,a] Process files modified before YYYYMMDDHHMMSS date" +#define MCHelpSwTN L"\n tn[mcao] Process files newer than time" +#define MCHelpSwTO L"\n to[mcao] Process files older than time" +#define MCHelpSwTA L"\n ta[mcao] Process files modified after YYYYMMDDHHMMSS date" +#define MCHelpSwTB L"\n tb[mcao] Process files modified before YYYYMMDDHHMMSS date" #define MCHelpSwTS L"\n ts[m,c,a] Save or restore file time (modification, creation, access)" #define MCHelpSwU L"\n u Update files" #define MCHelpSwV L"\n v Create volumes with size autodetection or list all volumes" diff --git a/match.cpp b/match.cpp index 4369a57..ec88fa6 100644 --- a/match.cpp +++ b/match.cpp @@ -25,10 +25,10 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode) if (CmpMode!=MATCH_NAMES) { size_t WildLength=wcslen(Wildcard); - if (CmpMode!=MATCH_EXACT && CmpMode!=MATCH_EXACTPATH && + if (CmpMode!=MATCH_EXACT && CmpMode!=MATCH_EXACTPATH && CmpMode!=MATCH_ALLWILD && mwcsnicompc(Wildcard,Name,WildLength,ForceCase)==0) { - // For all modes except MATCH_NAMES, MATCH_EXACT and MATCH_EXACTPATH + // For all modes except MATCH_NAMES, MATCH_EXACT, MATCH_EXACTPATH, MATCH_ALLWILD, // "path1" mask must match "path1\path2\filename.ext" and "path1" names. wchar NextCh=Name[WildLength]; if (NextCh==L'\\' || NextCh==L'/' || NextCh==0) @@ -46,6 +46,8 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode) if ((CmpMode==MATCH_EXACT || CmpMode==MATCH_EXACTPATH) && mwcsicompc(Path1,Path2,ForceCase)!=0) return(false); + if (CmpMode==MATCH_ALLWILD) + return match(Wildcard,Name,ForceCase); if (CmpMode==MATCH_SUBPATH || CmpMode==MATCH_WILDSUBPATH) if (IsWildcard(Path1)) return(match(Wildcard,Name,ForceCase)); @@ -64,8 +66,8 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode) // Always return false for RAR temporary files to exclude them // from archiving operations. - if (mwcsnicompc(L"__rar_",Name2,6,false)==0) - return(false); +// if (mwcsnicompc(L"__rar_",Name2,6,false)==0) +// return(false); if (CmpMode==MATCH_EXACT) return(mwcsicompc(Name1,Name2,ForceCase)==0); diff --git a/match.hpp b/match.hpp index 65493ff..1e65a3c 100644 --- a/match.hpp +++ b/match.hpp @@ -14,6 +14,10 @@ enum { MATCH_EXACT, // Paths must match exactly. // Names must match exactly. + MATCH_ALLWILD, // Paths and names are compared using wildcards. + // Unlike MATCH_SUBPATH, paths do not match subdirs + // unless a wildcard tells so. + MATCH_EXACTPATH, // Paths must match exactly. // Names are compared using wildcards. diff --git a/options.hpp b/options.hpp index 2d00ef6..7c33a03 100644 --- a/options.hpp +++ b/options.hpp @@ -69,6 +69,10 @@ enum POWER_MODE { POWERMODE_RESTART }; + +// Need "forced off" state to turn off sound in GUI command line. +enum SOUND_NOTIFY_MODE {SOUND_NOTIFY_DEFAULT=0,SOUND_NOTIFY_ON,SOUND_NOTIFY_OFF}; + struct FilterMode { FilterState State; @@ -113,7 +117,7 @@ class RAROptions wchar LogName[NM]; MESSAGE_TYPE MsgStream; - bool Sound; + SOUND_NOTIFY_MODE Sound; OVERWRITE_MODE Overwrite; int Method; HASH_TYPE HashType; @@ -164,12 +168,10 @@ class RAROptions bool SaveStreams; bool SetCompressedAttr; bool IgnoreGeneralAttr; - RarTime FileMtimeBefore; - RarTime FileMtimeAfter; - RarTime FileCtimeBefore; - RarTime FileCtimeAfter; - RarTime FileAtimeBefore; - RarTime FileAtimeAfter; + RarTime FileMtimeBefore,FileCtimeBefore,FileAtimeBefore; + bool FileMtimeBeforeOR,FileCtimeBeforeOR,FileAtimeBeforeOR; + RarTime FileMtimeAfter,FileCtimeAfter,FileAtimeAfter; + bool FileMtimeAfterOR,FileCtimeAfterOR,FileAtimeAfterOR; int64 FileSizeLess; int64 FileSizeMore; bool Lock; diff --git a/os.hpp b/os.hpp index d4a7426..3913520 100644 --- a/os.hpp +++ b/os.hpp @@ -32,7 +32,12 @@ #define STRICT 1 #endif +// 'ifndef' check here is needed for unrar.dll header to avoid macro +// re-definition warnings in third party projects. +#ifndef UNICODE #define UNICODE +#endif + #undef WINVER #undef _WIN32_WINNT #define WINVER 0x0501 diff --git a/pathfn.cpp b/pathfn.cpp index 9f4bca6..cb1d7ed 100644 --- a/pathfn.cpp +++ b/pathfn.cpp @@ -120,7 +120,14 @@ bool CmpExt(const wchar *Name,const wchar *Ext) bool IsWildcard(const wchar *Str) { - return Str==NULL ? false:wcspbrk(Str,L"*?")!=NULL; + if (Str==NULL) + return false; +#ifdef _WIN_ALL + // Not treat the special NTFS \\?\d: path prefix as a wildcard. + if (Str[0]=='\\' && Str[1]=='\\' && Str[2]=='?' && Str[3]=='\\') + Str+=4; +#endif + return wcspbrk(Str,L"*?")!=NULL; } diff --git a/rs16.cpp b/rs16.cpp index f23cff8..bc8dd09 100644 --- a/rs16.cpp +++ b/rs16.cpp @@ -27,7 +27,7 @@ RSCoder16::~RSCoder16() delete[] MX; delete[] ValidFlags; } - + // Initialize logarithms and exponents Galois field tables. void RSCoder16::gfInit() @@ -41,7 +41,7 @@ void RSCoder16::gfInit() gfExp[L]=E; gfExp[L+gfSize]=E; // Duplicate the table to avoid gfExp overflow check. E<<=1; - if (E>gfSize) + if (E>gfSize) E^=0x1100B; // Irreducible field-generator polynomial. } @@ -59,7 +59,7 @@ uint RSCoder16::gfAdd(uint a,uint b) // Addition in Galois field. } -uint RSCoder16::gfMul(uint a,uint b) // Multiplication in Galois field. +uint RSCoder16::gfMul(uint a,uint b) // Multiplication in Galois field. { return gfExp[gfLog[a]+gfLog[b]]; } @@ -156,7 +156,7 @@ void RSCoder16::InvertDecoderMatrix() for (uint Kr = 0, Kf = 0; Kr < NE; Kr++, Kf++) { while (ValidFlags[Kf]) // Skip trivial rows. - Kf++; + Kf++; MI[Kr * ND + Kf] = 1; // Set diagonal 1. } @@ -174,7 +174,7 @@ void RSCoder16::InvertDecoderMatrix() // 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++; + Kf++; } if (Kf == ND) @@ -186,14 +186,14 @@ void RSCoder16::InvertDecoderMatrix() 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. @@ -361,7 +361,7 @@ bool RSCoder16::SSE_UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte __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); @@ -377,7 +377,7 @@ bool RSCoder16::SSE_UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte // 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); @@ -413,7 +413,7 @@ bool RSCoder16::SSE_UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte // because Data and ECC can have different alignment offsets. for (; Pos5) diff --git a/unicode.cpp b/unicode.cpp index ffba8c1..9717055 100644 --- a/unicode.cpp +++ b/unicode.cpp @@ -70,7 +70,7 @@ bool WideToChar(const wchar *Src,char *Dest,size_t DestSize) #endif if (DestSize>0) Dest[DestSize-1]=0; - + // We tried to return the empty string if conversion is failed, // but it does not work well. WideCharToMultiByte returns 'failed' code // and partially converted string even if we wanted to convert only a part @@ -178,7 +178,7 @@ bool WideToCharMap(const wchar *Src,char *Dest,size_t DestSize,bool &Success) #if defined(_UNIX) && defined(MBFUNCTIONS) -// Convert and map inconvertible Unicode characters. +// Convert and map inconvertible Unicode characters. // We use it for extended ASCII names in Unix. void CharToWideMap(const char *Src,wchar *Dest,size_t DestSize,bool &Success) { diff --git a/unpack50.cpp b/unpack50.cpp index dac1f6f..ec60c82 100644 --- a/unpack50.cpp +++ b/unpack50.cpp @@ -11,7 +11,7 @@ void Unpack::Unpack5(bool Solid) // Check TablesRead5 to be sure that we read tables at least once // regardless of current block header TablePresent flag. // So we can safefly use these tables below. - if (!ReadBlockHeader(Inp,BlockHeader) || + if (!ReadBlockHeader(Inp,BlockHeader) || !ReadTables(Inp,BlockHeader,BlockTables) || !TablesRead5) return; } @@ -536,11 +536,11 @@ bool Unpack::ReadBlockHeader(BitInput &Inp,UnpackBlockHeader &Header) 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; diff --git a/unpack50frag.cpp b/unpack50frag.cpp index 745b1b3..3c008ff 100644 --- a/unpack50frag.cpp +++ b/unpack50frag.cpp @@ -48,7 +48,7 @@ void FragmentedWindow::Init(size_t WinSize) } 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); diff --git a/unpack50mt.cpp b/unpack50mt.cpp index 59e111b..691ac8e 100644 --- a/unpack50mt.cpp +++ b/unpack50mt.cpp @@ -165,7 +165,7 @@ void Unpack::Unpack5MT(bool Solid) if (DataLeftD=UnpThreadData+CurBlock; UTD->BlockCount=Min(MaxBlockPerThread,BlockNumberMT-CurBlock); - + #ifdef USE_THREADS if (BlockNumber==1) UnpackDecode(*UTD->D); @@ -200,7 +200,7 @@ void Unpack::Unpack5MT(bool Solid) #endif bool IncompleteThread=false; - + for (uint Block=0;BlockType=UNPDT_FILTER; CurItem->Length=Filter.Type; CurItem->Distance=Filter.BlockStart; @@ -498,7 +498,7 @@ bool Unpack::ProcessDecoded(UnpackThreadData &D) if (Item->Type==UNPDT_FILTER) { UnpackFilter Filter; - + Filter.Type=(byte)Item->Length; Filter.BlockStart=Item->Distance; @@ -534,7 +534,7 @@ bool Unpack::UnpackLargeBlock(UnpackThreadData &D) D.DamagedData=true; return false; } - + int BlockBorder=D.BlockHeader.BlockStart+D.BlockHeader.BlockSize-1; // Reserve enough space even for filter entry. diff --git a/version.hpp b/version.hpp index ebe7df0..de774ff 100644 --- a/version.hpp +++ b/version.hpp @@ -1,6 +1,6 @@ #define RARVER_MAJOR 5 #define RARVER_MINOR 70 -#define RARVER_BETA 1 -#define RARVER_DAY 28 -#define RARVER_MONTH 1 +#define RARVER_BETA 0 +#define RARVER_DAY 25 +#define RARVER_MONTH 2 #define RARVER_YEAR 2019