24 Commits
phpng ... unrar

Author SHA1 Message Date
Gustavo Lopes
6545fdd215 Added unrar 5.9.4 2020-10-11 18:54:32 +01:00
Gustavo Lopes
08f8190e49 Added unrar 5.9.3 2020-10-11 18:54:32 +01:00
Gustavo Lopes
544f55920a Add unrar 5.9.2 2020-04-29 20:12:36 +01:00
Gustavo Lopes
24b421e0e6 Add unrar 5.9.1 2020-04-29 20:12:36 +01:00
Gustavo Lopes
05a48cbbeb Added unrar 5.8.5 2020-04-29 20:12:36 +01:00
Gustavo Lopes
6d0e583ef9 Added unrar 5.8.4 2020-04-29 20:12:36 +01:00
Gustavo Lopes
714f15cb06 Added unrar 5.8.3 2020-04-29 20:12:36 +01:00
Gustavo Lopes
58bb195ae3 Added unrar 5.8.2 2020-04-29 20:12:36 +01:00
Gustavo Lopes
5293a8f07e Added unrar 5.8.1 2020-04-29 20:12:36 +01:00
Gustavo Lopes
61edb08973 Added unrar 5.7.5 2020-04-29 20:12:36 +01:00
Gustavo Lopes
adc9fe7d39 Added unrar 5.7.4 2020-04-29 20:12:36 +01:00
Gustavo Lopes
5eb1055447 Added unrar 5.7.3 2020-04-29 20:12:36 +01:00
Gustavo Lopes
7ca7561e09 Added unrar 5.7.2 2020-04-29 20:12:36 +01:00
Gustavo Lopes
61eca15136 Added unrar 5.7.1 2020-04-29 20:12:36 +01:00
Gustavo Lopes
dc8ee65999 Added unrar 5.6.8 2020-04-29 20:12:36 +01:00
Gustavo Lopes
656c3fa69d Added unrar 5.6.7 2020-04-29 20:12:36 +01:00
Gustavo Lopes
a6bea8fec8 Added unrar 5.6.6 2020-04-29 20:12:36 +01:00
Gustavo Lopes
3b405bea8e Added unrar 5.6.5 2020-04-29 20:12:36 +01:00
Gustavo Lopes
18cd0568aa Added unrar 5.6.4 2020-04-29 20:12:36 +01:00
Gustavo Lopes
dc298847c7 Added unrar 5.6.3 2020-04-29 20:12:36 +01:00
Gustavo Lopes
246a80fdeb Added unrar 5.6.2 2020-04-29 20:12:36 +01:00
Gustavo Lopes
4b6fd31d08 Added unrar 5.6.1 2020-04-29 20:12:36 +01:00
Gustavo Lopes
44e35b8f6a Added unrar 5.5.8 2020-04-29 20:12:36 +01:00
Gustavo Lopes
fe4a94305b Added unrar 5.5.7 2020-04-29 20:12:36 +01:00
103 changed files with 2101 additions and 5314 deletions

View File

@@ -1,643 +0,0 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="UnRAR"
ProjectGUID="{95CC809B-03FC-4EDB-BB20-FD07A698C05F}"
RootNamespace="UnRAR"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
<Platform
Name="x64"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="build\unrar32\$(ConfigurationName)"
IntermediateDirectory="build\unrar32\$(ConfigurationName)\obj"
ConfigurationType="1"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
PreprocessorDefinitions="UNRAR"
MinimalRebuild="false"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
RuntimeTypeInfo="false"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="rar.hpp"
WarningLevel="3"
DebugInformationFormat="4"
CallingConvention="2"
DisableSpecificWarnings="4007;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateManifest="false"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug|x64"
OutputDirectory="build\unrar64\$(ConfigurationName)"
IntermediateDirectory="build\unrar64\$(ConfigurationName)\obj"
ConfigurationType="1"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
PreprocessorDefinitions="UNRAR"
MinimalRebuild="false"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
RuntimeTypeInfo="false"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="rar.hpp"
WarningLevel="3"
DebugInformationFormat="3"
CallingConvention="2"
DisableSpecificWarnings="4007;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateManifest="false"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="build\unrar32\$(ConfigurationName)"
IntermediateDirectory="build\unrar32\$(ConfigurationName)\obj"
ConfigurationType="1"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="0"
OmitFramePointers="true"
WholeProgramOptimization="false"
PreprocessorDefinitions="UNRAR"
MinimalRebuild="false"
RuntimeLibrary="0"
StructMemberAlignment="0"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
EnableEnhancedInstructionSet="0"
FloatingPointModel="0"
RuntimeTypeInfo="false"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="rar.hpp"
WarningLevel="3"
DebugInformationFormat="3"
CallingConvention="2"
DisableSpecificWarnings="4007;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateManifest="false"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
LinkTimeCodeGeneration="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|x64"
OutputDirectory="build\unrar64\$(ConfigurationName)"
IntermediateDirectory="build\unrar64\$(ConfigurationName)\obj"
ConfigurationType="1"
CharacterSet="2"
WholeProgramOptimization="0"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="1"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="0"
OmitFramePointers="true"
WholeProgramOptimization="false"
PreprocessorDefinitions="UNRAR"
StringPooling="false"
MinimalRebuild="false"
RuntimeLibrary="0"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
RuntimeTypeInfo="false"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="rar.hpp"
WarningLevel="3"
DebugInformationFormat="3"
CallingConvention="2"
DisableSpecificWarnings="4007;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateManifest="false"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
LinkTimeCodeGeneration="0"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="archive.cpp"
>
</File>
<File
RelativePath="arcread.cpp"
>
</File>
<File
RelativePath="blake2s.cpp"
>
</File>
<File
RelativePath="cmddata.cpp"
>
</File>
<File
RelativePath="consio.cpp"
>
</File>
<File
RelativePath="crc.cpp"
>
</File>
<File
RelativePath="crypt.cpp"
>
</File>
<File
RelativePath="encname.cpp"
>
</File>
<File
RelativePath="errhnd.cpp"
>
</File>
<File
RelativePath="extinfo.cpp"
>
</File>
<File
RelativePath="extract.cpp"
>
</File>
<File
RelativePath="filcreat.cpp"
>
</File>
<File
RelativePath="file.cpp"
>
</File>
<File
RelativePath="filefn.cpp"
>
</File>
<File
RelativePath="filestr.cpp"
>
</File>
<File
RelativePath="find.cpp"
>
</File>
<File
RelativePath="getbits.cpp"
>
</File>
<File
RelativePath="global.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
</File>
<File
RelativePath="hash.cpp"
>
</File>
<File
RelativePath="headers.cpp"
>
</File>
<File
RelativePath="isnt.cpp"
>
</File>
<File
RelativePath="list.cpp"
>
</File>
<File
RelativePath="match.cpp"
>
</File>
<File
RelativePath="options.cpp"
>
</File>
<File
RelativePath="pathfn.cpp"
>
</File>
<File
RelativePath="qopen.cpp"
>
</File>
<File
RelativePath="rar.cpp"
>
</File>
<File
RelativePath="rarpch.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="rarvm.cpp"
>
</File>
<File
RelativePath="rawread.cpp"
>
</File>
<File
RelativePath="rdwrfn.cpp"
>
</File>
<File
RelativePath="recvol.cpp"
>
</File>
<File
RelativePath="resource.cpp"
>
</File>
<File
RelativePath="rijndael.cpp"
>
</File>
<File
RelativePath="rs.cpp"
>
</File>
<File
RelativePath="rs16.cpp"
>
</File>
<File
RelativePath="scantree.cpp"
>
</File>
<File
RelativePath="secpassword.cpp"
>
</File>
<File
RelativePath="sha1.cpp"
>
</File>
<File
RelativePath="sha256.cpp"
>
</File>
<File
RelativePath="smallfn.cpp"
>
</File>
<File
RelativePath="strfn.cpp"
>
</File>
<File
RelativePath="strlist.cpp"
>
</File>
<File
RelativePath="system.cpp"
>
</File>
<File
RelativePath="threadpool.cpp"
>
</File>
<File
RelativePath="timefn.cpp"
>
</File>
<File
RelativePath="ui.cpp"
>
</File>
<File
RelativePath="unicode.cpp"
>
</File>
<File
RelativePath="unpack.cpp"
>
</File>
<File
RelativePath="volume.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -1,876 +0,0 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="UnRAR"
ProjectGUID="{E815C46C-36C4-499F-BBC2-E772C6B17971}"
RootNamespace="UnRAR"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
<Platform
Name="x64"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="build\unrardll32\$(ConfigurationName)"
IntermediateDirectory="build\unrardll32\$(ConfigurationName)\obj"
ConfigurationType="2"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
PreprocessorDefinitions="RARDLL;UNRAR;SILENT"
MinimalRebuild="false"
ExceptionHandling="1"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
StructMemberAlignment="3"
RuntimeTypeInfo="false"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="rar.hpp"
WarningLevel="3"
DebugInformationFormat="4"
CallingConvention="0"
DisableSpecificWarnings="4007;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)\unrar.dll"
LinkIncremental="2"
GenerateManifest="true"
ModuleDefinitionFile="dll.def"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug|x64"
OutputDirectory="build\unrardll64\$(ConfigurationName)"
IntermediateDirectory="build\unrardll64\$(ConfigurationName)\obj"
ConfigurationType="2"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="0"
PreprocessorDefinitions="RARDLL;UNRAR;SILENT"
MinimalRebuild="false"
ExceptionHandling="1"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
StructMemberAlignment="3"
RuntimeTypeInfo="false"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="rar.hpp"
WarningLevel="3"
DebugInformationFormat="3"
CallingConvention="0"
DisableSpecificWarnings="4007;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)\unrar64.dll"
LinkIncremental="2"
GenerateManifest="true"
ModuleDefinitionFile="dll.def"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="build\unrardll32\$(ConfigurationName)"
IntermediateDirectory="build\unrardll32\$(ConfigurationName)\obj"
ConfigurationType="2"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="0"
OmitFramePointers="true"
WholeProgramOptimization="false"
PreprocessorDefinitions="RARDLL;UNRAR;SILENT"
MinimalRebuild="false"
ExceptionHandling="1"
RuntimeLibrary="0"
StructMemberAlignment="3"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
EnableEnhancedInstructionSet="0"
FloatingPointModel="0"
RuntimeTypeInfo="false"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="rar.hpp"
WarningLevel="3"
DebugInformationFormat="3"
CallingConvention="0"
DisableSpecificWarnings="4007;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/SAFESEH"
OutputFile="$(OutDir)\unrar.dll"
LinkIncremental="1"
GenerateManifest="true"
ModuleDefinitionFile="dll.def"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
LinkTimeCodeGeneration="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|x64"
OutputDirectory="build\unrardll64\$(ConfigurationName)"
IntermediateDirectory="build\unrardll64\$(ConfigurationName)\obj"
ConfigurationType="2"
CharacterSet="2"
WholeProgramOptimization="0"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="0"
OmitFramePointers="true"
WholeProgramOptimization="false"
PreprocessorDefinitions="RARDLL;UNRAR;SILENT"
StringPooling="false"
MinimalRebuild="false"
ExceptionHandling="1"
RuntimeLibrary="0"
StructMemberAlignment="3"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
RuntimeTypeInfo="false"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="rar.hpp"
WarningLevel="3"
DebugInformationFormat="3"
CallingConvention="0"
DisableSpecificWarnings="4007;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)\unrar64.dll"
LinkIncremental="1"
GenerateManifest="true"
ModuleDefinitionFile="dll.def"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
LinkTimeCodeGeneration="0"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="release_nocrypt|Win32"
OutputDirectory="build\unrardll32\$(ConfigurationName)"
IntermediateDirectory="build\unrardll32\$(ConfigurationName)\obj"
ConfigurationType="2"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="0"
OmitFramePointers="true"
WholeProgramOptimization="false"
PreprocessorDefinitions="RARDLL;UNRAR;SILENT;RAR_NOCRYPT"
MinimalRebuild="false"
ExceptionHandling="1"
RuntimeLibrary="0"
StructMemberAlignment="3"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
EnableEnhancedInstructionSet="0"
FloatingPointModel="0"
RuntimeTypeInfo="false"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="rar.hpp"
WarningLevel="3"
DebugInformationFormat="3"
CallingConvention="0"
DisableSpecificWarnings="4007;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalOptions="/SAFESEH"
OutputFile="$(OutDir)\unrar_nocrypt.dll"
LinkIncremental="1"
GenerateManifest="true"
ModuleDefinitionFile="dll_nocrypt.def"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
LinkTimeCodeGeneration="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="release_nocrypt|x64"
OutputDirectory="build\unrardll64\$(ConfigurationName)"
IntermediateDirectory="build\unrardll64\$(ConfigurationName)\obj"
ConfigurationType="2"
CharacterSet="2"
WholeProgramOptimization="0"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
TargetEnvironment="3"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/MP"
Optimization="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="0"
OmitFramePointers="true"
WholeProgramOptimization="false"
PreprocessorDefinitions="RARDLL;UNRAR;SILENT;RAR_NOCRYPT"
StringPooling="false"
MinimalRebuild="false"
ExceptionHandling="1"
RuntimeLibrary="0"
StructMemberAlignment="3"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
RuntimeTypeInfo="false"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="rar.hpp"
WarningLevel="3"
DebugInformationFormat="3"
CallingConvention="2"
DisableSpecificWarnings="4007;4996"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)\unrar64_nocrypt.dll"
LinkIncremental="1"
GenerateManifest="true"
ModuleDefinitionFile="dll_nocrypt.def"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
LinkTimeCodeGeneration="0"
TargetMachine="17"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="archive.cpp"
>
</File>
<File
RelativePath="arcread.cpp"
>
</File>
<File
RelativePath="blake2s.cpp"
>
</File>
<File
RelativePath="cmddata.cpp"
>
</File>
<File
RelativePath="consio.cpp"
>
</File>
<File
RelativePath="crc.cpp"
>
</File>
<File
RelativePath="crypt.cpp"
>
</File>
<File
RelativePath="dll.cpp"
>
</File>
<File
RelativePath="encname.cpp"
>
</File>
<File
RelativePath="errhnd.cpp"
>
</File>
<File
RelativePath="extinfo.cpp"
>
</File>
<File
RelativePath="extract.cpp"
>
</File>
<File
RelativePath="filcreat.cpp"
>
</File>
<File
RelativePath="file.cpp"
>
</File>
<File
RelativePath="filefn.cpp"
>
</File>
<File
RelativePath="filestr.cpp"
>
</File>
<File
RelativePath="find.cpp"
>
</File>
<File
RelativePath="getbits.cpp"
>
</File>
<File
RelativePath="global.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="release_nocrypt|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
<FileConfiguration
Name="release_nocrypt|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="0"
/>
</FileConfiguration>
</File>
<File
RelativePath="hash.cpp"
>
</File>
<File
RelativePath="headers.cpp"
>
</File>
<File
RelativePath="isnt.cpp"
>
</File>
<File
RelativePath="match.cpp"
>
</File>
<File
RelativePath="options.cpp"
>
</File>
<File
RelativePath="pathfn.cpp"
>
</File>
<File
RelativePath="qopen.cpp"
>
</File>
<File
RelativePath="rar.cpp"
>
</File>
<File
RelativePath="rarpch.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="release_nocrypt|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="release_nocrypt|x64"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="rarvm.cpp"
>
</File>
<File
RelativePath="rawread.cpp"
>
</File>
<File
RelativePath="rdwrfn.cpp"
>
</File>
<File
RelativePath="rijndael.cpp"
>
</File>
<File
RelativePath="rs.cpp"
>
</File>
<File
RelativePath="rs16.cpp"
>
</File>
<File
RelativePath="scantree.cpp"
>
</File>
<File
RelativePath="secpassword.cpp"
>
</File>
<File
RelativePath="sha1.cpp"
>
</File>
<File
RelativePath="sha256.cpp"
>
</File>
<File
RelativePath="smallfn.cpp"
>
</File>
<File
RelativePath="strfn.cpp"
>
</File>
<File
RelativePath="strlist.cpp"
>
</File>
<File
RelativePath="system.cpp"
>
</File>
<File
RelativePath="threadpool.cpp"
>
</File>
<File
RelativePath="timefn.cpp"
>
</File>
<File
RelativePath="ui.cpp"
>
</File>
<File
RelativePath="unicode.cpp"
>
</File>
<File
RelativePath="unpack.cpp"
>
</File>
<File
RelativePath="volume.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="rar.hpp"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
<File
RelativePath="dll.rc"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -4,10 +4,17 @@ bool Archive::GetComment(Array<wchar> *CmtData)
{
if (!MainComment)
return false;
SaveFilePos SavePos(*this);
int64 SavePos=Tell();
bool Success=DoGetComment(CmtData);
Seek(SavePos,SEEK_SET);
return Success;
}
bool Archive::DoGetComment(Array<wchar> *CmtData)
{
#ifndef SFX_MODULE
ushort CmtLength;
uint CmtLength;
if (Format==RARFMT14)
{
Seek(SFXSize+SIZEOF_MAINHEAD14,SEEK_SET);
@@ -22,7 +29,8 @@ bool Archive::GetComment(Array<wchar> *CmtData)
// Old style (RAR 2.9) archive comment embedded into the main
// archive header.
Seek(SFXSize+SIZEOF_MARKHEAD3+SIZEOF_MAINHEAD3,SEEK_SET);
ReadHeader();
if (!ReadHeader() || GetHeaderType()!=HEAD3_CMT)
return false;
}
else
{
@@ -33,7 +41,7 @@ bool Archive::GetComment(Array<wchar> *CmtData)
#ifndef SFX_MODULE
// Old style (RAR 2.9) comment header embedded into the main
// archive header.
if (BrokenHeader)
if (BrokenHeader || CommHead.HeadSize<SIZEOF_COMMHEAD)
{
uiMsg(UIERROR_CMTBROKEN,FileName);
return false;
@@ -52,10 +60,12 @@ bool Archive::GetComment(Array<wchar> *CmtData)
if (Format==RARFMT14)
{
#ifdef RAR_NOCRYPT
return(false);
return false;
#else
UnpCmtLength=GetByte();
UnpCmtLength+=(GetByte()<<8);
if (CmtLength<2)
return false;
CmtLength-=2;
DataIO.SetCmt13Encryption();
CommHead.UnpVer=15;
@@ -67,6 +77,7 @@ bool Archive::GetComment(Array<wchar> *CmtData)
DataIO.EnableShowProgress(false);
DataIO.SetPackedSizeToRead(CmtLength);
DataIO.UnpHash.Init(HASH_CRC32,1);
DataIO.SetNoFileHeader(true); // this->FileHead is not filled yet.
Unpack CmtUnpack(&DataIO);
CmtUnpack.Init(0x10000,false);
@@ -83,21 +94,31 @@ bool Archive::GetComment(Array<wchar> *CmtData)
byte *UnpData;
size_t UnpDataSize;
DataIO.GetUnpackedData(&UnpData,&UnpDataSize);
if (UnpDataSize>0)
{
#ifdef _WIN_ALL
// If we ever decide to extend it to Android, we'll need to alloc
// 4x memory for OEM to UTF-8 output here.
OemToCharBuffA((char *)UnpData,(char *)UnpData,(DWORD)UnpDataSize);
// If we ever decide to extend it to Android, we'll need to alloc
// 4x memory for OEM to UTF-8 output here.
OemToCharBuffA((char *)UnpData,(char *)UnpData,(DWORD)UnpDataSize);
#endif
CmtData->Alloc(UnpDataSize+1);
memset(CmtData->Addr(0),0,CmtData->Size()*sizeof(wchar));
CharToWide((char *)UnpData,CmtData->Addr(0),CmtData->Size());
CmtData->Alloc(wcslen(CmtData->Addr(0)));
CmtData->Alloc(UnpDataSize+1);
memset(CmtData->Addr(0),0,CmtData->Size()*sizeof(wchar));
CharToWide((char *)UnpData,CmtData->Addr(0),CmtData->Size());
CmtData->Alloc(wcslen(CmtData->Addr(0)));
}
}
}
else
{
if (CmtLength==0)
return false;
Array<byte> CmtRaw(CmtLength);
Read(&CmtRaw[0],CmtLength);
int ReadSize=Read(&CmtRaw[0],CmtLength);
if (ReadSize>=0 && (uint)ReadSize<CmtLength) // Comment is shorter than declared.
{
CmtLength=ReadSize;
CmtRaw.Alloc(CmtLength);
}
if (Format!=RARFMT14 && CommHead.CommCRC!=(~CRC32(0xffffffff,&CmtRaw[0],CmtLength)&0xffff))
{
@@ -111,7 +132,7 @@ bool Archive::GetComment(Array<wchar> *CmtData)
// 4x memory for OEM to UTF-8 output here.
OemToCharA((char *)&CmtRaw[0],(char *)&CmtRaw[0]);
#endif
CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtLength);
CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size());
CmtData->Alloc(wcslen(CmtData->Addr(0)));
}
#endif
@@ -122,7 +143,7 @@ bool Archive::GetComment(Array<wchar> *CmtData)
bool Archive::ReadCommentData(Array<wchar> *CmtData)
{
Array<byte> CmtRaw;
if (!ReadSubData(&CmtRaw,NULL))
if (!ReadSubData(&CmtRaw,NULL,false))
return false;
size_t CmtSize=CmtRaw.Size();
CmtRaw.Push(0);

View File

@@ -30,8 +30,6 @@ Archive::Archive(RAROptions *InitCmd)
CurBlockPos=0;
NextBlockPos=0;
RecoverySize=-1;
RecoveryPercent=-1;
memset(&MainHead,0,sizeof(MainHead));
memset(&CryptHead,0,sizeof(CryptHead));
@@ -48,6 +46,10 @@ Archive::Archive(RAROptions *InitCmd)
SilentOpen=false;
#ifdef USE_QOPEN
ProhibitQOpen=false;
#endif
}
@@ -114,7 +116,7 @@ RARFORMAT Archive::IsSignature(const byte *D,size_t Size)
if (D[6]==1)
Type=RARFMT50;
else
if (D[6]==2)
if (D[6]>1 && D[6]<5)
Type=RARFMT_FUTURE;
}
return Type;
@@ -175,8 +177,7 @@ bool Archive::IsArchive(bool EnableBroken)
}
if (Format==RARFMT50) // RAR 5.0 signature is by one byte longer.
{
Read(MarkHead.Mark+SIZEOF_MARKHEAD3,1);
if (MarkHead.Mark[SIZEOF_MARKHEAD3]!=0)
if (Read(MarkHead.Mark+SIZEOF_MARKHEAD3,1)!=1 || MarkHead.Mark[SIZEOF_MARKHEAD3]!=0)
return false;
MarkHead.HeadSize=SIZEOF_MARKHEAD5;
}
@@ -192,27 +193,31 @@ bool Archive::IsArchive(bool EnableBroken)
SilentOpen=true;
#endif
bool HeadersLeft; // Any headers left to read.
bool StartFound=false; // Main or encryption headers found.
// Skip the archive encryption header if any and read the main header.
while (ReadHeader()!=0)
while ((HeadersLeft=(ReadHeader()!=0))==true) // Additional parentheses to silence Clang.
{
SeekToNext();
HEADER_TYPE Type=GetHeaderType();
// In RAR 5.0 we need to quit after reading HEAD_CRYPT if we wish to
// avoid the password prompt.
if (Type==HEAD_MAIN || SilentOpen && Type==HEAD_CRYPT)
StartFound=Type==HEAD_MAIN || SilentOpen && Type==HEAD_CRYPT;
if (StartFound)
break;
SeekToNext();
}
// This check allows to make RS based recovery even if password is incorrect.
// But we should not do it for EnableBroken or we'll get 'not RAR archive'
// We should not do it for EnableBroken or we'll get 'not RAR archive'
// messages when extracting encrypted archives with wrong password.
if (FailedHeaderDecryption && !EnableBroken)
return false;
SeekToNext();
if (BrokenHeader) // Main archive header is corrupt.
if (BrokenHeader || !StartFound) // Main archive header is corrupt or missing.
{
uiMsg(UIERROR_MHEADERBROKEN,FileName);
if (!FailedHeaderDecryption) // If not reported a wrong password already.
uiMsg(UIERROR_MHEADERBROKEN,FileName);
if (!EnableBroken)
return false;
}
@@ -226,9 +231,9 @@ bool Archive::IsArchive(bool EnableBroken)
// first file header to set "comment" flag when reading service header.
// Unless we are in silent mode, we need to know about presence of comment
// immediately after IsArchive call.
if (!SilentOpen || !Encrypted)
if (HeadersLeft && (!SilentOpen || !Encrypted))
{
SaveFilePos SavePos(*this);
int64 SavePos=Tell();
int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;
HEADER_TYPE SaveCurHeaderType=CurHeaderType;
@@ -257,9 +262,10 @@ bool Archive::IsArchive(bool EnableBroken)
CurBlockPos=SaveCurBlockPos;
NextBlockPos=SaveNextBlockPos;
CurHeaderType=SaveCurHeaderType;
Seek(SavePos,SEEK_SET);
}
if (!Volume || FirstVolume)
wcscpy(FirstVolumeName,FileName);
wcsncpyz(FirstVolumeName,FileName,ASIZE(FirstVolumeName));
return true;
}

View File

@@ -20,13 +20,15 @@ enum ADDSUBDATA_FLAGS
ASDF_CRYPTIFHEADERS = 8 // Encrypt data after subheader only in -hp mode.
};
// RAR5 headers must not exceed 2 MB.
#define MAX_HEADER_SIZE_RAR5 0x200000
class Archive:public File
{
private:
void UpdateLatestTime(FileHeader *CurBlock);
void ConvertNameCase(wchar *Name);
void ConvertFileHeader(FileHeader *hd);
void WriteBlock50(HEADER_TYPE HeaderType,BaseBlock *wb,bool OnlySetSize,bool NonFinalWrite);
size_t ReadHeader14();
size_t ReadHeader15();
size_t ReadHeader50();
@@ -34,8 +36,8 @@ class Archive:public File
void RequestArcPassword();
void UnexpEndArcMsg();
void BrokenHeaderMsg();
void UnkEncVerMsg(const wchar *Name);
void UnkEncVerMsg();
void UnkEncVerMsg(const wchar *Name,const wchar *Info);
bool DoGetComment(Array<wchar> *CmtData);
bool ReadCommentData(Array<wchar> *CmtData);
#if !defined(RAR_NOCRYPT)
@@ -45,8 +47,6 @@ class Archive:public File
bool DummyCmd;
RAROptions *Cmd;
int64 RecoverySize;
int RecoveryPercent;
RarTime LatestTime;
int LastReadBlock;
@@ -55,6 +55,7 @@ class Archive:public File
bool SilentOpen;
#ifdef USE_QOPEN
QuickOpen QOpen;
bool ProhibitQOpen;
#endif
public:
Archive(RAROptions *InitCmd=NULL);
@@ -64,8 +65,6 @@ class Archive:public File
size_t SearchBlock(HEADER_TYPE HeaderType);
size_t SearchSubBlock(const wchar *Type);
size_t SearchRR();
void WriteBlock(HEADER_TYPE HeaderType,BaseBlock *wb=NULL,bool OnlySetSize=false,bool NonFinalWrite=false);
void SetBlockSize(HEADER_TYPE HeaderType,BaseBlock *wb=NULL) {WriteBlock(HeaderType,wb,true);}
size_t ReadHeader();
void CheckArc(bool EnableBroken);
void CheckOpen(const wchar *Name);
@@ -82,8 +81,8 @@ class Archive:public File
int64 GetStartPos();
void AddSubData(byte *SrcData,uint64 DataSize,File *SrcFile,
const wchar *Name,uint Flags);
bool ReadSubData(Array<byte> *UnpData,File *DestFile);
HEADER_TYPE GetHeaderType() {return CurHeaderType;};
bool ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode);
HEADER_TYPE GetHeaderType() {return CurHeaderType;}
RAROptions* GetRAROptions() {return Cmd;}
void SetSilentOpen(bool Mode) {SilentOpen=Mode;}
#if 0
@@ -95,6 +94,7 @@ class Archive:public File
void Seek(int64 Offset,int Method);
int64 Tell();
void QOpenUnload() {QOpen.Unload();}
void SetProhibitQOpen(bool Mode) {ProhibitQOpen=Mode;}
#endif
BaseBlock ShortBlock;
@@ -107,10 +107,7 @@ class Archive:public File
FileHeader SubHead;
CommentHeader CommHead;
ProtectHeader ProtectHead;
AVHeader AVHead;
SignHeader SignHead;
UnixOwnersHeader UOHead;
MacFInfoHeader MACHead;
EAHeader EAHead;
StreamHeader StreamHead;

View File

