Merge pull request #3734 from matrix/fix_rar_segfault_AppleSilicon

Dependencies: Updated unrar source to 6.2.7 | Fixed bug in 23800/unrar with Apple Silicon
pull/3721/head^2
Jens Steube 11 months ago committed by GitHub
commit 11502c77e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,279 +1,279 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32"> <ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
<Platform>Win32</Platform> <Platform>Win32</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64"> <ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
<Platform>x64</Platform> <Platform>x64</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32"> <ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<Platform>Win32</Platform> <Platform>Win32</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Release|x64"> <ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<Platform>x64</Platform> <Platform>x64</Platform>
</ProjectConfiguration> </ProjectConfiguration>
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectGuid>{95CC809B-03FC-4EDB-BB20-FD07A698C05F}</ProjectGuid> <ProjectGuid>{95CC809B-03FC-4EDB-BB20-FD07A698C05F}</ProjectGuid>
<RootNamespace>UnRAR</RootNamespace> <RootNamespace>UnRAR</RootNamespace>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset> <PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset> <PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset> <PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>false</WholeProgramOptimization> <WholeProgramOptimization>false</WholeProgramOptimization>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType> <ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset> <PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<PropertyGroup> <PropertyGroup>
<_ProjectFileVersion>14.0.24720.0</_ProjectFileVersion> <_ProjectFileVersion>14.0.24720.0</_ProjectFileVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>build\unrar32\$(Configuration)\</OutDir> <OutDir>build\unrar32\$(Configuration)\</OutDir>
<IntDir>build\unrar32\$(Configuration)\obj\</IntDir> <IntDir>build\unrar32\$(Configuration)\obj\</IntDir>
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>
<GenerateManifest>false</GenerateManifest> <GenerateManifest>false</GenerateManifest>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>build\unrar64\$(Configuration)\</OutDir> <OutDir>build\unrar64\$(Configuration)\</OutDir>
<IntDir>build\unrar64\$(Configuration)\obj\</IntDir> <IntDir>build\unrar64\$(Configuration)\obj\</IntDir>
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>
<GenerateManifest>false</GenerateManifest> <GenerateManifest>false</GenerateManifest>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>build\unrar32\$(Configuration)\</OutDir> <OutDir>build\unrar32\$(Configuration)\</OutDir>
<IntDir>build\unrar32\$(Configuration)\obj\</IntDir> <IntDir>build\unrar32\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental> <LinkIncremental>false</LinkIncremental>
<GenerateManifest>false</GenerateManifest> <GenerateManifest>false</GenerateManifest>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>build\unrar64\$(Configuration)\</OutDir> <OutDir>build\unrar64\$(Configuration)\</OutDir>
<IntDir>build\unrar64\$(Configuration)\obj\</IntDir> <IntDir>build\unrar64\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental> <LinkIncremental>false</LinkIncremental>
<GenerateManifest>false</GenerateManifest> <GenerateManifest>false</GenerateManifest>
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile> <ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<PreprocessorDefinitions>UNRAR;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>UNRAR;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<RuntimeTypeInfo>false</RuntimeTypeInfo> <RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile> <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention> <CallingConvention>StdCall</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine> <TargetMachine>MachineX86</TargetMachine>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl> <Midl>
<TargetEnvironment>X64</TargetEnvironment> <TargetEnvironment>X64</TargetEnvironment>
</Midl> </Midl>
<ClCompile> <ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<PreprocessorDefinitions>UNRAR;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>UNRAR;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<RuntimeTypeInfo>false</RuntimeTypeInfo> <RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile> <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention> <CallingConvention>StdCall</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<TargetMachine>MachineX64</TargetMachine> <TargetMachine>MachineX64</TargetMachine>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile> <ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed> <FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers> <OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization> <WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>UNRAR;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>UNRAR;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>Default</StructMemberAlignment> <StructMemberAlignment>Default</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck> <BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<FloatingPointModel>Precise</FloatingPointModel> <FloatingPointModel>Precise</FloatingPointModel>
<RuntimeTypeInfo>false</RuntimeTypeInfo> <RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile> <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention> <CallingConvention>StdCall</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration /> <LinkTimeCodeGeneration />
<TargetMachine>MachineX86</TargetMachine> <TargetMachine>MachineX86</TargetMachine>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl> <Midl>
<TargetEnvironment>X64</TargetEnvironment> <TargetEnvironment>X64</TargetEnvironment>
</Midl> </Midl>
<ClCompile> <ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MinSpace</Optimization> <Optimization>MinSpace</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed> <FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers> <OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization> <WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>UNRAR;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>UNRAR;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>false</StringPooling> <StringPooling>false</StringPooling>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<BufferSecurityCheck>true</BufferSecurityCheck> <BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo> <RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile> <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention> <CallingConvention>StdCall</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
</ClCompile> </ClCompile>
<Link> <Link>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration /> <LinkTimeCodeGeneration />
<TargetMachine>MachineX64</TargetMachine> <TargetMachine>MachineX64</TargetMachine>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="archive.cpp" /> <ClCompile Include="archive.cpp" />
<ClCompile Include="arcread.cpp" /> <ClCompile Include="arcread.cpp" />
<ClCompile Include="blake2s.cpp" /> <ClCompile Include="blake2s.cpp" />
<ClCompile Include="cmddata.cpp" /> <ClCompile Include="cmddata.cpp" />
<ClCompile Include="consio.cpp" /> <ClCompile Include="consio.cpp" />
<ClCompile Include="crc.cpp" /> <ClCompile Include="crc.cpp" />
<ClCompile Include="crypt.cpp" /> <ClCompile Include="crypt.cpp" />
<ClCompile Include="encname.cpp" /> <ClCompile Include="encname.cpp" />
<ClCompile Include="errhnd.cpp" /> <ClCompile Include="errhnd.cpp" />
<ClCompile Include="extinfo.cpp" /> <ClCompile Include="extinfo.cpp" />
<ClCompile Include="extract.cpp" /> <ClCompile Include="extract.cpp" />
<ClCompile Include="filcreat.cpp" /> <ClCompile Include="filcreat.cpp" />
<ClCompile Include="file.cpp" /> <ClCompile Include="file.cpp" />
<ClCompile Include="filefn.cpp" /> <ClCompile Include="filefn.cpp" />
<ClCompile Include="filestr.cpp" /> <ClCompile Include="filestr.cpp" />
<ClCompile Include="find.cpp" /> <ClCompile Include="find.cpp" />
<ClCompile Include="getbits.cpp" /> <ClCompile Include="getbits.cpp" />
<ClCompile Include="global.cpp"> <ClCompile Include="global.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</PrecompiledHeader> </PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeader> </PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</PrecompiledHeader> </PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeader> </PrecompiledHeader>
</ClCompile> </ClCompile>
<ClCompile Include="hash.cpp" /> <ClCompile Include="hash.cpp" />
<ClCompile Include="headers.cpp" /> <ClCompile Include="headers.cpp" />
<ClCompile Include="isnt.cpp" /> <ClCompile Include="isnt.cpp" />
<ClCompile Include="list.cpp" /> <ClCompile Include="list.cpp" />
<ClCompile Include="match.cpp" /> <ClCompile Include="match.cpp" />
<ClCompile Include="options.cpp" /> <ClCompile Include="options.cpp" />
<ClCompile Include="pathfn.cpp" /> <ClCompile Include="pathfn.cpp" />
<ClCompile Include="qopen.cpp" /> <ClCompile Include="qopen.cpp" />
<ClCompile Include="rar.cpp" /> <ClCompile Include="rar.cpp" />
<ClCompile Include="rarpch.cpp"> <ClCompile Include="rarpch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile> </ClCompile>
<ClCompile Include="rarvm.cpp" /> <ClCompile Include="rarvm.cpp" />
<ClCompile Include="rawread.cpp" /> <ClCompile Include="rawread.cpp" />
<ClCompile Include="rdwrfn.cpp" /> <ClCompile Include="rdwrfn.cpp" />
<ClCompile Include="recvol.cpp" /> <ClCompile Include="recvol.cpp" />
<ClCompile Include="resource.cpp" /> <ClCompile Include="resource.cpp" />
<ClCompile Include="rijndael.cpp" /> <ClCompile Include="rijndael.cpp" />
<ClCompile Include="rs.cpp" /> <ClCompile Include="rs.cpp" />
<ClCompile Include="rs16.cpp" /> <ClCompile Include="rs16.cpp" />
<ClCompile Include="scantree.cpp" /> <ClCompile Include="scantree.cpp" />
<ClCompile Include="secpassword.cpp" /> <ClCompile Include="secpassword.cpp" />
<ClCompile Include="sha1.cpp" /> <ClCompile Include="sha1.cpp" />
<ClCompile Include="sha256.cpp" /> <ClCompile Include="sha256.cpp" />
<ClCompile Include="smallfn.cpp" /> <ClCompile Include="smallfn.cpp" />
<ClCompile Include="strfn.cpp" /> <ClCompile Include="strfn.cpp" />
<ClCompile Include="strlist.cpp" /> <ClCompile Include="strlist.cpp" />
<ClCompile Include="system.cpp" /> <ClCompile Include="system.cpp" />
<ClCompile Include="threadpool.cpp" /> <ClCompile Include="threadpool.cpp" />
<ClCompile Include="timefn.cpp" /> <ClCompile Include="timefn.cpp" />
<ClCompile Include="ui.cpp" /> <ClCompile Include="ui.cpp" />
<ClCompile Include="unicode.cpp" /> <ClCompile Include="unicode.cpp" />
<ClCompile Include="unpack.cpp" /> <ClCompile Include="unpack.cpp" />
<ClCompile Include="volume.cpp" /> <ClCompile Include="volume.cpp" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>

@ -1,420 +1,420 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations"> <ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32"> <ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
<Platform>Win32</Platform> <Platform>Win32</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64"> <ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
<Platform>x64</Platform> <Platform>x64</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="release_nocrypt|Win32"> <ProjectConfiguration Include="release_nocrypt|Win32">
<Configuration>release_nocrypt</Configuration> <Configuration>release_nocrypt</Configuration>
<Platform>Win32</Platform> <Platform>Win32</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="release_nocrypt|x64"> <ProjectConfiguration Include="release_nocrypt|x64">
<Configuration>release_nocrypt</Configuration> <Configuration>release_nocrypt</Configuration>
<Platform>x64</Platform> <Platform>x64</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32"> <ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<Platform>Win32</Platform> <Platform>Win32</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Release|x64"> <ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<Platform>x64</Platform> <Platform>x64</Platform>
</ProjectConfiguration> </ProjectConfiguration>
</ItemGroup> </ItemGroup>
<PropertyGroup Label="Globals"> <PropertyGroup Label="Globals">
<ProjectName>UnRAR</ProjectName> <ProjectName>UnRAR</ProjectName>
<ProjectGuid>{E815C46C-36C4-499F-BBC2-E772C6B17971}</ProjectGuid> <ProjectGuid>{E815C46C-36C4-499F-BBC2-E772C6B17971}</ProjectGuid>
<RootNamespace>UnRAR</RootNamespace> <RootNamespace>UnRAR</RootNamespace>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset> <PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset> <PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset> <PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset> <PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>false</WholeProgramOptimization> <WholeProgramOptimization>false</WholeProgramOptimization>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset> <PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
<WholeProgramOptimization>false</WholeProgramOptimization> <WholeProgramOptimization>false</WholeProgramOptimization>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<PlatformToolset>v140_xp</PlatformToolset> <PlatformToolset>v140_xp</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet> <CharacterSet>MultiByte</CharacterSet>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'" Label="PropertySheets"> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets"> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets"> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'" Label="PropertySheets"> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<PropertyGroup> <PropertyGroup>
<_ProjectFileVersion>14.0.24720.0</_ProjectFileVersion> <_ProjectFileVersion>14.0.24720.0</_ProjectFileVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>build\unrardll32\$(Configuration)\</OutDir> <OutDir>build\unrardll32\$(Configuration)\</OutDir>
<IntDir>build\unrardll32\$(Configuration)\obj\</IntDir> <IntDir>build\unrardll32\$(Configuration)\obj\</IntDir>
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>
<GenerateManifest>true</GenerateManifest> <GenerateManifest>true</GenerateManifest>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>build\unrardll64\$(Configuration)\</OutDir> <OutDir>build\unrardll64\$(Configuration)\</OutDir>
<IntDir>build\unrardll64\$(Configuration)\obj\</IntDir> <IntDir>build\unrardll64\$(Configuration)\obj\</IntDir>
<LinkIncremental>true</LinkIncremental> <LinkIncremental>true</LinkIncremental>
<GenerateManifest>true</GenerateManifest> <GenerateManifest>true</GenerateManifest>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>build\unrardll32\$(Configuration)\</OutDir> <OutDir>build\unrardll32\$(Configuration)\</OutDir>
<IntDir>build\unrardll32\$(Configuration)\obj\</IntDir> <IntDir>build\unrardll32\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental> <LinkIncremental>false</LinkIncremental>
<GenerateManifest>true</GenerateManifest> <GenerateManifest>true</GenerateManifest>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>build\unrardll64\$(Configuration)\</OutDir> <OutDir>build\unrardll64\$(Configuration)\</OutDir>
<IntDir>build\unrardll64\$(Configuration)\obj\</IntDir> <IntDir>build\unrardll64\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental> <LinkIncremental>false</LinkIncremental>
<GenerateManifest>true</GenerateManifest> <GenerateManifest>true</GenerateManifest>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'">
<OutDir>build\unrardll32\$(Configuration)\</OutDir> <OutDir>build\unrardll32\$(Configuration)\</OutDir>
<IntDir>build\unrardll32\$(Configuration)\obj\</IntDir> <IntDir>build\unrardll32\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental> <LinkIncremental>false</LinkIncremental>
<GenerateManifest>true</GenerateManifest> <GenerateManifest>true</GenerateManifest>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'">
<OutDir>build\unrardll64\$(Configuration)\</OutDir> <OutDir>build\unrardll64\$(Configuration)\</OutDir>
<IntDir>build\unrardll64\$(Configuration)\obj\</IntDir> <IntDir>build\unrardll64\$(Configuration)\obj\</IntDir>
<LinkIncremental>false</LinkIncremental> <LinkIncremental>false</LinkIncremental>
<GenerateManifest>true</GenerateManifest> <GenerateManifest>true</GenerateManifest>
</PropertyGroup> </PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile> <ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling> <ExceptionHandling>Sync</ExceptionHandling>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment> <StructMemberAlignment>Default</StructMemberAlignment>
<RuntimeTypeInfo>false</RuntimeTypeInfo> <RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile> <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>Cdecl</CallingConvention> <CallingConvention>Cdecl</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile> </ClCompile>
<Link> <Link>
<OutputFile>$(OutDir)unrar.dll</OutputFile> <OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile> <ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<TargetMachine>MachineX86</TargetMachine> <TargetMachine>MachineX86</TargetMachine>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Midl> <Midl>
<TargetEnvironment>X64</TargetEnvironment> <TargetEnvironment>X64</TargetEnvironment>
</Midl> </Midl>
<ClCompile> <ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>Disabled</Optimization> <Optimization>Disabled</Optimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling> <ExceptionHandling>Sync</ExceptionHandling>
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment> <StructMemberAlignment>Default</StructMemberAlignment>
<RuntimeTypeInfo>false</RuntimeTypeInfo> <RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile> <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>Cdecl</CallingConvention> <CallingConvention>Cdecl</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
</ClCompile> </ClCompile>
<Link> <Link>
<OutputFile>$(OutDir)unrar.dll</OutputFile> <OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile> <ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<TargetMachine>MachineX64</TargetMachine> <TargetMachine>MachineX64</TargetMachine>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile> <ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed> <FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers> <OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization> <WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling> <ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment> <StructMemberAlignment>Default</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck> <BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<FloatingPointModel>Precise</FloatingPointModel> <FloatingPointModel>Precise</FloatingPointModel>
<RuntimeTypeInfo>false</RuntimeTypeInfo> <RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile> <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>Cdecl</CallingConvention> <CallingConvention>Cdecl</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalOptions>/SAFESEH %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/SAFESEH %(AdditionalOptions)</AdditionalOptions>
<OutputFile>$(OutDir)unrar.dll</OutputFile> <OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile> <ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration /> <LinkTimeCodeGeneration />
<TargetMachine>MachineX86</TargetMachine> <TargetMachine>MachineX86</TargetMachine>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Midl> <Midl>
<TargetEnvironment>X64</TargetEnvironment> <TargetEnvironment>X64</TargetEnvironment>
</Midl> </Midl>
<ClCompile> <ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed> <FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers> <OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization> <WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>RARDLL;UNRAR;SILENT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>false</StringPooling> <StringPooling>false</StringPooling>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling> <ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment> <StructMemberAlignment>Default</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck> <BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo> <RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile> <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>Cdecl</CallingConvention> <CallingConvention>Cdecl</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
</ClCompile> </ClCompile>
<Link> <Link>
<OutputFile>$(OutDir)unrar.dll</OutputFile> <OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll.def</ModuleDefinitionFile> <ModuleDefinitionFile>dll.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration /> <LinkTimeCodeGeneration />
<TargetMachine>MachineX64</TargetMachine> <TargetMachine>MachineX64</TargetMachine>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'">
<ClCompile> <ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed> <FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers> <OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization> <WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;RAR_NOCRYPT;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>RARDLL;UNRAR;SILENT;RAR_NOCRYPT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling> <ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment> <StructMemberAlignment>Default</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck> <BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
<FloatingPointModel>Precise</FloatingPointModel> <FloatingPointModel>Precise</FloatingPointModel>
<RuntimeTypeInfo>false</RuntimeTypeInfo> <RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile> <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>Cdecl</CallingConvention> <CallingConvention>Cdecl</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalOptions>/SAFESEH %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/SAFESEH %(AdditionalOptions)</AdditionalOptions>
<OutputFile>$(OutDir)unrar.dll</OutputFile> <OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll_nocrypt.def</ModuleDefinitionFile> <ModuleDefinitionFile>dll_nocrypt.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration /> <LinkTimeCodeGeneration />
<TargetMachine>MachineX86</TargetMachine> <TargetMachine>MachineX86</TargetMachine>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'">
<Midl> <Midl>
<TargetEnvironment>X64</TargetEnvironment> <TargetEnvironment>X64</TargetEnvironment>
</Midl> </Midl>
<ClCompile> <ClCompile>
<AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/MP %(AdditionalOptions)</AdditionalOptions>
<Optimization>MaxSpeed</Optimization> <Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions> <IntrinsicFunctions>true</IntrinsicFunctions>
<FavorSizeOrSpeed>Neither</FavorSizeOrSpeed> <FavorSizeOrSpeed>Neither</FavorSizeOrSpeed>
<OmitFramePointers>true</OmitFramePointers> <OmitFramePointers>true</OmitFramePointers>
<WholeProgramOptimization>false</WholeProgramOptimization> <WholeProgramOptimization>false</WholeProgramOptimization>
<PreprocessorDefinitions>RARDLL;UNRAR;SILENT;RAR_NOCRYPT;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>RARDLL;UNRAR;SILENT;RAR_NOCRYPT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<StringPooling>false</StringPooling> <StringPooling>false</StringPooling>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
<ExceptionHandling>Sync</ExceptionHandling> <ExceptionHandling>Sync</ExceptionHandling>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary> <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<StructMemberAlignment>4Bytes</StructMemberAlignment> <StructMemberAlignment>Default</StructMemberAlignment>
<BufferSecurityCheck>true</BufferSecurityCheck> <BufferSecurityCheck>true</BufferSecurityCheck>
<FunctionLevelLinking>true</FunctionLevelLinking> <FunctionLevelLinking>true</FunctionLevelLinking>
<RuntimeTypeInfo>false</RuntimeTypeInfo> <RuntimeTypeInfo>false</RuntimeTypeInfo>
<PrecompiledHeader>Use</PrecompiledHeader> <PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile> <PrecompiledHeaderFile>rar.hpp</PrecompiledHeaderFile>
<WarningLevel>Level3</WarningLevel> <WarningLevel>Level3</WarningLevel>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<CallingConvention>StdCall</CallingConvention> <CallingConvention>StdCall</CallingConvention>
<DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings> <DisableSpecificWarnings>4007;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
<EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet> <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
</ClCompile> </ClCompile>
<Link> <Link>
<OutputFile>$(OutDir)unrar.dll</OutputFile> <OutputFile>$(OutDir)unrar.dll</OutputFile>
<ModuleDefinitionFile>dll_nocrypt.def</ModuleDefinitionFile> <ModuleDefinitionFile>dll_nocrypt.def</ModuleDefinitionFile>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem> <SubSystem>Console</SubSystem>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<LinkTimeCodeGeneration /> <LinkTimeCodeGeneration />
<TargetMachine>MachineX64</TargetMachine> <TargetMachine>MachineX64</TargetMachine>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="archive.cpp" /> <ClCompile Include="archive.cpp" />
<ClCompile Include="arcread.cpp" /> <ClCompile Include="arcread.cpp" />
<ClCompile Include="blake2s.cpp" /> <ClCompile Include="blake2s.cpp" />
<ClCompile Include="cmddata.cpp" /> <ClCompile Include="cmddata.cpp" />
<ClCompile Include="consio.cpp" /> <ClCompile Include="consio.cpp" />
<ClCompile Include="crc.cpp" /> <ClCompile Include="crc.cpp" />
<ClCompile Include="crypt.cpp" /> <ClCompile Include="crypt.cpp" />
<ClCompile Include="dll.cpp" /> <ClCompile Include="dll.cpp" />
<ClCompile Include="encname.cpp" /> <ClCompile Include="encname.cpp" />
<ClCompile Include="errhnd.cpp" /> <ClCompile Include="errhnd.cpp" />
<ClCompile Include="extinfo.cpp" /> <ClCompile Include="extinfo.cpp" />
<ClCompile Include="extract.cpp" /> <ClCompile Include="extract.cpp" />
<ClCompile Include="filcreat.cpp" /> <ClCompile Include="filcreat.cpp" />
<ClCompile Include="file.cpp" /> <ClCompile Include="file.cpp" />
<ClCompile Include="filefn.cpp" /> <ClCompile Include="filefn.cpp" />
<ClCompile Include="filestr.cpp" /> <ClCompile Include="filestr.cpp" />
<ClCompile Include="find.cpp" /> <ClCompile Include="find.cpp" />
<ClCompile Include="getbits.cpp" /> <ClCompile Include="getbits.cpp" />
<ClCompile Include="global.cpp"> <ClCompile Include="global.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
</PrecompiledHeader> </PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
</PrecompiledHeader> </PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
</PrecompiledHeader> </PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
</PrecompiledHeader> </PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'">
</PrecompiledHeader> </PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'">
</PrecompiledHeader> </PrecompiledHeader>
</ClCompile> </ClCompile>
<ClCompile Include="hash.cpp" /> <ClCompile Include="hash.cpp" />
<ClCompile Include="headers.cpp" /> <ClCompile Include="headers.cpp" />
<ClCompile Include="isnt.cpp" /> <ClCompile Include="isnt.cpp" />
<ClCompile Include="match.cpp" /> <ClCompile Include="match.cpp" />
<ClCompile Include="options.cpp" /> <ClCompile Include="options.cpp" />
<ClCompile Include="pathfn.cpp" /> <ClCompile Include="pathfn.cpp" />
<ClCompile Include="qopen.cpp" /> <ClCompile Include="qopen.cpp" />
<ClCompile Include="rar.cpp" /> <ClCompile Include="rar.cpp" />
<ClCompile Include="rarpch.cpp"> <ClCompile Include="rarpch.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='release_nocrypt|x64'">Create</PrecompiledHeader>
</ClCompile> </ClCompile>
<ClCompile Include="rarvm.cpp" /> <ClCompile Include="rarvm.cpp" />
<ClCompile Include="rawread.cpp" /> <ClCompile Include="rawread.cpp" />
<ClCompile Include="rdwrfn.cpp" /> <ClCompile Include="rdwrfn.cpp" />
<ClCompile Include="rijndael.cpp" /> <ClCompile Include="rijndael.cpp" />
<ClCompile Include="rs.cpp" /> <ClCompile Include="rs.cpp" />
<ClCompile Include="rs16.cpp" /> <ClCompile Include="rs16.cpp" />
<ClCompile Include="scantree.cpp" /> <ClCompile Include="scantree.cpp" />
<ClCompile Include="secpassword.cpp" /> <ClCompile Include="secpassword.cpp" />
<ClCompile Include="sha1.cpp" /> <ClCompile Include="sha1.cpp" />
<ClCompile Include="sha256.cpp" /> <ClCompile Include="sha256.cpp" />
<ClCompile Include="smallfn.cpp" /> <ClCompile Include="smallfn.cpp" />
<ClCompile Include="strfn.cpp" /> <ClCompile Include="strfn.cpp" />
<ClCompile Include="strlist.cpp" /> <ClCompile Include="strlist.cpp" />
<ClCompile Include="system.cpp" /> <ClCompile Include="system.cpp" />
<ClCompile Include="threadpool.cpp" /> <ClCompile Include="threadpool.cpp" />
<ClCompile Include="timefn.cpp" /> <ClCompile Include="timefn.cpp" />
<ClCompile Include="ui.cpp" /> <ClCompile Include="ui.cpp" />
<ClCompile Include="unicode.cpp" /> <ClCompile Include="unicode.cpp" />
<ClCompile Include="unpack.cpp" /> <ClCompile Include="unpack.cpp" />
<ClCompile Include="volume.cpp" /> <ClCompile Include="volume.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="rar.hpp" /> <ClInclude Include="rar.hpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="dll.rc" /> <ResourceCompile Include="dll.rc" />
</ItemGroup> </ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>

@ -1,92 +1,59 @@
ACKNOWLEDGMENTS ACKNOWLEDGMENTS
* We used "Screaming Fast Galois Field Arithmetic Using Intel * We used "Screaming Fast Galois Field Arithmetic Using Intel
SIMD Instructions" paper by James S. Plank, Kevin M. Greenan SIMD Instructions" paper by James S. Plank, Kevin M. Greenan
and Ethan L. Miller to improve Reed-Solomon coding performance. and Ethan L. Miller to improve Reed-Solomon coding performance.
Also we are grateful to Artem Drobanov and Bulat Ziganshin Also we are grateful to Artem Drobanov and Bulat Ziganshin
for samples and ideas allowed to make Reed-Solomon coding for samples and ideas allowed to make Reed-Solomon coding
more efficient. more efficient.
* RAR text compression algorithm is based on Dmitry Shkarin PPMII * RAR4 text compression algorithm is based on Dmitry Shkarin PPMII
and Dmitry Subbotin carryless rangecoder public domain source code. and Dmitry Subbotin carryless rangecoder public domain source code.
You may find it in ftp.elf.stuba.sk/pub/pc/pack. You can find it in ftp.elf.stuba.sk/pub/pc/pack.
* RAR encryption includes parts of code from Szymon Stefanek * RAR encryption includes parts of public domain code
and Brian Gladman AES implementations also as Steve Reid SHA-1 source. from Szymon Stefanek AES and Steve Reid SHA-1 implementations.
--------------------------------------------------------------------------- * With exception of SFX modules, RAR uses CRC32 function based
Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. on Intel Slicing-by-8 algorithm. Original Intel Slicing-by-8 code
All rights reserved. is available here:
LICENSE TERMS https://sourceforge.net/projects/slicing-by-8/
The free distribution and use of this software in both source and binary Original Intel Slicing-by-8 code is licensed under BSD License
form is allowed (with or without changes) provided that: available at http://www.opensource.org/licenses/bsd-license.html
1. distributions of this source code include the above copyright Copyright (c) 2004-2006 Intel Corporation.
notice, this list of conditions and the following disclaimer; All Rights Reserved
2. distributions in binary form include the above copyright Redistribution and use in source and binary forms, with or without
notice, this list of conditions and the following disclaimer modification, are permitted provided that the following conditions
in the documentation and/or other associated materials; are met:
3. the copyright holder's name is not used to endorse products Redistributions of source code must retain the above copyright notice,
built using this software without specific written permission. this list of conditions and the following disclaimer.
ALTERNATIVELY, provided that this notice is retained in full, this product Redistributions in binary form must reproduce the above copyright
may be distributed under the terms of the GNU General Public License (GPL), notice, this list of conditions and the following disclaimer
in which case the provisions of the GPL apply INSTEAD OF those given above. in the documentation and/or other materials provided with
the distribution.
DISCLAIMER
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
This software is provided 'as is' with no explicit or implied warranties "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
in respect of its properties, including, but not limited to, correctness LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
and/or fitness for purpose. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
--------------------------------------------------------------------------- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Source code of this package also as other cryptographic technology LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
and computing project related links are available on Brian Gladman's DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
web site: http://www.gladman.me.uk ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* RAR uses CRC32 function based on Intel Slicing-by-8 algorithm. OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
Original Intel Slicing-by-8 code is available here: SUCH DAMAGE.
https://sourceforge.net/projects/slicing-by-8/ * RAR archives may optionally include BLAKE2sp hash ( https://blake2.net ),
designed by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn
Original Intel Slicing-by-8 code is licensed under BSD License and Christian Winnerlein.
available at http://www.opensource.org/licenses/bsd-license.html
* Useful hints provided by Alexander Khoroshev and Bulat Ziganshin allowed
Copyright (c) 2004-2006 Intel Corporation. to significantly improve RAR compression and speed.
All Rights Reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with
the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
* RAR archives may optionally include BLAKE2sp hash ( https://blake2.net ),
designed by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn
and Christian Winnerlein.
* Useful hints provided by Alexander Khoroshev and Bulat Ziganshin allowed
to significantly improve RAR compression and speed.

@ -3,15 +3,15 @@
#include "arccmt.cpp" #include "arccmt.cpp"
Archive::Archive(RAROptions *InitCmd) Archive::Archive(CommandData *InitCmd)
{ {
Cmd=NULL; // Just in case we'll have an exception in 'new' below. Cmd=NULL; // Just in case we'll have an exception in 'new' below.
DummyCmd=(InitCmd==NULL); DummyCmd=(InitCmd==NULL);
Cmd=DummyCmd ? (new RAROptions):InitCmd; Cmd=DummyCmd ? (new CommandData):InitCmd;
OpenShared=Cmd->OpenShared; OpenShared=Cmd->OpenShared;
Format=RARFMT15; Format=RARFMT_NONE;
Solid=false; Solid=false;
Volume=false; Volume=false;
MainComment=false; MainComment=false;
@ -31,9 +31,9 @@ Archive::Archive(RAROptions *InitCmd)
NextBlockPos=0; NextBlockPos=0;
memset(&MainHead,0,sizeof(MainHead)); MainHead.Reset();
memset(&CryptHead,0,sizeof(CryptHead)); CryptHead={};
memset(&EndArcHead,0,sizeof(EndArcHead)); EndArcHead.Reset();
VolNumber=0; VolNumber=0;
VolWrite=0; VolWrite=0;
@ -231,7 +231,7 @@ bool Archive::IsArchive(bool EnableBroken)
// first file header to set "comment" flag when reading service header. // 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 // Unless we are in silent mode, we need to know about presence of comment
// immediately after IsArchive call. // immediately after IsArchive call.
if (HeadersLeft && (!SilentOpen || !Encrypted)) if (HeadersLeft && (!SilentOpen || !Encrypted) && IsSeekable())
{ {
int64 SavePos=Tell(); int64 SavePos=Tell();
int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos; int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos;

@ -32,8 +32,8 @@ class Archive:public File
size_t ReadHeader14(); size_t ReadHeader14();
size_t ReadHeader15(); size_t ReadHeader15();
size_t ReadHeader50(); size_t ReadHeader50();
void ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb); void ProcessExtra50(RawRead *Raw,size_t ExtraSize,const BaseBlock *bb);
void RequestArcPassword(); void RequestArcPassword(RarCheckPassword *SelPwd);
void UnexpEndArcMsg(); void UnexpEndArcMsg();
void BrokenHeaderMsg(); void BrokenHeaderMsg();
void UnkEncVerMsg(const wchar *Name,const wchar *Info); void UnkEncVerMsg(const wchar *Name,const wchar *Info);
@ -45,7 +45,7 @@ class Archive:public File
#endif #endif
ComprDataIO SubDataIO; ComprDataIO SubDataIO;
bool DummyCmd; bool DummyCmd;
RAROptions *Cmd; CommandData *Cmd;
RarTime LatestTime; RarTime LatestTime;
@ -58,7 +58,7 @@ class Archive:public File
bool ProhibitQOpen; bool ProhibitQOpen;
#endif #endif
public: public:
Archive(RAROptions *InitCmd=NULL); Archive(CommandData *InitCmd=NULL);
~Archive(); ~Archive();
static RARFORMAT IsSignature(const byte *D,size_t Size); static RARFORMAT IsSignature(const byte *D,size_t Size);
bool IsArchive(bool EnableBroken); bool IsArchive(bool EnableBroken);
@ -83,7 +83,7 @@ class Archive:public File
const wchar *Name,uint Flags); const wchar *Name,uint Flags);
bool ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode); bool ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode);
HEADER_TYPE GetHeaderType() {return CurHeaderType;} HEADER_TYPE GetHeaderType() {return CurHeaderType;}
RAROptions* GetRAROptions() {return Cmd;} CommandData* GetCommandData() {return Cmd;}
void SetSilentOpen(bool Mode) {SilentOpen=Mode;} void SetSilentOpen(bool Mode) {SilentOpen=Mode;}
#if 0 #if 0
void GetRecoveryInfo(bool Required,int64 *Size,int *Percent); void GetRecoveryInfo(bool Required,int64 *Size,int *Percent);

