Include files listed in specified list file"
+#define MCHelpSwO "\n o[+|-] Set the overwrite mode"
+#define MCHelpSwOC "\n oc Set NTFS Compressed attribute"
+#define MCHelpSwOL "\n ol Save symbolic links as the link instead of the file"
+#define MCHelpSwOR "\n or Rename files automatically"
+#define MCHelpSwOS "\n os Save NTFS streams"
+#define MCHelpSwOW "\n ow Save or restore file owner and group"
+#define MCHelpSwP "\n p[password] Set password"
+#define MCHelpSwPm "\n p- Do not query password"
+#define MCHelpSwR "\n r Recurse subdirectories"
+#define MCHelpSwRm "\n r- Disable recursion"
+#define MCHelpSwR0 "\n r0 Recurse subdirectories for wildcard names only"
+#define MCHelpSwRI "\n ri[:] 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 Process files newer than "
+#define MCHelpSwTO "\n to Process files older than "
+#define MCHelpSwTA "\n ta Process files modified after in YYYYMMDDHHMMSS format"
+#define MCHelpSwTB "\n tb Process files modified before in YYYYMMDDHHMMSS format"
+#define MCHelpSwTS "\n ts[N] Save or restore file time (modification, creation, access)"
+#define MCHelpSwU "\n u Update files"
+#define MCHelpSwV "\n v Create volumes with size autodetection or list all volumes"
+#define MCHelpSwVUnr "\n v List all volumes"
+#define MCHelpSwVn "\n v[k,b] Create volumes with size=*1000 [*1024, *1]"
+#define MCHelpSwVD "\n vd Erase disk contents before creating volume"
+#define MCHelpSwVER "\n ver[n] File version control"
+#define MCHelpSwVN "\n vn Use the old style volume naming scheme"
+#define MCHelpSwVP "\n vp Pause before each volume"
+#define MCHelpSwW "\n w Assign work directory"
+#define MCHelpSwX "\n x Exclude specified file"
+#define MCHelpSwXa "\n x@ Read file names to exclude from stdin"
+#define MCHelpSwXal "\n x@ Exclude files listed in specified list file"
+#define MCHelpSwY "\n y Assume Yes on all queries"
+#define MCHelpSwZ "\n z[file] Read archive comment from file"
+#define MBadArc "\nERROR: Bad archive %s\n"
+#define MAskPsw "Enter password (will not be echoed)"
+#define MAskPswEcho "Enter password"
+#define MReAskPsw "\nReenter password: "
+#define MFor " for "
+#define MNotMatchPsw "\nERROR: Passwords do not match\n"
+#define MErrWrite "Write error in the file %s"
+#define MErrRead "Read error in the file %s"
+#define MErrSeek "Seek error in the file %s"
+#define MErrFClose "Cannot close the file %s"
+#define MErrOutMem "Not enough memory"
+#define MErrBrokenArc "Corrupt archive - use 'Repair' command"
+#define MProgAborted "Program aborted"
+#define MErrRename "\nCannot rename %s to %s"
+#define MAbsNextVol "\nCannot find volume %s"
+#define MBreak "\nUser break\n"
+#define MAskCreatVol "\nCreate next volume ?"
+#define MAskNextDisk "\nDisk full. Insert next"
+#define MCreatVol "\n\nCreating %sarchive %s\n"
+#define MAskNextVol "\nInsert disk with %s"
+#define MTestVol "\n\nTesting archive %s\n"
+#define MExtrVol "\n\nExtracting from %s\n"
+#define MConverting "\nConverting %s"
+#define MCvtToSFX "\nConvert archives to SFX"
+#define MCvtFromSFX "\nRemoving SFX module"
+#define MNotSFX "\n%s is not SFX archive"
+#define MNotRAR "\n%s is not RAR archive"
+#define MNotFirstVol "\n%s is not the first volume"
+#define MCvtOldFormat "\n%s - cannot convert to SFX archive with old format"
+#define MCannotCreate "\nCannot create %s"
+#define MCannotOpen "\nCannot open %s"
+#define MUnknownMeth "\nUnknown method in %s"
+#define MVerRequired "\nYou need RAR %d.%d to unpack it"
+#define MNewRarFormat "\nUnsupported archive format. Please update RAR to a newer version."
+#define MOk " OK"
+#define MDone "\nDone"
+#define MLockingArc "\nLocking archive"
+#define MNotMdfOld "\n\nERROR: Cannot modify old format archive"
+#define MNotMdfLock "\n\nERROR: Locked archive"
+#define MNotMdfVol "\n\nERROR: Cannot modify volume"
+#define MVerifyAV "\nVerifying authenticity information ... "
+#define MFailedAV " Failed\n"
+#define MStrAV1 "\n\nArchive %s"
+#define MStrAV2 "\ncreated at %s"
+#define MStrAV3 "\nby %s\n"
+#define MLogFailedAV "Invalid authenticity information"
+#define MAddingAV "\nAdding authenticity verification "
+#define MAVOldStyle "\n\nOld style authenticity information"
+#define MPackAskReg "\nEvaluation copy. Please register.\n"
+#define MCreateArchive "\nCreating %sarchive %s\n"
+#define MUpdateArchive "\nUpdating %sarchive %s\n"
+#define MAddSolid "solid "
+#define MAddFile "\nAdding %-58s "
+#define MUpdFile "\nUpdating %-58s "
+#define MAddPoints "\n... %-58s "
+#define MCannotUpdPswSolid "\nERROR: Cannot update solid archives with password\n"
+#define MMoveDelFiles "\n\nDeleting files %s..."
+#define MMoveDelDirs "and directories"
+#define MMoveDelFile "\nDeleting %-30s"
+#define MMoveDeleted " deleted"
+#define MMoveNotDeleted " NOT DELETED"
+#define MClearAttrib "\n\nClearing attributes..."
+#define MMoveDelDir "\nDeleting directory %-30s"
+#define MWarErrFOpen "\nWARNING: Cannot open %d %s"
+#define MErrOpenFiles "files"
+#define MErrOpenFile "file"
+#define MAddNoFiles "\nWARNING: No files"
+#define MMdfEncrSol "\n%s: encrypted"
+#define MCannotMdfEncrSol "\nCannot modify solid archive containing encrypted files"
+#define MAddAnalyze "\nAnalyzing archived files: "
+#define MRepacking "\nRepacking archived files: "
+#define MCRCFailed "\n%-20s - CRC failed"
+#define MExtrTest "\n\nTesting archive %s\n"
+#define MExtracting "\n\nExtracting from %s\n"
+#define MUseCurPsw "\n%s - use current password ?"
+#define MCreatDir "\nCreating %-56s"
+#define MExtrSkipFile "\nSkipping %-56s"
+#define MExtrTestFile "\nTesting %-56s"
+#define MExtrFile "\nExtracting %-56s"
+#define MExtrPoints "\n... %-56s"
+#define MExtrErrMkDir "\nCannot create directory %s"
+#define MExtrPrinting "\n------ Printing %s\n\n"
+#define MEncrBadCRC "\nCRC failed in the encrypted file %s. Corrupt file or wrong password."
+#define MExtrNoFiles "\nNo files to extract"
+#define MExtrAllOk "\nAll OK"
+#define MExtrTotalErr "\nTotal errors: %ld"
+#define MFileExists "\n\n%s already exists. Overwrite it ?"
+#define MAskOverwrite "\nOverwrite %s ?"
+#define MAskNewName "\nEnter new name: "
+#define MLogMainHead "\nThe archive header is corrupt"
+#define MLogFileHead "\n%s - the file header is corrupt"
+#define MLogCommHead "\nThe comment header is corrupt\n"
+#define MLogProtectHead "The data recovery header is corrupt"
+#define MReadStdinCmt "\nReading comment from stdin\n"
+#define MReadCommFrom "\nReading comment from %s"
+#define MDelComment "\nDeleting comment from %s"
+#define MAddComment "\nAdding comment to %s"
+#define MFCommAdd "\nAdding file comments"
+#define MAskFComm "\n\nReading comment for %s : %s from stdin\n"
+#define MLogCommBrk "\nThe archive comment is corrupt"
+#define MCommAskCont "\nPress 'Enter' to continue or 'Q' to quit:"
+#define MLogBrokFCmt "\nThe file comment is corrupt"
+#define MWriteCommTo "\nWrite comment to %s"
+#define MCommNotPres "\nComment is not present"
+#define MDelFrom "\nDeleting from %s"
+#define MDeleting "\nDeleting %s"
+#define MEraseArc "\nErasing empty archive %s"
+#define MNoDelFiles "\nNo files to delete"
+#define MLogTitle "\n\n-------- %2d %s %d, archive %s\n"
+#define MPathTooLong "\nERROR: Path too long\n"
+#define MListSolid "Solid "
+#define MListSFX "SFX "
+#define MListVol1 "volume"
+#define MListVol2 "Volume"
+#define MListArc1 "archive"
+#define MListArc2 "Archive"
+#define MListRecRec "\nRecovery record is present\n"
+#define MListLock "\nLock is present\n"
+#define MListPathComm "\nPathname/Comment\n "
+#define MListName "\n Name "
+#define MListTitle " Size Packed Ratio Date Time Attr CRC Meth Ver\n"
+#define MListTechTitle " Host OS Solid Old\n"
+#define MListEAHead "\n OS/2 extended attributes"
+#define MListUOHead "\n Unix Owner/Group data: %-14s %-14s"
+#define MListBeEAHead "\n BeOS extended attributes"
+#define MListNTACLHead "\n NTFS security data"
+#define MListStrmHead "\n NTFS stream: %s"
+#define MListUnkHead "\n Unknown subheader type: 0x%04x"
+#define MFileComment "\nComment: "
+#define MYes "Yes"
+#define MNo "No"
+#define MListNoFiles " 0 files\n"
+#define MRprReconstr "\nReconstructing %s"
+#define MRprBuild "\nBuilding %s"
+#define MRprOldFormat "\nCannot repair archive with old format"
+#define MRprFind "\nFound %s"
+#define MRprAskIsSol "\nThe archive header is corrupt. Mark archive as solid ?"
+#define MRprNoFiles "\nNo files found"
+#define MRprSuspEntry "\n\nSuspicious entry %s"
+#define MRprDir "\nDirectory"
+#define MRprSuspSize "\nSize %ld Packed %ld"
+#define MRprSuspAdd "\nAdd it to archive ?"
+#define MLogUnexpEOF "\nUnexpected end of archive"
+#define MRepAskReconst "\nReconstruct archive structure ?"
+#define MRecScanning "\nScanning..."
+#define MRecRNotFound "\nData recovery record not found"
+#define MRecRFound "\nData recovery record found"
+#define MRecSecDamage "\nSector %ld (offsets %lX...%lX) damaged"
+#define MRecCorrected " - data recovered"
+#define MRecFailed " - cannot recover data"
+#define MAddRecRec "\nAdding data recovery record"
+#define MEraseForVolume "\n\nErasing contents of drive %c:\n"
+#define MGetOwnersError "\nWARNING: Cannot get %s owner and group\n"
+#define MErrGetOwnerID "\nWARNING: Cannot get owner %s ID\n"
+#define MErrGetGroupID "\nWARNING: Cannot get group %s ID\n"
+#define MOwnersBroken "\nERROR: %s group and owner data are corrupt\n"
+#define MSetOwnersError "\nWARNING: Cannot set %s owner and group\n"
+#define MErrLnkRead "\nWARNING: Cannot read symbolic link %s"
+#define MErrCreateLnk "\nWARNING: Cannot create link %s"
+#define MSymLinkExists "\nWARNING: Symbolic link %s already exists"
+#define MAskRetryCreate "\nCannot create %s. Retry ?"
+#define MListMACHead1 "\n Mac OS file type: %c%c%c%c ; "
+#define MListMACHead2 "file creator: %c%c%c%c\n"
+#define MDataBadCRC "\n%-20s : packed data CRC failed in volume %s"
+#define MFileRO "\n%s is read-only"
+#define MACLGetError "\nWARNING: Cannot get %s security data\n"
+#define MACLSetError "\nWARNING: Cannot set %s security data\n"
+#define MACLBroken "\nERROR: %s security data are corrupt\n"
+#define MACLUnknown "\nWARNING: Unknown format of %s security data\n"
+#define MStreamBroken "\nERROR: %s stream data are corrupt\n"
+#define MStreamUnknown "\nWARNING: Unknown format of %s stream data\n"
+#define MInvalidName "\nERROR: Invalid file name %s"
+#define MEABroken "\nERROR: %s extended attributes are corrupt\n"
+#define MEAUnknHeader "\nWARNING: %s - unknown format of extended attributes\n"
+#define MCannotSetEA "\nWARNING: cannot set extended attributes to %s\n"
+#define MCannotGetEA "\nERROR: Cannot get extended attributes of %s\n"
+#define MShowEA " (+EA)"
+#define MSkipEA "\n...skipping extended attributes"
+#define MProcessArc "\n\nProcessing archive %s"
+#define MSyncScanError "\nFile search errors, cannot synchronize archive"
+#define MCorrectingName "\nWARNING: Attempting to correct the invalid file name"
+#define MUnpCannotMerge "\nWARNING: You need to start extraction from a previous volume to unpack %s"
+#define MUnknownOption "\nERROR: Unknown option: %s"
+#define MSubHeadCorrupt "\nERROR: Corrupt data header found, ignored"
+#define MSubHeadUnknown "\nWARNING: Unknown data header format, ignored"
+#define MSubHeadDataCRC "\nERROR: Corrupt %s data block"
+#define MSubHeadType "\nData header type: %s"
+#define MScanError "\nCannot read contents of %s"
+#define MNotVolume "\n%s is not volume"
+#define MRecVolDiffSets "\nERROR: %s and %s belong to different sets"
+#define MRecVolMissing "\n%d volumes missing"
+#define MRecVolFound "\n%d recovery volumes found"
+#define MRecVolAllExist "\nNothing to reconstruct"
+#define MRecVolCannotFix "\nReconstruction impossible"
+#define MReconstructing "\nReconstructing..."
+#define MCreating "\nCreating %s"
+#define MRenaming "\nRenaming %s to %s"
+#define MNTFSRequired "\nWrite error: only NTFS file system supports files larger than 4 GB"
+#define MErrChangeAttr "\nWARNING: Cannot change attributes of %s"
+#define MWrongSFXVer "\nERROR: default SFX module does not support RAR %d.%d archives"
+#define MCannotEncName "\nCannot encrypt archive already contained encrypted files"
+#define MCannotEmail "\nCannot email the file %s"
+#define MCopyrightS "\nRAR SFX archive"
+#define MSHelpCmd "\n\n"
+#define MSHelpCmdE "\n -x Extract from archive (default)"
+#define MSHelpCmdT "\n -t Test archive files"
+#define MSHelpCmdV "\n -v Verbosely list contents of archive"
+#define MMaxPathLimit "\nTotal path and file name length must not exceed %d characters"
+#define MRecVolLimit "\nTotal number of usual and recovery volumes must not exceed 255"
+#define MVolumeNumber "volume %d"
+#define MCannotDelete "\nCannot delete %s"
+#define MCalcCRC "\nCalculating the control sum"
+#define MTooLargeSFXArc "\nWARNING: Too large SFX archive. Windows cannot run the executable file exceeding 4 GB."
+#define MCalcCRCAllVol "\nCalculating control sums of all volumes."
+#define MNotEnoughDisk "\nERROR: Not enough disk space for %s."
diff --git a/src/unrar/log.cpp b/src/unrar/log.cpp
new file mode 100644
index 0000000000..966e9de150
--- /dev/null
+++ b/src/unrar/log.cpp
@@ -0,0 +1,24 @@
+#include "rar.hpp"
+
+
+static char LogName[NM];
+
+void InitLogOptions(char *LogName)
+{
+ strcpy(::LogName,LogName);
+}
+
+
+#ifndef SILENT
+void Log(const char *ArcName,const char *Format,...)
+{
+ safebuf char Msg[2*NM+1024];
+ va_list ArgPtr;
+ va_start(ArgPtr,Format);
+ vsprintf(Msg,Format,ArgPtr);
+ va_end(ArgPtr);
+ eprintf("%s",Msg);
+}
+#endif
+
+
diff --git a/src/unrar/log.hpp b/src/unrar/log.hpp
new file mode 100644
index 0000000000..52d6b8d56d
--- /dev/null
+++ b/src/unrar/log.hpp
@@ -0,0 +1,18 @@
+#ifndef _RAR_LOG_
+#define _RAR_LOG_
+
+void InitLogOptions(char *LogName);
+
+#ifndef SILENT
+void Log(const char *ArcName,const char *Format,...);
+#endif
+
+#ifdef SILENT
+#ifdef __GNUC__
+#define Log(args...)
+#else
+inline void Log(const char *a,const char *b,const char *c=NULL,const char *d=NULL) {}
+#endif
+#endif
+
+#endif
diff --git a/src/unrar/makefile.bcc b/src/unrar/makefile.bcc
new file mode 100644
index 0000000000..94a12bffda
--- /dev/null
+++ b/src/unrar/makefile.bcc
@@ -0,0 +1,493 @@
+.AUTODEPEND
+
+basepath = $(BASEPATHCC)
+binpath = $(basepath)\bin
+libpath = $(basepath)\lib
+rarpath = .
+incpath = $(basepath)\include;$(rarpath)
+
+cc = $(binpath)\bcc32
+link = $(binpath)\ilink32
+
+objpath = .
+guiopt = -WC -H=$(objpath)\rar.csm
+
+!ifdef SFX_MODULE
+guiopt=$(guiopt) -x-
+!endif
+
+!ifdef DEBUG
+optdeb=-Od -k -vi- -DDEBUG
+!else
+# -O is not safe to use with -pr and int64 return values, so let's turn it off
+optdeb=-O1 -O- -k-
+#optdeb=-Ob -Oe -Og -Oi -Ol -Om -Op -OS -Ov -Z -Oc
+!endif
+
+
+optunrar=-DUNRAR
+linkdest=unrar.exe
+
+!ifdef SFX_MODULE
+optunrar=-DUNRAR -DSFX_MODULE
+linkdest=sfx.exe
+!endif
+
+linkopt = -L$(libpath) -ap -c -v -s -V4.0 -Gn
+compopt = -P -c -I$(incpath) -R -v -vi -w-pch -w-par -K -f-\
+ -ff- -a4 -pr -RT- $(optdeb) $(guiopt) $(optunrar) -d -w-8072
+
+!ifdef RARDLL
+SILENT=true
+linkdest=unrar.dll
+linkopt=$(linkopt) -Tpd
+compopt=$(compopt) -DRARDLL
+!else
+linkopt=$(linkopt) -Tpe -B:0x400000
+!endif
+
+!ifdef SILENT
+compopt=$(compopt) -DSILENT
+!endif
+
+
+rar: $(linkdest)
+
+Dep_SFX= \
+ $(objpath)\strlist.obj\
+ $(objpath)\strfn.obj\
+ $(objpath)\pathfn.obj\
+ $(objpath)\secpassword.obj\
+ $(objpath)\cmddata.obj\
+ $(objpath)\consio.obj\
+ $(objpath)\savepos.obj\
+ $(objpath)\smallfn.obj\
+ $(objpath)\file.obj\
+ $(objpath)\filefn.obj\
+ $(objpath)\filcreat.obj\
+ $(objpath)\sha1.obj\
+ $(objpath)\archive.obj\
+ $(objpath)\arcread.obj\
+ $(objpath)\unicode.obj\
+ $(objpath)\system.obj\
+ $(objpath)\isnt.obj\
+ $(objpath)\crc.obj\
+ $(objpath)\crypt.obj\
+ $(objpath)\rijndael.obj\
+ $(objpath)\rawread.obj\
+ $(objpath)\encname.obj\
+ $(objpath)\resource.obj\
+ $(objpath)\match.obj\
+ $(objpath)\find.obj\
+ $(objpath)\timefn.obj\
+ $(objpath)\getbits.obj\
+ $(objpath)\rarvm.obj\
+ $(objpath)\rdwrfn.obj\
+ $(objpath)\options.obj\
+ $(objpath)\ulinks.obj\
+ $(objpath)\errhnd.obj\
+ $(objpath)\volume.obj\
+ $(objpath)\rs.obj\
+ $(objpath)\recvol.obj\
+ $(objpath)\extinfo.obj\
+ $(objpath)\extract.obj\
+ $(objpath)\unpack.obj\
+ $(objpath)\rar.obj\
+ $(objpath)\global.obj
+
+Dep_Unrar = \
+ $(objpath)\filestr.obj\
+ $(objpath)\scantree.obj
+
+Dep_Dll = \
+ $(objpath)\dll.obj
+
+#Dep_SFXOnly = $(objpath)\rtl.obj
+
+!ifndef GUI
+!ifndef SILENT
+Dep_Console = \
+ $(objpath)\list.obj
+!endif
+!endif
+
+!ifdef SFX_MODULE
+Dep = $(Dep_SFX) $(Dep_SFXOnly)
+!else
+Dep = $(Dep_SFX) $(Dep_Unrar)
+!endif
+
+!ifndef GUI
+Dep = $(Dep) $(Dep_Console)
+!endif
+
+!ifdef RARDLL
+Dep = $(Dep) $(Dep_Dll)
+!endif
+
+!ifdef GUI
+$(linkdest) : $(Dep)
+ echo Done
+!else
+$(linkdest) : $(Dep)
+ $(link) @&&|
+ $(linkopt) +
+#!ifdef SFX_MODULE
+#$(objpath)\dummy.obj+
+#$(objpath)\ll.obj+
+#$(objpath)\rtl.obj+
+#!else
+!ifdef RARDLL
+$(libpath)\c0d32.obj+
+!else
+$(libpath)\c0x32.obj+
+!endif
+#!endif
+$(objpath)\strlist.obj+
+$(objpath)\strfn.obj+
+$(objpath)\pathfn.obj+
+$(objpath)\savepos.obj+
+$(objpath)\smallfn.obj+
+$(objpath)\global.obj+
+$(objpath)\file.obj+
+$(objpath)\filefn.obj+
+$(objpath)\filcreat.obj+
+$(objpath)\sha1.obj+
+$(objpath)\archive.obj+
+$(objpath)\arcread.obj+
+$(objpath)\unicode.obj+
+$(objpath)\system.obj+
+$(objpath)\isnt.obj+
+$(objpath)\crc.obj+
+$(objpath)\crypt.obj+
+$(objpath)\rijndael.obj+
+$(objpath)\rawread.obj+
+$(objpath)\encname.obj+
+$(objpath)\resource.obj+
+$(objpath)\match.obj+
+$(objpath)\find.obj+
+!ifndef SFX_MODULE
+$(objpath)\filestr.obj+
+$(objpath)\scantree.obj+
+!endif
+$(objpath)\timefn.obj+
+$(objpath)\getbits.obj+
+$(objpath)\rarvm.obj+
+$(objpath)\rdwrfn.obj+
+$(objpath)\consio.obj+
+$(objpath)\secpassword.obj+
+$(objpath)\cmddata.obj+
+$(objpath)\options.obj+
+$(objpath)\ulinks.obj+
+$(objpath)\volume.obj+
+$(objpath)\extinfo.obj+
+$(objpath)\extract.obj+
+$(objpath)\rs.obj+
+$(objpath)\recvol.obj+
+!ifndef SILENT
+!ifndef GUI
+$(objpath)\list.obj+
+!endif
+!endif
+!ifdef RARDLL
+$(objpath)\dll.obj+
+!endif
+$(objpath)\errhnd.obj+
+$(objpath)\unpack.obj+
+$(objpath)\rar.obj
+$<,$*
+$(libpath)\cw32.lib+
+$(libpath)\import32.lib
+!ifdef RARDLL
+$(rarpath)\dll.def
+!else
+
+!endif
+|
+!endif
+
+$(objpath)\rar.obj : $(rarpath)\rar.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\rar.cpp
+|
+
+$(objpath)\strlist.obj : $(rarpath)\strlist.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\strlist.cpp
+|
+
+$(objpath)\strfn.obj : $(rarpath)\strfn.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\strfn.cpp
+|
+
+$(objpath)\pathfn.obj : $(rarpath)\pathfn.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\pathfn.cpp
+|
+
+$(objpath)\savepos.obj : $(rarpath)\savepos.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\savepos.cpp
+|
+
+$(objpath)\smallfn.obj : $(rarpath)\smallfn.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\smallfn.cpp
+|
+
+$(objpath)\global.obj : $(rarpath)\global.cpp
+ $(cc) -q @&&|
+ $(compopt) -H- -o$@ $(rarpath)\global.cpp
+|
+
+$(objpath)\file.obj : $(rarpath)\file.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\file.cpp
+|
+
+$(objpath)\filefn.obj : $(rarpath)\filefn.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\filefn.cpp
+|
+
+$(objpath)\filestr.obj : $(rarpath)\filestr.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\filestr.cpp
+|
+
+$(objpath)\filcreat.obj : $(rarpath)\filcreat.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\filcreat.cpp
+|
+
+$(objpath)\sha1.obj : $(rarpath)\sha1.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\sha1.cpp
+|
+
+$(objpath)\archive.obj : $(rarpath)\archive.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\archive.cpp
+|
+
+$(objpath)\arcread.obj : $(rarpath)\arcread.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\arcread.cpp
+|
+
+$(objpath)\unicode.obj : $(rarpath)\unicode.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\unicode.cpp
+|
+
+$(objpath)\system.obj : $(rarpath)\system.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\system.cpp
+|
+
+$(objpath)\isnt.obj : $(rarpath)\isnt.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\isnt.cpp
+|
+
+$(objpath)\crc.obj : $(rarpath)\crc.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\crc.cpp
+|
+
+$(objpath)\crypt.obj : $(rarpath)\crypt.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\crypt.cpp
+|
+
+$(objpath)\rijndael.obj : $(rarpath)\rijndael.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\rijndael.cpp
+|
+
+$(objpath)\rawread.obj : $(rarpath)\rawread.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\rawread.cpp
+|
+
+$(objpath)\rawwrite.obj : $(rarpath)\rawwrite.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\rawwrite.cpp
+|
+
+$(objpath)\encname.obj : $(rarpath)\encname.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\encname.cpp
+|
+
+$(objpath)\resource.obj : $(rarpath)\resource.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\resource.cpp
+|
+
+$(objpath)\match.obj : $(rarpath)\match.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\match.cpp
+|
+
+$(objpath)\find.obj : $(rarpath)\find.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\find.cpp
+|
+
+$(objpath)\scantree.obj : $(rarpath)\scantree.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\scantree.cpp
+|
+
+$(objpath)\timefn.obj : $(rarpath)\timefn.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\timefn.cpp
+|
+
+$(objpath)\getbits.obj : $(rarpath)\getbits.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\getbits.cpp
+|
+
+$(objpath)\rarvm.obj : $(rarpath)\rarvm.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\rarvm.cpp
+|
+
+$(objpath)\putbits.obj : $(rarpath)\putbits.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\putbits.cpp
+|
+
+$(objpath)\pack.obj : $(rarpath)\pack.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\pack.cpp
+|
+
+$(objpath)\packbord.obj : $(rarpath)\packbord.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\packbord.cpp
+|
+
+$(objpath)\packanlz.obj : $(rarpath)\packanlz.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\packanlz.cpp
+|
+
+$(objpath)\cblock.obj : $(rarpath)\cblock.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\cblock.cpp
+|
+
+$(objpath)\add.obj : $(rarpath)\add.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\add.cpp
+|
+
+$(objpath)\addlist.obj : $(rarpath)\addlist.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\addlist.cpp
+|
+
+$(objpath)\procarc.obj : $(rarpath)\procarc.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\procarc.cpp
+|
+
+$(objpath)\sfx.obj : $(rarpath)\sfx.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\sfx.cpp
+|
+
+$(objpath)\comment.obj : $(rarpath)\comment.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\comment.cpp
+|
+
+$(objpath)\rs.obj : $(rarpath)\rs.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\rs.cpp
+|
+
+$(objpath)\recvol.obj : $(rarpath)\recvol.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\recvol.cpp
+|
+
+$(objpath)\repair.obj : $(rarpath)\repair.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\repair.cpp
+|
+
+$(objpath)\rdwrfn.obj : $(rarpath)\rdwrfn.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\rdwrfn.cpp
+|
+
+$(objpath)\consio.obj : $(rarpath)\consio.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\consio.cpp
+|
+
+$(objpath)\secpassword.obj : $(rarpath)\secpassword.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\secpassword.cpp
+|
+
+$(objpath)\cmddata.obj : $(rarpath)\cmddata.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\cmddata.cpp
+|
+
+$(objpath)\options.obj : $(rarpath)\options.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\options.cpp
+|
+
+$(objpath)\ulinks.obj : $(rarpath)\ulinks.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\ulinks.cpp
+|
+
+$(objpath)\errhnd.obj : $(rarpath)\errhnd.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\errhnd.cpp
+|
+
+$(objpath)\volume.obj : $(rarpath)\volume.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\volume.cpp
+|
+
+$(objpath)\extinfo.obj : $(rarpath)\extinfo.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\extinfo.cpp
+|
+
+
+$(objpath)\extract.obj : $(rarpath)\extract.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\extract.cpp
+|
+
+$(objpath)\list.obj : $(rarpath)\list.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\list.cpp
+|
+
+$(objpath)\rtl.obj : $(rarpath)\rtl.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\rtl.cpp
+|
+
+$(objpath)\unpack.obj : $(rarpath)\unpack.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\unpack.cpp
+|
+
+$(objpath)\dll.obj : $(rarpath)\dll.cpp
+ $(cc) -q @&&|
+ $(compopt) -o$@ $(rarpath)\dll.cpp
+|
\ No newline at end of file
diff --git a/src/unrar/makefile.dj b/src/unrar/makefile.dj
new file mode 100644
index 0000000000..62376b291e
--- /dev/null
+++ b/src/unrar/makefile.dj
@@ -0,0 +1,50 @@
+#
+# Makefile for DJGPP - unrar
+#
+# Note: you have to 'make clean' before you can build
+# the sfx module
+#
+
+# DOS32 using DJGPP 2.03 Patchlevel 2 and GCC 2.95.3
+CXX = gpp
+CXXFLAGS = -O2 -Wno-deprecated
+#DEFINES = -D_MSC_VER -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+
+##########################
+
+.PHONY: all clean veryclean
+
+COMPILE=$(CXX) $(CXXFLAGS) $(DEFINES)
+LINK=$(CXX)
+
+UNRAR_OBJ=filestr.o recvol.o rs.o scantree.o
+
+OBJECTS=rar.o strlist.o strfn.o pathfn.o savepos.o smallfn.o global.o \
+ file.o filefn.o filcreat.o archive.o arcread.o unicode.o \
+ system.o isnt.o crypt.o crc.o rawread.o encname.o \
+ resource.o match.o timefn.o rdwrfn.o consio.o options.o \
+ ulinks.o errhnd.o rarvm.o rijndael.o getbits.o sha1.o \
+ extinfo.o extract.o volume.o list.o find.o unpack.o secpassword.o cmddata.o
+
+.cpp.o:
+ $(COMPILE) -D$(WHAT) -c $<
+
+all: unrar
+
+unrar: WHAT=UNRAR
+unrar: $(OBJECTS) $(UNRAR_OBJ)
+ $(LINK) -Wl,-s -o unrar.exe $(LDFLAGS) $(OBJECTS) $(UNRAR_OBJ) $(LIBS)
+ exe2coff unrar.exe
+ cp -u $(DJDIR)/bin/cwsdstub.exe .
+ copy /b cwsdstub.exe+unrar unrar.exe
+ -upx --ultra-brute unrar.exe
+
+sfx: WHAT=SFX_MODULE
+sfx: $(OBJECTS)
+ $(LINK) -Wl,-s -o default.sfx $(LDFLAGS) $(OBJECTS) -DSFX_MODULE
+
+clean:
+ $(RM) $(OBJECTS) $(UNRAR_OBJ)
+
+veryclean: clean
+ $(RM) unrar.exe default.sfx cwsdstub.exe unrar
diff --git a/src/unrar/makefile.dmc b/src/unrar/makefile.dmc
new file mode 100644
index 0000000000..83bf65e92f
--- /dev/null
+++ b/src/unrar/makefile.dmc
@@ -0,0 +1,54 @@
+# Makefile for Digital Mars C++ Compiler
+# http://www.rarlab.com
+# http://www.digitalmars.com
+#
+# DEFINES: UNRAR RARDLL GUI SFX_MODULE SILENT
+
+NAME = unrar
+EXT = exe
+
+CPP = dmc
+
+LINK = link
+
+# --------------
+# Release Build
+# --------------
+DEFINES = -DNDEBUG -D_MSC_VER -DUNRAR
+CPPFLAGS = -o+all -ff -Nc -g- -Ae
+LNKFLAGS = /EXETYPE:NT /MACHINE:i386 /SUBSYSTEM:CONSOLE /NOLOGO /NODEBUG /NOCODEVIEW /PACKFUNCTIONS
+
+# --------------
+# Debug Build
+# --------------
+#DEFINES = -D_DEBUG -D_MSC_VER -DUNRAR
+#CPPFLAGS = -o+none -Nc -S -gf -Ae
+#LNKFLAGS = /EXETYPE:NT /MACHINE:i386 /SUBSYSTEM:CONSOLE /NOLOGO /DEBUG
+
+OBJ = rar.obj strlist.obj strfn.obj pathfn.obj savepos.obj smallfn.o global.obj \
+ file.obj filefn.obj filcreat.obj archive.obj arcread.obj unicode.obj \
+ system.obj isnt.obj crypt.obj crc.obj rawread.obj encname.obj \
+ resource.obj match.obj timefn.obj rdwrfn.obj consio.obj options.obj \
+ ulinks.obj errhnd.obj rarvm.obj rijndael.obj getbits.obj sha1.obj \
+ extinfo.obj extract.obj volume.obj find.obj unpack.obj cmddata.obj \
+ secpassword.obj filestr.obj recvol.obj rs.obj scantree.obj \
+ list.obj \
+# dll.obj \
+
+LIB = kernel32.lib+user32.lib+advapi32.lib
+
+#DEF = dll.def
+
+link: $(OBJ)
+ $(LINK) $(LNKFLAGS) $(OBJ), $(NAME).$(EXT), $(NAME).map, $(LIB), $(DEF)
+
+.c.obj:
+ $(CPP) $(CPPFLAGS) $(DEFINES) -c $< -o $@
+
+.cpp.obj:
+ $(CPP) $(CPPFLAGS) $(DEFINES) -c $< -o $@
+
+clean:
+ del $(OBJ)
+ del $(NAME).$(EXT)
+ del $(NAME).map
diff --git a/src/unrar/makefile.unix b/src/unrar/makefile.unix
new file mode 100644
index 0000000000..bd06092233
--- /dev/null
+++ b/src/unrar/makefile.unix
@@ -0,0 +1,146 @@
+#
+# Makefile for UNIX - unrar
+
+# Linux using GCC
+CXX=g++
+CXXFLAGS=-O2
+LIBFLAGS=-fPIC
+DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+STRIP=strip
+DESTDIR=/usr
+
+# Linux using LCC
+#CXX=lcc
+#CXXFLAGS=-O2
+#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+#STRIP=strip
+#DESTDIR=/usr
+
+# HP UX using aCC
+#CXX=aCC
+#CXXFLAGS=-AA +O2 +Onolimit
+#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+#STRIP=strip
+#DESTDIR=/usr
+
+# IRIX using GCC
+#CXX=g++
+#CXXFLAGS=-O2
+#DEFINES=-DBIG_ENDIAN -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_BSD_COMPAT -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED=1
+#STRIP=strip
+#DESTDIR=/usr
+
+# IRIX using MIPSPro (experimental)
+#CXX=CC
+#CXXFLAGS=-O2 -mips3 -woff 1234,1156,3284 -LANG:std
+#DEFINES=-DBIG_ENDIAN -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_BSD_COMPAT -Dint64=int64_t
+#STRIP=strip
+#DESTDIR=/usr
+
+# AIX using xlC (IBM VisualAge C++ 5.0)
+#CXX=xlC
+#CXXFLAGS=-O -qinline -qro -qroconst -qmaxmem=16384 -qcpluscmt
+#DEFINES=-D_LARGE_FILES -D_LARGE_FILE_API
+#LIBS=-lbsd
+#STRIP=strip
+#DESTDIR=/usr
+
+# Solaris using CC
+#CXX=CC
+#CXXFLAGS=-fast -erroff=wvarhidemem
+#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+#STRIP=strip
+#DESTDIR=/usr
+
+# Solaris using GCC (optimized for UltraSPARC 1 CPU)
+#CXX=g++
+#CXXFLAGS=-O3 -mcpu=v9 -mtune=ultrasparc -m32
+#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+#STRIP=/usr/ccs/bin/strip
+#DESTDIR=/usr
+
+# Tru64 5.1B using GCC3
+#CXX=g++
+#CXXFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_XOPEN_SOURCE=500
+#STRIP=strip
+#LDFLAGS=-rpath /usr/local/gcc/lib
+#DESTDIR=/usr
+
+# Tru64 5.1B using DEC C++
+#CXX=cxx
+#CXXFLAGS=-O4 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Dint64=long
+#STRIP=strip
+#LDFLAGS=
+#DESTDIR=/usr
+
+# QNX 6.x using GCC
+#CXX=g++
+#CXXFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -fexceptions
+#STRIP=strip
+#LDFLAGS=-fexceptions
+#DESTDIR=/usr
+
+# Cross-compile
+# Linux using arm-linux-g++
+#CXX=arm-linux-g++
+#CXXFLAGS=-O2
+#DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+#STRIP=arm-linux-strip
+#LDFLAGS=-static
+#DESTDIR=/usr
+
+##########################
+
+COMPILE=$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEFINES)
+LINK=$(CXX)
+
+WHAT=UNRAR
+
+UNRAR_OBJ=filestr.o recvol.o rs.o scantree.o
+LIB_OBJ=filestr.o scantree.o dll.o
+
+OBJECTS=rar.o strlist.o strfn.o pathfn.o savepos.o smallfn.o global.o file.o filefn.o filcreat.o \
+ archive.o arcread.o unicode.o system.o isnt.o crypt.o crc.o rawread.o encname.o \
+ resource.o match.o timefn.o rdwrfn.o consio.o options.o ulinks.o errhnd.o rarvm.o secpassword.o \
+ rijndael.o getbits.o sha1.o extinfo.o extract.o volume.o list.o find.o unpack.o cmddata.o
+
+.cpp.o:
+ $(COMPILE) -D$(WHAT) -c $<
+
+all: unrar
+
+install: install-unrar
+
+uninstall: uninstall-unrar
+
+clean:
+ @rm -f *.o *.bak *~
+
+unrar: clean $(OBJECTS) $(UNRAR_OBJ)
+ @rm -f unrar
+ $(LINK) -o unrar $(LDFLAGS) $(OBJECTS) $(UNRAR_OBJ) $(LIBS)
+ $(STRIP) unrar
+
+sfx: WHAT=SFX_MODULE
+sfx: clean $(OBJECTS)
+ @rm -f default.sfx
+ $(LINK) -o default.sfx $(LDFLAGS) $(OBJECTS)
+ $(STRIP) default.sfx
+
+lib: WHAT=RARDLL
+lib: CXXFLAGS+=$(LIBFLAGS)
+lib: clean $(OBJECTS) $(LIB_OBJ)
+ @rm -f libunrar.so
+ $(LINK) -shared -o libunrar.so $(LDFLAGS) $(OBJECTS) $(LIB_OBJ)
+
+install-unrar:
+ install -D unrar $(DESTDIR)/bin/unrar
+
+uninstall-unrar:
+ rm -f $(DESTDIR)/bin/unrar
+
+install-lib:
+ install libunrar.so $(DESTDIR)/lib
+
+uninstall-lib:
+ rm -f $(DESTDIR)/lib/libunrar.so
diff --git a/src/unrar/match.cpp b/src/unrar/match.cpp
new file mode 100644
index 0000000000..4d5a1d053c
--- /dev/null
+++ b/src/unrar/match.cpp
@@ -0,0 +1,300 @@
+#include "rar.hpp"
+
+static bool match(const char *pattern,const char *string,bool ForceCase);
+static bool match(const wchar *pattern,const wchar *string,bool ForceCase);
+
+static int mstricompc(const char *Str1,const char *Str2,bool ForceCase);
+static int mwcsicompc(const wchar *Str1,const wchar *Str2,bool ForceCase);
+static int mstrnicompc(const char *Str1,const char *Str2,size_t N,bool ForceCase);
+static int mwcsnicompc(const wchar *Str1,const wchar *Str2,size_t N,bool ForceCase);
+
+inline uint toupperc(byte ch,bool ForceCase)
+{
+ if (ForceCase)
+ return(ch);
+#ifdef _WIN_ALL
+ return((uint)(LPARAM)CharUpper((LPTSTR)(ch)));
+#elif defined(_UNIX)
+ return(ch);
+#else
+ return(toupper(ch));
+#endif
+}
+
+
+inline uint touppercw(uint ch,bool ForceCase)
+{
+ if (ForceCase)
+ return(ch);
+#if defined(_UNIX)
+ return(ch);
+#else
+ return(toupperw(ch));
+#endif
+}
+
+
+bool CmpName(const char *Wildcard,const char *Name,int CmpMode)
+{
+ bool ForceCase=(CmpMode&MATCH_FORCECASESENSITIVE)!=0;
+
+ CmpMode&=MATCH_MODEMASK;
+
+ if (CmpMode!=MATCH_NAMES)
+ {
+ size_t WildLength=strlen(Wildcard);
+ if (CmpMode!=MATCH_EXACT && CmpMode!=MATCH_EXACTPATH &&
+ mstrnicompc(Wildcard,Name,WildLength,ForceCase)==0)
+ {
+ // For all modes except MATCH_NAMES, MATCH_EXACT and MATCH_EXACTPATH
+ // "path1" mask must match "path1\path2\filename.ext" and "path1" names.
+ char NextCh=Name[WildLength];
+ if (NextCh=='\\' || NextCh=='/' || NextCh==0)
+ return(true);
+ }
+
+ // Nothing more to compare for MATCH_SUBPATHONLY.
+ if (CmpMode==MATCH_SUBPATHONLY)
+ return(false);
+
+ char Path1[NM],Path2[NM];
+ GetFilePath(Wildcard,Path1,ASIZE(Path1));
+ GetFilePath(Name,Path2,ASIZE(Path1));
+
+ if ((CmpMode==MATCH_EXACT || CmpMode==MATCH_EXACTPATH) &&
+ mstricompc(Path1,Path2,ForceCase)!=0)
+ return(false);
+ if (CmpMode==MATCH_SUBPATH || CmpMode==MATCH_WILDSUBPATH)
+ if (IsWildcard(Path1))
+ return(match(Wildcard,Name,ForceCase));
+ else
+ if (CmpMode==MATCH_SUBPATH || IsWildcard(Wildcard))
+ {
+ if (*Path1 && mstrnicompc(Path1,Path2,strlen(Path1),ForceCase)!=0)
+ return(false);
+ }
+ else
+ if (mstricompc(Path1,Path2,ForceCase)!=0)
+ return(false);
+ }
+ char *Name1=PointToName(Wildcard);
+ char *Name2=PointToName(Name);
+
+ // Always return false for RAR temporary files to exclude them
+ // from archiving operations.
+ if (mstrnicompc("__rar_",Name2,6,false)==0)
+ return(false);
+
+ if (CmpMode==MATCH_EXACT)
+ return(mstricompc(Name1,Name2,ForceCase)==0);
+
+ return(match(Name1,Name2,ForceCase));
+}
+
+
+#ifndef SFX_MODULE
+bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode)
+{
+ bool ForceCase=(CmpMode&MATCH_FORCECASESENSITIVE)!=0;
+
+ CmpMode&=MATCH_MODEMASK;
+
+ if (CmpMode!=MATCH_NAMES)
+ {
+ size_t WildLength=wcslen(Wildcard);
+ if (CmpMode!=MATCH_EXACT && CmpMode!=MATCH_EXACTPATH &&
+ mwcsnicompc(Wildcard,Name,WildLength,ForceCase)==0)
+ {
+ // For all modes except MATCH_NAMES, MATCH_EXACT and MATCH_EXACTPATH
+ // "path1" mask must match "path1\path2\filename.ext" and "path1" names.
+ wchar NextCh=Name[WildLength];
+ if (NextCh==L'\\' || NextCh==L'/' || NextCh==0)
+ return(true);
+ }
+
+ // Nothing more to compare for MATCH_SUBPATHONLY.
+ if (CmpMode==MATCH_SUBPATHONLY)
+ return(false);
+
+ wchar Path1[NM],Path2[NM];
+ GetFilePath(Wildcard,Path1,ASIZE(Path1));
+ GetFilePath(Name,Path2,ASIZE(Path2));
+
+ if ((CmpMode==MATCH_EXACT || CmpMode==MATCH_EXACTPATH) &&
+ mwcsicompc(Path1,Path2,ForceCase)!=0)
+ return(false);
+ if (CmpMode==MATCH_SUBPATH || CmpMode==MATCH_WILDSUBPATH)
+ if (IsWildcard(NULL,Path1))
+ return(match(Wildcard,Name,ForceCase));
+ else
+ if (CmpMode==MATCH_SUBPATH || IsWildcard(NULL,Wildcard))
+ {
+ if (*Path1 && mwcsnicompc(Path1,Path2,wcslen(Path1),ForceCase)!=0)
+ return(false);
+ }
+ else
+ if (mwcsicompc(Path1,Path2,ForceCase)!=0)
+ return(false);
+ }
+ wchar *Name1=PointToName(Wildcard);
+ wchar *Name2=PointToName(Name);
+
+ // Always return false for RAR temporary files to exclude them
+ // from archiving operations.
+ if (mwcsnicompc(L"__rar_",Name2,6,false)==0)
+ return(false);
+
+ if (CmpMode==MATCH_EXACT)
+ return(mwcsicompc(Name1,Name2,ForceCase)==0);
+
+ return(match(Name1,Name2,ForceCase));
+}
+#endif
+
+
+bool match(const char *pattern,const char *string,bool ForceCase)
+{
+ for (;; ++string)
+ {
+ char stringc=toupperc(*string,ForceCase);
+ char patternc=toupperc(*pattern++,ForceCase);
+ switch (patternc)
+ {
+ case 0:
+ return(stringc==0);
+ case '?':
+ if (stringc == 0)
+ return(false);
+ break;
+ case '*':
+ if (*pattern==0)
+ return(true);
+ if (*pattern=='.')
+ {
+ if (pattern[1]=='*' && pattern[2]==0)
+ return(true);
+ const char *dot=strchr(string,'.');
+ if (pattern[1]==0)
+ return (dot==NULL || dot[1]==0);
+ if (dot!=NULL)
+ {
+ string=dot;
+ if (strpbrk(pattern,"*?")==NULL && strchr(string+1,'.')==NULL)
+ return(mstricompc(pattern+1,string+1,ForceCase)==0);
+ }
+ }
+
+ while (*string)
+ if (match(pattern,string++,ForceCase))
+ return(true);
+ return(false);
+ default:
+ if (patternc != stringc)
+ {
+ // Allow "name." mask match "name" and "name.\" match "name\".
+ if (patternc=='.' && (stringc==0 || stringc=='\\' || stringc=='.'))
+ return(match(pattern,string,ForceCase));
+ else
+ return(false);
+ }
+ break;
+ }
+ }
+}
+
+
+#ifndef SFX_MODULE
+bool match(const wchar *pattern,const wchar *string,bool ForceCase)
+{
+ for (;; ++string)
+ {
+ wchar stringc=touppercw(*string,ForceCase);
+ wchar patternc=touppercw(*pattern++,ForceCase);
+ switch (patternc)
+ {
+ case 0:
+ return(stringc==0);
+ case '?':
+ if (stringc == 0)
+ return(false);
+ break;
+ case '*':
+ if (*pattern==0)
+ return(true);
+ if (*pattern=='.')
+ {
+ if (pattern[1]=='*' && pattern[2]==0)
+ return(true);
+ const wchar *dot=wcschr(string,'.');
+ if (pattern[1]==0)
+ return (dot==NULL || dot[1]==0);
+ if (dot!=NULL)
+ {
+ string=dot;
+ if (wcspbrk(pattern,L"*?")==NULL && wcschr(string+1,'.')==NULL)
+ return(mwcsicompc(pattern+1,string+1,ForceCase)==0);
+ }
+ }
+
+ while (*string)
+ if (match(pattern,string++,ForceCase))
+ return(true);
+ return(false);
+ default:
+ if (patternc != stringc)
+ {
+ // Allow "name." mask match "name" and "name.\" match "name\".
+ if (patternc=='.' && (stringc==0 || stringc=='\\' || stringc=='.'))
+ return(match(pattern,string,ForceCase));
+ else
+ return(false);
+ }
+ break;
+ }
+ }
+}
+#endif
+
+
+int mstricompc(const char *Str1,const char *Str2,bool ForceCase)
+{
+ if (ForceCase)
+ return(strcmp(Str1,Str2));
+ return(stricompc(Str1,Str2));
+}
+
+
+#ifndef SFX_MODULE
+int mwcsicompc(const wchar *Str1,const wchar *Str2,bool ForceCase)
+{
+ if (ForceCase)
+ return(wcscmp(Str1,Str2));
+ return(wcsicompc(Str1,Str2));
+}
+#endif
+
+
+int mstrnicompc(const char *Str1,const char *Str2,size_t N,bool ForceCase)
+{
+ if (ForceCase)
+ return(strncmp(Str1,Str2,N));
+#if defined(_UNIX)
+ return(strncmp(Str1,Str2,N));
+#else
+ return(strnicomp(Str1,Str2,N));
+#endif
+}
+
+
+#ifndef SFX_MODULE
+int mwcsnicompc(const wchar *Str1,const wchar *Str2,size_t N,bool ForceCase)
+{
+ if (ForceCase)
+ return(wcsncmp(Str1,Str2,N));
+#if defined(_UNIX)
+ return(wcsncmp(Str1,Str2,N));
+#else
+ return(wcsnicomp(Str1,Str2,N));
+#endif
+}
+#endif
diff --git a/src/unrar/match.hpp b/src/unrar/match.hpp
new file mode 100644
index 0000000000..697286d855
--- /dev/null
+++ b/src/unrar/match.hpp
@@ -0,0 +1,35 @@
+#ifndef _RAR_MATCH_
+#define _RAR_MATCH_
+
+enum {
+ MATCH_NAMES, // Paths are ignored.
+ // Compares names only using wildcards.
+
+ MATCH_SUBPATHONLY, // Paths must match either exactly or path in wildcard
+ // must be present in the beginning of file path.
+ // For example, "c:\path1\*" or "c:\path1" will match
+ // "c:\path1\path2\file".
+ // Names are not compared.
+
+ MATCH_EXACT, // Paths must match exactly.
+ // Names must match exactly.
+
+ MATCH_EXACTPATH, // Paths must match exactly.
+ // Names are compared using wildcards.
+
+ MATCH_SUBPATH, // Names must be the same, but path in mask is allowed
+ // to be only a part of name path. In other words,
+ // we match all files matching the file mask
+ // in current folder and subfolders.
+
+ MATCH_WILDSUBPATH // Works as MATCH_SUBPATH if file mask contains
+ // wildcards and as MATCH_EXACTPATH otherwise.
+};
+
+#define MATCH_MODEMASK 0x0000ffff
+#define MATCH_FORCECASESENSITIVE 0x80000000
+
+bool CmpName(const char *Wildcard,const char *Name,int CmpMode);
+bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode);
+
+#endif
diff --git a/src/unrar/model.cpp b/src/unrar/model.cpp
new file mode 100644
index 0000000000..fb28c0774a
--- /dev/null
+++ b/src/unrar/model.cpp
@@ -0,0 +1,610 @@
+/****************************************************************************
+ * This file is part of PPMd project *
+ * Written and distributed to public domain by Dmitry Shkarin 1997, *
+ * 1999-2000 *
+ * Contents: model description and encoding/decoding routines *
+ ****************************************************************************/
+
+inline PPM_CONTEXT* PPM_CONTEXT::createChild(ModelPPM *Model,STATE* pStats,
+ STATE& FirstState)
+{
+ PPM_CONTEXT* pc = (PPM_CONTEXT*) Model->SubAlloc.AllocContext();
+ if ( pc )
+ {
+ pc->NumStats=1;
+ pc->OneState=FirstState;
+ pc->Suffix=this;
+ pStats->Successor=pc;
+ }
+ return pc;
+}
+
+
+ModelPPM::ModelPPM()
+{
+ MinContext=NULL;
+ MaxContext=NULL;
+ MedContext=NULL;
+}
+
+
+void ModelPPM::RestartModelRare()
+{
+ int i, k, m;
+ memset(CharMask,0,sizeof(CharMask));
+ SubAlloc.InitSubAllocator();
+ InitRL=-(MaxOrder < 12 ? MaxOrder:12)-1;
+ MinContext = MaxContext = (PPM_CONTEXT*) SubAlloc.AllocContext();
+ MinContext->Suffix=NULL;
+ OrderFall=MaxOrder;
+ MinContext->U.SummFreq=(MinContext->NumStats=256)+1;
+ FoundState=MinContext->U.Stats=(STATE*)SubAlloc.AllocUnits(256/2);
+ for (RunLength=InitRL, PrevSuccess=i=0;i < 256;i++)
+ {
+ MinContext->U.Stats[i].Symbol=i;
+ MinContext->U.Stats[i].Freq=1;
+ MinContext->U.Stats[i].Successor=NULL;
+ }
+
+ static const ushort InitBinEsc[]={
+ 0x3CDD,0x1F3F,0x59BF,0x48F3,0x64A1,0x5ABC,0x6632,0x6051
+ };
+
+ for (i=0;i < 128;i++)
+ for (k=0;k < 8;k++)
+ for (m=0;m < 64;m += 8)
+ BinSumm[i][k+m]=BIN_SCALE-InitBinEsc[k]/(i+2);
+ for (i=0;i < 25;i++)
+ for (k=0;k < 16;k++)
+ SEE2Cont[i][k].init(5*i+10);
+}
+
+
+void ModelPPM::StartModelRare(int MaxOrder)
+{
+ int i, k, m ,Step;
+ EscCount=1;
+/*
+ if (MaxOrder < 2)
+ {
+ memset(CharMask,0,sizeof(CharMask));
+ OrderFall=ModelPPM::MaxOrder;
+ MinContext=MaxContext;
+ while (MinContext->Suffix != NULL)
+ {
+ MinContext=MinContext->Suffix;
+ OrderFall--;
+ }
+ FoundState=MinContext->U.Stats;
+ MinContext=MaxContext;
+ }
+ else
+*/
+ {
+ ModelPPM::MaxOrder=MaxOrder;
+ RestartModelRare();
+ NS2BSIndx[0]=2*0;
+ NS2BSIndx[1]=2*1;
+ memset(NS2BSIndx+2,2*2,9);
+ memset(NS2BSIndx+11,2*3,256-11);
+ for (i=0;i < 3;i++)
+ NS2Indx[i]=i;
+ for (m=i, k=Step=1;i < 256;i++)
+ {
+ NS2Indx[i]=m;
+ if ( !--k )
+ {
+ k = ++Step;
+ m++;
+ }
+ }
+ memset(HB2Flag,0,0x40);
+ memset(HB2Flag+0x40,0x08,0x100-0x40);
+ DummySEE2Cont.Shift=PERIOD_BITS;
+ }
+}
+
+
+void PPM_CONTEXT::rescale(ModelPPM *Model)
+{
+ int OldNS=NumStats, i=NumStats-1, Adder, EscFreq;
+ STATE* p1, * p;
+ for (p=Model->FoundState;p != U.Stats;p--)
+ _PPMD_SWAP(p[0],p[-1]);
+ U.Stats->Freq += 4;
+ U.SummFreq += 4;
+ EscFreq=U.SummFreq-p->Freq;
+ Adder=(Model->OrderFall != 0);
+ U.SummFreq = (p->Freq=(p->Freq+Adder) >> 1);
+ do
+ {
+ EscFreq -= (++p)->Freq;
+ U.SummFreq += (p->Freq=(p->Freq+Adder) >> 1);
+ if (p[0].Freq > p[-1].Freq)
+ {
+ STATE tmp=*(p1=p);
+ do
+ {
+ p1[0]=p1[-1];
+ } while (--p1 != U.Stats && tmp.Freq > p1[-1].Freq);
+ *p1=tmp;
+ }
+ } while ( --i );
+ if (p->Freq == 0)
+ {
+ do
+ {
+ i++;
+ } while ((--p)->Freq == 0);
+ EscFreq += i;
+ if ((NumStats -= i) == 1)
+ {
+ STATE tmp=*U.Stats;
+ do
+ {
+ tmp.Freq-=(tmp.Freq >> 1);
+ EscFreq>>=1;
+ } while (EscFreq > 1);
+ Model->SubAlloc.FreeUnits(U.Stats,(OldNS+1) >> 1);
+ *(Model->FoundState=&OneState)=tmp; return;
+ }
+ }
+ U.SummFreq += (EscFreq -= (EscFreq >> 1));
+ int n0=(OldNS+1) >> 1, n1=(NumStats+1) >> 1;
+ if (n0 != n1)
+ U.Stats = (STATE*) Model->SubAlloc.ShrinkUnits(U.Stats,n0,n1);
+ Model->FoundState=U.Stats;
+}
+
+
+inline PPM_CONTEXT* ModelPPM::CreateSuccessors(bool Skip,STATE* p1)
+{
+#ifdef __ICL
+ static
+#endif
+ STATE UpState;
+ PPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor;
+ STATE * p, * ps[MAX_O], ** pps=ps;
+ if ( !Skip )
+ {
+ *pps++ = FoundState;
+ if ( !pc->Suffix )
+ goto NO_LOOP;
+ }
+ if ( p1 )
+ {
+ p=p1;
+ pc=pc->Suffix;
+ goto LOOP_ENTRY;
+ }
+ do
+ {
+ pc=pc->Suffix;
+ if (pc->NumStats != 1)
+ {
+ if ((p=pc->U.Stats)->Symbol != FoundState->Symbol)
+ do
+ {
+ p++;
+ } while (p->Symbol != FoundState->Symbol);
+ }
+ else
+ p=&(pc->OneState);
+LOOP_ENTRY:
+ if (p->Successor != UpBranch)
+ {
+ pc=p->Successor;
+ break;
+ }
+ *pps++ = p;
+ } while ( pc->Suffix );
+NO_LOOP:
+ if (pps == ps)
+ return pc;
+ UpState.Symbol=*(byte*) UpBranch;
+ UpState.Successor=(PPM_CONTEXT*) (((byte*) UpBranch)+1);
+ if (pc->NumStats != 1)
+ {
+ if ((byte*) pc <= SubAlloc.pText)
+ return(NULL);
+ if ((p=pc->U.Stats)->Symbol != UpState.Symbol)
+ do
+ {
+ p++;
+ } while (p->Symbol != UpState.Symbol);
+ uint cf=p->Freq-1;
+ uint s0=pc->U.SummFreq-pc->NumStats-cf;
+ UpState.Freq=1+((2*cf <= s0)?(5*cf > s0):((2*cf+3*s0-1)/(2*s0)));
+ }
+ else
+ UpState.Freq=pc->OneState.Freq;
+ do
+ {
+ pc = pc->createChild(this,*--pps,UpState);
+ if ( !pc )
+ return NULL;
+ } while (pps != ps);
+ return pc;
+}
+
+
+inline void ModelPPM::UpdateModel()
+{
+ STATE fs = *FoundState, *p = NULL;
+ PPM_CONTEXT *pc, *Successor;
+ uint ns1, ns, cf, sf, s0;
+ if (fs.Freq < MAX_FREQ/4 && (pc=MinContext->Suffix) != NULL)
+ {
+ if (pc->NumStats != 1)
+ {
+ if ((p=pc->U.Stats)->Symbol != fs.Symbol)
+ {
+ do
+ {
+ p++;
+ } while (p->Symbol != fs.Symbol);
+ if (p[0].Freq >= p[-1].Freq)
+ {
+ _PPMD_SWAP(p[0],p[-1]);
+ p--;
+ }
+ }
+ if (p->Freq < MAX_FREQ-9)
+ {
+ p->Freq += 2;
+ pc->U.SummFreq += 2;
+ }
+ }
+ else
+ {
+ p=&(pc->OneState);
+ p->Freq += (p->Freq < 32);
+ }
+ }
+ if ( !OrderFall )
+ {
+ MinContext=MaxContext=FoundState->Successor=CreateSuccessors(TRUE,p);
+ if ( !MinContext )
+ goto RESTART_MODEL;
+ return;
+ }
+ *SubAlloc.pText++ = fs.Symbol;
+ Successor = (PPM_CONTEXT*) SubAlloc.pText;
+ if (SubAlloc.pText >= SubAlloc.FakeUnitsStart)
+ goto RESTART_MODEL;
+ if ( fs.Successor )
+ {
+ if ((byte*) fs.Successor <= SubAlloc.pText &&
+ (fs.Successor=CreateSuccessors(FALSE,p)) == NULL)
+ goto RESTART_MODEL;
+ if ( !--OrderFall )
+ {
+ Successor=fs.Successor;
+ SubAlloc.pText -= (MaxContext != MinContext);
+ }
+ }
+ else
+ {
+ FoundState->Successor=Successor;
+ fs.Successor=MinContext;
+ }
+ s0=MinContext->U.SummFreq-(ns=MinContext->NumStats)-(fs.Freq-1);
+ for (pc=MaxContext;pc != MinContext;pc=pc->Suffix)
+ {
+ if ((ns1=pc->NumStats) != 1)
+ {
+ if ((ns1 & 1) == 0)
+ {
+ pc->U.Stats=(STATE*) SubAlloc.ExpandUnits(pc->U.Stats,ns1 >> 1);
+ if ( !pc->U.Stats )
+ goto RESTART_MODEL;
+ }
+ pc->U.SummFreq += (2*ns1 < ns)+2*((4*ns1 <= ns) & (pc->U.SummFreq <= 8*ns1));
+ }
+ else
+ {
+ p=(STATE*) SubAlloc.AllocUnits(1);
+ if ( !p )
+ goto RESTART_MODEL;
+ *p=pc->OneState;
+ pc->U.Stats=p;
+ if (p->Freq < MAX_FREQ/4-1)
+ p->Freq += p->Freq;
+ else
+ p->Freq = MAX_FREQ-4;
+ pc->U.SummFreq=p->Freq+InitEsc+(ns > 3);
+ }
+ cf=2*fs.Freq*(pc->U.SummFreq+6);
+ sf=s0+pc->U.SummFreq;
+ if (cf < 6*sf)
+ {
+ cf=1+(cf > sf)+(cf >= 4*sf);
+ pc->U.SummFreq += 3;
+ }
+ else
+ {
+ cf=4+(cf >= 9*sf)+(cf >= 12*sf)+(cf >= 15*sf);
+ pc->U.SummFreq += cf;
+ }
+ p=pc->U.Stats+ns1;
+ p->Successor=Successor;
+ p->Symbol = fs.Symbol;
+ p->Freq = cf;
+ pc->NumStats=++ns1;
+ }
+ MaxContext=MinContext=fs.Successor;
+ return;
+RESTART_MODEL:
+ RestartModelRare();
+ EscCount=0;
+}
+
+
+// Tabulated escapes for exponential symbol distribution
+static const byte ExpEscape[16]={ 25,14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
+#define GET_MEAN(SUMM,SHIFT,ROUND) ((SUMM+(1 << (SHIFT-ROUND))) >> (SHIFT))
+
+
+
+inline void PPM_CONTEXT::decodeBinSymbol(ModelPPM *Model)
+{
+ STATE& rs=OneState;
+ Model->HiBitsFlag=Model->HB2Flag[Model->FoundState->Symbol];
+ ushort& bs=Model->BinSumm[rs.Freq-1][Model->PrevSuccess+
+ Model->NS2BSIndx[Suffix->NumStats-1]+
+ Model->HiBitsFlag+2*Model->HB2Flag[rs.Symbol]+
+ ((Model->RunLength >> 26) & 0x20)];
+ if (Model->Coder.GetCurrentShiftCount(TOT_BITS) < bs)
+ {
+ Model->FoundState=&rs;
+ rs.Freq += (rs.Freq < 128);
+ Model->Coder.SubRange.LowCount=0;
+ Model->Coder.SubRange.HighCount=bs;
+ bs = GET_SHORT16(bs+INTERVAL-GET_MEAN(bs,PERIOD_BITS,2));
+ Model->PrevSuccess=1;
+ Model->RunLength++;
+ }
+ else
+ {
+ Model->Coder.SubRange.LowCount=bs;
+ bs = GET_SHORT16(bs-GET_MEAN(bs,PERIOD_BITS,2));
+ Model->Coder.SubRange.HighCount=BIN_SCALE;
+ Model->InitEsc=ExpEscape[bs >> 10];
+ Model->NumMasked=1;
+ Model->CharMask[rs.Symbol]=Model->EscCount;
+ Model->PrevSuccess=0;
+ Model->FoundState=NULL;
+ }
+}
+
+
+inline void PPM_CONTEXT::update1(ModelPPM *Model,STATE* p)
+{
+ (Model->FoundState=p)->Freq += 4;
+ U.SummFreq += 4;
+ if (p[0].Freq > p[-1].Freq)
+ {
+ _PPMD_SWAP(p[0],p[-1]);
+ Model->FoundState=--p;
+ if (p->Freq > MAX_FREQ)
+ rescale(Model);
+ }
+}
+
+
+
+
+inline bool PPM_CONTEXT::decodeSymbol1(ModelPPM *Model)
+{
+ Model->Coder.SubRange.scale=U.SummFreq;
+ STATE* p=U.Stats;
+ int i, HiCnt;
+ int count=Model->Coder.GetCurrentCount();
+ if (count>=(int)Model->Coder.SubRange.scale)
+ return(false);
+ if (count < (HiCnt=p->Freq))
+ {
+ Model->PrevSuccess=(2*(Model->Coder.SubRange.HighCount=HiCnt) > Model->Coder.SubRange.scale);
+ Model->RunLength += Model->PrevSuccess;
+ (Model->FoundState=p)->Freq=(HiCnt += 4);
+ U.SummFreq += 4;
+ if (HiCnt > MAX_FREQ)
+ rescale(Model);
+ Model->Coder.SubRange.LowCount=0;
+ return(true);
+ }
+ else
+ if (Model->FoundState==NULL)
+ return(false);
+ Model->PrevSuccess=0;
+ i=NumStats-1;
+ while ((HiCnt += (++p)->Freq) <= count)
+ if (--i == 0)
+ {
+ Model->HiBitsFlag=Model->HB2Flag[Model->FoundState->Symbol];
+ Model->Coder.SubRange.LowCount=HiCnt;
+ Model->CharMask[p->Symbol]=Model->EscCount;
+ i=(Model->NumMasked=NumStats)-1;
+ Model->FoundState=NULL;
+ do
+ {
+ Model->CharMask[(--p)->Symbol]=Model->EscCount;
+ } while ( --i );
+ Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale;
+ return(true);
+ }
+ Model->Coder.SubRange.LowCount=(Model->Coder.SubRange.HighCount=HiCnt)-p->Freq;
+ update1(Model,p);
+ return(true);
+}
+
+
+inline void PPM_CONTEXT::update2(ModelPPM *Model,STATE* p)
+{
+ (Model->FoundState=p)->Freq += 4;
+ U.SummFreq += 4;
+ if (p->Freq > MAX_FREQ)
+ rescale(Model);
+ Model->EscCount++;
+ Model->RunLength=Model->InitRL;
+}
+
+
+inline SEE2_CONTEXT* PPM_CONTEXT::makeEscFreq2(ModelPPM *Model,int Diff)
+{
+ SEE2_CONTEXT* psee2c;
+ if (NumStats != 256)
+ {
+ psee2c=Model->SEE2Cont[Model->NS2Indx[Diff-1]]+
+ (Diff < Suffix->NumStats-NumStats)+
+ 2*(U.SummFreq < 11*NumStats)+4*(Model->NumMasked > Diff)+
+ Model->HiBitsFlag;
+ Model->Coder.SubRange.scale=psee2c->getMean();
+ }
+ else
+ {
+ psee2c=&Model->DummySEE2Cont;
+ Model->Coder.SubRange.scale=1;
+ }
+ return psee2c;
+}
+
+
+
+
+inline bool PPM_CONTEXT::decodeSymbol2(ModelPPM *Model)
+{
+ int count, HiCnt, i=NumStats-Model->NumMasked;
+ SEE2_CONTEXT* psee2c=makeEscFreq2(Model,i);
+ STATE* ps[256], ** pps=ps, * p=U.Stats-1;
+ HiCnt=0;
+ do
+ {
+ do
+ {
+ p++;
+ } while (Model->CharMask[p->Symbol] == Model->EscCount);
+ HiCnt += p->Freq;
+ *pps++ = p;
+ } while ( --i );
+ Model->Coder.SubRange.scale += HiCnt;
+ count=Model->Coder.GetCurrentCount();
+ if (count>=(int)Model->Coder.SubRange.scale)
+ return(false);
+ p=*(pps=ps);
+ if (count < HiCnt)
+ {
+ HiCnt=0;
+ while ((HiCnt += p->Freq) <= count)
+ p=*++pps;
+ Model->Coder.SubRange.LowCount = (Model->Coder.SubRange.HighCount=HiCnt)-p->Freq;
+ psee2c->update();
+ update2(Model,p);
+ }
+ else
+ {
+ Model->Coder.SubRange.LowCount=HiCnt;
+ Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale;
+ i=NumStats-Model->NumMasked;
+ pps--;
+ do
+ {
+ Model->CharMask[(*++pps)->Symbol]=Model->EscCount;
+ } while ( --i );
+ psee2c->Summ += Model->Coder.SubRange.scale;
+ Model->NumMasked = NumStats;
+ }
+ return(true);
+}
+
+
+inline void ModelPPM::ClearMask()
+{
+ EscCount=1;
+ memset(CharMask,0,sizeof(CharMask));
+}
+
+
+
+
+// reset PPM variables after data error allowing safe resuming
+// of further data processing
+void ModelPPM::CleanUp()
+{
+ SubAlloc.StopSubAllocator();
+ SubAlloc.StartSubAllocator(1);
+ StartModelRare(2);
+}
+
+
+bool ModelPPM::DecodeInit(Unpack *UnpackRead,int &EscChar)
+{
+ int MaxOrder=UnpackRead->GetChar();
+ bool Reset=(MaxOrder & 0x20)!=0;
+
+ int MaxMB;
+ if (Reset)
+ MaxMB=UnpackRead->GetChar();
+ else
+ if (SubAlloc.GetAllocatedMemory()==0)
+ return(false);
+ if (MaxOrder & 0x40)
+ EscChar=UnpackRead->GetChar();
+ Coder.InitDecoder(UnpackRead);
+ if (Reset)
+ {
+ MaxOrder=(MaxOrder & 0x1f)+1;
+ if (MaxOrder>16)
+ MaxOrder=16+(MaxOrder-16)*3;
+ if (MaxOrder==1)
+ {
+ SubAlloc.StopSubAllocator();
+ return(false);
+ }
+ SubAlloc.StartSubAllocator(MaxMB+1);
+ StartModelRare(MaxOrder);
+ }
+ return(MinContext!=NULL);
+}
+
+
+int ModelPPM::DecodeChar()
+{
+ if ((byte*)MinContext <= SubAlloc.pText || (byte*)MinContext>SubAlloc.HeapEnd)
+ return(-1);
+ if (MinContext->NumStats != 1)
+ {
+ if ((byte*)MinContext->U.Stats <= SubAlloc.pText || (byte*)MinContext->U.Stats>SubAlloc.HeapEnd)
+ return(-1);
+ if (!MinContext->decodeSymbol1(this))
+ return(-1);
+ }
+ else
+ MinContext->decodeBinSymbol(this);
+ Coder.Decode();
+ while ( !FoundState )
+ {
+ ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead);
+ do
+ {
+ OrderFall++;
+ MinContext=MinContext->Suffix;
+ if ((byte*)MinContext <= SubAlloc.pText || (byte*)MinContext>SubAlloc.HeapEnd)
+ return(-1);
+ } while (MinContext->NumStats == NumMasked);
+ if (!MinContext->decodeSymbol2(this))
+ return(-1);
+ Coder.Decode();
+ }
+ int Symbol=FoundState->Symbol;
+ if (!OrderFall && (byte*) FoundState->Successor > SubAlloc.pText)
+ MinContext=MaxContext=FoundState->Successor;
+ else
+ {
+ UpdateModel();
+ if (EscCount == 0)
+ ClearMask();
+ }
+ ARI_DEC_NORMALIZE(Coder.code,Coder.low,Coder.range,Coder.UnpackRead);
+ return(Symbol);
+}
diff --git a/src/unrar/model.hpp b/src/unrar/model.hpp
new file mode 100644
index 0000000000..077742170c
--- /dev/null
+++ b/src/unrar/model.hpp
@@ -0,0 +1,132 @@
+#ifndef _RAR_PPMMODEL_
+#define _RAR_PPMMODEL_
+
+#include "coder.hpp"
+#include "suballoc.hpp"
+
+const int MAX_O=64; /* maximum allowed model order */
+
+const int INT_BITS=7, PERIOD_BITS=7, TOT_BITS=INT_BITS+PERIOD_BITS,
+ INTERVAL=1 << INT_BITS, BIN_SCALE=1 << TOT_BITS, MAX_FREQ=124;
+
+#ifndef STRICT_ALIGNMENT_REQUIRED
+#pragma pack(1)
+#endif
+
+struct SEE2_CONTEXT
+{ // SEE-contexts for PPM-contexts with masked symbols
+ ushort Summ;
+ byte Shift, Count;
+ void init(int InitVal)
+ {
+ Summ=InitVal << (Shift=PERIOD_BITS-4);
+ Count=4;
+ }
+ uint getMean()
+ {
+ uint RetVal=GET_SHORT16(Summ) >> Shift;
+ Summ -= RetVal;
+ return RetVal+(RetVal == 0);
+ }
+ void update()
+ {
+ if (Shift < PERIOD_BITS && --Count == 0)
+ {
+ Summ += Summ;
+ Count=3 << Shift++;
+ }
+ }
+};
+
+
+class ModelPPM;
+struct PPM_CONTEXT;
+
+struct STATE
+{
+ byte Symbol;
+ byte Freq;
+ PPM_CONTEXT* Successor;
+};
+
+struct FreqData
+{
+ ushort SummFreq;
+ STATE _PACK_ATTR * Stats;
+};
+
+struct PPM_CONTEXT
+{
+ ushort NumStats;
+ union
+ {
+ FreqData U;
+ STATE OneState;
+ };
+
+ PPM_CONTEXT* Suffix;
+ inline void encodeBinSymbol(ModelPPM *Model,int symbol); // MaxOrder:
+ inline void encodeSymbol1(ModelPPM *Model,int symbol); // ABCD context
+ inline void encodeSymbol2(ModelPPM *Model,int symbol); // BCD suffix
+ inline void decodeBinSymbol(ModelPPM *Model); // BCDE successor
+ inline bool decodeSymbol1(ModelPPM *Model); // other orders:
+ inline bool decodeSymbol2(ModelPPM *Model); // BCD context
+ inline void update1(ModelPPM *Model,STATE* p); // CD suffix
+ inline void update2(ModelPPM *Model,STATE* p); // BCDE successor
+ void rescale(ModelPPM *Model);
+ inline PPM_CONTEXT* createChild(ModelPPM *Model,STATE* pStats,STATE& FirstState);
+ inline SEE2_CONTEXT* makeEscFreq2(ModelPPM *Model,int Diff);
+};
+
+#ifndef STRICT_ALIGNMENT_REQUIRED
+#ifdef _AIX
+#pragma pack(pop)
+#else
+#pragma pack()
+#endif
+#endif
+
+const uint UNIT_SIZE=Max(sizeof(PPM_CONTEXT),sizeof(RAR_MEM_BLK));
+const uint FIXED_UNIT_SIZE=12;
+
+/*
+inline PPM_CONTEXT::PPM_CONTEXT(STATE* pStats,PPM_CONTEXT* ShorterContext):
+ NumStats(1), Suffix(ShorterContext) { pStats->Successor=this; }
+inline PPM_CONTEXT::PPM_CONTEXT(): NumStats(0) {}
+*/
+
+template
+inline void _PPMD_SWAP(T& t1,T& t2) { T tmp=t1; t1=t2; t2=tmp; }
+
+
+class ModelPPM
+{
+ private:
+ friend struct PPM_CONTEXT;
+
+ SEE2_CONTEXT SEE2Cont[25][16], DummySEE2Cont;
+
+ struct PPM_CONTEXT *MinContext, *MedContext, *MaxContext;
+ STATE* FoundState; // found next state transition
+ int NumMasked, InitEsc, OrderFall, MaxOrder, RunLength, InitRL;
+ byte CharMask[256], NS2Indx[256], NS2BSIndx[256], HB2Flag[256];
+ byte EscCount, PrevSuccess, HiBitsFlag;
+ ushort BinSumm[128][64]; // binary SEE-contexts
+
+ RangeCoder Coder;
+ SubAllocator SubAlloc;
+
+ void RestartModelRare();
+ void StartModelRare(int MaxOrder);
+ inline PPM_CONTEXT* CreateSuccessors(bool Skip,STATE* p1);
+
+ inline void UpdateModel();
+ inline void ClearMask();
+ public:
+ ModelPPM();
+ void CleanUp(); // reset PPM variables after data error
+ bool DecodeInit(Unpack *UnpackRead,int &EscChar);
+ int DecodeChar();
+};
+
+#endif
diff --git a/src/unrar/msc.dep b/src/unrar/msc.dep
new file mode 100644
index 0000000000..53d1a50123
--- /dev/null
+++ b/src/unrar/msc.dep
@@ -0,0 +1,2390 @@
+# Microsoft Developer Studio Generated Dependency File, included by unrar.mak
+
+.\archive.cpp : \
+ ".\arccmt.cpp"\
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\arcread.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\cmddata.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\consio.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.cpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\crc.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\crypt.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\encname.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\errhnd.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\extinfo.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+ ".\win32acl.cpp"\
+ ".\win32stm.cpp"\
+
+
+.\extract.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\filcreat.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\file.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\filefn.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\filestr.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\find.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\getbits.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\global.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\isnt.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\list.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\match.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\options.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\pathfn.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\rar.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.cpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\rarvm.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rarvmtbl.cpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\rawread.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\rdwrfn.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\recvol.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\resource.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\rijndael.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\rs.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\savepos.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\scantree.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\sha1.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\strfn.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\strlist.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\system.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\timefn.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\ulinks.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\unicode.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\unpack.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.cpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.cpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.cpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\unpack15.cpp"\
+ ".\unpack20.cpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
+
+.\volume.cpp : \
+ ".\archive.hpp"\
+ ".\array.hpp"\
+ ".\cmddata.hpp"\
+ ".\coder.hpp"\
+ ".\compress.hpp"\
+ ".\consio.hpp"\
+ ".\crc.hpp"\
+ ".\crypt.hpp"\
+ ".\encname.hpp"\
+ ".\errhnd.hpp"\
+ ".\extinfo.hpp"\
+ ".\extract.hpp"\
+ ".\filcreat.hpp"\
+ ".\file.hpp"\
+ ".\filefn.hpp"\
+ ".\filestr.hpp"\
+ ".\find.hpp"\
+ ".\getbits.hpp"\
+ ".\global.hpp"\
+ ".\headers.hpp"\
+ ".\isnt.hpp"\
+ ".\list.hpp"\
+ ".\loclang.hpp"\
+ ".\log.hpp"\
+ ".\match.hpp"\
+ ".\model.hpp"\
+ ".\options.hpp"\
+ ".\os.hpp"\
+ ".\pathfn.hpp"\
+ ".\rar.hpp"\
+ ".\rardefs.hpp"\
+ ".\rarlang.hpp"\
+ ".\raros.hpp"\
+ ".\rartypes.hpp"\
+ ".\rarvm.hpp"\
+ ".\rawread.hpp"\
+ ".\rdwrfn.hpp"\
+ ".\recvol.hpp"\
+ ".\resource.hpp"\
+ ".\rijndael.hpp"\
+ ".\rs.hpp"\
+ ".\savepos.hpp"\
+ ".\scantree.hpp"\
+ ".\sha1.hpp"\
+ ".\smallfn.hpp"\
+ ".\strfn.hpp"\
+ ".\strlist.hpp"\
+ ".\suballoc.hpp"\
+ ".\system.hpp"\
+ ".\timefn.hpp"\
+ ".\ulinks.hpp"\
+ ".\unicode.hpp"\
+ ".\unpack.hpp"\
+ ".\version.hpp"\
+ ".\volume.hpp"\
+
diff --git a/src/unrar/options.cpp b/src/unrar/options.cpp
new file mode 100644
index 0000000000..585ce52433
--- /dev/null
+++ b/src/unrar/options.cpp
@@ -0,0 +1,30 @@
+#include "rar.hpp"
+
+RAROptions::RAROptions()
+{
+ Init();
+}
+
+
+RAROptions::~RAROptions()
+{
+ // It is important for security reasons, so we do not have the unnecessary
+ // password data left in memory.
+ memset(this,0,sizeof(RAROptions));
+}
+
+
+void RAROptions::Init()
+{
+ memset(this,0,sizeof(RAROptions));
+ WinSize=0x400000;
+ Overwrite=OVERWRITE_DEFAULT;
+ Method=3;
+ MsgStream=MSG_STDOUT;
+ ConvertNames=NAMES_ORIGINALCASE;
+ ProcessEA=true;
+ xmtime=EXTTIME_HIGH3;
+ CurVolNum=0;
+ FileSizeLess=INT64NDF;
+ FileSizeMore=INT64NDF;
+}
diff --git a/src/unrar/options.hpp b/src/unrar/options.hpp
new file mode 100644
index 0000000000..b01912967b
--- /dev/null
+++ b/src/unrar/options.hpp
@@ -0,0 +1,175 @@
+#ifndef _RAR_OPTIONS_
+#define _RAR_OPTIONS_
+
+#define DEFAULT_RECOVERY -1
+
+#define DEFAULT_RECVOLUMES -10
+
+#define VOLSIZE_AUTO INT64NDF // Automatically detect the volume size.
+
+enum PATH_EXCL_MODE {
+ EXCL_UNCHANGED=0, // Process paths as is (default).
+ EXCL_SKIPWHOLEPATH, // -ep (exclude the path completely)
+ EXCL_BASEPATH, // -ep1 (exclude the base part of path)
+ EXCL_SAVEFULLPATH, // -ep2 (the full path without the disk letter)
+ EXCL_ABSPATH, // -ep3 (the full path with the disk letter)
+
+ EXCL_SKIPABSPATH // Works as EXCL_BASEPATH for fully qualified paths
+ // and as EXCL_UNCHANGED for relative paths.
+ // Used by WinRAR GUI only.
+};
+
+enum {SOLID_NONE=0,SOLID_NORMAL=1,SOLID_COUNT=2,SOLID_FILEEXT=4,
+ SOLID_VOLUME_DEPENDENT=8,SOLID_VOLUME_INDEPENDENT=16};
+
+enum {ARCTIME_NONE=0,ARCTIME_KEEP,ARCTIME_LATEST};
+
+enum EXTTIME_MODE {
+ EXTTIME_NONE=0,EXTTIME_1S,EXTTIME_HIGH1,EXTTIME_HIGH2,EXTTIME_HIGH3
+};
+
+enum {NAMES_ORIGINALCASE=0,NAMES_UPPERCASE,NAMES_LOWERCASE};
+
+enum MESSAGE_TYPE {MSG_STDOUT=0,MSG_STDERR,MSG_ERRONLY,MSG_NULL};
+
+enum RECURSE_MODE
+{
+ RECURSE_NONE=0, // no recurse switches
+ RECURSE_DISABLE, // switch -r-
+ RECURSE_ALWAYS, // switch -r
+ RECURSE_WILDCARDS, // switch -r0
+};
+
+enum OVERWRITE_MODE
+{
+ OVERWRITE_DEFAULT=0, // ask for extraction, silently overwrite for archiving
+ OVERWRITE_ALL,
+ OVERWRITE_NONE,
+ OVERWRITE_AUTORENAME,
+ OVERWRITE_FORCE_ASK
+};
+
+enum RAR_CHARSET { RCH_DEFAULT=0,RCH_ANSI,RCH_OEM,RCH_UNICODE };
+
+#define MAX_FILTER_TYPES 16
+enum FilterState {FILTER_DEFAULT=0,FILTER_AUTO,FILTER_FORCE,FILTER_DISABLE};
+
+
+struct FilterMode
+{
+ FilterState State;
+ int Param1;
+ int Param2;
+};
+
+#define MAX_GENERATE_MASK 128
+
+
+class RAROptions
+{
+ public:
+ RAROptions();
+ ~RAROptions();
+ void Init();
+
+ uint ExclFileAttr;
+ uint InclFileAttr;
+ bool InclAttrSet;
+ uint WinSize;
+ char TempPath[NM];
+ bool ConfigDisabled; // Switch -cfg-.
+ char ExtrPath[NM];
+ wchar ExtrPathW[NM];
+ char CommentFile[NM];
+ wchar CommentFileW[NM];
+ RAR_CHARSET CommentCharset;
+ RAR_CHARSET FilelistCharset;
+ char ArcPath[NM];
+ wchar ArcPathW[NM];
+ SecPassword Password;
+ bool EncryptHeaders;
+ char LogName[NM];
+ MESSAGE_TYPE MsgStream;
+ bool Sound;
+ OVERWRITE_MODE Overwrite;
+ int Method;
+ int Recovery;
+ int RecVolNumber;
+ bool DisablePercentage;
+ bool DisableCopyright;
+ bool DisableDone;
+ int Solid;
+ int SolidCount;
+ bool ClearArc;
+ bool AddArcOnly;
+ bool AV;
+ bool DisableComment;
+ bool FreshFiles;
+ bool UpdateFiles;
+ PATH_EXCL_MODE ExclPath;
+ RECURSE_MODE Recurse;
+ int64 VolSize;
+ Array NextVolSizes;
+ uint CurVolNum;
+ bool AllYes;
+ bool DisableViewAV;
+ bool DisableSortSolid;
+ int ArcTime;
+ int ConvertNames;
+ bool ProcessOwners;
+ bool SaveLinks;
+ int Priority;
+ int SleepTime;
+ bool KeepBroken;
+ bool OpenShared;
+ bool DeleteFiles;
+#ifndef SFX_MODULE
+ bool GenerateArcName;
+ char GenerateMask[MAX_GENERATE_MASK];
+#endif
+ bool SyncFiles;
+ bool ProcessEA;
+ bool SaveStreams;
+ bool SetCompressedAttr;
+ bool IgnoreGeneralAttr;
+ RarTime FileTimeBefore;
+ RarTime FileTimeAfter;
+ int64 FileSizeLess;
+ int64 FileSizeMore;
+ bool OldNumbering;
+ bool Lock;
+ bool Test;
+ bool VolumePause;
+ FilterMode FilterModes[MAX_FILTER_TYPES];
+ char EmailTo[NM];
+ uint VersionControl;
+ bool NoEndBlock;
+ bool AppendArcNameToPath;
+ bool Shutdown;
+ EXTTIME_MODE xmtime;
+ EXTTIME_MODE xctime;
+ EXTTIME_MODE xatime;
+ EXTTIME_MODE xarctime;
+ char CompressStdin[NM];
+
+#ifdef RAR_SMP
+ uint Threads;
+#endif
+
+
+
+
+
+
+#ifdef RARDLL
+ char DllDestName[NM];
+ wchar DllDestNameW[NM];
+ int DllOpMode;
+ int DllError;
+ LPARAM UserData;
+ UNRARCALLBACK Callback;
+ CHANGEVOLPROC ChangeVolProc;
+ PROCESSDATAPROC ProcessDataProc;
+#endif
+};
+#endif
diff --git a/src/unrar/os.hpp b/src/unrar/os.hpp
new file mode 100644
index 0000000000..21488a849b
--- /dev/null
+++ b/src/unrar/os.hpp
@@ -0,0 +1,254 @@
+#ifndef _RAR_OS_
+#define _RAR_OS_
+
+#define FALSE 0
+#define TRUE 1
+
+#ifdef __EMX__
+ #define INCL_BASE
+#endif
+
+#if defined(RARDLL) && !defined(SILENT)
+#define SILENT
+#endif
+
+#define ENABLE_BAD_ALLOC // Undefine if std::bad_alloc is not supported.
+
+#ifdef ENABLE_BAD_ALLOC
+ #include
+#endif
+
+
+#if defined(_WIN_ALL) || defined(_EMX)
+
+#define LITTLE_ENDIAN
+#define NM 1024
+
+#ifdef _WIN_ALL
+
+#define STRICT
+#define UNICODE
+#undef WINVER
+#undef _WIN32_WINNT
+#define WINVER 0x0501
+#define _WIN32_WINNT 0x0501
+
+
+#define WIN32_LEAN_AND_MEAN
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+
+#endif // _WIN_ALL
+
+#include
+#include
+#include
+
+#if !defined(_EMX) && !defined(_MSC_VER)
+ #include
+#endif
+#ifdef _MSC_VER
+ #if _MSC_VER<1500
+ #define for if (0) ; else for
+ #endif
+ #include
+#else
+ #include
+#endif // _MSC_VER
+
+#ifdef _EMX
+ #include
+ #include
+ #include
+ #include
+ #ifdef _DJGPP
+ #include
+ #else
+ #include
+ #include
+ #include
+ #endif
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define ENABLE_ACCESS
+
+#define DefConfigName "rar.ini"
+#define DefLogName "rar.log"
+
+
+#define PATHDIVIDER "\\"
+#define PATHDIVIDERW L"\\"
+#define CPATHDIVIDER '\\'
+#define MASKALL "*"
+#define MASKALLW L"*"
+
+#define READBINARY "rb"
+#define READTEXT "rt"
+#define UPDATEBINARY "r+b"
+#define CREATEBINARY "w+b"
+#define WRITEBINARY "wb"
+#define APPENDTEXT "at"
+
+#if defined(_WIN_ALL)
+ #ifdef _MSC_VER
+ #define _stdfunction __cdecl
+
+ #ifdef SFX_MODULE
+ // We want to keep SFX module small, so let compiler to decide.
+ #define _forceinline inline
+ #else
+ #define _forceinline __forceinline
+ #endif
+
+ #else
+ #define _stdfunction _USERENTRY
+ #define _forceinline inline
+ #endif
+#else
+ #define _stdfunction
+ #define _forceinline inline
+#endif
+
+#endif
+
+#ifdef _UNIX
+
+#define NM 1024
+
+#ifdef _BEOS
+#include
+#include
+#endif
+
+#include
+#include
+#include
+#include
+#if defined(__QNXNTO__)
+ #include
+#endif
+#if defined(RAR_SMP) && defined(__APPLE__)
+ #include
+#endif
+#if defined(__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined(__APPLE__)
+ #include
+ #include
+#else
+#endif
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef S_IFLNK
+#define SAVE_LINKS
+#endif
+
+#define ENABLE_ACCESS
+
+#define DefConfigName ".rarrc"
+#define DefLogName ".rarlog"
+
+
+#define PATHDIVIDER "/"
+#define PATHDIVIDERW L"/"
+#define CPATHDIVIDER '/'
+#define MASKALL "*"
+#define MASKALLW L"*"
+
+#define READBINARY "r"
+#define READTEXT "r"
+#define UPDATEBINARY "r+"
+#define CREATEBINARY "w+"
+#define WRITEBINARY "w"
+#define APPENDTEXT "a"
+
+#define _stdfunction
+#define _forceinline inline
+
+#ifdef _APPLE
+ #if defined(__BIG_ENDIAN__) && !defined(BIG_ENDIAN)
+ #define BIG_ENDIAN
+ #undef LITTLE_ENDIAN
+ #endif
+ #if defined(__i386__) && !defined(LITTLE_ENDIAN)
+ #define LITTLE_ENDIAN
+ #undef BIG_ENDIAN
+ #endif
+#endif
+
+#if defined(__sparc) || defined(sparc) || defined(__hpux)
+ #ifndef BIG_ENDIAN
+ #define BIG_ENDIAN
+ #endif
+#endif
+
+#endif
+
+ typedef const char* MSGID;
+
+#define safebuf static
+
+#if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
+ #if defined(__i386) || defined(i386) || defined(__i386__)
+ #define LITTLE_ENDIAN
+ #elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN
+ #define LITTLE_ENDIAN
+ #elif defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
+ #define BIG_ENDIAN
+ #else
+ #error "Neither LITTLE_ENDIAN nor BIG_ENDIAN are defined. Define one of them."
+ #endif
+#endif
+
+#if defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
+ #if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN
+ #undef LITTLE_ENDIAN
+ #elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN
+ #undef BIG_ENDIAN
+ #else
+ #error "Both LITTLE_ENDIAN and BIG_ENDIAN are defined. Undef one of them."
+ #endif
+#endif
+
+#if !defined(BIG_ENDIAN) && !defined(_WIN_CE) && defined(_WIN_ALL)
+// Allow not aligned integer access, increases speed in some operations.
+#define ALLOW_NOT_ALIGNED_INT
+#endif
+
+#if defined(__sparc) || defined(sparc) || defined(__sparcv9)
+// Prohibit not aligned access to data structures in text compression
+// algorithm, increases memory requirements
+#define STRICT_ALIGNMENT_REQUIRED
+#endif
+
+#endif // _RAR_OS_
diff --git a/src/unrar/os2ea.cpp b/src/unrar/os2ea.cpp
new file mode 100644
index 0000000000..fbb12dbdca
--- /dev/null
+++ b/src/unrar/os2ea.cpp
@@ -0,0 +1,94 @@
+#include
+
+
+
+void ExtractOS2EA(Archive &Arc,char *FileName)
+{
+ if (_osmode != OS2_MODE)
+ {
+ mprintf(St(MSkipEA));
+ return;
+ }
+
+ if (Arc.HeaderCRC!=Arc.EAHead.HeadCRC)
+ {
+ Log(Arc.FileName,St(MEABroken),FileName);
+ ErrHandler.SetErrorCode(RARX_CRC);
+ return;
+ }
+
+ if (Arc.EAHead.Method<0x31 || Arc.EAHead.Method>0x35 || Arc.EAHead.UnpVer>PACK_VER)
+ {
+ Log(Arc.FileName,St(MEAUnknHeader),FileName);
+ ErrHandler.SetErrorCode(RARX_WARNING);
+ return;
+ }
+
+ struct StructEAOP2
+ {
+ char *GEAPtr;
+ char *FEAPtr;
+ unsigned long Error;
+ } EAOP2;
+
+ ComprDataIO DataIO;
+ Unpack Unpack(&DataIO);
+ Unpack.Init();
+
+ Array UnpData(Arc.EAHead.UnpSize);
+ DataIO.SetUnpackToMemory(&UnpData[0],Arc.EAHead.UnpSize);
+ DataIO.SetPackedSizeToRead(Arc.EAHead.DataSize);
+ DataIO.EnableShowProgress(false);
+ DataIO.SetFiles(&Arc,NULL);
+ Unpack.SetDestSize(Arc.EAHead.UnpSize);
+ Unpack.DoUnpack(Arc.EAHead.UnpVer,false);
+
+ if (Arc.EAHead.EACRC!=~DataIO.UnpFileCRC)
+ {
+ Log(Arc.FileName,St(MEABroken),FileName);
+ ErrHandler.SetErrorCode(RARX_CRC);
+ return;
+ }
+
+ EAOP2.FEAPtr=(char *)&UnpData[0];
+ EAOP2.GEAPtr=NULL;
+ if (DosSetPathInfo((unsigned char *)FileName,2,&EAOP2,sizeof(EAOP2),0x10)!=0)
+ {
+ Log(Arc.FileName,St(MCannotSetEA),FileName);
+ ErrHandler.SetErrorCode(RARX_WARNING);
+ }
+ File::SetCloseFileTimeByName(FileName,&Arc.NewLhd.mtime,&Arc.NewLhd.atime);
+ mprintf(St(MShowEA));
+}
+
+
+void ExtractOS2EANew(Archive &Arc,char *FileName)
+{
+ if (_osmode != OS2_MODE)
+ {
+ mprintf(St(MSkipEA));
+ return;
+ }
+
+ Array SubData;
+ if (!Arc.ReadSubData(&SubData,NULL))
+ return;
+
+ struct StructEAOP2
+ {
+ char *GEAPtr;
+ char *FEAPtr;
+ unsigned long Error;
+ } EAOP2;
+
+ EAOP2.FEAPtr=(char *)&SubData[0];
+ EAOP2.GEAPtr=NULL;
+ if (DosSetPathInfo((unsigned char *)FileName,2,&EAOP2,sizeof(EAOP2),0x10)!=0)
+ {
+ Log(Arc.FileName,St(MCannotSetEA),FileName);
+ ErrHandler.SetErrorCode(RARX_WARNING);
+ }
+ File::SetCloseFileTimeByName(FileName,&Arc.NewLhd.mtime,&Arc.NewLhd.atime);
+ mprintf(St(MShowEA));
+}
+
diff --git a/src/unrar/pathfn.cpp b/src/unrar/pathfn.cpp
new file mode 100644
index 0000000000..b9244cdec2
--- /dev/null
+++ b/src/unrar/pathfn.cpp
@@ -0,0 +1,1457 @@
+#include "rar.hpp"
+
+char* PointToName(const char *Path)
+{
+ const char *Found=NULL;
+ for (const char *s=Path;*s!=0;s=charnext(s))
+ if (IsPathDiv(*s))
+ Found=(char*)(s+1);
+ if (Found!=NULL)
+ return((char*)Found);
+ return (char*)((*Path && IsDriveDiv(Path[1]) && charnext(Path)==Path+1) ? Path+2:Path);
+}
+
+
+wchar* PointToName(const wchar *Path)
+{
+ for (int I=(int)wcslen(Path)-1;I>=0;I--)
+ if (IsPathDiv(Path[I]))
+ return (wchar*)&Path[I+1];
+ return (wchar*)((*Path && IsDriveDiv(Path[1])) ? Path+2:Path);
+}
+
+
+char* PointToLastChar(const char *Path)
+{
+ for (const char *s=Path,*p=Path;;p=s,s=charnext(s))
+ if (*s==0)
+ return((char *)p);
+}
+
+
+wchar* PointToLastChar(const wchar *Path)
+{
+ size_t Length=wcslen(Path);
+ return((wchar*)(Length>0 ? Path+Length-1:Path));
+}
+
+
+char* ConvertPath(const char *SrcPath,char *DestPath)
+{
+ const char *DestPtr=SrcPath;
+
+ // Prevent \..\ in any part of path string.
+ for (const char *s=DestPtr;*s!=0;s++)
+ if (IsPathDiv(s[0]) && s[1]=='.' && s[2]=='.' && IsPathDiv(s[3]))
+ DestPtr=s+4;
+
+ // Remove :\ and any sequence of . and \ in the beginning of path string.
+ while (*DestPtr!=0)
+ {
+ const char *s=DestPtr;
+ if (s[0] && IsDriveDiv(s[1]))
+ s+=2;
+ else
+ if (s[0]=='\\' && s[1]=='\\')
+ {
+ const char *Slash=strchr(s+2,'\\');
+ if (Slash!=NULL && (Slash=strchr(Slash+1,'\\'))!=NULL)
+ s=Slash+1;
+ }
+ for (const char *t=s;*t!=0;t++)
+ if (IsPathDiv(*t))
+ s=t+1;
+ else
+ if (*t!='.')
+ break;
+ if (s==DestPtr)
+ break;
+ DestPtr=s;
+ }
+
+ // Code above does not remove last "..", doing here.
+ if (DestPtr[0]=='.' && DestPtr[1]=='.' && DestPtr[2]==0)
+ DestPtr+=2;
+
+ if (DestPath!=NULL)
+ {
+ // SrcPath and DestPath can point to same memory area,
+ // so we use the temporary buffer for copying.
+ char TmpStr[NM];
+ strncpyz(TmpStr,DestPtr,ASIZE(TmpStr));
+ strcpy(DestPath,TmpStr);
+ }
+ return((char *)DestPtr);
+}
+
+
+wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath)
+{
+ const wchar *DestPtr=SrcPath;
+
+ // Prevent \..\ in any part of path string.
+ for (const wchar *s=DestPtr;*s!=0;s++)
+ if (IsPathDiv(s[0]) && s[1]=='.' && s[2]=='.' && IsPathDiv(s[3]))
+ DestPtr=s+4;
+
+ // Remove :\ and any sequence of . and \ in the beginning of path string.
+ while (*DestPtr!=0)
+ {
+ const wchar *s=DestPtr;
+ if (s[0] && IsDriveDiv(s[1]))
+ s+=2;
+ if (s[0]=='\\' && s[1]=='\\')
+ {
+ const wchar *Slash=wcschr(s+2,'\\');
+ if (Slash!=NULL && (Slash=wcschr(Slash+1,'\\'))!=NULL)
+ s=Slash+1;
+ }
+ for (const wchar *t=s;*t!=0;t++)
+ if (IsPathDiv(*t))
+ s=t+1;
+ else
+ if (*t!='.')
+ break;
+ if (s==DestPtr)
+ break;
+ DestPtr=s;
+ }
+
+ // Code above does not remove last "..", doing here.
+ if (DestPtr[0]=='.' && DestPtr[1]=='.' && DestPtr[2]==0)
+ DestPtr+=2;
+
+ if (DestPath!=NULL)
+ {
+ // SrcPath and DestPath can point to same memory area,
+ // so we use the temporary buffer for copying.
+ wchar TmpStr[NM];
+ wcsncpyz(TmpStr,DestPtr,ASIZE(TmpStr));
+ wcscpy(DestPath,TmpStr);
+ }
+ return((wchar *)DestPtr);
+}
+
+
+void SetExt(char *Name,const char *NewExt)
+{
+ char *Dot=GetExt(Name);
+ if (NewExt==NULL)
+ {
+ if (Dot!=NULL)
+ *Dot=0;
+ }
+ else
+ if (Dot==NULL)
+ {
+ strcat(Name,".");
+ strcat(Name,NewExt);
+ }
+ else
+ strcpy(Dot+1,NewExt);
+}
+
+
+void SetExt(wchar *Name,const wchar *NewExt)
+{
+ if (Name==NULL || *Name==0)
+ return;
+ wchar *Dot=GetExt(Name);
+ if (NewExt==NULL)
+ {
+ if (Dot!=NULL)
+ *Dot=0;
+ }
+ else
+ if (Dot==NULL)
+ {
+ wcscat(Name,L".");
+ wcscat(Name,NewExt);
+ }
+ else
+ wcscpy(Dot+1,NewExt);
+}
+
+
+#ifndef SFX_MODULE
+void SetSFXExt(char *SFXName)
+{
+#ifdef _UNIX
+ SetExt(SFXName,"sfx");
+#endif
+
+#if defined(_WIN_ALL) || defined(_EMX)
+ SetExt(SFXName,"exe");
+#endif
+}
+#endif
+
+
+#ifndef SFX_MODULE
+void SetSFXExt(wchar *SFXName)
+{
+ if (SFXName==NULL || *SFXName==0)
+ return;
+
+#ifdef _UNIX
+ SetExt(SFXName,L"sfx");
+#endif
+
+#if defined(_WIN_ALL) || defined(_EMX)
+ SetExt(SFXName,L"exe");
+#endif
+}
+#endif
+
+
+char *GetExt(const char *Name)
+{
+ return(Name==NULL ? NULL:strrchrd(PointToName(Name),'.'));
+}
+
+
+wchar *GetExt(const wchar *Name)
+{
+ return(Name==NULL ? NULL:wcsrchr(PointToName(Name),'.'));
+}
+
+
+// 'Ext' is an extension without the leading dot, like "rar".
+bool CmpExt(const char *Name,const char *Ext)
+{
+ char *NameExt=GetExt(Name);
+ return(NameExt!=NULL && stricomp(NameExt+1,Ext)==0);
+}
+
+
+// 'Ext' is an extension without the leading dot, like L"rar".
+bool CmpExt(const wchar *Name,const wchar *Ext)
+{
+ wchar *NameExt=GetExt(Name);
+ return(NameExt!=NULL && wcsicomp(NameExt+1,Ext)==0);
+}
+
+
+bool IsWildcard(const char *Str,const wchar *StrW)
+{
+ if (StrW!=NULL && *StrW!=0)
+ return(wcspbrk(StrW,L"*?")!=NULL);
+ return(Str==NULL ? false:strpbrk(Str,"*?")!=NULL);
+}
+
+
+bool IsPathDiv(int Ch)
+{
+#if defined(_WIN_ALL) || defined(_EMX)
+ return(Ch=='\\' || Ch=='/');
+#else
+ return(Ch==CPATHDIVIDER);
+#endif
+}
+
+
+bool IsDriveDiv(int Ch)
+{
+#ifdef _UNIX
+ return(false);
+#else
+ return(Ch==':');
+#endif
+}
+
+
+int GetPathDisk(const char *Path)
+{
+ if (IsDiskLetter(Path))
+ return(etoupper(*Path)-'A');
+ else
+ return(-1);
+}
+
+
+int GetPathDisk(const wchar *Path)
+{
+ if (IsDiskLetter(Path))
+ return(etoupperw(*Path)-'A');
+ else
+ return(-1);
+}
+
+
+void AddEndSlash(char *Path)
+{
+ char *LastChar=PointToLastChar(Path);
+ if (*LastChar!=0 && *LastChar!=CPATHDIVIDER)
+ strcat(LastChar,PATHDIVIDER);
+}
+
+
+void AddEndSlash(wchar *Path)
+{
+ size_t Length=wcslen(Path);
+ if (Length>0 && Path[Length-1]!=CPATHDIVIDER)
+ wcscat(Path,PATHDIVIDERW);
+}
+
+
+// Returns file path including the trailing path separator symbol.
+void GetFilePath(const char *FullName,char *Path,int MaxLength)
+{
+ size_t PathLength=Min(MaxLength-1,PointToName(FullName)-FullName);
+ strncpy(Path,FullName,PathLength);
+ Path[PathLength]=0;
+}
+
+
+// Returns file path including the trailing path separator symbol.
+void GetFilePath(const wchar *FullName,wchar *Path,int MaxLength)
+{
+ size_t PathLength=Min(MaxLength-1,PointToName(FullName)-FullName);
+ wcsncpy(Path,FullName,PathLength);
+ Path[PathLength]=0;
+}
+
+
+// Removes name and returns file path without the trailing
+// path separator symbol.
+void RemoveNameFromPath(char *Path)
+{
+ char *Name=PointToName(Path);
+ if (Name>=Path+2 && (!IsDriveDiv(Path[1]) || Name>=Path+4))
+ Name--;
+ *Name=0;
+}
+
+
+// Removes name and returns file path without the trailing
+// path separator symbol.
+void RemoveNameFromPath(wchar *Path)
+{
+ wchar *Name=PointToName(Path);
+ if (Name>=Path+2 && (!IsDriveDiv(Path[1]) || Name>=Path+4))
+ Name--;
+ *Name=0;
+}
+
+
+#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
+void GetAppDataPath(char *Path)
+{
+ LPMALLOC g_pMalloc;
+ SHGetMalloc(&g_pMalloc);
+ LPITEMIDLIST ppidl;
+ *Path=0;
+ bool Success=false;
+ if (SHGetSpecialFolderLocation(NULL,CSIDL_APPDATA,&ppidl)==NOERROR &&
+ SHGetPathFromIDListA(ppidl,Path) && *Path!=0)
+ {
+ AddEndSlash(Path);
+ strcat(Path,"WinRAR");
+ Success=FileExist(Path) || MakeDir(Path,NULL,false,0)==MKDIR_SUCCESS;
+ }
+ if (!Success)
+ {
+ GetModuleFileNameA(NULL,Path,NM);
+ RemoveNameFromPath(Path);
+ }
+ g_pMalloc->Free(ppidl);
+}
+#endif
+
+
+#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
+void GetAppDataPath(wchar *Path)
+{
+ LPMALLOC g_pMalloc;
+ SHGetMalloc(&g_pMalloc);
+ LPITEMIDLIST ppidl;
+ *Path=0;
+ bool Success=false;
+ if (SHGetSpecialFolderLocation(NULL,CSIDL_APPDATA,&ppidl)==NOERROR &&
+ SHGetPathFromIDListW(ppidl,Path) && *Path!=0)
+ {
+ AddEndSlash(Path);
+ wcscat(Path,L"WinRAR");
+ Success=FileExist(NULL,Path) || MakeDir(NULL,Path,false,0)==MKDIR_SUCCESS;
+ }
+ if (!Success)
+ {
+ GetModuleFileNameW(NULL,Path,NM);
+ RemoveNameFromPath(Path);
+ }
+ g_pMalloc->Free(ppidl);
+}
+#endif
+
+
+#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
+void GetRarDataPath(char *Path)
+{
+ *Path=0;
+
+ HKEY hKey;
+ if (RegOpenKeyExA(HKEY_CURRENT_USER,"Software\\WinRAR\\Paths",0,
+ KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS)
+ {
+ DWORD DataSize=NM,Type;
+ RegQueryValueExA(hKey,"AppData",0,&Type,(BYTE *)Path,&DataSize);
+ RegCloseKey(hKey);
+ }
+
+ if (*Path==0 || !FileExist(Path))
+ GetAppDataPath(Path);
+}
+#endif
+
+
+#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
+void GetRarDataPath(wchar *Path)
+{
+ *Path=0;
+
+ HKEY hKey;
+ if (RegOpenKeyExW(HKEY_CURRENT_USER,L"Software\\WinRAR\\Paths",0,
+ KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS)
+ {
+ DWORD DataSize=NM,Type;
+ RegQueryValueExW(hKey,L"AppData",0,&Type,(BYTE *)Path,&DataSize);
+ RegCloseKey(hKey);
+ }
+
+ if (*Path==0 || !FileExist(NULL,Path))
+ GetAppDataPath(Path);
+}
+#endif
+
+
+#ifndef SFX_MODULE
+bool EnumConfigPaths(char *Path,int Number)
+{
+#ifdef _EMX
+ static char RARFileName[NM];
+ if (Number==-1)
+ strcpy(RARFileName,Path);
+ if (Number!=0)
+ return(false);
+#ifndef _DJGPP
+ if (_osmode==OS2_MODE)
+ {
+ PTIB ptib;
+ PPIB ppib;
+ DosGetInfoBlocks(&ptib, &ppib);
+ DosQueryModuleName(ppib->pib_hmte,NM,Path);
+ }
+ else
+#endif
+ strcpy(Path,RARFileName);
+ RemoveNameFromPath(Path);
+ return(true);
+#elif defined(_UNIX)
+ static const char *AltPath[]={
+ "/etc","/etc/rar","/usr/lib","/usr/local/lib","/usr/local/etc"
+ };
+ if (Number==0)
+ {
+ char *EnvStr=getenv("HOME");
+ strncpy(Path, (EnvStr==NULL) ? AltPath[0] : EnvStr, NM-1);
+ Path[NM-1]=0;
+ return(true);
+ }
+ Number--;
+ if (Number<0 || Number>=sizeof(AltPath)/sizeof(AltPath[0]))
+ return(false);
+ strcpy(Path,AltPath[Number]);
+ return(true);
+#elif defined(_WIN_ALL)
+
+ if (Number<0 || Number>1)
+ return(false);
+ if (Number==0)
+ GetRarDataPath(Path);
+ else
+ {
+ GetModuleFileNameA(NULL,Path,NM);
+ RemoveNameFromPath(Path);
+ }
+ return(true);
+
+#else
+ return(false);
+#endif
+}
+#endif
+
+
+#if defined(_WIN_ALL) && !defined(SFX_MODULE)
+bool EnumConfigPaths(wchar *Path,int Number)
+{
+ if (Number<0 || Number>1)
+ return(false);
+ if (Number==0)
+ GetRarDataPath(Path);
+ else
+ {
+ GetModuleFileNameW(NULL,Path,NM);
+ RemoveNameFromPath(Path);
+ }
+ return(true);
+}
+#endif
+
+
+#ifndef SFX_MODULE
+void GetConfigName(const char *Name,char *FullName,bool CheckExist)
+{
+ *FullName=0;
+ for (int I=0;EnumConfigPaths(FullName,I);I++)
+ {
+ AddEndSlash(FullName);
+ strcat(FullName,Name);
+ if (!CheckExist || WildFileExist(FullName))
+ break;
+ }
+}
+#endif
+
+
+#if defined(_WIN_ALL) && !defined(SFX_MODULE)
+void GetConfigName(const wchar *Name,wchar *FullName,bool CheckExist)
+{
+ *FullName=0;
+ for (int I=0;EnumConfigPaths(FullName,I);I++)
+ {
+ AddEndSlash(FullName);
+ wcscat(FullName,Name);
+ if (!CheckExist || WildFileExist(NULL,FullName))
+ break;
+ }
+}
+#endif
+
+
+// Returns a pointer to rightmost digit of volume number.
+char* GetVolNumPart(char *ArcName)
+{
+ // Pointing to last name character.
+ char *ChPtr=ArcName+strlen(ArcName)-1;
+
+ // Skipping the archive extension.
+ while (!IsDigit(*ChPtr) && ChPtr>ArcName)
+ ChPtr--;
+
+ // Skipping the numeric part of name.
+ char *NumPtr=ChPtr;
+ while (IsDigit(*NumPtr) && NumPtr>ArcName)
+ NumPtr--;
+
+ // Searching for first numeric part in names like name.part##of##.rar.
+ // Stop search on the first dot.
+ while (NumPtr>ArcName && *NumPtr!='.')
+ {
+ if (IsDigit(*NumPtr))
+ {
+ // Validate the first numeric part only if it has a dot somewhere
+ // before it.
+ char *Dot=strchrd(PointToName(ArcName),'.');
+ if (Dot!=NULL && DotArcName)
+ ChPtr--;
+
+ // Skipping the numeric part of name.
+ wchar *NumPtr=ChPtr;
+ while (IsDigit(*NumPtr) && NumPtr>ArcName)
+ NumPtr--;
+
+ // Searching for first numeric part in names like name.part##of##.rar.
+ // Stop search on the first dot.
+ while (NumPtr>ArcName && *NumPtr!='.')
+ {
+ if (IsDigit(*NumPtr))
+ {
+ // Validate the first numeric part only if it has a dot somewhere
+ // before it.
+ wchar *Dot=wcschr(PointToName(ArcName),'.');
+ if (Dot!=NULL && Dot|\"")==NULL);
+}
+
+
+bool IsNameUsable(const wchar *Name)
+{
+#ifndef _UNIX
+ if (Name[0] && Name[1] && wcschr(Name+2,':')!=NULL)
+ return(false);
+ for (const wchar *s=Name;*s!=0;s++)
+ {
+ if ((uint)*s<32)
+ return(false);
+ if (*s==' ' && IsPathDiv(s[1]))
+ return(false);
+ }
+#endif
+ return(*Name!=0 && wcspbrk(Name,L"?*<>|\"")==NULL);
+}
+
+
+void MakeNameUsable(char *Name,bool Extended)
+{
+#ifdef _WIN_ALL
+ // In Windows we also need to convert characters not defined in current
+ // code page. This double conversion changes them to '?', which is
+ // catched by code below.
+ size_t NameLength=strlen(Name);
+ wchar NameW[NM];
+ CharToWide(Name,NameW,ASIZE(NameW));
+ WideToChar(NameW,Name,NameLength+1);
+ Name[NameLength]=0;
+#endif
+ for (char *s=Name;*s!=0;s=charnext(s))
+ {
+ if (strchr(Extended ? "?*<>|\"":"?*",*s)!=NULL || Extended && (byte)*s<32)
+ *s='_';
+#ifdef _EMX
+ if (*s=='=')
+ *s='_';
+#endif
+#ifndef _UNIX
+ if (s-Name>1 && *s==':')
+ *s='_';
+ if (*s==' ' && IsPathDiv(s[1]))
+ *s='_';
+#endif
+ }
+}
+
+
+void MakeNameUsable(wchar *Name,bool Extended)
+{
+ for (wchar *s=Name;*s!=0;s++)
+ {
+ if (wcschr(Extended ? L"?*<>|\"":L"?*",*s)!=NULL || Extended && (uint)*s<32)
+ *s='_';
+#ifndef _UNIX
+ if (s-Name>1 && *s==':')
+ *s='_';
+ if (*s==' ' && IsPathDiv(s[1]))
+ *s='_';
+#endif
+ }
+}
+
+
+char* UnixSlashToDos(char *SrcName,char *DestName,uint MaxLength)
+{
+ if (DestName!=NULL && DestName!=SrcName)
+ if (strlen(SrcName)>=MaxLength)
+ {
+ *DestName=0;
+ return(DestName);
+ }
+ else
+ strcpy(DestName,SrcName);
+ for (char *s=SrcName;*s!=0;s=charnext(s))
+ {
+ if (*s=='/')
+ if (DestName==NULL)
+ *s='\\';
+ else
+ DestName[s-SrcName]='\\';
+ }
+ return(DestName==NULL ? SrcName:DestName);
+}
+
+
+char* DosSlashToUnix(char *SrcName,char *DestName,uint MaxLength)
+{
+ if (DestName!=NULL && DestName!=SrcName)
+ if (strlen(SrcName)>=MaxLength)
+ {
+ *DestName=0;
+ return(DestName);
+ }
+ else
+ strcpy(DestName,SrcName);
+ for (char *s=SrcName;*s!=0;s=charnext(s))
+ {
+ if (*s=='\\')
+ if (DestName==NULL)
+ *s='/';
+ else
+ DestName[s-SrcName]='/';
+ }
+ return(DestName==NULL ? SrcName:DestName);
+}
+
+
+wchar* UnixSlashToDos(wchar *SrcName,wchar *DestName,uint MaxLength)
+{
+ if (DestName!=NULL && DestName!=SrcName)
+ if (wcslen(SrcName)>=MaxLength)
+ {
+ *DestName=0;
+ return(DestName);
+ }
+ else
+ wcscpy(DestName,SrcName);
+ for (wchar *s=SrcName;*s!=0;s++)
+ {
+ if (*s=='/')
+ if (DestName==NULL)
+ *s='\\';
+ else
+ DestName[s-SrcName]='\\';
+ }
+ return(DestName==NULL ? SrcName:DestName);
+}
+
+
+wchar* DosSlashToUnix(wchar *SrcName,wchar *DestName,uint MaxLength)
+{
+ if (DestName!=NULL && DestName!=SrcName)
+ if (wcslen(SrcName)>=MaxLength)
+ {
+ *DestName=0;
+ return(DestName);
+ }
+ else
+ wcscpy(DestName,SrcName);
+ for (wchar *s=SrcName;*s!=0;s++)
+ {
+ if (*s=='\\')
+ if (DestName==NULL)
+ *s='/';
+ else
+ DestName[s-SrcName]='/';
+ }
+ return(DestName==NULL ? SrcName:DestName);
+}
+
+
+void ConvertNameToFull(const char *Src,char *Dest)
+{
+#ifdef _WIN_ALL
+#ifndef _WIN_CE
+ char FullName[NM],*NamePtr;
+ DWORD Code=GetFullPathNameA(Src,ASIZE(FullName),FullName,&NamePtr);
+ if (Code!=0 && Code='A' && Letter<='Z' && IsDriveDiv(Path[1]));
+}
+
+
+bool IsDiskLetter(const wchar *Path)
+{
+ wchar Letter=etoupperw(Path[0]);
+ return(Letter>='A' && Letter<='Z' && IsDriveDiv(Path[1]));
+}
+
+
+void GetPathRoot(const char *Path,char *Root)
+{
+ *Root=0;
+ if (IsDiskLetter(Path))
+ sprintf(Root,"%c:\\",*Path);
+ else
+ if (Path[0]=='\\' && Path[1]=='\\')
+ {
+ const char *Slash=strchr(Path+2,'\\');
+ if (Slash!=NULL)
+ {
+ size_t Length;
+ if ((Slash=strchr(Slash+1,'\\'))!=NULL)
+ Length=Slash-Path+1;
+ else
+ Length=strlen(Path);
+ strncpy(Root,Path,Length);
+ Root[Length]=0;
+ }
+ }
+}
+
+
+void GetPathRoot(const wchar *Path,wchar *Root)
+{
+ *Root=0;
+ if (IsDiskLetter(Path))
+ sprintfw(Root,4,L"%c:\\",*Path);
+ else
+ if (Path[0]=='\\' && Path[1]=='\\')
+ {
+ const wchar *Slash=wcschr(Path+2,'\\');
+ if (Slash!=NULL)
+ {
+ size_t Length;
+ if ((Slash=wcschr(Slash+1,'\\'))!=NULL)
+ Length=Slash-Path+1;
+ else
+ Length=wcslen(Path);
+ wcsncpy(Root,Path,Length);
+ Root[Length]=0;
+ }
+ }
+}
+
+
+int ParseVersionFileName(char *Name,wchar *NameW,bool Truncate)
+{
+ int Version=0;
+ char *VerText=strrchrd(Name,';');
+ if (VerText!=NULL)
+ {
+ Version=atoi(VerText+1);
+ if (Truncate)
+ *VerText=0;
+ }
+ if (NameW!=NULL)
+ {
+ wchar *VerTextW=wcsrchr(NameW,';');
+ if (VerTextW!=NULL)
+ {
+ if (Version==0)
+ Version=atoiw(VerTextW+1);
+ if (Truncate)
+ *VerTextW=0;
+ }
+ }
+ return(Version);
+}
+
+
+#if !defined(SFX_MODULE) && !defined(SETUP)
+// Get the name of first volume. Return the leftmost digit of volume number.
+char* VolNameToFirstName(const char *VolName,char *FirstName,bool NewNumbering)
+{
+ if (FirstName!=VolName)
+ strcpy(FirstName,VolName);
+ char *VolNumStart=FirstName;
+ if (NewNumbering)
+ {
+ char N='1';
+
+ // From the rightmost digit of volume number to the left.
+ for (char *ChPtr=GetVolNumPart(FirstName);ChPtr>FirstName;ChPtr--)
+ if (IsDigit(*ChPtr))
+ {
+ *ChPtr=N; // Set the rightmost digit to '1' and others to '0'.
+ N='0';
+ }
+ else
+ if (N=='0')
+ {
+ VolNumStart=ChPtr+1; // Store the position of leftmost digit in volume number.
+ break;
+ }
+ }
+ else
+ {
+ // Old volume numbering scheme. Just set the extension to ".rar".
+ SetExt(FirstName,"rar");
+ VolNumStart=GetExt(FirstName);
+ }
+ if (!FileExist(FirstName))
+ {
+ // If the first volume, which name we just generated, is not exist,
+ // check if volume with same name and any other extension is available.
+ // It can help in case of *.exe or *.sfx first volume.
+ char Mask[NM];
+ strcpy(Mask,FirstName);
+ SetExt(Mask,"*");
+ FindFile Find;
+ Find.SetMask(Mask);
+ FindData FD;
+ while (Find.Next(&FD))
+ {
+ Archive Arc;
+ if (Arc.Open(FD.Name,FD.NameW,0) && Arc.IsArchive(true) && !Arc.NotFirstVolume)
+ {
+ strcpy(FirstName,FD.Name);
+ break;
+ }
+ }
+ }
+ return(VolNumStart);
+}
+#endif
+
+
+#if !defined(SFX_MODULE) && !defined(SETUP)
+// Get the name of first volume. Return the leftmost digit of volume number.
+wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,bool NewNumbering)
+{
+ if (FirstName!=VolName)
+ wcscpy(FirstName,VolName);
+ wchar *VolNumStart=FirstName;
+ if (NewNumbering)
+ {
+ wchar N='1';
+
+ // From the rightmost digit of volume number to the left.
+ for (wchar *ChPtr=GetVolNumPart(FirstName);ChPtr>FirstName;ChPtr--)
+ if (IsDigit(*ChPtr))
+ {
+ *ChPtr=N; // Set the rightmost digit to '1' and others to '0'.
+ N='0';
+ }
+ else
+ if (N=='0')
+ {
+ VolNumStart=ChPtr+1; // Store the position of leftmost digit in volume number.
+ break;
+ }
+ }
+ else
+ {
+ // Old volume numbering scheme. Just set the extension to ".rar".
+ SetExt(FirstName,L"rar");
+ VolNumStart=GetExt(FirstName);
+ }
+ if (!FileExist(NULL,FirstName))
+ {
+ // If the first volume, which name we just generated, is not exist,
+ // check if volume with same name and any other extension is available.
+ // It can help in case of *.exe or *.sfx first volume.
+ wchar Mask[NM];
+ wcscpy(Mask,FirstName);
+ SetExt(Mask,L"*");
+ FindFile Find;
+ Find.SetMaskW(Mask);
+ FindData FD;
+ while (Find.Next(&FD))
+ {
+ Archive Arc;
+ if (Arc.Open(FD.Name,FD.NameW,0) && Arc.IsArchive(true) && !Arc.NotFirstVolume)
+ {
+ wcscpy(FirstName,FD.NameW);
+ break;
+ }
+ }
+ }
+ return(VolNumStart);
+}
+#endif
+
+
+#ifndef SFX_MODULE
+static void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
+ uint ArcNumber,bool &ArcNumPresent);
+
+void GenerateArchiveName(char *ArcName,wchar *ArcNameW,size_t MaxSize,
+ char *GenerateMask,bool Archiving)
+{
+ // Must be enough space for archive name plus all stuff in mask plus
+ // extra overhead produced by mask 'N' (archive number) characters.
+ // One 'N' character can result in several numbers if we process more
+ // than 9 archives.
+ char NewName[NM+MAX_GENERATE_MASK+20];
+ wchar NewNameW[NM+MAX_GENERATE_MASK+20];
+
+ uint ArcNumber=1;
+ while (true) // Loop for 'N' (archive number) processing.
+ {
+ strncpyz(NewName,NullToEmpty(ArcName),ASIZE(NewName));
+ wcsncpyz(NewNameW,NullToEmpty(ArcNameW),ASIZE(NewNameW));
+
+ bool ArcNumPresent=false;
+
+ GenArcName(NewName,NewNameW,GenerateMask,ArcNumber,ArcNumPresent);
+
+ if (!ArcNumPresent)
+ break;
+ if (!FileExist(NewName,NewNameW))
+ {
+ if (!Archiving && ArcNumber>1)
+ {
+ // If we perform non-archiving operation, we need to use the last
+ // existing archive before the first unused name. So we generate
+ // the name for (ArcNumber-1) below.
+ strncpyz(NewName,NullToEmpty(ArcName),ASIZE(NewName));
+ wcsncpyz(NewNameW,NullToEmpty(ArcNameW),ASIZE(NewNameW));
+ GenArcName(NewName,NewNameW,GenerateMask,ArcNumber-1,ArcNumPresent);
+ }
+ break;
+ }
+ ArcNumber++;
+ }
+ if (ArcName!=NULL && *ArcName!=0)
+ strncpyz(ArcName,NewName,MaxSize);
+ if (ArcNameW!=NULL && *ArcNameW!=0)
+ wcsncpyz(ArcNameW,NewNameW,MaxSize);
+}
+
+
+void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
+ uint ArcNumber,bool &ArcNumPresent)
+{
+ bool Prefix=false;
+ if (*GenerateMask=='+')
+ {
+ Prefix=true; // Add the time string before the archive name.
+ GenerateMask++; // Skip '+' in the beginning of time mask.
+ }
+
+ char Mask[MAX_GENERATE_MASK];
+ strncpyz(Mask,*GenerateMask ? GenerateMask:"yyyymmddhhmmss",ASIZE(Mask));
+
+ bool QuoteMode=false,Hours=false;
+ for (uint I=0;Mask[I]!=0;I++)
+ {
+ if (Mask[I]=='{' || Mask[I]=='}')
+ {
+ QuoteMode=(Mask[I]=='{');
+ continue;
+ }
+ if (QuoteMode)
+ continue;
+ int CurChar=etoupper(Mask[I]);
+ if (CurChar=='H')
+ Hours=true;
+
+ if (Hours && CurChar=='M')
+ {
+ // Replace minutes with 'I'. We use 'M' both for months and minutes,
+ // so we treat as minutes only those 'M' which are found after hours.
+ Mask[I]='I';
+ }
+ if (CurChar=='N')
+ {
+ uint Digits=GetDigits(ArcNumber);
+ uint NCount=0;
+ while (etoupper(Mask[I+NCount])=='N')
+ NCount++;
+
+ // Here we ensure that we have enough 'N' characters to fit all digits
+ // of archive number. We'll replace them by actual number later
+ // in this function.
+ if (NCount=4)
+ CurWeek++;
+
+ char Field[10][6];
+
+ sprintf(Field[0],"%04d",rlt.Year);
+ sprintf(Field[1],"%02d",rlt.Month);
+ sprintf(Field[2],"%02d",rlt.Day);
+ sprintf(Field[3],"%02d",rlt.Hour);
+ sprintf(Field[4],"%02d",rlt.Minute);
+ sprintf(Field[5],"%02d",rlt.Second);
+ sprintf(Field[6],"%02d",CurWeek);
+ sprintf(Field[7],"%d",WeekDay+1);
+ sprintf(Field[8],"%03d",rlt.yDay+1);
+ sprintf(Field[9],"%05d",ArcNumber);
+
+ const char *MaskChars="YMDHISWAEN";
+
+ int CField[sizeof(Field)/sizeof(Field[0])];
+ memset(CField,0,sizeof(CField));
+ QuoteMode=false;
+ for (int I=0;Mask[I]!=0;I++)
+ {
+ if (Mask[I]=='{' || Mask[I]=='}')
+ {
+ QuoteMode=(Mask[I]=='{');
+ continue;
+ }
+ if (QuoteMode)
+ continue;
+ const char *Ch=strchr(MaskChars,etoupper(Mask[I]));
+ if (Ch!=NULL)
+ CField[Ch-MaskChars]++;
+ }
+
+ char DateText[MAX_GENERATE_MASK];
+ *DateText=0;
+ QuoteMode=false;
+ for (size_t I=0,J=0;Mask[I]!=0 && J0)
+ DestW[DestSize-1]=0;
+
+ return(DestW);
+}
+
+
+// Unlike WideToChar, always returns the zero terminated string,
+// even if the destination buffer size is not enough.
+char* GetAsciiName(const wchar *NameW,char *Name,size_t DestSize)
+{
+ if (DestSize>0)
+ {
+ WideToChar(NameW,Name,DestSize);
+ Name[DestSize-1]=0;
+ }
+ else
+ *Name=0;
+ return Name;
+}
diff --git a/src/unrar/pathfn.hpp b/src/unrar/pathfn.hpp
new file mode 100644
index 0000000000..5ee6146967
--- /dev/null
+++ b/src/unrar/pathfn.hpp
@@ -0,0 +1,66 @@
+#ifndef _RAR_PATHFN_
+#define _RAR_PATHFN_
+
+char* PointToName(const char *Path);
+wchar* PointToName(const wchar *Path);
+char* PointToLastChar(const char *Path);
+wchar* PointToLastChar(const wchar *Path);
+char* ConvertPath(const char *SrcPath,char *DestPath);
+wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath);
+void SetExt(char *Name,const char *NewExt);
+void SetExt(wchar *Name,const wchar *NewExt);
+void SetSFXExt(char *SFXName);
+void SetSFXExt(wchar *SFXName);
+char *GetExt(const char *Name);
+wchar *GetExt(const wchar *Name);
+bool CmpExt(const char *Name,const char *Ext);
+bool CmpExt(const wchar *Name,const wchar *Ext);
+bool IsWildcard(const char *Str,const wchar *StrW=NULL);
+bool IsPathDiv(int Ch);
+bool IsDriveDiv(int Ch);
+int GetPathDisk(const char *Path);
+int GetPathDisk(const wchar *Path);
+void AddEndSlash(char *Path);
+void AddEndSlash(wchar *Path);
+void GetFilePath(const char *FullName,char *Path,int MaxLength);
+void GetFilePath(const wchar *FullName,wchar *Path,int MaxLength);
+void RemoveNameFromPath(char *Path);
+void RemoveNameFromPath(wchar *Path);
+void GetAppDataPath(char *Path);
+void GetAppDataPath(wchar *Path);
+void GetRarDataPath(char *Path);
+void GetRarDataPath(wchar *Path);
+bool EnumConfigPaths(wchar *Path,int Number);
+bool EnumConfigPaths(char *Path,int Number);
+void GetConfigName(const char *Name,char *FullName,bool CheckExist);
+void GetConfigName(const wchar *Name,wchar *FullName,bool CheckExist);
+char* GetVolNumPart(char *ArcName);
+wchar* GetVolNumPart(wchar *ArcName);
+void NextVolumeName(char *ArcName,wchar *ArcNameW,uint MaxLength,bool OldNumbering);
+bool IsNameUsable(const char *Name);
+bool IsNameUsable(const wchar *Name);
+void MakeNameUsable(char *Name,bool Extended);
+void MakeNameUsable(wchar *Name,bool Extended);
+char* UnixSlashToDos(char *SrcName,char *DestName=NULL,uint MaxLength=NM);
+char* DosSlashToUnix(char *SrcName,char *DestName=NULL,uint MaxLength=NM);
+wchar* UnixSlashToDos(wchar *SrcName,wchar *DestName=NULL,uint MaxLength=NM);
+wchar* DosSlashToUnix(wchar *SrcName,wchar *DestName=NULL,uint MaxLength=NM);
+void ConvertNameToFull(const char *Src,char *Dest);
+void ConvertNameToFull(const wchar *Src,wchar *Dest);
+bool IsFullPath(const char *Path);
+bool IsFullPath(const wchar *Path);
+bool IsDiskLetter(const char *Path);
+bool IsDiskLetter(const wchar *Path);
+void GetPathRoot(const char *Path,char *Root);
+void GetPathRoot(const wchar *Path,wchar *Root);
+int ParseVersionFileName(char *Name,wchar *NameW,bool Truncate);
+char* VolNameToFirstName(const char *VolName,char *FirstName,bool NewNumbering);
+wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,bool NewNumbering);
+wchar* GetWideName(const char *Name,const wchar *NameW,wchar *DestW,size_t DestSize);
+char* GetAsciiName(const wchar *NameW,char *Name,size_t DestSize);
+
+#ifndef SFX_MODULE
+void GenerateArchiveName(char *ArcName,wchar *ArcNameW,size_t MaxSize,char *GenerateMask,bool Archiving);
+#endif
+
+#endif
diff --git a/src/unrar/rar.cpp b/src/unrar/rar.cpp
new file mode 100644
index 0000000000..e487cc6392
--- /dev/null
+++ b/src/unrar/rar.cpp
@@ -0,0 +1,144 @@
+#include "rar.hpp"
+
+#if !defined(GUI) && !defined(RARDLL)
+int main(int argc, char *argv[])
+{
+
+#ifdef _UNIX
+ setlocale(LC_ALL,"");
+#endif
+
+#if defined(_EMX) && !defined(_DJGPP)
+ uni_init(0);
+#endif
+
+#if !defined(_SFX_RTL_) && !defined(_WIN_ALL)
+ setbuf(stdout,NULL);
+#endif
+
+#if !defined(SFX_MODULE) && defined(_EMX)
+ EnumConfigPaths(argv[0],-1);
+#endif
+
+ ErrHandler.SetSignalHandlers(true);
+
+ RARInitData();
+
+#ifdef SFX_MODULE
+ char ModuleNameA[NM];
+ wchar ModuleNameW[NM];
+#ifdef _WIN_ALL
+ GetModuleFileNameW(NULL,ModuleNameW,ASIZE(ModuleNameW));
+ WideToChar(ModuleNameW,ModuleNameA);
+#else
+ strcpy(ModuleNameA,argv[0]);
+ *ModuleNameW=0;
+#endif
+#endif
+
+#ifdef _WIN_ALL
+ SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT|SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
+
+
+#endif
+
+#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SHELL_EXT)
+ // Must be initialized, normal initialization can be skipped in case of
+ // exception.
+ bool ShutdownOnClose=false;
+#endif
+
+#ifdef ALLOW_EXCEPTIONS
+ try
+#endif
+ {
+
+ CommandData Cmd;
+#ifdef SFX_MODULE
+ strcpy(Cmd.Command,"X");
+ char *Switch=NULL;
+#ifdef _SFX_RTL_
+ char *CmdLine=GetCommandLineA();
+ if (CmdLine!=NULL && *CmdLine=='\"')
+ CmdLine=strchr(CmdLine+1,'\"');
+ if (CmdLine!=NULL && (CmdLine=strpbrk(CmdLine," /"))!=NULL)
+ {
+ while (IsSpace(*CmdLine))
+ CmdLine++;
+ Switch=CmdLine;
+ }
+#else
+ Switch=argc>1 ? argv[1]:NULL;
+#endif
+ if (Switch!=NULL && Cmd.IsSwitch(Switch[0]))
+ {
+ int UpperCmd=etoupper(Switch[1]);
+ switch(UpperCmd)
+ {
+ case 'T':
+ case 'V':
+ Cmd.Command[0]=UpperCmd;
+ break;
+ case '?':
+ Cmd.OutHelp(RARX_SUCCESS);
+ break;
+ }
+ }
+ Cmd.AddArcName(ModuleNameA,ModuleNameW);
+ Cmd.ParseDone();
+#else // !SFX_MODULE
+ Cmd.PreprocessCommandLine(argc,argv);
+ if (!Cmd.ConfigDisabled)
+ {
+ Cmd.ReadConfig();
+ Cmd.ParseEnvVar();
+ }
+ Cmd.ParseCommandLine(argc,argv);
+#endif
+
+#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SHELL_EXT)
+ ShutdownOnClose=Cmd.Shutdown;
+#endif
+
+ InitConsoleOptions(Cmd.MsgStream,Cmd.Sound);
+ InitLogOptions(Cmd.LogName);
+ ErrHandler.SetSilent(Cmd.AllYes || Cmd.MsgStream==MSG_NULL);
+ ErrHandler.SetShutdown(Cmd.Shutdown);
+
+ Cmd.OutTitle();
+ Cmd.ProcessCommand();
+ }
+#ifdef ALLOW_EXCEPTIONS
+ catch (RAR_EXIT ErrCode)
+ {
+ ErrHandler.SetErrorCode(ErrCode);
+ }
+#ifdef ENABLE_BAD_ALLOC
+ catch (std::bad_alloc)
+ {
+ ErrHandler.MemoryErrorMsg();
+ ErrHandler.SetErrorCode(RARX_MEMORY);
+ }
+#endif
+ catch (...)
+ {
+ ErrHandler.SetErrorCode(RARX_FATAL);
+ }
+#endif
+
+ File::RemoveCreated();
+#if defined(SFX_MODULE) && defined(_DJGPP)
+ _chmod(ModuleNameA,1,0x20);
+#endif
+#if defined(_EMX) && !defined(_DJGPP)
+ uni_done();
+#endif
+#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SHELL_EXT)
+ if (ShutdownOnClose)
+ Shutdown();
+#endif
+ return(ErrHandler.GetErrorCode());
+}
+#endif
+
+
diff --git a/src/unrar/rar.hpp b/src/unrar/rar.hpp
new file mode 100644
index 0000000000..73ebd2bc71
--- /dev/null
+++ b/src/unrar/rar.hpp
@@ -0,0 +1,79 @@
+#ifndef _RAR_RARCOMMON_
+#define _RAR_RARCOMMON_
+
+#include "raros.hpp"
+#include "os.hpp"
+
+#ifdef RARDLL
+#include "dll.hpp"
+#endif
+
+
+#ifndef _WIN_CE
+#include "version.hpp"
+#endif
+#include "rartypes.hpp"
+#include "rardefs.hpp"
+#include "rarlang.hpp"
+#include "unicode.hpp"
+#include "errhnd.hpp"
+#include "array.hpp"
+#include "timefn.hpp"
+#include "secpassword.hpp"
+#include "options.hpp"
+#include "headers.hpp"
+#include "pathfn.hpp"
+#include "strfn.hpp"
+#include "strlist.hpp"
+#include "file.hpp"
+#include "sha1.hpp"
+#include "crc.hpp"
+#include "rijndael.hpp"
+#include "crypt.hpp"
+#include "filefn.hpp"
+#include "filestr.hpp"
+#include "find.hpp"
+#include "scantree.hpp"
+#include "savepos.hpp"
+#include "getbits.hpp"
+#include "rdwrfn.hpp"
+#include "archive.hpp"
+#include "match.hpp"
+#include "cmddata.hpp"
+#include "filcreat.hpp"
+#include "consio.hpp"
+#include "system.hpp"
+#ifdef _WIN_ALL
+#include "isnt.hpp"
+#endif
+#include "log.hpp"
+#include "rawread.hpp"
+#include "encname.hpp"
+#include "resource.hpp"
+#include "compress.hpp"
+
+#include "rarvm.hpp"
+#include "model.hpp"
+
+#include "unpack.hpp"
+
+
+
+#include "extinfo.hpp"
+#include "extract.hpp"
+
+
+
+#include "list.hpp"
+
+
+#include "rs.hpp"
+#include "recvol.hpp"
+#include "volume.hpp"
+#include "smallfn.hpp"
+#include "ulinks.hpp"
+
+#include "global.hpp"
+
+
+#endif
diff --git a/src/unrar/rardefs.hpp b/src/unrar/rardefs.hpp
new file mode 100644
index 0000000000..1e9788b384
--- /dev/null
+++ b/src/unrar/rardefs.hpp
@@ -0,0 +1,28 @@
+#ifndef _RAR_DEFS_
+#define _RAR_DEFS_
+
+#define Min(x,y) (((x)<(y)) ? (x):(y))
+#define Max(x,y) (((x)>(y)) ? (x):(y))
+
+#define ASIZE(x) (sizeof(x)/sizeof(x[0]))
+
+// MAXPASSWORD is expected to be multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE (16)
+// for CryptProtectMemory in SecPassword.
+#define MAXPASSWORD 128
+
+#define MAXSFXSIZE 0x100000
+
+#define DefSFXName "default.sfx"
+#define DefSortListName "rarfiles.lst"
+
+#ifndef FA_RDONLY
+ #define FA_RDONLY 0x01
+ #define FA_HIDDEN 0x02
+ #define FA_SYSTEM 0x04
+ #define FA_LABEL 0x08
+ #define FA_DIREC 0x10
+ #define FA_ARCH 0x20
+#endif
+
+
+#endif
diff --git a/src/unrar/rarlang.hpp b/src/unrar/rarlang.hpp
new file mode 100644
index 0000000000..6151d15a94
--- /dev/null
+++ b/src/unrar/rarlang.hpp
@@ -0,0 +1,10 @@
+#ifndef _RAR_LANG_
+#define _RAR_LANG_
+
+ #ifdef USE_RC
+ #include "rarres.hpp"
+ #else
+ #include "loclang.hpp"
+ #endif
+
+#endif
diff --git a/src/unrar/raros.hpp b/src/unrar/raros.hpp
new file mode 100644
index 0000000000..ce853bd7d4
--- /dev/null
+++ b/src/unrar/raros.hpp
@@ -0,0 +1,46 @@
+#ifndef _RAR_RAROS_
+#define _RAR_RAROS_
+
+#ifdef __EMX__
+ #define _EMX
+#endif
+
+#ifdef __DJGPP__
+ #define _DJGPP
+ #define _EMX
+#endif
+
+#if defined(__WIN32__) || defined(_WIN32)
+ #define _WIN_ALL // Defined for all Windows platforms, 32 and 64 bit, mobile and desktop.
+ #ifdef _M_X64
+ #define _WIN_64
+ #else
+ #define _WIN_32
+ #endif
+#endif
+
+#ifdef _WIN32_WCE
+ #define _WIN_ALL
+ #define _WIN_CE
+ #ifdef WM_FILECHANGEINFO
+ #define PC2002
+ #else
+ #undef PC2002
+ #endif
+#endif
+
+#ifdef __BEOS__
+ #define _UNIX
+ #define _BEOS
+#endif
+
+#ifdef __APPLE__
+ #define _UNIX
+ #define _APPLE
+#endif
+
+#if !defined(_EMX) && !defined(_WIN_ALL) && !defined(_BEOS) && !defined(_APPLE)
+ #define _UNIX
+#endif
+
+#endif
diff --git a/src/unrar/rarpch.cpp b/src/unrar/rarpch.cpp
new file mode 100644
index 0000000000..c070cf74b8
--- /dev/null
+++ b/src/unrar/rarpch.cpp
@@ -0,0 +1,2 @@
+// We use rarpch.cpp to create precompiled headers for MS Visual C++.
+#include "rar.hpp"
diff --git a/src/unrar/rartypes.hpp b/src/unrar/rartypes.hpp
new file mode 100644
index 0000000000..a2d8b44a04
--- /dev/null
+++ b/src/unrar/rartypes.hpp
@@ -0,0 +1,47 @@
+#ifndef _RAR_TYPES_
+#define _RAR_TYPES_
+
+typedef unsigned char byte; // unsigned 8 bits
+typedef unsigned short ushort; // preferably 16 bits, but can be more
+typedef unsigned int uint; // 32 bits or more
+
+#define PRESENT_INT32 // undefine if signed 32 bits is not available
+
+typedef unsigned int uint32; // 32 bits exactly
+typedef signed int int32; // signed 32 bits exactly
+
+// If compiler does not support 64 bit variables, we can define
+// uint64 and int64 as 32 bit, but it will limit the maximum processed
+// file size to 2 GB.
+#if defined(__BORLANDC__) || defined(_MSC_VER)
+typedef unsigned __int64 uint64; // unsigned 64 bits
+typedef signed __int64 int64; // signed 64 bits
+#else
+typedef unsigned long long uint64; // unsigned 64 bits
+typedef signed long long int64; // signed 64 bits
+#endif
+
+
+#if defined(_WIN_ALL) || defined(__GNUC__) || defined(__sgi) || defined(_AIX) || defined(__sun) || defined(__hpux) || defined(_OSF_SOURCE)
+typedef wchar_t wchar;
+#else
+typedef ushort wchar;
+#endif
+
+// Get lowest 16 bits.
+#define GET_SHORT16(x) (sizeof(ushort)==2 ? (ushort)(x):((x)&0xffff))
+
+// Get lowest 32 bits.
+#define GET_UINT32(x) (sizeof(uint32)==4 ? (uint32)(x):((x)&0xffffffff))
+
+// Make 64 bit integer from two 32 bit.
+#define INT32TO64(high,low) ((((uint64)(high))<<32)+((uint64)low))
+
+// Special int64 value, large enough to never be found in real life.
+// We use it in situations, when we need to indicate that parameter
+// is not defined and probably should be calculated inside of function.
+// Lower part is intentionally 0x7fffffff, not 0xffffffff, to make it
+// compatible with 32 bit int64.
+#define INT64NDF INT32TO64(0x7fffffff,0x7fffffff)
+
+#endif
diff --git a/src/unrar/rarvm.cpp b/src/unrar/rarvm.cpp
new file mode 100644
index 0000000000..8b85800647
--- /dev/null
+++ b/src/unrar/rarvm.cpp
@@ -0,0 +1,1139 @@
+#include "rar.hpp"
+
+#include "rarvmtbl.cpp"
+
+RarVM::RarVM()
+{
+ Mem=NULL;
+}
+
+
+RarVM::~RarVM()
+{
+ delete[] Mem;
+}
+
+
+void RarVM::Init()
+{
+ if (Mem==NULL)
+ Mem=new byte[VM_MEMSIZE+4];
+}
+
+/*********************************************************************
+ IS_VM_MEM macro checks if address belongs to VM memory pool (Mem).
+ Only Mem data are always low endian regardless of machine architecture,
+ so we need to convert them to native format when reading or writing.
+ VM registers have endianness of host machine.
+**********************************************************************/
+#define IS_VM_MEM(a) (((byte*)a)>=Mem && ((byte*)a)>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);
+ break;
+#endif
+ case VM_PRINT:
+ break;
+ }
+ Cmd++;
+ --MaxOpCount;
+ }
+}
+
+
+
+
+void RarVM::Prepare(byte *Code,uint CodeSize,VM_PreparedProgram *Prg)
+{
+ InitBitInput();
+ memcpy(InBuf,Code,Min(CodeSize,BitInput::MAX_SIZE));
+
+ // Calculate the single byte XOR checksum to check validity of VM code.
+ byte XorSum=0;
+ for (uint I=1;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;
+ }
+#endif
+ uint DataFlag=fgetbits();
+ faddbits(1);
+
+ // Read static data contained in DB operators. This data cannot be
+ // changed, it is a part of VM code, not a filter parameter.
+
+ if (DataFlag&0x8000)
+ {
+ uint DataSize=ReadData(*this)+1;
+ for (uint I=0;(uint)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++;
+ }
+ }
+
+ // 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
+}
+
+
+void RarVM::DecodeArg(VM_PreparedOperand &Op,bool ByteMode)
+{
+ uint Data=fgetbits();
+ if (Data & 0x8000)
+ {
+ Op.Type=VM_OPREG; // Operand is register (R[0]..R[7])
+ Op.Data=(Data>>12)&7; // Register number
+ Op.Addr=&R[Op.Data]; // Register address
+ faddbits(4); // 1 flag bit and 3 register number bits
+ }
+ else
+ if ((Data & 0xc000)==0)
+ {
+ Op.Type=VM_OPINT; // Operand is integer
+ if (ByteMode)
+ {
+ Op.Data=(Data>>6) & 0xff; // Byte integer.
+ faddbits(10);
+ }
+ else
+ {
+ faddbits(2);
+ Op.Data=ReadData(*this); // 32 bit integer.
+ }
+ }
+ else
+ {
+ // Operand is data addressed by register data, base address or both.
+ Op.Type=VM_OPREGMEM;
+ if ((Data & 0x2000)==0)
+ {
+ // Base address is zero, just use the address from register.
+ Op.Data=(Data>>10)&7;
+ Op.Addr=&R[Op.Data];
+ Op.Base=0;
+ faddbits(6);
+ }
+ else
+ {
+ if ((Data & 0x1000)==0)
+ {
+ // Use both register and base address.
+ Op.Data=(Data>>9)&7;
+ Op.Addr=&R[Op.Data];
+ faddbits(7);
+ }
+ else
+ {
+ // Use base address only. Access memory by fixed address.
+ Op.Data=0;
+ faddbits(4);
+ }
+ Op.Base=ReadData(*this); // Read base address.
+ }
+ }
+}
+
+
+uint RarVM::ReadData(BitInput &Inp)
+{
+ uint Data=Inp.fgetbits();
+ switch(Data&0xc000)
+ {
+ case 0:
+ Inp.faddbits(6);
+ return((Data>>10)&0xf);
+ case 0x4000:
+ if ((Data&0x3c00)==0)
+ {
+ Data=0xffffff00|((Data>>2)&0xff);
+ Inp.faddbits(14);
+ }
+ else
+ {
+ Data=(Data>>6)&0xff;
+ Inp.faddbits(10);
+ }
+ return(Data);
+ case 0x8000:
+ Inp.faddbits(2);
+ Data=Inp.fgetbits();
+ Inp.faddbits(16);
+ return(Data);
+ default:
+ Inp.faddbits(2);
+ Data=(Inp.fgetbits()<<16);
+ Inp.faddbits(16);
+ Data|=Inp.fgetbits();
+ Inp.faddbits(16);
+ return(Data);
+ }
+}
+
+
+void RarVM::SetMemory(uint Pos,byte *Data,uint DataSize)
+{
+ if (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,
+ 40, 0x46b9c560, VMSF_UPCASE
+ };
+ uint CodeCRC=CRC(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;
+ case VMSF_UPCASE:
+ {
+ int DataSize=R[4],SrcPos=0,DestPos=DataSize;
+ if ((uint)DataSize>=VM_GLOBALMEMADDR/2)
+ break;
+ while (SrcPos>= 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
diff --git a/src/unrar/rarvm.hpp b/src/unrar/rarvm.hpp
new file mode 100644
index 0000000000..96d42c2337
--- /dev/null
+++ b/src/unrar/rarvm.hpp
@@ -0,0 +1,113 @@
+#ifndef _RAR_VM_
+#define _RAR_VM_
+
+#define VM_STANDARDFILTERS
+
+#ifndef SFX_MODULE
+#define VM_OPTIMIZE
+#endif
+
+
+#define VM_MEMSIZE 0x40000
+#define VM_MEMMASK (VM_MEMSIZE-1)
+#define VM_GLOBALMEMADDR 0x3C000
+#define VM_GLOBALMEMSIZE 0x2000
+#define VM_FIXEDGLOBALSIZE 64
+
+enum VM_Commands
+{
+ VM_MOV, VM_CMP, VM_ADD, VM_SUB, VM_JZ, VM_JNZ, VM_INC, VM_DEC,
+ VM_JMP, VM_XOR, VM_AND, VM_OR, VM_TEST, VM_JS, VM_JNS, VM_JB,
+ VM_JBE, VM_JA, VM_JAE, VM_PUSH, VM_POP, VM_CALL, VM_RET, VM_NOT,
+ VM_SHL, VM_SHR, VM_SAR, VM_NEG, VM_PUSHA,VM_POPA, VM_PUSHF,VM_POPF,
+ VM_MOVZX,VM_MOVSX,VM_XCHG, VM_MUL, VM_DIV, VM_ADC, VM_SBB, VM_PRINT,
+
+#ifdef VM_OPTIMIZE
+ VM_MOVB, VM_MOVD, VM_CMPB, VM_CMPD,
+
+ VM_ADDB, VM_ADDD, VM_SUBB, VM_SUBD, VM_INCB, VM_INCD, VM_DECB, VM_DECD,
+ VM_NEGB, VM_NEGD,
+#endif
+
+ VM_STANDARD
+};
+
+enum VM_StandardFilters {
+ VMSF_NONE, VMSF_E8, VMSF_E8E9, VMSF_ITANIUM, VMSF_RGB, VMSF_AUDIO,
+ VMSF_DELTA, VMSF_UPCASE
+};
+
+enum VM_Flags {VM_FC=1,VM_FZ=2,VM_FS=0x80000000};
+
+enum VM_OpType {VM_OPREG,VM_OPINT,VM_OPREGMEM,VM_OPNONE};
+
+struct VM_PreparedOperand
+{
+ VM_OpType Type;
+ uint Data;
+ uint Base;
+ uint *Addr;
+};
+
+struct VM_PreparedCommand
+{
+ VM_Commands OpCode;
+ bool ByteMode;
+ VM_PreparedOperand Op1,Op2;
+};
+
+
+struct VM_PreparedProgram
+{
+ VM_PreparedProgram()
+ {
+ AltCmd=NULL;
+ FilteredDataSize=0;
+ CmdCount=0;
+ }
+
+ Array Cmd;
+ VM_PreparedCommand *AltCmd;
+ int CmdCount;
+
+ Array GlobalData;
+ Array StaticData; // static data contained in DB operators
+ uint InitR[7];
+
+ byte *FilteredData;
+ uint FilteredDataSize;
+};
+
+class RarVM:private BitInput
+{
+ private:
+ inline uint GetValue(bool ByteMode,uint *Addr);
+ inline void SetValue(bool ByteMode,uint *Addr,uint Value);
+ inline uint* GetOperand(VM_PreparedOperand *CmdOp);
+ void DecodeArg(VM_PreparedOperand &Op,bool ByteMode);
+#ifdef VM_OPTIMIZE
+ void Optimize(VM_PreparedProgram *Prg);
+#endif
+ bool ExecuteCode(VM_PreparedCommand *PreparedCode,uint CodeSize);
+#ifdef VM_STANDARDFILTERS
+ VM_StandardFilters IsStandardFilter(byte *Code,uint CodeSize);
+ void ExecuteStandardFilter(VM_StandardFilters FilterType);
+ uint FilterItanium_GetBits(byte *Data,int BitPos,int BitCount);
+ void FilterItanium_SetBits(byte *Data,uint BitField,int BitPos,int BitCount);
+#endif
+
+ byte *Mem;
+ uint R[8];
+ uint Flags;
+ public:
+ RarVM();
+ ~RarVM();
+ void Init();
+ void Prepare(byte *Code,uint CodeSize,VM_PreparedProgram *Prg);
+ void Execute(VM_PreparedProgram *Prg);
+ void SetLowEndianValue(uint *Addr,uint Value);
+ void SetMemory(uint Pos,byte *Data,uint DataSize);
+ static uint ReadData(BitInput &Inp);
+};
+
+#endif
diff --git a/src/unrar/rarvmtbl.cpp b/src/unrar/rarvmtbl.cpp
new file mode 100644
index 0000000000..b5e6c7201c
--- /dev/null
+++ b/src/unrar/rarvmtbl.cpp
@@ -0,0 +1,53 @@
+#define VMCF_OP0 0
+#define VMCF_OP1 1
+#define VMCF_OP2 2
+#define VMCF_OPMASK 3
+#define VMCF_BYTEMODE 4
+#define VMCF_JUMP 8
+#define VMCF_PROC 16
+#define VMCF_USEFLAGS 32
+#define VMCF_CHFLAGS 64
+
+static byte VM_CmdFlags[]=
+{
+ /* VM_MOV */ VMCF_OP2 | VMCF_BYTEMODE ,
+ /* VM_CMP */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
+ /* VM_ADD */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
+ /* VM_SUB */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
+ /* VM_JZ */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
+ /* VM_JNZ */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
+ /* VM_INC */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
+ /* VM_DEC */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
+ /* VM_JMP */ VMCF_OP1 | VMCF_JUMP ,
+ /* VM_XOR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
+ /* VM_AND */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
+ /* VM_OR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
+ /* VM_TEST */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
+ /* VM_JS */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
+ /* VM_JNS */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
+ /* VM_JB */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
+ /* VM_JBE */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
+ /* VM_JA */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
+ /* VM_JAE */ VMCF_OP1 | VMCF_JUMP | VMCF_USEFLAGS ,
+ /* VM_PUSH */ VMCF_OP1 ,
+ /* VM_POP */ VMCF_OP1 ,
+ /* VM_CALL */ VMCF_OP1 | VMCF_PROC ,
+ /* VM_RET */ VMCF_OP0 | VMCF_PROC ,
+ /* VM_NOT */ VMCF_OP1 | VMCF_BYTEMODE ,
+ /* VM_SHL */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
+ /* VM_SHR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
+ /* VM_SAR */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
+ /* VM_NEG */ VMCF_OP1 | VMCF_BYTEMODE | VMCF_CHFLAGS ,
+ /* VM_PUSHA */ VMCF_OP0 ,
+ /* VM_POPA */ VMCF_OP0 ,
+ /* VM_PUSHF */ VMCF_OP0 | VMCF_USEFLAGS ,
+ /* VM_POPF */ VMCF_OP0 | VMCF_CHFLAGS ,
+ /* VM_MOVZX */ VMCF_OP2 ,
+ /* VM_MOVSX */ VMCF_OP2 ,
+ /* VM_XCHG */ VMCF_OP2 | VMCF_BYTEMODE ,
+ /* VM_MUL */ VMCF_OP2 | VMCF_BYTEMODE ,
+ /* VM_DIV */ VMCF_OP2 | VMCF_BYTEMODE ,
+ /* VM_ADC */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS ,
+ /* VM_SBB */ VMCF_OP2 | VMCF_BYTEMODE | VMCF_USEFLAGS | VMCF_CHFLAGS ,
+ /* VM_PRINT */ VMCF_OP0
+};
diff --git a/src/unrar/rawread.cpp b/src/unrar/rawread.cpp
new file mode 100644
index 0000000000..df90171eb5
--- /dev/null
+++ b/src/unrar/rawread.cpp
@@ -0,0 +1,126 @@
+#include "rar.hpp"
+
+RawRead::RawRead(File *SrcFile)
+{
+ RawRead::SrcFile=SrcFile;
+ ReadPos=0;
+ DataSize=0;
+#ifndef SHELL_EXT
+ Crypt=NULL;
+#endif
+}
+
+
+void RawRead::Read(size_t Size)
+{
+#if !defined(SHELL_EXT) && !defined(RAR_NOCRYPT)
+ if (Crypt!=NULL)
+ {
+ size_t CurSize=Data.Size();
+ size_t SizeToRead=Size-(CurSize-DataSize);
+ if (SizeToRead>0)
+ {
+ size_t AlignedReadSize=SizeToRead+((~SizeToRead+1)&0xf);
+ Data.Add(AlignedReadSize);
+ size_t ReadSize=SrcFile->Read(&Data[CurSize],AlignedReadSize);
+ Crypt->DecryptBlock(&Data[CurSize],AlignedReadSize);
+ DataSize+=ReadSize==0 ? 0:Size;
+ }
+ else
+ DataSize+=Size;
+ }
+ else
+#endif
+ if (Size!=0)
+ {
+ Data.Add(Size);
+ DataSize+=SrcFile->Read(&Data[DataSize],Size);
+ }
+}
+
+
+void RawRead::Read(byte *SrcData,size_t Size)
+{
+ if (Size!=0)
+ {
+ Data.Add(Size);
+ memcpy(&Data[DataSize],SrcData,Size);
+ DataSize+=Size;
+ }
+}
+
+
+void RawRead::Get(byte &Field)
+{
+ if (ReadPos2 ? CRC(0xffffffff,&Data[2],(ProcessedOnly ? ReadPos:DataSize)-2):0xffffffff);
+}
diff --git a/src/unrar/rawread.hpp b/src/unrar/rawread.hpp
new file mode 100644
index 0000000000..39fefe6f79
--- /dev/null
+++ b/src/unrar/rawread.hpp
@@ -0,0 +1,32 @@
+#ifndef _RAR_RAWREAD_
+#define _RAR_RAWREAD_
+
+class RawRead
+{
+ private:
+ Array Data;
+ File *SrcFile;
+ size_t DataSize;
+ size_t ReadPos;
+#ifndef SHELL_EXT
+ CryptData *Crypt;
+#endif
+ public:
+ RawRead(File *SrcFile);
+ void Read(size_t Size);
+ void Read(byte *SrcData,size_t Size);
+ void Get(byte &Field);
+ void Get(ushort &Field);
+ void Get(uint &Field);
+ void Get8(int64 &Field);
+ void Get(byte *Field,size_t Size);
+ void Get(wchar *Field,size_t Size);
+ uint GetCRC(bool ProcessedOnly);
+ size_t Size() {return DataSize;}
+ size_t PaddedSize() {return Data.Size()-DataSize;}
+#ifndef SHELL_EXT
+ void SetCrypt(CryptData *Crypt) {RawRead::Crypt=Crypt;}
+#endif
+};
+
+#endif
diff --git a/src/unrar/rdwrfn.cpp b/src/unrar/rdwrfn.cpp
new file mode 100644
index 0000000000..d7bacd478a
--- /dev/null
+++ b/src/unrar/rdwrfn.cpp
@@ -0,0 +1,295 @@
+#include "rar.hpp"
+
+ComprDataIO::ComprDataIO()
+{
+ Init();
+}
+
+
+void ComprDataIO::Init()
+{
+ UnpackFromMemory=false;
+ UnpackToMemory=false;
+ UnpPackedSize=0;
+ ShowProgress=true;
+ TestMode=false;
+ SkipUnpCRC=false;
+ PackVolume=false;
+ UnpVolume=false;
+ NextVolumeMissing=false;
+ SrcFile=NULL;
+ DestFile=NULL;
+ UnpWrSize=0;
+ Command=NULL;
+ Encryption=0;
+ Decryption=0;
+ TotalPackRead=0;
+ CurPackRead=CurPackWrite=CurUnpRead=CurUnpWrite=0;
+ PackFileCRC=UnpFileCRC=PackedCRC=0xffffffff;
+ LastPercent=-1;
+ SubHead=NULL;
+ SubHeadPos=NULL;
+ CurrentCommand=0;
+ ProcessedArcSize=TotalArcSize=0;
+}
+
+
+
+
+int ComprDataIO::UnpRead(byte *Addr,size_t Count)
+{
+ int RetCode=0,TotalRead=0;
+ byte *ReadAddr;
+ ReadAddr=Addr;
+ while (Count > 0)
+ {
+ Archive *SrcArc=(Archive *)SrcFile;
+
+ size_t ReadSize=((int64)Count>UnpPackedSize) ? (size_t)UnpPackedSize:Count;
+ if (UnpackFromMemory)
+ {
+ memcpy(Addr,UnpackFromMemoryAddr,UnpackFromMemorySize);
+ RetCode=(int)UnpackFromMemorySize;
+ UnpackFromMemorySize=0;
+ }
+ else
+ {
+ if (!SrcFile->IsOpened())
+ return(-1);
+ RetCode=SrcFile->Read(ReadAddr,ReadSize);
+ FileHeader *hd=SubHead!=NULL ? SubHead:&SrcArc->NewLhd;
+ if (hd->Flags & LHD_SPLIT_AFTER)
+ PackedCRC=CRC(PackedCRC,ReadAddr,RetCode);
+ }
+ CurUnpRead+=RetCode;
+ TotalRead+=RetCode;
+#ifndef NOVOLUME
+ // These variable are not used in NOVOLUME mode, so it is better
+ // to exclude commands below to avoid compiler warnings.
+ ReadAddr+=RetCode;
+ Count-=RetCode;
+#endif
+ UnpPackedSize-=RetCode;
+ if (UnpPackedSize == 0 && UnpVolume)
+ {
+#ifndef NOVOLUME
+ if (!MergeArchive(*SrcArc,this,true,CurrentCommand))
+#endif
+ {
+ NextVolumeMissing=true;
+ return(-1);
+ }
+ }
+ else
+ break;
+ }
+ Archive *SrcArc=(Archive *)SrcFile;
+ if (SrcArc!=NULL)
+ ShowUnpRead(SrcArc->CurBlockPos+CurUnpRead,UnpArcSize);
+ if (RetCode!=-1)
+ {
+ RetCode=TotalRead;
+#ifndef RAR_NOCRYPT
+ if (Decryption)
+#ifndef SFX_MODULE
+ if (Decryption<20)
+ Decrypt.Crypt(Addr,RetCode,(Decryption==15) ? NEW_CRYPT : OLD_DECODE);
+ else
+ if (Decryption==20)
+ for (int I=0;IGetRAROptions();
+ if (Cmd->DllOpMode!=RAR_SKIP)
+ {
+ if (Cmd->Callback!=NULL &&
+ Cmd->Callback(UCM_PROCESSDATA,Cmd->UserData,(LPARAM)Addr,Count)==-1)
+ ErrHandler.Exit(RARX_USERBREAK);
+ if (Cmd->ProcessDataProc!=NULL)
+ {
+ // Here we preserve ESP value. It is necessary for those developers,
+ // who still define ProcessDataProc callback as "C" type function,
+ // even though in year 2001 we announced in unrar.dll whatsnew.txt
+ // that it will be PASCAL type (for compatibility with Visual Basic).
+#if defined(_MSC_VER)
+#ifndef _WIN_64
+ __asm mov ebx,esp
+#endif
+#elif defined(_WIN_ALL) && defined(__BORLANDC__)
+ _EBX=_ESP;
+#endif
+ int RetCode=Cmd->ProcessDataProc(Addr,(int)Count);
+
+ // Restore ESP after ProcessDataProc with wrongly defined calling
+ // convention broken it.
+#if defined(_MSC_VER)
+#ifndef _WIN_64
+ __asm mov esp,ebx
+#endif
+#elif defined(_WIN_ALL) && defined(__BORLANDC__)
+ _ESP=_EBX;
+#endif
+ if (RetCode==0)
+ ErrHandler.Exit(RARX_USERBREAK);
+ }
+ }
+#endif // RARDLL
+
+ UnpWrAddr=Addr;
+ UnpWrSize=Count;
+ if (UnpackToMemory)
+ {
+ if (Count <= UnpackToMemorySize)
+ {
+ memcpy(UnpackToMemoryAddr,Addr,Count);
+ UnpackToMemoryAddr+=Count;
+ UnpackToMemorySize-=Count;
+ }
+ }
+ else
+ if (!TestMode)
+ DestFile->Write(Addr,Count);
+ CurUnpWrite+=Count;
+ if (!SkipUnpCRC)
+#ifndef SFX_MODULE
+ if (((Archive *)SrcFile)->OldFormat)
+ UnpFileCRC=OldCRC((ushort)UnpFileCRC,Addr,Count);
+ else
+#endif
+ UnpFileCRC=CRC(UnpFileCRC,Addr,Count);
+ ShowUnpWrite();
+ Wait();
+}
+
+#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
+// Restore the run time stack check for unrar.dll.
+#pragma runtime_checks( "s", restore )
+#endif
+
+
+
+
+
+
+void ComprDataIO::ShowUnpRead(int64 ArcPos,int64 ArcSize)
+{
+ if (ShowProgress && SrcFile!=NULL)
+ {
+ if (TotalArcSize!=0)
+ {
+ // important when processing several archives or multivolume archive
+ ArcSize=TotalArcSize;
+ ArcPos+=ProcessedArcSize;
+ }
+
+ Archive *SrcArc=(Archive *)SrcFile;
+ RAROptions *Cmd=SrcArc->GetRAROptions();
+
+ int CurPercent=ToPercent(ArcPos,ArcSize);
+ if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
+ {
+ mprintf("\b\b\b\b%3d%%",CurPercent);
+ LastPercent=CurPercent;
+ }
+ }
+}
+
+
+void ComprDataIO::ShowUnpWrite()
+{
+}
+
+
+
+
+
+
+
+
+void ComprDataIO::SetFiles(File *SrcFile,File *DestFile)
+{
+ if (SrcFile!=NULL)
+ ComprDataIO::SrcFile=SrcFile;
+ if (DestFile!=NULL)
+ ComprDataIO::DestFile=DestFile;
+ LastPercent=-1;
+}
+
+
+void ComprDataIO::GetUnpackedData(byte **Data,size_t *Size)
+{
+ *Data=UnpWrAddr;
+ *Size=UnpWrSize;
+}
+
+
+void ComprDataIO::SetEncryption(int Method,SecPassword *Password,const byte *Salt,bool Encrypt,bool HandsOffHash)
+{
+ if (Encrypt)
+ {
+ Encryption=Password->IsSet() ? Method:0;
+#ifndef RAR_NOCRYPT
+ Crypt.SetCryptKeys(Password,Salt,Encrypt,false,HandsOffHash);
+#endif
+ }
+ else
+ {
+ Decryption=Password->IsSet() ? Method:0;
+#ifndef RAR_NOCRYPT
+ Decrypt.SetCryptKeys(Password,Salt,Encrypt,Method<29,HandsOffHash);
+#endif
+ }
+}
+
+
+#if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT)
+void ComprDataIO::SetAV15Encryption()
+{
+ Decryption=15;
+ Decrypt.SetAV15Encryption();
+}
+#endif
+
+
+#if !defined(SFX_MODULE) && !defined(RAR_NOCRYPT)
+void ComprDataIO::SetCmt13Encryption()
+{
+ Decryption=13;
+ Decrypt.SetCmt13Encryption();
+}
+#endif
+
+
+
+
+void ComprDataIO::SetUnpackToMemory(byte *Addr,uint Size)
+{
+ UnpackToMemory=true;
+ UnpackToMemoryAddr=Addr;
+ UnpackToMemorySize=Size;
+}
+
+
diff --git a/src/unrar/rdwrfn.hpp b/src/unrar/rdwrfn.hpp
new file mode 100644
index 0000000000..0c6fd1dc54
--- /dev/null
+++ b/src/unrar/rdwrfn.hpp
@@ -0,0 +1,88 @@
+#ifndef _RAR_DATAIO_
+#define _RAR_DATAIO_
+
+class CmdAdd;
+class Unpack;
+
+
+class ComprDataIO
+{
+ private:
+ void ShowUnpRead(int64 ArcPos,int64 ArcSize);
+ void ShowUnpWrite();
+
+
+ bool UnpackFromMemory;
+ size_t UnpackFromMemorySize;
+ byte *UnpackFromMemoryAddr;
+
+ bool UnpackToMemory;
+ size_t UnpackToMemorySize;
+ byte *UnpackToMemoryAddr;
+
+ size_t UnpWrSize;
+ byte *UnpWrAddr;
+
+ int64 UnpPackedSize;
+
+ bool ShowProgress;
+ bool TestMode;
+ bool SkipUnpCRC;
+
+ File *SrcFile;
+ File *DestFile;
+
+ CmdAdd *Command;
+
+ FileHeader *SubHead;
+ int64 *SubHeadPos;
+
+#ifndef RAR_NOCRYPT
+ CryptData Crypt;
+ CryptData Decrypt;
+#endif
+
+
+ int LastPercent;
+
+ char CurrentCommand;
+
+ public:
+ ComprDataIO();
+ void Init();
+ int UnpRead(byte *Addr,size_t Count);
+ void UnpWrite(byte *Addr,size_t Count);
+ void EnableShowProgress(bool Show) {ShowProgress=Show;}
+ void GetUnpackedData(byte **Data,size_t *Size);
+ void SetPackedSizeToRead(int64 Size) {UnpPackedSize=Size;}
+ void SetTestMode(bool Mode) {TestMode=Mode;}
+ void SetSkipUnpCRC(bool Skip) {SkipUnpCRC=Skip;}
+ void SetFiles(File *SrcFile,File *DestFile);
+ void SetCommand(CmdAdd *Cmd) {Command=Cmd;}
+ void SetSubHeader(FileHeader *hd,int64 *Pos) {SubHead=hd;SubHeadPos=Pos;}
+ void SetEncryption(int Method,SecPassword *Password,const byte *Salt,bool Encrypt,bool HandsOffHash);
+ void SetAV15Encryption();
+ void SetCmt13Encryption();
+ void SetUnpackToMemory(byte *Addr,uint Size);
+ void SetCurrentCommand(char Cmd) {CurrentCommand=Cmd;}
+
+ bool PackVolume;
+ bool UnpVolume;
+ bool NextVolumeMissing;
+ int64 TotalPackRead;
+ int64 UnpArcSize;
+ int64 CurPackRead,CurPackWrite,CurUnpRead,CurUnpWrite;
+
+ // Size of already processed archives.
+ // Used to calculate the total operation progress.
+ int64 ProcessedArcSize;
+
+ int64 TotalArcSize;
+
+ uint PackFileCRC,UnpFileCRC,PackedCRC;
+
+ int Encryption;
+ int Decryption;
+};
+
+#endif
diff --git a/src/unrar/readme.txt b/src/unrar/readme.txt
new file mode 100644
index 0000000000..fd7137d952
--- /dev/null
+++ b/src/unrar/readme.txt
@@ -0,0 +1,66 @@
+
+ Portable UnRAR version
+
+
+ 1. General
+
+ This package includes freeware Unrar C++ source and a few makefiles
+ (makefile.bcc, makefile.msc+msc.dep, makefile.unix). Unrar source
+ is subset of RAR and generated from RAR source automatically,
+ by a small program removing blocks like '#ifndef UNRAR ... #endif'.
+ Such method is not perfect and you may find some RAR related
+ stuff unnecessary in Unrar, especially in header files.
+
+ If you wish to port Unrar to a new platform, you may need to edit
+ '#define LITTLE_ENDIAN' in os.hpp and data type definitions
+ in rartypes.hpp.
+
+ if computer architecture does not allow not aligned data access,
+ you need to undefine ALLOW_NOT_ALIGNED_INT and define
+ STRICT_ALIGNMENT_REQUIRED in os.h. Note that it will increase memory
+ requirements.
+
+ If you use Borland C++ makefile (makefile.bcc), you need to define
+ BASEPATHCC environment (or makefile) variable containing
+ the path to Borland C++ installation.
+
+ Makefile.unix contains numerous compiler option sets.
+ GCC Linux is selected by default. If you need to compile Unrar
+ for other platforms, uncomment corresponding lines.
+
+ UnRAR.vcproj and UnRARDll.vcproj are projects for Microsoft Visual C++.
+ UnRARDll.vcproj lets to build unrar.dll library.
+
+
+ 2. Unrar binaries
+
+ If you compiled Unrar for OS, which is not present in "Downloads"
+ and "RAR extras" on www.rarlab.com, we will appreciate if you send
+ us the compiled executable to place it to our site.
+
+
+ 3. Acknowledgements
+
+ This source includes parts of code written by the following authors:
+
+ Dmitry Shkarin PPMII v.H text compression
+ Dmitry Subbotin Carryless rangecoder
+ Szymon Stefanek AES encryption
+ Brian Gladman AES encryption
+ Steve Reid SHA-1 hash function
+ Marcus Herbert makefile.unix file
+ Tomasz Klim fixes for libunrar.so
+ Robert Riebisch makefile.dj and patches for DJGPP
+
+
+ 4. Legal stuff
+
+ Unrar source may be used in any software to handle RAR archives
+ without limitations free of charge, but cannot be used to re-create
+ the RAR compression algorithm, which is proprietary. Distribution
+ of modified Unrar source in separate form or as a part of other
+ software is permitted, provided that it is clearly stated in
+ the documentation and source comments that the code may not be used
+ to develop a RAR (WinRAR) compatible archiver.
+
+ More detailed license text is available in license.txt.
diff --git a/src/unrar/recvol.cpp b/src/unrar/recvol.cpp
new file mode 100644
index 0000000000..0d6162e176
--- /dev/null
+++ b/src/unrar/recvol.cpp
@@ -0,0 +1,572 @@
+#include "rar.hpp"
+
+// Buffer size for all volumes involved.
+static const size_t TotalBufferSize=0x4000000;
+
+class RSEncode // Encode or decode data area, one object per one thread.
+{
+ private:
+ RSCoder RSC;
+ public:
+ void EncodeBuf();
+ void DecodeBuf();
+
+ void Init(int RecVolNumber) {RSC.Init(RecVolNumber);}
+ byte *Buf;
+ byte *OutBuf;
+ int BufStart;
+ int BufEnd;
+ int FileNumber;
+ int RecVolNumber;
+ size_t RecBufferSize;
+ int *Erasures;
+ int EraSize;
+};
+
+
+#ifdef RAR_SMP
+THREAD_PROC(RSEncodeThread)
+{
+ RSEncode *rs=(RSEncode *)Data;
+ rs->EncodeBuf();
+}
+
+THREAD_PROC(RSDecodeThread)
+{
+ RSEncode *rs=(RSEncode *)Data;
+ rs->DecodeBuf();
+}
+#endif
+
+RecVolumes::RecVolumes()
+{
+ Buf.Alloc(TotalBufferSize);
+ memset(SrcFile,0,sizeof(SrcFile));
+}
+
+
+RecVolumes::~RecVolumes()
+{
+ for (int I=0;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--;
+ strcpy(Ext,"*.*");
+
+ if (*ArcNameW!=0)
+ {
+ wchar *ExtW=GetExt(ArcNameW);
+ for (int DigitGroup=0;ExtW>ArcNameW && DigitGroup<3;ExtW--)
+ if (!IsDigit(*ExtW))
+ if (IsDigit(*(ExtW-1)) && (*ExtW=='_' || DigitGroup<2))
+ DigitGroup++;
+ else
+ if (DigitGroup<2)
+ {
+ NewStyle=true;
+ break;
+ }
+ while (IsDigit(*ExtW) && ExtW>ArcNameW+1)
+ ExtW--;
+ wcscpy(ExtW,L"*.*");
+ }
+
+ FindFile Find;
+ Find.SetMask(ArcName);
+ Find.SetMaskW(ArcNameW);
+ FindData fd;
+ while (Find.Next(&fd))
+ {
+ Archive Arc(Cmd);
+ if (Arc.WOpen(fd.Name,fd.NameW) && Arc.IsArchive(true))
+ {
+ strcpy(ArcName,fd.Name);
+ wcscpy(ArcNameW,fd.NameW);
+ break;
+ }
+ }
+ }
+
+ Archive Arc(Cmd);
+ if (!Arc.WCheckOpen(ArcName,ArcNameW))
+ return(false);
+ if (!Arc.Volume)
+ {
+#ifndef SILENT
+ Log(ArcName,St(MNotVolume),ArcName);
+#endif
+ return(false);
+ }
+ bool NewNumbering=(Arc.NewMhd.Flags & MHD_NEWNUMBERING)!=0;
+ Arc.Close();
+
+ char *VolNumStart=VolNameToFirstName(ArcName,ArcName,NewNumbering);
+ char RecVolMask[NM];
+ strcpy(RecVolMask,ArcName);
+ size_t BaseNamePartLength=VolNumStart-ArcName;
+ strcpy(RecVolMask+BaseNamePartLength,"*.rev");
+
+ wchar RecVolMaskW[NM];
+ size_t BaseNamePartLengthW=0;
+ *RecVolMaskW=0;
+ if (*ArcNameW!=0)
+ {
+ wchar *VolNumStartW=VolNameToFirstName(ArcNameW,ArcNameW,NewNumbering);
+ wcscpy(RecVolMaskW,ArcNameW);
+ BaseNamePartLengthW=VolNumStartW-ArcNameW;
+ wcscpy(RecVolMaskW+BaseNamePartLengthW,L"*.rev");
+ }
+
+
+#ifndef SILENT
+ int64 RecFileSize=0;
+#endif
+
+ // We cannot display "Calculating CRC..." message here, because we do not
+ // know if we'll find any recovery volumes. We'll display it after finding
+ // the first recovery volume.
+ bool CalcCRCMessageDone=false;
+
+ FindFile Find;
+ Find.SetMask(RecVolMask);
+ Find.SetMaskW(RecVolMaskW);
+ FindData RecData;
+ int FileNumber=0,RecVolNumber=0,FoundRecVolumes=0,MissingVolumes=0;
+ char PrevName[NM];
+ wchar PrevNameW[NM];
+ while (Find.Next(&RecData))
+ {
+ char *CurName=RecData.Name;
+ wchar *CurNameW=RecData.NameW;
+ int P[3];
+ if (!RevName && !NewStyle)
+ {
+ NewStyle=true;
+
+ char *Dot=GetExt(CurName);
+ if (Dot!=NULL)
+ {
+ int LineCount=0;
+ Dot--;
+ while (Dot>CurName && *Dot!='.')
+ {
+ if (*Dot=='_')
+ LineCount++;
+ Dot--;
+ }
+ if (LineCount==2)
+ NewStyle=false;
+ }
+
+ wchar *DotW=GetExt(CurNameW);
+ if (DotW!=NULL)
+ {
+ int LineCount=0;
+ DotW--;
+ while (DotW>CurNameW && *DotW!='.')
+ {
+ if (*DotW=='_')
+ LineCount++;
+ DotW--;
+ }
+ if (LineCount==2)
+ NewStyle=false;
+ }
+ }
+ if (NewStyle)
+ {
+ if (!CalcCRCMessageDone)
+ {
+#ifndef SILENT
+ mprintf(St(MCalcCRCAllVol));
+#endif
+ CalcCRCMessageDone=true;
+ }
+
+#ifndef SILENT
+ mprintf("\r\n%s",CurName);
+#endif
+
+ File CurFile;
+ CurFile.TOpen(CurName,CurNameW);
+ CurFile.Seek(0,SEEK_END);
+ int64 Length=CurFile.Tell();
+ CurFile.Seek(Length-7,SEEK_SET);
+ for (int I=0;I<3;I++)
+ P[2-I]=CurFile.GetByte()+1;
+ uint FileCRC=0;
+ for (int I=0;I<4;I++)
+ FileCRC|=CurFile.GetByte()<<(I*8);
+ if (FileCRC!=CalcFileCRC(&CurFile,Length-4))
+ {
+#ifndef SILENT
+ mprintf(St(MCRCFailed),CurName);
+#endif
+ continue;
+ }
+ }
+ else
+ {
+ char *Dot=GetExt(CurName);
+ if (Dot==NULL)
+ continue;
+ bool WrongParam=false;
+ for (int I=0;I=CurName+BaseNamePartLength);
+ P[I]=atoi(Dot+1);
+ if (P[I]==0 || P[I]>255)
+ WrongParam=true;
+ }
+ if (WrongParam)
+ continue;
+ }
+ if (P[1]+P[2]>255)
+ continue;
+ if (RecVolNumber!=0 && RecVolNumber!=P[1] || FileNumber!=0 && FileNumber!=P[2])
+ {
+#ifndef SILENT
+ Log(NULL,St(MRecVolDiffSets),CurName,PrevName);
+#endif
+ return(false);
+ }
+ RecVolNumber=P[1];
+ FileNumber=P[2];
+ strcpy(PrevName,CurName);
+ wcscpy(PrevNameW,CurNameW);
+ File *NewFile=new File;
+ NewFile->TOpen(CurName,CurNameW);
+ SrcFile[FileNumber+P[0]-1]=NewFile;
+ FoundRecVolumes++;
+#ifndef SILENT
+ if (RecFileSize==0)
+ RecFileSize=NewFile->FileLength();
+#endif
+ }
+#ifndef SILENT
+ if (!Silent || FoundRecVolumes!=0)
+ {
+ mprintf(St(MRecVolFound),FoundRecVolumes);
+ }
+#endif
+ if (FoundRecVolumes==0)
+ return(false);
+
+ bool WriteFlags[256];
+ memset(WriteFlags,0,sizeof(WriteFlags));
+
+ char LastVolName[NM];
+ *LastVolName=0;
+ wchar LastVolNameW[NM];
+ *LastVolNameW=0;
+
+ for (int CurArcNum=0;CurArcNumTOpen(ArcName,ArcNameW);
+ ValidVolume=NewFile->IsArchive(false);
+ if (ValidVolume)
+ {
+ while (NewFile->ReadHeader()!=0)
+ {
+ if (NewFile->GetHeaderType()==ENDARC_HEAD)
+ {
+#ifndef SILENT
+ mprintf("\r\n%s",ArcName);
+#endif
+ if ((NewFile->EndArcHead.Flags&EARC_DATACRC)!=0 &&
+ NewFile->EndArcHead.ArcDataCRC!=CalcFileCRC(NewFile,NewFile->CurBlockPos))
+ {
+ ValidVolume=false;
+#ifndef SILENT
+ mprintf(St(MCRCFailed),ArcName);
+#endif
+ }
+ break;
+ }
+ NewFile->SeekToNext();
+ }
+ }
+ if (!ValidVolume)
+ {
+ NewFile->Close();
+ char NewName[NM];
+ strcpy(NewName,ArcName);
+ strcat(NewName,".bad");
+
+ wchar NewNameW[NM];
+ wcscpy(NewNameW,ArcNameW);
+ if (*NewNameW!=0)
+ wcscat(NewNameW,L".bad");
+#ifndef SILENT
+ mprintf(St(MBadArc),ArcName);
+ mprintf(St(MRenaming),ArcName,NewName);
+#endif
+ RenameFile(ArcName,ArcNameW,NewName,NewNameW);
+ }
+ NewFile->Seek(0,SEEK_SET);
+ }
+ if (!ValidVolume)
+ {
+ // It is important to return 'false' instead of aborting here,
+ // so if we are called from extraction, we will be able to continue
+ // extracting. It may happen if .rar and .rev are on read-only disks
+ // like CDs.
+ if (!NewFile->Create(ArcName,ArcNameW))
+ {
+ // We need to display the title of operation before the error message,
+ // to make clear for user that create error is related to recovery
+ // volumes. This is why we cannot use WCreate call here. Title must be
+ // before create error, not after that.
+#ifndef SILENT
+ mprintf(St(MReconstructing));
+#endif
+ ErrHandler.CreateErrorMsg(ArcName,ArcNameW);
+ return false;
+ }
+
+ WriteFlags[CurArcNum]=true;
+ MissingVolumes++;
+
+ if (CurArcNum==FileNumber-1)
+ {
+ strcpy(LastVolName,ArcName);
+ wcscpy(LastVolNameW,ArcNameW);
+ }
+
+#ifndef SILENT
+ mprintf(St(MAbsNextVol),ArcName);
+#endif
+ }
+ SrcFile[CurArcNum]=(File*)NewFile;
+ NextVolumeName(ArcName,ArcNameW,ASIZE(ArcName),!NewNumbering);
+ }
+
+#ifndef SILENT
+ mprintf(St(MRecVolMissing),MissingVolumes);
+#endif
+
+ if (MissingVolumes==0)
+ {
+#ifndef SILENT
+ mprintf(St(MRecVolAllExist));
+#endif
+ return(false);
+ }
+
+ if (MissingVolumes>FoundRecVolumes)
+ {
+#ifndef SILENT
+ mprintf(St(MRecVolCannotFix));
+#endif
+ return(false);
+ }
+#ifndef SILENT
+ mprintf(St(MReconstructing));
+#endif
+
+ int TotalFiles=FileNumber+RecVolNumber;
+ int Erasures[256],EraSize=0;
+
+ for (int I=0;IThreads;
+ RSEncode rse[MaxPoolThreads];
+ uint WaitHandles[MaxPoolThreads];
+#else
+ uint ThreadNumber=1;
+ RSEncode rse[1];
+#endif
+ for (uint I=0;IRead(&Buf[I*RecBufferSize],RecBufferSize);
+ if (ReadSize!=RecBufferSize)
+ memset(&Buf[I*RecBufferSize+ReadSize],0,RecBufferSize-ReadSize);
+ if (ReadSize>MaxRead)
+ MaxRead=ReadSize;
+ }
+ if (MaxRead==0)
+ break;
+#ifndef SILENT
+ int CurPercent=ToPercent(ProcessedSize,RecFileSize);
+ if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
+ {
+ mprintf("\b\b\b\b%3d%%",CurPercent);
+ LastPercent=CurPercent;
+ }
+ ProcessedSize+=MaxRead;
+#endif
+
+
+ int BlockStart=0;
+ int BlockSize=MaxRead/ThreadNumber;
+ if (BlockSize<0x100)
+ BlockSize=MaxRead;
+ uint CurThread=0;
+
+ while (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)
+ {
+ uint Handle=RSThreadPool.Start(RSDecodeThread,(void*)curenc);
+ WaitHandles[CurThread++]=Handle;
+ }
+ else
+ curenc->DecodeBuf();
+#else
+ curenc->DecodeBuf();
+#endif
+
+ BlockStart+=BlockSize;
+ }
+
+#ifdef RAR_SMP
+ if (CurThread>0)
+ RSThreadPool.Wait(WaitHandles,CurThread);
+#endif // RAR_SMP
+
+ for (int I=0;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 || *LastVolNameW!=0)
+ {
+ // Truncate the last volume to its real size.
+ Archive Arc(Cmd);
+ if (Arc.Open(LastVolName,LastVolNameW,FMF_UPDATE) && Arc.IsArchive(true) &&
+ Arc.SearchBlock(ENDARC_HEAD))
+ {
+ Arc.Seek(Arc.NextBlockPos,SEEK_SET);
+ char Buf[8192];
+ int ReadSize=Arc.Read(Buf,sizeof(Buf));
+ int ZeroCount=0;
+ while (ZeroCountDisablePercentage)
+ mprintf("\b\b\b\b100%%");
+ if (!Silent && !Cmd->DisableDone)
+ mprintf(St(MDone));
+#endif
+ return(true);
+}
+
+
+void RSEncode::DecodeBuf()
+{
+ for (int BufPos=BufStart;BufPos Buf;
+
+#ifdef RAR_SMP
+ ThreadPool RSThreadPool;
+#endif
+ public:
+ RecVolumes();
+ ~RecVolumes();
+ void Make(RAROptions *Cmd,char *ArcName,wchar *ArcNameW);
+ bool Restore(RAROptions *Cmd,const char *Name,const wchar *NameW,bool Silent);
+};
+
+#endif
diff --git a/src/unrar/resource.cpp b/src/unrar/resource.cpp
new file mode 100644
index 0000000000..1c966ce883
--- /dev/null
+++ b/src/unrar/resource.cpp
@@ -0,0 +1,27 @@
+#include "rar.hpp"
+
+
+
+#ifndef RARDLL
+const char *St(MSGID StringId)
+{
+ return(StringId);
+}
+#endif
+
+
+#ifndef RARDLL
+const wchar *StW(MSGID StringId)
+{
+ static wchar StrTable[8][512];
+ static int StrNum=0;
+ if (++StrNum >= sizeof(StrTable)/sizeof(StrTable[0]))
+ StrNum=0;
+ wchar *Str=StrTable[StrNum];
+ *Str=0;
+ CharToWide(StringId,Str,ASIZE(StrTable[0]));
+ return(Str);
+}
+#endif
+
+
diff --git a/src/unrar/resource.hpp b/src/unrar/resource.hpp
new file mode 100644
index 0000000000..7df5844388
--- /dev/null
+++ b/src/unrar/resource.hpp
@@ -0,0 +1,13 @@
+#ifndef _RAR_RESOURCE_
+#define _RAR_RESOURCE_
+
+#ifdef RARDLL
+#define St(x) ( "")
+#define StW(x) (L"")
+#else
+const char *St (MSGID StringId);
+const wchar *StW (MSGID StringId);
+#endif
+
+
+#endif
diff --git a/src/unrar/rijndael.cpp b/src/unrar/rijndael.cpp
new file mode 100644
index 0000000000..67434ba202
--- /dev/null
+++ b/src/unrar/rijndael.cpp
@@ -0,0 +1,298 @@
+/**************************************************************************
+ * This code is based on Szymon Stefanek AES implementation: *
+ * http://www.esat.kuleuven.ac.be/~rijmen/rijndael/rijndael-cpplib.tar.gz *
+ * *
+ * Dynamic tables generation is based on the Brian Gladman work: *
+ * http://fp.gladman.plus.com/cryptography_technology/rijndael *
+ **************************************************************************/
+#include "rar.hpp"
+
+const int uKeyLenInBytes=16, m_uRounds=10;
+
+static byte S[256],S5[256],rcon[30];
+static byte T1[256][4],T2[256][4],T3[256][4],T4[256][4];
+static byte T5[256][4],T6[256][4],T7[256][4],T8[256][4];
+static byte U1[256][4],U2[256][4],U3[256][4],U4[256][4];
+
+
+inline void Xor128(byte *dest,const byte *arg1,const byte *arg2)
+{
+#if defined(PRESENT_INT32) && defined(ALLOW_NOT_ALIGNED_INT)
+ ((uint32*)dest)[0]=((uint32*)arg1)[0]^((uint32*)arg2)[0];
+ ((uint32*)dest)[1]=((uint32*)arg1)[1]^((uint32*)arg2)[1];
+ ((uint32*)dest)[2]=((uint32*)arg1)[2]^((uint32*)arg2)[2];
+ ((uint32*)dest)[3]=((uint32*)arg1)[3]^((uint32*)arg2)[3];
+#else
+ for (int I=0;I<16;I++)
+ dest[I]=arg1[I]^arg2[I];
+#endif
+}
+
+
+inline void Xor128(byte *dest,const byte *arg1,const byte *arg2,
+ const byte *arg3,const byte *arg4)
+{
+#if defined(PRESENT_INT32) && defined(ALLOW_NOT_ALIGNED_INT)
+ (*(uint32*)dest)=(*(uint32*)arg1)^(*(uint32*)arg2)^(*(uint32*)arg3)^(*(uint32*)arg4);
+#else
+ for (int I=0;I<4;I++)
+ dest[I]=arg1[I]^arg2[I]^arg3[I]^arg4[I];
+#endif
+}
+
+
+inline void Copy128(byte *dest,const byte *src)
+{
+#if defined(PRESENT_INT32) && defined(ALLOW_NOT_ALIGNED_INT)
+ ((uint32*)dest)[0]=((uint32*)src)[0];
+ ((uint32*)dest)[1]=((uint32*)src)[1];
+ ((uint32*)dest)[2]=((uint32*)src)[2];
+ ((uint32*)dest)[3]=((uint32*)src)[3];
+#else
+ for (int I=0;I<16;I++)
+ dest[I]=src[I];
+#endif
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// API
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+Rijndael::Rijndael()
+{
+ if (S[0]==0)
+ GenerateTables();
+}
+
+
+void Rijndael::init(Direction dir,const byte * key,byte * initVector)
+{
+ m_direction = dir;
+
+ byte keyMatrix[_MAX_KEY_COLUMNS][4];
+
+ for(uint i = 0;i < uKeyLenInBytes;i++)
+ keyMatrix[i >> 2][i & 3] = key[i];
+
+ for(int i = 0;i < MAX_IV_SIZE;i++)
+ m_initVector[i] = initVector[i];
+
+ keySched(keyMatrix);
+
+ if(m_direction == Decrypt)
+ keyEncToDec();
+}
+
+
+
+size_t Rijndael::blockDecrypt(const byte *input, size_t inputLen, byte *outBuffer)
+{
+ if (input == 0 || inputLen <= 0)
+ return 0;
+
+ byte block[16], iv[4][4];
+ memcpy(iv,m_initVector,16);
+
+ size_t numBlocks=inputLen/16;
+ for (size_t i = numBlocks; i > 0; i--)
+ {
+ decrypt(input, block);
+ Xor128(block,block,(byte*)iv);
+#if STRICT_ALIGN
+ memcpy(iv, input, 16);
+ memcpy(outBuf, block, 16);
+#else
+ Copy128((byte*)iv,input);
+ Copy128(outBuffer,block);
+#endif
+ input += 16;
+ outBuffer += 16;
+ }
+
+ memcpy(m_initVector,iv,16);
+
+ return 16*numBlocks;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// ALGORITHM
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+void Rijndael::keySched(byte key[_MAX_KEY_COLUMNS][4])
+{
+ int j,rconpointer = 0;
+
+ // Calculate the necessary round keys
+ // The number of calculations depends on keyBits and blockBits
+ int uKeyColumns = m_uRounds - 6;
+
+ byte tempKey[_MAX_KEY_COLUMNS][4];
+
+ // Copy the input key to the temporary key matrix
+
+ memcpy(tempKey,key,sizeof(tempKey));
+
+ int r = 0;
+ int t = 0;
+
+ // copy values into round key array
+ for(j = 0;(j < uKeyColumns) && (r <= m_uRounds); )
+ {
+ for(;(j < uKeyColumns) && (t < 4); j++, t++)
+ for (int k=0;k<4;k++)
+ m_expandedKey[r][t][k]=tempKey[j][k];
+
+ if(t == 4)
+ {
+ r++;
+ t = 0;
+ }
+ }
+
+ while(r <= m_uRounds)
+ {
+ tempKey[0][0] ^= S[tempKey[uKeyColumns-1][1]];
+ tempKey[0][1] ^= S[tempKey[uKeyColumns-1][2]];
+ tempKey[0][2] ^= S[tempKey[uKeyColumns-1][3]];
+ tempKey[0][3] ^= S[tempKey[uKeyColumns-1][0]];
+ tempKey[0][0] ^= rcon[rconpointer++];
+
+ if (uKeyColumns != 8)
+ for(j = 1; j < uKeyColumns; j++)
+ for (int k=0;k<4;k++)
+ tempKey[j][k] ^= tempKey[j-1][k];
+ else
+ {
+ for(j = 1; j < uKeyColumns/2; j++)
+ for (int k=0;k<4;k++)
+ tempKey[j][k] ^= tempKey[j-1][k];
+
+ tempKey[uKeyColumns/2][0] ^= S[tempKey[uKeyColumns/2 - 1][0]];
+ tempKey[uKeyColumns/2][1] ^= S[tempKey[uKeyColumns/2 - 1][1]];
+ tempKey[uKeyColumns/2][2] ^= S[tempKey[uKeyColumns/2 - 1][2]];
+ tempKey[uKeyColumns/2][3] ^= S[tempKey[uKeyColumns/2 - 1][3]];
+ for(j = uKeyColumns/2 + 1; j < uKeyColumns; j++)
+ for (int k=0;k<4;k++)
+ tempKey[j][k] ^= tempKey[j-1][k];
+ }
+ for(j = 0; (j < uKeyColumns) && (r <= m_uRounds); )
+ {
+ for(; (j < uKeyColumns) && (t < 4); j++, t++)
+ for (int k=0;k<4;k++)
+ m_expandedKey[r][t][k] = tempKey[j][k];
+ if(t == 4)
+ {
+ r++;
+ t = 0;
+ }
+ }
+ }
+}
+
+void Rijndael::keyEncToDec()
+{
+ for(int r = 1; r < m_uRounds; r++)
+ {
+ byte n_expandedKey[4][4];
+ for (int i=0;i<4;i++)
+ for (int j=0;j<4;j++)
+ {
+ byte *w=m_expandedKey[r][j];
+ n_expandedKey[j][i]=U1[w[0]][i]^U2[w[1]][i]^U3[w[2]][i]^U4[w[3]][i];
+ }
+ memcpy(m_expandedKey[r],n_expandedKey,sizeof(m_expandedKey[0]));
+ }
+}
+
+
+void Rijndael::decrypt(const byte a[16], byte b[16])
+{
+ int r;
+ byte temp[4][4];
+
+ Xor128((byte*)temp,(byte*)a,(byte*)m_expandedKey[m_uRounds]);
+
+ Xor128(b, T5[temp[0][0]],T6[temp[3][1]],T7[temp[2][2]],T8[temp[1][3]]);
+ Xor128(b+4, T5[temp[1][0]],T6[temp[0][1]],T7[temp[3][2]],T8[temp[2][3]]);
+ Xor128(b+8, T5[temp[2][0]],T6[temp[1][1]],T7[temp[0][2]],T8[temp[3][3]]);
+ Xor128(b+12,T5[temp[3][0]],T6[temp[2][1]],T7[temp[1][2]],T8[temp[0][3]]);
+
+ for(r = m_uRounds-1; r > 1; r--)
+ {
+ Xor128((byte*)temp,(byte*)b,(byte*)m_expandedKey[r]);
+ Xor128(b, T5[temp[0][0]],T6[temp[3][1]],T7[temp[2][2]],T8[temp[1][3]]);
+ Xor128(b+4, T5[temp[1][0]],T6[temp[0][1]],T7[temp[3][2]],T8[temp[2][3]]);
+ Xor128(b+8, T5[temp[2][0]],T6[temp[1][1]],T7[temp[0][2]],T8[temp[3][3]]);
+ Xor128(b+12,T5[temp[3][0]],T6[temp[2][1]],T7[temp[1][2]],T8[temp[0][3]]);
+ }
+
+ Xor128((byte*)temp,(byte*)b,(byte*)m_expandedKey[1]);
+ b[ 0] = S5[temp[0][0]];
+ b[ 1] = S5[temp[3][1]];
+ b[ 2] = S5[temp[2][2]];
+ b[ 3] = S5[temp[1][3]];
+ b[ 4] = S5[temp[1][0]];
+ b[ 5] = S5[temp[0][1]];
+ b[ 6] = S5[temp[3][2]];
+ b[ 7] = S5[temp[2][3]];
+ b[ 8] = S5[temp[2][0]];
+ b[ 9] = S5[temp[1][1]];
+ b[10] = S5[temp[0][2]];
+ b[11] = S5[temp[3][3]];
+ b[12] = S5[temp[3][0]];
+ b[13] = S5[temp[2][1]];
+ b[14] = S5[temp[1][2]];
+ b[15] = S5[temp[0][3]];
+ Xor128((byte*)b,(byte*)b,(byte*)m_expandedKey[0]);
+}
+
+#define ff_poly 0x011b
+#define ff_hi 0x80
+
+#define FFinv(x) ((x) ? pow[255 - log[x]]: 0)
+
+#define FFmul02(x) (x ? pow[log[x] + 0x19] : 0)
+#define FFmul03(x) (x ? pow[log[x] + 0x01] : 0)
+#define FFmul09(x) (x ? pow[log[x] + 0xc7] : 0)
+#define FFmul0b(x) (x ? pow[log[x] + 0x68] : 0)
+#define FFmul0d(x) (x ? pow[log[x] + 0xee] : 0)
+#define FFmul0e(x) (x ? pow[log[x] + 0xdf] : 0)
+#define fwd_affine(x) \
+ (w = (uint)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), (byte)(0x63^(w^(w>>8))))
+
+#define inv_affine(x) \
+ (w = (uint)x, w = (w<<1)^(w<<3)^(w<<6), (byte)(0x05^(w^(w>>8))))
+
+void Rijndael::GenerateTables()
+{
+ unsigned char pow[512],log[256];
+ int i = 0, w = 1;
+ do
+ {
+ pow[i] = (byte)w;
+ pow[i + 255] = (byte)w;
+ log[w] = (byte)i++;
+ w ^= (w << 1) ^ (w & ff_hi ? ff_poly : 0);
+ } while (w != 1);
+
+ for (int i = 0,w = 1; i < sizeof(rcon)/sizeof(rcon[0]); i++)
+ {
+ rcon[i] = w;
+ w = (w << 1) ^ (w & ff_hi ? ff_poly : 0);
+ }
+ for(int i = 0; i < 256; ++i)
+ {
+ unsigned char b=S[i]=fwd_affine(FFinv((byte)i));
+ T1[i][1]=T1[i][2]=T2[i][2]=T2[i][3]=T3[i][0]=T3[i][3]=T4[i][0]=T4[i][1]=b;
+ T1[i][0]=T2[i][1]=T3[i][2]=T4[i][3]=FFmul02(b);
+ T1[i][3]=T2[i][0]=T3[i][1]=T4[i][2]=FFmul03(b);
+ S5[i] = b = FFinv(inv_affine((byte)i));
+ U1[b][3]=U2[b][0]=U3[b][1]=U4[b][2]=T5[i][3]=T6[i][0]=T7[i][1]=T8[i][2]=FFmul0b(b);
+ U1[b][1]=U2[b][2]=U3[b][3]=U4[b][0]=T5[i][1]=T6[i][2]=T7[i][3]=T8[i][0]=FFmul09(b);
+ U1[b][2]=U2[b][3]=U3[b][0]=U4[b][1]=T5[i][2]=T6[i][3]=T7[i][0]=T8[i][1]=FFmul0d(b);
+ U1[b][0]=U2[b][1]=U3[b][2]=U4[b][3]=T5[i][0]=T6[i][1]=T7[i][2]=T8[i][3]=FFmul0e(b);
+ }
+}
diff --git a/src/unrar/rijndael.hpp b/src/unrar/rijndael.hpp
new file mode 100644
index 0000000000..bb5bd881cc
--- /dev/null
+++ b/src/unrar/rijndael.hpp
@@ -0,0 +1,37 @@
+#ifndef _RIJNDAEL_H_
+#define _RIJNDAEL_H_
+
+/**************************************************************************
+ * This code is based on Szymon Stefanek AES implementation: *
+ * http://www.esat.kuleuven.ac.be/~rijmen/rijndael/rijndael-cpplib.tar.gz *
+ * *
+ * Dynamic tables generation is based on the Brian Gladman's work: *
+ * http://fp.gladman.plus.com/cryptography_technology/rijndael *
+ **************************************************************************/
+
+#define _MAX_KEY_COLUMNS (256/32)
+#define _MAX_ROUNDS 14
+#define MAX_IV_SIZE 16
+
+class Rijndael
+{
+ public:
+ enum Direction { Encrypt , Decrypt };
+ private:
+ void keySched(byte key[_MAX_KEY_COLUMNS][4]);
+ void keyEncToDec();
+ void encrypt(const byte a[16], byte b[16]);
+ void decrypt(const byte a[16], byte b[16]);
+ void GenerateTables();
+
+ Direction m_direction;
+ byte m_initVector[MAX_IV_SIZE];
+ byte m_expandedKey[_MAX_ROUNDS+1][4][4];
+ public:
+ Rijndael();
+ void init(Direction dir,const byte *key,byte *initVector);
+ size_t blockEncrypt(const byte *input, size_t inputLen, byte *outBuffer);
+ size_t blockDecrypt(const byte *input, size_t inputLen, byte *outBuffer);
+};
+
+#endif // _RIJNDAEL_H_
diff --git a/src/unrar/rs.cpp b/src/unrar/rs.cpp
new file mode 100644
index 0000000000..b7ce1db60c
--- /dev/null
+++ b/src/unrar/rs.cpp
@@ -0,0 +1,172 @@
+#include "rar.hpp"
+
+#define Clean(D,S) {for (int I=0;I<(S);I++) (D)[I]=0;}
+
+void RSCoder::Init(int ParSize)
+{
+ RSCoder::ParSize=ParSize; // Store the number of recovery volumes.
+ FirstBlockDone=false;
+ gfInit();
+ pnInit();
+}
+
+
+// Initialize logarithms and exponents Galois field tables.
+void RSCoder::gfInit()
+{
+ for (int I=0,J=1;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 && DataPosCloseCount)
+ SaveFile->Seek(SavePos,SEEK_SET);
+}
diff --git a/src/unrar/savepos.hpp b/src/unrar/savepos.hpp
new file mode 100644
index 0000000000..b3b2373399
--- /dev/null
+++ b/src/unrar/savepos.hpp
@@ -0,0 +1,15 @@
+#ifndef _RAR_SAVEPOS_
+#define _RAR_SAVEPOS_
+
+class SaveFilePos
+{
+ private:
+ File *SaveFile;
+ int64 SavePos;
+ uint CloseCount;
+ public:
+ SaveFilePos(File &SaveFile);
+ ~SaveFilePos();
+};
+
+#endif
diff --git a/src/unrar/scantree.cpp b/src/unrar/scantree.cpp
new file mode 100644
index 0000000000..9fbfd10cd8
--- /dev/null
+++ b/src/unrar/scantree.cpp
@@ -0,0 +1,413 @@
+#include "rar.hpp"
+
+ScanTree::ScanTree(StringList *FileMasks,RECURSE_MODE Recurse,bool GetLinks,SCAN_DIRS GetDirs)
+{
+ ScanTree::FileMasks=FileMasks;
+ ScanTree::Recurse=Recurse;
+ ScanTree::GetLinks=GetLinks;
+ ScanTree::GetDirs=GetDirs;
+
+ ScanEntireDisk=false;
+
+ SetAllMaskDepth=0;
+ *CurMask=0;
+ *CurMaskW=0;
+ memset(FindStack,0,sizeof(FindStack));
+ Depth=0;
+ Errors=0;
+ *ErrArcName=0;
+ Cmd=NULL;
+}
+
+
+ScanTree::~ScanTree()
+{
+ for (int I=Depth;I>=0;I--)
+ if (FindStack[I]!=NULL)
+ delete FindStack[I];
+}
+
+
+SCAN_CODE ScanTree::GetNext(FindData *FindData)
+{
+ if (Depth<0)
+ return(SCAN_DONE);
+
+
+ SCAN_CODE FindCode;
+ while (1)
+ {
+ if (*CurMask==0 && !GetNextMask())
+ return(SCAN_DONE);
+
+
+ FindCode=FindProc(FindData);
+ if (FindCode==SCAN_ERROR)
+ {
+ Errors++;
+ continue;
+ }
+ if (FindCode==SCAN_NEXT)
+ continue;
+ if (FindCode==SCAN_SUCCESS && FindData->IsDir && GetDirs==SCAN_SKIPDIRS)
+ continue;
+ if (FindCode==SCAN_DONE && GetNextMask())
+ continue;
+ break;
+ }
+ return(FindCode);
+}
+
+
+bool ScanTree::GetNextMask()
+{
+ if (!FileMasks->GetString(CurMask,CurMaskW,ASIZE(CurMask)))
+ return(false);
+
+ if (*CurMask==0 && *CurMaskW!=0)
+ {
+ // Unicode only mask is present. It is very unlikely in console tools,
+ // but possible if called from GUI WinRAR. We still need to have
+ // ASCII mask, because we use ASCII only mask in some checks later.
+ // So let's convert Unicode to ASCII.
+ WideToChar(CurMaskW,CurMask,ASIZE(CurMask));
+ }
+
+ CurMask[ASIZE(CurMask)-1]=0;
+ CurMaskW[ASIZE(CurMaskW)-1]=0;
+#ifdef _WIN_ALL
+ UnixSlashToDos(CurMask);
+#endif
+
+ // We wish to scan entire disk if mask like c:\ is specified
+ // regardless of recursion mode. Use c:\*.* mask when need to scan only
+ // the root directory.
+ ScanEntireDisk=IsDiskLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0;
+
+ char *Name=PointToName(CurMask);
+ if (*Name==0)
+ strcat(CurMask,MASKALL);
+ if (Name[0]=='.' && (Name[1]==0 || Name[1]=='.' && Name[2]==0))
+ {
+ AddEndSlash(CurMask);
+ strcat(CurMask,MASKALL);
+ }
+ SpecPathLength=Name-CurMask;
+
+ bool WideName=(*CurMaskW!=0);
+
+ if (WideName)
+ {
+ wchar *NameW=PointToName(CurMaskW);
+ if (*NameW==0)
+ wcscat(CurMaskW,MASKALLW);
+ if (NameW[0]=='.' && (NameW[1]==0 || NameW[1]=='.' && NameW[2]==0))
+ {
+ AddEndSlash(CurMaskW);
+ wcscat(CurMaskW,MASKALLW);
+ }
+ SpecPathLengthW=NameW-CurMaskW;
+ }
+ else
+ {
+ wchar WideMask[NM];
+ CharToWide(CurMask,WideMask);
+ SpecPathLengthW=PointToName(WideMask)-WideMask;
+ }
+ Depth=0;
+
+ strcpy(OrigCurMask,CurMask);
+
+ // It is better to have non-empty OrigCurMaskW even if CurMaskW is empty.
+ // We need OrigCurMaskW to process Unicode masks generated by FindProc
+ // when encountering Unicode directory name.
+ GetWideName(CurMask,CurMaskW,OrigCurMaskW,ASIZE(OrigCurMaskW));
+
+ return(true);
+}
+
+
+SCAN_CODE ScanTree::FindProc(FindData *FD)
+{
+ if (*CurMask==0)
+ return(SCAN_NEXT);
+ bool FastFindFile=false;
+
+ if (FindStack[Depth]==NULL) // No FindFile object for this depth yet.
+ {
+ bool Wildcards=IsWildcard(CurMask,CurMaskW);
+
+ // If we have a file name without wildcards, we can try to use
+ // FastFind to optimize speed. For example, in Unix it results in
+ // stat call instead of opendir/readdir/closedir.
+ bool FindCode=!Wildcards && FindFile::FastFind(CurMask,CurMaskW,FD,GetLinks);
+
+ bool IsDir=FindCode && FD->IsDir;
+
+ // SearchAll means that we'll use "*" mask for search, so we'll find
+ // subdirectories and will be able to recurse into them.
+ // We do not use "*" for directories at any level or for files
+ // at top level in recursion mode.
+ bool SearchAll=!IsDir && (Depth>0 || Recurse==RECURSE_ALWAYS ||
+ Wildcards && Recurse==RECURSE_WILDCARDS ||
+ ScanEntireDisk && Recurse!=RECURSE_DISABLE);
+ if (Depth==0)
+ SearchAllInRoot=SearchAll;
+ if (SearchAll || Wildcards)
+ {
+ // Create the new FindFile object for wildcard based search.
+ FindStack[Depth]=new FindFile;
+ char SearchMask[NM];
+ strcpy(SearchMask,CurMask);
+ if (SearchAll)
+ strcpy(PointToName(SearchMask),MASKALL);
+ FindStack[Depth]->SetMask(SearchMask);
+ if (*CurMaskW!=0)
+ {
+ wchar SearchMaskW[NM];
+ wcscpy(SearchMaskW,CurMaskW);
+ if (SearchAll)
+ wcscpy(PointToName(SearchMaskW),MASKALLW);
+ FindStack[Depth]->SetMaskW(SearchMaskW);
+ }
+ }
+ else
+ {
+ // Either we failed to fast find or we found a file or we found
+ // a directory in RECURSE_DISABLE mode, so we do not need to scan it.
+ // We can return here and do not need to process further.
+ // We need to process further only if we fast found a directory.
+ if (!FindCode || !FD->IsDir || Recurse==RECURSE_DISABLE)
+ {
+ // Return SCAN_SUCCESS if we found a file.
+ SCAN_CODE RetCode=SCAN_SUCCESS;
+
+ if (!FindCode)
+ {
+ // Return SCAN_ERROR if problem is more serious than just
+ // "file not found".
+ RetCode=FD->Error ? SCAN_ERROR:SCAN_NEXT;
+
+ // If we failed to find an object, but our current mask is excluded,
+ // we skip this object and avoid indicating an error.
+ if (Cmd!=NULL && Cmd->ExclCheck(CurMask,false,true,true))
+ RetCode=SCAN_NEXT;
+ else
+ ErrHandler.OpenErrorMsg(ErrArcName,NULL,CurMask,CurMaskW);
+ }
+
+ // If we searched only for one file or directory in "fast find"
+ // (without a wildcard) mode, let's set masks to zero,
+ // so calling function will know that current mask is used
+ // and next one must be read from mask list for next call.
+ // It is not necessary for directories, because even in "fast find"
+ // mode, directory recursing will quit by (Depth < 0) condition,
+ // which returns SCAN_DONE to calling function.
+ *CurMask=0;
+ *CurMaskW=0;
+
+ return(RetCode);
+ }
+
+ // We found a directory using only FindFile::FastFind function.
+ FastFindFile=true;
+ }
+ }
+
+ if (!FastFindFile && !FindStack[Depth]->Next(FD,GetLinks))
+ {
+ // We cannot find anything more in directory either because of
+ // some error or just as result of all directory entries already read.
+
+ bool Error=FD->Error;
+
+#ifdef _WIN_ALL
+ if (Error)
+ {
+ // Do not display an error if we cannot scan contents of reparse
+ // point. Vista contains a lot of reparse (or junction) points,
+ // which are not accessible.
+ if ((FD->FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0)
+ Error=false;
+
+ // Do not display an error if we cannot scan contents of
+ // "System Volume Information" folder. Normally it is not accessible.
+ if (strstr(CurMask,"System Volume Information\\")!=NULL)
+ Error=false;
+ }
+#endif
+
+ if (Error && Cmd!=NULL && Cmd->ExclCheck(CurMask,false,true,true))
+ Error=false;
+
+#ifndef SILENT
+ if (Error)
+ {
+ Log(NULL,St(MScanError),CurMask);
+ ErrHandler.SysErrMsg();
+ }
+#endif
+
+ char DirName[NM];
+ wchar DirNameW[NM];
+ *DirName=0;
+ *DirNameW=0;
+
+ // Going to at least one directory level higher.
+ delete FindStack[Depth];
+ FindStack[Depth--]=NULL;
+ while (Depth>=0 && FindStack[Depth]==NULL)
+ Depth--;
+ if (Depth < 0)
+ {
+ // Directories scanned both in normal and FastFindFile mode,
+ // finally exit from scan here, by (Depth < 0) condition.
+
+ if (Error)
+ Errors++;
+ return(SCAN_DONE);
+ }
+ char *Slash=strrchrd(CurMask,CPATHDIVIDER);
+ if (Slash!=NULL)
+ {
+ char Mask[NM];
+ strcpy(Mask,Slash);
+ if (DepthIsDir)
+ {
+ FD->Flags|=FDDF_SECONDDIR;
+ return(Error ? SCAN_ERROR:SCAN_SUCCESS);
+ }
+ return(Error ? SCAN_ERROR:SCAN_NEXT);
+ }
+
+ if (FD->IsDir)
+ {
+ // If we found the directory in top (Depth==0) directory
+ // and if we are not in "fast find" (directory name only as argument)
+ // or in recurse (SearchAll was set when opening the top directory) mode,
+ // we do not recurse into this directory. We either return it by itself
+ // or skip it.
+ if (!FastFindFile && Depth==0 && !SearchAllInRoot)
+ return(GetDirs==SCAN_GETCURDIRS ? SCAN_SUCCESS:SCAN_NEXT);
+
+ // Let's check if directory name is excluded, so we do not waste
+ // time searching in directory, which will be excluded anyway.
+ if (Cmd!=NULL && (Cmd->ExclCheck(FD->Name,true,false,false) ||
+ Cmd->ExclDirByAttr(FD->FileAttr)))
+ {
+ // If we are here in "fast find" mode, it means that entire directory
+ // specified in command line is excluded. Then we need to return
+ // SCAN_DONE to go to next mask and avoid the infinite loop
+ // in GetNext() function. Such loop would be possible in case of
+ // SCAN_NEXT code and "rar a arc dir -xdir" command.
+
+ return(FastFindFile ? SCAN_DONE:SCAN_NEXT);
+ }
+
+ char Mask[NM];
+
+ strcpy(Mask,FastFindFile ? MASKALL:PointToName(CurMask));
+ strcpy(CurMask,FD->Name);
+
+ if (strlen(CurMask)+strlen(Mask)+1>=NM || Depth>=MAXSCANDEPTH-1)
+ {
+#ifndef SILENT
+ Log(NULL,"\n%s%c%s",CurMask,CPATHDIVIDER,Mask);
+ Log(NULL,St(MPathTooLong));
+#endif
+ return(SCAN_ERROR);
+ }
+
+ AddEndSlash(CurMask);
+ strcat(CurMask,Mask);
+
+ if (*CurMaskW!=0 && *FD->NameW==0)
+ CharToWide(FD->Name,FD->NameW);
+ if (*FD->NameW!=0)
+ {
+ wchar Mask[NM];
+ if (FastFindFile)
+ wcscpy(Mask,MASKALLW);
+ else
+ if (*CurMaskW!=0)
+ wcscpy(Mask,PointToName(CurMaskW));
+ else
+ CharToWide(PointToName(CurMask),Mask);
+ wcscpy(CurMaskW,FD->NameW);
+ AddEndSlash(CurMaskW);
+ wcscat(CurMaskW,Mask);
+ }
+ Depth++;
+
+ // We need to use OrigCurMask for depths less than SetAllMaskDepth
+ // and "*" for depths equal or larger than SetAllMaskDepth.
+ // It is important when "fast finding" directories at Depth > 0.
+ // For example, if current directory is RootFolder and we compress
+ // the following directories structure:
+ // RootFolder
+ // +--Folder1
+ // | +--Folder2
+ // | +--Folder3
+ // +--Folder4
+ // with 'rar a -r arcname Folder2' command, rar could add not only
+ // Folder1\Folder2 contents, but also Folder1\Folder3 if we were using
+ // "*" mask at all levels. We need to use "*" mask inside of Folder2,
+ // but return to "Folder2" mask when completing scanning Folder2.
+ // We can rewrite SearchAll expression above to avoid fast finding
+ // directories at Depth > 0, but then 'rar a -r arcname Folder2'
+ // will add the empty Folder2 and do not add its contents.
+
+ if (FastFindFile)
+ SetAllMaskDepth=Depth;
+ }
+ if (!FastFindFile && !CmpName(CurMask,FD->Name,MATCH_NAMES))
+ return(SCAN_NEXT);
+
+ return(SCAN_SUCCESS);
+}
diff --git a/src/unrar/scantree.hpp b/src/unrar/scantree.hpp
new file mode 100644
index 0000000000..33a6d46785
--- /dev/null
+++ b/src/unrar/scantree.hpp
@@ -0,0 +1,60 @@
+#ifndef _RAR_SCANTREE_
+#define _RAR_SCANTREE_
+
+enum SCAN_DIRS
+{
+ SCAN_SKIPDIRS, // Skip directories, but recurse for files if recursion mode is enabled.
+ SCAN_GETDIRS, // Get subdirectories in recurse mode.
+ SCAN_GETDIRSTWICE, // Get the directory name both before and after the list of files it contains.
+ SCAN_GETCURDIRS // Get subdirectories in current directory even in RECURSE_NONE mode.
+};
+
+enum SCAN_CODE { SCAN_SUCCESS,SCAN_DONE,SCAN_ERROR,SCAN_NEXT };
+
+#define MAXSCANDEPTH (NM/2)
+
+class CommandData;
+
+class ScanTree
+{
+ private:
+ bool GetNextMask();
+ SCAN_CODE FindProc(FindData *FD);
+
+ FindFile *FindStack[MAXSCANDEPTH];
+ int Depth;
+
+ int SetAllMaskDepth;
+
+ StringList *FileMasks;
+ RECURSE_MODE Recurse;
+ bool GetLinks;
+ SCAN_DIRS GetDirs;
+ int Errors;
+
+ // set when processing paths like c:\ (root directory without wildcards)
+ bool ScanEntireDisk;
+
+ char CurMask[NM];
+ wchar CurMaskW[NM];
+ char OrigCurMask[NM];
+ wchar OrigCurMaskW[NM];
+ bool SearchAllInRoot;
+ size_t SpecPathLength;
+ size_t SpecPathLengthW;
+
+ char ErrArcName[NM];
+
+ CommandData *Cmd;
+ public:
+ ScanTree(StringList *FileMasks,RECURSE_MODE Recurse,bool GetLinks,SCAN_DIRS GetDirs);
+ ~ScanTree();
+ SCAN_CODE GetNext(FindData *FindData);
+ size_t GetSpecPathLength() {return(SpecPathLength);};
+ size_t GetSpecPathLengthW() {return(SpecPathLengthW);};
+ int GetErrors() {return(Errors);};
+ void SetErrArcName(const char *Name) {strcpy(ErrArcName,Name);}
+ void SetCommandData(CommandData *Cmd) {ScanTree::Cmd=Cmd;}
+};
+
+#endif
diff --git a/src/unrar/secpassword.cpp b/src/unrar/secpassword.cpp
new file mode 100644
index 0000000000..016e1360c0
--- /dev/null
+++ b/src/unrar/secpassword.cpp
@@ -0,0 +1,203 @@
+#include "rar.hpp"
+
+#ifdef _WIN_ALL
+typedef BOOL (WINAPI *CRYPTPROTECTMEMORY)(LPVOID pData,DWORD cbData,DWORD dwFlags);
+typedef BOOL (WINAPI *CRYPTUNPROTECTMEMORY)(LPVOID pData,DWORD cbData,DWORD dwFlags);
+
+#ifndef CRYPTPROTECTMEMORY_BLOCK_SIZE
+#define CRYPTPROTECTMEMORY_BLOCK_SIZE 16
+#define CRYPTPROTECTMEMORY_SAME_PROCESS 0x00
+#endif
+
+class CryptLoader
+{
+ private:
+ HMODULE hCrypt;
+ bool LoadCalled;
+ public:
+ CryptLoader()
+ {
+ hCrypt=NULL;
+ pCryptProtectMemory=NULL;
+ pCryptUnprotectMemory=NULL;
+ LoadCalled=false;
+ }
+ ~CryptLoader()
+ {
+ if (hCrypt!=NULL)
+ FreeLibrary(hCrypt);
+ hCrypt=NULL;
+ pCryptProtectMemory=NULL;
+ pCryptUnprotectMemory=NULL;
+ };
+ void Load()
+ {
+ if (!LoadCalled)
+ {
+ hCrypt = LoadLibraryW(L"Crypt32.dll");
+ if (hCrypt != NULL)
+ {
+ pCryptProtectMemory = (CRYPTPROTECTMEMORY)GetProcAddress(hCrypt, "CryptProtectMemory");
+ pCryptUnprotectMemory = (CRYPTUNPROTECTMEMORY)GetProcAddress(hCrypt, "CryptUnprotectMemory");
+ }
+ LoadCalled=true;
+ }
+ }
+
+ CRYPTPROTECTMEMORY pCryptProtectMemory;
+ CRYPTUNPROTECTMEMORY pCryptUnprotectMemory;
+};
+
+// We want to call FreeLibrary when RAR is exiting.
+CryptLoader GlobalCryptLoader;
+#endif
+
+SecPassword::SecPassword()
+{
+ Set(L"");
+}
+
+
+SecPassword::~SecPassword()
+{
+ Clean();
+}
+
+
+void SecPassword::Clean()
+{
+ PasswordSet=false;
+ cleandata(Password,sizeof(Password));
+}
+
+
+// When we call memset in end of function to clean local variables
+// for security reason, compiler optimizer can remove such call.
+// So we use our own function for this purpose.
+void cleandata(void *data,size_t size)
+{
+#if defined(_WIN_ALL) && defined(_MSC_VER)
+ SecureZeroMemory(data,size);
+#else
+ // 'volatile' is required. Otherwise optimizers can remove this function
+ // if cleaning local variables, which are not used after that.
+ volatile byte *d = (volatile byte *)data;
+ for (size_t i=0;i
+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 */
+}
+
+
diff --git a/src/unrar/sha1.hpp b/src/unrar/sha1.hpp
new file mode 100644
index 0000000000..f28403fd6f
--- /dev/null
+++ b/src/unrar/sha1.hpp
@@ -0,0 +1,19 @@
+#ifndef _RAR_SHA1_
+#define _RAR_SHA1_
+
+#define HW 5
+
+typedef struct {
+ uint32 state[5];
+ uint32 count[2];
+ unsigned char buffer[64];
+
+ unsigned char workspace[64]; // Temporary buffer.
+} hash_context;
+
+void hash_initial( hash_context * c );
+void hash_process( hash_context * c, unsigned char * data, size_t len,
+ bool handsoff);
+void hash_final( hash_context * c, uint32[HW], bool handsoff);
+
+#endif
diff --git a/src/unrar/smallfn.cpp b/src/unrar/smallfn.cpp
new file mode 100644
index 0000000000..f7d6fa1620
--- /dev/null
+++ b/src/unrar/smallfn.cpp
@@ -0,0 +1,42 @@
+#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);
+}
+
+
+char* RemoveLF(char *Str)
+{
+ for (int I=(int)strlen(Str)-1;I>=0 && (Str[I]=='\r' || Str[I]=='\n');I--)
+ Str[I]=0;
+ return(Str);
+}
+
+
+wchar* RemoveLF(wchar *Str)
+{
+ for (int I=(int)wcslen(Str)-1;I>=0 && (Str[I]=='\r' || Str[I]=='\n');I--)
+ Str[I]=0;
+ return(Str);
+}
+
+
+unsigned char loctolower(unsigned char ch)
+{
+#ifdef _WIN_ALL
+ // Convert to LPARAM first to avoid a warning in 64 bit mode.
+ return((int)(LPARAM)CharLowerA((LPSTR)ch));
+#else
+ return(tolower(ch));
+#endif
+}
+
+
+unsigned char loctoupper(unsigned char ch)
+{
+#ifdef _WIN_ALL
+ // Convert to LPARAM first to avoid a warning in 64 bit mode.
+ return((int)(LPARAM)CharUpperA((LPSTR)ch));
+#else
+ return(toupper(ch));
+#endif
+}
+
+
+// toupper with English only results if English input is provided.
+// It avoids Turkish (small i) -> (big I with dot) conversion problem.
+// We do not define 'ch' as 'int' to avoid necessity to cast all
+// signed chars passed to this function to unsigned char.
+unsigned char etoupper(unsigned char ch)
+{
+ if (ch=='i')
+ return('I');
+ return(toupper(ch));
+}
+
+
+// Unicode version of etoupper.
+wchar etoupperw(wchar ch)
+{
+ if (ch=='i')
+ return('I');
+ return(toupperw(ch));
+}
+
+
+// We do not want to cast every signed char to unsigned when passing to
+// isdigit, so we implement the replacement. Shall work for Unicode too.
+// If chars are signed, conversion from char to int could generate negative
+// values, resulting in undefined behavior in standard isdigit.
+bool IsDigit(int ch)
+{
+ return(ch>='0' && ch<='9');
+}
+
+
+// We do not want to cast every signed char to unsigned when passing to
+// isspace, so we implement the replacement. Shall work for Unicode too.
+// If chars are signed, conversion from char to int could generate negative
+// values, resulting in undefined behavior in standard isspace.
+bool IsSpace(int ch)
+{
+ return(ch==' ' || ch=='\t');
+}
+
+
+// We do not want to cast every signed char to unsigned when passing to
+// isalpha, so we implement the replacement. Shall work for Unicode too.
+// If chars are signed, conversion from char to int could generate negative
+// values, resulting in undefined behavior in standard function.
+bool IsAlpha(int ch)
+{
+ return(ch>='A' && ch<='Z' || ch>='a' && ch<='z');
+}
+
+
+
+
+#ifndef SFX_MODULE
+uint GetDigits(uint Number)
+{
+ uint Digits=1;
+ while (Number>=10)
+ {
+ Number/=10;
+ Digits++;
+ }
+ return(Digits);
+}
+#endif
+
+
+bool LowAscii(const char *Str)
+{
+ for (int I=0;Str[I]!=0;I++)
+ if ((byte)Str[I]<32 || (byte)Str[I]>127)
+ return(false);
+ return(true);
+}
+
+
+bool LowAscii(const wchar *Str)
+{
+ for (int I=0;Str[I]!=0;I++)
+ {
+ // We convert wchar_t to uint just in case if some compiler
+ // uses the signed wchar_t.
+ if ((uint)Str[I]<32 || (uint)Str[I]>127)
+ return(false);
+ }
+ return(true);
+}
+
+
+
+
+int stricompc(const char *Str1,const char *Str2)
+{
+#if defined(_UNIX)
+ return(strcmp(Str1,Str2));
+#else
+ return(stricomp(Str1,Str2));
+#endif
+}
+
+
+#ifndef SFX_MODULE
+int wcsicompc(const wchar *Str1,const wchar *Str2)
+{
+#if defined(_UNIX)
+ return(wcscmp(Str1,Str2));
+#else
+ return(wcsicomp(Str1,Str2));
+#endif
+}
+#endif
+
+
+// safe strncpy: copies maxlen-1 max and always returns zero terminated dest
+char* strncpyz(char *dest, const char *src, size_t maxlen)
+{
+ if (maxlen>0)
+ {
+ strncpy(dest,src,maxlen-1);
+ dest[maxlen-1]=0;
+ }
+ return(dest);
+}
+
+
+// Safe wcsncpy: copies maxlen-1 max and always returns zero terminated dest.
+wchar* wcsncpyz(wchar *dest, const wchar *src, size_t maxlen)
+{
+ if (maxlen>0)
+ {
+ wcsncpy(dest,src,maxlen-1);
+ dest[maxlen-1]=0;
+ }
+ return(dest);
+}
+
+
+// Safe strncat: resulting dest length cannot exceed maxlen and dest
+// is always zero terminated. Note that 'maxlen' parameter defines the entire
+// dest buffer size and is not compatible with standard strncat.
+char* strncatz(char* dest, const char* src, size_t maxlen)
+{
+ size_t Length = strlen(dest);
+ if (Length + 1 < maxlen)
+ strncat(dest, src, maxlen - Length - 1);
+ return dest;
+}
+
+
+// Safe wcsncat: resulting dest length cannot exceed maxlen and dest
+// is always zero terminated. Note that 'maxlen' parameter defines the entire
+// dest buffer size and is not compatible with standard wcsncat.
+wchar* wcsncatz(wchar* dest, const wchar* src, size_t maxlen)
+{
+ size_t Length = wcslen(dest);
+ if (Length + 1 < maxlen)
+ wcsncat(dest, src, maxlen - Length - 1);
+ return dest;
+}
+
+
+void itoa(int64 n,char *Str)
+{
+ char NumStr[50];
+ size_t Pos=0;
+
+ do
+ {
+ NumStr[Pos++]=char(n%10)+'0';
+ n=n/10;
+ } while (n!=0);
+
+ for (size_t I=0;I='0' && *Str<='9')
+ {
+ n=n*10+*Str-'0';
+ Str++;
+ }
+ return(n);
+}
+
+
+void itoa(int64 n,wchar *Str)
+{
+ wchar NumStr[50];
+ size_t Pos=0;
+
+ do
+ {
+ NumStr[Pos++]=wchar(n%10)+'0';
+ n=n/10;
+ } while (n!=0);
+
+ for (size_t I=0;I='0' && *Str<='9')
+ {
+ n=n*10+*Str-'0';
+ Str++;
+ }
+ return(n);
+}
+
+
+const wchar* GetWide(const char *Src)
+{
+ const size_t MaxLength=NM;
+ static wchar StrTable[4][MaxLength];
+ static uint StrNum=0;
+ if (++StrNum >= ASIZE(StrTable))
+ StrNum=0;
+ wchar *Str=StrTable[StrNum];
+ CharToWide(Src,Str,MaxLength);
+ Str[MaxLength-1]=0;
+ return(Str);
+}
+
+
+const wchar* GetWide(const char *Src,const wchar *SrcW)
+{
+ if (SrcW!=NULL && *SrcW!=0)
+ return SrcW;
+ return GetWide(Src);
+}
+
+
+#ifdef _WIN_ALL
+// Parse string containing parameters separated with spaces.
+// Support quote marks. Param can be NULL to return the pointer to next
+// parameter, which can be used to estimate the buffer size for Param.
+const wchar* GetCmdParam(const wchar *CmdLine,wchar *Param,size_t MaxSize)
+{
+ while (IsSpace(*CmdLine))
+ CmdLine++;
+ if (*CmdLine==0)
+ return NULL;
+
+ size_t ParamSize=0;
+ bool Quote=false;
+ while (*CmdLine!=0 && (Quote || !IsSpace(*CmdLine)))
+ {
+ if (*CmdLine=='\"')
+ {
+ if (CmdLine[1]=='\"')
+ {
+ // Insert the quote character instead of two adjoining quote characters.
+ if (Param!=NULL && ParamSize=0)
+ if (!GetString(Str,StrW,MaxLength))
+ {
+ RetCode=false;
+ break;
+ }
+ RestorePosition();
+ return(RetCode);
+}
+#endif
+
+
+char* StringList::GetString()
+{
+ char *Str;
+ GetString(&Str,NULL);
+ return(Str);
+}
+
+
+wchar* StringList::GetStringW()
+{
+ wchar *StrW;
+ GetString(NULL,&StrW);
+ return(StrW);
+}
+
+
+bool StringList::GetString(char **Str,wchar **StrW)
+{
+ // First check would be enough, because both buffers grow synchronously,
+ // but we check both for extra fail proof.
+ if (CurPos>=StringData.Size() || CurPosW>=StringDataW.Size())
+ {
+ // No more strings left unprocessed.
+ if (Str!=NULL)
+ *Str=NULL;
+ if (StrW!=NULL)
+ *StrW=NULL;
+ return(false);
+ }
+
+ // We move ASCII and Unicode buffer pointers synchronously.
+
+ char *CurStr=&StringData[CurPos];
+ CurPos+=strlen(CurStr)+1;
+ if (Str!=NULL)
+ *Str=CurStr;
+
+ wchar *CurStrW=&StringDataW[CurPosW];
+ CurPosW+=wcslen(CurStrW)+1;
+ if (StrW!=NULL)
+ *StrW=CurStrW;
+
+ return(true);
+}
+
+
+void StringList::Rewind()
+{
+ CurPos=0;
+ CurPosW=0;
+}
+
+
+// Return the total size of usual and Unicode characters stored in the list.
+size_t StringList::GetCharCount()
+{
+ return(StringData.Size()+StringDataW.Size());
+}
+
+
+#ifndef SFX_MODULE
+bool StringList::Search(char *Str,wchar *StrW,bool CaseSensitive)
+{
+ SavePosition();
+ Rewind();
+ bool Found=false;
+ char *CurStr;
+ wchar *CurStrW;
+ while (GetString(&CurStr,&CurStrW))
+ {
+ if (Str!=NULL && CurStr!=NULL)
+ if ((CaseSensitive ? strcmp(Str,CurStr):stricomp(Str,CurStr))!=0)
+ continue;
+ if (StrW!=NULL && CurStrW!=NULL)
+ if ((CaseSensitive ? wcscmp(StrW,CurStrW):wcsicomp(StrW,CurStrW))!=0)
+ continue;
+ Found=true;
+ break;
+ }
+ RestorePosition();
+ return(Found);
+}
+#endif
+
+
+#ifndef SFX_MODULE
+void StringList::SavePosition()
+{
+ if (SavePosNumber0)
+ {
+ SavePosNumber--;
+ CurPos=SaveCurPos[SavePosNumber];
+ CurPosW=SaveCurPosW[SavePosNumber];
+ }
+}
+#endif
diff --git a/src/unrar/strlist.hpp b/src/unrar/strlist.hpp
new file mode 100644
index 0000000000..4c8985ef0a
--- /dev/null
+++ b/src/unrar/strlist.hpp
@@ -0,0 +1,37 @@
+#ifndef _RAR_STRLIST_
+#define _RAR_STRLIST_
+
+class StringList
+{
+ private:
+ Array StringData;
+ size_t CurPos;
+
+ Array StringDataW;
+ size_t CurPosW;
+
+ uint StringsCount;
+
+ size_t SaveCurPos[16],SaveCurPosW[16],SavePosNumber;
+ public:
+ StringList();
+ void Reset();
+ void AddString(const char *Str);
+ void AddString(const wchar *Str);
+ void AddString(const char *Str,const wchar *StrW);
+ bool GetString(char *Str,size_t MaxLength);
+ bool GetString(wchar *Str,size_t MaxLength);
+ bool GetString(char *Str,wchar *StrW,size_t MaxLength);
+ bool GetString(char *Str,wchar *StrW,size_t MaxLength,int StringNum);
+ char* GetString();
+ wchar* GetStringW();
+ bool GetString(char **Str,wchar **StrW);
+ void Rewind();
+ uint ItemsCount() {return(StringsCount);};
+ size_t GetCharCount();
+ bool Search(char *Str,wchar *StrW,bool CaseSensitive);
+ void SavePosition();
+ void RestorePosition();
+};
+
+#endif
diff --git a/src/unrar/suballoc.cpp b/src/unrar/suballoc.cpp
new file mode 100644
index 0000000000..4a5c22a2e4
--- /dev/null
+++ b/src/unrar/suballoc.cpp
@@ -0,0 +1,294 @@
+/****************************************************************************
+ * This file is part of PPMd project *
+ * Written and distributed to public domain by Dmitry Shkarin 1997, *
+ * 1999-2000 *
+ * Contents: memory allocation routines *
+ ****************************************************************************/
+
+SubAllocator::SubAllocator()
+{
+ Clean();
+}
+
+
+void SubAllocator::Clean()
+{
+ SubAllocatorSize=0;
+}
+
+
+inline void SubAllocator::InsertNode(void* p,int indx)
+{
+ ((RAR_NODE*) p)->next=FreeList[indx].next;
+ FreeList[indx].next=(RAR_NODE*) p;
+}
+
+
+inline void* SubAllocator::RemoveNode(int indx)
+{
+ RAR_NODE* RetVal=FreeList[indx].next;
+ FreeList[indx].next=RetVal->next;
+ return RetVal;
+}
+
+
+inline uint SubAllocator::U2B(int NU)
+{
+ // We calculate the size of units in bytes based on real UNIT_SIZE.
+ // In original implementation it was 8*NU+4*NU.
+ return UNIT_SIZE*NU;
+}
+
+
+
+// Calculate RAR_MEM_BLK+Items address. Real RAR_MEM_BLK size must be
+// equal to UNIT_SIZE, so we cannot just add Items to RAR_MEM_BLK address.
+inline RAR_MEM_BLK* SubAllocator::MBPtr(RAR_MEM_BLK *BasePtr,int Items)
+{
+ return((RAR_MEM_BLK*)( ((byte *)(BasePtr))+U2B(Items) ));
+}
+
+
+inline void SubAllocator::SplitBlock(void* pv,int OldIndx,int NewIndx)
+{
+ int i, UDiff=Indx2Units[OldIndx]-Indx2Units[NewIndx];
+ byte* p=((byte*) pv)+U2B(Indx2Units[NewIndx]);
+ if (Indx2Units[i=Units2Indx[UDiff-1]] != UDiff)
+ {
+ InsertNode(p,--i);
+ p += U2B(i=Indx2Units[i]);
+ UDiff -= i;
+ }
+ InsertNode(p,Units2Indx[UDiff-1]);
+}
+
+
+
+
+void SubAllocator::StopSubAllocator()
+{
+ if ( SubAllocatorSize )
+ {
+ SubAllocatorSize=0;
+ free(HeapStart);
+ }
+}
+
+
+bool SubAllocator::StartSubAllocator(int SASize)
+{
+ uint t=SASize << 20;
+ if (SubAllocatorSize == t)
+ return TRUE;
+ StopSubAllocator();
+
+ // Original algorithm expects FIXED_UNIT_SIZE, but actual structure size
+ // can be larger. So let's recalculate the allocated size and add two more
+ // units: one as reserve for HeapEnd overflow checks and another
+ // to provide the space to correctly align UnitsStart.
+ uint AllocSize=t/FIXED_UNIT_SIZE*UNIT_SIZE+2*UNIT_SIZE;
+ if ((HeapStart=(byte *)malloc(AllocSize)) == NULL)
+ {
+ ErrHandler.MemoryError();
+ return FALSE;
+ }
+
+ // HeapEnd did not present in original algorithm. We added it to control
+ // invalid memory access attempts when processing corrupt archived data.
+ HeapEnd=HeapStart+AllocSize-UNIT_SIZE;
+
+ SubAllocatorSize=t;
+ return TRUE;
+}
+
+
+void SubAllocator::InitSubAllocator()
+{
+ int i, k;
+ memset(FreeList,0,sizeof(FreeList));
+ pText=HeapStart;
+
+ // Original algorithm operates with 12 byte FIXED_UNIT_SIZE, but actual
+ // size of RAR_MEM_BLK and PPM_CONTEXT structures can exceed this value
+ // because of alignment and larger pointer fields size.
+ // So we define UNIT_SIZE for this larger size and adjust memory
+ // pointers accordingly.
+
+ // Size2 is (HiUnit-LoUnit) memory area size to allocate as originally
+ // supposed by compression algorithm. It is 7/8 of total allocated size.
+ uint Size2=FIXED_UNIT_SIZE*(SubAllocatorSize/8/FIXED_UNIT_SIZE*7);
+
+ // RealSize2 is the real adjusted size of (HiUnit-LoUnit) memory taking
+ // into account that our UNIT_SIZE can be larger than FIXED_UNIT_SIZE.
+ uint RealSize2=Size2/FIXED_UNIT_SIZE*UNIT_SIZE;
+
+ // Size1 is the size of memory area from HeapStart to FakeUnitsStart
+ // as originally supposed by compression algorithm. This area can contain
+ // different data types, both single symbols and structures.
+ uint Size1=SubAllocatorSize-Size2;
+
+ // Real size of this area. We correct it according to UNIT_SIZE vs
+ // FIXED_UNIT_SIZE difference. Also we add one more UNIT_SIZE
+ // to compensate a possible reminder from Size1/FIXED_UNIT_SIZE,
+ // which would be lost otherwise. We add UNIT_SIZE instead of
+ // this Size1%FIXED_UNIT_SIZE reminder, because it allows to align
+ // UnitsStart easily and adding more than reminder is ok for algorithm.
+ uint RealSize1=Size1/FIXED_UNIT_SIZE*UNIT_SIZE+UNIT_SIZE;
+
+ // RealSize1 must be divided by UNIT_SIZE without a reminder, so UnitsStart
+ // is aligned to UNIT_SIZE. It is important for those architectures,
+ // where a proper memory alignment is mandatory. Since we produce RealSize1
+ // multiplying by UNIT_SIZE, this condition is always true. So LoUnit,
+ // UnitsStart, HeapStart are properly aligned,
+ LoUnit=UnitsStart=HeapStart+RealSize1;
+
+ // When we reach FakeUnitsStart, we restart the model. It is where
+ // the original algorithm expected to see UnitsStart. Real UnitsStart
+ // can have a larger value.
+ FakeUnitsStart=HeapStart+Size1;
+
+ HiUnit=LoUnit+RealSize2;
+ for (i=0,k=1;i < N1 ;i++,k += 1)
+ Indx2Units[i]=k;
+ for (k++;i < N1+N2 ;i++,k += 2)
+ Indx2Units[i]=k;
+ for (k++;i < N1+N2+N3 ;i++,k += 3)
+ Indx2Units[i]=k;
+ for (k++;i < N1+N2+N3+N4;i++,k += 4)
+ Indx2Units[i]=k;
+ for (GlueCount=k=i=0;k < 128;k++)
+ {
+ i += (Indx2Units[i] < k+1);
+ Units2Indx[k]=i;
+ }
+}
+
+
+inline void SubAllocator::GlueFreeBlocks()
+{
+ RAR_MEM_BLK s0, * p, * p1;
+ int i, k, sz;
+ if (LoUnit != HiUnit)
+ *LoUnit=0;
+ for (i=0, s0.next=s0.prev=&s0;i < N_INDEXES;i++)
+ while ( FreeList[i].next )
+ {
+ p=(RAR_MEM_BLK*)RemoveNode(i);
+ p->insertAt(&s0);
+ p->Stamp=0xFFFF;
+ p->NU=Indx2Units[i];
+ }
+ for (p=s0.next;p != &s0;p=p->next)
+ while ((p1=MBPtr(p,p->NU))->Stamp == 0xFFFF && int(p->NU)+p1->NU < 0x10000)
+ {
+ p1->remove();
+ p->NU += p1->NU;
+ }
+ while ((p=s0.next) != &s0)
+ {
+ for (p->remove(), sz=p->NU;sz > 128;sz -= 128, p=MBPtr(p,128))
+ InsertNode(p,N_INDEXES-1);
+ if (Indx2Units[i=Units2Indx[sz-1]] != sz)
+ {
+ k=sz-Indx2Units[--i];
+ InsertNode(MBPtr(p,sz-k),k-1);
+ }
+ InsertNode(p,i);
+ }
+}
+
+void* SubAllocator::AllocUnitsRare(int indx)
+{
+ if ( !GlueCount )
+ {
+ GlueCount = 255;
+ GlueFreeBlocks();
+ if ( FreeList[indx].next )
+ return RemoveNode(indx);
+ }
+ int i=indx;
+ do
+ {
+ if (++i == N_INDEXES)
+ {
+ GlueCount--;
+ i=U2B(Indx2Units[indx]);
+ int j=FIXED_UNIT_SIZE*Indx2Units[indx];
+ if (FakeUnitsStart-pText > j)
+ {
+ FakeUnitsStart-=j;
+ UnitsStart -= i;
+ return(UnitsStart);
+ }
+ return(NULL);
+ }
+ } while ( !FreeList[i].next );
+ void* RetVal=RemoveNode(i);
+ SplitBlock(RetVal,i,indx);
+ return RetVal;
+}
+
+
+inline void* SubAllocator::AllocUnits(int NU)
+{
+ int indx=Units2Indx[NU-1];
+ if ( FreeList[indx].next )
+ return RemoveNode(indx);
+ void* RetVal=LoUnit;
+ LoUnit += U2B(Indx2Units[indx]);
+ if (LoUnit <= HiUnit)
+ return RetVal;
+ LoUnit -= U2B(Indx2Units[indx]);
+ return AllocUnitsRare(indx);
+}
+
+
+void* SubAllocator::AllocContext()
+{
+ if (HiUnit != LoUnit)
+ return (HiUnit -= UNIT_SIZE);
+ if ( FreeList->next )
+ return RemoveNode(0);
+ return AllocUnitsRare(0);
+}
+
+
+void* SubAllocator::ExpandUnits(void* OldPtr,int OldNU)
+{
+ int i0=Units2Indx[OldNU-1], i1=Units2Indx[OldNU-1+1];
+ if (i0 == i1)
+ return OldPtr;
+ void* ptr=AllocUnits(OldNU+1);
+ if ( ptr )
+ {
+ memcpy(ptr,OldPtr,U2B(OldNU));
+ InsertNode(OldPtr,i0);
+ }
+ return ptr;
+}
+
+
+void* SubAllocator::ShrinkUnits(void* OldPtr,int OldNU,int NewNU)
+{
+ int i0=Units2Indx[OldNU-1], i1=Units2Indx[NewNU-1];
+ if (i0 == i1)
+ return OldPtr;
+ if ( FreeList[i1].next )
+ {
+ void* ptr=RemoveNode(i1);
+ memcpy(ptr,OldPtr,U2B(NewNU));
+ InsertNode(OldPtr,i0);
+ return ptr;
+ }
+ else
+ {
+ SplitBlock(OldPtr,i0,i1);
+ return OldPtr;
+ }
+}
+
+
+void SubAllocator::FreeUnits(void* ptr,int OldNU)
+{
+ InsertNode(ptr,Units2Indx[OldNU-1]);
+}
diff --git a/src/unrar/suballoc.hpp b/src/unrar/suballoc.hpp
new file mode 100644
index 0000000000..474ee59208
--- /dev/null
+++ b/src/unrar/suballoc.hpp
@@ -0,0 +1,87 @@
+/****************************************************************************
+ * This file is part of PPMd project *
+ * Written and distributed to public domain by Dmitry Shkarin 1997, *
+ * 1999-2000 *
+ * Contents: interface to memory allocation routines *
+ ****************************************************************************/
+#if !defined(_SUBALLOC_H_)
+#define _SUBALLOC_H_
+
+const int N1=4, N2=4, N3=4, N4=(128+3-1*N1-2*N2-3*N3)/4;
+const int N_INDEXES=N1+N2+N3+N4;
+
+#if defined(__GNUC__) && !defined(STRICT_ALIGNMENT_REQUIRED)
+#define _PACK_ATTR __attribute__ ((packed))
+#else
+#define _PACK_ATTR
+#endif /* defined(__GNUC__) */
+
+#ifndef STRICT_ALIGNMENT_REQUIRED
+#pragma pack(1)
+#endif
+
+struct RAR_MEM_BLK
+{
+ ushort Stamp, NU;
+ RAR_MEM_BLK* next, * prev;
+ void insertAt(RAR_MEM_BLK* p)
+ {
+ next=(prev=p)->next;
+ p->next=next->prev=this;
+ }
+ void remove()
+ {
+ prev->next=next;
+ next->prev=prev;
+ }
+} _PACK_ATTR;
+
+#ifndef STRICT_ALIGNMENT_REQUIRED
+#ifdef _AIX
+#pragma pack(pop)
+#else
+#pragma pack()
+#endif
+#endif
+
+
+struct RAR_NODE
+{
+ RAR_NODE* next;
+};
+
+class SubAllocator
+{
+ private:
+ inline void InsertNode(void* p,int indx);
+ inline void* RemoveNode(int indx);
+ inline uint U2B(int NU);
+ inline void SplitBlock(void* pv,int OldIndx,int NewIndx);
+ uint GetUsedMemory();
+ inline void GlueFreeBlocks();
+ void* AllocUnitsRare(int indx);
+ inline RAR_MEM_BLK* MBPtr(RAR_MEM_BLK *BasePtr,int Items);
+
+ long SubAllocatorSize;
+ byte Indx2Units[N_INDEXES], Units2Indx[128], GlueCount;
+ byte *HeapStart,*LoUnit, *HiUnit;
+ struct RAR_NODE FreeList[N_INDEXES];
+ public:
+ SubAllocator();
+ ~SubAllocator() {StopSubAllocator();}
+ void Clean();
+ bool StartSubAllocator(int SASize);
+ void StopSubAllocator();
+ void InitSubAllocator();
+ inline void* AllocContext();
+ inline void* AllocUnits(int NU);
+ inline void* ExpandUnits(void* ptr,int OldNU);
+ inline void* ShrinkUnits(void* ptr,int OldNU,int NewNU);
+ inline void FreeUnits(void* ptr,int OldNU);
+ long GetAllocatedMemory() {return(SubAllocatorSize);};
+
+ byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart;
+};
+
+
+#endif /* !defined(_SUBALLOC_H_) */
diff --git a/src/unrar/system.cpp b/src/unrar/system.cpp
new file mode 100644
index 0000000000..a3746aa122
--- /dev/null
+++ b/src/unrar/system.cpp
@@ -0,0 +1,102 @@
+#include "rar.hpp"
+
+#ifndef _WIN_CE
+static int SleepTime=0;
+
+void InitSystemOptions(int SleepTime)
+{
+ ::SleepTime=SleepTime;
+}
+#endif
+
+
+#if !defined(SFX_MODULE) && !defined(_WIN_CE) && !defined(SETUP)
+void SetPriority(int Priority)
+{
+#ifdef _WIN_ALL
+ uint PriorityClass;
+ int PriorityLevel;
+ if (Priority<1 || Priority>15)
+ return;
+
+ if (Priority==1)
+ {
+ PriorityClass=IDLE_PRIORITY_CLASS;
+ PriorityLevel=THREAD_PRIORITY_IDLE;
+ }
+ else
+ if (Priority<7)
+ {
+ PriorityClass=IDLE_PRIORITY_CLASS;
+ PriorityLevel=Priority-4;
+ }
+ else
+ if (Priority==7)
+ {
+ PriorityClass=BELOW_NORMAL_PRIORITY_CLASS;
+ PriorityLevel=THREAD_PRIORITY_ABOVE_NORMAL;
+ }
+ else
+ if (Priority<10)
+ {
+ PriorityClass=NORMAL_PRIORITY_CLASS;
+ PriorityLevel=Priority-7;
+ }
+ else
+ if (Priority==10)
+ {
+ PriorityClass=ABOVE_NORMAL_PRIORITY_CLASS;
+ PriorityLevel=THREAD_PRIORITY_NORMAL;
+ }
+ else
+ {
+ PriorityClass=HIGH_PRIORITY_CLASS;
+ PriorityLevel=Priority-13;
+ }
+ SetPriorityClass(GetCurrentProcess(),PriorityClass);
+ SetThreadPriority(GetCurrentThread(),PriorityLevel);
+
+#ifdef RAR_SMP
+ ThreadPool::SetPriority(PriorityLevel);
+#endif
+
+// Background mode for Vista, too slow for real life use.
+// if (WinNT()>=WNT_VISTA && Priority==1)
+// SetPriorityClass(GetCurrentProcess(),PROCESS_MODE_BACKGROUND_BEGIN);
+
+#endif
+}
+#endif
+
+
+#ifndef SETUP
+void Wait()
+{
+#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE)
+ if (SleepTime!=0)
+ Sleep(SleepTime);
+#endif
+}
+#endif
+
+
+
+
+#if defined(_WIN_ALL) && !defined(_WIN_CE) && !defined(SFX_MODULE) && !defined(SHELL_EXT) && !defined(SETUP)
+void Shutdown()
+{
+ HANDLE hToken;
+ TOKEN_PRIVILEGES tkp;
+ if (OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken))
+ {
+ LookupPrivilegeValue(NULL,SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid);
+ tkp.PrivilegeCount = 1;
+ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ AdjustTokenPrivileges(hToken,FALSE,&tkp,0,(PTOKEN_PRIVILEGES)NULL,0);
+ }
+ ExitWindowsEx(EWX_SHUTDOWN|EWX_FORCE|EWX_POWEROFF,SHTDN_REASON_FLAG_PLANNED);
+}
+#endif
+
+
diff --git a/src/unrar/system.hpp b/src/unrar/system.hpp
new file mode 100644
index 0000000000..a765564707
--- /dev/null
+++ b/src/unrar/system.hpp
@@ -0,0 +1,28 @@
+#ifndef _RAR_SYSTEM_
+#define _RAR_SYSTEM_
+
+#ifdef _WIN_ALL
+#ifndef BELOW_NORMAL_PRIORITY_CLASS
+#define BELOW_NORMAL_PRIORITY_CLASS 0x00004000
+#define ABOVE_NORMAL_PRIORITY_CLASS 0x00008000
+#endif
+#ifndef PROCESS_MODE_BACKGROUND_BEGIN
+#define PROCESS_MODE_BACKGROUND_BEGIN 0x00100000
+#define PROCESS_MODE_BACKGROUND_END 0x00200000
+#endif
+#ifndef SHTDN_REASON_MAJOR_APPLICATION
+#define SHTDN_REASON_MAJOR_APPLICATION 0x00040000
+#define SHTDN_REASON_FLAG_PLANNED 0x80000000
+#define SHTDN_REASON_MINOR_MAINTENANCE 0x00000001
+#endif
+#endif
+
+void InitSystemOptions(int SleepTime);
+void SetPriority(int Priority);
+void Wait();
+bool EmailFile(char *FileName,char *MailTo);
+void Shutdown();
+
+
+
+#endif
diff --git a/src/unrar/timefn.cpp b/src/unrar/timefn.cpp
new file mode 100644
index 0000000000..ed2bd88616
--- /dev/null
+++ b/src/unrar/timefn.cpp
@@ -0,0 +1,336 @@
+#include "rar.hpp"
+
+RarTime::RarTime()
+{
+ Reset();
+}
+
+#ifdef _WIN_ALL
+RarTime& RarTime::operator =(FILETIME &ft)
+{
+ FILETIME lft;
+ FileTimeToLocalFileTime(&ft,&lft);
+ SYSTEMTIME st;
+ FileTimeToSystemTime(&lft,&st);
+ rlt.Year=st.wYear;
+ rlt.Month=st.wMonth;
+ rlt.Day=st.wDay;
+ rlt.Hour=st.wHour;
+ rlt.Minute=st.wMinute;
+ rlt.Second=st.wSecond;
+ rlt.wDay=st.wDayOfWeek;
+ rlt.yDay=rlt.Day-1;
+ for (uint I=1;I2 && IsLeapYear(rlt.Year))
+ rlt.yDay++;
+
+ st.wMilliseconds=0;
+ FILETIME zft;
+ SystemTimeToFileTime(&st,&zft);
+
+ // Calculate the time reminder, which is the part of time smaller
+ // than 1 second, represented in 100-nanosecond intervals.
+ rlt.Reminder=INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime)-
+ INT32TO64(zft.dwHighDateTime,zft.dwLowDateTime);
+ return(*this);
+}
+
+
+void RarTime::GetWin32(FILETIME *ft)
+{
+ SYSTEMTIME st;
+ st.wYear=rlt.Year;
+ st.wMonth=rlt.Month;
+ st.wDay=rlt.Day;
+ st.wHour=rlt.Hour;
+ st.wMinute=rlt.Minute;
+ st.wSecond=rlt.Second;
+ st.wMilliseconds=0;
+ FILETIME lft;
+ SystemTimeToFileTime(&st,&lft);
+ lft.dwLowDateTime+=rlt.Reminder;
+ if (lft.dwLowDateTimetm_year+1900;
+ rlt.Month=t->tm_mon+1;
+ rlt.Day=t->tm_mday;
+ rlt.Hour=t->tm_hour;
+ rlt.Minute=t->tm_min;
+ rlt.Second=t->tm_sec;
+ rlt.Reminder=0;
+ rlt.wDay=t->tm_wday;
+ rlt.yDay=t->tm_yday;
+ return(*this);
+}
+
+
+time_t RarTime::GetUnix()
+{
+ struct tm t;
+
+ t.tm_sec=rlt.Second;
+ t.tm_min=rlt.Minute;
+ t.tm_hour=rlt.Hour;
+ t.tm_mday=rlt.Day;
+ t.tm_mon=rlt.Month-1;
+ t.tm_year=rlt.Year-1900;
+ t.tm_isdst=-1;
+ return(mktime(&t));
+}
+#endif
+
+// Return the stored time as 64-bit number of 100-nanosecond intervals
+// since January 1, 1601 for Windows and since January 1, 1970 for Unix.
+// Actually we do not care since which date this time starts from
+// as long as this date is the same for GetRaw and SetRaw. We use the value
+// returned by GetRaw() for time comparisons, for relative operations
+// like SetRaw(GetRaw()-C) and for compact time storage when necessary.
+int64 RarTime::GetRaw()
+{
+ if (!IsSet())
+ return(0);
+#ifdef _WIN_ALL
+ FILETIME ft;
+ GetWin32(&ft);
+ return(INT32TO64(ft.dwHighDateTime,ft.dwLowDateTime));
+#elif defined(_UNIX) || defined(_EMX)
+ time_t ut=GetUnix();
+ return(INT32TO64(0,ut)*10000000+rlt.Reminder);
+#else
+ // We should never be here. It is better to use standard time functions.
+
+ // Days since 1970. We do not care about leap years for code simplicity.
+ // It should be acceptable for comprisons.
+ int64 r=(rlt.Year-1970)*365; // Days since 1970.
+
+ // Cumulative day value for beginning of every month.
+ static int MonthToDay[12]={0,31,60,91,121,152,182,213,244,274,305,335};
+
+ r+=MonthToDay[rlt.Month-1]+(rlt.Day-1); // Add days since beginning of year.
+ r=r*24+rlt.Hour; // Hours.
+ r=r*60+rlt.Minute; // Minutes.
+ r=r*60+rlt.Second; // Seconds.
+ r=r*10000000+rlt.Reminder; // 100-nanosecond intervals.
+
+ return(r);
+#endif
+}
+
+
+#ifndef SFX_MODULE
+void RarTime::SetRaw(int64 RawTime)
+{
+#ifdef _WIN_ALL
+ FILETIME ft;
+ ft.dwHighDateTime=(DWORD)(RawTime>>32);
+ ft.dwLowDateTime=(DWORD)RawTime;
+ *this=ft;
+#elif defined(_UNIX) || defined(_EMX)
+ time_t ut=(time_t)(RawTime/10000000);
+ *this=ut;
+ rlt.Reminder=(uint)(RawTime%10000000);
+#else
+ // We should never be here. It is better to use standard time functions.
+ rlt.Reminder=RawTime%10000000;
+ RawTime/=10000000; // Seconds.
+ rlt.Second=uint(RawTime%60);
+ RawTime/=60; // Minutes.
+ rlt.Minute=uint(RawTime%60);
+ RawTime/=60; // Hours.
+ rlt.Hour=uint(RawTime%24);
+ RawTime/=24; // Days since 1970.
+ rlt.Year=uint(1970+RawTime/365);
+ RawTime%=365; // Days since beginning of year.
+
+ // Cumulative day value for beginning of every month.
+ static int MonthToDay[12]={0,31,60,91,121,152,182,213,244,274,305,335};
+
+ for (int I=0;I<12;I++)
+ if (RawTime>=MonthToDay[I])
+ {
+ rlt.Day=uint(RawTime-MonthToDay[I]+1);
+ rlt.Month=I+1;
+ }
+
+ rlt.wDay=0;
+ rlt.yDay=0;
+#endif
+}
+#endif
+
+
+bool RarTime::operator == (RarTime &rt)
+{
+ return(rlt.Year==rt.rlt.Year && rlt.Month==rt.rlt.Month &&
+ rlt.Day==rt.rlt.Day && rlt.Hour==rt.rlt.Hour &&
+ rlt.Minute==rt.rlt.Minute && rlt.Second==rt.rlt.Second &&
+ rlt.Reminder==rt.rlt.Reminder);
+}
+
+
+bool RarTime::operator < (RarTime &rt)
+{
+ return(GetRaw() (RarTime &rt)
+{
+ return(GetRaw()>rt.GetRaw());
+}
+
+
+bool RarTime::operator >= (RarTime &rt)
+{
+ return(*this>rt || *this==rt);
+}
+
+
+uint RarTime::GetDos()
+{
+ uint DosTime=(rlt.Second/2)|(rlt.Minute<<5)|(rlt.Hour<<11)|
+ (rlt.Day<<16)|(rlt.Month<<21)|((rlt.Year-1980)<<25);
+ return(DosTime);
+}
+
+
+void RarTime::SetDos(uint DosTime)
+{
+ rlt.Second=(DosTime & 0x1f)*2;
+ rlt.Minute=(DosTime>>5) & 0x3f;
+ rlt.Hour=(DosTime>>11) & 0x1f;
+ rlt.Day=(DosTime>>16) & 0x1f;
+ rlt.Month=(DosTime>>21) & 0x0f;
+ rlt.Year=(DosTime>>25)+1980;
+ rlt.Reminder=0;
+}
+
+
+#if !defined(GUI) || !defined(SFX_MODULE)
+void RarTime::GetText(char *DateStr,bool FullYear)
+{
+ if (FullYear)
+ sprintf(DateStr,"%02u-%02u-%u %02u:%02u",rlt.Day,rlt.Month,rlt.Year,rlt.Hour,rlt.Minute);
+ else
+ sprintf(DateStr,"%02u-%02u-%02u %02u:%02u",rlt.Day,rlt.Month,rlt.Year%100,rlt.Hour,rlt.Minute);
+}
+#endif
+
+
+#ifndef SFX_MODULE
+void RarTime::SetIsoText(const char *TimeText)
+{
+ int Field[6];
+ memset(Field,0,sizeof(Field));
+ for (int DigitCount=0;*TimeText!=0;TimeText++)
+ if (IsDigit(*TimeText))
+ {
+ int FieldPos=DigitCount<4 ? 0:(DigitCount-4)/2+1;
+ if (FieldPos (RarTime &rt);
+ bool operator >= (RarTime &rt);
+ void GetLocal(RarLocalTime *lt) {*lt=rlt;}
+ void SetLocal(RarLocalTime *lt) {rlt=*lt;}
+ int64 GetRaw();
+ void SetRaw(int64 RawTime);
+ uint GetDos();
+ void SetDos(uint DosTime);
+ void GetText(char *DateStr,bool FullYear);
+ void SetIsoText(const char *TimeText);
+ void SetAgeText(const char *TimeText);
+ void SetCurrentTime();
+ void Reset() {rlt.Year=0;}
+ bool IsSet() {return(rlt.Year!=0);}
+};
+
+const char *GetMonthName(int Month);
+bool IsLeapYear(int Year);
+
+#endif
diff --git a/src/unrar/ulinks.cpp b/src/unrar/ulinks.cpp
new file mode 100644
index 0000000000..c3c828d2c2
--- /dev/null
+++ b/src/unrar/ulinks.cpp
@@ -0,0 +1,35 @@
+#include "rar.hpp"
+
+
+
+bool ExtractLink(ComprDataIO &DataIO,Archive &Arc,const char *LinkName,uint &LinkCRC,bool Create)
+{
+#if defined(SAVE_LINKS) && defined(_UNIX)
+ char LinkTarget[NM];
+ if (IsLink(Arc.NewLhd.FileAttr))
+ {
+ int DataSize=Min(Arc.NewLhd.PackSize,sizeof(LinkTarget)-1);
+ DataIO.UnpRead((byte *)LinkTarget,DataSize);
+ LinkTarget[DataSize]=0;
+ if (Create)
+ {
+ CreatePath(LinkName,NULL,true);
+ if (symlink(LinkTarget,LinkName)==-1) // Error.
+ if (errno==EEXIST)
+ Log(Arc.FileName,St(MSymLinkExists),LinkName);
+ else
+ {
+ Log(Arc.FileName,St(MErrCreateLnk),LinkName);
+ ErrHandler.SetErrorCode(RARX_WARNING);
+ }
+ // We do not set time of created symlink, because utime changes
+ // time of link target and lutimes is not available on all Linux
+ // systems at the moment of writing this code.
+ }
+ int NameSize=Min(DataSize,strlen(LinkTarget));
+ LinkCRC=CRC(0xffffffff,LinkTarget,NameSize);
+ return(true);
+ }
+#endif
+ return(false);
+}
diff --git a/src/unrar/ulinks.hpp b/src/unrar/ulinks.hpp
new file mode 100644
index 0000000000..fdd831f254
--- /dev/null
+++ b/src/unrar/ulinks.hpp
@@ -0,0 +1,9 @@
+#ifndef _RAR_ULINKS_
+#define _RAR_ULINKS_
+
+void SaveLinkData(ComprDataIO &DataIO,Archive &TempArc,FileHeader &hd,
+ const char *Name);
+bool ExtractLink(ComprDataIO &DataIO,Archive &Arc,const char *LinkName,
+ uint &LinkCRC,bool Create);
+
+#endif
diff --git a/src/unrar/unicode.cpp b/src/unrar/unicode.cpp
new file mode 100644
index 0000000000..a3022d2339
--- /dev/null
+++ b/src/unrar/unicode.cpp
@@ -0,0 +1,420 @@
+#include "rar.hpp"
+
+#if defined(_EMX) && !defined(_DJGPP)
+#include "unios2.cpp"
+#endif
+
+bool WideToChar(const wchar *Src,char *Dest,size_t DestSize)
+{
+ bool RetCode=true;
+ *Dest=0; // Set 'Dest' to zero just in case the conversion will fail.
+
+#ifdef _WIN_ALL
+ if (WideCharToMultiByte(CP_ACP,0,Src,-1,Dest,(int)DestSize,NULL,NULL)==0)
+ RetCode=false;
+
+#elif defined(_APPLE)
+ WideToUtf(Src,Dest,DestSize);
+
+#elif defined(MBFUNCTIONS)
+ size_t ResultingSize=wcstombs(Dest,Src,DestSize);
+ if (ResultingSize==(size_t)-1)
+ RetCode=false;
+ if (ResultingSize==0 && *Src!=0)
+ RetCode=false;
+
+ if ((!RetCode || *Dest==0 && *Src!=0) && DestSize>NM && wcslen(Src)len*2)
+ RetCode=false;
+ Dest[DestSize]=0;
+#endif
+ }
+ else
+ for (int I=0;I