@@ -10,7 +10,10 @@ size_t Archive::ReadHeader()
CurBlockPos=Tell();
size_t ReadSize;
// Other developers asked us to initialize it to suppress "may be used
// uninitialized" warning in code below in some compilers.
size_t ReadSize=0;
switch(Format)
{
#ifndef SFX_MODULE
@@ -26,11 +29,18 @@ size_t Archive::ReadHeader()
break;
}
// It is important to check ReadSize>0 here, because it is normal
// for RAR2 and RAR3 archives without end of archive block to have
// NextBlockPos==CurBlockPos after the end of archive has reached.
if (ReadSize>0 && NextBlockPos<=CurBlockPos)
{
BrokenHeaderMsg();
return 0;
ReadSize=0;
}
if (ReadSize==0)
CurHeaderType=HEAD_UNKNOWN;
return ReadSize;
}
@@ -106,13 +116,24 @@ void Archive::BrokenHeaderMsg()
}
void Archive::UnkEncVerMsg(const wchar *Name)
void Archive::UnkEncVerMsg(const wchar *Name,const wchar *Info)
{
uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name);
uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name,Info);
ErrHandler.SetErrorCode(RARX_WARNING);
}
// Return f in case of signed integer overflow or negative parameters
// or v1+v2 otherwise. We use it for file offsets, which are signed
// for compatibility with off_t in POSIX file functions and third party code.
// Signed integer overflow is the undefined behavior according to
// C++ standard and it causes fuzzers to complain.
inline int64 SafeAdd(int64 v1,int64 v2,int64 f)
{
return v1>=0 && v2>=0 && v1<=MAX_INT64-v2 ? v1+v2 : f;
}
size_t Archive::ReadHeader15()
{
RawRead Raw(this);
@@ -183,7 +204,7 @@ size_t Archive::ReadHeader15()
if (ShortBlock.HeaderType==HEAD_MAIN && (ShortBlock.Flags & MHD_COMMENT)!=0)
{
// Old style (up to RAR 2.9) main archive comment embedded into
// the main archive header found. While we can read the entire
// the main archive header found. While we can read the entire
// ShortBlock.HeadSize here and remove this part of "if", it would be
// waste of memory, because we'll read and process this comment data
// in other function anyway and we do not need them here now.
@@ -209,7 +230,7 @@ size_t Archive::ReadHeader15()
Encrypted=(MainHead.Flags & MHD_PASSWORD)!=0;
Signed=MainHead.PosAV!=0 || MainHead.HighPosAV!=0;
MainHead.CommentInHeader=(MainHead.Flags & MHD_COMMENT)!=0;
// Only for encrypted 3.0+ archives. 2.x archives did not have this
// flag, so for non-encrypted archives, we'll set it later based on
// file attributes.
@@ -236,7 +257,7 @@ size_t Archive::ReadHeader15()
hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5);
hd->CommentInHeader=(hd->Flags & LHD_COMMENT)!=0;
hd->Version=(hd->Flags & LHD_VERSION)!=0;
hd->DataSize=Raw.Get4();
uint LowUnpSize=Raw.Get4();
hd->HostOS=Raw.Get1();
@@ -246,17 +267,22 @@ size_t Archive::ReadHeader15()
uint FileTime=Raw.Get4();
hd->UnpVer=Raw.Get1();
hd->Method=Raw.Get1()-0x30;
size_t NameSize=Raw.Get2();
hd->FileAttr=Raw.Get4();
// RAR15 did not use the special dictionary size to mark dirs.
if (hd->UnpVer<20 && (hd->FileAttr & 0x10)!=0)
hd->Dir=true;
hd->CryptMethod=CRYPT_NONE;
if (hd->Encrypted)
switch(hd->UnpVer)
{
case 13: hd->CryptMethod=CRYPT_RAR13; break;
case 15: hd->CryptMethod=CRYPT_RAR15; break;
case 20:
case 20:
case 26: hd->CryptMethod=CRYPT_RAR20; break;
default: hd->CryptMethod=CRYPT_RAR30; break;
}
@@ -278,7 +304,7 @@ size_t Archive::ReadHeader15()
}
hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0;
hd->LargeFile=(hd->Flags & LHD_LARGE)!=0;
uint HighPackSize,HighUnpSize;
@@ -288,7 +314,7 @@ size_t Archive::ReadHeader15()
HighUnpSize=Raw.Get4();
hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff);
}
else
else
{
HighPackSize=HighUnpSize=0;
// UnpSize equal to 0xffffffff without LHD_LARGE flag indicates
@@ -308,17 +334,17 @@ size_t Archive::ReadHeader15()
if (FileBlock)
{
*hd->FileName=0;
if ((hd->Flags & LHD_UNICODE)!=0)
{
EncodeFileName NameCoder;
size_t Length=strlen(FileName);
Length++;
NameCoder.Decode(FileName,(byte *)FileName+Length,
NameSize-Length,hd->FileName,
ASIZE(hd->FileName));
if (ReadNameSize>Length)
NameCoder.Decode(FileName,ReadNameSize,(byte *)FileName+Length,
ReadNameSize-Length,hd->FileName,
ASIZE(hd->FileName));
}
else
*hd->FileName=0;
if (*hd->FileName==0)
ArcCharToWide(FileName,hd->FileName,ASIZE(hd->FileName),ACTW_OEM);
@@ -343,17 +369,7 @@ size_t Archive::ReadHeader15()
// They are stored after the file name and before salt.
hd->SubData.Alloc(DataSize);
Raw.GetB(&hd->SubData[0],DataSize);
if (hd->CmpName(SUBHEAD_TYPE_RR))
{
byte *D=&hd->SubData[8];
RecoverySize=D[0]+((uint)D[1]<<8)+((uint)D[2]<<16)+((uint)D[3]<<24);
RecoverySize*=512; // Sectors to size.
int64 CurPos=Tell();
RecoveryPercent=ToPercent(RecoverySize,CurPos);
// Round fractional percent exceeding .5 to upper value.
if (ToPercent(RecoverySize+CurPos/200,CurPos)>RecoveryPercent)
RecoveryPercent++;
}
}
if (hd->CmpName(SUBHEAD_TYPE_CMT))
@@ -386,8 +402,8 @@ size_t Archive::ReadHeader15()
if (rmode & 4)
rlt.Second++;
rlt.Reminder=0;
int count=rmode&3;
for (int J=0;J<count;J++)
uint count=rmode&3;
for (uint J=0;J<count;J++)
{
byte CurByte=Raw.Get1();
rlt.Reminder|=(((uint)CurByte)<<((J+3-count)*8));
@@ -397,7 +413,9 @@ size_t Archive::ReadHeader15()
CurTime->SetLocal(&rlt);
}
}
NextBlockPos+=hd->PackSize;
// Set to 0 in case of overflow, so end of ReadHeader cares about it.
NextBlockPos=SafeAdd(NextBlockPos,hd->PackSize,0);
bool CRCProcessedOnly=hd->CommentInHeader;
ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly);
if (hd->HeadCRC!=HeaderCRC)
@@ -434,19 +452,6 @@ size_t Archive::ReadHeader15()
CommHead.Method=Raw.Get1();
CommHead.CommCRC=Raw.Get2();
break;
case HEAD3_SIGN:
*(BaseBlock *)&SignHead=ShortBlock;
SignHead.CreationTime=Raw.Get4();
SignHead.ArcNameSize=Raw.Get2();
SignHead.UserNameSize=Raw.Get2();
break;
case HEAD3_AV:
*(BaseBlock *)&AVHead=ShortBlock;
AVHead.UnpVer=Raw.Get1();
AVHead.Method=Raw.Get1();
AVHead.AVVer=Raw.Get1();
AVHead.AVInfoCRC=Raw.Get4();
break;
case HEAD3_PROTECT:
*(BaseBlock *)&ProtectHead=ShortBlock;
ProtectHead.DataSize=Raw.Get4();
@@ -455,9 +460,8 @@ size_t Archive::ReadHeader15()
ProtectHead.TotalBlocks=Raw.Get4();
Raw.GetB(ProtectHead.Mark,8);
NextBlockPos+=ProtectHead.DataSize;
RecoverySize=ProtectHead.RecSectors*512;
break;
case HEAD3_OLDSERVICE:
case HEAD3_OLDSERVICE: // RAR 2.9 and earlier.
*(BaseBlock *)&SubBlockHead=ShortBlock;
SubBlockHead.DataSize=Raw.Get4();
NextBlockPos+=SubBlockHead.DataSize;
@@ -478,13 +482,6 @@ size_t Archive::ReadHeader15()
UOHead.OwnerName[UOHead.OwnerNameSize]=0;
UOHead.GroupName[UOHead.GroupNameSize]=0;
break;
case MAC_HEAD:
*(SubBlockHeader *)&MACHead=SubBlockHead;
MACHead.fileType=Raw.Get4();
MACHead.fileCreator=Raw.Get4();
break;
case EA_HEAD:
case BEEA_HEAD:
case NTACL_HEAD:
*(SubBlockHeader *)&EAHead=SubBlockHead;
EAHead.UnpSize=Raw.Get4();
@@ -512,7 +509,7 @@ size_t Archive::ReadHeader15()
NextBlockPos+=Raw.Get4();
break;
}
ushort HeaderCRC=Raw.GetCRC15(false);
// Old AV header does not have header CRC properly set.
@@ -524,7 +521,6 @@ size_t Archive::ReadHeader15()
{
// Last 7 bytes of recovered volume can contain zeroes, because
// REV files store its own information (volume number, etc.) here.
SaveFilePos SavePos(*this);
int64 Length=Tell();
Seek(Length-7,SEEK_SET);
Recovered=true;
@@ -546,12 +542,6 @@ size_t Archive::ReadHeader15()
}
}
if (NextBlockPos<=CurBlockPos)
{
BrokenHeaderMsg();
return 0;
}
return Raw.Size();
}
@@ -567,7 +557,6 @@ size_t Archive::ReadHeader50()
#if defined(RAR_NOCRYPT)
return 0;
#else
RequestArcPassword();
byte HeadersInitV[SIZE_INITV];
if (Read(HeadersInitV,SIZE_INITV)!=SIZE_INITV)
@@ -576,15 +565,48 @@ size_t Archive::ReadHeader50()
return 0;
}
byte PswCheck[SIZE_PSWCHECK];
HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck);
// Verify password validity.
if (CryptHead.UsePswCheck && memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0)
// We repeat the password request only for manually entered passwords
// and not for -p<pwd>. Wrong password can be intentionally provided
// in -p<pwd> to not stop batch processing for encrypted archives.
bool GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet();
while (true) // Repeat the password prompt for wrong passwords.
{
uiMsg(UIERROR_BADPSW,FileName);
FailedHeaderDecryption=true;
ErrHandler.SetErrorCode(RARX_BADPWD);
return 0;
RequestArcPassword();
byte PswCheck[SIZE_PSWCHECK];
HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck);
// Verify password validity.
if (CryptHead.UsePswCheck && memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0)
{
if (GlobalPassword) // For -p<pwd> or Ctrl+P.
{
// This message is used by Android GUI to reset cached passwords.
// Update appropriate code if changed.
uiMsg(UIERROR_BADPSW,FileName,FileName);
FailedHeaderDecryption=true;
ErrHandler.SetErrorCode(RARX_BADPWD);
return 0;
}
else // For passwords entered manually.
{
// This message is used by Android GUI and Windows GUI and SFX to
// reset cached passwords. Update appropriate code if changed.
uiMsg(UIWAIT_BADPSW,FileName,FileName);
Cmd->Password.Clean();
}
#ifdef RARDLL
// Avoid new requests for unrar.dll to prevent the infinite loop
// if app always returns the same password.
ErrHandler.SetErrorCode(RARX_BADPWD);
Cmd->DllError=ERAR_BAD_PASSWORD;
ErrHandler.Exit(RARX_BADPWD);
#else
continue; // Request a password again.
#endif
}
break;
}
Raw.SetCrypt(&HeadersCrypt);
@@ -592,8 +614,8 @@ size_t Archive::ReadHeader50()
}
// Header size must not occupy more than 3 variable length integer bytes
// resulting in 2 MB maximum header size, so here we read 4 byte CRC32
// followed by 3 bytes or less of header size.
// resulting in 2 MB maximum header size (MAX_HEADER_SIZE_RAR5),
// so here we read 4 byte CRC32 followed by 3 bytes or less of header size.
const size_t FirstReadSize=7; // Smallest possible block size.
if (Raw.Read(FirstReadSize)<FirstReadSize)
{
@@ -621,7 +643,7 @@ size_t Archive::ReadHeader50()
BrokenHeaderMsg();
return 0;
}
Raw.Read(SizeToRead);
if (Raw.Size()<HeaderSize)
@@ -654,7 +676,7 @@ size_t Archive::ReadHeader50()
return 0;
}
}
uint64 ExtraSize=0;
if ((ShortBlock.Flags & HFL_EXTRA)!=0)
{
@@ -670,7 +692,9 @@ size_t Archive::ReadHeader50()
if ((ShortBlock.Flags & HFL_DATA)!=0)
DataSize=Raw.GetV();
NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize)+DataSize;
NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize);
// Set to 0 in case of overflow, so end of ReadHeader cares about it.
NextBlockPos=SafeAdd(NextBlockPos,DataSize,0);
switch(ShortBlock.HeaderType)
{
@@ -680,7 +704,9 @@ size_t Archive::ReadHeader50()
uint CryptVersion=(uint)Raw.GetV();
if (CryptVersion>CRYPT_VERSION)
{
UnkEncVerMsg(FileName);
wchar Info[20];
swprintf(Info,ASIZE(Info),L"h%u",CryptVersion);
UnkEncVerMsg(FileName,Info);
return 0;
}
uint EncFlags=(uint)Raw.GetV();
@@ -688,9 +714,12 @@ size_t Archive::ReadHeader50()
CryptHead.Lg2Count=Raw.Get1();
if (CryptHead.Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
{
UnkEncVerMsg(FileName);
wchar Info[20];
swprintf(Info,ASIZE(Info),L"hc%u",CryptHead.Lg2Count);
UnkEncVerMsg(FileName,Info);
return 0;
}
Raw.GetB(CryptHead.Salt,SIZE_SALT50);
if (CryptHead.UsePswCheck)
{
@@ -734,14 +763,14 @@ size_t Archive::ReadHeader50()
ProcessExtra50(&Raw,(size_t)ExtraSize,&MainHead);
#ifdef USE_QOPEN
if (MainHead.Locator && MainHead.QOpenOffset>0 && Cmd->QOpenMode!=QOPEN_NONE)
if (!ProhibitQOpen && MainHead.Locator && MainHead.QOpenOffset>0 && Cmd->QOpenMode!=QOPEN_NONE)
{
// We seek to QO block in the end of archive when processing
// QOpen.Load, so we need to preserve current block positions
// to not break normal archive processing by calling function.
int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;
HEADER_TYPE SaveCurHeaderType=CurHeaderType;
QOpen.Init(this,false);
QOpen.Load(MainHead.QOpenOffset);
@@ -766,7 +795,7 @@ size_t Archive::ReadHeader50()
hd->PackSize=DataSize;
hd->FileFlags=(uint)Raw.GetV();
hd->UnpSize=Raw.GetV();
hd->UnknownUnpSize=(hd->FileFlags & FHFL_UNPUNKNOWN)!=0;
if (hd->UnknownUnpSize)
hd->UnpSize=INT64NDF;
@@ -793,6 +822,8 @@ size_t Archive::ReadHeader50()
// but it was already used in RAR 1.5 and Unpack needs to distinguish
// them.
hd->UnpVer=(CompInfo & 0x3f) + 50;
if (hd->UnpVer!=50) // Only 5.0 compression is known now.
hd->UnpVer=VER_UNKNOWN;
hd->HostOS=(byte)Raw.GetV();
size_t NameSize=(size_t)Raw.GetV();
@@ -851,7 +882,7 @@ size_t Archive::ReadHeader50()
RecoverySize=Header.RecSectionSize*Header.RecCount;
}
#endif
if (BadCRC) // Add the file name to broken header message displayed above.
uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName);
}
@@ -868,11 +899,6 @@ size_t Archive::ReadHeader50()
break;
}
if (NextBlockPos<=CurBlockPos)
{
BrokenHeaderMsg();
return 0;
}
return Raw.Size();
}
@@ -908,11 +934,10 @@ void Archive::RequestArcPassword()
ErrHandler.Exit(RARX_USERBREAK);
}
#else
if (!uiGetPassword(UIPASSWORD_ARCHIVE,FileName,&Cmd->Password) ||
!Cmd->Password.IsSet())
if (!uiGetPassword(UIPASSWORD_ARCHIVE,FileName,&Cmd->Password))
{
Close();
uiMsg(UIERROR_INCERRCOUNT);
uiMsg(UIERROR_INCERRCOUNT); // Prevent archive deleting if delete after extraction is on.
ErrHandler.Exit(RARX_USERBREAK);
}
#endif
@@ -931,14 +956,17 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
Raw->SetPos(ExtraStart);
while (Raw->DataLeft()>=2)
{
int64 FieldSize=Raw->GetV();
if (FieldSize==0 || Raw->DataLeft()==0 || FieldSize>(int64)Raw->DataLeft())
int64 FieldSize=Raw->GetV(); // Needs to be signed for check below and can be negative.
if (FieldSize<=0 || Raw->DataLeft()==0 || FieldSize>(int64)Raw->DataLeft())
break;
size_t NextPos=size_t(Raw->GetPos()+FieldSize);
uint64 FieldType=Raw->GetV();
FieldSize=int64(NextPos-Raw->GetPos()); // Field size without size and type fields.
if (FieldSize<0) // FieldType is longer than expected extra field size.
break;
if (bb->HeaderType==HEAD_MAIN)
{
MainHeader *hd=(MainHeader *)bb;
@@ -970,8 +998,12 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
{
FileHeader *hd=(FileHeader *)bb;
uint EncVersion=(uint)Raw->GetV();
if (EncVersion > CRYPT_VERSION)
UnkEncVerMsg(hd->FileName);
if (EncVersion>CRYPT_VERSION)
{
wchar Info[20];
swprintf(Info,ASIZE(Info),L"x%u",EncVersion);
UnkEncVerMsg(hd->FileName,Info);
}
else
{
uint Flags=(uint)Raw->GetV();
@@ -979,7 +1011,11 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0;
hd->Lg2Count=Raw->Get1();
if (hd->Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX)
UnkEncVerMsg(hd->FileName);
{
wchar Info[20];
swprintf(Info,ASIZE(Info),L"xc%u",hd->Lg2Count);
UnkEncVerMsg(hd->FileName,Info);
}
Raw->GetB(hd->Salt,SIZE_SALT50);
Raw->GetB(hd->InitV,SIZE_INITV);
if (hd->UsePswCheck)
@@ -1070,7 +1106,7 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
wchar VerText[20];
swprintf(VerText,ASIZE(VerText),L";%u",Version);
wcsncatz(FileHead.FileName,VerText,ASIZE(FileHead.FileName));
wcsncatz(hd->FileName,VerText,ASIZE(hd->FileName));
}
}
break;
@@ -1136,7 +1172,7 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
// required. It did not hurt extraction, because UnRAR 5.21
// and earlier ignored this field and set FieldSize as data left
// in entire extra area. But now we set the correct field size
// and set FieldSize based on actual extra record size,
// and set FieldSize based on the actual extra record size,
// so we need to adjust it for those older archives here.
// FHEXTRA_SUBDATA in those archives always belongs to HEAD_SERVICE
// and always is last in extra area. So since its size is by 1
@@ -1145,6 +1181,9 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
if (bb->HeaderType==HEAD_SERVICE && Raw->Size()-NextPos==1)
FieldSize++;
// We cannot allocate too much memory here, because above
// we check FieldSize againt Raw size and we control that Raw size
// is sensible when reading headers.
hd->SubData.Alloc((size_t)FieldSize);
Raw->GetB(hd->SubData.Addr(0),(size_t)FieldSize);
}
@@ -1168,6 +1207,8 @@ size_t Archive::ReadHeader14()
byte Mark[4];
Raw.GetB(Mark,4);
uint HeadSize=Raw.Get2();
if (HeadSize<7)
return false;
byte Flags=Raw.Get1();
NextBlockPos=CurBlockPos+HeadSize;
CurHeaderType=HEAD_MAIN;
@@ -1189,6 +1230,8 @@ size_t Archive::ReadHeader14()
FileHead.FileHash.Type=HASH_RAR14;
FileHead.FileHash.CRC32=Raw.Get2();
FileHead.HeadSize=Raw.Get2();
if (FileHead.HeadSize<21)
return false;
uint FileTime=Raw.Get4();
FileHead.FileAttr=Raw.Get1();
FileHead.Flags=Raw.Get1()|LONG_BLOCK;
@@ -1203,17 +1246,23 @@ size_t Archive::ReadHeader14()
FileHead.PackSize=FileHead.DataSize;
FileHead.WinSize=0x10000;
FileHead.Dir=(FileHead.FileAttr & 0x10)!=0;
FileHead.HostOS=HOST_MSDOS;
FileHead.HSType=HSYS_WINDOWS;
FileHead.mtime.SetDos(FileTime);
Raw.Read(NameSize);
char FileName[NM];
Raw.GetB((byte *)FileName,Min(NameSize,ASIZE(FileName)));
FileName[NameSize]=0;
size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
Raw.GetB((byte *)FileName,ReadNameSize);
FileName[ReadNameSize]=0;
IntToExt(FileName,FileName,ASIZE(FileName));
CharToWide(FileName,FileHead.FileName,ASIZE(FileHead.FileName));
ConvertNameCase(FileHead.FileName);
ConvertFileHeader(&FileHead);
if (Raw.Size()!=0)
NextBlockPos=CurBlockPos+FileHead.HeadSize+FileHead.PackSize;
@@ -1260,7 +1309,7 @@ void Archive::ConvertAttributes()
if (mask == (mode_t) -1)
{
// umask call returns the current umask value. Argument (022) is not
// umask call returns the current umask value. Argument (022) is not
// really important here.
mask = umask(022);
@@ -1308,8 +1357,6 @@ void Archive::ConvertAttributes()
void Archive::ConvertFileHeader(FileHeader *hd)
{
if (Format==RARFMT15 && hd->UnpVer<20 && (hd->FileAttr & 0x10))
hd->Dir=true;
if (hd->HSType==HSYS_UNKNOWN)
if (hd->Dir)
hd->FileAttr=0x10;
@@ -1339,8 +1386,8 @@ void Archive::ConvertFileHeader(FileHeader *hd)
// ':' in file names is allowed in Unix, but not in Windows.
// Even worse, file data will be written to NTFS stream on NTFS,
// so automatic name correction on file create error in extraction
// routine does not work. In Windows and DOS versions we better
// so automatic name correction on file create error in extraction
// routine does not work. In Windows and DOS versions we better
// replace ':' now.
if (*s==':')
*s='_';
@@ -1369,7 +1416,7 @@ int64 Archive::GetStartPos()
}
bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile)
bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode)
{
if (BrokenHeader)
{
@@ -1417,6 +1464,7 @@ bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile)
SubDataIO.SetPackedSizeToRead(SubHead.PackSize);
SubDataIO.EnableShowProgress(false);
SubDataIO.SetFiles(this,DestFile);
SubDataIO.SetTestMode(TestMode);
SubDataIO.UnpVolume=SubHead.SplitAfter;
SubDataIO.SetSubHeader(&SubHead,NULL);
Unpack.SetDestSize(SubHead.UnpSize);

View File

@@ -3,6 +3,7 @@
#define _RAR_BLAKE2_
#define BLAKE2_DIGEST_SIZE 32
#define BLAKE2_THREADS_NUMBER 8
enum blake2s_constant
{

View File

@@ -1,5 +1,8 @@
#include "rar.hpp"
#include "cmdfilter.cpp"
#include "cmdmix.cpp"
CommandData::CommandData()
{
Init();
@@ -13,6 +16,7 @@ void CommandData::Init()
*Command=0;
*ArcName=0;
FileLists=false;
NoMoreSwitches=false;
ListMode=RCLM_AUTO;
@@ -96,7 +100,7 @@ void CommandData::ParseArg(wchar *Arg)
else
if (*Command==0)
{
wcsncpy(Command,Arg,ASIZE(Command));
wcsncpyz(Command,Arg,ASIZE(Command));
*Command=toupperw(*Command);
@@ -119,6 +123,7 @@ void CommandData::ParseArg(wchar *Arg)
wchar CmdChar=toupperw(*Command);
bool Add=wcschr(L"AFUM",CmdChar)!=NULL;
bool Extract=CmdChar=='X' || CmdChar=='E';
bool Repair=CmdChar=='R' && Command[1]==0;
if (EndSeparator && !Add)
wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
else
@@ -129,25 +134,15 @@ void CommandData::ParseArg(wchar *Arg)
FindData FileData;
bool Found=FindFile::FastFind(Arg,&FileData);
if ((!Found || ListMode==RCLM_ACCEPT_LISTS) &&
ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg))
ListMode!=RCLM_REJECT_LISTS && *Arg=='@' && !IsWildcard(Arg+1))
{
FileLists=true;
RAR_CHARSET Charset=FilelistCharset;
#if defined(_WIN_ALL)
// for compatibility reasons we use OEM encoding
// in Win32 console version by default
// if (Charset==RCH_DEFAULT)
// Charset=RCH_OEM;
#endif
ReadTextFile(Arg+1,&FileArgs,false,true,Charset,true,true,true);
ReadTextFile(Arg+1,&FileArgs,false,true,FilelistCharset,true,true,true);
}
else
if (Found && FileData.IsDir && Extract && *ExtrPath==0)
else // We use 'destpath\' when extracting and reparing.
if (Found && FileData.IsDir && (Extract || Repair) && *ExtrPath==0)
{
wcsncpyz(ExtrPath,Arg,ASIZE(ExtrPath));
AddEndSlash(ExtrPath,ASIZE(ExtrPath));
@@ -248,7 +243,7 @@ void CommandData::ReadConfig()
if (C0=='R' && (C1=='R' || C1=='V'))
Cmd[2]=0;
wchar SwName[16+ASIZE(Cmd)];
swprintf(SwName,ASIZE(SwName),L"switches_%s=",Cmd);
swprintf(SwName,ASIZE(SwName),L"switches_%ls=",Cmd);
size_t Length=wcslen(SwName);
if (wcsnicomp(Str,SwName,Length)==0)
ProcessSwitchesString(Str+Length);
@@ -289,17 +284,24 @@ void CommandData::ProcessSwitch(const wchar *Switch)
ClearArc=true;
break;
case 'D':
AppendArcNameToPath=true;
if (Switch[2]==0)
AppendArcNameToPath=APPENDARCNAME_DESTPATH;
else
if (Switch[2]=='1')
AppendArcNameToPath=APPENDARCNAME_OWNDIR;
break;
#ifndef SFX_MODULE
case 'G':
if (Switch[2]=='-' && Switch[3]==0)
GenerateArcName=0;
else
{
GenerateArcName=true;
wcsncpyz(GenerateMask,Switch+2,ASIZE(GenerateMask));
}
if (toupperw(Switch[2])=='F')
wcsncpyz(DefGenerateMask,Switch+3,ASIZE(DefGenerateMask));
else
{
GenerateArcName=true;
wcsncpyz(GenerateMask,Switch+2,ASIZE(GenerateMask));
}
break;
#endif
case 'I':
@@ -311,7 +313,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
AddArcOnly=true;
break;
case 'P':
wcscpy(ArcPath,Switch+2);
wcsncpyz(ArcPath,Switch+2,ASIZE(ArcPath));
break;
case 'S':
SyncFiles=true;
@@ -374,11 +376,11 @@ void CommandData::ProcessSwitch(const wchar *Switch)
default:
if (Switch[1]=='+')
{
InclFileAttr|=GetExclAttr(Switch+2);
InclFileAttr|=GetExclAttr(Switch+2,InclDir);
InclAttrSet=true;
}
else
ExclFileAttr|=GetExclAttr(Switch+1);
ExclFileAttr|=GetExclAttr(Switch+1,ExclDir);
break;
}
break;
@@ -416,14 +418,17 @@ void CommandData::ProcessSwitch(const wchar *Switch)
wcsncpyz(LogName,Switch[4]!=0 ? Switch+4:DefLogName,ASIZE(LogName));
break;
}
if (wcsicomp(Switch+1,L"SND")==0)
if (wcsnicomp(Switch+1,L"SND",3)==0)
{
Sound=true;
Sound=Switch[4]=='-' ? SOUND_NOTIFY_OFF : SOUND_NOTIFY_ON;
break;
}
if (wcsicomp(Switch+1,L"ERR")==0)
{
MsgStream=MSG_STDERR;
// Set it immediately when parsing the command line, so it also
// affects messages issued while parsing the command line.
SetConsoleMsgStream(MSG_STDERR);
break;
}
if (wcsnicomp(Switch+1,L"EML",3)==0)
@@ -431,9 +436,15 @@ void CommandData::ProcessSwitch(const wchar *Switch)
wcsncpyz(EmailTo,Switch[4]!=0 ? Switch+4:L"@",ASIZE(EmailTo));
break;
}
if (wcsicomp(Switch+1,L"M")==0)
{
MoreInfo=true;
break;
}
if (wcsicomp(Switch+1,L"NUL")==0)
{
MsgStream=MSG_NULL;
SetConsoleMsgStream(MSG_NULL);
break;
}
if (toupperw(Switch[1])=='D')
@@ -443,6 +454,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
{
case 'Q':
MsgStream=MSG_ERRONLY;
SetConsoleMsgStream(MSG_ERRONLY);
break;
case 'C':
DisableCopyright=true;
@@ -456,9 +468,24 @@ void CommandData::ProcessSwitch(const wchar *Switch)
}
break;
}
if (wcsicomp(Switch+1,L"OFF")==0)
if (wcsnicomp(Switch+1,L"OFF",3)==0)
{
Shutdown=true;
switch(Switch[4])
{
case 0:
case '1':
Shutdown=POWERMODE_OFF;
break;
case '2':
Shutdown=POWERMODE_HIBERNATE;
break;
case '3':
Shutdown=POWERMODE_SLEEP;
break;
case '4':
Shutdown=POWERMODE_RESTART;
break;
}
break;
}
if (wcsicomp(Switch+1,L"VER")==0)
@@ -574,19 +601,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
{
StringList *Args=toupperw(Switch[0])=='N' ? &InclArgs:&ExclArgs;
if (Switch[1]=='@' && !IsWildcard(Switch))
{
RAR_CHARSET Charset=FilelistCharset;
#if defined(_WIN_ALL)
// for compatibility reasons we use OEM encoding
// in Win32 console version by default
// if (Charset==RCH_DEFAULT)
// Charset=RCH_OEM;
#endif
ReadTextFile(Switch+2,Args,false,true,Charset,true,true,true);
}
ReadTextFile(Switch+2,Args,false,true,FilelistCharset,true,true,true);
else
Args->AddString(Switch+1);
}
@@ -783,6 +798,9 @@ void CommandData::ProcessSwitch(const wchar *Switch)
AlreadyBad=true;
break;
}
// Set it immediately when parsing the command line, so it also
// affects messages issued while parsing the command line.
SetConsoleRedirectCharset(RedirectCharset);
}
break;
@@ -798,51 +816,19 @@ void CommandData::ProcessSwitch(const wchar *Switch)
ArcTime=ARCTIME_LATEST;
break;
case 'O':
FileTimeBefore.SetAgeText(Switch+2);
SetTimeFilters(Switch+2,true,true);
break;
case 'N':
FileTimeAfter.SetAgeText(Switch+2);
SetTimeFilters(Switch+2,false,true);
break;
case 'B':
FileTimeBefore.SetIsoText(Switch+2);
SetTimeFilters(Switch+2,true,false);
break;
case 'A':
FileTimeAfter.SetIsoText(Switch+2);
SetTimeFilters(Switch+2,false,false);
break;
case 'S':
{
EXTTIME_MODE Mode=EXTTIME_HIGH3;
bool CommonMode=Switch[2]>='0' && Switch[2]<='4';
if (CommonMode)
Mode=(EXTTIME_MODE)(Switch[2]-'0');
if (Mode==EXTTIME_HIGH1 || Mode==EXTTIME_HIGH2) // '2' and '3' not supported anymore.
Mode=EXTTIME_HIGH3;
if (Switch[2]=='-')
Mode=EXTTIME_NONE;
if (CommonMode || Switch[2]=='-' || Switch[2]=='+' || Switch[2]==0)
xmtime=xctime=xatime=Mode;
else
{
if (Switch[3]>='0' && Switch[3]<='4')
Mode=(EXTTIME_MODE)(Switch[3]-'0');
if (Mode==EXTTIME_HIGH1 || Mode==EXTTIME_HIGH2) // '2' and '3' not supported anymore.
Mode=EXTTIME_HIGH3;
if (Switch[3]=='-')
Mode=EXTTIME_NONE;
switch(toupperw(Switch[2]))
{
case 'M':
xmtime=Mode;
break;
case 'C':
xctime=Mode;
break;
case 'A':
xatime=Mode;
break;
}
}
}
SetStoreTimeMode(Switch+2);
break;
case '-':
Test=false;
@@ -890,7 +876,7 @@ void CommandData::ProcessSwitch(const wchar *Switch)
if (Switch[1]==0)
{
// If comment file is not specified, we read data from stdin.
wcscpy(CommentFile,L"stdin");
wcsncpyz(CommentFile,L"stdin",ASIZE(CommentFile));
}
else
wcsncpyz(CommentFile,Switch+1,ASIZE(CommentFile));
@@ -915,309 +901,6 @@ void CommandData::BadSwitch(const wchar *Switch)
#endif
void CommandData::OutTitle()
{
if (BareOutput || DisableCopyright)
return;
#if defined(__GNUC__) && defined(SFX_MODULE)
mprintf(St(MCopyrightS));
#else
#ifndef SILENT
static bool TitleShown=false;
if (TitleShown)
return;
TitleShown=true;
wchar Version[80];
if (RARVER_BETA!=0)
swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA);
else
swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR);
#if defined(_WIN_32) || defined(_WIN_64)
wcsncatz(Version,L" ",ASIZE(Version));
#endif
#ifdef _WIN_32
wcsncatz(Version,St(Mx86),ASIZE(Version));
#endif
#ifdef _WIN_64
wcsncatz(Version,St(Mx64),ASIZE(Version));
#endif
if (PrintVersion)
{
mprintf(L"%s",Version);
exit(0);
}
mprintf(St(MUCopyright),Version,RARVER_YEAR);
#endif
#endif
}
inline bool CmpMSGID(MSGID i1,MSGID i2)
{
#ifdef MSGID_INT
return i1==i2;
#else
// If MSGID is const char*, we cannot compare pointers only.
// Pointers to different instances of same string can differ,
// so we need to compare complete strings.
return wcscmp(i1,i2)==0;
#endif
}
void CommandData::OutHelp(RAR_EXIT ExitCode)
{
#if !defined(SILENT)
OutTitle();
static MSGID Help[]={
#ifdef SFX_MODULE
// Console SFX switches definition.
MCHelpCmd,MSHelpCmdE,MSHelpCmdT,MSHelpCmdV
#else
// UnRAR switches definition.
MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL,
MCHelpCmdP,MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,MCHelpSwm,
MCHelpSwAT,MCHelpSwAC,MCHelpSwAD,MCHelpSwAG,MCHelpSwAI,MCHelpSwAP,
MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU,
MCHelpSwDH,MCHelpSwEP,MCHelpSwEP3,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR,
MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwN,MCHelpSwNa,MCHelpSwNal,
MCHelpSwO,MCHelpSwOC,MCHelpSwOL,MCHelpSwOR,MCHelpSwOW,MCHelpSwP,
MCHelpSwPm,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSL,MCHelpSwSM,
MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU,
MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal,
MCHelpSwY
#endif
};
for (uint I=0;I<ASIZE(Help);I++)
{
#ifndef SFX_MODULE
if (CmpMSGID(Help[I],MCHelpSwV))
continue;
#ifndef _WIN_ALL
static MSGID Win32Only[]={
MCHelpSwIEML,MCHelpSwVD,MCHelpSwAO,MCHelpSwOS,MCHelpSwIOFF,
MCHelpSwEP2,MCHelpSwOC,MCHelpSwONI,MCHelpSwDR,MCHelpSwRI
};
bool Found=false;
for (int J=0;J<sizeof(Win32Only)/sizeof(Win32Only[0]);J++)
if (CmpMSGID(Help[I],Win32Only[J]))
{
Found=true;
break;
}
if (Found)
continue;
#endif
#if !defined(_UNIX) && !defined(_WIN_ALL)
if (CmpMSGID(Help[I],MCHelpSwOW))
continue;
#endif
#if !defined(_WIN_ALL) && !defined(_EMX)
if (CmpMSGID(Help[I],MCHelpSwAC))
continue;
#endif
#ifndef SAVE_LINKS
if (CmpMSGID(Help[I],MCHelpSwOL))
continue;
#endif
#ifndef RAR_SMP
if (CmpMSGID(Help[I],MCHelpSwMT))
continue;
#endif
#endif
mprintf(St(Help[I]));
}
mprintf(L"\n");
ErrHandler.Exit(ExitCode);
#endif
}
// Return 'true' if we need to exclude the file from processing as result
// of -x switch. If CheckInclList is true, we also check the file against
// the include list created with -n switch.
bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList)
{
if (CheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return true;
if (!CheckInclList || InclArgs.ItemsCount()==0)
return false;
if (CheckArgs(&InclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return false;
return true;
}
bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode)
{
wchar *Name=ConvertPath(CheckName,NULL);
wchar FullName[NM];
wchar CurMask[NM];
*FullName=0;
Args->Rewind();
while (Args->GetString(CurMask,ASIZE(CurMask)))
{
wchar *LastMaskChar=PointToLastChar(CurMask);
bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only.
if (Dir)
{
// CheckName is a directory.
if (DirMask)
{
// We process the directory and have the directory exclusion mask.
// So let's convert "mask\" to "mask" and process it normally.
*LastMaskChar=0;
}
else
{
// REMOVED, we want -npath\* to match empty folders too.
// If mask has wildcards in name part and does not have the trailing
// '\' character, we cannot use it for directories.
// if (IsWildcard(PointToName(CurMask)))
// continue;
}
}
else
{
// If we process a file inside of directory excluded by "dirmask\".
// we want to exclude such file too. So we convert "dirmask\" to
// "dirmask\*". It is important for operations other than archiving
// with -x. When archiving with -x, directory matched by "dirmask\"
// is excluded from further scanning.
if (DirMask)
wcsncatz(CurMask,L"*",ASIZE(CurMask));
}
#ifndef SFX_MODULE
if (CheckFullPath && IsFullPath(CurMask))
{
// We do not need to do the special "*\" processing here, because
// unlike the "else" part of this "if", now we convert names to full
// format, so they all include the path, which is matched by "*\"
// correctly. Moreover, removing "*\" from mask would break
// the comparison, because now all names have the path.
if (*FullName==0)
ConvertNameToFull(CheckName,FullName,ASIZE(FullName));
if (CmpName(CurMask,FullName,MatchMode))
return true;
}
else
#endif
{
wchar NewName[NM+2],*CurName=Name;
// Important to convert before "*\" check below, so masks like
// d:*\something are processed properly.
wchar *CmpMask=ConvertPath(CurMask,NULL);
if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1]))
{
// We want "*\name" to match 'name' not only in subdirectories,
// but also in the current directory. We convert the name
// from 'name' to '.\name' to be matched by "*\" part even if it is
// in current directory.
NewName[0]='.';
NewName[1]=CPATHDIVIDER;
wcsncpyz(NewName+2,Name,ASIZE(NewName)-2);
CurName=NewName;
}
if (CmpName(CmpMask,CurName,MatchMode))
return true;
}
}
return false;
}
#ifndef SFX_MODULE
// Now this function performs only one task and only in Windows version:
// it skips symlinks to directories if -e1024 switch is specified.
// Symlinks are skipped in ScanTree class, so their entire contents
// is skipped too. Without this function we would check the attribute
// only directly before archiving, so we would skip the symlink record,
// but not the contents of symlinked directory.
bool CommandData::ExclDirByAttr(uint FileAttr)
{
#ifdef _WIN_ALL
if ((FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0 &&
(ExclFileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0)
return true;
#endif
return false;
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::TimeCheck(RarTime &ft)
{
if (FileTimeBefore.IsSet() && ft>=FileTimeBefore)
return true;
if (FileTimeAfter.IsSet() && ft<=FileTimeAfter)
return true;
return false;
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::SizeCheck(int64 Size)
{
if (FileSizeLess!=INT64NDF && Size>=FileSizeLess)
return(true);
if (FileSizeMore!=INT64NDF && Size<=FileSizeMore)
return(true);
return(false);
}
#endif
int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
wchar *MatchedArg,uint MatchedArgSize)
{
if (MatchedArg!=NULL && MatchedArgSize>0)
*MatchedArg=0;
if (wcslen(FileHead.FileName)>=NM)
return 0;
bool Dir=FileHead.Dir;
if (ExclCheck(FileHead.FileName,Dir,false,true))
return 0;
#ifndef SFX_MODULE
if (TimeCheck(FileHead.mtime))
return 0;
if ((FileHead.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0)
return 0;
if (!Dir && SizeCheck(FileHead.UnpSize))
return 0;
#endif
wchar *ArgName;
FileArgs.Rewind();
for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++)
if (CmpName(ArgName,FileHead.FileName,MatchType))
{
if (ExactMatch!=NULL)
*ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0;
if (MatchedArg!=NULL)
wcsncpyz(MatchedArg,ArgName,MatchedArgSize);
return StringCount;
}
return 0;
}
void CommandData::ProcessCommand()
{
#ifndef SFX_MODULE
@@ -1248,7 +931,10 @@ void CommandData::ProcessCommand()
if (wcschr(L"AFUMD",*Command)==NULL)
{
if (GenerateArcName)
GenerateArchiveName(ArcName,ASIZE(ArcName),GenerateMask,false);
{
const wchar *Mask=*GenerateMask!=0 ? GenerateMask:DefGenerateMask;
GenerateArchiveName(ArcName,ASIZE(ArcName),Mask,false);
}
StringList ArcMasks;
ArcMasks.AddString(ArcName);
@@ -1267,7 +953,6 @@ void CommandData::ProcessCommand()
case 'X':
case 'E':
case 'T':
case 'I':
{
CmdExtract Extract(this);
Extract.DoExtract();
@@ -1310,7 +995,7 @@ bool CommandData::IsSwitch(int Ch)
#ifndef SFX_MODULE
uint CommandData::GetExclAttr(const wchar *Str)
uint CommandData::GetExclAttr(const wchar *Str,bool &Dir)
{
if (IsDigit(*Str))
return wcstol(Str,NULL,0);
@@ -1320,10 +1005,10 @@ uint CommandData::GetExclAttr(const wchar *Str)
{
switch(toupperw(*Str))
{
#ifdef _UNIX
case 'D':
Attr|=S_IFDIR;
Dir=true;
break;
#ifdef _UNIX
case 'V':
Attr|=S_IFCHR;
break;
@@ -1337,9 +1022,6 @@ uint CommandData::GetExclAttr(const wchar *Str)
case 'S':
Attr|=0x4;
break;
case 'D':
Attr|=0x10;
break;
case 'A':
Attr|=0x20;
break;

View File

@@ -6,13 +6,19 @@
enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS};
enum IS_PROCESS_FILE_FLAGS {IPFF_EXCLUDE_PARENT=1};
class CommandData:public RAROptions
{
private:
void ProcessSwitchesString(const wchar *Str);
void ProcessSwitch(const wchar *Switch);
void BadSwitch(const wchar *Switch);
uint GetExclAttr(const wchar *Str);
uint GetExclAttr(const wchar *Str,bool &Dir);
#if !defined(SFX_MODULE)
void SetTimeFilters(const wchar *Mod,bool Before,bool Age);
void SetStoreTimeMode(const wchar *S);
#endif
bool FileLists;
bool NoMoreSwitches;
@@ -34,11 +40,11 @@ class CommandData:public RAROptions
bool ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList);
static bool CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode);
bool ExclDirByAttr(uint FileAttr);
bool TimeCheck(RarTime &ft);
bool TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta);
bool SizeCheck(int64 Size);
bool AnyFiltersActive();
int IsProcessFile(FileHeader &FileHead,bool *ExactMatch=NULL,int MatchType=MATCH_WILDSUBPATH,
wchar *MatchedArg=NULL,uint MatchedArgSize=0);
int IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
bool Flags,wchar *MatchedArg,uint MatchedArgSize);
void ProcessCommand();
void AddArcName(const wchar *Name);
bool GetArcName(wchar *Name,int MaxSize);

352
unrar/cmdfilter.cpp Normal file
View File

@@ -0,0 +1,352 @@
// Return 'true' if we need to exclude the file from processing as result
// of -x switch. If CheckInclList is true, we also check the file against
// the include list created with -n switch.
bool CommandData::ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList)
{
if (CheckArgs(&ExclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return true;
if (!CheckInclList || InclArgs.ItemsCount()==0)
return false;
if (CheckArgs(&InclArgs,Dir,CheckName,CheckFullPath,MATCH_WILDSUBPATH))
return false;
return true;
}
bool CommandData::CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode)
{
wchar *Name=ConvertPath(CheckName,NULL,0);
wchar FullName[NM];
wchar CurMask[NM];
*FullName=0;
Args->Rewind();
while (Args->GetString(CurMask,ASIZE(CurMask)))
{
wchar *LastMaskChar=PointToLastChar(CurMask);
bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only.
if (Dir)
{
// CheckName is a directory.
if (DirMask)
{
// We process the directory and have the directory exclusion mask.
// So let's convert "mask\" to "mask" and process it normally.
*LastMaskChar=0;
}
else
{
// REMOVED, we want -npath\* to match empty folders too.
// If mask has wildcards in name part and does not have the trailing
// '\' character, we cannot use it for directories.
// if (IsWildcard(PointToName(CurMask)))
// continue;
}
}
else
{
// If we process a file inside of directory excluded by "dirmask\".
// we want to exclude such file too. So we convert "dirmask\" to
// "dirmask\*". It is important for operations other than archiving
// with -x. When archiving with -x, directory matched by "dirmask\"
// is excluded from further scanning.
if (DirMask)
wcsncatz(CurMask,L"*",ASIZE(CurMask));
}
#ifndef SFX_MODULE
if (CheckFullPath && IsFullPath(CurMask))
{
// We do not need to do the special "*\" processing here, because
// unlike the "else" part of this "if", now we convert names to full
// format, so they all include the path, which is matched by "*\"
// correctly. Moreover, removing "*\" from mask would break
// the comparison, because now all names have the path.
if (*FullName==0)
ConvertNameToFull(CheckName,FullName,ASIZE(FullName));
if (CmpName(CurMask,FullName,MatchMode))
return true;
}
else
#endif
{
wchar NewName[NM+2],*CurName=Name;
// Important to convert before "*\" check below, so masks like
// d:*\something are processed properly.
wchar *CmpMask=ConvertPath(CurMask,NULL,0);
if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1]))
{
// We want "*\name" to match 'name' not only in subdirectories,
// but also in the current directory. We convert the name
// from 'name' to '.\name' to be matched by "*\" part even if it is
// in current directory.
NewName[0]='.';
NewName[1]=CPATHDIVIDER;
wcsncpyz(NewName+2,Name,ASIZE(NewName)-2);
CurName=NewName;
}
if (CmpName(CmpMask,CurName,MatchMode))
return true;
}
}
return false;
}
#ifndef SFX_MODULE
// Now this function performs only one task and only in Windows version:
// it skips symlinks to directories if -e1024 switch is specified.
// Symlinks are skipped in ScanTree class, so their entire contents
// is skipped too. Without this function we would check the attribute
// only directly before archiving, so we would skip the symlink record,
// but not the contents of symlinked directory.
bool CommandData::ExclDirByAttr(uint FileAttr)
{
#ifdef _WIN_ALL
if ((FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0 &&
(ExclFileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0)
return true;
#endif
return false;
}
#endif
#if !defined(SFX_MODULE)
void CommandData::SetTimeFilters(const wchar *Mod,bool Before,bool Age)
{
bool ModeOR=false,TimeMods=false;
const wchar *S=Mod;
// Check if any 'mca' modifiers are present, set OR mode if 'o' is present,
// skip modifiers and set S to beginning of time string. Be sure to check
// *S!=0, because termination 0 is a part of string for wcschr.
for (;*S!=0 && wcschr(L"MCAOmcao",*S)!=NULL;S++)
if (*S=='o' || *S=='O')
ModeOR=true;
else
TimeMods=true;
if (!TimeMods) // Assume 'm' if no modifiers are specified.
Mod=L"m";
// Set the specified time for every modifier. Be sure to check *Mod!=0,
// because termination 0 is a part of string for wcschr. This check is
// important when we set Mod to "m" above.
for (;*Mod!=0 && wcschr(L"MCAOmcao",*Mod)!=NULL;Mod++)
switch(toupperw(*Mod))
{
case 'M':
if (Before)
{
Age ? FileMtimeBefore.SetAgeText(S):FileMtimeBefore.SetIsoText(S);
FileMtimeBeforeOR=ModeOR;
}
else
{
Age ? FileMtimeAfter.SetAgeText(S):FileMtimeAfter.SetIsoText(S);
FileMtimeAfterOR=ModeOR;
}
break;
case 'C':
if (Before)
{
Age ? FileCtimeBefore.SetAgeText(S):FileCtimeBefore.SetIsoText(S);
FileCtimeBeforeOR=ModeOR;
}
else
{
Age ? FileCtimeAfter.SetAgeText(S):FileCtimeAfter.SetIsoText(S);
FileCtimeAfterOR=ModeOR;
}
break;
case 'A':
if (Before)
{
Age ? FileAtimeBefore.SetAgeText(S):FileAtimeBefore.SetIsoText(S);
FileAtimeBeforeOR=ModeOR;
}
else
{
Age ? FileAtimeAfter.SetAgeText(S):FileAtimeAfter.SetIsoText(S);
FileAtimeAfterOR=ModeOR;
}
break;
}
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta)
{
bool FilterOR=false;
if (FileMtimeBefore.IsSet()) // Filter present.
if (ftm>=FileMtimeBefore) // Condition not matched.
if (FileMtimeBeforeOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileMtimeBeforeOR)
return false; // Include file in OR mode.
if (FileMtimeAfter.IsSet()) // Filter present.
if (ftm<FileMtimeAfter) // Condition not matched.
if (FileMtimeAfterOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileMtimeAfterOR)
return false; // Include file in OR mode.
if (FileCtimeBefore.IsSet()) // Filter present.
if (ftc>=FileCtimeBefore) // Condition not matched.
if (FileCtimeBeforeOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileCtimeBeforeOR)
return false; // Include file in OR mode.
if (FileCtimeAfter.IsSet()) // Filter present.
if (ftc<FileCtimeAfter) // Condition not matched.
if (FileCtimeAfterOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileCtimeAfterOR)
return false; // Include file in OR mode.
if (FileAtimeBefore.IsSet()) // Filter present.
if (fta>=FileAtimeBefore) // Condition not matched.
if (FileAtimeBeforeOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileAtimeBeforeOR)
return false; // Include file in OR mode.
if (FileAtimeAfter.IsSet()) // Filter present.
if (fta<FileAtimeAfter) // Condition not matched.
if (FileAtimeAfterOR)
FilterOR=true; // Not matched OR filter is present.
else
return true; // Exclude file in AND mode.
else // Condition matched.
if (FileAtimeAfterOR)
return false; // Include file in OR mode.
return FilterOR; // Exclude if all OR filters are not matched.
}
#endif
#ifndef SFX_MODULE
// Return 'true' if we need to exclude the file from processing.
bool CommandData::SizeCheck(int64 Size)
{
if (FileSizeLess!=INT64NDF && Size>=FileSizeLess)
return true;
if (FileSizeMore!=INT64NDF && Size<=FileSizeMore)
return true;
return false;
}
#endif
// Return 0 if file must not be processed or a number of matched parameter otherwise.
int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType,
bool Flags,wchar *MatchedArg,uint MatchedArgSize)
{
if (MatchedArg!=NULL && MatchedArgSize>0)
*MatchedArg=0;
bool Dir=FileHead.Dir;
if (ExclCheck(FileHead.FileName,Dir,false,true))
return 0;
#ifndef SFX_MODULE
if (TimeCheck(FileHead.mtime,FileHead.ctime,FileHead.atime))
return 0;
if ((FileHead.FileAttr & ExclFileAttr)!=0 || FileHead.Dir && ExclDir)
return 0;
if (InclAttrSet && (!FileHead.Dir && (FileHead.FileAttr & InclFileAttr)==0 ||
FileHead.Dir && !InclDir))
return 0;
if (!Dir && SizeCheck(FileHead.UnpSize))
return 0;
#endif
wchar *ArgName;
FileArgs.Rewind();
for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++)
if (CmpName(ArgName,FileHead.FileName,MatchType))
{
if (ExactMatch!=NULL)
*ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0;
if (MatchedArg!=NULL)
wcsncpyz(MatchedArg,ArgName,MatchedArgSize);
return StringCount;
}
return 0;
}
#if !defined(SFX_MODULE)
void CommandData::SetStoreTimeMode(const wchar *S)
{
if (*S==0 || IsDigit(*S) || *S=='-' || *S=='+')
{
// Apply -ts, -ts1, -ts-, -ts+ to all 3 times.
// Handle obsolete -ts[2,3,4] as ts+.
EXTTIME_MODE Mode=EXTTIME_MAX;
if (*S=='-')
Mode=EXTTIME_NONE;
if (*S=='1')
Mode=EXTTIME_1S;
xmtime=xctime=xatime=Mode;
S++;
}
while (*S!=0)
{
EXTTIME_MODE Mode=EXTTIME_MAX;
if (S[1]=='-')
Mode=EXTTIME_NONE;
if (S[1]=='1')
Mode=EXTTIME_1S;
switch(toupperw(*S))
{
case 'M':
xmtime=Mode;
break;
case 'C':
xctime=Mode;
break;
case 'A':
xatime=Mode;
break;
case 'P':
PreserveAtime=true;
break;
}
S++;
}
}
#endif

118
unrar/cmdmix.cpp Normal file
View File

@@ -0,0 +1,118 @@
void CommandData::OutTitle()
{
if (BareOutput || DisableCopyright)
return;
#if defined(__GNUC__) && defined(SFX_MODULE)
mprintf(St(MCopyrightS));
#else
#ifndef SILENT
static bool TitleShown=false;
if (TitleShown)
return;
TitleShown=true;
wchar Version[80];
if (RARVER_BETA!=0)
swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA);
else
swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR);
#if defined(_WIN_32) || defined(_WIN_64)
wcsncatz(Version,L" ",ASIZE(Version));
#endif
#ifdef _WIN_32
wcsncatz(Version,St(Mx86),ASIZE(Version));
#endif
#ifdef _WIN_64
wcsncatz(Version,St(Mx64),ASIZE(Version));
#endif
if (PrintVersion)
{
mprintf(L"%s",Version);
exit(0);
}
mprintf(St(MUCopyright),Version,RARVER_YEAR);
#endif
#endif
}
inline bool CmpMSGID(MSGID i1,MSGID i2)
{
#ifdef MSGID_INT
return i1==i2;
#else
// If MSGID is const char*, we cannot compare pointers only.
// Pointers to different instances of same string can differ,
// so we need to compare complete strings.
return wcscmp(i1,i2)==0;
#endif
}
void CommandData::OutHelp(RAR_EXIT ExitCode)
{
#if !defined(SILENT)
OutTitle();
static MSGID Help[]={
#ifdef SFX_MODULE
// Console SFX switches definition.
MCHelpCmd,MSHelpCmdE,MSHelpCmdT,MSHelpCmdV
#else
// UnRAR switches definition.
MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL,
MCHelpCmdP,MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,MCHelpSwm,
MCHelpSwAT,MCHelpSwAC,MCHelpSwAD,MCHelpSwAG,MCHelpSwAI,MCHelpSwAP,
MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU,
MCHelpSwDH,MCHelpSwEP,MCHelpSwEP3,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR,
MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwN,MCHelpSwNa,MCHelpSwNal,
MCHelpSwO,MCHelpSwOC,MCHelpSwOL,MCHelpSwOR,MCHelpSwOW,MCHelpSwP,
MCHelpSwPm,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSL,MCHelpSwSM,
MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU,
MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal,
MCHelpSwY
#endif
};
for (uint I=0;I<ASIZE(Help);I++)
{
#ifndef SFX_MODULE
if (CmpMSGID(Help[I],MCHelpSwV))
continue;
#ifndef _WIN_ALL
static MSGID Win32Only[]={
MCHelpSwIEML,MCHelpSwVD,MCHelpSwAO,MCHelpSwOS,MCHelpSwIOFF,
MCHelpSwEP2,MCHelpSwOC,MCHelpSwONI,MCHelpSwDR,MCHelpSwRI
};
bool Found=false;
for (uint J=0;J<ASIZE(Win32Only);J++)
if (CmpMSGID(Help[I],Win32Only[J]))
{
Found=true;
break;
}
if (Found)
continue;
#endif
#if !defined(_UNIX) && !defined(_WIN_ALL)
if (CmpMSGID(Help[I],MCHelpSwOW))
continue;
#endif
#if !defined(_WIN_ALL) && !defined(_EMX)
if (CmpMSGID(Help[I],MCHelpSwAC))
continue;
#endif
#ifndef SAVE_LINKS
if (CmpMSGID(Help[I],MCHelpSwOL))
continue;
#endif
#ifndef RAR_SMP
if (CmpMSGID(Help[I],MCHelpSwMT))
continue;
#endif
#endif
mprintf(St(Help[I]));
}
mprintf(L"\n");
ErrHandler.Exit(ExitCode);
#endif
}