@ -100,6 +100,9 @@ void Archive::UnexpEndArcMsg()
// If block positions are equal to file size, this is not an error. // If block positions are equal to file size, this is not an error.
// It can happen when we reached the end of older RAR 1.5 archive, // It can happen when we reached the end of older RAR 1.5 archive,
// which did not have the end of archive block. // which did not have the end of archive block.
// We can't replace this check by checking that read size is exactly 0
// in the beginning of file header, because in this case the read position
// still can be beyond the end of archive.
if (CurBlockPos!=ArcSize || NextBlockPos!=ArcSize) if (CurBlockPos!=ArcSize || NextBlockPos!=ArcSize)
{ {
uiMsg(UIERROR_UNEXPEOF,FileName); uiMsg(UIERROR_UNEXPEOF,FileName);
@ -145,7 +148,7 @@ size_t Archive::ReadHeader15()
#ifdef RAR_NOCRYPT // For rarext.dll and unrar_nocrypt.dll. #ifdef RAR_NOCRYPT // For rarext.dll and unrar_nocrypt.dll.
return 0; return 0;
#else #else
RequestArcPassword(); RequestArcPassword(NULL);
byte Salt[SIZE_SALT30]; byte Salt[SIZE_SALT30];
if (Read(Salt,SIZE_SALT30)!=SIZE_SALT30) if (Read(Salt,SIZE_SALT30)!=SIZE_SALT30)
@ -251,7 +254,11 @@ size_t Archive::ReadHeader15()
hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0; hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0;
hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0; hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0;
hd->SaltSet=(hd->Flags & LHD_SALT)!=0; hd->SaltSet=(hd->Flags & LHD_SALT)!=0;
// RAR versions earlier than 2.0 do not set the solid flag
// in file header. They use only a global solid archive flag.
hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0; hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0;
hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0; hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0;
hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY; hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY;
hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5); hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5);
@ -558,6 +565,13 @@ size_t Archive::ReadHeader50()
return 0; return 0;
#else #else
if (Cmd->SkipEncrypted)
{
uiMsg(UIMSG_SKIPENCARC,FileName);
FailedHeaderDecryption=true; // Suppress error messages and quit quietly.
return 0;
}
byte HeadersInitV[SIZE_INITV]; byte HeadersInitV[SIZE_INITV];
if (Read(HeadersInitV,SIZE_INITV)!=SIZE_INITV) if (Read(HeadersInitV,SIZE_INITV)!=SIZE_INITV)
{ {
@ -570,14 +584,20 @@ size_t Archive::ReadHeader50()
// in -p<pwd> to not stop batch processing for encrypted archives. // in -p<pwd> to not stop batch processing for encrypted archives.
bool GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet(); bool GlobalPassword=Cmd->Password.IsSet() || uiIsGlobalPasswordSet();
RarCheckPassword CheckPwd;
if (CryptHead.UsePswCheck && !BrokenHeader)
CheckPwd.Set(CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,CryptHead.PswCheck);
while (true) // Repeat the password prompt for wrong passwords. while (true) // Repeat the password prompt for wrong passwords.
{ {
RequestArcPassword(); RequestArcPassword(CheckPwd.IsSet() ? &CheckPwd:NULL);
byte PswCheck[SIZE_PSWCHECK]; byte PswCheck[SIZE_PSWCHECK];
HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck); HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck);
// Verify password validity. // Verify password validity. If header is damaged, we cannot rely on
if (CryptHead.UsePswCheck && memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0) // password check value, because it can be damaged too.
if (CryptHead.UsePswCheck && !BrokenHeader &&
memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0)
{ {
if (GlobalPassword) // For -p<pwd> or Ctrl+P. if (GlobalPassword) // For -p<pwd> or Ctrl+P.
{ {
@ -843,8 +863,6 @@ size_t Archive::ReadHeader50()
hd->Dir=(hd->FileFlags & FHFL_DIRECTORY)!=0; hd->Dir=(hd->FileFlags & FHFL_DIRECTORY)!=0;
hd->WinSize=hd->Dir ? 0:size_t(0x20000)<<((CompInfo>>10)&0xf); hd->WinSize=hd->Dir ? 0:size_t(0x20000)<<((CompInfo>>10)&0xf);
hd->CryptMethod=hd->Encrypted ? CRYPT_RAR50:CRYPT_NONE;
char FileName[NM*4]; char FileName[NM*4];
size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1); size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1);
Raw.GetB((byte *)FileName,ReadNameSize); Raw.GetB((byte *)FileName,ReadNameSize);
@ -868,20 +886,6 @@ size_t Archive::ReadHeader50()
if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_CMT)) if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_CMT))
MainComment=true; MainComment=true;
#if 0
// For RAR5 format we read the user specified recovery percent here.
// It would be useful to do it for shell extension too, so we display
// the correct recovery record size in archive properties. But then
// we would need to include the entire recovery record processing
// code to shell extension, which is not done now.
if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_RR) && hd->SubData.Size()>0)
{
RecoveryPercent=hd->SubData[0];
RSBlockHeader Header;
GetRRInfo(this,&Header);
RecoverySize=Header.RecSectionSize*Header.RecCount;
}
#endif
if (BadCRC) // Add the file name to broken header message displayed above. if (BadCRC) // Add the file name to broken header message displayed above.
uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName); uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName);
@ -904,7 +908,7 @@ size_t Archive::ReadHeader50()
#if !defined(RAR_NOCRYPT) #if !defined(RAR_NOCRYPT)
void Archive::RequestArcPassword() void Archive::RequestArcPassword(RarCheckPassword *CheckPwd)
{ {
if (!Cmd->Password.IsSet()) if (!Cmd->Password.IsSet())
{ {
@ -934,7 +938,7 @@ void Archive::RequestArcPassword()
ErrHandler.Exit(RARX_USERBREAK); ErrHandler.Exit(RARX_USERBREAK);
} }
#else #else
if (!uiGetPassword(UIPASSWORD_ARCHIVE,FileName,&Cmd->Password)) if (!uiGetPassword(UIPASSWORD_ARCHIVE,FileName,&Cmd->Password,CheckPwd))
{ {
Close(); Close();
uiMsg(UIERROR_INCERRCOUNT); // Prevent archive deleting if delete after extraction is on. uiMsg(UIERROR_INCERRCOUNT); // Prevent archive deleting if delete after extraction is on.
@ -947,7 +951,7 @@ void Archive::RequestArcPassword()
#endif #endif
void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb) void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,const BaseBlock *bb)
{ {
// Read extra data from the end of block skipping any fields before it. // Read extra data from the end of block skipping any fields before it.
size_t ExtraStart=Raw->Size()-ExtraSize; size_t ExtraStart=Raw->Size()-ExtraSize;
@ -970,22 +974,57 @@ void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb)
if (bb->HeaderType==HEAD_MAIN) if (bb->HeaderType==HEAD_MAIN)
{ {
MainHeader *hd=(MainHeader *)bb; MainHeader *hd=(MainHeader *)bb;
if (FieldType==MHEXTRA_LOCATOR) switch(FieldType)
{ {
hd->Locator=true; case MHEXTRA_LOCATOR:
uint Flags=(uint)Raw->GetV(); {
if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0) hd->Locator=true;
{ uint Flags=(uint)Raw->GetV();
uint64 Offset=Raw->GetV(); if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0)
if (Offset!=0) // 0 means that reserved space was not enough to write the offset. {
hd->QOpenOffset=Offset+CurBlockPos; uint64 Offset=Raw->GetV();
} if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
if ((Flags & MHEXTRA_LOCATOR_RR)!=0) hd->QOpenOffset=Offset+CurBlockPos;
{ }
uint64 Offset=Raw->GetV(); if ((Flags & MHEXTRA_LOCATOR_RR)!=0)
if (Offset!=0) // 0 means that reserved space was not enough to write the offset. {
hd->RROffset=Offset+CurBlockPos; uint64 Offset=Raw->GetV();
} if (Offset!=0) // 0 means that reserved space was not enough to write the offset.
hd->RROffset=Offset+CurBlockPos;
}
}
break;
case MHEXTRA_METADATA:
{
uint Flags=(uint)Raw->GetV();
if ((Flags & MHEXTRA_METADATA_NAME)!=0)
{
uint64 NameSize=Raw->GetV();
if (NameSize<0x10000) // Prevent excessive allocation.
{
std::vector<char> NameU((size_t)NameSize); // UTF-8 name.
Raw->GetB(&NameU[0],(size_t)NameSize);
// If starts from 0, the name was longer than reserved space
// when saving this extra field.
if (NameU[0]!=0)
{
NameU.push_back(0);
std::vector<wchar> NameW(NameU.size()*4);
UtfToWide(&NameU[0],&NameW[0],NameW.size());
hd->OrigName.assign(&NameW[0]);
}
}
}
if ((Flags & MHEXTRA_METADATA_CTIME)!=0)
if ((Flags & MHEXTRA_METADATA_UNIXTIME)!=0)
if ((Flags & MHEXTRA_METADATA_UNIX_NS)!=0)
hd->OrigTime.SetUnixNS(Raw->Get8());
else
hd->OrigTime.SetUnix((time_t)Raw->Get4());
else
hd->OrigTime.SetWin(Raw->Get8());
}
break;
} }
} }
@ -1441,7 +1480,9 @@ bool Archive::ReadSubData(Array<byte> *UnpData,File *DestFile,bool TestMode)
{ {
if (SubHead.UnpSize>0x1000000) if (SubHead.UnpSize>0x1000000)
{ {
// So huge allocation must never happen in valid archives. // Prevent the excessive allocation. When reading to memory, normally
// this function operates with reasonably small blocks, such as
// the archive comment, NTFS ACL or "Zone.Identifier" NTFS stream.
uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName); uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName);
return false; return false;
} }

@ -10,7 +10,6 @@ template <class T> class Array
size_t BufSize; size_t BufSize;
size_t AllocSize; size_t AllocSize;
size_t MaxSize; size_t MaxSize;
bool Secure; // Clean memory if true.
public: public:
Array(); Array();
Array(size_t Size); Array(size_t Size);
@ -24,14 +23,13 @@ template <class T> class Array
void Alloc(size_t Items); void Alloc(size_t Items);
void Reset(); void Reset();
void SoftReset(); void SoftReset();
void operator = (Array<T> &Src); Array<T>& operator = (const Array<T> &Src);
void Push(T Item); void Push(T Item);
void Append(T *Item,size_t Count); void Append(T *Item,size_t Count);
T* Addr(size_t Item) {return Buffer+Item;} T* Addr(size_t Item) {return Buffer+Item;}
void SetMaxSize(size_t Size) {MaxSize=Size;} void SetMaxSize(size_t Size) {MaxSize=Size;}
T* Begin() {return Buffer;} T* Begin() {return Buffer;}
T* End() {return Buffer==NULL ? NULL:Buffer+BufSize;} T* End() {return Buffer==NULL ? NULL:Buffer+BufSize;}
void SetSecure() {Secure=true;}
}; };
@ -41,7 +39,6 @@ template <class T> void Array<T>::CleanData()
BufSize=0; BufSize=0;
AllocSize=0; AllocSize=0;
MaxSize=0; MaxSize=0;
Secure=false;
} }
@ -71,11 +68,7 @@ template <class T> Array<T>::Array(const Array &Src)
template <class T> Array<T>::~Array() template <class T> Array<T>::~Array()
{ {
if (Buffer!=NULL) if (Buffer!=NULL)
{
if (Secure)
cleandata(Buffer,AllocSize*sizeof(T));
free(Buffer); free(Buffer);
}
} }
@ -111,25 +104,9 @@ template <class T> void Array<T>::Add(size_t Items)
size_t Suggested=AllocSize+AllocSize/4+32; size_t Suggested=AllocSize+AllocSize/4+32;
size_t NewSize=Max(BufSize,Suggested); size_t NewSize=Max(BufSize,Suggested);
T *NewBuffer; T *NewBuffer=(T *)realloc(Buffer,NewSize*sizeof(T));
if (Secure) if (NewBuffer==NULL)
{ ErrHandler.MemoryError();
NewBuffer=(T *)malloc(NewSize*sizeof(T));
if (NewBuffer==NULL)
ErrHandler.MemoryError();
if (Buffer!=NULL)
{
memcpy(NewBuffer,Buffer,AllocSize*sizeof(T));
cleandata(Buffer,AllocSize*sizeof(T));
free(Buffer);
}
}
else
{
NewBuffer=(T *)realloc(Buffer,NewSize*sizeof(T));
if (NewBuffer==NULL)
ErrHandler.MemoryError();
}
Buffer=NewBuffer; Buffer=NewBuffer;
AllocSize=NewSize; AllocSize=NewSize;
} }
@ -165,12 +142,13 @@ template <class T> void Array<T>::SoftReset()
} }
template <class T> void Array<T>::operator =(Array<T> &Src) template <class T> Array<T>& Array<T>::operator =(const Array<T> &Src)
{ {
Reset(); Reset();
Alloc(Src.BufSize); Alloc(Src.BufSize);
if (Src.BufSize!=0) if (Src.BufSize!=0)
memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T)); memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T));
return *this;
} }

@ -20,10 +20,15 @@ enum blake2s_constant
// 'new' operator. // 'new' operator.
struct blake2s_state struct blake2s_state
{ {
enum { BLAKE_ALIGNMENT = 64 }; // Use constexpr instead of enums, because otherwise clang -std=c++20
// issues a warning about "arithmetic between different enumeration types"
// in ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT] declaration.
static constexpr size_t BLAKE_ALIGNMENT = 64;
// buffer and uint32 h[8], t[2], f[2]; // buffer and uint32 h[8], t[2], f[2];
enum { BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES }; // 2 * BLAKE2S_BLOCKBYTES is the buf size in blake2_code_20140114.zip.
// It might differ in later versions.
static constexpr size_t BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES;
byte ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT]; byte ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT];

@ -26,9 +26,10 @@ void CommandData::Init()
FileArgs.Reset(); FileArgs.Reset();
ExclArgs.Reset(); ExclArgs.Reset();
InclArgs.Reset(); InclArgs.Reset();
StoreArgs.Reset();
ArcNames.Reset(); ArcNames.Reset();
NextVolSizes.Reset(); StoreArgs.Reset();
Password.Clean();
NextVolSizes.clear();
} }
@ -108,6 +109,11 @@ void CommandData::ParseArg(wchar *Arg)
// 'S' can contain SFX name, which case is important in Unix. // 'S' can contain SFX name, which case is important in Unix.
if (*Command!='I' && *Command!='S') if (*Command!='I' && *Command!='S')
wcsupper(Command); wcsupper(Command);
if (*Command=='P') // Enforce -idq for print command.
{
MsgStream=MSG_ERRONLY;
SetConsoleMsgStream(MSG_ERRONLY);
}
} }
else else
if (*ArcName==0) if (*ArcName==0)
@ -309,6 +315,21 @@ void CommandData::ProcessSwitch(const wchar *Switch)
case 'I': case 'I':
IgnoreGeneralAttr=true; IgnoreGeneralAttr=true;
break; break;
case 'M':
switch(toupperw(Switch[2]))
{
case 0:
case 'S':
ArcMetadata=ARCMETA_SAVE;
break;
case 'R':
ArcMetadata=ARCMETA_RESTORE;
break;
default:
BadSwitch(Switch);
break;
}
break;
case 'N': // Reserved for archive name. case 'N': // Reserved for archive name.
break; break;
case 'O': case 'O':
@ -373,6 +394,9 @@ void CommandData::ProcessSwitch(const wchar *Switch)
case '3': case '3':
ExclPath=EXCL_ABSPATH; ExclPath=EXCL_ABSPATH;
break; break;
case '4':
wcsncpyz(ExclArcPath,Switch+3,ASIZE(ExclArcPath));
break;
} }
break; break;
default: default:
@ -399,13 +423,15 @@ void CommandData::ProcessSwitch(const wchar *Switch)
EncryptHeaders=true; EncryptHeaders=true;
if (Switch[2]!=0) if (Switch[2]!=0)
{ {
if (wcslen(Switch+2)>=MAXPASSWORD)
uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
Password.Set(Switch+2); Password.Set(Switch+2);
cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0])); cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0]));
} }
else else
if (!Password.IsSet()) if (!Password.IsSet())
{ {
uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password); uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password,NULL);
eprintf(L"\n"); eprintf(L"\n");
} }
break; break;
@ -561,6 +587,10 @@ void CommandData::ProcessSwitch(const wchar *Switch)
break; break;
case 'D': case 'D':
break; break;
case 'E':
if (toupperw(Switch[2])=='S' && Switch[3]==0)
SkipEncrypted=true;
break;
case 'S': case 'S':
{ {
wchar StoreNames[1024]; wchar StoreNames[1024];
@ -648,6 +678,10 @@ void CommandData::ProcessSwitch(const wchar *Switch)
AllowIncompatNames=true; AllowIncompatNames=true;
break; break;
#endif #endif
case 'P':
wcsncpyz(ExtrPath,Switch+2,ASIZE(ExtrPath));
AddEndSlash(ExtrPath,ASIZE(ExtrPath));
break;
case 'R': case 'R':
Overwrite=OVERWRITE_AUTORENAME; Overwrite=OVERWRITE_AUTORENAME;
break; break;
@ -667,11 +701,13 @@ void CommandData::ProcessSwitch(const wchar *Switch)
case 'P': case 'P':
if (Switch[1]==0) if (Switch[1]==0)
{ {
uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password); uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password,NULL);
eprintf(L"\n"); eprintf(L"\n");
} }
else else
{ {
if (wcslen(Switch+1)>=MAXPASSWORD)
uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
Password.Set(Switch+1); Password.Set(Switch+1);
cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0])); cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0]));
} }
@ -752,6 +788,10 @@ void CommandData::ProcessSwitch(const wchar *Switch)
case 'D': case 'D':
Solid|=SOLID_VOLUME_DEPENDENT; Solid|=SOLID_VOLUME_DEPENDENT;
break; break;
case 'I':
ProhibitConsoleInput();
wcsncpyz(UseStdin,Switch[2] ? Switch+2:L"stdin",ASIZE(UseStdin));
break;
case 'L': case 'L':
if (IsDigit(Switch[2])) if (IsDigit(Switch[2]))
FileSizeLess=atoilw(Switch+2); FileSizeLess=atoilw(Switch+2);
@ -935,7 +975,7 @@ void CommandData::ProcessCommand()
wcsncpyz(ArcName,Name,ASIZE(ArcName)); wcsncpyz(ArcName,Name,ASIZE(ArcName));
} }
if (wcschr(L"AFUMD",*Command)==NULL) if (wcschr(L"AFUMD",*Command)==NULL && *UseStdin==0)
{ {
if (GenerateArcName) if (GenerateArcName)
{ {

@ -2,7 +2,7 @@
#define _RAR_CMDDATA_ #define _RAR_CMDDATA_
#define DefaultStoreList L"7z;ace;arj;bz2;cab;gz;jpeg;jpg;lha;lz;lzh;mp3;rar;taz;tgz;xz;z;zip;zipx" #define DefaultStoreList L"7z;ace;arj;bz2;cab;gz;jpeg;jpg;lha;lz;lzh;mp3;rar;taz;tbz;tbz2;tgz;txz;xz;z;zip;zipx;zst;tzst"
enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS}; enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS};
@ -50,7 +50,7 @@ class CommandData:public RAROptions
bool GetArcName(wchar *Name,int MaxSize); bool GetArcName(wchar *Name,int MaxSize);
bool CheckWinSize(); bool CheckWinSize();
int GetRecoverySize(const wchar *Str,int DefSize); int GetRecoverySize(const wchar *CmdStr,const wchar *Value,int DefSize);
#ifndef SFX_MODULE #ifndef SFX_MODULE
void ReportWrongSwitches(RARFORMAT Format); void ReportWrongSwitches(RARFORMAT Format);
@ -65,6 +65,10 @@ class CommandData:public RAROptions
StringList InclArgs; StringList InclArgs;
StringList ArcNames; StringList ArcNames;
StringList StoreArgs; StringList StoreArgs;
SecPassword Password;
std::vector<int64> NextVolSizes;
}; };
#endif #endif

@ -262,6 +262,8 @@ bool CommandData::TimeCheck(RarTime &ftm,RarTime &ftc,RarTime &fta)
// Return 'true' if we need to exclude the file from processing. // Return 'true' if we need to exclude the file from processing.
bool CommandData::SizeCheck(int64 Size) bool CommandData::SizeCheck(int64 Size)
{ {
if (Size==INT64NDF) // If called from archive formats like bzip2, not storing the file size.
return false;
if (FileSizeLess!=INT64NDF && Size>=FileSizeLess) if (FileSizeLess!=INT64NDF && Size>=FileSizeLess)
return true; return true;
if (FileSizeMore!=INT64NDF && Size<=FileSizeMore) if (FileSizeMore!=INT64NDF && Size<=FileSizeMore)
@ -287,8 +289,8 @@ int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchTy
return 0; return 0;
if ((FileHead.FileAttr & ExclFileAttr)!=0 || FileHead.Dir && ExclDir) if ((FileHead.FileAttr & ExclFileAttr)!=0 || FileHead.Dir && ExclDir)
return 0; return 0;
if (InclAttrSet && (!FileHead.Dir && (FileHead.FileAttr & InclFileAttr)==0 || if (InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0 &&
FileHead.Dir && !InclDir)) (!FileHead.Dir || !InclDir))
return 0; return 0;
if (!Dir && SizeCheck(FileHead.UnpSize)) if (!Dir && SizeCheck(FileHead.UnpSize))
return 0; return 0;

@ -61,14 +61,14 @@ void CommandData::OutHelp(RAR_EXIT ExitCode)
MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL, MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL,
MCHelpCmdP,MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,MCHelpSwm, MCHelpCmdP,MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,MCHelpSwm,
MCHelpSwAT,MCHelpSwAC,MCHelpSwAD,MCHelpSwAG,MCHelpSwAI,MCHelpSwAP, MCHelpSwAT,MCHelpSwAC,MCHelpSwAD,MCHelpSwAG,MCHelpSwAI,MCHelpSwAP,
MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU, MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU,MCHelpSwDH,MCHelpSwEP,
MCHelpSwDH,MCHelpSwEP,MCHelpSwEP3,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR, MCHelpSwEP3,MCHelpSwEP4,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR,
MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwN,MCHelpSwNa,MCHelpSwNal, MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwME,MCHelpSwN,MCHelpSwNa,
MCHelpSwO,MCHelpSwOC,MCHelpSwOL,MCHelpSwOR,MCHelpSwOW,MCHelpSwP, MCHelpSwNal,MCHelpSwO,MCHelpSwOC,MCHelpSwOL,MCHelpSwOP,MCHelpSwOR,
MCHelpSwPm,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSL,MCHelpSwSM, MCHelpSwOW,MCHelpSwP,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSI,
MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU, MCHelpSwSL,MCHelpSwSM,MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,
MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal, MCHelpSwTS,MCHelpSwU,MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,
MCHelpSwY MCHelpSwXa,MCHelpSwXal,MCHelpSwY
#endif #endif
}; };
@ -92,6 +92,13 @@ void CommandData::OutHelp(RAR_EXIT ExitCode)
if (Found) if (Found)
continue; continue;
#endif #endif
#ifdef _UNIX
if (CmpMSGID(Help[I],MRARTitle2))
{
mprintf(St(MFwrSlTitle2));
continue;
}
#endif
#if !defined(_UNIX) && !defined(_WIN_ALL) #if !defined(_UNIX) && !defined(_WIN_ALL)
if (CmpMSGID(Help[I],MCHelpSwOW)) if (CmpMSGID(Help[I],MCHelpSwOW))
continue; continue;

@ -17,6 +17,7 @@ class PackDef
static const uint MAX_INC_LZ_MATCH = MAX_LZ_MATCH + 3; 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 MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3.
static const uint MAX3_INC_LZ_MATCH = MAX3_LZ_MATCH + 3;
static const uint LOW_DIST_REP_COUNT = 16; static const uint LOW_DIST_REP_COUNT = 16;
static const uint NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */ static const uint NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */

@ -3,6 +3,7 @@
static MESSAGE_TYPE MsgStream=MSG_STDOUT; static MESSAGE_TYPE MsgStream=MSG_STDOUT;
static RAR_CHARSET RedirectCharset=RCH_DEFAULT; static RAR_CHARSET RedirectCharset=RCH_DEFAULT;
static bool ProhibitInput=false;
const int MaxMsgSize=2*NM+2048; const int MaxMsgSize=2*NM+2048;
@ -61,6 +62,12 @@ void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset)
} }
void ProhibitConsoleInput()
{
ProhibitInput=true;
}
#ifndef SILENT #ifndef SILENT
static void cvt_wprintf(FILE *dest,const wchar *fmt,va_list arglist) static void cvt_wprintf(FILE *dest,const wchar *fmt,va_list arglist)
{ {
@ -141,28 +148,56 @@ void eprintf(const wchar *fmt,...)
#ifndef SILENT #ifndef SILENT
static void QuitIfInputProhibited()
{
// We cannot handle user prompts if -si is used to read file or archive data
// from stdin.
if (ProhibitInput)
{
mprintf(St(MStdinNoInput));
ErrHandler.Exit(RARX_FATAL);
}
}
static void GetPasswordText(wchar *Str,uint MaxLength) static void GetPasswordText(wchar *Str,uint MaxLength)
{ {
if (MaxLength==0) if (MaxLength==0)
return; return;
QuitIfInputProhibited();
if (StdinRedirected) if (StdinRedirected)
getwstr(Str,MaxLength); // Read from pipe or redirected file. getwstr(Str,MaxLength); // Read from pipe or redirected file.
else else
{ {
#ifdef _WIN_ALL #ifdef _WIN_ALL
HANDLE hConIn=GetStdHandle(STD_INPUT_HANDLE); HANDLE hConIn=GetStdHandle(STD_INPUT_HANDLE);
HANDLE hConOut=GetStdHandle(STD_OUTPUT_HANDLE); DWORD ConInMode;
DWORD ConInMode,ConOutMode;
DWORD Read=0;
GetConsoleMode(hConIn,&ConInMode); GetConsoleMode(hConIn,&ConInMode);
GetConsoleMode(hConOut,&ConOutMode); SetConsoleMode(hConIn,ENABLE_LINE_INPUT); // Remove ENABLE_ECHO_INPUT.
SetConsoleMode(hConIn,ENABLE_LINE_INPUT);
SetConsoleMode(hConOut,ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT);
// We prefer ReadConsole to ReadFile, so we can read Unicode input.
DWORD Read=0;
ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL); ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL);
Str[Read]=0; Str[Read]=0;
SetConsoleMode(hConIn,ConInMode); SetConsoleMode(hConIn,ConInMode);
SetConsoleMode(hConOut,ConOutMode);
// If entered password is longer than MAXPASSWORD and truncated,
// read its unread part anyway, so it isn't read later as the second
// password for -p switch. Low level FlushConsoleInputBuffer doesn't help
// for high level ReadConsole, which in line input mode seems to store
// the rest of string in its own internal buffer.
if (wcschr(Str,'\r')==NULL) // If '\r' is missing, the password was truncated.
while (true)
{
wchar Trail[64];
DWORD TrailRead=0;
// Use ASIZE(Trail)-1 to reserve the space for trailing 0.
ReadConsole(hConIn,Trail,ASIZE(Trail)-1,&TrailRead,NULL);
Trail[TrailRead]=0;
if (TrailRead==0 || wcschr(Trail,'\r')!=NULL)
break;
}
#else #else
char StrA[MAXPASSWORD*4]; // "*4" for multibyte UTF-8 characters. char StrA[MAXPASSWORD*4]; // "*4" for multibyte UTF-8 characters.
#if defined(_EMX) || defined (__VMS) #if defined(_EMX) || defined (__VMS)
@ -190,16 +225,21 @@ bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *
while (true) while (true)
{ {
if (!StdinRedirected) // if (!StdinRedirected)
if (Type==UIPASSWORD_GLOBAL) if (Type==UIPASSWORD_GLOBAL)
eprintf(L"\n%s: ",St(MAskPsw)); eprintf(L"\n%s: ",St(MAskPsw));
else else
eprintf(St(MAskPswFor),FileName); eprintf(St(MAskPswFor),FileName);
wchar PlainPsw[MAXPASSWORD]; wchar PlainPsw[MAXPASSWORD+1];
GetPasswordText(PlainPsw,ASIZE(PlainPsw)); GetPasswordText(PlainPsw,ASIZE(PlainPsw));
if (*PlainPsw==0 && Type==UIPASSWORD_GLOBAL) if (*PlainPsw==0 && Type==UIPASSWORD_GLOBAL)
return false; return false;
if (wcslen(PlainPsw)>=MAXPASSWORD)
{
PlainPsw[MAXPASSWORD-1]=0;
uiMsg(UIERROR_TRUNCPSW,MAXPASSWORD-1);
}
if (!StdinRedirected && Type==UIPASSWORD_GLOBAL) if (!StdinRedirected && Type==UIPASSWORD_GLOBAL)
{ {
eprintf(St(MReAskPsw)); eprintf(St(MReAskPsw));
@ -229,6 +269,8 @@ bool getwstr(wchar *str,size_t n)
// Print buffered prompt title function before waiting for input. // Print buffered prompt title function before waiting for input.
fflush(stderr); fflush(stderr);
QuitIfInputProhibited();
*str=0; *str=0;
#if defined(_WIN_ALL) #if defined(_WIN_ALL)
// fgetws does not work well with non-English text in Windows, // fgetws does not work well with non-English text in Windows,
@ -240,6 +282,7 @@ bool getwstr(wchar *str,size_t n)
Array<char> StrA(n*4); // Up to 4 UTF-8 characters per wchar_t. Array<char> StrA(n*4); // Up to 4 UTF-8 characters per wchar_t.
File SrcFile; File SrcFile;
SrcFile.SetHandleType(FILE_HANDLESTD); SrcFile.SetHandleType(FILE_HANDLESTD);
SrcFile.SetLineInputMode(true);
int ReadSize=SrcFile.Read(&StrA[0],StrA.Size()-1); int ReadSize=SrcFile.Read(&StrA[0],StrA.Size()-1);
if (ReadSize<=0) if (ReadSize<=0)
{ {

@ -4,6 +4,7 @@
void InitConsole(); void InitConsole();
void SetConsoleMsgStream(MESSAGE_TYPE MsgStream); void SetConsoleMsgStream(MESSAGE_TYPE MsgStream);
void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset); void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset);
void ProhibitConsoleInput();
void OutComment(const wchar *Comment,size_t Size); void OutComment(const wchar *Comment,size_t Size);
#ifndef SILENT #ifndef SILENT

171
deps/unrar/crc.cpp vendored

@ -14,6 +14,12 @@
#include "rar.hpp" #include "rar.hpp"
#ifndef SFX_MODULE
// User suggested to avoid BSD license in SFX module, so they do not need
// to include the license to SFX archive.
#define USE_SLICING
#endif
static uint crc_tables[8][256]; // Tables for Slicing-by-8. static uint crc_tables[8][256]; // Tables for Slicing-by-8.
@ -37,6 +43,7 @@ static void InitTables()
{ {
InitCRC32(crc_tables[0]); InitCRC32(crc_tables[0]);
#ifdef USE_SLICING
for (uint I=0;I<256;I++) // Build additional lookup tables. for (uint I=0;I<256;I++) // Build additional lookup tables.
{ {
uint C=crc_tables[0][I]; uint C=crc_tables[0][I];
@ -46,6 +53,7 @@ static void InitTables()
crc_tables[J][I]=C; crc_tables[J][I]=C;
} }
} }
#endif
} }
@ -55,6 +63,7 @@ uint CRC32(uint StartCRC,const void *Addr,size_t Size)
{ {
byte *Data=(byte *)Addr; byte *Data=(byte *)Addr;
#ifdef USE_SLICING
// Align Data to 8 for better performance. // Align Data to 8 for better performance.
for (;Size>0 && ((size_t)Data & 7);Size--,Data++) for (;Size>0 && ((size_t)Data & 7);Size--,Data++)
StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8); StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
@ -77,6 +86,7 @@ uint CRC32(uint StartCRC,const void *Addr,size_t Size)
crc_tables[1][(byte)(NextData >> 16)] ^ crc_tables[1][(byte)(NextData >> 16)] ^
crc_tables[0][(byte)(NextData >> 24)]; crc_tables[0][(byte)(NextData >> 24)];
} }
#endif
for (;Size>0;Size--,Data++) // Process left data. for (;Size>0;Size--,Data++) // Process left data.
StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8); StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
@ -100,3 +110,164 @@ ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size)
#endif #endif
#if 0
static uint64 crc64_tables[8][256]; // Tables for Slicing-by-8 for CRC64.
void InitCRC64(uint64 *CRCTab)
{
const uint64 poly=INT32TO64(0xC96C5795, 0xD7870F42); // 0xC96C5795D7870F42;
for (uint I=0;I<256;I++)
{
uint64 C=I;
for (uint J=0;J<8;J++)
C=(C & 1) ? (C>>1)^poly: (C>>1);
CRCTab[I]=C;
}
}
static void InitTables64()
{
InitCRC64(crc64_tables[0]);
for (uint I=0;I<256;I++) // Build additional lookup tables.
{
uint64 C=crc64_tables[0][I];
for (uint J=1;J<8;J++)
{
C=crc64_tables[0][(byte)C]^(C>>8);
crc64_tables[J][I]=C;
}
}
}
// We cannot place the intialization to CRC64(), because we use this function
// in multithreaded mode and it conflicts with multithreading.
struct CallInitCRC64 {CallInitCRC64() {InitTables64();}} static CallInit64;
uint64 CRC64(uint64 StartCRC,const void *Addr,size_t Size)
{
byte *Data=(byte *)Addr;
// Align Data to 8 for better performance.
for (;Size>0 && ((size_t)Data & 7)!=0;Size--,Data++)
StartCRC=crc64_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
for (byte *DataEnd=Data+Size/8*8; Data<DataEnd; Data+=8 )
{
uint64 Index=StartCRC;
#ifdef BIG_ENDIAN
Index ^= (uint64(Data[0])|(uint64(Data[1])<<8)|(uint64(Data[2])<<16)|(uint64(Data[3])<<24))|
(uint64(Data[4])<<32)|(uint64(Data[5])<<40)|(uint64(Data[6])<<48)|(uint64(Data[7])<<56);
#else
Index ^= *(uint64 *)Data;
#endif
StartCRC = crc64_tables[ 7 ] [ ( byte ) (Index ) ] ^
crc64_tables[ 6 ] [ ( byte ) (Index >> 8 ) ] ^
crc64_tables[ 5 ] [ ( byte ) (Index >> 16 ) ] ^
crc64_tables[ 4 ] [ ( byte ) (Index >> 24 ) ] ^
crc64_tables[ 3 ] [ ( byte ) (Index >> 32 ) ] ^
crc64_tables[ 2 ] [ ( byte ) (Index >> 40 ) ] ^
crc64_tables[ 1 ] [ ( byte ) (Index >> 48 ) ] ^
crc64_tables[ 0 ] [ ( byte ) (Index >> 56 ) ] ;
}
for (Size%=8;Size>0;Size--,Data++) // Process left data.
StartCRC=crc64_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8);
return StartCRC;
}
#if 0
static void TestCRC();
struct TestCRCStruct {TestCRCStruct() {TestCRC();exit(0);}} GlobalTesCRC;
void TestCRC()
{
const uint FirstSize=300;
byte b[FirstSize];
if ((CRC32(0xffffffff,(byte*)"testtesttest",12)^0xffffffff)==0x44608e84)
mprintf(L"\nCRC32 test1 OK");
else
mprintf(L"\nCRC32 test1 FAILED");
if (CRC32(0,(byte*)"te\x80st",5)==0xB2E5C5AE)
mprintf(L"\nCRC32 test2 OK");
else
mprintf(L"\nCRC32 test2 FAILED");
for (uint I=0;I<14;I++) // Check for possible int sign extension.
b[I]=(byte)0x7f+I;
if ((CRC32(0xffffffff,b,14)^0xffffffff)==0x1DFA75DA)
mprintf(L"\nCRC32 test3 OK");
else
mprintf(L"\nCRC32 test3 FAILED");
for (uint I=0;I<FirstSize;I++)
b[I]=(byte)I;
uint r32=CRC32(0xffffffff,b,FirstSize);
for (uint I=FirstSize;I<1024;I++)
{
b[0]=(byte)I;
r32=CRC32(r32,b,1);
}
if ((r32^0xffffffff)==0xB70B4C26)
mprintf(L"\nCRC32 test4 OK");
else
mprintf(L"\nCRC32 test4 FAILED");
if ((CRC64(0xffffffffffffffff,(byte*)"testtesttest",12)^0xffffffffffffffff)==0x7B1C2D230EDEB436)
mprintf(L"\nCRC64 test1 OK");
else
mprintf(L"\nCRC64 test1 FAILED");
if (CRC64(0,(byte*)"te\x80st",5)==0xB5DBF9583A6EED4A)
mprintf(L"\nCRC64 test2 OK");
else
mprintf(L"\nCRC64 test2 FAILED");
for (uint I=0;I<14;I++) // Check for possible int sign extension.
b[I]=(byte)0x7f+I;
if ((CRC64(0xffffffffffffffff,b,14)^0xffffffffffffffff)==0xE019941C05B2820C)
mprintf(L"\nCRC64 test3 OK");
else
mprintf(L"\nCRC64 test3 FAILED");
for (uint I=0;I<FirstSize;I++)
b[I]=(byte)I;
uint64 r64=CRC64(0xffffffffffffffff,b,FirstSize);
for (uint I=FirstSize;I<1024;I++)
{
b[0]=(byte)I;
r64=CRC64(r64,b,1);
}
if ((r64^0xffffffffffffffff)==0xD51FB58DC789C400)
mprintf(L"\nCRC64 test4 OK");
else
mprintf(L"\nCRC64 test4 FAILED");
const size_t BufSize=0x100000;
byte *Buf=new byte[BufSize];
memset(Buf,0,BufSize);
clock_t StartTime=clock();
r32=0xffffffff;
const uint BufCount=5000;
for (uint I=0;I<BufCount;I++)
r32=CRC32(r32,Buf,BufSize);
if (r32!=0) // Otherwise compiler optimizer removes CRC calculation.
mprintf(L"\nCRC32 speed: %d MB/s",BufCount*1000/(clock()-StartTime));
StartTime=clock();
r64=0xffffffffffffffff;
for (uint I=0;I<BufCount;I++)
r64=CRC64(r64,Buf,BufSize);
if (r64!=0) // Otherwise compiler optimizer removes CRC calculation.
mprintf(L"\nCRC64 speed: %d MB/s",BufCount*1000/(clock()-StartTime));
}
#endif
#endif

@ -11,5 +11,9 @@ uint CRC32(uint StartCRC,const void *Addr,size_t Size);
ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size); ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size);
#endif #endif
#if 0
void InitCRC64(uint64 *CRCTab);
uint64 CRC64(uint64 StartCRC,const void *Addr,size_t Size);
#endif
#endif #endif

@ -11,21 +11,12 @@
CryptData::CryptData() CryptData::CryptData()
{ {
Method=CRYPT_NONE; Method=CRYPT_NONE;
memset(KDF3Cache,0,sizeof(KDF3Cache));
memset(KDF5Cache,0,sizeof(KDF5Cache));
KDF3CachePos=0; KDF3CachePos=0;
KDF5CachePos=0; KDF5CachePos=0;
memset(CRCTab,0,sizeof(CRCTab)); memset(CRCTab,0,sizeof(CRCTab));
} }
CryptData::~CryptData()
{
cleandata(KDF3Cache,sizeof(KDF3Cache));
cleandata(KDF5Cache,sizeof(KDF5Cache));
}
void CryptData::DecryptBlock(byte *Buf,size_t Size) void CryptData::DecryptBlock(byte *Buf,size_t Size)
@ -56,15 +47,18 @@ bool CryptData::SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,
SecPassword *Password,const byte *Salt, SecPassword *Password,const byte *Salt,
const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck) const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck)
{ {
if (!Password->IsSet() || Method==CRYPT_NONE) if (Method==CRYPT_NONE || !Password->IsSet())
return false; return false;
CryptData::Method=Method; CryptData::Method=Method;
wchar PwdW[MAXPASSWORD]; wchar PwdW[MAXPASSWORD];
Password->Get(PwdW,ASIZE(PwdW)); Password->Get(PwdW,ASIZE(PwdW));
PwdW[Min(MAXPASSWORD_RAR,MAXPASSWORD)-1]=0; // For compatibility with existing archives.
char PwdA[MAXPASSWORD]; char PwdA[MAXPASSWORD];
WideToChar(PwdW,PwdA,ASIZE(PwdA)); WideToChar(PwdW,PwdA,ASIZE(PwdA));
PwdA[Min(MAXPASSWORD_RAR,MAXPASSWORD)-1]=0; // For compatibility with existing archives.
switch(Method) switch(Method)
{ {

@ -30,6 +30,18 @@ class CryptData
uint Lg2Count; // Log2 of PBKDF2 repetition count. uint Lg2Count; // Log2 of PBKDF2 repetition count.
byte PswCheckValue[SHA256_DIGEST_SIZE]; byte PswCheckValue[SHA256_DIGEST_SIZE];
byte HashKeyValue[SHA256_DIGEST_SIZE]; byte HashKeyValue[SHA256_DIGEST_SIZE];
KDF5CacheItem() {Clean();}
~KDF5CacheItem() {Clean();}
void Clean()
{
cleandata(Salt,sizeof(Salt));
cleandata(Key,sizeof(Key));
cleandata(&Lg2Count,sizeof(Lg2Count));
cleandata(PswCheckValue,sizeof(PswCheckValue));
cleandata(HashKeyValue,sizeof(HashKeyValue));
}
}; };
struct KDF3CacheItem struct KDF3CacheItem
@ -39,6 +51,17 @@ class CryptData
byte Key[16]; byte Key[16];
byte Init[16]; byte Init[16];
bool SaltPresent; bool SaltPresent;
KDF3CacheItem() {Clean();}
~KDF3CacheItem() {Clean();}
void Clean()
{
cleandata(Salt,sizeof(Salt));
cleandata(Key,sizeof(Key));
cleandata(Init,sizeof(Init));
cleandata(&SaltPresent,sizeof(SaltPresent));
}
}; };
@ -77,7 +100,6 @@ class CryptData
ushort Key15[4]; ushort Key15[4];
public: public:
CryptData(); CryptData();
~CryptData();
bool SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,SecPassword *Password, bool SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,SecPassword *Password,
const byte *Salt,const byte *InitV,uint Lg2Cnt, const byte *Salt,const byte *InitV,uint Lg2Cnt,
byte *HashKey,byte *PswCheck); byte *HashKey,byte *PswCheck);
@ -89,6 +111,54 @@ class CryptData
static void SetSalt(byte *Salt,size_t SaltSize); static void SetSalt(byte *Salt,size_t SaltSize);
}; };
class CheckPassword
{
public:
enum CONFIDENCE {CONFIDENCE_HIGH,CONFIDENCE_MEDIUM,CONFIDENCE_LOW};
virtual CONFIDENCE GetConfidence()=0;
virtual bool Check(SecPassword *Password)=0;
};
class RarCheckPassword:public CheckPassword
{
private:
CryptData *Crypt;
uint Lg2Count;
byte Salt[SIZE_SALT50];
byte InitV[SIZE_INITV];
byte PswCheck[SIZE_PSWCHECK];
public:
RarCheckPassword()
{
Crypt=NULL;
}
~RarCheckPassword()
{
delete Crypt;
}
void Set(byte *Salt,byte *InitV,uint Lg2Count,byte *PswCheck)
{
if (Crypt==NULL)
Crypt=new CryptData;
memcpy(this->Salt,Salt,sizeof(this->Salt));
memcpy(this->InitV,InitV,sizeof(this->InitV));
this->Lg2Count=Lg2Count;
memcpy(this->PswCheck,PswCheck,sizeof(this->PswCheck));
}
bool IsSet() {return Crypt!=NULL;}
// RAR5 provides the higly reliable 64 bit password verification value.
CONFIDENCE GetConfidence() {return CONFIDENCE_HIGH;}
bool Check(SecPassword *Password)
{
byte PswCheck[SIZE_PSWCHECK];
Crypt->SetCryptKeys(false,CRYPT_RAR50,Password,Salt,InitV,Lg2Count,NULL,PswCheck);
return memcmp(PswCheck,this->PswCheck,sizeof(this->PswCheck))==0;
}
};
void GetRnd(byte *RndBuf,size_t BufSize); void GetRnd(byte *RndBuf,size_t BufSize);
void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data, void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data,