View File

@@ -6,7 +6,16 @@
class PackDef
{
public:
// Maximum LZ match length we can encode even for short distances.
static const uint MAX_LZ_MATCH = 0x1001;
// We increment LZ match length for longer distances, because shortest
// matches are not allowed for them. Maximum length increment is 3
// for distances larger than 256KB (0x40000). Here we define the maximum
// incremented LZ match. Normally packer does not use it, but we must be
// ready to process it in corrupt archives.
static const uint MAX_INC_LZ_MATCH = MAX_LZ_MATCH + 3;
static const uint MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3.
static const uint LOW_DIST_REP_COUNT = 16;

View File

@@ -49,9 +49,14 @@ void InitConsole()
}
void InitConsoleOptions(MESSAGE_TYPE MsgStream,RAR_CHARSET RedirectCharset)
void SetConsoleMsgStream(MESSAGE_TYPE MsgStream)
{
::MsgStream=MsgStream;
}
void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset)
{
::RedirectCharset=RedirectCharset;
}

View File

@@ -2,7 +2,8 @@
#define _RAR_CONSIO_
void InitConsole();
void InitConsoleOptions(MESSAGE_TYPE MsgStream,RAR_CHARSET RedirectCharset);
void SetConsoleMsgStream(MESSAGE_TYPE MsgStream);
void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset);
void OutComment(const wchar *Comment,size_t Size);
#ifndef SILENT

View File

@@ -66,14 +66,14 @@ uint CRC32(uint StartCRC,const void *Addr,size_t Size)
uint NextData = Data[4]|(Data[5] << 8)|(Data[6] << 16)|(Data[7] << 24);
#else
StartCRC ^= *(uint32 *) Data;
uint NextData = *(uint32 *) (Data +4);
uint NextData = *(uint32 *) (Data+4);
#endif
StartCRC = crc_tables[7][(byte) StartCRC ] ^
crc_tables[6][(byte)(StartCRC >> 8) ] ^
crc_tables[5][(byte)(StartCRC >> 16)] ^
crc_tables[4][(byte)(StartCRC >> 24)] ^
crc_tables[3][(byte) NextData ] ^
crc_tables[2][(byte)(NextData >>8 ) ] ^
crc_tables[2][(byte)(NextData >> 8) ] ^
crc_tables[1][(byte)(NextData >> 16)] ^
crc_tables[0][(byte)(NextData >> 24)];
}

View File

@@ -28,8 +28,8 @@ void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,co
sha1_context c;
sha1_init(&c);
const int HashRounds=0x40000;
for (int I=0;I<HashRounds;I++)
const uint HashRounds=0x40000;
for (uint I=0;I<HashRounds;I++)
{
sha1_process_rar29( &c, RawPsw, RawLength );
byte PswNum[3];
@@ -47,8 +47,8 @@ void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,co
}
uint32 digest[5];
sha1_done( &c, digest );
for (int I=0;I<4;I++)
for (int J=0;J<4;J++)
for (uint I=0;I<4;I++)
for (uint J=0;J<4;J++)
AESKey[I*4+J]=(byte)(digest[I]>>(J*8));
KDF3Cache[KDF3CachePos].Pwd=*Password;

View File

@@ -35,11 +35,14 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
DataSet *Data=NULL;
try
{
ErrHandler.Clean();
r->OpenResult=0;
Data=new DataSet;
Data->Cmd.DllError=0;
Data->OpenMode=r->OpenMode;
Data->Cmd.FileArgs.AddString(L"*");
Data->Cmd.KeepBroken=(r->OpFlags&ROADOF_KEEPBROKEN)!=0;
char AnsiArcName[NM];
*AnsiArcName=0;
@@ -92,36 +95,50 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
r->Flags=0;
if (Data->Arc.Volume)
r->Flags|=0x01;
r->Flags|=ROADF_VOLUME;
if (Data->Arc.MainComment)
r->Flags|=ROADF_COMMENT;
if (Data->Arc.Locked)
r->Flags|=0x04;
r->Flags|=ROADF_LOCK;
if (Data->Arc.Solid)
r->Flags|=0x08;
r->Flags|=ROADF_SOLID;
if (Data->Arc.NewNumbering)
r->Flags|=0x10;
r->Flags|=ROADF_NEWNUMBERING;
if (Data->Arc.Signed)
r->Flags|=0x20;
r->Flags|=ROADF_SIGNED;
if (Data->Arc.Protected)
r->Flags|=0x40;
r->Flags|=ROADF_RECOVERY;
if (Data->Arc.Encrypted)
r->Flags|=0x80;
r->Flags|=ROADF_ENCHEADERS;
if (Data->Arc.FirstVolume)
r->Flags|=0x100;
r->Flags|=ROADF_FIRSTVOLUME;
Array<wchar> CmtDataW;
if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtDataW))
{
Array<char> CmtData(CmtDataW.Size()*4+1);
memset(&CmtData[0],0,CmtData.Size());
WideToChar(&CmtDataW[0],&CmtData[0],CmtData.Size()-1);
size_t Size=strlen(&CmtData[0])+1;
if (r->CmtBufW!=NULL)
{
CmtDataW.Push(0);
size_t Size=wcslen(&CmtDataW[0])+1;
r->Flags|=2;
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1);
if (Size<=r->CmtBufSize)
r->CmtBuf[r->CmtSize-1]=0;
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
memcpy(r->CmtBufW,&CmtDataW[0],(r->CmtSize-1)*sizeof(*r->CmtBufW));
r->CmtBufW[r->CmtSize-1]=0;
}
else
if (r->CmtBuf!=NULL)
{
Array<char> CmtData(CmtDataW.Size()*4+1);
memset(&CmtData[0],0,CmtData.Size());
WideToChar(&CmtDataW[0],&CmtData[0],CmtData.Size()-1);
size_t Size=strlen(&CmtData[0])+1;
r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1;
r->CmtSize=(uint)Min(Size,r->CmtBufSize);
memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1);
r->CmtBuf[r->CmtSize-1]=0;
}
}
else
r->CmtState=r->CmtSize=0;
@@ -151,9 +168,16 @@ HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r)
int PASCAL RARCloseArchive(HANDLE hArcData)
{
DataSet *Data=(DataSet *)hArcData;
bool Success=Data==NULL ? false:Data->Arc.Close();
delete Data;
return Success ? ERAR_SUCCESS : ERAR_ECLOSE;
try
{
bool Success=Data==NULL ? false:Data->Arc.Close();
delete Data;
return Success ? ERAR_SUCCESS : ERAR_ECLOSE;
}
catch (RAR_EXIT ErrCode)
{
return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode);
}
}
@@ -244,10 +268,7 @@ int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D)
D->UnpSize=uint(hd->UnpSize & 0xffffffff);
D->UnpSizeHigh=uint(hd->UnpSize>>32);
D->HostOS=hd->HSType==HSYS_WINDOWS ? HOST_WIN32:HOST_UNIX;
if (Data->Arc.Format==RARFMT50)
D->UnpVer=Data->Arc.FileHead.UnpVer==0 ? 50 : 200; // If it is not 0, just set it to something big.
else
D->UnpVer=Data->Arc.FileHead.UnpVer;
D->UnpVer=Data->Arc.FileHead.UnpVer;
D->FileCRC=hd->FileHash.CRC32;
D->FileTime=hd->mtime.GetDos();
@@ -363,7 +384,7 @@ int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestNa
if (DestNameW!=NULL)
wcsncpyz(Data->Cmd.DllDestName,DestNameW,ASIZE(Data->Cmd.DllDestName));
wcscpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T");
wcsncpyz(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T",ASIZE(Data->Cmd.Command));
Data->Cmd.Test=Operation!=RAR_EXTRACT;
bool Repeat=false;
Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat);
@@ -398,13 +419,13 @@ int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestNa
int PASCAL RARProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName)
{
return(ProcessFile(hArcData,Operation,DestPath,DestName,NULL,NULL));
return ProcessFile(hArcData,Operation,DestPath,DestName,NULL,NULL);
}
int PASCAL RARProcessFileW(HANDLE hArcData,int Operation,wchar *DestPath,wchar *DestName)
{
return(ProcessFile(hArcData,Operation,NULL,NULL,DestPath,DestName));
return ProcessFile(hArcData,Operation,NULL,NULL,DestPath,DestName);
}
@@ -430,16 +451,16 @@ void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataPro
}
#ifndef RAR_NOCRYPT
void PASCAL RARSetPassword(HANDLE hArcData,char *Password)
{
#ifndef RAR_NOCRYPT
DataSet *Data=(DataSet *)hArcData;
wchar PasswordW[MAXPASSWORD];
GetWideName(Password,NULL,PasswordW,ASIZE(PasswordW));
Data->Cmd.Password.Set(PasswordW);
cleandata(PasswordW,sizeof(PasswordW));
}
#endif
}
int PASCAL RARGetDllVersion()

View File

@@ -5,6 +5,7 @@ EXPORTS
RARReadHeader
RARReadHeaderEx
RARProcessFile
RARProcessFileW
RARSetCallback
RARSetChangeVolProc
RARSetProcessDataProc

View File

@@ -1,7 +1,7 @@
#ifndef _UNRAR_DLL_
#define _UNRAR_DLL_
#pragma pack(1)
#pragma pack(push, 1)
#define ERAR_SUCCESS 0
#define ERAR_END_ARCHIVE 10
@@ -135,6 +135,8 @@ typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM
#define ROADF_ENCHEADERS 0x0080
#define ROADF_FIRSTVOLUME 0x0100
#define ROADOF_KEEPBROKEN 0x0001
struct RAROpenArchiveDataEx
{
char *ArcName;
@@ -148,7 +150,9 @@ struct RAROpenArchiveDataEx
unsigned int Flags;
UNRARCALLBACK Callback;
LPARAM UserData;
unsigned int Reserved[28];
unsigned int OpFlags;
wchar_t *CmtBufW;
unsigned int Reserved[25];
};
enum UNRARCALLBACK_MESSAGES {
@@ -180,6 +184,6 @@ int PASCAL RARGetDllVersion();
}
#endif
#pragma pack()
#pragma pack(pop)
#endif

View File

@@ -2,8 +2,8 @@
#include <commctrl.h>
VS_VERSION_INFO VERSIONINFO
FILEVERSION 5, 50, 5, 2378
PRODUCTVERSION 5, 50, 5, 2378
FILEVERSION 5, 91, 100, 3470
PRODUCTVERSION 5, 91, 100, 3470
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
{
@@ -14,9 +14,9 @@ FILETYPE VFT_APP
VALUE "CompanyName", "Alexander Roshal\0"
VALUE "ProductName", "RAR decompression library\0"
VALUE "FileDescription", "RAR decompression library\0"
VALUE "FileVersion", "5.50.5\0"
VALUE "ProductVersion", "5.50.5\0"
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2017\0"
VALUE "FileVersion", "5.91.0\0"
VALUE "ProductVersion", "5.91.0\0"
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2020\0"
VALUE "OriginalFilename", "Unrar.dll\0"
}
}

13
unrar/dll_nocrypt.def Normal file
View File

@@ -0,0 +1,13 @@
EXPORTS
RAROpenArchive
RAROpenArchiveEx
RARCloseArchive
RARReadHeader
RARReadHeaderEx
RARProcessFile
RARProcessFileW
RARSetCallback
RARSetChangeVolProc
RARSetProcessDataProc
; RARSetPassword
RARGetDllVersion

View File

@@ -11,41 +11,53 @@ EncodeFileName::EncodeFileName()
void EncodeFileName::Decode(char *Name,byte *EncName,size_t EncSize,wchar *NameW,
size_t MaxDecSize)
void EncodeFileName::Decode(char *Name,size_t NameSize,byte *EncName,size_t EncSize,
wchar *NameW,size_t MaxDecSize)
{
size_t EncPos=0,DecPos=0;
byte HighByte=EncName[EncPos++];
byte HighByte=EncPos<EncSize ? EncName[EncPos++] : 0;
while (EncPos<EncSize && DecPos<MaxDecSize)
{
if (FlagBits==0)
{
if (EncPos>=EncSize)
break;
Flags=EncName[EncPos++];
FlagBits=8;
}
switch(Flags>>6)
{
case 0:
if (EncPos>=EncSize)
break;
NameW[DecPos++]=EncName[EncPos++];
break;
case 1:
if (EncPos>=EncSize)
break;
NameW[DecPos++]=EncName[EncPos++]+(HighByte<<8);
break;
case 2:
if (EncPos+1>=EncSize)
break;
NameW[DecPos++]=EncName[EncPos]+(EncName[EncPos+1]<<8);
EncPos+=2;
break;
case 3:
{
if (EncPos>=EncSize)
break;
int Length=EncName[EncPos++];
if (Length & 0x80)
if ((Length & 0x80)!=0)
{
if (EncPos>=EncSize)
break;
byte Correction=EncName[EncPos++];
for (Length=(Length&0x7f)+2;Length>0 && DecPos<MaxDecSize;Length--,DecPos++)
for (Length=(Length&0x7f)+2;Length>0 && DecPos<MaxDecSize && DecPos<NameSize;Length--,DecPos++)
NameW[DecPos]=((Name[DecPos]+Correction)&0xff)+(HighByte<<8);
}
else
for (Length+=2;Length>0 && DecPos<MaxDecSize;Length--,DecPos++)
for (Length+=2;Length>0 && DecPos<MaxDecSize && DecPos<NameSize;Length--,DecPos++)
NameW[DecPos]=Name[DecPos];
}
break;

View File

@@ -14,7 +14,7 @@ class EncodeFileName
public:
EncodeFileName();
size_t Encode(char *Name,wchar *NameW,byte *EncName);
void Decode(char *Name,byte *EncName,size_t EncSize,wchar *NameW,size_t MaxDecSize);
void Decode(char *Name,size_t NameSize,byte *EncName,size_t EncSize,wchar *NameW,size_t MaxDecSize);
};
#endif

View File

@@ -41,9 +41,12 @@ void ErrorHandler::CloseError(const wchar *FileName)
uiMsg(UIERROR_FILECLOSE,FileName);
SysErrMsg();
}
#if !defined(SILENT) || defined(RARDLL)
Exit(RARX_FATAL);
#endif
// We must not call Exit and throw an exception here, because this function
// is called from File object destructor and can be invoked when stack
// unwinding while handling another exception. Throwing a new exception
// when stack unwinding is prohibited and terminates a program.
// If necessary, we can check std::uncaught_exception() before throw.
SetErrorCode(RARX_FATAL);
}
@@ -155,6 +158,7 @@ void ErrorHandler::OpenErrorMsg(const wchar *FileName)
void ErrorHandler::OpenErrorMsg(const wchar *ArcName,const wchar *FileName)
{
Wait(); // Keep GUI responsive if many files cannot be opened when archiving.
uiMsg(UIERROR_FILEOPEN,ArcName,FileName);
SysErrMsg();
SetErrorCode(RARX_OPEN);
@@ -267,6 +271,7 @@ void _stdfunction ProcessSignal(int SigType)
#endif
ErrHandler.UserBreak=true;
ErrHandler.SetDisableShutdown();
mprintf(St(MBreak));
#ifdef _WIN_ALL
@@ -290,7 +295,7 @@ void _stdfunction ProcessSignal(int SigType)
#endif
#if defined(_WIN_ALL) && !defined(_MSC_VER)
// never reached, just to avoid a compiler warning
// Never reached, just to avoid a compiler warning
return TRUE;
#endif
}
@@ -322,36 +327,15 @@ void ErrorHandler::Throw(RAR_EXIT Code)
}
void ErrorHandler::SysErrMsg()
bool ErrorHandler::GetSysErrMsg(wchar *Msg,size_t Size)
{
#if !defined(SFX_MODULE) && !defined(SILENT)
#ifndef SILENT
#ifdef _WIN_ALL
wchar *lpMsgBuf=NULL;
int ErrType=GetLastError();
if (ErrType!=0 && FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL,ErrType,MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf,0,NULL))
{
wchar *CurMsg=lpMsgBuf;
while (CurMsg!=NULL)
{
while (*CurMsg=='\r' || *CurMsg=='\n')
CurMsg++;
if (*CurMsg==0)
break;
wchar *EndMsg=wcschr(CurMsg,'\r');
if (EndMsg==NULL)
EndMsg=wcschr(CurMsg,'\n');
if (EndMsg!=NULL)
{
*EndMsg=0;
EndMsg++;
}
uiMsg(UIERROR_SYSERRMSG,CurMsg);
CurMsg=EndMsg;
}
}
LocalFree( lpMsgBuf );
if (ErrType!=0)
return FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,ErrType,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
Msg,(DWORD)Size,NULL)!=0;
#endif
#if defined(_UNIX) || defined(_EMX)
@@ -360,12 +344,46 @@ void ErrorHandler::SysErrMsg()
char *err=strerror(errno);
if (err!=NULL)
{
wchar Msg[1024];
CharToWide(err,Msg,ASIZE(Msg));
uiMsg(UIERROR_SYSERRMSG,Msg);
CharToWide(err,Msg,Size);
return true;
}
}
#endif
#endif
return false;
}
void ErrorHandler::SysErrMsg()
{
#if !defined(SFX_MODULE) && !defined(SILENT)
wchar Msg[1024];
if (!GetSysErrMsg(Msg,ASIZE(Msg)))
return;
#ifdef _WIN_ALL
wchar *CurMsg=Msg;
while (CurMsg!=NULL) // Print string with \r\n as several strings to multiple lines.
{
while (*CurMsg=='\r' || *CurMsg=='\n')
CurMsg++;
if (*CurMsg==0)
break;
wchar *EndMsg=wcschr(CurMsg,'\r');
if (EndMsg==NULL)
EndMsg=wcschr(CurMsg,'\n');
if (EndMsg!=NULL)
{
*EndMsg=0;
EndMsg++;
}
uiMsg(UIERROR_SYSERRMSG,CurMsg);
CurMsg=EndMsg;
}
#endif
#if defined(_UNIX) || defined(_EMX)
uiMsg(UIERROR_SYSERRMSG,Msg);
#endif
#endif
}

View File

@@ -56,10 +56,12 @@ class ErrorHandler
uint GetErrorCount() {return ErrCount;}
void SetSignalHandlers(bool Enable);
void Throw(RAR_EXIT Code);
void SetSilent(bool Mode) {Silent=Mode;};
void SetSilent(bool Mode) {Silent=Mode;}
bool GetSysErrMsg(wchar *Msg,size_t Size);
void SysErrMsg();
int GetSystemErrorCode();
void SetSystemErrorCode(int Code);
void SetDisableShutdown() {DisableShutdown=true;}
bool IsShutdownEnabled() {return !DisableShutdown;}
bool UserBreak; // Ctrl+Break is pressed.

View File