@ -18,8 +18,9 @@ void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,co
if (!Cached) if (!Cached)
{ {
byte RawPsw[2*MAXPASSWORD+SIZE_SALT30]; byte RawPsw[2*MAXPASSWORD+SIZE_SALT30];
WideToRaw(PwdW,RawPsw,ASIZE(RawPsw)); size_t PswLength=wcslen(PwdW);
size_t RawLength=2*wcslen(PwdW); size_t RawLength=2*PswLength;
WideToRaw(PwdW,PswLength,RawPsw,RawLength);
if (Salt!=NULL) if (Salt!=NULL)
{ {
memcpy(RawPsw+RawLength,Salt,SIZE_SALT30); memcpy(RawPsw+RawLength,Salt,SIZE_SALT30);

@ -21,7 +21,7 @@ static void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data,
sha256_context ICtx; sha256_context ICtx;
if (ICtxOpt!=NULL && *SetIOpt) if (ICtxOpt!=NULL && *SetIOpt)
ICtx=*ICtxOpt; // Use already calculated first block context. ICtx=*ICtxOpt; // Use already calculated the first block context.
else else
{ {
// This calculation is the same for all iterations with same password. // This calculation is the same for all iterations with same password.
@ -90,10 +90,10 @@ void pbkdf2(const byte *Pwd, size_t PwdLength,
byte SaltData[MaxSalt+4]; byte SaltData[MaxSalt+4];
memcpy(SaltData, Salt, Min(SaltLength,MaxSalt)); memcpy(SaltData, Salt, Min(SaltLength,MaxSalt));
SaltData[SaltLength + 0] = 0; // Salt concatenated to 1. SaltData[SaltLength + 0] = 0; // Block index appened to salt.
SaltData[SaltLength + 1] = 0; SaltData[SaltLength + 1] = 0; //
SaltData[SaltLength + 2] = 0; SaltData[SaltLength + 2] = 0; // Since we do not request the key width
SaltData[SaltLength + 3] = 1; SaltData[SaltLength + 3] = 1; // exceeding HMAC width, it is always 1.
// First iteration: HMAC of password, salt and block index (1). // First iteration: HMAC of password, salt and block index (1).
byte U1[SHA256_DIGEST_SIZE]; byte U1[SHA256_DIGEST_SIZE];
@ -140,7 +140,7 @@ void CryptData::SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,
for (uint I=0;I<ASIZE(KDF5Cache);I++) for (uint I=0;I<ASIZE(KDF5Cache);I++)
{ {
KDF5CacheItem *Item=KDF5Cache+I; KDF5CacheItem *Item=KDF5Cache+I;
if (Item->Lg2Count==Lg2Cnt && Item->Pwd==*Password && if (Item->Pwd==*Password && Item->Lg2Count==Lg2Cnt &&
memcmp(Item->Salt,Salt,SIZE_SALT50)==0) memcmp(Item->Salt,Salt,SIZE_SALT50)==0)
{ {
memcpy(Key,Item->Key,sizeof(Key)); memcpy(Key,Item->Key,sizeof(Key));

26
deps/unrar/dll.def vendored

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

56
deps/unrar/dll.rc vendored

@ -1,28 +1,28 @@
#include <windows.h> #include <windows.h>
#include <commctrl.h> #include <commctrl.h>
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 6, 1, 100, 3756 FILEVERSION 6, 22, 1, 865
PRODUCTVERSION 6, 1, 100, 3756 PRODUCTVERSION 6, 22, 1, 865
FILEOS VOS__WINDOWS32 FILEOS VOS__WINDOWS32
FILETYPE VFT_APP FILETYPE VFT_APP
{ {
BLOCK "StringFileInfo" BLOCK "StringFileInfo"
{ {
BLOCK "040904E4" BLOCK "040904E4"
{ {
VALUE "CompanyName", "Alexander Roshal\0" VALUE "CompanyName", "Alexander Roshal\0"
VALUE "ProductName", "RAR decompression library\0" VALUE "ProductName", "RAR decompression library\0"
VALUE "FileDescription", "RAR decompression library\0" VALUE "FileDescription", "RAR decompression library\0"
VALUE "FileVersion", "6.1.0\0" VALUE "FileVersion", "6.22.1\0"
VALUE "ProductVersion", "6.1.0\0" VALUE "ProductVersion", "6.22.1\0"
VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2021\0" VALUE "LegalCopyright", "Copyright © Alexander Roshal 1993-2023\0"
VALUE "OriginalFilename", "Unrar.dll\0" VALUE "OriginalFilename", "Unrar.dll\0"
} }
} }
BLOCK "VarFileInfo" BLOCK "VarFileInfo"
{ {
VALUE "Translation", 0x0409, 0x04E4 VALUE "Translation", 0x0409, 0x04E4
} }
} }

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

@ -20,8 +20,6 @@ void EncodeFileName::Decode(char *Name,size_t NameSize,byte *EncName,size_t EncS
{ {
if (FlagBits==0) if (FlagBits==0)
{ {
if (EncPos>=EncSize)
break;
Flags=EncName[EncPos++]; Flags=EncName[EncPos++];
FlagBits=8; FlagBits=8;
} }

@ -4,9 +4,8 @@
class EncodeFileName class EncodeFileName
{ {
private: private:
void AddFlags(int Value); void AddFlags(byte Value,byte *EncName);
byte *EncName;
byte Flags; byte Flags;
uint FlagBits; uint FlagBits;
size_t FlagsPos; size_t FlagsPos;

@ -169,10 +169,13 @@ void ErrorHandler::OpenErrorMsg(const wchar *FileName)
void ErrorHandler::OpenErrorMsg(const wchar *ArcName,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); uiMsg(UIERROR_FILEOPEN,ArcName,FileName);
SysErrMsg(); SysErrMsg();
SetErrorCode(RARX_OPEN); SetErrorCode(RARX_OPEN);
// Keep GUI responsive if many files cannot be opened when archiving.
// Call after SysErrMsg to avoid modifying the error code and SysErrMsg text.
Wait();
} }
@ -367,7 +370,7 @@ bool ErrorHandler::GetSysErrMsg(wchar *Msg,size_t Size)
void ErrorHandler::SysErrMsg() void ErrorHandler::SysErrMsg()
{ {
#if !defined(SFX_MODULE) && !defined(SILENT) #ifndef SILENT
wchar Msg[1024]; wchar Msg[1024];
if (!GetSysErrMsg(Msg,ASIZE(Msg))) if (!GetSysErrMsg(Msg,ASIZE(Msg)))
return; return;

@ -112,6 +112,68 @@ static bool LinkInPath(const wchar *Name)
} }
// Delete symbolic links in file path, if any, and replace them by directories.
// Prevents extracting files outside of destination folder with symlink chains.
bool LinksToDirs(const wchar *SrcName,const wchar *SkipPart,std::wstring &LastChecked)
{
// Unlike Unix, Windows doesn't expand lnk1 in symlink targets like
// "lnk1/../dir", but converts the path to "dir". In Unix we need to call
// this function to prevent placing unpacked files outside of destination
// folder if previously we unpacked "dir/lnk1" -> "..",
// "dir/lnk2" -> "lnk1/.." and "dir/lnk2/anypath/poc.txt".
// We may still need this function to prevent abusing symlink chains
// in link source path if we remove detection of such chains
// in IsRelativeSymlinkSafe. This function seems to make other symlink
// related safety checks redundant, but for now we prefer to keep them too.
//
// 2022.12.01: the performance impact is minimized after adding the check
// against the previous path and enabling this verification only after
// extracting a symlink with ".." in target. So we enabled it for Windows
// as well for extra safety.
//#ifdef _UNIX
wchar Path[NM];
if (wcslen(SrcName)>=ASIZE(Path))
return false; // It should not be that long, skip.
wcsncpyz(Path,SrcName,ASIZE(Path));
size_t SkipLength=wcslen(SkipPart);
if (SkipLength>0 && wcsncmp(Path,SkipPart,SkipLength)!=0)
SkipLength=0; // Parameter validation, not really needed now.
// Do not check parts already checked in previous path to improve performance.
for (uint I=0;Path[I]!=0 && I<LastChecked.size() && Path[I]==LastChecked[I];I++)
if (IsPathDiv(Path[I]) && I>SkipLength)
SkipLength=I;
wchar *Name=Path;
if (SkipLength>0)
{
// Avoid converting symlinks in destination path part specified by user.
Name+=SkipLength;
while (IsPathDiv(*Name))
Name++;
}
for (wchar *s=Path+wcslen(Path)-1;s>Name;s--)
if (IsPathDiv(*s))
{
*s=0;
FindData FD;
if (FindFile::FastFind(Path,&FD,true) && FD.IsLink)
#ifdef _WIN_ALL
if (!DelDir(Path))
#else
if (!DelFile(Path))
#endif
return false; // Couldn't delete the symlink to replace it with directory.
}
LastChecked=SrcName;
//#endif
return true;
}
bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName) bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName)
{ {
// Catch root dir based /path/file paths also as stuff like \\?\. // Catch root dir based /path/file paths also as stuff like \\?\.
@ -131,10 +193,14 @@ bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *Pr
UpLevels++; UpLevels++;
TargetName++; TargetName++;
} }
// If link target includes "..", it must not have another links // If link target includes "..", it must not have another links in its
// in the path, because they can bypass our safety check. For example, // source path, because they can bypass our safety check. For example,
// suppose we extracted "lnk1" -> "." first and "lnk1/lnk2" -> ".." next // suppose we extracted "lnk1" -> "." first and "lnk1/lnk2" -> ".." next
// or "dir/lnk1" -> ".." first and "dir/lnk1/lnk2" -> ".." next. // or "dir/lnk1" -> ".." first, "dir/lnk1/lnk2" -> ".." next and
// file "dir/lnk1/lnk2/poc.txt" last.
// Do not confuse with link chains in target, this is in link source path.
// It is important for Windows too, though this check can be omitted
// if LinksToDirs is invoked in Windows as well.
if (UpLevels>0 && LinkInPath(PrepSrcName)) if (UpLevels>0 && LinkInPath(PrepSrcName))
return false; return false;
@ -160,15 +226,26 @@ bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *Pr
} }
bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName) bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName,bool &UpLink)
{ {
// Returning true in Uplink indicates that link target might include ".."
// and enables additional checks. It is ok to falsely return true here,
// as it implies only the minor performance penalty. But we shall always
// return true for links with ".." in target for security reason.
UpLink=true; // Assume the target might include potentially unsafe "..".
#if defined(SAVE_LINKS) && defined(_UNIX) || defined(_WIN_ALL)
if (Arc.Format==RARFMT50) // For RAR5 archives we can check RedirName for both Unix and Windows.
UpLink=wcsstr(Arc.FileHead.RedirName,L"..")!=NULL;
#endif
#if defined(SAVE_LINKS) && defined(_UNIX) #if defined(SAVE_LINKS) && defined(_UNIX)
// For RAR 3.x archives we process links even in test mode to skip link data. // For RAR 3.x archives we process links even in test mode to skip link data.
if (Arc.Format==RARFMT15) if (Arc.Format==RARFMT15)
return ExtractUnixLink30(Cmd,DataIO,Arc,LinkName); return ExtractUnixLink30(Cmd,DataIO,Arc,LinkName,UpLink);
if (Arc.Format==RARFMT50) if (Arc.Format==RARFMT50)
return ExtractUnixLink50(Cmd,LinkName,&Arc.FileHead); return ExtractUnixLink50(Cmd,LinkName,&Arc.FileHead);
#elif defined _WIN_ALL #elif defined(_WIN_ALL)
// RAR 5.0 archives store link information in file header, so there is // RAR 5.0 archives store link information in file header, so there is
// no need to additionally test it if we do not create a file. // no need to additionally test it if we do not create a file.
if (Arc.Format==RARFMT50) if (Arc.Format==RARFMT50)

@ -1,8 +1,9 @@
#ifndef _RAR_EXTINFO_ #ifndef _RAR_EXTINFO_
#define _RAR_EXTINFO_ #define _RAR_EXTINFO_
bool LinksToDirs(const wchar *SrcName,const wchar *SkipPart,std::wstring &LastChecked);
bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName); bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName);
bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName); bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName,bool &UpLink);
#ifdef _UNIX #ifdef _UNIX
void SetUnixOwner(Archive &Arc,const wchar *FileName); void SetUnixOwner(Archive &Arc,const wchar *FileName);
#endif #endif

@ -5,10 +5,30 @@ CmdExtract::CmdExtract(CommandData *Cmd)
CmdExtract::Cmd=Cmd; CmdExtract::Cmd=Cmd;
*ArcName=0; *ArcName=0;
*DestFileName=0; *DestFileName=0;
ArcAnalyzed=false;
Analyze=new AnalyzeData;
memset(Analyze,0,sizeof(*Analyze));
TotalFileCount=0; TotalFileCount=0;
// Common for all archives involved. Set here instead of DoExtract()
// to use in unrar.dll too. Allows to avoid LinksToDirs() calls
// and save CPU time in no symlinks including ".." in target were extracted.
#if defined(_WIN_ALL)
// We can't expand symlink path components in another symlink target
// in Windows. We can't create symlinks in Android now. Even though we do not
// really need LinksToDirs() calls in these systems, we still call it
// for extra safety, but only if symlink with ".." in target was extracted.
ConvertSymlinkPaths=false;
#else
// We enable it by default in Unix to care about the case when several
// archives are unpacked to same directory with several independent RAR runs.
// Worst case performance penalty for a lot of small files seems to be ~3%.
ConvertSymlinkPaths=true;
#endif
Unp=new Unpack(&DataIO); Unp=new Unpack(&DataIO);
#ifdef RAR_SMP #ifdef RAR_SMP
Unp->SetThreads(Cmd->Threads); Unp->SetThreads(Cmd->Threads);
@ -18,7 +38,26 @@ CmdExtract::CmdExtract(CommandData *Cmd)
CmdExtract::~CmdExtract() CmdExtract::~CmdExtract()
{ {
FreeAnalyzeData();
delete Unp; delete Unp;
delete Analyze;
}
void CmdExtract::FreeAnalyzeData()
{
for (size_t I=0;I<RefList.Size();I++)
{
// We can have undeleted temporary reference source here if extraction
// was interrupted early or if user refused to overwrite prompt.
if (RefList[I].TmpName!=NULL)
DelFile(RefList[I].TmpName);
free(RefList[I].RefName);
free(RefList[I].TmpName);
}
RefList.Reset();
memset(Analyze,0,sizeof(*Analyze));
} }
@ -30,10 +69,13 @@ void CmdExtract::DoExtract()
PasswordCancelled=false; PasswordCancelled=false;
DataIO.SetCurrentCommand(Cmd->Command[0]); DataIO.SetCurrentCommand(Cmd->Command[0]);
FindData FD; if (*Cmd->UseStdin==0)
while (Cmd->GetArcName(ArcName,ASIZE(ArcName))) {
if (FindFile::FastFind(ArcName,&FD)) FindData FD;
DataIO.TotalArcSize+=FD.Size; while (Cmd->GetArcName(ArcName,ASIZE(ArcName)))
if (FindFile::FastFind(ArcName,&FD))
DataIO.TotalArcSize+=FD.Size;
}
Cmd->ArcNames.Rewind(); Cmd->ArcNames.Rewind();
while (Cmd->GetArcName(ArcName,ASIZE(ArcName))) while (Cmd->GetArcName(ArcName,ASIZE(ArcName)))
@ -49,8 +91,7 @@ void CmdExtract::DoExtract()
if (Code!=EXTRACT_ARC_REPEAT) if (Code!=EXTRACT_ARC_REPEAT)
break; break;
} }
if (FindFile::FastFind(ArcName,&FD)) DataIO.ProcessedArcSize+=DataIO.LastArcSize;
DataIO.ProcessedArcSize+=FD.Size;
} }
// Clean user entered password. Not really required, just for extra safety. // Clean user entered password. Not really required, just for extra safety.
@ -82,7 +123,7 @@ void CmdExtract::DoExtract()
void CmdExtract::ExtractArchiveInit(Archive &Arc) void CmdExtract::ExtractArchiveInit(Archive &Arc)
{ {
DataIO.UnpArcSize=Arc.FileLength(); DataIO.AdjustTotalArcSize(&Arc);
FileCount=0; FileCount=0;
MatchedArgs=0; MatchedArgs=0;
@ -98,15 +139,33 @@ void CmdExtract::ExtractArchiveInit(Archive &Arc)
AllMatchesExact=true; AllMatchesExact=true;
AnySolidDataUnpackedWell=false; AnySolidDataUnpackedWell=false;
ArcAnalyzed=false;
StartTime.SetCurrentTime(); StartTime.SetCurrentTime();
LastCheckedSymlink.clear();
} }
EXTRACT_ARC_CODE CmdExtract::ExtractArchive() EXTRACT_ARC_CODE CmdExtract::ExtractArchive()
{ {
Archive Arc(Cmd); Archive Arc(Cmd);
if (!Arc.WOpen(ArcName)) if (*Cmd->UseStdin!=0)
return EXTRACT_ARC_NEXT; {
Arc.SetHandleType(FILE_HANDLESTD);
#ifdef USE_QOPEN
Arc.SetProhibitQOpen(true);
#endif
}
else
{
#if defined(_WIN_ALL) && !defined(SFX_MODULE) // WinRAR GUI code also resets the cache.
if (*Cmd->Command=='T' || Cmd->Test)
ResetFileCache(ArcName); // Reset the file cache when testing an archive.
#endif
if (!Arc.WOpen(ArcName))
return EXTRACT_ARC_NEXT;
}
if (!Arc.IsArchive(true)) if (!Arc.IsArchive(true))
{ {
@ -155,20 +214,33 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive()
} }
#endif #endif
Arc.ViewComment(); // Must be before possible EXTRACT_ARC_REPEAT.
int64 VolumeSetSize=0; // Total size of volumes after the current volume. int64 VolumeSetSize=0; // Total size of volumes after the current volume.
#ifndef SFX_MODULE
if (!ArcAnalyzed && *Cmd->UseStdin==0)
{
AnalyzeArchive(Arc.FileName,Arc.Volume,Arc.NewNumbering);
ArcAnalyzed=true; // Avoid repeated analysis on EXTRACT_ARC_REPEAT.
}
#endif
if (Arc.Volume) if (Arc.Volume)
{ {
#ifndef SFX_MODULE #ifndef SFX_MODULE
// Try to speed up extraction for independent solid volumes by starting // Try to speed up extraction for independent solid volumes by starting
// extraction from non-first volume if we can. // extraction from non-first volume if we can.
if (!UseExactVolName && Arc.Solid && DetectStartVolume(Arc.FileName,Arc.NewNumbering)) if (*Analyze->StartName!=0)
{ {
wcsncpyz(ArcName,Analyze->StartName,ASIZE(ArcName));
*Analyze->StartName=0;
UseExactVolName=true; UseExactVolName=true;
return EXTRACT_ARC_REPEAT; return EXTRACT_ARC_REPEAT;
} }
#endif #endif
// Calculate the total size of all accessible volumes. // Calculate the total size of all accessible volumes.
// This size is necessary to display the correct total progress indicator. // This size is necessary to display the correct total progress indicator.
@ -203,7 +275,13 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive()
else else
uiStartArchiveExtract(!Cmd->Test,ArcName); uiStartArchiveExtract(!Cmd->Test,ArcName);
Arc.ViewComment(); #ifndef SFX_MODULE
if (Analyze->StartPos!=0)
{
Arc.Seek(Analyze->StartPos,SEEK_SET);
Analyze->StartPos=0;
}
#endif
while (1) while (1)
@ -216,14 +294,11 @@ EXTRACT_ARC_CODE CmdExtract::ExtractArchive()
if (Repeat) if (Repeat)
{ {
// If we started extraction from not first volume and need to // If we started extraction from not first volume and need to
// restart it from first, we must correct DataIO.TotalArcSize // restart it from first, we must set DataIO.TotalArcSize to size
// for correct total progress display. We subtract the size // of new first volume to display the total progress correctly.
// of current volume and all volumes after it and add the size FindData NewArc;
// of new (first) volume. if (FindFile::FastFind(ArcName,&NewArc))
FindData OldArc,NewArc; DataIO.TotalArcSize=NewArc.Size;
if (FindFile::FastFind(Arc.FileName,&OldArc) &&
FindFile::FastFind(ArcName,&NewArc))
DataIO.TotalArcSize-=VolumeSetSize+OldArc.Size-NewArc.Size;
return EXTRACT_ARC_REPEAT; return EXTRACT_ARC_REPEAT;
} }
else else
@ -262,7 +337,14 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
return false; return false;
HEADER_TYPE HeaderType=Arc.GetHeaderType(); HEADER_TYPE HeaderType=Arc.GetHeaderType();
if (HeaderType!=HEAD_FILE) if (HeaderType==HEAD_FILE)
{
// Unlike Arc.FileName, ArcName might store an old volume name here.
if (Analyze->EndPos!=0 && Analyze->EndPos==Arc.CurBlockPos &&
(*Analyze->EndName==0 || wcscmp(Analyze->EndName,Arc.FileName)==0))
return false;
}
else
{ {
#ifndef SFX_MODULE #ifndef SFX_MODULE
if (Arc.Format==RARFMT15 && HeaderType==HEAD3_OLDSERVICE && PrevProcessed) if (Arc.Format==RARFMT15 && HeaderType==HEAD3_OLDSERVICE && PrevProcessed)
@ -305,6 +387,9 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
if (Arc.FileHead.UnpSize<0) if (Arc.FileHead.UnpSize<0)
Arc.FileHead.UnpSize=0; Arc.FileHead.UnpSize=0;
// 2022.03.20: We might remove this check in the future.
// It duplicates Analyze->EndPos and Analyze->EndName in all cases except
// volumes on removable media.
if (!Cmd->Recurse && MatchedArgs>=Cmd->FileArgs.ItemsCount() && AllMatchesExact) if (!Cmd->Recurse && MatchedArgs>=Cmd->FileArgs.ItemsCount() && AllMatchesExact)
return false; return false;
@ -403,7 +488,39 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
FirstFile=false; FirstFile=false;
#endif #endif
if (MatchFound || (SkipSolid=Arc.Solid)!=0) bool RefTarget=false;
if (!MatchFound)
for (size_t I=0;I<RefList.Size();I++)
if (wcscmp(ArcFileName,RefList[I].RefName)==0)
{
ExtractRef *MatchedRef=&RefList[I];
if (!Cmd->Test) // While harmless, it is useless for 't'.
{
// If reference source isn't selected, but target is selected,
// we unpack the source under the temporary name and then rename
// or copy it to target name. We do not unpack it under the target
// name immediately, because the same source can be used by multiple
// targets and it is possible that first target isn't unpacked
// for some reason. Also targets might have associated service blocks
// like ACLs. All this would complicate processing a lot.
wcsncpyz(DestFileName,*Cmd->TempPath!=0 ? Cmd->TempPath:Cmd->ExtrPath,ASIZE(DestFileName));
AddEndSlash(DestFileName,ASIZE(DestFileName));
wcsncatz(DestFileName,L"__tmp_reference_source_",ASIZE(DestFileName));
MkTemp(DestFileName,ASIZE(DestFileName));
MatchedRef->TmpName=wcsdup(DestFileName);
}
RefTarget=true; // Need it even for 't' to test the reference source.
break;
}
if (Arc.FileHead.Encrypted && Cmd->SkipEncrypted)
if (Arc.Solid)
return false; // Abort the entire extraction for solid archive.
else
MatchFound=false; // Skip only the current file for non-solid archive.
if (MatchFound || RefTarget || (SkipSolid=Arc.Solid)!=0)
{ {
// First common call of uiStartFileExtract. It is done before overwrite // First common call of uiStartFileExtract. It is done before overwrite
// prompts, so if SkipSolid state is changed below, we'll need to make // prompts, so if SkipSolid state is changed below, we'll need to make
@ -411,7 +528,8 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
if (!uiStartFileExtract(ArcFileName,!Cmd->Test,Cmd->Test && Command!='I',SkipSolid)) if (!uiStartFileExtract(ArcFileName,!Cmd->Test,Cmd->Test && Command!='I',SkipSolid))
return false; return false;
ExtrPrepareName(Arc,ArcFileName,DestFileName,ASIZE(DestFileName)); if (!RefTarget)
ExtrPrepareName(Arc,ArcFileName,DestFileName,ASIZE(DestFileName));
// DestFileName can be set empty in case of excessive -ap switch. // DestFileName can be set empty in case of excessive -ap switch.
ExtrFile=!SkipSolid && *DestFileName!=0 && !Arc.FileHead.SplitBefore; ExtrFile=!SkipSolid && *DestFileName!=0 && !Arc.FileHead.SplitBefore;
@ -448,9 +566,13 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
return !Arc.Solid; // Can try extracting next file only in non-solid archive. return !Arc.Solid; // Can try extracting next file only in non-solid archive.
} }
while (true) // Repeat the password prompt for wrong and empty passwords. if (Arc.FileHead.Encrypted)
{ {
if (Arc.FileHead.Encrypted) RarCheckPassword CheckPwd;
if (Arc.Format==RARFMT50 && Arc.FileHead.UsePswCheck && !Arc.BrokenHeader)
CheckPwd.Set(Arc.FileHead.Salt,Arc.FileHead.InitV,Arc.FileHead.Lg2Count,Arc.FileHead.PswCheck);
while (true) // Repeat the password prompt for wrong and empty passwords.
{ {
// Stop archive extracting if user cancelled a password prompt. // Stop archive extracting if user cancelled a password prompt.
#ifdef RARDLL #ifdef RARDLL
@ -460,77 +582,83 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
return false; return false;
} }
#else #else
if (!ExtrGetPassword(Arc,ArcFileName)) if (!ExtrGetPassword(Arc,ArcFileName,CheckPwd.IsSet() ? &CheckPwd:NULL))
{ {
PasswordCancelled=true; PasswordCancelled=true;
return false; return false;
} }
#endif #endif
}
// Set a password before creating the file, so we can skip creating
// in case of wrong password.
SecPassword FilePassword=Cmd->Password;
#if defined(_WIN_ALL) && !defined(SFX_MODULE)
ConvertDosPassword(Arc,FilePassword);
#endif
byte PswCheck[SIZE_PSWCHECK]; // Set a password before creating the file, so we can skip creating
DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword, // in case of wrong password.
Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL, SecPassword FilePassword=Cmd->Password;
Arc.FileHead.InitV,Arc.FileHead.Lg2Count, #if defined(_WIN_ALL) && !defined(SFX_MODULE)
Arc.FileHead.HashKey,PswCheck); ConvertDosPassword(Arc,FilePassword);
#endif
// If header is damaged, we cannot rely on password check value,
// because it can be damaged too. byte PswCheck[SIZE_PSWCHECK];
if (Arc.FileHead.Encrypted && Arc.FileHead.UsePswCheck && DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword,
memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 && Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL,
!Arc.BrokenHeader) Arc.FileHead.InitV,Arc.FileHead.Lg2Count,
{ Arc.FileHead.HashKey,PswCheck);
if (GlobalPassword) // For -p<pwd> or Ctrl+P to avoid the infinite loop.
{ // If header is damaged, we cannot rely on password check value,
// This message is used by Android GUI to reset cached passwords. // because it can be damaged too.
// Update appropriate code if changed. if (Arc.FileHead.UsePswCheck && !Arc.BrokenHeader &&
uiMsg(UIERROR_BADPSW,Arc.FileName,ArcFileName); memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0)
}
else // For passwords entered manually.
{ {
// This message is used by Android GUI and Windows GUI and SFX to if (GlobalPassword) // For -p<pwd> or Ctrl+P to avoid the infinite loop.
// reset cached passwords. Update appropriate code if changed. {
uiMsg(UIWAIT_BADPSW,Arc.FileName,ArcFileName); // This message is used by Android GUI to reset cached passwords.
Cmd->Password.Clean(); // Update appropriate code if changed.
uiMsg(UIERROR_BADPSW,Arc.FileName,ArcFileName);
// Avoid new requests for unrar.dll to prevent the infinite loop }
// if app always returns the same password. else // For passwords entered manually.
#ifndef RARDLL {
continue; // Request a password again. // This message is used by Android GUI and Windows GUI and SFX to
#endif // 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,
// we should not replace it with less precise ERAR_BAD_PASSWORD.
if (Cmd->DllError!=ERAR_EOPEN)
Cmd->DllError=ERAR_BAD_PASSWORD;
#endif
ErrHandler.SetErrorCode(RARX_BADPWD);
ExtrFile=false;
} }
#ifdef RARDLL break;
// If we already have ERAR_EOPEN as result of missing volume,
// we should not replace it with less precise ERAR_BAD_PASSWORD.
if (Cmd->DllError!=ERAR_EOPEN)
Cmd->DllError=ERAR_BAD_PASSWORD;
#endif
ErrHandler.SetErrorCode(RARX_BADPWD);
ExtrFile=false;
} }
break;
} }
else
DataIO.SetEncryption(false,CRYPT_NONE,NULL,NULL,NULL,0,NULL,NULL);
#ifdef RARDLL #ifdef RARDLL
if (*Cmd->DllDestName!=0) if (*Cmd->DllDestName!=0)
wcsncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName)); wcsncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName));
#endif #endif
if (ExtrFile && Command!='P' && !Cmd->Test && !Cmd->AbsoluteLinks &&
ConvertSymlinkPaths)
ExtrFile=LinksToDirs(DestFileName,Cmd->ExtrPath,LastCheckedSymlink);
File CurFile; File CurFile;
bool LinkEntry=Arc.FileHead.RedirType!=FSREDIR_NONE; bool LinkEntry=Arc.FileHead.RedirType!=FSREDIR_NONE;
if (LinkEntry && Arc.FileHead.RedirType!=FSREDIR_FILECOPY) if (LinkEntry && (Arc.FileHead.RedirType!=FSREDIR_FILECOPY))
{ {
if (ExtrFile && Command!='P' && !Cmd->Test) if (ExtrFile && Command!='P' && !Cmd->Test)
{ {
// Overwrite prompt for symbolic and hard links. // Overwrite prompt for symbolic and hard links and when we move
// a temporary file to the file reference instead of copying it.
bool UserReject=false; bool UserReject=false;
if (FileExist(DestFileName) && !UserReject) if (FileExist(DestFileName) && !UserReject)
FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime); FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime);
@ -632,7 +760,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
uint64 Preallocated=0; uint64 Preallocated=0;
if (!TestMode && !Arc.BrokenHeader && Arc.FileHead.UnpSize>1000000 && if (!TestMode && !Arc.BrokenHeader && Arc.FileHead.UnpSize>1000000 &&
Arc.FileHead.PackSize*1024>Arc.FileHead.UnpSize && Arc.FileHead.PackSize*1024>Arc.FileHead.UnpSize && Arc.IsSeekable() &&
(Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize)) (Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize))
{ {
CurFile.Prealloc(Arc.FileHead.UnpSize); CurFile.Prealloc(Arc.FileHead.UnpSize);
@ -650,23 +778,51 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
if (Type==FSREDIR_HARDLINK || Type==FSREDIR_FILECOPY) if (Type==FSREDIR_HARDLINK || Type==FSREDIR_FILECOPY)
{ {
wchar RedirName[NM];
// 2022.11.15: Might be needed when unpacking WinRAR 5.0 links with
// Unix RAR. WinRAR 5.0 used \ path separators here, when beginning
// from 5.10 even Windows version uses / internally and converts
// them to \ when reading FHEXTRA_REDIR.
// We must perform this conversion before ConvertPath call,
// so paths mixing different slashes like \dir1/dir2\file are
// processed correctly.
SlashToNative(Arc.FileHead.RedirName,RedirName,ASIZE(RedirName));
ConvertPath(RedirName,RedirName,ASIZE(RedirName));
wchar NameExisting[NM]; wchar NameExisting[NM];
ExtrPrepareName(Arc,Arc.FileHead.RedirName,NameExisting,ASIZE(NameExisting)); ExtrPrepareName(Arc,RedirName,NameExisting,ASIZE(NameExisting));
if (FileCreateMode && *NameExisting!=0) // *NameExisting can be 0 in case of excessive -ap switch. if (FileCreateMode && *NameExisting!=0) // *NameExisting can be 0 in case of excessive -ap switch.
if (Type==FSREDIR_HARDLINK) if (Type==FSREDIR_HARDLINK)
LinkSuccess=ExtractHardlink(Cmd,DestFileName,NameExisting,ASIZE(NameExisting)); LinkSuccess=ExtractHardlink(Cmd,DestFileName,NameExisting,ASIZE(NameExisting));
else else
LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,DestFileName,NameExisting,ASIZE(NameExisting)); LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,RedirName,DestFileName,NameExisting,ASIZE(NameExisting),Arc.FileHead.UnpSize);
} }
else else
if (Type==FSREDIR_UNIXSYMLINK || Type==FSREDIR_WINSYMLINK || Type==FSREDIR_JUNCTION) if (Type==FSREDIR_UNIXSYMLINK || Type==FSREDIR_WINSYMLINK || Type==FSREDIR_JUNCTION)
{ {
if (FileCreateMode) if (FileCreateMode)
LinkSuccess=ExtractSymlink(Cmd,DataIO,Arc,DestFileName); {
bool UpLink;
LinkSuccess=ExtractSymlink(Cmd,DataIO,Arc,DestFileName,UpLink);
ConvertSymlinkPaths|=LinkSuccess && UpLink;
// We do not actually need to reset the cache here if we cache
// only the single last checked path, because at this point
// it will always contain the link own path and link can't
// overwrite its parent folder. But if we ever decide to cache
// several already checked paths, we'll need to reset them here.
// Otherwise if no files were created in one of such paths,
// let's say because of file create error, it might be possible
// to overwrite the path with link and avoid checks. We keep this
// code here as a reminder in case of possible modifications.
LastCheckedSymlink.clear(); // Reset cache for safety reason.
}
} }
else else
{ {
uiMsg(UIERROR_UNKNOWNEXTRA,Arc.FileName,DestFileName); uiMsg(UIERROR_UNKNOWNEXTRA,Arc.FileName,ArcFileName);
LinkSuccess=false; LinkSuccess=false;
} }
@ -690,6 +846,7 @@ bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat)
Unp->Init(Arc.FileHead.WinSize,Arc.FileHead.Solid); Unp->Init(Arc.FileHead.WinSize,Arc.FileHead.Solid);
Unp->SetDestSize(Arc.FileHead.UnpSize); Unp->SetDestSize(Arc.FileHead.UnpSize);
#ifndef SFX_MODULE #ifndef SFX_MODULE
// RAR 1.3 - 1.5 archives do not set per file solid flag.
if (Arc.Format!=RARFMT50 && Arc.FileHead.UnpVer<=15) if (Arc.Format!=RARFMT50 && Arc.FileHead.UnpVer<=15)
Unp->DoUnpack(15,FileCount>1 && Arc.Solid); Unp->DoUnpack(15,FileCount>1 && Arc.Solid);
else else
@ -847,22 +1004,64 @@ void CmdExtract::UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize)
} }
bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize) bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,const wchar *RedirName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize,int64 UnpSize)
{ {
SlashToNative(NameExisting,NameExisting,NameExistingSize); // Not needed for RAR 5.1+ archives.
File Existing; File Existing;
if (!Existing.WOpen(NameExisting)) if (!Existing.Open(NameExisting))
{ {
uiMsg(UIERROR_FILECOPY,ArcName,NameExisting,NameNew); bool OpenFailed=true;
uiMsg(UIERROR_FILECOPYHINT,ArcName); // If we couldn't find the existing file, check if match is present
// in temporary reference sources list.
for (size_t I=0;I<RefList.Size();I++)
if (wcscmp(RedirName,RefList[I].RefName)==0 && RefList[I].TmpName!=NULL)
{
// If only one reference left targeting to this temporary file,
// it is faster to move the file instead of copying and deleting it.
bool RefMove=RefList[I].RefCount-- == 1;
NameExisting=RefList[I].TmpName;
if (RefMove) // Only one reference left for this temporary file.
{
New.Delete(); // Delete the previously opened destination file.
// Try moving the file first.
bool MoveFailed=!RenameFile(NameExisting,NameNew);
if (MoveFailed)
{
// If move failed, re-create the destination and try coping.
if (!New.WCreate(NameNew,FMF_WRITE|FMF_SHAREREAD))
return false;
RefMove=false; // Try copying below.
}
else
{
// If moved successfully, reopen the destination file and seek to
// end for SetOpenFileTime() and possible Truncate() calls later.
if (New.Open(NameNew))
New.Seek(0,SEEK_END);
// We already moved the file, so clean the name to not try
// deleting non-existent temporary file later.
free(RefList[I].TmpName);
RefList[I].TmpName=NULL;
return true;
}
}
if (!RefMove)
OpenFailed=!Existing.Open(NameExisting);
break;
}
if (OpenFailed)
{
ErrHandler.OpenErrorMsg(NameExisting);
uiMsg(UIERROR_FILECOPY,ArcName,NameExisting,NameNew);
uiMsg(UIERROR_FILECOPYHINT,ArcName);
#ifdef RARDLL #ifdef RARDLL
Cmd->DllError=ERAR_EREFERENCE; Cmd->DllError=ERAR_EREFERENCE;
#endif #endif
return false; return false;
}
} }
Array<char> Buffer(0x100000); Array<byte> Buffer(0x100000);
int64 CopySize=0; int64 CopySize=0;
while (true) while (true)
@ -871,6 +1070,10 @@ bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *
int ReadSize=Existing.Read(&Buffer[0],Buffer.Size()); int ReadSize=Existing.Read(&Buffer[0],Buffer.Size());
if (ReadSize==0) if (ReadSize==0)
break; break;
// Update only the current file progress in WinRAR, set the total to 0
// to keep it as is. It looks better for WinRAR.
uiExtractProgress(CopySize,UnpSize,0,0);
New.Write(&Buffer[0],ReadSize); New.Write(&Buffer[0],ReadSize);
CopySize+=ReadSize; CopySize+=ReadSize;
} }
@ -881,6 +1084,16 @@ bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *
void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize) void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize)
{ {
if (Cmd->Test)
{
// Destination name conversion isn't needed for simple archive test.
// This check also allows to avoid issuing "Attempting to correct...
// Renaming..." messages in MakeNameCompatible() below for problematic
// names like aux.txt when testing an archive.
wcsncpyz(DestName,ArcFileName,DestSize);
return;
}
wcsncpyz(DestName,Cmd->ExtrPath,DestSize); wcsncpyz(DestName,Cmd->ExtrPath,DestSize);
if (*Cmd->ExtrPath!=0) if (*Cmd->ExtrPath!=0)
@ -888,6 +1101,8 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De
wchar LastChar=*PointToLastChar(Cmd->ExtrPath); wchar LastChar=*PointToLastChar(Cmd->ExtrPath);
// We need IsPathDiv check here to correctly handle Unix forward slash // We need IsPathDiv check here to correctly handle Unix forward slash
// in the end of destination path in Windows: rar x arc dest/ // in the end of destination path in Windows: rar x arc dest/
// so we call IsPathDiv first instead of just calling AddEndSlash,
// which checks for only one type of path separator.
// IsDriveDiv is needed for current drive dir: rar x arc d: // IsDriveDiv is needed for current drive dir: rar x arc d:
if (!IsPathDiv(LastChar) && !IsDriveDiv(LastChar)) if (!IsPathDiv(LastChar) && !IsDriveDiv(LastChar))
{ {
@ -919,19 +1134,13 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De
#endif #endif
#ifndef SFX_MODULE #ifndef SFX_MODULE
size_t ArcPathLength=wcslen(Cmd->ArcPath); wchar *ArcPath=*Cmd->ExclArcPath!=0 ? Cmd->ExclArcPath:Cmd->ArcPath;
size_t ArcPathLength=wcslen(ArcPath);
if (ArcPathLength>0) if (ArcPathLength>0)
{ {
size_t NameLength=wcslen(ArcFileName); size_t NameLength=wcslen(ArcFileName);
if (NameLength>=ArcPathLength && wcsnicompc(ArcPath,ArcFileName,ArcPathLength)==0 &&
// Earlier we compared lengths only here, but then noticed a cosmetic bug (IsPathDiv(ArcPath[ArcPathLength-1]) ||
// in WinRAR. When extracting a file reference from subfolder with
// "Extract relative paths", so WinRAR sets ArcPath, if reference target
// is missing, error message removed ArcPath both from reference and target
// names. If target was stored in another folder, its name looked wrong.
if (NameLength>=ArcPathLength &&
wcsnicompc(Cmd->ArcPath,ArcFileName,ArcPathLength)==0 &&
(IsPathDiv(Cmd->ArcPath[ArcPathLength-1]) ||
IsPathDiv(ArcFileName[ArcPathLength]) || ArcFileName[ArcPathLength]==0)) IsPathDiv(ArcFileName[ArcPathLength]) || ArcFileName[ArcPathLength]==0))
{ {
ArcFileName+=Min(ArcPathLength,NameLength); ArcFileName+=Min(ArcPathLength,NameLength);
@ -964,7 +1173,7 @@ void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *De
// Must do after Cmd->ArcPath processing above, so file name and arc path // Must do after Cmd->ArcPath processing above, so file name and arc path
// trailing spaces are in sync. // trailing spaces are in sync.
if (!Cmd->AllowIncompatNames) if (!Cmd->AllowIncompatNames)
MakeNameCompatible(DestName); MakeNameCompatible(DestName,DestSize);
#endif #endif
wchar DiskLetter=toupperw(DestName[0]); wchar DiskLetter=toupperw(DestName[0]);
@ -1018,18 +1227,14 @@ bool CmdExtract::ExtrDllGetPassword()
#ifndef RARDLL #ifndef RARDLL
bool CmdExtract::ExtrGetPassword(Archive &Arc,const wchar *ArcFileName) bool CmdExtract::ExtrGetPassword(Archive &Arc,const wchar *ArcFileName,RarCheckPassword *CheckPwd)
{ {
if (!Cmd->Password.IsSet()) if (!Cmd->Password.IsSet())
{ {
if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password)/* || !Cmd->Password.IsSet()*/) if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password,CheckPwd)/* || !Cmd->Password.IsSet()*/)
{ {
// Suppress "test is ok" message if user cancelled the password prompt. // 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, uiMsg(UIERROR_INCERRCOUNT);
// 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; return false;
} }
Cmd->ManualPassword=true; Cmd->ManualPassword=true;
@ -1044,7 +1249,7 @@ bool CmdExtract::ExtrGetPassword(Archive &Arc,const wchar *ArcFileName)
case -1: case -1:
ErrHandler.Exit(RARX_USERBREAK); ErrHandler.Exit(RARX_USERBREAK);
case 2: case 2:
if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password)) if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password,CheckPwd))
return false; return false;
break; break;
case 3: case 3:
@ -1120,6 +1325,8 @@ void CmdExtract::ExtrCreateDir(Archive &Arc,const wchar *ArcFileName)
DirExist=FileExist(DestFileName) && IsDir(GetFileAttr(DestFileName)); DirExist=FileExist(DestFileName) && IsDir(GetFileAttr(DestFileName));
if (!DirExist) if (!DirExist)
{ {
if (!Cmd->AbsoluteLinks && ConvertSymlinkPaths)
LinksToDirs(DestFileName,Cmd->ExtrPath,LastCheckedSymlink);
CreatePath(DestFileName,true,Cmd->DisableNames); CreatePath(DestFileName,true,Cmd->DisableNames);
MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr); MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr);
} }
@ -1201,6 +1408,8 @@ bool CmdExtract::ExtrCreateFile(Archive &Arc,File &CurFile)
MakeNameUsable(DestFileName,true); MakeNameUsable(DestFileName,true);
if (!Cmd->AbsoluteLinks && ConvertSymlinkPaths)
LinksToDirs(DestFileName,Cmd->ExtrPath,LastCheckedSymlink);
CreatePath(DestFileName,true,Cmd->DisableNames); CreatePath(DestFileName,true,Cmd->DisableNames);
if (FileCreate(Cmd,&CurFile,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,true)) if (FileCreate(Cmd,&CurFile,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,true))
{ {
@ -1247,31 +1456,59 @@ bool CmdExtract::CheckUnpVer(Archive &Arc,const wchar *ArcFileName)
#ifndef SFX_MODULE #ifndef SFX_MODULE
// To speed up solid volumes extraction, try to find a non-first start volume, // Find non-matched reference sources in solid and non-solid archives.
// which still allows to unpack all files. It is possible for independent // Detect the optimal start position for semi-solid archives
// solid volumes with solid statistics reset in the beginning. // and optimal start volume for independent solid volumes.
bool CmdExtract::DetectStartVolume(const wchar *VolName,bool NewNumbering) //
// Alternatively we could collect references while extracting an archive
// and perform the second extraction pass for references only.
// But it would be slower for solid archives than scaning headers
// in first pass and extracting everything in second, as implemented now.
//
void CmdExtract::AnalyzeArchive(const wchar *ArcName,bool Volume,bool NewNumbering)
{ {
FreeAnalyzeData(); // If processing non-first archive in multiple archives set.
wchar *ArgName=Cmd->FileArgs.GetString(); wchar *ArgName=Cmd->FileArgs.GetString();
Cmd->FileArgs.Rewind(); Cmd->FileArgs.Rewind();
if (ArgName!=NULL && (wcscmp(ArgName,L"*")==0 || wcscmp(ArgName,L"*.*")==0)) if (ArgName!=NULL && (wcscmp(ArgName,L"*")==0 || wcscmp(ArgName,L"*.*")==0))
return false; // No need to check further for * and *.* masks. return; // No need to check further for * and *.* masks.
wchar StartName[NM];
*StartName=0;
// Start search from first volume if all volumes preceding current are available. // Start search from first volume if all volumes preceding current are available.
wchar NextName[NM]; wchar NextName[NM];
GetFirstVolIfFullSet(VolName,NewNumbering,NextName,ASIZE(NextName)); if (Volume)
GetFirstVolIfFullSet(ArcName,NewNumbering,NextName,ASIZE(NextName));
else
wcsncpyz(NextName,ArcName,ASIZE(NextName));
bool MatchFound=false;
bool PrevMatched=false;
bool OpenNext=false;
bool FirstVolume=true;
// We shall set FirstFile once for all volumes and not for each volume.
// So we do not reuse the outdated Analyze->StartPos from previous volume
// if extracted file resides completely in the beginning of current one.
bool FirstFile=true;
bool Matched=false; while (true)
while (!Matched)
{ {
Archive Arc(Cmd); Archive Arc(Cmd);
if (!Arc.Open(NextName) || !Arc.IsArchive(false) || !Arc.Volume) if (!Arc.Open(NextName) || !Arc.IsArchive(false))
{
if (OpenNext)
{
// If we couldn't open trailing volumes, we can't set early exit
// parameters. It is possible that some volume are on removable media
// and will be provided by user when extracting.
*Analyze->EndName=0;
Analyze->EndPos=0;
}
break; break;
}
bool OpenNext=false; OpenNext=false;
while (Arc.ReadHeader()>0) while (Arc.ReadHeader()>0)
{ {
Wait(); Wait();
@ -1284,17 +1521,88 @@ bool CmdExtract::DetectStartVolume(const wchar *VolName,bool NewNumbering)
} }
if (HeaderType==HEAD_FILE) if (HeaderType==HEAD_FILE)
{ {
if ((Arc.Format==RARFMT14 || Arc.Format==RARFMT15) && Arc.FileHead.UnpVer<=15)
{
// RAR versions earlier than 2.0 do not set per file solid flag.
// They have only the global archive solid flag, so we can't
// reliably analyze them here.
OpenNext=false;
break;
}
if (!Arc.FileHead.SplitBefore) if (!Arc.FileHead.SplitBefore)
{ {
if (!Arc.FileHead.Solid) // Can start extraction from here. if (!MatchFound && !Arc.FileHead.Solid) // Can start extraction from here.
wcsncpyz(StartName,NextName,ASIZE(StartName)); {
// We would gain nothing and unnecessarily complicate extraction
// if we set StartName for first volume or StartPos for first
// archived file.
if (!FirstVolume)
wcsncpyz(Analyze->StartName,NextName,ASIZE(Analyze->StartName));
// We shall set FirstFile once for all volumes for this code
// to work properly. Alternatively we could append
// "|| Analyze->StartPos!=0" to the condition, so we do not reuse
// the outdated Analyze->StartPos value from previous volume.
if (!FirstFile)
Analyze->StartPos=Arc.CurBlockPos;
}
if (Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0) if (Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0)
{ {
Matched=true; // First matched file found, must stop further scan. MatchFound = true;
break; PrevMatched = true;
// Reset the previously set early exit position, if any, because
// we found a new matched file.
Analyze->EndPos=0;
// Matched file reference pointing at maybe non-matched source file.
// Even though we know RedirName, we can't check if source file
// is certainly non-matched, because it can be filtered out by
// date or attributes, which we do not know here.
if (Arc.FileHead.RedirType==FSREDIR_FILECOPY)
{
bool AlreadyAdded=false;
for (size_t I=0;I<RefList.Size();I++)
if (wcscmp(Arc.FileHead.RedirName,RefList[I].RefName)==0)
{
// Increment the reference count if we added such reference
// source earlier.
RefList[I].RefCount++;
AlreadyAdded=true;
break;
}
// Limit the maximum size of reference sources list to some
// sensible value to prevent the excessive memory allocation.
size_t MaxListSize=1000000;
if (!AlreadyAdded && RefList.Size()<MaxListSize)
{
ExtractRef Ref={0};
Ref.RefName=wcsdup(Arc.FileHead.RedirName);
Ref.RefCount=1;
RefList.Push(Ref);
}
}
}
else
{
if (PrevMatched) // First non-matched item after matched.
{
// We would perform the unnecessarily string comparison
// when extracting if we set this value for first volume
// or non-volume archive.
if (!FirstVolume)
wcsncpyz(Analyze->EndName,NextName,ASIZE(Analyze->EndName));
Analyze->EndPos=Arc.CurBlockPos;
}
PrevMatched=false;
} }
} }
FirstFile=false;
if (Arc.FileHead.SplitAfter) if (Arc.FileHead.SplitAfter)
{ {
OpenNext=true; // Allow open next volume. OpenNext=true; // Allow open next volume.
@ -1305,16 +1613,25 @@ bool CmdExtract::DetectStartVolume(const wchar *VolName,bool NewNumbering)
} }
Arc.Close(); Arc.Close();
if (!OpenNext) if (Volume && OpenNext)
break; {
NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering);
FirstVolume=false;
NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering); // Needed for multivolume archives. Added in case some 'break'
// will quit early from loop above, so we do not set it in the loop.
// Now it can happen for hypothetical archive without file records
// and with HEAD_ENDARC record.
FirstFile=false;
}
else
break;
} }
bool NewStartFound=wcscmp(VolName,StartName)!=0;
if (NewStartFound) // Found a new volume to start extraction. // If file references are present, we can't reliably skip in semi-solid
wcsncpyz(ArcName,StartName,ASIZE(ArcName)); // archives, because reference source can be present in skipped data.
if (RefList.Size()!=0)
return NewStartFound; memset(Analyze,0,sizeof(*Analyze));
} }
#endif #endif

@ -6,13 +6,32 @@ enum EXTRACT_ARC_CODE {EXTRACT_ARC_NEXT,EXTRACT_ARC_REPEAT};
class CmdExtract class CmdExtract
{ {
private: private:
struct ExtractRef
{
wchar *RefName;
wchar *TmpName;
uint64 RefCount;
};
Array<ExtractRef> RefList;
struct AnalyzeData
{
wchar StartName[NM];
uint64 StartPos;
wchar EndName[NM];
uint64 EndPos;
} *Analyze;
bool ArcAnalyzed;
void FreeAnalyzeData();
EXTRACT_ARC_CODE ExtractArchive(); EXTRACT_ARC_CODE ExtractArchive();
bool ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize); bool ExtractFileCopy(File &New,wchar *ArcName,const wchar *RedirName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize,int64 UnpSize);
void ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize); void ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize);
#ifdef RARDLL #ifdef RARDLL
bool ExtrDllGetPassword(); bool ExtrDllGetPassword();
#else #else
bool ExtrGetPassword(Archive &Arc,const wchar *ArcFileName); bool ExtrGetPassword(Archive &Arc,const wchar *ArcFileName,RarCheckPassword *CheckPwd);
#endif #endif
#if defined(_WIN_ALL) && !defined(SFX_MODULE) #if defined(_WIN_ALL) && !defined(SFX_MODULE)
void ConvertDosPassword(Archive &Arc,SecPassword &DestPwd); void ConvertDosPassword(Archive &Arc,SecPassword &DestPwd);
@ -21,7 +40,7 @@ class CmdExtract
bool ExtrCreateFile(Archive &Arc,File &CurFile); bool ExtrCreateFile(Archive &Arc,File &CurFile);
bool CheckUnpVer(Archive &Arc,const wchar *ArcFileName); bool CheckUnpVer(Archive &Arc,const wchar *ArcFileName);
#ifndef SFX_MODULE #ifndef SFX_MODULE
bool DetectStartVolume(const wchar *VolName,bool NewNumbering); void AnalyzeArchive(const wchar *ArcName,bool Volume,bool NewNumbering);
void GetFirstVolIfFullSet(const wchar *SrcName,bool NewNumbering,wchar *DestName,size_t DestSize); void GetFirstVolIfFullSet(const wchar *SrcName,bool NewNumbering,wchar *DestName,size_t DestSize);
#endif #endif
@ -52,6 +71,15 @@ class CmdExtract
bool PrevProcessed; // If previous file was successfully extracted or tested. bool PrevProcessed; // If previous file was successfully extracted or tested.
wchar DestFileName[NM]; wchar DestFileName[NM];
bool PasswordCancelled; bool PasswordCancelled;
// In Windows it is set to true if at least one symlink with ".."
// in target was extracted.
bool ConvertSymlinkPaths;
// Last path checked for symlinks. We use it to improve the performance,
// so we do not check recently checked folders again.
std::wstring LastCheckedSymlink;
#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT) #if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT)
bool Fat32,NotFat32; bool Fat32,NotFat32;
#endif #endif

@ -1,9 +1,9 @@
#include "rar.hpp" #include "rar.hpp"
// If NewFile==NULL, we delete created file after user confirmation. // If NewFile==NULL, we delete created file after user confirmation.
// It is useful we we need to overwrite an existing folder or file, // It is useful if we need to overwrite an existing folder or file,
// but need user confirmation for that. // but need user confirmation for that.
bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize, bool FileCreate(CommandData *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
bool *UserReject,int64 FileSize,RarTime *FileTime,bool WriteOnly) bool *UserReject,int64 FileSize,RarTime *FileTime,bool WriteOnly)
{ {
if (UserReject!=NULL) if (UserReject!=NULL)
@ -44,7 +44,9 @@ bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
} }
// Try to truncate the existing file first instead of delete, // Try to truncate the existing file first instead of delete,
// so we preserve existing file permissions such as NTFS permissions. // so we preserve existing file permissions, such as NTFS permissions,
// also as "Compressed" attribute and hard links. In GUI version we avoid
// deleting an existing file for non-.rar archive formats as well.
uint FileMode=WriteOnly ? FMF_WRITE|FMF_SHAREREAD:FMF_UPDATE|FMF_SHAREREAD; uint FileMode=WriteOnly ? FMF_WRITE|FMF_SHAREREAD:FMF_UPDATE|FMF_SHAREREAD;
if (NewFile!=NULL && NewFile->Create(Name,FileMode)) if (NewFile!=NULL && NewFile->Create(Name,FileMode))
return true; return true;

@ -1,7 +1,7 @@
#ifndef _RAR_FILECREATE_ #ifndef _RAR_FILECREATE_
#define _RAR_FILECREATE_ #define _RAR_FILECREATE_
bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize, bool FileCreate(CommandData *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize,
bool *UserReject,int64 FileSize=INT64NDF, bool *UserReject,int64 FileSize=INT64NDF,
RarTime *FileTime=NULL,bool WriteOnly=false); RarTime *FileTime=NULL,bool WriteOnly=false);

102
deps/unrar/file.cpp vendored

@ -7,6 +7,7 @@ File::File()
NewFile=false; NewFile=false;
LastWrite=false; LastWrite=false;
HandleType=FILE_HANDLENORMAL; HandleType=FILE_HANDLENORMAL;
LineInput=false;
SkipClose=false; SkipClose=false;
ErrorType=FILE_SUCCESS; ErrorType=FILE_SUCCESS;
OpenShared=false; OpenShared=false;
@ -14,11 +15,11 @@ File::File()
AllowExceptions=true; AllowExceptions=true;
PreserveAtime=false; PreserveAtime=false;
#ifdef _WIN_ALL #ifdef _WIN_ALL
NoSequentialRead=false;
CreateMode=FMF_UNDEFINED; CreateMode=FMF_UNDEFINED;
#endif #endif
ReadErrorMode=FREM_ASK; ReadErrorMode=FREM_ASK;
TruncatedAfterReadError=false; TruncatedAfterReadError=false;
CurFilePos=0;
} }
@ -58,7 +59,7 @@ bool File::Open(const wchar *Name,uint Mode)
uint ShareMode=(Mode & FMF_OPENEXCLUSIVE) ? 0 : FILE_SHARE_READ; uint ShareMode=(Mode & FMF_OPENEXCLUSIVE) ? 0 : FILE_SHARE_READ;
if (OpenShared) if (OpenShared)
ShareMode|=FILE_SHARE_WRITE; ShareMode|=FILE_SHARE_WRITE;
uint Flags=NoSequentialRead ? 0:FILE_FLAG_SEQUENTIAL_SCAN; uint Flags=FILE_FLAG_SEQUENTIAL_SCAN;
FindData FD; FindData FD;
if (PreserveAtime) if (PreserveAtime)
Access|=FILE_WRITE_ATTRIBUTES; // Needed to preserve atime. Access|=FILE_WRITE_ATTRIBUTES; // Needed to preserve atime.
@ -379,10 +380,11 @@ int File::Read(void *Data,size_t Size)
if (ReadErrorMode==FREM_IGNORE) if (ReadErrorMode==FREM_IGNORE)
FilePos=Tell(); FilePos=Tell();
int ReadSize; int TotalRead=0;
while (true) while (true)
{ {
ReadSize=DirectRead(Data,Size); int ReadSize=DirectRead(Data,Size);
if (ReadSize==-1) if (ReadSize==-1)
{ {
ErrorType=FILE_READERROR; ErrorType=FILE_READERROR;
@ -396,6 +398,8 @@ int File::Read(void *Data,size_t Size)
size_t SizeToRead=Min(Size-I,512); size_t SizeToRead=Min(Size-I,512);
int ReadCode=DirectRead(Data,SizeToRead); int ReadCode=DirectRead(Data,SizeToRead);
ReadSize+=(ReadCode==-1) ? 512:ReadCode; ReadSize+=(ReadCode==-1) ? 512:ReadCode;
if (ReadSize!=-1)
TotalRead+=ReadSize;
} }
} }
else else
@ -415,9 +419,28 @@ int File::Read(void *Data,size_t Size)
ErrHandler.ReadError(FileName); ErrHandler.ReadError(FileName);
} }
} }
TotalRead+=ReadSize; // If ReadSize is -1, TotalRead is also set to -1 here.
if (HandleType==FILE_HANDLESTD && !LineInput && ReadSize>0 && (uint)ReadSize<Size)
{
// Unlike regular files, for pipe we can read only as much as was
// written at the other end of pipe. We had seen data coming in small
// ~80 byte chunks when piping from 'type arc.rar'. Extraction code
// would fail if we read an incomplete archive header from stdin.
// So here we ensure that requested size is completely read.
// But we return the available data immediately in "line input" mode,
// when processing user's input in console prompts. Otherwise apps
// piping user responses to multiple Ask() prompts can hang if no more
// data is available yet and pipe isn't closed.
Data=(byte*)Data+ReadSize;
Size-=ReadSize;
continue;
}
break; break;
} }
return ReadSize; // It can return -1 only if AllowExceptions is disabled. if (TotalRead>0) // Can be -1 for error and AllowExceptions disabled.
CurFilePos+=TotalRead;
return TotalRead; // It can return -1 only if AllowExceptions is disabled.
} }
@ -499,6 +522,36 @@ bool File::RawSeek(int64 Offset,int Method)
{ {
if (hFile==FILE_BAD_HANDLE) if (hFile==FILE_BAD_HANDLE)
return true; return true;
if (!IsSeekable()) // To extract archives from stdin with -si.
{
// We tried to dynamically allocate 32 KB buffer here, but it improved
// speed in Windows 10 by mere ~1.5%.
byte Buf[4096];
if (Method==SEEK_CUR || Method==SEEK_SET && Offset>=CurFilePos)
{
uint64 SkipSize=Method==SEEK_CUR ? Offset:Offset-CurFilePos;
while (SkipSize>0) // Reading to emulate seek forward.
{
int ReadSize=Read(Buf,(size_t)Min(SkipSize,ASIZE(Buf)));
if (ReadSize<=0)
return false;
SkipSize-=ReadSize;
CurFilePos+=ReadSize;
}
return true;
}
// May need it in FileLength() in Archive::UnexpEndArcMsg() when unpacking
// RAR 4.x archives without the end of archive block created with -en.
if (Method==SEEK_END)
{
int ReadSize;
while ((ReadSize=Read(Buf,ASIZE(Buf)))>0)
CurFilePos+=ReadSize;
return true;
}
return false; // Backward seek on unseekable file.
}
if (Offset<0 && Method!=SEEK_SET) if (Offset<0 && Method!=SEEK_SET)
{ {
Offset=(Method==SEEK_CUR ? Tell():FileLength())+Offset; Offset=(Method==SEEK_CUR ? Tell():FileLength())+Offset;
@ -533,6 +586,8 @@ int64 File::Tell()
ErrHandler.SeekError(FileName); ErrHandler.SeekError(FileName);
else else
return -1; return -1;
if (!IsSeekable())
return CurFilePos;
#ifdef _WIN_ALL #ifdef _WIN_ALL
LONG HighDist=0; LONG HighDist=0;
uint LowDist=SetFilePointer(hFile,0,&HighDist,FILE_CURRENT); uint LowDist=SetFilePointer(hFile,0,&HighDist,FILE_CURRENT);
@ -683,17 +738,40 @@ void File::SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta)
} }
void File::GetOpenFileTime(RarTime *ft) #ifdef _UNIX
void File::StatToRarTime(struct stat &st,RarTime *ftm,RarTime *ftc,RarTime *fta)
{ {
#ifdef _WIN_ALL #ifdef UNIX_TIME_NS
FILETIME FileTime; #if defined(_APPLE)
GetFileTime(hFile,NULL,NULL,&FileTime); if (ftm!=NULL) ftm->SetUnixNS(st.st_mtimespec.tv_sec*(uint64)1000000000+st.st_mtimespec.tv_nsec);
ft->SetWinFT(&FileTime); if (ftc!=NULL) ftc->SetUnixNS(st.st_ctimespec.tv_sec*(uint64)1000000000+st.st_ctimespec.tv_nsec);
if (fta!=NULL) fta->SetUnixNS(st.st_atimespec.tv_sec*(uint64)1000000000+st.st_atimespec.tv_nsec);
#else
if (ftm!=NULL) ftm->SetUnixNS(st.st_mtim.tv_sec*(uint64)1000000000+st.st_mtim.tv_nsec);
if (ftc!=NULL) ftc->SetUnixNS(st.st_ctim.tv_sec*(uint64)1000000000+st.st_ctim.tv_nsec);
if (fta!=NULL) fta->SetUnixNS(st.st_atim.tv_sec*(uint64)1000000000+st.st_atim.tv_nsec);
#endif
#else
if (ftm!=NULL) ftm->SetUnix(st.st_mtime);
if (ftc!=NULL) ftc->SetUnix(st.st_ctime);
if (fta!=NULL) fta->SetUnix(st.st_atime);
#endif #endif
#if defined(_UNIX) || defined(_EMX) }
#endif
void File::GetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta)
{
#ifdef _WIN_ALL
FILETIME ctime,atime,mtime;
GetFileTime(hFile,&ctime,&atime,&mtime);
if (ftm!=NULL) ftm->SetWinFT(&mtime);
if (ftc!=NULL) ftc->SetWinFT(&ctime);
if (fta!=NULL) fta->SetWinFT(&atime);
#elif defined(_UNIX)
struct stat st; struct stat st;
fstat(GetFD(),&st); fstat(GetFD(),&st);
ft->SetUnix(st.st_mtime); StatToRarTime(st,ftm,ftc,fta);
#endif #endif
} }

@ -14,8 +14,6 @@
#define FILE_BAD_HANDLE NULL #define FILE_BAD_HANDLE NULL
#endif #endif
class RAROptions;
enum FILE_HANDLETYPE {FILE_HANDLENORMAL,FILE_HANDLESTD}; enum FILE_HANDLETYPE {FILE_HANDLENORMAL,FILE_HANDLESTD};
enum FILE_ERRORTYPE {FILE_SUCCESS,FILE_NOTFOUND,FILE_READERROR}; enum FILE_ERRORTYPE {FILE_SUCCESS,FILE_NOTFOUND,FILE_READERROR};
@ -59,6 +57,16 @@ class File
FileHandle hFile; FileHandle hFile;
bool LastWrite; bool LastWrite;
FILE_HANDLETYPE HandleType; FILE_HANDLETYPE HandleType;
// If we read the user input in console prompts from stdin, we shall
// process the available line immediately, not waiting for rest of data.
// Otherwise apps piping user responses to multiple Ask() prompts can
// hang if no more data is available yet and pipe isn't closed.
// If we read RAR archive or other file data from stdin, we shall collect
// the entire requested block as long as pipe isn't closed, so we get
// complete archive headers, not split between different reads.
bool LineInput;
bool SkipClose; bool SkipClose;
FILE_READ_ERROR_MODE ReadErrorMode; FILE_READ_ERROR_MODE ReadErrorMode;
bool NewFile; bool NewFile;
@ -70,12 +78,17 @@ class File
#endif #endif
bool PreserveAtime; bool PreserveAtime;
bool TruncatedAfterReadError; bool TruncatedAfterReadError;
int64 CurFilePos; // Used for forward seeks in stdin files.
protected: protected:
bool OpenShared; // Set by 'Archive' class. bool OpenShared; // Set by 'Archive' class.
public: public:
wchar FileName[NM]; wchar FileName[NM];
FILE_ERRORTYPE ErrorType; FILE_ERRORTYPE ErrorType;
byte *SeekBuf; // To read instead of seek for stdin files.
static const size_t SeekBufSize=0x10000;
public: public:
File(); File();
virtual ~File(); virtual ~File();
@ -106,11 +119,16 @@ class File
void SetOpenFileTime(RarTime *ftm,RarTime *ftc=NULL,RarTime *fta=NULL); void SetOpenFileTime(RarTime *ftm,RarTime *ftc=NULL,RarTime *fta=NULL);
void SetCloseFileTime(RarTime *ftm,RarTime *fta=NULL); void SetCloseFileTime(RarTime *ftm,RarTime *fta=NULL);
static void SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta); static void SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta);
void GetOpenFileTime(RarTime *ft); #ifdef _UNIX
static void StatToRarTime(struct stat &st,RarTime *ftm,RarTime *ftc,RarTime *fta);
#endif
void GetOpenFileTime(RarTime *ftm,RarTime *ftc=NULL,RarTime *fta=NULL);
virtual bool IsOpened() {return hFile!=FILE_BAD_HANDLE;} // 'virtual' for MultiFile class. virtual bool IsOpened() {return hFile!=FILE_BAD_HANDLE;} // 'virtual' for MultiFile class.
int64 FileLength(); int64 FileLength();
void SetHandleType(FILE_HANDLETYPE Type) {HandleType=Type;} void SetHandleType(FILE_HANDLETYPE Type) {HandleType=Type;}
void SetLineInputMode(bool Mode) {LineInput=Mode;}
FILE_HANDLETYPE GetHandleType() {return HandleType;} FILE_HANDLETYPE GetHandleType() {return HandleType;}
bool IsSeekable() {return HandleType!=FILE_HANDLESTD;}
bool IsDevice(); bool IsDevice();
static bool RemoveCreated(); static bool RemoveCreated();
FileHandle GetHandle() {return hFile;} FileHandle GetHandle() {return hFile;}
@ -119,9 +137,6 @@ class File
int64 Copy(File &Dest,int64 Length=INT64NDF); int64 Copy(File &Dest,int64 Length=INT64NDF);
void SetAllowDelete(bool Allow) {AllowDelete=Allow;} void SetAllowDelete(bool Allow) {AllowDelete=Allow;}
void SetExceptions(bool Allow) {AllowExceptions=Allow;} void SetExceptions(bool Allow) {AllowExceptions=Allow;}
#ifdef _WIN_ALL
void RemoveSequentialFlag() {NoSequentialRead=true;}
#endif
void SetPreserveAtime(bool Preserve) {PreserveAtime=Preserve;} void SetPreserveAtime(bool Preserve) {PreserveAtime=Preserve;}
bool IsTruncatedAfterReadError() {return TruncatedAfterReadError;} bool IsTruncatedAfterReadError() {return TruncatedAfterReadError;}
#ifdef _UNIX #ifdef _UNIX