@@ -93,6 +93,25 @@ static int CalcAllowedDepth(const wchar *Name)
}
// Check if all existing path components are directories and not links.
static bool LinkInPath(const wchar *Name)
{
wchar Path[NM];
if (wcslen(Name)>=ASIZE(Path))
return true; // It should not be that long, skip.
wcsncpyz(Path,Name,ASIZE(Path));
for (wchar *s=Path+wcslen(Path)-1;s>Path;s--)
if (IsPathDiv(*s))
{
*s=0;
FindData FD;
if (FindFile::FastFind(Path,&FD,true) && (FD.IsLink || !FD.IsDir))
return true;
}
return false;
}
bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName)
{
// Catch root dir based /path/file paths also as stuff like \\?\.
@@ -100,7 +119,25 @@ bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *Pr
// is a root based.
if (IsFullRootPath(SrcName) || IsFullRootPath(TargetName))
return false;
// Number of ".." in link target.
int UpLevels=0;
for (int Pos=0;*TargetName!=0;Pos++)
{
bool Dot2=TargetName[0]=='.' && TargetName[1]=='.' &&
(IsPathDiv(TargetName[2]) || TargetName[2]==0) &&
(Pos==0 || IsPathDiv(*(TargetName-1)));
if (Dot2)
UpLevels++;
TargetName++;
}
// If link target includes "..", it must not have another links
// in the path, because they can bypass our safety check. For example,
// suppose we extracted "lnk1" -> "." first and "lnk1/lnk2" -> ".." next
// or "dir/lnk1" -> ".." first and "dir/lnk1/lnk2" -> ".." next.
if (UpLevels>0 && LinkInPath(PrepSrcName))
return false;
// We could check just prepared src name, but for extra safety
// we check both original (as from archive header) and prepared
// (after applying the destination path and -ep switches) names.
@@ -119,17 +156,6 @@ bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *Pr
}
int PrepAllowedDepth=CalcAllowedDepth(PrepSrcName);
// Number of ".." in link target.
int UpLevels=0;
for (int Pos=0;*TargetName!=0;Pos++)
{
bool Dot2=TargetName[0]=='.' && TargetName[1]=='.' &&
(IsPathDiv(TargetName[2]) || TargetName[2]==0) &&
(Pos==0 || IsPathDiv(*(TargetName-1)));
if (Dot2)
UpLevels++;
TargetName++;
}
return AllowedDepth>=UpLevels && PrepAllowedDepth>=UpLevels;
}

View File

@@ -40,6 +40,8 @@ void CmdExtract::DoExtract()
{
if (Cmd->ManualPassword)
Cmd->Password.Clean(); // Clean user entered password before processing next archive.
ReconstructDone=false; // Must be reset here, not in ExtractArchiveInit().
while (true)
{
EXTRACT_ARC_CODE Code=ExtractArchive();
@@ -59,7 +61,11 @@ void CmdExtract::DoExtract()
{
if (!PasswordCancelled)
uiMsg(UIERROR_NOFILESTOEXTRACT,ArcName);
ErrHandler.SetErrorCode(RARX_NOFILES);
// Other error codes may explain a reason of "no files extracted" clearer,
// so set it only if no other errors found (wrong mask set by user).
if (ErrHandler.GetErrorCode()==RARX_SUCCESS)
ErrHandler.SetErrorCode(RARX_NOFILES);
}
else
if (!Cmd->DisableDone)
@@ -83,13 +89,12 @@ void CmdExtract::ExtractArchiveInit(Archive &Arc)
FirstFile=true;
#endif
PasswordAll=(Cmd->Password.IsSet());
GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet();
DataIO.UnpVolume=false;
PrevProcessed=false;
AllMatchesExact=true;
ReconstructDone=false;
AnySolidDataUnpackedWell=false;
StartTime.SetCurrentTime();
@@ -157,7 +162,7 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive()
// This size is necessary to display the correct total progress indicator.
wchar NextName[NM];
wcscpy(NextName,Arc.FileName);
wcsncpyz(NextName,Arc.FileName,ASIZE(NextName));
while (true)
{
@@ -226,18 +231,6 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive()
bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
{
// We can get negative sizes in corrupt archive and it is unacceptable
// for size comparisons in CmdExtract::UnstoreFile and ComprDataIO::UnpRead,
// where we cast sizes to size_t and can exceed another read or available
// size. We could fix it when reading an archive. But we prefer to do it
// here, because this function is called directly in unrar.dll, so we fix
// bad parameters passed to dll. Also we want to see real negative sizes
// in the listing of corrupt archive.
if (Arc.FileHead.PackSize<0)
Arc.FileHead.PackSize=0;
if (Arc.FileHead.UnpSize<0)
Arc.FileHead.UnpSize=0;
wchar Command=Cmd->Command[0];
if (HeaderSize==0)
if (DataIO.UnpVolume)
@@ -245,8 +238,8 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
#ifdef NOVOLUME
return false;
#else
// Supposing we unpack an old RAR volume without end of archive record
// and last file is not split between volumes.
// Supposing we unpack an old RAR volume without the end of archive
// record and last file is not split between volumes.
if (!MergeArchive(Arc,&DataIO,false,Command))
{
ErrHandler.SetErrorCode(RARX_WARNING);
@@ -256,11 +249,12 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
}
else
return false;
HEADER_TYPE HeaderType=Arc.GetHeaderType();
if (HeaderType!=HEAD_FILE)
{
#ifndef SFX_MODULE
if (HeaderType==HEAD3_OLDSERVICE && PrevProcessed)
if (Arc.Format==RARFMT15 && HeaderType==HEAD3_OLDSERVICE && PrevProcessed)
SetExtraInfo20(Cmd,Arc,DestFileName);
#endif
if (HeaderType==HEAD_SERVICE && PrevProcessed)
@@ -268,15 +262,17 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
if (HeaderType==HEAD_ENDARC)
if (Arc.EndArcHead.NextVolume)
{
#ifndef NOVOLUME
#ifdef NOVOLUME
return false;
#else
if (!MergeArchive(Arc,&DataIO,false,Command))
{
ErrHandler.SetErrorCode(RARX_WARNING);
return false;
}
#endif
Arc.Seek(Arc.CurBlockPos,SEEK_SET);
return true;
#endif
}
else
return false;
@@ -285,6 +281,19 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
}
PrevProcessed=false;
// We can get negative sizes in corrupt archive and it is unacceptable
// for size comparisons in ComprDataIO::UnpRead, where we cast sizes
// to size_t and can exceed another read or available size. We could fix it
// when reading an archive. But we prefer to do it here, because this
// function is called directly in unrar.dll, so we fix bad parameters
// passed to dll. Also we want to see real negative sizes in the listing
// of corrupt archive. To prevent uninitialized data access perform
// these checks after rejecting zero length and non-file headers above.
if (Arc.FileHead.PackSize<0)
Arc.FileHead.PackSize=0;
if (Arc.FileHead.UnpSize<0)
Arc.FileHead.UnpSize=0;
if (!Cmd->Recurse && MatchedArgs>=Cmd->FileArgs.ItemsCount() && AllMatchesExact)
return false;
@@ -292,7 +301,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
bool EqualNames=false;
wchar MatchedArg[NM];
int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType,MatchedArg,ASIZE(MatchedArg));
int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType,0,MatchedArg,ASIZE(MatchedArg));
bool MatchFound=MatchNumber!=0;
#ifndef SFX_MODULE
if (Cmd->ExclPath==EXCL_BASEPATH)
@@ -317,6 +326,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
if (wcsicomp(ArcName,CurVolName)!=0 && FileExist(ArcName))
{
wcsncpyz(Cmd->ArcName,ArcName,ASIZE(ArcName)); // For GUI "Delete archive after extraction".
// If first volume name does not match the current name and if such
// volume name really exists, let's unpack from this first volume.
Repeat=true;
@@ -338,7 +348,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
#endif
wchar ArcFileName[NM];
ConvertPath(Arc.FileHead.FileName,ArcFileName);
ConvertPath(Arc.FileHead.FileName,ArcFileName,ASIZE(ArcFileName));
if (Arc.FileHead.Version)
{
@@ -427,7 +437,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
return !Arc.Solid; // Can try extracting next file only in non-solid archive.
}
while (true) // Repeat password prompt in case of wrong password here.
while (true) // Repeat the password prompt for wrong and empty passwords.
{
if (Arc.FileHead.Encrypted)
{
@@ -445,21 +455,8 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
return false;
}
#endif
// Skip only the current encrypted file if empty password is entered.
// Actually our "cancel" code above intercepts empty passwords too now,
// so we keep the code below just in case we'll decide process empty
// and cancelled passwords differently sometimes.
if (!Cmd->Password.IsSet())
{
ErrHandler.SetErrorCode(RARX_WARNING);
#ifdef RARDLL
Cmd->DllError=ERAR_MISSING_PASSWORD;
#endif
ExtrFile=false;
}
}
// Set a password before creating the file, so we can skip creating
// in case of wrong password.
SecPassword FilePassword=Cmd->Password;
@@ -479,12 +476,24 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 &&
!Arc.BrokenHeader)
{
uiMsg(UIWAIT_BADPSW,ArcFileName);
if (!PasswordAll) // If entered manually and not through -p<pwd>.
if (GlobalPassword) // For -p<pwd> or Ctrl+P to avoid the infinite loop.
{
// This message is used by Android GUI to reset cached passwords.
// Update appropriate code if changed.
uiMsg(UIERROR_BADPSW,Arc.FileName,ArcFileName);
}
else // For passwords entered manually.
{
// This message is used by Android GUI and Windows GUI and SFX to
// reset cached passwords. Update appropriate code if changed.
uiMsg(UIWAIT_BADPSW,Arc.FileName,ArcFileName);
Cmd->Password.Clean();
// Avoid new requests for unrar.dll to prevent the infinite loop
// if app always returns the same password.
#ifndef RARDLL
continue; // Request a password again.
#endif
}
#ifdef RARDLL
// If we already have ERAR_EOPEN as result of missing volume,
@@ -608,11 +617,14 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
}
#endif
if (!TestMode && !Arc.BrokenHeader &&
(Arc.FileHead.PackSize<<11)>Arc.FileHead.UnpSize &&
uint64 Preallocated=0;
if (!TestMode && !Arc.BrokenHeader && Arc.FileHead.UnpSize>1000000 &&
Arc.FileHead.PackSize*1024>Arc.FileHead.UnpSize &&
(Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize))
{
CurFile.Prealloc(Arc.FileHead.UnpSize);
Preallocated=Arc.FileHead.UnpSize;
}
CurFile.SetAllowDelete(!Cmd->KeepBroken);
bool FileCreateMode=!TestMode && !SkipSolid && Command!='P';
@@ -724,37 +736,52 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
else
mprintf(L"\b\b\b\b\b ");
// If we successfully unpacked a hard link, we wish to set its file
// attributes. Hard link shares file metadata with link target,
// so we do not need to set link time or owner. But when we overwrite
// an existing link, we can call PrepareToDelete(), which affects
// link target attributes as well. So we set link attributes to restore
// both target and link attributes if PrepareToDelete() changed them.
bool SetAttrOnly=LinkEntry && Arc.FileHead.RedirType==FSREDIR_HARDLINK && LinkSuccess;
if (!TestMode && (Command=='X' || Command=='E') &&
(!LinkEntry || Arc.FileHead.RedirType==FSREDIR_FILECOPY && LinkSuccess) &&
(!LinkEntry || SetAttrOnly || Arc.FileHead.RedirType==FSREDIR_FILECOPY && LinkSuccess) &&
(!BrokenFile || Cmd->KeepBroken))
{
// We could preallocate more space that really written to broken file.
if (BrokenFile)
CurFile.Truncate();
// Below we use DestFileName instead of CurFile.FileName,
// so we can set file attributes also for hard links, which do not
// have the open CurFile. These strings are the same for other items.
#if defined(_WIN_ALL) || defined(_EMX)
if (Cmd->ClearArc)
Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE;
#endif
if (!SetAttrOnly)
{
// We could preallocate more space that really written to broken file
// or file with crafted header.
if (Preallocated>0 && (BrokenFile || DataIO.CurUnpWrite!=Preallocated))
CurFile.Truncate();
CurFile.SetOpenFileTime(
Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime,
Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime,
Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
CurFile.Close();
CurFile.SetOpenFileTime(
Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime,
Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime,
Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
CurFile.Close();
SetFileHeaderExtra(Cmd,Arc,DestFileName);
CurFile.SetCloseFileTime(
Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime,
Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
}
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
if (Cmd->SetCompressedAttr &&
(Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0)
SetFileCompression(CurFile.FileName,true);
SetFileCompression(DestFileName,true);
if (Cmd->ClearArc)
Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE;
#endif
SetFileHeaderExtra(Cmd,Arc,CurFile.FileName);
CurFile.SetCloseFileTime(
Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime,
Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime);
if (!Cmd->IgnoreGeneralAttr && !SetFileAttr(CurFile.FileName,Arc.FileHead.FileAttr))
uiMsg(UIERROR_FILEATTR,Arc.FileName,CurFile.FileName);
if (!Cmd->IgnoreGeneralAttr && !SetFileAttr(DestFileName,Arc.FileHead.FileAttr))
uiMsg(UIERROR_FILEATTR,Arc.FileName,DestFileName);
PrevProcessed=true;
}
@@ -779,19 +806,18 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
void CmdExtract::UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize)
{
// 512 KB and larger buffer reported to reduce performance on old XP
// computers with WDC WD2000JD HDD. According to test made by user
// 256 KB buffer is optimal.
Array<byte> Buffer(0x40000);
while (1)
Array<byte> Buffer(File::CopyBufferSize());
while (true)
{
uint Code=DataIO.UnpRead(&Buffer[0],Buffer.Size());
if (Code==0 || (int)Code==-1)
int ReadSize=DataIO.UnpRead(&Buffer[0],Buffer.Size());
if (ReadSize<=0)
break;
Code=Code<DestUnpSize ? Code:(uint)DestUnpSize;
DataIO.UnpWrite(&Buffer[0],Code);
if (DestUnpSize>=0)
DestUnpSize-=Code;
int WriteSize=ReadSize<DestUnpSize ? ReadSize:(int)DestUnpSize;
if (WriteSize>0)
{
DataIO.UnpWrite(&Buffer[0],WriteSize);
DestUnpSize-=WriteSize;
}
}
}
@@ -846,9 +872,12 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De
}
#ifndef SFX_MODULE
if (Cmd->AppendArcNameToPath)
if (Cmd->AppendArcNameToPath!=APPENDARCNAME_NONE)
{
wcsncatz(DestName,PointToName(Arc.FirstVolumeName),DestSize);
if (Cmd->AppendArcNameToPath==APPENDARCNAME_DESTPATH)
wcsncatz(DestName,PointToName(Arc.FirstVolumeName),DestSize);
else
wcsncpyz(DestName,Arc.FirstVolumeName,DestSize); // To archive own dir.
SetExt(DestName,NULL,DestSize);
AddEndSlash(DestName,DestSize);
}
@@ -958,19 +987,21 @@ bool CmdExtract::ExtrGetPassword(Archive &Arc,const wchar *ArcFileName)
{
if (!Cmd->Password.IsSet())
{
if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password) || !Cmd->Password.IsSet())
if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password)/* || !Cmd->Password.IsSet()*/)
{
// Suppress "test is ok" message in GUI if user entered
// an empty password or cancelled a password prompt.
uiMsg(UIERROR_INCERRCOUNT);
// Suppress "test is ok" message if user cancelled the password prompt.
// 2019.03.23: If some archives are tested ok and prompt is cancelled for others,
// do we really need to suppress "test is ok"? Also if we set an empty password
// and "Use for all archives" in WinRAR Ctrl+P and skip some encrypted archives.
// We commented out this UIERROR_INCERRCOUNT for now.
// uiMsg(UIERROR_INCERRCOUNT);
return false;
}
Cmd->ManualPassword=true;
}
#if !defined(SILENT)
else
if (!PasswordAll && !Arc.FileHead.Solid)
if (!GlobalPassword && !Arc.FileHead.Solid)
{
eprintf(St(MUseCurPsw),ArcFileName);
switch(Cmd->AllYes ? 1 : Ask(St(MYesNoAll)))
@@ -982,7 +1013,7 @@ bool CmdExtract::ExtrGetPassword(Archive &Arc,const wchar *ArcFileName)
return false;
break;
case 3:
PasswordAll=true;
GlobalPassword=true;
break;
}
}
@@ -1079,7 +1110,7 @@ void CmdExtract::ExtrCreateDir(Archive &Arc,const wchar *ArcFileName)
{
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
if (Cmd->SetCompressedAttr &&
(Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT())
(Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT()!=WNT_NONE)
SetFileCompression(DestFileName,true);
#endif
SetFileHeaderExtra(Cmd,Arc,DestFileName);

View File

@@ -43,7 +43,7 @@ class CmdExtract
wchar ArcName[NM];
bool PasswordAll;
bool GlobalPassword;
bool PrevProcessed; // If previous file was successfully extracted or tested.
wchar DestFileName[NM];
bool PasswordCancelled;

View File

@@ -13,6 +13,7 @@ File::File()
OpenShared=false;
AllowDelete=true;
AllowExceptions=true;
PreserveAtime=false;
#ifdef _WIN_ALL
NoSequentialRead=false;
CreateMode=FMF_UNDEFINED;
@@ -56,6 +57,9 @@ bool File::Open(const wchar *Name,uint Mode)
if (OpenShared)
ShareMode|=FILE_SHARE_WRITE;
uint Flags=NoSequentialRead ? 0:FILE_FLAG_SEQUENTIAL_SCAN;
FindData FD;
if (PreserveAtime)
Access|=FILE_WRITE_ATTRIBUTES; // Needed to preserve atime.
hNewFile=CreateFile(Name,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL);
DWORD LastError;
@@ -86,6 +90,11 @@ bool File::Open(const wchar *Name,uint Mode)
}
if (hNewFile==FILE_BAD_HANDLE && LastError==ERROR_FILE_NOT_FOUND)
ErrorType=FILE_NOTFOUND;
if (PreserveAtime && hNewFile!=FILE_BAD_HANDLE)
{
FILETIME ft={0xffffffff,0xffffffff}; // This value prevents atime modification.
SetFileTime(hNewFile,NULL,&ft,NULL);
}
#else
int flags=UpdateMode ? O_RDWR:(WriteMode ? O_WRONLY:O_RDONLY);
@@ -94,6 +103,11 @@ bool File::Open(const wchar *Name,uint Mode)
#if defined(_AIX) && defined(_LARGE_FILE_API)
flags|=O_LARGEFILE;
#endif
#endif
// NDK r20 has O_NOATIME, but fails to create files with it in Android 7+.
#if defined(O_NOATIME)
if (PreserveAtime)
flags|=O_NOATIME;
#endif
char NameA[NM];
WideToChar(Name,NameA,ASIZE(NameA));
@@ -173,7 +187,7 @@ bool File::Create(const wchar *Name,uint Mode)
wchar *LastChar=PointToLastChar(Name);
bool Special=*LastChar=='.' || *LastChar==' ';
if (Special)
if (Special && (Mode & FMF_STANDARDNAMES)==0)
hFile=FILE_BAD_HANDLE;
else
hFile=CreateFile(Name,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL);
@@ -230,7 +244,7 @@ bool File::Close()
{
#ifdef _WIN_ALL
// We use the standard system handle for stdout in Windows
// and it must not be closed here.
// and it must not be closed here.
if (HandleType==FILE_HANDLENORMAL)
Success=CloseHandle(hFile)==TRUE;
#else
@@ -271,7 +285,7 @@ bool File::Rename(const wchar *NewName)
Success=RenameFile(FileName,NewName);
if (Success)
wcscpy(FileName,NewName);
wcsncpyz(FileName,NewName,ASIZE(FileName));
return Success;
}
@@ -387,7 +401,7 @@ int File::Read(void *Data,size_t Size)
}
break;
}
return ReadSize;
return ReadSize; // It can return -1 only if AllowExceptions is disabled.
}
@@ -670,9 +684,11 @@ void File::GetOpenFileTime(RarTime *ft)
int64 File::FileLength()
{
SaveFilePos SavePos(*this);
int64 SavePos=Tell();
Seek(0,SEEK_END);
return Tell();
int64 Length=Tell();
Seek(SavePos,SEEK_SET);
return Length;
}
@@ -692,7 +708,7 @@ bool File::IsDevice()
#ifndef SFX_MODULE
int64 File::Copy(File &Dest,int64 Length)
{
Array<char> Buffer(0x40000);
Array<byte> Buffer(File::CopyBufferSize());
int64 CopySize=0;
bool CopyAll=(Length==INT64NDF);
@@ -700,7 +716,7 @@ int64 File::Copy(File &Dest,int64 Length)
{
Wait();
size_t SizeToRead=(!CopyAll && Length<(int64)Buffer.Size()) ? (size_t)Length:Buffer.Size();
char *Buf=&Buffer[0];
byte *Buf=&Buffer[0];
int ReadSize=Read(Buf,SizeToRead);
if (ReadSize==0)
break;

View File

@@ -39,6 +39,9 @@ enum FILE_MODE_FLAGS {
// Provide read access to created file for other programs.
FMF_SHAREREAD=16,
// Use standard NTFS names without trailing dots and spaces.
FMF_STANDARDNAMES=32,
// Mode flags are not defined yet.
FMF_UNDEFINED=256
};
@@ -59,6 +62,7 @@ class File
bool NoSequentialRead;
uint CreateMode;
#endif
bool PreserveAtime;
protected:
bool OpenShared; // Set by 'Archive' class.
public:
@@ -69,13 +73,16 @@ class File
File();
virtual ~File();
void operator = (File &SrcFile);
// Several functions below are 'virtual', because they are redefined
// by Archive for QOpen and by MultiFile for split files in WinRAR.
virtual bool Open(const wchar *Name,uint Mode=FMF_READ);
void TOpen(const wchar *Name);
bool WOpen(const wchar *Name);
bool Create(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
void TCreate(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
bool WCreate(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD);
bool Close();
virtual bool Close(); // 'virtual' for MultiFile class.
bool Delete();
bool Rename(const wchar *NewName);
bool Write(const void *Data,size_t Size);
@@ -93,7 +100,7 @@ class File
void SetCloseFileTime(RarTime *ftm,RarTime *fta=NULL);
static void SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta);
void GetOpenFileTime(RarTime *ft);
bool IsOpened() {return hFile!=FILE_BAD_HANDLE;};
virtual bool IsOpened() {return hFile!=FILE_BAD_HANDLE;} // 'virtual' for MultiFile class.
int64 FileLength();
void SetHandleType(FILE_HANDLETYPE Type) {HandleType=Type;}
FILE_HANDLETYPE GetHandleType() {return HandleType;}
@@ -108,6 +115,7 @@ class File
#ifdef _WIN_ALL
void RemoveSequentialFlag() {NoSequentialRead=true;}
#endif
void SetPreserveAtime(bool Preserve) {PreserveAtime=Preserve;}
#ifdef _UNIX
int GetFD()
{
@@ -118,6 +126,17 @@ class File
#endif
}
#endif
static size_t CopyBufferSize()
{
#ifdef _WIN_ALL
// USB flash performance is poor with 64 KB buffer, 256+ KB resolved it.
// For copying from HDD to same HDD the best performance was with 256 KB
// buffer in XP and with 1 MB buffer in Win10.
return WinNT()==WNT_WXP ? 0x40000:0x100000;
#else
return 0x100000;
#endif
}
};
#endif

View File

@@ -348,7 +348,7 @@ wchar *MkTemp(wchar *Name,size_t MaxSize)
swprintf(RndText,ASIZE(RndText),L"%u.%03u",PID,Ext);
if (Length+wcslen(RndText)>=MaxSize || Attempt==1000)
return NULL;
wcscpy(Name+Length,RndText);
wcsncpyz(Name+Length,RndText,MaxSize-Length);
if (!FileExist(Name))
break;
}
@@ -360,7 +360,7 @@ wchar *MkTemp(wchar *Name,size_t MaxSize)
#if !defined(SFX_MODULE)
void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,uint Flags)
{
SaveFilePos SavePos(*SrcFile);
int64 SavePos=SrcFile->Tell();
#ifndef SILENT
int64 FileLength=Size==INT64NDF ? SrcFile->FileLength() : Size;
#endif
@@ -415,6 +415,8 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,
if (Size!=INT64NDF)
Size-=ReadSize;
}
SrcFile->Seek(SavePos,SEEK_SET);
if ((Flags & CALCFSUM_SHOWPERCENT)!=0)
uiMsg(UIEVENT_FILESUMEND);

View File

@@ -46,26 +46,12 @@ bool ReadTextFile(
// Set to really read size, so we can zero terminate it correctly.
Data.Alloc(DataSize);
int LowEndian=DataSize>=2 && Data[0]==255 && Data[1]==254 ? 1:0;
int LittleEndian=DataSize>=2 && Data[0]==255 && Data[1]==254 ? 1:0;
int BigEndian=DataSize>=2 && Data[0]==254 && Data[1]==255 ? 1:0;
bool Utf8=DataSize>=3 && Data[0]==0xef && Data[1]==0xbb && Data[2]==0xbf;
if (SrcCharset==RCH_DEFAULT)
{
if (LowEndian || BigEndian)
for (size_t I=2;I<DataSize;I++)
if (Data[I]<32 && Data[I]!='\r' && Data[I]!='\n')
{
SrcCharset=RCH_UNICODE; // High byte in UTF-16 char is found.
break;
}
if (Utf8)
{
Data.Push(0); // Need a zero terminated string for UtfToWide.
if (IsTextUtf8((const char *)(Data+3)))
SrcCharset=RCH_UTF8;
}
}
SrcCharset=DetectTextEncoding(&Data[0],DataSize);
Array<wchar> DataW;
@@ -83,16 +69,16 @@ bool ReadTextFile(
if (SrcCharset==RCH_UNICODE)
{
size_t Start=2; // Skip byte order mark.
if (!LowEndian && !BigEndian) // No byte order mask.
if (!LittleEndian && !BigEndian) // No byte order mask.
{
Start=0;
LowEndian=1;
LittleEndian=1;
}
DataW.Alloc(Data.Size()/2+1);
size_t End=Data.Size() & ~1; // We need even bytes number for UTF-16.
for (size_t I=Start;I<End;I+=2)
DataW[(I-Start)/2]=Data[I+BigEndian]+Data[I+LowEndian]*256;
DataW[(I-Start)/2]=Data[I+BigEndian]+Data[I+LittleEndian]*256;
DataW[(End-Start)/2]=0;
}
@@ -160,3 +146,21 @@ bool ReadTextFile(
}
return true;
}
RAR_CHARSET DetectTextEncoding(const byte *Data,size_t DataSize)
{
if (DataSize>3 && Data[0]==0xef && Data[1]==0xbb && Data[2]==0xbf &&
IsTextUtf8(Data+3,DataSize-3))
return RCH_UTF8;
bool LittleEndian=DataSize>2 && Data[0]==255 && Data[1]==254;
bool BigEndian=DataSize>2 && Data[0]==254 && Data[1]==255;
if (LittleEndian || BigEndian)
for (size_t I=LittleEndian ? 3 : 2;I<DataSize;I+=2)
if (Data[I]<32 && Data[I]!='\r' && Data[I]!='\n')
return RCH_UNICODE; // High byte in UTF-16 char is found.
return RCH_DEFAULT;
}

View File

@@ -12,4 +12,6 @@ bool ReadTextFile(
bool ExpandEnvStr=false
);
RAR_CHARSET DetectTextEncoding(const byte *Data,size_t DataSize);
#endif

View File

@@ -26,7 +26,7 @@ FindFile::~FindFile()
void FindFile::SetMask(const wchar *Mask)
{
wcscpy(FindMask,Mask);
wcsncpyz(FindMask,Mask,ASIZE(FindMask));
FirstCall=true;
}
@@ -52,7 +52,7 @@ bool FindFile::Next(FindData *fd,bool GetSymLink)
wcsncpyz(DirName,FindMask,ASIZE(DirName));
RemoveNameFromPath(DirName);
if (*DirName==0)
wcscpy(DirName,L".");
wcsncpyz(DirName,L".",ASIZE(DirName));
char DirNameA[NM];
WideToChar(DirName,DirNameA,ASIZE(DirNameA));
if ((dirp=opendir(DirNameA))==NULL)
@@ -63,32 +63,32 @@ bool FindFile::Next(FindData *fd,bool GetSymLink)
}
while (1)
{
wchar Name[NM];
struct dirent *ent=readdir(dirp);
if (ent==NULL)
return false;
if (strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0)
continue;
wchar Name[NM];
if (!CharToWide(ent->d_name,Name,ASIZE(Name)))
uiMsg(UIERROR_INVALIDNAME,UINULL,Name);
if (CmpName(FindMask,Name,MATCH_NAMES))
{
wchar FullName[NM];
wcscpy(FullName,FindMask);
wcsncpyz(FullName,FindMask,ASIZE(FullName));
*PointToName(FullName)=0;
if (wcslen(FullName)+wcslen(Name)>=ASIZE(FullName)-1)
{
uiMsg(UIERROR_PATHTOOLONG,FullName,L"",Name);
return false;
}
wcscat(FullName,Name);
wcsncatz(FullName,Name,ASIZE(FullName));
if (!FastFind(FullName,fd,GetSymLink))
{
ErrHandler.OpenErrorMsg(FullName);
continue;
}
wcscpy(fd->Name,FullName);
wcsncpyz(fd->Name,FullName,ASIZE(fd->Name));
break;
}
}

View File

@@ -3,7 +3,12 @@ bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize)
SlashToNative(NameExisting,NameExisting,NameExistingSize); // Not needed for RAR 5.1+ archives.
if (!FileExist(NameExisting))
{
uiMsg(UIERROR_HLINKCREATE,NameNew);
uiMsg(UIERROR_NOLINKTARGET);
ErrHandler.SetErrorCode(RARX_CREATE);
return false;
}
CreatePath(NameNew,true);
#ifdef _WIN_ALL

View File

@@ -53,7 +53,7 @@ DataHash::DataHash()
DataHash::~DataHash()
{
#ifdef RAR_SMP
DestroyThreadPool(ThPool);
delete ThPool;
#endif
cleandata(&CurCRC32, sizeof(CurCRC32));
if (blake2ctx!=NULL)
@@ -94,7 +94,7 @@ void DataHash::Update(const void *Data,size_t DataSize)
{
#ifdef RAR_SMP
if (MaxThreads>1 && ThPool==NULL)
ThPool=CreateThreadPool();
ThPool=new ThreadPool(BLAKE2_THREADS_NUMBER);
blake2ctx->ThPool=ThPool;
blake2ctx->MaxThreads=MaxThreads;
#endif

View File

@@ -11,18 +11,14 @@
#define SIZEOF_SUBBLOCKHEAD 14
#define SIZEOF_COMMHEAD 13
#define SIZEOF_PROTECTHEAD 26
#define SIZEOF_AVHEAD 14
#define SIZEOF_SIGNHEAD 15
#define SIZEOF_UOHEAD 18
#define SIZEOF_MACHEAD 22
#define SIZEOF_EAHEAD 24
#define SIZEOF_BEEAHEAD 24
#define SIZEOF_STREAMHEAD 26
#define VER_PACK 29
#define VER_PACK5 50 // It is stored as 0, but we subtract 50 when saving an archive.
#define VER_UNPACK 29
#define VER_UNPACK5 50 // It is stored as 0, but we add 50 when reading an archive.
#define VER_PACK 29U
#define VER_PACK5 50U // It is stored as 0, but we subtract 50 when saving an archive.
#define VER_UNPACK 29U
#define VER_UNPACK5 50U // It is stored as 0, but we add 50 when reading an archive.
#define VER_UNKNOWN 9999U // Just some large value.
#define MHD_VOLUME 0x0001U
@@ -86,6 +82,8 @@ enum HEADER_TYPE {
HEAD3_SERVICE=0x7a,HEAD3_ENDARC=0x7b
};
// RAR 2.9 and earlier.
enum { EA_HEAD=0x100,UO_HEAD=0x101,MAC_HEAD=0x102,BEEA_HEAD=0x103,
NTACL_HEAD=0x104,STREAM_HEAD=0x105 };
@@ -177,7 +175,7 @@ struct MainHeader:BaseBlock
struct FileHeader:BlockHeader
{
byte HostOS;
byte UnpVer;
uint UnpVer; // It is 1 byte in RAR29 and bit field in RAR5.
byte Method;
union {
uint FileAttr;
@@ -193,7 +191,7 @@ struct FileHeader:BlockHeader
int64 PackSize;
int64 UnpSize;
int64 MaxSize; // Reserve size bytes for vint of this size.
int64 MaxSize; // Reserve packed and unpacked size bytes for vint of this size.
HashValue FileHash;
@@ -323,23 +321,6 @@ struct ProtectHeader:BlockHeader
};
struct AVHeader:BaseBlock
{
byte UnpVer;
byte Method;
byte AVVer;
uint AVInfoCRC;
};
struct SignHeader:BaseBlock
{
uint CreationTime;
ushort ArcNameSize;
ushort UserNameSize;
};
struct UnixOwnersHeader:SubBlockHeader
{
ushort OwnerNameSize;
@@ -370,11 +351,4 @@ struct StreamHeader:SubBlockHeader
};
struct MacFInfoHeader:SubBlockHeader
{
uint fileType;
uint fileCreator;
};
#endif

View File

@@ -71,6 +71,7 @@ void ListArchive(CommandData *Cmd)
*VolNumText=0;
while(Arc.ReadHeader()>0)
{
Wait(); // Allow quit listing with Ctrl+C.
HEADER_TYPE HeaderType=Arc.GetHeaderType();
if (HeaderType==HEAD_ENDARC)
{
@@ -91,7 +92,7 @@ void ListArchive(CommandData *Cmd)
switch(HeaderType)
{
case HEAD_FILE:
FileMatched=Cmd->IsProcessFile(Arc.FileHead)!=0;
FileMatched=Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0;
if (FileMatched)
{
ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare);
@@ -215,7 +216,7 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
wchar UnpSizeText[30],PackSizeText[30];
if (hd.UnpSize==INT64NDF)
wcscpy(UnpSizeText,L"?");
wcsncpyz(UnpSizeText,L"?",ASIZE(UnpSizeText));
else
itoa(hd.UnpSize,UnpSizeText,ASIZE(UnpSizeText));
itoa(hd.PackSize,PackSizeText,ASIZE(PackSizeText));
@@ -229,13 +230,13 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
wchar RatioStr[10];
if (hd.SplitBefore && hd.SplitAfter)
wcscpy(RatioStr,L"<->");
wcsncpyz(RatioStr,L"<->",ASIZE(RatioStr));
else
if (hd.SplitBefore)
wcscpy(RatioStr,L"<--");
wcsncpyz(RatioStr,L"<--",ASIZE(RatioStr));
else
if (hd.SplitAfter)
wcscpy(RatioStr,L"-->");
wcsncpyz(RatioStr,L"-->",ASIZE(RatioStr));
else
swprintf(RatioStr,ASIZE(RatioStr),L"%d%%",ToPercentUnlim(hd.PackSize,hd.UnpSize));
@@ -344,7 +345,8 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
mprintf(L"\n%12ls: %ls",St(MListHostOS),HostOS);
mprintf(L"\n%12ls: RAR %ls(v%d) -m%d -md=%d%s",St(MListCompInfo),
Format==RARFMT15 ? L"3.0":L"5.0",hd.UnpVer,hd.Method,
Format==RARFMT15 ? L"1.5":L"5.0",
hd.UnpVer==VER_UNKNOWN ? 0 : hd.UnpVer,hd.Method,
hd.WinSize>=0x100000 ? hd.WinSize/0x100000:hd.WinSize/0x400,
hd.WinSize>=0x100000 ? L"M":L"K");
@@ -466,7 +468,7 @@ void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSiz
(A & 0x0001) ? ((A & 0x200)!=0 ? 't' : 'x') : '-');
break;
case HSYS_UNKNOWN:
wcscpy(AttrStr,L"?");
wcsncpyz(AttrStr,L"?",AttrSize);
break;
}
}

View File

@@ -82,10 +82,10 @@
#define MCHelpSwIDP L"\n id[c,d,p,q] Disable messages"
#define MCHelpSwIEML L"\n ieml[addr] Send archive by email"
#define MCHelpSwIERR L"\n ierr Send all messages to stderr"
#define MCHelpSwILOG L"\n ilog[name] Log errors to file (registered versions only)"
#define MCHelpSwILOG L"\n ilog[name] Log errors to file"
#define MCHelpSwINUL L"\n inul Disable all messages"
#define MCHelpSwIOFF L"\n ioff Turn PC off after completing an operation"
#define MCHelpSwISND L"\n isnd Enable sound"
#define MCHelpSwIOFF L"\n ioff[n] Turn PC off after completing an operation"
#define MCHelpSwISND L"\n isnd[-] Control notification sounds"
#define MCHelpSwIVER L"\n iver Display the version number"
#define MCHelpSwK L"\n k Lock archive"
#define MCHelpSwKB L"\n kb Keep broken extracted files"
@@ -127,11 +127,11 @@
#define MCHelpSwT L"\n t Test files after archiving"
#define MCHelpSwTK L"\n tk Keep original archive time"
#define MCHelpSwTL L"\n tl Set archive time to latest file"
#define MCHelpSwTN L"\n tn<time> Process files newer than <time>"
#define MCHelpSwTO L"\n to<time> Process files older than <time>"
#define MCHelpSwTA L"\n ta<date> Process files modified after <date> in YYYYMMDDHHMMSS format"
#define MCHelpSwTB L"\n tb<date> Process files modified before <date> in YYYYMMDDHHMMSS format"
#define MCHelpSwTS L"\n ts[m|c|a] Save or restore file time (modification, creation, access)"
#define MCHelpSwTN L"\n tn[mcao]<t> Process files newer than <t> time"
#define MCHelpSwTO L"\n to[mcao]<t> Process files older than <t> time"
#define MCHelpSwTA L"\n ta[mcao]<d> Process files modified after <d> YYYYMMDDHHMMSS date"
#define MCHelpSwTB L"\n tb[mcao]<d> Process files modified before <d> YYYYMMDDHHMMSS date"
#define MCHelpSwTS L"\n ts[m,c,a,p] Save or restore time (modification, creation, access, preserve)"
#define MCHelpSwU L"\n u Update files"
#define MCHelpSwV L"\n v Create volumes with size autodetection or list all volumes"
#define MCHelpSwVUnr L"\n v List all volumes"
@@ -203,7 +203,6 @@
#define MErrOpenFile L"file"
#define MAddNoFiles L"\nWARNING: No files"
#define MMdfEncrSol L"\n%s: encrypted"
#define MCannotMdfEncrSol L"\nCannot modify solid archive containing encrypted files"
#define MAddAnalyze L"\nAnalyzing archived files: "
#define MRepacking L"\nRepacking archived files: "
#define MCRCFailed L"\n%-20s - checksum error"
@@ -294,7 +293,8 @@
#define MRprNoFiles L"\nNo files found"
#define MLogUnexpEOF L"\nUnexpected end of archive"
#define MRepAskReconst L"\nReconstruct archive structure ?"
#define MRecScanning L"\nScanning..."
#define MRRSearch L"\nSearching for recovery record"
#define MAnalyzeFileData L"\nAnalyzing file data"
#define MRecRNotFound L"\nData recovery record not found"
#define MRecRFound L"\nData recovery record found"
#define MRecSecDamage L"\nSector %ld (offsets %lX...%lX) damaged"
@@ -310,8 +310,6 @@
#define MErrLnkRead L"\nWARNING: Cannot read symbolic link %s"
#define MSymLinkExists L"\nWARNING: Symbolic link %s already exists"
#define MAskRetryCreate L"\nCannot create %s. Retry ?"
#define MListMACHead1 L"\n Mac OS file type: %c%c%c%c ; "
#define MListMACHead2 L"file creator: %c%c%c%c\n"
#define MDataBadCRC L"\n%-20s : packed data checksum error in volume %s"
#define MFileRO L"\n%s is read-only"
#define MACLGetError L"\nWARNING: Cannot get %s security data\n"
@@ -343,7 +341,7 @@
#define MFAT32Size L"\nWARNING: FAT32 file system does not support 4 GB or larger files"
#define MErrChangeAttr L"\nWARNING: Cannot change attributes of %s"
#define MWrongSFXVer L"\nERROR: default SFX module does not support RAR %d.%d archives"
#define MCannotEncName L"\nCannot encrypt archive already containing encrypted files"
#define MHeadEncMismatch L"\nCannot change the header encryption mode in already encrypted archive"
#define MCannotEmail L"\nCannot email the file %s"
#define MCopyrightS L"\nRAR SFX archive"
#define MSHelpCmd L"\n\n<Commands>"
@@ -353,16 +351,17 @@
#define MRecVolLimit L"\nTotal number of usual and recovery volumes must not exceed %d"
#define MVolumeNumber L"volume %d"
#define MCannotDelete L"\nCannot delete %s"
#define MRecycleFailed L"\nCannot move some files and folders to Recycle Bin"
#define MCalcCRC L"\nCalculating the checksum"
#define MTooLargeSFXArc L"\nWARNING: Too large SFX archive. Windows cannot run the executable file exceeding 4 GB."
#define MTooLargeSFXArc L"\nToo large SFX archive. Windows cannot run the executable file exceeding 4 GB."
#define MCalcCRCAllVol L"\nCalculating checksums of all volumes."
#define MNotEnoughDisk L"\nERROR: Not enough disk space for %s."
#define MNewerRAR L"\nYou may need a newer version of RAR."
#define MUnkEncMethod L"\nUnknown encryption method in %s"
#define MWrongPassword L"\nThe specified password is incorrect."
#define MRepairing L"\nRepairing"
#define MWrongFilePassword L"\nIncorrect password for %s"
#define MAreaDamaged L"\nCorrupt %d bytes at %08x %08x"
#define MBlocksRecovered L"\n%d blocks recovered."
#define MBlocksRecovered L"\n%u blocks are recovered, %u blocks are relocated"
#define MRRDamaged L"\nRecovery record is corrupt."
#define MTestingRR L"\nTesting the recovery record"
#define MFailed L"Failed"
@@ -376,6 +375,8 @@
#define MCopyingData L"\nCopying data"
#define MErrCreateLnkS L"\nCannot create symbolic link %s"
#define MErrCreateLnkH L"\nCannot create hard link %s"
#define MErrLnkTarget L"\nYou need to unpack the link target first"
#define MNeedAdmin L"\nYou may need to run RAR as administrator"
#define MDictOutMem L"\nNot enough memory for %d MB compression dictionary, changed to %d MB."
#define MUseSmalllerDict L"\nPlease use a smaller compression dictionary."
#define MOpenErrAtime L"\nYou may need to remove -tsp switch to open this file."

View File

@@ -3,7 +3,7 @@
# Linux using GCC
CXX=c++
CXXFLAGS=-O2
CXXFLAGS=-O2 -Wno-logical-op-parentheses -Wno-switch -Wno-dangling-else
LIBFLAGS=-fPIC
DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -DRAR_SMP
STRIP=strip
@@ -138,7 +138,9 @@ install: install-unrar
uninstall: uninstall-unrar
clean:
@rm -f *.o *.bak *~
@rm -f *.bak *~
@rm -f $(OBJECTS) $(UNRAR_OBJ) $(LIB_OBJ)
@rm -f unrar libunrar.*
unrar: clean $(OBJECTS) $(UNRAR_OBJ)
@rm -f unrar
@@ -154,8 +156,7 @@ sfx: clean $(OBJECTS)
lib: WHAT=RARDLL
lib: CXXFLAGS+=$(LIBFLAGS)
lib: clean $(OBJECTS) $(LIB_OBJ)
@rm -f libunrar.so
@rm -f libunrar.a
@rm -f libunrar.*
$(LINK) -shared -o libunrar.so $(LDFLAGS) $(OBJECTS) $(LIB_OBJ)
$(AR) rcs libunrar.a $(OBJECTS) $(LIB_OBJ)

View File

@@ -25,10 +25,10 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode)
if (CmpMode!=MATCH_NAMES)
{
size_t WildLength=wcslen(Wildcard);
if (CmpMode!=MATCH_EXACT && CmpMode!=MATCH_EXACTPATH &&
if (CmpMode!=MATCH_EXACT && CmpMode!=MATCH_EXACTPATH && CmpMode!=MATCH_ALLWILD &&
mwcsnicompc(Wildcard,Name,WildLength,ForceCase)==0)
{
// For all modes except MATCH_NAMES, MATCH_EXACT and MATCH_EXACTPATH
// For all modes except MATCH_NAMES, MATCH_EXACT, MATCH_EXACTPATH, MATCH_ALLWILD,
// "path1" mask must match "path1\path2\filename.ext" and "path1" names.
wchar NextCh=Name[WildLength];
if (NextCh==L'\\' || NextCh==L'/' || NextCh==0)
@@ -46,6 +46,8 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode)
if ((CmpMode==MATCH_EXACT || CmpMode==MATCH_EXACTPATH) &&
mwcsicompc(Path1,Path2,ForceCase)!=0)
return(false);
if (CmpMode==MATCH_ALLWILD)
return match(Wildcard,Name,ForceCase);
if (CmpMode==MATCH_SUBPATH || CmpMode==MATCH_WILDSUBPATH)
if (IsWildcard(Path1))
return(match(Wildcard,Name,ForceCase));
@@ -64,8 +66,8 @@ bool CmpName(const wchar *Wildcard,const wchar *Name,int CmpMode)
// Always return false for RAR temporary files to exclude them
// from archiving operations.
if (mwcsnicompc(L"__rar_",Name2,6,false)==0)
return(false);
// if (mwcsnicompc(L"__rar_",Name2,6,false)==0)
// return(false);
if (CmpMode==MATCH_EXACT)
return(mwcsicompc(Name1,Name2,ForceCase)==0);

View File

@@ -14,6 +14,10 @@ enum {
MATCH_EXACT, // Paths must match exactly.
// Names must match exactly.
MATCH_ALLWILD, // Paths and names are compared using wildcards.
// Unlike MATCH_SUBPATH, paths do not match subdirs
// unless a wildcard tells so.
MATCH_EXACTPATH, // Paths must match exactly.
// Names are compared using wildcards.

View File

@@ -42,10 +42,14 @@ void ModelPPM::RestartModelRare()
SubAlloc.InitSubAllocator();
InitRL=-(MaxOrder < 12 ? MaxOrder:12)-1;
MinContext = MaxContext = (RARPPM_CONTEXT*) SubAlloc.AllocContext();
if (MinContext == NULL)
throw std::bad_alloc();
MinContext->Suffix=NULL;
OrderFall=MaxOrder;
MinContext->U.SummFreq=(MinContext->NumStats=256)+1;
FoundState=MinContext->U.Stats=(RARPPM_STATE*)SubAlloc.AllocUnits(256/2);
if (FoundState == NULL)
throw std::bad_alloc();
for (RunLength=InitRL, PrevSuccess=i=0;i < 256;i++)
{
MinContext->U.Stats[i].Symbol=i;
@@ -166,9 +170,6 @@ void RARPPM_CONTEXT::rescale(ModelPPM *Model)
inline RARPPM_CONTEXT* ModelPPM::CreateSuccessors(bool Skip,RARPPM_STATE* p1)
{
#ifdef __ICL
static
#endif
RARPPM_STATE UpState;
RARPPM_CONTEXT* pc=MinContext, * UpBranch=FoundState->Successor;
RARPPM_STATE * p, * ps[MAX_O], ** pps=ps;
@@ -202,7 +203,14 @@ LOOP_ENTRY:
{
pc=p->Successor;
break;
}
// We ensure that PPM order input parameter does not exceed MAX_O (64),
// so we do not really need this check and added it for extra safety.
// See CVE-2017-17969 for details.
if (pps>=ps+ASIZE(ps))
return NULL;
*pps++ = p;
} while ( pc->Suffix );
NO_LOOP:
@@ -492,6 +500,12 @@ inline bool RARPPM_CONTEXT::decodeSymbol2(ModelPPM *Model)
p++;
} while (Model->CharMask[p->Symbol] == Model->EscCount);
HiCnt += p->Freq;
// We do not reuse PPMd coder in unstable state, so we do not really need
// this check and added it for extra safety. See CVE-2017-17969 for details.
if (pps>=ps+ASIZE(ps))
return false;
*pps++ = p;
} while ( --i );
Model->Coder.SubRange.scale += HiCnt;
@@ -503,7 +517,12 @@ inline bool RARPPM_CONTEXT::decodeSymbol2(ModelPPM *Model)
{
HiCnt=0;
while ((HiCnt += p->Freq) <= count)
p=*++pps;
{
pps++;
if (pps>=ps+ASIZE(ps)) // Extra safety check.
return false;
p=*pps;
}
Model->Coder.SubRange.LowCount = (Model->Coder.SubRange.HighCount=HiCnt)-p->Freq;
psee2c->update();
update2(Model,p);
@@ -516,12 +535,15 @@ inline bool RARPPM_CONTEXT::decodeSymbol2(ModelPPM *Model)
pps--;
do
{
Model->CharMask[(*++pps)->Symbol]=Model->EscCount;
pps++;
if (pps>=ps+ASIZE(ps)) // Extra safety check.
return false;
Model->CharMask[(*pps)->Symbol]=Model->EscCount;
} while ( --i );
psee2c->Summ += Model->Coder.SubRange.scale;
Model->NumMasked = NumStats;
}
return(true);
return true;
}

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,7 @@ void RAROptions::Init()
Method=3;
MsgStream=MSG_STDOUT;
ConvertNames=NAMES_ORIGINALCASE;
xmtime=EXTTIME_HIGH3;
xmtime=EXTTIME_MAX;
FileSizeLess=INT64NDF;
FileSizeMore=INT64NDF;
HashType=HASH_CRC32;

View File

@@ -12,11 +12,7 @@ enum PATH_EXCL_MODE {
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.
EXCL_ABSPATH // -ep3 (the full path with the disk letter)
};
enum {SOLID_NONE=0,SOLID_NORMAL=1,SOLID_COUNT=2,SOLID_FILEEXT=4,
@@ -25,7 +21,7 @@ enum {SOLID_NONE=0,SOLID_NORMAL=1,SOLID_COUNT=2,SOLID_FILEEXT=4,
enum {ARCTIME_NONE=0,ARCTIME_KEEP,ARCTIME_LATEST};
enum EXTTIME_MODE {
EXTTIME_NONE=0,EXTTIME_1S,EXTTIME_HIGH1,EXTTIME_HIGH2,EXTTIME_HIGH3
EXTTIME_NONE=0,EXTTIME_1S,EXTTIME_MAX
};
enum {NAMES_ORIGINALCASE=0,NAMES_UPPERCASE,NAMES_LOWERCASE};
@@ -63,6 +59,20 @@ enum SAVECOPY_MODE {
SAVECOPY_DUPLISTEXIT
};
enum APPENDARCNAME_MODE
{
APPENDARCNAME_NONE=0,APPENDARCNAME_DESTPATH,APPENDARCNAME_OWNDIR
};
enum POWER_MODE {
POWERMODE_KEEP=0,POWERMODE_OFF,POWERMODE_HIBERNATE,POWERMODE_SLEEP,
POWERMODE_RESTART
};
// Need "forced off" state to turn off sound in GUI command line.
enum SOUND_NOTIFY_MODE {SOUND_NOTIFY_DEFAULT=0,SOUND_NOTIFY_ON,SOUND_NOTIFY_OFF};
struct FilterMode
{
FilterState State;
@@ -82,13 +92,21 @@ class RAROptions
uint ExclFileAttr;
uint InclFileAttr;
// We handle -ed and -e+d with special flags instead of attribute mask,
// so it works with both Windows and Unix archives.
bool ExclDir;
bool InclDir;
bool InclAttrSet;
size_t WinSize;
wchar TempPath[NM];
#ifdef USE_QOPEN
wchar SFXModule[NM];
#ifdef USE_QOPEN
QOPEN_MODE QOpenMode;
#endif
bool ConfigDisabled; // Switch -cfg-.
wchar ExtrPath[NM];
wchar CommentFile[NM];
@@ -105,7 +123,7 @@ class RAROptions
wchar LogName[NM];
MESSAGE_TYPE MsgStream;
bool Sound;
SOUND_NOTIFY_MODE Sound;
OVERWRITE_MODE Overwrite;
int Method;
HASH_TYPE HashType;
@@ -128,6 +146,7 @@ class RAROptions
Array<int64> NextVolSizes;
uint CurVolNum;
bool AllYes;
bool MoreInfo; // -im, show more information, used only in "WinRAR t" now.
bool DisableSortSolid;
int ArcTime;
int ConvertNames;
@@ -149,14 +168,17 @@ class RAROptions
#ifndef SFX_MODULE
bool GenerateArcName;
wchar GenerateMask[MAX_GENERATE_MASK];
wchar DefGenerateMask[MAX_GENERATE_MASK];
#endif
bool SyncFiles;
bool ProcessEA;
bool SaveStreams;
bool SetCompressedAttr;
bool IgnoreGeneralAttr;
RarTime FileTimeBefore;
RarTime FileTimeAfter;
RarTime FileMtimeBefore,FileCtimeBefore,FileAtimeBefore;
bool FileMtimeBeforeOR,FileCtimeBeforeOR,FileAtimeBeforeOR;
RarTime FileMtimeAfter,FileCtimeAfter,FileAtimeAfter;
bool FileMtimeAfterOR,FileCtimeAfterOR,FileAtimeAfterOR;
int64 FileSizeLess;
int64 FileSizeMore;
bool Lock;
@@ -165,11 +187,12 @@ class RAROptions
FilterMode FilterModes[MAX_FILTER_TYPES];
wchar EmailTo[NM];
uint VersionControl;
bool AppendArcNameToPath;
bool Shutdown;
EXTTIME_MODE xmtime;
APPENDARCNAME_MODE AppendArcNameToPath;
POWER_MODE Shutdown;
EXTTIME_MODE xmtime; // Extended time modes (time precision to store).
EXTTIME_MODE xctime;
EXTTIME_MODE xatime;
bool PreserveAtime;
wchar CompressStdin[NM];
uint Threads; // We use it to init hash even if RAR_SMP is not defined.

View File

@@ -22,8 +22,22 @@
#ifdef _WIN_ALL
#define STRICT
// We got a report that just "#define STRICT" is incompatible with
// "#define STRICT 1" in Windows 10 SDK minwindef.h and depending on the order
// in which these statements are reached this may cause a compiler warning
// and build break for other projects incorporating this source.
// So we changed it to "#define STRICT 1".
#ifndef STRICT
#define STRICT 1
#endif
// 'ifndef' check here is needed for unrar.dll header to avoid macro
// re-definition warnings in third party projects.
#ifndef UNICODE
#define UNICODE
#endif
#undef WINVER
#undef _WIN32_WINNT
#define WINVER 0x0501
@@ -39,6 +53,8 @@
#include <prsht.h>
#include <shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
#include <PowrProf.h>
#pragma comment(lib, "PowrProf.lib")
#include <shellapi.h>
#include <shlobj.h>
#include <winioctl.h>
@@ -117,7 +133,7 @@
#ifdef _UNIX
#define NM 2048
#define NM 2048
#include <unistd.h>
#include <sys/types.h>

View File

@@ -16,7 +16,7 @@ wchar* PointToLastChar(const wchar *Path)
}
wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath)
wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath,size_t DestSize)
{
const wchar *DestPtr=SrcPath;
@@ -25,7 +25,7 @@ wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath)
if (IsPathDiv(s[0]) && s[1]=='.' && s[2]=='.' && IsPathDiv(s[3]))
DestPtr=s+4;
// Remove <d>:\ and any sequence of . and \ in the beginning of path string.
// Remove any amount of <d>:\ and any sequence of . and \ in the beginning of path string.
while (*DestPtr!=0)
{
const wchar *s=DestPtr;
@@ -58,7 +58,7 @@ wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath)
// so we use the temporary buffer for copying.
wchar TmpStr[NM];
wcsncpyz(TmpStr,DestPtr,ASIZE(TmpStr));
wcscpy(DestPath,TmpStr);
wcsncpyz(DestPath,TmpStr,DestSize);
}
return (wchar *)DestPtr;
}
@@ -120,7 +120,14 @@ bool CmpExt(const wchar *Name,const wchar *Ext)
bool IsWildcard(const wchar *Str)
{
return Str==NULL ? false:wcspbrk(Str,L"*?")!=NULL;
if (Str==NULL)
return false;
#ifdef _WIN_ALL
// Not treat the special NTFS \\?\d: path prefix as a wildcard.
if (Str[0]=='\\' && Str[1]=='\\' && Str[2]=='?' && Str[3]=='\\')
Str+=4;
#endif
return wcspbrk(Str,L"*?")!=NULL;
}
@@ -164,13 +171,16 @@ void AddEndSlash(wchar *Path,size_t MaxLength)
{
size_t Length=wcslen(Path);
if (Length>0 && Path[Length-1]!=CPATHDIVIDER && Length+1<MaxLength)
wcscat(Path,SPATHDIVIDER);
{
Path[Length]=CPATHDIVIDER;
Path[Length+1]=0;
}
}
void MakeName(const wchar *Path,const wchar *Name,wchar *Pathname,size_t MaxSize)
{
// 'Name' and 'Pathname' can point to same memory area. This is why we use
// 'Path', 'Name' and 'Pathname' can point to same memory area. So we use
// the temporary buffer instead of constructing the name in 'Pathname'.
wchar OutName[NM];
wcsncpyz(OutName,Path,ASIZE(OutName));
@@ -260,9 +270,9 @@ bool EnumConfigPaths(uint Number,wchar *Path,size_t MaxSize,bool Create)
{
char *EnvStr=getenv("HOME");
if (EnvStr!=NULL)
GetWideName(EnvStr,NULL,Path,MaxSize);
CharToWide(EnvStr,Path,MaxSize);
else
wcsncpyz(Path, ConfPath[0], MaxSize);
wcsncpyz(Path,ConfPath[0],MaxSize);
return true;
}
Number--;
@@ -303,9 +313,13 @@ void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckEx
#endif
// Returns a pointer to rightmost digit of volume number.
// Returns a pointer to rightmost digit of volume number or to beginning
// of file name if numeric part is missing.
wchar* GetVolNumPart(const wchar *ArcName)
{
if (*ArcName==0)
return (wchar *)ArcName;
// Pointing to last name character.
const wchar *ChPtr=ArcName+wcslen(ArcName)-1;
@@ -346,18 +360,33 @@ void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering)
ChPtr=GetExt(ArcName);
}
else
if (ChPtr[1]==0 && wcslen(ArcName)<MaxLength-3 || wcsicomp(ChPtr+1,L"exe")==0 || wcsicomp(ChPtr+1,L"sfx")==0)
wcscpy(ChPtr+1,L"rar");
if (ChPtr[1]==0 || wcsicomp(ChPtr,L".exe")==0 || wcsicomp(ChPtr,L".sfx")==0)
wcsncpyz(ChPtr,L".rar",MaxLength-(ChPtr-ArcName));
if (ChPtr==NULL || *ChPtr!='.' || ChPtr[1]==0)
{
// Normally we shall have some extension here. If we don't, it means
// the name has no extension and buffer has no free space to append one.
// Let's clear the name to prevent a new call with same name and return.
*ArcName=0;
return;
}
if (!OldNumbering)
{
ChPtr=GetVolNumPart(ArcName);
// We should not check for IsDigit(*ChPtr) here and should increment
// even non-digits. If we got a corrupt archive with volume flag,
// but without numeric part, we still need to modify its name somehow,
// so while (exist(name)) {NextVolumeName()} loops do not run infinitely.
while ((++(*ChPtr))=='9'+1)
{
*ChPtr='0';
ChPtr--;
if (ChPtr<ArcName || !IsDigit(*ChPtr))
{
// Convert .part:.rar (.part9.rar after increment) to part10.rar.
for (wchar *EndPtr=ArcName+wcslen(ArcName);EndPtr!=ChPtr;EndPtr--)
*(EndPtr+1)=*EndPtr;
*(ChPtr+1)='1';
@@ -366,15 +395,15 @@ void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering)
}
}
else
if (!IsDigit(*(ChPtr+2)) || !IsDigit(*(ChPtr+3)))
wcscpy(ChPtr+2,L"00");
if (!IsDigit(ChPtr[2]) || !IsDigit(ChPtr[3]))
wcsncpyz(ChPtr+2,L"00",MaxLength-(ChPtr-ArcName)-2); // From .rar to .r00.
else
{
ChPtr+=3;
while ((++(*ChPtr))=='9'+1)
if (*(ChPtr-1)=='.')
ChPtr+=wcslen(ChPtr)-1; // Set to last character.
while (++(*ChPtr)=='9'+1)
if (ChPtr<=ArcName || *(ChPtr-1)=='.')
{
*ChPtr='A';
*ChPtr='a'; // From .999 to .a00 if started from .001 or for too short names.
break;
}
else
@@ -585,8 +614,7 @@ int ParseVersionFileName(wchar *Name,bool Truncate)
wchar *VerText=wcsrchr(Name,';');
if (VerText!=NULL)
{
if (Version==0)
Version=atoiw(VerText+1);
Version=atoiw(VerText+1);
if (Truncate)
*VerText=0;
}
@@ -652,7 +680,7 @@ wchar* VolNameToFirstName(const wchar *VolName,wchar *FirstName,size_t MaxSize,b
#ifndef SFX_MODULE
static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,bool &ArcNumPresent)
static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,uint ArcNumber,bool &ArcNumPresent)
{
bool Prefix=false;
if (*GenerateMask=='+')
@@ -713,7 +741,7 @@ static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,b
wchar Ext[NM],*Dot=GetExt(ArcName);
*Ext=0;
if (Dot==NULL)
wcscpy(Ext,*PointToName(ArcName)==0 ? L".rar":L"");
wcsncpyz(Ext,*PointToName(ArcName)==0 ? L".rar":L"",ASIZE(Ext));
else
{
wcsncpyz(Ext,Dot,ASIZE(Ext));
@@ -749,7 +777,7 @@ static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,b
int CField[sizeof(Field)/sizeof(Field[0])];
memset(CField,0,sizeof(CField));
QuoteMode=false;
for (int I=0;Mask[I]!=0;I++)
for (uint I=0;Mask[I]!=0;I++)
{
if (Mask[I]=='{' || Mask[I]=='}')
{
@@ -810,21 +838,17 @@ static void GenArcName(wchar *ArcName,const wchar *GenerateMask,uint ArcNumber,b
AddEndSlash(NewName,ASIZE(NewName));
wcsncatz(NewName,DateText,ASIZE(NewName));
wcsncatz(NewName,PointToName(ArcName),ASIZE(NewName));
wcscpy(ArcName,NewName);
wcsncpyz(ArcName,NewName,MaxSize);
}
else
wcscat(ArcName,DateText);
wcscat(ArcName,Ext);
wcsncatz(ArcName,DateText,MaxSize);
wcsncatz(ArcName,Ext,MaxSize);
}
void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,bool Archiving)
{
// Must be enough space for archive name plus all stuff in mask plus
// extra overhead produced by mask 'N' (archive number) characters.
// One 'N' character can result in several numbers if we process more
// than 9 archives.
wchar NewName[NM+MAX_GENERATE_MASK+20];
wchar NewName[NM];
uint ArcNumber=1;
while (true) // Loop for 'N' (archive number) processing.
@@ -833,7 +857,7 @@ void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask
bool ArcNumPresent=false;
GenArcName(NewName,GenerateMask,ArcNumber,ArcNumPresent);
GenArcName(NewName,ASIZE(NewName),GenerateMask,ArcNumber,ArcNumPresent);
if (!ArcNumPresent)
break;
@@ -845,7 +869,7 @@ void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask
// existing archive before the first unused name. So we generate
// the name for (ArcNumber-1) below.
wcsncpyz(NewName,NullToEmpty(ArcName),ASIZE(NewName));
GenArcName(NewName,GenerateMask,ArcNumber-1,ArcNumPresent);
GenArcName(NewName,ASIZE(NewName),GenerateMask,ArcNumber-1,ArcNumPresent);
}
break;
}
@@ -895,8 +919,8 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize)
{
if (MaxSize<=PrefixLength+SrcLength)
return false;
wcsncpy(Dest,Prefix,PrefixLength);
wcscpy(Dest+PrefixLength,Src);
wcsncpyz(Dest,Prefix,MaxSize);
wcsncatz(Dest,Src,MaxSize); // "\\?\D:\very long path".
return true;
}
else
@@ -904,9 +928,9 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize)
{
if (MaxSize<=PrefixLength+SrcLength+2)
return false;
wcsncpy(Dest,Prefix,PrefixLength);
wcscpy(Dest+PrefixLength,L"UNC");
wcscpy(Dest+PrefixLength+3,Src+1);
wcsncpyz(Dest,Prefix,MaxSize);
wcsncatz(Dest,L"UNC",MaxSize);
wcsncatz(Dest,Src+1,MaxSize); // "\\?\UNC\server\share".
return true;
}
// We may be here only if we modify IsFullPath in the future.
@@ -923,9 +947,10 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize)
{
if (MaxSize<=PrefixLength+SrcLength+2)
return false;
wcsncpy(Dest,Prefix,PrefixLength);
wcsncpy(Dest+PrefixLength,CurDir,2); // Copy drive letter 'd:'.
wcscpy(Dest+PrefixLength+2,Src);
wcsncpyz(Dest,Prefix,MaxSize);
CurDir[2]=0;
wcsncatz(Dest,CurDir,MaxSize); // Copy drive letter 'd:'.
wcsncatz(Dest,Src,MaxSize);
return true;
}
else // Paths in path\name format.
@@ -933,8 +958,8 @@ bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize)
AddEndSlash(CurDir,ASIZE(CurDir));
if (MaxSize<=PrefixLength+wcslen(CurDir)+SrcLength)
return false;
wcsncpy(Dest,Prefix,PrefixLength);
wcscpy(Dest+PrefixLength,CurDir);
wcsncpyz(Dest,Prefix,MaxSize);
wcsncatz(Dest,CurDir,MaxSize);
if (Src[0]=='.' && IsPathDiv(Src[1])) // Remove leading .\ in pathname.
Src+=2;
@@ -969,7 +994,8 @@ void MakeNameCompatible(wchar *Name)
if (IsPathDiv(Name[Src]) || Name[Src]==0)
for (int I=Dest-1;I>0 && (Name[I]==' ' || Name[I]=='.');I--)
{
if (IsPathDiv(Name[I-1])) // Permit path1/./path2 paths.
// Permit path1/./path2 and ../path1 paths.
if (Name[I]=='.' && (IsPathDiv(Name[I-1]) || Name[I-1]=='.' && I==1))
break;
Dest--;
}

View File

@@ -3,7 +3,7 @@
wchar* PointToName(const wchar *Path);
wchar* PointToLastChar(const wchar *Path);
wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath);
wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath,size_t DestSize);
void SetName(wchar *FullName,const wchar *Name,size_t MaxSize);
void SetExt(wchar *Name,const wchar *NewExt,size_t MaxSize);
void SetSFXExt(wchar *SFXName,size_t MaxSize);

View File

@@ -61,19 +61,36 @@ void QuickOpen::Close()
void QuickOpen::Load(uint64 BlockPos)
{
if (!Loaded) // If loading the first time, perform additional intialization.
if (!Loaded)
{
// If loading for the first time, perform additional intialization.
SeekPos=Arc->Tell();
UnsyncSeekPos=false;
SaveFilePos SavePos(*Arc);
int64 SavePos=SeekPos;
Arc->Seek(BlockPos,SEEK_SET);
if (Arc->ReadHeader()==0 || Arc->GetHeaderType()!=HEAD_SERVICE ||
// If BlockPos points to original main header, we'll have the infinite
// recursion, because ReadHeader() for main header will attempt to load
// QOpen and call QuickOpen::Load again. If BlockPos points to long chain
// of other main headers, we'll have multiple recursive calls of this
// function wasting resources. So we prohibit QOpen temporarily to
// prevent this. ReadHeader() calls QOpen.Init and sets MainHead Locator
// and QOpenOffset fields, so we cannot use them to prohibit QOpen.
Arc->SetProhibitQOpen(true);
size_t ReadSize=Arc->ReadHeader();
Arc->SetProhibitQOpen(false);
if (ReadSize==0 || Arc->GetHeaderType()!=HEAD_SERVICE ||
!Arc->SubHead.CmpName(SUBHEAD_TYPE_QOPEN))
{
Arc->Seek(SavePos,SEEK_SET);
return;
QLHeaderPos=Arc->CurBlockPos;
}
QOHeaderPos=Arc->CurBlockPos;
RawDataStart=Arc->Tell();
RawDataSize=Arc->SubHead.UnpSize;
Arc->Seek(SavePos,SEEK_SET);
Loaded=true; // Set only after all file processing calls like Tell, Seek, ReadHeader.
}
@@ -88,7 +105,10 @@ void QuickOpen::Load(uint64 BlockPos)
Arc->SubHead.HashKey,Arc->SubHead.PswCheck);
else
#endif
{
Loaded=false;
return;
}
}
RawDataPos=0;
@@ -156,7 +176,7 @@ bool QuickOpen::Seek(int64 Offset,int Method)
// archive updating involve several passes. So if we detect that file
// pointer is moved back, we reload quick open data from beginning.
if (Method==SEEK_SET && (uint64)Offset<SeekPos && (uint64)Offset<LastReadHeaderPos)
Load(QLHeaderPos);
Load(QOHeaderPos);
if (Method==SEEK_SET)
SeekPos=Offset;
@@ -185,22 +205,28 @@ bool QuickOpen::Tell(int64 *Pos)
uint QuickOpen::ReadBuffer()
{
SaveFilePos SavePos(*Arc);
int64 SavePos=Arc->Tell();
Arc->File::Seek(RawDataStart+RawDataPos,SEEK_SET);
size_t SizeToRead=(size_t)Min(RawDataSize-RawDataPos,MaxBufSize-ReadBufSize);
if (Arc->SubHead.Encrypted)
SizeToRead &= ~CRYPT_BLOCK_MASK;
if (SizeToRead==0)
return 0;
int ReadSize=Arc->File::Read(Buf+ReadBufSize,SizeToRead);
if (ReadSize<=0)
return 0;
int ReadSize=0;
if (SizeToRead!=0)
{
ReadSize=Arc->File::Read(Buf+ReadBufSize,SizeToRead);
if (ReadSize<=0)
ReadSize=0;
else
{
#ifndef RAR_NOCRYPT
if (Arc->SubHead.Encrypted)
Crypt.DecryptBlock(Buf+ReadBufSize,ReadSize & ~CRYPT_BLOCK_MASK);
if (Arc->SubHead.Encrypted)
Crypt.DecryptBlock(Buf+ReadBufSize,ReadSize & ~CRYPT_BLOCK_MASK);
#endif
RawDataPos+=ReadSize;
ReadBufSize+=ReadSize;
RawDataPos+=ReadSize;
ReadBufSize+=ReadSize;
}
}
Arc->Seek(SavePos,SEEK_SET);
return ReadSize;
}
@@ -234,10 +260,10 @@ bool QuickOpen::ReadRaw(RawRead &Raw)
return false;
}
// If rest of block data crosses buffer boundary, read it in loop.
size_t DataLeft=ReadBufSize-ReadBufPos;
// If rest of block data crosses Buf boundary, read it in loop.
while (SizeToRead>0)
{
size_t DataLeft=ReadBufSize-ReadBufPos;
size_t CurSizeToRead=Min(DataLeft,(size_t)SizeToRead);
Raw.Read(Buf+ReadBufPos,CurSizeToRead);
ReadBufPos+=CurSizeToRead;
@@ -264,9 +290,11 @@ bool QuickOpen::ReadNext()
uint Flags=(uint)Raw.GetV();
uint64 Offset=Raw.GetV();
size_t HeaderSize=(size_t)Raw.GetV();
if (HeaderSize>MAX_HEADER_SIZE_RAR5)
return false;
LastReadHeader.Alloc(HeaderSize);
Raw.GetB(&LastReadHeader[0],HeaderSize);
// Calculate the absolute position as offset from quick open service header.
LastReadHeaderPos=QLHeaderPos-Offset;
LastReadHeaderPos=QOHeaderPos-Offset;
return true;
}