@ -320,7 +320,6 @@ bool SetFileAttr(const wchar *Name,uint Attr)
} }
#if 0
wchar *MkTemp(wchar *Name,size_t MaxSize) wchar *MkTemp(wchar *Name,size_t MaxSize)
{ {
size_t Length=wcslen(Name); size_t Length=wcslen(Name);
@ -354,7 +353,6 @@ wchar *MkTemp(wchar *Name,size_t MaxSize)
} }
return Name; return Name;
} }
#endif
#if !defined(SFX_MODULE) #if !defined(SFX_MODULE)
@ -397,7 +395,11 @@ void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,
{ {
#ifndef SILENT #ifndef SILENT
if ((Flags & CALCFSUM_SHOWPROGRESS)!=0) if ((Flags & CALCFSUM_SHOWPROGRESS)!=0)
uiExtractProgress(TotalRead,FileLength,TotalRead,FileLength); {
// Update only the current file progress in WinRAR, set the total to 0
// to keep it as is. It looks better for WinRAR.
uiExtractProgress(TotalRead,FileLength,0,0);
}
else else
{ {
if ((Flags & CALCFSUM_SHOWPERCENT)!=0) if ((Flags & CALCFSUM_SHOWPERCENT)!=0)
@ -517,6 +519,18 @@ bool SetFileCompression(const wchar *Name,bool State)
CloseHandle(hFile); CloseHandle(hFile);
return RetCode!=0; return RetCode!=0;
} }
void ResetFileCache(const wchar *Name)
{
// To reset file cache in Windows it is enough to open it with
// FILE_FLAG_NO_BUFFERING and then close it.
HANDLE hSrc=CreateFile(Name,GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,FILE_FLAG_NO_BUFFERING,NULL);
if (hSrc!=INVALID_HANDLE_VALUE)
CloseHandle(hSrc);
}
#endif #endif

@ -27,9 +27,7 @@ bool IsDeleteAllowed(uint FileAttr);
void PrepareToDelete(const wchar *Name); void PrepareToDelete(const wchar *Name);
uint GetFileAttr(const wchar *Name); uint GetFileAttr(const wchar *Name);
bool SetFileAttr(const wchar *Name,uint Attr); bool SetFileAttr(const wchar *Name,uint Attr);
#if 0
wchar* MkTemp(wchar *Name,size_t MaxSize); wchar* MkTemp(wchar *Name,size_t MaxSize);
#endif
enum CALCFSUM_FLAGS {CALCFSUM_SHOWTEXT=1,CALCFSUM_SHOWPERCENT=2,CALCFSUM_SHOWPROGRESS=4,CALCFSUM_CURPOS=8}; enum CALCFSUM_FLAGS {CALCFSUM_SHOWTEXT=1,CALCFSUM_SHOWPERCENT=2,CALCFSUM_SHOWPROGRESS=4,CALCFSUM_CURPOS=8};
@ -41,6 +39,7 @@ bool DelDir(const wchar *Name);
#if defined(_WIN_ALL) && !defined(SFX_MODULE) #if defined(_WIN_ALL) && !defined(SFX_MODULE)
bool SetFileCompression(const wchar *Name,bool State); bool SetFileCompression(const wchar *Name,bool State);
void ResetFileCache(const wchar *Name);
#endif #endif

@ -117,7 +117,7 @@ bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
if (hFind==INVALID_HANDLE_VALUE) if (hFind==INVALID_HANDLE_VALUE)
return false; return false;
FindClose(hFind); FindClose(hFind);
#else #elif defined(_UNIX)
char FindMaskA[NM]; char FindMaskA[NM];
WideToChar(FindMask,FindMaskA,ASIZE(FindMaskA)); WideToChar(FindMask,FindMaskA,ASIZE(FindMaskA));
@ -143,15 +143,7 @@ bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink)
fd->FileAttr=st.st_mode; fd->FileAttr=st.st_mode;
fd->Size=st.st_size; fd->Size=st.st_size;
#ifdef UNIX_TIME_NS File::StatToRarTime(st,&fd->mtime,&fd->ctime,&fd->atime);
fd->mtime.SetUnixNS(st.st_mtim.tv_sec*(uint64)1000000000+st.st_mtim.tv_nsec);
fd->atime.SetUnixNS(st.st_atim.tv_sec*(uint64)1000000000+st.st_atim.tv_nsec);
fd->ctime.SetUnixNS(st.st_ctim.tv_sec*(uint64)1000000000+st.st_ctim.tv_nsec);
#else
fd->mtime.SetUnix(st.st_mtime);
fd->atime.SetUnix(st.st_atime);
fd->ctime.SetUnix(st.st_ctime);
#endif
wcsncpyz(fd->Name,FindMask,ASIZE(fd->Name)); wcsncpyz(fd->Name,FindMask,ASIZE(fd->Name));
#endif #endif

@ -5,7 +5,7 @@ BitInput::BitInput(bool AllocBuffer)
ExternalBuffer=false; ExternalBuffer=false;
if (AllocBuffer) if (AllocBuffer)
{ {
// getbits32 attempts to read data from InAddr, ... InAddr+3 positions. // getbits*() attempt to read data from InAddr, ... InAddr+3 positions.
// So let's allocate 3 additional bytes for situation, when we need to // So let's allocate 3 additional bytes for situation, when we need to
// read only 1 byte from the last position of buffer and avoid a crash // read only 1 byte from the last position of buffer and avoid a crash
// from access to next 3 bytes, which contents we do not need. // from access to next 3 bytes, which contents we do not need.

@ -4,7 +4,7 @@
class BitInput class BitInput
{ {
public: public:
enum BufferSize {MAX_SIZE=0x50000}; // Size of input buffer. enum BufferSize {MAX_SIZE=0x8000}; // Size of input buffer.
int InAddr; // Curent byte position in the buffer. int InAddr; // Curent byte position in the buffer.
int InBit; // Current bit position in the current byte. int InBit; // Current bit position in the current byte.
@ -28,26 +28,38 @@ class BitInput
InAddr+=Bits>>3; InAddr+=Bits>>3;
InBit=Bits&7; InBit=Bits&7;
} }
// Return 16 bits from current position in the buffer. // Return 16 bits from current position in the buffer.
// Bit at (InAddr,InBit) has the highest position in returning data. // Bit at (InAddr,InBit) has the highest position in returning data.
uint getbits() uint getbits()
{ {
#if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED)
uint32 BitField=*(uint32*)(InBuf+InAddr);
BitField=ByteSwap32(BitField);
BitField >>= (16-InBit);
#else
uint BitField=(uint)InBuf[InAddr] << 16; uint BitField=(uint)InBuf[InAddr] << 16;
BitField|=(uint)InBuf[InAddr+1] << 8; BitField|=(uint)InBuf[InAddr+1] << 8;
BitField|=(uint)InBuf[InAddr+2]; BitField|=(uint)InBuf[InAddr+2];
BitField >>= (8-InBit); BitField >>= (8-InBit);
#endif
return BitField & 0xffff; return BitField & 0xffff;
} }
// Return 32 bits from current position in the buffer. // Return 32 bits from current position in the buffer.
// Bit at (InAddr,InBit) has the highest position in returning data. // Bit at (InAddr,InBit) has the highest position in returning data.
uint getbits32() uint getbits32()
{ {
#if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED)
uint32 BitField=*(uint32*)(InBuf+InAddr);
BitField=ByteSwap32(BitField);
#else
uint BitField=(uint)InBuf[InAddr] << 24; uint BitField=(uint)InBuf[InAddr] << 24;
BitField|=(uint)InBuf[InAddr+1] << 16; BitField|=(uint)InBuf[InAddr+1] << 16;
BitField|=(uint)InBuf[InAddr+2] << 8; BitField|=(uint)InBuf[InAddr+2] << 8;
BitField|=(uint)InBuf[InAddr+3]; BitField|=(uint)InBuf[InAddr+3];
#endif
BitField <<= InBit; BitField <<= InBit;
BitField|=(uint)InBuf[InAddr+4] >> (8-InBit); BitField|=(uint)InBuf[InAddr+4] >> (8-InBit);
return BitField & 0xffffffff; return BitField & 0xffffffff;

@ -1,6 +1,6 @@
#define INCLUDEGLOBAL #define INCLUDEGLOBAL
#if defined(__BORLANDC__) || defined(_MSC_VER) #ifdef _MSC_VER
#pragma hdrstop #pragma hdrstop
#endif #endif

@ -1,7 +1,5 @@
bool ExtractHardlink(CommandData *Cmd,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize) bool ExtractHardlink(CommandData *Cmd,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize)
{ {
SlashToNative(NameExisting,NameExisting,NameExistingSize); // Not needed for RAR 5.1+ archives.
if (!FileExist(NameExisting)) if (!FileExist(NameExisting))
{ {
uiMsg(UIERROR_HLINKCREATE,NameNew); uiMsg(UIERROR_HLINKCREATE,NameNew);

@ -26,7 +26,7 @@ void HashValue::Init(HASH_TYPE Type)
} }
bool HashValue::operator == (const HashValue &cmp) bool HashValue::operator == (const HashValue &cmp) const
{ {
if (Type==HASH_NONE || cmp.Type==HASH_NONE) if (Type==HASH_NONE || cmp.Type==HASH_NONE)
return true; return true;

@ -6,8 +6,14 @@ enum HASH_TYPE {HASH_NONE,HASH_RAR14,HASH_CRC32,HASH_BLAKE2};
struct HashValue struct HashValue
{ {
void Init(HASH_TYPE Type); void Init(HASH_TYPE Type);
bool operator == (const HashValue &cmp);
bool operator != (const HashValue &cmp) {return !(*this==cmp);} // Use the const member, so types on both sides of "==" match.
// Otherwise clang -std=c++20 issues "ambiguity is between a regular call
// to this operator and a call with the argument order reversed" warning.
bool operator == (const HashValue &cmp) const;
// Not actually used now. Const member for same reason as operator == above.
bool operator != (const HashValue &cmp) const {return !(*this==cmp);}
HASH_TYPE Type; HASH_TYPE Type;
union union

@ -49,13 +49,5 @@ FileHeader& FileHeader::operator = (FileHeader &hd)
void MainHeader::Reset() void MainHeader::Reset()
{ {
HighPosAV=0; *this={};
PosAV=0;
CommentInHeader=false;
PackComment=false;
Locator=false;
QOpenOffset=0;
QOpenMaxSize=0;
RROffset=0;
RRMaxSize=0;
} }

@ -6,7 +6,7 @@
#define SIZEOF_MAINHEAD3 13 // Size of RAR 4.x main archive header. #define SIZEOF_MAINHEAD3 13 // Size of RAR 4.x main archive header.
#define SIZEOF_FILEHEAD14 21 // Size of RAR 1.4 file header. #define SIZEOF_FILEHEAD14 21 // Size of RAR 1.4 file header.
#define SIZEOF_FILEHEAD3 32 // Size of RAR 3.0 file header. #define SIZEOF_FILEHEAD3 32 // Size of RAR 3.0 file header.
#define SIZEOF_SHORTBLOCKHEAD 7 #define SIZEOF_SHORTBLOCKHEAD 7 // Smallest RAR 4.x block size.
#define SIZEOF_LONGBLOCKHEAD 11 #define SIZEOF_LONGBLOCKHEAD 11
#define SIZEOF_SUBBLOCKHEAD 14 #define SIZEOF_SUBBLOCKHEAD 14
#define SIZEOF_COMMHEAD 13 #define SIZEOF_COMMHEAD 13
@ -162,12 +162,16 @@ struct MainHeader:BaseBlock
ushort HighPosAV; ushort HighPosAV;
uint PosAV; uint PosAV;
bool CommentInHeader; bool CommentInHeader;
bool PackComment; // For RAR 1.4 archive format only. bool PackComment; // For RAR 1.4 archive format only.
bool Locator; bool Locator;
uint64 QOpenOffset; // Offset of quick list record. uint64 QOpenOffset; // Offset of quick list record.
uint64 QOpenMaxSize; // Maximum size of QOpen offset in locator extra field. uint64 QOpenMaxSize; // Maximum size of QOpen offset in locator extra field.
uint64 RROffset; // Offset of recovery record. uint64 RROffset; // Offset of recovery record.
uint64 RRMaxSize; // Maximum size of RR offset in locator extra field. uint64 RRMaxSize; // Maximum size of RR offset in locator extra field.
size_t MetaNameMaxSize; // Maximum size of archive name in metadata extra field.
std::wstring OrigName; // Original archive name.
RarTime OrigTime; // Original archive time.
void Reset(); void Reset();
}; };
@ -230,7 +234,7 @@ struct FileHeader:BlockHeader
bool LargeFile; bool LargeFile;
// 'true' for HEAD_SERVICE block, which is a child of preceding file block. // 'true' for HEAD_SERVICE block, which is a child of preceding file block.
// RAR 4.x uses 'solid' flag to indicate child subheader blocks in archives. // RAR 4.x uses 'solid' flag to indicate children subheader blocks in archives.
bool SubBlock; bool SubBlock;
HOST_SYSTEM_TYPE HSType; HOST_SYSTEM_TYPE HSType;

@ -59,11 +59,18 @@
// Main header extra field values. // Main header extra field values.
#define MHEXTRA_LOCATOR 0x01 // Position of quick list and other blocks. #define MHEXTRA_LOCATOR 0x01 // Position of quick list and other blocks.
#define MHEXTRA_METADATA 0x02 // Archive metadata.
// Flags for MHEXTRA_LOCATOR. // Flags for MHEXTRA_LOCATOR.
#define MHEXTRA_LOCATOR_QLIST 0x01 // Quick open offset is present. #define MHEXTRA_LOCATOR_QLIST 0x01 // Quick open offset is present.
#define MHEXTRA_LOCATOR_RR 0x02 // Recovery record offset is present. #define MHEXTRA_LOCATOR_RR 0x02 // Recovery record offset is present.
// Flags for MHEXTRA_METADATA.
#define MHEXTRA_METADATA_NAME 0x01 // Archive name is present.
#define MHEXTRA_METADATA_CTIME 0x02 // Archive creation time is present.
#define MHEXTRA_METADATA_UNIXTIME 0x04 // Use Unix nanosecond time format.
#define MHEXTRA_METADATA_UNIX_NS 0x08 // Unix format with nanosecond precision.
// File and service header extra field values. // File and service header extra field values.
#define FHEXTRA_CRYPT 0x01 // Encryption parameters. #define FHEXTRA_CRYPT 0x01 // Encryption parameters.
#define FHEXTRA_HASH 0x02 // File hash. #define FHEXTRA_HASH 0x02 // File hash.

101
deps/unrar/isnt.cpp vendored

@ -13,6 +13,7 @@ DWORD WinNT()
dwPlatformId=WinVer.dwPlatformId; dwPlatformId=WinVer.dwPlatformId;
dwMajorVersion=WinVer.dwMajorVersion; dwMajorVersion=WinVer.dwMajorVersion;
dwMinorVersion=WinVer.dwMinorVersion; dwMinorVersion=WinVer.dwMinorVersion;
} }
DWORD Result=0; DWORD Result=0;
if (dwPlatformId==VER_PLATFORM_WIN32_NT) if (dwPlatformId==VER_PLATFORM_WIN32_NT)
@ -21,4 +22,102 @@ DWORD WinNT()
return Result; return Result;
} }
#endif
// Replace it with documented Windows 11 check when available.
#include <comdef.h>
#include <wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
static bool WMI_IsWindows10()
{
IWbemLocator *pLoc = NULL;
HRESULT hres = CoCreateInstance(CLSID_WbemLocator,0,CLSCTX_INPROC_SERVER,
IID_IWbemLocator,(LPVOID *)&pLoc);
if (FAILED(hres))
return false;
IWbemServices *pSvc = NULL;
BSTR bstr_root_cimv2 = SysAllocString(L"ROOT\\CIMV2");
hres = pLoc->ConnectServer(bstr_root_cimv2,NULL,NULL,NULL,0,0,0,&pSvc);
if (FAILED(hres))
{
pLoc->Release();
return false;
}
hres = CoSetProxyBlanket(pSvc,RPC_C_AUTHN_WINNT,RPC_C_AUTHZ_NONE,NULL,
RPC_C_AUTHN_LEVEL_CALL,RPC_C_IMP_LEVEL_IMPERSONATE,NULL,EOAC_NONE);
if (FAILED(hres))
{
pSvc->Release();
pLoc->Release();
return false;
}
IEnumWbemClassObject *pEnumerator = NULL;
BSTR bstr_wql = SysAllocString(L"WQL");
BSTR bstr_sql = SysAllocString(L"SELECT * FROM Win32_OperatingSystem");
hres = pSvc->ExecQuery(bstr_wql, bstr_sql,
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
if (FAILED(hres))
{
pSvc->Release();
pLoc->Release();
return false;
}
IWbemClassObject *pclsObj = NULL;
ULONG uReturn = 0;
bool Win10=false;
while (pEnumerator!=NULL)
{
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);
if (uReturn==0)
break;
VARIANT vtProp;
hr = pclsObj->Get(L"Name", 0, &vtProp, 0, 0);
Win10|=wcsstr(vtProp.bstrVal,L"Windows 10")!=NULL;
VariantClear(&vtProp);
pclsObj->Release();
}
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
return Win10;
}
// Replace it with actual check when available.
bool IsWindows11OrGreater()
{
static bool IsSet=false,IsWin11=false;
if (!IsSet)
{
OSVERSIONINFO WinVer;
WinVer.dwOSVersionInfoSize=sizeof(WinVer);
GetVersionEx(&WinVer);
IsWin11=WinVer.dwMajorVersion>10 ||
WinVer.dwMajorVersion==10 && WinVer.dwBuildNumber >= 22000 && !WMI_IsWindows10();
IsSet=true;
}
return IsWin11;
}
#endif // _WIN_ALL

@ -10,4 +10,7 @@ enum WINNT_VERSION {
DWORD WinNT(); DWORD WinNT();
// Replace it with actual check when available.
bool IsWindows11OrGreater();
#endif #endif

@ -1,6 +1,6 @@
#include "rar.hpp" #include "rar.hpp"
static void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare); static void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare,bool DisableNames);
static void ListSymLink(Archive &Arc); static void ListSymLink(Archive &Arc);
static void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize); static void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize);
static void ListOldSubHeader(Archive &Arc); static void ListOldSubHeader(Archive &Arc);
@ -22,9 +22,6 @@ void ListArchive(CommandData *Cmd)
Cmd->Password.Clean(); // Clean user entered password before processing next archive. Cmd->Password.Clean(); // Clean user entered password before processing next archive.
Archive Arc(Cmd); Archive Arc(Cmd);
#ifdef _WIN_ALL
Arc.RemoveSequentialFlag();
#endif
if (!Arc.WOpen(ArcName)) if (!Arc.WOpen(ArcName))
continue; continue;
bool FileMatched=true; bool FileMatched=true;
@ -39,6 +36,7 @@ void ListArchive(CommandData *Cmd)
{ {
Arc.ViewComment(); Arc.ViewComment();
mprintf(L"\n%s: %s",St(MListArchive),Arc.FileName); mprintf(L"\n%s: %s",St(MListArchive),Arc.FileName);
mprintf(L"\n%s: ",St(MListDetails)); mprintf(L"\n%s: ",St(MListDetails));
uint SetCount=0; uint SetCount=0;
const wchar *Fmt=Arc.Format==RARFMT14 ? L"RAR 1.4":(Arc.Format==RARFMT15 ? L"RAR 4":L"RAR 5"); const wchar *Fmt=Arc.Format==RARFMT14 ? L"RAR 1.4":(Arc.Format==RARFMT15 ? L"RAR 4":L"RAR 5");
@ -64,6 +62,16 @@ void ListArchive(CommandData *Cmd)
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListLock)); mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListLock));
if (Arc.Encrypted) if (Arc.Encrypted)
mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListEncHead)); mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListEncHead));
if (!Arc.MainHead.OrigName.empty())
mprintf(L"\n%s: %s",St(MOrigName),Arc.MainHead.OrigName.c_str());
if (Arc.MainHead.OrigTime.IsSet())
{
wchar DateStr[50];
Arc.MainHead.OrigTime.GetText(DateStr,ASIZE(DateStr),Technical);
mprintf(L"\n%s: %s",St(MOriginalTime),DateStr);
}
mprintf(L"\n"); mprintf(L"\n");
} }
@ -95,7 +103,7 @@ void ListArchive(CommandData *Cmd)
FileMatched=Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0; FileMatched=Cmd->IsProcessFile(Arc.FileHead,NULL,MATCH_WILDSUBPATH,0,NULL,0)!=0;
if (FileMatched) if (FileMatched)
{ {
ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare); ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare,Cmd->DisableNames);
if (!Arc.FileHead.SplitBefore) if (!Arc.FileHead.SplitBefore)
{ {
TotalUnpSize+=Arc.FileHead.UnpSize; TotalUnpSize+=Arc.FileHead.UnpSize;
@ -108,7 +116,7 @@ void ListArchive(CommandData *Cmd)
if (FileMatched && !Bare) if (FileMatched && !Bare)
{ {
if (Technical && ShowService) if (Technical && ShowService)
ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false); ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false,Cmd->DisableNames);
} }
break; break;
} }
@ -188,31 +196,37 @@ enum LISTCOL_TYPE {
}; };
void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare) void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare,bool DisableNames)
{ {
wchar *Name=hd.FileName; if (!TitleShown && !Technical && !Bare)
RARFORMAT Format=Arc.Format;
if (Bare)
{
mprintf(L"%s\n",Name);
return;
}
if (!TitleShown && !Technical)
{ {
if (Verbose) if (Verbose)
{ {
mprintf(L"\n%ls",St(MListTitleV)); mprintf(L"\n%ls",St(MListTitleV));
mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----"); if (!DisableNames)
mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----");
} }
else else
{ {
mprintf(L"\n%ls",St(MListTitleL)); mprintf(L"\n%ls",St(MListTitleL));
mprintf(L"\n----------- --------- ---------- ----- ----"); if (!DisableNames)
mprintf(L"\n----------- --------- ---------- ----- ----");
} }
// Must be set even in DisableNames mode to suppress "0 files" output
// unless no files are matched.
TitleShown=true; TitleShown=true;
} }
if (DisableNames)
return;
wchar *Name=hd.FileName;
RARFORMAT Format=Arc.Format;
if (Bare)
{
mprintf(L"%s\n",Name);
return;
}
wchar UnpSizeText[30],PackSizeText[30]; wchar UnpSizeText[30],PackSizeText[30];
if (hd.UnpSize==INT64NDF) if (hd.UnpSize==INT64NDF)
@ -304,17 +318,21 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
mprintf(L"\n%12ls: %ls",St(MListPacked),PackSizeText); mprintf(L"\n%12ls: %ls",St(MListPacked),PackSizeText);
mprintf(L"\n%12ls: %ls",St(MListRatio),RatioStr); mprintf(L"\n%12ls: %ls",St(MListRatio),RatioStr);
} }
bool WinTitles=false;
#ifdef _WIN_ALL
WinTitles=true;
#endif
if (hd.mtime.IsSet()) if (hd.mtime.IsSet())
mprintf(L"\n%12ls: %ls",St(MListMtime),DateStr); mprintf(L"\n%12ls: %ls",St(WinTitles ? MListModified:MListMtime),DateStr);
if (hd.ctime.IsSet()) if (hd.ctime.IsSet())
{ {
hd.ctime.GetText(DateStr,ASIZE(DateStr),true); hd.ctime.GetText(DateStr,ASIZE(DateStr),true);
mprintf(L"\n%12ls: %ls",St(MListCtime),DateStr); mprintf(L"\n%12ls: %ls",St(WinTitles ? MListCreated:MListCtime),DateStr);
} }
if (hd.atime.IsSet()) if (hd.atime.IsSet())
{ {
hd.atime.GetText(DateStr,ASIZE(DateStr),true); hd.atime.GetText(DateStr,ASIZE(DateStr),true);
mprintf(L"\n%12ls: %ls",St(MListAtime),DateStr); mprintf(L"\n%12ls: %ls",St(WinTitles ? MListAccessed:MListAtime),DateStr);
} }
mprintf(L"\n%12ls: %ls",St(MListAttr),AttrStr); mprintf(L"\n%12ls: %ls",St(MListAttr),AttrStr);
if (hd.FileHash.Type==HASH_CRC32) if (hd.FileHash.Type==HASH_CRC32)
@ -370,15 +388,16 @@ void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bo
{ {
mprintf(L"\n%12ls: ",L"Unix owner"); mprintf(L"\n%12ls: ",L"Unix owner");
if (*hd.UnixOwnerName!=0) if (*hd.UnixOwnerName!=0)
mprintf(L"%ls:",GetWide(hd.UnixOwnerName)); mprintf(L"%ls",GetWide(hd.UnixOwnerName));
else
if (hd.UnixOwnerNumeric)
mprintf(L"#%d",hd.UnixOwnerID);
mprintf(L":");
if (*hd.UnixGroupName!=0) if (*hd.UnixGroupName!=0)
mprintf(L"%ls",GetWide(hd.UnixGroupName)); mprintf(L"%ls",GetWide(hd.UnixGroupName));
if ((*hd.UnixOwnerName!=0 || *hd.UnixGroupName!=0) && (hd.UnixOwnerNumeric || hd.UnixGroupNumeric)) else
mprintf(L" "); if (hd.UnixGroupNumeric)
if (hd.UnixOwnerNumeric) mprintf(L"#%d",hd.UnixGroupID);
mprintf(L"#%d:",hd.UnixOwnerID);
if (hd.UnixGroupNumeric)
mprintf(L"#%d:",hd.UnixGroupID);
} }
mprintf(L"\n"); mprintf(L"\n");

@ -28,6 +28,7 @@
#define MRARTitle1 L"\nUsage: rar <command> -<switch 1> -<switch N> <archive> <files...>" #define MRARTitle1 L"\nUsage: rar <command> -<switch 1> -<switch N> <archive> <files...>"
#define MUNRARTitle1 L"\nUsage: unrar <command> -<switch 1> -<switch N> <archive> <files...>" #define MUNRARTitle1 L"\nUsage: unrar <command> -<switch 1> -<switch N> <archive> <files...>"
#define MRARTitle2 L"\n <@listfiles...> <path_to_extract\\>" #define MRARTitle2 L"\n <@listfiles...> <path_to_extract\\>"
#define MFwrSlTitle2 L"\n <@listfiles...> <path_to_extract/>"
#define MCHelpCmd L"\n\n<Commands>" #define MCHelpCmd L"\n\n<Commands>"
#define MCHelpCmdA L"\n a Add files to archive" #define MCHelpCmdA L"\n a Add files to archive"
#define MCHelpCmdC L"\n c Add archive comment" #define MCHelpCmdC L"\n c Add archive comment"
@ -58,6 +59,7 @@
#define MCHelpSwAD L"\n ad[1,2] Alternate destination path" #define MCHelpSwAD L"\n ad[1,2] Alternate destination path"
#define MCHelpSwAG L"\n ag[format] Generate archive name using the current date" #define MCHelpSwAG L"\n ag[format] Generate archive name using the current date"
#define MCHelpSwAI L"\n ai Ignore file attributes" #define MCHelpSwAI L"\n ai Ignore file attributes"
#define MCHelpSwAM L"\n am[s,r] Archive name and time [save, restore]"
#define MCHelpSwAO L"\n ao Add files with Archive attribute set" #define MCHelpSwAO L"\n ao Add files with Archive attribute set"
#define MCHelpSwAP L"\n ap<path> Set path inside archive" #define MCHelpSwAP L"\n ap<path> Set path inside archive"
#define MCHelpSwAS L"\n as Synchronize archive contents" #define MCHelpSwAS L"\n as Synchronize archive contents"
@ -72,11 +74,11 @@
#define MCHelpSwDW L"\n dw Wipe files after archiving" #define MCHelpSwDW L"\n dw Wipe files after archiving"
#define MCHelpSwEa L"\n e[+]<attr> Set file exclude and include attributes" #define MCHelpSwEa L"\n e[+]<attr> Set file exclude and include attributes"
#define MCHelpSwED L"\n ed Do not add empty directories" #define MCHelpSwED L"\n ed Do not add empty directories"
#define MCHelpSwEN L"\n en Do not put 'end of archive' block"
#define MCHelpSwEP L"\n ep Exclude paths from names" #define MCHelpSwEP L"\n ep Exclude paths from names"
#define MCHelpSwEP1 L"\n ep1 Exclude base directory from names" #define MCHelpSwEP1 L"\n ep1 Exclude base directory from names"
#define MCHelpSwEP2 L"\n ep2 Expand paths to full" #define MCHelpSwEP2 L"\n ep2 Expand paths to full"
#define MCHelpSwEP3 L"\n ep3 Expand paths to full including the drive letter" #define MCHelpSwEP3 L"\n ep3 Expand paths to full including the drive letter"
#define MCHelpSwEP4 L"\n ep4<path> Exclude the path prefix from names"
#define MCHelpSwF L"\n f Freshen files" #define MCHelpSwF L"\n f Freshen files"
#define MCHelpSwHP L"\n hp[password] Encrypt both file data and headers" #define MCHelpSwHP L"\n hp[password] Encrypt both file data and headers"
#define MCHelpSwHT L"\n ht[b|c] Select hash type [BLAKE2,CRC32] for file checksum" #define MCHelpSwHT L"\n ht[b|c] Select hash type [BLAKE2,CRC32] for file checksum"
@ -95,6 +97,7 @@
#define MCHelpSwMA L"\n ma[4|5] Specify a version of archiving format" #define MCHelpSwMA L"\n ma[4|5] Specify a version of archiving format"
#define MCHelpSwMC L"\n mc<par> Set advanced compression parameters" #define MCHelpSwMC L"\n mc<par> Set advanced compression parameters"
#define MCHelpSwMD L"\n md<n>[k,m,g] Dictionary size in KB, MB or GB" #define MCHelpSwMD L"\n md<n>[k,m,g] Dictionary size in KB, MB or GB"
#define MCHelpSwME L"\n me[par] Set encryption parameters"
#define MCHelpSwMS L"\n ms[ext;ext] Specify file types to store" #define MCHelpSwMS L"\n ms[ext;ext] Specify file types to store"
#define MCHelpSwMT L"\n mt<threads> Set the number of threads" #define MCHelpSwMT L"\n mt<threads> Set the number of threads"
#define MCHelpSwN L"\n n<file> Additionally filter included files" #define MCHelpSwN L"\n n<file> Additionally filter included files"
@ -106,11 +109,11 @@
#define MCHelpSwOI L"\n oi[0-4][:min] Save identical files as references" #define MCHelpSwOI L"\n oi[0-4][:min] Save identical files as references"
#define MCHelpSwOL L"\n ol[a] Process symbolic links as the link [absolute paths]" #define MCHelpSwOL L"\n ol[a] Process symbolic links as the link [absolute paths]"
#define MCHelpSwONI L"\n oni Allow potentially incompatible names" #define MCHelpSwONI L"\n oni Allow potentially incompatible names"
#define MCHelpSwOP L"\n op<path> Set the output path for extracted files"
#define MCHelpSwOR L"\n or Rename files automatically" #define MCHelpSwOR L"\n or Rename files automatically"
#define MCHelpSwOS L"\n os Save NTFS streams" #define MCHelpSwOS L"\n os Save NTFS streams"
#define MCHelpSwOW L"\n ow Save or restore file owner and group" #define MCHelpSwOW L"\n ow Save or restore file owner and group"
#define MCHelpSwP L"\n p[password] Set password" #define MCHelpSwP L"\n p[password] Set password"
#define MCHelpSwPm L"\n p- Do not query password"
#define MCHelpSwQO L"\n qo[-|+] Add quick open information [none|force]" #define MCHelpSwQO L"\n qo[-|+] Add quick open information [none|force]"
#define MCHelpSwR L"\n r Recurse subdirectories" #define MCHelpSwR L"\n r Recurse subdirectories"
#define MCHelpSwRm L"\n r- Disable recursion" #define MCHelpSwRm L"\n r- Disable recursion"
@ -272,6 +275,9 @@
#define MListMtime L"mtime" #define MListMtime L"mtime"
#define MListCtime L"ctime" #define MListCtime L"ctime"
#define MListAtime L"atime" #define MListAtime L"atime"
#define MListModified L"Modified"
#define MListCreated L"Created"
#define MListAccessed L"Accessed"
#define MListAttr L"Attributes" #define MListAttr L"Attributes"
#define MListFlags L"Flags" #define MListFlags L"Flags"
#define MListCompInfo L"Compression" #define MListCompInfo L"Compression"
@ -385,3 +391,11 @@
#define MErrReadTrunc L"\n%s is archived incompletely because of read error.\n" #define MErrReadTrunc L"\n%s is archived incompletely because of read error.\n"
#define MErrReadCount L"\n%u files are archived incompletely because of read errors." #define MErrReadCount L"\n%u files are archived incompletely because of read errors."
#define MDirNameExists L"\nDirectory with such name already exists" #define MDirNameExists L"\nDirectory with such name already exists"
#define MStdinNoInput L"\nKeyboard input is not allowed when reading data from stdin"
#define MTruncPsw L"\nPassword exceeds the maximum allowed length of %u characters and will be truncated."
#define MAdjustValue L"\nAdjusting %s value to %s."
#define MOpFailed L"\nOperation failed"
#define MSkipEncArc L"\nSkipping the encrypted archive %s"
#define MOrigName L"Original name"
#define MOriginalTime L"Original time"
#define MFileRenamed L"\n%s is renamed to %s"

@ -123,10 +123,10 @@ UNRAR_OBJ=filestr.o recvol.o rs.o scantree.o qopen.o
LIB_OBJ=filestr.o scantree.o dll.o qopen.o LIB_OBJ=filestr.o scantree.o dll.o qopen.o
OBJECTS=rar.o strlist.o strfn.o pathfn.o smallfn.o global.o file.o filefn.o filcreat.o \ OBJECTS=rar.o strlist.o strfn.o pathfn.o smallfn.o global.o file.o filefn.o filcreat.o \
archive.o arcread.o unicode.o system.o isnt.o crypt.o crc.o rawread.o encname.o \ archive.o arcread.o unicode.o system.o crypt.o crc.o rawread.o encname.o \
resource.o match.o timefn.o rdwrfn.o consio.o options.o errhnd.o rarvm.o secpassword.o \ resource.o match.o timefn.o rdwrfn.o consio.o options.o errhnd.o rarvm.o secpassword.o \
rijndael.o getbits.o sha1.o sha256.o blake2s.o hash.o extinfo.o extract.o volume.o \ rijndael.o getbits.o sha1.o sha256.o blake2s.o hash.o extinfo.o extract.o volume.o \
list.o find.o unpack.o headers.o threadpool.o rs16.o cmddata.o ui.o list.o find.o unpack.o headers.o threadpool.o rs16.o cmddata.o ui.o
.cpp.o: .cpp.o:
$(COMPILE) -D$(WHAT) -c $< $(COMPILE) -D$(WHAT) -c $<
@ -142,20 +142,23 @@ clean:
@rm -f $(OBJECTS) $(UNRAR_OBJ) $(LIB_OBJ) @rm -f $(OBJECTS) $(UNRAR_OBJ) $(LIB_OBJ)
@rm -f unrar libunrar.* @rm -f unrar libunrar.*
unrar: clean $(OBJECTS) $(UNRAR_OBJ) # We removed 'clean' from dependencies, because it prevented parallel
# 'make -Jn' builds.
unrar: $(OBJECTS) $(UNRAR_OBJ)
@rm -f unrar @rm -f unrar
$(LINK) -o unrar $(LDFLAGS) $(OBJECTS) $(UNRAR_OBJ) $(LIBS) $(LINK) -o unrar $(LDFLAGS) $(OBJECTS) $(UNRAR_OBJ) $(LIBS)
$(STRIP) unrar $(STRIP) unrar
sfx: WHAT=SFX_MODULE sfx: WHAT=SFX_MODULE
sfx: clean $(OBJECTS) sfx: $(OBJECTS)
@rm -f default.sfx @rm -f default.sfx
$(LINK) -o default.sfx $(LDFLAGS) $(OBJECTS) $(LINK) -o default.sfx $(LDFLAGS) $(OBJECTS)
$(STRIP) default.sfx $(STRIP) default.sfx
lib: WHAT=RARDLL lib: WHAT=RARDLL
lib: CXXFLAGS+=$(LIBFLAGS) lib: CXXFLAGS+=$(LIBFLAGS)
lib: clean $(OBJECTS) $(LIB_OBJ) lib: $(OBJECTS) $(LIB_OBJ)
@rm -f libunrar.* @rm -f libunrar.*
$(LINK) -shared -o libunrar.so $(LDFLAGS) $(OBJECTS) $(LIB_OBJ) $(LINK) -shared -o libunrar.so $(LDFLAGS) $(OBJECTS) $(LIB_OBJ)
$(AR) rcs libunrar.a $(OBJECTS) $(LIB_OBJ) $(AR) rcs libunrar.a $(OBJECTS) $(LIB_OBJ)

@ -532,13 +532,15 @@ inline bool RARPPM_CONTEXT::decodeSymbol2(ModelPPM *Model)
Model->Coder.SubRange.LowCount=HiCnt; Model->Coder.SubRange.LowCount=HiCnt;
Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale; Model->Coder.SubRange.HighCount=Model->Coder.SubRange.scale;
i=NumStats-Model->NumMasked; i=NumStats-Model->NumMasked;
pps--;
// 2022.12.02: we removed pps-- here and changed the code below to avoid
// "array subscript -1 is outside array bounds" warning in some compilers.
do do
{ {
pps++;
if (pps>=ps+ASIZE(ps)) // Extra safety check. if (pps>=ps+ASIZE(ps)) // Extra safety check.
return false; return false;
Model->CharMask[(*pps)->Symbol]=Model->EscCount; Model->CharMask[(*pps)->Symbol]=Model->EscCount;
pps++;
} while ( --i ); } while ( --i );
psee2c->Summ += Model->Coder.SubRange.scale; psee2c->Summ += Model->Coder.SubRange.scale;
Model->NumMasked = NumStats; Model->NumMasked = NumStats;
@ -566,17 +568,14 @@ void ModelPPM::CleanUp()
} }
bool ModelPPM::DecodeInit(Unpack *UnpackRead,int &EscChar,byte *hcppm) bool ModelPPM::DecodeInit(Unpack *UnpackRead,int &EscChar)
{ {
int MaxOrder=UnpackRead->GetChar(); int MaxOrder=UnpackRead->GetChar();
bool Reset=(MaxOrder & 0x20)!=0; bool Reset=(MaxOrder & 0x20)!=0;
int MaxMB; int MaxMB;
if (Reset) if (Reset)
{
MaxMB=UnpackRead->GetChar(); MaxMB=UnpackRead->GetChar();
if (MaxMB>128) return(false);
}
else else
if (SubAlloc.GetAllocatedMemory()==0) if (SubAlloc.GetAllocatedMemory()==0)
return(false); return(false);
@ -593,7 +592,6 @@ bool ModelPPM::DecodeInit(Unpack *UnpackRead,int &EscChar,byte *hcppm)
SubAlloc.StopSubAllocator(); SubAlloc.StopSubAllocator();
return(false); return(false);
} }
SubAlloc.SetHeapStartFixed(hcppm);
SubAlloc.StartSubAllocator(MaxMB+1); SubAlloc.StartSubAllocator(MaxMB+1);
StartModelRare(MaxOrder); StartModelRare(MaxOrder);
} }

@ -115,7 +115,7 @@ class ModelPPM : RARPPM_DEF
public: public:
ModelPPM(); ModelPPM();
void CleanUp(); // reset PPM variables after data error void CleanUp(); // reset PPM variables after data error
bool DecodeInit(Unpack *UnpackRead,int &EscChar,byte *hcppm); bool DecodeInit(Unpack *UnpackRead,int &EscChar);
int DecodeChar(); int DecodeChar();
}; };