View File

@@ -29,24 +29,24 @@ class QuickOpen
QuickOpenItem *ListStart;
QuickOpenItem *ListEnd;
byte *Buf;
static const size_t MaxBufSize=0x10000; // Must be multiple of CRYPT_BLOCK_SIZE.
size_t CurBufSize;
byte *Buf; // Read quick open data here.
static const size_t MaxBufSize=0x10000; // Buf size, must be multiple of CRYPT_BLOCK_SIZE.
size_t CurBufSize; // Current size of buffered data in write mode.
#ifndef RAR_NOCRYPT // For shell extension.
CryptData Crypt;
#endif
bool Loaded;
uint64 QLHeaderPos;
uint64 RawDataStart;
uint64 RawDataSize;
uint64 RawDataPos;
size_t ReadBufSize;
size_t ReadBufPos;
uint64 QOHeaderPos; // Main QO header position.
uint64 RawDataStart; // Start of QO data, just after the main header.
uint64 RawDataSize; // Size of entire QO data.
uint64 RawDataPos; // Current read position in QO data.
size_t ReadBufSize; // Size of Buf data currently read from QO.
size_t ReadBufPos; // Current read position in Buf data.
Array<byte> LastReadHeader;
uint64 LastReadHeaderPos;
uint64 SeekPos;
bool UnsyncSeekPos; // QOpen SeekPos does not match an actual file pointer.
bool UnsyncSeekPos; // QOpen SeekPos does not match an actual file pointer.
public:
QuickOpen();
~QuickOpen();

View File

@@ -29,7 +29,7 @@ int main(int argc, char *argv[])
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
// Must be initialized, normal initialization can be skipped in case of
// exception.
bool ShutdownOnClose=false;
POWER_MODE ShutdownOnClose=POWERMODE_KEEP;
#endif
try
@@ -37,7 +37,7 @@ int main(int argc, char *argv[])
CommandData *Cmd=new CommandData;
#ifdef SFX_MODULE
wcscpy(Cmd->Command,L"X");
wcsncpyz(Cmd->Command,L"X",ASIZE(Cmd->Command));
char *Switch=argc>1 ? argv[1]:NULL;
if (Switch!=NULL && Cmd->IsSwitch(Switch[0]))
{
@@ -68,10 +68,11 @@ int main(int argc, char *argv[])
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
ShutdownOnClose=Cmd->Shutdown;
if (ShutdownOnClose)
ShutdownCheckAnother(true);
#endif
uiInit(Cmd->Sound);
InitConsoleOptions(Cmd->MsgStream,Cmd->RedirectCharset);
InitLogOptions(Cmd->LogName,Cmd->ErrlogCharset);
ErrHandler.SetSilent(Cmd->AllYes || Cmd->MsgStream==MSG_NULL);
@@ -94,8 +95,9 @@ int main(int argc, char *argv[])
}
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
if (ShutdownOnClose && ErrHandler.IsShutdownEnabled())
Shutdown();
if (ShutdownOnClose!=POWERMODE_KEEP && ErrHandler.IsShutdownEnabled() &&
!ShutdownCheckAnother(false))
Shutdown(ShutdownOnClose);
#endif
ErrHandler.MainExit=true;
return ErrHandler.GetErrorCode();

View File

@@ -29,6 +29,9 @@
#include "pathfn.hpp"
#include "strfn.hpp"
#include "strlist.hpp"
#ifdef _WIN_ALL
#include "isnt.hpp"
#endif
#include "file.hpp"
#include "crc.hpp"
#include "ui.hpp"
@@ -36,7 +39,6 @@
#include "filestr.hpp"
#include "find.hpp"
#include "scantree.hpp"
#include "savepos.hpp"
#include "getbits.hpp"
#include "rdwrfn.hpp"
#ifdef USE_QOPEN
@@ -48,9 +50,6 @@
#include "filcreat.hpp"
#include "consio.hpp"
#include "system.hpp"
#ifdef _WIN_ALL
#include "isnt.hpp"
#endif
#include "log.hpp"
#include "rawint.hpp"
#include "rawread.hpp"
@@ -77,6 +76,9 @@
#include "rs.hpp"
#include "rs16.hpp"
#include "recvol.hpp"
#include "volume.hpp"
#include "smallfn.hpp"

View File

@@ -4,7 +4,7 @@
#define Min(x,y) (((x)<(y)) ? (x):(y))
#define Max(x,y) (((x)>(y)) ? (x):(y))
// Universal replacement of abs function for non-int arguments.
// Universal replacement of abs function.
#define Abs(x) (((x)<0) ? -(x):(x))
#define ASIZE(x) (sizeof(x)/sizeof(x[0]))

View File

@@ -18,15 +18,15 @@ typedef wchar_t wchar; // Unicode character
// 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.
// Maximum int64 value.
#define MAX_INT64 int64(INT32TO64(0x7fffffff,0xffffffff))
// Special int64 value, large enough to never be found in real life
// and small enough to fit to both signed and unsigned 64-bit ints.
// 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.
// compatible with 32 bit int64 if 64 bit type is not supported.
#define INT64NDF INT32TO64(0x7fffffff,0x7fffffff)
// Maximum uint64 value.
#define MAX_UINT64 INT32TO64(0xffffffff,0xffffffff)
#define UINT64NDF MAX_UINT64
#endif

View File

@@ -22,6 +22,7 @@ void RarVM::Init()
void RarVM::Execute(VM_PreparedProgram *Prg)
{
memcpy(R,Prg->InitR,sizeof(Prg->InitR));
Prg->FilteredData=NULL;
if (Prg->Type!=VMSF_NONE)
{
bool Success=ExecuteStandardFilter(Prg->Type);
@@ -107,7 +108,14 @@ uint RarVM::ReadData(BitInput &Inp)
void RarVM::SetMemory(size_t Pos,byte *Data,size_t DataSize)
{
if (Pos<VM_MEMSIZE && Data!=Mem+Pos)
memmove(Mem+Pos,Data,Min(DataSize,VM_MEMSIZE-Pos));
{
// We can have NULL Data for invalid filters with DataSize==0. While most
// sensible memmove implementations do not care about data if size is 0,
// let's follow the standard and check the size first.
size_t CopySize=Min(DataSize,VM_MEMSIZE-Pos);
if (CopySize!=0)
memmove(Mem+Pos,Data,CopySize);
}
}
@@ -279,7 +287,10 @@ bool RarVM::ExecuteStandardFilter(VM_StandardFilters FilterType)
PrevDelta=(signed char)(Predicted-PrevByte);
PrevByte=Predicted;
int D=((signed char)CurByte)<<3;
int D=(signed char)CurByte;
// Left shift of negative value is undefined behavior in C++,
// so we cast it to unsigned to follow the standard.
D=(uint)D<<3;
Dif[0]+=abs(D);
Dif[1]+=abs(D-D1);

View File

@@ -1,53 +0,0 @@
#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
};

View File

@@ -115,7 +115,9 @@ uint64 RawRead::Get8()
uint64 RawRead::GetV()
{
uint64 Result=0;
for (uint Shift=0;ReadPos<DataSize;Shift+=7)
// Need to check Shift<64, because for shift greater than or equal to
// the width of the promoted left operand, the behavior is undefined.
for (uint Shift=0;ReadPos<DataSize && Shift<64;Shift+=7)
{
byte CurByte=Data[ReadPos++];
Result+=uint64(CurByte & 0x7f)<<Shift;

View File

@@ -19,11 +19,13 @@ void ComprDataIO::Init()
ShowProgress=true;
TestMode=false;
SkipUnpCRC=false;
NoFileHeader=false;
PackVolume=false;
UnpVolume=false;
NextVolumeMissing=false;
SrcFile=NULL;
DestFile=NULL;
UnpWrAddr=NULL;
UnpWrSize=0;
Command=NULL;
Encryption=false;
@@ -95,7 +97,7 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
return -1;
ReadSize=SrcFile->Read(ReadAddr,SizeToRead);
FileHeader *hd=SubHead!=NULL ? SubHead:&SrcArc->FileHead;
if (hd->SplitAfter)
if (!NoFileHeader && hd->SplitAfter)
PackedDataHash.Update(ReadAddr,ReadSize);
}
}

View File

@@ -3,6 +3,7 @@
class CmdAdd;
class Unpack;
class ArcFileSearch;
#if 0
// We use external i/o calls for Benchmark command.
@@ -32,6 +33,7 @@ class ComprDataIO
bool ShowProgress;
bool TestMode;
bool SkipUnpCRC;
bool NoFileHeader;
File *SrcFile;
File *DestFile;
@@ -62,6 +64,7 @@ class ComprDataIO
void SetPackedSizeToRead(int64 Size) {UnpPackedSize=Size;}
void SetTestMode(bool Mode) {TestMode=Mode;}
void SetSkipUnpCRC(bool Skip) {SkipUnpCRC=Skip;}
void SetNoFileHeader(bool Mode) {NoFileHeader=Mode;}
void SetFiles(File *SrcFile,File *DestFile);
void SetCommand(CmdAdd *Cmd) {Command=Cmd;}
void SetSubHeader(FileHeader *hd,int64 *Pos) {SubHead=hd;SubHeadPos=Pos;}

View File

@@ -31,12 +31,12 @@ bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent)
// handling exceptions. So it can close and delete files on Cancel.
if (Fmt==RARFMT15)
{
RecVolumes3 RecVol(false);
RecVolumes3 RecVol(Cmd,false);
return RecVol.Restore(Cmd,Name,Silent);
}
else
{
RecVolumes5 RecVol(false);
RecVolumes5 RecVol(Cmd,false);
return RecVol.Restore(Cmd,Name,Silent);
}
}
@@ -100,12 +100,12 @@ void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name)
RevFile.Close();
if (Rev5)
{
RecVolumes5 RecVol(true);
RecVolumes5 RecVol(Cmd,true);
RecVol.Test(Cmd,Name);
}
else
{
RecVolumes3 RecVol(true);
RecVolumes3 RecVol(Cmd,true);
RecVol.Test(Cmd,Name);
}
}

View File

@@ -14,7 +14,7 @@ class RecVolumes3
ThreadPool *RSThreadPool;
#endif
public:
RecVolumes3(bool TestOnly);
RecVolumes3(RAROptions *Cmd,bool TestOnly);
~RecVolumes3();
void Make(RAROptions *Cmd,wchar *ArcName);
bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent);
@@ -71,11 +71,12 @@ class RecVolumes5
#ifdef RAR_SMP
ThreadPool *RecThreadPool;
#endif
RecRSThreadData ThreadData[MaxPoolThreads]; // Store thread parameters.
uint MaxUserThreads; // Maximum number of threads defined by user.
RecRSThreadData *ThreadData; // Array to store thread parameters.
public: // 'public' only because called from thread functions.
void ProcessAreaRS(RecRSThreadData *td);
public:
RecVolumes5(bool TestOnly);
RecVolumes5(RAROptions *Cmd,bool TestOnly);
~RecVolumes5();
bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent);
void Test(RAROptions *Cmd,const wchar *Name);

View File

@@ -36,7 +36,7 @@ THREAD_PROC(RSDecodeThread)
}
#endif
RecVolumes3::RecVolumes3(bool TestOnly)
RecVolumes3::RecVolumes3(RAROptions *Cmd,bool TestOnly)
{
memset(SrcFile,0,sizeof(SrcFile));
if (TestOnly)
@@ -50,7 +50,7 @@ RecVolumes3::RecVolumes3(bool TestOnly)
Buf.Alloc(TotalBufferSize);
memset(SrcFile,0,sizeof(SrcFile));
#ifdef RAR_SMP
RSThreadPool=CreateThreadPool();
RSThreadPool=new ThreadPool(Cmd->Threads);
#endif
}
}
@@ -61,7 +61,7 @@ RecVolumes3::~RecVolumes3()
for (size_t I=0;I<ASIZE(SrcFile);I++)
delete SrcFile[I];
#ifdef RAR_SMP
DestroyThreadPool(RSThreadPool);
delete RSThreadPool;
#endif
}
@@ -111,7 +111,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
NewStyle=IsNewStyleRev(ArcName);
while (Ext>ArcName+1 && (IsDigit(*(Ext-1)) || *(Ext-1)=='_'))
Ext--;
wcscpy(Ext,L"*.*");
wcsncpyz(Ext,L"*.*",ASIZE(ArcName)-(Ext-ArcName));
FindFile Find;
Find.SetMask(ArcName);
@@ -235,7 +235,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
}
RecVolNumber=P[1];
FileNumber=P[2];
wcscpy(PrevName,CurName);
wcsncpyz(PrevName,CurName,ASIZE(PrevName));
File *NewFile=new File;
NewFile->TOpen(CurName);
SrcFile[FileNumber+P[0]-1]=NewFile;
@@ -247,7 +247,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
if (!Silent || FoundRecVolumes!=0)
uiMsg(UIMSG_RECVOLFOUND,FoundRecVolumes);
if (FoundRecVolumes==0)
return(false);
return false;
bool WriteFlags[256];
memset(WriteFlags,0,sizeof(WriteFlags));
@@ -290,8 +290,8 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
{
NewFile->Close();
wchar NewName[NM];
wcscpy(NewName,ArcName);
wcscat(NewName,L".bad");
wcsncpyz(NewName,ArcName,ASIZE(NewName));
wcsncatz(NewName,L".bad",ASIZE(NewName));
uiMsg(UIMSG_BADARCHIVE,ArcName);
uiMsg(UIMSG_RENAMING,ArcName,NewName);
@@ -322,7 +322,7 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
MissingVolumes++;
if (CurArcNum==FileNumber-1)
wcscpy(LastVolName,ArcName);
wcsncpyz(LastVolName,ArcName,ASIZE(LastVolName));
uiMsg(UIMSG_MISSINGVOL,ArcName);
uiMsg(UIEVENT_NEWARCHIVE,ArcName);
@@ -363,11 +363,10 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
#ifdef RAR_SMP
uint ThreadNumber=Cmd->Threads;
RSEncode rse[MaxPoolThreads];
#else
uint ThreadNumber=1;
RSEncode rse[1];
#endif
RSEncode *rse=new RSEncode[ThreadNumber];
for (uint I=0;I<ThreadNumber;I++)
rse[I].Init(RecVolNumber);
@@ -438,6 +437,8 @@ bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
if (WriteFlags[I])
SrcFile[I]->Write(&Buf[I*RecBufferSize],MaxRead);
}
delete[] rse;
for (int I=0;I<RecVolNumber+FileNumber;I++)
if (SrcFile[I]!=NULL)
{

View File

@@ -1,6 +1,6 @@
static const uint MaxVolumes=65535;
RecVolumes5::RecVolumes5(bool TestOnly)
RecVolumes5::RecVolumes5(RAROptions *Cmd,bool TestOnly)
{
RealBuf=NULL;
RealReadBuffer=NULL;
@@ -10,7 +10,14 @@ RecVolumes5::RecVolumes5(bool TestOnly)
TotalCount=0;
RecBufferSize=0;
for (uint I=0;I<ASIZE(ThreadData);I++)
#ifdef RAR_SMP
MaxUserThreads=Cmd->Threads;
#else
MaxUserThreads=1;
#endif
ThreadData=new RecRSThreadData[MaxUserThreads];
for (uint I=0;I<MaxUserThreads;I++)
{
ThreadData[I].RecRSPtr=this;
ThreadData[I].RS=NULL;
@@ -25,7 +32,7 @@ RecVolumes5::RecVolumes5(bool TestOnly)
else
{
#ifdef RAR_SMP
RecThreadPool=CreateThreadPool();
RecThreadPool=new ThreadPool(MaxUserThreads);
#endif
RealBuf=new byte[TotalBufferSize+SSE_ALIGNMENT];
Buf=(byte *)ALIGN_VALUE(RealBuf,SSE_ALIGNMENT);
@@ -39,10 +46,11 @@ RecVolumes5::~RecVolumes5()
delete[] RealReadBuffer;
for (uint I=0;I<RecItems.Size();I++)
delete RecItems[I].f;
for (uint I=0;I<ASIZE(ThreadData);I++)
for (uint I=0;I<MaxUserThreads;I++)
delete ThreadData[I].RS;
delete[] ThreadData;
#ifdef RAR_SMP
DestroyThreadPool(RecThreadPool);
delete RecThreadPool;
#endif
}
@@ -68,11 +76,7 @@ void RecVolumes5::ProcessRS(RAROptions *Cmd,uint DataNum,const byte *Data,uint M
RS.UpdateECC(DataNum, I, Data, Buf+I*RecBufferSize, MaxRead);
*/
#ifdef RAR_SMP
uint ThreadNumber=Cmd->Threads;
#else
uint ThreadNumber=1;
#endif
uint ThreadNumber=MaxUserThreads;
const uint MinThreadBlock=0x1000;
ThreadNumber=Min(ThreadNumber,MaxRead/MinThreadBlock);
@@ -141,6 +145,8 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
wchar *Num=GetVolNumPart(ArcName);
while (Num>ArcName && IsDigit(*(Num-1)))
Num--;
if (Num==ArcName)
return false; // Numeric part is missing or entire volume name is numeric, not possible for RAR or REV volume.
wcsncpyz(Num,L"*.*",ASIZE(ArcName)-(Num-ArcName));
wchar FirstVolName[NM];
@@ -236,7 +242,7 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
uiMsg(UIMSG_STRING,Item->Name);
uint RevCRC;
CalcFileSum(Item->f,&RevCRC,NULL,Cmd->Threads,INT64NDF,CALCFSUM_CURPOS);
CalcFileSum(Item->f,&RevCRC,NULL,MaxUserThreads,INT64NDF,CALCFSUM_CURPOS);
Item->Valid=RevCRC==Item->CRC;
if (!Item->Valid)
{
@@ -285,8 +291,8 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
Item->f->Close();
wchar NewName[NM];
wcscpy(NewName,Item->Name);
wcscat(NewName,L".bad");
wcsncpyz(NewName,Item->Name,ASIZE(NewName));
wcsncatz(NewName,L".bad",ASIZE(NewName));
uiMsg(UIMSG_BADARCHIVE,Item->Name);
uiMsg(UIMSG_RENAMING,Item->Name,NewName);

View File

@@ -2,10 +2,21 @@
#ifndef RARDLL
const wchar *St(MSGID StringId)
const wchar* St(MSGID StringId)
{
return StringId;
}
// Needed for Unix swprintf to convert %s to %ls in legacy language resources.
const wchar *StF(MSGID StringId)
{
static wchar FormattedStr[512];
PrintfPrepareFmt(St(StringId),FormattedStr,ASIZE(FormattedStr));
return FormattedStr;
}
#endif

View File

@@ -3,8 +3,10 @@
#ifdef RARDLL
#define St(x) (L"")
#define StF(x) (L"")
#else
const wchar *St(MSGID StringId);
const wchar *StF(MSGID StringId);
#endif

View File

@@ -75,11 +75,20 @@ void Rijndael::Init(bool Encrypt,const byte *key,uint keyLen,const byte * initVe
// Check SSE here instead of constructor, so if object is a part of some
// structure memset'ed before use, this variable is not lost.
int CPUInfo[4];
__cpuid(CPUInfo, 1);
AES_NI=(CPUInfo[2] & 0x2000000)!=0;
__cpuid(CPUInfo, 0x80000000); // Get the maximum supported cpuid function.
if ((CPUInfo[0] & 0x7fffffff)>=1)
{
__cpuid(CPUInfo, 1);
AES_NI=(CPUInfo[2] & 0x2000000)!=0;
}
else
AES_NI=0;
#endif
uint uKeyLenInBytes;
// Other developers asked us to initialize it to suppress "may be used
// uninitialized" warning in code below in some compilers.
uint uKeyLenInBytes=0;
switch(keyLen)
{
case 128:

View File

@@ -27,7 +27,7 @@ RSCoder16::~RSCoder16()
delete[] MX;
delete[] ValidFlags;
}
// Initialize logarithms and exponents Galois field tables.
void RSCoder16::gfInit()
@@ -41,7 +41,7 @@ void RSCoder16::gfInit()
gfExp[L]=E;
gfExp[L+gfSize]=E; // Duplicate the table to avoid gfExp overflow check.
E<<=1;
if (E>gfSize)
if (E>gfSize)
E^=0x1100B; // Irreducible field-generator polynomial.
}
@@ -59,7 +59,7 @@ uint RSCoder16::gfAdd(uint a,uint b) // Addition in Galois field.
}
uint RSCoder16::gfMul(uint a,uint b) // Multiplication in Galois field.
uint RSCoder16::gfMul(uint a,uint b) // Multiplication in Galois field.
{
return gfExp[gfLog[a]+gfLog[b]];
}
@@ -156,7 +156,7 @@ void RSCoder16::InvertDecoderMatrix()
for (uint Kr = 0, Kf = 0; Kr < NE; Kr++, Kf++)
{
while (ValidFlags[Kf]) // Skip trivial rows.
Kf++;
Kf++;
MI[Kr * ND + Kf] = 1; // Set diagonal 1.
}
@@ -174,7 +174,7 @@ void RSCoder16::InvertDecoderMatrix()
// after MI[..]^=, but we do not need it for matrix inversion.
for (uint I = 0; I < NE; I++)
MI[I * ND + Kf] ^= MX[I * ND + Kf];
Kf++;
Kf++;
}
if (Kf == ND)
@@ -186,14 +186,14 @@ void RSCoder16::InvertDecoderMatrix()
uint PInv = gfInv( MXk[Kf] ); // Pivot inverse.
// Divide the pivot row by pivot, so pivot cell contains 1.
for (uint I = 0; I < ND; I++)
{
{
MXk[I] = gfMul( MXk[I], PInv );
MIk[I] = gfMul( MIk[I], PInv );
}
for (uint I = 0; I < NE; I++)
if (I != Kr) // For all rows except containing the pivot cell.
{
{
// Apply Gaussian elimination Mij -= Mkj * Mik / pivot.
// Since pivot is already 1, it is reduced to Mij -= Mkj * Mik.
uint *MXi = MX + I * ND; // i-th row of main matrix.
@@ -361,7 +361,7 @@ bool RSCoder16::SSE_UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte
__m128i LowBytes1=_mm_and_si128(D[1],LowByteMask);
__m128i HighBytes=_mm_packus_epi16(HighBytes0,HighBytes1);
__m128i LowBytes=_mm_packus_epi16(LowBytes0,LowBytes1);
// Multiply bits 0..3 of low bytes. Store low and high product bytes
// separately in cumulative sum variables.
__m128i LowBytesLow4=_mm_and_si128(LowBytes,Low4Mask);
@@ -377,7 +377,7 @@ bool RSCoder16::SSE_UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte
// Add new product to existing sum, low and high bytes separately.
LowBytesMultSum=_mm_xor_si128(LowBytesMultSum,LowBytesHigh4MultLow);
HighBytesMultSum=_mm_xor_si128(HighBytesMultSum,LowBytesHigh4MultHigh);
// Multiply bits 0..3 of high bytes. Store low and high product bytes separately.
__m128i HighBytesLow4=_mm_and_si128(HighBytes,Low4Mask);
__m128i HighBytesLow4MultLow=_mm_shuffle_epi8(T2L,HighBytesLow4);
@@ -413,7 +413,7 @@ bool RSCoder16::SSE_UpdateECC(uint DataNum, uint ECCNum, const byte *Data, byte
// because Data and ECC can have different alignment offsets.
for (; Pos<BlockSize; Pos+=2)
*(ushort*)(ECC+Pos) ^= gfMul( M, *(ushort*)(Data+Pos) );
return true;
}
#endif

View File

@@ -14,7 +14,26 @@ class SaveFilePos
}
~SaveFilePos()
{
SaveFile->Seek(SavePos,SEEK_SET);
// Unless the file is already closed either by current exception
// processing or intentionally by external code.
if (SaveFile->IsOpened())
{
try
{
SaveFile->Seek(SavePos,SEEK_SET);
}
catch(RAR_EXIT)
{
// Seek() can throw an exception and it terminates process
// if we are already processing another exception. Also in C++ 11
// an exception in destructor always terminates process unless
// we mark destructor with noexcept(false). So we do not want to
// throw here. To prevent data loss we do not want to continue
// execution after seek error, so we close the file.
// Any next access to this file will return an error.
SaveFile->Close();
}
}
}
};

View File

@@ -142,7 +142,12 @@ bool ScanTree::GetFilteredMask()
bool WildcardFound=false;
uint FolderWildcardCount=0;
uint SlashPos=0;
for (int I=0;CurMask[I]!=0;I++)
uint StartPos=0;
#ifdef _WIN_ALL // Not treat the special NTFS \\?\d: path prefix as a wildcard.
if (CurMask[0]=='\\' && CurMask[1]=='\\' && CurMask[2]=='?' && CurMask[3]=='\\')
StartPos=4;
#endif
for (uint I=StartPos;CurMask[I]!=0;I++)
{
if (CurMask[I]=='?' || CurMask[I]=='*')
WildcardFound=true;
@@ -171,7 +176,7 @@ bool ScanTree::GetFilteredMask()
wchar Filter[NM];
// Convert path\dir*\ to *\dir filter to search for 'dir' in all 'path' subfolders.
wcscpy(Filter,L"*");
wcsncpyz(Filter,L"*",ASIZE(Filter));
AddEndSlash(Filter,ASIZE(Filter));
// SlashPos might point or not point to path separator for masks like 'dir*', '\dir*' or 'd:dir*'
wchar *WildName=IsPathDiv(CurMask[SlashPos]) || IsDriveDiv(CurMask[SlashPos]) ? CurMask+SlashPos+1 : CurMask+SlashPos;
@@ -226,7 +231,7 @@ bool ScanTree::GetNextMask()
SpecPathLength=Name-CurMask;
Depth=0;
wcscpy(OrigCurMask,CurMask);
wcsncpyz(OrigCurMask,CurMask,ASIZE(OrigCurMask));
return true;
}
@@ -350,16 +355,19 @@ SCAN_CODE ScanTree::FindProc(FindData *FD)
if (Slash!=NULL)
{
wchar Mask[NM];
wcscpy(Mask,Slash);
wcsncpyz(Mask,Slash,ASIZE(Mask));
if (Depth<SetAllMaskDepth)
wcscpy(Mask+1,PointToName(OrigCurMask));
wcsncpyz(Mask+1,PointToName(OrigCurMask),ASIZE(Mask)-1);
*Slash=0;
wcscpy(DirName,CurMask);
wcsncpyz(DirName,CurMask,ASIZE(DirName));
wchar *PrevSlash=wcsrchr(CurMask,CPATHDIVIDER);
if (PrevSlash==NULL)
wcscpy(CurMask,Mask+1);
wcsncpyz(CurMask,Mask+1,ASIZE(CurMask));
else
wcscpy(PrevSlash,Mask);
{
*PrevSlash=0;
wcsncatz(CurMask,Mask,ASIZE(CurMask));
}
}
if (GetDirs==SCAN_GETDIRSTWICE &&
FindFile::FastFind(DirName,FD,GetLinks) && FD->IsDir)
@@ -397,8 +405,8 @@ SCAN_CODE ScanTree::FindProc(FindData *FD)
wchar Mask[NM];
wcscpy(Mask,FastFindFile ? MASKALL:PointToName(CurMask));
wcscpy(CurMask,FD->Name);
wcsncpyz(Mask,FastFindFile ? MASKALL:PointToName(CurMask),ASIZE(Mask));
wcsncpyz(CurMask,FD->Name,ASIZE(CurMask));
if (wcslen(CurMask)+wcslen(Mask)+1>=NM || Depth>=MAXSCANDEPTH-1)
{

View File

@@ -64,7 +64,7 @@ class ScanTree
ScanTree(StringList *FileMasks,RECURSE_MODE Recurse,bool GetLinks,SCAN_DIRS GetDirs);
~ScanTree();
SCAN_CODE GetNext(FindData *FindData);
size_t GetSpecPathLength() {return SpecPathLength;};
size_t GetSpecPathLength() {return SpecPathLength;}
int GetErrors() {return Errors;};
void SetErrArcName(const wchar *Name) {wcsncpyz(ErrArcName,Name,ASIZE(ErrArcName));}
void SetCommandData(CommandData *Cmd) {ScanTree::Cmd=Cmd;}

View File

@@ -28,7 +28,8 @@ void IntToExt(const char *Src,char *Dest,size_t DestSize)
}
// Convert archived names to Unicode. Allow user to select a code page in GUI.
// Convert archived names and comments to Unicode.
// Allows user to select a code page in GUI.
void ArcCharToWide(const char *Src,wchar *Dest,size_t DestSize,ACTW_ENCODING Encoding)
{
#if defined(_WIN_ALL) // Console Windows RAR.
@@ -36,11 +37,12 @@ void ArcCharToWide(const char *Src,wchar *Dest,size_t DestSize,ACTW_ENCODING Enc
UtfToWide(Src,Dest,DestSize);
else
{
char NameA[NM];
Array<char> NameA;
if (Encoding==ACTW_OEM)
{
IntToExt(Src,NameA,ASIZE(NameA));
Src=NameA;
NameA.Alloc(DestSize+1);
IntToExt(Src,&NameA[0],NameA.Size());
Src=&NameA[0];
}
CharToWide(Src,Dest,DestSize);
}
@@ -58,6 +60,8 @@ void ArcCharToWide(const char *Src,wchar *Dest,size_t DestSize,ACTW_ENCODING Enc
}
int stricomp(const char *s1,const char *s2)
{
#ifdef _WIN_ALL
@@ -121,7 +125,8 @@ unsigned char loctolower(unsigned char ch)
{
#if defined(_WIN_ALL)
// Convert to LPARAM first to avoid a warning in 64 bit mode.
return (int)(LPARAM)CharLowerA((LPSTR)ch);
// Convert to uintptr_t to avoid Clang/win error: cast to 'char *' from smaller integer type 'unsigned char' [-Werror,-Wint-to-pointer-cast]
return (int)(LPARAM)CharLowerA((LPSTR)(uintptr_t)ch);
#else
return tolower(ch);
#endif
@@ -132,7 +137,8 @@ unsigned char loctoupper(unsigned char ch)
{
#if defined(_WIN_ALL)
// Convert to LPARAM first to avoid a warning in 64 bit mode.
return (int)(LPARAM)CharUpperA((LPSTR)ch);
// Convert to uintptr_t to avoid Clang/win error: cast to 'char *' from smaller integer type 'unsigned char' [-Werror,-Wint-to-pointer-cast]
return (int)(LPARAM)CharUpperA((LPSTR)(uintptr_t)ch);
#else
return toupper(ch);
#endif
@@ -235,8 +241,8 @@ uint GetDigits(uint Number)
bool LowAscii(const char *Str)
{
for (int I=0;Str[I]!=0;I++)
if ((byte)Str[I]<32 || (byte)Str[I]>127)
for (size_t I=0;Str[I]!=0;I++)
if (/*(byte)Str[I]<32 || */(byte)Str[I]>127)
return false;
return true;
}
@@ -244,11 +250,11 @@ bool LowAscii(const char *Str)
bool LowAscii(const wchar *Str)
{
for (int I=0;Str[I]!=0;I++)
for (size_t I=0;Str[I]!=0;I++)
{
// We convert wchar_t to uint just in case if some compiler
// uses signed wchar_t.
if ((uint)Str[I]<32 || (uint)Str[I]>127)
if (/*(uint)Str[I]<32 || */(uint)Str[I]>127)
return false;
}
return true;
@@ -275,53 +281,49 @@ int wcsnicompc(const wchar *s1,const wchar *s2,size_t n)
}
// Safe strncpy: copies maxlen-1 max and always returns zero terminated dest.
char* strncpyz(char *dest, const char *src, size_t maxlen)
// Safe copy: copies maxlen-1 max and for maxlen>0 returns zero terminated dest.
void strncpyz(char *dest, const char *src, size_t maxlen)
{
if (maxlen>0)
{
strncpy(dest,src,maxlen-1);
dest[maxlen-1]=0;
while (--maxlen>0 && *src!=0)
*dest++=*src++;
*dest=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)
// Safe copy: copies maxlen-1 max and for maxlen>0 returns zero terminated dest.
void wcsncpyz(wchar *dest, const wchar *src, size_t maxlen)
{
if (maxlen>0)
{
wcsncpy(dest,src,maxlen-1);
dest[maxlen-1]=0;
while (--maxlen>0 && *src!=0)
*dest++=*src++;
*dest=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)
// Safe append: resulting dest length cannot exceed maxlen and dest
// is always zero terminated. 'maxlen' parameter defines the entire
// dest buffer size and is not compatible with wcsncat.
void strncatz(char* dest, const char* src, size_t maxlen)
{
size_t Length = strlen(dest);
int avail=int(maxlen - Length - 1);
if (avail > 0)
strncat(dest, src, avail);
return dest;
size_t length = strlen(dest);
if (maxlen > length)
strncpyz(dest + length, src, maxlen - length);
}
// 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)
// Safe append: resulting dest length cannot exceed maxlen and dest
// is always zero terminated. 'maxlen' parameter defines the entire
// dest buffer size and is not compatible with wcsncat.
void wcsncatz(wchar* dest, const wchar* src, size_t maxlen)
{
size_t Length = wcslen(dest);
int avail=int(maxlen - Length - 1);
if (avail > 0)
wcsncat(dest, src, avail);
return dest;
size_t length = wcslen(dest);
if (maxlen > length)
wcsncpyz(dest + length, src, maxlen - length);
}
@@ -428,7 +430,7 @@ const wchar* GetCmdParam(const wchar *CmdLine,wchar *Param,size_t MaxSize)
}
#ifndef SILENT
#ifndef RARDLL
// For compatibility with existing translations we use %s to print Unicode
// strings in format strings and convert them to %ls here. %s could work
// without such conversion in Windows, but not in Unix wprintf.

View File

@@ -8,6 +8,7 @@ void IntToExt(const char *Src,char *Dest,size_t DestSize);
enum ACTW_ENCODING { ACTW_DEFAULT, ACTW_OEM, ACTW_UTF8};
void ArcCharToWide(const char *Src,wchar *Dest,size_t DestSize,ACTW_ENCODING Encoding);
int stricomp(const char *s1,const char *s2);
int strnicomp(const char *s1,const char *s2,size_t n);
wchar* RemoveEOL(wchar *Str);
@@ -15,10 +16,10 @@ wchar* RemoveLF(wchar *Str);
unsigned char loctolower(unsigned char ch);
unsigned char loctoupper(unsigned char ch);
char* strncpyz(char *dest, const char *src, size_t maxlen);
wchar* wcsncpyz(wchar *dest, const wchar *src, size_t maxlen);
char* strncatz(char* dest, const char* src, size_t maxlen);
wchar* wcsncatz(wchar* dest, const wchar* src, size_t maxlen);
void strncpyz(char *dest, const char *src, size_t maxlen);
void wcsncpyz(wchar *dest, const wchar *src, size_t maxlen);
void strncatz(char* dest, const char* src, size_t maxlen);
void wcsncatz(wchar* dest, const wchar* src, size_t maxlen);
unsigned char etoupper(unsigned char ch);
wchar etoupperw(wchar ch);
@@ -43,7 +44,7 @@ void itoa(int64 n,char *Str,size_t MaxSize);
void itoa(int64 n,wchar *Str,size_t MaxSize);
const wchar* GetWide(const char *Src);
const wchar* GetCmdParam(const wchar *CmdLine,wchar *Param,size_t MaxSize);
#ifndef SILENT
#ifndef RARDLL
void PrintfPrepareFmt(const wchar *Org,wchar *Cvt,size_t MaxSize);
#endif

View File

@@ -7,7 +7,7 @@ class StringList
Array<wchar> StringData;
size_t CurPos;
uint StringsCount;
size_t StringsCount;
size_t SaveCurPos[16],SavePosNumber;
public:
@@ -21,7 +21,7 @@ class StringList
wchar* GetString();
bool GetString(wchar **Str);
void Rewind();
uint ItemsCount() {return StringsCount;};
size_t ItemsCount() {return StringsCount;};
size_t GetCharCount() {return StringData.Size();}
bool Search(const wchar *Str,bool CaseSensitive);
void SavePosition();

View File

@@ -80,7 +80,7 @@ bool SubAllocator::StartSubAllocator(int SASize)
{
uint t=SASize << 20;
if (SubAllocatorSize == t)
return TRUE;
return true;
StopSubAllocator();
// Original algorithm expects FIXED_UNIT_SIZE, but actual structure size
@@ -91,7 +91,7 @@ bool SubAllocator::StartSubAllocator(int SASize)
if ((HeapStart=(byte *)malloc(AllocSize)) == NULL)
{
ErrHandler.MemoryError();
return FALSE;
return false;
}
// HeapEnd did not present in original algorithm. We added it to control
@@ -99,7 +99,7 @@ bool SubAllocator::StartSubAllocator(int SASize)
HeapEnd=HeapStart+AllocSize-UNIT_SIZE;
SubAllocatorSize=t;
return TRUE;
return true;
}
@@ -215,13 +215,13 @@ void* SubAllocator::AllocUnitsRare(int indx)
GlueCount--;
i=U2B(Indx2Units[indx]);
int j=FIXED_UNIT_SIZE*Indx2Units[indx];
if (FakeUnitsStart-pText > j)
if (FakeUnitsStart - pText > j)
{
FakeUnitsStart-=j;
FakeUnitsStart -= j;
UnitsStart -= i;
return(UnitsStart);
return UnitsStart;
}
return(NULL);
return NULL;
}
} while ( !FreeList[i].next );
void* RetVal=RemoveNode(i);

View File

@@ -77,7 +77,7 @@ class SubAllocator
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);};
long GetAllocatedMemory() {return(SubAllocatorSize);}
byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart;
};

View File

@@ -102,7 +102,7 @@ void Wait()
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
void Shutdown()
void Shutdown(POWER_MODE Mode)
{
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
@@ -114,7 +114,36 @@ void Shutdown()
AdjustTokenPrivileges(hToken,FALSE,&tkp,0,(PTOKEN_PRIVILEGES)NULL,0);
}
ExitWindowsEx(EWX_SHUTDOWN|EWX_FORCE|EWX_POWEROFF,SHTDN_REASON_FLAG_PLANNED);
if (Mode==POWERMODE_OFF)
ExitWindowsEx(EWX_SHUTDOWN|EWX_FORCE,SHTDN_REASON_FLAG_PLANNED);
if (Mode==POWERMODE_SLEEP)
SetSuspendState(FALSE,FALSE,FALSE);
if (Mode==POWERMODE_HIBERNATE)
SetSuspendState(TRUE,FALSE,FALSE);
if (Mode==POWERMODE_RESTART)
ExitWindowsEx(EWX_REBOOT|EWX_FORCE,SHTDN_REASON_FLAG_PLANNED);
}
bool ShutdownCheckAnother(bool Open)
{
const wchar *EventName=L"rar -ioff";
static HANDLE hEvent=NULL;
bool Result=false; // Return false if no other RAR -ioff are running.
if (Open) // Create or open the event.
hEvent=CreateEvent(NULL,FALSE,FALSE,EventName);
else
{
if (hEvent!=NULL)
CloseHandle(hEvent); // Close our event.
// Check if other copies still own the event. While race conditions
// are possible, they are improbable and their harm is minimal.
hEvent=CreateEvent(NULL,FALSE,FALSE,EventName);
Result=GetLastError()==ERROR_ALREADY_EXISTS;
if (hEvent!=NULL)
CloseHandle(hEvent);
}
return Result;
}
#endif
@@ -158,18 +187,29 @@ SSE_VERSION _SSE_Version=GetSSEVersion();
SSE_VERSION GetSSEVersion()
{
int CPUInfo[4];
__cpuid(CPUInfo, 7);
if ((CPUInfo[1] & 0x20)!=0)
return SSE_AVX2;
__cpuid(CPUInfo, 1);
if ((CPUInfo[2] & 0x80000)!=0)
return SSE_SSE41;
if ((CPUInfo[2] & 0x200)!=0)
return SSE_SSSE3;
if ((CPUInfo[3] & 0x4000000)!=0)
return SSE_SSE2;
if ((CPUInfo[3] & 0x2000000)!=0)
return SSE_SSE;
__cpuid(CPUInfo, 0x80000000);
// Maximum supported cpuid function. For example, Pentium M 755 returns 4 here.
uint MaxSupported=CPUInfo[0] & 0x7fffffff;
if (MaxSupported>=7)
{
__cpuid(CPUInfo, 7);
if ((CPUInfo[1] & 0x20)!=0)
return SSE_AVX2;
}
if (MaxSupported>=1)
{
__cpuid(CPUInfo, 1);
if ((CPUInfo[2] & 0x80000)!=0)
return SSE_SSE41;
if ((CPUInfo[2] & 0x200)!=0)
return SSE_SSSE3;
if ((CPUInfo[3] & 0x4000000)!=0)
return SSE_SSE2;
if ((CPUInfo[3] & 0x2000000)!=0)
return SSE_SSE;
}
return SSE_NONE;
}
#endif

View File

@@ -22,7 +22,8 @@ void SetPriority(int Priority);
clock_t MonoClock();
void Wait();
bool EmailFile(const wchar *FileName,const wchar *MailToW);
void Shutdown();
void Shutdown(POWER_MODE Mode);
bool ShutdownCheckAnother(bool Open);
#ifdef _WIN_ALL
HMODULE WINAPI LoadSysLibrary(const wchar *Name);

View File

@@ -1,7 +1,3 @@
// Typically we use the same global thread pool for all RAR modules.
static ThreadPool *GlobalPool=NULL;
static uint GlobalPoolUseCount=0;
static inline bool CriticalSectionCreate(CRITSECT_HANDLE *CritSection)
{
#ifdef _WIN_ALL
@@ -43,57 +39,6 @@ static inline void CriticalSectionEnd(CRITSECT_HANDLE *CritSection)
}
static struct GlobalPoolCreateSync
{
CRITSECT_HANDLE CritSection;
GlobalPoolCreateSync() { CriticalSectionCreate(&CritSection); }
~GlobalPoolCreateSync() { CriticalSectionDelete(&CritSection); }
} PoolCreateSync;
ThreadPool* CreateThreadPool()
{
CriticalSectionStart(&PoolCreateSync.CritSection);
if (GlobalPoolUseCount++ == 0)
GlobalPool=new ThreadPool(MaxPoolThreads);
// We use a simple thread pool, which does not allow to add tasks from
// different functions and threads in the same time. It is ok for RAR,
// but UnRAR.dll can be used in multithreaded environment. So if one of
// threads requests a copy of global pool and another copy is already
// in use, we create and return a new pool instead of existing global.
if (GlobalPoolUseCount > 1)
{
ThreadPool *Pool = new ThreadPool(MaxPoolThreads);
CriticalSectionEnd(&PoolCreateSync.CritSection);
return Pool;
}
CriticalSectionEnd(&PoolCreateSync.CritSection);
return GlobalPool;
}
void DestroyThreadPool(ThreadPool *Pool)
{
if (Pool!=NULL)
{
CriticalSectionStart(&PoolCreateSync.CritSection);
if (Pool==GlobalPool && GlobalPoolUseCount > 0 && --GlobalPoolUseCount == 0)
delete GlobalPool;
// To correctly work in multithreaded environment UnRAR.dll creates
// new pools if global pool is already in use. We delete such pools here.
if (Pool!=GlobalPool)
delete Pool;
CriticalSectionEnd(&PoolCreateSync.CritSection);
}
}
static THREAD_HANDLE ThreadCreate(NATIVE_THREAD_PTR Proc,void *Data)
{
#ifdef _UNIX

View File

@@ -170,12 +170,13 @@ void ThreadPool::AddTask(PTHREAD_PROC Proc,void *Data)
CreateThreads();
// If queue is full, wait until it is empty.
if ((QueueTop + 1) % ASIZE(TaskQueue) == QueueBottom)
if (ActiveThreads>=ASIZE(TaskQueue))
WaitDone();
TaskQueue[QueueTop].Proc = Proc;
TaskQueue[QueueTop].Param = Data;
QueueTop = (QueueTop + 1) % ASIZE(TaskQueue);
ActiveThreads++;
}
@@ -184,9 +185,6 @@ void ThreadPool::AddTask(PTHREAD_PROC Proc,void *Data)
// are sleeping yet.
void ThreadPool::WaitDone()
{
// We add ASIZE(TaskQueue) for case if TaskQueue array size is not
// a power of two. Negative numbers would not suit our purpose here.
ActiveThreads=(QueueTop+ASIZE(TaskQueue)-QueueBottom) % ASIZE(TaskQueue);
if (ActiveThreads==0)
return;
#ifdef _WIN_ALL

View File

@@ -4,7 +4,10 @@
#ifndef RAR_SMP
const uint MaxPoolThreads=1; // For single threaded version.
#else
const uint MaxPoolThreads=32;
// We need to use the processor groups API to increase it beyond 64.
// Also be sure to check and adjust if needed per thread and total block size
// when compressing if going above 64.
const uint MaxPoolThreads=64;
#ifdef _UNIX
@@ -98,9 +101,6 @@ class ThreadPool
#endif
};
ThreadPool* CreateThreadPool();
void DestroyThreadPool(ThreadPool *Pool);
#endif // RAR_SMP
#endif // _RAR_THREADPOOL_

View File

@@ -25,9 +25,9 @@ void RarTime::GetLocal(RarLocalTime *lt)
// Correct precision loss (low 4 decimal digits) in FileTimeToSystemTime.
FILETIME rft;
SystemTimeToFileTime(&st1,&rft);
int64 Corrected=INT32TO64(ft.dwHighDateTime,ft.dwLowDateTime)-
INT32TO64(rft.dwHighDateTime,rft.dwLowDateTime)+
INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime);
uint64 Corrected=INT32TO64(ft.dwHighDateTime,ft.dwLowDateTime)-
INT32TO64(rft.dwHighDateTime,rft.dwLowDateTime)+
INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime);
lft.dwLowDateTime=(DWORD)Corrected;
lft.dwHighDateTime=(DWORD)(Corrected>>32);
}
@@ -100,9 +100,9 @@ void RarTime::SetLocal(RarLocalTime *lt)
// Correct precision loss (low 4 decimal digits) in FileTimeToSystemTime.
FILETIME rft;
SystemTimeToFileTime(&st2,&rft);
int64 Corrected=INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime)-
INT32TO64(rft.dwHighDateTime,rft.dwLowDateTime)+
INT32TO64(ft.dwHighDateTime,ft.dwLowDateTime);
uint64 Corrected=INT32TO64(lft.dwHighDateTime,lft.dwLowDateTime)-
INT32TO64(rft.dwHighDateTime,rft.dwLowDateTime)+
INT32TO64(ft.dwHighDateTime,ft.dwLowDateTime);
ft.dwLowDateTime=(DWORD)Corrected;
ft.dwHighDateTime=(DWORD)(Corrected>>32);
}
@@ -236,7 +236,7 @@ void RarTime::GetText(wchar *DateStr,size_t MaxSize,bool FullMS)
else
{
// We use escape before '?' to avoid weird C trigraph characters.
wcscpy(DateStr,L"\?\?\?\?-\?\?-\?\? \?\?:\?\?");
wcsncpyz(DateStr,L"\?\?\?\?-\?\?-\?\? \?\?:\?\?",MaxSize);
}
}
@@ -271,7 +271,7 @@ void RarTime::SetIsoText(const wchar *TimeText)
void RarTime::SetAgeText(const wchar *TimeText)
{
uint Seconds=0,Value=0;
for (int I=0;TimeText[I]!=0;I++)
for (uint I=0;TimeText[I]!=0;I++)
{
int Ch=TimeText[I];
if (IsDigit(Ch))

View File

@@ -10,16 +10,17 @@ enum UIMESSAGE_CODE {
UIERROR_SYSERRMSG, UIERROR_GENERALERRMSG, UIERROR_INCERRCOUNT,
UIERROR_CHECKSUM, UIERROR_CHECKSUMENC, UIERROR_CHECKSUMPACKED,
UIERROR_BADPSW, UIERROR_MEMORY, UIERROR_FILEOPEN, UIERROR_FILECREATE,
UIERROR_FILECLOSE, UIERROR_FILESEEK, UIERROR_FILEREAD,
UIERROR_FILEWRITE, UIERROR_FILEDELETE, UIERROR_FILERENAME,
UIERROR_FILECLOSE, UIERROR_FILESEEK, UIERROR_FILEREAD, UIERROR_FILEWRITE,
UIERROR_FILEDELETE, UIERROR_RECYCLEFAILED, UIERROR_FILERENAME,
UIERROR_FILEATTR, UIERROR_FILECOPY, UIERROR_FILECOPYHINT,
UIERROR_DIRCREATE, UIERROR_SLINKCREATE, UIERROR_HLINKCREATE,
UIERROR_NEEDADMIN, UIERROR_ARCBROKEN, UIERROR_HEADERBROKEN,
UIERROR_MHEADERBROKEN, UIERROR_FHEADERBROKEN, UIERROR_SUBHEADERBROKEN,
UIERROR_SUBHEADERUNKNOWN, UIERROR_SUBHEADERDATABROKEN, UIERROR_RRDAMAGED,
UIERROR_UNKNOWNMETHOD, UIERROR_UNKNOWNENCMETHOD, UIERROR_RENAMING,
UIERROR_NEWERRAR, UIERROR_NOTSFX, UIERROR_OLDTOSFX,
UIERROR_WRONGSFXVER, UIERROR_ALREADYENC, UIERROR_DICTOUTMEM,
UIERROR_NOLINKTARGET, UIERROR_NEEDADMIN, UIERROR_ARCBROKEN,
UIERROR_HEADERBROKEN, UIERROR_MHEADERBROKEN, UIERROR_FHEADERBROKEN,
UIERROR_SUBHEADERBROKEN, UIERROR_SUBHEADERUNKNOWN,
UIERROR_SUBHEADERDATABROKEN, UIERROR_RRDAMAGED, UIERROR_UNKNOWNMETHOD,
UIERROR_UNKNOWNENCMETHOD, UIERROR_RENAMING, UIERROR_NEWERRAR,
UIERROR_NOTSFX, UIERROR_OLDTOSFX,
UIERROR_WRONGSFXVER, UIERROR_HEADENCMISMATCH, UIERROR_DICTOUTMEM,
UIERROR_USESMALLERDICT, UIERROR_MODIFYUNKNOWN, UIERROR_MODIFYOLD,
UIERROR_MODIFYLOCKED, UIERROR_MODIFYVOLUME, UIERROR_NOTVOLUME,
UIERROR_NOTFIRSTVOLUME, UIERROR_RECVOLLIMIT, UIERROR_RECVOLDIFFSETS,
@@ -31,16 +32,17 @@ enum UIMESSAGE_CODE {
UIERROR_NOFILESTOADD, UIERROR_NOFILESTODELETE, UIERROR_NOFILESTOEXTRACT,
UIERROR_MISSINGVOL, UIERROR_NEEDPREVVOL, UIERROR_UNKNOWNEXTRA,
UIERROR_CORRUPTEXTRA, UIERROR_NTFSREQUIRED, UIERROR_ZIPVOLSFX,
UIERROR_FILERO, UIERROR_TOOLARGESFX, UIERROR_EMAIL, UIERROR_ACLGET,
UIERROR_ACLBROKEN, UIERROR_ACLUNKNOWN, UIERROR_ACLSET, UIERROR_STREAMBROKEN,
UIERROR_STREAMUNKNOWN, UIERROR_INCOMPATSWITCH, UIERROR_PATHTOOLONG,
UIERROR_DIRSCAN, UIERROR_UOWNERGET, UIERROR_UOWNERBROKEN,
UIERROR_UOWNERGETOWNERID, UIERROR_UOWNERGETGROUPID, UIERROR_UOWNERSET,
UIERROR_ULINKREAD, UIERROR_ULINKEXIST,
UIERROR_FILERO, UIERROR_TOOLARGESFX, UIERROR_NOZIPSFX, UIERROR_EMAIL,
UIERROR_ACLGET, UIERROR_ACLBROKEN, UIERROR_ACLUNKNOWN, UIERROR_ACLSET,
UIERROR_STREAMBROKEN, UIERROR_STREAMUNKNOWN, UIERROR_INCOMPATSWITCH,
UIERROR_PATHTOOLONG, UIERROR_DIRSCAN, UIERROR_UOWNERGET,
UIERROR_UOWNERBROKEN, UIERROR_UOWNERGETOWNERID, UIERROR_UOWNERGETGROUPID,
UIERROR_UOWNERSET, UIERROR_ULINKREAD, UIERROR_ULINKEXIST,
UIERROR_OPENPRESERVEATIME,
UIMSG_FIRST,
UIMSG_STRING, UIMSG_BUILD, UIMSG_RRSEARCH, UIMSG_RRFOUND,
UIMSG_RRNOTFOUND, UIMSG_RRDAMAGED, UIMSG_BLOCKSRECOVERED,
UIMSG_STRING, UIMSG_BUILD, UIMSG_RRSEARCH, UIMSG_ANALYZEFILEDATA,
UIMSG_RRFOUND, UIMSG_RRNOTFOUND, UIMSG_RRDAMAGED, UIMSG_BLOCKSRECOVERED,
UIMSG_COPYINGDATA, UIMSG_AREADAMAGED, UIMSG_SECTORDAMAGED,
UIMSG_SECTORRECOVERED, UIMSG_SECTORNOTRECOVERED, UIMSG_FOUND,
UIMSG_CORRECTINGNAME, UIMSG_BADARCHIVE, UIMSG_CREATING, UIMSG_RENAMING,
@@ -75,7 +77,7 @@ enum UIASKREP_RESULT {
UIASKREP_RESULT uiAskReplace(wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags);
UIASKREP_RESULT uiAskReplaceEx(RAROptions *Cmd,wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags);
void uiInit(bool Sound);
void uiInit(SOUND_NOTIFY_MODE Sound);
void uiStartArchiveExtract(bool Extract,const wchar *ArcName);
@@ -85,6 +87,7 @@ void uiProcessProgress(const char *Command,int64 CurSize,int64 TotalSize);
enum UIPASSWORD_TYPE {UIPASSWORD_GLOBAL,UIPASSWORD_FILE,UIPASSWORD_ARCHIVE};
bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password);
bool uiIsGlobalPasswordSet();
enum UIALARM_TYPE {UIALARM_ERROR, UIALARM_INFO, UIALARM_QUESTION};
void uiAlarm(UIALARM_TYPE Type);
@@ -110,6 +113,11 @@ class uiMsgStore
public:
uiMsgStore(UIMESSAGE_CODE Code)
{
// Init arrays in case a caller passes fewer parameters than expected.
for (uint I=0;I<ASIZE(Str);I++)
Str[I]=L"";
memset(Num,0,sizeof(Num));
NumSize=StrSize=0;
this->Code=Code;
}

View File

@@ -1,8 +1,8 @@
static bool uiSoundEnabled;
static SOUND_NOTIFY_MODE uiSoundNotify;
void uiInit(bool Sound)
void uiInit(SOUND_NOTIFY_MODE Sound)
{
uiSoundEnabled = Sound;
uiSoundNotify = Sound;
}

View File

@@ -18,7 +18,10 @@ UIASKREP_RESULT uiAskReplace(wchar *Name,size_t MaxNameSize,int64 FileSize,RarTi
{
itoa(FileSize,SizeText2,ASIZE(SizeText2));
FileTime->GetText(DateStr2,ASIZE(DateStr2),false);
eprintf(St(MAskReplace),Name,SizeText1,DateStr1,SizeText2,DateStr2);
if ((Flags & UIASKREP_F_EXCHSRCDEST)==0)
eprintf(St(MAskReplace),Name,SizeText1,DateStr1,SizeText2,DateStr2);
else
eprintf(St(MAskReplace),Name,SizeText2,DateStr2,SizeText1,DateStr1);
}
bool AllowRename=(Flags & UIASKREP_F_NORENAME)==0;
@@ -96,10 +99,13 @@ void uiMsgStore::Msg()
Log(Str[0],St(MDataBadCRC),Str[1],Str[0]);
break;
case UIERROR_BADPSW:
Log(Str[0],St(MWrongFilePassword),Str[1]);
break;
case UIWAIT_BADPSW:
Log(Str[0],St(MWrongPassword));
break;
case UIERROR_MEMORY:
mprintf(L"\n");
Log(NULL,St(MErrOutMem));
break;
case UIERROR_FILEOPEN:
@@ -124,6 +130,9 @@ void uiMsgStore::Msg()
case UIERROR_FILEDELETE:
Log(Str[0],St(MCannotDelete),Str[1]);
break;
case UIERROR_RECYCLEFAILED:
Log(Str[0],St(MRecycleFailed));
break;
case UIERROR_FILERENAME:
Log(Str[0],St(MErrRename),Str[1],Str[2]);
break;
@@ -147,6 +156,10 @@ void uiMsgStore::Msg()
case UIERROR_HLINKCREATE:
Log(NULL,St(MErrCreateLnkH),Str[0]);
break;
case UIERROR_NOLINKTARGET:
Log(NULL,St(MErrLnkTarget));
mprintf(L" "); // For progress percent.
break;
case UIERROR_NEEDADMIN:
Log(NULL,St(MNeedAdmin));
break;
@@ -178,7 +191,11 @@ void uiMsgStore::Msg()
Log(Str[0],St(MUnknownMeth),Str[1]);
break;
case UIERROR_UNKNOWNENCMETHOD:
Log(Str[0],St(MUnkEncMethod),Str[1]);
{
wchar Msg[256];
swprintf(Msg,ASIZE(Msg),St(MUnkEncMethod),Str[1]);
Log(Str[0],L"%s: %s",Msg,Str[2]);
}
break;
#ifndef SFX_MODULE
case UIERROR_RENAMING:
@@ -211,6 +228,7 @@ void uiMsgStore::Msg()
break;
case UIERROR_INVALIDNAME:
Log(Str[0],St(MInvalidName),Str[1]);
mprintf(L"\n"); // Needed when called from CmdExtract::ExtractCurrentFile.
break;
#ifndef SFX_MODULE
case UIERROR_NEWRARFORMAT:
@@ -339,13 +357,22 @@ void uiMsgStore::Msg()
bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password)
{
return GetConsolePassword(Type,FileName,Password);
// Unlike GUI we cannot provide Cancel button here, so we use the empty
// password to abort. Otherwise user not knowing a password would need to
// press Ctrl+C multiple times to quit from infinite password request loop.
return GetConsolePassword(Type,FileName,Password) && Password->IsSet();
}
bool uiIsGlobalPasswordSet()
{
return false;
}
void uiAlarm(UIALARM_TYPE Type)
{
if (uiSoundEnabled)
if (uiSoundNotify==SOUND_NOTIFY_ON)
{
static clock_t LastTime=-10; // Negative to always beep first time.
if ((MonoClock()-LastTime)/CLOCKS_PER_SEC>5)

View File

@@ -39,6 +39,12 @@ bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Passw
}
bool uiIsGlobalPasswordSet()
{
return false;
}
void uiAlarm(UIALARM_TYPE Type)
{
}

View File

@@ -50,8 +50,11 @@ bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const w
char Target[NM];
if (IsLink(Arc.FileHead.FileAttr))
{
size_t DataSize=Min(Arc.FileHead.PackSize,ASIZE(Target)-1);
DataIO.UnpRead((byte *)Target,DataSize);
size_t DataSize=(size_t)Arc.FileHead.PackSize;
if (DataSize>ASIZE(Target)-1)
return false;
if ((size_t)DataIO.UnpRead((byte *)Target,DataSize)!=DataSize)
return false;
Target[DataSize]=0;
DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,1);

View File

@@ -1,9 +0,0 @@
#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

View File

@@ -36,7 +36,25 @@ bool WideToChar(const wchar *Src,char *Dest,size_t DestSize)
mbstate_t ps; // Use thread safe external state based functions.
memset (&ps, 0, sizeof(ps));
const wchar *SrcParam=Src; // wcsrtombs can change the pointer.
// Some implementations of wcsrtombs can cause memory analyzing tools
// like valgrind to report uninitialized data access. It happens because
// internally these implementations call SSE4 based wcslen function,
// which reads 16 bytes at once including those beyond of trailing 0.
size_t ResultingSize=wcsrtombs(Dest,&SrcParam,DestSize,&ps);
if (ResultingSize==(size_t)-1 && errno==EILSEQ)
{
// Aborted on inconvertible character not zero terminating the result.
// EILSEQ helps to distinguish it from small output buffer abort.
// We want to convert as much as we can, so we clean the output buffer
// and repeat conversion.
memset (&ps, 0, sizeof(ps));
SrcParam=Src; // wcsrtombs can change the pointer.
memset(Dest,0,DestSize);
ResultingSize=wcsrtombs(Dest,&SrcParam,DestSize,&ps);
}
if (ResultingSize==(size_t)-1)
RetCode=false;
if (ResultingSize==0 && *Src!=0)
@@ -52,7 +70,7 @@ bool WideToChar(const wchar *Src,char *Dest,size_t DestSize)
#endif
if (DestSize>0)
Dest[DestSize-1]=0;
// We tried to return the empty string if conversion is failed,
// but it does not work well. WideCharToMultiByte returns 'failed' code
// and partially converted string even if we wanted to convert only a part
@@ -120,21 +138,21 @@ bool WideToCharMap(const wchar *Src,char *Dest,size_t DestSize,bool &Success)
if (wcschr(Src,(wchar)MappedStringMark)==NULL)
return false;
// Seems to be that wcrtomb in some memory analyzing libraries
// can produce uninitilized output while reporting success on garbage input.
// So we clean the destination to calm analyzers.
memset(Dest,0,DestSize);
Success=true;
uint SrcPos=0,DestPos=0;
while (DestPos<DestSize-MB_CUR_MAX)
while (Src[SrcPos]!=0 && DestPos<DestSize-MB_CUR_MAX)
{
if (Src[SrcPos]==0)
{
Dest[DestPos]=0;
break;
}
if (uint(Src[SrcPos])==MappedStringMark)
{
SrcPos++;
continue;
}
// For security reasons do not retore low ASCII codes, so mapping cannot
// For security reasons do not restore low ASCII codes, so mapping cannot
// be used to hide control codes like path separators.
if (uint(Src[SrcPos])>=MapAreaStart+0x80 && uint(Src[SrcPos])<MapAreaStart+0x100)
Dest[DestPos++]=char(uint(Src[SrcPos++])-MapAreaStart);
@@ -142,21 +160,25 @@ bool WideToCharMap(const wchar *Src,char *Dest,size_t DestSize,bool &Success)
{
mbstate_t ps;
memset(&ps,0,sizeof(ps));
if (wcrtomb(Dest+DestPos,Src[SrcPos],&ps)==-1)
if (wcrtomb(Dest+DestPos,Src[SrcPos],&ps)==(size_t)-1)
{
Dest[DestPos]='_';
Success=false;
}
SrcPos++;
memset(&ps,0,sizeof(ps));
int Length=mbrlen(Dest+DestPos,MB_CUR_MAX,&ps);
DestPos+=Max(Length,1);
}
}
Dest[Min(DestPos,DestSize-1)]=0;
return true;
}
#endif
#if defined(_UNIX) && defined(MBFUNCTIONS)
// Convert and map inconvertible Unicode characters.
// Convert and map inconvertible Unicode characters.
// We use it for extended ASCII names in Unix.
void CharToWideMap(const char *Src,wchar *Dest,size_t DestSize,bool &Success)
{
@@ -170,13 +192,13 @@ void CharToWideMap(const char *Src,wchar *Dest,size_t DestSize,bool &Success)
{
if (Src[SrcPos]==0)
{
Dest[DestPos]=0;
Success=true;
break;
}
mbstate_t ps;
memset(&ps,0,sizeof(ps));
if (mbrtowc(Dest+DestPos,Src+SrcPos,MB_CUR_MAX,&ps)==-1)
size_t res=mbrtowc(Dest+DestPos,Src+SrcPos,MB_CUR_MAX,&ps);
if (res==(size_t)-1 || res==(size_t)-2)
{
// For security reasons we do not want to map low ASCII characters,
// so we do not have additional .. and path separator codes.
@@ -202,6 +224,7 @@ void CharToWideMap(const char *Src,wchar *Dest,size_t DestSize,bool &Success)
DestPos++;
}
}
Dest[Min(DestPos,DestSize-1)]=0;
}
#endif
@@ -281,7 +304,7 @@ size_t WideToUtfSize(const wchar *Src)
if (*Src<0x800)
Size+=2;
else
if (*Src<0x10000)
if ((uint)*Src<0x10000) //(uint) to avoid Clang/win "always true" warning for 16-bit wchar_t.
{
if (Src[0]>=0xd800 && Src[0]<=0xdbff && Src[1]>=0xdc00 && Src[1]<=0xdfff)
{
@@ -292,13 +315,12 @@ size_t WideToUtfSize(const wchar *Src)
Size+=3;
}
else
if (*Src<0x200000)
if ((uint)*Src<0x200000) //(uint) to avoid Clang/win "always true" warning for 16-bit wchar_t.
Size+=4;
return Size+1; // Include terminating zero.
}
// Dest can be NULL if we only need to check validity of Src.
bool UtfToWide(const char *Src,wchar *Dest,size_t DestSize)
{
bool Success=true;
@@ -347,40 +369,56 @@ bool UtfToWide(const char *Src,wchar *Dest,size_t DestSize)
Success=false;
break;
}
if (Dest!=NULL && --dsize<0)
if (--dsize<0)
break;
if (d>0xffff)
{
if (Dest!=NULL && --dsize<0)
if (--dsize<0)
break;
if (d>0x10ffff) // UTF-8 must end at 0x10ffff according to RFC 3629.
{
Success=false;
continue;
}
if (Dest!=NULL)
if (sizeof(*Dest)==2) // Use the surrogate pair.
{
*(Dest++)=((d-0x10000)>>10)+0xd800;
*(Dest++)=(d&0x3ff)+0xdc00;
}
else
*(Dest++)=d;
if (sizeof(*Dest)==2) // Use the surrogate pair.
{
*(Dest++)=((d-0x10000)>>10)+0xd800;
*(Dest++)=(d&0x3ff)+0xdc00;
}
else
*(Dest++)=d;
}
else
if (Dest!=NULL)
*(Dest++)=d;
*(Dest++)=d;
}
if (Dest!=NULL)
*Dest=0;
*Dest=0;
return Success;
}
// Source data can be both with and without UTF-8 BOM.
bool IsTextUtf8(const char *Src)
// For zero terminated strings.
bool IsTextUtf8(const byte *Src)
{
return UtfToWide(Src,NULL,0);
return IsTextUtf8(Src,strlen((const char *)Src));
}
// Source data can be both with and without UTF-8 BOM.
bool IsTextUtf8(const byte *Src,size_t SrcSize)
{
while (SrcSize-- > 0)
{
byte C=*(Src++);
int HighOne=0; // Number of leftmost '1' bits.
for (byte Mask=0x80;Mask!=0 && (C & Mask)!=0;Mask>>=1)
HighOne++;
if (HighOne==1 || HighOne>6)
return false;
while (--HighOne > 0)
if (SrcSize-- <= 0 || (*(Src++) & 0xc0)!=0x80)
return false;
}
return true;
}
@@ -451,6 +489,8 @@ const wchar_t* wcscasestr(const wchar_t *str, const wchar_t *search)
wchar* wcslower(wchar *s)
{
#ifdef _WIN_ALL
// _wcslwr requires setlocale and we do not want to depend on setlocale
// in Windows. Also CharLower involves less overhead.
CharLower(s);
#else
for (wchar *c=s;*c!=0;c++)
@@ -465,6 +505,8 @@ wchar* wcslower(wchar *s)
wchar* wcsupper(wchar *s)
{
#ifdef _WIN_ALL
// _wcsupr requires setlocale and we do not want to depend on setlocale
// in Windows. Also CharUpper involves less overhead.
CharUpper(s);
#else
for (wchar *c=s;*c!=0;c++)
@@ -482,8 +524,9 @@ int toupperw(int ch)
#if defined(_WIN_ALL)
// CharUpper is more reliable than towupper in Windows, which seems to be
// C locale dependent even in Unicode version. For example, towupper failed
// to convert lowercase Russian characters.
return (int)(INT_PTR)CharUpper((wchar *)(INT_PTR)ch);
// to convert lowercase Russian characters. Use 0xffff mask to prevent crash
// if value larger than 0xffff is passed to this function.
return (int)(INT_PTR)CharUpper((wchar *)(INT_PTR)(ch&0xffff));
#else
return towupper(ch);
#endif
@@ -494,8 +537,9 @@ int tolowerw(int ch)
{
#if defined(_WIN_ALL)
// CharLower is more reliable than towlower in Windows.
// See comment for towupper above.
return (int)(INT_PTR)CharLower((wchar *)(INT_PTR)ch);
// See comment for towupper above. Use 0xffff mask to prevent crash
// if value larger than 0xffff is passed to this function.
return (int)(INT_PTR)CharLower((wchar *)(INT_PTR)(ch&0xffff));
#else
return towlower(ch);
#endif
@@ -510,19 +554,23 @@ int atoiw(const wchar *s)
int64 atoilw(const wchar *s)
{
int sign=1;
if (*s=='-')
bool sign=false;
if (*s=='-') // We do use signed integers here, for example, in GUI SFX.
{
s++;
sign=-1;
sign=true;
}
int64 n=0;
// Use unsigned type here, since long string can overflow the variable
// and signed integer overflow is undefined behavior in C++.
uint64 n=0;
while (*s>='0' && *s<='9')
{
n=n*10+(*s-'0');
s++;
}
return sign*n;
// Check int64(n)>=0 to avoid the signed overflow with undefined behavior
// when negating 0x8000000000000000.
return sign && int64(n)>=0 ? -int64(n) : int64(n);
}
@@ -606,3 +654,5 @@ char* SupportDBCS::strrchrd(const char *s, int c)
return((char *)found);
}
#endif

View File

@@ -12,7 +12,8 @@ wchar* RawToWide(const byte *Src,wchar *Dest,size_t DestSize);
void WideToUtf(const wchar *Src,char *Dest,size_t DestSize);
size_t WideToUtfSize(const wchar *Src);
bool UtfToWide(const char *Src,wchar *Dest,size_t DestSize);
bool IsTextUtf8(const char *Src);
bool IsTextUtf8(const byte *Src);
bool IsTextUtf8(const byte *Src,size_t SrcSize);
int wcsicomp(const wchar *s1,const wchar *s2);
int wcsnicomp(const wchar *s1,const wchar *s2,size_t n);
@@ -62,4 +63,5 @@ inline void InitDBCS() {gdbcs.Init();}
inline void copychrd(char *dest,const char *src) {*dest=*src;}
#endif
#endif

View File

@@ -26,7 +26,7 @@ Unpack::Unpack(ComprDataIO *DataIO)
UnpSomeRead=false;
#ifdef RAR_SMP
MaxUserThreads=1;
UnpThreadPool=CreateThreadPool();
UnpThreadPool=NULL;
ReadBufMT=NULL;
UnpThreadData=NULL;
#endif
@@ -52,13 +52,24 @@ Unpack::~Unpack()
if (Window!=NULL)
free(Window);
#ifdef RAR_SMP
DestroyThreadPool(UnpThreadPool);
delete UnpThreadPool;
delete[] ReadBufMT;
delete[] UnpThreadData;
#endif
}
#ifdef RAR_SMP
void Unpack::SetThreads(uint Threads)
{
// More than 8 threads are unlikely to provide noticeable gain
// for unpacking, but would use the additional memory.
MaxUserThreads=Min(Threads,8);
UnpThreadPool=new ThreadPool(MaxUserThreads);
}
#endif
void Unpack::Init(size_t WinSize,bool Solid)
{
// If 32-bit RAR unpacks an archive with 4 GB dictionary, the window size
@@ -135,7 +146,7 @@ void Unpack::Init(size_t WinSize,bool Solid)
}
void Unpack::DoUnpack(int Method,bool Solid)
void Unpack::DoUnpack(uint Method,bool Solid)
{
// Methods <50 will crash in Fragmented mode when accessing NULL Window.
// They cannot be called in such mode now, but we check it below anyway
@@ -206,6 +217,7 @@ void Unpack::UnpInitData(bool Solid)
UnpInitData20(Solid);
#endif
UnpInitData30(Solid);
UnpInitData50(Solid);
}

View File

@@ -24,7 +24,7 @@
#define MAX_FILTER_BLOCK_SIZE 0x400000
// Write data in 4 MB or smaller blocks. Must not exceed PACK_MAX_WRITE,
// so we keep number of buffered filter in unpacker reasonable.
// so we keep a number of buffered filters in unpacker reasonable.
#define UNPACK_MAX_WRITE 0x400000
// Decode compressed bit fields to alphabet numbers.
@@ -211,6 +211,7 @@ class Unpack:PackDef
void UnpWriteArea(size_t StartPtr,size_t EndPtr);
void UnpWriteData(byte *Data,size_t Size);
_forceinline uint SlotToLength(BitInput &Inp,uint Slot);
void UnpInitData50(bool Solid);
bool ReadBlockHeader(BitInput &Inp,UnpackBlockHeader &Header);
bool ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTables &Tables);
void MakeDecodeTables(byte *LengthTable,DecodeTable *Dec,uint Size);
@@ -307,7 +308,9 @@ class Unpack:PackDef
DecodeTable MD[4]; // Decode multimedia data, up to 4 channels.
unsigned char UnpOldTable20[MC20*4];
int UnpAudioBlock,UnpChannels,UnpCurChannel,UnpChannelDelta;
bool UnpAudioBlock;
uint UnpChannels,UnpCurChannel;
int UnpChannelDelta;
void CopyString20(uint Length,uint Distance);
bool ReadTables20();
void UnpWriteBuf20();
@@ -326,7 +329,7 @@ class Unpack:PackDef
bool ReadEndOfBlock();
bool ReadVMCode();
bool ReadVMCodePPM();
bool AddVMCode(uint FirstByte,byte *Code,int CodeSize);
bool AddVMCode(uint FirstByte,byte *Code,uint CodeSize);
int SafePPMDecodeChar();
bool ReadTables30();
bool UnpReadBuf30();
@@ -341,7 +344,12 @@ class Unpack:PackDef
byte UnpOldTable[HUFF_TABLE_SIZE30];
int UnpBlockType;
bool TablesRead;
// If we already read decoding tables for Unpack v2,v3,v5.
// We should not use a single variable for all algorithm versions,
// because we can have a corrupt archive with one algorithm file
// followed by another algorithm file with "solid" flag and we do not
// want to reuse tables from one algorithm in another.
bool TablesRead2,TablesRead3,TablesRead5;
// Virtual machine to execute filters code.
RarVM VM;
@@ -368,16 +376,13 @@ class Unpack:PackDef
Unpack(ComprDataIO *DataIO);
~Unpack();
void Init(size_t WinSize,bool Solid);
void DoUnpack(int Method,bool Solid);
void DoUnpack(uint Method,bool Solid);
bool IsFileExtracted() {return(FileExtracted);}
void SetDestSize(int64 DestSize) {DestUnpSize=DestSize;FileExtracted=false;}
void SetSuspended(bool Suspended) {Unpack::Suspended=Suspended;}
#ifdef RAR_SMP
// More than 8 threads are unlikely to provide a noticeable gain
// for unpacking, but would use the additional memory.
void SetThreads(uint Threads) {MaxUserThreads=Min(Threads,8);}
void SetThreads(uint Threads);
void UnpackDecode(UnpackThreadData &D);
#endif
@@ -387,8 +392,12 @@ class Unpack:PackDef
uint GetChar()
{
if (Inp.InAddr>BitInput::MAX_SIZE-30)
{
UnpReadBuf();
return(Inp.InBuf[Inp.InAddr++]);
if (Inp.InAddr>=BitInput::MAX_SIZE) // If nothing was read.
return 0;
}
return Inp.InBuf[Inp.InAddr++];
}
};

View File

@@ -285,7 +285,7 @@ void Unpack::LongLZ()
break;
}
ChSetB[DistancePlace]=ChSetB[NewDistancePlace];
ChSetB[DistancePlace & 0xff]=ChSetB[NewDistancePlace];
ChSetB[NewDistancePlace]=Distance;
Distance=((Distance & 0xff00) | (Inp.fgetbits() >> 8)) >> 1;