@ -6,14 +6,6 @@ RAROptions::RAROptions()
} }
RAROptions::~RAROptions()
{
// It is important for security reasons, so we do not have the unnecessary
// password data left in memory.
memset(this,0,sizeof(RAROptions));
}
void RAROptions::Init() void RAROptions::Init()
{ {
memset(this,0,sizeof(RAROptions)); memset(this,0,sizeof(RAROptions));

@ -45,6 +45,12 @@ enum OVERWRITE_MODE
OVERWRITE_FORCE_ASK OVERWRITE_FORCE_ASK
}; };
enum ARC_METADATA
{
ARCMETA_NONE=0,
ARCMETA_SAVE, // -ams
ARCMETA_RESTORE // -amr
};
enum QOPEN_MODE { QOPEN_NONE, QOPEN_AUTO, QOPEN_ALWAYS }; enum QOPEN_MODE { QOPEN_NONE, QOPEN_AUTO, QOPEN_ALWAYS };
@ -84,11 +90,12 @@ struct FilterMode
#define MAX_GENERATE_MASK 128 #define MAX_GENERATE_MASK 128
// Here we store simple data types, which we can clear and move all together
// quickly. Rest of data types goes to CommandData.
class RAROptions class RAROptions
{ {
public: public:
RAROptions(); RAROptions();
~RAROptions();
void Init(); void Init();
uint ExclFileAttr; uint ExclFileAttr;
@ -116,9 +123,10 @@ class RAROptions
RAR_CHARSET ErrlogCharset; RAR_CHARSET ErrlogCharset;
RAR_CHARSET RedirectCharset; RAR_CHARSET RedirectCharset;
wchar ArcPath[NM]; wchar ArcPath[NM]; // For -ap<path>.
SecPassword Password; wchar ExclArcPath[NM]; // For -ep4<path> switch.
bool EncryptHeaders; bool EncryptHeaders;
bool SkipEncrypted;
bool ManualPassword; // Password entered manually during operation, might need to clean for next archive. bool ManualPassword; // Password entered manually during operation, might need to clean for next archive.
@ -130,6 +138,7 @@ class RAROptions
HASH_TYPE HashType; HASH_TYPE HashType;
int Recovery; int Recovery;
int RecVolNumber; int RecVolNumber;
ARC_METADATA ArcMetadata;
bool DisablePercentage; bool DisablePercentage;
bool DisableCopyright; bool DisableCopyright;
bool DisableDone; bool DisableDone;
@ -145,7 +154,6 @@ class RAROptions
PATH_EXCL_MODE ExclPath; PATH_EXCL_MODE ExclPath;
RECURSE_MODE Recurse; RECURSE_MODE Recurse;
int64 VolSize; int64 VolSize;
Array<int64> NextVolSizes;
uint CurVolNum; uint CurVolNum;
bool AllYes; bool AllYes;
bool VerboseOutput; // -iv, display verbose output, used only in "WinRAR t" now. bool VerboseOutput; // -iv, display verbose output, used only in "WinRAR t" now.
@ -195,7 +203,11 @@ class RAROptions
EXTTIME_MODE xctime; EXTTIME_MODE xctime;
EXTTIME_MODE xatime; EXTTIME_MODE xatime;
bool PreserveAtime; bool PreserveAtime;
wchar CompressStdin[NM];
// Read data from stdin and store in archive under a name specified here
// when archiving. Read an archive from stdin if any non-empty string
// is specified here when extracting.
wchar UseStdin[NM];
uint Threads; // We use it to init hash even if RAR_SMP is not defined. uint Threads; // We use it to init hash even if RAR_SMP is not defined.

33
deps/unrar/os.hpp vendored

@ -13,6 +13,8 @@
#endif #endif
#include <new> #include <new>
#include <string>
#include <vector>
#if defined(_WIN_ALL) || defined(_EMX) #if defined(_WIN_ALL) || defined(_EMX)
@ -36,12 +38,23 @@
// re-definition warnings in third party projects. // re-definition warnings in third party projects.
#ifndef UNICODE #ifndef UNICODE
#define UNICODE #define UNICODE
#define _UNICODE // Set _T() macro to convert from narrow to wide strings.
#endif #endif
#undef WINVER
#ifdef _WIN32_WINNT
#undef _WIN32_WINNT #undef _WIN32_WINNT
#define WINVER 0x0501 #endif
#define _WIN32_WINNT 0x0501
#if 0
// 2021.09.05: Allow newer Vista+ APIs like IFileOpenDialog for WinRAR,
// but still keep SFX modules XP compatible.
#define WINVER _WIN32_WINNT_VISTA
#define _WIN32_WINNT _WIN32_WINNT_VISTA
#else
#define WINVER _WIN32_WINNT_WINXP
#define _WIN32_WINNT _WIN32_WINNT_WINXP
#endif
#if !defined(ZIPSFX) #if !defined(ZIPSFX)
#define RAR_SMP #define RAR_SMP
@ -73,14 +86,14 @@
#include <dir.h> #include <dir.h>
#endif #endif
#ifdef _MSC_VER #ifdef _MSC_VER
#if _MSC_VER<1500
#define for if (0) ; else for
#endif
#include <direct.h> #include <direct.h>
#include <intrin.h> #include <intrin.h>
#define USE_SSE // Use SSE only for x86/x64, not ARM Windows.
#define SSE_ALIGNMENT 16 #if defined(_M_IX86) || defined(_M_X64)
#define USE_SSE
#define SSE_ALIGNMENT 16
#endif
#else #else
#include <dirent.h> #include <dirent.h>
#endif // _MSC_VER #endif // _MSC_VER
@ -96,7 +109,6 @@
#include <time.h> #include <time.h>
#include <signal.h> #include <signal.h>
#define SAVE_LINKS #define SAVE_LINKS
#define ENABLE_ACCESS #define ENABLE_ACCESS
@ -212,7 +224,8 @@
#endif #endif
#endif #endif
#if _POSIX_C_SOURCE >= 200809L // Unlike Apple x64, utimensat shall be available in all Apple M1 systems.
#if _POSIX_C_SOURCE >= 200809L || defined(__APPLE__) && defined(__arm64__)
#define UNIX_TIME_NS // Nanosecond time precision in Unix. #define UNIX_TIME_NS // Nanosecond time precision in Unix.
#endif #endif

@ -5,7 +5,7 @@ wchar* PointToName(const wchar *Path)
for (int I=(int)wcslen(Path)-1;I>=0;I--) for (int I=(int)wcslen(Path)-1;I>=0;I--)
if (IsPathDiv(Path[I])) if (IsPathDiv(Path[I]))
return (wchar*)&Path[I+1]; return (wchar*)&Path[I+1];
return (wchar*)((*Path && IsDriveDiv(Path[1])) ? Path+2:Path); return (wchar*)((*Path!=0 && IsDriveDiv(Path[1])) ? Path+2:Path);
} }
@ -31,11 +31,17 @@ wchar* ConvertPath(const wchar *SrcPath,wchar *DestPath,size_t DestSize)
const wchar *s=DestPtr; const wchar *s=DestPtr;
if (s[0]!=0 && IsDriveDiv(s[1])) if (s[0]!=0 && IsDriveDiv(s[1]))
s+=2; s+=2;
if (s[0]=='\\' && s[1]=='\\')
// Skip UNC Windows \\server\share\ or Unix //server/share/
if (IsPathDiv(s[0]) && IsPathDiv(s[1]))
{ {
const wchar *Slash=wcschr(s+2,'\\'); uint SlashCount=0;
if (Slash!=NULL && (Slash=wcschr(Slash+1,'\\'))!=NULL) for (const wchar *t=s+2;*t!=0;t++)
s=Slash+1; if (IsPathDiv(*t) && ++SlashCount==2)
{
s=t+1; // Found two more path separators after leading two.
break;
}
} }
for (const wchar *t=s;*t!=0;t++) for (const wchar *t=s;*t!=0;t++)
if (IsPathDiv(*t)) if (IsPathDiv(*t))
@ -184,7 +190,9 @@ void MakeName(const wchar *Path,const wchar *Name,wchar *Pathname,size_t MaxSize
// the temporary buffer instead of constructing the name in 'Pathname'. // the temporary buffer instead of constructing the name in 'Pathname'.
wchar OutName[NM]; wchar OutName[NM];
wcsncpyz(OutName,Path,ASIZE(OutName)); wcsncpyz(OutName,Path,ASIZE(OutName));
AddEndSlash(OutName,ASIZE(OutName)); // Do not add slash to d:, we want to allow relative paths like d:filename.
if (!IsDriveLetter(Path) || Path[2]!=0)
AddEndSlash(OutName,ASIZE(OutName));
wcsncatz(OutName,Name,ASIZE(OutName)); wcsncatz(OutName,Name,ASIZE(OutName));
wcsncpyz(Pathname,OutName,MaxSize); wcsncpyz(Pathname,OutName,MaxSize);
} }
@ -317,6 +325,9 @@ void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckEx
// of file name if numeric part is missing. // of file name if numeric part is missing.
wchar* GetVolNumPart(const wchar *ArcName) wchar* GetVolNumPart(const wchar *ArcName)
{ {
// We do not want to increment any characters in path component.
ArcName=PointToName(ArcName);
if (*ArcName==0) if (*ArcName==0)
return (wchar *)ArcName; return (wchar *)ArcName;
@ -340,7 +351,7 @@ wchar* GetVolNumPart(const wchar *ArcName)
{ {
// Validate the first numeric part only if it has a dot somewhere // Validate the first numeric part only if it has a dot somewhere
// before it. // before it.
wchar *Dot=wcschr(PointToName(ArcName),'.'); const wchar *Dot=wcschr(ArcName,'.');
if (Dot!=NULL && Dot<NumPtr) if (Dot!=NULL && Dot<NumPtr)
ChPtr=NumPtr; ChPtr=NumPtr;
break; break;
@ -417,50 +428,39 @@ void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering)
bool IsNameUsable(const wchar *Name) bool IsNameUsable(const wchar *Name)
{ {
#ifndef _UNIX // We were asked to apply Windows-like conversion in Linux in case
if (Name[0] && Name[1] && wcschr(Name+2,':')!=NULL) // files are unpacked to Windows share. This code is invoked only
// if file failed to be created, so it doesn't affect extraction
// of Unix compatible names to native Unix drives.
#ifdef _UNIX
// Windows shares in Unix do not allow the drive letter,
// so unlike Windows version, we check all characters here.
if (wcschr(Name,':')!=NULL)
return false; return false;
#else
if (Name[0]!=0 && Name[1]!=0 && wcschr(Name+2,':')!=NULL)
return false;
#endif
for (const wchar *s=Name;*s!=0;s++) for (const wchar *s=Name;*s!=0;s++)
{ {
if ((uint)*s<32) if ((uint)*s<32)
return false; return false;
// It is for Windows shares in Unix. We can create such names in Windows.
#ifdef _UNIX
// No spaces or dots before the path separator are allowed in Windows
// shares. But they are allowed and automtically removed at the end of
// file or folder name, so it is useless to replace them here.
// Since such files or folders are created successfully, a supposed
// conversion here would never be invoked.
if ((*s==' ' || *s=='.') && IsPathDiv(s[1])) if ((*s==' ' || *s=='.') && IsPathDiv(s[1]))
return false; return false;
}
#endif #endif
}
return *Name!=0 && wcspbrk(Name,L"?*<>|\"")==NULL; return *Name!=0 && wcspbrk(Name,L"?*<>|\"")==NULL;
} }
void MakeNameUsable(char *Name,bool Extended)
{
#ifdef _WIN_ALL
// In Windows we also need to convert characters not defined in current
// code page. This double conversion changes them to '?', which is
// catched by code below.
size_t NameLength=strlen(Name);
wchar NameW[NM];
CharToWide(Name,NameW,ASIZE(NameW));
WideToChar(NameW,Name,NameLength+1);
Name[NameLength]=0;
#endif
for (char *s=Name;*s!=0;s=charnext(s))
{
if (strchr(Extended ? "?*<>|\"":"?*",*s)!=NULL || Extended && (byte)*s<32)
*s='_';
#ifdef _EMX
if (*s=='=')
*s='_';
#endif
#ifndef _UNIX
if (s-Name>1 && *s==':')
*s='_';
// Remove ' ' and '.' before path separator, but allow .\ and ..\.
if ((*s==' ' || *s=='.' && s>Name && !IsPathDiv(s[-1]) && s[-1]!='.') && IsPathDiv(s[1]))
*s='_';
#endif
}
}
void MakeNameUsable(wchar *Name,bool Extended) void MakeNameUsable(wchar *Name,bool Extended)
@ -469,7 +469,27 @@ void MakeNameUsable(wchar *Name,bool Extended)
{ {
if (wcschr(Extended ? L"?*<>|\"":L"?*",*s)!=NULL || Extended && (uint)*s<32) if (wcschr(Extended ? L"?*<>|\"":L"?*",*s)!=NULL || Extended && (uint)*s<32)
*s='_'; *s='_';
#ifndef _UNIX #ifdef _UNIX
// We were asked to apply Windows-like conversion in Linux in case
// files are unpacked to Windows share. This code is invoked only
// if file failed to be created, so it doesn't affect extraction
// of Unix compatible names to native Unix drives.
if (Extended)
{
// Windows shares in Unix do not allow the drive letter,
// so unlike Windows version, we check all characters here.
if (*s==':')
*s='_';
// No spaces or dots before the path separator are allowed on Windows
// shares. But they are allowed and automtically removed at the end of
// file or folder name, so it is useless to replace them here.
// Since such files or folders are created successfully, a supposed
// conversion here would never be invoked.
if ((*s==' ' || *s=='.') && IsPathDiv(s[1]))
*s='_';
}
#else
if (s-Name>1 && *s==':') if (s-Name>1 && *s==':')
*s='_'; *s='_';
#if 0 // We already can create such files. #if 0 // We already can create such files.
@ -692,7 +712,8 @@ static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,u
wchar Mask[MAX_GENERATE_MASK]; wchar Mask[MAX_GENERATE_MASK];
wcsncpyz(Mask,*GenerateMask!=0 ? GenerateMask:L"yyyymmddhhmmss",ASIZE(Mask)); wcsncpyz(Mask,*GenerateMask!=0 ? GenerateMask:L"yyyymmddhhmmss",ASIZE(Mask));
bool QuoteMode=false,Hours=false; bool QuoteMode=false;
uint MAsMinutes=0; // By default we treat 'M' as months.
for (uint I=0;Mask[I]!=0;I++) for (uint I=0;Mask[I]!=0;I++)
{ {
if (Mask[I]=='{' || Mask[I]=='}') if (Mask[I]=='{' || Mask[I]=='}')
@ -704,13 +725,16 @@ static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,u
continue; continue;
int CurChar=toupperw(Mask[I]); int CurChar=toupperw(Mask[I]);
if (CurChar=='H') if (CurChar=='H')
Hours=true; MAsMinutes=2; // Treat next two 'M' after 'H' as minutes.
if (CurChar=='D' || CurChar=='Y')
MAsMinutes=0; // Treat 'M' in HHDDMMYY and HHYYMMDD as month.
if (Hours && CurChar=='M') if (MAsMinutes>0 && CurChar=='M')
{ {
// Replace minutes with 'I'. We use 'M' both for months and minutes, // Replace minutes with 'I'. We use 'M' both for months and minutes,
// so we treat as minutes only those 'M' which are found after hours. // so we treat as minutes only those 'M', which are found after hours.
Mask[I]='I'; Mask[I]='I';
MAsMinutes--;
} }
if (CurChar=='N') if (CurChar=='N')
{ {
@ -774,7 +798,9 @@ static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,u
const wchar *MaskChars=L"YMDHISWAEN"; const wchar *MaskChars=L"YMDHISWAEN";
// How many times every modifier character was encountered in the mask.
int CField[sizeof(Field)/sizeof(Field[0])]; int CField[sizeof(Field)/sizeof(Field[0])];
memset(CField,0,sizeof(CField)); memset(CField,0,sizeof(CField));
QuoteMode=false; QuoteMode=false;
for (uint I=0;Mask[I]!=0;I++) for (uint I=0;Mask[I]!=0;I++)
@ -816,13 +842,22 @@ static void GenArcName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask,u
{ {
size_t FieldPos=ChPtr-MaskChars; size_t FieldPos=ChPtr-MaskChars;
int CharPos=(int)strlen(Field[FieldPos])-CField[FieldPos]--; int CharPos=(int)strlen(Field[FieldPos])-CField[FieldPos]--;
if (FieldPos==1 && toupperw(Mask[I+1])=='M' && toupperw(Mask[I+2])=='M')
// CField[FieldPos] shall have exactly 3 "MMM" symbols, so we do not
// repeat the month name in case "MMMMMMMM" mask. But since we
// decremented CField[FieldPos] above, we compared it with 2.
if (FieldPos==1 && CField[FieldPos]==2 &&
toupperw(Mask[I+1])=='M' && toupperw(Mask[I+2])=='M')
{ {
wcsncpyz(DateText+J,GetMonthName(rlt.Month-1),ASIZE(DateText)-J); wcsncpyz(DateText+J,GetMonthName(rlt.Month-1),ASIZE(DateText)-J);
J=wcslen(DateText); J=wcslen(DateText);
I+=2; I+=2;
continue; continue;
} }
// If CharPos is negative, we have more modifier characters than
// matching time data. We prefer to issue a modifier character
// instead of repeating time data from beginning, so user can notice
// excessive modifiers added by mistake.
if (CharPos<0) if (CharPos<0)
DateText[J]=Mask[I]; DateText[J]=Mask[I];
else else
@ -985,9 +1020,9 @@ void ConvertToPrecomposed(wchar *Name,size_t NameSize)
} }
// Remove trailing spaces and dots in file name and in dir names in path. void MakeNameCompatible(wchar *Name,size_t MaxSize)
void MakeNameCompatible(wchar *Name)
{ {
// Remove trailing spaces and dots in file name and in dir names in path.
int Src=0,Dest=0; int Src=0,Dest=0;
while (true) while (true)
{ {
@ -1005,5 +1040,47 @@ void MakeNameCompatible(wchar *Name)
Src++; Src++;
Dest++; Dest++;
} }
// Rename reserved device names, such as aux.txt to _aux.txt.
// We check them in path components too, where they are also prohibited.
for (uint I=0;Name[I]!=0;I++)
if (I==0 || I>0 && IsPathDiv(Name[I-1]))
{
static const wchar *Devices[]={L"CON",L"PRN",L"AUX",L"NUL",L"COM#",L"LPT#"};
wchar *s=Name+I;
bool MatchFound=false;
for (uint J=0;J<ASIZE(Devices);J++)
for (uint K=0;;K++)
if (Devices[J][K]=='#')
{
if (!IsDigit(s[K]))
break;
}
else
if (Devices[J][K]==0)
{
// Names like aux.txt are accessible without \\?\ prefix
// since Windows 11. Pure aux is still prohibited.
MatchFound=s[K]==0 || s[K]=='.' && !IsWindows11OrGreater() || IsPathDiv(s[K]);
break;
}
else
if (Devices[J][K]!=toupperw(s[K]))
break;
if (MatchFound)
{
wchar OrigName[NM];
wcsncpyz(OrigName,Name,ASIZE(OrigName));
if (MaxSize>I+1) // I+1, because we do not move the trailing 0.
memmove(s+1,s,(MaxSize-I-1)*sizeof(*s));
*s='_';
#ifndef SFX_MODULE
uiMsg(UIMSG_CORRECTINGNAME,nullptr);
uiMsg(UIERROR_RENAMING,nullptr,OrigName,Name);
#endif
}
}
} }
#endif #endif

@ -29,7 +29,6 @@ void GetConfigName(const wchar *Name,wchar *FullName,size_t MaxSize,bool CheckEx
wchar* GetVolNumPart(const wchar *ArcName); wchar* GetVolNumPart(const wchar *ArcName);
void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering); void NextVolumeName(wchar *ArcName,uint MaxLength,bool OldNumbering);
bool IsNameUsable(const wchar *Name); bool IsNameUsable(const wchar *Name);
void MakeNameUsable(char *Name,bool Extended);
void MakeNameUsable(wchar *Name,bool Extended); void MakeNameUsable(wchar *Name,bool Extended);
void UnixSlashToDos(const char *SrcName,char *DestName,size_t MaxLength); void UnixSlashToDos(const char *SrcName,char *DestName,size_t MaxLength);
@ -70,7 +69,8 @@ void GenerateArchiveName(wchar *ArcName,size_t MaxSize,const wchar *GenerateMask
#ifdef _WIN_ALL #ifdef _WIN_ALL
bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize); bool GetWinLongPath(const wchar *Src,wchar *Dest,size_t MaxSize);
void ConvertToPrecomposed(wchar *Name,size_t NameSize); void ConvertToPrecomposed(wchar *Name,size_t NameSize);
void MakeNameCompatible(wchar *Name); void MakeNameCompatible(wchar *Name,size_t MaxSize);
#endif #endif
#endif #endif

@ -97,7 +97,7 @@ void QuickOpen::Load(uint64 BlockPos)
if (Arc->SubHead.Encrypted) if (Arc->SubHead.Encrypted)
{ {
RAROptions *Cmd=Arc->GetRAROptions(); CommandData *Cmd=Arc->GetCommandData();
#ifndef RAR_NOCRYPT #ifndef RAR_NOCRYPT
if (Cmd->Password.IsSet()) if (Cmd->Password.IsSet())
Crypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,Arc->SubHead.Salt, Crypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,Arc->SubHead.Salt,

@ -12,10 +12,12 @@
#include "version.hpp" #include "version.hpp"
#include "rardefs.hpp" #include "rardefs.hpp"
#include "rarlang.hpp" #include "rarlang.hpp"
#include "rawint.hpp"
#include "unicode.hpp" #include "unicode.hpp"
#include "errhnd.hpp" #include "errhnd.hpp"
#include "secpassword.hpp" #include "secpassword.hpp"
#include "array.hpp" #include "array.hpp"
#include "strlist.hpp"
#include "timefn.hpp" #include "timefn.hpp"
#include "sha1.hpp" #include "sha1.hpp"
#include "sha256.hpp" #include "sha256.hpp"
@ -28,13 +30,11 @@
#include "headers.hpp" #include "headers.hpp"
#include "pathfn.hpp" #include "pathfn.hpp"
#include "strfn.hpp" #include "strfn.hpp"
#include "strlist.hpp"
#ifdef _WIN_ALL #ifdef _WIN_ALL
#include "isnt.hpp" #include "isnt.hpp"
#endif #endif
#include "file.hpp" #include "file.hpp"
#include "crc.hpp" #include "crc.hpp"
#include "ui.hpp"
#include "filefn.hpp" #include "filefn.hpp"
#include "filestr.hpp" #include "filestr.hpp"
#include "find.hpp" #include "find.hpp"
@ -47,11 +47,11 @@
#include "archive.hpp" #include "archive.hpp"
#include "match.hpp" #include "match.hpp"
#include "cmddata.hpp" #include "cmddata.hpp"
#include "ui.hpp"
#include "filcreat.hpp" #include "filcreat.hpp"
#include "consio.hpp" #include "consio.hpp"
#include "system.hpp" #include "system.hpp"
#include "log.hpp" #include "log.hpp"
#include "rawint.hpp"
#include "rawread.hpp" #include "rawread.hpp"
#include "encname.hpp" #include "encname.hpp"
#include "resource.hpp" #include "resource.hpp"

@ -9,9 +9,13 @@
#define ASIZE(x) (sizeof(x)/sizeof(x[0])) #define ASIZE(x) (sizeof(x)/sizeof(x[0]))
// MAXPASSWORD is expected to be multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE (16) // MAXPASSWORD and MAXPASSWORD_RAR are expected to be multiple of
// for CryptProtectMemory in SecPassword. // CRYPTPROTECTMEMORY_BLOCK_SIZE (16) for CryptProtectMemory in SecPassword.
#define MAXPASSWORD 128 // We allow a larger MAXPASSWORD to unpack archives with lengthy passwords
// in non-RAR formats in GUI versions. For RAR format we set MAXPASSWORD_RAR
// to 128 for compatibility and because it is enough for AES-256.
#define MAXPASSWORD 512
#define MAXPASSWORD_RAR 128
#define MAXSFXSIZE 0x200000 #define MAXSFXSIZE 0x200000

@ -84,7 +84,7 @@ inline uint32 RawGetBE4(const byte *m)
{ {
#if defined(USE_MEM_BYTESWAP) && defined(_MSC_VER) #if defined(USE_MEM_BYTESWAP) && defined(_MSC_VER)
return _byteswap_ulong(*(uint32 *)m); return _byteswap_ulong(*(uint32 *)m);
#elif defined(USE_MEM_BYTESWAP) && (__GNUC__ > 3) && (__GNUC_MINOR__ > 2) #elif defined(USE_MEM_BYTESWAP) && (defined(__clang__) || defined(__GNUC__))
return __builtin_bswap32(*(uint32 *)m); return __builtin_bswap32(*(uint32 *)m);
#else #else
return uint32(m[0]<<24) | uint32(m[1]<<16) | uint32(m[2]<<8) | m[3]; return uint32(m[0]<<24) | uint32(m[1]<<16) | uint32(m[2]<<8) | m[3];
@ -97,7 +97,7 @@ inline void RawPutBE4(uint32 i,byte *mem)
{ {
#if defined(USE_MEM_BYTESWAP) && defined(_MSC_VER) #if defined(USE_MEM_BYTESWAP) && defined(_MSC_VER)
*(uint32*)mem = _byteswap_ulong(i); *(uint32*)mem = _byteswap_ulong(i);
#elif defined(USE_MEM_BYTESWAP) && (__GNUC__ > 3) && (__GNUC_MINOR__ > 2) #elif defined(USE_MEM_BYTESWAP) && (defined(__clang__) || defined(__GNUC__))
*(uint32*)mem = __builtin_bswap32(i); *(uint32*)mem = __builtin_bswap32(i);
#else #else
mem[0]=byte(i>>24); mem[0]=byte(i>>24);
@ -112,7 +112,7 @@ inline uint32 ByteSwap32(uint32 i)
{ {
#ifdef _MSC_VER #ifdef _MSC_VER
return _byteswap_ulong(i); return _byteswap_ulong(i);
#elif (__GNUC__ > 3) && (__GNUC_MINOR__ > 2) #elif defined(__clang__) || defined(__GNUC__)
return __builtin_bswap32(i); return __builtin_bswap32(i);
#else #else
return (rotl32(i,24)&0xFF00FF00)|(rotl32(i,8)&0x00FF00FF); return (rotl32(i,24)&0xFF00FF00)|(rotl32(i,8)&0x00FF00FF);

@ -16,6 +16,7 @@ void ComprDataIO::Init()
UnpackFromMemory=false; UnpackFromMemory=false;
UnpackToMemory=false; UnpackToMemory=false;
UnpPackedSize=0; UnpPackedSize=0;
UnpPackedLeft=0;
ShowProgress=true; ShowProgress=true;
TestMode=false; TestMode=false;
SkipUnpCRC=false; SkipUnpCRC=false;
@ -35,7 +36,9 @@ void ComprDataIO::Init()
SubHead=NULL; SubHead=NULL;
SubHeadPos=NULL; SubHeadPos=NULL;
CurrentCommand=0; CurrentCommand=0;
ProcessedArcSize=TotalArcSize=0; ProcessedArcSize=0;
LastArcSize=0;
TotalArcSize=0;
} }
@ -75,10 +78,10 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
} }
else else
{ {
size_t SizeToRead=((int64)Count>UnpPackedSize) ? (size_t)UnpPackedSize:Count; size_t SizeToRead=((int64)Count>UnpPackedLeft) ? (size_t)UnpPackedLeft:Count;
if (SizeToRead > 0) if (SizeToRead > 0)
{ {
if (UnpVolume && Decryption && (int64)Count>UnpPackedSize) if (UnpVolume && Decryption && (int64)Count>UnpPackedLeft)
{ {
// We need aligned blocks for decryption and we want "Keep broken // We need aligned blocks for decryption and we want "Keep broken
// files" to work efficiently with missing encrypted volumes. // files" to work efficiently with missing encrypted volumes.
@ -109,7 +112,7 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
ReadAddr+=ReadSize; ReadAddr+=ReadSize;
Count-=ReadSize; Count-=ReadSize;
#endif #endif
UnpPackedSize-=ReadSize; UnpPackedLeft-=ReadSize;
// Do not ask for next volume if we read something from current volume. // Do not ask for next volume if we read something from current volume.
// If next volume is missing, we need to process all data from current // If next volume is missing, we need to process all data from current
@ -118,7 +121,7 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
// we ask for next volume also if we have non-aligned encryption block. // we ask for next volume also if we have non-aligned encryption block.
// Since we adjust data size for decryption earlier above, // Since we adjust data size for decryption earlier above,
// it does not hurt "Keep broken files" mode efficiency. // it does not hurt "Keep broken files" mode efficiency.
if (UnpVolume && UnpPackedSize == 0 && if (UnpVolume && UnpPackedLeft == 0 &&
(ReadSize==0 || Decryption && (TotalRead & CRYPT_BLOCK_MASK) != 0) ) (ReadSize==0 || Decryption && (TotalRead & CRYPT_BLOCK_MASK) != 0) )
{ {
#ifndef NOVOLUME #ifndef NOVOLUME
@ -134,7 +137,7 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
} }
Archive *SrcArc=(Archive *)SrcFile; Archive *SrcArc=(Archive *)SrcFile;
if (SrcArc!=NULL) if (SrcArc!=NULL)
ShowUnpRead(SrcArc->CurBlockPos+CurUnpRead,UnpArcSize); ShowUnpRead(SrcArc->NextBlockPos-UnpPackedSize+CurUnpRead,TotalArcSize);
if (ReadSize!=-1) if (ReadSize!=-1)
{ {
ReadSize=TotalRead; ReadSize=TotalRead;
@ -148,18 +151,11 @@ int ComprDataIO::UnpRead(byte *Addr,size_t Count)
} }
#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
// Disable the run time stack check for unrar.dll, so we can manipulate
// with ProcessDataProc call type below. Run time check would intercept
// a wrong ESP before we restore it.
#pragma runtime_checks( "s", off )
#endif
void ComprDataIO::UnpWrite(byte *Addr,size_t Count) void ComprDataIO::UnpWrite(byte *Addr,size_t Count)
{ {
#ifdef RARDLL #ifdef RARDLL
RAROptions *Cmd=((Archive *)SrcFile)->GetRAROptions(); CommandData *Cmd=((Archive *)SrcFile)->GetCommandData();
if (Cmd->DllOpMode!=RAR_SKIP) if (Cmd->DllOpMode!=RAR_SKIP)
{ {
if (Cmd->Callback!=NULL && if (Cmd->Callback!=NULL &&
@ -167,28 +163,7 @@ void ComprDataIO::UnpWrite(byte *Addr,size_t Count)
ErrHandler.Exit(RARX_USERBREAK); ErrHandler.Exit(RARX_USERBREAK);
if (Cmd->ProcessDataProc!=NULL) if (Cmd->ProcessDataProc!=NULL)
{ {
// Here we preserve ESP value. It is necessary for those developers,
// who still define ProcessDataProc callback as "C" type function,
// even though in year 2001 we announced in unrar.dll whatsnew.txt
// that it will be PASCAL type (for compatibility with Visual Basic).
#if defined(_MSC_VER)
#ifndef _WIN_64
__asm mov ebx,esp
#endif
#elif defined(_WIN_ALL) && defined(__BORLANDC__)
_EBX=_ESP;
#endif
int RetCode=Cmd->ProcessDataProc(Addr,(int)Count); int RetCode=Cmd->ProcessDataProc(Addr,(int)Count);
// Restore ESP after ProcessDataProc with wrongly defined calling
// convention broken it.
#if defined(_MSC_VER)
#ifndef _WIN_64
__asm mov esp,ebx
#endif
#elif defined(_WIN_ALL) && defined(__BORLANDC__)
_ESP=_EBX;
#endif
if (RetCode==0) if (RetCode==0)
ErrHandler.Exit(RARX_USERBREAK); ErrHandler.Exit(RARX_USERBREAK);
} }
@ -216,11 +191,6 @@ void ComprDataIO::UnpWrite(byte *Addr,size_t Count)
Wait(); Wait();
} }
#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
// Restore the run time stack check for unrar.dll.
#pragma runtime_checks( "s", restore )
#endif
@ -230,15 +200,11 @@ void ComprDataIO::ShowUnpRead(int64 ArcPos,int64 ArcSize)
{ {
if (ShowProgress && SrcFile!=NULL) if (ShowProgress && SrcFile!=NULL)
{ {
if (TotalArcSize!=0) // Important when processing several archives or multivolume archive.
{ ArcPos+=ProcessedArcSize;
// important when processing several archives or multivolume archive
ArcSize=TotalArcSize;
ArcPos+=ProcessedArcSize;
}
Archive *SrcArc=(Archive *)SrcFile; Archive *SrcArc=(Archive *)SrcFile;
RAROptions *Cmd=SrcArc->GetRAROptions(); CommandData *Cmd=SrcArc->GetCommandData();
int CurPercent=ToPercent(ArcPos,ArcSize); int CurPercent=ToPercent(ArcPos,ArcSize);
if (!Cmd->DisablePercentage && CurPercent!=LastPercent) if (!Cmd->DisablePercentage && CurPercent!=LastPercent)
@ -333,3 +299,37 @@ void ComprDataIO::SetUnpackFromMemory(byte *Addr,uint Size)
UnpackFromMemoryAddr=Addr; UnpackFromMemoryAddr=Addr;
UnpackFromMemorySize=Size; UnpackFromMemorySize=Size;
} }
// Extraction progress is based on the position in archive and we adjust
// the total archives size here, so trailing blocks do not prevent progress
// reaching 100% at the end of extraction. Alternatively we could print "100%"
// after completing the entire archive extraction, but then we would need
// to take into account possible messages like the checksum error after
// last file percent progress.
void ComprDataIO::AdjustTotalArcSize(Archive *Arc)
{
// If we know a position of QO or RR blocks, use them to adjust the total
// packed size to beginning of these blocks. Earlier we already calculated
// the total size based on entire archive sizes. We also set LastArcSize
// to start of first trailing block, to add it later to ProcessedArcSize.
int64 ArcLength=Arc->IsSeekable() ? Arc->FileLength() : 0;
if (Arc->MainHead.QOpenOffset!=0) // QO is always preceding RR record.
LastArcSize=Arc->MainHead.QOpenOffset;
else
if (Arc->MainHead.RROffset!=0)
LastArcSize=Arc->MainHead.RROffset;
else
{
// If neither QO nor RR are found, exclude the approximate size of
// end of archive block.
// We select EndBlock to be larger than typical 8 bytes HEAD_ENDARC,
// but to not exceed the smallest 22 bytes HEAD_FILE with 1 byte file
// name, so we do not have two files with 100% at the end of archive.
const uint EndBlock=23;
if (ArcLength>EndBlock)
LastArcSize=ArcLength-EndBlock;
}
TotalArcSize-=ArcLength-LastArcSize;
}

@ -1,6 +1,7 @@
#ifndef _RAR_DATAIO_ #ifndef _RAR_DATAIO_
#define _RAR_DATAIO_ #define _RAR_DATAIO_
class Archive;
class CmdAdd; class CmdAdd;
class Unpack; class Unpack;
class ArcFileSearch; class ArcFileSearch;
@ -29,6 +30,7 @@ class ComprDataIO
byte *UnpWrAddr; byte *UnpWrAddr;
int64 UnpPackedSize; int64 UnpPackedSize;
int64 UnpPackedLeft;
bool ShowProgress; bool ShowProgress;
bool TestMode; bool TestMode;
@ -61,7 +63,7 @@ class ComprDataIO
void UnpWrite(byte *Addr,size_t Count); void UnpWrite(byte *Addr,size_t Count);
void EnableShowProgress(bool Show) {ShowProgress=Show;} void EnableShowProgress(bool Show) {ShowProgress=Show;}
void GetUnpackedData(byte **Data,size_t *Size); void GetUnpackedData(byte **Data,size_t *Size);
void SetPackedSizeToRead(int64 Size) {UnpPackedSize=Size;} void SetPackedSizeToRead(int64 Size) {UnpPackedSize=UnpPackedLeft=Size;}
void SetTestMode(bool Mode) {TestMode=Mode;} void SetTestMode(bool Mode) {TestMode=Mode;}
void SetSkipUnpCRC(bool Skip) {SkipUnpCRC=Skip;} void SetSkipUnpCRC(bool Skip) {SkipUnpCRC=Skip;}
void SetNoFileHeader(bool Mode) {NoFileHeader=Mode;} void SetNoFileHeader(bool Mode) {NoFileHeader=Mode;}
@ -76,12 +78,12 @@ class ComprDataIO
void SetUnpackToMemory(byte *Addr,uint Size); void SetUnpackToMemory(byte *Addr,uint Size);
void SetUnpackFromMemory(byte *Addr,uint Size); void SetUnpackFromMemory(byte *Addr,uint Size);
void SetCurrentCommand(wchar Cmd) {CurrentCommand=Cmd;} void SetCurrentCommand(wchar Cmd) {CurrentCommand=Cmd;}
void AdjustTotalArcSize(Archive *Arc);
bool PackVolume; bool PackVolume;
bool UnpVolume; bool UnpVolume;
bool NextVolumeMissing; bool NextVolumeMissing;
int64 UnpArcSize;
int64 CurPackRead,CurPackWrite,CurUnpRead,CurUnpWrite; int64 CurPackRead,CurPackWrite,CurUnpRead,CurUnpWrite;
@ -89,6 +91,9 @@ class ComprDataIO
// Used to calculate the total operation progress. // Used to calculate the total operation progress.
int64 ProcessedArcSize; int64 ProcessedArcSize;
// Last extracted archive size up to QO or RR block.
int64 LastArcSize;
int64 TotalArcSize; int64 TotalArcSize;
DataHash PackedDataHash; // Packed write and unpack read hash. DataHash PackedDataHash; // Packed write and unpack read hash.

@ -5,7 +5,7 @@
bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent) bool RecVolumesRestore(CommandData *Cmd,const wchar *Name,bool Silent)
{ {
Archive Arc(Cmd); Archive Arc(Cmd);
if (!Arc.Open(Name)) if (!Arc.Open(Name))
@ -42,7 +42,7 @@ bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent)
} }
void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name) void RecVolumesTest(CommandData *Cmd,Archive *Arc,const wchar *Name)
{ {
wchar RevName[NM]; wchar RevName[NM];
*RevName=0; *RevName=0;

@ -14,11 +14,11 @@ class RecVolumes3
ThreadPool *RSThreadPool; ThreadPool *RSThreadPool;
#endif #endif
public: public:
RecVolumes3(RAROptions *Cmd,bool TestOnly); RecVolumes3(CommandData *Cmd,bool TestOnly);
~RecVolumes3(); ~RecVolumes3();
void Make(RAROptions *Cmd,wchar *ArcName); void Make(CommandData *Cmd,wchar *ArcName);
bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent); bool Restore(CommandData *Cmd,const wchar *Name,bool Silent);
void Test(RAROptions *Cmd,const wchar *Name); void Test(CommandData *Cmd,const wchar *Name);
}; };
@ -48,8 +48,8 @@ struct RecRSThreadData
class RecVolumes5 class RecVolumes5
{ {
private: private:
void ProcessRS(RAROptions *Cmd,uint DataNum,const byte *Data,uint MaxRead,bool Encode); void ProcessRS(CommandData *Cmd,uint DataNum,const byte *Data,uint MaxRead,bool Encode);
void ProcessRS(RAROptions *Cmd,uint MaxRead,bool Encode); void ProcessRS(CommandData *Cmd,uint MaxRead,bool Encode);
uint ReadHeader(File *RecFile,bool FirstRev); uint ReadHeader(File *RecFile,bool FirstRev);
Array<RecVolItem> RecItems; Array<RecVolItem> RecItems;
@ -76,13 +76,13 @@ class RecVolumes5
public: // 'public' only because called from thread functions. public: // 'public' only because called from thread functions.
void ProcessAreaRS(RecRSThreadData *td); void ProcessAreaRS(RecRSThreadData *td);
public: public:
RecVolumes5(RAROptions *Cmd,bool TestOnly); RecVolumes5(CommandData *Cmd,bool TestOnly);
~RecVolumes5(); ~RecVolumes5();
bool Restore(RAROptions *Cmd,const wchar *Name,bool Silent); bool Restore(CommandData *Cmd,const wchar *Name,bool Silent);
void Test(RAROptions *Cmd,const wchar *Name); void Test(CommandData *Cmd,const wchar *Name);
}; };
bool RecVolumesRestore(RAROptions *Cmd,const wchar *Name,bool Silent); bool RecVolumesRestore(CommandData *Cmd,const wchar *Name,bool Silent);
void RecVolumesTest(RAROptions *Cmd,Archive *Arc,const wchar *Name); void RecVolumesTest(CommandData *Cmd,Archive *Arc,const wchar *Name);
#endif #endif

@ -36,7 +36,7 @@ THREAD_PROC(RSDecodeThread)
} }
#endif #endif
RecVolumes3::RecVolumes3(RAROptions *Cmd,bool TestOnly) RecVolumes3::RecVolumes3(CommandData *Cmd,bool TestOnly)
{ {
memset(SrcFile,0,sizeof(SrcFile)); memset(SrcFile,0,sizeof(SrcFile));
if (TestOnly) if (TestOnly)
@ -99,7 +99,7 @@ static bool IsNewStyleRev(const wchar *Name)
} }
bool RecVolumes3::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) bool RecVolumes3::Restore(CommandData *Cmd,const wchar *Name,bool Silent)
{ {
wchar ArcName[NM]; wchar ArcName[NM];
wcsncpyz(ArcName,Name,ASIZE(ArcName)); wcsncpyz(ArcName,Name,ASIZE(ArcName));
@ -497,7 +497,7 @@ void RSEncode::DecodeBuf()
} }
void RecVolumes3::Test(RAROptions *Cmd,const wchar *Name) void RecVolumes3::Test(CommandData *Cmd,const wchar *Name)
{ {
if (!IsNewStyleRev(Name)) // RAR 3.0 name#_#_#.rev do not include CRC32. if (!IsNewStyleRev(Name)) // RAR 3.0 name#_#_#.rev do not include CRC32.
{ {

@ -1,6 +1,10 @@
static const uint MaxVolumes=65535; static const uint MaxVolumes=65535;
RecVolumes5::RecVolumes5(RAROptions *Cmd,bool TestOnly) // We select this limit arbitrarily, to prevent user creating too many
// rev files by mistake.
#define MAX_REV_TO_DATA_RATIO 10 // 1000% of rev files.
RecVolumes5::RecVolumes5(CommandData *Cmd,bool TestOnly)
{ {
RealBuf=NULL; RealBuf=NULL;
RealReadBuffer=NULL; RealReadBuffer=NULL;
@ -66,7 +70,7 @@ THREAD_PROC(RecThreadRS)
#endif #endif
void RecVolumes5::ProcessRS(RAROptions *Cmd,uint DataNum,const byte *Data,uint MaxRead,bool Encode) void RecVolumes5::ProcessRS(CommandData *Cmd,uint DataNum,const byte *Data,uint MaxRead,bool Encode)
{ {
/* /*
RSCoder16 RS; RSCoder16 RS;
@ -137,7 +141,7 @@ void RecVolumes5::ProcessAreaRS(RecRSThreadData *td)
bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent) bool RecVolumes5::Restore(CommandData *Cmd,const wchar *Name,bool Silent)
{ {
wchar ArcName[NM]; wchar ArcName[NM];
wcsncpyz(ArcName,Name,ASIZE(ArcName)); wcsncpyz(ArcName,Name,ASIZE(ArcName));
@ -145,13 +149,16 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
wchar *Num=GetVolNumPart(ArcName); wchar *Num=GetVolNumPart(ArcName);
while (Num>ArcName && IsDigit(*(Num-1))) while (Num>ArcName && IsDigit(*(Num-1)))
Num--; Num--;
if (Num==ArcName) if (Num<=PointToName(ArcName))
return false; // Numeric part is missing or entire volume name is numeric, not possible for RAR or REV volume. 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)); wcsncpyz(Num,L"*.*",ASIZE(ArcName)-(Num-ArcName));
wchar FirstVolName[NM]; wchar FirstVolName[NM];
*FirstVolName=0; *FirstVolName=0;
wchar LongestRevName[NM];
*LongestRevName=0;
int64 RecFileSize=0; int64 RecFileSize=0;
FindFile VolFind; FindFile VolFind;
@ -164,7 +171,7 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
Archive *Vol=new Archive(Cmd); Archive *Vol=new Archive(Cmd);
int ItemPos=-1; int ItemPos=-1;
if (Vol->WOpen(fd.Name)) if (!fd.IsDir && Vol->WOpen(fd.Name))
{ {
if (CmpExt(fd.Name,L"rev")) if (CmpExt(fd.Name,L"rev"))
{ {
@ -176,6 +183,9 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
ItemPos=RecNum; ItemPos=RecNum;
FoundRecVolumes++; FoundRecVolumes++;
if (wcslen(fd.Name)>wcslen(LongestRevName))
wcsncpyz(LongestRevName,fd.Name,ASIZE(LongestRevName));
} }
} }
else else
@ -231,6 +241,15 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
if (FoundRecVolumes==0) if (FoundRecVolumes==0)
return false; return false;
// If we did not find even a single .rar volume, create .rar volume name
// based on the longest .rev file name. Use longest .rev, so we have
// enough space for volume number.
if (*FirstVolName==0)
{
SetExt(LongestRevName,L"rar",ASIZE(LongestRevName));
VolNameToFirstName(LongestRevName,FirstVolName,ASIZE(FirstVolName),true);
}
uiMsg(UIMSG_RECVOLCALCCHECKSUM); uiMsg(UIMSG_RECVOLCALCCHECKSUM);
MissingVolumes=0; MissingVolumes=0;
@ -301,7 +320,7 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
Item->f=NULL; Item->f=NULL;
} }
if ((Item->New=(Item->f==NULL))) // Additional parentheses to avoid GCC warning. if ((Item->New=(Item->f==NULL))==true)
{ {
wcsncpyz(Item->Name,FirstVolName,ASIZE(Item->Name)); wcsncpyz(Item->Name,FirstVolName,ASIZE(Item->Name));
uiMsg(UIMSG_CREATING,Item->Name); uiMsg(UIMSG_CREATING,Item->Name);
@ -316,7 +335,6 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
} }
NewVol->Prealloc(Item->FileSize); NewVol->Prealloc(Item->FileSize);
Item->f=NewVol; Item->f=NewVol;
Item->New=true;
} }
NextVolumeName(FirstVolName,ASIZE(FirstVolName),false); NextVolumeName(FirstVolName,ASIZE(FirstVolName),false);
} }
@ -346,13 +364,11 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
RecBufferSize&=~(SSE_ALIGNMENT-1); // Align for SSE. RecBufferSize&=~(SSE_ALIGNMENT-1); // Align for SSE.
#endif #endif
uint *Data=new uint[TotalCount];
RSCoder16 RS; RSCoder16 RS;
if (!RS.Init(DataCount,RecCount,ValidFlags)) if (!RS.Init(DataCount,RecCount,ValidFlags))
{ {
uiMsg(UIERROR_OPFAILED);
delete[] ValidFlags; delete[] ValidFlags;
delete[] Data;
return false; // Should not happen, we check parameter validity above. return false; // Should not happen, we check parameter validity above.
} }
@ -415,7 +431,6 @@ bool RecVolumes5::Restore(RAROptions *Cmd,const wchar *Name,bool Silent)
RecItems[I].f->Close(); RecItems[I].f->Close();
delete[] ValidFlags; delete[] ValidFlags;
delete[] Data;
#if !defined(SILENT) #if !defined(SILENT)
if (!Cmd->DisablePercentage) if (!Cmd->DisablePercentage)
mprintf(L"\b\b\b\b100%%"); mprintf(L"\b\b\b\b100%%");
@ -479,7 +494,7 @@ uint RecVolumes5::ReadHeader(File *RecFile,bool FirstRev)
} }
void RecVolumes5::Test(RAROptions *Cmd,const wchar *Name) void RecVolumes5::Test(CommandData *Cmd,const wchar *Name)
{ {
wchar VolName[NM]; wchar VolName[NM];
wcsncpyz(VolName,Name,ASIZE(VolName)); wcsncpyz(VolName,Name,ASIZE(VolName));

@ -1,22 +1,40 @@
/*************************************************************************** /**************************************************************************
* This code is based on public domain Szymon Stefanek AES implementation: * * This code is based on Szymon Stefanek public domain AES implementation *
* http://www.pragmaware.net/software/rijndael/index.php * **************************************************************************/
* *
* Dynamic tables generation is based on the Brian Gladman work: *
* http://fp.gladman.plus.com/cryptography_technology/rijndael *
***************************************************************************/
#include "rar.hpp" #include "rar.hpp"
#ifdef USE_SSE #ifdef USE_SSE
#include <wmmintrin.h> #include <wmmintrin.h>
#endif #endif
// not thread-safe ? static byte S[256]=
//static byte S[256],S5[256],rcon[30]; {
//static byte T1[256][4],T2[256][4],T3[256][4],T4[256][4]; 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
//static byte T5[256][4],T6[256][4],T7[256][4],T8[256][4]; 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192,
//static byte U1[256][4],U2[256][4],U3[256][4],U4[256][4]; 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21,
4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117,
9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132,
83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207,
208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168,
81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210,
205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115,
96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219,
224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121,
231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8,
186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138,
112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158,
225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22
};
static byte S5[256];
// Round constants. 10 items are used by AES-128, 8 by AES-192, 7 by AES-256.
static byte rcon[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36};
static byte T1[256][4],T2[256][4],T3[256][4],T4[256][4];
static byte T5[256][4],T6[256][4],T7[256][4],T8[256][4];
static byte U1[256][4],U2[256][4],U3[256][4],U4[256][4];
inline void Xor128(void *dest,const void *arg1,const void *arg2) inline void Xor128(void *dest,const void *arg1,const void *arg2)
{ {
@ -64,7 +82,7 @@ inline void Copy128(byte *dest,const byte *src)
Rijndael::Rijndael() Rijndael::Rijndael()
{ {
//if (S[0]==0) if (S5[0]==0)
GenerateTables(); GenerateTables();
CBCMode = true; // Always true for RAR. CBCMode = true; // Always true for RAR.
} }
@ -72,18 +90,20 @@ Rijndael::Rijndael()
void Rijndael::Init(bool Encrypt,const byte *key,uint keyLen,const byte * initVector) void Rijndael::Init(bool Encrypt,const byte *key,uint keyLen,const byte * initVector)
{ {
#ifdef USE_SSE // Check SIMD here instead of constructor, so if object is a part of some
// Check SSE here instead of constructor, so if object is a part of some // structure memset'ed before use, these variables are not lost.
// structure memset'ed before use, this variable is not lost. #if defined(USE_SSE)
int CPUInfo[4]; int CPUInfo[4];
__cpuid(CPUInfo, 0x80000000); // Get the maximum supported cpuid function. __cpuid(CPUInfo, 0);
if ((CPUInfo[0] & 0x7fffffff)>=1) if (CPUInfo[0]>=1) // Check the maximum supported cpuid function.
{ {
__cpuid(CPUInfo, 1); __cpuid(CPUInfo, 1);
AES_NI=(CPUInfo[2] & 0x2000000)!=0; AES_NI=(CPUInfo[2] & 0x2000000)!=0;
} }
else else
AES_NI=0; AES_NI=false;
#elif defined(USE_NEON)
AES_Neon=(getauxval(AT_HWCAP) & HWCAP_AES)!=0;
#endif #endif
// Other developers asked us to initialize it to suppress "may be used // Other developers asked us to initialize it to suppress "may be used
@ -123,18 +143,25 @@ void Rijndael::Init(bool Encrypt,const byte *key,uint keyLen,const byte * initVe
keyEncToDec(); keyEncToDec();
} }
void Rijndael::blockEncrypt(const byte *input,size_t inputLen,byte *outBuffer) void Rijndael::blockEncrypt(const byte *input,size_t inputLen,byte *outBuffer)
{ {
if (inputLen <= 0) if (inputLen <= 0)
return; return;
size_t numBlocks = inputLen/16; size_t numBlocks = inputLen/16;
#ifdef USE_SSE #if defined(USE_SSE)
if (AES_NI) if (AES_NI)
{ {
blockEncryptSSE(input,numBlocks,outBuffer); blockEncryptSSE(input,numBlocks,outBuffer);
return; return;
} }
#elif defined(USE_NEON)
if (AES_Neon)
{
blockEncryptNeon(input,numBlocks,outBuffer);
return;
}
#endif #endif
byte *prevBlock = m_initVector; byte *prevBlock = m_initVector;
@ -221,6 +248,40 @@ void Rijndael::blockEncryptSSE(const byte *input,size_t numBlocks,byte *outBuffe
} }
#endif #endif
#ifdef USE_NEON
void Rijndael::blockEncryptNeon(const byte *input,size_t numBlocks,byte *outBuffer)
{
byte *prevBlock = m_initVector;
while (numBlocks > 0)
{
byte block[16];
if (CBCMode)
vst1q_u8(block, veorq_u8(vld1q_u8(prevBlock), vld1q_u8(input)));
else
vst1q_u8(block, vld1q_u8(input));
uint8x16_t data = vld1q_u8(block);
for (uint i = 0; i < m_uRounds-1; i++)
{
data = vaeseq_u8(data, vld1q_u8((byte *)m_expandedKey[i]));
data = vaesmcq_u8(data);
}
data = vaeseq_u8(data, vld1q_u8((byte *)(m_expandedKey[m_uRounds-1])));
data = veorq_u8(data, vld1q_u8((byte *)(m_expandedKey[m_uRounds])));
vst1q_u8(outBuffer, data);
prevBlock=outBuffer;
outBuffer += 16;
input += 16;
numBlocks--;
}
vst1q_u8(m_initVector, vld1q_u8(prevBlock));
return;
}
#endif
void Rijndael::blockDecrypt(const byte *input, size_t inputLen, byte *outBuffer) void Rijndael::blockDecrypt(const byte *input, size_t inputLen, byte *outBuffer)
{ {
@ -228,12 +289,18 @@ void Rijndael::blockDecrypt(const byte *input, size_t inputLen, byte *outBuffer)
return; return;
size_t numBlocks=inputLen/16; size_t numBlocks=inputLen/16;
#ifdef USE_SSE #if defined(USE_SSE)
if (AES_NI) if (AES_NI)
{ {
blockDecryptSSE(input,numBlocks,outBuffer); blockDecryptSSE(input,numBlocks,outBuffer);
return; return;
} }
#elif defined(USE_NEON)
if (AES_Neon)
{
blockDecryptNeon(input,numBlocks,outBuffer);
return;
}
#endif #endif
byte block[16], iv[4][4]; byte block[16], iv[4][4];
@ -325,6 +392,41 @@ void Rijndael::blockDecryptSSE(const byte *input, size_t numBlocks, byte *outBuf
#endif #endif
#ifdef USE_NEON
void Rijndael::blockDecryptNeon(const byte *input, size_t numBlocks, byte *outBuffer)
{
byte iv[16];
memcpy(iv,m_initVector,16);
while (numBlocks > 0)
{
uint8x16_t data = vld1q_u8(input);
for (int i=m_uRounds-1; i>0; i--)
{
data = vaesdq_u8(data, vld1q_u8((byte *)m_expandedKey[i+1]));
data = vaesimcq_u8(data);
}
data = vaesdq_u8(data, vld1q_u8((byte *)m_expandedKey[1]));
data = veorq_u8(data, vld1q_u8((byte *)m_expandedKey[0]));
if (CBCMode)
data = veorq_u8(data, vld1q_u8(iv));
vst1q_u8(iv, vld1q_u8(input));
vst1q_u8(outBuffer, data);
input += 16;
outBuffer += 16;
numBlocks--;
}
memcpy(m_initVector,iv,16);
}
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ALGORITHM // ALGORITHM
////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -417,51 +519,40 @@ void Rijndael::keyEncToDec()
} }
#define ff_poly 0x011b static byte gmul(byte a, byte b) // Galois field "peasant's algorithm" multiplication.
#define ff_hi 0x80 {
const byte poly=0x1b; // Lower byte of AES 0x11b irreducible polynomial.
#define FFinv(x) ((x) ? pow[255 - log[x]]: 0) byte result = 0;
while (b>0)
#define FFmul02(x) (x ? pow[log[x] + 0x19] : 0) {
#define FFmul03(x) (x ? pow[log[x] + 0x01] : 0) if ((b & 1) != 0)
#define FFmul09(x) (x ? pow[log[x] + 0xc7] : 0) result ^= a;
#define FFmul0b(x) (x ? pow[log[x] + 0x68] : 0) a = (a & 0x80) ? (a<<1)^poly : a<<1;
#define FFmul0d(x) (x ? pow[log[x] + 0xee] : 0) b >>= 1;
#define FFmul0e(x) (x ? pow[log[x] + 0xdf] : 0) }
#define fwd_affine(x) \ return result;
(w = (uint)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), (byte)(0x63^(w^(w>>8)))) }
#define inv_affine(x) \
(w = (uint)x, w = (w<<1)^(w<<3)^(w<<6), (byte)(0x05^(w^(w>>8))))
// 2021-09-24: changed to slower and simpler code without interim tables.
// It is still fast enough for our purpose.
void Rijndael::GenerateTables() void Rijndael::GenerateTables()
{ {
unsigned char pow[512],log[256]; for (int I=0;I<256;I++)
int i = 0, w = 1; S5[S[I]]=I;
do
{ for (int I=0;I<256;I++)
pow[i] = (byte)w;
pow[i + 255] = (byte)w;
log[w] = (byte)i++;
w ^= (w << 1) ^ (w & ff_hi ? ff_poly : 0);
} while (w != 1);
for (int i = 0,w = 1; i < sizeof(rcon)/sizeof(rcon[0]); i++)
{
rcon[i] = w;
w = (w << 1) ^ (w & ff_hi ? ff_poly : 0);
}
for(int i = 0; i < 256; ++i)
{ {
unsigned char b=S[i]=fwd_affine(FFinv((byte)i)); byte s=S[I];
T1[i][1]=T1[i][2]=T2[i][2]=T2[i][3]=T3[i][0]=T3[i][3]=T4[i][0]=T4[i][1]=b; T1[I][1]=T1[I][2]=T2[I][2]=T2[I][3]=T3[I][0]=T3[I][3]=T4[I][0]=T4[I][1]=s;
T1[i][0]=T2[i][1]=T3[i][2]=T4[i][3]=FFmul02(b); T1[I][0]=T2[I][1]=T3[I][2]=T4[I][3]=gmul(s,2);
T1[i][3]=T2[i][0]=T3[i][1]=T4[i][2]=FFmul03(b); T1[I][3]=T2[I][0]=T3[I][1]=T4[I][2]=gmul(s,3);
S5[i] = b = FFinv(inv_affine((byte)i));
U1[b][3]=U2[b][0]=U3[b][1]=U4[b][2]=T5[i][3]=T6[i][0]=T7[i][1]=T8[i][2]=FFmul0b(b); byte b=S5[I];
U1[b][1]=U2[b][2]=U3[b][3]=U4[b][0]=T5[i][1]=T6[i][2]=T7[i][3]=T8[i][0]=FFmul09(b); U1[b][3]=U2[b][0]=U3[b][1]=U4[b][2]=T5[I][3]=T6[I][0]=T7[I][1]=T8[I][2]=gmul(b,0xb);
U1[b][2]=U2[b][3]=U3[b][0]=U4[b][1]=T5[i][2]=T6[i][3]=T7[i][0]=T8[i][1]=FFmul0d(b); U1[b][1]=U2[b][2]=U3[b][3]=U4[b][0]=T5[I][1]=T6[I][2]=T7[I][3]=T8[I][0]=gmul(b,0x9);
U1[b][0]=U2[b][1]=U3[b][2]=U4[b][3]=T5[i][0]=T6[i][1]=T7[i][2]=T8[i][3]=FFmul0e(b); U1[b][2]=U2[b][3]=U3[b][0]=U4[b][1]=T5[I][2]=T6[I][3]=T7[I][0]=T8[I][1]=gmul(b,0xd);
U1[b][0]=U2[b][1]=U3[b][2]=U4[b][3]=T5[I][0]=T6[I][1]=T7[I][2]=T8[I][3]=gmul(b,0xe);
} }
} }

@ -2,11 +2,7 @@
#define _RIJNDAEL_H_ #define _RIJNDAEL_H_
/************************************************************************** /**************************************************************************
* This code is based on Szymon Stefanek AES implementation: * * This code is based on Szymon Stefanek public domain AES implementation *
* http://www.esat.kuleuven.ac.be/~rijmen/rijndael/rijndael-cpplib.tar.gz *
* *
* Dynamic tables generation is based on the Brian Gladman's work: *
* http://fp.gladman.plus.com/cryptography_technology/rijndael *
**************************************************************************/ **************************************************************************/
#define _MAX_KEY_COLUMNS (256/32) #define _MAX_KEY_COLUMNS (256/32)
@ -22,6 +18,16 @@ class Rijndael
bool AES_NI; bool AES_NI;
#endif #endif
#ifdef USE_NEON
// Set "crypto" attribute as replacement of -march=armv8-a+crypto switch.
__attribute__((target("crypto")))
void blockEncryptNeon(const byte *input,size_t numBlocks,byte *outBuffer);
__attribute__((target("crypto")))
void blockDecryptNeon(const byte *input, size_t numBlocks, byte *outBuffer);
bool AES_Neon;
#endif
void keySched(byte key[_MAX_KEY_COLUMNS][4]); void keySched(byte key[_MAX_KEY_COLUMNS][4]);
void keyEncToDec(); void keyEncToDec();
void GenerateTables(); void GenerateTables();
@ -33,11 +39,6 @@ class Rijndael
int m_uRounds; int m_uRounds;
byte m_initVector[MAX_IV_SIZE]; byte m_initVector[MAX_IV_SIZE];
byte m_expandedKey[_MAX_ROUNDS+1][4][4]; byte m_expandedKey[_MAX_ROUNDS+1][4][4];
byte S[256],S5[256],rcon[30];
byte T1[256][4],T2[256][4],T3[256][4],T4[256][4];
byte T5[256][4],T6[256][4],T7[256][4],T8[256][4];
byte U1[256][4],U2[256][4],U3[256][4],U4[256][4];
public: public:
Rijndael(); Rijndael();
void Init(bool Encrypt,const byte *key,uint keyLen,const byte *initVector); void Init(bool Encrypt,const byte *key,uint keyLen,const byte *initVector);

@ -95,7 +95,9 @@ bool RSCoder16::Init(uint DataCount, uint RecCount, bool *ValidityFlags)
if (NE > ValidECC || NE == 0 || ValidECC == 0) if (NE > ValidECC || NE == 0 || ValidECC == 0)
return false; return false;
} }
if (ND + NR > gfSize || NR > ND || ND == 0 || NR == 0)
// 2021.09.01 - we allowed RR and REV >100%, so no more NR > ND check.
if (ND + NR > gfSize || /*NR > ND ||*/ ND == 0 || NR == 0)
return false; return false;
delete[] MX; delete[] MX;

@ -1,40 +0,0 @@
#ifndef _RAR_SAVEPOS_
#define _RAR_SAVEPOS_
class SaveFilePos
{
private:
File *SaveFile;
int64 SavePos;
public:
SaveFilePos(File &Src)
{
SaveFile=&Src;
SavePos=Src.Tell();
}
~SaveFilePos()
{
// 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();
}
}
}
};
#endif

@ -215,10 +215,23 @@ bool ScanTree::GetNextMask()
UnixSlashToDos(CurMask,CurMask,ASIZE(CurMask)); UnixSlashToDos(CurMask,CurMask,ASIZE(CurMask));
#endif #endif
// We wish to scan entire disk if mask like c:\ is specified /*
// regardless of recursion mode. Use c:\*.* mask when need to scan only We prefer to scan entire disk if mask like \\server\share\ or c:\
// the root directory. is specified regardless of recursion mode. Use \\server\share\*.*
ScanEntireDisk=IsDriveLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0; or c:\*.* mask to scan only the root directory.
*/
if (CurMask[0]=='\\' && CurMask[1]=='\\')
{
const wchar *Slash=wcschr(CurMask+2,'\\');
if (Slash!=NULL)
{
Slash=wcschr(Slash+1,'\\');
ScanEntireDisk=Slash!=NULL && *(Slash+1)==0;
}
}
else
ScanEntireDisk=IsDriveLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0;
wchar *Name=PointToName(CurMask); wchar *Name=PointToName(CurMask);
if (*Name==0) if (*Name==0)

@ -56,7 +56,6 @@ static CryptLoader GlobalCryptLoader;
SecPassword::SecPassword() SecPassword::SecPassword()
{ {
CrossProcess=false;
Set(L""); Set(L"");
} }
@ -70,7 +69,8 @@ SecPassword::~SecPassword()
void SecPassword::Clean() void SecPassword::Clean()
{ {
PasswordSet=false; PasswordSet=false;
cleandata(Password,sizeof(Password)); if (Password.size()>0)
cleandata(&Password[0],Password.size());
} }
@ -104,7 +104,7 @@ void SecPassword::Process(const wchar *Src,size_t SrcSize,wchar *Dst,size_t DstS
// Source string can be shorter than destination as in case when we process // Source string can be shorter than destination as in case when we process
// -p<pwd> parameter, so we need to take into account both sizes. // -p<pwd> parameter, so we need to take into account both sizes.
memcpy(Dst,Src,Min(SrcSize,DstSize)*sizeof(*Dst)); memcpy(Dst,Src,Min(SrcSize,DstSize)*sizeof(*Dst));
SecHideData(Dst,DstSize*sizeof(*Dst),Encode,CrossProcess); SecHideData(Dst,DstSize*sizeof(*Dst),Encode,false);
} }
@ -112,7 +112,7 @@ void SecPassword::Get(wchar *Psw,size_t MaxSize)
{ {
if (PasswordSet) if (PasswordSet)
{ {
Process(Password,ASIZE(Password),Psw,MaxSize,false); Process(&Password[0],Password.size(),Psw,MaxSize,false);
Psw[MaxSize-1]=0; Psw[MaxSize-1]=0;
} }
else else
@ -124,15 +124,14 @@ void SecPassword::Get(wchar *Psw,size_t MaxSize)
void SecPassword::Set(const wchar *Psw) void SecPassword::Set(const wchar *Psw)
{ {
if (*Psw==0) // Eliminate any traces of previously stored password for security reason
{ // in case it was longer than new one.
PasswordSet=false; Clean();
memset(Password,0,sizeof(Password));
} if (*Psw!=0)
else
{ {
PasswordSet=true; PasswordSet=true;
Process(Psw,wcslen(Psw)+1,Password,ASIZE(Password),true); Process(Psw,wcslen(Psw)+1,&Password[0],Password.size(),true);
} }
} }
@ -163,6 +162,9 @@ bool SecPassword::operator == (SecPassword &psw)
} }
// Set CrossProcess to true if we need to pass a password to another process.
// We use CrossProcess when transferring parameters to UAC elevated WinRAR
// and Windows GUI SFX modules.
void SecHideData(void *Data,size_t DataSize,bool Encode,bool CrossProcess) void SecHideData(void *Data,size_t DataSize,bool Encode,bool CrossProcess)
{ {
// CryptProtectMemory is not available in UWP and CryptProtectData // CryptProtectMemory is not available in UWP and CryptProtectData

@ -8,10 +8,7 @@ class SecPassword
private: private:
void Process(const wchar *Src,size_t SrcSize,wchar *Dst,size_t DstSize,bool Encode); void Process(const wchar *Src,size_t SrcSize,wchar *Dst,size_t DstSize,bool Encode);
wchar Password[MAXPASSWORD]; std::vector<wchar> Password = std::vector<wchar>(MAXPASSWORD);
// It is important to have this 'bool' value, so if our object is cleaned
// with memset as a part of larger structure, it is handled correctly.
bool PasswordSet; bool PasswordSet;
public: public:
SecPassword(); SecPassword();
@ -22,10 +19,6 @@ class SecPassword
bool IsSet() {return PasswordSet;} bool IsSet() {return PasswordSet;}
size_t Length(); size_t Length();
bool operator == (SecPassword &psw); bool operator == (SecPassword &psw);
// Set to true if we need to pass a password to another process.
// We use it when transferring parameters to UAC elevated WinRAR.
bool CrossProcess;
}; };

@ -121,48 +121,26 @@ wchar* RemoveLF(wchar *Str)
} }
unsigned char loctolower(unsigned char ch) #if defined(SFX_MODULE)
{ // char version of etoupperw. Used in console SFX module only.
#if defined(_WIN_ALL) // Fast toupper for English only input and output. Additionally to speed,
// Convert to LPARAM first to avoid a warning in 64 bit mode. // it also avoids Turkish small i to big I with dot conversion problem.
// Convert to uintptr_t to avoid Clang/win error: cast to 'char *' from smaller integer type 'unsigned char' [-Werror,-Wint-to-pointer-cast] // We do not define 'c' as 'int' to avoid necessity to cast all
return (int)(LPARAM)CharLowerA((LPSTR)(uintptr_t)ch);
#else
return tolower(ch);
#endif
}
unsigned char loctoupper(unsigned char ch)
{
#if defined(_WIN_ALL)
// Convert to LPARAM first to avoid a warning in 64 bit mode.
// 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
}
// toupper with English only results if English input is provided.
// It avoids Turkish (small i) -> (big I with dot) conversion problem.
// We do not define 'ch' as 'int' to avoid necessity to cast all
// signed chars passed to this function to unsigned char. // signed chars passed to this function to unsigned char.
unsigned char etoupper(unsigned char ch) unsigned char etoupper(unsigned char c)
{ {
if (ch=='i') return c>='a' && c<='z' ? c-'a'+'A' : c;
return 'I';
return toupper(ch);
} }
#endif
// Unicode version of etoupper. // Fast toupper for English only input and output. Additionally to speed,
wchar etoupperw(wchar ch) // it also avoids Turkish small i to big I with dot conversion problem.
// We do not define 'c' as 'int' to avoid necessity to cast all
// signed wchars passed to this function to unsigned char.
wchar etoupperw(wchar c)
{ {
if (ch=='i') return c>='a' && c<='z' ? c-'a'+'A' : c;
return 'I';
return toupperw(ch);
} }
@ -379,6 +357,32 @@ void itoa(int64 n,wchar *Str,size_t MaxSize)
} }
// Convert the number to string using thousand separators.
void fmtitoa(int64 n,wchar *Str,size_t MaxSize)
{
static wchar ThSep=0; // Thousands separator.
#ifdef _WIN_ALL
wchar Info[10];
if (!ThSep!=0 && GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_STHOUSAND,Info,ASIZE(Info))>0)
ThSep=*Info;
#elif defined(_UNIX)
ThSep=*localeconv()->thousands_sep;
#endif
if (ThSep==0) // If failed to detect the actual separator value.
ThSep=' ';
wchar RawText[30]; // 20 characters are enough for largest unsigned 64 bit int.
itoa(n,RawText,ASIZE(RawText));
uint S=0,D=0,L=wcslen(RawText)%3;
while (RawText[S]!=0 && D+1<MaxSize)
{
if (S!=0 && (S+3-L)%3==0)
Str[D++]=ThSep;
Str[D++]=RawText[S++];
}
Str[D]=0;
}
const wchar* GetWide(const char *Src) const wchar* GetWide(const char *Src)
{ {
const size_t MaxLength=NM; const size_t MaxLength=NM;

@ -13,16 +13,16 @@ int stricomp(const char *s1,const char *s2);
int strnicomp(const char *s1,const char *s2,size_t n); int strnicomp(const char *s1,const char *s2,size_t n);
wchar* RemoveEOL(wchar *Str); wchar* RemoveEOL(wchar *Str);
wchar* RemoveLF(wchar *Str); wchar* RemoveLF(wchar *Str);
unsigned char loctolower(unsigned char ch);
unsigned char loctoupper(unsigned char ch);
void strncpyz(char *dest, const char *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 wcsncpyz(wchar *dest, const wchar *src, size_t maxlen);
void strncatz(char* dest, const char* src, size_t maxlen); void strncatz(char* dest, const char* src, size_t maxlen);
void wcsncatz(wchar* dest, const wchar* src, size_t maxlen); void wcsncatz(wchar* dest, const wchar* src, size_t maxlen);
unsigned char etoupper(unsigned char ch); #if defined(SFX_MODULE)
wchar etoupperw(wchar ch); unsigned char etoupper(unsigned char c);
#endif
wchar etoupperw(wchar c);
bool IsDigit(int ch); bool IsDigit(int ch);
bool IsSpace(int ch); bool IsSpace(int ch);
@ -42,6 +42,7 @@ int wcsnicompc(const wchar *s1,const wchar *s2,size_t n);
void itoa(int64 n,char *Str,size_t MaxSize); void itoa(int64 n,char *Str,size_t MaxSize);
void itoa(int64 n,wchar *Str,size_t MaxSize); void itoa(int64 n,wchar *Str,size_t MaxSize);
void fmtitoa(int64 n,wchar *Str,size_t MaxSize);
const wchar* GetWide(const char *Src); const wchar* GetWide(const char *Src);
const wchar* GetCmdParam(const wchar *CmdLine,wchar *Param,size_t MaxSize); const wchar* GetCmdParam(const wchar *CmdLine,wchar *Param,size_t MaxSize);
#ifndef RARDLL #ifndef RARDLL

@ -71,7 +71,7 @@ void SubAllocator::StopSubAllocator()
if ( SubAllocatorSize ) if ( SubAllocatorSize )
{ {
SubAllocatorSize=0; SubAllocatorSize=0;
//free(HeapStart); free(HeapStart);
} }
} }
@ -88,8 +88,7 @@ bool SubAllocator::StartSubAllocator(int SASize)
// units: one as reserve for HeapEnd overflow checks and another // units: one as reserve for HeapEnd overflow checks and another
// to provide the space to correctly align UnitsStart. // to provide the space to correctly align UnitsStart.
uint AllocSize=t/FIXED_UNIT_SIZE*UNIT_SIZE+2*UNIT_SIZE; uint AllocSize=t/FIXED_UNIT_SIZE*UNIT_SIZE+2*UNIT_SIZE;
//if ((HeapStart=(byte *)malloc(AllocSize)) == NULL) if ((HeapStart=(byte *)malloc(AllocSize)) == NULL)
if ((HeapStart=(byte *)HeapStartFixed) == NULL)
{ {
ErrHandler.MemoryError(); ErrHandler.MemoryError();
return false; return false;

@ -80,9 +80,6 @@ class SubAllocator
long GetAllocatedMemory() {return(SubAllocatorSize);} long GetAllocatedMemory() {return(SubAllocatorSize);}
byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart; byte *pText, *UnitsStart,*HeapEnd,*FakeUnitsStart;
byte *HeapStartFixed;
void SetHeapStartFixed(byte *p) {HeapStartFixed=p;}
}; };

@ -187,10 +187,10 @@ SSE_VERSION _SSE_Version=GetSSEVersion();
SSE_VERSION GetSSEVersion() SSE_VERSION GetSSEVersion()
{ {
int CPUInfo[4]; int CPUInfo[4];
__cpuid(CPUInfo, 0x80000000); __cpuid(CPUInfo, 0);
// Maximum supported cpuid function. For example, Pentium M 755 returns 4 here. // Maximum supported cpuid function.
uint MaxSupported=CPUInfo[0] & 0x7fffffff; uint MaxSupported=CPUInfo[0];
if (MaxSupported>=7) if (MaxSupported>=7)
{ {

@ -149,3 +149,5 @@ uint GetNumberOfThreads()
return NumCPU; return NumCPU;
} }

@ -273,12 +273,12 @@ void RarTime::SetAgeText(const wchar *TimeText)
uint Seconds=0,Value=0; uint Seconds=0,Value=0;
for (uint I=0;TimeText[I]!=0;I++) for (uint I=0;TimeText[I]!=0;I++)
{ {
int Ch=TimeText[I]; wchar Ch=TimeText[I];
if (IsDigit(Ch)) if (IsDigit(Ch))
Value=Value*10+Ch-'0'; Value=Value*10+Ch-'0';
else else
{ {
switch(etoupper(Ch)) switch(etoupperw(Ch))
{ {
case 'D': case 'D':
Seconds+=Value*24*3600; Seconds+=Value*24*3600;

@ -22,6 +22,17 @@ class RarTime
// Internal time representation in 1/TICKS_PER_SECOND since 01.01.1601. // Internal time representation in 1/TICKS_PER_SECOND since 01.01.1601.
// We use nanoseconds here to handle the high precision Unix time. // We use nanoseconds here to handle the high precision Unix time.
// It allows dates up to July 2185.
//
// If we'll ever need to extend the date range, we can define a lower
// precision Windows version of TICKS_PER_SECOND. But then Unix and Windows
// versions can differ in least significant digits of "lt" time output
// for Unix archives.
// Alternatively we can introduce 'bool HighPrecision' set to true
// in SetUnixNS() and TicksPerSecond() instead of constant above.
// It might be more reliable than defining TicksPerSecond variable,
// which wouldn't survive memset of any structure hosting RarTime.
// We would need to eliminate all such memsets in the entire code first.
uint64 itime; uint64 itime;
public: public:
// RarLocalTime::Reminder precision. Must be equal to TICKS_PER_SECOND. // RarLocalTime::Reminder precision. Must be equal to TICKS_PER_SECOND.

38
deps/unrar/ui.hpp vendored

@ -39,7 +39,7 @@ enum UIMESSAGE_CODE {
UIERROR_UOWNERBROKEN, UIERROR_UOWNERGETOWNERID, UIERROR_UOWNERGETGROUPID, UIERROR_UOWNERBROKEN, UIERROR_UOWNERGETOWNERID, UIERROR_UOWNERGETGROUPID,
UIERROR_UOWNERSET, UIERROR_ULINKREAD, UIERROR_ULINKEXIST, UIERROR_UOWNERSET, UIERROR_ULINKREAD, UIERROR_ULINKEXIST,
UIERROR_OPENPRESERVEATIME, UIERROR_READERRTRUNCATED, UIERROR_READERRCOUNT, UIERROR_OPENPRESERVEATIME, UIERROR_READERRTRUNCATED, UIERROR_READERRCOUNT,
UIERROR_DIRNAMEEXISTS, UIERROR_DIRNAMEEXISTS,UIERROR_TRUNCPSW,UIERROR_ADJUSTVALUE,
UIMSG_FIRST, UIMSG_FIRST,
UIMSG_STRING, UIMSG_BUILD, UIMSG_RRSEARCH, UIMSG_ANALYZEFILEDATA, UIMSG_STRING, UIMSG_BUILD, UIMSG_RRSEARCH, UIMSG_ANALYZEFILEDATA,
@ -49,6 +49,7 @@ enum UIMESSAGE_CODE {
UIMSG_CORRECTINGNAME, UIMSG_BADARCHIVE, UIMSG_CREATING, UIMSG_RENAMING, UIMSG_CORRECTINGNAME, UIMSG_BADARCHIVE, UIMSG_CREATING, UIMSG_RENAMING,
UIMSG_RECVOLCALCCHECKSUM, UIMSG_RECVOLFOUND, UIMSG_RECVOLMISSING, UIMSG_RECVOLCALCCHECKSUM, UIMSG_RECVOLFOUND, UIMSG_RECVOLMISSING,
UIMSG_MISSINGVOL, UIMSG_RECONSTRUCTING, UIMSG_CHECKSUM, UIMSG_FAT32SIZE, UIMSG_MISSINGVOL, UIMSG_RECONSTRUCTING, UIMSG_CHECKSUM, UIMSG_FAT32SIZE,
UIMSG_SKIPENCARC, UIMSG_FILERENAME,
UIWAIT_FIRST, UIWAIT_FIRST,
UIWAIT_DISKFULLNEXT, UIWAIT_FCREATEERROR, UIWAIT_BADPSW, UIWAIT_DISKFULLNEXT, UIWAIT_FCREATEERROR, UIWAIT_BADPSW,
@ -76,7 +77,7 @@ enum UIASKREP_RESULT {
}; };
UIASKREP_RESULT uiAskReplace(wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags); 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); UIASKREP_RESULT uiAskReplaceEx(CommandData *Cmd,wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags);
void uiInit(SOUND_NOTIFY_MODE Sound); void uiInit(SOUND_NOTIFY_MODE Sound);
@ -87,7 +88,7 @@ void uiExtractProgress(int64 CurFileSize,int64 TotalFileSize,int64 CurSize,int64
void uiProcessProgress(const char *Command,int64 CurSize,int64 TotalSize); void uiProcessProgress(const char *Command,int64 CurSize,int64 TotalSize);
enum UIPASSWORD_TYPE {UIPASSWORD_GLOBAL,UIPASSWORD_FILE,UIPASSWORD_ARCHIVE}; enum UIPASSWORD_TYPE {UIPASSWORD_GLOBAL,UIPASSWORD_FILE,UIPASSWORD_ARCHIVE};
bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password); bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password,CheckPassword *CheckPwd);
bool uiIsGlobalPasswordSet(); bool uiIsGlobalPasswordSet();
enum UIALARM_TYPE {UIALARM_ERROR, UIALARM_INFO, UIALARM_QUESTION}; enum UIALARM_TYPE {UIALARM_ERROR, UIALARM_INFO, UIALARM_QUESTION};
@ -144,30 +145,31 @@ class uiMsgStore
// Templates recognize usual NULL as integer, not wchar*. // Templates recognize usual NULL as integer, not wchar*.
#define UINULL ((wchar *)NULL) #define UINULL ((wchar *)NULL)
inline void uiMsg(UIMESSAGE_CODE Code) inline void uiMsgBase(uiMsgStore &Store)
{ {
uiMsgStore Store(Code); // Called last, when no parameters are left.
Store.Msg();
} }
template<class T1> void uiMsg(UIMESSAGE_CODE Code,T1 a1) template<class T1,class... TN> void uiMsgBase(uiMsgStore &Store,T1&& a1,TN&&... aN)
{ {
uiMsgStore Store(Code); // Process first parameter and pass the rest to same uiMsgBase.
Store<<a1; Store<<a1;
Store.Msg(); uiMsgBase(Store,aN...);
} }
template<class T1,class T2> void uiMsg(UIMESSAGE_CODE Code,T1 a1,T2 a2)
{
uiMsgStore Store(Code);
Store<<a1<<a2;
Store.Msg();
}
template<class T1,class T2,class T3> void uiMsg(UIMESSAGE_CODE code,T1 a1,T2 a2,T3 a3) // Use variadic templates.
//
// We must pass variable parameters by reference, so no temporary copies are
// created for custom string objects like CStringBase in 7-Zip decompression
// code. Such temporary copies would be destroyed inside of recursive
// uiMsgBase calls, leaving us with Str[] items pointing at released memory.
// Since we pass integer values as well, we can't use & references
// and must resort to && rvalue references.
template<class... TN> void uiMsg(UIMESSAGE_CODE Code,TN&&... aN)
{ {
uiMsgStore Store(code); uiMsgStore Store(Code);
Store<<a1<<a2<<a3; uiMsgBase(Store,aN...);
Store.Msg(); Store.Msg();
} }

@ -8,7 +8,7 @@ void uiInit(SOUND_NOTIFY_MODE Sound)
// Additionally to handling user input, it analyzes and sets command options. // Additionally to handling user input, it analyzes and sets command options.
// Returns only 'replace', 'skip' and 'cancel' codes. // Returns only 'replace', 'skip' and 'cancel' codes.
UIASKREP_RESULT uiAskReplaceEx(RAROptions *Cmd,wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags) UIASKREP_RESULT uiAskReplaceEx(CommandData *Cmd,wchar *Name,size_t MaxNameSize,int64 FileSize,RarTime *FileTime,uint Flags)
{ {
if (Cmd->Overwrite==OVERWRITE_NONE) if (Cmd->Overwrite==OVERWRITE_NONE)
return UIASKREP_R_SKIP; return UIASKREP_R_SKIP;

@ -71,7 +71,10 @@ bool uiStartFileExtract(const wchar *FileName,bool Extract,bool Test,bool Skip)
void uiExtractProgress(int64 CurFileSize,int64 TotalFileSize,int64 CurSize,int64 TotalSize) void uiExtractProgress(int64 CurFileSize,int64 TotalFileSize,int64 CurSize,int64 TotalSize)
{ {
int CurPercent=ToPercent(CurSize,TotalSize); // We set the total size to 0 to update only the current progress and keep
// the total progress intact in WinRAR. Unlike WinRAR, console RAR has only
// the total progress and updates it with current values in such case.
int CurPercent=TotalSize!=0 ? ToPercent(CurSize,TotalSize) : ToPercent(CurFileSize,TotalFileSize);
mprintf(L"\b\b\b\b%3d%%",CurPercent); mprintf(L"\b\b\b\b%3d%%",CurPercent);
} }
@ -247,6 +250,9 @@ void uiMsgStore::Msg()
mprintf(L"\n"); // Needed when called from CmdExtract::ExtractCurrentFile. mprintf(L"\n"); // Needed when called from CmdExtract::ExtractCurrentFile.
break; break;
#ifndef SFX_MODULE #ifndef SFX_MODULE
case UIERROR_OPFAILED:
Log(NULL,St(MOpFailed));
break;
case UIERROR_NEWRARFORMAT: case UIERROR_NEWRARFORMAT:
Log(Str[0],St(MNewRarFormat)); Log(Str[0],St(MNewRarFormat));
break; break;
@ -256,6 +262,7 @@ void uiMsgStore::Msg()
break; break;
case UIERROR_MISSINGVOL: case UIERROR_MISSINGVOL:
Log(Str[0],St(MAbsNextVol),Str[0]); Log(Str[0],St(MAbsNextVol),Str[0]);
mprintf(L" "); // For progress percent.
break; break;
#ifndef SFX_MODULE #ifndef SFX_MODULE
case UIERROR_NEEDPREVVOL: case UIERROR_NEEDPREVVOL:
@ -329,6 +336,13 @@ void uiMsgStore::Msg()
case UIERROR_DIRNAMEEXISTS: case UIERROR_DIRNAMEEXISTS:
Log(NULL,St(MDirNameExists)); Log(NULL,St(MDirNameExists));
break; break;
case UIERROR_TRUNCPSW:
eprintf(St(MTruncPsw),Num[0]);
eprintf(L"\n");
break;
case UIERROR_ADJUSTVALUE:
Log(NULL,St(MAdjustValue),Str[0],Str[1]);
break;
#ifndef SFX_MODULE #ifndef SFX_MODULE
case UIMSG_STRING: case UIMSG_STRING:
@ -369,6 +383,9 @@ void uiMsgStore::Msg()
mprintf(St(MFAT32Size)); mprintf(St(MFAT32Size));
mprintf(L" "); // For progress percent. mprintf(L" "); // For progress percent.
break; break;
case UIMSG_SKIPENCARC:
Log(NULL,St(MSkipEncArc),Str[0]);
break;
@ -379,7 +396,8 @@ void uiMsgStore::Msg()
} }
bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password) bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,
SecPassword *Password,CheckPassword *CheckPwd)
{ {
// Unlike GUI we cannot provide Cancel button here, so we use the empty // 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 // password to abort. Otherwise user not knowing a password would need to

@ -33,7 +33,8 @@ void uiMsgStore::Msg()
} }
bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password) bool uiGetPassword(UIPASSWORD_TYPE Type,const wchar *FileName,
SecPassword *Password,CheckPassword *CheckPwd)
{ {
return false; return false;
} }

@ -50,7 +50,28 @@ static bool IsFullPath(const char *PathA) // Unix ASCII version.
} }
bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName) // For security purpose we prefer to be sure that CharToWide completed
// successfully and even if it truncated a string for some reason,
// it didn't affect the number of path related characters we analyze
// in IsRelativeSymlinkSafe later.
// This check is likely to be excessive, but let's keep it anyway.
static bool SafeCharToWide(const char *Src,wchar *Dest,size_t DestSize)
{
if (!CharToWide(Src,Dest,DestSize) || *Dest==0)
return false;
uint SrcChars=0,DestChars=0;
for (uint I=0;Src[I]!=0;I++)
if (Src[I]=='/' || Src[I]=='.')
SrcChars++;
for (uint I=0;Dest[I]!=0;I++)
if (Dest[I]=='/' || Dest[I]=='.')
DestChars++;
return SrcChars==DestChars;
}
static bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,
const wchar *LinkName,bool &UpLink)
{ {
char Target[NM]; char Target[NM];
if (IsLink(Arc.FileHead.FileAttr)) if (IsLink(Arc.FileHead.FileAttr))
@ -72,21 +93,22 @@ bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const w
return true; return true;
wchar TargetW[NM]; wchar TargetW[NM];
CharToWide(Target,TargetW,ASIZE(TargetW)); if (!SafeCharToWide(Target,TargetW,ASIZE(TargetW)))
// Check for *TargetW==0 to catch CharToWide failure. return false;
// Use Arc.FileHead.FileName instead of LinkName, since LinkName // Use Arc.FileHead.FileName instead of LinkName, since LinkName
// can include the destination path as a prefix, which can // can include the destination path as a prefix, which can
// confuse IsRelativeSymlinkSafe algorithm. // confuse IsRelativeSymlinkSafe algorithm.
if (!Cmd->AbsoluteLinks && (*TargetW==0 || IsFullPath(TargetW) || if (!Cmd->AbsoluteLinks && (IsFullPath(TargetW) ||
!IsRelativeSymlinkSafe(Cmd,Arc.FileHead.FileName,LinkName,TargetW))) !IsRelativeSymlinkSafe(Cmd,Arc.FileHead.FileName,LinkName,TargetW)))
return false; return false;
UpLink=strstr(Target,"..")!=NULL;
return UnixSymlink(Cmd,Target,LinkName,&Arc.FileHead.mtime,&Arc.FileHead.atime); return UnixSymlink(Cmd,Target,LinkName,&Arc.FileHead.mtime,&Arc.FileHead.atime);
} }
return false; return false;
} }
bool ExtractUnixLink50(CommandData *Cmd,const wchar *Name,FileHeader *hd) static bool ExtractUnixLink50(CommandData *Cmd,const wchar *Name,FileHeader *hd)
{ {
char Target[NM]; char Target[NM];
WideToChar(hd->RedirName,Target,ASIZE(Target)); WideToChar(hd->RedirName,Target,ASIZE(Target));
@ -100,11 +122,15 @@ bool ExtractUnixLink50(CommandData *Cmd,const wchar *Name,FileHeader *hd)
return false; return false;
DosSlashToUnix(Target,Target,ASIZE(Target)); DosSlashToUnix(Target,Target,ASIZE(Target));
} }
wchar TargetW[NM];
if (!SafeCharToWide(Target,TargetW,ASIZE(TargetW)))
return false;
// Use hd->FileName instead of LinkName, since LinkName can include // Use hd->FileName instead of LinkName, since LinkName can include
// the destination path as a prefix, which can confuse // the destination path as a prefix, which can confuse
// IsRelativeSymlinkSafe algorithm. // IsRelativeSymlinkSafe algorithm.
if (!Cmd->AbsoluteLinks && (IsFullPath(Target) || if (!Cmd->AbsoluteLinks && (IsFullPath(TargetW) ||
!IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,hd->RedirName))) !IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,TargetW)))
return false; return false;
return UnixSymlink(Cmd,Target,Name,&hd->mtime,&hd->atime); return UnixSymlink(Cmd,Target,Name,&hd->mtime,&hd->atime);
} }

@ -229,10 +229,11 @@ void CharToWideMap(const char *Src,wchar *Dest,size_t DestSize,bool &Success)
#endif #endif
// SrcSize is in wide characters, not in bytes. // SrcSize is source data size in wide characters, not in bytes.
byte* WideToRaw(const wchar *Src,byte *Dest,size_t SrcSize) // DestSize is the maximum allowed destination size.
byte* WideToRaw(const wchar *Src,size_t SrcSize,byte *Dest,size_t DestSize)
{ {
for (size_t I=0;I<SrcSize;I++,Src++) for (size_t I=0;I<SrcSize && I*2+1<DestSize;I++,Src++)
{ {
Dest[I*2]=(byte)*Src; Dest[I*2]=(byte)*Src;
Dest[I*2+1]=(byte)(*Src>>8); Dest[I*2+1]=(byte)(*Src>>8);
@ -601,59 +602,6 @@ char* SupportDBCS::charnext(const char *s)
// to break string processing loops. // to break string processing loops.
return (char *)(IsLeadByte[(byte)*s] && s[1]!=0 ? s+2:s+1); return (char *)(IsLeadByte[(byte)*s] && s[1]!=0 ? s+2:s+1);
} }
size_t SupportDBCS::strlend(const char *s)
{
size_t Length=0;
while (*s!=0)
{
if (IsLeadByte[(byte)*s])
s+=2;
else
s++;
Length++;
}
return(Length);
}
char* SupportDBCS::strchrd(const char *s, int c)
{
while (*s!=0)
if (IsLeadByte[(byte)*s])
s+=2;
else
if (*s==c)
return((char *)s);
else
s++;
return(NULL);
}
void SupportDBCS::copychrd(char *dest,const char *src)
{
dest[0]=src[0];
if (IsLeadByte[(byte)src[0]])
dest[1]=src[1];
}
char* SupportDBCS::strrchrd(const char *s, int c)
{
const char *found=NULL;
while (*s!=0)
if (IsLeadByte[(byte)*s])
s+=2;
else
{
if (*s==c)
found=s;
s++;
}
return((char *)found);
}
#endif #endif

@ -7,7 +7,7 @@
bool WideToChar(const wchar *Src,char *Dest,size_t DestSize); bool WideToChar(const wchar *Src,char *Dest,size_t DestSize);
bool CharToWide(const char *Src,wchar *Dest,size_t DestSize); bool CharToWide(const char *Src,wchar *Dest,size_t DestSize);
byte* WideToRaw(const wchar *Src,byte *Dest,size_t SrcSize); byte* WideToRaw(const wchar *Src,size_t SrcSize,byte *Dest,size_t DestSize);
wchar* RawToWide(const byte *Src,wchar *Dest,size_t DestSize); wchar* RawToWide(const byte *Src,wchar *Dest,size_t DestSize);
void WideToUtf(const wchar *Src,char *Dest,size_t DestSize); void WideToUtf(const wchar *Src,char *Dest,size_t DestSize);
size_t WideToUtfSize(const wchar *Src); size_t WideToUtfSize(const wchar *Src);
@ -33,34 +33,19 @@ class SupportDBCS
public: public:
SupportDBCS(); SupportDBCS();
void Init(); void Init();
char* charnext(const char *s); char* charnext(const char *s);
size_t strlend(const char *s);
char *strchrd(const char *s, int c);
char *strrchrd(const char *s, int c);
void copychrd(char *dest,const char *src);
bool IsLeadByte[256]; bool IsLeadByte[256];
bool DBCSMode; bool DBCSMode;
}; };
extern SupportDBCS gdbcs; extern SupportDBCS gdbcs;
inline char* charnext(const char *s) {return (char *)(gdbcs.DBCSMode ? gdbcs.charnext(s):s+1);} inline char* charnext(const char *s) {return (char *)(gdbcs.DBCSMode ? gdbcs.charnext(s):s+1);}
inline size_t strlend(const char *s) {return (uint)(gdbcs.DBCSMode ? gdbcs.strlend(s):strlen(s));} inline bool IsDBCSMode() {return gdbcs.DBCSMode;}
inline char* strchrd(const char *s, int c) {return (char *)(gdbcs.DBCSMode ? gdbcs.strchrd(s,c):strchr(s,c));}
inline char* strrchrd(const char *s, int c) {return (char *)(gdbcs.DBCSMode ? gdbcs.strrchrd(s,c):strrchr(s,c));}
inline void copychrd(char *dest,const char *src) {if (gdbcs.DBCSMode) gdbcs.copychrd(dest,src); else *dest=*src;}
inline bool IsDBCSMode() {return(gdbcs.DBCSMode);}
inline void InitDBCS() {gdbcs.Init();}
#else #else
#define charnext(s) ((s)+1) #define charnext(s) ((s)+1)
#define strlend strlen #define IsDBCSMode() (false)
#define strchrd strchr
#define strrchrd strrchr
#define IsDBCSMode() (true)
inline void copychrd(char *dest,const char *src) {*dest=*src;}
#endif #endif

@ -16,7 +16,7 @@
#include "unpack50frag.cpp" #include "unpack50frag.cpp"
Unpack::Unpack(ComprDataIO *DataIO) Unpack::Unpack(ComprDataIO *DataIO)
:Inp(false),VMCodeInp(false) :Inp(true),VMCodeInp(true)
{ {
UnpIO=DataIO; UnpIO=DataIO;
Window=NULL; Window=NULL;
@ -49,8 +49,8 @@ Unpack::~Unpack()
{ {
InitFilters30(false); InitFilters30(false);
//if (Window!=NULL) if (Window!=NULL)
// free(Window); free(Window);
#ifdef RAR_SMP #ifdef RAR_SMP
delete UnpThreadPool; delete UnpThreadPool;
delete[] ReadBufMT; delete[] ReadBufMT;
@ -117,7 +117,7 @@ void Unpack::Init(size_t WinSize,bool Solid)
if (Grow && Fragmented) if (Grow && Fragmented)
throw std::bad_alloc(); throw std::bad_alloc();
byte *NewWindow=Fragmented ? NULL : (byte *)hcwin; byte *NewWindow=Fragmented ? NULL : (byte *)malloc(WinSize);
if (NewWindow==NULL) if (NewWindow==NULL)
if (Grow || WinSize<0x1000000) if (Grow || WinSize<0x1000000)
@ -130,7 +130,7 @@ void Unpack::Init(size_t WinSize,bool Solid)
{ {
if (Window!=NULL) // If allocated by preceding files. if (Window!=NULL) // If allocated by preceding files.
{ {
//free(Window); free(Window);
Window=NULL; Window=NULL;
} }
FragWindow.Init(WinSize); FragWindow.Init(WinSize);
@ -141,7 +141,7 @@ void Unpack::Init(size_t WinSize,bool Solid)
{ {
// Clean the window to generate the same output when unpacking corrupt // Clean the window to generate the same output when unpacking corrupt
// RAR files, which may access unused areas of sliding dictionary. // RAR files, which may access unused areas of sliding dictionary.
//memset(NewWindow,0,WinSize); memset(NewWindow,0,WinSize);
// If Window is not NULL, it means that window size has grown. // If Window is not NULL, it means that window size has grown.
// In solid streams we need to copy data to a new window in such case. // In solid streams we need to copy data to a new window in such case.
@ -151,8 +151,8 @@ void Unpack::Init(size_t WinSize,bool Solid)
for (size_t I=1;I<=MaxWinSize;I++) for (size_t I=1;I<=MaxWinSize;I++)
NewWindow[(UnpPtr-I)&(WinSize-1)]=Window[(UnpPtr-I)&(MaxWinSize-1)]; NewWindow[(UnpPtr-I)&(WinSize-1)]=Window[(UnpPtr-I)&(MaxWinSize-1)];
//if (Window!=NULL) if (Window!=NULL)
// free(Window); free(Window);
Window=NewWindow; Window=NewWindow;
} }
@ -324,7 +324,7 @@ void Unpack::MakeDecodeTables(byte *LengthTable,DecodeTable *Dec,uint Size)
Dec->QuickBits=MAX_QUICK_DECODE_BITS; Dec->QuickBits=MAX_QUICK_DECODE_BITS;
break; break;
default: default:
Dec->QuickBits=MAX_QUICK_DECODE_BITS-3; Dec->QuickBits=MAX_QUICK_DECODE_BITS>3 ? MAX_QUICK_DECODE_BITS-3 : 0;
break; break;
} }

@ -23,8 +23,8 @@
// allocation. Must be equal or larger than MAX_ANALYZE_SIZE. // allocation. Must be equal or larger than MAX_ANALYZE_SIZE.
#define MAX_FILTER_BLOCK_SIZE 0x400000 #define MAX_FILTER_BLOCK_SIZE 0x400000
// Write data in 4 MB or smaller blocks. Must not exceed PACK_MAX_WRITE, // Write data in 4 MB or smaller blocks. Must not exceed PACK_MAX_READ,
// so we keep a number of buffered filters in unpacker reasonable. // so we keep the number of buffered filters in unpacker reasonable.
#define UNPACK_MAX_WRITE 0x400000 #define UNPACK_MAX_WRITE 0x400000
// Decode compressed bit fields to alphabet numbers. // Decode compressed bit fields to alphabet numbers.
@ -93,17 +93,17 @@ struct UnpackBlockTables
#ifdef RAR_SMP #ifdef RAR_SMP
enum UNP_DEC_TYPE { enum UNP_DEC_TYPE {
UNPDT_LITERAL,UNPDT_MATCH,UNPDT_FULLREP,UNPDT_REP,UNPDT_FILTER UNPDT_LITERAL=0,UNPDT_MATCH,UNPDT_FULLREP,UNPDT_REP,UNPDT_FILTER
}; };
struct UnpackDecodedItem struct UnpackDecodedItem
{ {
UNP_DEC_TYPE Type; byte Type; // 'byte' instead of enum type to reduce memory use.
ushort Length; ushort Length;
union union
{ {
uint Distance; uint Distance;
byte Literal[4]; byte Literal[8]; // Store up to 8 chars here to speed up extraction.
}; };
}; };

@ -55,7 +55,7 @@ void Unpack::Unpack29(bool Solid)
if (!UnpReadBuf30()) if (!UnpReadBuf30())
break; break;
} }
if (((WrPtr-UnpPtr) & MaxWinMask)<260 && WrPtr!=UnpPtr) if (((WrPtr-UnpPtr) & MaxWinMask)<=MAX3_INC_LZ_MATCH && WrPtr!=UnpPtr)
{ {
UnpWriteBuf30(); UnpWriteBuf30();
if (WrittenFileSize>DestUnpSize) if (WrittenFileSize>DestUnpSize)
@ -637,7 +637,7 @@ bool Unpack::ReadTables30()
if (BitField & 0x8000) if (BitField & 0x8000)
{ {
UnpBlockType=BLOCK_PPM; UnpBlockType=BLOCK_PPM;
return(PPM.DecodeInit(this,PPMEscChar,hcppm)); return(PPM.DecodeInit(this,PPMEscChar));
} }
UnpBlockType=BLOCK_LZ; UnpBlockType=BLOCK_LZ;

@ -42,7 +42,7 @@ void Unpack::Unpack5(bool Solid)
break; break;
} }
if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr) if (((WriteBorder-UnpPtr) & MaxWinMask)<=MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
{ {
UnpWriteBuf(); UnpWriteBuf();
if (WrittenFileSize>DestUnpSize) if (WrittenFileSize>DestUnpSize)
@ -93,7 +93,7 @@ void Unpack::Unpack5(bool Solid)
} }
else else
{ {
Distance+=Inp.getbits32()>>(32-DBits); Distance+=Inp.getbits()>>(16-DBits);
Inp.addbits(DBits); Inp.addbits(DBits);
} }
} }

@ -345,7 +345,7 @@ void Unpack::UnpackDecode(UnpackThreadData &D)
if (D.DecodedSize>1) if (D.DecodedSize>1)
{ {
UnpackDecodedItem *PrevItem=CurItem-1; UnpackDecodedItem *PrevItem=CurItem-1;
if (PrevItem->Type==UNPDT_LITERAL && PrevItem->Length<3) if (PrevItem->Type==UNPDT_LITERAL && PrevItem->Length<ASIZE(PrevItem->Literal)-1)
{ {
PrevItem->Length++; PrevItem->Length++;
PrevItem->Literal[PrevItem->Length]=(byte)MainSlot; PrevItem->Literal[PrevItem->Length]=(byte)MainSlot;
@ -388,7 +388,7 @@ void Unpack::UnpackDecode(UnpackThreadData &D)
} }
else else
{ {
Distance+=D.Inp.getbits32()>>(32-DBits); Distance+=D.Inp.getbits()>>(16-DBits);
D.Inp.addbits(DBits); D.Inp.addbits(DBits);
} }
} }
@ -451,7 +451,7 @@ bool Unpack::ProcessDecoded(UnpackThreadData &D)
while (Item<Border) while (Item<Border)
{ {
UnpPtr&=MaxWinMask; UnpPtr&=MaxWinMask;
if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr) if (((WriteBorder-UnpPtr) & MaxWinMask)<=MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
{ {
UnpWriteBuf(); UnpWriteBuf();
if (WrittenFileSize>DestUnpSize) if (WrittenFileSize>DestUnpSize)
@ -461,10 +461,10 @@ bool Unpack::ProcessDecoded(UnpackThreadData &D)
if (Item->Type==UNPDT_LITERAL) if (Item->Type==UNPDT_LITERAL)
{ {
#if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED) #if defined(LITTLE_ENDIAN) && defined(ALLOW_MISALIGNED)
if (Item->Length==3 && UnpPtr<MaxWinSize-4) if (Item->Length==7 && UnpPtr<MaxWinSize-8)
{ {
*(uint32 *)(Window+UnpPtr)=*(uint32 *)Item->Literal; *(uint64 *)(Window+UnpPtr)=*(uint64 *)(Item->Literal);
UnpPtr+=4; UnpPtr+=8;
} }
else else
#endif #endif
@ -559,7 +559,7 @@ bool Unpack::UnpackLargeBlock(UnpackThreadData &D)
break; break;
} }
} }
if (((WriteBorder-UnpPtr) & MaxWinMask)<MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr) if (((WriteBorder-UnpPtr) & MaxWinMask)<=MAX_INC_LZ_MATCH && WriteBorder!=UnpPtr)
{ {
UnpWriteBuf(); UnpWriteBuf();
if (WrittenFileSize>DestUnpSize) if (WrittenFileSize>DestUnpSize)

@ -1,6 +1,6 @@
#define RARVER_MAJOR 6 #define RARVER_MAJOR 6
#define RARVER_MINOR 1 #define RARVER_MINOR 22
#define RARVER_BETA 0 #define RARVER_BETA 1
#define RARVER_DAY 7 #define RARVER_DAY 14
#define RARVER_MONTH 4 #define RARVER_MONTH 5
#define RARVER_YEAR 2021 #define RARVER_YEAR 2023

@ -1,15 +1,15 @@
#include "rar.hpp" #include "rar.hpp"
#ifdef RARDLL #ifdef RARDLL
static bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize); static bool DllVolChange(CommandData *Cmd,wchar *NextName,size_t NameSize);
static bool DllVolNotify(RAROptions *Cmd,wchar *NextName); static bool DllVolNotify(CommandData *Cmd,wchar *NextName);
#endif #endif
bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Command) bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Command)
{ {
RAROptions *Cmd=Arc.GetRAROptions(); CommandData *Cmd=Arc.GetCommandData();
HEADER_TYPE HeaderType=Arc.GetHeaderType(); HEADER_TYPE HeaderType=Arc.GetHeaderType();
FileHeader *hd=HeaderType==HEAD_SERVICE ? &Arc.SubHead:&Arc.FileHead; FileHeader *hd=HeaderType==HEAD_SERVICE ? &Arc.SubHead:&Arc.FileHead;
@ -25,10 +25,12 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma
uiMsg(UIERROR_CHECKSUMPACKED, Arc.FileName, hd->FileName); uiMsg(UIERROR_CHECKSUMPACKED, Arc.FileName, hd->FileName);
} }
bool PrevVolEncrypted=Arc.Encrypted;
int64 PosBeforeClose=Arc.Tell(); int64 PosBeforeClose=Arc.Tell();
if (DataIO!=NULL) if (DataIO!=NULL)
DataIO->ProcessedArcSize+=Arc.FileLength(); DataIO->ProcessedArcSize+=DataIO->LastArcSize;
Arc.Close(); Arc.Close();
@ -40,12 +42,20 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma
#if !defined(SFX_MODULE) && !defined(RARDLL) #if !defined(SFX_MODULE) && !defined(RARDLL)
bool RecoveryDone=false; bool RecoveryDone=false;
#endif #endif
bool FailedOpen=false,OldSchemeTested=false; bool OldSchemeTested=false;
bool FailedOpen=false; // No more next volume open attempts if true.
#if !defined(SILENT) #if !defined(SILENT)
// In -vp mode we force the pause before next volume even if it is present // In -vp mode we force the pause before next volume even if it is present
// and even if we are on the hard disk. It is important when user does not // and even if we are on the hard disk. It is important when user does not
// want to process partially downloaded volumes preliminary. // want to process partially downloaded volumes preliminary.
// 2022.01.11: In WinRAR 6.10 beta versions we tried to ignore VolumePause
// if we could open the next volume with FMF_OPENEXCLUSIVE. But another
// developer asked us to return the previous behavior and always prompt
// for confirmation. They want to control when unrar continues, because
// the next file might not be fully decoded yet. They write chunks of data
// and then close the file again until the next chunk comes in.
if (Cmd->VolumePause && !uiAskNextVolume(NextName,ASIZE(NextName))) if (Cmd->VolumePause && !uiAskNextVolume(NextName,ASIZE(NextName)))
FailedOpen=true; FailedOpen=true;
#endif #endif
@ -127,6 +137,16 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma
return false; return false;
#endif #endif
if (Arc.Encrypted!=PrevVolEncrypted)
{
// There is no legitimate reason for encrypted header state to be
// changed in the middle of volume sequence. So we abort here to prevent
// replacing an encrypted header volume to unencrypted and adding
// unexpected files by third party to encrypted extraction.
uiMsg(UIERROR_BADARCHIVE,Arc.FileName);
ErrHandler.Exit(RARX_FATAL);
}
if (SplitHeader) if (SplitHeader)
Arc.SearchBlock(HeaderType); Arc.SearchBlock(HeaderType);
else else
@ -151,10 +171,9 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma
DataIO->UnpVolume=hd->SplitAfter; DataIO->UnpVolume=hd->SplitAfter;
DataIO->SetPackedSizeToRead(hd->PackSize); DataIO->SetPackedSizeToRead(hd->PackSize);
} }
#ifdef SFX_MODULE
DataIO->UnpArcSize=Arc.FileLength(); DataIO->AdjustTotalArcSize(&Arc);
#endif
// Reset the size of packed data read from current volume. It is used // Reset the size of packed data read from current volume. It is used
// to display the total progress and preceding volumes are already // to display the total progress and preceding volumes are already
// compensated with ProcessedArcSize, so we need to reset this variable. // compensated with ProcessedArcSize, so we need to reset this variable.
@ -171,14 +190,7 @@ bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,wchar Comma
#ifdef RARDLL #ifdef RARDLL
#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64) bool DllVolChange(CommandData *Cmd,wchar *NextName,size_t NameSize)
// Disable the run time stack check for unrar.dll, so we can manipulate
// with ChangeVolProc call type below. Run time check would intercept
// a wrong ESP before we restore it.
#pragma runtime_checks( "s", off )
#endif
bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize)
{ {
bool DllVolChanged=false,DllVolAborted=false; bool DllVolChanged=false,DllVolAborted=false;
@ -212,28 +224,7 @@ bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize)
{ {
char NextNameA[NM]; char NextNameA[NM];
WideToChar(NextName,NextNameA,ASIZE(NextNameA)); WideToChar(NextName,NextNameA,ASIZE(NextNameA));
// Here we preserve ESP value. It is necessary for those developers,
// who still define ChangeVolProc callback as "C" type function,
// even though in year 2001 we announced in unrar.dll whatsnew.txt
// that it will be PASCAL type (for compatibility with Visual Basic).
#if defined(_MSC_VER)
#ifndef _WIN_64
__asm mov ebx,esp
#endif
#elif defined(_WIN_ALL) && defined(__BORLANDC__)
_EBX=_ESP;
#endif
int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_ASK); int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_ASK);
// Restore ESP after ChangeVolProc with wrongly defined calling
// convention broken it.
#if defined(_MSC_VER)
#ifndef _WIN_64
__asm mov esp,ebx
#endif
#elif defined(_WIN_ALL) && defined(__BORLANDC__)
_ESP=_EBX;
#endif
if (RetCode==0) if (RetCode==0)
DllVolAborted=true; DllVolAborted=true;
else else
@ -255,7 +246,7 @@ bool DllVolChange(RAROptions *Cmd,wchar *NextName,size_t NameSize)
#ifdef RARDLL #ifdef RARDLL
bool DllVolNotify(RAROptions *Cmd,wchar *NextName) bool DllVolNotify(CommandData *Cmd,wchar *NextName)
{ {
char NextNameA[NM]; char NextNameA[NM];
WideToChar(NextName,NextNameA,ASIZE(NextNameA)); WideToChar(NextName,NextNameA,ASIZE(NextNameA));
@ -268,21 +259,10 @@ bool DllVolNotify(RAROptions *Cmd,wchar *NextName)
} }
if (Cmd->ChangeVolProc!=NULL) if (Cmd->ChangeVolProc!=NULL)
{ {
#if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__)
_EBX=_ESP;
#endif
int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_NOTIFY); int RetCode=Cmd->ChangeVolProc(NextNameA,RAR_VOL_NOTIFY);
#if defined(_WIN_ALL) && !defined(_MSC_VER) && !defined(__MINGW32__)
_ESP=_EBX;
#endif
if (RetCode==0) if (RetCode==0)
return false; return false;
} }
return true; return true;
} }
#if defined(RARDLL) && defined(_MSC_VER) && !defined(_WIN_64)
// Restore the run time stack check for unrar.dll.
#pragma runtime_checks( "s", restore )
#endif
#endif #endif

@ -1,10 +1,7 @@
#ifndef _RAR_VOLUME_ #ifndef _RAR_VOLUME_
#define _RAR_VOLUME_ #define _RAR_VOLUME_
void SplitArchive(Archive &Arc,FileHeader *fh,int64 *HeaderPos,
ComprDataIO *DataIO);
bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName, bool MergeArchive(Archive &Arc,ComprDataIO *DataIO,bool ShowFileName,
wchar Command); wchar Command);
void SetVolWrite(Archive &Dest,int64 VolSize);
#endif #endif

@ -111,16 +111,23 @@ void ExtractStreams(Archive &Arc,const wchar *FileName,bool TestMode)
wcsncatz(FullName,StreamName,ASIZE(FullName)); wcsncatz(FullName,StreamName,ASIZE(FullName));
FindData fd; FindData fd;
bool Found=FindFile::FastFind(FileName,&fd); bool HostFound=FindFile::FastFind(FileName,&fd);
if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0) if ((fd.FileAttr & FILE_ATTRIBUTE_READONLY)!=0)
SetFileAttr(FileName,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY); SetFileAttr(FileName,fd.FileAttr & ~FILE_ATTRIBUTE_READONLY);
File CurFile; File CurFile;
if (CurFile.WCreate(FullName) && Arc.ReadSubData(NULL,&CurFile,false))
CurFile.Close(); if (CurFile.WCreate(FullName))
{
if (Arc.ReadSubData(NULL,&CurFile,false))
CurFile.Close();
}
// Restoring original file timestamps.
File HostFile; File HostFile;
if (Found && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE)) if (HostFound && HostFile.Open(FileName,FMF_OPENSHARED|FMF_UPDATE))
SetFileTime(HostFile.GetHandle(),&fd.ftCreationTime,&fd.ftLastAccessTime, SetFileTime(HostFile.GetHandle(),&fd.ftCreationTime,&fd.ftLastAccessTime,
&fd.ftLastWriteTime); &fd.ftLastWriteTime);

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

Loading…
Cancel
Save