View File

@@ -2,7 +2,8 @@
void Unpack::CopyString20(uint Length,uint Distance)
{
LastDist=OldDist[OldDistPtr++ & 3]=Distance;
LastDist=OldDist[OldDistPtr++]=Distance;
OldDistPtr = OldDistPtr & 3; // Needed if RAR 1.5 file is called after RAR 2.0.
LastLength=Length;
DestUnpSize-=Length;
CopyString(Length,Distance);
@@ -13,11 +14,11 @@ void Unpack::Unpack20(bool Solid)
{
static unsigned char LDecode[]={0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224};
static unsigned char LBits[]= {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5};
static int DDecode[]={0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040};
static uint DDecode[]={0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040};
static unsigned char DBits[]= {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16};
static unsigned char SDDecode[]={0,4,8,16,32,64,128,192};
static unsigned char SDBits[]= {2,2,3, 4, 5, 6, 6, 6};
unsigned int Bits;
uint Bits;
if (Suspended)
UnpPtr=WrPtr;
@@ -26,9 +27,8 @@ void Unpack::Unpack20(bool Solid)
UnpInitData(Solid);
if (!UnpReadBuf())
return;
if (!Solid)
if (!ReadTables20())
return;
if ((!Solid || !TablesRead2) && !ReadTables20())
return;
--DestUnpSize;
}
@@ -47,7 +47,7 @@ void Unpack::Unpack20(bool Solid)
}
if (UnpAudioBlock)
{
int AudioNumber=DecodeNumber(Inp,&MD[UnpCurChannel]);
uint AudioNumber=DecodeNumber(Inp,&MD[UnpCurChannel]);
if (AudioNumber==256)
{
@@ -55,14 +55,14 @@ void Unpack::Unpack20(bool Solid)
break;
continue;
}
Window[UnpPtr++]=DecodeAudio(AudioNumber);
Window[UnpPtr++]=DecodeAudio((int)AudioNumber);
if (++UnpCurChannel==UnpChannels)
UnpCurChannel=0;
--DestUnpSize;
continue;
}
int Number=DecodeNumber(Inp,&BlockTables.LD);
uint Number=DecodeNumber(Inp,&BlockTables.LD);
if (Number<256)
{
Window[UnpPtr++]=(byte)Number;
@@ -71,15 +71,15 @@ void Unpack::Unpack20(bool Solid)
}
if (Number>269)
{
int Length=LDecode[Number-=270]+3;
uint Length=LDecode[Number-=270]+3;
if ((Bits=LBits[Number])>0)
{
Length+=Inp.getbits()>>(16-Bits);
Inp.addbits(Bits);
}
int DistNumber=DecodeNumber(Inp,&BlockTables.DD);
unsigned int Distance=DDecode[DistNumber]+1;
uint DistNumber=DecodeNumber(Inp,&BlockTables.DD);
uint Distance=DDecode[DistNumber]+1;
if ((Bits=DBits[DistNumber])>0)
{
Distance+=Inp.getbits()>>(16-Bits);
@@ -109,9 +109,9 @@ void Unpack::Unpack20(bool Solid)
}
if (Number<261)
{
unsigned int Distance=OldDist[(OldDistPtr-(Number-256)) & 3];
int LengthNumber=DecodeNumber(Inp,&BlockTables.RD);
int Length=LDecode[LengthNumber]+2;
uint Distance=OldDist[(OldDistPtr-(Number-256)) & 3];
uint LengthNumber=DecodeNumber(Inp,&BlockTables.RD);
uint Length=LDecode[LengthNumber]+2;
if ((Bits=LBits[LengthNumber])>0)
{
Length+=Inp.getbits()>>(16-Bits);
@@ -132,7 +132,7 @@ void Unpack::Unpack20(bool Solid)
}
if (Number<270)
{
unsigned int Distance=SDDecode[Number-=261]+1;
uint Distance=SDDecode[Number-=261]+1;
if ((Bits=SDBits[Number])>0)
{
Distance+=Inp.getbits()>>(16-Bits);
@@ -167,17 +167,17 @@ bool Unpack::ReadTables20()
{
byte BitLength[BC20];
byte Table[MC20*4];
int TableSize,N,I;
if (Inp.InAddr>ReadTop-25)
if (!UnpReadBuf())
return(false);
return false;
uint BitField=Inp.getbits();
UnpAudioBlock=(BitField & 0x8000);
UnpAudioBlock=(BitField & 0x8000)!=0;
if (!(BitField & 0x4000))
memset(UnpOldTable20,0,sizeof(UnpOldTable20));
Inp.addbits(2);
uint TableSize;
if (UnpAudioBlock)
{
UnpChannels=((BitField>>12) & 3)+1;
@@ -189,19 +189,18 @@ bool Unpack::ReadTables20()
else
TableSize=NC20+DC20+RC20;
for (I=0;I<BC20;I++)
for (uint I=0;I<BC20;I++)
{
BitLength[I]=(byte)(Inp.getbits() >> 12);
Inp.addbits(4);
}
MakeDecodeTables(BitLength,&BlockTables.BD,BC20);
I=0;
while (I<TableSize)
for (uint I=0;I<TableSize;)
{
if (Inp.InAddr>ReadTop-5)
if (!UnpReadBuf())
return false;
int Number=DecodeNumber(Inp,&BlockTables.BD);
uint Number=DecodeNumber(Inp,&BlockTables.BD);
if (Number<16)
{
Table[I]=(Number+UnpOldTable20[I]) & 0xf;
@@ -210,9 +209,11 @@ bool Unpack::ReadTables20()
else
if (Number==16)
{
N=(Inp.getbits() >> 14)+3;
uint N=(Inp.getbits() >> 14)+3;
Inp.addbits(2);
if (I>0)
if (I==0)
return false; // We cannot have "repeat previous" code at the first position.
else
while (N-- > 0 && I<TableSize)
{
Table[I]=Table[I-1];
@@ -221,6 +222,7 @@ bool Unpack::ReadTables20()
}
else
{
uint N;
if (Number==17)
{
N=(Inp.getbits() >> 13)+3;
@@ -235,10 +237,11 @@ bool Unpack::ReadTables20()
Table[I++]=0;
}
}
TablesRead2=true;
if (Inp.InAddr>ReadTop)
return(true);
return true;
if (UnpAudioBlock)
for (I=0;I<UnpChannels;I++)
for (uint I=0;I<UnpChannels;I++)
MakeDecodeTables(&Table[I*MC20],&MD[I],MC20);
else
{
@@ -246,8 +249,8 @@ bool Unpack::ReadTables20()
MakeDecodeTables(&Table[NC20],&BlockTables.DD,DC20);
MakeDecodeTables(&Table[NC20+DC20],&BlockTables.RD,RC20);
}
memcpy(UnpOldTable20,Table,sizeof(UnpOldTable20));
return(true);
memcpy(UnpOldTable20,Table,TableSize);
return true;
}
@@ -269,7 +272,10 @@ void Unpack::UnpInitData20(int Solid)
{
if (!Solid)
{
UnpAudioBlock=UnpChannelDelta=UnpCurChannel=0;
TablesRead2=false;
UnpAudioBlock=false;
UnpChannelDelta=0;
UnpCurChannel=0;
UnpChannels=1;
memset(AudV,0,sizeof(AudV));
@@ -290,9 +296,12 @@ byte Unpack::DecodeAudio(int Delta)
int PCh=8*V->LastChar+V->K1*V->D1+V->K2*V->D2+V->K3*V->D3+V->K4*V->D4+V->K5*UnpChannelDelta;
PCh=(PCh>>3) & 0xFF;
unsigned int Ch=PCh-Delta;
uint Ch=PCh-Delta;
int D=((signed char)Delta)<<3;
int D=(signed char)Delta;
// Left shift of negative value is undefined behavior in C++,
// so we cast it to unsigned to follow the standard.
D=(uint)D<<3;
V->Dif[0]+=abs(D);
V->Dif[1]+=abs(D-V->D1);
@@ -311,9 +320,9 @@ byte Unpack::DecodeAudio(int Delta)
if ((V->ByteCount & 0x1F)==0)
{
unsigned int MinDif=V->Dif[0],NumMinDif=0;
uint MinDif=V->Dif[0],NumMinDif=0;
V->Dif[0]=0;
for (int I=1;I<sizeof(V->Dif)/sizeof(V->Dif[0]);I++)
for (uint I=1;I<ASIZE(V->Dif);I++)
{
if (V->Dif[I]<MinDif)
{
@@ -366,5 +375,5 @@ byte Unpack::DecodeAudio(int Delta)
break;
}
}
return((byte)Ch);
return (byte)Ch;
}

View File

@@ -42,7 +42,7 @@ void Unpack::Unpack29(bool Solid)
UnpInitData(Solid);
if (!UnpReadBuf30())
return;
if ((!Solid || !TablesRead) && !ReadTables30())
if ((!Solid || !TablesRead3) && !ReadTables30())
return;
}
@@ -133,7 +133,7 @@ void Unpack::Unpack29(bool Solid)
continue;
}
int Number=DecodeNumber(Inp,&BlockTables.LD);
uint Number=DecodeNumber(Inp,&BlockTables.LD);
if (Number<256)
{
Window[UnpPtr++]=(byte)Number;
@@ -141,15 +141,15 @@ void Unpack::Unpack29(bool Solid)
}
if (Number>=271)
{
int Length=LDecode[Number-=271]+3;
uint Length=LDecode[Number-=271]+3;
if ((Bits=LBits[Number])>0)
{
Length+=Inp.getbits()>>(16-Bits);
Inp.addbits(Bits);
}
int DistNumber=DecodeNumber(Inp,&BlockTables.DD);
unsigned int Distance=DDecode[DistNumber]+1;
uint DistNumber=DecodeNumber(Inp,&BlockTables.DD);
uint Distance=DDecode[DistNumber]+1;
if ((Bits=DBits[DistNumber])>0)
{
if (DistNumber>9)
@@ -166,7 +166,7 @@ void Unpack::Unpack29(bool Solid)
}
else
{
int LowDist=DecodeNumber(Inp,&BlockTables.LDD);
uint LowDist=DecodeNumber(Inp,&BlockTables.LDD);
if (LowDist==16)
{
LowDistRepCount=LOW_DIST_REP_COUNT-1;
@@ -189,7 +189,7 @@ void Unpack::Unpack29(bool Solid)
if (Distance>=0x2000)
{
Length++;
if (Distance>=0x40000L)
if (Distance>=0x40000)
Length++;
}
@@ -218,13 +218,13 @@ void Unpack::Unpack29(bool Solid)
}
if (Number<263)
{
int DistNum=Number-259;
unsigned int Distance=OldDist[DistNum];
for (int I=DistNum;I>0;I--)
uint DistNum=Number-259;
uint Distance=OldDist[DistNum];
for (uint I=DistNum;I>0;I--)
OldDist[I]=OldDist[I-1];
OldDist[0]=Distance;
int LengthNumber=DecodeNumber(Inp,&BlockTables.RD);
uint LengthNumber=DecodeNumber(Inp,&BlockTables.RD);
int Length=LDecode[LengthNumber]+2;
if ((Bits=LBits[LengthNumber])>0)
{
@@ -237,7 +237,7 @@ void Unpack::Unpack29(bool Solid)
}
if (Number<272)
{
unsigned int Distance=SDDecode[Number-=263]+1;
uint Distance=SDDecode[Number-=263]+1;
if ((Bits=SDBits[Number])>0)
{
Distance+=Inp.getbits()>>(16-Bits);
@@ -274,11 +274,11 @@ bool Unpack::ReadEndOfBlock()
NewTable=(BitField & 0x4000)!=0;
Inp.addbits(2);
}
TablesRead=!NewTable;
TablesRead3=!NewTable;
// Quit immediately if "new file" flag is set. If "new table" flag
// is present, we'll read the table in beginning of next file
// based on 'TablesRead' 'false' value.
// based on 'TablesRead3' 'false' value.
if (NewFile)
return false;
return ReadTables30(); // Quit only if we failed to read tables.
@@ -290,9 +290,9 @@ bool Unpack::ReadVMCode()
// Entire VM code is guaranteed to fully present in block defined
// by current Huffman table. Compressor checks that VM code does not cross
// Huffman block boundaries.
unsigned int FirstByte=Inp.getbits()>>8;
uint FirstByte=Inp.getbits()>>8;
Inp.addbits(8);
int Length=(FirstByte & 7)+1;
uint Length=(FirstByte & 7)+1;
if (Length==7)
{
Length=(Inp.getbits()>>8)+7;
@@ -304,8 +304,10 @@ bool Unpack::ReadVMCode()
Length=Inp.getbits();
Inp.addbits(16);
}
if (Length==0)
return false;
Array<byte> VMCode(Length);
for (int I=0;I<Length;I++)
for (uint I=0;I<Length;I++)
{
// Try to read the new buffer if only one byte is left.
// But if we read all bytes except the last, one byte is enough.
@@ -320,15 +322,15 @@ bool Unpack::ReadVMCode()
bool Unpack::ReadVMCodePPM()
{
unsigned int FirstByte=SafePPMDecodeChar();
uint FirstByte=SafePPMDecodeChar();
if ((int)FirstByte==-1)
return false;
int Length=(FirstByte & 7)+1;
uint Length=(FirstByte & 7)+1;
if (Length==7)
{
int B1=SafePPMDecodeChar();
if (B1==-1)
return(false);
return false;
Length=B1+7;
}
else
@@ -342,19 +344,21 @@ bool Unpack::ReadVMCodePPM()
return false;
Length=B1*256+B2;
}
if (Length==0)
return false;
Array<byte> VMCode(Length);
for (int I=0;I<Length;I++)
for (uint I=0;I<Length;I++)
{
int Ch=SafePPMDecodeChar();
if (Ch==-1)
return(false);
return false;
VMCode[I]=Ch;
}
return AddVMCode(FirstByte,&VMCode[0],Length);
}
bool Unpack::AddVMCode(uint FirstByte,byte *Code,int CodeSize)
bool Unpack::AddVMCode(uint FirstByte,byte *Code,uint CodeSize)
{
VMCodeInp.InitBitInput();
memcpy(VMCodeInp.InBuf,Code,Min(BitInput::MAX_SIZE,CodeSize));
@@ -405,7 +409,7 @@ bool Unpack::AddVMCode(uint FirstByte,byte *Code,int CodeSize)
StackFilter->ParentFilter=FiltPos;
}
int EmptyCount=0;
uint EmptyCount=0;
for (uint I=0;I<PrgStack.Size();I++)
{
PrgStack[I-EmptyCount]=PrgStack[I];
@@ -424,7 +428,7 @@ bool Unpack::AddVMCode(uint FirstByte,byte *Code,int CodeSize)
PrgStack.Add(1);
EmptyCount=1;
}
int StackPos=(int)(PrgStack.Size()-EmptyCount);
size_t StackPos=PrgStack.Size()-EmptyCount;
PrgStack[StackPos]=StackFilter;
uint BlockStart=RarVM::ReadData(VMCodeInp);
@@ -458,7 +462,7 @@ bool Unpack::AddVMCode(uint FirstByte,byte *Code,int CodeSize)
{
uint InitMask=VMCodeInp.fgetbits()>>9;
VMCodeInp.faddbits(7);
for (int I=0;I<7;I++)
for (uint I=0;I<7;I++)
if (InitMask & (1<<I))
StackFilter->Prg.InitR[I]=RarVM::ReadData(VMCodeInp);
}
@@ -466,7 +470,7 @@ bool Unpack::AddVMCode(uint FirstByte,byte *Code,int CodeSize)
if (NewFilter)
{
uint VMCodeSize=RarVM::ReadData(VMCodeInp);
if (VMCodeSize>=0x10000 || VMCodeSize==0)
if (VMCodeSize>=0x10000 || VMCodeSize==0 || VMCodeInp.InAddr+VMCodeSize>CodeSize)
return false;
Array<byte> VMCode(VMCodeSize);
for (uint I=0;I<VMCodeSize;I++)
@@ -644,13 +648,13 @@ bool Unpack::ReadTables30()
memset(UnpOldTable,0,sizeof(UnpOldTable));
Inp.faddbits(2);
for (int I=0;I<BC;I++)
for (uint I=0;I<BC;I++)
{
int Length=(byte)(Inp.fgetbits() >> 12);
uint Length=(byte)(Inp.fgetbits() >> 12);
Inp.faddbits(4);
if (Length==15)
{
int ZeroCount=(byte)(Inp.fgetbits() >> 12);
uint ZeroCount=(byte)(Inp.fgetbits() >> 12);
Inp.faddbits(4);
if (ZeroCount==0)
BitLength[I]=15;
@@ -667,13 +671,13 @@ bool Unpack::ReadTables30()
}
MakeDecodeTables(BitLength,&BlockTables.BD,BC30);
const int TableSize=HUFF_TABLE_SIZE30;
for (int I=0;I<TableSize;)
const uint TableSize=HUFF_TABLE_SIZE30;
for (uint I=0;I<TableSize;)
{
if (Inp.InAddr>ReadTop-5)
if (!UnpReadBuf30())
return(false);
int Number=DecodeNumber(Inp,&BlockTables.BD);
uint Number=DecodeNumber(Inp,&BlockTables.BD);
if (Number<16)
{
Table[I]=(Number+UnpOldTable[I]) & 0xf;
@@ -682,7 +686,7 @@ bool Unpack::ReadTables30()
else
if (Number<18)
{
int N;
uint N;
if (Number==16)
{
N=(Inp.fgetbits() >> 13)+3;
@@ -693,7 +697,9 @@ bool Unpack::ReadTables30()
N=(Inp.fgetbits() >> 9)+11;
Inp.faddbits(7);
}
if (I>0)
if (I==0)
return false; // We cannot have "repeat previous" code at the first position.
else
while (N-- > 0 && I<TableSize)
{
Table[I]=Table[I-1];
@@ -702,7 +708,7 @@ bool Unpack::ReadTables30()
}
else
{
int N;
uint N;
if (Number==18)
{
N=(Inp.fgetbits() >> 13)+3;
@@ -717,7 +723,7 @@ bool Unpack::ReadTables30()
Table[I++]=0;
}
}
TablesRead=true;
TablesRead3=true;
if (Inp.InAddr>ReadTop)
return false;
MakeDecodeTables(&Table[0],&BlockTables.LD,NC30);
@@ -733,7 +739,7 @@ void Unpack::UnpInitData30(bool Solid)
{
if (!Solid)
{
TablesRead=false;
TablesRead3=false;
memset(UnpOldTable,0,sizeof(UnpOldTable));
PPMEscChar=2;
UnpBlockType=BLOCK_LZ;

View File

@@ -7,7 +7,12 @@ void Unpack::Unpack5(bool Solid)
UnpInitData(Solid);
if (!UnpReadBuf())
return;
if (!ReadBlockHeader(Inp,BlockHeader) || !ReadTables(Inp,BlockHeader,BlockTables))
// Check TablesRead5 to be sure that we read tables at least once
// regardless of current block header TablePresent flag.
// So we can safefly use these tables below.
if (!ReadBlockHeader(Inp,BlockHeader) ||
!ReadTables(Inp,BlockHeader,BlockTables) || !TablesRead5)
return;
}
@@ -37,7 +42,7 @@ void Unpack::Unpack5(bool Solid)
break;
}
if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_LZ_MATCH+3 && WriteBorder!=UnpPtr)
if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
{
UnpWriteBuf();
if (WrittenFileSize>DestUnpSize)
@@ -431,6 +436,10 @@ byte* Unpack::ApplyFilter(byte *Data,uint DataSize,UnpackFilter *Flt)
}
return SrcData;
case FILTER_ARM:
// 2019-11-15: we turned off ARM filter by default when compressing,
// mostly because it is inefficient for modern 64 bit ARM binaries.
// It was turned on by default in 5.0 - 5.80b3 , so we still need it
// here for compatibility with some of previously created archives.
{
uint FileOffset=(uint)WrittenFileSize;
// DataSize is unsigned, so we use "CurPos+3" and not "DataSize-3"
@@ -516,6 +525,13 @@ void Unpack::UnpWriteData(byte *Data,size_t Size)
}
void Unpack::UnpInitData50(bool Solid)
{
if (!Solid)
TablesRead5=false;
}
bool Unpack::ReadBlockHeader(BitInput &Inp,UnpackBlockHeader &Header)
{
Header.HeaderSize=0;
@@ -524,11 +540,11 @@ bool Unpack::ReadBlockHeader(BitInput &Inp,UnpackBlockHeader &Header)
if (!UnpReadBuf())
return false;
Inp.faddbits((8-Inp.InBit)&7);
byte BlockFlags=Inp.fgetbits()>>8;
Inp.faddbits(8);
uint ByteCount=((BlockFlags>>3)&3)+1; // Block size byte count.
if (ByteCount==4)
return false;
@@ -570,13 +586,13 @@ bool Unpack::ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTable
return false;
byte BitLength[BC];
for (int I=0;I<BC;I++)
for (uint I=0;I<BC;I++)
{
int Length=(byte)(Inp.fgetbits() >> 12);
uint Length=(byte)(Inp.fgetbits() >> 12);
Inp.faddbits(4);
if (Length==15)
{
int ZeroCount=(byte)(Inp.fgetbits() >> 12);
uint ZeroCount=(byte)(Inp.fgetbits() >> 12);
Inp.faddbits(4);
if (ZeroCount==0)
BitLength[I]=15;
@@ -595,13 +611,13 @@ bool Unpack::ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTable
MakeDecodeTables(BitLength,&Tables.BD,BC);
byte Table[HUFF_TABLE_SIZE];
const int TableSize=HUFF_TABLE_SIZE;
for (int I=0;I<TableSize;)
const uint TableSize=HUFF_TABLE_SIZE;
for (uint I=0;I<TableSize;)
{
if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop-5)
if (!UnpReadBuf())
return false;
int Number=DecodeNumber(Inp,&Tables.BD);
uint Number=DecodeNumber(Inp,&Tables.BD);
if (Number<16)
{
Table[I]=Number;
@@ -610,7 +626,7 @@ bool Unpack::ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTable
else
if (Number<18)
{
int N;
uint N;
if (Number==16)
{
N=(Inp.fgetbits() >> 13)+3;
@@ -621,7 +637,16 @@ bool Unpack::ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTable
N=(Inp.fgetbits() >> 9)+11;
Inp.faddbits(7);
}
if (I>0)
if (I==0)
{
// We cannot have "repeat previous" code at the first position.
// Multiple such codes would shift Inp position without changing I,
// which can lead to reading beyond of Inp boundary in mutithreading
// mode, where Inp.ExternalBuffer disables bounds check and we just
// reserve a lot of buffer space to not need such check normally.
return false;
}
else
while (N-- > 0 && I<TableSize)
{
Table[I]=Table[I-1];
@@ -630,7 +655,7 @@ bool Unpack::ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTable
}
else
{
int N;
uint N;
if (Number==18)
{
N=(Inp.fgetbits() >> 13)+3;
@@ -645,6 +670,7 @@ bool Unpack::ReadTables(BitInput &Inp,UnpackBlockHeader &Header,UnpackBlockTable
Table[I++]=0;
}
}
TablesRead5=true;
if (!Inp.ExternalBuffer && Inp.InAddr>ReadTop)
return false;
MakeDecodeTables(&Table[0],&Tables.LD,NC);

View File

@@ -48,7 +48,7 @@ void FragmentedWindow::Init(size_t WinSize)
}
if (NewMem==NULL)
throw std::bad_alloc();
// Clean the window to generate the same output when unpacking corrupt
// RAR files, which may access to unused areas of sliding dictionary.
memset(NewMem,0,Size);

View File

@@ -133,11 +133,13 @@ void Unpack::Unpack5MT(bool Solid)
if (!CurData->HeaderRead)
{
CurData->HeaderRead=true;
if (!ReadBlockHeader(CurData->Inp,CurData->BlockHeader))
if (!ReadBlockHeader(CurData->Inp,CurData->BlockHeader) ||
!CurData->BlockHeader.TablePresent && !TablesRead5)
{
Done=true;
break;
}
TablesRead5=true;
}
// To prevent too high memory use we switch to single threaded mode
@@ -163,7 +165,7 @@ void Unpack::Unpack5MT(bool Solid)
if (DataLeft<TooSmallToProcess)
break;
}
//#undef USE_THREADS
UnpackThreadDataList UTDArray[MaxPoolThreads];
uint UTDArrayPos=0;
@@ -178,7 +180,7 @@ void Unpack::Unpack5MT(bool Solid)
UnpackThreadDataList *UTD=UTDArray+UTDArrayPos++;
UTD->D=UnpThreadData+CurBlock;
UTD->BlockCount=Min(MaxBlockPerThread,BlockNumberMT-CurBlock);
#ifdef USE_THREADS
if (BlockNumber==1)
UnpackDecode(*UTD->D);
@@ -198,7 +200,7 @@ void Unpack::Unpack5MT(bool Solid)
#endif
bool IncompleteThread=false;
for (uint Block=0;Block<BlockNumber;Block++)
{
UnpackThreadData *CurData=UnpThreadData+Block;
@@ -249,7 +251,7 @@ void Unpack::Unpack5MT(bool Solid)
break;
}
}
if (IncompleteThread || Done)
break; // Current buffer is done, read more data or quit.
else
@@ -301,7 +303,7 @@ void Unpack::UnpackDecode(UnpackThreadData &D)
D.DamagedData=true;
return;
}
D.DecodedSize=0;
int BlockBorder=D.BlockHeader.BlockStart+D.BlockHeader.BlockSize-1;
@@ -411,7 +413,7 @@ void Unpack::UnpackDecode(UnpackThreadData &D)
{
UnpackFilter Filter;
ReadFilter(D.Inp,Filter);
CurItem->Type=UNPDT_FILTER;
CurItem->Length=Filter.Type;
CurItem->Distance=Filter.BlockStart;
@@ -449,7 +451,7 @@ bool Unpack::ProcessDecoded(UnpackThreadData &D)
while (Item<Border)
{
UnpPtr&=MaxWinMask;
if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_LZ_MATCH+3 && WriteBorder!=UnpPtr)
if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
{
UnpWriteBuf();
if (WrittenFileSize>DestUnpSize)
@@ -496,7 +498,7 @@ bool Unpack::ProcessDecoded(UnpackThreadData &D)
if (Item->Type==UNPDT_FILTER)
{
UnpackFilter Filter;
Filter.Type=(byte)Item->Length;
Filter.BlockStart=Item->Distance;
@@ -532,7 +534,7 @@ bool Unpack::UnpackLargeBlock(UnpackThreadData &D)
D.DamagedData=true;
return false;
}
int BlockBorder=D.BlockHeader.BlockStart+D.BlockHeader.BlockSize-1;
// Reserve enough space even for filter entry.
@@ -557,7 +559,7 @@ bool Unpack::UnpackLargeBlock(UnpackThreadData &D)
break;
}
}
if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_LZ_MATCH+3 && WriteBorder!=UnpPtr)
if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
{
UnpWriteBuf();
if (WrittenFileSize>DestUnpSize)

View File

@@ -13,7 +13,7 @@ _forceinline void Unpack::InsertOldDist(uint Distance)
_forceinline void Unpack::CopyString(uint Length,uint Distance)
{
size_t SrcPtr=UnpPtr-Distance;
if (SrcPtr<MaxWinSize-MAX_LZ_MATCH && UnpPtr<MaxWinSize-MAX_LZ_MATCH)
if (SrcPtr<MaxWinSize-MAX_INC_LZ_MATCH && UnpPtr<MaxWinSize-MAX_INC_LZ_MATCH)
{
// If we are not close to end of window, we do not need to waste time
// to "& MaxWinMask" pointer protection.
@@ -46,7 +46,7 @@ _forceinline void Unpack::CopyString(uint Length,uint Distance)
{
// In theory we still could overlap here.
// Supposing Distance == MaxWinSize - 1 we have memcpy(Src, Src + 1, 8).
// But for real RAR archives Distance <= MaxWinSize - MAX_LZ_MATCH
// But for real RAR archives Distance <= MaxWinSize - MAX_INC_LZ_MATCH
// always, so overlap here is impossible.
// This memcpy expanded inline by MSVC. We could also use uint64
@@ -120,7 +120,7 @@ _forceinline uint Unpack::DecodeNumber(BitInput &Inp,DecodeTable *Dec)
// Convert the position in the code list to position in alphabet
// and return it.
return(Dec->DecodeNum[Pos]);
return Dec->DecodeNum[Pos];
}

View File

@@ -1,6 +1,6 @@
#define RARVER_MAJOR 5
#define RARVER_MINOR 50
#define RARVER_BETA 5
#define RARVER_DAY 2
#define RARVER_MONTH 7
#define RARVER_YEAR 2017
#define RARVER_MINOR 91
#define RARVER_BETA 0
#define RARVER_DAY 25
#define RARVER_MONTH 6
#define RARVER_YEAR 2020

Some files were not shown because too many files have changed in this diff Show More