VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Boot/EFI/DcsBoot.efibin24088 -> 25160 bytes
-rw-r--r--src/Boot/EFI/DcsBoot32.efibin20472 -> 21544 bytes
-rw-r--r--src/Boot/EFI/DcsCfg.efibin952824 -> 976168 bytes
-rw-r--r--src/Boot/EFI/DcsCfg32.efibin816440 -> 846280 bytes
-rw-r--r--src/Boot/EFI/DcsInfo.efibin37168 -> 38216 bytes
-rw-r--r--src/Boot/EFI/DcsInfo32.efibin33880 -> 34936 bytes
-rw-r--r--src/Boot/EFI/DcsInt.efibin911352 -> 934744 bytes
-rw-r--r--src/Boot/EFI/DcsInt32.efibin795664 -> 825464 bytes
-rw-r--r--src/Boot/EFI/DcsRe.efibin28472 -> 29576 bytes
-rw-r--r--src/Boot/EFI/DcsRe32.efibin24056 -> 25160 bytes
-rw-r--r--src/Boot/EFI/LegacySpeaker.efibin9816 -> 10888 bytes
-rw-r--r--src/Boot/EFI/LegacySpeaker32.efibin9560 -> 10632 bytes
-rw-r--r--src/Boot/Windows/Boot.vcxproj2
-rw-r--r--src/Boot/Windows/Boot.vcxproj.filters6
-rw-r--r--src/Boot/Windows/BootCommon.h2
-rw-r--r--src/Boot/Windows/Makefile4
-rw-r--r--src/Boot/Windows/Release/BootLoader.com.gzbin17287 -> 17457 bytes
-rw-r--r--src/Boot/Windows/Release_AES/BootLoader.com.gzbin11556 -> 11662 bytes
-rw-r--r--src/Boot/Windows/Release_AES_SHA2/BootLoader.com.gzbin11752 -> 11747 bytes
-rw-r--r--src/Boot/Windows/Release_Camellia/BootLoader.com.gzbin12479 -> 12582 bytes
-rw-r--r--src/Boot/Windows/Release_Camellia_SHA2/BootLoader.com.gzbin12618 -> 12619 bytes
-rw-r--r--src/Boot/Windows/Release_SHA2/BootLoader.com.gzbin17486 -> 17480 bytes
-rw-r--r--src/Boot/Windows/Release_Serpent/BootLoader.com.gzbin11878 -> 11985 bytes
-rw-r--r--src/Boot/Windows/Release_Serpent_SHA2/BootLoader.com.gzbin12048 -> 12045 bytes
-rw-r--r--src/Boot/Windows/Release_Twofish/BootLoader.com.gzbin11521 -> 11666 bytes
-rw-r--r--src/Boot/Windows/Release_Twofish_SHA2/BootLoader.com.gzbin11724 -> 11723 bytes
-rw-r--r--src/Boot/Windows/Rescue/BootLoader.com.gzbin17855 -> 17984 bytes
-rw-r--r--src/Boot/Windows/Rescue_AES/BootLoader.com.gzbin12096 -> 12228 bytes
-rw-r--r--src/Boot/Windows/Rescue_AES_SHA2/BootLoader.com.gzbin12277 -> 12281 bytes
-rw-r--r--src/Boot/Windows/Rescue_Camellia/BootLoader.com.gzbin13024 -> 13123 bytes
-rw-r--r--src/Boot/Windows/Rescue_Camellia_SHA2/BootLoader.com.gzbin13168 -> 13164 bytes
-rw-r--r--src/Boot/Windows/Rescue_SHA2/BootLoader.com.gzbin18021 -> 18021 bytes
-rw-r--r--src/Boot/Windows/Rescue_Serpent/BootLoader.com.gzbin12429 -> 12517 bytes
-rw-r--r--src/Boot/Windows/Rescue_Serpent_SHA2/BootLoader.com.gzbin12605 -> 12605 bytes
-rw-r--r--src/Boot/Windows/Rescue_Twofish/BootLoader.com.gzbin12104 -> 12216 bytes
-rw-r--r--src/Boot/Windows/Rescue_Twofish_SHA2/BootLoader.com.gzbin12266 -> 12264 bytes
-rw-r--r--src/Build/CMakeLists.txt4
-rw-r--r--src/Build/Include/Makefile.inc24
-rw-r--r--src/Build/Resources/MacOSX/Info.plist.legacy.xml2
-rw-r--r--src/Build/Resources/MacOSX/Info.plist.xml2
-rwxr-xr-xsrc/Build/build_cmake_deb.sh2
-rw-r--r--src/Build/build_cmake_opensuse.sh2
-rw-r--r--src/Build/build_cmake_rpm_gtk2.sh2
-rw-r--r--src/Build/build_cmake_rpm_gtk3.sh2
-rwxr-xr-xsrc/Build/build_veracrypt_freebsd.sh2
-rwxr-xr-xsrc/Build/build_veracrypt_linux.sh2
-rw-r--r--src/Build/build_veracrypt_linux_gtk3.sh2
-rwxr-xr-xsrc/Build/build_veracrypt_linux_no_sse2.sh2
-rw-r--r--src/COMReg/COMReg.cpp29
-rw-r--r--src/COMReg/COMReg.rc100
-rw-r--r--src/COMReg/COMReg.vcxproj119
-rw-r--r--src/COMReg/COMReg.vcxproj.filters49
-rw-r--r--src/COMReg/COMReg.vcxproj.user7
-rw-r--r--src/COMReg/Resource.h18
-rw-r--r--src/Common/Apidrvr.h15
-rw-r--r--src/Common/BootEncryption.cpp52
-rw-r--r--src/Common/BootEncryption.h12
-rw-r--r--src/Common/Cache.c14
-rw-r--r--src/Common/Cache.h2
-rw-r--r--src/Common/Common.rc2
-rw-r--r--src/Common/Crypto.c26
-rw-r--r--src/Common/Crypto.h14
-rw-r--r--src/Common/Dlgcode.c2344
-rw-r--r--src/Common/Dlgcode.h27
-rw-r--r--src/Common/EncryptionThreadPool.c4
-rw-r--r--src/Common/Format.c14
-rw-r--r--src/Common/Language.c5
-rw-r--r--src/Common/Language.xml1
-rw-r--r--src/Common/Lzma.vcxproj179
-rw-r--r--src/Common/Lzma.vcxproj.filters84
-rw-r--r--src/Common/Lzma.vcxproj.user3
-rw-r--r--src/Common/Lzma_vs2019.vcxproj246
-rw-r--r--src/Common/Lzma_vs2019.vcxproj.filters84
-rw-r--r--src/Common/Lzma_vs2019.vcxproj.user3
-rw-r--r--src/Common/Pkcs5.c294
-rw-r--r--src/Common/Pkcs5.h6
-rw-r--r--src/Common/Random.c18
-rw-r--r--src/Common/Random.h2
-rw-r--r--src/Common/Tcdefs.h18
-rw-r--r--src/Common/Tests.c234
-rw-r--r--src/Common/Tests.h2
-rw-r--r--src/Common/Volumes.c36
-rw-r--r--src/Common/lzma/7zTypes.h525
-rw-r--r--src/Common/lzma/Alloc.c463
-rw-r--r--src/Common/lzma/Alloc.h58
-rw-r--r--src/Common/lzma/Compiler.h43
-rw-r--r--src/Common/lzma/CpuArch.c478
-rw-r--r--src/Common/lzma/CpuArch.h442
-rw-r--r--src/Common/lzma/LzFind.c1628
-rw-r--r--src/Common/lzma/LzFind.h136
-rw-r--r--src/Common/lzma/LzFindMt.c1400
-rw-r--r--src/Common/lzma/LzFindMt.h109
-rw-r--r--src/Common/lzma/LzFindOpt.c578
-rw-r--r--src/Common/lzma/LzHash.h34
-rw-r--r--src/Common/lzma/LzmaDec.c1363
-rw-r--r--src/Common/lzma/LzmaDec.h236
-rw-r--r--src/Common/lzma/LzmaEnc.c3165
-rw-r--r--src/Common/lzma/LzmaEnc.h78
-rw-r--r--src/Common/lzma/LzmaLib.c40
-rw-r--r--src/Common/lzma/LzmaLib.h138
-rw-r--r--src/Common/lzma/Precomp.h10
-rw-r--r--src/Common/lzma/Threads.c540
-rw-r--r--src/Common/lzma/Threads.h232
-rw-r--r--src/Common/lzma/lzma-history.txt520
-rw-r--r--src/Common/lzma/lzma-sdk.txt404
-rw-r--r--src/Common/zlib/README11
-rw-r--r--src/Common/zlib/crc32.c1258
-rw-r--r--src/Common/zlib/crc32.h9877
-rw-r--r--src/Common/zlib/deflate.c108
-rw-r--r--src/Common/zlib/deflate.h27
-rw-r--r--src/Common/zlib/gzguts.h5
-rw-r--r--src/Common/zlib/gzlib.c8
-rw-r--r--src/Common/zlib/gzread.c12
-rw-r--r--src/Common/zlib/gzwrite.c38
-rw-r--r--src/Common/zlib/infback.c3
-rw-r--r--src/Common/zlib/inffast.c28
-rw-r--r--src/Common/zlib/inflate.c47
-rw-r--r--src/Common/zlib/inflate.h5
-rw-r--r--src/Common/zlib/inftrees.c6
-rw-r--r--src/Common/zlib/trees.c75
-rw-r--r--src/Common/zlib/zlib.h223
-rw-r--r--src/Common/zlib/zutil.c4
-rw-r--r--src/Common/zlib/zutil.h21
-rw-r--r--src/Core/RandomNumberGenerator.cpp6
-rw-r--r--src/Core/Unix/Linux/CoreLinux.cpp3
-rw-r--r--src/Crypto/Crypto.vcxproj21
-rw-r--r--src/Crypto/Crypto.vcxproj.filters36
-rw-r--r--src/Crypto/Crypto_vs2019.vcxproj23
-rw-r--r--src/Crypto/GostCipher.c265
-rw-r--r--src/Crypto/GostCipher.h68
-rw-r--r--src/Crypto/Makefile.inc3
-rw-r--r--src/Crypto/Rmd160.c500
-rw-r--r--src/Crypto/Rmd160.h33
-rw-r--r--src/Crypto/Sources8
-rw-r--r--src/Crypto/blake2-impl.h86
-rw-r--r--src/Crypto/blake2.h102
-rw-r--r--src/Crypto/blake2s-load-sse2.h64
-rw-r--r--src/Crypto/blake2s-load-sse41.h240
-rw-r--r--src/Crypto/blake2s-ref.c336
-rw-r--r--src/Crypto/blake2s-round.h159
-rw-r--r--src/Crypto/blake2s.c349
-rw-r--r--src/Crypto/blake2s_SSE2.c39
-rw-r--r--src/Crypto/blake2s_SSE41.c52
-rw-r--r--src/Crypto/blake2s_SSSE3.c47
-rw-r--r--src/Crypto/chacha-xmm.c23
-rw-r--r--src/Crypto/config.h6
-rw-r--r--src/Crypto/cpu.c6
-rw-r--r--src/Crypto/cpu.h13
-rw-r--r--src/Crypto/gost89_x64.asm483
-rw-r--r--src/Driver/DriveFilter.c1
-rw-r--r--src/Driver/Driver.rc8
-rw-r--r--src/Driver/Driver.vcxproj5
-rw-r--r--src/Driver/Driver.vcxproj.filters15
-rw-r--r--src/Driver/EncryptedIoQueue.c97
-rw-r--r--src/Driver/EncryptedIoQueue.h3
-rw-r--r--src/Driver/Ntdriver.c76
-rw-r--r--src/Driver/Ntdriver.h4
-rw-r--r--src/Driver/Ntvol.c13
-rw-r--r--src/Driver/veracrypt_vs2019.vcxproj11
-rw-r--r--src/Driver/veracrypt_vs2019.vcxproj.filters12
-rw-r--r--src/ExpandVolume/ExpandVolume.c6
-rw-r--r--src/ExpandVolume/ExpandVolume.rc8
-rw-r--r--src/ExpandVolume/ExpandVolume.vcxproj171
-rw-r--r--src/ExpandVolume/ExpandVolume_vs2019.vcxproj21
-rw-r--r--src/Format/Format.rc8
-rw-r--r--src/Format/Format.vcxproj162
-rw-r--r--src/Format/Format_vs2019.vcxproj21
-rw-r--r--src/Format/InPlace.c2
-rw-r--r--src/Format/Tcformat.c26
-rw-r--r--src/LICENSE2
-rw-r--r--src/License.txt4
-rw-r--r--src/Main/Forms/AboutDialog.cpp7
-rw-r--r--src/Main/Forms/MountOptionsDialog.cpp3
-rw-r--r--src/Main/Forms/VolumePasswordPanel.cpp7
-rw-r--r--src/Main/Forms/VolumePasswordPanel.h1
-rwxr-xr-xsrc/Main/Main.make1
-rw-r--r--src/Makefile31
-rw-r--r--src/Mount/Favorites.cpp2
-rw-r--r--src/Mount/Mount.c148
-rw-r--r--src/Mount/Mount.rc8
-rw-r--r--src/Mount/Mount.vcxproj166
-rw-r--r--src/Mount/Mount_vs2019.vcxproj21
-rw-r--r--src/NOTICE4
-rw-r--r--src/Platform/Unix/Process.cpp1
-rw-r--r--src/Readme.txt5
-rw-r--r--src/Release/Setup Files/Product64.wxs16
-rw-r--r--src/Release/Setup Files/veracrypt-arm64.catbin10640 -> 11663 bytes
-rw-r--r--src/Release/Setup Files/veracrypt-arm64.sysbin451928 -> 437768 bytes
-rw-r--r--src/Release/Setup Files/veracrypt-x64.catbin10695 -> 10682 bytes
-rw-r--r--src/Release/Setup Files/veracrypt-x64.sysbin825176 -> 811512 bytes
-rw-r--r--src/Release/Setup Files/veracrypt.Inf4
-rw-r--r--src/Release/Setup Files/veracrypt.catbin10628 -> 11649 bytes
-rw-r--r--src/Release/Setup Files/veracrypt.sysbin791384 -> 796680 bytes
-rw-r--r--src/Resources/Texts/License.rtf435
-rw-r--r--src/Setup/Dir.c12
-rw-r--r--src/Setup/Linux/veracrypt-uninstall.sh2
-rw-r--r--src/Setup/Linux/veracrypt_install_template.sh2
-rwxr-xr-xsrc/Setup/MacOSX/postinstall.sh4
-rwxr-xr-xsrc/Setup/MacOSX/veracrypt.pkgproj5
-rwxr-xr-xsrc/Setup/MacOSX/veracrypt_Legacy.pkgproj4
-rw-r--r--src/Setup/Portable.rc8
-rw-r--r--src/Setup/Portable.vcxproj76
-rw-r--r--src/Setup/SelfExtract.c93
-rw-r--r--src/Setup/SelfExtract.h5
-rw-r--r--src/Setup/Setup.c287
-rw-r--r--src/Setup/Setup.rc12
-rw-r--r--src/Setup/Setup.vcxproj78
-rw-r--r--src/SetupDLL/Dir.c12
-rw-r--r--src/SetupDLL/Setup.c58
-rw-r--r--src/SetupDLL/Setup.rc8
-rw-r--r--src/SetupDLL/SetupDLL.vcxproj12
-rw-r--r--src/Signing/sign.bat16
-rw-r--r--src/Signing/sign_TESTSIGNING.bat59
-rw-r--r--src/Signing/sign_test.bat4
-rw-r--r--src/Signing/sign_test_debug.bat4
-rw-r--r--src/VeraCrypt.sln194
-rw-r--r--src/VeraCrypt_vs2019.sln130
-rw-r--r--src/Volume/Cipher.cpp44
-rw-r--r--src/Volume/Cipher.h3
-rw-r--r--src/Volume/EncryptionAlgorithm.cpp12
-rw-r--r--src/Volume/EncryptionAlgorithm.h1
-rw-r--r--src/Volume/EncryptionTest.cpp61
-rw-r--r--src/Volume/Hash.cpp21
-rw-r--r--src/Volume/Hash.h20
-rw-r--r--src/Volume/Pkcs5Kdf.cpp11
-rw-r--r--src/Volume/Pkcs5Kdf.h36
-rw-r--r--src/Volume/Volume.make16
-rw-r--r--src/Volume/VolumeLayout.cpp8
228 files changed, 29790 insertions, 4536 deletions
diff --git a/src/Boot/EFI/DcsBoot.efi b/src/Boot/EFI/DcsBoot.efi
index 8586811b..02884df9 100644
--- a/src/Boot/EFI/DcsBoot.efi
+++ b/src/Boot/EFI/DcsBoot.efi
Binary files differ
diff --git a/src/Boot/EFI/DcsBoot32.efi b/src/Boot/EFI/DcsBoot32.efi
index 74aa566d..1447e98b 100644
--- a/src/Boot/EFI/DcsBoot32.efi
+++ b/src/Boot/EFI/DcsBoot32.efi
Binary files differ
diff --git a/src/Boot/EFI/DcsCfg.efi b/src/Boot/EFI/DcsCfg.efi
index 00bc092b..82dc446a 100644
--- a/src/Boot/EFI/DcsCfg.efi
+++ b/src/Boot/EFI/DcsCfg.efi
Binary files differ
diff --git a/src/Boot/EFI/DcsCfg32.efi b/src/Boot/EFI/DcsCfg32.efi
index 2b128f6c..899197ff 100644
--- a/src/Boot/EFI/DcsCfg32.efi
+++ b/src/Boot/EFI/DcsCfg32.efi
Binary files differ
diff --git a/src/Boot/EFI/DcsInfo.efi b/src/Boot/EFI/DcsInfo.efi
index 734a37a1..15810f4d 100644
--- a/src/Boot/EFI/DcsInfo.efi
+++ b/src/Boot/EFI/DcsInfo.efi
Binary files differ
diff --git a/src/Boot/EFI/DcsInfo32.efi b/src/Boot/EFI/DcsInfo32.efi
index ccb535a4..ddb1e64b 100644
--- a/src/Boot/EFI/DcsInfo32.efi
+++ b/src/Boot/EFI/DcsInfo32.efi
Binary files differ
diff --git a/src/Boot/EFI/DcsInt.efi b/src/Boot/EFI/DcsInt.efi
index b99dc7e9..3816327a 100644
--- a/src/Boot/EFI/DcsInt.efi
+++ b/src/Boot/EFI/DcsInt.efi
Binary files differ
diff --git a/src/Boot/EFI/DcsInt32.efi b/src/Boot/EFI/DcsInt32.efi
index ec17389b..36d7b61f 100644
--- a/src/Boot/EFI/DcsInt32.efi
+++ b/src/Boot/EFI/DcsInt32.efi
Binary files differ
diff --git a/src/Boot/EFI/DcsRe.efi b/src/Boot/EFI/DcsRe.efi
index 4805129e..599f7026 100644
--- a/src/Boot/EFI/DcsRe.efi
+++ b/src/Boot/EFI/DcsRe.efi
Binary files differ
diff --git a/src/Boot/EFI/DcsRe32.efi b/src/Boot/EFI/DcsRe32.efi
index 841c1497..f2a935b7 100644
--- a/src/Boot/EFI/DcsRe32.efi
+++ b/src/Boot/EFI/DcsRe32.efi
Binary files differ
diff --git a/src/Boot/EFI/LegacySpeaker.efi b/src/Boot/EFI/LegacySpeaker.efi
index 2164ad57..034c760b 100644
--- a/src/Boot/EFI/LegacySpeaker.efi
+++ b/src/Boot/EFI/LegacySpeaker.efi
Binary files differ
diff --git a/src/Boot/EFI/LegacySpeaker32.efi b/src/Boot/EFI/LegacySpeaker32.efi
index 2b6e8cbd..5b52ba9f 100644
--- a/src/Boot/EFI/LegacySpeaker32.efi
+++ b/src/Boot/EFI/LegacySpeaker32.efi
Binary files differ
diff --git a/src/Boot/Windows/Boot.vcxproj b/src/Boot/Windows/Boot.vcxproj
index 68d5d270..b9a04d80 100644
--- a/src/Boot/Windows/Boot.vcxproj
+++ b/src/Boot/Windows/Boot.vcxproj
@@ -222,6 +222,7 @@ nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=TWOFISH</NMakeReBuildCommandLine>
<ItemDefinitionGroup>
</ItemDefinitionGroup>
<ItemGroup>
+ <ClCompile Include="..\..\Crypto\blake2s-ref.c" />
<ClCompile Include="BootConfig.cpp" />
<ClCompile Include="BootConsoleIo.cpp" />
<ClCompile Include="BootDebug.cpp" />
@@ -240,7 +241,6 @@ nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=TWOFISH</NMakeReBuildCommandLine>
<ClCompile Include="..\..\Common\Xts.c" />
<ClCompile Include="..\..\Crypto\AesSmall.c" />
<ClCompile Include="..\..\Crypto\CamelliaSmall.c" />
- <ClCompile Include="..\..\Crypto\Rmd160.c" />
<ClCompile Include="..\..\Crypto\Serpent.c" />
<ClCompile Include="..\..\Crypto\Sha2Small.c" />
<ClCompile Include="..\..\Crypto\Twofish.c" />
diff --git a/src/Boot/Windows/Boot.vcxproj.filters b/src/Boot/Windows/Boot.vcxproj.filters
index 1a60ac81..24d23894 100644
--- a/src/Boot/Windows/Boot.vcxproj.filters
+++ b/src/Boot/Windows/Boot.vcxproj.filters
@@ -74,9 +74,6 @@
<ClCompile Include="..\..\Crypto\CamelliaSmall.c">
<Filter>Source Files\Crypto</Filter>
</ClCompile>
- <ClCompile Include="..\..\Crypto\Rmd160.c">
- <Filter>Source Files\Crypto</Filter>
- </ClCompile>
<ClCompile Include="..\..\Crypto\Serpent.c">
<Filter>Source Files\Crypto</Filter>
</ClCompile>
@@ -86,6 +83,9 @@
<ClCompile Include="..\..\Crypto\Twofish.c">
<Filter>Source Files\Crypto</Filter>
</ClCompile>
+ <ClCompile Include="..\..\Crypto\blake2s-ref.c">
+ <Filter>Source Files\Crypto</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="BootCrt.asm">
diff --git a/src/Boot/Windows/BootCommon.h b/src/Boot/Windows/BootCommon.h
index 78bf55d8..d2ee42a1 100644
--- a/src/Boot/Windows/BootCommon.h
+++ b/src/Boot/Windows/BootCommon.h
@@ -17,7 +17,7 @@
#include "BootDefs.h"
// The user will be advised to upgrade the rescue disk if upgrading from the following or any previous version
-#define TC_RESCUE_DISK_UPGRADE_NOTICE_MAX_VERSION 0x0123
+#define TC_RESCUE_DISK_UPGRADE_NOTICE_MAX_VERSION 0x0125
#define TC_BOOT_LOADER_AREA_SIZE (TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS)
diff --git a/src/Boot/Windows/Makefile b/src/Boot/Windows/Makefile
index 9689b7cf..d08e1f50 100644
--- a/src/Boot/Windows/Makefile
+++ b/src/Boot/Windows/Makefile
@@ -46,7 +46,7 @@ CFLAGS = $(CFLAGS) /D TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE /D TC_WINDOWS_BOOT_$(SI
OBJDIR = $(OBJDIR)_$(SINGLE_PRF)
CFLAGS = $(CFLAGS) /D TC_WINDOWS_BOOT_$(SINGLE_PRF)
!else
-CFLAGS = $(CFLAGS) /D TC_WINDOWS_BOOT_RIPEMD160
+CFLAGS = $(CFLAGS) /D TC_WINDOWS_BOOT_BLAKE2S
!endif
OUTDIR = $(OBJDIR)
@@ -85,7 +85,7 @@ OBJS = $(OBJS) $(OUTDIR)\Xts.obj
!if "$(SINGLE_PRF)" == "SHA2"
OBJS = $(OBJS) $(OUTDIR)\Sha2Small.obj
!else
-OBJS = $(OBJS) $(OUTDIR)\Rmd160.obj
+OBJS = $(OBJS) $(OUTDIR)\blake2s-ref.obj
!endif
!if !DEFINED (SINGLE_CIPHER)
diff --git a/src/Boot/Windows/Release/BootLoader.com.gz b/src/Boot/Windows/Release/BootLoader.com.gz
index a44400cf..d4cd2a66 100644
--- a/src/Boot/Windows/Release/BootLoader.com.gz
+++ b/src/Boot/Windows/Release/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Release_AES/BootLoader.com.gz b/src/Boot/Windows/Release_AES/BootLoader.com.gz
index d5388b1f..de7d9c35 100644
--- a/src/Boot/Windows/Release_AES/BootLoader.com.gz
+++ b/src/Boot/Windows/Release_AES/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Release_AES_SHA2/BootLoader.com.gz b/src/Boot/Windows/Release_AES_SHA2/BootLoader.com.gz
index 1605d8db..42c271aa 100644
--- a/src/Boot/Windows/Release_AES_SHA2/BootLoader.com.gz
+++ b/src/Boot/Windows/Release_AES_SHA2/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Release_Camellia/BootLoader.com.gz b/src/Boot/Windows/Release_Camellia/BootLoader.com.gz
index 2ced32fa..090efd03 100644
--- a/src/Boot/Windows/Release_Camellia/BootLoader.com.gz
+++ b/src/Boot/Windows/Release_Camellia/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Release_Camellia_SHA2/BootLoader.com.gz b/src/Boot/Windows/Release_Camellia_SHA2/BootLoader.com.gz
index c67ef74c..13ff1405 100644
--- a/src/Boot/Windows/Release_Camellia_SHA2/BootLoader.com.gz
+++ b/src/Boot/Windows/Release_Camellia_SHA2/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Release_SHA2/BootLoader.com.gz b/src/Boot/Windows/Release_SHA2/BootLoader.com.gz
index 77d6df0f..d596c445 100644
--- a/src/Boot/Windows/Release_SHA2/BootLoader.com.gz
+++ b/src/Boot/Windows/Release_SHA2/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Release_Serpent/BootLoader.com.gz b/src/Boot/Windows/Release_Serpent/BootLoader.com.gz
index 6c387e95..9cb0b0cb 100644
--- a/src/Boot/Windows/Release_Serpent/BootLoader.com.gz
+++ b/src/Boot/Windows/Release_Serpent/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Release_Serpent_SHA2/BootLoader.com.gz b/src/Boot/Windows/Release_Serpent_SHA2/BootLoader.com.gz
index 3eae4149..7353e440 100644
--- a/src/Boot/Windows/Release_Serpent_SHA2/BootLoader.com.gz
+++ b/src/Boot/Windows/Release_Serpent_SHA2/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Release_Twofish/BootLoader.com.gz b/src/Boot/Windows/Release_Twofish/BootLoader.com.gz
index 701d3f5a..69e3b264 100644
--- a/src/Boot/Windows/Release_Twofish/BootLoader.com.gz
+++ b/src/Boot/Windows/Release_Twofish/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Release_Twofish_SHA2/BootLoader.com.gz b/src/Boot/Windows/Release_Twofish_SHA2/BootLoader.com.gz
index aed584fe..6e008a19 100644
--- a/src/Boot/Windows/Release_Twofish_SHA2/BootLoader.com.gz
+++ b/src/Boot/Windows/Release_Twofish_SHA2/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Rescue/BootLoader.com.gz b/src/Boot/Windows/Rescue/BootLoader.com.gz
index 054ff948..3e6ee5c3 100644
--- a/src/Boot/Windows/Rescue/BootLoader.com.gz
+++ b/src/Boot/Windows/Rescue/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Rescue_AES/BootLoader.com.gz b/src/Boot/Windows/Rescue_AES/BootLoader.com.gz
index a2c9ec65..6a3cfdcb 100644
--- a/src/Boot/Windows/Rescue_AES/BootLoader.com.gz
+++ b/src/Boot/Windows/Rescue_AES/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Rescue_AES_SHA2/BootLoader.com.gz b/src/Boot/Windows/Rescue_AES_SHA2/BootLoader.com.gz
index 70b79a65..0cb31996 100644
--- a/src/Boot/Windows/Rescue_AES_SHA2/BootLoader.com.gz
+++ b/src/Boot/Windows/Rescue_AES_SHA2/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Rescue_Camellia/BootLoader.com.gz b/src/Boot/Windows/Rescue_Camellia/BootLoader.com.gz
index 5f16ceb3..7c934a57 100644
--- a/src/Boot/Windows/Rescue_Camellia/BootLoader.com.gz
+++ b/src/Boot/Windows/Rescue_Camellia/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Rescue_Camellia_SHA2/BootLoader.com.gz b/src/Boot/Windows/Rescue_Camellia_SHA2/BootLoader.com.gz
index da441175..ca2952aa 100644
--- a/src/Boot/Windows/Rescue_Camellia_SHA2/BootLoader.com.gz
+++ b/src/Boot/Windows/Rescue_Camellia_SHA2/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Rescue_SHA2/BootLoader.com.gz b/src/Boot/Windows/Rescue_SHA2/BootLoader.com.gz
index 535690af..3a9410ba 100644
--- a/src/Boot/Windows/Rescue_SHA2/BootLoader.com.gz
+++ b/src/Boot/Windows/Rescue_SHA2/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Rescue_Serpent/BootLoader.com.gz b/src/Boot/Windows/Rescue_Serpent/BootLoader.com.gz
index 46c441ce..cd6fe5d5 100644
--- a/src/Boot/Windows/Rescue_Serpent/BootLoader.com.gz
+++ b/src/Boot/Windows/Rescue_Serpent/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Rescue_Serpent_SHA2/BootLoader.com.gz b/src/Boot/Windows/Rescue_Serpent_SHA2/BootLoader.com.gz
index 1de40c72..37d4d02b 100644
--- a/src/Boot/Windows/Rescue_Serpent_SHA2/BootLoader.com.gz
+++ b/src/Boot/Windows/Rescue_Serpent_SHA2/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Rescue_Twofish/BootLoader.com.gz b/src/Boot/Windows/Rescue_Twofish/BootLoader.com.gz
index 8c10f643..6a2d1c5f 100644
--- a/src/Boot/Windows/Rescue_Twofish/BootLoader.com.gz
+++ b/src/Boot/Windows/Rescue_Twofish/BootLoader.com.gz
Binary files differ
diff --git a/src/Boot/Windows/Rescue_Twofish_SHA2/BootLoader.com.gz b/src/Boot/Windows/Rescue_Twofish_SHA2/BootLoader.com.gz
index 0cc44dc4..f262a558 100644
--- a/src/Boot/Windows/Rescue_Twofish_SHA2/BootLoader.com.gz
+++ b/src/Boot/Windows/Rescue_Twofish_SHA2/BootLoader.com.gz
Binary files differ
diff --git a/src/Build/CMakeLists.txt b/src/Build/CMakeLists.txt
index 4f88523b..24c37df9 100644
--- a/src/Build/CMakeLists.txt
+++ b/src/Build/CMakeLists.txt
@@ -11,8 +11,8 @@ elseif ( NOT DEFINED NOGUI )
endif()
# - Set version of the package
-set( FULL_VERSION "1.25.4" )
-set( VERSION "1.25.4" )
+set( FULL_VERSION "1.26.0" )
+set( VERSION "1.26.0" )
set( RELEASE "1" )
# - Set PROJECT_NAME and CONFLICT_PACKAGE values
diff --git a/src/Build/Include/Makefile.inc b/src/Build/Include/Makefile.inc
index 4c153657..b7ed20c9 100644
--- a/src/Build/Include/Makefile.inc
+++ b/src/Build/Include/Makefile.inc
@@ -14,7 +14,7 @@ $(NAME): $(NAME).a
clean:
@echo Cleaning $(NAME)
- rm -f $(APPNAME) $(NAME).a $(OBJS) $(OBJSEX) $(OBJSNOOPT) $(OBJS:.o=.d) $(OBJSEX:.oo=.d) $(OBJSNOOPT:.o0=.d) *.gch
+ rm -f $(APPNAME) $(NAME).a $(OBJS) $(OBJSEX) $(OBJSNOOPT) $(OBJSSSE41) $(OBJSSSSE3) $(OBJS:.o=.d) $(OBJSEX:.oo=.d) $(OBJSNOOPT:.o0=.d) $(OBJSSSE41:.osse41=.d) $(OBJSSSSE3:.ossse3=.d) *.gch
%.o: %.c
@echo Compiling $(<F)
@@ -23,11 +23,27 @@ clean:
%.o0: %.c
@echo Compiling $(<F)
$(CC) $(CFLAGS) -O0 -c $< -o $@
+
+%.osse41: %.c
+ @echo Compiling $(<F)
+ $(CC) $(CFLAGS) -mssse3 -msse4.1 -c $< -o $@
+
+%.ossse3: %.c
+ @echo Compiling $(<F)
+ $(CC) $(CFLAGS) -mssse3 -c $< -o $@
%.o: %.cpp
@echo Compiling $(<F)
$(CXX) $(CXXFLAGS) -c $< -o $@
+%.osse41: %.cpp
+ @echo Compiling $(<F)
+ $(CXX) $(CXXFLAGS) -mssse3 -msse4.1 -c $< -o $@
+
+%.ossse3: %.cpp
+ @echo Compiling $(<F)
+ $(CXX) $(CXXFLAGS) -mssse3 -c $< -o $@
+
%.o: %.S
@echo Compiling $(<F)
$(CC) $(CFLAGS) -c $< -o $@
@@ -72,10 +88,10 @@ TR_SED_BIN := tr '\n' ' ' | tr -s ' ' ',' | sed -e 's/^,//g' -e 's/,$$/n/' | tr
# Dependencies
--include $(OBJS:.o=.d) $(OBJSEX:.oo=.d) $(OBJSNOOPT:.o0=.d)
+-include $(OBJS:.o=.d) $(OBJSEX:.oo=.d) $(OBJSNOOPT:.o0=.d) $(OBJSSSE41:.osse41=.d) $(OBJSSSSE3:.ossse3=.d)
-$(NAME).a: $(OBJS) $(OBJSEX) $(OBJSNOOPT)
+$(NAME).a: $(OBJS) $(OBJSEX) $(OBJSNOOPT) $(OBJSSSE41) $(OBJSSSSE3)
@echo Updating library $@
- $(AR) $(AFLAGS) -rcu $@ $(OBJS) $(OBJSEX) $(OBJSNOOPT)
+ $(AR) $(AFLAGS) -rcu $@ $(OBJS) $(OBJSEX) $(OBJSNOOPT) $(OBJSSSE41) $(OBJSSSSE3)
$(RANLIB) $@
diff --git a/src/Build/Resources/MacOSX/Info.plist.legacy.xml b/src/Build/Resources/MacOSX/Info.plist.legacy.xml
index 6d4aa2ed..ffe0ed69 100644
--- a/src/Build/Resources/MacOSX/Info.plist.legacy.xml
+++ b/src/Build/Resources/MacOSX/Info.plist.legacy.xml
@@ -74,7 +74,7 @@
<string>TRUE</string>
<key>CFBundleVersion</key>
- <string>1.25.4</string>
+ <string>1.26.0</string>
<key>CFBundleShortVersionString</key>
<string>_VERSION_</string>
diff --git a/src/Build/Resources/MacOSX/Info.plist.xml b/src/Build/Resources/MacOSX/Info.plist.xml
index cd7da625..d4729eff 100644
--- a/src/Build/Resources/MacOSX/Info.plist.xml
+++ b/src/Build/Resources/MacOSX/Info.plist.xml
@@ -74,7 +74,7 @@
<string>TRUE</string>
<key>CFBundleVersion</key>
- <string>1.25.4</string>
+ <string>1.26.0</string>
<key>CFBundleShortVersionString</key>
<string>_VERSION_</string>
diff --git a/src/Build/build_cmake_deb.sh b/src/Build/build_cmake_deb.sh
index 7a0eefc6..e02edf2f 100755
--- a/src/Build/build_cmake_deb.sh
+++ b/src/Build/build_cmake_deb.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2013-2021 IDRIX
+# Copyright (c) 2013-2022 IDRIX
# Governed by the Apache License 2.0 the full text of which is contained
# in the file License.txt included in VeraCrypt binary and source
# code distribution packages.
diff --git a/src/Build/build_cmake_opensuse.sh b/src/Build/build_cmake_opensuse.sh
index 9f642e46..81ca47cf 100644
--- a/src/Build/build_cmake_opensuse.sh
+++ b/src/Build/build_cmake_opensuse.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2013-2021 IDRIX
+# Copyright (c) 2013-2022 IDRIX
# Governed by the Apache License 2.0 the full text of which is contained
# in the file License.txt included in VeraCrypt binary and source
# code distribution packages.
diff --git a/src/Build/build_cmake_rpm_gtk2.sh b/src/Build/build_cmake_rpm_gtk2.sh
index 7e2599d3..23472356 100644
--- a/src/Build/build_cmake_rpm_gtk2.sh
+++ b/src/Build/build_cmake_rpm_gtk2.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2013-2021 IDRIX
+# Copyright (c) 2013-2022 IDRIX
# Governed by the Apache License 2.0 the full text of which is contained
# in the file License.txt included in VeraCrypt binary and source
# code distribution packages.
diff --git a/src/Build/build_cmake_rpm_gtk3.sh b/src/Build/build_cmake_rpm_gtk3.sh
index 20f62604..e13b5d06 100644
--- a/src/Build/build_cmake_rpm_gtk3.sh
+++ b/src/Build/build_cmake_rpm_gtk3.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2013-2021 IDRIX
+# Copyright (c) 2013-2022 IDRIX
# Governed by the Apache License 2.0 the full text of which is contained
# in the file License.txt included in VeraCrypt binary and source
# code distribution packages.
diff --git a/src/Build/build_veracrypt_freebsd.sh b/src/Build/build_veracrypt_freebsd.sh
index c5c07719..33f4bf48 100755
--- a/src/Build/build_veracrypt_freebsd.sh
+++ b/src/Build/build_veracrypt_freebsd.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# Copyright (c) 2013-2021 IDRIX
+# Copyright (c) 2013-2022 IDRIX
# Governed by the Apache License 2.0 the full text of which is contained
# in the file License.txt included in VeraCrypt binary and source
# code distribution packages.
diff --git a/src/Build/build_veracrypt_linux.sh b/src/Build/build_veracrypt_linux.sh
index 5d289255..7815e63f 100755
--- a/src/Build/build_veracrypt_linux.sh
+++ b/src/Build/build_veracrypt_linux.sh
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013-2021 IDRIX
+# Copyright (c) 2013-2022 IDRIX
# Governed by the Apache License 2.0 the full text of which is contained
# in the file License.txt included in VeraCrypt binary and source
# code distribution packages.
diff --git a/src/Build/build_veracrypt_linux_gtk3.sh b/src/Build/build_veracrypt_linux_gtk3.sh
index f8c1afed..d5a7444a 100644
--- a/src/Build/build_veracrypt_linux_gtk3.sh
+++ b/src/Build/build_veracrypt_linux_gtk3.sh
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013-2021 IDRIX
+# Copyright (c) 2013-2022 IDRIX
# Governed by the Apache License 2.0 the full text of which is contained
# in the file License.txt included in VeraCrypt binary and source
# code distribution packages.
diff --git a/src/Build/build_veracrypt_linux_no_sse2.sh b/src/Build/build_veracrypt_linux_no_sse2.sh
index e439582c..2916f846 100755
--- a/src/Build/build_veracrypt_linux_no_sse2.sh
+++ b/src/Build/build_veracrypt_linux_no_sse2.sh
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013-2021 IDRIX
+# Copyright (c) 2013-2022 IDRIX
# Governed by the Apache License 2.0 the full text of which is contained
# in the file License.txt included in VeraCrypt binary and source
# code distribution packages.
diff --git a/src/COMReg/COMReg.cpp b/src/COMReg/COMReg.cpp
new file mode 100644
index 00000000..9582b413
--- /dev/null
+++ b/src/COMReg/COMReg.cpp
@@ -0,0 +1,29 @@
+#include "Tcdefs.h"
+#include <windows.h>
+#include "SelfExtract.h"
+
+int APIENTRY _tWinMain(HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPTSTR lpCmdLine,
+ int nCmdShow)
+{
+ wchar_t SetupFilesDir[TC_MAX_PATH];
+ wchar_t *s;
+ UNREFERENCED_PARAMETER(hInstance);
+ UNREFERENCED_PARAMETER(hPrevInstance);
+ UNREFERENCED_PARAMETER(nCmdShow);
+
+ if (lpCmdLine[0] == L'/' && lpCmdLine[1] == L'p')
+ {
+ SelfExtractStartupInit();
+ GetModuleFileName (NULL, SetupFilesDir, ARRAYSIZE (SetupFilesDir));
+ s = wcsrchr (SetupFilesDir, L'\\');
+ if (s)
+ s[1] = 0;
+
+ /* Create self-extracting package */
+ MakeSelfExtractingPackage (NULL, SetupFilesDir, TRUE);
+ }
+
+ return 0;
+}
diff --git a/src/COMReg/COMReg.rc b/src/COMReg/COMReg.rc
new file mode 100644
index 00000000..9923286e
--- /dev/null
+++ b/src/COMReg/COMReg.rc
@@ -0,0 +1,100 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,26,0,0
+ PRODUCTVERSION 1,26,0,0
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "IDRIX"
+ VALUE "FileDescription", "VeraCrypt COMReg"
+ VALUE "FileVersion", "1.26"
+ VALUE "LegalTrademarks", "VeraCrypt"
+ VALUE "OriginalFilename", "VeraCrypt COMReg.exe"
+ VALUE "ProductName", "VeraCrypt"
+ VALUE "ProductVersion", "1.26"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// REGISTRY
+//
+
+IDR_COMREG REGISTRY "..\Setup\ComSetup.rgs"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_COMREG ICON "..\Setup\Setup.ico"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "#include ""..\\\\common\\\\resource.h""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
diff --git a/src/COMReg/COMReg.vcxproj b/src/COMReg/COMReg.vcxproj
new file mode 100644
index 00000000..91a440e1
--- /dev/null
+++ b/src/COMReg/COMReg.vcxproj
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{C8914211-32AC-4F48-ACD9-8212E8DE53F3}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>COMReg</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <TargetName>VeraCryptCOMRegBase</TargetName>
+ <OutDir>Debug\</OutDir>
+ <IntDir>Debug\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <TargetName>VeraCryptCOMRegBase</TargetName>
+ <OutDir>Release\</OutDir>
+ <IntDir>Release\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;VC_COMREG;_DEBUG;_WINDOWS;HAVE_CONFIG_H;ZIP_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <AdditionalIncludeDirectories>..\Setup;..\Common;..\Crypto;..\;..\PKCS11;..\Common\zlib;..\Common\libzip;..\Common\lzma;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>..\Common\Debug\Zip.lib;..\Crypto\Debug\crypto.lib;..\Common\Debug\lzma.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <PostBuildEvent>
+ <Command>copy Debug\VeraCryptCOMRegBase.exe "..\Debug\Setup Files\VeraCryptCOMRegBase.exe"</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>NotUsing</PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;VC_COMREG;NDEBUG;_WINDOWS;HAVE_CONFIG_H;ZIP_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <AdditionalIncludeDirectories>..\Setup;..\Common;..\Crypto;..\;..\PKCS11;..\Common\zlib;..\Common\libzip;..\Common\lzma;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>..\Common\Release\Zip.lib;..\Crypto\Release\crypto.lib;..\Common\Release\lzma.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <PostBuildEvent>
+ <Command>copy Release\VeraCryptCOMRegBase.exe "..\Release\Setup Files\VeraCryptCOMRegBase.exe"</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\Common\Crc.c" />
+ <ClCompile Include="..\Common\Dlgcode.c">
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">CompileAsCpp</CompileAs>
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">CompileAsCpp</CompileAs>
+ </ClCompile>
+ <ClCompile Include="..\Setup\SelfExtract.c">
+ <CompileAs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Default</CompileAs>
+ </ClCompile>
+ <ClCompile Include="COMReg.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="COMReg.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\Common\Crc.h" />
+ <ClInclude Include="..\Common\Dlgcode.h" />
+ <ClInclude Include="..\Setup\SelfExtract.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Common\Lzma.vcxproj">
+ <Project>{b896fe1f-6bf3-4f75-9148-f841829073d9}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/src/COMReg/COMReg.vcxproj.filters b/src/COMReg/COMReg.vcxproj.filters
new file mode 100644
index 00000000..cc5c60a3
--- /dev/null
+++ b/src/COMReg/COMReg.vcxproj.filters
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{453a6bf1-2afd-4016-8b8f-e3821a6c8ab5}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\Common">
+ <UniqueIdentifier>{efcd999c-3973-4bd6-af14-0583669e6722}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="COMReg.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\Setup\SelfExtract.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\Common\Dlgcode.c">
+ <Filter>Source Files\Common</Filter>
+ </ClCompile>
+ <ClCompile Include="..\Common\Crc.c">
+ <Filter>Source Files\Common</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="COMReg.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\Setup\SelfExtract.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\Common\Dlgcode.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\Common\Crc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/COMReg/COMReg.vcxproj.user b/src/COMReg/COMReg.vcxproj.user
new file mode 100644
index 00000000..deea718b
--- /dev/null
+++ b/src/COMReg/COMReg.vcxproj.user
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LocalDebuggerCommand>$(TargetPath)</LocalDebuggerCommand>
+ <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+ </PropertyGroup>
+</Project> \ No newline at end of file
diff --git a/src/COMReg/Resource.h b/src/COMReg/Resource.h
new file mode 100644
index 00000000..14901ce6
--- /dev/null
+++ b/src/COMReg/Resource.h
@@ -0,0 +1,18 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by COMReg.rc
+//
+#define IDR_COMREG 10
+#define IDI_COMREG 11
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 12
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/Common/Apidrvr.h b/src/Common/Apidrvr.h
index c56d9ff7..2eddc3dd 100644
--- a/src/Common/Apidrvr.h
+++ b/src/Common/Apidrvr.h
@@ -127,6 +127,8 @@
#define VC_IOCTL_IS_RAM_ENCRYPTION_ENABLED TC_IOCTL (42)
+#define VC_IOCTL_ENCRYPTION_QUEUE_PARAMS TC_IOCTL (43)
+
// Legacy IOCTLs used before version 5.0
#define TC_IOCTL_LEGACY_GET_DRIVER_VERSION 466968
#define TC_IOCTL_LEGACY_GET_MOUNTED_VOLUMES 466948
@@ -390,6 +392,13 @@ typedef struct
BOOL HwEncryptionEnabled;
} GetSystemDriveDumpConfigRequest;
+typedef struct
+{
+ int EncryptionIoRequestCount;
+ int EncryptionItemCount;
+ int EncryptionFragmentSize;
+} EncryptionQueueParameters;
+
#pragma pack (pop)
#define DRIVER_STR WIDE
@@ -407,6 +416,12 @@ typedef struct
#define TC_DRIVER_CONFIG_REG_VALUE_NAME DRIVER_STR("VeraCryptConfig")
#define TC_ENCRYPTION_FREE_CPU_COUNT_REG_VALUE_NAME DRIVER_STR("VeraCryptEncryptionFreeCpuCount")
+#define VC_ENCRYPTION_IO_REQUEST_COUNT DRIVER_STR("VeraCryptEncryptionIoRequestCount")
+#define VC_ENCRYPTION_ITEM_COUNT DRIVER_STR("VeraCryptEncryptionItemCount")
+#define VC_ENCRYPTION_FRAGMENT_SIZE DRIVER_STR("VeraCryptEncryptionFragmentSize")
+
+#define VC_ERASE_KEYS_SHUTDOWN DRIVER_STR("VeraCryptEraseKeysShutdown")
+
// WARNING: Modifying the following values can introduce incompatibility with previous versions.
#define TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD 0x1
#define TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD_FOR_SYS_FAVORITES 0x2
diff --git a/src/Common/BootEncryption.cpp b/src/Common/BootEncryption.cpp
index c8fc90bf..079eacc6 100644
--- a/src/Common/BootEncryption.cpp
+++ b/src/Common/BootEncryption.cpp
@@ -1705,15 +1705,11 @@ namespace VeraCrypt
ea = TWOFISH;
else if (_stricmp (request.BootEncryptionAlgorithmName, "Camellia") == 0)
ea = CAMELLIA;
-#if defined(CIPHER_GOST89)
- else if (_stricmp (request.BootEncryptionAlgorithmName, "GOST89") == 0)
- ea = GOST89;
-#endif
if (_stricmp(request.BootPrfAlgorithmName, "SHA-256") == 0)
pkcs5_prf = SHA256;
- else if (_stricmp(request.BootPrfAlgorithmName, "RIPEMD-160") == 0)
- pkcs5_prf = RIPEMD160;
+ else if (_stricmp(request.BootPrfAlgorithmName, "BLAKE2s-256") == 0)
+ pkcs5_prf = BLAKE2S;
else if (_stricmp(request.BootPrfAlgorithmName, "SHA-512") == 0)
pkcs5_prf = SHA512;
else if (_stricmp(request.BootPrfAlgorithmName, "Whirlpool") == 0)
@@ -1721,7 +1717,7 @@ namespace VeraCrypt
else if (_stricmp(request.BootPrfAlgorithmName, "Streebog") == 0)
pkcs5_prf = STREEBOG;
else if (strlen(request.BootPrfAlgorithmName) == 0) // case of version < 1.0f
- pkcs5_prf = RIPEMD160;
+ pkcs5_prf = BLAKE2S;
}
catch (...)
{
@@ -1747,8 +1743,8 @@ namespace VeraCrypt
pkcs5_prf = SelectedPrfAlgorithmId;
}
- // Only RIPEMD160 and SHA-256 are supported for MBR boot loader
- if (!bIsGPT && pkcs5_prf != RIPEMD160 && pkcs5_prf != SHA256)
+ // Only BLAKE2s and SHA-256 are supported for MBR boot loader
+ if (!bIsGPT && pkcs5_prf != BLAKE2S && pkcs5_prf != SHA256)
throw ParameterIncorrect (SRC_POS);
int bootSectorId = 0;
@@ -2218,12 +2214,11 @@ namespace VeraCrypt
#endif // !SETUP
- NtQuerySystemInformationFn NtQuerySystemInformationPtr = NULL;
EfiBootConf::EfiBootConf() : passwordType (0),
passwordMsg ("Password: "),
passwordPicture ("login.bmp"),
- hashMsg ("(0) TEST ALL (1) SHA512 (2) WHIRLPOOL (3) SHA256 (4) RIPEMD160 (5) STREEBOG\nHash: "),
+ hashMsg ("(0) TEST ALL (1) SHA512 (2) WHIRLPOOL (3) SHA256 (4) BLAKE2S (5) STREEBOG\nHash: "),
hashAlgo (0),
requestHash (0),
pimMsg ("PIM (Leave empty for default): "),
@@ -2340,7 +2335,7 @@ namespace VeraCrypt
passwordType = ReadConfigInteger (configContent, "PasswordType", 0);
passwordMsg = ReadConfigString (configContent, "PasswordMsg", "Password: ", buffer, sizeof (buffer));
passwordPicture = ReadConfigString (configContent, "PasswordPicture", "\\EFI\\VeraCrypt\\login.bmp", buffer, sizeof (buffer));
- //hashMsg = ReadConfigString (configContent, "HashMsg", "(0) TEST ALL (1) SHA512 (2) WHIRLPOOL (3) SHA256 (4) RIPEMD160 (5) STREEBOG\nHash: ", buffer, sizeof (buffer));
+ //hashMsg = ReadConfigString (configContent, "HashMsg", "(0) TEST ALL (1) SHA512 (2) WHIRLPOOL (3) SHA256 (4) BLAKE2S (5) STREEBOG\nHash: ", buffer, sizeof (buffer));
hashAlgo = ReadConfigInteger (configContent, "Hash", 0);
requestHash = ReadConfigInteger (configContent, "HashRqt", 1);
pimMsg = ReadConfigString (configContent, "PimMsg", "PIM: ", buffer, sizeof (buffer));
@@ -2510,14 +2505,13 @@ namespace VeraCrypt
ULONG len;
NTSTATUS res;
WCHAR tempBuf[1024];
+ NtQuerySystemInformationFn NtQuerySystemInformationPtr = (NtQuerySystemInformationFn) GetProcAddress (GetModuleHandle (L"ntdll.dll"), "NtQuerySystemInformation");
memset(tempBuf, 0, sizeof(tempBuf));
// Load NtQuerySystemInformation function point
if (!NtQuerySystemInformationPtr)
{
- NtQuerySystemInformationPtr = (NtQuerySystemInformationFn) GetProcAddress (GetModuleHandle (L"ntdll.dll"), "NtQuerySystemInformation");
- if (!NtQuerySystemInformationPtr)
- throw SystemException (SRC_POS);
+ throw SystemException (SRC_POS);
}
res = NtQuerySystemInformationPtr((SYSTEM_INFORMATION_CLASS)SYSPARTITIONINFORMATION, tempBuf, sizeof(tempBuf), &len);
@@ -5838,4 +5832,32 @@ namespace VeraCrypt
{
return (::RestartComputer(bShutdown) != FALSE);
}
+
+ bool BootEncryption::IsUsingUnsupportedAlgorithm(LONG driverVersion)
+ {
+ bool bRet = false;
+
+ try
+ {
+ if (driverVersion <= 0x125)
+ {
+ // version 1.25 is last version to support RIPEMD160 and GOST89
+ static int GOST89_EA = 5;
+ static int RIPEMD160_PRF = 4;
+
+ VOLUME_PROPERTIES_STRUCT props = {0};
+ GetVolumeProperties(&props);
+
+ //
+ if (props.ea == GOST89_EA || props.pkcs5 == RIPEMD160_PRF)
+ bRet = true;
+ }
+ }
+ catch(...)
+ {
+
+ }
+
+ return bRet;
+ }
}
diff --git a/src/Common/BootEncryption.h b/src/Common/BootEncryption.h
index decacb8b..03c30ea7 100644
--- a/src/Common/BootEncryption.h
+++ b/src/Common/BootEncryption.h
@@ -18,16 +18,6 @@
#include "Exception.h"
#include "Platform/PlatformBase.h"
#include "Volumes.h"
-#include <Winternl.h>
-
-#define SYSPARTITIONINFORMATION 0x62
-
-typedef NTSTATUS (WINAPI *NtQuerySystemInformationFn)(
- SYSTEM_INFORMATION_CLASS SystemInformationClass,
- PVOID SystemInformation,
- ULONG SystemInformationLength,
- PULONG ReturnLength
-);
typedef ULONG (WINAPI *RtlNtStatusToDosErrorFn)(
NTSTATUS Status
@@ -323,6 +313,7 @@ namespace VeraCrypt
void RestoreSystemLoader ();
static void UpdateSetupConfigFile (bool bForInstall);
void GetSecureBootConfig (BOOL* pSecureBootEnabled, BOOL *pVeraCryptKeysLoaded);
+ bool IsUsingUnsupportedAlgorithm(LONG driverVersion);
protected:
static const uint32 RescueIsoImageSize = 1835008; // Size of ISO9660 image with bootable emulated 1.44MB floppy disk image
@@ -370,6 +361,7 @@ namespace VeraCrypt
#define TC_SYSTEM_FAVORITES_SERVICE_LOAD_ORDER_GROUP L"Event Log"
#define TC_SYSTEM_FAVORITES_SERVICE_CMDLINE_OPTION L"/systemFavoritesService"
#define VC_SYSTEM_FAVORITES_SERVICE_ARG_SKIP_MOUNT L"/SkipMount"
+#define VC_SYSTEM_FAVORITES_SERVICE_ARG_UPDATE_LOADER L"/UpdateLoader"
#define VC_SYSTEM_FAVORITES_SERVICE_CONFIG_DONT_UPDATE_LOADER 0x1
#define VC_SYSTEM_FAVORITES_SERVICE_CONFIG_FORCE_SET_BOOTNEXT 0x2
diff --git a/src/Common/Cache.c b/src/Common/Cache.c
index c204e03e..fe56a554 100644
--- a/src/Common/Cache.c
+++ b/src/Common/Cache.c
@@ -146,7 +146,7 @@ int ReadVolumeHeaderWCache (BOOL bBoot, BOOL bCache, BOOL bCachePim, char *heade
}
-void AddPasswordToCache (Password *password, int pim)
+void AddPasswordToCache (Password *password, int pim, BOOL bCachePim)
{
#ifdef _WIN64
Password tmpPass;
@@ -174,10 +174,18 @@ void AddPasswordToCache (Password *password, int pim)
if (IsRamEncryptionEnabled ())
VcProtectPassword (&CachedPasswords[nPasswordIdx], VcGetPasswordEncryptionID (&CachedPasswords[nPasswordIdx]));
#endif
- CachedPim[nPasswordIdx] = pim > 0? pim : 0;
+ /* Store also PIM if requested, otherwise set to default */
+ if (bCachePim && (pim > 0))
+ CachedPim[nPasswordIdx] = pim;
+ else
+ CachedPim[nPasswordIdx] = 0;
nPasswordIdx = (nPasswordIdx + 1) % CACHE_SIZE;
cacheEmpty = 0;
}
+ else if (bCachePim)
+ {
+ CachedPim[i] = pim > 0? pim : 0;
+ }
#ifdef _WIN64
if (IsRamEncryptionEnabled())
burn (&tmpPass, sizeof (Password));
@@ -190,7 +198,7 @@ void AddLegacyPasswordToCache (PasswordLegacy *password, int pim)
inputPass.Length = password->Length;
memcpy (inputPass.Text, password->Text, password->Length);
- AddPasswordToCache (&inputPass, pim);
+ AddPasswordToCache (&inputPass, pim, TRUE);
burn (&inputPass, sizeof (inputPass));
}
diff --git a/src/Common/Cache.h b/src/Common/Cache.h
index a9ed58a7..841d5e67 100644
--- a/src/Common/Cache.h
+++ b/src/Common/Cache.h
@@ -20,7 +20,7 @@
extern int cacheEmpty;
-void AddPasswordToCache (Password *password, int pim);
+void AddPasswordToCache (Password *password, int pim, BOOL bCachePim);
void AddLegacyPasswordToCache (PasswordLegacy *password, int pim);
int ReadVolumeHeaderWCache (BOOL bBoot, BOOL bCache, BOOL bCachePim,char *header, Password *password, int pkcs5_prf, int pim, BOOL truecryptMode, PCRYPTO_INFO *retInfo);
void WipeCache (void);
diff --git a/src/Common/Common.rc b/src/Common/Common.rc
index b26a400a..6d50a1fb 100644
--- a/src/Common/Common.rc
+++ b/src/Common/Common.rc
@@ -325,7 +325,7 @@ EXSTYLE WS_EX_TOPMOST | WS_EX_TOOLWINDOW
CAPTION "VeraCrypt"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
- LTEXT "Please wait. This process may take a long time...",IDT_STATIC_MODELESS_WAIT_DLG_INFO,9,8,274,9
+ LTEXT "Please wait. This process may take a long time...",IDT_STATIC_MODELESS_WAIT_DLG_INFO,9,8,274,27
END
IDD_STATIC_MODAL_WAIT_DLG DIALOGEX 0, 0, 292, 74
diff --git a/src/Common/Crypto.c b/src/Common/Crypto.c
index da233090..10c97e98 100644
--- a/src/Common/Crypto.c
+++ b/src/Common/Crypto.c
@@ -64,9 +64,6 @@ static Cipher Ciphers[] =
{ SERPENT, L"Serpent", 16, 32, 140*4 },
{ TWOFISH, L"Twofish", 16, 32, TWOFISH_KS },
{ CAMELLIA, L"Camellia", 16, 32, CAMELLIA_KS },
-#if defined(CIPHER_GOST89)
- { GOST89, L"GOST89", 16, 32, GOST_KS },
-#endif // defined(CIPHER_GOST89)
{ KUZNYECHIK, L"Kuznyechik",16, 32, KUZNYECHIK_KS },
#endif
{ 0, 0, 0, 0, 0 }
@@ -85,9 +82,6 @@ static EncryptionAlgorithm EncryptionAlgorithms[] =
{ { SERPENT, 0 }, { XTS, 0 }, 1, 1 },
{ { TWOFISH, 0 }, { XTS, 0 }, 1, 1 },
{ { CAMELLIA, 0 }, { XTS, 0 }, 1, 1 },
-#if defined(CIPHER_GOST89)
- { { GOST89, 0 }, { XTS, 0 }, 0, 0 },
-#endif // defined(CIPHER_GOST89)
{ { KUZNYECHIK, 0 }, { XTS, 0 }, 0, 1 },
{ { TWOFISH, AES, 0 }, { XTS, 0 }, 1, 1 },
{ { SERPENT, TWOFISH, AES, 0 }, { XTS, 0 }, 1, 1 },
@@ -126,8 +120,8 @@ static Hash Hashes[] =
{ // ID Name Deprecated System Encryption
{ SHA512, L"SHA-512", FALSE, FALSE },
{ WHIRLPOOL, L"Whirlpool", FALSE, FALSE },
+ { BLAKE2S, L"BLAKE2s-256", FALSE, TRUE },
{ SHA256, L"SHA-256", FALSE, TRUE },
- { RIPEMD160, L"RIPEMD-160", TRUE, TRUE },
{ STREEBOG, L"Streebog", FALSE, FALSE },
{ 0, 0, 0 }
};
@@ -168,11 +162,6 @@ int CipherInit (int cipher, unsigned char *key, unsigned __int8 *ks)
#endif
#if !defined(TC_WINDOWS_BOOT)
-#if defined(CIPHER_GOST89)
- case GOST89:
- gost_set_key(key, (gost_kds*)ks, 1);
- break;
-#endif // && defined(CIPHER_GOST89)
case KUZNYECHIK:
kuznyechik_set_key(key, (kuznyechik_kds*)ks);
break;
@@ -206,9 +195,6 @@ void EncipherBlock(int cipher, void *data, void *ks)
case CAMELLIA: camellia_encrypt (data, data, ks); break;
#endif
#if !defined(TC_WINDOWS_BOOT)
-#if defined(CIPHER_GOST89)
- case GOST89: gost_encrypt(data, data, ks, 1); break;
-#endif // defined(CIPHER_GOST89)
case KUZNYECHIK: kuznyechik_encrypt_block(data, data, ks); break;
#endif // !defined(TC_WINDOWS_BOOT)
default: TC_THROW_FATAL_EXCEPTION; // Unknown/wrong ID
@@ -281,9 +267,6 @@ void EncipherBlocks (int cipher, void *dataPtr, void *ks, size_t blockCount)
#endif
}
#endif
- else if (cipher == GOST89) {
- gost_encrypt(data, data, ks, (int)blockCount);
- }
else
{
size_t blockSize = CipherGetBlockSize (cipher);
@@ -307,9 +290,6 @@ void DecipherBlock(int cipher, void *data, void *ks)
case CAMELLIA: camellia_decrypt (data, data, ks); break;
#endif
#if !defined(TC_WINDOWS_BOOT)
-#if defined(CIPHER_GOST89)
- case GOST89: gost_decrypt(data, data, ks, 1); break;
-#endif // defined(CIPHER_GOST89)
case KUZNYECHIK: kuznyechik_decrypt_block(data, data, ks); break;
#endif // !defined(TC_WINDOWS_BOOT)
@@ -398,9 +378,6 @@ void DecipherBlocks (int cipher, void *dataPtr, void *ks, size_t blockCount)
#endif
}
#endif
- else if (cipher == GOST89) {
- gost_decrypt(data, data, ks, (int)blockCount);
- }
else
{
size_t blockSize = CipherGetBlockSize (cipher);
@@ -466,7 +443,6 @@ int CipherGetKeyScheduleSize (int cipherId)
BOOL CipherSupportsIntraDataUnitParallelization (int cipher)
{
return (cipher == AES && IsAesHwCpuSupported())
- || (cipher == GOST89)
#if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLE && !defined (_UEFI)
|| (cipher == SERPENT && HasSSE2())
|| (cipher == KUZNYECHIK && HasSSE2())
diff --git a/src/Common/Crypto.h b/src/Common/Crypto.h
index 95222ba6..b9600cf9 100644
--- a/src/Common/Crypto.h
+++ b/src/Common/Crypto.h
@@ -53,7 +53,7 @@ enum
SHA512 = FIRST_PRF_ID,
WHIRLPOOL,
SHA256,
- RIPEMD160,
+ BLAKE2S,
STREEBOG,
HASH_ENUM_END_ID
};
@@ -61,8 +61,8 @@ enum
// The last PRF to try when mounting and also the number of implemented PRFs
#define LAST_PRF_ID (HASH_ENUM_END_ID - 1)
-#define RIPEMD160_BLOCKSIZE 64
-#define RIPEMD160_DIGESTSIZE 20
+#define BLAKE2S_BLOCKSIZE 64
+#define BLAKE2S_DIGESTSIZE 32
#define SHA256_BLOCKSIZE 64
#define SHA256_DIGESTSIZE 32
@@ -112,7 +112,6 @@ enum
SERPENT,
TWOFISH,
CAMELLIA,
- GOST89,
KUZNYECHIK
};
@@ -173,7 +172,7 @@ typedef struct
#ifdef TC_WINDOWS_BOOT
#define MAX_EXPANDED_KEY VC_MAX((AES_KS + SERPENT_KS + TWOFISH_KS), CAMELLIA_KS)
#else
-#define MAX_EXPANDED_KEY VC_MAX(VC_MAX(VC_MAX(VC_MAX((AES_KS + SERPENT_KS + TWOFISH_KS), GOST_KS), CAMELLIA_KS + KUZNYECHIK_KS + SERPENT_KS), KUZNYECHIK_KS + TWOFISH_KS), AES_KS + KUZNYECHIK_KS)
+#define MAX_EXPANDED_KEY VC_MAX(VC_MAX(VC_MAX((AES_KS + SERPENT_KS + TWOFISH_KS), CAMELLIA_KS + KUZNYECHIK_KS + SERPENT_KS), KUZNYECHIK_KS + TWOFISH_KS), AES_KS + KUZNYECHIK_KS)
#endif
#endif
@@ -200,12 +199,11 @@ typedef struct
#endif
#include "Twofish.h"
-#include "Rmd160.h"
+#include "blake2.h"
#ifndef TC_WINDOWS_BOOT
# include "Sha2.h"
# include "Whirlpool.h"
# include "Streebog.h"
-# include "GostCipher.h"
# include "kuznyechik.h"
# include "Camellia.h"
#if !defined (_UEFI)
@@ -252,7 +250,7 @@ typedef struct CRYPTO_INFO_t
uint16 HeaderVersion;
#ifdef TC_WINDOWS_DRIVER
- unsigned __int8 master_keydata_hash[RIPEMD160_DIGESTSIZE];
+ unsigned __int8 master_keydata_hash[BLAKE2S_DIGESTSIZE];
#else
CRYPTOPP_ALIGN_DATA(16) unsigned __int8 master_keydata[MASTER_KEYDATA_SIZE]; /* This holds the volume header area containing concatenated master key(s) and secondary key(s) (XTS mode). For LRW (deprecated/legacy), it contains the tweak key before the master key(s). For CBC (deprecated/legacy), it contains the IV seed before the master key(s). */
CRYPTOPP_ALIGN_DATA(16) unsigned __int8 k2[MASTER_KEYDATA_SIZE]; /* For XTS, this contains the secondary key (if cascade, multiple concatenated). For LRW (deprecated/legacy), it contains the tweak key. For CBC (deprecated/legacy), it contains the IV seed. */
diff --git a/src/Common/Dlgcode.c b/src/Common/Dlgcode.c
index 6462e319..7b3d2d45 100644
--- a/src/Common/Dlgcode.c
+++ b/src/Common/Dlgcode.c
@@ -82,6 +82,11 @@
#include <WinTrust.h>
#include <strsafe.h>
+#define _WIN32_DCOM
+#include <comdef.h>
+#include <Wbemidl.h>
+
+#pragma comment(lib, "wbemuuid.lib")
#pragma comment( lib, "setupapi.lib" )
#ifndef TTI_INFO_LARGE
@@ -166,6 +171,12 @@ BOOL bHistory = FALSE;
#ifndef SETUP
BOOL bLanguageSetInSetup = FALSE;
+#else
+extern BOOL bMakePackage;
+#endif
+
+#ifdef TCMOUNT
+extern BOOL ServiceMode;
#endif
// Status of detection of hidden sectors (whole-system-drive encryption).
@@ -367,6 +378,12 @@ typedef BOOL (WINAPI *CreateProcessWithTokenWFn)(
__out LPPROCESS_INFORMATION lpProcessInformation
);
+typedef HRESULT (WINAPI *IUnknown_QueryServiceFn)(
+ __in IUnknown* punk,
+ __in REFGUID guidService,
+ __in REFIID riid,
+ __deref_out void ** ppvOut);
+
SetDllDirectoryPtr SetDllDirectoryFn = NULL;
SetSearchPathModePtr SetSearchPathModeFn = NULL;
SetDefaultDllDirectoriesPtr SetDefaultDllDirectoriesFn = NULL;
@@ -383,6 +400,7 @@ SHStrDupWPtr SHStrDupWFn = NULL;
UrlUnescapeWPtr UrlUnescapeWFn = NULL;
ChangeWindowMessageFilterPtr ChangeWindowMessageFilterFn = NULL;
CreateProcessWithTokenWFn CreateProcessWithTokenWPtr = NULL;
+IUnknown_QueryServiceFn IUnknown_QueryServicePtr = NULL;
typedef LONG (WINAPI *WINVERIFYTRUST)(HWND hwnd, GUID *pgActionID, LPVOID pWVTData);
typedef CRYPT_PROVIDER_DATA* (WINAPI *WTHELPERPROVDATAFROMSTATEDATA)(HANDLE hStateData);
@@ -399,12 +417,21 @@ static WTHELPERGETPROVSIGNERFROMCHAIN WTHelperGetProvSignerFromChainFn = NULL;
static WTHELPERGETPROVCERTFROMCHAIN WTHelperGetProvCertFromChainFn = NULL;
static unsigned char gpbSha256CodeSignCertFingerprint[64] = {
- 0xF2, 0x09, 0xD3, 0xC5, 0xF5, 0x36, 0x73, 0x4A, 0x64, 0x33, 0xEA, 0x00,
- 0x6C, 0x4D, 0x44, 0xE9, 0xAF, 0x3D, 0x50, 0xE5, 0x6B, 0xBB, 0xCD, 0xED,
- 0xD1, 0x37, 0x75, 0x49, 0xF5, 0xC1, 0xDE, 0xFB, 0xAD, 0xA0, 0xA6, 0x9A,
- 0xC9, 0xA1, 0xD7, 0x2E, 0xB1, 0xCC, 0xFE, 0x68, 0xA0, 0x2C, 0x00, 0xCA,
- 0x26, 0x52, 0xD3, 0x27, 0xDF, 0x4C, 0xEF, 0x94, 0x3D, 0x0D, 0xD1, 0xAA,
- 0xB1, 0x3B, 0xA6, 0xBF
+ 0x9C, 0xA0, 0x21, 0xD3, 0x7C, 0x90, 0x61, 0x88, 0xEF, 0x5F, 0x99, 0x3D,
+ 0x54, 0x9F, 0xB8, 0xCE, 0x72, 0x32, 0x4F, 0x57, 0x4F, 0x19, 0xD2, 0xA4,
+ 0xDC, 0x84, 0xFF, 0xE2, 0x84, 0x2B, 0xD4, 0x30, 0xAB, 0xA7, 0xE4, 0x63,
+ 0x18, 0xD1, 0xD8, 0x32, 0x0E, 0xA4, 0x81, 0x3C, 0x19, 0xBF, 0x13, 0x11,
+ 0xA4, 0x37, 0xD6, 0xDB, 0x26, 0xBA, 0xDC, 0x8F, 0x86, 0x96, 0x55, 0x96,
+ 0xDB, 0x6F, 0xC0, 0x62
+};
+
+static unsigned char gpbSha256MSCodeSignCertFingerprint[64] = {
+ 0x9C, 0x96, 0x81, 0x3B, 0x88, 0x54, 0xCB, 0x81, 0xB5, 0x94, 0x40, 0x4E,
+ 0x15, 0x81, 0x20, 0xA1, 0x19, 0x00, 0x4E, 0x49, 0x8A, 0xA8, 0x98, 0x13,
+ 0x9D, 0xE2, 0x86, 0x6A, 0xC1, 0xFA, 0xD3, 0x00, 0x0D, 0xAC, 0xE9, 0xE3,
+ 0x3B, 0xFC, 0x6B, 0x26, 0xCE, 0xC8, 0xE2, 0x36, 0x3B, 0x60, 0x9C, 0x8E,
+ 0x0A, 0x2A, 0x74, 0x20, 0xD7, 0x4E, 0x0F, 0xEE, 0x2E, 0x79, 0xE2, 0xAF,
+ 0x1C, 0x90, 0x0B, 0x9C
};
@@ -487,6 +514,959 @@ typedef struct
} MULTI_CHOICE_DLGPROC_PARAMS;
+
+
+
+// Loads a 32-bit integer from the file at the specified file offset. The saved value is assumed to have been
+// processed by mputLong(). The result is stored in *result. Returns TRUE if successful (otherwise FALSE).
+BOOL LoadInt32 (const wchar_t *filePath, unsigned __int32 *result, __int64 fileOffset)
+{
+ DWORD bufSize = sizeof(__int32);
+ unsigned char *buffer = (unsigned char *) malloc (bufSize);
+ unsigned char *bufferPtr = buffer;
+ HANDLE src = NULL;
+ DWORD bytesRead;
+ LARGE_INTEGER seekOffset, seekOffsetNew;
+ BOOL retVal = FALSE;
+
+ if (buffer == NULL)
+ return -1;
+
+ src = CreateFile (filePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (src == INVALID_HANDLE_VALUE)
+ {
+ free (buffer);
+ return FALSE;
+ }
+
+ seekOffset.QuadPart = fileOffset;
+
+ if (SetFilePointerEx (src, seekOffset, &seekOffsetNew, FILE_BEGIN) == 0)
+ goto fsif_end;
+
+ if (ReadFile (src, buffer, bufSize, &bytesRead, NULL) == 0
+ || bytesRead != bufSize)
+ goto fsif_end;
+
+
+ retVal = TRUE;
+
+ *result = mgetLong(bufferPtr);
+
+fsif_end:
+ CloseHandle (src);
+ free (buffer);
+
+ return retVal;
+}
+
+// Loads a 16-bit integer from the file at the specified file offset. The saved value is assumed to have been
+// processed by mputWord(). The result is stored in *result. Returns TRUE if successful (otherwise FALSE).
+BOOL LoadInt16 (const wchar_t *filePath, int *result, __int64 fileOffset)
+{
+ DWORD bufSize = sizeof(__int16);
+ unsigned char *buffer = (unsigned char *) malloc (bufSize);
+ unsigned char *bufferPtr = buffer;
+ HANDLE src = NULL;
+ DWORD bytesRead;
+ LARGE_INTEGER seekOffset, seekOffsetNew;
+ BOOL retVal = FALSE;
+
+ if (buffer == NULL)
+ return -1;
+
+ src = CreateFile (filePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (src == INVALID_HANDLE_VALUE)
+ {
+ free (buffer);
+ return FALSE;
+ }
+
+ seekOffset.QuadPart = fileOffset;
+
+ if (SetFilePointerEx (src, seekOffset, &seekOffsetNew, FILE_BEGIN) == 0)
+ goto fsif_end;
+
+ if (ReadFile (src, buffer, bufSize, &bytesRead, NULL) == 0
+ || bytesRead != bufSize)
+ goto fsif_end;
+
+
+ retVal = TRUE;
+
+ *result = mgetWord(bufferPtr);
+
+fsif_end:
+ CloseHandle (src);
+ free (buffer);
+
+ return retVal;
+}
+
+// Returns NULL if there's any error. Although the buffer can contain binary data, it is always null-terminated.
+char *LoadFile (const wchar_t *fileName, DWORD *size)
+{
+ char *buf;
+ DWORD fileSize = INVALID_FILE_SIZE;
+ HANDLE h = CreateFile (fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ *size = 0;
+ if (h == INVALID_HANDLE_VALUE)
+ return NULL;
+
+ if ((fileSize = GetFileSize (h, NULL)) == INVALID_FILE_SIZE)
+ {
+ CloseHandle (h);
+ return NULL;
+ }
+
+ buf = (char *) calloc (fileSize + 1, 1);
+
+ if (buf == NULL)
+ {
+ CloseHandle (h);
+ return NULL;
+ }
+
+ if (!ReadFile (h, buf, fileSize, size, NULL))
+ {
+ free (buf);
+ buf = NULL;
+ }
+ else
+ {
+ buf[*size] = 0; //make coverity happy eventhough buf is guaranteed to be null terminated because of fileSize+1 in calloc call
+ }
+
+ CloseHandle (h);
+ return buf;
+}
+
+
+// Returns NULL if there's any error.
+char *LoadFileBlock (const wchar_t *fileName, __int64 fileOffset, DWORD count)
+{
+ char *buf;
+ DWORD bytesRead = 0;
+ LARGE_INTEGER seekOffset, seekOffsetNew;
+ BOOL bStatus;
+
+ HANDLE h = CreateFile (fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ return NULL;
+
+ seekOffset.QuadPart = fileOffset;
+
+ if (SetFilePointerEx (h, seekOffset, &seekOffsetNew, FILE_BEGIN) == 0)
+ {
+ CloseHandle (h);
+ return NULL;
+ }
+
+ buf = (char *) calloc (count, 1);
+
+ if (buf == NULL)
+ {
+ CloseHandle (h);
+ return NULL;
+ }
+
+ bStatus = ReadFile (h, buf, count, &bytesRead, NULL);
+
+ CloseHandle (h);
+
+ if (!bStatus || (bytesRead != count))
+ {
+ free (buf);
+ return NULL;
+ }
+
+ return buf;
+}
+
+
+// Returns -1 if there is an error, or the size of the file.
+__int64 GetFileSize64 (const wchar_t *path)
+{
+ HANDLE h = CreateFile (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ LARGE_INTEGER size;
+ __int64 retSize = -1;
+
+ if (h)
+ {
+ if (GetFileSizeEx (h, &size))
+ {
+ retSize = size.QuadPart;
+ }
+
+ CloseHandle (h);
+ }
+
+ return retSize;
+}
+
+// If bAppend is TRUE, the buffer is appended to an existing file. If bAppend is FALSE, any existing file
+// is replaced. If an error occurs, the incomplete file is deleted (provided that bAppend is FALSE).
+BOOL SaveBufferToFile (const char *inputBuffer, const wchar_t *destinationFile, DWORD inputLength, BOOL bAppend, BOOL bRenameIfFailed)
+{
+ HANDLE dst;
+ DWORD bytesWritten;
+ BOOL res = TRUE;
+ DWORD dwLastError = 0;
+
+ dst = CreateFile (destinationFile,
+ GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, bAppend ? OPEN_EXISTING : CREATE_ALWAYS, 0, NULL);
+
+ dwLastError = GetLastError();
+ if (!bAppend && bRenameIfFailed && (dst == INVALID_HANDLE_VALUE) && (GetLastError () == ERROR_SHARING_VIOLATION))
+ {
+ wchar_t renamedPath[TC_MAX_PATH + 1];
+ StringCbCopyW (renamedPath, sizeof(renamedPath), destinationFile);
+ StringCbCatW (renamedPath, sizeof(renamedPath), VC_FILENAME_RENAMED_SUFFIX);
+
+ /* rename the locked file in order to be able to create a new one */
+ if (MoveFileEx (destinationFile, renamedPath, MOVEFILE_REPLACE_EXISTING))
+ {
+ dst = CreateFile (destinationFile,
+ GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
+ dwLastError = GetLastError();
+ if (dst == INVALID_HANDLE_VALUE)
+ {
+ /* restore the original file name */
+ MoveFileEx (renamedPath, destinationFile, MOVEFILE_REPLACE_EXISTING);
+ }
+ else
+ {
+ /* delete the renamed file when the machine reboots */
+ MoveFileEx (renamedPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
+ }
+ }
+ }
+
+ if (dst == INVALID_HANDLE_VALUE)
+ {
+ SetLastError (dwLastError);
+ handleWin32Error (MainDlg, SRC_POS);
+ return FALSE;
+ }
+
+ if (bAppend)
+ SetFilePointer (dst, 0, NULL, FILE_END);
+
+ if (!WriteFile (dst, inputBuffer, inputLength, &bytesWritten, NULL)
+ || inputLength != bytesWritten)
+ {
+ res = FALSE;
+ }
+
+ if (!res)
+ {
+ // If CREATE_ALWAYS is used, ERROR_ALREADY_EXISTS is returned after successful overwrite
+ // of an existing file (it's not an error)
+ if (! (GetLastError() == ERROR_ALREADY_EXISTS && !bAppend) )
+ handleWin32Error (MainDlg, SRC_POS);
+ }
+
+ CloseHandle (dst);
+
+ if (!res && !bAppend)
+ _wremove (destinationFile);
+
+ return res;
+}
+
+
+// Returns -1 if the specified string is not found in the buffer. Otherwise, returns the
+// offset of the first occurrence of the string. The string and the buffer may contain zeroes,
+// which do NOT terminate them.
+int64 FindString (const char *buf, const char *str, int64 bufLen, int64 strLen, int64 startOffset)
+{
+ if (buf == NULL
+ || str == NULL
+ || strLen > bufLen
+ || bufLen < 1
+ || strLen < 1
+ || startOffset > bufLen - strLen)
+ {
+ return -1;
+ }
+
+ for (int64 i = startOffset; i <= bufLen - strLen; i++)
+ {
+ if (memcmp (buf + i, str, (size_t) strLen) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+// Returns TRUE if the file or directory exists (both may be enclosed in quotation marks).
+BOOL FileExists (const wchar_t *filePathPtr)
+{
+ wchar_t filePath [TC_MAX_PATH * 2 + 1];
+
+ // Strip quotation marks (if any)
+ if (filePathPtr [0] == L'"')
+ {
+ StringCbCopyW (filePath, sizeof(filePath), filePathPtr + 1);
+ }
+ else
+ {
+ StringCbCopyW (filePath, sizeof(filePath), filePathPtr);
+ }
+
+ // Strip quotation marks (if any)
+ if (filePath [wcslen (filePath) - 1] == L'"')
+ filePath [wcslen (filePath) - 1] = 0;
+
+ return (_waccess (filePath, 0) != -1);
+}
+
+
+// Searches the file from its end for the LAST occurrence of the string str.
+// The string may contain zeroes, which do NOT terminate the string.
+// If the string is found, its offset from the start of the file is returned.
+// If the string isn't found or if any error occurs, -1 is returned.
+__int64 FindStringInFile (const wchar_t *filePath, const char* str, int strLen)
+{
+ int bufSize = 64 * BYTES_PER_KB;
+ char *buffer = (char *) err_malloc (bufSize);
+ HANDLE src = NULL;
+ DWORD bytesRead;
+ BOOL readRetVal;
+ __int64 filePos = GetFileSize64 (filePath);
+ int bufPos = 0;
+ LARGE_INTEGER seekOffset, seekOffsetNew;
+ BOOL bExit = FALSE;
+ int filePosStep;
+ __int64 retVal = -1;
+
+ if (filePos <= 0
+ || buffer == NULL
+ || strLen > bufSize
+ || strLen < 1)
+ {
+ if (buffer)
+ free (buffer);
+ return -1;
+ }
+
+ src = CreateFile (filePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (src == INVALID_HANDLE_VALUE)
+ {
+ free (buffer);
+ return -1;
+ }
+
+ filePosStep = bufSize - strLen + 1;
+
+ do
+ {
+ filePos -= filePosStep;
+
+ if (filePos < 0)
+ {
+ filePos = 0;
+ bExit = TRUE;
+ }
+
+ seekOffset.QuadPart = filePos;
+
+ if (SetFilePointerEx (src, seekOffset, &seekOffsetNew, FILE_BEGIN) == 0)
+ goto fsif_end;
+
+ if ((readRetVal = ReadFile (src, buffer, bufSize, &bytesRead, NULL)) == 0
+ || bytesRead == 0)
+ goto fsif_end;
+
+ bufPos = bytesRead - strLen;
+
+ while (bufPos > 0)
+ {
+ if (memcmp (buffer + bufPos, str, strLen) == 0)
+ {
+ // String found
+ retVal = filePos + bufPos;
+ goto fsif_end;
+ }
+ bufPos--;
+ }
+
+ } while (!bExit);
+
+fsif_end:
+ CloseHandle (src);
+ free (buffer);
+
+ return retVal;
+}
+
+// System CopyFile() copies source file attributes (like FILE_ATTRIBUTE_ENCRYPTED)
+// so we need to use our own copy function
+BOOL TCCopyFileBase (HANDLE src, HANDLE dst)
+{
+ __int8 *buffer;
+ FILETIME fileTime;
+ DWORD bytesRead, bytesWritten;
+ BOOL res;
+
+ buffer = (char *) malloc (64 * 1024);
+ if (!buffer)
+ {
+ CloseHandle (src);
+ CloseHandle (dst);
+ return FALSE;
+ }
+
+ while (res = ReadFile (src, buffer, 64 * 1024, &bytesRead, NULL))
+ {
+ if (bytesRead == 0)
+ {
+ res = 1;
+ break;
+ }
+
+ if (!WriteFile (dst, buffer, bytesRead, &bytesWritten, NULL)
+ || bytesRead != bytesWritten)
+ {
+ res = 0;
+ break;
+ }
+ }
+
+ if (GetFileTime (src, NULL, NULL, &fileTime))
+ SetFileTime (dst, NULL, NULL, &fileTime);
+
+ CloseHandle (src);
+ CloseHandle (dst);
+
+ free (buffer);
+ return res != 0;
+}
+
+BOOL TCCopyFile (wchar_t *sourceFileName, wchar_t *destinationFile)
+{
+ HANDLE src, dst;
+
+ src = CreateFileW (sourceFileName,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (src == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ dst = CreateFileW (destinationFile,
+ GENERIC_WRITE,
+ 0, NULL, CREATE_ALWAYS, 0, NULL);
+
+ if (dst == INVALID_HANDLE_VALUE)
+ {
+ CloseHandle (src);
+ return FALSE;
+ }
+
+ return TCCopyFileBase (src, dst);
+}
+
+#if defined(NDEBUG) && !defined(VC_SKIP_OS_DRIVER_REQ_CHECK)
+static BOOL InitializeWintrust()
+{
+ if (!hWinTrustLib)
+ {
+ wchar_t szPath[MAX_PATH] = {0};
+
+ if (GetSystemDirectory(szPath, MAX_PATH))
+ StringCchCatW (szPath, MAX_PATH, L"\\Wintrust.dll");
+ else
+ StringCchCopyW (szPath, MAX_PATH, L"C:\\Windows\\System32\\Wintrust.dll");
+
+ hWinTrustLib = LoadLibrary (szPath);
+ if (hWinTrustLib)
+ {
+ WinVerifyTrustFn = (WINVERIFYTRUST) GetProcAddress (hWinTrustLib, "WinVerifyTrust");
+ WTHelperProvDataFromStateDataFn = (WTHELPERPROVDATAFROMSTATEDATA) GetProcAddress (hWinTrustLib, "WTHelperProvDataFromStateData");
+ WTHelperGetProvSignerFromChainFn = (WTHELPERGETPROVSIGNERFROMCHAIN) GetProcAddress (hWinTrustLib, "WTHelperGetProvSignerFromChain");
+ WTHelperGetProvCertFromChainFn = (WTHELPERGETPROVCERTFROMCHAIN) GetProcAddress (hWinTrustLib, "WTHelperGetProvCertFromChain");
+
+ if ( !WinVerifyTrustFn
+ || !WTHelperProvDataFromStateDataFn
+ || !WTHelperGetProvSignerFromChainFn
+ || !WTHelperGetProvCertFromChainFn)
+ {
+ FreeLibrary (hWinTrustLib);
+ hWinTrustLib = NULL;
+ }
+
+ }
+ }
+
+ if (hWinTrustLib)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static void FinalizeWintrust()
+{
+ if (hWinTrustLib)
+ {
+ FreeLibrary (hWinTrustLib);
+ hWinTrustLib = NULL;
+ }
+}
+
+#endif
+
+BOOL VerifyModuleSignature (const wchar_t* path)
+{
+#if defined(NDEBUG) && !defined (VC_SKIP_OS_DRIVER_REQ_CHECK)
+ BOOL bResult = FALSE;
+ HRESULT hResult;
+ GUID gActionID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
+ WINTRUST_FILE_INFO fileInfo = {0};
+ WINTRUST_DATA WVTData = {0};
+ wchar_t filePath [TC_MAX_PATH + 1024];
+
+ // we check our own authenticode signature only starting from Windows 10 since this is
+ // the minimal supported OS apart from XP where we can't verify SHA256 signatures
+ if (!IsOSAtLeast (WIN_10))
+ return TRUE;
+
+ // Strip quotation marks (if any)
+ if (path [0] == L'"')
+ {
+ StringCbCopyW (filePath, sizeof(filePath), path + 1);
+ }
+ else
+ {
+ StringCbCopyW (filePath, sizeof(filePath), path);
+ }
+
+ // Strip quotation marks (if any)
+ if (filePath [wcslen (filePath) - 1] == L'"')
+ filePath [wcslen (filePath) - 1] = 0;
+
+ if (!InitializeWintrust ())
+ return FALSE;
+
+ fileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
+ fileInfo.pcwszFilePath = filePath;
+ fileInfo.hFile = NULL;
+
+ WVTData.cbStruct = sizeof(WINTRUST_DATA);
+ WVTData.dwUIChoice = WTD_UI_NONE;
+ WVTData.fdwRevocationChecks = WTD_REVOKE_NONE;
+ WVTData.dwUnionChoice = WTD_CHOICE_FILE;
+ WVTData.pFile = &fileInfo;
+ WVTData.dwStateAction = WTD_STATEACTION_VERIFY;
+ WVTData.dwProvFlags = WTD_REVOCATION_CHECK_NONE | WTD_CACHE_ONLY_URL_RETRIEVAL;
+
+ hResult = WinVerifyTrustFn(0, &gActionID, &WVTData);
+ if (0 == hResult)
+ {
+ PCRYPT_PROVIDER_DATA pProviderData = WTHelperProvDataFromStateDataFn (WVTData.hWVTStateData);
+ if (pProviderData)
+ {
+ PCRYPT_PROVIDER_SGNR pProviderSigner = WTHelperGetProvSignerFromChainFn (pProviderData, 0, FALSE, 0);
+ if (pProviderSigner)
+ {
+ PCRYPT_PROVIDER_CERT pProviderCert = WTHelperGetProvCertFromChainFn (pProviderSigner, 0);
+ if (pProviderCert && (pProviderCert->pCert))
+ {
+ BYTE hashVal[64];
+ sha512 (hashVal, pProviderCert->pCert->pbCertEncoded, pProviderCert->pCert->cbCertEncoded);
+
+ if ( (0 == memcmp (hashVal, gpbSha256CodeSignCertFingerprint, 64))
+ || (0 == memcmp (hashVal, gpbSha256MSCodeSignCertFingerprint, 64))
+ )
+ {
+ bResult = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ WVTData.dwUIChoice = WTD_UI_NONE;
+ WVTData.dwStateAction = WTD_STATEACTION_CLOSE;
+ WinVerifyTrustFn(0, &gActionID, &WVTData);
+
+ FinalizeWintrust ();
+
+ return bResult;
+#else
+ return TRUE;
+#endif
+}
+
+DWORD handleWin32Error (HWND hwndDlg, const char* srcPos)
+{
+#ifndef VC_COMREG
+ PWSTR lpMsgBuf;
+ DWORD dwError = GetLastError ();
+ wchar_t szErrorValue[32];
+ wchar_t* pszDesc;
+
+ if (Silent || dwError == 0 || dwError == ERROR_INVALID_WINDOW_HANDLE)
+ return dwError;
+
+ // Access denied
+ if (dwError == ERROR_ACCESS_DENIED && !IsAdmin ())
+ {
+ ErrorDirect ( AppendSrcPos (GetString ("ERR_ACCESS_DENIED"), srcPos).c_str (), hwndDlg);
+ SetLastError (dwError); // Preserve the original error code
+ return dwError;
+ }
+
+ FormatMessageW (
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ dwError,
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+ (PWSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+
+ if (lpMsgBuf)
+ pszDesc = (wchar_t*) lpMsgBuf;
+ else
+ {
+ StringCchPrintfW (szErrorValue, ARRAYSIZE (szErrorValue), L"Error 0x%.8X", dwError);
+ pszDesc = szErrorValue;
+ }
+
+ MessageBoxW (hwndDlg, AppendSrcPos (pszDesc, srcPos).c_str (), lpszTitle, ICON_HAND);
+ if (lpMsgBuf) LocalFree (lpMsgBuf);
+
+ // User-friendly hardware error explanation
+ if (IsDiskError (dwError))
+ Error ("ERR_HARDWARE_ERROR", hwndDlg);
+
+ // Device not ready
+ if (dwError == ERROR_NOT_READY)
+ HandleDriveNotReadyError(hwndDlg);
+
+ SetLastError (dwError); // Preserve the original error code
+
+ return dwError;
+#else
+ return GetLastError();
+#endif
+}
+
+int Error (char *stringId, HWND hwnd)
+{
+#ifndef VC_COMREG
+ if (Silent) return 0;
+ return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONERROR);
+#else
+ return 0;
+#endif
+}
+
+BOOL IsOSAtLeast (OSVersionEnum reqMinOS)
+{
+ return IsOSVersionAtLeast (reqMinOS, 0);
+}
+
+
+// Returns TRUE if the operating system is at least reqMinOS and service pack at least reqMinServicePack.
+// Example 1: IsOSVersionAtLeast (WIN_VISTA, 1) called under Windows 2008, returns TRUE.
+// Example 2: IsOSVersionAtLeast (WIN_XP, 3) called under Windows XP SP1, returns FALSE.
+// Example 3: IsOSVersionAtLeast (WIN_XP, 3) called under Windows Vista SP1, returns TRUE.
+BOOL IsOSVersionAtLeast (OSVersionEnum reqMinOS, int reqMinServicePack)
+{
+ /* When updating this function, update IsOSAtLeast() in Ntdriver.c too. */
+
+ if (CurrentOSMajor <= 0)
+ TC_THROW_FATAL_EXCEPTION;
+
+ int major = 0, minor = 0;
+
+ switch (reqMinOS)
+ {
+ case WIN_2000: major = 5; minor = 0; break;
+ case WIN_XP: major = 5; minor = 1; break;
+ case WIN_SERVER_2003: major = 5; minor = 2; break;
+ case WIN_VISTA: major = 6; minor = 0; break;
+ case WIN_7: major = 6; minor = 1; break;
+ case WIN_8: major = 6; minor = 2; break;
+ case WIN_8_1: major = 6; minor = 3; break;
+ case WIN_10: major = 10; minor = 0; break;
+
+ default:
+ TC_THROW_FATAL_EXCEPTION;
+ break;
+ }
+
+ return ((CurrentOSMajor << 16 | CurrentOSMinor << 8 | CurrentOSServicePack)
+ >= (major << 16 | minor << 8 | reqMinServicePack));
+}
+
+#ifdef SETUP_DLL
+static BOOL GetWindowVersionFromFile(DWORD* pdwMajor, DWORD* pdwMinor, DWORD* pdwBuildNumber)
+{
+ wchar_t dllPath[MAX_PATH];
+ BOOL bRet = FALSE;
+ LPBYTE versionInfo = NULL;
+ UINT size;
+ VS_FIXEDFILEINFO *vinfo;
+
+ /* Load dll explictely from System32 to avoid Dll hijacking attacks*/
+ if (!GetSystemDirectory(dllPath, MAX_PATH))
+ StringCbCopyW(dllPath, sizeof(dllPath), L"C:\\Windows\\System32");
+
+ StringCbCatW(dllPath, sizeof(dllPath), L"\\");
+ StringCbCatW(dllPath, sizeof(dllPath), L"Kernel32.dll");
+
+ size = GetFileVersionInfoSizeW(dllPath, NULL);
+ if (size)
+ {
+ versionInfo = (LPBYTE) TCalloc(size);
+ if (GetFileVersionInfo(dllPath, 0, size, versionInfo))
+ {
+
+ if (VerQueryValueW(versionInfo, L"\\", (LPVOID *)&vinfo, &size) && (size >=sizeof(VS_FIXEDFILEINFO)))
+ {
+ *pdwMajor = HIWORD(vinfo->dwProductVersionMS);
+ *pdwMinor = LOWORD(vinfo->dwProductVersionMS);
+ *pdwBuildNumber = HIWORD(vinfo->dwProductVersionLS);
+ bRet = TRUE;
+ }
+ }
+ }
+
+ if (versionInfo)
+ TCfree(versionInfo);
+ return bRet;
+}
+#endif
+
+/*
+ * Use RtlGetVersion to get Windows version because GetVersionEx is affected by application manifestation.
+ */
+typedef NTSTATUS (WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
+
+static BOOL GetWindowsVersion(LPOSVERSIONINFOW lpVersionInformation)
+{
+ BOOL bRet = FALSE;
+#ifdef SETUP_DLL
+ DWORD dwMajor, dwMinor, dwBuildNumber;
+#endif
+ RtlGetVersionPtr RtlGetVersionFn = (RtlGetVersionPtr) GetProcAddress(GetModuleHandle (L"ntdll.dll"), "RtlGetVersion");
+ if (RtlGetVersionFn != NULL)
+ {
+ if (ERROR_SUCCESS == RtlGetVersionFn (lpVersionInformation))
+ bRet = TRUE;
+ }
+
+ if (!bRet)
+ bRet = GetVersionExW (lpVersionInformation);
+
+#ifdef SETUP_DLL
+ // we get real version from Kernel32.dll version since MSI always sets current version to 6.0
+ // https://stackoverflow.com/questions/49335885/windows-10-not-detecting-on-installshield/49343826#49343826
+ if (GetWindowVersionFromFile(&dwMajor, &dwMinor, &dwBuildNumber))
+ {
+ lpVersionInformation->dwMajorVersion = dwMajor;
+ lpVersionInformation->dwMinorVersion = dwMinor;
+ lpVersionInformation->dwBuildNumber = dwBuildNumber;
+ }
+#endif
+
+ return bRet;
+}
+
+
+void InitOSVersionInfo ()
+{
+ OSVERSIONINFOEXW os;
+ os.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEXW);
+
+ if (GetWindowsVersion ((LPOSVERSIONINFOW) &os) == FALSE)
+ AbortProcess ("NO_OS_VER");
+
+ CurrentOSMajor = os.dwMajorVersion;
+ CurrentOSMinor = os.dwMinorVersion;
+ CurrentOSServicePack = os.wServicePackMajor;
+ CurrentOSBuildNumber = os.dwBuildNumber;
+
+ if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 5 && CurrentOSMinor == 0)
+ nCurrentOS = WIN_2000;
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 5 && CurrentOSMinor == 1)
+ nCurrentOS = WIN_XP;
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 5 && CurrentOSMinor == 2)
+ {
+ if (os.wProductType == VER_NT_SERVER || os.wProductType == VER_NT_DOMAIN_CONTROLLER)
+ nCurrentOS = WIN_SERVER_2003;
+ else
+ nCurrentOS = WIN_XP64;
+ }
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 6 && CurrentOSMinor == 0)
+ {
+ if (os.wProductType != VER_NT_WORKSTATION)
+ nCurrentOS = WIN_SERVER_2008;
+ else
+ nCurrentOS = WIN_VISTA;
+ }
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 6 && CurrentOSMinor == 1)
+ nCurrentOS = ((os.wProductType != VER_NT_WORKSTATION) ? WIN_SERVER_2008_R2 : WIN_7);
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 6 && CurrentOSMinor == 2)
+ nCurrentOS = ((os.wProductType != VER_NT_WORKSTATION) ? WIN_SERVER_2012 : WIN_8);
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 6 && CurrentOSMinor == 3)
+ nCurrentOS = ((os.wProductType != VER_NT_WORKSTATION) ? WIN_SERVER_2012_R2 : WIN_8_1);
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 10 && CurrentOSMinor == 0)
+ nCurrentOS = ((os.wProductType != VER_NT_WORKSTATION) ? WIN_SERVER_2016 : WIN_10);
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 4)
+ nCurrentOS = WIN_NT4;
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && os.dwMajorVersion == 4 && os.dwMinorVersion == 0)
+ nCurrentOS = WIN_95;
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && os.dwMajorVersion == 4 && os.dwMinorVersion == 10)
+ nCurrentOS = WIN_98;
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && os.dwMajorVersion == 4 && os.dwMinorVersion == 90)
+ nCurrentOS = WIN_ME;
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32s)
+ nCurrentOS = WIN_31;
+ else
+ nCurrentOS = WIN_UNKNOWN;
+}
+
+#pragma warning(push)
+#pragma warning(disable:4702)
+
+void *err_malloc (size_t size)
+{
+ void *z = (void *) TCalloc (size);
+ if (z)
+ return z;
+ AbortProcess ("OUTOFMEMORY");
+ return 0;
+}
+
+#pragma warning(pop)
+
+
+char *err_strdup (char *lpszText)
+{
+ size_t j = (strlen (lpszText) + 1) * sizeof (char);
+ char *z = (char *) err_malloc (j);
+ memmove (z, lpszText, j);
+ return z;
+}
+
+void AbortProcessDirect (wchar_t *abortMsg)
+{
+ // Note that this function also causes localcleanup() to be called (see atexit())
+ MessageBeep (MB_ICONEXCLAMATION);
+ MessageBoxW (NULL, abortMsg, lpszTitle, ICON_HAND);
+#ifndef VC_COMREG
+ FREE_DLL (hRichEditDll);
+ FREE_DLL (hComctl32Dll);
+ FREE_DLL (hSetupDll);
+ FREE_DLL (hShlwapiDll);
+ FREE_DLL (hProfApiDll);
+ FREE_DLL (hUsp10Dll);
+ FREE_DLL (hCryptSpDll);
+ FREE_DLL (hUXThemeDll);
+ FREE_DLL (hUserenvDll);
+ FREE_DLL (hRsaenhDll);
+ FREE_DLL (himm32dll);
+ FREE_DLL (hMSCTFdll);
+ FREE_DLL (hfltlibdll);
+ FREE_DLL (hframedyndll);
+ FREE_DLL (hpsapidll);
+ FREE_DLL (hsecur32dll);
+ FREE_DLL (hnetapi32dll);
+ FREE_DLL (hauthzdll);
+ FREE_DLL (hxmllitedll);
+ FREE_DLL (hmprdll);
+ FREE_DLL (hsppdll);
+ FREE_DLL (vssapidll);
+ FREE_DLL (hvsstracedll);
+ FREE_DLL (hCryptSpDll);
+ FREE_DLL (hcfgmgr32dll);
+ FREE_DLL (hdevobjdll);
+ FREE_DLL (hpowrprofdll);
+ FREE_DLL (hsspiclidll);
+ FREE_DLL (hcryptbasedll);
+ FREE_DLL (hdwmapidll);
+ FREE_DLL (hmsasn1dll);
+ FREE_DLL (hcrypt32dll);
+ FREE_DLL (hbcryptdll);
+ FREE_DLL (hbcryptprimitivesdll);
+ FREE_DLL (hMsls31);
+ FREE_DLL (hntmartadll);
+ FREE_DLL (hwinscarddll);
+ FREE_DLL (hmsvcrtdll);
+ FREE_DLL (hAdvapi32Dll);
+#endif
+ exit (1);
+}
+
+void AbortProcess (char *stringId)
+{
+ // Note that this function also causes localcleanup() to be called (see atexit())
+#ifndef VC_COMREG
+ AbortProcessDirect (GetString (stringId));
+#else
+ static wchar_t g_wszUnknown[1024];
+ StringCbPrintfW (g_wszUnknown, sizeof(g_wszUnknown), UNKNOWN_STRING_ID L"%hs" UNKNOWN_STRING_ID, stringId);
+ AbortProcessDirect (g_wszUnknown);
+#endif
+}
+
+#ifndef VC_COMREG
+void AbortProcessSilent (void)
+{
+ FREE_DLL (hRichEditDll);
+ FREE_DLL (hComctl32Dll);
+ FREE_DLL (hSetupDll);
+ FREE_DLL (hShlwapiDll);
+ FREE_DLL (hProfApiDll);
+ FREE_DLL (hUsp10Dll);
+ FREE_DLL (hCryptSpDll);
+ FREE_DLL (hUXThemeDll);
+ FREE_DLL (hUserenvDll);
+ FREE_DLL (hRsaenhDll);
+ FREE_DLL (himm32dll);
+ FREE_DLL (hMSCTFdll);
+ FREE_DLL (hfltlibdll);
+ FREE_DLL (hframedyndll);
+ FREE_DLL (hpsapidll);
+ FREE_DLL (hsecur32dll);
+ FREE_DLL (hnetapi32dll);
+ FREE_DLL (hauthzdll);
+ FREE_DLL (hxmllitedll);
+ FREE_DLL (hmprdll);
+ FREE_DLL (hsppdll);
+ FREE_DLL (vssapidll);
+ FREE_DLL (hvsstracedll);
+ FREE_DLL (hCryptSpDll);
+ FREE_DLL (hcfgmgr32dll);
+ FREE_DLL (hdevobjdll);
+ FREE_DLL (hpowrprofdll);
+ FREE_DLL (hsspiclidll);
+ FREE_DLL (hcryptbasedll);
+ FREE_DLL (hdwmapidll);
+ FREE_DLL (hmsasn1dll);
+ FREE_DLL (hcrypt32dll);
+ FREE_DLL (hbcryptdll);
+ FREE_DLL (hbcryptprimitivesdll);
+ FREE_DLL (hMsls31);
+ FREE_DLL (hntmartadll);
+ FREE_DLL (hwinscarddll);
+ FREE_DLL (hmsvcrtdll);
+ FREE_DLL (hAdvapi32Dll);
+
+ // Note that this function also causes localcleanup() to be called (see atexit())
+ exit (1);
+}
+
void InitGlobalLocks ()
{
InitializeCriticalSection (&csWNetCalls);
@@ -753,131 +1733,6 @@ int RemoveFakeDosName (wchar_t *lpszDiskFile, wchar_t *lpszDosDevice)
}
-void AbortProcessDirect (wchar_t *abortMsg)
-{
- // Note that this function also causes localcleanup() to be called (see atexit())
- MessageBeep (MB_ICONEXCLAMATION);
- MessageBoxW (NULL, abortMsg, lpszTitle, ICON_HAND);
- FREE_DLL (hRichEditDll);
- FREE_DLL (hComctl32Dll);
- FREE_DLL (hSetupDll);
- FREE_DLL (hShlwapiDll);
- FREE_DLL (hProfApiDll);
- FREE_DLL (hUsp10Dll);
- FREE_DLL (hCryptSpDll);
- FREE_DLL (hUXThemeDll);
- FREE_DLL (hUserenvDll);
- FREE_DLL (hRsaenhDll);
- FREE_DLL (himm32dll);
- FREE_DLL (hMSCTFdll);
- FREE_DLL (hfltlibdll);
- FREE_DLL (hframedyndll);
- FREE_DLL (hpsapidll);
- FREE_DLL (hsecur32dll);
- FREE_DLL (hnetapi32dll);
- FREE_DLL (hauthzdll);
- FREE_DLL (hxmllitedll);
- FREE_DLL (hmprdll);
- FREE_DLL (hsppdll);
- FREE_DLL (vssapidll);
- FREE_DLL (hvsstracedll);
- FREE_DLL (hCryptSpDll);
- FREE_DLL (hcfgmgr32dll);
- FREE_DLL (hdevobjdll);
- FREE_DLL (hpowrprofdll);
- FREE_DLL (hsspiclidll);
- FREE_DLL (hcryptbasedll);
- FREE_DLL (hdwmapidll);
- FREE_DLL (hmsasn1dll);
- FREE_DLL (hcrypt32dll);
- FREE_DLL (hbcryptdll);
- FREE_DLL (hbcryptprimitivesdll);
- FREE_DLL (hMsls31);
- FREE_DLL (hntmartadll);
- FREE_DLL (hwinscarddll);
- FREE_DLL (hmsvcrtdll);
- FREE_DLL (hAdvapi32Dll);
-
- exit (1);
-}
-
-void AbortProcess (char *stringId)
-{
- // Note that this function also causes localcleanup() to be called (see atexit())
- AbortProcessDirect (GetString (stringId));
-}
-
-void AbortProcessSilent (void)
-{
- FREE_DLL (hRichEditDll);
- FREE_DLL (hComctl32Dll);
- FREE_DLL (hSetupDll);
- FREE_DLL (hShlwapiDll);
- FREE_DLL (hProfApiDll);
- FREE_DLL (hUsp10Dll);
- FREE_DLL (hCryptSpDll);
- FREE_DLL (hUXThemeDll);
- FREE_DLL (hUserenvDll);
- FREE_DLL (hRsaenhDll);
- FREE_DLL (himm32dll);
- FREE_DLL (hMSCTFdll);
- FREE_DLL (hfltlibdll);
- FREE_DLL (hframedyndll);
- FREE_DLL (hpsapidll);
- FREE_DLL (hsecur32dll);
- FREE_DLL (hnetapi32dll);
- FREE_DLL (hauthzdll);
- FREE_DLL (hxmllitedll);
- FREE_DLL (hmprdll);
- FREE_DLL (hsppdll);
- FREE_DLL (vssapidll);
- FREE_DLL (hvsstracedll);
- FREE_DLL (hCryptSpDll);
- FREE_DLL (hcfgmgr32dll);
- FREE_DLL (hdevobjdll);
- FREE_DLL (hpowrprofdll);
- FREE_DLL (hsspiclidll);
- FREE_DLL (hcryptbasedll);
- FREE_DLL (hdwmapidll);
- FREE_DLL (hmsasn1dll);
- FREE_DLL (hcrypt32dll);
- FREE_DLL (hbcryptdll);
- FREE_DLL (hbcryptprimitivesdll);
- FREE_DLL (hMsls31);
- FREE_DLL (hntmartadll);
- FREE_DLL (hwinscarddll);
- FREE_DLL (hmsvcrtdll);
- FREE_DLL (hAdvapi32Dll);
-
- // Note that this function also causes localcleanup() to be called (see atexit())
- exit (1);
-}
-
-
-#pragma warning(push)
-#pragma warning(disable:4702)
-
-void *err_malloc (size_t size)
-{
- void *z = (void *) TCalloc (size);
- if (z)
- return z;
- AbortProcess ("OUTOFMEMORY");
- return 0;
-}
-
-#pragma warning(pop)
-
-
-char *err_strdup (char *lpszText)
-{
- size_t j = (strlen (lpszText) + 1) * sizeof (char);
- char *z = (char *) err_malloc (j);
- memmove (z, lpszText, j);
- return z;
-}
-
-
BOOL IsDiskReadError (DWORD error)
{
return (error == ERROR_CRC
@@ -906,59 +1761,6 @@ BOOL IsDiskError (DWORD error)
return IsDiskReadError (error) || IsDiskWriteError (error);
}
-
-DWORD handleWin32Error (HWND hwndDlg, const char* srcPos)
-{
- PWSTR lpMsgBuf;
- DWORD dwError = GetLastError ();
- wchar_t szErrorValue[32];
- wchar_t* pszDesc;
-
- if (Silent || dwError == 0 || dwError == ERROR_INVALID_WINDOW_HANDLE)
- return dwError;
-
- // Access denied
- if (dwError == ERROR_ACCESS_DENIED && !IsAdmin ())
- {
- ErrorDirect ( AppendSrcPos (GetString ("ERR_ACCESS_DENIED"), srcPos).c_str (), hwndDlg);
- SetLastError (dwError); // Preserve the original error code
- return dwError;
- }
-
- FormatMessageW (
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- dwError,
- MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
- (PWSTR) &lpMsgBuf,
- 0,
- NULL
- );
-
- if (lpMsgBuf)
- pszDesc = (wchar_t*) lpMsgBuf;
- else
- {
- StringCchPrintfW (szErrorValue, ARRAYSIZE (szErrorValue), L"Error 0x%.8X", dwError);
- pszDesc = szErrorValue;
- }
-
- MessageBoxW (hwndDlg, AppendSrcPos (pszDesc, srcPos).c_str (), lpszTitle, ICON_HAND);
- if (lpMsgBuf) LocalFree (lpMsgBuf);
-
- // User-friendly hardware error explanation
- if (IsDiskError (dwError))
- Error ("ERR_HARDWARE_ERROR", hwndDlg);
-
- // Device not ready
- if (dwError == ERROR_NOT_READY)
- HandleDriveNotReadyError(hwndDlg);
-
- SetLastError (dwError); // Preserve the original error code
-
- return dwError;
-}
-
BOOL translateWin32Error (wchar_t *lpszMsgBuf, int nWSizeOfBuf)
{
DWORD dwError = GetLastError ();
@@ -1530,7 +2332,7 @@ BOOL CALLBACK AboutDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam
L"Based on TrueCrypt 7.1a, freely available at http://www.truecrypt.org/ .\r\n\r\n"
L"Portions of this software:\r\n"
- L"Copyright \xA9 2013-2021 IDRIX. All rights reserved.\r\n"
+ L"Copyright \xA9 2013-2022 IDRIX. All rights reserved.\r\n"
L"Copyright \xA9 2003-2012 TrueCrypt Developers Association. All Rights Reserved.\r\n"
L"Copyright \xA9 1998-2000 Paul Le Roux. All Rights Reserved.\r\n"
L"Copyright \xA9 1998-2008 Brian Gladman. All Rights Reserved.\r\n"
@@ -1539,10 +2341,11 @@ BOOL CALLBACK AboutDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam
L"Copyright \xA9 1999-2017 Dieter Baron and Thomas Klausner.\r\n"
L"Copyright \xA9 2013, Alexey Degtyarev. All rights reserved.\r\n"
L"Copyright \xA9 1999-2016 Jack Lloyd. All rights reserved.\r\n"
- L"Copyright \xA9 2013-2019 Stephan Mueller <smueller@chronox.de>\r\n\r\n"
+ L"Copyright \xA9 2013-2019 Stephan Mueller <smueller@chronox.de>\r\n"
+ L"Copyright \xA9 1999-2021 Igor Pavlov\r\n\r\n"
L"This software as a whole:\r\n"
- L"Copyright \xA9 2013-2021 IDRIX. All rights reserved.\r\n\r\n"
+ L"Copyright \xA9 2013-2022 IDRIX. All rights reserved.\r\n\r\n"
L"An IDRIX Release");
@@ -2875,134 +3678,6 @@ void DoPostInstallTasks (HWND hwndDlg)
SavePostInstallTasksSettings (TC_POST_INSTALL_CFG_REMOVE_ALL);
}
-#ifdef SETUP_DLL
-static BOOL GetWindowVersionFromFile(DWORD* pdwMajor, DWORD* pdwMinor, DWORD* pdwBuildNumber)
-{
- wchar_t dllPath[MAX_PATH];
- BOOL bRet = FALSE;
- LPBYTE versionInfo = NULL;
- UINT size;
- VS_FIXEDFILEINFO *vinfo;
-
- /* Load dll explictely from System32 to avoid Dll hijacking attacks*/
- if (!GetSystemDirectory(dllPath, MAX_PATH))
- StringCbCopyW(dllPath, sizeof(dllPath), L"C:\\Windows\\System32");
-
- StringCbCatW(dllPath, sizeof(dllPath), L"\\");
- StringCbCatW(dllPath, sizeof(dllPath), L"Kernel32.dll");
-
- size = GetFileVersionInfoSizeW(dllPath, NULL);
- if (size)
- {
- versionInfo = (LPBYTE) TCalloc(size);
- if (GetFileVersionInfo(dllPath, 0, size, versionInfo))
- {
-
- if (VerQueryValueW(versionInfo, L"\\", (LPVOID *)&vinfo, &size) && (size >=sizeof(VS_FIXEDFILEINFO)))
- {
- *pdwMajor = HIWORD(vinfo->dwProductVersionMS);
- *pdwMinor = LOWORD(vinfo->dwProductVersionMS);
- *pdwBuildNumber = HIWORD(vinfo->dwProductVersionLS);
- bRet = TRUE;
- }
- }
- }
-
- if (versionInfo)
- TCfree(versionInfo);
- return bRet;
-}
-#endif
-
-/*
- * Use RtlGetVersion to get Windows version because GetVersionEx is affected by application manifestation.
- */
-typedef NTSTATUS (WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
-
-static BOOL GetWindowsVersion(LPOSVERSIONINFOW lpVersionInformation)
-{
- BOOL bRet = FALSE;
-#ifdef SETUP_DLL
- DWORD dwMajor, dwMinor, dwBuildNumber;
-#endif
- RtlGetVersionPtr RtlGetVersionFn = (RtlGetVersionPtr) GetProcAddress(GetModuleHandle (L"ntdll.dll"), "RtlGetVersion");
- if (RtlGetVersionFn != NULL)
- {
- if (ERROR_SUCCESS == RtlGetVersionFn (lpVersionInformation))
- bRet = TRUE;
- }
-
- if (!bRet)
- bRet = GetVersionExW (lpVersionInformation);
-
-#ifdef SETUP_DLL
- // we get real version from Kernel32.dll version since MSI always sets current version to 6.0
- // https://stackoverflow.com/questions/49335885/windows-10-not-detecting-on-installshield/49343826#49343826
- if (GetWindowVersionFromFile(&dwMajor, &dwMinor, &dwBuildNumber))
- {
- lpVersionInformation->dwMajorVersion = dwMajor;
- lpVersionInformation->dwMinorVersion = dwMinor;
- lpVersionInformation->dwBuildNumber = dwBuildNumber;
- }
-#endif
-
- return bRet;
-}
-
-
-void InitOSVersionInfo ()
-{
- OSVERSIONINFOEXW os;
- os.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEXW);
-
- if (GetWindowsVersion ((LPOSVERSIONINFOW) &os) == FALSE)
- AbortProcess ("NO_OS_VER");
-
- CurrentOSMajor = os.dwMajorVersion;
- CurrentOSMinor = os.dwMinorVersion;
- CurrentOSServicePack = os.wServicePackMajor;
- CurrentOSBuildNumber = os.dwBuildNumber;
-
- if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 5 && CurrentOSMinor == 0)
- nCurrentOS = WIN_2000;
- else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 5 && CurrentOSMinor == 1)
- nCurrentOS = WIN_XP;
- else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 5 && CurrentOSMinor == 2)
- {
- if (os.wProductType == VER_NT_SERVER || os.wProductType == VER_NT_DOMAIN_CONTROLLER)
- nCurrentOS = WIN_SERVER_2003;
- else
- nCurrentOS = WIN_XP64;
- }
- else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 6 && CurrentOSMinor == 0)
- {
- if (os.wProductType != VER_NT_WORKSTATION)
- nCurrentOS = WIN_SERVER_2008;
- else
- nCurrentOS = WIN_VISTA;
- }
- else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 6 && CurrentOSMinor == 1)
- nCurrentOS = ((os.wProductType != VER_NT_WORKSTATION) ? WIN_SERVER_2008_R2 : WIN_7);
- else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 6 && CurrentOSMinor == 2)
- nCurrentOS = ((os.wProductType != VER_NT_WORKSTATION) ? WIN_SERVER_2012 : WIN_8);
- else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 6 && CurrentOSMinor == 3)
- nCurrentOS = ((os.wProductType != VER_NT_WORKSTATION) ? WIN_SERVER_2012_R2 : WIN_8_1);
- else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 10 && CurrentOSMinor == 0)
- nCurrentOS = ((os.wProductType != VER_NT_WORKSTATION) ? WIN_SERVER_2016 : WIN_10);
- else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 4)
- nCurrentOS = WIN_NT4;
- else if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && os.dwMajorVersion == 4 && os.dwMinorVersion == 0)
- nCurrentOS = WIN_95;
- else if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && os.dwMajorVersion == 4 && os.dwMinorVersion == 10)
- nCurrentOS = WIN_98;
- else if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && os.dwMajorVersion == 4 && os.dwMinorVersion == 90)
- nCurrentOS = WIN_ME;
- else if (os.dwPlatformId == VER_PLATFORM_WIN32s)
- nCurrentOS = WIN_31;
- else
- nCurrentOS = WIN_UNKNOWN;
-}
-
static void LoadSystemDll (LPCTSTR szModuleName, HMODULE *pHandle, BOOL bIgnoreError, const char* srcPos)
{
wchar_t dllPath[MAX_PATH];
@@ -3157,7 +3832,10 @@ void InitApp (HINSTANCE hInstance, wchar_t *lpszCommandLine)
SHDeleteKeyWFn = (SHDeleteKeyWPtr) GetProcAddress (hShlwapiDll, "SHDeleteKeyW");
SHStrDupWFn = (SHStrDupWPtr) GetProcAddress (hShlwapiDll, "SHStrDupW");
UrlUnescapeWFn = (UrlUnescapeWPtr) GetProcAddress(hShlwapiDll, "UrlUnescapeW");
- if (!SHDeleteKeyWFn || !SHStrDupWFn || !UrlUnescapeWFn)
+ IUnknown_QueryServicePtr = (IUnknown_QueryServiceFn) GetProcAddress(hShlwapiDll, "IUnknown_QueryService");
+ if (!IUnknown_QueryServicePtr)
+ IUnknown_QueryServicePtr = (IUnknown_QueryServiceFn) GetProcAddress(hShlwapiDll, MAKEINTRESOURCEA(176));
+ if (!SHDeleteKeyWFn || !SHStrDupWFn || !UrlUnescapeWFn || !IUnknown_QueryServicePtr)
AbortProcess ("INIT_DLL");
if (IsOSAtLeast (WIN_VISTA))
@@ -3259,12 +3937,35 @@ void InitApp (HINSTANCE hInstance, wchar_t *lpszCommandLine)
RemoteSession = GetSystemMetrics (SM_REMOTESESSION) != 0;
- // OS version check: from version 1.25, only Windows XP, Windows 10 and Windows 11 are supported because of new driver signing requirements
- if (!(IsOSVersionAtLeast(WIN_10, 0) || (nCurrentOS == WIN_XP) || (nCurrentOS == WIN_XP64)))
+#ifndef VC_SKIP_OS_DRIVER_REQ_CHECK
+ if (!IsSupportedOS())
{
MessageBoxW (NULL, GetString ("UNSUPPORTED_OS"), lpszTitle, MB_ICONSTOP);
exit (1);
}
+#else
+ // in TESTSIGNING mode, we support only Windows Vista, Windows 7, Windows 8/8.1
+ if ( !IsOSVersionAtLeast(WIN_VISTA, 0)
+#ifndef SETUP
+ || IsOSVersionAtLeast(WIN_10, 0)
+#else
+ || (IsOSVersionAtLeast(WIN_10, 0) && !bMakePackage)
+#endif
+ )
+ {
+ MessageBoxW (NULL, L"TESTSIGNING version of VeraCrypt targets only Windows Vista, Windows 7 and Windows 8/8.1.\n\nPlease use the standard version of VeraCrypt instead.", lpszTitle, MB_ICONSTOP);
+ exit (1);
+ }
+ else if ( !IsTestSigningModeEnabled()
+#ifdef SETUP
+ && !bMakePackage
+#endif
+ )
+ {
+ MessageBoxW (NULL, L"Test-Signing Mode, which is required to run VeraCrypt TESTSIGNING binaries, is not enabled in Windows.\n\nExecution aborted!", lpszTitle, MB_ICONSTOP);
+ exit (1);
+ }
+#endif
else
{
// Service pack check & warnings about critical MS issues
@@ -4719,10 +5420,16 @@ load:
if (IsNonInstallMode () && CreateDriverSetupMutex () && DriverUnload () && nLoadRetryCount++ < 3)
goto load;
- CloseDriverSetupMutex ();
- CloseHandle (hDriver);
- hDriver = INVALID_HANDLE_VALUE;
- return ERR_DRIVER_VERSION;
+#ifdef TCMOUNT
+ // don't fail in case of service. This solves issues during upgrade when system encryption is enabled
+ if (!ServiceMode)
+#endif
+ {
+ CloseDriverSetupMutex ();
+ CloseHandle (hDriver);
+ hDriver = INVALID_HANDLE_VALUE;
+ return ERR_DRIVER_VERSION;
+ }
}
#else
if (!bResult)
@@ -5709,7 +6416,7 @@ static BOOL PerformBenchmark(HWND hBenchDlg, HWND hwndDlg)
{
BYTE digest [MAX_DIGESTSIZE];
WHIRLPOOL_CTX wctx;
- RMD160_CTX rctx;
+ blake2s_state bctx;
sha512_ctx s2ctx;
sha256_ctx s256ctx;
STREEBOG_CTX stctx;
@@ -5738,10 +6445,10 @@ static BOOL PerformBenchmark(HWND hBenchDlg, HWND hwndDlg)
sha256_end ((unsigned char *) digest, &s256ctx);
break;
- case RIPEMD160:
- RMD160Init(&rctx);
- RMD160Update(&rctx, lpTestBuffer, benchmarkBufferSize);
- RMD160Final((unsigned char *) digest, &rctx);
+ case BLAKE2S:
+ blake2s_init(&bctx);
+ blake2s_update(&bctx, lpTestBuffer, benchmarkBufferSize);
+ blake2s_final(&bctx, (unsigned char *) digest);
break;
case WHIRLPOOL:
@@ -5806,9 +6513,9 @@ static BOOL PerformBenchmark(HWND hBenchDlg, HWND hwndDlg)
derive_key_sha256 ("passphrase-1234567890", 21, tmp_salt, 64, get_pkcs5_iteration_count(thid, benchmarkPim, FALSE, benchmarkPreBoot), dk, MASTER_KEYDATA_SIZE);
break;
- case RIPEMD160:
- /* PKCS-5 test with HMAC-RIPEMD-160 used as the PRF */
- derive_key_ripemd160 ("passphrase-1234567890", 21, tmp_salt, 64, get_pkcs5_iteration_count(thid, benchmarkPim, FALSE, benchmarkPreBoot), dk, MASTER_KEYDATA_SIZE);
+ case BLAKE2S:
+ /* PKCS-5 test with HMAC-BLAKE2s used as the PRF */
+ derive_key_blake2s ("passphrase-1234567890", 21, tmp_salt, 64, get_pkcs5_iteration_count(thid, benchmarkPim, FALSE, benchmarkPreBoot), dk, MASTER_KEYDATA_SIZE);
break;
case WHIRLPOOL:
@@ -7192,9 +7899,6 @@ ResetCipherTest(HWND hwndDlg, int idTestCipher)
SetWindowText(GetDlgItem(hwndDlg, IDC_CIPHERTEXT), L"0000000000000000");
if (idTestCipher == AES || idTestCipher == SERPENT || idTestCipher == TWOFISH || idTestCipher == CAMELLIA
-#if defined(CIPHER_GOST89)
- || idTestCipher == GOST89
-#endif
|| idTestCipher == KUZNYECHIK
)
{
@@ -9145,198 +9849,6 @@ HANDLE DismountDrive (wchar_t *devName, wchar_t *devicePath)
return (bResult ? hVolume : INVALID_HANDLE_VALUE);
}
-// Returns -1 if the specified string is not found in the buffer. Otherwise, returns the
-// offset of the first occurrence of the string. The string and the buffer may contain zeroes,
-// which do NOT terminate them.
-int64 FindString (const char *buf, const char *str, int64 bufLen, int64 strLen, int64 startOffset)
-{
- if (buf == NULL
- || str == NULL
- || strLen > bufLen
- || bufLen < 1
- || strLen < 1
- || startOffset > bufLen - strLen)
- {
- return -1;
- }
-
- for (int64 i = startOffset; i <= bufLen - strLen; i++)
- {
- if (memcmp (buf + i, str, (size_t) strLen) == 0)
- return i;
- }
-
- return -1;
-}
-
-// Returns TRUE if the file or directory exists (both may be enclosed in quotation marks).
-BOOL FileExists (const wchar_t *filePathPtr)
-{
- wchar_t filePath [TC_MAX_PATH * 2 + 1];
-
- // Strip quotation marks (if any)
- if (filePathPtr [0] == L'"')
- {
- StringCbCopyW (filePath, sizeof(filePath), filePathPtr + 1);
- }
- else
- {
- StringCbCopyW (filePath, sizeof(filePath), filePathPtr);
- }
-
- // Strip quotation marks (if any)
- if (filePath [wcslen (filePath) - 1] == L'"')
- filePath [wcslen (filePath) - 1] = 0;
-
- return (_waccess (filePath, 0) != -1);
-}
-
-// Searches the file from its end for the LAST occurrence of the string str.
-// The string may contain zeroes, which do NOT terminate the string.
-// If the string is found, its offset from the start of the file is returned.
-// If the string isn't found or if any error occurs, -1 is returned.
-__int64 FindStringInFile (const wchar_t *filePath, const char* str, int strLen)
-{
- int bufSize = 64 * BYTES_PER_KB;
- char *buffer = (char *) err_malloc (bufSize);
- HANDLE src = NULL;
- DWORD bytesRead;
- BOOL readRetVal;
- __int64 filePos = GetFileSize64 (filePath);
- int bufPos = 0;
- LARGE_INTEGER seekOffset, seekOffsetNew;
- BOOL bExit = FALSE;
- int filePosStep;
- __int64 retVal = -1;
-
- if (filePos <= 0
- || buffer == NULL
- || strLen > bufSize
- || strLen < 1)
- {
- if (buffer)
- free (buffer);
- return -1;
- }
-
- src = CreateFile (filePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
-
- if (src == INVALID_HANDLE_VALUE)
- {
- free (buffer);
- return -1;
- }
-
- filePosStep = bufSize - strLen + 1;
-
- do
- {
- filePos -= filePosStep;
-
- if (filePos < 0)
- {
- filePos = 0;
- bExit = TRUE;
- }
-
- seekOffset.QuadPart = filePos;
-
- if (SetFilePointerEx (src, seekOffset, &seekOffsetNew, FILE_BEGIN) == 0)
- goto fsif_end;
-
- if ((readRetVal = ReadFile (src, buffer, bufSize, &bytesRead, NULL)) == 0
- || bytesRead == 0)
- goto fsif_end;
-
- bufPos = bytesRead - strLen;
-
- while (bufPos > 0)
- {
- if (memcmp (buffer + bufPos, str, strLen) == 0)
- {
- // String found
- retVal = filePos + bufPos;
- goto fsif_end;
- }
- bufPos--;
- }
-
- } while (!bExit);
-
-fsif_end:
- CloseHandle (src);
- free (buffer);
-
- return retVal;
-}
-
-// System CopyFile() copies source file attributes (like FILE_ATTRIBUTE_ENCRYPTED)
-// so we need to use our own copy function
-BOOL TCCopyFileBase (HANDLE src, HANDLE dst)
-{
- __int8 *buffer;
- FILETIME fileTime;
- DWORD bytesRead, bytesWritten;
- BOOL res;
-
- buffer = (char *) malloc (64 * 1024);
- if (!buffer)
- {
- CloseHandle (src);
- CloseHandle (dst);
- return FALSE;
- }
-
- while (res = ReadFile (src, buffer, 64 * 1024, &bytesRead, NULL))
- {
- if (bytesRead == 0)
- {
- res = 1;
- break;
- }
-
- if (!WriteFile (dst, buffer, bytesRead, &bytesWritten, NULL)
- || bytesRead != bytesWritten)
- {
- res = 0;
- break;
- }
- }
-
- if (GetFileTime (src, NULL, NULL, &fileTime))
- SetFileTime (dst, NULL, NULL, &fileTime);
-
- CloseHandle (src);
- CloseHandle (dst);
-
- free (buffer);
- return res != 0;
-}
-
-BOOL TCCopyFile (wchar_t *sourceFileName, wchar_t *destinationFile)
-{
- HANDLE src, dst;
-
- src = CreateFileW (sourceFileName,
- GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
-
- if (src == INVALID_HANDLE_VALUE)
- return FALSE;
-
- dst = CreateFileW (destinationFile,
- GENERIC_WRITE,
- 0, NULL, CREATE_ALWAYS, 0, NULL);
-
- if (dst == INVALID_HANDLE_VALUE)
- {
- CloseHandle (src);
- return FALSE;
- }
-
- return TCCopyFileBase (src, dst);
-}
-
BOOL DecompressZipToDir (const unsigned char *inputBuffer, DWORD inputLength, const wchar_t *destinationDir, ProgressFn progressFnPtr, HWND hwndDlg)
{
BOOL res = TRUE;
@@ -9394,79 +9906,6 @@ BOOL DecompressZipToDir (const unsigned char *inputBuffer, DWORD inputLength, co
return res;
}
-// If bAppend is TRUE, the buffer is appended to an existing file. If bAppend is FALSE, any existing file
-// is replaced. If an error occurs, the incomplete file is deleted (provided that bAppend is FALSE).
-BOOL SaveBufferToFile (const char *inputBuffer, const wchar_t *destinationFile, DWORD inputLength, BOOL bAppend, BOOL bRenameIfFailed)
-{
- HANDLE dst;
- DWORD bytesWritten;
- BOOL res = TRUE;
- DWORD dwLastError = 0;
-
- dst = CreateFile (destinationFile,
- GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, bAppend ? OPEN_EXISTING : CREATE_ALWAYS, 0, NULL);
-
- dwLastError = GetLastError();
- if (!bAppend && bRenameIfFailed && (dst == INVALID_HANDLE_VALUE) && (GetLastError () == ERROR_SHARING_VIOLATION))
- {
- wchar_t renamedPath[TC_MAX_PATH + 1];
- StringCbCopyW (renamedPath, sizeof(renamedPath), destinationFile);
- StringCbCatW (renamedPath, sizeof(renamedPath), VC_FILENAME_RENAMED_SUFFIX);
-
- /* rename the locked file in order to be able to create a new one */
- if (MoveFileEx (destinationFile, renamedPath, MOVEFILE_REPLACE_EXISTING))
- {
- dst = CreateFile (destinationFile,
- GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
- dwLastError = GetLastError();
- if (dst == INVALID_HANDLE_VALUE)
- {
- /* restore the original file name */
- MoveFileEx (renamedPath, destinationFile, MOVEFILE_REPLACE_EXISTING);
- }
- else
- {
- /* delete the renamed file when the machine reboots */
- MoveFileEx (renamedPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
- }
- }
- }
-
- if (dst == INVALID_HANDLE_VALUE)
- {
- SetLastError (dwLastError);
- handleWin32Error (MainDlg, SRC_POS);
- return FALSE;
- }
-
- if (bAppend)
- SetFilePointer (dst, 0, NULL, FILE_END);
-
- if (!WriteFile (dst, inputBuffer, inputLength, &bytesWritten, NULL)
- || inputLength != bytesWritten)
- {
- res = FALSE;
- }
-
- if (!res)
- {
- // If CREATE_ALWAYS is used, ERROR_ALREADY_EXISTS is returned after successful overwrite
- // of an existing file (it's not an error)
- if (! (GetLastError() == ERROR_ALREADY_EXISTS && !bAppend) )
- handleWin32Error (MainDlg, SRC_POS);
- }
-
- CloseHandle (dst);
-
- if (!res && !bAppend)
- _wremove (destinationFile);
-
- return res;
-}
-
-
// Proper flush for Windows systems. Returns TRUE if successful.
BOOL TCFlushFile (FILE *f)
{
@@ -9909,191 +10348,6 @@ int GetDriverRefCount ()
return -1;
}
-// Loads a 32-bit integer from the file at the specified file offset. The saved value is assumed to have been
-// processed by mputLong(). The result is stored in *result. Returns TRUE if successful (otherwise FALSE).
-BOOL LoadInt32 (const wchar_t *filePath, unsigned __int32 *result, __int64 fileOffset)
-{
- DWORD bufSize = sizeof(__int32);
- unsigned char *buffer = (unsigned char *) malloc (bufSize);
- unsigned char *bufferPtr = buffer;
- HANDLE src = NULL;
- DWORD bytesRead;
- LARGE_INTEGER seekOffset, seekOffsetNew;
- BOOL retVal = FALSE;
-
- if (buffer == NULL)
- return -1;
-
- src = CreateFile (filePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
-
- if (src == INVALID_HANDLE_VALUE)
- {
- free (buffer);
- return FALSE;
- }
-
- seekOffset.QuadPart = fileOffset;
-
- if (SetFilePointerEx (src, seekOffset, &seekOffsetNew, FILE_BEGIN) == 0)
- goto fsif_end;
-
- if (ReadFile (src, buffer, bufSize, &bytesRead, NULL) == 0
- || bytesRead != bufSize)
- goto fsif_end;
-
-
- retVal = TRUE;
-
- *result = mgetLong(bufferPtr);
-
-fsif_end:
- CloseHandle (src);
- free (buffer);
-
- return retVal;
-}
-
-// Loads a 16-bit integer from the file at the specified file offset. The saved value is assumed to have been
-// processed by mputWord(). The result is stored in *result. Returns TRUE if successful (otherwise FALSE).
-BOOL LoadInt16 (const wchar_t *filePath, int *result, __int64 fileOffset)
-{
- DWORD bufSize = sizeof(__int16);
- unsigned char *buffer = (unsigned char *) malloc (bufSize);
- unsigned char *bufferPtr = buffer;
- HANDLE src = NULL;
- DWORD bytesRead;
- LARGE_INTEGER seekOffset, seekOffsetNew;
- BOOL retVal = FALSE;
-
- if (buffer == NULL)
- return -1;
-
- src = CreateFile (filePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
-
- if (src == INVALID_HANDLE_VALUE)
- {
- free (buffer);
- return FALSE;
- }
-
- seekOffset.QuadPart = fileOffset;
-
- if (SetFilePointerEx (src, seekOffset, &seekOffsetNew, FILE_BEGIN) == 0)
- goto fsif_end;
-
- if (ReadFile (src, buffer, bufSize, &bytesRead, NULL) == 0
- || bytesRead != bufSize)
- goto fsif_end;
-
-
- retVal = TRUE;
-
- *result = mgetWord(bufferPtr);
-
-fsif_end:
- CloseHandle (src);
- free (buffer);
-
- return retVal;
-}
-
-// Returns NULL if there's any error. Although the buffer can contain binary data, it is always null-terminated.
-char *LoadFile (const wchar_t *fileName, DWORD *size)
-{
- char *buf;
- DWORD fileSize = INVALID_FILE_SIZE;
- HANDLE h = CreateFile (fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
- if (h == INVALID_HANDLE_VALUE)
- return NULL;
-
- if ((fileSize = GetFileSize (h, NULL)) == INVALID_FILE_SIZE)
- {
- CloseHandle (h);
- return NULL;
- }
-
- *size = fileSize;
- buf = (char *) calloc (*size + 1, 1);
-
- if (buf == NULL)
- {
- CloseHandle (h);
- return NULL;
- }
-
- if (!ReadFile (h, buf, *size, size, NULL))
- {
- free (buf);
- buf = NULL;
- }
-
- CloseHandle (h);
- return buf;
-}
-
-
-// Returns NULL if there's any error.
-char *LoadFileBlock (const wchar_t *fileName, __int64 fileOffset, DWORD count)
-{
- char *buf;
- DWORD bytesRead = 0;
- LARGE_INTEGER seekOffset, seekOffsetNew;
- BOOL bStatus;
-
- HANDLE h = CreateFile (fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
- if (h == INVALID_HANDLE_VALUE)
- return NULL;
-
- seekOffset.QuadPart = fileOffset;
-
- if (SetFilePointerEx (h, seekOffset, &seekOffsetNew, FILE_BEGIN) == 0)
- {
- CloseHandle (h);
- return NULL;
- }
-
- buf = (char *) calloc (count, 1);
-
- if (buf == NULL)
- {
- CloseHandle (h);
- return NULL;
- }
-
- bStatus = ReadFile (h, buf, count, &bytesRead, NULL);
-
- CloseHandle (h);
-
- if (!bStatus || (bytesRead != count))
- {
- free (buf);
- return NULL;
- }
-
- return buf;
-}
-
-
-// Returns -1 if there is an error, or the size of the file.
-__int64 GetFileSize64 (const wchar_t *path)
-{
- HANDLE h = CreateFile (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
- LARGE_INTEGER size;
- __int64 retSize = -1;
-
- if (h)
- {
- if (GetFileSizeEx (h, &size))
- {
- retSize = size.QuadPart;
- }
-
- CloseHandle (h);
- }
-
- return retSize;
-}
-
wchar_t *GetModPath (wchar_t *path, int maxSize)
{
@@ -10296,13 +10550,6 @@ int WarningDirect (const wchar_t *warnMsg, HWND hwnd)
return MessageBoxW (hwnd, warnMsg, lpszTitle, MB_ICONWARNING);
}
-
-int Error (char *stringId, HWND hwnd)
-{
- if (Silent) return 0;
- return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONERROR);
-}
-
int ErrorRetryCancel (char *stringId, HWND hwnd)
{
if (Silent) return 0;
@@ -10781,47 +11028,38 @@ void DebugMsgBox (char *format, ...)
MessageBoxA (MainDlg, buf, "VeraCrypt debug", 0);
}
-
-BOOL IsOSAtLeast (OSVersionEnum reqMinOS)
-{
- return IsOSVersionAtLeast (reqMinOS, 0);
-}
-
-
-// Returns TRUE if the operating system is at least reqMinOS and service pack at least reqMinServicePack.
-// Example 1: IsOSVersionAtLeast (WIN_VISTA, 1) called under Windows 2008, returns TRUE.
-// Example 2: IsOSVersionAtLeast (WIN_XP, 3) called under Windows XP SP1, returns FALSE.
-// Example 3: IsOSVersionAtLeast (WIN_XP, 3) called under Windows Vista SP1, returns TRUE.
-BOOL IsOSVersionAtLeast (OSVersionEnum reqMinOS, int reqMinServicePack)
+BOOL IsSupportedOS ()
{
- /* When updating this function, update IsOSAtLeast() in Ntdriver.c too. */
-
- if (CurrentOSMajor <= 0)
- TC_THROW_FATAL_EXCEPTION;
-
- int major = 0, minor = 0;
-
- switch (reqMinOS)
+ BOOL bRet = FALSE;
+#ifdef SETUP
+ static const wchar_t* szWin7KBs[] = {L"KB3033929", L"KB4474419"};
+ static const wchar_t* szWinVistaKBs[] = {L"KB4039648", L"KB4474419"};
+ if (IsOSAtLeast(WIN_8))
+ bRet = TRUE;
+ else if (IsOSAtLeast(WIN_7))
{
- case WIN_2000: major = 5; minor = 0; break;
- case WIN_XP: major = 5; minor = 1; break;
- case WIN_SERVER_2003: major = 5; minor = 2; break;
- case WIN_VISTA: major = 6; minor = 0; break;
- case WIN_7: major = 6; minor = 1; break;
- case WIN_8: major = 6; minor = 2; break;
- case WIN_8_1: major = 6; minor = 3; break;
- case WIN_10: major = 10; minor = 0; break;
-
- default:
- TC_THROW_FATAL_EXCEPTION;
- break;
+ if (OneOfKBsInstalled(szWin7KBs, 2))
+ bRet = TRUE;
+ else
+ MessageBoxW (NULL, L"SHA-2 support missing from Windows.\n\nPlease Install KB3033929 or KB4474419", lpszTitle, MB_ICONWARNING);
}
+ else if (IsOSAtLeast(WIN_VISTA))
+ {
+ if (OneOfKBsInstalled(szWinVistaKBs, 2))
+ bRet = TRUE;
+ else
+ MessageBoxW (NULL, L"SHA-2 support missing from Windows.\n\nPlease Install KB4039648 or KB4474419", lpszTitle, MB_ICONWARNING);
+ }
+ else if (IsOSAtLeast(WIN_XP))
+ bRet = TRUE;
+#else
+ if (IsOSAtLeast(WIN_XP))
+ bRet = TRUE;
+#endif
- return ((CurrentOSMajor << 16 | CurrentOSMinor << 8 | CurrentOSServicePack)
- >= (major << 16 | minor << 8 | reqMinServicePack));
+ return bRet;
}
-
BOOL Is64BitOs()
{
#ifdef _WIN64
@@ -14035,135 +14273,6 @@ INT_PTR SecureDesktopDialogBoxParam(
#endif
-#ifdef NDEBUG
-static BOOL InitializeWintrust()
-{
- if (!hWinTrustLib)
- {
- wchar_t szPath[MAX_PATH] = {0};
-
- if (GetSystemDirectory(szPath, MAX_PATH))
- StringCchCatW (szPath, MAX_PATH, L"\\Wintrust.dll");
- else
- StringCchCopyW (szPath, MAX_PATH, L"C:\\Windows\\System32\\Wintrust.dll");
-
- hWinTrustLib = LoadLibrary (szPath);
- if (hWinTrustLib)
- {
- WinVerifyTrustFn = (WINVERIFYTRUST) GetProcAddress (hWinTrustLib, "WinVerifyTrust");
- WTHelperProvDataFromStateDataFn = (WTHELPERPROVDATAFROMSTATEDATA) GetProcAddress (hWinTrustLib, "WTHelperProvDataFromStateData");
- WTHelperGetProvSignerFromChainFn = (WTHELPERGETPROVSIGNERFROMCHAIN) GetProcAddress (hWinTrustLib, "WTHelperGetProvSignerFromChain");
- WTHelperGetProvCertFromChainFn = (WTHELPERGETPROVCERTFROMCHAIN) GetProcAddress (hWinTrustLib, "WTHelperGetProvCertFromChain");
-
- if ( !WinVerifyTrustFn
- || !WTHelperProvDataFromStateDataFn
- || !WTHelperGetProvSignerFromChainFn
- || !WTHelperGetProvCertFromChainFn)
- {
- FreeLibrary (hWinTrustLib);
- hWinTrustLib = NULL;
- }
-
- }
- }
-
- if (hWinTrustLib)
- return TRUE;
- else
- return FALSE;
-}
-
-static void FinalizeWintrust()
-{
- if (hWinTrustLib)
- {
- FreeLibrary (hWinTrustLib);
- hWinTrustLib = NULL;
- }
-}
-
-#endif
-
-BOOL VerifyModuleSignature (const wchar_t* path)
-{
-#ifdef NDEBUG
- BOOL bResult = FALSE;
- HRESULT hResult;
- GUID gActionID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
- WINTRUST_FILE_INFO fileInfo = {0};
- WINTRUST_DATA WVTData = {0};
- wchar_t filePath [TC_MAX_PATH + 1024];
-
- // we check our own authenticode signature only starting from Windows 10 since this is
- // the minimal supported OS apart from XP where we can't verify SHA256 signatures
- if (!IsOSAtLeast (WIN_10))
- return TRUE;
-
- // Strip quotation marks (if any)
- if (path [0] == L'"')
- {
- StringCbCopyW (filePath, sizeof(filePath), path + 1);
- }
- else
- {
- StringCbCopyW (filePath, sizeof(filePath), path);
- }
-
- // Strip quotation marks (if any)
- if (filePath [wcslen (filePath) - 1] == L'"')
- filePath [wcslen (filePath) - 1] = 0;
-
- if (!InitializeWintrust ())
- return FALSE;
-
- fileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
- fileInfo.pcwszFilePath = filePath;
- fileInfo.hFile = NULL;
-
- WVTData.cbStruct = sizeof(WINTRUST_DATA);
- WVTData.dwUIChoice = WTD_UI_NONE;
- WVTData.fdwRevocationChecks = WTD_REVOKE_NONE;
- WVTData.dwUnionChoice = WTD_CHOICE_FILE;
- WVTData.pFile = &fileInfo;
- WVTData.dwStateAction = WTD_STATEACTION_VERIFY;
- WVTData.dwProvFlags = WTD_REVOCATION_CHECK_NONE | WTD_CACHE_ONLY_URL_RETRIEVAL;
-
- hResult = WinVerifyTrustFn(0, &gActionID, &WVTData);
- if (0 == hResult)
- {
- PCRYPT_PROVIDER_DATA pProviderData = WTHelperProvDataFromStateDataFn (WVTData.hWVTStateData);
- if (pProviderData)
- {
- PCRYPT_PROVIDER_SGNR pProviderSigner = WTHelperGetProvSignerFromChainFn (pProviderData, 0, FALSE, 0);
- if (pProviderSigner)
- {
- PCRYPT_PROVIDER_CERT pProviderCert = WTHelperGetProvCertFromChainFn (pProviderSigner, 0);
- if (pProviderCert && (pProviderCert->pCert))
- {
- BYTE hashVal[64];
- sha512 (hashVal, pProviderCert->pCert->pbCertEncoded, pProviderCert->pCert->cbCertEncoded);
-
- if (0 == memcmp (hashVal, gpbSha256CodeSignCertFingerprint, 64))
- {
- bResult = TRUE;
- }
- }
- }
- }
- }
-
- WVTData.dwUIChoice = WTD_UI_NONE;
- WVTData.dwStateAction = WTD_STATEACTION_CLOSE;
- WinVerifyTrustFn(0, &gActionID, &WVTData);
-
- FinalizeWintrust ();
-
- return bResult;
-#else
- return TRUE;
-#endif
-}
-
void GetInstallationPath (HWND hwndDlg, wchar_t* szInstallPath, DWORD cchSize, BOOL* pbInstallPathDetermined)
{
HKEY hkey;
@@ -14551,6 +14660,98 @@ BOOL IsElevated()
return bReturn;
}
+// Based on code from:
+// https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/winui/shell/appplatform/ExecInExplorer/ExecInExplorer.cpp
+HRESULT GetShellViewForDesktop(REFIID riid, void **ppv)
+{
+ *ppv = NULL;
+
+ IShellWindows *psw;
+ HRESULT hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&psw));
+ if (SUCCEEDED(hr))
+ {
+ HWND hwnd;
+ IDispatch* pdisp;
+ VARIANT vEmpty = {}; // VT_EMPTY
+ if (S_OK == psw->FindWindowSW(&vEmpty, &vEmpty, SWC_DESKTOP, (long*)&hwnd, SWFO_NEEDDISPATCH, &pdisp))
+ {
+ IShellBrowser *psb;
+ hr = IUnknown_QueryServicePtr(pdisp, SID_STopLevelBrowser, IID_PPV_ARGS(&psb));
+ if (SUCCEEDED(hr))
+ {
+ IShellView *psv;
+ hr = psb->QueryActiveShellView(&psv);
+ if (SUCCEEDED(hr))
+ {
+ hr = psv->QueryInterface(riid, ppv);
+ psv->Release();
+ }
+ psb->Release();
+ }
+ pdisp->Release();
+ }
+ else
+ {
+ hr = E_FAIL;
+ }
+ psw->Release();
+ }
+ return hr;
+}
+
+HRESULT GetShellDispatchFromView(IShellView *psv, REFIID riid, void **ppv)
+{
+ *ppv = NULL;
+
+ IDispatch *pdispBackground;
+ HRESULT hr = psv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&pdispBackground));
+ if (SUCCEEDED(hr))
+ {
+ IShellFolderViewDual *psfvd;
+ hr = pdispBackground->QueryInterface(IID_PPV_ARGS(&psfvd));
+ if (SUCCEEDED(hr))
+ {
+ IDispatch *pdisp;
+ hr = psfvd->get_Application(&pdisp);
+ if (SUCCEEDED(hr))
+ {
+ hr = pdisp->QueryInterface(riid, ppv);
+ pdisp->Release();
+ }
+ psfvd->Release();
+ }
+ pdispBackground->Release();
+ }
+ return hr;
+}
+
+HRESULT ShellExecInExplorerProcess(PCWSTR pszFile)
+{
+ IShellView *psv;
+ CoInitialize(NULL);
+ HRESULT hr = GetShellViewForDesktop(IID_PPV_ARGS(&psv));
+ if (SUCCEEDED(hr))
+ {
+ IShellDispatch2 *psd;
+ hr = GetShellDispatchFromView(psv, IID_PPV_ARGS(&psd));
+ if (SUCCEEDED(hr))
+ {
+ BSTR bstrFile = SysAllocString(pszFile);
+ hr = bstrFile ? S_OK : E_OUTOFMEMORY;
+ if (SUCCEEDED(hr))
+ {
+ VARIANT vtEmpty = {}; // VT_EMPTY
+ hr = psd->ShellExecuteW(bstrFile, vtEmpty, vtEmpty, vtEmpty, vtEmpty);
+ SysFreeString(bstrFile);
+ }
+ psd->Release();
+ }
+ psv->Release();
+ }
+ CoUninitialize();
+ return hr;
+}
+
// This function always loads a URL in a non-privileged mode
// If current process has admin privileges, we execute the command "rundll32 url.dll,FileProtocolHandler URL" as non-elevated
// Use this security mechanism only starting from Windows Vista and only if we can get the window of the Shell's desktop since
@@ -14558,7 +14759,8 @@ BOOL IsElevated()
// then we can't protect the user in such non standard environment
void SafeOpenURL (LPCWSTR szUrl)
{
- if (IsOSAtLeast (WIN_VISTA) && IsAdmin () && IsElevated() && GetShellWindow())
+ BOOL bFallback = TRUE;
+ if (IsOSAtLeast (WIN_VISTA) && IsUacSupported() && IsAdmin () && IsElevated() && GetShellWindow())
{
WCHAR szRunDllPath[TC_MAX_PATH];
WCHAR szUrlDllPath[TC_MAX_PATH];
@@ -14572,11 +14774,23 @@ void SafeOpenURL (LPCWSTR szUrl)
StringCbPrintfW(szUrlDllPath, sizeof(szUrlDllPath), L"%s\\%s", szSystemPath, L"url.dll");
StringCchPrintfW(szCommandLine, 1024, L"%s %s,FileProtocolHandler %s", szRunDllPath, szUrlDllPath, szUrl);
- RunAsDesktopUser (NULL, szCommandLine);
+ if (RunAsDesktopUser (NULL, szCommandLine))
+ {
+ bFallback = FALSE;
+ }
+ else
+ {
+ // fallback to IShellDispatch2::ShellExecuteW
+ if (SUCCEEDED(ShellExecInExplorerProcess(szUrl)))
+ {
+ bFallback = FALSE;
+ }
+ }
delete [] szCommandLine;
}
- else
+
+ if (bFallback)
{
ShellExecuteW (NULL, L"open", szUrl, NULL, NULL, SW_SHOWNORMAL);
}
@@ -15233,3 +15447,219 @@ BOOL GetHibernateStatus (BOOL& bHibernateEnabled, BOOL& bHiberbootEnabled)
return bResult;
}
+/* return TRUE if Windows is in Test Signing mode */
+/* ref: https://social.msdn.microsoft.com/Forums/Windowsapps/en-US/e6c1be93-7003-4594-b8e4-18ab4a75d273/detecting-testsigning-onoff-via-api */
+BOOL IsTestSigningModeEnabled ()
+{
+ BOOL bEnabled = FALSE;
+ NtQuerySystemInformationFn NtQuerySystemInformationPtr = (NtQuerySystemInformationFn) GetProcAddress (GetModuleHandle (L"ntdll.dll"), "NtQuerySystemInformation");
+ if(NtQuerySystemInformationPtr)
+ {
+ SYSTEM_CODEINTEGRITY_INFORMATION info = {0};
+ ULONG cbReturnedData = 0;
+ info.Length = sizeof(info);
+ if ( (NtQuerySystemInformationPtr((SYSTEM_INFORMATION_CLASS) SYSTEMCODEINTEGRITYINFORMATION, &info, sizeof(info), &cbReturnedData) >= 0)
+ && (cbReturnedData == sizeof(info))
+ )
+ {
+ if ((info.CodeIntegrityOptions & (CODEINTEGRITY_OPTION_TESTSIGN | CODEINTEGRITY_OPTION_ENABLED)) == (CODEINTEGRITY_OPTION_TESTSIGN | CODEINTEGRITY_OPTION_ENABLED))
+ {
+ bEnabled = TRUE;
+ }
+ }
+ }
+
+ return bEnabled;
+}
+
+// Adapted from https://docs.microsoft.com/en-us/windows/win32/wmisdk/example-creating-a-wmi-application
+bool GetKbList (std::vector<std::wstring>& kbList)
+{
+ HRESULT hres;
+ kbList.clear();
+
+ // Initialize COM.
+ hres = CoInitialize(NULL);
+ if (FAILED(hres))
+ {
+ return false;
+ }
+
+ // Initialize
+ hres = CoInitializeSecurity(
+ NULL,
+ -1, // COM negotiates service
+ NULL, // Authentication services
+ NULL, // Reserved
+ RPC_C_AUTHN_LEVEL_DEFAULT, // authentication
+ RPC_C_IMP_LEVEL_IMPERSONATE, // Impersonation
+ NULL, // Authentication info
+ EOAC_NONE, // Additional capabilities
+ NULL // Reserved
+ );
+
+
+ if (FAILED(hres))
+ {
+ CoUninitialize();
+ return false;
+ }
+
+ // Obtain the initial locator to Windows Management
+ // on a particular host computer.
+ IWbemLocator *pLoc = 0;
+
+ hres = CoCreateInstance(
+ CLSID_WbemLocator,
+ 0,
+ CLSCTX_INPROC_SERVER,
+ IID_IWbemLocator, (LPVOID *) &pLoc);
+
+ if (FAILED(hres))
+ {
+ CoUninitialize();
+ return false;
+ }
+
+ IWbemServices *pSvc = 0;
+
+ // Connect to the root\cimv2 namespace with the
+ // current user and obtain pointer pSvc
+ // to make IWbemServices calls.
+
+ hres = pLoc->ConnectServer(
+
+ _bstr_t(L"ROOT\\CIMV2"), // WMI namespace
+ NULL, // User name
+ NULL, // User password
+ 0, // Locale
+ NULL, // Security flags
+ 0, // Authority
+ 0, // Context object
+ &pSvc // IWbemServices proxy
+ );
+
+ if (FAILED(hres))
+ {
+ pLoc->Release();
+ CoUninitialize();
+ return false;
+ }
+
+ // Set the IWbemServices proxy so that impersonation
+ // of the user (client) occurs.
+ hres = CoSetProxyBlanket(
+
+ pSvc, // the proxy to set
+ RPC_C_AUTHN_WINNT, // authentication service
+ RPC_C_AUTHZ_NONE, // authorization service
+ NULL, // Server principal name
+ RPC_C_AUTHN_LEVEL_CALL, // authentication level
+ RPC_C_IMP_LEVEL_IMPERSONATE, // impersonation level
+ NULL, // client identity
+ EOAC_NONE // proxy capabilities
+ );
+
+ if (FAILED(hres))
+ {
+ pSvc->Release();
+ pLoc->Release();
+ CoUninitialize();
+ return false;
+ }
+
+
+ // Use the IWbemServices pointer to make requests of WMI.
+ // Make requests here:
+
+ // query for all installed KBs
+ IEnumWbemClassObject* pEnumerator = NULL;
+ hres = pSvc->ExecQuery(
+ bstr_t("WQL"),
+ bstr_t("SELECT * FROM Win32_QuickFixEngineering"),
+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+ NULL,
+ &pEnumerator);
+
+ if (FAILED(hres))
+ {
+ pSvc->Release();
+ pLoc->Release();
+ CoUninitialize();
+ return false;
+ }
+ else
+ {
+ IWbemClassObject *pclsObj;
+ ULONG uReturn = 0;
+
+ while (pEnumerator)
+ {
+ hres = pEnumerator->Next(WBEM_INFINITE, 1,
+ &pclsObj, &uReturn);
+
+ if(0 == uReturn)
+ {
+ break;
+ }
+
+ VARIANT vtProp;
+
+ // Get the value of the "hotfixid" property
+ hres = pclsObj->Get(L"hotfixid", 0, &vtProp, 0, 0);
+ if (SUCCEEDED(hres) && (V_VT(&vtProp) == VT_BSTR))
+ {
+ kbList.push_back(vtProp.bstrVal);
+ }
+ VariantClear(&vtProp);
+
+ pclsObj->Release();
+ pclsObj = NULL;
+ }
+
+ }
+
+ // Cleanup
+ // ========
+
+ pSvc->Release();
+ pLoc->Release();
+ pEnumerator->Release();
+
+ CoUninitialize();
+
+ return true;
+}
+
+bool OneOfKBsInstalled (const wchar_t* szKBs[], int count)
+{
+ std::vector<std::wstring> kbList;
+ bool bRet = GetKbList(kbList);
+ if (bRet)
+ {
+ // at least one of the given KBs must be present
+ bool bFound = false;
+
+ for (size_t j = 0; j < kbList.size(); j++)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ if (_wcsicmp(szKBs[i], kbList[j].c_str()) == 0)
+ {
+ bFound = true;
+ break;
+ }
+ }
+
+ if (bFound)
+ {
+ break;
+ }
+ }
+
+ bRet = bFound;
+ }
+
+ return bRet;
+}
+#endif // VC_COMREG \ No newline at end of file
diff --git a/src/Common/Dlgcode.h b/src/Common/Dlgcode.h
index 6370c2a7..362b2d6d 100644
--- a/src/Common/Dlgcode.h
+++ b/src/Common/Dlgcode.h
@@ -18,6 +18,7 @@
#include "Apidrvr.h"
#include "Keyfiles.h"
#include "Wipe.h"
+#include <Winternl.h>
#ifdef __cplusplus
extern "C" {
@@ -250,6 +251,28 @@ typedef enum BitLockerEncryptionStatus
BL_Status_Protected
} BitLockerEncryptionStatus;
+#ifndef CODEINTEGRITY_OPTION_ENABLED
+
+#define CODEINTEGRITY_OPTION_ENABLED 0x01
+#define CODEINTEGRITY_OPTION_TESTSIGN 0x02
+
+typedef struct _SYSTEM_CODEINTEGRITY_INFORMATION {
+ ULONG Length;
+ ULONG CodeIntegrityOptions;
+} SYSTEM_CODEINTEGRITY_INFORMATION, *PSYSTEM_CODEINTEGRITY_INFORMATION;
+
+#endif
+
+#define SYSPARTITIONINFORMATION 0x62
+#define SYSTEMCODEINTEGRITYINFORMATION 0x67
+
+typedef NTSTATUS (WINAPI *NtQuerySystemInformationFn)(
+ SYSTEM_INFORMATION_CLASS SystemInformationClass,
+ PVOID SystemInformation,
+ ULONG SystemInformationLength,
+ PULONG ReturnLength
+);
+
#define DEFAULT_VOL_CREATION_WIZARD_MODE WIZARD_MODE_FILE_CONTAINER
@@ -472,6 +495,7 @@ void Debug (char *format, ...);
void DebugMsgBox (char *format, ...);
BOOL IsOSAtLeast (OSVersionEnum reqMinOS);
BOOL IsOSVersionAtLeast (OSVersionEnum reqMinOS, int reqMinServicePack);
+BOOL IsSupportedOS ();
BOOL Is64BitOs ();
BOOL IsARM();
BOOL IsServerOS ();
@@ -560,6 +584,7 @@ BOOL BufferHasPattern (const unsigned char* buffer, size_t bufferLen, const void
BOOL EnableProcessProtection();
void SafeOpenURL (LPCWSTR szUrl);
BitLockerEncryptionStatus GetBitLockerEncryptionStatus(WCHAR driveLetter);
+BOOL IsTestSigningModeEnabled ();
#ifdef _WIN64
void GetAppRandomSeed (unsigned char* pbRandSeed, size_t cbRandSeed);
#endif
@@ -750,6 +775,8 @@ public:
};
BOOL GetHibernateStatus (BOOL& bHibernateEnabled, BOOL& bHiberbootEnabled);
+bool GetKbList (std::vector<std::wstring>& kbList);
+bool OneOfKBsInstalled (const wchar_t* szKBs[], int count);
#endif // __cplusplus
diff --git a/src/Common/EncryptionThreadPool.c b/src/Common/EncryptionThreadPool.c
index 1401e8a0..62b2cae8 100644
--- a/src/Common/EncryptionThreadPool.c
+++ b/src/Common/EncryptionThreadPool.c
@@ -248,8 +248,8 @@ static TC_THREAD_PROC EncryptionThreadProc (void *threadArg)
case DeriveKeyWork:
switch (workItem->KeyDerivation.Pkcs5Prf)
{
- case RIPEMD160:
- derive_key_ripemd160 (workItem->KeyDerivation.Password, workItem->KeyDerivation.PasswordLength, workItem->KeyDerivation.Salt, PKCS5_SALT_SIZE,
+ case BLAKE2S:
+ derive_key_blake2s (workItem->KeyDerivation.Password, workItem->KeyDerivation.PasswordLength, workItem->KeyDerivation.Salt, PKCS5_SALT_SIZE,
workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.DerivedKey, GetMaxPkcs5OutSize());
break;
diff --git a/src/Common/Format.c b/src/Common/Format.c
index f691c78d..4363f474 100644
--- a/src/Common/Format.c
+++ b/src/Common/Format.c
@@ -1216,10 +1216,16 @@ BOOL ExternalFormatFs (int driveNo, int clusterSize, int fsType)
DWORD dwExitCode, dwWritten;
LPCSTR newLine = "\n";
- WriteFile(hChildStd_IN_Wr, (LPCVOID) newLine, 1, &dwWritten, NULL);
-
- /* wait for the format process to finish */
- WaitForSingleObject (piProcInfo.hProcess, INFINITE);
+ if (WriteFile(hChildStd_IN_Wr, (LPCVOID) newLine, 1, &dwWritten, NULL))
+ {
+ /* wait for the format process to finish */
+ WaitForSingleObject (piProcInfo.hProcess, INFINITE);
+ }
+ else
+ {
+ /* we failed to write "\n". Maybe process exited too quickly. We wait 1 second */
+ WaitForSingleObject (piProcInfo.hProcess, 1000);
+ }
/* check if it was successfull */
if (GetExitCodeProcess (piProcInfo.hProcess, &dwExitCode))
diff --git a/src/Common/Language.c b/src/Common/Language.c
index ffccd44e..278b7dd1 100644
--- a/src/Common/Language.c
+++ b/src/Common/Language.c
@@ -226,7 +226,7 @@ static BOOL LoadLanguageData (int resourceid, BOOL bForceSetPreferredLanguage, B
XmlGetAttributeText (xml, "prog-version", attr, sizeof (attr));
// Check version of external language file
- if (defaultLangParsed && strcmp (attr, VERSION_STRING VERSION_STRING_SUFFIX) && strcmp (attr, "DEBUG"))
+ if (defaultLangParsed && strcmp (attr, VERSION_STRING) && strcmp (attr, "DEBUG"))
{
wchar_t m[2048];
StringCbPrintfW (m, sizeof(m), L"The installed language pack is incompatible with this version of VeraCrypt (the language pack is for VeraCrypt %hs). A newer version may be available at www.idrix.fr.\n\nTo prevent this message from being displayed, do any of the following:\n\n- Select 'Settings' > 'Language'; then select 'English' and click 'OK'.\n\n- Remove or replace the language pack with a compatible version (the language pack may reside e.g. in 'C:\\Program Files\\VeraCrypt' or '%%LOCALAPPDATA%%\\VirtualStore\\Program Files\\VeraCrypt', etc.)", attr);
@@ -611,7 +611,8 @@ char *GetPreferredLangId ()
void SetPreferredLangId (char *langId)
{
- StringCbCopyA (PreferredLangId, sizeof(PreferredLangId), langId);
+ if (strlen(langId) < sizeof(PreferredLangId))
+ StringCbCopyA (PreferredLangId, sizeof(PreferredLangId), langId);
}
diff --git a/src/Common/Language.xml b/src/Common/Language.xml
index 8002a08c..e4ceac7a 100644
--- a/src/Common/Language.xml
+++ b/src/Common/Language.xml
@@ -1567,6 +1567,7 @@
<entry lang="en" key="VOLUME_HOST_IN_USE">WARNING: The host file/device {0} is already in use!\n\nIgnoring this can cause undesired results including system instability. All applications that might be using the host file/device should be closed before mounting the volume.\n\nContinue mounting?</entry>
<entry lang="en" key="CANT_INSTALL_WITH_EXE_OVER_MSI">VeraCrypt was previously installed using an MSI package and so it can't be updated using the standard installer.\n\nPlease use the MSI package to update your VeraCrypt installation.</entry>
<entry lang="en" key="IDC_USE_ALL_FREE_SPACE">Use all available free space</entry>
+ <entry lang="en" key="SYS_ENCRYPTION_UPGRADE_UNSUPPORTED_ALGORITHM">VeraCrypt cannot be upgraded because the system partition/drive was encrypted using an algorithm that is not supported anymore.\nPlease decrypt your system before upgrading VeraCrypt and then encrypt it again.</entry>
</localization>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="VeraCrypt">
diff --git a/src/Common/Lzma.vcxproj b/src/Common/Lzma.vcxproj
new file mode 100644
index 00000000..b6d31bde
--- /dev/null
+++ b/src/Common/Lzma.vcxproj
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="lzma\lzma-history.txt" />
+ <None Include="lzma\lzma-sdk.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="lzma\Alloc.c" />
+ <ClCompile Include="lzma\CpuArch.c" />
+ <ClCompile Include="lzma\LzFind.c" />
+ <ClCompile Include="lzma\LzFindMt.c" />
+ <ClCompile Include="lzma\LzFindOpt.c" />
+ <ClCompile Include="lzma\LzmaDec.c" />
+ <ClCompile Include="lzma\LzmaEnc.c" />
+ <ClCompile Include="lzma\LzmaLib.c" />
+ <ClCompile Include="lzma\Threads.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="lzma\7zTypes.h" />
+ <ClInclude Include="lzma\Alloc.h" />
+ <ClInclude Include="lzma\Compiler.h" />
+ <ClInclude Include="lzma\CpuArch.h" />
+ <ClInclude Include="lzma\LzFind.h" />
+ <ClInclude Include="lzma\LzFindMt.h" />
+ <ClInclude Include="lzma\LzHash.h" />
+ <ClInclude Include="lzma\LzmaDec.h" />
+ <ClInclude Include="lzma\LzmaEnc.h" />
+ <ClInclude Include="lzma\LzmaLib.h" />
+ <ClInclude Include="lzma\Precomp.h" />
+ <ClInclude Include="lzma\Threads.h" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{B896FE1F-6BF3-4F75-9148-F841829073D9}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>Lzma</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>Windows7.1SDK</PlatformToolset>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>Windows7.1SDK</PlatformToolset>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>Windows7.1SDK</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>Windows7.1SDK</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <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" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <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" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <OutDir>$(Platform)\$(Configuration)\</OutDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <OutDir>$(Platform)\$(Configuration)\</OutDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/src/Common/Lzma.vcxproj.filters b/src/Common/Lzma.vcxproj.filters
new file mode 100644
index 00000000..1c763e5a
--- /dev/null
+++ b/src/Common/Lzma.vcxproj.filters
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="lzma\lzma-history.txt" />
+ <None Include="lzma\lzma-sdk.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="lzma\Alloc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lzma\CpuArch.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lzma\LzFind.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lzma\LzFindMt.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lzma\LzFindOpt.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lzma\LzmaDec.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lzma\LzmaEnc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lzma\LzmaLib.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lzma\Threads.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="lzma\7zTypes.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\Alloc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\Compiler.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\CpuArch.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\LzFind.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\LzFindMt.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\LzHash.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\LzmaDec.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\LzmaEnc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\LzmaLib.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\Precomp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\Threads.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/Common/Lzma.vcxproj.user b/src/Common/Lzma.vcxproj.user
new file mode 100644
index 00000000..ace9a86a
--- /dev/null
+++ b/src/Common/Lzma.vcxproj.user
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project> \ No newline at end of file
diff --git a/src/Common/Lzma_vs2019.vcxproj b/src/Common/Lzma_vs2019.vcxproj
new file mode 100644
index 00000000..fae6762a
--- /dev/null
+++ b/src/Common/Lzma_vs2019.vcxproj
@@ -0,0 +1,246 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|ARM64">
+ <Configuration>Debug</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|ARM64">
+ <Configuration>Release</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="lzma\lzma-history.txt" />
+ <None Include="lzma\lzma-sdk.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="lzma\Alloc.c" />
+ <ClCompile Include="lzma\CpuArch.c" />
+ <ClCompile Include="lzma\LzFind.c" />
+ <ClCompile Include="lzma\LzFindMt.c" />
+ <ClCompile Include="lzma\LzFindOpt.c" />
+ <ClCompile Include="lzma\LzmaDec.c" />
+ <ClCompile Include="lzma\LzmaEnc.c" />
+ <ClCompile Include="lzma\LzmaLib.c" />
+ <ClCompile Include="lzma\Threads.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="lzma\7zTypes.h" />
+ <ClInclude Include="lzma\Alloc.h" />
+ <ClInclude Include="lzma\Compiler.h" />
+ <ClInclude Include="lzma\CpuArch.h" />
+ <ClInclude Include="lzma\LzFind.h" />
+ <ClInclude Include="lzma\LzFindMt.h" />
+ <ClInclude Include="lzma\LzHash.h" />
+ <ClInclude Include="lzma\LzmaDec.h" />
+ <ClInclude Include="lzma\LzmaEnc.h" />
+ <ClInclude Include="lzma\LzmaLib.h" />
+ <ClInclude Include="lzma\Precomp.h" />
+ <ClInclude Include="lzma\Threads.h" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{B896FE1F-6BF3-4F75-9148-F841829073D9}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>Lzma</RootNamespace>
+ <ProjectName>Lzma</ProjectName>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v142</PlatformToolset>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v142</PlatformToolset>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v142</PlatformToolset>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v142</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v142</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
+ <ConfigurationType>StaticLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v142</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <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" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <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" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <OutDir>$(Platform)\$(Configuration)\</OutDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <OutDir>$(Platform)\$(Configuration)\</OutDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <OutDir>$(Configuration)\</OutDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <OutDir>$(Platform)\$(Configuration)\</OutDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <OutDir>$(Platform)\$(Configuration)\</OutDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <ClCompile>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ </Link>
+ </ItemDefinitionGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/src/Common/Lzma_vs2019.vcxproj.filters b/src/Common/Lzma_vs2019.vcxproj.filters
new file mode 100644
index 00000000..1c763e5a
--- /dev/null
+++ b/src/Common/Lzma_vs2019.vcxproj.filters
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="lzma\lzma-history.txt" />
+ <None Include="lzma\lzma-sdk.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="lzma\Alloc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lzma\CpuArch.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lzma\LzFind.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lzma\LzFindMt.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lzma\LzFindOpt.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lzma\LzmaDec.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lzma\LzmaEnc.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lzma\LzmaLib.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="lzma\Threads.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="lzma\7zTypes.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\Alloc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\Compiler.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\CpuArch.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\LzFind.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\LzFindMt.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\LzHash.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\LzmaDec.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\LzmaEnc.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\LzmaLib.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\Precomp.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="lzma\Threads.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/Common/Lzma_vs2019.vcxproj.user b/src/Common/Lzma_vs2019.vcxproj.user
new file mode 100644
index 00000000..ace9a86a
--- /dev/null
+++ b/src/Common/Lzma_vs2019.vcxproj.user
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project> \ No newline at end of file
diff --git a/src/Common/Pkcs5.c b/src/Common/Pkcs5.c
index 3ac3cc2c..36e491a0 100644
--- a/src/Common/Pkcs5.c
+++ b/src/Common/Pkcs5.c
@@ -16,7 +16,7 @@
#include <memory.h>
#include <stdlib.h>
#endif
-#include "Rmd160.h"
+#include "blake2.h"
#ifndef TC_WINDOWS_BOOT
#include "Sha2.h"
#include "Whirlpool.h"
@@ -550,100 +550,131 @@ void derive_key_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, uint32
#endif // TC_WINDOWS_BOOT
-#if !defined(TC_WINDOWS_BOOT) || defined(TC_WINDOWS_BOOT_RIPEMD160)
+#if !defined(TC_WINDOWS_BOOT) || defined(TC_WINDOWS_BOOT_BLAKE2S)
-typedef struct hmac_ripemd160_ctx_struct
+typedef struct hmac_blake2s_ctx_struct
{
- RMD160_CTX context;
- RMD160_CTX inner_digest_ctx; /*pre-computed inner digest context */
- RMD160_CTX outer_digest_ctx; /*pre-computed outer digest context */
- char k[PKCS5_SALT_SIZE + 4]; /* enough to hold (salt_len + 4) and also the RIPEMD-160 hash */
- char u[RIPEMD160_DIGESTSIZE];
-} hmac_ripemd160_ctx;
-
-void hmac_ripemd160_internal (char *input_digest, int len, hmac_ripemd160_ctx* hmac)
+ blake2s_state ctx;
+ blake2s_state inner_digest_ctx; /*pre-computed inner digest context */
+ blake2s_state outer_digest_ctx; /*pre-computed outer digest context */
+ char k[PKCS5_SALT_SIZE + 4]; /* enough to hold (salt_len + 4) and also the SHA256 hash */
+ char u[BLAKE2S_DIGESTSIZE];
+} hmac_blake2s_ctx;
+
+void hmac_blake2s_internal
+(
+ char *d, /* input data. d pointer is guaranteed to be at least 32-bytes long */
+ int ld, /* length of input data in bytes */
+ hmac_blake2s_ctx* hmac /* HMAC-SHA256 context which holds temporary variables */
+)
{
- RMD160_CTX* context = &(hmac->context);
+ blake2s_state* ctx = &(hmac->ctx);
/**** Restore Precomputed Inner Digest Context ****/
- memcpy (context, &(hmac->inner_digest_ctx), sizeof (RMD160_CTX));
+ memcpy (ctx, &(hmac->inner_digest_ctx), sizeof (blake2s_state));
- RMD160Update(context, (const unsigned char *) input_digest, len); /* then text of datagram */
- RMD160Final((unsigned char *) input_digest, context); /* finish up 1st pass */
+ blake2s_update (ctx, d, ld);
+
+ blake2s_final (ctx, (unsigned char*) d); /* d = inner digest */
/**** Restore Precomputed Outer Digest Context ****/
- memcpy (context, &(hmac->outer_digest_ctx), sizeof (RMD160_CTX));
+ memcpy (ctx, &(hmac->outer_digest_ctx), sizeof (blake2s_state));
+
+ blake2s_update (ctx, d, SHA256_DIGESTSIZE);
- /* results of 1st hash */
- RMD160Update(context, (const unsigned char *) input_digest, RIPEMD160_DIGESTSIZE);
- RMD160Final((unsigned char *) input_digest, context); /* finish up 2nd pass */
+ blake2s_final (ctx, (unsigned char *) d); /* d = outer digest */
}
#ifndef TC_WINDOWS_BOOT
-void hmac_ripemd160 (char *key, int keylen, char *input_digest, int len)
+void hmac_blake2s
+(
+ char *k, /* secret key */
+ int lk, /* length of the key in bytes */
+ char *d, /* data */
+ int ld /* length of data in bytes */
+)
{
- hmac_ripemd160_ctx hmac;
- RMD160_CTX* ctx;
- unsigned char* k_pad = (unsigned char*) hmac.k; /* inner/outer padding - key XORd with ipad */
- unsigned char tk[RIPEMD160_DIGESTSIZE];
- int i;
-
- /* If the key is longer than the hash algorithm block size,
- let key = ripemd160(key), as per HMAC specifications. */
- if (keylen > RIPEMD160_BLOCKSIZE)
+ hmac_blake2s_ctx hmac;
+ blake2s_state* ctx;
+ char* buf = hmac.k;
+ int b;
+ char key[BLAKE2S_DIGESTSIZE];
+#if defined (DEVICE_DRIVER)
+ NTSTATUS saveStatus = STATUS_INVALID_PARAMETER;
+#ifdef _WIN64
+ XSTATE_SAVE SaveState;
+ if (IsCpuIntel() && HasSAVX())
+ saveStatus = KeSaveExtendedProcessorStateVC(XSTATE_MASK_GSSE, &SaveState);
+#else
+ KFLOATING_SAVE floatingPointState;
+ if (HasSSE2())
+ saveStatus = KeSaveFloatingPointState (&floatingPointState);
+#endif
+#endif
+ /* If the key is longer than the hash algorithm block size,
+ let key = blake2s(key), as per HMAC specifications. */
+ if (lk > BLAKE2S_BLOCKSIZE)
{
- RMD160_CTX tctx;
+ blake2s_state tctx;
- RMD160Init(&tctx);
- RMD160Update(&tctx, (const unsigned char *) key, keylen);
- RMD160Final(tk, &tctx);
+ blake2s_init (&tctx);
+ blake2s_update (&tctx, k, lk);
+ blake2s_final (&tctx, (unsigned char *) key);
- key = (char *) tk;
- keylen = RIPEMD160_DIGESTSIZE;
+ k = key;
+ lk = BLAKE2S_DIGESTSIZE;
- burn (&tctx, sizeof(tctx)); // Prevent leaks
- }
+ burn (&tctx, sizeof(tctx)); // Prevent leaks
+ }
+
+ /**** Precompute HMAC Inner Digest ****/
- /* perform inner RIPEMD-160 */
ctx = &(hmac.inner_digest_ctx);
- /* start out by storing key in pads */
- memset(k_pad, 0x36, 64);
- /* XOR key with ipad and opad values */
- for (i=0; i<keylen; i++)
- {
- k_pad[i] ^= key[i];
- }
+ blake2s_init (ctx);
- RMD160Init(ctx); /* init context for 1st pass */
- RMD160Update(ctx, k_pad, RIPEMD160_BLOCKSIZE); /* start with inner pad */
+ /* Pad the key for inner digest */
+ for (b = 0; b < lk; ++b)
+ buf[b] = (char) (k[b] ^ 0x36);
+ memset (&buf[lk], 0x36, BLAKE2S_BLOCKSIZE - lk);
+
+ blake2s_update (ctx, (unsigned char *) buf, BLAKE2S_BLOCKSIZE);
+
+ /**** Precompute HMAC Outer Digest ****/
- /* perform outer RIPEMD-160 */
ctx = &(hmac.outer_digest_ctx);
- memset(k_pad, 0x5c, 64);
- for (i=0; i<keylen; i++)
- {
- k_pad[i] ^= key[i];
- }
+ blake2s_init (ctx);
- RMD160Init(ctx); /* init context for 2nd pass */
- RMD160Update(ctx, k_pad, RIPEMD160_BLOCKSIZE); /* start with outer pad */
+ for (b = 0; b < lk; ++b)
+ buf[b] = (char) (k[b] ^ 0x5C);
+ memset (&buf[lk], 0x5C, SHA256_BLOCKSIZE - lk);
- hmac_ripemd160_internal (input_digest, len, &hmac);
+ blake2s_update (ctx, (unsigned char *) buf, BLAKE2S_BLOCKSIZE);
- burn (&hmac, sizeof(hmac));
- burn (tk, sizeof(tk));
-}
+ hmac_blake2s_internal(d, ld, &hmac);
+
+#if defined (DEVICE_DRIVER)
+ if (NT_SUCCESS (saveStatus))
+#ifdef _WIN64
+ KeRestoreExtendedProcessorStateVC(&SaveState);
+#else
+ KeRestoreFloatingPointState (&floatingPointState);
+#endif
#endif
+ /* Prevent leaks */
+ burn(&hmac, sizeof(hmac));
+ burn(key, sizeof(key));
+}
+#endif
-static void derive_u_ripemd160 (char *salt, int salt_len, uint32 iterations, int b, hmac_ripemd160_ctx* hmac)
+static void derive_u_blake2s (char *salt, int salt_len, uint32 iterations, int b, hmac_blake2s_ctx* hmac)
{
char* k = hmac->k;
char* u = hmac->u;
uint32 c;
- int i;
+ int i;
#ifdef TC_WINDOWS_BOOT
/* In bootloader mode, least significant bit of iterations is a boolean (TRUE for boot derivation mode, FALSE otherwise)
@@ -653,11 +684,11 @@ static void derive_u_ripemd160 (char *salt, int salt_len, uint32 iterations, int
c = iterations >> 16;
i = ((int) iterations) & 0x01;
if (i)
- c = (c == 0)? 327661 : c << 11;
+ c = (c == 0)? 200000 : c << 11;
else
- c = (c == 0)? 655331 : 15000 + c * 1000;
+ c = (c == 0)? 500000 : 15000 + c * 1000;
#else
- c = iterations;
+ c = iterations;
#endif
/* iteration 1 */
@@ -665,7 +696,7 @@ static void derive_u_ripemd160 (char *salt, int salt_len, uint32 iterations, int
/* big-endian block number */
#ifdef TC_WINDOWS_BOOT
- /* specific case of 16-bit bootloader: b is a 16-bit integer that is always < 256*/
+ /* specific case of 16-bit bootloader: b is a 16-bit integer that is always < 256 */
memset (&k[salt_len], 0, 3);
k[salt_len + 3] = (char) b;
#else
@@ -673,14 +704,14 @@ static void derive_u_ripemd160 (char *salt, int salt_len, uint32 iterations, int
memcpy (&k[salt_len], &b, 4);
#endif
- hmac_ripemd160_internal (k, salt_len + 4, hmac);
- memcpy (u, k, RIPEMD160_DIGESTSIZE);
+ hmac_blake2s_internal (k, salt_len + 4, hmac);
+ memcpy (u, k, BLAKE2S_DIGESTSIZE);
/* remaining iterations */
- while ( c > 1)
+ while (c > 1)
{
- hmac_ripemd160_internal (k, RIPEMD160_DIGESTSIZE, hmac);
- for (i = 0; i < RIPEMD160_DIGESTSIZE; i++)
+ hmac_blake2s_internal (k, BLAKE2S_DIGESTSIZE, hmac);
+ for (i = 0; i < BLAKE2S_DIGESTSIZE; i++)
{
u[i] ^= k[i];
}
@@ -688,86 +719,107 @@ static void derive_u_ripemd160 (char *salt, int salt_len, uint32 iterations, int
}
}
-void derive_key_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, char *dk, int dklen)
+
+void derive_key_blake2s (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, char *dk, int dklen)
{
+ hmac_blake2s_ctx hmac;
+ blake2s_state* ctx;
+ char* buf = hmac.k;
int b, l, r;
- hmac_ripemd160_ctx hmac;
- RMD160_CTX* ctx;
- unsigned char* k_pad = (unsigned char*) hmac.k;
#ifndef TC_WINDOWS_BOOT
- unsigned char tk[RIPEMD160_DIGESTSIZE];
+ char key[BLAKE2S_DIGESTSIZE];
+#if defined (DEVICE_DRIVER)
+ NTSTATUS saveStatus = STATUS_INVALID_PARAMETER;
+#ifdef _WIN64
+ XSTATE_SAVE SaveState;
+ if (IsCpuIntel() && HasSAVX())
+ saveStatus = KeSaveExtendedProcessorStateVC(XSTATE_MASK_GSSE, &SaveState);
+#else
+ KFLOATING_SAVE floatingPointState;
+ if (HasSSE2())
+ saveStatus = KeSaveFloatingPointState (&floatingPointState);
+#endif
+#endif
/* If the password is longer than the hash algorithm block size,
- let password = ripemd160(password), as per HMAC specifications. */
- if (pwd_len > RIPEMD160_BLOCKSIZE)
+ let pwd = blake2s(pwd), as per HMAC specifications. */
+ if (pwd_len > BLAKE2S_BLOCKSIZE)
{
- RMD160_CTX tctx;
+ blake2s_state tctx;
- RMD160Init(&tctx);
- RMD160Update(&tctx, (const unsigned char *) pwd, pwd_len);
- RMD160Final(tk, &tctx);
+ blake2s_init (&tctx);
+ blake2s_update (&tctx, pwd, pwd_len);
+ blake2s_final (&tctx, (unsigned char *) key);
- pwd = (char *) tk;
- pwd_len = RIPEMD160_DIGESTSIZE;
+ pwd = key;
+ pwd_len = SHA256_DIGESTSIZE;
- burn (&tctx, sizeof(tctx)); // Prevent leaks
- }
+ burn (&tctx, sizeof(tctx)); // Prevent leaks
+ }
#endif
- if (dklen % RIPEMD160_DIGESTSIZE)
+ if (dklen % BLAKE2S_DIGESTSIZE)
{
- l = 1 + dklen / RIPEMD160_DIGESTSIZE;
+ l = 1 + dklen / BLAKE2S_DIGESTSIZE;
}
else
{
- l = dklen / RIPEMD160_DIGESTSIZE;
+ l = dklen / BLAKE2S_DIGESTSIZE;
}
- r = dklen - (l - 1) * RIPEMD160_DIGESTSIZE;
+ r = dklen - (l - 1) * BLAKE2S_DIGESTSIZE;
+
+ /**** Precompute HMAC Inner Digest ****/
- /* perform inner RIPEMD-160 */
ctx = &(hmac.inner_digest_ctx);
- /* start out by storing key in pads */
- memset(k_pad, 0x36, 64);
- /* XOR key with ipad and opad values */
- for (b=0; b<pwd_len; b++)
- {
- k_pad[b] ^= pwd[b];
- }
+ blake2s_init (ctx);
+
+ /* Pad the key for inner digest */
+ for (b = 0; b < pwd_len; ++b)
+ buf[b] = (char) (pwd[b] ^ 0x36);
+ memset (&buf[pwd_len], 0x36, BLAKE2S_BLOCKSIZE - pwd_len);
+
+ blake2s_update (ctx, buf, BLAKE2S_BLOCKSIZE);
- RMD160Init(ctx); /* init context for 1st pass */
- RMD160Update(ctx, k_pad, RIPEMD160_BLOCKSIZE); /* start with inner pad */
+ /**** Precompute HMAC Outer Digest ****/
- /* perform outer RIPEMD-160 */
ctx = &(hmac.outer_digest_ctx);
- memset(k_pad, 0x5c, 64);
- for (b=0; b<pwd_len; b++)
- {
- k_pad[b] ^= pwd[b];
- }
+ blake2s_init (ctx);
+
+ for (b = 0; b < pwd_len; ++b)
+ buf[b] = (char) (pwd[b] ^ 0x5C);
+ memset (&buf[pwd_len], 0x5C, BLAKE2S_BLOCKSIZE - pwd_len);
- RMD160Init(ctx); /* init context for 2nd pass */
- RMD160Update(ctx, k_pad, RIPEMD160_BLOCKSIZE); /* start with outer pad */
+ blake2s_update (ctx, buf, BLAKE2S_BLOCKSIZE);
/* first l - 1 blocks */
for (b = 1; b < l; b++)
{
- derive_u_ripemd160 (salt, salt_len, iterations, b, &hmac);
- memcpy (dk, hmac.u, RIPEMD160_DIGESTSIZE);
- dk += RIPEMD160_DIGESTSIZE;
+ derive_u_blake2s (salt, salt_len, iterations, b, &hmac);
+ memcpy (dk, hmac.u, BLAKE2S_DIGESTSIZE);
+ dk += BLAKE2S_DIGESTSIZE;
}
/* last block */
- derive_u_ripemd160 (salt, salt_len, iterations, b, &hmac);
+ derive_u_blake2s (salt, salt_len, iterations, b, &hmac);
memcpy (dk, hmac.u, r);
+#if defined (DEVICE_DRIVER)
+ if (NT_SUCCESS (saveStatus))
+#ifdef _WIN64
+ KeRestoreExtendedProcessorStateVC(&SaveState);
+#else
+ KeRestoreFloatingPointState (&floatingPointState);
+#endif
+#endif
/* Prevent possible leaks. */
burn (&hmac, sizeof(hmac));
#ifndef TC_WINDOWS_BOOT
- burn (tk, sizeof(tk));
+ burn (key, sizeof(key));
#endif
}
-#endif // TC_WINDOWS_BOOT
+
+#endif
#ifndef TC_WINDOWS_BOOT
@@ -1210,8 +1262,8 @@ wchar_t *get_pkcs5_prf_name (int pkcs5_prf_id)
case SHA256:
return L"HMAC-SHA-256";
- case RIPEMD160:
- return L"HMAC-RIPEMD-160";
+ case BLAKE2S:
+ return L"HMAC-BLAKE2s-256";
case WHIRLPOOL:
return L"HMAC-Whirlpool";
@@ -1238,11 +1290,11 @@ int get_pkcs5_iteration_count (int pkcs5_prf_id, int pim, BOOL truecryptMode, BO
switch (pkcs5_prf_id)
{
- case RIPEMD160:
+ case BLAKE2S:
if (truecryptMode)
- return bBoot ? 1000 : 2000;
+ return 0; // BLAKE2s not supported by TrueCrypt
else if (pim == 0)
- return bBoot? 327661 : 655331;
+ return bBoot? 200000 : 500000;
else
{
return bBoot? pim * 2048 : 15000 + pim * 1000;
@@ -1290,14 +1342,14 @@ int is_pkcs5_prf_supported (int pkcs5_prf_id, BOOL truecryptMode, PRF_BOOT_TYPE
if (truecryptMode)
{
if ( (bootType == PRF_BOOT_GPT)
- || (bootType == PRF_BOOT_MBR && pkcs5_prf_id != RIPEMD160)
- || (bootType == PRF_BOOT_NO && pkcs5_prf_id != SHA512 && pkcs5_prf_id != WHIRLPOOL && pkcs5_prf_id != RIPEMD160)
+ || (bootType == PRF_BOOT_MBR)
+ || (bootType == PRF_BOOT_NO && pkcs5_prf_id != SHA512 && pkcs5_prf_id != WHIRLPOOL)
)
return 0;
}
else
{
- if ( (bootType == PRF_BOOT_MBR && pkcs5_prf_id != RIPEMD160 && pkcs5_prf_id != SHA256)
+ if ( (bootType == PRF_BOOT_MBR && pkcs5_prf_id != BLAKE2S && pkcs5_prf_id != SHA256)
|| (bootType != PRF_BOOT_MBR && (pkcs5_prf_id < FIRST_PRF_ID || pkcs5_prf_id > LAST_PRF_ID))
)
return 0;
diff --git a/src/Common/Pkcs5.h b/src/Common/Pkcs5.h
index 98d8bf74..4a6b6882 100644
--- a/src/Common/Pkcs5.h
+++ b/src/Common/Pkcs5.h
@@ -20,9 +20,9 @@
extern "C"
{
#endif
-/* output written to input_digest which must be at lease 20 bytes long */
-void hmac_ripemd160 (char *key, int keylen, char *input_digest, int len);
-void derive_key_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, char *dk, int dklen);
+/* output written to input_digest which must be at lease 32 bytes long */
+void hmac_blake2s (char *key, int keylen, char *input_digest, int len);
+void derive_key_blake2s (char *pwd, int pwd_len, char *salt, int salt_len, uint32 iterations, char *dk, int dklen);
/* output written to d which must be at lease 32 bytes long */
void hmac_sha256 (char *k, int lk, char *d, int ld);
diff --git a/src/Common/Random.c b/src/Common/Random.c
index 1080ce7e..c44c69d7 100644
--- a/src/Common/Random.c
+++ b/src/Common/Random.c
@@ -263,7 +263,7 @@ BOOL Randmix ()
{
unsigned char hashOutputBuffer [MAX_DIGESTSIZE];
WHIRLPOOL_CTX wctx;
- RMD160_CTX rctx;
+ blake2s_state bctx;
sha512_ctx sctx;
sha256_ctx s256ctx;
STREEBOG_CTX stctx;
@@ -271,8 +271,8 @@ BOOL Randmix ()
switch (HashFunction)
{
- case RIPEMD160:
- digestSize = RIPEMD160_DIGESTSIZE;
+ case BLAKE2S:
+ digestSize = BLAKE2S_DIGESTSIZE;
break;
case SHA512:
@@ -303,10 +303,10 @@ BOOL Randmix ()
/* Compute the message digest of the entire pool using the selected hash function. */
switch (HashFunction)
{
- case RIPEMD160:
- RMD160Init(&rctx);
- RMD160Update(&rctx, pRandPool, RNG_POOL_SIZE);
- RMD160Final(hashOutputBuffer, &rctx);
+ case BLAKE2S:
+ blake2s_init(&bctx);
+ blake2s_update(&bctx, pRandPool, RNG_POOL_SIZE);
+ blake2s_final(&bctx, hashOutputBuffer);
break;
case SHA512:
@@ -349,8 +349,8 @@ BOOL Randmix ()
burn (hashOutputBuffer, MAX_DIGESTSIZE);
switch (HashFunction)
{
- case RIPEMD160:
- burn (&rctx, sizeof(rctx));
+ case BLAKE2S:
+ burn (&bctx, sizeof(bctx));
break;
case SHA512:
diff --git a/src/Common/Random.h b/src/Common/Random.h
index 88dd041b..68758782 100644
--- a/src/Common/Random.h
+++ b/src/Common/Random.h
@@ -21,7 +21,7 @@ extern "C" {
/* RNG defines & pool pointers */
#define RNG_POOL_SIZE 320 // Must be divisible by the size of the output of each of the implemented hash functions. (in bytes)
-#if RNG_POOL_SIZE % SHA512_DIGESTSIZE || RNG_POOL_SIZE % WHIRLPOOL_DIGESTSIZE || RNG_POOL_SIZE % RIPEMD160_DIGESTSIZE
+#if RNG_POOL_SIZE % SHA512_DIGESTSIZE || RNG_POOL_SIZE % WHIRLPOOL_DIGESTSIZE || RNG_POOL_SIZE % BLAKE2S_DIGESTSIZE
#error RNG_POOL_SIZE must be divisible by the size of the output of each of the implemented hash functions.
#endif
diff --git a/src/Common/Tcdefs.h b/src/Common/Tcdefs.h
index d7dc73d2..eb8fefdc 100644
--- a/src/Common/Tcdefs.h
+++ b/src/Common/Tcdefs.h
@@ -52,24 +52,30 @@ extern unsigned short _rotl16(unsigned short value, unsigned char shift);
#endif // defined(_UEFI)
+#ifdef TC_WINDOWS_BOOT
+#include <stddef.h>
+#endif
+
#define TC_APP_NAME "VeraCrypt"
// Version displayed to user
-#define VERSION_STRING "1.25.4"
+#define VERSION_STRING "1.26"
#ifdef VC_EFI_CUSTOM_MODE
#define VERSION_STRING_SUFFIX "-CustomEFI"
+#elif defined(VC_SKIP_OS_DRIVER_REQ_CHECK)
+#define VERSION_STRING_SUFFIX "-TESTSIGNING"
#else
#define VERSION_STRING_SUFFIX ""
#endif
// Version number to compare against driver
-#define VERSION_NUM 0x0125
+#define VERSION_NUM 0x0126
// Release date
-#define TC_STR_RELEASE_DATE L"December 3, 2021"
-#define TC_RELEASE_DATE_YEAR 2021
-#define TC_RELEASE_DATE_MONTH 12
+#define TC_STR_RELEASE_DATE L"March 21, 2022"
+#define TC_RELEASE_DATE_YEAR 2022
+#define TC_RELEASE_DATE_MONTH 03
#define BYTES_PER_KB 1024LL
#define BYTES_PER_MB 1048576LL
@@ -90,6 +96,7 @@ typedef __int8 int8;
typedef __int16 int16;
typedef __int32 int32;
typedef unsigned __int8 byte;
+typedef unsigned __int8 uint8;
typedef unsigned __int16 uint16;
typedef unsigned __int32 uint32;
@@ -116,6 +123,7 @@ typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint8_t byte;
+typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
diff --git a/src/Common/Tests.c b/src/Common/Tests.c
index a66c7b54..4f53d4ed 100644
--- a/src/Common/Tests.c
+++ b/src/Common/Tests.c
@@ -374,27 +374,6 @@ CAMELLIA_TEST camellia_vectors[CAMELLIA_TEST_COUNT] = {
0xAD, 0x5C, 0x4D, 0x84
}
};
-#if defined(CIPHER_GOST89)
-// GOST89 ECB test vectors
-#define GOST89_TEST_COUNT 1
-
-typedef struct {
- unsigned char key[32];
- unsigned char plaintext[16];
- unsigned char ciphertext[16];
- } GOST89_TEST;
-
-GOST89_TEST gost89_vectors[GOST89_TEST_COUNT] = {
-{
- 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44,
- 0x33, 0x22, 0x11, 0x00, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
- 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xFE, 0xDC, 0xBA, 0x98,
- 0x76, 0x54, 0x32, 0x10, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88,
- 0x8F, 0xC6, 0xFE, 0xB8, 0x91, 0x51, 0x4C, 0x37, 0x4D, 0x51, 0x46, 0xEF,
- 0x02, 0x9D, 0xBD, 0x9F
-}
-};
-#endif
// Kuznyechik ECB test vectors
#define KUZNYECHIK_TEST_COUNT 4
@@ -503,22 +482,34 @@ char *hmac_sha512_test_vectors[] =
"\xe3\x7b\x6a\x77\x5d\xc8\x7d\xba\xa4\xdf\xa9\xf9\x6e\x5e\x3f\xfd\xde\xbd\x71\xf8\x86\x72\x89\x86\x5d\xf5\xa3\x2d\x20\xcd\xc9\x44\xb6\x02\x2c\xac\x3c\x49\x82\xb1\x0d\x5e\xeb\x55\xc3\xe4\xde\x15\x13\x46\x76\xfb\x6d\xe0\x44\x60\x65\xc9\x74\x40\xfa\x8c\x6a\x58",
};
-char *hmac_ripemd160_test_keys[] =
+char *hmac_blake2s_test_keys[] =
{
- "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x01\x23\x45\x67",
- "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10\x00\x11\x22\x33",
+ "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b",
+ "Jefe",
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
+ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19",
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
+ "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa",
};
-char *hmac_ripemd160_test_data[] =
+char *hmac_blake2s_test_data[] =
{
- "message digest",
- "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "Hi There",
+ "what do ya want for nothing?",
+ "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd",
+ "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd",
+ "Test Using Larger Than Block-Size Key - Hash Key First",
+ "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
};
-char *hmac_ripemd160_test_vectors[] =
+char *hmac_blake2s_test_vectors[] =
{
- "\xf8\x36\x62\xcc\x8d\x33\x9c\x22\x7e\x60\x0f\xcd\x63\x6c\x57\xd2\x57\x1b\x1c\x34",
- "\x85\xf1\x64\x70\x3e\x61\xa6\x31\x31\xbe\x7e\x45\x95\x8e\x07\x94\x12\x39\x04\xf9",
+ "\x65\xa8\xb7\xc5\xcc\x91\x36\xd4\x24\xe8\x2c\x37\xe2\x70\x7e\x74\xe9\x13\xc0\x65\x5b\x99\xc7\x5f\x40\xed\xf3\x87\x45\x3a\x32\x60",
+ "\x90\xb6\x28\x1e\x2f\x30\x38\xc9\x05\x6a\xf0\xb4\xa7\xe7\x63\xca\xe6\xfe\x5d\x9e\xb4\x38\x6a\x0e\xc9\x52\x37\x89\x0c\x10\x4f\xf0",
+ "\xfc\xc4\xf5\x95\x29\x50\x2e\x34\xc3\xd8\xda\x3f\xfd\xab\x82\x96\x6a\x2c\xb6\x37\xff\x5e\x9b\xd7\x01\x13\x5c\x2e\x94\x69\xe7\x90",
+ "\x46\x44\x34\xdc\xbe\xce\x09\x5d\x45\x6a\x1d\x62\xd6\xec\x56\xf8\x98\xe6\x25\xa3\x9e\x5c\x52\xbd\xf9\x4d\xaf\x11\x1b\xad\x83\xaa",
+ "\xd2\x3d\x79\x39\x4f\x53\xd5\x36\xa0\x96\xe6\x51\x44\x47\xee\xaa\xbb\x05\xde\xd0\x1b\xe3\x2c\x19\x37\xda\x6a\x8f\x71\x03\xbc\x4e",
+ "\xcb\x60\xf6\xa7\x91\xf1\x40\xbf\x8a\xa2\xe5\x1f\xf3\x58\xcd\xb2\xcc\x5c\x03\x33\x04\x5b\x7f\xb7\x7a\xba\x7a\xb3\xb0\xcf\xb2\x37",
};
char *hmac_whirlpool_test_key =
@@ -628,6 +619,32 @@ HashTestVector Streebog512TestVectors[] = {
{NULL, NULL}
};
+/* https://github.com/openssl/openssl/blob/2d0b44126763f989a4cbffbffe9d0c7518158bb7/test/evptests.txt */
+HashTestVector Blake2sTestVectors[] = {
+ {"",
+ "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9"
+ },
+ {"61",
+ "4a0d129873403037c2cd9b9048203687f6233fb6738956e0349bd4320fec3e90"
+ },
+ {"616263",
+ "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982"
+ },
+ {"6d65737361676520646967657374",
+ "fa10ab775acf89b7d3c8a6e823d586f6b67bdbac4ce207fe145b7d3ac25cd28c"
+ },
+ {"6162636465666768696a6b6c6d6e6f707172737475767778797a",
+ "bdf88eb1f86a0cdf0e840ba88fa118508369df186c7355b4b16cf79fa2710a12"
+ },
+ {"4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a30313233343536373839",
+ "c75439ea17e1de6fa4510c335dc3d3f343e6f9e1ce2773e25b4174f1df8b119b"
+ },
+ {"3132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930313233343536373839303132333435363738393031323334353637383930",
+ "fdaedb290a0d5af9870864fec2e090200989dc9cd53a3c092129e8535e8b4f66"
+ },
+ {NULL, NULL}
+};
+
unsigned char ks_tmp[MAX_EXPANDED_KEY];
void CipherInit2(int cipher, void* key, void* ks, int key_len)
@@ -650,11 +667,6 @@ void CipherInit2(int cipher, void* key, void* ks, int key_len)
case CAMELLIA:
CipherInit(cipher,key,ks);
break;
-#if defined(CIPHER_GOST89)
- case GOST89:
- CipherInit(cipher,key,ks);
- break;
-#endif // defined(CIPHER_GOST89)
case KUZNYECHIK:
CipherInit(cipher, key, ks);
break;
@@ -850,34 +862,6 @@ BOOL TestSectorBufEncryption (PCRYPTO_INFO ci)
break;
}
}
-#if defined(CIPHER_GOST89)
- else if (wcscmp (name, L"GOST89") == 0)
- {
- switch (testCase)
- {
- case 0:
- if (crc != 0x12194ef5)
- return FALSE;
- nTestsPerformed++;
- break;
- case 1:
- if (crc != 0xda8d429b)
- return FALSE;
- nTestsPerformed++;
- break;
- case 2:
- if (crc != 0xdbf0b12e)
- return FALSE;
- nTestsPerformed++;
- break;
- case 3:
- if (crc != 0xb986eb4a)
- return FALSE;
- nTestsPerformed++;
- break;
- }
- }
-#endif
else if (wcscmp (name, L"Kuznyechik") == 0)
{
switch (testCase)
@@ -1234,14 +1218,6 @@ BOOL TestSectorBufEncryption (PCRYPTO_INFO ci)
return FALSE;
nTestsPerformed++;
}
-#if defined(CIPHER_GOST89)
- else if (wcscmp (name, L"GOST89") == 0)
- {
- if (crc != 0x9e8653cb)
- return FALSE;
- nTestsPerformed++;
- }
-#endif
else if (wcscmp (name, L"Kuznyechik") == 0)
{
if (crc != 0xd6d39cdb)
@@ -1319,11 +1295,7 @@ BOOL TestSectorBufEncryption (PCRYPTO_INFO ci)
nTestsPerformed++;
}
-#if defined(CIPHER_GOST89)
- return (nTestsPerformed == 160);
-#else
- return (nTestsPerformed == 155);
-#endif
+ return (nTestsPerformed == 150);
}
static BOOL DoAutoTestAlgorithms (void)
@@ -1466,28 +1438,6 @@ static BOOL DoAutoTestAlgorithms (void)
if (i != KUZNYECHIK_TEST_COUNT)
bFailed = TRUE;
-#if defined(CIPHER_GOST89)
- /* GOST89 */
-
- for (i = 0; i < GOST89_TEST_COUNT; i++)
- {
- int cipher = GOST89;
- memcpy(key, gost89_vectors[i].key, 32);
- memcpy(tmp, gost89_vectors[i].plaintext, 16);
- gost_set_key(key, (gost_kds*)ks_tmp, 0);
-
- EncipherBlock(cipher, tmp, ks_tmp);
- if (memcmp(gost89_vectors[i].ciphertext, tmp, 16) != 0)
- break;
-
- DecipherBlock(cipher, tmp, ks_tmp);
- if (memcmp(gost89_vectors[i].plaintext, tmp, 16) != 0)
- break;
- }
- if (i != GOST89_TEST_COUNT)
- bFailed = TRUE;
-#endif
-
/* PKCS #5 and HMACs */
if (!test_pkcs5 ())
bFailed = TRUE;
@@ -1569,12 +1519,20 @@ BOOL test_hmac_sha256 ()
for (i = 0; i < sizeof (hmac_sha256_test_data) / sizeof(char *); i++)
{
char digest[1024]; /* large enough to hold digets and test vector inputs */
- memcpy (digest, hmac_sha256_test_data[i], strlen (hmac_sha256_test_data[i]));
- hmac_sha256 (hmac_sha256_test_keys[i], (int) strlen (hmac_sha256_test_keys[i]), digest, (int) strlen (hmac_sha256_test_data[i]));
- if (memcmp (digest, hmac_sha256_test_vectors[i], SHA256_DIGESTSIZE) != 0)
- return FALSE;
+ size_t dataLen = strlen (hmac_sha256_test_data[i]);
+ if (dataLen <= sizeof(digest))
+ {
+ memcpy (digest, hmac_sha256_test_data[i], dataLen);
+ hmac_sha256 (hmac_sha256_test_keys[i], (int) strlen (hmac_sha256_test_keys[i]), digest, (int) dataLen);
+ if (memcmp (digest, hmac_sha256_test_vectors[i], SHA256_DIGESTSIZE) != 0)
+ return FALSE;
+ else
+ nTestsPerformed++;
+ }
else
- nTestsPerformed++;
+ {
+ return FALSE;
+ }
}
return (nTestsPerformed == 6);
@@ -1588,34 +1546,56 @@ BOOL test_hmac_sha512 ()
for (i = 0; i < sizeof (hmac_sha512_test_data) / sizeof(char *); i++)
{
char digest[1024]; /* large enough to hold digets and test vector inputs */
- memcpy (digest, hmac_sha512_test_data[i], (int) strlen (hmac_sha512_test_data[i]));
- hmac_sha512 (hmac_sha512_test_keys[i], (int) strlen (hmac_sha512_test_keys[i]), digest, (int) strlen (hmac_sha512_test_data[i]));
- if (memcmp (digest, hmac_sha512_test_vectors[i], SHA512_DIGESTSIZE) != 0)
- return FALSE;
+ size_t dataLen = strlen (hmac_sha512_test_data[i]);
+ if (dataLen <= sizeof(digest))
+ {
+ memcpy (digest, hmac_sha512_test_data[i], dataLen );
+ hmac_sha512 (hmac_sha512_test_keys[i], (int) strlen (hmac_sha512_test_keys[i]), digest, (int) dataLen);
+ if (memcmp (digest, hmac_sha512_test_vectors[i], SHA512_DIGESTSIZE) != 0)
+ return FALSE;
+ else
+ nTestsPerformed++;
+ }
else
- nTestsPerformed++;
+ {
+ return FALSE;
+ }
}
return (nTestsPerformed == 6);
}
-BOOL test_hmac_ripemd160 ()
+BOOL test_hmac_blake2s ()
{
- int nTestsPerformed = 0;
unsigned int i;
+ int nTestsPerformed = 0;
- for (i = 0; i < sizeof (hmac_ripemd160_test_data) / sizeof(char *); i++)
+ for (i = 0; i < sizeof (hmac_blake2s_test_data) / sizeof(char *); i++)
{
char digest[1024]; /* large enough to hold digets and test vector inputs */
- memcpy (digest, hmac_ripemd160_test_data[i], strlen (hmac_ripemd160_test_data[i]));
- hmac_ripemd160 (hmac_ripemd160_test_keys[i], RIPEMD160_DIGESTSIZE, digest, (int) strlen (hmac_ripemd160_test_data[i]));
- if (memcmp (digest, hmac_ripemd160_test_vectors[i], RIPEMD160_DIGESTSIZE) != 0)
- return FALSE;
+ size_t dataLen = strlen (hmac_blake2s_test_data[i]);
+ if (dataLen <= sizeof(digest))
+ {
+ memcpy (digest, hmac_blake2s_test_data[i], dataLen);
+ hmac_blake2s (hmac_blake2s_test_keys[i], (int) strlen (hmac_blake2s_test_keys[i]), digest, (int) dataLen);
+ if (memcmp (digest, hmac_blake2s_test_vectors[i], BLAKE2S_DIGESTSIZE) != 0)
+ return FALSE;
+ else
+ nTestsPerformed++;
+ }
else
- nTestsPerformed++;
+ {
+ return FALSE;
+ }
}
- return (nTestsPerformed == 2);
+ return (nTestsPerformed == 6);
+}
+
+int __cdecl Blake2sHash (unsigned char* input, unsigned long inputLen, unsigned char* output)
+{
+ blake2s(output, input, (size_t) inputLen);
+ return BLAKE2S_DIGESTSIZE;
}
BOOL test_hmac_whirlpool ()
@@ -1686,8 +1666,12 @@ BOOL test_pkcs5 ()
if (!test_hmac_sha512())
return FALSE;
- /* HMAC-RIPEMD-160 tests */
- if (test_hmac_ripemd160() == FALSE)
+ /* HMAC-BLAKE2s tests */
+ if (test_hmac_blake2s() == FALSE)
+ return FALSE;
+
+ /* Blake2s hash tests */
+ if (RunHashTest (Blake2sHash, Blake2sTestVectors, (HasSSE2())? TRUE : FALSE) == FALSE)
return FALSE;
/* HMAC-Whirlpool tests */
@@ -1733,14 +1717,14 @@ BOOL test_pkcs5 ()
if (memcmp (dk, "\x13\x64\xae\xf8\x0d\xf5\x57\x6c\x30\xd5\x71\x4c\xa7\x75\x3f\xfd\x00\xe5\x25\x8b\x39\xc7\x44\x7f\xce\x23\x3d\x08\x75\xe0\x2f\x48\xd6\x30\xd7\x00\xb6\x24\xdb\xe0\x5a\xd7\x47\xef\x52\xca\xa6\x34\x83\x47\xe5\xcb\xe9\x87\xf1\x20\x59\x6a\xe6\xa9\xcf\x51\x78\xc6\xb6\x23\xa6\x74\x0d\xe8\x91\xbe\x1a\xd0\x28\xcc\xce\x16\x98\x9a\xbe\xfb\xdc\x78\xc9\xe1\x7d\x72\x67\xce\xe1\x61\x56\x5f\x96\x68\xe6\xe1\xdd\xf4\xbf\x1b\x80\xe0\x19\x1c\xf4\xc4\xd3\xdd\xd5\xd5\x57\x2d\x83\xc7\xa3\x37\x87\xf4\x4e\xe0\xf6\xd8\x6d\x65\xdc\xa0\x52\xa3\x13\xbe\x81\xfc\x30\xbe\x7d\x69\x58\x34\xb6\xdd\x41\xc6", 144) != 0)
return FALSE;
- /* PKCS-5 test 1 with HMAC-RIPEMD-160 used as the PRF */
- derive_key_ripemd160 ("password", 8, "\x12\x34\x56\x78", 4, 5, dk, 4);
- if (memcmp (dk, "\x7a\x3d\x7c\x03", 4) != 0)
+ /* PKCS-5 test 1 with HMAC-BLAKE2s used as the PRF */
+ derive_key_blake2s ("password", 8, "\x12\x34\x56\x78", 4, 5, dk, 4);
+ if (memcmp (dk, "\x8d\x51\xfa\x31", 4) != 0)
return FALSE;
- /* PKCS-5 test 2 with HMAC-RIPEMD-160 used as the PRF (derives a key longer than the underlying hash) */
- derive_key_ripemd160 ("password", 8, "\x12\x34\x56\x78", 4, 5, dk, 48);
- if (memcmp (dk, "\x7a\x3d\x7c\x03\xe7\x26\x6b\xf8\x3d\x78\xfb\x29\xd2\x64\x1f\x56\xea\xf0\xe5\xf5\xcc\xc4\x3a\x31\xa8\x84\x70\xbf\xbd\x6f\x8e\x78\x24\x5a\xc0\x0a\xf6\xfa\xf0\xf6\xe9\x00\x47\x5f\x73\xce\xe1\x43", 48) != 0)
+ /* PKCS-5 test 2 with HMAC-BLAKE2s used as the PRF (derives a key longer than the underlying hash) */
+ derive_key_blake2s ("password", 8, "\x12\x34\x56\x78", 4, 5, dk, 48);
+ if (memcmp (dk, "\x8d\x51\xfa\x31\x46\x25\x37\x67\xa3\x29\x6b\x3c\x6b\xc1\x5d\xb2\xee\xe1\x6c\x28\x00\x26\xea\x08\x65\x9c\x12\xf1\x07\xde\x0d\xb9\x9b\x4f\x39\xfa\xc6\x80\x26\xb1\x8f\x8e\x48\x89\x85\x2d\x24\x2d", 48) != 0)
return FALSE;
/* PKCS-5 test 1 with HMAC-Whirlpool used as the PRF */
diff --git a/src/Common/Tests.h b/src/Common/Tests.h
index 6aff505f..356d54f4 100644
--- a/src/Common/Tests.h
+++ b/src/Common/Tests.h
@@ -19,7 +19,7 @@ extern unsigned char ks_tmp[MAX_EXPANDED_KEY];
void CipherInit2(int cipher, void* key, void* ks, int key_len);
BOOL test_hmac_sha512 (void);
-BOOL test_hmac_ripemd160 (void);
+BOOL test_hmac_blake2s (void);
BOOL test_hmac_whirlpool (void);
BOOL test_pkcs5 (void);
BOOL TestSectorBufEncryption ();
diff --git a/src/Common/Volumes.c b/src/Common/Volumes.c
index 7bfb8ec2..9590715e 100644
--- a/src/Common/Volumes.c
+++ b/src/Common/Volumes.c
@@ -27,6 +27,8 @@
#ifndef DEVICE_DRIVER
#include "Random.h"
+#else
+#include "cpu.h"
#endif
#endif // !defined(_UEFI)
@@ -283,7 +285,7 @@ int ReadVolumeHeader (BOOL bBoot, char *encryptedHeader, Password *password, int
*noOutstandingWorkItemEvent = CreateEvent (NULL, FALSE, TRUE, NULL);
if (!*noOutstandingWorkItemEvent)
{
- CloseHandle (keyDerivationCompletedEvent);
+ CloseHandle (*keyDerivationCompletedEvent);
TCfree (keyDerivationWorkItems);
TCfree(keyDerivationCompletedEvent);
TCfree(noOutstandingWorkItemEvent);
@@ -378,8 +380,8 @@ KeyReady: ;
switch (pkcs5_prf)
{
- case RIPEMD160:
- derive_key_ripemd160 (keyInfo->userKey, keyInfo->keyLength, keyInfo->salt,
+ case BLAKE2S:
+ derive_key_blake2s (keyInfo->userKey, keyInfo->keyLength, keyInfo->salt,
PKCS5_SALT_SIZE, keyInfo->noIterations, dk, GetMaxPkcs5OutSize());
break;
@@ -577,12 +579,22 @@ KeyReady: ;
memcpy (keyInfo->master_keydata, header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE);
#ifdef TC_WINDOWS_DRIVER
{
- RMD160_CTX ctx;
- RMD160Init (&ctx);
- RMD160Update (&ctx, keyInfo->master_keydata, MASTER_KEYDATA_SIZE);
- RMD160Update (&ctx, header, sizeof(header));
- RMD160Final (cryptoInfo->master_keydata_hash, &ctx);
+ blake2s_state ctx;
+#ifndef _WIN64
+ NTSTATUS saveStatus = STATUS_INVALID_PARAMETER;
+ KFLOATING_SAVE floatingPointState;
+ if (HasSSE2())
+ saveStatus = KeSaveFloatingPointState (&floatingPointState);
+#endif
+ blake2s_init (&ctx);
+ blake2s_update (&ctx, keyInfo->master_keydata, MASTER_KEYDATA_SIZE);
+ blake2s_update (&ctx, header, sizeof(header));
+ blake2s_final (&ctx, cryptoInfo->master_keydata_hash);
burn(&ctx, sizeof (ctx));
+#ifndef _WIN64
+ if (NT_SUCCESS (saveStatus))
+ KeRestoreFloatingPointState (&floatingPointState);
+#endif
}
#else
memcpy (cryptoInfo->master_keydata, keyInfo->master_keydata, MASTER_KEYDATA_SIZE);
@@ -709,7 +721,7 @@ int ReadVolumeHeader (BOOL bBoot, char *header, Password *password, int pim, PCR
derive_key_sha256 (password->Text, (int) password->Length, header + HEADER_SALT_OFFSET,
PKCS5_SALT_SIZE, iterations, dk, sizeof (dk));
#else
- derive_key_ripemd160 (password->Text, (int) password->Length, header + HEADER_SALT_OFFSET,
+ derive_key_blake2s (password->Text, (int) password->Length, header + HEADER_SALT_OFFSET,
PKCS5_SALT_SIZE, iterations, dk, sizeof (dk));
#endif
@@ -792,7 +804,7 @@ int ReadVolumeHeader (BOOL bBoot, char *header, Password *password, int pim, PCR
#ifdef TC_WINDOWS_BOOT_SHA2
cryptoInfo->pkcs5 = SHA256;
#else
- cryptoInfo->pkcs5 = RIPEMD160;
+ cryptoInfo->pkcs5 = BLAKE2S;
#endif
memcpy (dk, header + HEADER_MASTER_KEYDATA_OFFSET, sizeof (dk));
@@ -981,8 +993,8 @@ int CreateVolumeHeaderInMemory (HWND hwndDlg, BOOL bBoot, char *header, int ea,
PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
break;
- case RIPEMD160:
- derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
+ case BLAKE2S:
+ derive_key_blake2s (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt,
PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize());
break;
diff --git a/src/Common/lzma/7zTypes.h b/src/Common/lzma/7zTypes.h
new file mode 100644
index 00000000..fe4fde3f
--- /dev/null
+++ b/src/Common/lzma/7zTypes.h
@@ -0,0 +1,525 @@
+/* 7zTypes.h -- Basic types
+2021-12-25 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_TYPES_H
+#define __7Z_TYPES_H
+
+#ifdef _WIN32
+/* #include <windows.h> */
+#else
+#include <errno.h>
+#endif
+
+#include <stddef.h>
+
+#ifndef EXTERN_C_BEGIN
+#ifdef __cplusplus
+#define EXTERN_C_BEGIN extern "C" {
+#define EXTERN_C_END }
+#else
+#define EXTERN_C_BEGIN
+#define EXTERN_C_END
+#endif
+#endif
+
+EXTERN_C_BEGIN
+
+#define SZ_OK 0
+
+#define SZ_ERROR_DATA 1
+#define SZ_ERROR_MEM 2
+#define SZ_ERROR_CRC 3
+#define SZ_ERROR_UNSUPPORTED 4
+#define SZ_ERROR_PARAM 5
+#define SZ_ERROR_INPUT_EOF 6
+#define SZ_ERROR_OUTPUT_EOF 7
+#define SZ_ERROR_READ 8
+#define SZ_ERROR_WRITE 9
+#define SZ_ERROR_PROGRESS 10
+#define SZ_ERROR_FAIL 11
+#define SZ_ERROR_THREAD 12
+
+#define SZ_ERROR_ARCHIVE 16
+#define SZ_ERROR_NO_ARCHIVE 17
+
+typedef int SRes;
+
+
+#ifdef _MSC_VER
+ #if _MSC_VER > 1200
+ #define MY_ALIGN(n) __declspec(align(n))
+ #else
+ #define MY_ALIGN(n)
+ #endif
+#else
+ #define MY_ALIGN(n) __attribute__ ((aligned(n)))
+#endif
+
+
+#ifdef _WIN32
+
+/* typedef DWORD WRes; */
+typedef unsigned WRes;
+#define MY_SRes_HRESULT_FROM_WRes(x) HRESULT_FROM_WIN32(x)
+
+// #define MY_HRES_ERROR__INTERNAL_ERROR MY_SRes_HRESULT_FROM_WRes(ERROR_INTERNAL_ERROR)
+
+#else // _WIN32
+
+// #define ENV_HAVE_LSTAT
+typedef int WRes;
+
+// (FACILITY_ERRNO = 0x800) is 7zip's FACILITY constant to represent (errno) errors in HRESULT
+#define MY__FACILITY_ERRNO 0x800
+#define MY__FACILITY_WIN32 7
+#define MY__FACILITY__WRes MY__FACILITY_ERRNO
+
+#define MY_HRESULT_FROM_errno_CONST_ERROR(x) ((HRESULT)( \
+ ( (HRESULT)(x) & 0x0000FFFF) \
+ | (MY__FACILITY__WRes << 16) \
+ | (HRESULT)0x80000000 ))
+
+#define MY_SRes_HRESULT_FROM_WRes(x) \
+ ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : MY_HRESULT_FROM_errno_CONST_ERROR(x))
+
+// we call macro HRESULT_FROM_WIN32 for system errors (WRes) that are (errno)
+#define HRESULT_FROM_WIN32(x) MY_SRes_HRESULT_FROM_WRes(x)
+
+/*
+#define ERROR_FILE_NOT_FOUND 2L
+#define ERROR_ACCESS_DENIED 5L
+#define ERROR_NO_MORE_FILES 18L
+#define ERROR_LOCK_VIOLATION 33L
+#define ERROR_FILE_EXISTS 80L
+#define ERROR_DISK_FULL 112L
+#define ERROR_NEGATIVE_SEEK 131L
+#define ERROR_ALREADY_EXISTS 183L
+#define ERROR_DIRECTORY 267L
+#define ERROR_TOO_MANY_POSTS 298L
+
+#define ERROR_INTERNAL_ERROR 1359L
+#define ERROR_INVALID_REPARSE_DATA 4392L
+#define ERROR_REPARSE_TAG_INVALID 4393L
+#define ERROR_REPARSE_TAG_MISMATCH 4394L
+*/
+
+// we use errno equivalents for some WIN32 errors:
+
+#define ERROR_INVALID_PARAMETER EINVAL
+#define ERROR_INVALID_FUNCTION EINVAL
+#define ERROR_ALREADY_EXISTS EEXIST
+#define ERROR_FILE_EXISTS EEXIST
+#define ERROR_PATH_NOT_FOUND ENOENT
+#define ERROR_FILE_NOT_FOUND ENOENT
+#define ERROR_DISK_FULL ENOSPC
+// #define ERROR_INVALID_HANDLE EBADF
+
+// we use FACILITY_WIN32 for errors that has no errno equivalent
+// Too many posts were made to a semaphore.
+#define ERROR_TOO_MANY_POSTS ((HRESULT)0x8007012AL)
+#define ERROR_INVALID_REPARSE_DATA ((HRESULT)0x80071128L)
+#define ERROR_REPARSE_TAG_INVALID ((HRESULT)0x80071129L)
+
+// if (MY__FACILITY__WRes != FACILITY_WIN32),
+// we use FACILITY_WIN32 for COM errors:
+#define E_OUTOFMEMORY ((HRESULT)0x8007000EL)
+#define E_INVALIDARG ((HRESULT)0x80070057L)
+#define MY__E_ERROR_NEGATIVE_SEEK ((HRESULT)0x80070083L)
+
+/*
+// we can use FACILITY_ERRNO for some COM errors, that have errno equivalents:
+#define E_OUTOFMEMORY MY_HRESULT_FROM_errno_CONST_ERROR(ENOMEM)
+#define E_INVALIDARG MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL)
+#define MY__E_ERROR_NEGATIVE_SEEK MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL)
+*/
+
+// gcc / clang : (sizeof(long) == sizeof(void*)) in 32/64 bits
+typedef long INT_PTR;
+typedef unsigned long UINT_PTR;
+
+#define TEXT(quote) quote
+
+#define FILE_ATTRIBUTE_READONLY 0x0001
+#define FILE_ATTRIBUTE_HIDDEN 0x0002
+#define FILE_ATTRIBUTE_SYSTEM 0x0004
+#define FILE_ATTRIBUTE_DIRECTORY 0x0010
+#define FILE_ATTRIBUTE_ARCHIVE 0x0020
+#define FILE_ATTRIBUTE_DEVICE 0x0040
+#define FILE_ATTRIBUTE_NORMAL 0x0080
+#define FILE_ATTRIBUTE_TEMPORARY 0x0100
+#define FILE_ATTRIBUTE_SPARSE_FILE 0x0200
+#define FILE_ATTRIBUTE_REPARSE_POINT 0x0400
+#define FILE_ATTRIBUTE_COMPRESSED 0x0800
+#define FILE_ATTRIBUTE_OFFLINE 0x1000
+#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x2000
+#define FILE_ATTRIBUTE_ENCRYPTED 0x4000
+
+#define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000 /* trick for Unix */
+
+#endif
+
+
+#ifndef RINOK
+#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
+#endif
+
+#ifndef RINOK_WRes
+#define RINOK_WRes(x) { WRes __result__ = (x); if (__result__ != 0) return __result__; }
+#endif
+
+typedef unsigned char Byte;
+typedef short Int16;
+typedef unsigned short UInt16;
+
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef long Int32;
+typedef unsigned long UInt32;
+#else
+typedef int Int32;
+typedef unsigned int UInt32;
+#endif
+
+
+#ifndef _WIN32
+
+typedef int INT;
+typedef Int32 INT32;
+typedef unsigned int UINT;
+typedef UInt32 UINT32;
+typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit for _WIN32 compatibility
+typedef UINT32 ULONG;
+
+#undef DWORD
+typedef UINT32 DWORD;
+
+#define VOID void
+
+#define HRESULT LONG
+
+typedef void *LPVOID;
+// typedef void VOID;
+// typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
+// gcc / clang on Unix : sizeof(long==sizeof(void*) in 32 or 64 bits)
+typedef long INT_PTR;
+typedef unsigned long UINT_PTR;
+typedef long LONG_PTR;
+typedef unsigned long DWORD_PTR;
+
+typedef size_t SIZE_T;
+
+#endif // _WIN32
+
+
+#define MY_HRES_ERROR__INTERNAL_ERROR ((HRESULT)0x8007054FL)
+
+
+#ifdef _SZ_NO_INT_64
+
+/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
+ NOTES: Some code will work incorrectly in that case! */
+
+typedef long Int64;
+typedef unsigned long UInt64;
+
+#else
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#define UINT64_CONST(n) n
+#else
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+#define UINT64_CONST(n) n ## ULL
+#endif
+
+#endif
+
+#ifdef _LZMA_NO_SYSTEM_SIZE_T
+typedef UInt32 SizeT;
+#else
+typedef size_t SizeT;
+#endif
+
+typedef int BoolInt;
+/* typedef BoolInt Bool; */
+#define True 1
+#define False 0
+
+
+#ifdef _WIN32
+#define MY_STD_CALL __stdcall
+#else
+#define MY_STD_CALL
+#endif
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1300
+#define MY_NO_INLINE __declspec(noinline)
+#else
+#define MY_NO_INLINE
+#endif
+
+#define MY_FORCE_INLINE __forceinline
+
+#define MY_CDECL __cdecl
+#define MY_FAST_CALL __fastcall
+
+#else // _MSC_VER
+
+#if (defined(__GNUC__) && (__GNUC__ >= 4)) \
+ || (defined(__clang__) && (__clang_major__ >= 4)) \
+ || defined(__INTEL_COMPILER) \
+ || defined(__xlC__)
+#define MY_NO_INLINE __attribute__((noinline))
+// #define MY_FORCE_INLINE __attribute__((always_inline)) inline
+#else
+#define MY_NO_INLINE
+#endif
+
+#define MY_FORCE_INLINE
+
+
+#define MY_CDECL
+
+#if defined(_M_IX86) \
+ || defined(__i386__)
+// #define MY_FAST_CALL __attribute__((fastcall))
+// #define MY_FAST_CALL __attribute__((cdecl))
+#define MY_FAST_CALL
+#elif defined(MY_CPU_AMD64)
+// #define MY_FAST_CALL __attribute__((ms_abi))
+#define MY_FAST_CALL
+#else
+#define MY_FAST_CALL
+#endif
+
+#endif // _MSC_VER
+
+
+/* The following interfaces use first parameter as pointer to structure */
+
+typedef struct IByteIn IByteIn;
+struct IByteIn
+{
+ Byte (*Read)(const IByteIn *p); /* reads one byte, returns 0 in case of EOF or error */
+};
+#define IByteIn_Read(p) (p)->Read(p)
+
+
+typedef struct IByteOut IByteOut;
+struct IByteOut
+{
+ void (*Write)(const IByteOut *p, Byte b);
+};
+#define IByteOut_Write(p, b) (p)->Write(p, b)
+
+
+typedef struct ISeqInStream ISeqInStream;
+struct ISeqInStream
+{
+ SRes (*Read)(const ISeqInStream *p, void *buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) < input(*size)) is allowed */
+};
+#define ISeqInStream_Read(p, buf, size) (p)->Read(p, buf, size)
+
+/* it can return SZ_ERROR_INPUT_EOF */
+SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size);
+SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType);
+SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf);
+
+
+typedef struct ISeqOutStream ISeqOutStream;
+struct ISeqOutStream
+{
+ size_t (*Write)(const ISeqOutStream *p, const void *buf, size_t size);
+ /* Returns: result - the number of actually written bytes.
+ (result < size) means error */
+};
+#define ISeqOutStream_Write(p, buf, size) (p)->Write(p, buf, size)
+
+typedef enum
+{
+ SZ_SEEK_SET = 0,
+ SZ_SEEK_CUR = 1,
+ SZ_SEEK_END = 2
+} ESzSeek;
+
+
+typedef struct ISeekInStream ISeekInStream;
+struct ISeekInStream
+{
+ SRes (*Read)(const ISeekInStream *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
+ SRes (*Seek)(const ISeekInStream *p, Int64 *pos, ESzSeek origin);
+};
+#define ISeekInStream_Read(p, buf, size) (p)->Read(p, buf, size)
+#define ISeekInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin)
+
+
+typedef struct ILookInStream ILookInStream;
+struct ILookInStream
+{
+ SRes (*Look)(const ILookInStream *p, const void **buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) > input(*size)) is not allowed
+ (output(*size) < input(*size)) is allowed */
+ SRes (*Skip)(const ILookInStream *p, size_t offset);
+ /* offset must be <= output(*size) of Look */
+
+ SRes (*Read)(const ILookInStream *p, void *buf, size_t *size);
+ /* reads directly (without buffer). It's same as ISeqInStream::Read */
+ SRes (*Seek)(const ILookInStream *p, Int64 *pos, ESzSeek origin);
+};
+
+#define ILookInStream_Look(p, buf, size) (p)->Look(p, buf, size)
+#define ILookInStream_Skip(p, offset) (p)->Skip(p, offset)
+#define ILookInStream_Read(p, buf, size) (p)->Read(p, buf, size)
+#define ILookInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin)
+
+
+SRes LookInStream_LookRead(const ILookInStream *stream, void *buf, size_t *size);
+SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset);
+
+/* reads via ILookInStream::Read */
+SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType);
+SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size);
+
+
+
+typedef struct
+{
+ ILookInStream vt;
+ const ISeekInStream *realStream;
+
+ size_t pos;
+ size_t size; /* it's data size */
+
+ /* the following variables must be set outside */
+ Byte *buf;
+ size_t bufSize;
+} CLookToRead2;
+
+void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead);
+
+#define LookToRead2_Init(p) { (p)->pos = (p)->size = 0; }
+
+
+typedef struct
+{
+ ISeqInStream vt;
+ const ILookInStream *realStream;
+} CSecToLook;
+
+void SecToLook_CreateVTable(CSecToLook *p);
+
+
+
+typedef struct
+{
+ ISeqInStream vt;
+ const ILookInStream *realStream;
+} CSecToRead;
+
+void SecToRead_CreateVTable(CSecToRead *p);
+
+
+typedef struct ICompressProgress ICompressProgress;
+
+struct ICompressProgress
+{
+ SRes (*Progress)(const ICompressProgress *p, UInt64 inSize, UInt64 outSize);
+ /* Returns: result. (result != SZ_OK) means break.
+ Value (UInt64)(Int64)-1 for size means unknown value. */
+};
+#define ICompressProgress_Progress(p, inSize, outSize) (p)->Progress(p, inSize, outSize)
+
+
+
+typedef struct ISzAlloc ISzAlloc;
+typedef const ISzAlloc * ISzAllocPtr;
+
+struct ISzAlloc
+{
+ void *(*Alloc)(ISzAllocPtr p, size_t size);
+ void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */
+};
+
+#define ISzAlloc_Alloc(p, size) (p)->Alloc(p, size)
+#define ISzAlloc_Free(p, a) (p)->Free(p, a)
+
+/* deprecated */
+#define IAlloc_Alloc(p, size) ISzAlloc_Alloc(p, size)
+#define IAlloc_Free(p, a) ISzAlloc_Free(p, a)
+
+
+
+
+
+#ifndef MY_offsetof
+ #ifdef offsetof
+ #define MY_offsetof(type, m) offsetof(type, m)
+ /*
+ #define MY_offsetof(type, m) FIELD_OFFSET(type, m)
+ */
+ #else
+ #define MY_offsetof(type, m) ((size_t)&(((type *)0)->m))
+ #endif
+#endif
+
+
+
+#ifndef MY_container_of
+
+/*
+#define MY_container_of(ptr, type, m) container_of(ptr, type, m)
+#define MY_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m)
+#define MY_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m)))
+#define MY_container_of(ptr, type, m) (&((type *)0)->m == (ptr), ((type *)(((char *)(ptr)) - MY_offsetof(type, m))))
+*/
+
+/*
+ GCC shows warning: "perhaps the 'offsetof' macro was used incorrectly"
+ GCC 3.4.4 : classes with constructor
+ GCC 4.8.1 : classes with non-public variable members"
+*/
+
+#define MY_container_of(ptr, type, m) ((type *)(void *)((char *)(void *)(1 ? (ptr) : &((type *)0)->m) - MY_offsetof(type, m)))
+
+#endif
+
+#define CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(void *)(ptr))
+
+/*
+#define CONTAINER_FROM_VTBL(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m)
+*/
+#define CONTAINER_FROM_VTBL(ptr, type, m) MY_container_of(ptr, type, m)
+
+#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m)
+/*
+#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL(ptr, type, m)
+*/
+
+
+#define MY_memset_0_ARRAY(a) memset((a), 0, sizeof(a))
+
+#ifdef _WIN32
+
+#define CHAR_PATH_SEPARATOR '\\'
+#define WCHAR_PATH_SEPARATOR L'\\'
+#define STRING_PATH_SEPARATOR "\\"
+#define WSTRING_PATH_SEPARATOR L"\\"
+
+#else
+
+#define CHAR_PATH_SEPARATOR '/'
+#define WCHAR_PATH_SEPARATOR L'/'
+#define STRING_PATH_SEPARATOR "/"
+#define WSTRING_PATH_SEPARATOR L"/"
+
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/src/Common/lzma/Alloc.c b/src/Common/lzma/Alloc.c
new file mode 100644
index 00000000..d1af76c5
--- /dev/null
+++ b/src/Common/lzma/Alloc.c
@@ -0,0 +1,463 @@
+/* Alloc.c -- Memory allocation functions
+2021-07-13 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <stdio.h>
+
+#ifdef _WIN32
+#include <Windows.h>
+#endif
+#include <stdlib.h>
+
+#include "Alloc.h"
+
+/* #define _SZ_ALLOC_DEBUG */
+
+/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
+#ifdef _SZ_ALLOC_DEBUG
+
+#include <stdio.h>
+int g_allocCount = 0;
+int g_allocCountMid = 0;
+int g_allocCountBig = 0;
+
+
+#define CONVERT_INT_TO_STR(charType, tempSize) \
+ unsigned char temp[tempSize]; unsigned i = 0; \
+ while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \
+ *s++ = (charType)('0' + (unsigned)val); \
+ while (i != 0) { i--; *s++ = temp[i]; } \
+ *s = 0;
+
+static void ConvertUInt64ToString(UInt64 val, char *s)
+{
+ CONVERT_INT_TO_STR(char, 24);
+}
+
+#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))
+
+static void ConvertUInt64ToHex(UInt64 val, char *s)
+{
+ UInt64 v = val;
+ unsigned i;
+ for (i = 1;; i++)
+ {
+ v >>= 4;
+ if (v == 0)
+ break;
+ }
+ s[i] = 0;
+ do
+ {
+ unsigned t = (unsigned)(val & 0xF);
+ val >>= 4;
+ s[--i] = GET_HEX_CHAR(t);
+ }
+ while (i);
+}
+
+#define DEBUG_OUT_STREAM stderr
+
+static void Print(const char *s)
+{
+ fputs(s, DEBUG_OUT_STREAM);
+}
+
+static void PrintAligned(const char *s, size_t align)
+{
+ size_t len = strlen(s);
+ for(;;)
+ {
+ fputc(' ', DEBUG_OUT_STREAM);
+ if (len >= align)
+ break;
+ ++len;
+ }
+ Print(s);
+}
+
+static void PrintLn()
+{
+ Print("\n");
+}
+
+static void PrintHex(UInt64 v, size_t align)
+{
+ char s[32];
+ ConvertUInt64ToHex(v, s);
+ PrintAligned(s, align);
+}
+
+static void PrintDec(UInt64 v, size_t align)
+{
+ char s[32];
+ ConvertUInt64ToString(v, s);
+ PrintAligned(s, align);
+}
+
+static void PrintAddr(void *p)
+{
+ PrintHex((UInt64)(size_t)(ptrdiff_t)p, 12);
+}
+
+
+#define PRINT_ALLOC(name, cnt, size, ptr) \
+ Print(name " "); \
+ PrintDec(cnt++, 10); \
+ PrintHex(size, 10); \
+ PrintAddr(ptr); \
+ PrintLn();
+
+#define PRINT_FREE(name, cnt, ptr) if (ptr) { \
+ Print(name " "); \
+ PrintDec(--cnt, 10); \
+ PrintAddr(ptr); \
+ PrintLn(); }
+
+#else
+
+#define PRINT_ALLOC(name, cnt, size, ptr)
+#define PRINT_FREE(name, cnt, ptr)
+#define Print(s)
+#define PrintLn()
+#define PrintHex(v, align)
+#define PrintAddr(p)
+
+#endif
+
+
+
+void *MyAlloc(size_t size)
+{
+ if (size == 0)
+ return NULL;
+ PRINT_ALLOC("Alloc ", g_allocCount, size, NULL);
+ #ifdef _SZ_ALLOC_DEBUG
+ {
+ void *p = malloc(size);
+ // PRINT_ALLOC("Alloc ", g_allocCount, size, p);
+ return p;
+ }
+ #else
+ return malloc(size);
+ #endif
+}
+
+void MyFree(void *address)
+{
+ PRINT_FREE("Free ", g_allocCount, address);
+
+ free(address);
+}
+
+#ifdef _WIN32
+
+void *MidAlloc(size_t size)
+{
+ if (size == 0)
+ return NULL;
+
+ PRINT_ALLOC("Alloc-Mid", g_allocCountMid, size, NULL);
+
+ return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
+}
+
+void MidFree(void *address)
+{
+ PRINT_FREE("Free-Mid", g_allocCountMid, address);
+
+ if (!address)
+ return;
+ VirtualFree(address, 0, MEM_RELEASE);
+}
+
+#ifdef _7ZIP_LARGE_PAGES
+
+#ifdef MEM_LARGE_PAGES
+ #define MY__MEM_LARGE_PAGES MEM_LARGE_PAGES
+#else
+ #define MY__MEM_LARGE_PAGES 0x20000000
+#endif
+
+extern
+SIZE_T g_LargePageSize;
+SIZE_T g_LargePageSize = 0;
+typedef SIZE_T (WINAPI *GetLargePageMinimumP)(VOID);
+
+#endif // _7ZIP_LARGE_PAGES
+
+void SetLargePageSize()
+{
+ #ifdef _7ZIP_LARGE_PAGES
+ SIZE_T size;
+ GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP)
+ GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum");
+ if (!largePageMinimum)
+ return;
+ size = largePageMinimum();
+ if (size == 0 || (size & (size - 1)) != 0)
+ return;
+ g_LargePageSize = size;
+ #endif
+}
+
+
+void *BigAlloc(size_t size)
+{
+ if (size == 0)
+ return NULL;
+
+ PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL);
+
+ #ifdef _7ZIP_LARGE_PAGES
+ {
+ SIZE_T ps = g_LargePageSize;
+ if (ps != 0 && ps <= (1 << 30) && size > (ps / 2))
+ {
+ size_t size2;
+ ps--;
+ size2 = (size + ps) & ~ps;
+ if (size2 >= size)
+ {
+ void *res = VirtualAlloc(NULL, size2, MEM_COMMIT | MY__MEM_LARGE_PAGES, PAGE_READWRITE);
+ if (res)
+ return res;
+ }
+ }
+ }
+ #endif
+
+ return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
+}
+
+void BigFree(void *address)
+{
+ PRINT_FREE("Free-Big", g_allocCountBig, address);
+
+ if (!address)
+ return;
+ VirtualFree(address, 0, MEM_RELEASE);
+}
+
+#endif
+
+
+static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MyAlloc(size); }
+static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MyFree(address); }
+const ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+#ifdef _WIN32
+static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MidAlloc(size); }
+static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MidFree(address); }
+static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return BigAlloc(size); }
+static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); BigFree(address); }
+const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree };
+const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+#endif
+
+/*
+ uintptr_t : <stdint.h> C99 (optional)
+ : unsupported in VS6
+*/
+
+#ifdef _WIN32
+ typedef UINT_PTR UIntPtr;
+#else
+ /*
+ typedef uintptr_t UIntPtr;
+ */
+ typedef ptrdiff_t UIntPtr;
+#endif
+
+
+#define ADJUST_ALLOC_SIZE 0
+/*
+#define ADJUST_ALLOC_SIZE (sizeof(void *) - 1)
+*/
+/*
+ Use (ADJUST_ALLOC_SIZE = (sizeof(void *) - 1)), if
+ MyAlloc() can return address that is NOT multiple of sizeof(void *).
+*/
+
+
+/*
+#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((char *)(p) - ((size_t)(UIntPtr)(p) & ((align) - 1))))
+*/
+#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((((UIntPtr)(p)) & ~((UIntPtr)(align) - 1))))
+
+
+#if !defined(_WIN32) && defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)
+ #define USE_posix_memalign
+#endif
+
+#ifndef USE_posix_memalign
+#define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align)
+#endif
+
+/*
+ This posix_memalign() is for test purposes only.
+ We also need special Free() function instead of free(),
+ if this posix_memalign() is used.
+*/
+
+/*
+static int posix_memalign(void **ptr, size_t align, size_t size)
+{
+ size_t newSize = size + align;
+ void *p;
+ void *pAligned;
+ *ptr = NULL;
+ if (newSize < size)
+ return 12; // ENOMEM
+ p = MyAlloc(newSize);
+ if (!p)
+ return 12; // ENOMEM
+ pAligned = MY_ALIGN_PTR_UP_PLUS(p, align);
+ ((void **)pAligned)[-1] = p;
+ *ptr = pAligned;
+ return 0;
+}
+*/
+
+/*
+ ALLOC_ALIGN_SIZE >= sizeof(void *)
+ ALLOC_ALIGN_SIZE >= cache_line_size
+*/
+
+#define ALLOC_ALIGN_SIZE ((size_t)1 << 7)
+
+static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size)
+{
+ #ifndef USE_posix_memalign
+
+ void *p;
+ void *pAligned;
+ size_t newSize;
+ UNUSED_VAR(pp);
+
+ /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned
+ block to prevent cache line sharing with another allocated blocks */
+
+ newSize = size + ALLOC_ALIGN_SIZE * 1 + ADJUST_ALLOC_SIZE;
+ if (newSize < size)
+ return NULL;
+
+ p = MyAlloc(newSize);
+
+ if (!p)
+ return NULL;
+ pAligned = MY_ALIGN_PTR_UP_PLUS(p, ALLOC_ALIGN_SIZE);
+
+ Print(" size="); PrintHex(size, 8);
+ Print(" a_size="); PrintHex(newSize, 8);
+ Print(" ptr="); PrintAddr(p);
+ Print(" a_ptr="); PrintAddr(pAligned);
+ PrintLn();
+
+ ((void **)pAligned)[-1] = p;
+
+ return pAligned;
+
+ #else
+
+ void *p;
+ UNUSED_VAR(pp);
+ if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size))
+ return NULL;
+
+ Print(" posix_memalign="); PrintAddr(p);
+ PrintLn();
+
+ return p;
+
+ #endif
+}
+
+
+static void SzAlignedFree(ISzAllocPtr pp, void *address)
+{
+ UNUSED_VAR(pp);
+ #ifndef USE_posix_memalign
+ if (address)
+ MyFree(((void **)address)[-1]);
+ #else
+ free(address);
+ #endif
+}
+
+
+const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree };
+
+
+
+#define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *))
+
+/* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */
+#define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1]
+/*
+#define REAL_BLOCK_PTR_VAR(p) ((void **)(p))[-1]
+*/
+
+static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size)
+{
+ CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt);
+ void *adr;
+ void *pAligned;
+ size_t newSize;
+ size_t extra;
+ size_t alignSize = (size_t)1 << p->numAlignBits;
+
+ if (alignSize < sizeof(void *))
+ alignSize = sizeof(void *);
+
+ if (p->offset >= alignSize)
+ return NULL;
+
+ /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned
+ block to prevent cache line sharing with another allocated blocks */
+ extra = p->offset & (sizeof(void *) - 1);
+ newSize = size + alignSize + extra + ADJUST_ALLOC_SIZE;
+ if (newSize < size)
+ return NULL;
+
+ adr = ISzAlloc_Alloc(p->baseAlloc, newSize);
+
+ if (!adr)
+ return NULL;
+
+ pAligned = (char *)MY_ALIGN_PTR_DOWN((char *)adr +
+ alignSize - p->offset + extra + ADJUST_ALLOC_SIZE, alignSize) + p->offset;
+
+ PrintLn();
+ Print("- Aligned: ");
+ Print(" size="); PrintHex(size, 8);
+ Print(" a_size="); PrintHex(newSize, 8);
+ Print(" ptr="); PrintAddr(adr);
+ Print(" a_ptr="); PrintAddr(pAligned);
+ PrintLn();
+
+ REAL_BLOCK_PTR_VAR(pAligned) = adr;
+
+ return pAligned;
+}
+
+
+static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address)
+{
+ if (address)
+ {
+ CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt);
+ PrintLn();
+ Print("- Aligned Free: ");
+ PrintLn();
+ ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address));
+ }
+}
+
+
+void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p)
+{
+ p->vt.Alloc = AlignOffsetAlloc_Alloc;
+ p->vt.Free = AlignOffsetAlloc_Free;
+}
diff --git a/src/Common/lzma/Alloc.h b/src/Common/lzma/Alloc.h
new file mode 100644
index 00000000..3be2041e
--- /dev/null
+++ b/src/Common/lzma/Alloc.h
@@ -0,0 +1,58 @@
+/* Alloc.h -- Memory allocation functions
+2021-07-13 : Igor Pavlov : Public domain */
+
+#ifndef __COMMON_ALLOC_H
+#define __COMMON_ALLOC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+void *MyAlloc(size_t size);
+void MyFree(void *address);
+
+#ifdef _WIN32
+
+void SetLargePageSize(void);
+
+void *MidAlloc(size_t size);
+void MidFree(void *address);
+void *BigAlloc(size_t size);
+void BigFree(void *address);
+
+#else
+
+#define MidAlloc(size) MyAlloc(size)
+#define MidFree(address) MyFree(address)
+#define BigAlloc(size) MyAlloc(size)
+#define BigFree(address) MyFree(address)
+
+#endif
+
+extern const ISzAlloc g_Alloc;
+
+#ifdef _WIN32
+extern const ISzAlloc g_BigAlloc;
+extern const ISzAlloc g_MidAlloc;
+#else
+#define g_BigAlloc g_AlignedAlloc
+#define g_MidAlloc g_AlignedAlloc
+#endif
+
+extern const ISzAlloc g_AlignedAlloc;
+
+
+typedef struct
+{
+ ISzAlloc vt;
+ ISzAllocPtr baseAlloc;
+ unsigned numAlignBits; /* ((1 << numAlignBits) >= sizeof(void *)) */
+ size_t offset; /* (offset == (k * sizeof(void *)) && offset < (1 << numAlignBits) */
+} CAlignOffsetAlloc;
+
+void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p);
+
+
+EXTERN_C_END
+
+#endif
diff --git a/src/Common/lzma/Compiler.h b/src/Common/lzma/Compiler.h
new file mode 100644
index 00000000..a9816fa5
--- /dev/null
+++ b/src/Common/lzma/Compiler.h
@@ -0,0 +1,43 @@
+/* Compiler.h
+2021-01-05 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_COMPILER_H
+#define __7Z_COMPILER_H
+
+ #ifdef __clang__
+ #pragma clang diagnostic ignored "-Wunused-private-field"
+ #endif
+
+#ifdef _MSC_VER
+
+ #ifdef UNDER_CE
+ #define RPC_NO_WINDOWS_H
+ /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */
+ #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
+ #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int
+ #endif
+
+ #if _MSC_VER >= 1300
+ #pragma warning(disable : 4996) // This function or variable may be unsafe
+ #else
+ #pragma warning(disable : 4511) // copy constructor could not be generated
+ #pragma warning(disable : 4512) // assignment operator could not be generated
+ #pragma warning(disable : 4514) // unreferenced inline function has been removed
+ #pragma warning(disable : 4702) // unreachable code
+ #pragma warning(disable : 4710) // not inlined
+ #pragma warning(disable : 4714) // function marked as __forceinline not inlined
+ #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information
+ #endif
+
+ #ifdef __clang__
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ #pragma clang diagnostic ignored "-Wmicrosoft-exception-spec"
+ // #pragma clang diagnostic ignored "-Wreserved-id-macro"
+ #endif
+
+#endif
+
+#define UNUSED_VAR(x) (void)x;
+/* #define UNUSED_VAR(x) x=x; */
+
+#endif
diff --git a/src/Common/lzma/CpuArch.c b/src/Common/lzma/CpuArch.c
new file mode 100644
index 00000000..fa9afe39
--- /dev/null
+++ b/src/Common/lzma/CpuArch.c
@@ -0,0 +1,478 @@
+/* CpuArch.c -- CPU specific code
+2021-07-13 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "CpuArch.h"
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__)
+#define USE_ASM
+#endif
+
+#if !defined(USE_ASM) && _MSC_VER >= 1500
+#include <intrin.h>
+#endif
+
+#if defined(USE_ASM) && !defined(MY_CPU_AMD64)
+static UInt32 CheckFlag(UInt32 flag)
+{
+ #ifdef _MSC_VER
+ __asm pushfd;
+ __asm pop EAX;
+ __asm mov EDX, EAX;
+ __asm xor EAX, flag;
+ __asm push EAX;
+ __asm popfd;
+ __asm pushfd;
+ __asm pop EAX;
+ __asm xor EAX, EDX;
+ __asm push EDX;
+ __asm popfd;
+ __asm and flag, EAX;
+ #else
+ __asm__ __volatile__ (
+ "pushf\n\t"
+ "pop %%EAX\n\t"
+ "movl %%EAX,%%EDX\n\t"
+ "xorl %0,%%EAX\n\t"
+ "push %%EAX\n\t"
+ "popf\n\t"
+ "pushf\n\t"
+ "pop %%EAX\n\t"
+ "xorl %%EDX,%%EAX\n\t"
+ "push %%EDX\n\t"
+ "popf\n\t"
+ "andl %%EAX, %0\n\t":
+ "=c" (flag) : "c" (flag) :
+ "%eax", "%edx");
+ #endif
+ return flag;
+}
+#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False;
+#else
+#define CHECK_CPUID_IS_SUPPORTED
+#endif
+
+#ifndef USE_ASM
+ #ifdef _MSC_VER
+ #if _MSC_VER >= 1600
+ #define MY__cpuidex __cpuidex
+ #else
+
+/*
+ __cpuid (function == 4) requires subfunction number in ECX.
+ MSDN: The __cpuid intrinsic clears the ECX register before calling the cpuid instruction.
+ __cpuid() in new MSVC clears ECX.
+ __cpuid() in old MSVC (14.00) doesn't clear ECX
+ We still can use __cpuid for low (function) values that don't require ECX,
+ but __cpuid() in old MSVC will be incorrect for some function values: (function == 4).
+ So here we use the hack for old MSVC to send (subFunction) in ECX register to cpuid instruction,
+ where ECX value is first parameter for FAST_CALL / NO_INLINE function,
+ So the caller of MY__cpuidex_HACK() sets ECX as subFunction, and
+ old MSVC for __cpuid() doesn't change ECX and cpuid instruction gets (subFunction) value.
+
+ DON'T remove MY_NO_INLINE and MY_FAST_CALL for MY__cpuidex_HACK() !!!
+*/
+
+static
+MY_NO_INLINE
+void MY_FAST_CALL MY__cpuidex_HACK(UInt32 subFunction, int *CPUInfo, UInt32 function)
+{
+ UNUSED_VAR(subFunction);
+ __cpuid(CPUInfo, function);
+}
+
+ #define MY__cpuidex(info, func, func2) MY__cpuidex_HACK(func2, info, func)
+ #pragma message("======== MY__cpuidex_HACK WAS USED ========")
+ #endif
+ #else
+ #define MY__cpuidex(info, func, func2) __cpuid(info, func)
+ #pragma message("======== (INCORRECT ?) cpuid WAS USED ========")
+ #endif
+#endif
+
+
+
+
+void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
+{
+ #ifdef USE_ASM
+
+ #ifdef _MSC_VER
+
+ UInt32 a2, b2, c2, d2;
+ __asm xor EBX, EBX;
+ __asm xor ECX, ECX;
+ __asm xor EDX, EDX;
+ __asm mov EAX, function;
+ __asm cpuid;
+ __asm mov a2, EAX;
+ __asm mov b2, EBX;
+ __asm mov c2, ECX;
+ __asm mov d2, EDX;
+
+ *a = a2;
+ *b = b2;
+ *c = c2;
+ *d = d2;
+
+ #else
+
+ __asm__ __volatile__ (
+ #if defined(MY_CPU_AMD64) && defined(__PIC__)
+ "mov %%rbx, %%rdi;"
+ "cpuid;"
+ "xchg %%rbx, %%rdi;"
+ : "=a" (*a) ,
+ "=D" (*b) ,
+ #elif defined(MY_CPU_X86) && defined(__PIC__)
+ "mov %%ebx, %%edi;"
+ "cpuid;"
+ "xchgl %%ebx, %%edi;"
+ : "=a" (*a) ,
+ "=D" (*b) ,
+ #else
+ "cpuid"
+ : "=a" (*a) ,
+ "=b" (*b) ,
+ #endif
+ "=c" (*c) ,
+ "=d" (*d)
+ : "0" (function), "c"(0) ) ;
+
+ #endif
+
+ #else
+
+ int CPUInfo[4];
+
+ MY__cpuidex(CPUInfo, (int)function, 0);
+
+ *a = (UInt32)CPUInfo[0];
+ *b = (UInt32)CPUInfo[1];
+ *c = (UInt32)CPUInfo[2];
+ *d = (UInt32)CPUInfo[3];
+
+ #endif
+}
+
+BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p)
+{
+ CHECK_CPUID_IS_SUPPORTED
+ MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]);
+ MyCPUID(1, &p->ver, &p->b, &p->c, &p->d);
+ return True;
+}
+
+static const UInt32 kVendors[][3] =
+{
+ { 0x756E6547, 0x49656E69, 0x6C65746E},
+ { 0x68747541, 0x69746E65, 0x444D4163},
+ { 0x746E6543, 0x48727561, 0x736C7561}
+};
+
+int x86cpuid_GetFirm(const Cx86cpuid *p)
+{
+ unsigned i;
+ for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++)
+ {
+ const UInt32 *v = kVendors[i];
+ if (v[0] == p->vendor[0] &&
+ v[1] == p->vendor[1] &&
+ v[2] == p->vendor[2])
+ return (int)i;
+ }
+ return -1;
+}
+
+BoolInt CPU_Is_InOrder()
+{
+ Cx86cpuid p;
+ int firm;
+ UInt32 family, model;
+ if (!x86cpuid_CheckAndRead(&p))
+ return True;
+
+ family = x86cpuid_GetFamily(p.ver);
+ model = x86cpuid_GetModel(p.ver);
+
+ firm = x86cpuid_GetFirm(&p);
+
+ switch (firm)
+ {
+ case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && (
+ /* In-Order Atom CPU */
+ model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */
+ || model == 0x26 /* 45 nm, Z6xx */
+ || model == 0x27 /* 32 nm, Z2460 */
+ || model == 0x35 /* 32 nm, Z2760 */
+ || model == 0x36 /* 32 nm, N2xxx, D2xxx */
+ )));
+ case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
+ case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
+ }
+ return True;
+}
+
+#if !defined(MY_CPU_AMD64) && defined(_WIN32)
+#include <Windows.h>
+static BoolInt CPU_Sys_Is_SSE_Supported()
+{
+ OSVERSIONINFO vi;
+ vi.dwOSVersionInfoSize = sizeof(vi);
+ if (!GetVersionEx(&vi))
+ return False;
+ return (vi.dwMajorVersion >= 5);
+}
+#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;
+#else
+#define CHECK_SYS_SSE_SUPPORT
+#endif
+
+
+static UInt32 X86_CPUID_ECX_Get_Flags()
+{
+ Cx86cpuid p;
+ CHECK_SYS_SSE_SUPPORT
+ if (!x86cpuid_CheckAndRead(&p))
+ return 0;
+ return p.c;
+}
+
+BoolInt CPU_IsSupported_AES()
+{
+ return (X86_CPUID_ECX_Get_Flags() >> 25) & 1;
+}
+
+BoolInt CPU_IsSupported_SSSE3()
+{
+ return (X86_CPUID_ECX_Get_Flags() >> 9) & 1;
+}
+
+BoolInt CPU_IsSupported_SSE41()
+{
+ return (X86_CPUID_ECX_Get_Flags() >> 19) & 1;
+}
+
+BoolInt CPU_IsSupported_SHA()
+{
+ Cx86cpuid p;
+ CHECK_SYS_SSE_SUPPORT
+ if (!x86cpuid_CheckAndRead(&p))
+ return False;
+
+ if (p.maxFunc < 7)
+ return False;
+ {
+ UInt32 d[4] = { 0 };
+ MyCPUID(7, &d[0], &d[1], &d[2], &d[3]);
+ return (d[1] >> 29) & 1;
+ }
+}
+
+// #include <stdio.h>
+
+#ifdef _WIN32
+#include <Windows.h>
+#endif
+
+BoolInt CPU_IsSupported_AVX2()
+{
+ Cx86cpuid p;
+ CHECK_SYS_SSE_SUPPORT
+
+ #ifdef _WIN32
+ #define MY__PF_XSAVE_ENABLED 17
+ if (!IsProcessorFeaturePresent(MY__PF_XSAVE_ENABLED))
+ return False;
+ #endif
+
+ if (!x86cpuid_CheckAndRead(&p))
+ return False;
+ if (p.maxFunc < 7)
+ return False;
+ {
+ UInt32 d[4] = { 0 };
+ MyCPUID(7, &d[0], &d[1], &d[2], &d[3]);
+ // printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]);
+ return 1
+ & (d[1] >> 5); // avx2
+ }
+}
+
+BoolInt CPU_IsSupported_VAES_AVX2()
+{
+ Cx86cpuid p;
+ CHECK_SYS_SSE_SUPPORT
+
+ #ifdef _WIN32
+ #define MY__PF_XSAVE_ENABLED 17
+ if (!IsProcessorFeaturePresent(MY__PF_XSAVE_ENABLED))
+ return False;
+ #endif
+
+ if (!x86cpuid_CheckAndRead(&p))
+ return False;
+ if (p.maxFunc < 7)
+ return False;
+ {
+ UInt32 d[4] = { 0 };
+ MyCPUID(7, &d[0], &d[1], &d[2], &d[3]);
+ // printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]);
+ return 1
+ & (d[1] >> 5) // avx2
+ // & (d[1] >> 31) // avx512vl
+ & (d[2] >> 9); // vaes // VEX-256/EVEX
+ }
+}
+
+BoolInt CPU_IsSupported_PageGB()
+{
+ Cx86cpuid cpuid;
+ if (!x86cpuid_CheckAndRead(&cpuid))
+ return False;
+ {
+ UInt32 d[4] = { 0 };
+ MyCPUID(0x80000000, &d[0], &d[1], &d[2], &d[3]);
+ if (d[0] < 0x80000001)
+ return False;
+ }
+ {
+ UInt32 d[4] = { 0 };
+ MyCPUID(0x80000001, &d[0], &d[1], &d[2], &d[3]);
+ return (d[3] >> 26) & 1;
+ }
+}
+
+
+#elif defined(MY_CPU_ARM_OR_ARM64)
+
+#ifdef _WIN32
+
+#include <Windows.h>
+
+BoolInt CPU_IsSupported_CRC32() { return IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) ? 1 : 0; }
+BoolInt CPU_IsSupported_CRYPTO() { return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) ? 1 : 0; }
+BoolInt CPU_IsSupported_NEON() { return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) ? 1 : 0; }
+
+#else
+
+#if defined(__APPLE__)
+
+/*
+#include <stdio.h>
+#include <string.h>
+static void Print_sysctlbyname(const char *name)
+{
+ size_t bufSize = 256;
+ char buf[256];
+ int res = sysctlbyname(name, &buf, &bufSize, NULL, 0);
+ {
+ int i;
+ printf("\nres = %d : %s : '%s' : bufSize = %d, numeric", res, name, buf, (unsigned)bufSize);
+ for (i = 0; i < 20; i++)
+ printf(" %2x", (unsigned)(Byte)buf[i]);
+
+ }
+}
+*/
+
+static BoolInt My_sysctlbyname_Get_BoolInt(const char *name)
+{
+ UInt32 val = 0;
+ if (My_sysctlbyname_Get_UInt32(name, &val) == 0 && val == 1)
+ return 1;
+ return 0;
+}
+
+ /*
+ Print_sysctlbyname("hw.pagesize");
+ Print_sysctlbyname("machdep.cpu.brand_string");
+ */
+
+BoolInt CPU_IsSupported_CRC32(void)
+{
+ return My_sysctlbyname_Get_BoolInt("hw.optional.armv8_crc32");
+}
+
+BoolInt CPU_IsSupported_NEON(void)
+{
+ return My_sysctlbyname_Get_BoolInt("hw.optional.neon");
+}
+
+#ifdef MY_CPU_ARM64
+#define APPLE_CRYPTO_SUPPORT_VAL 1
+#else
+#define APPLE_CRYPTO_SUPPORT_VAL 0
+#endif
+
+BoolInt CPU_IsSupported_SHA1(void) { return APPLE_CRYPTO_SUPPORT_VAL; }
+BoolInt CPU_IsSupported_SHA2(void) { return APPLE_CRYPTO_SUPPORT_VAL; }
+BoolInt CPU_IsSupported_AES (void) { return APPLE_CRYPTO_SUPPORT_VAL; }
+
+
+#else // __APPLE__
+
+#include <sys/auxv.h>
+
+#define USE_HWCAP
+
+#ifdef USE_HWCAP
+
+#include <asm/hwcap.h>
+
+ #define MY_HWCAP_CHECK_FUNC_2(name1, name2) \
+ BoolInt CPU_IsSupported_ ## name1() { return (getauxval(AT_HWCAP) & (HWCAP_ ## name2)) ? 1 : 0; }
+
+#ifdef MY_CPU_ARM64
+ #define MY_HWCAP_CHECK_FUNC(name) \
+ MY_HWCAP_CHECK_FUNC_2(name, name)
+ MY_HWCAP_CHECK_FUNC_2(NEON, ASIMD)
+// MY_HWCAP_CHECK_FUNC (ASIMD)
+#elif defined(MY_CPU_ARM)
+ #define MY_HWCAP_CHECK_FUNC(name) \
+ BoolInt CPU_IsSupported_ ## name() { return (getauxval(AT_HWCAP2) & (HWCAP2_ ## name)) ? 1 : 0; }
+ MY_HWCAP_CHECK_FUNC_2(NEON, NEON)
+#endif
+
+#else // USE_HWCAP
+
+ #define MY_HWCAP_CHECK_FUNC(name) \
+ BoolInt CPU_IsSupported_ ## name() { return 0; }
+ MY_HWCAP_CHECK_FUNC(NEON)
+
+#endif // USE_HWCAP
+
+MY_HWCAP_CHECK_FUNC (CRC32)
+MY_HWCAP_CHECK_FUNC (SHA1)
+MY_HWCAP_CHECK_FUNC (SHA2)
+MY_HWCAP_CHECK_FUNC (AES)
+
+#endif // __APPLE__
+#endif // _WIN32
+
+#endif // MY_CPU_ARM_OR_ARM64
+
+
+
+#ifdef __APPLE__
+
+#include <sys/sysctl.h>
+
+int My_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize)
+{
+ return sysctlbyname(name, buf, bufSize, NULL, 0);
+}
+
+int My_sysctlbyname_Get_UInt32(const char *name, UInt32 *val)
+{
+ size_t bufSize = sizeof(*val);
+ int res = My_sysctlbyname_Get(name, val, &bufSize);
+ if (res == 0 && bufSize != sizeof(*val))
+ return EFAULT;
+ return res;
+}
+
+#endif
diff --git a/src/Common/lzma/CpuArch.h b/src/Common/lzma/CpuArch.h
new file mode 100644
index 00000000..529d3a50
--- /dev/null
+++ b/src/Common/lzma/CpuArch.h
@@ -0,0 +1,442 @@
+/* CpuArch.h -- CPU specific code
+2021-07-13 : Igor Pavlov : Public domain */
+
+#ifndef __CPU_ARCH_H
+#define __CPU_ARCH_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/*
+MY_CPU_LE means that CPU is LITTLE ENDIAN.
+MY_CPU_BE means that CPU is BIG ENDIAN.
+If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform.
+
+MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
+
+MY_CPU_64BIT means that processor can work with 64-bit registers.
+ MY_CPU_64BIT can be used to select fast code branch
+ MY_CPU_64BIT doesn't mean that (sizeof(void *) == 8)
+*/
+
+#if defined(_M_X64) \
+ || defined(_M_AMD64) \
+ || defined(__x86_64__) \
+ || defined(__AMD64__) \
+ || defined(__amd64__)
+ #define MY_CPU_AMD64
+ #ifdef __ILP32__
+ #define MY_CPU_NAME "x32"
+ #define MY_CPU_SIZEOF_POINTER 4
+ #else
+ #define MY_CPU_NAME "x64"
+ #define MY_CPU_SIZEOF_POINTER 8
+ #endif
+ #define MY_CPU_64BIT
+#endif
+
+
+#if defined(_M_IX86) \
+ || defined(__i386__)
+ #define MY_CPU_X86
+ #define MY_CPU_NAME "x86"
+ /* #define MY_CPU_32BIT */
+ #define MY_CPU_SIZEOF_POINTER 4
+#endif
+
+
+#if defined(_M_ARM64) \
+ || defined(__AARCH64EL__) \
+ || defined(__AARCH64EB__) \
+ || defined(__aarch64__)
+ #define MY_CPU_ARM64
+ #define MY_CPU_NAME "arm64"
+ #define MY_CPU_64BIT
+#endif
+
+
+#if defined(_M_ARM) \
+ || defined(_M_ARM_NT) \
+ || defined(_M_ARMT) \
+ || defined(__arm__) \
+ || defined(__thumb__) \
+ || defined(__ARMEL__) \
+ || defined(__ARMEB__) \
+ || defined(__THUMBEL__) \
+ || defined(__THUMBEB__)
+ #define MY_CPU_ARM
+
+ #if defined(__thumb__) || defined(__THUMBEL__) || defined(_M_ARMT)
+ #define MY_CPU_NAME "armt"
+ #else
+ #define MY_CPU_NAME "arm"
+ #endif
+ /* #define MY_CPU_32BIT */
+ #define MY_CPU_SIZEOF_POINTER 4
+#endif
+
+
+#if defined(_M_IA64) \
+ || defined(__ia64__)
+ #define MY_CPU_IA64
+ #define MY_CPU_NAME "ia64"
+ #define MY_CPU_64BIT
+#endif
+
+
+#if defined(__mips64) \
+ || defined(__mips64__) \
+ || (defined(__mips) && (__mips == 64 || __mips == 4 || __mips == 3))
+ #define MY_CPU_NAME "mips64"
+ #define MY_CPU_64BIT
+#elif defined(__mips__)
+ #define MY_CPU_NAME "mips"
+ /* #define MY_CPU_32BIT */
+#endif
+
+
+#if defined(__ppc64__) \
+ || defined(__powerpc64__) \
+ || defined(__ppc__) \
+ || defined(__powerpc__) \
+ || defined(__PPC__) \
+ || defined(_POWER)
+
+#if defined(__ppc64__) \
+ || defined(__powerpc64__) \
+ || defined(_LP64) \
+ || defined(__64BIT__)
+ #ifdef __ILP32__
+ #define MY_CPU_NAME "ppc64-32"
+ #define MY_CPU_SIZEOF_POINTER 4
+ #else
+ #define MY_CPU_NAME "ppc64"
+ #define MY_CPU_SIZEOF_POINTER 8
+ #endif
+ #define MY_CPU_64BIT
+#else
+ #define MY_CPU_NAME "ppc"
+ #define MY_CPU_SIZEOF_POINTER 4
+ /* #define MY_CPU_32BIT */
+#endif
+#endif
+
+
+#if defined(__sparc64__)
+ #define MY_CPU_NAME "sparc64"
+ #define MY_CPU_64BIT
+#elif defined(__sparc__)
+ #define MY_CPU_NAME "sparc"
+ /* #define MY_CPU_32BIT */
+#endif
+
+
+#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
+#define MY_CPU_X86_OR_AMD64
+#endif
+
+#if defined(MY_CPU_ARM) || defined(MY_CPU_ARM64)
+#define MY_CPU_ARM_OR_ARM64
+#endif
+
+
+#ifdef _WIN32
+
+ #ifdef MY_CPU_ARM
+ #define MY_CPU_ARM_LE
+ #endif
+
+ #ifdef MY_CPU_ARM64
+ #define MY_CPU_ARM64_LE
+ #endif
+
+ #ifdef _M_IA64
+ #define MY_CPU_IA64_LE
+ #endif
+
+#endif
+
+
+#if defined(MY_CPU_X86_OR_AMD64) \
+ || defined(MY_CPU_ARM_LE) \
+ || defined(MY_CPU_ARM64_LE) \
+ || defined(MY_CPU_IA64_LE) \
+ || defined(__LITTLE_ENDIAN__) \
+ || defined(__ARMEL__) \
+ || defined(__THUMBEL__) \
+ || defined(__AARCH64EL__) \
+ || defined(__MIPSEL__) \
+ || defined(__MIPSEL) \
+ || defined(_MIPSEL) \
+ || defined(__BFIN__) \
+ || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
+ #define MY_CPU_LE
+#endif
+
+#if defined(__BIG_ENDIAN__) \
+ || defined(__ARMEB__) \
+ || defined(__THUMBEB__) \
+ || defined(__AARCH64EB__) \
+ || defined(__MIPSEB__) \
+ || defined(__MIPSEB) \
+ || defined(_MIPSEB) \
+ || defined(__m68k__) \
+ || defined(__s390__) \
+ || defined(__s390x__) \
+ || defined(__zarch__) \
+ || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
+ #define MY_CPU_BE
+#endif
+
+
+#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
+ #error Stop_Compiling_Bad_Endian
+#endif
+
+
+#if defined(MY_CPU_32BIT) && defined(MY_CPU_64BIT)
+ #error Stop_Compiling_Bad_32_64_BIT
+#endif
+
+#ifdef __SIZEOF_POINTER__
+ #ifdef MY_CPU_SIZEOF_POINTER
+ #if MY_CPU_SIZEOF_POINTER != __SIZEOF_POINTER__
+ #error Stop_Compiling_Bad_MY_CPU_PTR_SIZE
+ #endif
+ #else
+ #define MY_CPU_SIZEOF_POINTER __SIZEOF_POINTER__
+ #endif
+#endif
+
+#if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4)
+#if defined (_LP64)
+ #error Stop_Compiling_Bad_MY_CPU_PTR_SIZE
+#endif
+#endif
+
+#ifdef _MSC_VER
+ #if _MSC_VER >= 1300
+ #define MY_CPU_pragma_pack_push_1 __pragma(pack(push, 1))
+ #define MY_CPU_pragma_pop __pragma(pack(pop))
+ #else
+ #define MY_CPU_pragma_pack_push_1
+ #define MY_CPU_pragma_pop
+ #endif
+#else
+ #ifdef __xlC__
+ #define MY_CPU_pragma_pack_push_1 _Pragma("pack(1)")
+ #define MY_CPU_pragma_pop _Pragma("pack()")
+ #else
+ #define MY_CPU_pragma_pack_push_1 _Pragma("pack(push, 1)")
+ #define MY_CPU_pragma_pop _Pragma("pack(pop)")
+ #endif
+#endif
+
+
+#ifndef MY_CPU_NAME
+ #ifdef MY_CPU_LE
+ #define MY_CPU_NAME "LE"
+ #elif defined(MY_CPU_BE)
+ #define MY_CPU_NAME "BE"
+ #else
+ /*
+ #define MY_CPU_NAME ""
+ */
+ #endif
+#endif
+
+
+
+
+
+#ifdef MY_CPU_LE
+ #if defined(MY_CPU_X86_OR_AMD64) \
+ || defined(MY_CPU_ARM64)
+ #define MY_CPU_LE_UNALIGN
+ #define MY_CPU_LE_UNALIGN_64
+ #elif defined(__ARM_FEATURE_UNALIGNED)
+ /* gcc9 for 32-bit arm can use LDRD instruction that requires 32-bit alignment.
+ So we can't use unaligned 64-bit operations. */
+ #define MY_CPU_LE_UNALIGN
+ #endif
+#endif
+
+
+#ifdef MY_CPU_LE_UNALIGN
+
+#define GetUi16(p) (*(const UInt16 *)(const void *)(p))
+#define GetUi32(p) (*(const UInt32 *)(const void *)(p))
+#ifdef MY_CPU_LE_UNALIGN_64
+#define GetUi64(p) (*(const UInt64 *)(const void *)(p))
+#endif
+
+#define SetUi16(p, v) { *(UInt16 *)(void *)(p) = (v); }
+#define SetUi32(p, v) { *(UInt32 *)(void *)(p) = (v); }
+#ifdef MY_CPU_LE_UNALIGN_64
+#define SetUi64(p, v) { *(UInt64 *)(void *)(p) = (v); }
+#endif
+
+#else
+
+#define GetUi16(p) ( (UInt16) ( \
+ ((const Byte *)(p))[0] | \
+ ((UInt16)((const Byte *)(p))[1] << 8) ))
+
+#define GetUi32(p) ( \
+ ((const Byte *)(p))[0] | \
+ ((UInt32)((const Byte *)(p))[1] << 8) | \
+ ((UInt32)((const Byte *)(p))[2] << 16) | \
+ ((UInt32)((const Byte *)(p))[3] << 24))
+
+#define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+ _ppp_[0] = (Byte)_vvv_; \
+ _ppp_[1] = (Byte)(_vvv_ >> 8); }
+
+#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+ _ppp_[0] = (Byte)_vvv_; \
+ _ppp_[1] = (Byte)(_vvv_ >> 8); \
+ _ppp_[2] = (Byte)(_vvv_ >> 16); \
+ _ppp_[3] = (Byte)(_vvv_ >> 24); }
+
+#endif
+
+
+#ifndef MY_CPU_LE_UNALIGN_64
+
+#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
+
+#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \
+ SetUi32(_ppp2_ , (UInt32)_vvv2_); \
+ SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); }
+
+#endif
+
+
+
+
+#ifdef __has_builtin
+ #define MY__has_builtin(x) __has_builtin(x)
+#else
+ #define MY__has_builtin(x) 0
+#endif
+
+#if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ defined(_MSC_VER) && (_MSC_VER >= 1300)
+
+/* Note: we use bswap instruction, that is unsupported in 386 cpu */
+
+#include <stdlib.h>
+
+#pragma intrinsic(_byteswap_ushort)
+#pragma intrinsic(_byteswap_ulong)
+#pragma intrinsic(_byteswap_uint64)
+
+/* #define GetBe16(p) _byteswap_ushort(*(const UInt16 *)(const Byte *)(p)) */
+#define GetBe32(p) _byteswap_ulong (*(const UInt32 *)(const void *)(p))
+#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const void *)(p))
+
+#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v)
+
+#elif defined(MY_CPU_LE_UNALIGN) && ( \
+ (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \
+ || (defined(__clang__) && MY__has_builtin(__builtin_bswap16)) )
+
+/* #define GetBe16(p) __builtin_bswap16(*(const UInt16 *)(const void *)(p)) */
+#define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const void *)(p))
+#define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const void *)(p))
+
+#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v)
+
+#else
+
+#define GetBe32(p) ( \
+ ((UInt32)((const Byte *)(p))[0] << 24) | \
+ ((UInt32)((const Byte *)(p))[1] << 16) | \
+ ((UInt32)((const Byte *)(p))[2] << 8) | \
+ ((const Byte *)(p))[3] )
+
+#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
+
+#define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+ _ppp_[0] = (Byte)(_vvv_ >> 24); \
+ _ppp_[1] = (Byte)(_vvv_ >> 16); \
+ _ppp_[2] = (Byte)(_vvv_ >> 8); \
+ _ppp_[3] = (Byte)_vvv_; }
+
+#endif
+
+
+#ifndef GetBe16
+
+#define GetBe16(p) ( (UInt16) ( \
+ ((UInt16)((const Byte *)(p))[0] << 8) | \
+ ((const Byte *)(p))[1] ))
+
+#endif
+
+
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+typedef struct
+{
+ UInt32 maxFunc;
+ UInt32 vendor[3];
+ UInt32 ver;
+ UInt32 b;
+ UInt32 c;
+ UInt32 d;
+} Cx86cpuid;
+
+enum
+{
+ CPU_FIRM_INTEL,
+ CPU_FIRM_AMD,
+ CPU_FIRM_VIA
+};
+
+void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d);
+
+BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p);
+int x86cpuid_GetFirm(const Cx86cpuid *p);
+
+#define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF))
+#define x86cpuid_GetModel(ver) (((ver >> 12) & 0xF0) | ((ver >> 4) & 0xF))
+#define x86cpuid_GetStepping(ver) (ver & 0xF)
+
+BoolInt CPU_Is_InOrder(void);
+
+BoolInt CPU_IsSupported_AES(void);
+BoolInt CPU_IsSupported_AVX2(void);
+BoolInt CPU_IsSupported_VAES_AVX2(void);
+BoolInt CPU_IsSupported_SSSE3(void);
+BoolInt CPU_IsSupported_SSE41(void);
+BoolInt CPU_IsSupported_SHA(void);
+BoolInt CPU_IsSupported_PageGB(void);
+
+#elif defined(MY_CPU_ARM_OR_ARM64)
+
+BoolInt CPU_IsSupported_CRC32(void);
+BoolInt CPU_IsSupported_NEON(void);
+
+#if defined(_WIN32)
+BoolInt CPU_IsSupported_CRYPTO(void);
+#define CPU_IsSupported_SHA1 CPU_IsSupported_CRYPTO
+#define CPU_IsSupported_SHA2 CPU_IsSupported_CRYPTO
+#define CPU_IsSupported_AES CPU_IsSupported_CRYPTO
+#else
+BoolInt CPU_IsSupported_SHA1(void);
+BoolInt CPU_IsSupported_SHA2(void);
+BoolInt CPU_IsSupported_AES(void);
+#endif
+
+#endif
+
+#if defined(__APPLE__)
+int My_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize);
+int My_sysctlbyname_Get_UInt32(const char *name, UInt32 *val);
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/src/Common/lzma/LzFind.c b/src/Common/lzma/LzFind.c
new file mode 100644
index 00000000..1b73c284
--- /dev/null
+++ b/src/Common/lzma/LzFind.c
@@ -0,0 +1,1628 @@
+/* LzFind.c -- Match finder for LZ algorithms
+2021-11-29 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+// #include <stdio.h>
+
+#include "CpuArch.h"
+#include "LzFind.h"
+#include "LzHash.h"
+
+#define kBlockMoveAlign (1 << 7) // alignment for memmove()
+#define kBlockSizeAlign (1 << 16) // alignment for block allocation
+#define kBlockSizeReserveMin (1 << 24) // it's 1/256 from 4 GB dictinary
+
+#define kEmptyHashValue 0
+
+#define kMaxValForNormalize ((UInt32)0)
+// #define kMaxValForNormalize ((UInt32)(1 << 20) + 0xFFF) // for debug
+
+// #define kNormalizeAlign (1 << 7) // alignment for speculated accesses
+
+#define GET_AVAIL_BYTES(p) \
+ Inline_MatchFinder_GetNumAvailableBytes(p)
+
+
+// #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
+#define kFix5HashSize kFix4HashSize
+
+/*
+ HASH2_CALC:
+ if (hv) match, then cur[0] and cur[1] also match
+*/
+#define HASH2_CALC hv = GetUi16(cur);
+
+// (crc[0 ... 255] & 0xFF) provides one-to-one correspondence to [0 ... 255]
+
+/*
+ HASH3_CALC:
+ if (cur[0]) and (h2) match, then cur[1] also match
+ if (cur[0]) and (hv) match, then cur[1] and cur[2] also match
+*/
+#define HASH3_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ h2 = temp & (kHash2Size - 1); \
+ hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
+
+#define HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ h2 = temp & (kHash2Size - 1); \
+ temp ^= ((UInt32)cur[2] << 8); \
+ h3 = temp & (kHash3Size - 1); \
+ hv = (temp ^ (p->crc[cur[3]] << kLzHash_CrcShift_1)) & p->hashMask; }
+
+#define HASH5_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ h2 = temp & (kHash2Size - 1); \
+ temp ^= ((UInt32)cur[2] << 8); \
+ h3 = temp & (kHash3Size - 1); \
+ temp ^= (p->crc[cur[3]] << kLzHash_CrcShift_1); \
+ /* h4 = temp & p->hash4Mask; */ /* (kHash4Size - 1); */ \
+ hv = (temp ^ (p->crc[cur[4]] << kLzHash_CrcShift_2)) & p->hashMask; }
+
+#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
+
+
+static void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc)
+{
+ if (!p->directInput)
+ {
+ ISzAlloc_Free(alloc, p->bufferBase);
+ p->bufferBase = NULL;
+ }
+}
+
+
+static int LzInWindow_Create2(CMatchFinder *p, UInt32 blockSize, ISzAllocPtr alloc)
+{
+ if (blockSize == 0)
+ return 0;
+ if (!p->bufferBase || p->blockSize != blockSize)
+ {
+ // size_t blockSizeT;
+ LzInWindow_Free(p, alloc);
+ p->blockSize = blockSize;
+ // blockSizeT = blockSize;
+
+ // printf("\nblockSize = 0x%x\n", blockSize);
+ /*
+ #if defined _WIN64
+ // we can allocate 4GiB, but still use UInt32 for (p->blockSize)
+ // we use UInt32 type for (p->blockSize), because
+ // we don't want to wrap over 4 GiB,
+ // when we use (p->streamPos - p->pos) that is UInt32.
+ if (blockSize >= (UInt32)0 - (UInt32)kBlockSizeAlign)
+ {
+ blockSizeT = ((size_t)1 << 32);
+ printf("\nchanged to blockSizeT = 4GiB\n");
+ }
+ #endif
+ */
+
+ p->bufferBase = (Byte *)ISzAlloc_Alloc(alloc, blockSize);
+ // printf("\nbufferBase = %p\n", p->bufferBase);
+ // return 0; // for debug
+ }
+ return (p->bufferBase != NULL);
+}
+
+static const Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
+
+static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return GET_AVAIL_BYTES(p); }
+
+
+MY_NO_INLINE
+static void MatchFinder_ReadBlock(CMatchFinder *p)
+{
+ if (p->streamEndWasReached || p->result != SZ_OK)
+ return;
+
+ /* We use (p->streamPos - p->pos) value.
+ (p->streamPos < p->pos) is allowed. */
+
+ if (p->directInput)
+ {
+ UInt32 curSize = 0xFFFFFFFF - GET_AVAIL_BYTES(p);
+ if (curSize > p->directInputRem)
+ curSize = (UInt32)p->directInputRem;
+ p->directInputRem -= curSize;
+ p->streamPos += curSize;
+ if (p->directInputRem == 0)
+ p->streamEndWasReached = 1;
+ return;
+ }
+
+ for (;;)
+ {
+ Byte *dest = p->buffer + GET_AVAIL_BYTES(p);
+ size_t size = (size_t)(p->bufferBase + p->blockSize - dest);
+ if (size == 0)
+ {
+ /* we call ReadBlock() after NeedMove() and MoveBlock().
+ NeedMove() and MoveBlock() povide more than (keepSizeAfter)
+ to the end of (blockSize).
+ So we don't execute this branch in normal code flow.
+ We can go here, if we will call ReadBlock() before NeedMove(), MoveBlock().
+ */
+ // p->result = SZ_ERROR_FAIL; // we can show error here
+ return;
+ }
+
+ // #define kRead 3
+ // if (size > kRead) size = kRead; // for debug
+
+ p->result = ISeqInStream_Read(p->stream, dest, &size);
+ if (p->result != SZ_OK)
+ return;
+ if (size == 0)
+ {
+ p->streamEndWasReached = 1;
+ return;
+ }
+ p->streamPos += (UInt32)size;
+ if (GET_AVAIL_BYTES(p) > p->keepSizeAfter)
+ return;
+ /* here and in another (p->keepSizeAfter) checks we keep on 1 byte more than was requested by Create() function
+ (GET_AVAIL_BYTES(p) >= p->keepSizeAfter) - minimal required size */
+ }
+
+ // on exit: (p->result != SZ_OK || p->streamEndWasReached || GET_AVAIL_BYTES(p) > p->keepSizeAfter)
+}
+
+
+
+MY_NO_INLINE
+void MatchFinder_MoveBlock(CMatchFinder *p)
+{
+ const size_t offset = (size_t)(p->buffer - p->bufferBase) - p->keepSizeBefore;
+ const size_t keepBefore = (offset & (kBlockMoveAlign - 1)) + p->keepSizeBefore;
+ p->buffer = p->bufferBase + keepBefore;
+ memmove(p->bufferBase,
+ p->bufferBase + (offset & ~((size_t)kBlockMoveAlign - 1)),
+ keepBefore + (size_t)GET_AVAIL_BYTES(p));
+}
+
+/* We call MoveBlock() before ReadBlock().
+ So MoveBlock() can be wasteful operation, if the whole input data
+ can fit in current block even without calling MoveBlock().
+ in important case where (dataSize <= historySize)
+ condition (p->blockSize > dataSize + p->keepSizeAfter) is met
+ So there is no MoveBlock() in that case case.
+*/
+
+int MatchFinder_NeedMove(CMatchFinder *p)
+{
+ if (p->directInput)
+ return 0;
+ if (p->streamEndWasReached || p->result != SZ_OK)
+ return 0;
+ return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
+}
+
+void MatchFinder_ReadIfRequired(CMatchFinder *p)
+{
+ if (p->keepSizeAfter >= GET_AVAIL_BYTES(p))
+ MatchFinder_ReadBlock(p);
+}
+
+
+
+static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
+{
+ p->cutValue = 32;
+ p->btMode = 1;
+ p->numHashBytes = 4;
+ p->bigHash = 0;
+}
+
+#define kCrcPoly 0xEDB88320
+
+void MatchFinder_Construct(CMatchFinder *p)
+{
+ unsigned i;
+ p->bufferBase = NULL;
+ p->directInput = 0;
+ p->hash = NULL;
+ p->expectedDataSize = (UInt64)(Int64)-1;
+ MatchFinder_SetDefaultSettings(p);
+
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = (UInt32)i;
+ unsigned j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1)));
+ p->crc[i] = r;
+ }
+}
+
+static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->hash);
+ p->hash = NULL;
+}
+
+void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc)
+{
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ LzInWindow_Free(p, alloc);
+}
+
+static CLzRef* AllocRefs(size_t num, ISzAllocPtr alloc)
+{
+ size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
+ if (sizeInBytes / sizeof(CLzRef) != num)
+ return NULL;
+ return (CLzRef *)ISzAlloc_Alloc(alloc, sizeInBytes);
+}
+
+#if (kBlockSizeReserveMin < kBlockSizeAlign * 2)
+ #error Stop_Compiling_Bad_Reserve
+#endif
+
+
+
+static UInt32 GetBlockSize(CMatchFinder *p, UInt32 historySize)
+{
+ UInt32 blockSize = (p->keepSizeBefore + p->keepSizeAfter);
+ /*
+ if (historySize > kMaxHistorySize)
+ return 0;
+ */
+ // printf("\nhistorySize == 0x%x\n", historySize);
+
+ if (p->keepSizeBefore < historySize || blockSize < p->keepSizeBefore) // if 32-bit overflow
+ return 0;
+
+ {
+ const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)kBlockSizeAlign;
+ const UInt32 rem = kBlockSizeMax - blockSize;
+ const UInt32 reserve = (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2))
+ + (1 << 12) + kBlockMoveAlign + kBlockSizeAlign; // do not overflow 32-bit here
+ if (blockSize >= kBlockSizeMax
+ || rem < kBlockSizeReserveMin) // we reject settings that will be slow
+ return 0;
+ if (reserve >= rem)
+ blockSize = kBlockSizeMax;
+ else
+ {
+ blockSize += reserve;
+ blockSize &= ~(UInt32)(kBlockSizeAlign - 1);
+ }
+ }
+ // printf("\n LzFind_blockSize = %x\n", blockSize);
+ // printf("\n LzFind_blockSize = %d\n", blockSize >> 20);
+ return blockSize;
+}
+
+
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+ ISzAllocPtr alloc)
+{
+ /* we need one additional byte in (p->keepSizeBefore),
+ since we use MoveBlock() after (p->pos++) and before dictionary using */
+ // keepAddBufferBefore = (UInt32)0xFFFFFFFF - (1 << 22); // for debug
+ p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
+
+ keepAddBufferAfter += matchMaxLen;
+ /* we need (p->keepSizeAfter >= p->numHashBytes) */
+ if (keepAddBufferAfter < p->numHashBytes)
+ keepAddBufferAfter = p->numHashBytes;
+ // keepAddBufferAfter -= 2; // for debug
+ p->keepSizeAfter = keepAddBufferAfter;
+
+ if (p->directInput)
+ p->blockSize = 0;
+ if (p->directInput || LzInWindow_Create2(p, GetBlockSize(p, historySize), alloc))
+ {
+ const UInt32 newCyclicBufferSize = historySize + 1; // do not change it
+ UInt32 hs;
+ p->matchMaxLen = matchMaxLen;
+ {
+ // UInt32 hs4;
+ p->fixedHashSize = 0;
+ hs = (1 << 16) - 1;
+ if (p->numHashBytes != 2)
+ {
+ hs = historySize;
+ if (hs > p->expectedDataSize)
+ hs = (UInt32)p->expectedDataSize;
+ if (hs != 0)
+ hs--;
+ hs |= (hs >> 1);
+ hs |= (hs >> 2);
+ hs |= (hs >> 4);
+ hs |= (hs >> 8);
+ // we propagated 16 bits in (hs). Low 16 bits must be set later
+ hs >>= 1;
+ if (hs >= (1 << 24))
+ {
+ if (p->numHashBytes == 3)
+ hs = (1 << 24) - 1;
+ else
+ hs >>= 1;
+ /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */
+ }
+
+ // hs = ((UInt32)1 << 25) - 1; // for test
+
+ // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2)
+ hs |= (1 << 16) - 1; /* don't change it! */
+
+ // bt5: we adjust the size with recommended minimum size
+ if (p->numHashBytes >= 5)
+ hs |= (256 << kLzHash_CrcShift_2) - 1;
+ }
+ p->hashMask = hs;
+ hs++;
+
+ /*
+ hs4 = (1 << 20);
+ if (hs4 > hs)
+ hs4 = hs;
+ // hs4 = (1 << 16); // for test
+ p->hash4Mask = hs4 - 1;
+ */
+
+ if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
+ if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
+ // if (p->numHashBytes > 4) p->fixedHashSize += hs4; // kHash4Size;
+ hs += p->fixedHashSize;
+ }
+
+ {
+ size_t newSize;
+ size_t numSons;
+ p->historySize = historySize;
+ p->hashSizeSum = hs;
+ p->cyclicBufferSize = newCyclicBufferSize; // it must be = (historySize + 1)
+
+ numSons = newCyclicBufferSize;
+ if (p->btMode)
+ numSons <<= 1;
+ newSize = hs + numSons;
+
+ // aligned size is not required here, but it can be better for some loops
+ #define NUM_REFS_ALIGN_MASK 0xF
+ newSize = (newSize + NUM_REFS_ALIGN_MASK) & ~(size_t)NUM_REFS_ALIGN_MASK;
+
+ if (p->hash && p->numRefs == newSize)
+ return 1;
+
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ p->numRefs = newSize;
+ p->hash = AllocRefs(newSize, alloc);
+
+ if (p->hash)
+ {
+ p->son = p->hash + p->hashSizeSum;
+ return 1;
+ }
+ }
+ }
+
+ MatchFinder_Free(p, alloc);
+ return 0;
+}
+
+
+static void MatchFinder_SetLimits(CMatchFinder *p)
+{
+ UInt32 k;
+ UInt32 n = kMaxValForNormalize - p->pos;
+ if (n == 0)
+ n = (UInt32)(Int32)-1; // we allow (pos == 0) at start even with (kMaxValForNormalize == 0)
+
+ k = p->cyclicBufferSize - p->cyclicBufferPos;
+ if (k < n)
+ n = k;
+
+ k = GET_AVAIL_BYTES(p);
+ {
+ const UInt32 ksa = p->keepSizeAfter;
+ UInt32 mm = p->matchMaxLen;
+ if (k > ksa)
+ k -= ksa; // we must limit exactly to keepSizeAfter for ReadBlock
+ else if (k >= mm)
+ {
+ // the limitation for (p->lenLimit) update
+ k -= mm; // optimization : to reduce the number of checks
+ k++;
+ // k = 1; // non-optimized version : for debug
+ }
+ else
+ {
+ mm = k;
+ if (k != 0)
+ k = 1;
+ }
+ p->lenLimit = mm;
+ }
+ if (k < n)
+ n = k;
+
+ p->posLimit = p->pos + n;
+}
+
+
+void MatchFinder_Init_LowHash(CMatchFinder *p)
+{
+ size_t i;
+ CLzRef *items = p->hash;
+ const size_t numItems = p->fixedHashSize;
+ for (i = 0; i < numItems; i++)
+ items[i] = kEmptyHashValue;
+}
+
+
+void MatchFinder_Init_HighHash(CMatchFinder *p)
+{
+ size_t i;
+ CLzRef *items = p->hash + p->fixedHashSize;
+ const size_t numItems = (size_t)p->hashMask + 1;
+ for (i = 0; i < numItems; i++)
+ items[i] = kEmptyHashValue;
+}
+
+
+void MatchFinder_Init_4(CMatchFinder *p)
+{
+ p->buffer = p->bufferBase;
+ {
+ /* kEmptyHashValue = 0 (Zero) is used in hash tables as NO-VALUE marker.
+ the code in CMatchFinderMt expects (pos = 1) */
+ p->pos =
+ p->streamPos =
+ 1; // it's smallest optimal value. do not change it
+ // 0; // for debug
+ }
+ p->result = SZ_OK;
+ p->streamEndWasReached = 0;
+}
+
+
+// (CYC_TO_POS_OFFSET == 0) is expected by some optimized code
+#define CYC_TO_POS_OFFSET 0
+// #define CYC_TO_POS_OFFSET 1 // for debug
+
+void MatchFinder_Init(CMatchFinder *p)
+{
+ MatchFinder_Init_HighHash(p);
+ MatchFinder_Init_LowHash(p);
+ MatchFinder_Init_4(p);
+ // if (readData)
+ MatchFinder_ReadBlock(p);
+
+ /* if we init (cyclicBufferPos = pos), then we can use one variable
+ instead of both (cyclicBufferPos) and (pos) : only before (cyclicBufferPos) wrapping */
+ p->cyclicBufferPos = (p->pos - CYC_TO_POS_OFFSET); // init with relation to (pos)
+ // p->cyclicBufferPos = 0; // smallest value
+ // p->son[0] = p->son[1] = 0; // unused: we can init skipped record for speculated accesses.
+ MatchFinder_SetLimits(p);
+}
+
+
+
+#ifdef MY_CPU_X86_OR_AMD64
+ #if defined(__clang__) && (__clang_major__ >= 8) \
+ || defined(__GNUC__) && (__GNUC__ >= 8) \
+ || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1900)
+ #define USE_SATUR_SUB_128
+ #define USE_AVX2
+ #define ATTRIB_SSE41 __attribute__((__target__("sse4.1")))
+ #define ATTRIB_AVX2 __attribute__((__target__("avx2")))
+ #elif defined(_MSC_VER)
+ #if (_MSC_VER >= 1600)
+ #define USE_SATUR_SUB_128
+ #if (_MSC_VER >= 1900)
+ #define USE_AVX2
+ #include <immintrin.h> // avx
+ #endif
+ #endif
+ #endif
+
+// #elif defined(MY_CPU_ARM_OR_ARM64)
+#elif defined(MY_CPU_ARM64)
+
+ #if defined(__clang__) && (__clang_major__ >= 8) \
+ || defined(__GNUC__) && (__GNUC__ >= 8)
+ #define USE_SATUR_SUB_128
+ #ifdef MY_CPU_ARM64
+ // #define ATTRIB_SSE41 __attribute__((__target__("")))
+ #else
+ // #define ATTRIB_SSE41 __attribute__((__target__("fpu=crypto-neon-fp-armv8")))
+ #endif
+
+ #elif defined(_MSC_VER)
+ #if (_MSC_VER >= 1910)
+ #define USE_SATUR_SUB_128
+ #endif
+ #endif
+
+ #if defined(_MSC_VER) && defined(MY_CPU_ARM64)
+ #include <arm64_neon.h>
+ #else
+ #include <arm_neon.h>
+ #endif
+
+#endif
+
+/*
+#ifndef ATTRIB_SSE41
+ #define ATTRIB_SSE41
+#endif
+#ifndef ATTRIB_AVX2
+ #define ATTRIB_AVX2
+#endif
+*/
+
+#ifdef USE_SATUR_SUB_128
+
+// #define _SHOW_HW_STATUS
+
+#ifdef _SHOW_HW_STATUS
+#include <stdio.h>
+#define _PRF(x) x
+_PRF(;)
+#else
+#define _PRF(x)
+#endif
+
+#ifdef MY_CPU_ARM_OR_ARM64
+
+#ifdef MY_CPU_ARM64
+// #define FORCE_SATUR_SUB_128
+#endif
+
+typedef uint32x4_t v128;
+#define SASUB_128(i) \
+ *(v128 *)(void *)(items + (i) * 4) = \
+ vsubq_u32(vmaxq_u32(*(const v128 *)(const void *)(items + (i) * 4), sub2), sub2);
+
+#else
+
+#include <smmintrin.h> // sse4.1
+
+typedef __m128i v128;
+#define SASUB_128(i) \
+ *(v128 *)(void *)(items + (i) * 4) = \
+ _mm_sub_epi32(_mm_max_epu32(*(const v128 *)(const void *)(items + (i) * 4), sub2), sub2); // SSE 4.1
+
+#endif
+
+
+
+MY_NO_INLINE
+static
+#ifdef ATTRIB_SSE41
+ATTRIB_SSE41
+#endif
+void
+MY_FAST_CALL
+LzFind_SaturSub_128(UInt32 subValue, CLzRef *items, const CLzRef *lim)
+{
+ v128 sub2 =
+ #ifdef MY_CPU_ARM_OR_ARM64
+ vdupq_n_u32(subValue);
+ #else
+ _mm_set_epi32((Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue);
+ #endif
+ do
+ {
+ SASUB_128(0)
+ SASUB_128(1)
+ SASUB_128(2)
+ SASUB_128(3)
+ items += 4 * 4;
+ }
+ while (items != lim);
+}
+
+
+
+#ifdef USE_AVX2
+
+#include <immintrin.h> // avx
+
+#define SASUB_256(i) *(__m256i *)(void *)(items + (i) * 8) = _mm256_sub_epi32(_mm256_max_epu32(*(const __m256i *)(const void *)(items + (i) * 8), sub2), sub2); // AVX2
+
+MY_NO_INLINE
+static
+#ifdef ATTRIB_AVX2
+ATTRIB_AVX2
+#endif
+void
+MY_FAST_CALL
+LzFind_SaturSub_256(UInt32 subValue, CLzRef *items, const CLzRef *lim)
+{
+ __m256i sub2 = _mm256_set_epi32(
+ (Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue,
+ (Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue);
+ do
+ {
+ SASUB_256(0)
+ SASUB_256(1)
+ items += 2 * 8;
+ }
+ while (items != lim);
+}
+#endif // USE_AVX2
+
+#ifndef FORCE_SATUR_SUB_128
+typedef void (MY_FAST_CALL *LZFIND_SATUR_SUB_CODE_FUNC)(
+ UInt32 subValue, CLzRef *items, const CLzRef *lim);
+static LZFIND_SATUR_SUB_CODE_FUNC g_LzFind_SaturSub;
+#endif // FORCE_SATUR_SUB_128
+
+#endif // USE_SATUR_SUB_128
+
+
+// kEmptyHashValue must be zero
+// #define SASUB_32(i) v = items[i]; m = v - subValue; if (v < subValue) m = kEmptyHashValue; items[i] = m;
+#define SASUB_32(i) v = items[i]; if (v < subValue) v = subValue; items[i] = v - subValue;
+
+#ifdef FORCE_SATUR_SUB_128
+
+#define DEFAULT_SaturSub LzFind_SaturSub_128
+
+#else
+
+#define DEFAULT_SaturSub LzFind_SaturSub_32
+
+MY_NO_INLINE
+static
+void
+MY_FAST_CALL
+LzFind_SaturSub_32(UInt32 subValue, CLzRef *items, const CLzRef *lim)
+{
+ do
+ {
+ UInt32 v;
+ SASUB_32(0)
+ SASUB_32(1)
+ SASUB_32(2)
+ SASUB_32(3)
+ SASUB_32(4)
+ SASUB_32(5)
+ SASUB_32(6)
+ SASUB_32(7)
+ items += 8;
+ }
+ while (items != lim);
+}
+
+#endif
+
+
+MY_NO_INLINE
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems)
+{
+ #define K_NORM_ALIGN_BLOCK_SIZE (1 << 6)
+
+ CLzRef *lim;
+
+ for (; numItems != 0 && ((unsigned)(ptrdiff_t)items & (K_NORM_ALIGN_BLOCK_SIZE - 1)) != 0; numItems--)
+ {
+ UInt32 v;
+ SASUB_32(0);
+ items++;
+ }
+
+ {
+ #define K_NORM_ALIGN_MASK (K_NORM_ALIGN_BLOCK_SIZE / 4 - 1)
+ lim = items + (numItems & ~(size_t)K_NORM_ALIGN_MASK);
+ numItems &= K_NORM_ALIGN_MASK;
+ if (items != lim)
+ {
+ #if defined(USE_SATUR_SUB_128) && !defined(FORCE_SATUR_SUB_128)
+ if (g_LzFind_SaturSub)
+ g_LzFind_SaturSub(subValue, items, lim);
+ else
+ #endif
+ DEFAULT_SaturSub(subValue, items, lim);
+ }
+ items = lim;
+ }
+
+
+ for (; numItems != 0; numItems--)
+ {
+ UInt32 v;
+ SASUB_32(0);
+ items++;
+ }
+}
+
+
+
+// call MatchFinder_CheckLimits() only after (p->pos++) update
+
+MY_NO_INLINE
+static void MatchFinder_CheckLimits(CMatchFinder *p)
+{
+ if (// !p->streamEndWasReached && p->result == SZ_OK &&
+ p->keepSizeAfter == GET_AVAIL_BYTES(p))
+ {
+ // we try to read only in exact state (p->keepSizeAfter == GET_AVAIL_BYTES(p))
+ if (MatchFinder_NeedMove(p))
+ MatchFinder_MoveBlock(p);
+ MatchFinder_ReadBlock(p);
+ }
+
+ if (p->pos == kMaxValForNormalize)
+ if (GET_AVAIL_BYTES(p) >= p->numHashBytes) // optional optimization for last bytes of data.
+ /*
+ if we disable normalization for last bytes of data, and
+ if (data_size == 4 GiB), we don't call wastfull normalization,
+ but (pos) will be wrapped over Zero (0) in that case.
+ And we cannot resume later to normal operation
+ */
+ {
+ // MatchFinder_Normalize(p);
+ /* after normalization we need (p->pos >= p->historySize + 1); */
+ /* we can reduce subValue to aligned value, if want to keep alignment
+ of (p->pos) and (p->buffer) for speculated accesses. */
+ const UInt32 subValue = (p->pos - p->historySize - 1) /* & ~(UInt32)(kNormalizeAlign - 1) */;
+ // const UInt32 subValue = (1 << 15); // for debug
+ // printf("\nMatchFinder_Normalize() subValue == 0x%x\n", subValue);
+ size_t numSonRefs = p->cyclicBufferSize;
+ if (p->btMode)
+ numSonRefs <<= 1;
+ Inline_MatchFinder_ReduceOffsets(p, subValue);
+ MatchFinder_Normalize3(subValue, p->hash, (size_t)p->hashSizeSum + numSonRefs);
+ }
+
+ if (p->cyclicBufferPos == p->cyclicBufferSize)
+ p->cyclicBufferPos = 0;
+
+ MatchFinder_SetLimits(p);
+}
+
+
+/*
+ (lenLimit > maxLen)
+*/
+MY_FORCE_INLINE
+static UInt32 * Hc_GetMatchesSpec(size_t lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+ UInt32 *d, unsigned maxLen)
+{
+ /*
+ son[_cyclicBufferPos] = curMatch;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ return d;
+ {
+ const Byte *pb = cur - delta;
+ curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+ if (pb[maxLen] == cur[maxLen] && *pb == *cur)
+ {
+ UInt32 len = 0;
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ maxLen = len;
+ *d++ = len;
+ *d++ = delta - 1;
+ if (len == lenLimit)
+ return d;
+ }
+ }
+ }
+ }
+ */
+
+ const Byte *lim = cur + lenLimit;
+ son[_cyclicBufferPos] = curMatch;
+
+ do
+ {
+ UInt32 delta;
+
+ if (curMatch == 0)
+ break;
+ // if (curMatch2 >= curMatch) return NULL;
+ delta = pos - curMatch;
+ if (delta >= _cyclicBufferSize)
+ break;
+ {
+ ptrdiff_t diff;
+ curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+ diff = (ptrdiff_t)0 - (ptrdiff_t)delta;
+ if (cur[maxLen] == cur[(ptrdiff_t)maxLen + diff])
+ {
+ const Byte *c = cur;
+ while (*c == c[diff])
+ {
+ if (++c == lim)
+ {
+ d[0] = (UInt32)(lim - cur);
+ d[1] = delta - 1;
+ return d + 2;
+ }
+ }
+ {
+ const unsigned len = (unsigned)(c - cur);
+ if (maxLen < len)
+ {
+ maxLen = len;
+ d[0] = (UInt32)len;
+ d[1] = delta - 1;
+ d += 2;
+ }
+ }
+ }
+ }
+ }
+ while (--cutValue);
+
+ return d;
+}
+
+
+MY_FORCE_INLINE
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+ UInt32 *d, UInt32 maxLen)
+{
+ CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
+ unsigned len0 = 0, len1 = 0;
+
+ UInt32 cmCheck;
+
+ // if (curMatch >= pos) { *ptr0 = *ptr1 = kEmptyHashValue; return NULL; }
+
+ cmCheck = (UInt32)(pos - _cyclicBufferSize);
+ if ((UInt32)pos <= _cyclicBufferSize)
+ cmCheck = 0;
+
+ if (cmCheck < curMatch)
+ do
+ {
+ const UInt32 delta = pos - curMatch;
+ {
+ CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ unsigned len = (len0 < len1 ? len0 : len1);
+ const UInt32 pair0 = pair[0];
+ if (pb[len] == cur[len])
+ {
+ if (++len != lenLimit && pb[len] == cur[len])
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ maxLen = (UInt32)len;
+ *d++ = (UInt32)len;
+ *d++ = delta - 1;
+ if (len == lenLimit)
+ {
+ *ptr1 = pair0;
+ *ptr0 = pair[1];
+ return d;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ // const UInt32 curMatch2 = pair[1];
+ // if (curMatch2 >= curMatch) { *ptr0 = *ptr1 = kEmptyHashValue; return NULL; }
+ // curMatch = curMatch2;
+ curMatch = pair[1];
+ ptr1 = pair + 1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ curMatch = pair[0];
+ ptr0 = pair;
+ len0 = len;
+ }
+ }
+ }
+ while(--cutValue && cmCheck < curMatch);
+
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ return d;
+}
+
+
+static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
+{
+ CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
+ unsigned len0 = 0, len1 = 0;
+
+ UInt32 cmCheck;
+
+ cmCheck = (UInt32)(pos - _cyclicBufferSize);
+ if ((UInt32)pos <= _cyclicBufferSize)
+ cmCheck = 0;
+
+ if (// curMatch >= pos || // failure
+ cmCheck < curMatch)
+ do
+ {
+ const UInt32 delta = pos - curMatch;
+ {
+ CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ unsigned len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ {
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ curMatch = pair[1];
+ ptr1 = pair + 1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ curMatch = pair[0];
+ ptr0 = pair;
+ len0 = len;
+ }
+ }
+ }
+ while(--cutValue && cmCheck < curMatch);
+
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ return;
+}
+
+
+#define MOVE_POS \
+ ++p->cyclicBufferPos; \
+ p->buffer++; \
+ { const UInt32 pos1 = p->pos + 1; p->pos = pos1; if (pos1 == p->posLimit) MatchFinder_CheckLimits(p); }
+
+#define MOVE_POS_RET MOVE_POS return distances;
+
+MY_NO_INLINE
+static void MatchFinder_MovePos(CMatchFinder *p)
+{
+ /* we go here at the end of stream data, when (avail < num_hash_bytes)
+ We don't update sons[cyclicBufferPos << btMode].
+ So (sons) record will contain junk. And we cannot resume match searching
+ to normal operation, even if we will provide more input data in buffer.
+ p->sons[p->cyclicBufferPos << p->btMode] = 0; // kEmptyHashValue
+ if (p->btMode)
+ p->sons[(p->cyclicBufferPos << p->btMode) + 1] = 0; // kEmptyHashValue
+ */
+ MOVE_POS;
+}
+
+#define GET_MATCHES_HEADER2(minLen, ret_op) \
+ unsigned lenLimit; UInt32 hv; Byte *cur; UInt32 curMatch; \
+ lenLimit = (unsigned)p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
+ cur = p->buffer;
+
+#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return distances)
+#define SKIP_HEADER(minLen) do { GET_MATCHES_HEADER2(minLen, continue)
+
+#define MF_PARAMS(p) lenLimit, curMatch, p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
+
+#define SKIP_FOOTER SkipMatchesSpec(MF_PARAMS(p)); MOVE_POS; } while (--num);
+
+#define GET_MATCHES_FOOTER_BASE(_maxLen_, func) \
+ distances = func(MF_PARAMS(p), \
+ distances, (UInt32)_maxLen_); MOVE_POS_RET;
+
+#define GET_MATCHES_FOOTER_BT(_maxLen_) \
+ GET_MATCHES_FOOTER_BASE(_maxLen_, GetMatchesSpec1)
+
+#define GET_MATCHES_FOOTER_HC(_maxLen_) \
+ GET_MATCHES_FOOTER_BASE(_maxLen_, Hc_GetMatchesSpec)
+
+
+
+#define UPDATE_maxLen { \
+ const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)d2; \
+ const Byte *c = cur + maxLen; \
+ const Byte *lim = cur + lenLimit; \
+ for (; c != lim; c++) if (*(c + diff) != *c) break; \
+ maxLen = (unsigned)(c - cur); }
+
+static UInt32* Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ GET_MATCHES_HEADER(2)
+ HASH2_CALC;
+ curMatch = p->hash[hv];
+ p->hash[hv] = p->pos;
+ GET_MATCHES_FOOTER_BT(1)
+}
+
+UInt32* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ GET_MATCHES_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hv];
+ p->hash[hv] = p->pos;
+ GET_MATCHES_FOOTER_BT(2)
+}
+
+
+#define SET_mmm \
+ mmm = p->cyclicBufferSize; \
+ if (pos < mmm) \
+ mmm = pos;
+
+
+static UInt32* Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 mmm;
+ UInt32 h2, d2, pos;
+ unsigned maxLen;
+ UInt32 *hash;
+ GET_MATCHES_HEADER(3)
+
+ HASH3_CALC;
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash[h2];
+
+ curMatch = (hash + kFix3HashSize)[hv];
+
+ hash[h2] = pos;
+ (hash + kFix3HashSize)[hv] = pos;
+
+ SET_mmm
+
+ maxLen = 2;
+
+ if (d2 < mmm && *(cur - d2) == *cur)
+ {
+ UPDATE_maxLen
+ distances[0] = (UInt32)maxLen;
+ distances[1] = d2 - 1;
+ distances += 2;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(MF_PARAMS(p));
+ MOVE_POS_RET;
+ }
+ }
+
+ GET_MATCHES_FOOTER_BT(maxLen)
+}
+
+
+static UInt32* Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 mmm;
+ UInt32 h2, h3, d2, d3, pos;
+ unsigned maxLen;
+ UInt32 *hash;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC;
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash [h2];
+ d3 = pos - (hash + kFix3HashSize)[h3];
+ curMatch = (hash + kFix4HashSize)[hv];
+
+ hash [h2] = pos;
+ (hash + kFix3HashSize)[h3] = pos;
+ (hash + kFix4HashSize)[hv] = pos;
+
+ SET_mmm
+
+ maxLen = 3;
+
+ for (;;)
+ {
+ if (d2 < mmm && *(cur - d2) == *cur)
+ {
+ distances[0] = 2;
+ distances[1] = d2 - 1;
+ distances += 2;
+ if (*(cur - d2 + 2) == cur[2])
+ {
+ // distances[-2] = 3;
+ }
+ else if (d3 < mmm && *(cur - d3) == *cur)
+ {
+ d2 = d3;
+ distances[1] = d3 - 1;
+ distances += 2;
+ }
+ else
+ break;
+ }
+ else if (d3 < mmm && *(cur - d3) == *cur)
+ {
+ d2 = d3;
+ distances[1] = d3 - 1;
+ distances += 2;
+ }
+ else
+ break;
+
+ UPDATE_maxLen
+ distances[-2] = (UInt32)maxLen;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(MF_PARAMS(p));
+ MOVE_POS_RET
+ }
+ break;
+ }
+
+ GET_MATCHES_FOOTER_BT(maxLen)
+}
+
+
+static UInt32* Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 mmm;
+ UInt32 h2, h3, d2, d3, maxLen, pos;
+ UInt32 *hash;
+ GET_MATCHES_HEADER(5)
+
+ HASH5_CALC;
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash [h2];
+ d3 = pos - (hash + kFix3HashSize)[h3];
+ // d4 = pos - (hash + kFix4HashSize)[h4];
+
+ curMatch = (hash + kFix5HashSize)[hv];
+
+ hash [h2] = pos;
+ (hash + kFix3HashSize)[h3] = pos;
+ // (hash + kFix4HashSize)[h4] = pos;
+ (hash + kFix5HashSize)[hv] = pos;
+
+ SET_mmm
+
+ maxLen = 4;
+
+ for (;;)
+ {
+ if (d2 < mmm && *(cur - d2) == *cur)
+ {
+ distances[0] = 2;
+ distances[1] = d2 - 1;
+ distances += 2;
+ if (*(cur - d2 + 2) == cur[2])
+ {
+ }
+ else if (d3 < mmm && *(cur - d3) == *cur)
+ {
+ distances[1] = d3 - 1;
+ distances += 2;
+ d2 = d3;
+ }
+ else
+ break;
+ }
+ else if (d3 < mmm && *(cur - d3) == *cur)
+ {
+ distances[1] = d3 - 1;
+ distances += 2;
+ d2 = d3;
+ }
+ else
+ break;
+
+ distances[-2] = 3;
+ if (*(cur - d2 + 3) != cur[3])
+ break;
+ UPDATE_maxLen
+ distances[-2] = (UInt32)maxLen;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(MF_PARAMS(p));
+ MOVE_POS_RET;
+ }
+ break;
+ }
+
+ GET_MATCHES_FOOTER_BT(maxLen)
+}
+
+
+static UInt32* Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 mmm;
+ UInt32 h2, h3, d2, d3, pos;
+ unsigned maxLen;
+ UInt32 *hash;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC;
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash [h2];
+ d3 = pos - (hash + kFix3HashSize)[h3];
+ curMatch = (hash + kFix4HashSize)[hv];
+
+ hash [h2] = pos;
+ (hash + kFix3HashSize)[h3] = pos;
+ (hash + kFix4HashSize)[hv] = pos;
+
+ SET_mmm
+
+ maxLen = 3;
+
+ for (;;)
+ {
+ if (d2 < mmm && *(cur - d2) == *cur)
+ {
+ distances[0] = 2;
+ distances[1] = d2 - 1;
+ distances += 2;
+ if (*(cur - d2 + 2) == cur[2])
+ {
+ // distances[-2] = 3;
+ }
+ else if (d3 < mmm && *(cur - d3) == *cur)
+ {
+ d2 = d3;
+ distances[1] = d3 - 1;
+ distances += 2;
+ }
+ else
+ break;
+ }
+ else if (d3 < mmm && *(cur - d3) == *cur)
+ {
+ d2 = d3;
+ distances[1] = d3 - 1;
+ distances += 2;
+ }
+ else
+ break;
+
+ UPDATE_maxLen
+ distances[-2] = (UInt32)maxLen;
+ if (maxLen == lenLimit)
+ {
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS_RET;
+ }
+ break;
+ }
+
+ GET_MATCHES_FOOTER_HC(maxLen);
+}
+
+
+static UInt32 * Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 mmm;
+ UInt32 h2, h3, d2, d3, maxLen, pos;
+ UInt32 *hash;
+ GET_MATCHES_HEADER(5)
+
+ HASH5_CALC;
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash [h2];
+ d3 = pos - (hash + kFix3HashSize)[h3];
+ // d4 = pos - (hash + kFix4HashSize)[h4];
+
+ curMatch = (hash + kFix5HashSize)[hv];
+
+ hash [h2] = pos;
+ (hash + kFix3HashSize)[h3] = pos;
+ // (hash + kFix4HashSize)[h4] = pos;
+ (hash + kFix5HashSize)[hv] = pos;
+
+ SET_mmm
+
+ maxLen = 4;
+
+ for (;;)
+ {
+ if (d2 < mmm && *(cur - d2) == *cur)
+ {
+ distances[0] = 2;
+ distances[1] = d2 - 1;
+ distances += 2;
+ if (*(cur - d2 + 2) == cur[2])
+ {
+ }
+ else if (d3 < mmm && *(cur - d3) == *cur)
+ {
+ distances[1] = d3 - 1;
+ distances += 2;
+ d2 = d3;
+ }
+ else
+ break;
+ }
+ else if (d3 < mmm && *(cur - d3) == *cur)
+ {
+ distances[1] = d3 - 1;
+ distances += 2;
+ d2 = d3;
+ }
+ else
+ break;
+
+ distances[-2] = 3;
+ if (*(cur - d2 + 3) != cur[3])
+ break;
+ UPDATE_maxLen
+ distances[-2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS_RET;
+ }
+ break;
+ }
+
+ GET_MATCHES_FOOTER_HC(maxLen);
+}
+
+
+UInt32* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ GET_MATCHES_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hv];
+ p->hash[hv] = p->pos;
+ GET_MATCHES_FOOTER_HC(2)
+}
+
+
+static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ SKIP_HEADER(2)
+ {
+ HASH2_CALC;
+ curMatch = p->hash[hv];
+ p->hash[hv] = p->pos;
+ }
+ SKIP_FOOTER
+}
+
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ SKIP_HEADER(3)
+ {
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hv];
+ p->hash[hv] = p->pos;
+ }
+ SKIP_FOOTER
+}
+
+static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ SKIP_HEADER(3)
+ {
+ UInt32 h2;
+ UInt32 *hash;
+ HASH3_CALC;
+ hash = p->hash;
+ curMatch = (hash + kFix3HashSize)[hv];
+ hash[h2] =
+ (hash + kFix3HashSize)[hv] = p->pos;
+ }
+ SKIP_FOOTER
+}
+
+static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ SKIP_HEADER(4)
+ {
+ UInt32 h2, h3;
+ UInt32 *hash;
+ HASH4_CALC;
+ hash = p->hash;
+ curMatch = (hash + kFix4HashSize)[hv];
+ hash [h2] =
+ (hash + kFix3HashSize)[h3] =
+ (hash + kFix4HashSize)[hv] = p->pos;
+ }
+ SKIP_FOOTER
+}
+
+static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ SKIP_HEADER(5)
+ {
+ UInt32 h2, h3;
+ UInt32 *hash;
+ HASH5_CALC;
+ hash = p->hash;
+ curMatch = (hash + kFix5HashSize)[hv];
+ hash [h2] =
+ (hash + kFix3HashSize)[h3] =
+ // (hash + kFix4HashSize)[h4] =
+ (hash + kFix5HashSize)[hv] = p->pos;
+ }
+ SKIP_FOOTER
+}
+
+
+#define HC_SKIP_HEADER(minLen) \
+ do { if (p->lenLimit < minLen) { MatchFinder_MovePos(p); num--; continue; } { \
+ Byte *cur; \
+ UInt32 *hash; \
+ UInt32 *son; \
+ UInt32 pos = p->pos; \
+ UInt32 num2 = num; \
+ /* (p->pos == p->posLimit) is not allowed here !!! */ \
+ { const UInt32 rem = p->posLimit - pos; if (num2 > rem) num2 = rem; } \
+ num -= num2; \
+ { const UInt32 cycPos = p->cyclicBufferPos; \
+ son = p->son + cycPos; \
+ p->cyclicBufferPos = cycPos + num2; } \
+ cur = p->buffer; \
+ hash = p->hash; \
+ do { \
+ UInt32 curMatch; \
+ UInt32 hv;
+
+
+#define HC_SKIP_FOOTER \
+ cur++; pos++; *son++ = curMatch; \
+ } while (--num2); \
+ p->buffer = cur; \
+ p->pos = pos; \
+ if (pos == p->posLimit) MatchFinder_CheckLimits(p); \
+ }} while(num); \
+
+
+static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ HC_SKIP_HEADER(4)
+
+ UInt32 h2, h3;
+ HASH4_CALC;
+ curMatch = (hash + kFix4HashSize)[hv];
+ hash [h2] =
+ (hash + kFix3HashSize)[h3] =
+ (hash + kFix4HashSize)[hv] = pos;
+
+ HC_SKIP_FOOTER
+}
+
+
+static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ HC_SKIP_HEADER(5)
+
+ UInt32 h2, h3;
+ HASH5_CALC
+ curMatch = (hash + kFix5HashSize)[hv];
+ hash [h2] =
+ (hash + kFix3HashSize)[h3] =
+ // (hash + kFix4HashSize)[h4] =
+ (hash + kFix5HashSize)[hv] = pos;
+
+ HC_SKIP_FOOTER
+}
+
+
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ HC_SKIP_HEADER(3)
+
+ HASH_ZIP_CALC;
+ curMatch = hash[hv];
+ hash[hv] = pos;
+
+ HC_SKIP_FOOTER
+}
+
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable)
+{
+ vTable->Init = (Mf_Init_Func)MatchFinder_Init;
+ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+ if (!p->btMode)
+ {
+ if (p->numHashBytes <= 4)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+ }
+ else
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip;
+ }
+ }
+ else if (p->numHashBytes == 2)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
+ }
+ else if (p->numHashBytes == 3)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
+ }
+ else if (p->numHashBytes == 4)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+ }
+ else
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip;
+ }
+}
+
+
+
+void LzFindPrepare()
+{
+ #ifndef FORCE_SATUR_SUB_128
+ #ifdef USE_SATUR_SUB_128
+ LZFIND_SATUR_SUB_CODE_FUNC f = NULL;
+ #ifdef MY_CPU_ARM_OR_ARM64
+ {
+ if (CPU_IsSupported_NEON())
+ {
+ // #pragma message ("=== LzFind NEON")
+ _PRF(printf("\n=== LzFind NEON\n"));
+ f = LzFind_SaturSub_128;
+ }
+ // f = 0; // for debug
+ }
+ #else // MY_CPU_ARM_OR_ARM64
+ if (CPU_IsSupported_SSE41())
+ {
+ // #pragma message ("=== LzFind SSE41")
+ _PRF(printf("\n=== LzFind SSE41\n"));
+ f = LzFind_SaturSub_128;
+
+ #ifdef USE_AVX2
+ if (CPU_IsSupported_AVX2())
+ {
+ // #pragma message ("=== LzFind AVX2")
+ _PRF(printf("\n=== LzFind AVX2\n"));
+ f = LzFind_SaturSub_256;
+ }
+ #endif
+ }
+ #endif // MY_CPU_ARM_OR_ARM64
+ g_LzFind_SaturSub = f;
+ #endif // USE_SATUR_SUB_128
+ #endif // FORCE_SATUR_SUB_128
+}
diff --git a/src/Common/lzma/LzFind.h b/src/Common/lzma/LzFind.h
new file mode 100644
index 00000000..eea873ff
--- /dev/null
+++ b/src/Common/lzma/LzFind.h
@@ -0,0 +1,136 @@
+/* LzFind.h -- Match finder for LZ algorithms
+2021-07-13 : Igor Pavlov : Public domain */
+
+#ifndef __LZ_FIND_H
+#define __LZ_FIND_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+typedef UInt32 CLzRef;
+
+typedef struct _CMatchFinder
+{
+ Byte *buffer;
+ UInt32 pos;
+ UInt32 posLimit;
+ UInt32 streamPos; /* wrap over Zero is allowed (streamPos < pos). Use (UInt32)(streamPos - pos) */
+ UInt32 lenLimit;
+
+ UInt32 cyclicBufferPos;
+ UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
+
+ Byte streamEndWasReached;
+ Byte btMode;
+ Byte bigHash;
+ Byte directInput;
+
+ UInt32 matchMaxLen;
+ CLzRef *hash;
+ CLzRef *son;
+ UInt32 hashMask;
+ UInt32 cutValue;
+
+ Byte *bufferBase;
+ ISeqInStream *stream;
+
+ UInt32 blockSize;
+ UInt32 keepSizeBefore;
+ UInt32 keepSizeAfter;
+
+ UInt32 numHashBytes;
+ size_t directInputRem;
+ UInt32 historySize;
+ UInt32 fixedHashSize;
+ UInt32 hashSizeSum;
+ SRes result;
+ UInt32 crc[256];
+ size_t numRefs;
+
+ UInt64 expectedDataSize;
+} CMatchFinder;
+
+#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((const Byte *)(p)->buffer)
+
+#define Inline_MatchFinder_GetNumAvailableBytes(p) ((UInt32)((p)->streamPos - (p)->pos))
+
+/*
+#define Inline_MatchFinder_IsFinishedOK(p) \
+ ((p)->streamEndWasReached \
+ && (p)->streamPos == (p)->pos \
+ && (!(p)->directInput || (p)->directInputRem == 0))
+*/
+
+int MatchFinder_NeedMove(CMatchFinder *p);
+/* Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); */
+void MatchFinder_MoveBlock(CMatchFinder *p);
+void MatchFinder_ReadIfRequired(CMatchFinder *p);
+
+void MatchFinder_Construct(CMatchFinder *p);
+
+/* Conditions:
+ historySize <= 3 GB
+ keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
+*/
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+ ISzAllocPtr alloc);
+void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc);
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems);
+// void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
+
+/*
+#define Inline_MatchFinder_InitPos(p, val) \
+ (p)->pos = (val); \
+ (p)->streamPos = (val);
+*/
+
+#define Inline_MatchFinder_ReduceOffsets(p, subValue) \
+ (p)->pos -= (subValue); \
+ (p)->streamPos -= (subValue);
+
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
+ size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
+ UInt32 *distances, UInt32 maxLen);
+
+/*
+Conditions:
+ Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
+ Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
+*/
+
+typedef void (*Mf_Init_Func)(void *object);
+typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
+typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
+typedef UInt32 * (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
+typedef void (*Mf_Skip_Func)(void *object, UInt32);
+
+typedef struct _IMatchFinder
+{
+ Mf_Init_Func Init;
+ Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
+ Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
+ Mf_GetMatches_Func GetMatches;
+ Mf_Skip_Func Skip;
+} IMatchFinder2;
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable);
+
+void MatchFinder_Init_LowHash(CMatchFinder *p);
+void MatchFinder_Init_HighHash(CMatchFinder *p);
+void MatchFinder_Init_4(CMatchFinder *p);
+void MatchFinder_Init(CMatchFinder *p);
+
+UInt32* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+UInt32* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+
+void LzFindPrepare(void);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/Common/lzma/LzFindMt.c b/src/Common/lzma/LzFindMt.c
new file mode 100644
index 00000000..4e67fc3f
--- /dev/null
+++ b/src/Common/lzma/LzFindMt.c
@@ -0,0 +1,1400 @@
+/* LzFindMt.c -- multithreaded Match finder for LZ algorithms
+2021-12-21 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+// #include <stdio.h>
+
+#include "CpuArch.h"
+
+#include "LzHash.h"
+#include "LzFindMt.h"
+
+// #define LOG_ITERS
+
+// #define LOG_THREAD
+
+#ifdef LOG_THREAD
+#include <stdio.h>
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#ifdef LOG_ITERS
+#include <stdio.h>
+extern UInt64 g_NumIters_Tree;
+extern UInt64 g_NumIters_Loop;
+extern UInt64 g_NumIters_Bytes;
+#define LOG_ITER(x) x
+#else
+#define LOG_ITER(x)
+#endif
+
+#define kMtHashBlockSize ((UInt32)1 << 17)
+#define kMtHashNumBlocks (1 << 1)
+
+#define GET_HASH_BLOCK_OFFSET(i) (((i) & (kMtHashNumBlocks - 1)) * kMtHashBlockSize)
+
+#define kMtBtBlockSize ((UInt32)1 << 16)
+#define kMtBtNumBlocks (1 << 4)
+
+#define GET_BT_BLOCK_OFFSET(i) (((i) & (kMtBtNumBlocks - 1)) * (size_t)kMtBtBlockSize)
+
+/*
+ HASH functions:
+ We use raw 8/16 bits from a[1] and a[2],
+ xored with crc(a[0]) and crc(a[3]).
+ We check a[0], a[3] only. We don't need to compare a[1] and a[2] in matches.
+ our crc() function provides one-to-one correspondence for low 8-bit values:
+ (crc[0...0xFF] & 0xFF) <-> [0...0xFF]
+*/
+
+#define MF(mt) ((mt)->MatchFinder)
+#define MF_CRC (p->crc)
+
+// #define MF(mt) (&(mt)->MatchFinder)
+// #define MF_CRC (p->MatchFinder.crc)
+
+#define MT_HASH2_CALC \
+ h2 = (MF_CRC[cur[0]] ^ cur[1]) & (kHash2Size - 1);
+
+#define MT_HASH3_CALC { \
+ UInt32 temp = MF_CRC[cur[0]] ^ cur[1]; \
+ h2 = temp & (kHash2Size - 1); \
+ h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
+
+/*
+#define MT_HASH3_CALC__NO_2 { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
+
+#define __MT_HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ h2 = temp & (kHash2Size - 1); \
+ temp ^= ((UInt32)cur[2] << 8); \
+ h3 = temp & (kHash3Size - 1); \
+ h4 = (temp ^ (p->crc[cur[3]] << kLzHash_CrcShift_1)) & p->hash4Mask; }
+ // (kHash4Size - 1);
+*/
+
+
+MY_NO_INLINE
+static void MtSync_Construct(CMtSync *p)
+{
+ p->affinity = 0;
+ p->wasCreated = False;
+ p->csWasInitialized = False;
+ p->csWasEntered = False;
+ Thread_Construct(&p->thread);
+ Event_Construct(&p->canStart);
+ Event_Construct(&p->wasStopped);
+ Semaphore_Construct(&p->freeSemaphore);
+ Semaphore_Construct(&p->filledSemaphore);
+}
+
+
+#define DEBUG_BUFFER_LOCK // define it to debug lock state
+
+#ifdef DEBUG_BUFFER_LOCK
+#include <stdlib.h>
+#define BUFFER_MUST_BE_LOCKED(p) if (!(p)->csWasEntered) exit(1);
+#define BUFFER_MUST_BE_UNLOCKED(p) if ( (p)->csWasEntered) exit(1);
+#else
+#define BUFFER_MUST_BE_LOCKED(p)
+#define BUFFER_MUST_BE_UNLOCKED(p)
+#endif
+
+#define LOCK_BUFFER(p) { \
+ BUFFER_MUST_BE_UNLOCKED(p); \
+ CriticalSection_Enter(&(p)->cs); \
+ (p)->csWasEntered = True; }
+
+#define UNLOCK_BUFFER(p) { \
+ BUFFER_MUST_BE_LOCKED(p); \
+ CriticalSection_Leave(&(p)->cs); \
+ (p)->csWasEntered = False; }
+
+
+MY_NO_INLINE
+static UInt32 MtSync_GetNextBlock(CMtSync *p)
+{
+ UInt32 numBlocks = 0;
+ if (p->needStart)
+ {
+ BUFFER_MUST_BE_UNLOCKED(p)
+ p->numProcessedBlocks = 1;
+ p->needStart = False;
+ p->stopWriting = False;
+ p->exit = False;
+ Event_Reset(&p->wasStopped);
+ Event_Set(&p->canStart);
+ }
+ else
+ {
+ UNLOCK_BUFFER(p)
+ // we free current block
+ numBlocks = p->numProcessedBlocks++;
+ Semaphore_Release1(&p->freeSemaphore);
+ }
+
+ // buffer is UNLOCKED here
+ Semaphore_Wait(&p->filledSemaphore);
+ LOCK_BUFFER(p);
+ return numBlocks;
+}
+
+
+/* if Writing (Processing) thread was started, we must call MtSync_StopWriting() */
+
+MY_NO_INLINE
+static void MtSync_StopWriting(CMtSync *p)
+{
+ if (!Thread_WasCreated(&p->thread) || p->needStart)
+ return;
+
+ PRF(printf("\nMtSync_StopWriting %p\n", p));
+
+ if (p->csWasEntered)
+ {
+ /* we don't use buffer in this thread after StopWriting().
+ So we UNLOCK buffer.
+ And we restore default UNLOCKED state for stopped thread */
+ UNLOCK_BUFFER(p)
+ }
+
+ /* We send (p->stopWriting) message and release freeSemaphore
+ to free current block.
+ So the thread will see (p->stopWriting) at some
+ iteration after Wait(freeSemaphore).
+ The thread doesn't need to fill all avail free blocks,
+ so we can get fast thread stop.
+ */
+
+ p->stopWriting = True;
+ Semaphore_Release1(&p->freeSemaphore); // check semaphore count !!!
+
+ PRF(printf("\nMtSync_StopWriting %p : Event_Wait(&p->wasStopped)\n", p));
+ Event_Wait(&p->wasStopped);
+ PRF(printf("\nMtSync_StopWriting %p : Event_Wait() finsihed\n", p));
+
+ /* 21.03 : we don't restore samaphore counters here.
+ We will recreate and reinit samaphores in next start */
+
+ p->needStart = True;
+}
+
+
+MY_NO_INLINE
+static void MtSync_Destruct(CMtSync *p)
+{
+ PRF(printf("\nMtSync_Destruct %p\n", p));
+
+ if (Thread_WasCreated(&p->thread))
+ {
+ /* we want thread to be in Stopped state before sending EXIT command.
+ note: stop(btSync) will stop (htSync) also */
+ MtSync_StopWriting(p);
+ /* thread in Stopped state here : (p->needStart == true) */
+ p->exit = True;
+ // if (p->needStart) // it's (true)
+ Event_Set(&p->canStart); // we send EXIT command to thread
+ Thread_Wait_Close(&p->thread); // we wait thread finishing
+ }
+
+ if (p->csWasInitialized)
+ {
+ CriticalSection_Delete(&p->cs);
+ p->csWasInitialized = False;
+ }
+ p->csWasEntered = False;
+
+ Event_Close(&p->canStart);
+ Event_Close(&p->wasStopped);
+ Semaphore_Close(&p->freeSemaphore);
+ Semaphore_Close(&p->filledSemaphore);
+
+ p->wasCreated = False;
+}
+
+
+// #define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; }
+// we want to get real system error codes here instead of SZ_ERROR_THREAD
+#define RINOK_THREAD(x) RINOK(x)
+
+
+// call it before each new file (when new starting is required):
+MY_NO_INLINE
+static SRes MtSync_Init(CMtSync *p, UInt32 numBlocks)
+{
+ WRes wres;
+ // BUFFER_MUST_BE_UNLOCKED(p)
+ if (!p->needStart || p->csWasEntered)
+ return SZ_ERROR_FAIL;
+ wres = Semaphore_OptCreateInit(&p->freeSemaphore, numBlocks, numBlocks);
+ if (wres == 0)
+ wres = Semaphore_OptCreateInit(&p->filledSemaphore, 0, numBlocks);
+ return MY_SRes_HRESULT_FROM_WRes(wres);
+}
+
+
+static WRes MtSync_Create_WRes(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj)
+{
+ WRes wres;
+
+ if (p->wasCreated)
+ return SZ_OK;
+
+ RINOK_THREAD(CriticalSection_Init(&p->cs));
+ p->csWasInitialized = True;
+ p->csWasEntered = False;
+
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart));
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped));
+
+ p->needStart = True;
+ p->exit = True; /* p->exit is unused before (canStart) Event.
+ But in case of some unexpected code failure we will get fast exit from thread */
+
+ // return ERROR_TOO_MANY_POSTS; // for debug
+ // return EINVAL; // for debug
+
+ if (p->affinity != 0)
+ wres = Thread_Create_With_Affinity(&p->thread, startAddress, obj, (CAffinityMask)p->affinity);
+ else
+ wres = Thread_Create(&p->thread, startAddress, obj);
+
+ RINOK_THREAD(wres);
+ p->wasCreated = True;
+ return SZ_OK;
+}
+
+
+MY_NO_INLINE
+static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj)
+{
+ const WRes wres = MtSync_Create_WRes(p, startAddress, obj);
+ if (wres == 0)
+ return 0;
+ MtSync_Destruct(p);
+ return MY_SRes_HRESULT_FROM_WRes(wres);
+}
+
+
+// ---------- HASH THREAD ----------
+
+#define kMtMaxValForNormalize 0xFFFFFFFF
+// #define kMtMaxValForNormalize ((1 << 21)) // for debug
+// #define kNormalizeAlign (1 << 7) // alignment for speculated accesses
+
+#ifdef MY_CPU_LE_UNALIGN
+ #define GetUi24hi_from32(p) ((UInt32)GetUi32(p) >> 8)
+#else
+ #define GetUi24hi_from32(p) ((p)[1] ^ ((UInt32)(p)[2] << 8) ^ ((UInt32)(p)[3] << 16))
+#endif
+
+#define GetHeads_DECL(name) \
+ static void GetHeads ## name(const Byte *p, UInt32 pos, \
+ UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc)
+
+#define GetHeads_LOOP(v) \
+ for (; numHeads != 0; numHeads--) { \
+ const UInt32 value = (v); \
+ p++; \
+ *heads++ = pos - hash[value]; \
+ hash[value] = pos++; }
+
+#define DEF_GetHeads2(name, v, action) \
+ GetHeads_DECL(name) { action \
+ GetHeads_LOOP(v) }
+
+#define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;)
+
+DEF_GetHeads2(2, GetUi16(p), UNUSED_VAR(hashMask); UNUSED_VAR(crc); )
+DEF_GetHeads(3, (crc[p[0]] ^ GetUi16(p + 1)) & hashMask)
+DEF_GetHeads2(3b, GetUi16(p) ^ ((UInt32)(p)[2] << 16), UNUSED_VAR(hashMask); UNUSED_VAR(crc); )
+// BT3 is not good for crc collisions for big hashMask values.
+
+/*
+GetHeads_DECL(3b)
+{
+ UNUSED_VAR(hashMask);
+ UNUSED_VAR(crc);
+ {
+ const Byte *pLim = p + numHeads;
+ if (numHeads == 0)
+ return;
+ pLim--;
+ while (p < pLim)
+ {
+ UInt32 v1 = GetUi32(p);
+ UInt32 v0 = v1 & 0xFFFFFF;
+ UInt32 h0, h1;
+ p += 2;
+ v1 >>= 8;
+ h0 = hash[v0]; hash[v0] = pos; heads[0] = pos - h0; pos++;
+ h1 = hash[v1]; hash[v1] = pos; heads[1] = pos - h1; pos++;
+ heads += 2;
+ }
+ if (p == pLim)
+ {
+ UInt32 v0 = GetUi16(p) ^ ((UInt32)(p)[2] << 16);
+ *heads = pos - hash[v0];
+ hash[v0] = pos;
+ }
+ }
+}
+*/
+
+/*
+GetHeads_DECL(4)
+{
+ unsigned sh = 0;
+ UNUSED_VAR(crc)
+ while ((hashMask & 0x80000000) == 0)
+ {
+ hashMask <<= 1;
+ sh++;
+ }
+ GetHeads_LOOP((GetUi32(p) * 0xa54a1) >> sh)
+}
+#define GetHeads4b GetHeads4
+*/
+
+#define USE_GetHeads_LOCAL_CRC
+
+#ifdef USE_GetHeads_LOCAL_CRC
+
+GetHeads_DECL(4)
+{
+ UInt32 crc0[256];
+ UInt32 crc1[256];
+ {
+ unsigned i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 v = crc[i];
+ crc0[i] = v & hashMask;
+ crc1[i] = (v << kLzHash_CrcShift_1) & hashMask;
+ // crc1[i] = rotlFixed(v, 8) & hashMask;
+ }
+ }
+ GetHeads_LOOP(crc0[p[0]] ^ crc1[p[3]] ^ (UInt32)GetUi16(p+1))
+}
+
+GetHeads_DECL(4b)
+{
+ UInt32 crc0[256];
+ {
+ unsigned i;
+ for (i = 0; i < 256; i++)
+ crc0[i] = crc[i] & hashMask;
+ }
+ GetHeads_LOOP(crc0[p[0]] ^ GetUi24hi_from32(p))
+}
+
+GetHeads_DECL(5)
+{
+ UInt32 crc0[256];
+ UInt32 crc1[256];
+ UInt32 crc2[256];
+ {
+ unsigned i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 v = crc[i];
+ crc0[i] = v & hashMask;
+ crc1[i] = (v << kLzHash_CrcShift_1) & hashMask;
+ crc2[i] = (v << kLzHash_CrcShift_2) & hashMask;
+ }
+ }
+ GetHeads_LOOP(crc0[p[0]] ^ crc1[p[3]] ^ crc2[p[4]] ^ (UInt32)GetUi16(p+1))
+}
+
+GetHeads_DECL(5b)
+{
+ UInt32 crc0[256];
+ UInt32 crc1[256];
+ {
+ unsigned i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 v = crc[i];
+ crc0[i] = v & hashMask;
+ crc1[i] = (v << kLzHash_CrcShift_1) & hashMask;
+ }
+ }
+ GetHeads_LOOP(crc0[p[0]] ^ crc1[p[4]] ^ GetUi24hi_from32(p))
+}
+
+#else
+
+DEF_GetHeads(4, (crc[p[0]] ^ (crc[p[3]] << kLzHash_CrcShift_1) ^ (UInt32)GetUi16(p+1)) & hashMask)
+DEF_GetHeads(4b, (crc[p[0]] ^ GetUi24hi_from32(p)) & hashMask)
+DEF_GetHeads(5, (crc[p[0]] ^ (crc[p[3]] << kLzHash_CrcShift_1) ^ (crc[p[4]] << kLzHash_CrcShift_2) ^ (UInt32)GetUi16(p + 1)) & hashMask)
+DEF_GetHeads(5b, (crc[p[0]] ^ (crc[p[4]] << kLzHash_CrcShift_1) ^ GetUi24hi_from32(p)) & hashMask)
+
+#endif
+
+
+static void HashThreadFunc(CMatchFinderMt *mt)
+{
+ CMtSync *p = &mt->hashSync;
+ PRF(printf("\nHashThreadFunc\n"));
+
+ for (;;)
+ {
+ UInt32 blockIndex = 0;
+ PRF(printf("\nHashThreadFunc : Event_Wait(&p->canStart)\n"));
+ Event_Wait(&p->canStart);
+ PRF(printf("\nHashThreadFunc : Event_Wait(&p->canStart) : after \n"));
+ if (p->exit)
+ {
+ PRF(printf("\nHashThreadFunc : exit \n"));
+ return;
+ }
+
+ MatchFinder_Init_HighHash(MF(mt));
+
+ for (;;)
+ {
+ PRF(printf("Hash thread block = %d pos = %d\n", (unsigned)blockIndex, mt->MatchFinder->pos));
+
+ {
+ CMatchFinder *mf = MF(mt);
+ if (MatchFinder_NeedMove(mf))
+ {
+ CriticalSection_Enter(&mt->btSync.cs);
+ CriticalSection_Enter(&mt->hashSync.cs);
+ {
+ const Byte *beforePtr = Inline_MatchFinder_GetPointerToCurrentPos(mf);
+ ptrdiff_t offset;
+ MatchFinder_MoveBlock(mf);
+ offset = beforePtr - Inline_MatchFinder_GetPointerToCurrentPos(mf);
+ mt->pointerToCurPos -= offset;
+ mt->buffer -= offset;
+ }
+ CriticalSection_Leave(&mt->hashSync.cs);
+ CriticalSection_Leave(&mt->btSync.cs);
+ continue;
+ }
+
+ Semaphore_Wait(&p->freeSemaphore);
+
+ if (p->exit) // exit is unexpected here. But we check it here for some failure case
+ return;
+
+ // for faster stop : we check (p->stopWriting) after Wait(freeSemaphore)
+ if (p->stopWriting)
+ break;
+
+ MatchFinder_ReadIfRequired(mf);
+ {
+ UInt32 *heads = mt->hashBuf + GET_HASH_BLOCK_OFFSET(blockIndex++);
+ UInt32 num = Inline_MatchFinder_GetNumAvailableBytes(mf);
+ heads[0] = 2;
+ heads[1] = num;
+
+ /* heads[1] contains the number of avail bytes:
+ if (avail < mf->numHashBytes) :
+ {
+ it means that stream was finished
+ HASH_THREAD and BT_TREAD must move position for heads[1] (avail) bytes.
+ HASH_THREAD doesn't stop,
+ HASH_THREAD fills only the header (2 numbers) for all next blocks:
+ {2, NumHashBytes - 1}, {2,0}, {2,0}, ... , {2,0}
+ }
+ else
+ {
+ HASH_THREAD and BT_TREAD must move position for (heads[0] - 2) bytes;
+ }
+ */
+
+ if (num >= mf->numHashBytes)
+ {
+ num = num - mf->numHashBytes + 1;
+ if (num > kMtHashBlockSize - 2)
+ num = kMtHashBlockSize - 2;
+
+ if (mf->pos > (UInt32)kMtMaxValForNormalize - num)
+ {
+ const UInt32 subValue = (mf->pos - mf->historySize - 1); // & ~(UInt32)(kNormalizeAlign - 1);
+ Inline_MatchFinder_ReduceOffsets(mf, subValue);
+ MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, (size_t)mf->hashMask + 1);
+ }
+
+ heads[0] = 2 + num;
+ mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc);
+ }
+
+ mf->pos += num; // wrap over zero is allowed at the end of stream
+ mf->buffer += num;
+ }
+ }
+
+ Semaphore_Release1(&p->filledSemaphore);
+ } // for() processing end
+
+ // p->numBlocks_Sent = blockIndex;
+ Event_Set(&p->wasStopped);
+ } // for() thread end
+}
+
+
+
+
+// ---------- BT THREAD ----------
+
+/* we use one variable instead of two (cyclicBufferPos == pos) before CyclicBuf wrap.
+ here we define fixed offset of (p->pos) from (p->cyclicBufferPos) */
+#define CYC_TO_POS_OFFSET 0
+// #define CYC_TO_POS_OFFSET 1 // for debug
+
+#define MFMT_GM_INLINE
+
+#ifdef MFMT_GM_INLINE
+
+/*
+ we use size_t for (pos) instead of UInt32
+ to eliminate "movsx" BUG in old MSVC x64 compiler.
+*/
+
+
+UInt32 * MY_FAST_CALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son,
+ UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size,
+ size_t _cyclicBufferPos, UInt32 _cyclicBufferSize,
+ UInt32 *posRes);
+
+#endif
+
+
+static void BtGetMatches(CMatchFinderMt *p, UInt32 *d)
+{
+ UInt32 numProcessed = 0;
+ UInt32 curPos = 2;
+
+ /* GetMatchesSpec() functions don't create (len = 1)
+ in [len, dist] match pairs, if (p->numHashBytes >= 2)
+ Also we suppose here that (matchMaxLen >= 2).
+ So the following code for (reserve) is not required
+ UInt32 reserve = (p->matchMaxLen * 2);
+ const UInt32 kNumHashBytes_Max = 5; // BT_HASH_BYTES_MAX
+ if (reserve < kNumHashBytes_Max - 1)
+ reserve = kNumHashBytes_Max - 1;
+ const UInt32 limit = kMtBtBlockSize - (reserve);
+ */
+
+ const UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2);
+
+ d[1] = p->hashNumAvail;
+
+ if (p->failure_BT)
+ {
+ // printf("\n == 1 BtGetMatches() p->failure_BT\n");
+ d[0] = 0;
+ // d[1] = 0;
+ return;
+ }
+
+ while (curPos < limit)
+ {
+ if (p->hashBufPos == p->hashBufPosLimit)
+ {
+ // MatchFinderMt_GetNextBlock_Hash(p);
+ UInt32 avail;
+ {
+ const UInt32 bi = MtSync_GetNextBlock(&p->hashSync);
+ const UInt32 k = GET_HASH_BLOCK_OFFSET(bi);
+ const UInt32 *h = p->hashBuf + k;
+ avail = h[1];
+ p->hashBufPosLimit = k + h[0];
+ p->hashNumAvail = avail;
+ p->hashBufPos = k + 2;
+ }
+
+ {
+ /* we must prevent UInt32 overflow for avail total value,
+ if avail was increased with new hash block */
+ UInt32 availSum = numProcessed + avail;
+ if (availSum < numProcessed)
+ availSum = (UInt32)(Int32)-1;
+ d[1] = availSum;
+ }
+
+ if (avail >= p->numHashBytes)
+ continue;
+
+ // if (p->hashBufPos != p->hashBufPosLimit) exit(1);
+
+ /* (avail < p->numHashBytes)
+ It means that stream was finished.
+ And (avail) - is a number of remaining bytes,
+ we fill (d) for (avail) bytes for LZ_THREAD (receiver).
+ but we don't update (p->pos) and (p->cyclicBufferPos) here in BT_THREAD */
+
+ /* here we suppose that we have space enough:
+ (kMtBtBlockSize - curPos >= p->hashNumAvail) */
+ p->hashNumAvail = 0;
+ d[0] = curPos + avail;
+ d += curPos;
+ for (; avail != 0; avail--)
+ *d++ = 0;
+ return;
+ }
+ {
+ UInt32 size = p->hashBufPosLimit - p->hashBufPos;
+ UInt32 pos = p->pos;
+ UInt32 cyclicBufferPos = p->cyclicBufferPos;
+ UInt32 lenLimit = p->matchMaxLen;
+ if (lenLimit >= p->hashNumAvail)
+ lenLimit = p->hashNumAvail;
+ {
+ UInt32 size2 = p->hashNumAvail - lenLimit + 1;
+ if (size2 < size)
+ size = size2;
+ size2 = p->cyclicBufferSize - cyclicBufferPos;
+ if (size2 < size)
+ size = size2;
+ }
+
+ if (pos > (UInt32)kMtMaxValForNormalize - size)
+ {
+ const UInt32 subValue = (pos - p->cyclicBufferSize); // & ~(UInt32)(kNormalizeAlign - 1);
+ pos -= subValue;
+ p->pos = pos;
+ MatchFinder_Normalize3(subValue, p->son, (size_t)p->cyclicBufferSize * 2);
+ }
+
+ #ifndef MFMT_GM_INLINE
+ while (curPos < limit && size-- != 0)
+ {
+ UInt32 *startDistances = d + curPos;
+ UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++],
+ pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
+ startDistances + 1, p->numHashBytes - 1) - startDistances);
+ *startDistances = num - 1;
+ curPos += num;
+ cyclicBufferPos++;
+ pos++;
+ p->buffer++;
+ }
+ #else
+ {
+ UInt32 posRes = pos;
+ const UInt32 *d_end;
+ {
+ d_end = GetMatchesSpecN_2(
+ p->buffer + lenLimit - 1,
+ pos, p->buffer, p->son, p->cutValue, d + curPos,
+ p->numHashBytes - 1, p->hashBuf + p->hashBufPos,
+ d + limit, p->hashBuf + p->hashBufPos + size,
+ cyclicBufferPos, p->cyclicBufferSize,
+ &posRes);
+ }
+ {
+ if (!d_end)
+ {
+ // printf("\n == 2 BtGetMatches() p->failure_BT\n");
+ // internal data failure
+ p->failure_BT = True;
+ d[0] = 0;
+ // d[1] = 0;
+ return;
+ }
+ }
+ curPos = (UInt32)(d_end - d);
+ {
+ const UInt32 processed = posRes - pos;
+ pos = posRes;
+ p->hashBufPos += processed;
+ cyclicBufferPos += processed;
+ p->buffer += processed;
+ }
+ }
+ #endif
+
+ {
+ const UInt32 processed = pos - p->pos;
+ numProcessed += processed;
+ p->hashNumAvail -= processed;
+ p->pos = pos;
+ }
+ if (cyclicBufferPos == p->cyclicBufferSize)
+ cyclicBufferPos = 0;
+ p->cyclicBufferPos = cyclicBufferPos;
+ }
+ }
+
+ d[0] = curPos;
+}
+
+
+static void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex)
+{
+ CMtSync *sync = &p->hashSync;
+
+ BUFFER_MUST_BE_UNLOCKED(sync)
+
+ if (!sync->needStart)
+ {
+ LOCK_BUFFER(sync)
+ }
+
+ BtGetMatches(p, p->btBuf + GET_BT_BLOCK_OFFSET(globalBlockIndex));
+
+ /* We suppose that we have called GetNextBlock() from start.
+ So buffer is LOCKED */
+
+ UNLOCK_BUFFER(sync)
+}
+
+
+MY_NO_INLINE
+static void BtThreadFunc(CMatchFinderMt *mt)
+{
+ CMtSync *p = &mt->btSync;
+ for (;;)
+ {
+ UInt32 blockIndex = 0;
+ Event_Wait(&p->canStart);
+
+ for (;;)
+ {
+ PRF(printf(" BT thread block = %d pos = %d\n", (unsigned)blockIndex, mt->pos));
+ /* (p->exit == true) is possible after (p->canStart) at first loop iteration
+ and is unexpected after more Wait(freeSemaphore) iterations */
+ if (p->exit)
+ return;
+
+ Semaphore_Wait(&p->freeSemaphore);
+
+ // for faster stop : we check (p->stopWriting) after Wait(freeSemaphore)
+ if (p->stopWriting)
+ break;
+
+ BtFillBlock(mt, blockIndex++);
+
+ Semaphore_Release1(&p->filledSemaphore);
+ }
+
+ // we stop HASH_THREAD here
+ MtSync_StopWriting(&mt->hashSync);
+
+ // p->numBlocks_Sent = blockIndex;
+ Event_Set(&p->wasStopped);
+ }
+}
+
+
+void MatchFinderMt_Construct(CMatchFinderMt *p)
+{
+ p->hashBuf = NULL;
+ MtSync_Construct(&p->hashSync);
+ MtSync_Construct(&p->btSync);
+}
+
+static void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->hashBuf);
+ p->hashBuf = NULL;
+}
+
+void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc)
+{
+ /*
+ HASH_THREAD can use CriticalSection(s) btSync.cs and hashSync.cs.
+ So we must be sure that HASH_THREAD will not use CriticalSection(s)
+ after deleting CriticalSection here.
+
+ we call ReleaseStream(p)
+ that calls StopWriting(btSync)
+ that calls StopWriting(hashSync), if it's required to stop HASH_THREAD.
+ after StopWriting() it's safe to destruct MtSync(s) in any order */
+
+ MatchFinderMt_ReleaseStream(p);
+
+ MtSync_Destruct(&p->btSync);
+ MtSync_Destruct(&p->hashSync);
+
+ LOG_ITER(
+ printf("\nTree %9d * %7d iter = %9d = sum : bytes = %9d\n",
+ (UInt32)(g_NumIters_Tree / 1000),
+ (UInt32)(((UInt64)g_NumIters_Loop * 1000) / (g_NumIters_Tree + 1)),
+ (UInt32)(g_NumIters_Loop / 1000),
+ (UInt32)(g_NumIters_Bytes / 1000)
+ ));
+
+ MatchFinderMt_FreeMem(p, alloc);
+}
+
+
+#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks)
+#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks)
+
+
+static THREAD_FUNC_DECL HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; }
+static THREAD_FUNC_DECL BtThreadFunc2(void *p)
+{
+ Byte allocaDummy[0x180];
+ unsigned i = 0;
+ for (i = 0; i < 16; i++)
+ allocaDummy[i] = (Byte)0;
+ if (allocaDummy[0] == 0)
+ BtThreadFunc((CMatchFinderMt *)p);
+ return 0;
+}
+
+
+SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc)
+{
+ CMatchFinder *mf = MF(p);
+ p->historySize = historySize;
+ if (kMtBtBlockSize <= matchMaxLen * 4)
+ return SZ_ERROR_PARAM;
+ if (!p->hashBuf)
+ {
+ p->hashBuf = (UInt32 *)ISzAlloc_Alloc(alloc, ((size_t)kHashBufferSize + (size_t)kBtBufferSize) * sizeof(UInt32));
+ if (!p->hashBuf)
+ return SZ_ERROR_MEM;
+ p->btBuf = p->hashBuf + kHashBufferSize;
+ }
+ keepAddBufferBefore += (kHashBufferSize + kBtBufferSize);
+ keepAddBufferAfter += kMtHashBlockSize;
+ if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc))
+ return SZ_ERROR_MEM;
+
+ RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p));
+ RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p));
+ return SZ_OK;
+}
+
+
+SRes MatchFinderMt_InitMt(CMatchFinderMt *p)
+{
+ RINOK(MtSync_Init(&p->hashSync, kMtHashNumBlocks));
+ return MtSync_Init(&p->btSync, kMtBtNumBlocks);
+}
+
+
+static void MatchFinderMt_Init(CMatchFinderMt *p)
+{
+ CMatchFinder *mf = MF(p);
+
+ p->btBufPos =
+ p->btBufPosLimit = NULL;
+ p->hashBufPos =
+ p->hashBufPosLimit = 0;
+ p->hashNumAvail = 0; // 21.03
+
+ p->failure_BT = False;
+
+ /* Init without data reading. We don't want to read data in this thread */
+ MatchFinder_Init_4(mf);
+
+ MatchFinder_Init_LowHash(mf);
+
+ p->pointerToCurPos = Inline_MatchFinder_GetPointerToCurrentPos(mf);
+ p->btNumAvailBytes = 0;
+ p->failure_LZ_BT = False;
+ // p->failure_LZ_LZ = False;
+
+ p->lzPos =
+ 1; // optimal smallest value
+ // 0; // for debug: ignores match to start
+ // kNormalizeAlign; // for debug
+
+ p->hash = mf->hash;
+ p->fixedHashSize = mf->fixedHashSize;
+ // p->hash4Mask = mf->hash4Mask;
+ p->crc = mf->crc;
+ // memcpy(p->crc, mf->crc, sizeof(mf->crc));
+
+ p->son = mf->son;
+ p->matchMaxLen = mf->matchMaxLen;
+ p->numHashBytes = mf->numHashBytes;
+
+ /* (mf->pos) and (mf->streamPos) were already initialized to 1 in MatchFinder_Init_4() */
+ // mf->streamPos = mf->pos = 1; // optimal smallest value
+ // 0; // for debug: ignores match to start
+ // kNormalizeAlign; // for debug
+
+ /* we must init (p->pos = mf->pos) for BT, because
+ BT code needs (p->pos == delta_value_for_empty_hash_record == mf->pos) */
+ p->pos = mf->pos; // do not change it
+
+ p->cyclicBufferPos = (p->pos - CYC_TO_POS_OFFSET);
+ p->cyclicBufferSize = mf->cyclicBufferSize;
+ p->buffer = mf->buffer;
+ p->cutValue = mf->cutValue;
+ // p->son[0] = p->son[1] = 0; // unused: to init skipped record for speculated accesses.
+}
+
+
+/* ReleaseStream is required to finish multithreading */
+void MatchFinderMt_ReleaseStream(CMatchFinderMt *p)
+{
+ // Sleep(1); // for debug
+ MtSync_StopWriting(&p->btSync);
+ // Sleep(200); // for debug
+ /* p->MatchFinder->ReleaseStream(); */
+}
+
+
+MY_NO_INLINE
+static UInt32 MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p)
+{
+ if (p->failure_LZ_BT)
+ p->btBufPos = p->failureBuf;
+ else
+ {
+ const UInt32 bi = MtSync_GetNextBlock(&p->btSync);
+ const UInt32 *bt = p->btBuf + GET_BT_BLOCK_OFFSET(bi);
+ {
+ const UInt32 numItems = bt[0];
+ p->btBufPosLimit = bt + numItems;
+ p->btNumAvailBytes = bt[1];
+ p->btBufPos = bt + 2;
+ if (numItems < 2 || numItems > kMtBtBlockSize)
+ {
+ p->failureBuf[0] = 0;
+ p->btBufPos = p->failureBuf;
+ p->btBufPosLimit = p->failureBuf + 1;
+ p->failure_LZ_BT = True;
+ // p->btNumAvailBytes = 0;
+ /* we don't want to decrease AvailBytes, that was load before.
+ that can be unxepected for the code that have loaded anopther value before */
+ }
+ }
+
+ if (p->lzPos >= (UInt32)kMtMaxValForNormalize - (UInt32)kMtBtBlockSize)
+ {
+ /* we don't check (lzPos) over exact avail bytes in (btBuf).
+ (fixedHashSize) is small, so normalization is fast */
+ const UInt32 subValue = (p->lzPos - p->historySize - 1); // & ~(UInt32)(kNormalizeAlign - 1);
+ p->lzPos -= subValue;
+ MatchFinder_Normalize3(subValue, p->hash, p->fixedHashSize);
+ }
+ }
+ return p->btNumAvailBytes;
+}
+
+
+
+static const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p)
+{
+ return p->pointerToCurPos;
+}
+
+
+#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);
+
+
+static UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p)
+{
+ if (p->btBufPos != p->btBufPosLimit)
+ return p->btNumAvailBytes;
+ return MatchFinderMt_GetNextBlock_Bt(p);
+}
+
+
+// #define CHECK_FAILURE_LZ(_match_, _pos_) if (_match_ >= _pos_) { p->failure_LZ_LZ = True; return d; }
+#define CHECK_FAILURE_LZ(_match_, _pos_)
+
+static UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d)
+{
+ UInt32 h2, c2;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ const UInt32 m = p->lzPos;
+ MT_HASH2_CALC
+
+ c2 = hash[h2];
+ hash[h2] = m;
+
+ if (c2 >= matchMinPos)
+ {
+ CHECK_FAILURE_LZ(c2, m)
+ if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0])
+ {
+ *d++ = 2;
+ *d++ = m - c2 - 1;
+ }
+ }
+
+ return d;
+}
+
+static UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d)
+{
+ UInt32 h2, h3, c2, c3;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ const UInt32 m = p->lzPos;
+ MT_HASH3_CALC
+
+ c2 = hash[h2];
+ c3 = (hash + kFix3HashSize)[h3];
+
+ hash[h2] = m;
+ (hash + kFix3HashSize)[h3] = m;
+
+ if (c2 >= matchMinPos)
+ {
+ CHECK_FAILURE_LZ(c2, m)
+ if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0])
+ {
+ d[1] = m - c2 - 1;
+ if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2])
+ {
+ d[0] = 3;
+ return d + 2;
+ }
+ d[0] = 2;
+ d += 2;
+ }
+ }
+
+ if (c3 >= matchMinPos)
+ {
+ CHECK_FAILURE_LZ(c3, m)
+ if (cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0])
+ {
+ *d++ = 3;
+ *d++ = m - c3 - 1;
+ }
+ }
+
+ return d;
+}
+
+
+#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++;
+
+/*
+static
+UInt32* MatchFinderMt_GetMatches_Bt4(CMatchFinderMt *p, UInt32 *d)
+{
+ const UInt32 *bt = p->btBufPos;
+ const UInt32 len = *bt++;
+ const UInt32 *btLim = bt + len;
+ UInt32 matchMinPos;
+ UInt32 avail = p->btNumAvailBytes - 1;
+ p->btBufPos = btLim;
+
+ {
+ p->btNumAvailBytes = avail;
+
+ #define BT_HASH_BYTES_MAX 5
+
+ matchMinPos = p->lzPos;
+
+ if (len != 0)
+ matchMinPos -= bt[1];
+ else if (avail < (BT_HASH_BYTES_MAX - 1) - 1)
+ {
+ INCREASE_LZ_POS
+ return d;
+ }
+ else
+ {
+ const UInt32 hs = p->historySize;
+ if (matchMinPos > hs)
+ matchMinPos -= hs;
+ else
+ matchMinPos = 1;
+ }
+ }
+
+ for (;;)
+ {
+
+ UInt32 h2, h3, c2, c3;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ UInt32 m = p->lzPos;
+ MT_HASH3_CALC
+
+ c2 = hash[h2];
+ c3 = (hash + kFix3HashSize)[h3];
+
+ hash[h2] = m;
+ (hash + kFix3HashSize)[h3] = m;
+
+ if (c2 >= matchMinPos && cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0])
+ {
+ d[1] = m - c2 - 1;
+ if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2])
+ {
+ d[0] = 3;
+ d += 2;
+ break;
+ }
+ // else
+ {
+ d[0] = 2;
+ d += 2;
+ }
+ }
+ if (c3 >= matchMinPos && cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0])
+ {
+ *d++ = 3;
+ *d++ = m - c3 - 1;
+ }
+ break;
+ }
+
+ if (len != 0)
+ {
+ do
+ {
+ const UInt32 v0 = bt[0];
+ const UInt32 v1 = bt[1];
+ bt += 2;
+ d[0] = v0;
+ d[1] = v1;
+ d += 2;
+ }
+ while (bt != btLim);
+ }
+ INCREASE_LZ_POS
+ return d;
+}
+*/
+
+
+static UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d)
+{
+ UInt32 h2, h3, /* h4, */ c2, c3 /* , c4 */;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ const UInt32 m = p->lzPos;
+ MT_HASH3_CALC
+ // MT_HASH4_CALC
+ c2 = hash[h2];
+ c3 = (hash + kFix3HashSize)[h3];
+ // c4 = (hash + kFix4HashSize)[h4];
+
+ hash[h2] = m;
+ (hash + kFix3HashSize)[h3] = m;
+ // (hash + kFix4HashSize)[h4] = m;
+
+ #define _USE_H2
+
+ #ifdef _USE_H2
+ if (c2 >= matchMinPos && cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0])
+ {
+ d[1] = m - c2 - 1;
+ if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2])
+ {
+ // d[0] = (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 3] == cur[3]) ? 4 : 3;
+ // return d + 2;
+
+ if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 3] == cur[3])
+ {
+ d[0] = 4;
+ return d + 2;
+ }
+ d[0] = 3;
+ d += 2;
+
+ #ifdef _USE_H4
+ if (c4 >= matchMinPos)
+ if (
+ cur[(ptrdiff_t)c4 - (ptrdiff_t)m] == cur[0] &&
+ cur[(ptrdiff_t)c4 - (ptrdiff_t)m + 3] == cur[3]
+ )
+ {
+ *d++ = 4;
+ *d++ = m - c4 - 1;
+ }
+ #endif
+ return d;
+ }
+ d[0] = 2;
+ d += 2;
+ }
+ #endif
+
+ if (c3 >= matchMinPos && cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0])
+ {
+ d[1] = m - c3 - 1;
+ if (cur[(ptrdiff_t)c3 - (ptrdiff_t)m + 3] == cur[3])
+ {
+ d[0] = 4;
+ return d + 2;
+ }
+ d[0] = 3;
+ d += 2;
+ }
+
+ #ifdef _USE_H4
+ if (c4 >= matchMinPos)
+ if (
+ cur[(ptrdiff_t)c4 - (ptrdiff_t)m] == cur[0] &&
+ cur[(ptrdiff_t)c4 - (ptrdiff_t)m + 3] == cur[3]
+ )
+ {
+ *d++ = 4;
+ *d++ = m - c4 - 1;
+ }
+ #endif
+
+ return d;
+}
+
+
+static UInt32* MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *d)
+{
+ const UInt32 *bt = p->btBufPos;
+ const UInt32 len = *bt++;
+ const UInt32 *btLim = bt + len;
+ p->btBufPos = btLim;
+ p->btNumAvailBytes--;
+ INCREASE_LZ_POS
+ {
+ while (bt != btLim)
+ {
+ const UInt32 v0 = bt[0];
+ const UInt32 v1 = bt[1];
+ bt += 2;
+ d[0] = v0;
+ d[1] = v1;
+ d += 2;
+ }
+ }
+ return d;
+}
+
+
+
+static UInt32* MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *d)
+{
+ const UInt32 *bt = p->btBufPos;
+ UInt32 len = *bt++;
+ const UInt32 avail = p->btNumAvailBytes - 1;
+ p->btNumAvailBytes = avail;
+ p->btBufPos = bt + len;
+ if (len == 0)
+ {
+ #define BT_HASH_BYTES_MAX 5
+ if (avail >= (BT_HASH_BYTES_MAX - 1) - 1)
+ {
+ UInt32 m = p->lzPos;
+ if (m > p->historySize)
+ m -= p->historySize;
+ else
+ m = 1;
+ d = p->MixMatchesFunc(p, m, d);
+ }
+ }
+ else
+ {
+ /*
+ first match pair from BinTree: (match_len, match_dist),
+ (match_len >= numHashBytes).
+ MixMatchesFunc() inserts only hash matches that are nearer than (match_dist)
+ */
+ d = p->MixMatchesFunc(p, p->lzPos - bt[1], d);
+ // if (d) // check for failure
+ do
+ {
+ const UInt32 v0 = bt[0];
+ const UInt32 v1 = bt[1];
+ bt += 2;
+ d[0] = v0;
+ d[1] = v1;
+ d += 2;
+ }
+ while (len -= 2);
+ }
+ INCREASE_LZ_POS
+ return d;
+}
+
+#define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED
+#define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash;
+#define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += (size_t)*p->btBufPos + 1; } while (--num != 0);
+
+static void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER2_MT { p->btNumAvailBytes--;
+ SKIP_FOOTER_MT
+}
+
+static void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(2)
+ UInt32 h2;
+ MT_HASH2_CALC
+ hash[h2] = p->lzPos;
+ SKIP_FOOTER_MT
+}
+
+static void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(3)
+ UInt32 h2, h3;
+ MT_HASH3_CALC
+ (hash + kFix3HashSize)[h3] =
+ hash[ h2] =
+ p->lzPos;
+ SKIP_FOOTER_MT
+}
+
+/*
+// MatchFinderMt4_Skip() is similar to MatchFinderMt3_Skip().
+// The difference is that MatchFinderMt3_Skip() updates hash for last 3 bytes of stream.
+
+static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(4)
+ UInt32 h2, h3; // h4
+ MT_HASH3_CALC
+ // MT_HASH4_CALC
+ // (hash + kFix4HashSize)[h4] =
+ (hash + kFix3HashSize)[h3] =
+ hash[ h2] =
+ p->lzPos;
+ SKIP_FOOTER_MT
+}
+*/
+
+void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder2 *vTable)
+{
+ vTable->Init = (Mf_Init_Func)MatchFinderMt_Init;
+ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes;
+ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos;
+ vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches;
+
+ switch (MF(p)->numHashBytes)
+ {
+ case 2:
+ p->GetHeadsFunc = GetHeads2;
+ p->MixMatchesFunc = (Mf_Mix_Matches)NULL;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip;
+ vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches;
+ break;
+ case 3:
+ p->GetHeadsFunc = MF(p)->bigHash ? GetHeads3b : GetHeads3;
+ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip;
+ break;
+ case 4:
+ p->GetHeadsFunc = MF(p)->bigHash ? GetHeads4b : GetHeads4;
+
+ // it's fast inline version of GetMatches()
+ // vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches_Bt4;
+
+ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip;
+ break;
+ default:
+ p->GetHeadsFunc = MF(p)->bigHash ? GetHeads5b : GetHeads5;
+ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4;
+ vTable->Skip =
+ (Mf_Skip_Func)MatchFinderMt3_Skip;
+ // (Mf_Skip_Func)MatchFinderMt4_Skip;
+ break;
+ }
+}
diff --git a/src/Common/lzma/LzFindMt.h b/src/Common/lzma/LzFindMt.h
new file mode 100644
index 00000000..660b7244
--- /dev/null
+++ b/src/Common/lzma/LzFindMt.h
@@ -0,0 +1,109 @@
+/* LzFindMt.h -- multithreaded Match finder for LZ algorithms
+2021-07-12 : Igor Pavlov : Public domain */
+
+#ifndef __LZ_FIND_MT_H
+#define __LZ_FIND_MT_H
+
+#include "LzFind.h"
+#include "Threads.h"
+
+EXTERN_C_BEGIN
+
+typedef struct _CMtSync
+{
+ UInt32 numProcessedBlocks;
+ CThread thread;
+ UInt64 affinity;
+
+ BoolInt wasCreated;
+ BoolInt needStart;
+ BoolInt csWasInitialized;
+ BoolInt csWasEntered;
+
+ BoolInt exit;
+ BoolInt stopWriting;
+
+ CAutoResetEvent canStart;
+ CAutoResetEvent wasStopped;
+ CSemaphore freeSemaphore;
+ CSemaphore filledSemaphore;
+ CCriticalSection cs;
+ // UInt32 numBlocks_Sent;
+} CMtSync;
+
+typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances);
+
+/* kMtCacheLineDummy must be >= size_of_CPU_cache_line */
+#define kMtCacheLineDummy 128
+
+typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos,
+ UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc);
+
+typedef struct _CMatchFinderMt
+{
+ /* LZ */
+ const Byte *pointerToCurPos;
+ UInt32 *btBuf;
+ const UInt32 *btBufPos;
+ const UInt32 *btBufPosLimit;
+ UInt32 lzPos;
+ UInt32 btNumAvailBytes;
+
+ UInt32 *hash;
+ UInt32 fixedHashSize;
+ // UInt32 hash4Mask;
+ UInt32 historySize;
+ const UInt32 *crc;
+
+ Mf_Mix_Matches MixMatchesFunc;
+ UInt32 failure_LZ_BT; // failure in BT transfered to LZ
+ // UInt32 failure_LZ_LZ; // failure in LZ tables
+ UInt32 failureBuf[1];
+ // UInt32 crc[256];
+
+ /* LZ + BT */
+ CMtSync btSync;
+ Byte btDummy[kMtCacheLineDummy];
+
+ /* BT */
+ UInt32 *hashBuf;
+ UInt32 hashBufPos;
+ UInt32 hashBufPosLimit;
+ UInt32 hashNumAvail;
+ UInt32 failure_BT;
+
+
+ CLzRef *son;
+ UInt32 matchMaxLen;
+ UInt32 numHashBytes;
+ UInt32 pos;
+ const Byte *buffer;
+ UInt32 cyclicBufferPos;
+ UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
+ UInt32 cutValue;
+
+ /* BT + Hash */
+ CMtSync hashSync;
+ /* Byte hashDummy[kMtCacheLineDummy]; */
+
+ /* Hash */
+ Mf_GetHeads GetHeadsFunc;
+ CMatchFinder *MatchFinder;
+ // CMatchFinder MatchFinder;
+} CMatchFinderMt;
+
+// only for Mt part
+void MatchFinderMt_Construct(CMatchFinderMt *p);
+void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc);
+
+SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc);
+void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder2 *vTable);
+
+/* call MatchFinderMt_InitMt() before IMatchFinder::Init() */
+SRes MatchFinderMt_InitMt(CMatchFinderMt *p);
+void MatchFinderMt_ReleaseStream(CMatchFinderMt *p);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/Common/lzma/LzFindOpt.c b/src/Common/lzma/LzFindOpt.c
new file mode 100644
index 00000000..8ff006e0
--- /dev/null
+++ b/src/Common/lzma/LzFindOpt.c
@@ -0,0 +1,578 @@
+/* LzFindOpt.c -- multithreaded Match finder for LZ algorithms
+2021-07-13 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "CpuArch.h"
+#include "LzFind.h"
+
+// #include "LzFindMt.h"
+
+// #define LOG_ITERS
+
+// #define LOG_THREAD
+
+#ifdef LOG_THREAD
+#include <stdio.h>
+#define PRF(x) x
+#else
+// #define PRF(x)
+#endif
+
+#ifdef LOG_ITERS
+#include <stdio.h>
+UInt64 g_NumIters_Tree;
+UInt64 g_NumIters_Loop;
+UInt64 g_NumIters_Bytes;
+#define LOG_ITER(x) x
+#else
+#define LOG_ITER(x)
+#endif
+
+// ---------- BT THREAD ----------
+
+#define USE_SON_PREFETCH
+#define USE_LONG_MATCH_OPT
+
+#define kEmptyHashValue 0
+
+// #define CYC_TO_POS_OFFSET 0
+
+// #define CYC_TO_POS_OFFSET 1 // for debug
+
+/*
+MY_NO_INLINE
+UInt32 * MY_FAST_CALL GetMatchesSpecN_1(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son,
+ UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, UInt32 *posRes)
+{
+ do
+ {
+ UInt32 delta;
+ if (hash == size)
+ break;
+ delta = *hash++;
+
+ if (delta == 0 || delta > (UInt32)pos)
+ return NULL;
+
+ lenLimit++;
+
+ if (delta == (UInt32)pos)
+ {
+ CLzRef *ptr1 = son + ((size_t)pos << 1) - CYC_TO_POS_OFFSET * 2;
+ *d++ = 0;
+ ptr1[0] = kEmptyHashValue;
+ ptr1[1] = kEmptyHashValue;
+ }
+else
+{
+ UInt32 *_distances = ++d;
+
+ CLzRef *ptr0 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2 + 1;
+ CLzRef *ptr1 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2;
+
+ const Byte *len0 = cur, *len1 = cur;
+ UInt32 cutValue = _cutValue;
+ const Byte *maxLen = cur + _maxLen;
+
+ for (LOG_ITER(g_NumIters_Tree++);;)
+ {
+ LOG_ITER(g_NumIters_Loop++);
+ {
+ const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta;
+ CLzRef *pair = son + ((size_t)(((ptrdiff_t)pos - CYC_TO_POS_OFFSET) + diff) << 1);
+ const Byte *len = (len0 < len1 ? len0 : len1);
+
+ #ifdef USE_SON_PREFETCH
+ const UInt32 pair0 = *pair;
+ #endif
+
+ if (len[diff] == len[0])
+ {
+ if (++len != lenLimit && len[diff] == len[0])
+ while (++len != lenLimit)
+ {
+ LOG_ITER(g_NumIters_Bytes++);
+ if (len[diff] != len[0])
+ break;
+ }
+ if (maxLen < len)
+ {
+ maxLen = len;
+ *d++ = (UInt32)(len - cur);
+ *d++ = delta - 1;
+
+ if (len == lenLimit)
+ {
+ const UInt32 pair1 = pair[1];
+ *ptr1 =
+ #ifdef USE_SON_PREFETCH
+ pair0;
+ #else
+ pair[0];
+ #endif
+ *ptr0 = pair1;
+
+ _distances[-1] = (UInt32)(d - _distances);
+
+ #ifdef USE_LONG_MATCH_OPT
+
+ if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit)
+ break;
+
+ {
+ for (;;)
+ {
+ hash++;
+ pos++;
+ cur++;
+ lenLimit++;
+ {
+ CLzRef *ptr = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2;
+ #if 0
+ *(UInt64 *)(void *)ptr = ((const UInt64 *)(const void *)ptr)[diff];
+ #else
+ const UInt32 p0 = ptr[0 + (diff * 2)];
+ const UInt32 p1 = ptr[1 + (diff * 2)];
+ ptr[0] = p0;
+ ptr[1] = p1;
+ // ptr[0] = ptr[0 + (diff * 2)];
+ // ptr[1] = ptr[1 + (diff * 2)];
+ #endif
+ }
+ // PrintSon(son + 2, pos - 1);
+ // printf("\npos = %x delta = %x\n", pos, delta);
+ len++;
+ *d++ = 2;
+ *d++ = (UInt32)(len - cur);
+ *d++ = delta - 1;
+ if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit)
+ break;
+ }
+ }
+ #endif
+
+ break;
+ }
+ }
+ }
+
+ {
+ const UInt32 curMatch = (UInt32)pos - delta; // (UInt32)(pos + diff);
+ if (len[diff] < len[0])
+ {
+ delta = pair[1];
+ if (delta >= curMatch)
+ return NULL;
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ len1 = len;
+ }
+ else
+ {
+ delta = *pair;
+ if (delta >= curMatch)
+ return NULL;
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ len0 = len;
+ }
+
+ delta = (UInt32)pos - delta;
+
+ if (--cutValue == 0 || delta >= pos)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ _distances[-1] = (UInt32)(d - _distances);
+ break;
+ }
+ }
+ }
+ } // for (tree iterations)
+}
+ pos++;
+ cur++;
+ }
+ while (d < limit);
+ *posRes = (UInt32)pos;
+ return d;
+}
+*/
+
+/* define cbs if you use 2 functions.
+ GetMatchesSpecN_1() : (pos < _cyclicBufferSize)
+ GetMatchesSpecN_2() : (pos >= _cyclicBufferSize)
+
+ do not define cbs if you use 1 function:
+ GetMatchesSpecN_2()
+*/
+
+// #define cbs _cyclicBufferSize
+
+/*
+ we use size_t for (pos) and (_cyclicBufferPos_ instead of UInt32
+ to eliminate "movsx" BUG in old MSVC x64 compiler.
+*/
+
+UInt32 * MY_FAST_CALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son,
+ UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size,
+ size_t _cyclicBufferPos, UInt32 _cyclicBufferSize,
+ UInt32 *posRes);
+
+MY_NO_INLINE
+UInt32 * MY_FAST_CALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son,
+ UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size,
+ size_t _cyclicBufferPos, UInt32 _cyclicBufferSize,
+ UInt32 *posRes)
+{
+ do // while (hash != size)
+ {
+ UInt32 delta;
+
+ #ifndef cbs
+ UInt32 cbs;
+ #endif
+
+ if (hash == size)
+ break;
+
+ delta = *hash++;
+
+ if (delta == 0)
+ return NULL;
+
+ lenLimit++;
+
+ #ifndef cbs
+ cbs = _cyclicBufferSize;
+ if ((UInt32)pos < cbs)
+ {
+ if (delta > (UInt32)pos)
+ return NULL;
+ cbs = (UInt32)pos;
+ }
+ #endif
+
+ if (delta >= cbs)
+ {
+ CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
+ *d++ = 0;
+ ptr1[0] = kEmptyHashValue;
+ ptr1[1] = kEmptyHashValue;
+ }
+else
+{
+ UInt32 *_distances = ++d;
+
+ CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
+
+ UInt32 cutValue = _cutValue;
+ const Byte *len0 = cur, *len1 = cur;
+ const Byte *maxLen = cur + _maxLen;
+
+ // if (cutValue == 0) { *ptr0 = *ptr1 = kEmptyHashValue; } else
+ for (LOG_ITER(g_NumIters_Tree++);;)
+ {
+ LOG_ITER(g_NumIters_Loop++);
+ {
+ // SPEC code
+ CLzRef *pair = son + ((size_t)((ptrdiff_t)_cyclicBufferPos - (ptrdiff_t)delta
+ + (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0)
+ ) << 1);
+
+ const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta;
+ const Byte *len = (len0 < len1 ? len0 : len1);
+
+ #ifdef USE_SON_PREFETCH
+ const UInt32 pair0 = *pair;
+ #endif
+
+ if (len[diff] == len[0])
+ {
+ if (++len != lenLimit && len[diff] == len[0])
+ while (++len != lenLimit)
+ {
+ LOG_ITER(g_NumIters_Bytes++);
+ if (len[diff] != len[0])
+ break;
+ }
+ if (maxLen < len)
+ {
+ maxLen = len;
+ *d++ = (UInt32)(len - cur);
+ *d++ = delta - 1;
+
+ if (len == lenLimit)
+ {
+ const UInt32 pair1 = pair[1];
+ *ptr1 =
+ #ifdef USE_SON_PREFETCH
+ pair0;
+ #else
+ pair[0];
+ #endif
+ *ptr0 = pair1;
+
+ _distances[-1] = (UInt32)(d - _distances);
+
+ #ifdef USE_LONG_MATCH_OPT
+
+ if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit)
+ break;
+
+ {
+ for (;;)
+ {
+ *d++ = 2;
+ *d++ = (UInt32)(lenLimit - cur);
+ *d++ = delta - 1;
+ cur++;
+ lenLimit++;
+ // SPEC
+ _cyclicBufferPos++;
+ {
+ // SPEC code
+ CLzRef *dest = son + ((size_t)(_cyclicBufferPos) << 1);
+ const CLzRef *src = dest + ((diff
+ + (ptrdiff_t)(UInt32)((_cyclicBufferPos < delta) ? cbs : 0)) << 1);
+ // CLzRef *ptr = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2;
+ #if 0
+ *(UInt64 *)(void *)dest = *((const UInt64 *)(const void *)src);
+ #else
+ const UInt32 p0 = src[0];
+ const UInt32 p1 = src[1];
+ dest[0] = p0;
+ dest[1] = p1;
+ #endif
+ }
+ pos++;
+ hash++;
+ if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit)
+ break;
+ } // for() end for long matches
+ }
+ #endif
+
+ break; // break from TREE iterations
+ }
+ }
+ }
+ {
+ const UInt32 curMatch = (UInt32)pos - delta; // (UInt32)(pos + diff);
+ if (len[diff] < len[0])
+ {
+ delta = pair[1];
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ len1 = len;
+ if (delta >= curMatch)
+ return NULL;
+ }
+ else
+ {
+ delta = *pair;
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ len0 = len;
+ if (delta >= curMatch)
+ return NULL;
+ }
+ delta = (UInt32)pos - delta;
+
+ if (--cutValue == 0 || delta >= cbs)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ _distances[-1] = (UInt32)(d - _distances);
+ break;
+ }
+ }
+ }
+ } // for (tree iterations)
+}
+ pos++;
+ _cyclicBufferPos++;
+ cur++;
+ }
+ while (d < limit);
+ *posRes = (UInt32)pos;
+ return d;
+}
+
+
+
+/*
+typedef UInt32 uint32plus; // size_t
+
+UInt32 * MY_FAST_CALL GetMatchesSpecN_3(uint32plus lenLimit, size_t pos, const Byte *cur, CLzRef *son,
+ UInt32 _cutValue, UInt32 *d, uint32plus _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size,
+ size_t _cyclicBufferPos, UInt32 _cyclicBufferSize,
+ UInt32 *posRes)
+{
+ do // while (hash != size)
+ {
+ UInt32 delta;
+
+ #ifndef cbs
+ UInt32 cbs;
+ #endif
+
+ if (hash == size)
+ break;
+
+ delta = *hash++;
+
+ if (delta == 0)
+ return NULL;
+
+ #ifndef cbs
+ cbs = _cyclicBufferSize;
+ if ((UInt32)pos < cbs)
+ {
+ if (delta > (UInt32)pos)
+ return NULL;
+ cbs = (UInt32)pos;
+ }
+ #endif
+
+ if (delta >= cbs)
+ {
+ CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
+ *d++ = 0;
+ ptr1[0] = kEmptyHashValue;
+ ptr1[1] = kEmptyHashValue;
+ }
+else
+{
+ CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
+ UInt32 *_distances = ++d;
+ uint32plus len0 = 0, len1 = 0;
+ UInt32 cutValue = _cutValue;
+ uint32plus maxLen = _maxLen;
+ // lenLimit++; // const Byte *lenLimit = cur + _lenLimit;
+
+ for (LOG_ITER(g_NumIters_Tree++);;)
+ {
+ LOG_ITER(g_NumIters_Loop++);
+ {
+ // const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta;
+ CLzRef *pair = son + ((size_t)((ptrdiff_t)_cyclicBufferPos - delta
+ + (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0)
+ ) << 1);
+ const Byte *pb = cur - delta;
+ uint32plus len = (len0 < len1 ? len0 : len1);
+
+ #ifdef USE_SON_PREFETCH
+ const UInt32 pair0 = *pair;
+ #endif
+
+ if (pb[len] == cur[len])
+ {
+ if (++len != lenLimit && pb[len] == cur[len])
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ maxLen = len;
+ *d++ = (UInt32)len;
+ *d++ = delta - 1;
+ if (len == lenLimit)
+ {
+ {
+ const UInt32 pair1 = pair[1];
+ *ptr0 = pair1;
+ *ptr1 =
+ #ifdef USE_SON_PREFETCH
+ pair0;
+ #else
+ pair[0];
+ #endif
+ }
+
+ _distances[-1] = (UInt32)(d - _distances);
+
+ #ifdef USE_LONG_MATCH_OPT
+
+ if (hash == size || *hash != delta || pb[lenLimit] != cur[lenLimit] || d >= limit)
+ break;
+
+ {
+ const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta;
+ for (;;)
+ {
+ *d++ = 2;
+ *d++ = (UInt32)lenLimit;
+ *d++ = delta - 1;
+ _cyclicBufferPos++;
+ {
+ CLzRef *dest = son + ((size_t)_cyclicBufferPos << 1);
+ const CLzRef *src = dest + ((diff +
+ (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0)) << 1);
+ #if 0
+ *(UInt64 *)(void *)dest = *((const UInt64 *)(const void *)src);
+ #else
+ const UInt32 p0 = src[0];
+ const UInt32 p1 = src[1];
+ dest[0] = p0;
+ dest[1] = p1;
+ #endif
+ }
+ hash++;
+ pos++;
+ cur++;
+ pb++;
+ if (hash == size || *hash != delta || pb[lenLimit] != cur[lenLimit] || d >= limit)
+ break;
+ }
+ }
+ #endif
+
+ break;
+ }
+ }
+ }
+ {
+ const UInt32 curMatch = (UInt32)pos - delta;
+ if (pb[len] < cur[len])
+ {
+ delta = pair[1];
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ len1 = len;
+ }
+ else
+ {
+ delta = *pair;
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ len0 = len;
+ }
+
+ {
+ if (delta >= curMatch)
+ return NULL;
+ delta = (UInt32)pos - delta;
+ if (delta >= cbs
+ // delta >= _cyclicBufferSize || delta >= pos
+ || --cutValue == 0)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ _distances[-1] = (UInt32)(d - _distances);
+ break;
+ }
+ }
+ }
+ }
+ } // for (tree iterations)
+}
+ pos++;
+ _cyclicBufferPos++;
+ cur++;
+ }
+ while (d < limit);
+ *posRes = (UInt32)pos;
+ return d;
+}
+*/
diff --git a/src/Common/lzma/LzHash.h b/src/Common/lzma/LzHash.h
new file mode 100644
index 00000000..77b898cf
--- /dev/null
+++ b/src/Common/lzma/LzHash.h
@@ -0,0 +1,34 @@
+/* LzHash.h -- HASH functions for LZ algorithms
+2019-10-30 : Igor Pavlov : Public domain */
+
+#ifndef __LZ_HASH_H
+#define __LZ_HASH_H
+
+/*
+ (kHash2Size >= (1 << 8)) : Required
+ (kHash3Size >= (1 << 16)) : Required
+*/
+
+#define kHash2Size (1 << 10)
+#define kHash3Size (1 << 16)
+// #define kHash4Size (1 << 20)
+
+#define kFix3HashSize (kHash2Size)
+#define kFix4HashSize (kHash2Size + kHash3Size)
+// #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
+
+/*
+ We use up to 3 crc values for hash:
+ crc0
+ crc1 << Shift_1
+ crc2 << Shift_2
+ (Shift_1 = 5) and (Shift_2 = 10) is good tradeoff.
+ Small values for Shift are not good for collision rate.
+ Big value for Shift_2 increases the minimum size
+ of hash table, that will be slow for small files.
+*/
+
+#define kLzHash_CrcShift_1 5
+#define kLzHash_CrcShift_2 10
+
+#endif
diff --git a/src/Common/lzma/LzmaDec.c b/src/Common/lzma/LzmaDec.c
new file mode 100644
index 00000000..d6742e5a
--- /dev/null
+++ b/src/Common/lzma/LzmaDec.c
@@ -0,0 +1,1363 @@
+/* LzmaDec.c -- LZMA Decoder
+2021-04-01 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+/* #include "CpuArch.h" */
+#include "LzmaDec.h"
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+
+#define RC_INIT_SIZE 5
+
+#ifndef _LZMA_DEC_OPT
+
+#define kNumMoveBits 5
+#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound)
+#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
+#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
+ { UPDATE_0(p); i = (i + i); A0; } else \
+ { UPDATE_1(p); i = (i + i) + 1; A1; }
+
+#define TREE_GET_BIT(probs, i) { GET_BIT2(probs + i, i, ;, ;); }
+
+#define REV_BIT(p, i, A0, A1) IF_BIT_0(p + i) \
+ { UPDATE_0(p + i); A0; } else \
+ { UPDATE_1(p + i); A1; }
+#define REV_BIT_VAR( p, i, m) REV_BIT(p, i, i += m; m += m, m += m; i += m; )
+#define REV_BIT_CONST(p, i, m) REV_BIT(p, i, i += m; , i += m * 2; )
+#define REV_BIT_LAST( p, i, m) REV_BIT(p, i, i -= m , ; )
+
+#define TREE_DECODE(probs, limit, i) \
+ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
+
+/* #define _LZMA_SIZE_OPT */
+
+#ifdef _LZMA_SIZE_OPT
+#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
+#else
+#define TREE_6_DECODE(probs, i) \
+ { i = 1; \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ i -= 0x40; }
+#endif
+
+#define NORMAL_LITER_DEC TREE_GET_BIT(prob, symbol)
+#define MATCHED_LITER_DEC \
+ matchByte += matchByte; \
+ bit = offs; \
+ offs &= matchByte; \
+ probLit = prob + (offs + bit + symbol); \
+ GET_BIT2(probLit, symbol, offs ^= bit; , ;)
+
+#endif // _LZMA_DEC_OPT
+
+
+#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_INPUT_EOF; range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound)
+#define UPDATE_0_CHECK range = bound;
+#define UPDATE_1_CHECK range -= bound; code -= bound;
+#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
+ { UPDATE_0_CHECK; i = (i + i); A0; } else \
+ { UPDATE_1_CHECK; i = (i + i) + 1; A1; }
+#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
+#define TREE_DECODE_CHECK(probs, limit, i) \
+ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
+
+
+#define REV_BIT_CHECK(p, i, m) IF_BIT_0_CHECK(p + i) \
+ { UPDATE_0_CHECK; i += m; m += m; } else \
+ { UPDATE_1_CHECK; m += m; i += m; }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenLow 0
+#define LenHigh (LenLow + 2 * (kNumPosStatesMax << kLenNumLowBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+#define LenChoice LenLow
+#define LenChoice2 (LenLow + (1 << kLenNumLowBits))
+
+#define kNumStates 12
+#define kNumStates2 16
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols)
+
+#define kMatchSpecLen_Error_Data (1 << 9)
+#define kMatchSpecLen_Error_Fail (kMatchSpecLen_Error_Data - 1)
+
+/* External ASM code needs same CLzmaProb array layout. So don't change it. */
+
+/* (probs_1664) is faster and better for code size at some platforms */
+/*
+#ifdef MY_CPU_X86_OR_AMD64
+*/
+#define kStartOffset 1664
+#define GET_PROBS p->probs_1664
+/*
+#define GET_PROBS p->probs + kStartOffset
+#else
+#define kStartOffset 0
+#define GET_PROBS p->probs
+#endif
+*/
+
+#define SpecPos (-kStartOffset)
+#define IsRep0Long (SpecPos + kNumFullDistances)
+#define RepLenCoder (IsRep0Long + (kNumStates2 << kNumPosBitsMax))
+#define LenCoder (RepLenCoder + kNumLenProbs)
+#define IsMatch (LenCoder + kNumLenProbs)
+#define Align (IsMatch + (kNumStates2 << kNumPosBitsMax))
+#define IsRep (Align + kAlignTableSize)
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define PosSlot (IsRepG2 + kNumStates)
+#define Literal (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define NUM_BASE_PROBS (Literal + kStartOffset)
+
+#if Align != 0 && kStartOffset != 0
+ #error Stop_Compiling_Bad_LZMA_kAlign
+#endif
+
+#if NUM_BASE_PROBS != 1984
+ #error Stop_Compiling_Bad_LZMA_PROBS
+#endif
+
+
+#define LZMA_LIT_SIZE 0x300
+
+#define LzmaProps_GetNumProbs(p) (NUM_BASE_PROBS + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
+
+
+#define CALC_POS_STATE(processedPos, pbMask) (((processedPos) & (pbMask)) << 4)
+#define COMBINED_PS_STATE (posState + state)
+#define GET_LEN_STATE (posState)
+
+#define LZMA_DIC_MIN (1 << 12)
+
+/*
+p->remainLen : shows status of LZMA decoder:
+ < kMatchSpecLenStart : the number of bytes to be copied with (p->rep0) offset
+ = kMatchSpecLenStart : the LZMA stream was finished with end mark
+ = kMatchSpecLenStart + 1 : need init range coder
+ = kMatchSpecLenStart + 2 : need init range coder and state
+ = kMatchSpecLen_Error_Fail : Internal Code Failure
+ = kMatchSpecLen_Error_Data + [0 ... 273] : LZMA Data Error
+*/
+
+/* ---------- LZMA_DECODE_REAL ---------- */
+/*
+LzmaDec_DecodeReal_3() can be implemented in external ASM file.
+3 - is the code compatibility version of that function for check at link time.
+*/
+
+#define LZMA_DECODE_REAL LzmaDec_DecodeReal_3
+
+/*
+LZMA_DECODE_REAL()
+In:
+ RangeCoder is normalized
+ if (p->dicPos == limit)
+ {
+ LzmaDec_TryDummy() was called before to exclude LITERAL and MATCH-REP cases.
+ So first symbol can be only MATCH-NON-REP. And if that MATCH-NON-REP symbol
+ is not END_OF_PAYALOAD_MARKER, then the function doesn't write any byte to dictionary,
+ the function returns SZ_OK, and the caller can use (p->remainLen) and (p->reps[0]) later.
+ }
+
+Processing:
+ The first LZMA symbol will be decoded in any case.
+ All main checks for limits are at the end of main loop,
+ It decodes additional LZMA-symbols while (p->buf < bufLimit && dicPos < limit),
+ RangeCoder is still without last normalization when (p->buf < bufLimit) is being checked.
+ But if (p->buf < bufLimit), the caller provided at least (LZMA_REQUIRED_INPUT_MAX + 1) bytes for
+ next iteration before limit (bufLimit + LZMA_REQUIRED_INPUT_MAX),
+ that is enough for worst case LZMA symbol with one additional RangeCoder normalization for one bit.
+ So that function never reads bufLimit [LZMA_REQUIRED_INPUT_MAX] byte.
+
+Out:
+ RangeCoder is normalized
+ Result:
+ SZ_OK - OK
+ p->remainLen:
+ < kMatchSpecLenStart : the number of bytes to be copied with (p->reps[0]) offset
+ = kMatchSpecLenStart : the LZMA stream was finished with end mark
+
+ SZ_ERROR_DATA - error, when the MATCH-Symbol refers out of dictionary
+ p->remainLen : undefined
+ p->reps[*] : undefined
+*/
+
+
+#ifdef _LZMA_DEC_OPT
+
+int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit);
+
+#else
+
+static
+int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ CLzmaProb *probs = GET_PROBS;
+ unsigned state = (unsigned)p->state;
+ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
+ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
+ unsigned lc = p->prop.lc;
+ unsigned lpMask = ((unsigned)0x100 << p->prop.lp) - ((unsigned)0x100 >> lc);
+
+ Byte *dic = p->dic;
+ SizeT dicBufSize = p->dicBufSize;
+ SizeT dicPos = p->dicPos;
+
+ UInt32 processedPos = p->processedPos;
+ UInt32 checkDicSize = p->checkDicSize;
+ unsigned len = 0;
+
+ const Byte *buf = p->buf;
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+
+ do
+ {
+ CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = CALC_POS_STATE(processedPos, pbMask);
+
+ prob = probs + IsMatch + COMBINED_PS_STATE;
+ IF_BIT_0(prob)
+ {
+ unsigned symbol;
+ UPDATE_0(prob);
+ prob = probs + Literal;
+ if (processedPos != 0 || checkDicSize != 0)
+ prob += (UInt32)3 * ((((processedPos << 8) + dic[(dicPos == 0 ? dicBufSize : dicPos) - 1]) & lpMask) << lc);
+ processedPos++;
+
+ if (state < kNumLitStates)
+ {
+ state -= (state < 4) ? state : 3;
+ symbol = 1;
+ #ifdef _LZMA_SIZE_OPT
+ do { NORMAL_LITER_DEC } while (symbol < 0x100);
+ #else
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ #endif
+ }
+ else
+ {
+ unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+ unsigned offs = 0x100;
+ state -= (state < 10) ? 3 : 6;
+ symbol = 1;
+ #ifdef _LZMA_SIZE_OPT
+ do
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ MATCHED_LITER_DEC
+ }
+ while (symbol < 0x100);
+ #else
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ }
+ #endif
+ }
+
+ dic[dicPos++] = (Byte)symbol;
+ continue;
+ }
+
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRep + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ state += kNumStates;
+ prob = probs + LenCoder;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ prob = probs + IsRep0Long + COMBINED_PS_STATE;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+
+ // that case was checked before with kBadRepCode
+ // if (checkDicSize == 0 && processedPos == 0) { len = kMatchSpecLen_Error_Data + 1; break; }
+ // The caller doesn't allow (dicPos == limit) case here
+ // so we don't need the following check:
+ // if (dicPos == limit) { state = state < kNumLitStates ? 9 : 11; len = 1; break; }
+
+ dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+ dicPos++;
+ processedPos++;
+ state = state < kNumLitStates ? 9 : 11;
+ continue;
+ }
+ UPDATE_1(prob);
+ }
+ else
+ {
+ UInt32 distance;
+ UPDATE_1(prob);
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ distance = rep1;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ distance = rep2;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < kNumLitStates ? 8 : 11;
+ prob = probs + RepLenCoder;
+ }
+
+ #ifdef _LZMA_SIZE_OPT
+ {
+ unsigned lim, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + GET_LEN_STATE;
+ offset = 0;
+ lim = (1 << kLenNumLowBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenChoice2;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits);
+ offset = kLenNumLowSymbols;
+ lim = (1 << kLenNumLowBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols * 2;
+ lim = (1 << kLenNumHighBits);
+ }
+ }
+ TREE_DECODE(probLen, lim, len);
+ len += offset;
+ }
+ #else
+ {
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + GET_LEN_STATE;
+ len = 1;
+ TREE_GET_BIT(probLen, len);
+ TREE_GET_BIT(probLen, len);
+ TREE_GET_BIT(probLen, len);
+ len -= 8;
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenChoice2;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits);
+ len = 1;
+ TREE_GET_BIT(probLen, len);
+ TREE_GET_BIT(probLen, len);
+ TREE_GET_BIT(probLen, len);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenHigh;
+ TREE_DECODE(probLen, (1 << kLenNumHighBits), len);
+ len += kLenNumLowSymbols * 2;
+ }
+ }
+ }
+ #endif
+
+ if (state >= kNumStates)
+ {
+ UInt32 distance;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
+ TREE_6_DECODE(prob, distance);
+ if (distance >= kStartPosModelIndex)
+ {
+ unsigned posSlot = (unsigned)distance;
+ unsigned numDirectBits = (unsigned)(((distance >> 1) - 1));
+ distance = (2 | (distance & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ distance <<= numDirectBits;
+ prob = probs + SpecPos;
+ {
+ UInt32 m = 1;
+ distance++;
+ do
+ {
+ REV_BIT_VAR(prob, distance, m);
+ }
+ while (--numDirectBits);
+ distance -= m;
+ }
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE
+ range >>= 1;
+
+ {
+ UInt32 t;
+ code -= range;
+ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
+ distance = (distance << 1) + (t + 1);
+ code += range & t;
+ }
+ /*
+ distance <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ distance |= 1;
+ }
+ */
+ }
+ while (--numDirectBits);
+ prob = probs + Align;
+ distance <<= kNumAlignBits;
+ {
+ unsigned i = 1;
+ REV_BIT_CONST(prob, i, 1);
+ REV_BIT_CONST(prob, i, 2);
+ REV_BIT_CONST(prob, i, 4);
+ REV_BIT_LAST (prob, i, 8);
+ distance |= i;
+ }
+ if (distance == (UInt32)0xFFFFFFFF)
+ {
+ len = kMatchSpecLenStart;
+ state -= kNumStates;
+ break;
+ }
+ }
+ }
+
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ rep0 = distance + 1;
+ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
+ if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize))
+ {
+ len += kMatchSpecLen_Error_Data + kMatchMinLen;
+ // len = kMatchSpecLen_Error_Data;
+ // len += kMatchMinLen;
+ break;
+ }
+ }
+
+ len += kMatchMinLen;
+
+ {
+ SizeT rem;
+ unsigned curLen;
+ SizeT pos;
+
+ if ((rem = limit - dicPos) == 0)
+ {
+ /*
+ We stop decoding and return SZ_OK, and we can resume decoding later.
+ Any error conditions can be tested later in caller code.
+ For more strict mode we can stop decoding with error
+ // len += kMatchSpecLen_Error_Data;
+ */
+ break;
+ }
+
+ curLen = ((rem < len) ? (unsigned)rem : len);
+ pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0);
+
+ processedPos += (UInt32)curLen;
+
+ len -= curLen;
+ if (curLen <= dicBufSize - pos)
+ {
+ Byte *dest = dic + dicPos;
+ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
+ const Byte *lim = dest + curLen;
+ dicPos += (SizeT)curLen;
+ do
+ *(dest) = (Byte)*(dest + src);
+ while (++dest != lim);
+ }
+ else
+ {
+ do
+ {
+ dic[dicPos++] = dic[pos];
+ if (++pos == dicBufSize)
+ pos = 0;
+ }
+ while (--curLen != 0);
+ }
+ }
+ }
+ }
+ while (dicPos < limit && buf < bufLimit);
+
+ NORMALIZE;
+
+ p->buf = buf;
+ p->range = range;
+ p->code = code;
+ p->remainLen = (UInt32)len; // & (kMatchSpecLen_Error_Data - 1); // we can write real length for error matches too.
+ p->dicPos = dicPos;
+ p->processedPos = processedPos;
+ p->reps[0] = rep0;
+ p->reps[1] = rep1;
+ p->reps[2] = rep2;
+ p->reps[3] = rep3;
+ p->state = (UInt32)state;
+ if (len >= kMatchSpecLen_Error_Data)
+ return SZ_ERROR_DATA;
+ return SZ_OK;
+}
+#endif
+
+
+
+static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
+{
+ unsigned len = (unsigned)p->remainLen;
+ if (len == 0 /* || len >= kMatchSpecLenStart */)
+ return;
+ {
+ SizeT dicPos = p->dicPos;
+ Byte *dic;
+ SizeT dicBufSize;
+ SizeT rep0; /* we use SizeT to avoid the BUG of VC14 for AMD64 */
+ {
+ SizeT rem = limit - dicPos;
+ if (rem < len)
+ {
+ len = (unsigned)(rem);
+ if (len == 0)
+ return;
+ }
+ }
+
+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
+ p->checkDicSize = p->prop.dicSize;
+
+ p->processedPos += (UInt32)len;
+ p->remainLen -= (UInt32)len;
+ dic = p->dic;
+ rep0 = p->reps[0];
+ dicBufSize = p->dicBufSize;
+ do
+ {
+ dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+ dicPos++;
+ }
+ while (--len);
+ p->dicPos = dicPos;
+ }
+}
+
+
+/*
+At staring of new stream we have one of the following symbols:
+ - Literal - is allowed
+ - Non-Rep-Match - is allowed only if it's end marker symbol
+ - Rep-Match - is not allowed
+We use early check of (RangeCoder:Code) over kBadRepCode to simplify main decoding code
+*/
+
+#define kRange0 0xFFFFFFFF
+#define kBound0 ((kRange0 >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1))
+#define kBadRepCode (kBound0 + (((kRange0 - kBound0) >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1)))
+#if kBadRepCode != (0xC0000000 - 0x400)
+ #error Stop_Compiling_Bad_LZMA_Check
+#endif
+
+
+/*
+LzmaDec_DecodeReal2():
+ It calls LZMA_DECODE_REAL() and it adjusts limit according (p->checkDicSize).
+
+We correct (p->checkDicSize) after LZMA_DECODE_REAL() and in LzmaDec_WriteRem(),
+and we support the following state of (p->checkDicSize):
+ if (total_processed < p->prop.dicSize) then
+ {
+ (total_processed == p->processedPos)
+ (p->checkDicSize == 0)
+ }
+ else
+ (p->checkDicSize == p->prop.dicSize)
+*/
+
+static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ if (p->checkDicSize == 0)
+ {
+ UInt32 rem = p->prop.dicSize - p->processedPos;
+ if (limit - p->dicPos > rem)
+ limit = p->dicPos + rem;
+ }
+ {
+ int res = LZMA_DECODE_REAL(p, limit, bufLimit);
+ if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize)
+ p->checkDicSize = p->prop.dicSize;
+ return res;
+ }
+}
+
+
+
+typedef enum
+{
+ DUMMY_INPUT_EOF, /* need more input data */
+ DUMMY_LIT,
+ DUMMY_MATCH,
+ DUMMY_REP
+} ELzmaDummy;
+
+
+#define IS_DUMMY_END_MARKER_POSSIBLE(dummyRes) ((dummyRes) == DUMMY_MATCH)
+
+static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, const Byte **bufOut)
+{
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+ const Byte *bufLimit = *bufOut;
+ const CLzmaProb *probs = GET_PROBS;
+ unsigned state = (unsigned)p->state;
+ ELzmaDummy res;
+
+ for (;;)
+ {
+ const CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = CALC_POS_STATE(p->processedPos, ((unsigned)1 << p->prop.pb) - 1);
+
+ prob = probs + IsMatch + COMBINED_PS_STATE;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK
+
+ prob = probs + Literal;
+ if (p->checkDicSize != 0 || p->processedPos != 0)
+ prob += ((UInt32)LZMA_LIT_SIZE *
+ ((((p->processedPos) & (((unsigned)1 << (p->prop.lp)) - 1)) << p->prop.lc) +
+ ((unsigned)p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
+
+ if (state < kNumLitStates)
+ {
+ unsigned symbol = 1;
+ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
+ }
+ else
+ {
+ unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
+ (p->dicPos < p->reps[0] ? p->dicBufSize : 0)];
+ unsigned offs = 0x100;
+ unsigned symbol = 1;
+ do
+ {
+ unsigned bit;
+ const CLzmaProb *probLit;
+ matchByte += matchByte;
+ bit = offs;
+ offs &= matchByte;
+ probLit = prob + (offs + bit + symbol);
+ GET_BIT2_CHECK(probLit, symbol, offs ^= bit; , ; )
+ }
+ while (symbol < 0x100);
+ }
+ res = DUMMY_LIT;
+ }
+ else
+ {
+ unsigned len;
+ UPDATE_1_CHECK;
+
+ prob = probs + IsRep + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ state = 0;
+ prob = probs + LenCoder;
+ res = DUMMY_MATCH;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ res = DUMMY_REP;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ prob = probs + IsRep0Long + COMBINED_PS_STATE;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ break;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ }
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ }
+ }
+ }
+ state = kNumStates;
+ prob = probs + RepLenCoder;
+ }
+ {
+ unsigned limit, offset;
+ const CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenLow + GET_LEN_STATE;
+ offset = 0;
+ limit = 1 << kLenNumLowBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenChoice2;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits);
+ offset = kLenNumLowSymbols;
+ limit = 1 << kLenNumLowBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols * 2;
+ limit = 1 << kLenNumHighBits;
+ }
+ }
+ TREE_DECODE_CHECK(probLen, limit, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ unsigned posSlot;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates - 1 ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ unsigned numDirectBits = ((posSlot >> 1) - 1);
+
+ if (posSlot < kEndPosModelIndex)
+ {
+ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits);
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE_CHECK
+ range >>= 1;
+ code -= range & (((code - range) >> 31) - 1);
+ /* if (code >= range) code -= range; */
+ }
+ while (--numDirectBits);
+ prob = probs + Align;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ unsigned i = 1;
+ unsigned m = 1;
+ do
+ {
+ REV_BIT_CHECK(prob, i, m);
+ }
+ while (--numDirectBits);
+ }
+ }
+ }
+ }
+ break;
+ }
+ NORMALIZE_CHECK;
+
+ *bufOut = buf;
+ return res;
+}
+
+void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState);
+void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState)
+{
+ p->remainLen = kMatchSpecLenStart + 1;
+ p->tempBufSize = 0;
+
+ if (initDic)
+ {
+ p->processedPos = 0;
+ p->checkDicSize = 0;
+ p->remainLen = kMatchSpecLenStart + 2;
+ }
+ if (initState)
+ p->remainLen = kMatchSpecLenStart + 2;
+}
+
+void LzmaDec_Init(CLzmaDec *p)
+{
+ p->dicPos = 0;
+ LzmaDec_InitDicAndState(p, True, True);
+}
+
+
+/*
+LZMA supports optional end_marker.
+So the decoder can lookahead for one additional LZMA-Symbol to check end_marker.
+That additional LZMA-Symbol can require up to LZMA_REQUIRED_INPUT_MAX bytes in input stream.
+When the decoder reaches dicLimit, it looks (finishMode) parameter:
+ if (finishMode == LZMA_FINISH_ANY), the decoder doesn't lookahead
+ if (finishMode != LZMA_FINISH_ANY), the decoder lookahead, if end_marker is possible for current position
+
+When the decoder lookahead, and the lookahead symbol is not end_marker, we have two ways:
+ 1) Strict mode (default) : the decoder returns SZ_ERROR_DATA.
+ 2) The relaxed mode (alternative mode) : we could return SZ_OK, and the caller
+ must check (status) value. The caller can show the error,
+ if the end of stream is expected, and the (status) is noit
+ LZMA_STATUS_FINISHED_WITH_MARK or LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK.
+*/
+
+
+#define RETURN__NOT_FINISHED__FOR_FINISH \
+ *status = LZMA_STATUS_NOT_FINISHED; \
+ return SZ_ERROR_DATA; // for strict mode
+ // return SZ_OK; // for relaxed mode
+
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
+ ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT inSize = *srcLen;
+ (*srcLen) = 0;
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+
+ if (p->remainLen > kMatchSpecLenStart)
+ {
+ if (p->remainLen > kMatchSpecLenStart + 2)
+ return p->remainLen == kMatchSpecLen_Error_Fail ? SZ_ERROR_FAIL : SZ_ERROR_DATA;
+
+ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
+ p->tempBuf[p->tempBufSize++] = *src++;
+ if (p->tempBufSize != 0 && p->tempBuf[0] != 0)
+ return SZ_ERROR_DATA;
+ if (p->tempBufSize < RC_INIT_SIZE)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ p->code =
+ ((UInt32)p->tempBuf[1] << 24)
+ | ((UInt32)p->tempBuf[2] << 16)
+ | ((UInt32)p->tempBuf[3] << 8)
+ | ((UInt32)p->tempBuf[4]);
+
+ if (p->checkDicSize == 0
+ && p->processedPos == 0
+ && p->code >= kBadRepCode)
+ return SZ_ERROR_DATA;
+
+ p->range = 0xFFFFFFFF;
+ p->tempBufSize = 0;
+
+ if (p->remainLen > kMatchSpecLenStart + 1)
+ {
+ SizeT numProbs = LzmaProps_GetNumProbs(&p->prop);
+ SizeT i;
+ CLzmaProb *probs = p->probs;
+ for (i = 0; i < numProbs; i++)
+ probs[i] = kBitModelTotal >> 1;
+ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
+ p->state = 0;
+ }
+
+ p->remainLen = 0;
+ }
+
+ for (;;)
+ {
+ if (p->remainLen == kMatchSpecLenStart)
+ {
+ if (p->code != 0)
+ return SZ_ERROR_DATA;
+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+ }
+
+ LzmaDec_WriteRem(p, dicLimit);
+
+ {
+ // (p->remainLen == 0 || p->dicPos == dicLimit)
+
+ int checkEndMarkNow = 0;
+
+ if (p->dicPos >= dicLimit)
+ {
+ if (p->remainLen == 0 && p->code == 0)
+ {
+ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
+ return SZ_OK;
+ }
+ if (finishMode == LZMA_FINISH_ANY)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+ if (p->remainLen != 0)
+ {
+ RETURN__NOT_FINISHED__FOR_FINISH;
+ }
+ checkEndMarkNow = 1;
+ }
+
+ // (p->remainLen == 0)
+
+ if (p->tempBufSize == 0)
+ {
+ const Byte *bufLimit;
+ int dummyProcessed = -1;
+
+ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ const Byte *bufOut = src + inSize;
+
+ ELzmaDummy dummyRes = LzmaDec_TryDummy(p, src, &bufOut);
+
+ if (dummyRes == DUMMY_INPUT_EOF)
+ {
+ size_t i;
+ if (inSize >= LZMA_REQUIRED_INPUT_MAX)
+ break;
+ (*srcLen) += inSize;
+ p->tempBufSize = (unsigned)inSize;
+ for (i = 0; i < inSize; i++)
+ p->tempBuf[i] = src[i];
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+
+ dummyProcessed = (int)(bufOut - src);
+ if ((unsigned)dummyProcessed > LZMA_REQUIRED_INPUT_MAX)
+ break;
+
+ if (checkEndMarkNow && !IS_DUMMY_END_MARKER_POSSIBLE(dummyRes))
+ {
+ unsigned i;
+ (*srcLen) += (unsigned)dummyProcessed;
+ p->tempBufSize = (unsigned)dummyProcessed;
+ for (i = 0; i < (unsigned)dummyProcessed; i++)
+ p->tempBuf[i] = src[i];
+ // p->remainLen = kMatchSpecLen_Error_Data;
+ RETURN__NOT_FINISHED__FOR_FINISH;
+ }
+
+ bufLimit = src;
+ // we will decode only one iteration
+ }
+ else
+ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
+
+ p->buf = src;
+
+ {
+ int res = LzmaDec_DecodeReal2(p, dicLimit, bufLimit);
+
+ SizeT processed = (SizeT)(p->buf - src);
+
+ if (dummyProcessed < 0)
+ {
+ if (processed > inSize)
+ break;
+ }
+ else if ((unsigned)dummyProcessed != processed)
+ break;
+
+ src += processed;
+ inSize -= processed;
+ (*srcLen) += processed;
+
+ if (res != SZ_OK)
+ {
+ p->remainLen = kMatchSpecLen_Error_Data;
+ return SZ_ERROR_DATA;
+ }
+ }
+ continue;
+ }
+
+ {
+ // we have some data in (p->tempBuf)
+ // in strict mode: tempBufSize is not enough for one Symbol decoding.
+ // in relaxed mode: tempBufSize not larger than required for one Symbol decoding.
+
+ unsigned rem = p->tempBufSize;
+ unsigned ahead = 0;
+ int dummyProcessed = -1;
+
+ while (rem < LZMA_REQUIRED_INPUT_MAX && ahead < inSize)
+ p->tempBuf[rem++] = src[ahead++];
+
+ // ahead - the size of new data copied from (src) to (p->tempBuf)
+ // rem - the size of temp buffer including new data from (src)
+
+ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ const Byte *bufOut = p->tempBuf + rem;
+
+ ELzmaDummy dummyRes = LzmaDec_TryDummy(p, p->tempBuf, &bufOut);
+
+ if (dummyRes == DUMMY_INPUT_EOF)
+ {
+ if (rem >= LZMA_REQUIRED_INPUT_MAX)
+ break;
+ p->tempBufSize = rem;
+ (*srcLen) += (SizeT)ahead;
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+
+ dummyProcessed = (int)(bufOut - p->tempBuf);
+
+ if ((unsigned)dummyProcessed < p->tempBufSize)
+ break;
+
+ if (checkEndMarkNow && !IS_DUMMY_END_MARKER_POSSIBLE(dummyRes))
+ {
+ (*srcLen) += (unsigned)dummyProcessed - p->tempBufSize;
+ p->tempBufSize = (unsigned)dummyProcessed;
+ // p->remainLen = kMatchSpecLen_Error_Data;
+ RETURN__NOT_FINISHED__FOR_FINISH;
+ }
+ }
+
+ p->buf = p->tempBuf;
+
+ {
+ // we decode one symbol from (p->tempBuf) here, so the (bufLimit) is equal to (p->buf)
+ int res = LzmaDec_DecodeReal2(p, dicLimit, p->buf);
+
+ SizeT processed = (SizeT)(p->buf - p->tempBuf);
+ rem = p->tempBufSize;
+
+ if (dummyProcessed < 0)
+ {
+ if (processed > LZMA_REQUIRED_INPUT_MAX)
+ break;
+ if (processed < rem)
+ break;
+ }
+ else if ((unsigned)dummyProcessed != processed)
+ break;
+
+ processed -= rem;
+
+ src += processed;
+ inSize -= processed;
+ (*srcLen) += processed;
+ p->tempBufSize = 0;
+
+ if (res != SZ_OK)
+ {
+ p->remainLen = kMatchSpecLen_Error_Data;
+ return SZ_ERROR_DATA;
+ }
+ }
+ }
+ }
+ }
+
+ /* Some unexpected error: internal error of code, memory corruption or hardware failure */
+ p->remainLen = kMatchSpecLen_Error_Fail;
+ return SZ_ERROR_FAIL;
+}
+
+
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT outSize = *destLen;
+ SizeT inSize = *srcLen;
+ *srcLen = *destLen = 0;
+ for (;;)
+ {
+ SizeT inSizeCur = inSize, outSizeCur, dicPos;
+ ELzmaFinishMode curFinishMode;
+ SRes res;
+ if (p->dicPos == p->dicBufSize)
+ p->dicPos = 0;
+ dicPos = p->dicPos;
+ if (outSize > p->dicBufSize - dicPos)
+ {
+ outSizeCur = p->dicBufSize;
+ curFinishMode = LZMA_FINISH_ANY;
+ }
+ else
+ {
+ outSizeCur = dicPos + outSize;
+ curFinishMode = finishMode;
+ }
+
+ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
+ src += inSizeCur;
+ inSize -= inSizeCur;
+ *srcLen += inSizeCur;
+ outSizeCur = p->dicPos - dicPos;
+ memcpy(dest, p->dic + dicPos, outSizeCur);
+ dest += outSizeCur;
+ outSize -= outSizeCur;
+ *destLen += outSizeCur;
+ if (res != 0)
+ return res;
+ if (outSizeCur == 0 || outSize == 0)
+ return SZ_OK;
+ }
+}
+
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->probs);
+ p->probs = NULL;
+}
+
+static void LzmaDec_FreeDict(CLzmaDec *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->dic);
+ p->dic = NULL;
+}
+
+void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc)
+{
+ LzmaDec_FreeProbs(p, alloc);
+ LzmaDec_FreeDict(p, alloc);
+}
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
+{
+ UInt32 dicSize;
+ Byte d;
+
+ if (size < LZMA_PROPS_SIZE)
+ return SZ_ERROR_UNSUPPORTED;
+ else
+ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
+
+ if (dicSize < LZMA_DIC_MIN)
+ dicSize = LZMA_DIC_MIN;
+ p->dicSize = dicSize;
+
+ d = data[0];
+ if (d >= (9 * 5 * 5))
+ return SZ_ERROR_UNSUPPORTED;
+
+ p->lc = (Byte)(d % 9);
+ d /= 9;
+ p->pb = (Byte)(d / 5);
+ p->lp = (Byte)(d % 5);
+
+ return SZ_OK;
+}
+
+static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAllocPtr alloc)
+{
+ UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
+ if (!p->probs || numProbs != p->numProbs)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ p->probs = (CLzmaProb *)ISzAlloc_Alloc(alloc, numProbs * sizeof(CLzmaProb));
+ if (!p->probs)
+ return SZ_ERROR_MEM;
+ p->probs_1664 = p->probs + 1664;
+ p->numProbs = numProbs;
+ }
+ return SZ_OK;
+}
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc)
+{
+ CLzmaProps propNew;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc)
+{
+ CLzmaProps propNew;
+ SizeT dicBufSize;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+
+ {
+ UInt32 dictSize = propNew.dicSize;
+ SizeT mask = ((UInt32)1 << 12) - 1;
+ if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1;
+ else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;;
+ dicBufSize = ((SizeT)dictSize + mask) & ~mask;
+ if (dicBufSize < dictSize)
+ dicBufSize = dictSize;
+ }
+
+ if (!p->dic || dicBufSize != p->dicBufSize)
+ {
+ LzmaDec_FreeDict(p, alloc);
+ p->dic = (Byte *)ISzAlloc_Alloc(alloc, dicBufSize);
+ if (!p->dic)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ return SZ_ERROR_MEM;
+ }
+ }
+ p->dicBufSize = dicBufSize;
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAllocPtr alloc)
+{
+ CLzmaDec p;
+ SRes res;
+ SizeT outSize = *destLen, inSize = *srcLen;
+ *destLen = *srcLen = 0;
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+ if (inSize < RC_INIT_SIZE)
+ return SZ_ERROR_INPUT_EOF;
+ LzmaDec_Construct(&p);
+ RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc));
+ p.dic = dest;
+ p.dicBufSize = outSize;
+ LzmaDec_Init(&p);
+ *srcLen = inSize;
+ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
+ *destLen = p.dicPos;
+ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ res = SZ_ERROR_INPUT_EOF;
+ LzmaDec_FreeProbs(&p, alloc);
+ return res;
+}
diff --git a/src/Common/lzma/LzmaDec.h b/src/Common/lzma/LzmaDec.h
new file mode 100644
index 00000000..6f129625
--- /dev/null
+++ b/src/Common/lzma/LzmaDec.h
@@ -0,0 +1,236 @@
+/* LzmaDec.h -- LZMA Decoder
+2020-03-19 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA_DEC_H
+#define __LZMA_DEC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/* #define _LZMA_PROB32 */
+/* _LZMA_PROB32 can increase the speed on some CPUs,
+ but memory usage for CLzmaDec::probs will be doubled in that case */
+
+typedef
+#ifdef _LZMA_PROB32
+ UInt32
+#else
+ UInt16
+#endif
+ CLzmaProb;
+
+
+/* ---------- LZMA Properties ---------- */
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct _CLzmaProps
+{
+ Byte lc;
+ Byte lp;
+ Byte pb;
+ Byte _pad_;
+ UInt32 dicSize;
+} CLzmaProps;
+
+/* LzmaProps_Decode - decodes properties
+Returns:
+ SZ_OK
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
+
+
+/* ---------- LZMA Decoder state ---------- */
+
+/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
+ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
+
+#define LZMA_REQUIRED_INPUT_MAX 20
+
+typedef struct
+{
+ /* Don't change this structure. ASM code can use it. */
+ CLzmaProps prop;
+ CLzmaProb *probs;
+ CLzmaProb *probs_1664;
+ Byte *dic;
+ SizeT dicBufSize;
+ SizeT dicPos;
+ const Byte *buf;
+ UInt32 range;
+ UInt32 code;
+ UInt32 processedPos;
+ UInt32 checkDicSize;
+ UInt32 reps[4];
+ UInt32 state;
+ UInt32 remainLen;
+
+ UInt32 numProbs;
+ unsigned tempBufSize;
+ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
+} CLzmaDec;
+
+#define LzmaDec_Construct(p) { (p)->dic = NULL; (p)->probs = NULL; }
+
+void LzmaDec_Init(CLzmaDec *p);
+
+/* There are two types of LZMA streams:
+ - Stream with end mark. That end mark adds about 6 bytes to compressed size.
+ - Stream without end mark. You must know exact uncompressed size to decompress such stream. */
+
+typedef enum
+{
+ LZMA_FINISH_ANY, /* finish at any point */
+ LZMA_FINISH_END /* block must be finished at the end */
+} ELzmaFinishMode;
+
+/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
+
+ You must use LZMA_FINISH_END, when you know that current output buffer
+ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
+
+ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
+ and output value of destLen will be less than output buffer size limit.
+ You can check status result also.
+
+ You can use multiple checks to test data integrity after full decompression:
+ 1) Check Result and "status" variable.
+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
+ You must use correct finish mode in that case. */
+
+typedef enum
+{
+ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */
+ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
+ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */
+ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */
+} ELzmaStatus;
+
+/* ELzmaStatus is used only as output value for function call */
+
+
+/* ---------- Interfaces ---------- */
+
+/* There are 3 levels of interfaces:
+ 1) Dictionary Interface
+ 2) Buffer Interface
+ 3) One Call Interface
+ You can select any of these interfaces, but don't mix functions from different
+ groups for same object. */
+
+
+/* There are two variants to allocate state for Dictionary Interface:
+ 1) LzmaDec_Allocate / LzmaDec_Free
+ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
+ You can use variant 2, if you set dictionary buffer manually.
+ For Buffer Interface you must always use variant 1.
+
+LzmaDec_Allocate* can return:
+ SZ_OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc);
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc);
+
+SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc);
+void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc);
+
+/* ---------- Dictionary Interface ---------- */
+
+/* You can use it, if you want to eliminate the overhead for data copying from
+ dictionary to some other external buffer.
+ You must work with CLzmaDec variables directly in this interface.
+
+ STEPS:
+ LzmaDec_Construct()
+ LzmaDec_Allocate()
+ for (each new stream)
+ {
+ LzmaDec_Init()
+ while (it needs more decompression)
+ {
+ LzmaDec_DecodeToDic()
+ use data from CLzmaDec::dic and update CLzmaDec::dicPos
+ }
+ }
+ LzmaDec_Free()
+*/
+
+/* LzmaDec_DecodeToDic
+
+ The decoding to internal dictionary buffer (CLzmaDec::dic).
+ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (dicLimit).
+ LZMA_FINISH_ANY - Decode just dicLimit bytes.
+ LZMA_FINISH_END - Stream must be finished after dicLimit.
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_NEEDS_MORE_INPUT
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_FAIL - Some unexpected error: internal error of code, memory corruption or hardware failure
+*/
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- Buffer Interface ---------- */
+
+/* It's zlib-like interface.
+ See LzmaDec_DecodeToDic description for information about STEPS and return results,
+ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
+ to work with CLzmaDec variables manually.
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+*/
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- One Call Interface ---------- */
+
+/* LzmaDecode
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+ SZ_ERROR_FAIL - Some unexpected error: internal error of code, memory corruption or hardware failure
+*/
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAllocPtr alloc);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/Common/lzma/LzmaEnc.c b/src/Common/lzma/LzmaEnc.c
new file mode 100644
index 00000000..b04a7b7b
--- /dev/null
+++ b/src/Common/lzma/LzmaEnc.c
@@ -0,0 +1,3165 @@
+/* LzmaEnc.c -- LZMA Encoder
+2021-11-18: Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+/* #define SHOW_STAT */
+/* #define SHOW_STAT2 */
+
+#if defined(SHOW_STAT) || defined(SHOW_STAT2)
+#include <stdio.h>
+#endif
+
+#include "CpuArch.h"
+#include "LzmaEnc.h"
+
+#include "LzFind.h"
+#ifndef _7ZIP_ST
+#include "LzFindMt.h"
+#endif
+
+/* the following LzmaEnc_* declarations is internal LZMA interface for LZMA2 encoder */
+
+SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize,
+ ISzAllocPtr alloc, ISzAllocPtr allocBig);
+SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
+ UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig);
+SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit,
+ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize);
+const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp);
+void LzmaEnc_Finish(CLzmaEncHandle pp);
+void LzmaEnc_SaveState(CLzmaEncHandle pp);
+void LzmaEnc_RestoreState(CLzmaEncHandle pp);
+
+#ifdef SHOW_STAT
+static unsigned g_STAT_OFFSET = 0;
+#endif
+
+/* for good normalization speed we still reserve 256 MB before 4 GB range */
+#define kLzmaMaxHistorySize ((UInt32)15 << 28)
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+#define kProbInitValue (kBitModelTotal >> 1)
+
+#define kNumMoveReducingBits 4
+#define kNumBitPriceShiftBits 4
+// #define kBitPrice (1 << kNumBitPriceShiftBits)
+
+#define REP_LEN_COUNT 64
+
+void LzmaEncProps_Init(CLzmaEncProps *p)
+{
+ p->level = 5;
+ p->dictSize = p->mc = 0;
+ p->reduceSize = (UInt64)(Int64)-1;
+ p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
+ p->writeEndMark = 0;
+ p->affinity = 0;
+}
+
+void LzmaEncProps_Normalize(CLzmaEncProps *p)
+{
+ int level = p->level;
+ if (level < 0) level = 5;
+ p->level = level;
+
+ if (p->dictSize == 0)
+ p->dictSize =
+ ( level <= 3 ? ((UInt32)1 << (level * 2 + 16)) :
+ ( level <= 6 ? ((UInt32)1 << (level + 19)) :
+ ( level <= 7 ? ((UInt32)1 << 25) : ((UInt32)1 << 26)
+ )));
+
+ if (p->dictSize > p->reduceSize)
+ {
+ UInt32 v = (UInt32)p->reduceSize;
+ const UInt32 kReduceMin = ((UInt32)1 << 12);
+ if (v < kReduceMin)
+ v = kReduceMin;
+ if (p->dictSize > v)
+ p->dictSize = v;
+ }
+
+ if (p->lc < 0) p->lc = 3;
+ if (p->lp < 0) p->lp = 0;
+ if (p->pb < 0) p->pb = 2;
+
+ if (p->algo < 0) p->algo = (level < 5 ? 0 : 1);
+ if (p->fb < 0) p->fb = (level < 7 ? 32 : 64);
+ if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1);
+ if (p->numHashBytes < 0) p->numHashBytes = (p->btMode ? 4 : 5);
+ if (p->mc == 0) p->mc = (16 + ((unsigned)p->fb >> 1)) >> (p->btMode ? 0 : 1);
+
+ if (p->numThreads < 0)
+ p->numThreads =
+ #ifndef _7ZIP_ST
+ ((p->btMode && p->algo) ? 2 : 1);
+ #else
+ 1;
+ #endif
+}
+
+UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
+{
+ CLzmaEncProps props = *props2;
+ LzmaEncProps_Normalize(&props);
+ return props.dictSize;
+}
+
+
+/*
+x86/x64:
+
+BSR:
+ IF (SRC == 0) ZF = 1, DEST is undefined;
+ AMD : DEST is unchanged;
+ IF (SRC != 0) ZF = 0; DEST is index of top non-zero bit
+ BSR is slow in some processors
+
+LZCNT:
+ IF (SRC == 0) CF = 1, DEST is size_in_bits_of_register(src) (32 or 64)
+ IF (SRC != 0) CF = 0, DEST = num_lead_zero_bits
+ IF (DEST == 0) ZF = 1;
+
+LZCNT works only in new processors starting from Haswell.
+if LZCNT is not supported by processor, then it's executed as BSR.
+LZCNT can be faster than BSR, if supported.
+*/
+
+// #define LZMA_LOG_BSR
+
+#if defined(MY_CPU_ARM_OR_ARM64) /* || defined(MY_CPU_X86_OR_AMD64) */
+
+ #if (defined(__clang__) && (__clang_major__ >= 6)) \
+ || (defined(__GNUC__) && (__GNUC__ >= 6))
+ #define LZMA_LOG_BSR
+ #elif defined(_MSC_VER) && (_MSC_VER >= 1300)
+ // #if defined(MY_CPU_ARM_OR_ARM64)
+ #define LZMA_LOG_BSR
+ // #endif
+ #endif
+#endif
+
+// #include <intrin.h>
+
+#ifdef LZMA_LOG_BSR
+
+#if defined(__clang__) \
+ || defined(__GNUC__)
+
+/*
+ C code: : (30 - __builtin_clz(x))
+ gcc9/gcc10 for x64 /x86 : 30 - (bsr(x) xor 31)
+ clang10 for x64 : 31 + (bsr(x) xor -32)
+*/
+
+ #define MY_clz(x) ((unsigned)__builtin_clz(x))
+ // __lzcnt32
+ // __builtin_ia32_lzcnt_u32
+
+#else // #if defined(_MSC_VER)
+
+ #ifdef MY_CPU_ARM_OR_ARM64
+
+ #define MY_clz _CountLeadingZeros
+
+ #else // if defined(MY_CPU_X86_OR_AMD64)
+
+ // #define MY_clz __lzcnt // we can use lzcnt (unsupported by old CPU)
+ // _BitScanReverse code is not optimal for some MSVC compilers
+ #define BSR2_RET(pos, res) { unsigned long zz; _BitScanReverse(&zz, (pos)); zz--; \
+ res = (zz + zz) + (pos >> zz); }
+
+ #endif // MY_CPU_X86_OR_AMD64
+
+#endif // _MSC_VER
+
+
+#ifndef BSR2_RET
+
+ #define BSR2_RET(pos, res) { unsigned zz = 30 - MY_clz(pos); \
+ res = (zz + zz) + (pos >> zz); }
+
+#endif
+
+
+unsigned GetPosSlot1(UInt32 pos);
+unsigned GetPosSlot1(UInt32 pos)
+{
+ unsigned res;
+ BSR2_RET(pos, res);
+ return res;
+}
+#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
+#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
+
+
+#else // ! LZMA_LOG_BSR
+
+#define kNumLogBits (11 + sizeof(size_t) / 8 * 3)
+
+#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
+
+static void LzmaEnc_FastPosInit(Byte *g_FastPos)
+{
+ unsigned slot;
+ g_FastPos[0] = 0;
+ g_FastPos[1] = 1;
+ g_FastPos += 2;
+
+ for (slot = 2; slot < kNumLogBits * 2; slot++)
+ {
+ size_t k = ((size_t)1 << ((slot >> 1) - 1));
+ size_t j;
+ for (j = 0; j < k; j++)
+ g_FastPos[j] = (Byte)slot;
+ g_FastPos += k;
+ }
+}
+
+/* we can use ((limit - pos) >> 31) only if (pos < ((UInt32)1 << 31)) */
+/*
+#define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \
+ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
+ res = p->g_FastPos[pos >> zz] + (zz * 2); }
+*/
+
+/*
+#define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \
+ (0 - (((((UInt32)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \
+ res = p->g_FastPos[pos >> zz] + (zz * 2); }
+*/
+
+#define BSR2_RET(pos, res) { unsigned zz = (pos < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1; \
+ res = p->g_FastPos[pos >> zz] + (zz * 2); }
+
+/*
+#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
+ p->g_FastPos[pos >> 6] + 12 : \
+ p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
+*/
+
+#define GetPosSlot1(pos) p->g_FastPos[pos]
+#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
+#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos & (kNumFullDistances - 1)]; else BSR2_RET(pos, res); }
+
+#endif // LZMA_LOG_BSR
+
+
+#define LZMA_NUM_REPS 4
+
+typedef UInt16 CState;
+typedef UInt16 CExtra;
+
+typedef struct
+{
+ UInt32 price;
+ CState state;
+ CExtra extra;
+ // 0 : normal
+ // 1 : LIT : MATCH
+ // > 1 : MATCH (extra-1) : LIT : REP0 (len)
+ UInt32 len;
+ UInt32 dist;
+ UInt32 reps[LZMA_NUM_REPS];
+} COptimal;
+
+
+// 18.06
+#define kNumOpts (1 << 11)
+#define kPackReserve (kNumOpts * 8)
+// #define kNumOpts (1 << 12)
+// #define kPackReserve (1 + kNumOpts * 2)
+
+#define kNumLenToPosStates 4
+#define kNumPosSlotBits 6
+// #define kDicLogSizeMin 0
+#define kDicLogSizeMax 32
+#define kDistTableSizeMax (kDicLogSizeMax * 2)
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+#define kAlignMask (kAlignTableSize - 1)
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+typedef
+#ifdef _LZMA_PROB32
+ UInt32
+#else
+ UInt16
+#endif
+ CLzmaProb;
+
+#define LZMA_PB_MAX 4
+#define LZMA_LC_MAX 8
+#define LZMA_LP_MAX 4
+
+#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+#define kLenNumSymbolsTotal (kLenNumLowSymbols * 2 + kLenNumHighSymbols)
+
+#define LZMA_MATCH_LEN_MIN 2
+#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
+
+#define kNumStates 12
+
+
+typedef struct
+{
+ CLzmaProb low[LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)];
+ CLzmaProb high[kLenNumHighSymbols];
+} CLenEnc;
+
+
+typedef struct
+{
+ unsigned tableSize;
+ UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
+ // UInt32 prices1[LZMA_NUM_PB_STATES_MAX][kLenNumLowSymbols * 2];
+ // UInt32 prices2[kLenNumSymbolsTotal];
+} CLenPriceEnc;
+
+#define GET_PRICE_LEN(p, posState, len) \
+ ((p)->prices[posState][(size_t)(len) - LZMA_MATCH_LEN_MIN])
+
+/*
+#define GET_PRICE_LEN(p, posState, len) \
+ ((p)->prices2[(size_t)(len) - 2] + ((p)->prices1[posState][((len) - 2) & (kLenNumLowSymbols * 2 - 1)] & (((len) - 2 - kLenNumLowSymbols * 2) >> 9)))
+*/
+
+typedef struct
+{
+ UInt32 range;
+ unsigned cache;
+ UInt64 low;
+ UInt64 cacheSize;
+ Byte *buf;
+ Byte *bufLim;
+ Byte *bufBase;
+ ISeqOutStream *outStream;
+ UInt64 processed;
+ SRes res;
+} CRangeEnc;
+
+
+typedef struct
+{
+ CLzmaProb *litProbs;
+
+ unsigned state;
+ UInt32 reps[LZMA_NUM_REPS];
+
+ CLzmaProb posAlignEncoder[1 << kNumAlignBits];
+ CLzmaProb isRep[kNumStates];
+ CLzmaProb isRepG0[kNumStates];
+ CLzmaProb isRepG1[kNumStates];
+ CLzmaProb isRepG2[kNumStates];
+ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
+ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
+
+ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
+ CLzmaProb posEncoders[kNumFullDistances];
+
+ CLenEnc lenProbs;
+ CLenEnc repLenProbs;
+
+} CSaveState;
+
+
+typedef UInt32 CProbPrice;
+
+
+typedef struct
+{
+ void *matchFinderObj;
+ IMatchFinder2 matchFinder;
+
+ unsigned optCur;
+ unsigned optEnd;
+
+ unsigned longestMatchLen;
+ unsigned numPairs;
+ UInt32 numAvail;
+
+ unsigned state;
+ unsigned numFastBytes;
+ unsigned additionalOffset;
+ UInt32 reps[LZMA_NUM_REPS];
+ unsigned lpMask, pbMask;
+ CLzmaProb *litProbs;
+ CRangeEnc rc;
+
+ UInt32 backRes;
+
+ unsigned lc, lp, pb;
+ unsigned lclp;
+
+ BoolInt fastMode;
+ BoolInt writeEndMark;
+ BoolInt finished;
+ BoolInt multiThread;
+ BoolInt needInit;
+ // BoolInt _maxMode;
+
+ UInt64 nowPos64;
+
+ unsigned matchPriceCount;
+ // unsigned alignPriceCount;
+ int repLenEncCounter;
+
+ unsigned distTableSize;
+
+ UInt32 dictSize;
+ SRes result;
+
+ #ifndef _7ZIP_ST
+ BoolInt mtMode;
+ // begin of CMatchFinderMt is used in LZ thread
+ CMatchFinderMt matchFinderMt;
+ // end of CMatchFinderMt is used in BT and HASH threads
+ // #else
+ // CMatchFinder matchFinderBase;
+ #endif
+ CMatchFinder matchFinderBase;
+
+
+ // we suppose that we have 8-bytes alignment after CMatchFinder
+
+ #ifndef _7ZIP_ST
+ Byte pad[128];
+ #endif
+
+ // LZ thread
+ CProbPrice ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
+
+ // we want {len , dist} pairs to be 8-bytes aligned in matches array
+ UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2];
+
+ // we want 8-bytes alignment here
+ UInt32 alignPrices[kAlignTableSize];
+ UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
+ UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
+
+ CLzmaProb posAlignEncoder[1 << kNumAlignBits];
+ CLzmaProb isRep[kNumStates];
+ CLzmaProb isRepG0[kNumStates];
+ CLzmaProb isRepG1[kNumStates];
+ CLzmaProb isRepG2[kNumStates];
+ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
+ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
+ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
+ CLzmaProb posEncoders[kNumFullDistances];
+
+ CLenEnc lenProbs;
+ CLenEnc repLenProbs;
+
+ #ifndef LZMA_LOG_BSR
+ Byte g_FastPos[1 << kNumLogBits];
+ #endif
+
+ CLenPriceEnc lenEnc;
+ CLenPriceEnc repLenEnc;
+
+ COptimal opt[kNumOpts];
+
+ CSaveState saveState;
+
+ // BoolInt mf_Failure;
+ #ifndef _7ZIP_ST
+ Byte pad2[128];
+ #endif
+} CLzmaEnc;
+
+
+#define MFB (p->matchFinderBase)
+/*
+#ifndef _7ZIP_ST
+#define MFB (p->matchFinderMt.MatchFinder)
+#endif
+*/
+
+#define COPY_ARR(dest, src, arr) memcpy(dest->arr, src->arr, sizeof(src->arr));
+
+void LzmaEnc_SaveState(CLzmaEncHandle pp)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ CSaveState *dest = &p->saveState;
+
+ dest->state = p->state;
+
+ dest->lenProbs = p->lenProbs;
+ dest->repLenProbs = p->repLenProbs;
+
+ COPY_ARR(dest, p, reps);
+
+ COPY_ARR(dest, p, posAlignEncoder);
+ COPY_ARR(dest, p, isRep);
+ COPY_ARR(dest, p, isRepG0);
+ COPY_ARR(dest, p, isRepG1);
+ COPY_ARR(dest, p, isRepG2);
+ COPY_ARR(dest, p, isMatch);
+ COPY_ARR(dest, p, isRep0Long);
+ COPY_ARR(dest, p, posSlotEncoder);
+ COPY_ARR(dest, p, posEncoders);
+
+ memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << p->lclp) * sizeof(CLzmaProb));
+}
+
+
+void LzmaEnc_RestoreState(CLzmaEncHandle pp)
+{
+ CLzmaEnc *dest = (CLzmaEnc *)pp;
+ const CSaveState *p = &dest->saveState;
+
+ dest->state = p->state;
+
+ dest->lenProbs = p->lenProbs;
+ dest->repLenProbs = p->repLenProbs;
+
+ COPY_ARR(dest, p, reps);
+
+ COPY_ARR(dest, p, posAlignEncoder);
+ COPY_ARR(dest, p, isRep);
+ COPY_ARR(dest, p, isRepG0);
+ COPY_ARR(dest, p, isRepG1);
+ COPY_ARR(dest, p, isRepG2);
+ COPY_ARR(dest, p, isMatch);
+ COPY_ARR(dest, p, isRep0Long);
+ COPY_ARR(dest, p, posSlotEncoder);
+ COPY_ARR(dest, p, posEncoders);
+
+ memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << dest->lclp) * sizeof(CLzmaProb));
+}
+
+
+
+SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ CLzmaEncProps props = *props2;
+ LzmaEncProps_Normalize(&props);
+
+ if (props.lc > LZMA_LC_MAX
+ || props.lp > LZMA_LP_MAX
+ || props.pb > LZMA_PB_MAX)
+ return SZ_ERROR_PARAM;
+
+
+ if (props.dictSize > kLzmaMaxHistorySize)
+ props.dictSize = kLzmaMaxHistorySize;
+
+ #ifndef LZMA_LOG_BSR
+ {
+ const UInt64 dict64 = props.dictSize;
+ if (dict64 > ((UInt64)1 << kDicLogSizeMaxCompress))
+ return SZ_ERROR_PARAM;
+ }
+ #endif
+
+ p->dictSize = props.dictSize;
+ {
+ unsigned fb = (unsigned)props.fb;
+ if (fb < 5)
+ fb = 5;
+ if (fb > LZMA_MATCH_LEN_MAX)
+ fb = LZMA_MATCH_LEN_MAX;
+ p->numFastBytes = fb;
+ }
+ p->lc = (unsigned)props.lc;
+ p->lp = (unsigned)props.lp;
+ p->pb = (unsigned)props.pb;
+ p->fastMode = (props.algo == 0);
+ // p->_maxMode = True;
+ MFB.btMode = (Byte)(props.btMode ? 1 : 0);
+ {
+ unsigned numHashBytes = 4;
+ if (props.btMode)
+ {
+ if (props.numHashBytes < 2) numHashBytes = 2;
+ else if (props.numHashBytes < 4) numHashBytes = (unsigned)props.numHashBytes;
+ }
+ if (props.numHashBytes >= 5) numHashBytes = 5;
+
+ MFB.numHashBytes = numHashBytes;
+ }
+
+ MFB.cutValue = props.mc;
+
+ p->writeEndMark = (BoolInt)props.writeEndMark;
+
+ #ifndef _7ZIP_ST
+ /*
+ if (newMultiThread != _multiThread)
+ {
+ ReleaseMatchFinder();
+ _multiThread = newMultiThread;
+ }
+ */
+ p->multiThread = (props.numThreads > 1);
+ p->matchFinderMt.btSync.affinity =
+ p->matchFinderMt.hashSync.affinity = props.affinity;
+ #endif
+
+ return SZ_OK;
+}
+
+
+void LzmaEnc_SetDataSize(CLzmaEncHandle pp, UInt64 expectedDataSiize)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ MFB.expectedDataSize = expectedDataSiize;
+}
+
+
+#define kState_Start 0
+#define kState_LitAfterMatch 4
+#define kState_LitAfterRep 5
+#define kState_MatchAfterLit 7
+#define kState_RepAfterLit 8
+
+static const Byte kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
+static const Byte kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
+static const Byte kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
+static const Byte kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
+
+#define IsLitState(s) ((s) < 7)
+#define GetLenToPosState2(len) (((len) < kNumLenToPosStates - 1) ? (len) : kNumLenToPosStates - 1)
+#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1)
+
+#define kInfinityPrice (1 << 30)
+
+static void RangeEnc_Construct(CRangeEnc *p)
+{
+ p->outStream = NULL;
+ p->bufBase = NULL;
+}
+
+#define RangeEnc_GetProcessed(p) ( (p)->processed + (size_t)((p)->buf - (p)->bufBase) + (p)->cacheSize)
+#define RangeEnc_GetProcessed_sizet(p) ((size_t)(p)->processed + (size_t)((p)->buf - (p)->bufBase) + (size_t)(p)->cacheSize)
+
+#define RC_BUF_SIZE (1 << 16)
+
+static int RangeEnc_Alloc(CRangeEnc *p, ISzAllocPtr alloc)
+{
+ if (!p->bufBase)
+ {
+ p->bufBase = (Byte *)ISzAlloc_Alloc(alloc, RC_BUF_SIZE);
+ if (!p->bufBase)
+ return 0;
+ p->bufLim = p->bufBase + RC_BUF_SIZE;
+ }
+ return 1;
+}
+
+static void RangeEnc_Free(CRangeEnc *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->bufBase);
+ p->bufBase = NULL;
+}
+
+static void RangeEnc_Init(CRangeEnc *p)
+{
+ p->range = 0xFFFFFFFF;
+ p->cache = 0;
+ p->low = 0;
+ p->cacheSize = 0;
+
+ p->buf = p->bufBase;
+
+ p->processed = 0;
+ p->res = SZ_OK;
+}
+
+MY_NO_INLINE static void RangeEnc_FlushStream(CRangeEnc *p)
+{
+ const size_t num = (size_t)(p->buf - p->bufBase);
+ if (p->res == SZ_OK)
+ {
+ if (num != ISeqOutStream_Write(p->outStream, p->bufBase, num))
+ p->res = SZ_ERROR_WRITE;
+ }
+ p->processed += num;
+ p->buf = p->bufBase;
+}
+
+MY_NO_INLINE static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p)
+{
+ UInt32 low = (UInt32)p->low;
+ unsigned high = (unsigned)(p->low >> 32);
+ p->low = (UInt32)(low << 8);
+ if (low < (UInt32)0xFF000000 || high != 0)
+ {
+ {
+ Byte *buf = p->buf;
+ *buf++ = (Byte)(p->cache + high);
+ p->cache = (unsigned)(low >> 24);
+ p->buf = buf;
+ if (buf == p->bufLim)
+ RangeEnc_FlushStream(p);
+ if (p->cacheSize == 0)
+ return;
+ }
+ high += 0xFF;
+ for (;;)
+ {
+ Byte *buf = p->buf;
+ *buf++ = (Byte)(high);
+ p->buf = buf;
+ if (buf == p->bufLim)
+ RangeEnc_FlushStream(p);
+ if (--p->cacheSize == 0)
+ return;
+ }
+ }
+ p->cacheSize++;
+}
+
+static void RangeEnc_FlushData(CRangeEnc *p)
+{
+ int i;
+ for (i = 0; i < 5; i++)
+ RangeEnc_ShiftLow(p);
+}
+
+#define RC_NORM(p) if (range < kTopValue) { range <<= 8; RangeEnc_ShiftLow(p); }
+
+#define RC_BIT_PRE(p, prob) \
+ ttt = *(prob); \
+ newBound = (range >> kNumBitModelTotalBits) * ttt;
+
+// #define _LZMA_ENC_USE_BRANCH
+
+#ifdef _LZMA_ENC_USE_BRANCH
+
+#define RC_BIT(p, prob, bit) { \
+ RC_BIT_PRE(p, prob) \
+ if (bit == 0) { range = newBound; ttt += (kBitModelTotal - ttt) >> kNumMoveBits; } \
+ else { (p)->low += newBound; range -= newBound; ttt -= ttt >> kNumMoveBits; } \
+ *(prob) = (CLzmaProb)ttt; \
+ RC_NORM(p) \
+ }
+
+#else
+
+#define RC_BIT(p, prob, bit) { \
+ UInt32 mask; \
+ RC_BIT_PRE(p, prob) \
+ mask = 0 - (UInt32)bit; \
+ range &= mask; \
+ mask &= newBound; \
+ range -= mask; \
+ (p)->low += mask; \
+ mask = (UInt32)bit - 1; \
+ range += newBound & mask; \
+ mask &= (kBitModelTotal - ((1 << kNumMoveBits) - 1)); \
+ mask += ((1 << kNumMoveBits) - 1); \
+ ttt += (UInt32)((Int32)(mask - ttt) >> kNumMoveBits); \
+ *(prob) = (CLzmaProb)ttt; \
+ RC_NORM(p) \
+ }
+
+#endif
+
+
+
+
+#define RC_BIT_0_BASE(p, prob) \
+ range = newBound; *(prob) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+
+#define RC_BIT_1_BASE(p, prob) \
+ range -= newBound; (p)->low += newBound; *(prob) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); \
+
+#define RC_BIT_0(p, prob) \
+ RC_BIT_0_BASE(p, prob) \
+ RC_NORM(p)
+
+#define RC_BIT_1(p, prob) \
+ RC_BIT_1_BASE(p, prob) \
+ RC_NORM(p)
+
+static void RangeEnc_EncodeBit_0(CRangeEnc *p, CLzmaProb *prob)
+{
+ UInt32 range, ttt, newBound;
+ range = p->range;
+ RC_BIT_PRE(p, prob)
+ RC_BIT_0(p, prob)
+ p->range = range;
+}
+
+static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 sym)
+{
+ UInt32 range = p->range;
+ sym |= 0x100;
+ do
+ {
+ UInt32 ttt, newBound;
+ // RangeEnc_EncodeBit(p, probs + (sym >> 8), (sym >> 7) & 1);
+ CLzmaProb *prob = probs + (sym >> 8);
+ UInt32 bit = (sym >> 7) & 1;
+ sym <<= 1;
+ RC_BIT(p, prob, bit);
+ }
+ while (sym < 0x10000);
+ p->range = range;
+}
+
+static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 sym, UInt32 matchByte)
+{
+ UInt32 range = p->range;
+ UInt32 offs = 0x100;
+ sym |= 0x100;
+ do
+ {
+ UInt32 ttt, newBound;
+ CLzmaProb *prob;
+ UInt32 bit;
+ matchByte <<= 1;
+ // RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (sym >> 8)), (sym >> 7) & 1);
+ prob = probs + (offs + (matchByte & offs) + (sym >> 8));
+ bit = (sym >> 7) & 1;
+ sym <<= 1;
+ offs &= ~(matchByte ^ sym);
+ RC_BIT(p, prob, bit);
+ }
+ while (sym < 0x10000);
+ p->range = range;
+}
+
+
+
+static void LzmaEnc_InitPriceTables(CProbPrice *ProbPrices)
+{
+ UInt32 i;
+ for (i = 0; i < (kBitModelTotal >> kNumMoveReducingBits); i++)
+ {
+ const unsigned kCyclesBits = kNumBitPriceShiftBits;
+ UInt32 w = (i << kNumMoveReducingBits) + (1 << (kNumMoveReducingBits - 1));
+ unsigned bitCount = 0;
+ unsigned j;
+ for (j = 0; j < kCyclesBits; j++)
+ {
+ w = w * w;
+ bitCount <<= 1;
+ while (w >= ((UInt32)1 << 16))
+ {
+ w >>= 1;
+ bitCount++;
+ }
+ }
+ ProbPrices[i] = (CProbPrice)(((unsigned)kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
+ // printf("\n%3d: %5d", i, ProbPrices[i]);
+ }
+}
+
+
+#define GET_PRICE(prob, bit) \
+ p->ProbPrices[((prob) ^ (unsigned)(((-(int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
+
+#define GET_PRICEa(prob, bit) \
+ ProbPrices[((prob) ^ (unsigned)((-((int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
+
+#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits]
+#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
+
+#define GET_PRICEa_0(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
+#define GET_PRICEa_1(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
+
+
+static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 sym, const CProbPrice *ProbPrices)
+{
+ UInt32 price = 0;
+ sym |= 0x100;
+ do
+ {
+ unsigned bit = sym & 1;
+ sym >>= 1;
+ price += GET_PRICEa(probs[sym], bit);
+ }
+ while (sym >= 2);
+ return price;
+}
+
+
+static UInt32 LitEnc_Matched_GetPrice(const CLzmaProb *probs, UInt32 sym, UInt32 matchByte, const CProbPrice *ProbPrices)
+{
+ UInt32 price = 0;
+ UInt32 offs = 0x100;
+ sym |= 0x100;
+ do
+ {
+ matchByte <<= 1;
+ price += GET_PRICEa(probs[offs + (matchByte & offs) + (sym >> 8)], (sym >> 7) & 1);
+ sym <<= 1;
+ offs &= ~(matchByte ^ sym);
+ }
+ while (sym < 0x10000);
+ return price;
+}
+
+
+static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, unsigned numBits, unsigned sym)
+{
+ UInt32 range = rc->range;
+ unsigned m = 1;
+ do
+ {
+ UInt32 ttt, newBound;
+ unsigned bit = sym & 1;
+ // RangeEnc_EncodeBit(rc, probs + m, bit);
+ sym >>= 1;
+ RC_BIT(rc, probs + m, bit);
+ m = (m << 1) | bit;
+ }
+ while (--numBits);
+ rc->range = range;
+}
+
+
+
+static void LenEnc_Init(CLenEnc *p)
+{
+ unsigned i;
+ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)); i++)
+ p->low[i] = kProbInitValue;
+ for (i = 0; i < kLenNumHighSymbols; i++)
+ p->high[i] = kProbInitValue;
+}
+
+static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, unsigned sym, unsigned posState)
+{
+ UInt32 range, ttt, newBound;
+ CLzmaProb *probs = p->low;
+ range = rc->range;
+ RC_BIT_PRE(rc, probs);
+ if (sym >= kLenNumLowSymbols)
+ {
+ RC_BIT_1(rc, probs);
+ probs += kLenNumLowSymbols;
+ RC_BIT_PRE(rc, probs);
+ if (sym >= kLenNumLowSymbols * 2)
+ {
+ RC_BIT_1(rc, probs);
+ rc->range = range;
+ // RcTree_Encode(rc, p->high, kLenNumHighBits, sym - kLenNumLowSymbols * 2);
+ LitEnc_Encode(rc, p->high, sym - kLenNumLowSymbols * 2);
+ return;
+ }
+ sym -= kLenNumLowSymbols;
+ }
+
+ // RcTree_Encode(rc, probs + (posState << kLenNumLowBits), kLenNumLowBits, sym);
+ {
+ unsigned m;
+ unsigned bit;
+ RC_BIT_0(rc, probs);
+ probs += (posState << (1 + kLenNumLowBits));
+ bit = (sym >> 2) ; RC_BIT(rc, probs + 1, bit); m = (1 << 1) + bit;
+ bit = (sym >> 1) & 1; RC_BIT(rc, probs + m, bit); m = (m << 1) + bit;
+ bit = sym & 1; RC_BIT(rc, probs + m, bit);
+ rc->range = range;
+ }
+}
+
+static void SetPrices_3(const CLzmaProb *probs, UInt32 startPrice, UInt32 *prices, const CProbPrice *ProbPrices)
+{
+ unsigned i;
+ for (i = 0; i < 8; i += 2)
+ {
+ UInt32 price = startPrice;
+ UInt32 prob;
+ price += GET_PRICEa(probs[1 ], (i >> 2));
+ price += GET_PRICEa(probs[2 + (i >> 2)], (i >> 1) & 1);
+ prob = probs[4 + (i >> 1)];
+ prices[i ] = price + GET_PRICEa_0(prob);
+ prices[i + 1] = price + GET_PRICEa_1(prob);
+ }
+}
+
+
+MY_NO_INLINE static void MY_FAST_CALL LenPriceEnc_UpdateTables(
+ CLenPriceEnc *p,
+ unsigned numPosStates,
+ const CLenEnc *enc,
+ const CProbPrice *ProbPrices)
+{
+ UInt32 b;
+
+ {
+ unsigned prob = enc->low[0];
+ UInt32 a, c;
+ unsigned posState;
+ b = GET_PRICEa_1(prob);
+ a = GET_PRICEa_0(prob);
+ c = b + GET_PRICEa_0(enc->low[kLenNumLowSymbols]);
+ for (posState = 0; posState < numPosStates; posState++)
+ {
+ UInt32 *prices = p->prices[posState];
+ const CLzmaProb *probs = enc->low + (posState << (1 + kLenNumLowBits));
+ SetPrices_3(probs, a, prices, ProbPrices);
+ SetPrices_3(probs + kLenNumLowSymbols, c, prices + kLenNumLowSymbols, ProbPrices);
+ }
+ }
+
+ /*
+ {
+ unsigned i;
+ UInt32 b;
+ a = GET_PRICEa_0(enc->low[0]);
+ for (i = 0; i < kLenNumLowSymbols; i++)
+ p->prices2[i] = a;
+ a = GET_PRICEa_1(enc->low[0]);
+ b = a + GET_PRICEa_0(enc->low[kLenNumLowSymbols]);
+ for (i = kLenNumLowSymbols; i < kLenNumLowSymbols * 2; i++)
+ p->prices2[i] = b;
+ a += GET_PRICEa_1(enc->low[kLenNumLowSymbols]);
+ }
+ */
+
+ // p->counter = numSymbols;
+ // p->counter = 64;
+
+ {
+ unsigned i = p->tableSize;
+
+ if (i > kLenNumLowSymbols * 2)
+ {
+ const CLzmaProb *probs = enc->high;
+ UInt32 *prices = p->prices[0] + kLenNumLowSymbols * 2;
+ i -= kLenNumLowSymbols * 2 - 1;
+ i >>= 1;
+ b += GET_PRICEa_1(enc->low[kLenNumLowSymbols]);
+ do
+ {
+ /*
+ p->prices2[i] = a +
+ // RcTree_GetPrice(enc->high, kLenNumHighBits, i - kLenNumLowSymbols * 2, ProbPrices);
+ LitEnc_GetPrice(probs, i - kLenNumLowSymbols * 2, ProbPrices);
+ */
+ // UInt32 price = a + RcTree_GetPrice(probs, kLenNumHighBits - 1, sym, ProbPrices);
+ unsigned sym = --i + (1 << (kLenNumHighBits - 1));
+ UInt32 price = b;
+ do
+ {
+ unsigned bit = sym & 1;
+ sym >>= 1;
+ price += GET_PRICEa(probs[sym], bit);
+ }
+ while (sym >= 2);
+
+ {
+ unsigned prob = probs[(size_t)i + (1 << (kLenNumHighBits - 1))];
+ prices[(size_t)i * 2 ] = price + GET_PRICEa_0(prob);
+ prices[(size_t)i * 2 + 1] = price + GET_PRICEa_1(prob);
+ }
+ }
+ while (i);
+
+ {
+ unsigned posState;
+ size_t num = (p->tableSize - kLenNumLowSymbols * 2) * sizeof(p->prices[0][0]);
+ for (posState = 1; posState < numPosStates; posState++)
+ memcpy(p->prices[posState] + kLenNumLowSymbols * 2, p->prices[0] + kLenNumLowSymbols * 2, num);
+ }
+ }
+ }
+}
+
+/*
+ #ifdef SHOW_STAT
+ g_STAT_OFFSET += num;
+ printf("\n MovePos %u", num);
+ #endif
+*/
+
+#define MOVE_POS(p, num) { \
+ p->additionalOffset += (num); \
+ p->matchFinder.Skip(p->matchFinderObj, (UInt32)(num)); }
+
+
+static unsigned ReadMatchDistances(CLzmaEnc *p, unsigned *numPairsRes)
+{
+ unsigned numPairs;
+
+ p->additionalOffset++;
+ p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
+ {
+ const UInt32 *d = p->matchFinder.GetMatches(p->matchFinderObj, p->matches);
+ // if (!d) { p->mf_Failure = True; *numPairsRes = 0; return 0; }
+ numPairs = (unsigned)(d - p->matches);
+ }
+ *numPairsRes = numPairs;
+
+ #ifdef SHOW_STAT
+ printf("\n i = %u numPairs = %u ", g_STAT_OFFSET, numPairs / 2);
+ g_STAT_OFFSET++;
+ {
+ unsigned i;
+ for (i = 0; i < numPairs; i += 2)
+ printf("%2u %6u | ", p->matches[i], p->matches[i + 1]);
+ }
+ #endif
+
+ if (numPairs == 0)
+ return 0;
+ {
+ const unsigned len = p->matches[(size_t)numPairs - 2];
+ if (len != p->numFastBytes)
+ return len;
+ {
+ UInt32 numAvail = p->numAvail;
+ if (numAvail > LZMA_MATCH_LEN_MAX)
+ numAvail = LZMA_MATCH_LEN_MAX;
+ {
+ const Byte *p1 = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ const Byte *p2 = p1 + len;
+ const ptrdiff_t dif = (ptrdiff_t)-1 - (ptrdiff_t)p->matches[(size_t)numPairs - 1];
+ const Byte *lim = p1 + numAvail;
+ for (; p2 != lim && *p2 == p2[dif]; p2++)
+ {}
+ return (unsigned)(p2 - p1);
+ }
+ }
+ }
+}
+
+#define MARK_LIT ((UInt32)(Int32)-1)
+
+#define MakeAs_Lit(p) { (p)->dist = MARK_LIT; (p)->extra = 0; }
+#define MakeAs_ShortRep(p) { (p)->dist = 0; (p)->extra = 0; }
+#define IsShortRep(p) ((p)->dist == 0)
+
+
+#define GetPrice_ShortRep(p, state, posState) \
+ ( GET_PRICE_0(p->isRepG0[state]) + GET_PRICE_0(p->isRep0Long[state][posState]))
+
+#define GetPrice_Rep_0(p, state, posState) ( \
+ GET_PRICE_1(p->isMatch[state][posState]) \
+ + GET_PRICE_1(p->isRep0Long[state][posState])) \
+ + GET_PRICE_1(p->isRep[state]) \
+ + GET_PRICE_0(p->isRepG0[state])
+
+MY_FORCE_INLINE
+static UInt32 GetPrice_PureRep(const CLzmaEnc *p, unsigned repIndex, size_t state, size_t posState)
+{
+ UInt32 price;
+ UInt32 prob = p->isRepG0[state];
+ if (repIndex == 0)
+ {
+ price = GET_PRICE_0(prob);
+ price += GET_PRICE_1(p->isRep0Long[state][posState]);
+ }
+ else
+ {
+ price = GET_PRICE_1(prob);
+ prob = p->isRepG1[state];
+ if (repIndex == 1)
+ price += GET_PRICE_0(prob);
+ else
+ {
+ price += GET_PRICE_1(prob);
+ price += GET_PRICE(p->isRepG2[state], repIndex - 2);
+ }
+ }
+ return price;
+}
+
+
+static unsigned Backward(CLzmaEnc *p, unsigned cur)
+{
+ unsigned wr = cur + 1;
+ p->optEnd = wr;
+
+ for (;;)
+ {
+ UInt32 dist = p->opt[cur].dist;
+ unsigned len = (unsigned)p->opt[cur].len;
+ unsigned extra = (unsigned)p->opt[cur].extra;
+ cur -= len;
+
+ if (extra)
+ {
+ wr--;
+ p->opt[wr].len = (UInt32)len;
+ cur -= extra;
+ len = extra;
+ if (extra == 1)
+ {
+ p->opt[wr].dist = dist;
+ dist = MARK_LIT;
+ }
+ else
+ {
+ p->opt[wr].dist = 0;
+ len--;
+ wr--;
+ p->opt[wr].dist = MARK_LIT;
+ p->opt[wr].len = 1;
+ }
+ }
+
+ if (cur == 0)
+ {
+ p->backRes = dist;
+ p->optCur = wr;
+ return len;
+ }
+
+ wr--;
+ p->opt[wr].dist = dist;
+ p->opt[wr].len = (UInt32)len;
+ }
+}
+
+
+
+#define LIT_PROBS(pos, prevByte) \
+ (p->litProbs + (UInt32)3 * (((((pos) << 8) + (prevByte)) & p->lpMask) << p->lc))
+
+
+static unsigned GetOptimum(CLzmaEnc *p, UInt32 position)
+{
+ unsigned last, cur;
+ UInt32 reps[LZMA_NUM_REPS];
+ unsigned repLens[LZMA_NUM_REPS];
+ UInt32 *matches;
+
+ {
+ UInt32 numAvail;
+ unsigned numPairs, mainLen, repMaxIndex, i, posState;
+ UInt32 matchPrice, repMatchPrice;
+ const Byte *data;
+ Byte curByte, matchByte;
+
+ p->optCur = p->optEnd = 0;
+
+ if (p->additionalOffset == 0)
+ mainLen = ReadMatchDistances(p, &numPairs);
+ else
+ {
+ mainLen = p->longestMatchLen;
+ numPairs = p->numPairs;
+ }
+
+ numAvail = p->numAvail;
+ if (numAvail < 2)
+ {
+ p->backRes = MARK_LIT;
+ return 1;
+ }
+ if (numAvail > LZMA_MATCH_LEN_MAX)
+ numAvail = LZMA_MATCH_LEN_MAX;
+
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ repMaxIndex = 0;
+
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ unsigned len;
+ const Byte *data2;
+ reps[i] = p->reps[i];
+ data2 = data - reps[i];
+ if (data[0] != data2[0] || data[1] != data2[1])
+ {
+ repLens[i] = 0;
+ continue;
+ }
+ for (len = 2; len < numAvail && data[len] == data2[len]; len++)
+ {}
+ repLens[i] = len;
+ if (len > repLens[repMaxIndex])
+ repMaxIndex = i;
+ if (len == LZMA_MATCH_LEN_MAX) // 21.03 : optimization
+ break;
+ }
+
+ if (repLens[repMaxIndex] >= p->numFastBytes)
+ {
+ unsigned len;
+ p->backRes = (UInt32)repMaxIndex;
+ len = repLens[repMaxIndex];
+ MOVE_POS(p, len - 1)
+ return len;
+ }
+
+ matches = p->matches;
+ #define MATCHES matches
+ // #define MATCHES p->matches
+
+ if (mainLen >= p->numFastBytes)
+ {
+ p->backRes = MATCHES[(size_t)numPairs - 1] + LZMA_NUM_REPS;
+ MOVE_POS(p, mainLen - 1)
+ return mainLen;
+ }
+
+ curByte = *data;
+ matchByte = *(data - reps[0]);
+
+ last = repLens[repMaxIndex];
+ if (last <= mainLen)
+ last = mainLen;
+
+ if (last < 2 && curByte != matchByte)
+ {
+ p->backRes = MARK_LIT;
+ return 1;
+ }
+
+ p->opt[0].state = (CState)p->state;
+
+ posState = (position & p->pbMask);
+
+ {
+ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
+ p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) +
+ (!IsLitState(p->state) ?
+ LitEnc_Matched_GetPrice(probs, curByte, matchByte, p->ProbPrices) :
+ LitEnc_GetPrice(probs, curByte, p->ProbPrices));
+ }
+
+ MakeAs_Lit(&p->opt[1]);
+
+ matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]);
+ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]);
+
+ // 18.06
+ if (matchByte == curByte && repLens[0] == 0)
+ {
+ UInt32 shortRepPrice = repMatchPrice + GetPrice_ShortRep(p, p->state, posState);
+ if (shortRepPrice < p->opt[1].price)
+ {
+ p->opt[1].price = shortRepPrice;
+ MakeAs_ShortRep(&p->opt[1]);
+ }
+ if (last < 2)
+ {
+ p->backRes = p->opt[1].dist;
+ return 1;
+ }
+ }
+
+ p->opt[1].len = 1;
+
+ p->opt[0].reps[0] = reps[0];
+ p->opt[0].reps[1] = reps[1];
+ p->opt[0].reps[2] = reps[2];
+ p->opt[0].reps[3] = reps[3];
+
+ // ---------- REP ----------
+
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ unsigned repLen = repLens[i];
+ UInt32 price;
+ if (repLen < 2)
+ continue;
+ price = repMatchPrice + GetPrice_PureRep(p, i, p->state, posState);
+ do
+ {
+ UInt32 price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState, repLen);
+ COptimal *opt = &p->opt[repLen];
+ if (price2 < opt->price)
+ {
+ opt->price = price2;
+ opt->len = (UInt32)repLen;
+ opt->dist = (UInt32)i;
+ opt->extra = 0;
+ }
+ }
+ while (--repLen >= 2);
+ }
+
+
+ // ---------- MATCH ----------
+ {
+ unsigned len = repLens[0] + 1;
+ if (len <= mainLen)
+ {
+ unsigned offs = 0;
+ UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]);
+
+ if (len < 2)
+ len = 2;
+ else
+ while (len > MATCHES[offs])
+ offs += 2;
+
+ for (; ; len++)
+ {
+ COptimal *opt;
+ UInt32 dist = MATCHES[(size_t)offs + 1];
+ UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len);
+ unsigned lenToPosState = GetLenToPosState(len);
+
+ if (dist < kNumFullDistances)
+ price += p->distancesPrices[lenToPosState][dist & (kNumFullDistances - 1)];
+ else
+ {
+ unsigned slot;
+ GetPosSlot2(dist, slot);
+ price += p->alignPrices[dist & kAlignMask];
+ price += p->posSlotPrices[lenToPosState][slot];
+ }
+
+ opt = &p->opt[len];
+
+ if (price < opt->price)
+ {
+ opt->price = price;
+ opt->len = (UInt32)len;
+ opt->dist = dist + LZMA_NUM_REPS;
+ opt->extra = 0;
+ }
+
+ if (len == MATCHES[offs])
+ {
+ offs += 2;
+ if (offs == numPairs)
+ break;
+ }
+ }
+ }
+ }
+
+
+ cur = 0;
+
+ #ifdef SHOW_STAT2
+ /* if (position >= 0) */
+ {
+ unsigned i;
+ printf("\n pos = %4X", position);
+ for (i = cur; i <= last; i++)
+ printf("\nprice[%4X] = %u", position - cur + i, p->opt[i].price);
+ }
+ #endif
+ }
+
+
+
+ // ---------- Optimal Parsing ----------
+
+ for (;;)
+ {
+ unsigned numAvail;
+ UInt32 numAvailFull;
+ unsigned newLen, numPairs, prev, state, posState, startLen;
+ UInt32 litPrice, matchPrice, repMatchPrice;
+ BoolInt nextIsLit;
+ Byte curByte, matchByte;
+ const Byte *data;
+ COptimal *curOpt, *nextOpt;
+
+ if (++cur == last)
+ break;
+
+ // 18.06
+ if (cur >= kNumOpts - 64)
+ {
+ unsigned j, best;
+ UInt32 price = p->opt[cur].price;
+ best = cur;
+ for (j = cur + 1; j <= last; j++)
+ {
+ UInt32 price2 = p->opt[j].price;
+ if (price >= price2)
+ {
+ price = price2;
+ best = j;
+ }
+ }
+ {
+ unsigned delta = best - cur;
+ if (delta != 0)
+ {
+ MOVE_POS(p, delta);
+ }
+ }
+ cur = best;
+ break;
+ }
+
+ newLen = ReadMatchDistances(p, &numPairs);
+
+ if (newLen >= p->numFastBytes)
+ {
+ p->numPairs = numPairs;
+ p->longestMatchLen = newLen;
+ break;
+ }
+
+ curOpt = &p->opt[cur];
+
+ position++;
+
+ // we need that check here, if skip_items in p->opt are possible
+ /*
+ if (curOpt->price >= kInfinityPrice)
+ continue;
+ */
+
+ prev = cur - curOpt->len;
+
+ if (curOpt->len == 1)
+ {
+ state = (unsigned)p->opt[prev].state;
+ if (IsShortRep(curOpt))
+ state = kShortRepNextStates[state];
+ else
+ state = kLiteralNextStates[state];
+ }
+ else
+ {
+ const COptimal *prevOpt;
+ UInt32 b0;
+ UInt32 dist = curOpt->dist;
+
+ if (curOpt->extra)
+ {
+ prev -= (unsigned)curOpt->extra;
+ state = kState_RepAfterLit;
+ if (curOpt->extra == 1)
+ state = (dist < LZMA_NUM_REPS ? kState_RepAfterLit : kState_MatchAfterLit);
+ }
+ else
+ {
+ state = (unsigned)p->opt[prev].state;
+ if (dist < LZMA_NUM_REPS)
+ state = kRepNextStates[state];
+ else
+ state = kMatchNextStates[state];
+ }
+
+ prevOpt = &p->opt[prev];
+ b0 = prevOpt->reps[0];
+
+ if (dist < LZMA_NUM_REPS)
+ {
+ if (dist == 0)
+ {
+ reps[0] = b0;
+ reps[1] = prevOpt->reps[1];
+ reps[2] = prevOpt->reps[2];
+ reps[3] = prevOpt->reps[3];
+ }
+ else
+ {
+ reps[1] = b0;
+ b0 = prevOpt->reps[1];
+ if (dist == 1)
+ {
+ reps[0] = b0;
+ reps[2] = prevOpt->reps[2];
+ reps[3] = prevOpt->reps[3];
+ }
+ else
+ {
+ reps[2] = b0;
+ reps[0] = prevOpt->reps[dist];
+ reps[3] = prevOpt->reps[dist ^ 1];
+ }
+ }
+ }
+ else
+ {
+ reps[0] = (dist - LZMA_NUM_REPS + 1);
+ reps[1] = b0;
+ reps[2] = prevOpt->reps[1];
+ reps[3] = prevOpt->reps[2];
+ }
+ }
+
+ curOpt->state = (CState)state;
+ curOpt->reps[0] = reps[0];
+ curOpt->reps[1] = reps[1];
+ curOpt->reps[2] = reps[2];
+ curOpt->reps[3] = reps[3];
+
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ curByte = *data;
+ matchByte = *(data - reps[0]);
+
+ posState = (position & p->pbMask);
+
+ /*
+ The order of Price checks:
+ < LIT
+ <= SHORT_REP
+ < LIT : REP_0
+ < REP [ : LIT : REP_0 ]
+ < MATCH [ : LIT : REP_0 ]
+ */
+
+ {
+ UInt32 curPrice = curOpt->price;
+ unsigned prob = p->isMatch[state][posState];
+ matchPrice = curPrice + GET_PRICE_1(prob);
+ litPrice = curPrice + GET_PRICE_0(prob);
+ }
+
+ nextOpt = &p->opt[(size_t)cur + 1];
+ nextIsLit = False;
+
+ // here we can allow skip_items in p->opt, if we don't check (nextOpt->price < kInfinityPrice)
+ // 18.new.06
+ if ((nextOpt->price < kInfinityPrice
+ // && !IsLitState(state)
+ && matchByte == curByte)
+ || litPrice > nextOpt->price
+ )
+ litPrice = 0;
+ else
+ {
+ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
+ litPrice += (!IsLitState(state) ?
+ LitEnc_Matched_GetPrice(probs, curByte, matchByte, p->ProbPrices) :
+ LitEnc_GetPrice(probs, curByte, p->ProbPrices));
+
+ if (litPrice < nextOpt->price)
+ {
+ nextOpt->price = litPrice;
+ nextOpt->len = 1;
+ MakeAs_Lit(nextOpt);
+ nextIsLit = True;
+ }
+ }
+
+ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]);
+
+ numAvailFull = p->numAvail;
+ {
+ unsigned temp = kNumOpts - 1 - cur;
+ if (numAvailFull > temp)
+ numAvailFull = (UInt32)temp;
+ }
+
+ // 18.06
+ // ---------- SHORT_REP ----------
+ if (IsLitState(state)) // 18.new
+ if (matchByte == curByte)
+ if (repMatchPrice < nextOpt->price) // 18.new
+ // if (numAvailFull < 2 || data[1] != *(data - reps[0] + 1))
+ if (
+ // nextOpt->price >= kInfinityPrice ||
+ nextOpt->len < 2 // we can check nextOpt->len, if skip items are not allowed in p->opt
+ || (nextOpt->dist != 0
+ // && nextOpt->extra <= 1 // 17.old
+ )
+ )
+ {
+ UInt32 shortRepPrice = repMatchPrice + GetPrice_ShortRep(p, state, posState);
+ // if (shortRepPrice <= nextOpt->price) // 17.old
+ if (shortRepPrice < nextOpt->price) // 18.new
+ {
+ nextOpt->price = shortRepPrice;
+ nextOpt->len = 1;
+ MakeAs_ShortRep(nextOpt);
+ nextIsLit = False;
+ }
+ }
+
+ if (numAvailFull < 2)
+ continue;
+ numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes);
+
+ // numAvail <= p->numFastBytes
+
+ // ---------- LIT : REP_0 ----------
+
+ if (!nextIsLit
+ && litPrice != 0 // 18.new
+ && matchByte != curByte
+ && numAvailFull > 2)
+ {
+ const Byte *data2 = data - reps[0];
+ if (data[1] == data2[1] && data[2] == data2[2])
+ {
+ unsigned len;
+ unsigned limit = p->numFastBytes + 1;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+ for (len = 3; len < limit && data[len] == data2[len]; len++)
+ {}
+
+ {
+ unsigned state2 = kLiteralNextStates[state];
+ unsigned posState2 = (position + 1) & p->pbMask;
+ UInt32 price = litPrice + GetPrice_Rep_0(p, state2, posState2);
+ {
+ unsigned offset = cur + len;
+
+ if (last < offset)
+ last = offset;
+
+ // do
+ {
+ UInt32 price2;
+ COptimal *opt;
+ len--;
+ // price2 = price + GetPrice_Len_Rep_0(p, len, state2, posState2);
+ price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len);
+
+ opt = &p->opt[offset];
+ // offset--;
+ if (price2 < opt->price)
+ {
+ opt->price = price2;
+ opt->len = (UInt32)len;
+ opt->dist = 0;
+ opt->extra = 1;
+ }
+ }
+ // while (len >= 3);
+ }
+ }
+ }
+ }
+
+ startLen = 2; /* speed optimization */
+
+ {
+ // ---------- REP ----------
+ unsigned repIndex = 0; // 17.old
+ // unsigned repIndex = IsLitState(state) ? 0 : 1; // 18.notused
+ for (; repIndex < LZMA_NUM_REPS; repIndex++)
+ {
+ unsigned len;
+ UInt32 price;
+ const Byte *data2 = data - reps[repIndex];
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+
+ for (len = 2; len < numAvail && data[len] == data2[len]; len++)
+ {}
+
+ // if (len < startLen) continue; // 18.new: speed optimization
+
+ {
+ unsigned offset = cur + len;
+ if (last < offset)
+ last = offset;
+ }
+ {
+ unsigned len2 = len;
+ price = repMatchPrice + GetPrice_PureRep(p, repIndex, state, posState);
+ do
+ {
+ UInt32 price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState, len2);
+ COptimal *opt = &p->opt[cur + len2];
+ if (price2 < opt->price)
+ {
+ opt->price = price2;
+ opt->len = (UInt32)len2;
+ opt->dist = (UInt32)repIndex;
+ opt->extra = 0;
+ }
+ }
+ while (--len2 >= 2);
+ }
+
+ if (repIndex == 0) startLen = len + 1; // 17.old
+ // startLen = len + 1; // 18.new
+
+ /* if (_maxMode) */
+ {
+ // ---------- REP : LIT : REP_0 ----------
+ // numFastBytes + 1 + numFastBytes
+
+ unsigned len2 = len + 1;
+ unsigned limit = len2 + p->numFastBytes;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+
+ len2 += 2;
+ if (len2 <= limit)
+ if (data[len2 - 2] == data2[len2 - 2])
+ if (data[len2 - 1] == data2[len2 - 1])
+ {
+ unsigned state2 = kRepNextStates[state];
+ unsigned posState2 = (position + len) & p->pbMask;
+ price += GET_PRICE_LEN(&p->repLenEnc, posState, len)
+ + GET_PRICE_0(p->isMatch[state2][posState2])
+ + LitEnc_Matched_GetPrice(LIT_PROBS(position + len, data[(size_t)len - 1]),
+ data[len], data2[len], p->ProbPrices);
+
+ // state2 = kLiteralNextStates[state2];
+ state2 = kState_LitAfterRep;
+ posState2 = (posState2 + 1) & p->pbMask;
+
+
+ price += GetPrice_Rep_0(p, state2, posState2);
+
+ for (; len2 < limit && data[len2] == data2[len2]; len2++)
+ {}
+
+ len2 -= len;
+ // if (len2 >= 3)
+ {
+ {
+ unsigned offset = cur + len + len2;
+
+ if (last < offset)
+ last = offset;
+ // do
+ {
+ UInt32 price2;
+ COptimal *opt;
+ len2--;
+ // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2);
+ price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len2);
+
+ opt = &p->opt[offset];
+ // offset--;
+ if (price2 < opt->price)
+ {
+ opt->price = price2;
+ opt->len = (UInt32)len2;
+ opt->extra = (CExtra)(len + 1);
+ opt->dist = (UInt32)repIndex;
+ }
+ }
+ // while (len2 >= 3);
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ // ---------- MATCH ----------
+ /* for (unsigned len = 2; len <= newLen; len++) */
+ if (newLen > numAvail)
+ {
+ newLen = numAvail;
+ for (numPairs = 0; newLen > MATCHES[numPairs]; numPairs += 2);
+ MATCHES[numPairs] = (UInt32)newLen;
+ numPairs += 2;
+ }
+
+ // startLen = 2; /* speed optimization */
+
+ if (newLen >= startLen)
+ {
+ UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]);
+ UInt32 dist;
+ unsigned offs, posSlot, len;
+
+ {
+ unsigned offset = cur + newLen;
+ if (last < offset)
+ last = offset;
+ }
+
+ offs = 0;
+ while (startLen > MATCHES[offs])
+ offs += 2;
+ dist = MATCHES[(size_t)offs + 1];
+
+ // if (dist >= kNumFullDistances)
+ GetPosSlot2(dist, posSlot);
+
+ for (len = /*2*/ startLen; ; len++)
+ {
+ UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len);
+ {
+ COptimal *opt;
+ unsigned lenNorm = len - 2;
+ lenNorm = GetLenToPosState2(lenNorm);
+ if (dist < kNumFullDistances)
+ price += p->distancesPrices[lenNorm][dist & (kNumFullDistances - 1)];
+ else
+ price += p->posSlotPrices[lenNorm][posSlot] + p->alignPrices[dist & kAlignMask];
+
+ opt = &p->opt[cur + len];
+ if (price < opt->price)
+ {
+ opt->price = price;
+ opt->len = (UInt32)len;
+ opt->dist = dist + LZMA_NUM_REPS;
+ opt->extra = 0;
+ }
+ }
+
+ if (len == MATCHES[offs])
+ {
+ // if (p->_maxMode) {
+ // MATCH : LIT : REP_0
+
+ const Byte *data2 = data - dist - 1;
+ unsigned len2 = len + 1;
+ unsigned limit = len2 + p->numFastBytes;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+
+ len2 += 2;
+ if (len2 <= limit)
+ if (data[len2 - 2] == data2[len2 - 2])
+ if (data[len2 - 1] == data2[len2 - 1])
+ {
+ for (; len2 < limit && data[len2] == data2[len2]; len2++)
+ {}
+
+ len2 -= len;
+
+ // if (len2 >= 3)
+ {
+ unsigned state2 = kMatchNextStates[state];
+ unsigned posState2 = (position + len) & p->pbMask;
+ unsigned offset;
+ price += GET_PRICE_0(p->isMatch[state2][posState2]);
+ price += LitEnc_Matched_GetPrice(LIT_PROBS(position + len, data[(size_t)len - 1]),
+ data[len], data2[len], p->ProbPrices);
+
+ // state2 = kLiteralNextStates[state2];
+ state2 = kState_LitAfterMatch;
+
+ posState2 = (posState2 + 1) & p->pbMask;
+ price += GetPrice_Rep_0(p, state2, posState2);
+
+ offset = cur + len + len2;
+
+ if (last < offset)
+ last = offset;
+ // do
+ {
+ UInt32 price2;
+ COptimal *opt;
+ len2--;
+ // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2);
+ price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len2);
+ opt = &p->opt[offset];
+ // offset--;
+ if (price2 < opt->price)
+ {
+ opt->price = price2;
+ opt->len = (UInt32)len2;
+ opt->extra = (CExtra)(len + 1);
+ opt->dist = dist + LZMA_NUM_REPS;
+ }
+ }
+ // while (len2 >= 3);
+ }
+
+ }
+
+ offs += 2;
+ if (offs == numPairs)
+ break;
+ dist = MATCHES[(size_t)offs + 1];
+ // if (dist >= kNumFullDistances)
+ GetPosSlot2(dist, posSlot);
+ }
+ }
+ }
+ }
+
+ do
+ p->opt[last].price = kInfinityPrice;
+ while (--last);
+
+ return Backward(p, cur);
+}
+
+
+
+#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist))
+
+
+
+static unsigned GetOptimumFast(CLzmaEnc *p)
+{
+ UInt32 numAvail, mainDist;
+ unsigned mainLen, numPairs, repIndex, repLen, i;
+ const Byte *data;
+
+ if (p->additionalOffset == 0)
+ mainLen = ReadMatchDistances(p, &numPairs);
+ else
+ {
+ mainLen = p->longestMatchLen;
+ numPairs = p->numPairs;
+ }
+
+ numAvail = p->numAvail;
+ p->backRes = MARK_LIT;
+ if (numAvail < 2)
+ return 1;
+ // if (mainLen < 2 && p->state == 0) return 1; // 18.06.notused
+ if (numAvail > LZMA_MATCH_LEN_MAX)
+ numAvail = LZMA_MATCH_LEN_MAX;
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ repLen = repIndex = 0;
+
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ unsigned len;
+ const Byte *data2 = data - p->reps[i];
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+ for (len = 2; len < numAvail && data[len] == data2[len]; len++)
+ {}
+ if (len >= p->numFastBytes)
+ {
+ p->backRes = (UInt32)i;
+ MOVE_POS(p, len - 1)
+ return len;
+ }
+ if (len > repLen)
+ {
+ repIndex = i;
+ repLen = len;
+ }
+ }
+
+ if (mainLen >= p->numFastBytes)
+ {
+ p->backRes = p->matches[(size_t)numPairs - 1] + LZMA_NUM_REPS;
+ MOVE_POS(p, mainLen - 1)
+ return mainLen;
+ }
+
+ mainDist = 0; /* for GCC */
+
+ if (mainLen >= 2)
+ {
+ mainDist = p->matches[(size_t)numPairs - 1];
+ while (numPairs > 2)
+ {
+ UInt32 dist2;
+ if (mainLen != p->matches[(size_t)numPairs - 4] + 1)
+ break;
+ dist2 = p->matches[(size_t)numPairs - 3];
+ if (!ChangePair(dist2, mainDist))
+ break;
+ numPairs -= 2;
+ mainLen--;
+ mainDist = dist2;
+ }
+ if (mainLen == 2 && mainDist >= 0x80)
+ mainLen = 1;
+ }
+
+ if (repLen >= 2)
+ if ( repLen + 1 >= mainLen
+ || (repLen + 2 >= mainLen && mainDist >= (1 << 9))
+ || (repLen + 3 >= mainLen && mainDist >= (1 << 15)))
+ {
+ p->backRes = (UInt32)repIndex;
+ MOVE_POS(p, repLen - 1)
+ return repLen;
+ }
+
+ if (mainLen < 2 || numAvail <= 2)
+ return 1;
+
+ {
+ unsigned len1 = ReadMatchDistances(p, &p->numPairs);
+ p->longestMatchLen = len1;
+
+ if (len1 >= 2)
+ {
+ UInt32 newDist = p->matches[(size_t)p->numPairs - 1];
+ if ( (len1 >= mainLen && newDist < mainDist)
+ || (len1 == mainLen + 1 && !ChangePair(mainDist, newDist))
+ || (len1 > mainLen + 1)
+ || (len1 + 1 >= mainLen && mainLen >= 3 && ChangePair(newDist, mainDist)))
+ return 1;
+ }
+ }
+
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ unsigned len, limit;
+ const Byte *data2 = data - p->reps[i];
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+ limit = mainLen - 1;
+ for (len = 2;; len++)
+ {
+ if (len >= limit)
+ return 1;
+ if (data[len] != data2[len])
+ break;
+ }
+ }
+
+ p->backRes = mainDist + LZMA_NUM_REPS;
+ if (mainLen != 2)
+ {
+ MOVE_POS(p, mainLen - 2)
+ }
+ return mainLen;
+}
+
+
+
+
+static void WriteEndMarker(CLzmaEnc *p, unsigned posState)
+{
+ UInt32 range;
+ range = p->rc.range;
+ {
+ UInt32 ttt, newBound;
+ CLzmaProb *prob = &p->isMatch[p->state][posState];
+ RC_BIT_PRE(&p->rc, prob)
+ RC_BIT_1(&p->rc, prob)
+ prob = &p->isRep[p->state];
+ RC_BIT_PRE(&p->rc, prob)
+ RC_BIT_0(&p->rc, prob)
+ }
+ p->state = kMatchNextStates[p->state];
+
+ p->rc.range = range;
+ LenEnc_Encode(&p->lenProbs, &p->rc, 0, posState);
+ range = p->rc.range;
+
+ {
+ // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[0], (1 << kNumPosSlotBits) - 1);
+ CLzmaProb *probs = p->posSlotEncoder[0];
+ unsigned m = 1;
+ do
+ {
+ UInt32 ttt, newBound;
+ RC_BIT_PRE(p, probs + m)
+ RC_BIT_1(&p->rc, probs + m);
+ m = (m << 1) + 1;
+ }
+ while (m < (1 << kNumPosSlotBits));
+ }
+ {
+ // RangeEnc_EncodeDirectBits(&p->rc, ((UInt32)1 << (30 - kNumAlignBits)) - 1, 30 - kNumAlignBits); UInt32 range = p->range;
+ unsigned numBits = 30 - kNumAlignBits;
+ do
+ {
+ range >>= 1;
+ p->rc.low += range;
+ RC_NORM(&p->rc)
+ }
+ while (--numBits);
+ }
+
+ {
+ // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
+ CLzmaProb *probs = p->posAlignEncoder;
+ unsigned m = 1;
+ do
+ {
+ UInt32 ttt, newBound;
+ RC_BIT_PRE(p, probs + m)
+ RC_BIT_1(&p->rc, probs + m);
+ m = (m << 1) + 1;
+ }
+ while (m < kAlignTableSize);
+ }
+ p->rc.range = range;
+}
+
+
+static SRes CheckErrors(CLzmaEnc *p)
+{
+ if (p->result != SZ_OK)
+ return p->result;
+ if (p->rc.res != SZ_OK)
+ p->result = SZ_ERROR_WRITE;
+
+ #ifndef _7ZIP_ST
+ if (
+ // p->mf_Failure ||
+ (p->mtMode &&
+ ( // p->matchFinderMt.failure_LZ_LZ ||
+ p->matchFinderMt.failure_LZ_BT))
+ )
+ {
+ p->result = MY_HRES_ERROR__INTERNAL_ERROR;
+ // printf("\nCheckErrors p->matchFinderMt.failureLZ\n");
+ }
+ #endif
+
+ if (MFB.result != SZ_OK)
+ p->result = SZ_ERROR_READ;
+
+ if (p->result != SZ_OK)
+ p->finished = True;
+ return p->result;
+}
+
+
+MY_NO_INLINE static SRes Flush(CLzmaEnc *p, UInt32 nowPos)
+{
+ /* ReleaseMFStream(); */
+ p->finished = True;
+ if (p->writeEndMark)
+ WriteEndMarker(p, nowPos & p->pbMask);
+ RangeEnc_FlushData(&p->rc);
+ RangeEnc_FlushStream(&p->rc);
+ return CheckErrors(p);
+}
+
+
+MY_NO_INLINE static void FillAlignPrices(CLzmaEnc *p)
+{
+ unsigned i;
+ const CProbPrice *ProbPrices = p->ProbPrices;
+ const CLzmaProb *probs = p->posAlignEncoder;
+ // p->alignPriceCount = 0;
+ for (i = 0; i < kAlignTableSize / 2; i++)
+ {
+ UInt32 price = 0;
+ unsigned sym = i;
+ unsigned m = 1;
+ unsigned bit;
+ UInt32 prob;
+ bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit;
+ bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit;
+ bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit;
+ prob = probs[m];
+ p->alignPrices[i ] = price + GET_PRICEa_0(prob);
+ p->alignPrices[i + 8] = price + GET_PRICEa_1(prob);
+ // p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
+ }
+}
+
+
+MY_NO_INLINE static void FillDistancesPrices(CLzmaEnc *p)
+{
+ // int y; for (y = 0; y < 100; y++) {
+
+ UInt32 tempPrices[kNumFullDistances];
+ unsigned i, lps;
+
+ const CProbPrice *ProbPrices = p->ProbPrices;
+ p->matchPriceCount = 0;
+
+ for (i = kStartPosModelIndex / 2; i < kNumFullDistances / 2; i++)
+ {
+ unsigned posSlot = GetPosSlot1(i);
+ unsigned footerBits = (posSlot >> 1) - 1;
+ unsigned base = ((2 | (posSlot & 1)) << footerBits);
+ const CLzmaProb *probs = p->posEncoders + (size_t)base * 2;
+ // tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base, footerBits, i - base, p->ProbPrices);
+ UInt32 price = 0;
+ unsigned m = 1;
+ unsigned sym = i;
+ unsigned offset = (unsigned)1 << footerBits;
+ base += i;
+
+ if (footerBits)
+ do
+ {
+ unsigned bit = sym & 1;
+ sym >>= 1;
+ price += GET_PRICEa(probs[m], bit);
+ m = (m << 1) + bit;
+ }
+ while (--footerBits);
+
+ {
+ unsigned prob = probs[m];
+ tempPrices[base ] = price + GET_PRICEa_0(prob);
+ tempPrices[base + offset] = price + GET_PRICEa_1(prob);
+ }
+ }
+
+ for (lps = 0; lps < kNumLenToPosStates; lps++)
+ {
+ unsigned slot;
+ unsigned distTableSize2 = (p->distTableSize + 1) >> 1;
+ UInt32 *posSlotPrices = p->posSlotPrices[lps];
+ const CLzmaProb *probs = p->posSlotEncoder[lps];
+
+ for (slot = 0; slot < distTableSize2; slot++)
+ {
+ // posSlotPrices[slot] = RcTree_GetPrice(encoder, kNumPosSlotBits, slot, p->ProbPrices);
+ UInt32 price;
+ unsigned bit;
+ unsigned sym = slot + (1 << (kNumPosSlotBits - 1));
+ unsigned prob;
+ bit = sym & 1; sym >>= 1; price = GET_PRICEa(probs[sym], bit);
+ bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit);
+ bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit);
+ bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit);
+ bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit);
+ prob = probs[(size_t)slot + (1 << (kNumPosSlotBits - 1))];
+ posSlotPrices[(size_t)slot * 2 ] = price + GET_PRICEa_0(prob);
+ posSlotPrices[(size_t)slot * 2 + 1] = price + GET_PRICEa_1(prob);
+ }
+
+ {
+ UInt32 delta = ((UInt32)((kEndPosModelIndex / 2 - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
+ for (slot = kEndPosModelIndex / 2; slot < distTableSize2; slot++)
+ {
+ posSlotPrices[(size_t)slot * 2 ] += delta;
+ posSlotPrices[(size_t)slot * 2 + 1] += delta;
+ delta += ((UInt32)1 << kNumBitPriceShiftBits);
+ }
+ }
+
+ {
+ UInt32 *dp = p->distancesPrices[lps];
+
+ dp[0] = posSlotPrices[0];
+ dp[1] = posSlotPrices[1];
+ dp[2] = posSlotPrices[2];
+ dp[3] = posSlotPrices[3];
+
+ for (i = 4; i < kNumFullDistances; i += 2)
+ {
+ UInt32 slotPrice = posSlotPrices[GetPosSlot1(i)];
+ dp[i ] = slotPrice + tempPrices[i];
+ dp[i + 1] = slotPrice + tempPrices[i + 1];
+ }
+ }
+ }
+ // }
+}
+
+
+
+static void LzmaEnc_Construct(CLzmaEnc *p)
+{
+ RangeEnc_Construct(&p->rc);
+ MatchFinder_Construct(&MFB);
+
+ #ifndef _7ZIP_ST
+ p->matchFinderMt.MatchFinder = &MFB;
+ MatchFinderMt_Construct(&p->matchFinderMt);
+ #endif
+
+ {
+ CLzmaEncProps props;
+ LzmaEncProps_Init(&props);
+ LzmaEnc_SetProps(p, &props);
+ }
+
+ #ifndef LZMA_LOG_BSR
+ LzmaEnc_FastPosInit(p->g_FastPos);
+ #endif
+
+ LzmaEnc_InitPriceTables(p->ProbPrices);
+ p->litProbs = NULL;
+ p->saveState.litProbs = NULL;
+}
+
+CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc)
+{
+ void *p;
+ p = ISzAlloc_Alloc(alloc, sizeof(CLzmaEnc));
+ if (p)
+ LzmaEnc_Construct((CLzmaEnc *)p);
+ return p;
+}
+
+static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->litProbs);
+ ISzAlloc_Free(alloc, p->saveState.litProbs);
+ p->litProbs = NULL;
+ p->saveState.litProbs = NULL;
+}
+
+static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ #ifndef _7ZIP_ST
+ MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
+ #endif
+
+ MatchFinder_Free(&MFB, allocBig);
+ LzmaEnc_FreeLits(p, alloc);
+ RangeEnc_Free(&p->rc, alloc);
+}
+
+void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);
+ ISzAlloc_Free(alloc, p);
+}
+
+
+MY_NO_INLINE
+static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpackSize)
+{
+ UInt32 nowPos32, startPos32;
+ if (p->needInit)
+ {
+ #ifndef _7ZIP_ST
+ if (p->mtMode)
+ {
+ RINOK(MatchFinderMt_InitMt(&p->matchFinderMt));
+ }
+ #endif
+ p->matchFinder.Init(p->matchFinderObj);
+ p->needInit = 0;
+ }
+
+ if (p->finished)
+ return p->result;
+ RINOK(CheckErrors(p));
+
+ nowPos32 = (UInt32)p->nowPos64;
+ startPos32 = nowPos32;
+
+ if (p->nowPos64 == 0)
+ {
+ unsigned numPairs;
+ Byte curByte;
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
+ return Flush(p, nowPos32);
+ ReadMatchDistances(p, &numPairs);
+ RangeEnc_EncodeBit_0(&p->rc, &p->isMatch[kState_Start][0]);
+ // p->state = kLiteralNextStates[p->state];
+ curByte = *(p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset);
+ LitEnc_Encode(&p->rc, p->litProbs, curByte);
+ p->additionalOffset--;
+ nowPos32++;
+ }
+
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0)
+
+ for (;;)
+ {
+ UInt32 dist;
+ unsigned len, posState;
+ UInt32 range, ttt, newBound;
+ CLzmaProb *probs;
+
+ if (p->fastMode)
+ len = GetOptimumFast(p);
+ else
+ {
+ unsigned oci = p->optCur;
+ if (p->optEnd == oci)
+ len = GetOptimum(p, nowPos32);
+ else
+ {
+ const COptimal *opt = &p->opt[oci];
+ len = opt->len;
+ p->backRes = opt->dist;
+ p->optCur = oci + 1;
+ }
+ }
+
+ posState = (unsigned)nowPos32 & p->pbMask;
+ range = p->rc.range;
+ probs = &p->isMatch[p->state][posState];
+
+ RC_BIT_PRE(&p->rc, probs)
+
+ dist = p->backRes;
+
+ #ifdef SHOW_STAT2
+ printf("\n pos = %6X, len = %3u pos = %6u", nowPos32, len, dist);
+ #endif
+
+ if (dist == MARK_LIT)
+ {
+ Byte curByte;
+ const Byte *data;
+ unsigned state;
+
+ RC_BIT_0(&p->rc, probs);
+ p->rc.range = range;
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
+ probs = LIT_PROBS(nowPos32, *(data - 1));
+ curByte = *data;
+ state = p->state;
+ p->state = kLiteralNextStates[state];
+ if (IsLitState(state))
+ LitEnc_Encode(&p->rc, probs, curByte);
+ else
+ LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0]));
+ }
+ else
+ {
+ RC_BIT_1(&p->rc, probs);
+ probs = &p->isRep[p->state];
+ RC_BIT_PRE(&p->rc, probs)
+
+ if (dist < LZMA_NUM_REPS)
+ {
+ RC_BIT_1(&p->rc, probs);
+ probs = &p->isRepG0[p->state];
+ RC_BIT_PRE(&p->rc, probs)
+ if (dist == 0)
+ {
+ RC_BIT_0(&p->rc, probs);
+ probs = &p->isRep0Long[p->state][posState];
+ RC_BIT_PRE(&p->rc, probs)
+ if (len != 1)
+ {
+ RC_BIT_1_BASE(&p->rc, probs);
+ }
+ else
+ {
+ RC_BIT_0_BASE(&p->rc, probs);
+ p->state = kShortRepNextStates[p->state];
+ }
+ }
+ else
+ {
+ RC_BIT_1(&p->rc, probs);
+ probs = &p->isRepG1[p->state];
+ RC_BIT_PRE(&p->rc, probs)
+ if (dist == 1)
+ {
+ RC_BIT_0_BASE(&p->rc, probs);
+ dist = p->reps[1];
+ }
+ else
+ {
+ RC_BIT_1(&p->rc, probs);
+ probs = &p->isRepG2[p->state];
+ RC_BIT_PRE(&p->rc, probs)
+ if (dist == 2)
+ {
+ RC_BIT_0_BASE(&p->rc, probs);
+ dist = p->reps[2];
+ }
+ else
+ {
+ RC_BIT_1_BASE(&p->rc, probs);
+ dist = p->reps[3];
+ p->reps[3] = p->reps[2];
+ }
+ p->reps[2] = p->reps[1];
+ }
+ p->reps[1] = p->reps[0];
+ p->reps[0] = dist;
+ }
+
+ RC_NORM(&p->rc)
+
+ p->rc.range = range;
+
+ if (len != 1)
+ {
+ LenEnc_Encode(&p->repLenProbs, &p->rc, len - LZMA_MATCH_LEN_MIN, posState);
+ --p->repLenEncCounter;
+ p->state = kRepNextStates[p->state];
+ }
+ }
+ else
+ {
+ unsigned posSlot;
+ RC_BIT_0(&p->rc, probs);
+ p->rc.range = range;
+ p->state = kMatchNextStates[p->state];
+
+ LenEnc_Encode(&p->lenProbs, &p->rc, len - LZMA_MATCH_LEN_MIN, posState);
+ // --p->lenEnc.counter;
+
+ dist -= LZMA_NUM_REPS;
+ p->reps[3] = p->reps[2];
+ p->reps[2] = p->reps[1];
+ p->reps[1] = p->reps[0];
+ p->reps[0] = dist + 1;
+
+ p->matchPriceCount++;
+ GetPosSlot(dist, posSlot);
+ // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], posSlot);
+ {
+ UInt32 sym = (UInt32)posSlot + (1 << kNumPosSlotBits);
+ range = p->rc.range;
+ probs = p->posSlotEncoder[GetLenToPosState(len)];
+ do
+ {
+ CLzmaProb *prob = probs + (sym >> kNumPosSlotBits);
+ UInt32 bit = (sym >> (kNumPosSlotBits - 1)) & 1;
+ sym <<= 1;
+ RC_BIT(&p->rc, prob, bit);
+ }
+ while (sym < (1 << kNumPosSlotBits * 2));
+ p->rc.range = range;
+ }
+
+ if (dist >= kStartPosModelIndex)
+ {
+ unsigned footerBits = ((posSlot >> 1) - 1);
+
+ if (dist < kNumFullDistances)
+ {
+ unsigned base = ((2 | (posSlot & 1)) << footerBits);
+ RcTree_ReverseEncode(&p->rc, p->posEncoders + base, footerBits, (unsigned)(dist /* - base */));
+ }
+ else
+ {
+ UInt32 pos2 = (dist | 0xF) << (32 - footerBits);
+ range = p->rc.range;
+ // RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
+ /*
+ do
+ {
+ range >>= 1;
+ p->rc.low += range & (0 - ((dist >> --footerBits) & 1));
+ RC_NORM(&p->rc)
+ }
+ while (footerBits > kNumAlignBits);
+ */
+ do
+ {
+ range >>= 1;
+ p->rc.low += range & (0 - (pos2 >> 31));
+ pos2 += pos2;
+ RC_NORM(&p->rc)
+ }
+ while (pos2 != 0xF0000000);
+
+
+ // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
+
+ {
+ unsigned m = 1;
+ unsigned bit;
+ bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit;
+ bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit;
+ bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit;
+ bit = dist & 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit);
+ p->rc.range = range;
+ // p->alignPriceCount++;
+ }
+ }
+ }
+ }
+ }
+
+ nowPos32 += (UInt32)len;
+ p->additionalOffset -= len;
+
+ if (p->additionalOffset == 0)
+ {
+ UInt32 processed;
+
+ if (!p->fastMode)
+ {
+ /*
+ if (p->alignPriceCount >= 16) // kAlignTableSize
+ FillAlignPrices(p);
+ if (p->matchPriceCount >= 128)
+ FillDistancesPrices(p);
+ if (p->lenEnc.counter <= 0)
+ LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices);
+ */
+ if (p->matchPriceCount >= 64)
+ {
+ FillAlignPrices(p);
+ // { int y; for (y = 0; y < 100; y++) {
+ FillDistancesPrices(p);
+ // }}
+ LenPriceEnc_UpdateTables(&p->lenEnc, (unsigned)1 << p->pb, &p->lenProbs, p->ProbPrices);
+ }
+ if (p->repLenEncCounter <= 0)
+ {
+ p->repLenEncCounter = REP_LEN_COUNT;
+ LenPriceEnc_UpdateTables(&p->repLenEnc, (unsigned)1 << p->pb, &p->repLenProbs, p->ProbPrices);
+ }
+ }
+
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
+ break;
+ processed = nowPos32 - startPos32;
+
+ if (maxPackSize)
+ {
+ if (processed + kNumOpts + 300 >= maxUnpackSize
+ || RangeEnc_GetProcessed_sizet(&p->rc) + kPackReserve >= maxPackSize)
+ break;
+ }
+ else if (processed >= (1 << 17))
+ {
+ p->nowPos64 += nowPos32 - startPos32;
+ return CheckErrors(p);
+ }
+ }
+ }
+
+ p->nowPos64 += nowPos32 - startPos32;
+ return Flush(p, nowPos32);
+}
+
+
+
+#define kBigHashDicLimit ((UInt32)1 << 24)
+
+static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ UInt32 beforeSize = kNumOpts;
+ UInt32 dictSize;
+
+ if (!RangeEnc_Alloc(&p->rc, alloc))
+ return SZ_ERROR_MEM;
+
+ #ifndef _7ZIP_ST
+ p->mtMode = (p->multiThread && !p->fastMode && (MFB.btMode != 0));
+ #endif
+
+ {
+ unsigned lclp = p->lc + p->lp;
+ if (!p->litProbs || !p->saveState.litProbs || p->lclp != lclp)
+ {
+ LzmaEnc_FreeLits(p, alloc);
+ p->litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb));
+ p->saveState.litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb));
+ if (!p->litProbs || !p->saveState.litProbs)
+ {
+ LzmaEnc_FreeLits(p, alloc);
+ return SZ_ERROR_MEM;
+ }
+ p->lclp = lclp;
+ }
+ }
+
+ MFB.bigHash = (Byte)(p->dictSize > kBigHashDicLimit ? 1 : 0);
+
+
+ dictSize = p->dictSize;
+ if (dictSize == ((UInt32)2 << 30) ||
+ dictSize == ((UInt32)3 << 30))
+ {
+ /* 21.03 : here we reduce the dictionary for 2 reasons:
+ 1) we don't want 32-bit back_distance matches in decoder for 2 GB dictionary.
+ 2) we want to elimate useless last MatchFinder_Normalize3() for corner cases,
+ where data size is aligned for 1 GB: 5/6/8 GB.
+ That reducing must be >= 1 for such corner cases. */
+ dictSize -= 1;
+ }
+
+ if (beforeSize + dictSize < keepWindowSize)
+ beforeSize = keepWindowSize - dictSize;
+
+ /* in worst case we can look ahead for
+ max(LZMA_MATCH_LEN_MAX, numFastBytes + 1 + numFastBytes) bytes.
+ we send larger value for (keepAfter) to MantchFinder_Create():
+ (numFastBytes + LZMA_MATCH_LEN_MAX + 1)
+ */
+
+ #ifndef _7ZIP_ST
+ if (p->mtMode)
+ {
+ RINOK(MatchFinderMt_Create(&p->matchFinderMt, dictSize, beforeSize,
+ p->numFastBytes, LZMA_MATCH_LEN_MAX + 1 /* 18.04 */
+ , allocBig));
+ p->matchFinderObj = &p->matchFinderMt;
+ MFB.bigHash = (Byte)(
+ (p->dictSize > kBigHashDicLimit && MFB.hashMask >= 0xFFFFFF) ? 1 : 0);
+ MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder);
+ }
+ else
+ #endif
+ {
+ if (!MatchFinder_Create(&MFB, dictSize, beforeSize,
+ p->numFastBytes, LZMA_MATCH_LEN_MAX + 1 /* 21.03 */
+ , allocBig))
+ return SZ_ERROR_MEM;
+ p->matchFinderObj = &MFB;
+ MatchFinder_CreateVTable(&MFB, &p->matchFinder);
+ }
+
+ return SZ_OK;
+}
+
+static void LzmaEnc_Init(CLzmaEnc *p)
+{
+ unsigned i;
+ p->state = 0;
+ p->reps[0] =
+ p->reps[1] =
+ p->reps[2] =
+ p->reps[3] = 1;
+
+ RangeEnc_Init(&p->rc);
+
+ for (i = 0; i < (1 << kNumAlignBits); i++)
+ p->posAlignEncoder[i] = kProbInitValue;
+
+ for (i = 0; i < kNumStates; i++)
+ {
+ unsigned j;
+ for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
+ {
+ p->isMatch[i][j] = kProbInitValue;
+ p->isRep0Long[i][j] = kProbInitValue;
+ }
+ p->isRep[i] = kProbInitValue;
+ p->isRepG0[i] = kProbInitValue;
+ p->isRepG1[i] = kProbInitValue;
+ p->isRepG2[i] = kProbInitValue;
+ }
+
+ {
+ for (i = 0; i < kNumLenToPosStates; i++)
+ {
+ CLzmaProb *probs = p->posSlotEncoder[i];
+ unsigned j;
+ for (j = 0; j < (1 << kNumPosSlotBits); j++)
+ probs[j] = kProbInitValue;
+ }
+ }
+ {
+ for (i = 0; i < kNumFullDistances; i++)
+ p->posEncoders[i] = kProbInitValue;
+ }
+
+ {
+ UInt32 num = (UInt32)0x300 << (p->lp + p->lc);
+ UInt32 k;
+ CLzmaProb *probs = p->litProbs;
+ for (k = 0; k < num; k++)
+ probs[k] = kProbInitValue;
+ }
+
+
+ LenEnc_Init(&p->lenProbs);
+ LenEnc_Init(&p->repLenProbs);
+
+ p->optEnd = 0;
+ p->optCur = 0;
+
+ {
+ for (i = 0; i < kNumOpts; i++)
+ p->opt[i].price = kInfinityPrice;
+ }
+
+ p->additionalOffset = 0;
+
+ p->pbMask = ((unsigned)1 << p->pb) - 1;
+ p->lpMask = ((UInt32)0x100 << p->lp) - ((unsigned)0x100 >> p->lc);
+
+ // p->mf_Failure = False;
+}
+
+
+static void LzmaEnc_InitPrices(CLzmaEnc *p)
+{
+ if (!p->fastMode)
+ {
+ FillDistancesPrices(p);
+ FillAlignPrices(p);
+ }
+
+ p->lenEnc.tableSize =
+ p->repLenEnc.tableSize =
+ p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
+
+ p->repLenEncCounter = REP_LEN_COUNT;
+
+ LenPriceEnc_UpdateTables(&p->lenEnc, (unsigned)1 << p->pb, &p->lenProbs, p->ProbPrices);
+ LenPriceEnc_UpdateTables(&p->repLenEnc, (unsigned)1 << p->pb, &p->repLenProbs, p->ProbPrices);
+}
+
+static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ unsigned i;
+ for (i = kEndPosModelIndex / 2; i < kDicLogSizeMax; i++)
+ if (p->dictSize <= ((UInt32)1 << i))
+ break;
+ p->distTableSize = i * 2;
+
+ p->finished = False;
+ p->result = SZ_OK;
+ RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig));
+ LzmaEnc_Init(p);
+ LzmaEnc_InitPrices(p);
+ p->nowPos64 = 0;
+ return SZ_OK;
+}
+
+static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
+ ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ MFB.stream = inStream;
+ p->needInit = 1;
+ p->rc.outStream = outStream;
+ return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
+}
+
+SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,
+ ISeqInStream *inStream, UInt32 keepWindowSize,
+ ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ MFB.stream = inStream;
+ p->needInit = 1;
+ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+}
+
+static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
+{
+ MFB.directInput = 1;
+ MFB.bufferBase = (Byte *)src;
+ MFB.directInputRem = srcLen;
+}
+
+SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
+ UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ LzmaEnc_SetInputBuf(p, src, srcLen);
+ p->needInit = 1;
+
+ LzmaEnc_SetDataSize(pp, srcLen);
+ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+}
+
+void LzmaEnc_Finish(CLzmaEncHandle pp)
+{
+ #ifndef _7ZIP_ST
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ if (p->mtMode)
+ MatchFinderMt_ReleaseStream(&p->matchFinderMt);
+ #else
+ UNUSED_VAR(pp);
+ #endif
+}
+
+
+typedef struct
+{
+ ISeqOutStream vt;
+ Byte *data;
+ SizeT rem;
+ BoolInt overflow;
+} CLzmaEnc_SeqOutStreamBuf;
+
+static size_t SeqOutStreamBuf_Write(const ISeqOutStream *pp, const void *data, size_t size)
+{
+ CLzmaEnc_SeqOutStreamBuf *p = CONTAINER_FROM_VTBL(pp, CLzmaEnc_SeqOutStreamBuf, vt);
+ if (p->rem < size)
+ {
+ size = p->rem;
+ p->overflow = True;
+ }
+ if (size != 0)
+ {
+ memcpy(p->data, data, size);
+ p->rem -= size;
+ p->data += size;
+ }
+ return size;
+}
+
+
+/*
+UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
+{
+ const CLzmaEnc *p = (CLzmaEnc *)pp;
+ return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
+}
+*/
+
+const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
+{
+ const CLzmaEnc *p = (CLzmaEnc *)pp;
+ return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
+}
+
+
+SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit,
+ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
+{
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+ UInt64 nowPos64;
+ SRes res;
+ CLzmaEnc_SeqOutStreamBuf outStream;
+
+ outStream.vt.Write = SeqOutStreamBuf_Write;
+ outStream.data = dest;
+ outStream.rem = *destLen;
+ outStream.overflow = False;
+
+ p->writeEndMark = False;
+ p->finished = False;
+ p->result = SZ_OK;
+
+ if (reInit)
+ LzmaEnc_Init(p);
+ LzmaEnc_InitPrices(p);
+
+ nowPos64 = p->nowPos64;
+ RangeEnc_Init(&p->rc);
+ p->rc.outStream = &outStream.vt;
+
+ if (desiredPackSize == 0)
+ return SZ_ERROR_OUTPUT_EOF;
+
+ res = LzmaEnc_CodeOneBlock(p, desiredPackSize, *unpackSize);
+
+ *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
+ *destLen -= outStream.rem;
+ if (outStream.overflow)
+ return SZ_ERROR_OUTPUT_EOF;
+
+ return res;
+}
+
+
+MY_NO_INLINE
+static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
+{
+ SRes res = SZ_OK;
+
+ #ifndef _7ZIP_ST
+ Byte allocaDummy[0x300];
+ allocaDummy[0] = 0;
+ allocaDummy[1] = allocaDummy[0];
+ #endif
+
+ for (;;)
+ {
+ res = LzmaEnc_CodeOneBlock(p, 0, 0);
+ if (res != SZ_OK || p->finished)
+ break;
+ if (progress)
+ {
+ res = ICompressProgress_Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
+ if (res != SZ_OK)
+ {
+ res = SZ_ERROR_PROGRESS;
+ break;
+ }
+ }
+ }
+
+ LzmaEnc_Finish(p);
+
+ /*
+ if (res == SZ_OK && !Inline_MatchFinder_IsFinishedOK(&MFB))
+ res = SZ_ERROR_FAIL;
+ }
+ */
+
+ return res;
+}
+
+
+SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
+ ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));
+ return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);
+}
+
+
+SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
+{
+ if (*size < LZMA_PROPS_SIZE)
+ return SZ_ERROR_PARAM;
+ *size = LZMA_PROPS_SIZE;
+ {
+ const CLzmaEnc *p = (const CLzmaEnc *)pp;
+ const UInt32 dictSize = p->dictSize;
+ UInt32 v;
+ props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);
+
+ // we write aligned dictionary value to properties for lzma decoder
+ if (dictSize >= ((UInt32)1 << 21))
+ {
+ const UInt32 kDictMask = ((UInt32)1 << 20) - 1;
+ v = (dictSize + kDictMask) & ~kDictMask;
+ if (v < dictSize)
+ v = dictSize;
+ }
+ else
+ {
+ unsigned i = 11 * 2;
+ do
+ {
+ v = (UInt32)(2 + (i & 1)) << (i >> 1);
+ i++;
+ }
+ while (v < dictSize);
+ }
+
+ SetUi32(props + 1, v);
+ return SZ_OK;
+ }
+}
+
+
+unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle pp)
+{
+ return (unsigned)((CLzmaEnc *)pp)->writeEndMark;
+}
+
+
+SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ SRes res;
+ CLzmaEnc *p = (CLzmaEnc *)pp;
+
+ CLzmaEnc_SeqOutStreamBuf outStream;
+
+ outStream.vt.Write = SeqOutStreamBuf_Write;
+ outStream.data = dest;
+ outStream.rem = *destLen;
+ outStream.overflow = False;
+
+ p->writeEndMark = writeEndMark;
+ p->rc.outStream = &outStream.vt;
+
+ res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig);
+
+ if (res == SZ_OK)
+ {
+ res = LzmaEnc_Encode2(p, progress);
+ if (res == SZ_OK && p->nowPos64 != srcLen)
+ res = SZ_ERROR_FAIL;
+ }
+
+ *destLen -= outStream.rem;
+ if (outStream.overflow)
+ return SZ_ERROR_OUTPUT_EOF;
+ return res;
+}
+
+
+SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+ ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
+ SRes res;
+ if (!p)
+ return SZ_ERROR_MEM;
+
+ res = LzmaEnc_SetProps(p, props);
+ if (res == SZ_OK)
+ {
+ res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
+ if (res == SZ_OK)
+ res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
+ writeEndMark, progress, alloc, allocBig);
+ }
+
+ LzmaEnc_Destroy(p, alloc, allocBig);
+ return res;
+}
+
+
+/*
+#ifndef _7ZIP_ST
+void LzmaEnc_GetLzThreads(CLzmaEncHandle pp, HANDLE lz_threads[2])
+{
+ const CLzmaEnc *p = (CLzmaEnc *)pp;
+ lz_threads[0] = p->matchFinderMt.hashSync.thread;
+ lz_threads[1] = p->matchFinderMt.btSync.thread;
+}
+#endif
+*/
diff --git a/src/Common/lzma/LzmaEnc.h b/src/Common/lzma/LzmaEnc.h
new file mode 100644
index 00000000..bc2ed504
--- /dev/null
+++ b/src/Common/lzma/LzmaEnc.h
@@ -0,0 +1,78 @@
+/* LzmaEnc.h -- LZMA Encoder
+2019-10-30 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA_ENC_H
+#define __LZMA_ENC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct _CLzmaEncProps
+{
+ int level; /* 0 <= level <= 9 */
+ UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
+ (1 << 12) <= dictSize <= (3 << 29) for 64-bit version
+ default = (1 << 24) */
+ int lc; /* 0 <= lc <= 8, default = 3 */
+ int lp; /* 0 <= lp <= 4, default = 0 */
+ int pb; /* 0 <= pb <= 4, default = 2 */
+ int algo; /* 0 - fast, 1 - normal, default = 1 */
+ int fb; /* 5 <= fb <= 273, default = 32 */
+ int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
+ int numHashBytes; /* 2, 3 or 4, default = 4 */
+ UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */
+ unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
+ int numThreads; /* 1 or 2, default = 2 */
+
+ UInt64 reduceSize; /* estimated size of data that will be compressed. default = (UInt64)(Int64)-1.
+ Encoder uses this value to reduce dictionary size */
+
+ UInt64 affinity;
+} CLzmaEncProps;
+
+void LzmaEncProps_Init(CLzmaEncProps *p);
+void LzmaEncProps_Normalize(CLzmaEncProps *p);
+UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
+
+
+/* ---------- CLzmaEncHandle Interface ---------- */
+
+/* LzmaEnc* functions can return the following exit codes:
+SRes:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater in props
+ SZ_ERROR_WRITE - ISeqOutStream write callback error
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output
+ SZ_ERROR_PROGRESS - some break from progress callback
+ SZ_ERROR_THREAD - error in multithreading functions (only for Mt version)
+*/
+
+typedef void * CLzmaEncHandle;
+
+CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc);
+void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig);
+
+SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
+void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize);
+SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
+unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p);
+
+SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
+ ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);
+SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);
+
+
+/* ---------- One Call Interface ---------- */
+
+SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+ ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/Common/lzma/LzmaLib.c b/src/Common/lzma/LzmaLib.c
new file mode 100644
index 00000000..706e9e58
--- /dev/null
+++ b/src/Common/lzma/LzmaLib.c
@@ -0,0 +1,40 @@
+/* LzmaLib.c -- LZMA library wrapper
+2015-06-13 : Igor Pavlov : Public domain */
+
+#include "Alloc.h"
+#include "LzmaDec.h"
+#include "LzmaEnc.h"
+#include "LzmaLib.h"
+
+MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen,
+ unsigned char *outProps, size_t *outPropsSize,
+ int level, /* 0 <= level <= 9, default = 5 */
+ unsigned dictSize, /* use (1 << N) or (3 << N). 4 KB < dictSize <= 128 MB */
+ int lc, /* 0 <= lc <= 8, default = 3 */
+ int lp, /* 0 <= lp <= 4, default = 0 */
+ int pb, /* 0 <= pb <= 4, default = 2 */
+ int fb, /* 5 <= fb <= 273, default = 32 */
+ int numThreads /* 1 or 2, default = 2 */
+)
+{
+ CLzmaEncProps props;
+ LzmaEncProps_Init(&props);
+ props.level = level;
+ props.dictSize = dictSize;
+ props.lc = lc;
+ props.lp = lp;
+ props.pb = pb;
+ props.fb = fb;
+ props.numThreads = numThreads;
+
+ return LzmaEncode(dest, destLen, src, srcLen, &props, outProps, outPropsSize, 0,
+ NULL, &g_Alloc, &g_Alloc);
+}
+
+
+MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen,
+ const unsigned char *props, size_t propsSize)
+{
+ ELzmaStatus status;
+ return LzmaDecode(dest, destLen, src, srcLen, props, (unsigned)propsSize, LZMA_FINISH_ANY, &status, &g_Alloc);
+}
diff --git a/src/Common/lzma/LzmaLib.h b/src/Common/lzma/LzmaLib.h
new file mode 100644
index 00000000..c343a859
--- /dev/null
+++ b/src/Common/lzma/LzmaLib.h
@@ -0,0 +1,138 @@
+/* LzmaLib.h -- LZMA library interface
+2021-04-03 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA_LIB_H
+#define __LZMA_LIB_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define MY_STDAPI int MY_STD_CALL
+
+#define LZMA_PROPS_SIZE 5
+
+/*
+RAM requirements for LZMA:
+ for compression: (dictSize * 11.5 + 6 MB) + state_size
+ for decompression: dictSize + state_size
+ state_size = (4 + (1.5 << (lc + lp))) KB
+ by default (lc=3, lp=0), state_size = 16 KB.
+
+LZMA properties (5 bytes) format
+ Offset Size Description
+ 0 1 lc, lp and pb in encoded form.
+ 1 4 dictSize (little endian).
+*/
+
+/*
+LzmaCompress
+------------
+
+outPropsSize -
+ In: the pointer to the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.
+ Out: the pointer to the size of written properties in outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.
+
+ LZMA Encoder will use defult values for any parameter, if it is
+ -1 for any from: level, loc, lp, pb, fb, numThreads
+ 0 for dictSize
+
+level - compression level: 0 <= level <= 9;
+
+ level dictSize algo fb
+ 0: 64 KB 0 32
+ 1: 256 KB 0 32
+ 2: 1 MB 0 32
+ 3: 4 MB 0 32
+ 4: 16 MB 0 32
+ 5: 16 MB 1 32
+ 6: 32 MB 1 32
+ 7: 32 MB 1 64
+ 8: 64 MB 1 64
+ 9: 64 MB 1 64
+
+ The default value for "level" is 5.
+
+ algo = 0 means fast method
+ algo = 1 means normal method
+
+dictSize - The dictionary size in bytes. The maximum value is
+ 128 MB = (1 << 27) bytes for 32-bit version
+ 1 GB = (1 << 30) bytes for 64-bit version
+ The default value is 16 MB = (1 << 24) bytes.
+ It's recommended to use the dictionary that is larger than 4 KB and
+ that can be calculated as (1 << N) or (3 << N) sizes.
+
+lc - The number of literal context bits (high bits of previous literal).
+ It can be in the range from 0 to 8. The default value is 3.
+ Sometimes lc=4 gives the gain for big files.
+
+lp - The number of literal pos bits (low bits of current position for literals).
+ It can be in the range from 0 to 4. The default value is 0.
+ The lp switch is intended for periodical data when the period is equal to 2^lp.
+ For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's
+ better to set lc=0, if you change lp switch.
+
+pb - The number of pos bits (low bits of current position).
+ It can be in the range from 0 to 4. The default value is 2.
+ The pb switch is intended for periodical data when the period is equal 2^pb.
+
+fb - Word size (the number of fast bytes).
+ It can be in the range from 5 to 273. The default value is 32.
+ Usually, a big number gives a little bit better compression ratio and
+ slower compression process.
+
+numThreads - The number of thereads. 1 or 2. The default value is 2.
+ Fast mode (algo = 0) can use only 1 thread.
+
+In:
+ dest - output data buffer
+ destLen - output data buffer size
+ src - input data
+ srcLen - input data size
+Out:
+ destLen - processed output size
+Returns:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen,
+ unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */
+ int level, /* 0 <= level <= 9, default = 5 */
+ unsigned dictSize, /* default = (1 << 24) */
+ int lc, /* 0 <= lc <= 8, default = 3 */
+ int lp, /* 0 <= lp <= 4, default = 0 */
+ int pb, /* 0 <= pb <= 4, default = 2 */
+ int fb, /* 5 <= fb <= 273, default = 32 */
+ int numThreads /* 1 or 2, default = 2 */
+ );
+
+/*
+LzmaUncompress
+--------------
+In:
+ dest - output data buffer
+ destLen - output data buffer size
+ src - input data
+ srcLen - input data size
+Out:
+ destLen - processed output size
+ srcLen - processed input size
+Returns:
+ SZ_OK - OK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation arror
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer (src)
+*/
+
+MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, SizeT *srcLen,
+ const unsigned char *props, size_t propsSize);
+
+EXTERN_C_END
+
+#endif
diff --git a/src/Common/lzma/Precomp.h b/src/Common/lzma/Precomp.h
new file mode 100644
index 00000000..e8ff8b40
--- /dev/null
+++ b/src/Common/lzma/Precomp.h
@@ -0,0 +1,10 @@
+/* Precomp.h -- StdAfx
+2013-11-12 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_PRECOMP_H
+#define __7Z_PRECOMP_H
+
+#include "Compiler.h"
+/* #include "7zTypes.h" */
+
+#endif
diff --git a/src/Common/lzma/Threads.c b/src/Common/lzma/Threads.c
new file mode 100644
index 00000000..58eb90ff
--- /dev/null
+++ b/src/Common/lzma/Threads.c
@@ -0,0 +1,540 @@
+/* Threads.c -- multithreading library
+2021-12-21 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#ifdef _WIN32
+
+#ifndef USE_THREADS_CreateThread
+#include <process.h>
+#endif
+
+#include "Threads.h"
+
+static WRes GetError()
+{
+ DWORD res = GetLastError();
+ return res ? (WRes)res : 1;
+}
+
+static WRes HandleToWRes(HANDLE h) { return (h != NULL) ? 0 : GetError(); }
+static WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); }
+
+WRes HandlePtr_Close(HANDLE *p)
+{
+ if (*p != NULL)
+ {
+ if (!CloseHandle(*p))
+ return GetError();
+ *p = NULL;
+ }
+ return 0;
+}
+
+WRes Handle_WaitObject(HANDLE h)
+{
+ DWORD dw = WaitForSingleObject(h, INFINITE);
+ /*
+ (dw) result:
+ WAIT_OBJECT_0 // 0
+ WAIT_ABANDONED // 0x00000080 : is not compatible with Win32 Error space
+ WAIT_TIMEOUT // 0x00000102 : is compatible with Win32 Error space
+ WAIT_FAILED // 0xFFFFFFFF
+ */
+ if (dw == WAIT_FAILED)
+ {
+ dw = GetLastError();
+ if (dw == 0)
+ return WAIT_FAILED;
+ }
+ return (WRes)dw;
+}
+
+#define Thread_Wait(p) Handle_WaitObject(*(p))
+
+WRes Thread_Wait_Close(CThread *p)
+{
+ WRes res = Thread_Wait(p);
+ WRes res2 = Thread_Close(p);
+ return (res != 0 ? res : res2);
+}
+
+WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
+{
+ /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
+
+ #ifdef USE_THREADS_CreateThread
+
+ DWORD threadId;
+ *p = CreateThread(NULL, 0, func, param, 0, &threadId);
+
+ #else
+
+ unsigned threadId;
+ *p = (HANDLE)(_beginthreadex(NULL, 0, func, param, 0, &threadId));
+
+ #endif
+
+ /* maybe we must use errno here, but probably GetLastError() is also OK. */
+ return HandleToWRes(*p);
+}
+
+
+WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity)
+{
+ #ifdef USE_THREADS_CreateThread
+
+ UNUSED_VAR(affinity)
+ return Thread_Create(p, func, param);
+
+ #else
+
+ /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
+ HANDLE h;
+ WRes wres;
+ unsigned threadId;
+ h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId));
+ *p = h;
+ wres = HandleToWRes(h);
+ if (h)
+ {
+ {
+ // DWORD_PTR prevMask =
+ SetThreadAffinityMask(h, (DWORD_PTR)affinity);
+ /*
+ if (prevMask == 0)
+ {
+ // affinity change is non-critical error, so we can ignore it
+ // wres = GetError();
+ }
+ */
+ }
+ {
+ DWORD prevSuspendCount = ResumeThread(h);
+ /* ResumeThread() returns:
+ 0 : was_not_suspended
+ 1 : was_resumed
+ -1 : error
+ */
+ if (prevSuspendCount == (DWORD)-1)
+ wres = GetError();
+ }
+ }
+
+ /* maybe we must use errno here, but probably GetLastError() is also OK. */
+ return wres;
+
+ #endif
+}
+
+
+static WRes Event_Create(CEvent *p, BOOL manualReset, int signaled)
+{
+ *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL);
+ return HandleToWRes(*p);
+}
+
+WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); }
+WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); }
+
+WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); }
+WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); }
+WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); }
+WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); }
+
+
+WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
+{
+ // negative ((LONG)maxCount) is not supported in WIN32::CreateSemaphore()
+ *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL);
+ return HandleToWRes(*p);
+}
+
+WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
+{
+ // if (Semaphore_IsCreated(p))
+ {
+ WRes wres = Semaphore_Close(p);
+ if (wres != 0)
+ return wres;
+ }
+ return Semaphore_Create(p, initCount, maxCount);
+}
+
+static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount)
+ { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); }
+WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num)
+ { return Semaphore_Release(p, (LONG)num, NULL); }
+WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); }
+
+WRes CriticalSection_Init(CCriticalSection *p)
+{
+ /* InitializeCriticalSection() can raise exception:
+ Windows XP, 2003 : can raise a STATUS_NO_MEMORY exception
+ Windows Vista+ : no exceptions */
+ #ifdef _MSC_VER
+ __try
+ #endif
+ {
+ InitializeCriticalSection(p);
+ /* InitializeCriticalSectionAndSpinCount(p, 0); */
+ }
+ #ifdef _MSC_VER
+ __except (EXCEPTION_EXECUTE_HANDLER) { return ERROR_NOT_ENOUGH_MEMORY; }
+ #endif
+ return 0;
+}
+
+
+
+
+#else // _WIN32
+
+// ---------- POSIX ----------
+
+#ifndef __APPLE__
+#ifndef _7ZIP_AFFINITY_DISABLE
+// _GNU_SOURCE can be required for pthread_setaffinity_np() / CPU_ZERO / CPU_SET
+#define _GNU_SOURCE
+#endif
+#endif
+
+#include "Threads.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _7ZIP_AFFINITY_SUPPORTED
+// #include <sched.h>
+#endif
+
+
+// #include <stdio.h>
+// #define PRF(p) p
+#define PRF(p)
+
+#define Print(s) PRF(printf("\n%s\n", s))
+
+// #include <stdio.h>
+
+WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet)
+{
+ // new thread in Posix probably inherits affinity from parrent thread
+ Print("Thread_Create_With_CpuSet");
+
+ pthread_attr_t attr;
+ int ret;
+ // int ret2;
+
+ p->_created = 0;
+
+ RINOK(pthread_attr_init(&attr));
+
+ ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ if (!ret)
+ {
+ if (cpuSet)
+ {
+ #ifdef _7ZIP_AFFINITY_SUPPORTED
+
+ /*
+ printf("\n affinity :");
+ unsigned i;
+ for (i = 0; i < sizeof(*cpuSet) && i < 8; i++)
+ {
+ Byte b = *((const Byte *)cpuSet + i);
+ char temp[32];
+ #define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))
+ temp[0] = GET_HEX_CHAR((b & 0xF));
+ temp[1] = GET_HEX_CHAR((b >> 4));
+ // temp[0] = GET_HEX_CHAR((b >> 4)); // big-endian
+ // temp[1] = GET_HEX_CHAR((b & 0xF)); // big-endian
+ temp[2] = 0;
+ printf("%s", temp);
+ }
+ printf("\n");
+ */
+
+ // ret2 =
+ pthread_attr_setaffinity_np(&attr, sizeof(*cpuSet), cpuSet);
+ // if (ret2) ret = ret2;
+ #endif
+ }
+
+ ret = pthread_create(&p->_tid, &attr, func, param);
+
+ if (!ret)
+ {
+ p->_created = 1;
+ /*
+ if (cpuSet)
+ {
+ // ret2 =
+ pthread_setaffinity_np(p->_tid, sizeof(*cpuSet), cpuSet);
+ // if (ret2) ret = ret2;
+ }
+ */
+ }
+ }
+ // ret2 =
+ pthread_attr_destroy(&attr);
+ // if (ret2 != 0) ret = ret2;
+ return ret;
+}
+
+
+WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
+{
+ return Thread_Create_With_CpuSet(p, func, param, NULL);
+}
+
+
+WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity)
+{
+ Print("Thread_Create_WithAffinity");
+ CCpuSet cs;
+ unsigned i;
+ CpuSet_Zero(&cs);
+ for (i = 0; i < sizeof(affinity) * 8; i++)
+ {
+ if (affinity == 0)
+ break;
+ if (affinity & 1)
+ {
+ CpuSet_Set(&cs, i);
+ }
+ affinity >>= 1;
+ }
+ return Thread_Create_With_CpuSet(p, func, param, &cs);
+}
+
+
+WRes Thread_Close(CThread *p)
+{
+ // Print("Thread_Close");
+ int ret;
+ if (!p->_created)
+ return 0;
+
+ ret = pthread_detach(p->_tid);
+ p->_tid = 0;
+ p->_created = 0;
+ return ret;
+}
+
+
+WRes Thread_Wait_Close(CThread *p)
+{
+ // Print("Thread_Wait_Close");
+ void *thread_return;
+ int ret;
+ if (!p->_created)
+ return EINVAL;
+
+ ret = pthread_join(p->_tid, &thread_return);
+ // probably we can't use that (_tid) after pthread_join(), so we close thread here
+ p->_created = 0;
+ p->_tid = 0;
+ return ret;
+}
+
+
+
+static WRes Event_Create(CEvent *p, int manualReset, int signaled)
+{
+ RINOK(pthread_mutex_init(&p->_mutex, NULL));
+ RINOK(pthread_cond_init(&p->_cond, NULL));
+ p->_manual_reset = manualReset;
+ p->_state = (signaled ? True : False);
+ p->_created = 1;
+ return 0;
+}
+
+WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled)
+ { return Event_Create(p, True, signaled); }
+WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p)
+ { return ManualResetEvent_Create(p, 0); }
+WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled)
+ { return Event_Create(p, False, signaled); }
+WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p)
+ { return AutoResetEvent_Create(p, 0); }
+
+
+WRes Event_Set(CEvent *p)
+{
+ RINOK(pthread_mutex_lock(&p->_mutex));
+ p->_state = True;
+ int res1 = pthread_cond_broadcast(&p->_cond);
+ int res2 = pthread_mutex_unlock(&p->_mutex);
+ return (res2 ? res2 : res1);
+}
+
+WRes Event_Reset(CEvent *p)
+{
+ RINOK(pthread_mutex_lock(&p->_mutex));
+ p->_state = False;
+ return pthread_mutex_unlock(&p->_mutex);
+}
+
+WRes Event_Wait(CEvent *p)
+{
+ RINOK(pthread_mutex_lock(&p->_mutex));
+ while (p->_state == False)
+ {
+ // ETIMEDOUT
+ // ret =
+ pthread_cond_wait(&p->_cond, &p->_mutex);
+ // if (ret != 0) break;
+ }
+ if (p->_manual_reset == False)
+ {
+ p->_state = False;
+ }
+ return pthread_mutex_unlock(&p->_mutex);
+}
+
+WRes Event_Close(CEvent *p)
+{
+ if (!p->_created)
+ return 0;
+ p->_created = 0;
+ {
+ int res1 = pthread_mutex_destroy(&p->_mutex);
+ int res2 = pthread_cond_destroy(&p->_cond);
+ return (res1 ? res1 : res2);
+ }
+}
+
+
+WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
+{
+ if (initCount > maxCount || maxCount < 1)
+ return EINVAL;
+ RINOK(pthread_mutex_init(&p->_mutex, NULL));
+ RINOK(pthread_cond_init(&p->_cond, NULL));
+ p->_count = initCount;
+ p->_maxCount = maxCount;
+ p->_created = 1;
+ return 0;
+}
+
+
+WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
+{
+ if (Semaphore_IsCreated(p))
+ {
+ /*
+ WRes wres = Semaphore_Close(p);
+ if (wres != 0)
+ return wres;
+ */
+ if (initCount > maxCount || maxCount < 1)
+ return EINVAL;
+ // return EINVAL; // for debug
+ p->_count = initCount;
+ p->_maxCount = maxCount;
+ return 0;
+ }
+ return Semaphore_Create(p, initCount, maxCount);
+}
+
+
+WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount)
+{
+ UInt32 newCount;
+ int ret;
+
+ if (releaseCount < 1)
+ return EINVAL;
+
+ RINOK(pthread_mutex_lock(&p->_mutex));
+
+ newCount = p->_count + releaseCount;
+ if (newCount > p->_maxCount)
+ ret = ERROR_TOO_MANY_POSTS; // EINVAL;
+ else
+ {
+ p->_count = newCount;
+ ret = pthread_cond_broadcast(&p->_cond);
+ }
+ RINOK(pthread_mutex_unlock(&p->_mutex));
+ return ret;
+}
+
+WRes Semaphore_Wait(CSemaphore *p)
+{
+ RINOK(pthread_mutex_lock(&p->_mutex));
+ while (p->_count < 1)
+ {
+ pthread_cond_wait(&p->_cond, &p->_mutex);
+ }
+ p->_count--;
+ return pthread_mutex_unlock(&p->_mutex);
+}
+
+WRes Semaphore_Close(CSemaphore *p)
+{
+ if (!p->_created)
+ return 0;
+ p->_created = 0;
+ {
+ int res1 = pthread_mutex_destroy(&p->_mutex);
+ int res2 = pthread_cond_destroy(&p->_cond);
+ return (res1 ? res1 : res2);
+ }
+}
+
+
+
+WRes CriticalSection_Init(CCriticalSection *p)
+{
+ // Print("CriticalSection_Init");
+ if (!p)
+ return EINTR;
+ return pthread_mutex_init(&p->_mutex, NULL);
+}
+
+void CriticalSection_Enter(CCriticalSection *p)
+{
+ // Print("CriticalSection_Enter");
+ if (p)
+ {
+ // int ret =
+ pthread_mutex_lock(&p->_mutex);
+ }
+}
+
+void CriticalSection_Leave(CCriticalSection *p)
+{
+ // Print("CriticalSection_Leave");
+ if (p)
+ {
+ // int ret =
+ pthread_mutex_unlock(&p->_mutex);
+ }
+}
+
+void CriticalSection_Delete(CCriticalSection *p)
+{
+ // Print("CriticalSection_Delete");
+ if (p)
+ {
+ // int ret =
+ pthread_mutex_destroy(&p->_mutex);
+ }
+}
+
+LONG InterlockedIncrement(LONG volatile *addend)
+{
+ // Print("InterlockedIncrement");
+ #ifdef USE_HACK_UNSAFE_ATOMIC
+ LONG val = *addend + 1;
+ *addend = val;
+ return val;
+ #else
+ return __sync_add_and_fetch(addend, 1);
+ #endif
+}
+
+#endif // _WIN32
diff --git a/src/Common/lzma/Threads.h b/src/Common/lzma/Threads.h
new file mode 100644
index 00000000..89ecb92b
--- /dev/null
+++ b/src/Common/lzma/Threads.h
@@ -0,0 +1,232 @@
+/* Threads.h -- multithreading library
+2021-12-21 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_THREADS_H
+#define __7Z_THREADS_H
+
+#ifdef _WIN32
+#include <Windows.h>
+#else
+
+#if defined(__linux__)
+#if !defined(__APPLE__) && !defined(_AIX) && !defined(__ANDROID__)
+#ifndef _7ZIP_AFFINITY_DISABLE
+#define _7ZIP_AFFINITY_SUPPORTED
+// #pragma message(" ==== _7ZIP_AFFINITY_SUPPORTED")
+// #define _GNU_SOURCE
+#endif
+#endif
+#endif
+
+#include <pthread.h>
+
+#endif
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#ifdef _WIN32
+
+WRes HandlePtr_Close(HANDLE *h);
+WRes Handle_WaitObject(HANDLE h);
+
+typedef HANDLE CThread;
+
+#define Thread_Construct(p) { *(p) = NULL; }
+#define Thread_WasCreated(p) (*(p) != NULL)
+#define Thread_Close(p) HandlePtr_Close(p)
+// #define Thread_Wait(p) Handle_WaitObject(*(p))
+
+#ifdef UNDER_CE
+ // if (USE_THREADS_CreateThread is defined), we use _beginthreadex()
+ // if (USE_THREADS_CreateThread is not definned), we use CreateThread()
+ #define USE_THREADS_CreateThread
+#endif
+
+typedef
+ #ifdef USE_THREADS_CreateThread
+ DWORD
+ #else
+ unsigned
+ #endif
+ THREAD_FUNC_RET_TYPE;
+
+typedef DWORD_PTR CAffinityMask;
+typedef DWORD_PTR CCpuSet;
+
+#define CpuSet_Zero(p) { *(p) = 0; }
+#define CpuSet_Set(p, cpu) { *(p) |= ((DWORD_PTR)1 << (cpu)); }
+
+#else // _WIN32
+
+typedef struct _CThread
+{
+ pthread_t _tid;
+ int _created;
+} CThread;
+
+#define Thread_Construct(p) { (p)->_tid = 0; (p)->_created = 0; }
+#define Thread_WasCreated(p) ((p)->_created != 0)
+WRes Thread_Close(CThread *p);
+// #define Thread_Wait Thread_Wait_Close
+
+typedef void * THREAD_FUNC_RET_TYPE;
+
+typedef UInt64 CAffinityMask;
+
+#ifdef _7ZIP_AFFINITY_SUPPORTED
+
+typedef cpu_set_t CCpuSet;
+#define CpuSet_Zero(p) CPU_ZERO(p)
+#define CpuSet_Set(p, cpu) CPU_SET(cpu, p)
+#define CpuSet_IsSet(p, cpu) CPU_ISSET(cpu, p)
+
+#else
+
+typedef UInt64 CCpuSet;
+#define CpuSet_Zero(p) { *(p) = 0; }
+#define CpuSet_Set(p, cpu) { *(p) |= ((UInt64)1 << (cpu)); }
+#define CpuSet_IsSet(p, cpu) ((*(p) & ((UInt64)1 << (cpu))) != 0)
+
+#endif
+
+
+#endif // _WIN32
+
+
+#define THREAD_FUNC_CALL_TYPE MY_STD_CALL
+
+#if defined(_WIN32) && defined(__GNUC__)
+/* GCC compiler for x86 32-bit uses the rule:
+ the stack is 16-byte aligned before CALL instruction for function calling.
+ But only root function main() contains instructions that
+ set 16-byte alignment for stack pointer. And another functions
+ just keep alignment, if it was set in some parent function.
+
+ The problem:
+ if we create new thread in MinGW (GCC) 32-bit x86 via _beginthreadex() or CreateThread(),
+ the root function of thread doesn't set 16-byte alignment.
+ And stack frames in all child functions also will be unaligned in that case.
+
+ Here we set (force_align_arg_pointer) attribute for root function of new thread.
+ Do we need (force_align_arg_pointer) also for another systems? */
+
+ #define THREAD_FUNC_ATTRIB_ALIGN_ARG __attribute__((force_align_arg_pointer))
+ // #define THREAD_FUNC_ATTRIB_ALIGN_ARG // for debug : bad alignment in SSE functions
+#else
+ #define THREAD_FUNC_ATTRIB_ALIGN_ARG
+#endif
+
+#define THREAD_FUNC_DECL THREAD_FUNC_ATTRIB_ALIGN_ARG THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE
+
+typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *);
+WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param);
+WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity);
+WRes Thread_Wait_Close(CThread *p);
+
+#ifdef _WIN32
+#define Thread_Create_With_CpuSet(p, func, param, cs) \
+ Thread_Create_With_Affinity(p, func, param, *cs)
+#else
+WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet);
+#endif
+
+
+#ifdef _WIN32
+
+typedef HANDLE CEvent;
+typedef CEvent CAutoResetEvent;
+typedef CEvent CManualResetEvent;
+#define Event_Construct(p) *(p) = NULL
+#define Event_IsCreated(p) (*(p) != NULL)
+#define Event_Close(p) HandlePtr_Close(p)
+#define Event_Wait(p) Handle_WaitObject(*(p))
+WRes Event_Set(CEvent *p);
+WRes Event_Reset(CEvent *p);
+WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled);
+WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p);
+WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled);
+WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p);
+
+typedef HANDLE CSemaphore;
+#define Semaphore_Construct(p) *(p) = NULL
+#define Semaphore_IsCreated(p) (*(p) != NULL)
+#define Semaphore_Close(p) HandlePtr_Close(p)
+#define Semaphore_Wait(p) Handle_WaitObject(*(p))
+WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
+WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
+WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num);
+WRes Semaphore_Release1(CSemaphore *p);
+
+typedef CRITICAL_SECTION CCriticalSection;
+WRes CriticalSection_Init(CCriticalSection *p);
+#define CriticalSection_Delete(p) DeleteCriticalSection(p)
+#define CriticalSection_Enter(p) EnterCriticalSection(p)
+#define CriticalSection_Leave(p) LeaveCriticalSection(p)
+
+
+#else // _WIN32
+
+typedef struct _CEvent
+{
+ int _created;
+ int _manual_reset;
+ int _state;
+ pthread_mutex_t _mutex;
+ pthread_cond_t _cond;
+} CEvent;
+
+typedef CEvent CAutoResetEvent;
+typedef CEvent CManualResetEvent;
+
+#define Event_Construct(p) (p)->_created = 0
+#define Event_IsCreated(p) ((p)->_created)
+
+WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled);
+WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p);
+WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled);
+WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p);
+WRes Event_Set(CEvent *p);
+WRes Event_Reset(CEvent *p);
+WRes Event_Wait(CEvent *p);
+WRes Event_Close(CEvent *p);
+
+
+typedef struct _CSemaphore
+{
+ int _created;
+ UInt32 _count;
+ UInt32 _maxCount;
+ pthread_mutex_t _mutex;
+ pthread_cond_t _cond;
+} CSemaphore;
+
+#define Semaphore_Construct(p) (p)->_created = 0
+#define Semaphore_IsCreated(p) ((p)->_created)
+
+WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
+WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
+WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num);
+#define Semaphore_Release1(p) Semaphore_ReleaseN(p, 1)
+WRes Semaphore_Wait(CSemaphore *p);
+WRes Semaphore_Close(CSemaphore *p);
+
+
+typedef struct _CCriticalSection
+{
+ pthread_mutex_t _mutex;
+} CCriticalSection;
+
+WRes CriticalSection_Init(CCriticalSection *p);
+void CriticalSection_Delete(CCriticalSection *cs);
+void CriticalSection_Enter(CCriticalSection *cs);
+void CriticalSection_Leave(CCriticalSection *cs);
+
+LONG InterlockedIncrement(LONG volatile *addend);
+
+#endif // _WIN32
+
+EXTERN_C_END
+
+#endif
diff --git a/src/Common/lzma/lzma-history.txt b/src/Common/lzma/lzma-history.txt
new file mode 100644
index 00000000..0963c7bf
--- /dev/null
+++ b/src/Common/lzma/lzma-history.txt
@@ -0,0 +1,520 @@
+HISTORY of the LZMA SDK
+-----------------------
+
+21.07 2021-12-26
+-------------------------
+- New switches: -spm and -im!{file_path} to exclude directories from processing
+ for specified paths that don't contain path separator character at the end of path.
+- The sorting order of files in archives was slightly changed to be more consistent
+ for cases where the name of some directory is the same as the prefix part of the name
+ of another directory or file.
+
+
+21.06 2021-11-24
+-------------------------
+- Bug in LZMA encoder in file LzmaEnc.c was fixed:
+ LzmaEnc_MemEncode(), LzmaEncode() and LzmaCompress() could work incorrectly,
+ if size value for output buffer is smaller than size required for all compressed data.
+ LzmaEnc_Encode() could work incorrectly,
+ if callback ISeqOutStream::Write() doesn't write all compressed data.
+ NCompress::NLzma::CEncoder::Code() could work incorrectly,
+ if callback ISequentialOutStream::Write() returns error code.
+- Bug in versions 21.00-21.05 was fixed:
+ 7-Zip didn't set attributes of directories during archive extracting.
+
+
+21.04 beta 2021-11-02
+-------------------------
+- 7-Zip now reduces the number of working CPU threads for compression,
+ if RAM size is not enough for compression with big LZMA2 dictionary.
+- 7-Zip now can create and check "file.sha256" text files that contain the list
+ of file names and SHA-256 checksums in format compatible with sha256sum program.
+
+
+21.03 beta 2021-07-20
+-------------------------
+- The maximum dictionary size for LZMA/LZMA2 compressing was increased to 4 GB (3840 MiB).
+- Minor speed optimizations in LZMA/LZMA2 compressing.
+
+
+21.02 alpha 2021-05-06
+-------------------------
+- The command line version of 7-Zip for macOS was released.
+- The speed for LZMA and LZMA2 decompression in arm64 versions for macOS and Linux
+ was increased by 20%-60%.
+
+
+21.01 alpha 2021-03-09
+-------------------------
+- The command line version of 7-Zip for Linux was released.
+- The improvements for speed of ARM64 version using hardware CPU instructions
+ for AES, CRC-32, SHA-1 and SHA-256.
+- Some bugs were fixed.
+
+
+20.02 alpha 2020-08-08
+-------------------------
+- The default number of LZMA2 chunks per solid block in 7z archive was increased to 64.
+ It allows to increase the compression speed for big 7z archives, if there is a big number
+ of CPU cores and threads.
+- The speed of PPMd compressing/decompressing was increased for 7z archives.
+- The new -ssp switch. If the switch -ssp is specified, 7-Zip doesn't allow the system
+ to modify "Last Access Time" property of source files for archiving and hashing operations.
+- Some bugs were fixed.
+
+
+20.00 alpha 2020-02-06
+-------------------------
+- 7-Zip now supports new optional match finders for LZMA/LZMA2 compression: bt5 and hc5,
+ that can work faster than bt4 and hc4 match finders for the data with big redundancy.
+- The compression ratio was improved for Fast and Fastest compression levels with the
+ following default settings:
+ - Fastest level (-mx1) : hc5 match finder with 256 KB dictionary.
+ - Fast level (-mx3) : hc5 match finder with 4 MB dictionary.
+- Minor speed optimizations in multithreaded LZMA/LZMA2 compression for Normal/Maximum/Ultra
+ compression levels.
+
+
+19.00 2019-02-21
+-------------------------
+- Encryption strength for 7z archives was increased:
+ the size of random initialization vector was increased from 64-bit to 128-bit,
+ and the pseudo-random number generator was improved.
+- The bug in 7zIn.c code was fixed.
+
+
+18.06 2018-12-30
+-------------------------
+- The speed for LZMA/LZMA2 compressing was increased by 3-10%,
+ and there are minor changes in compression ratio.
+- Some bugs were fixed.
+- The bug in 7-Zip 18.02-18.05 was fixed:
+ There was memory leak in multithreading xz decoder - XzDecMt_Decode(),
+ if xz stream contains only one block.
+- The changes for MSVS compiler makefiles:
+ - the makefiles now use "PLATFORM" macroname with values (x64, x86, arm64)
+ instead of "CPU" macroname with values (AMD64, ARM64).
+ - the makefiles by default now use static version of the run-time library.
+
+
+18.05 2018-04-30
+-------------------------
+- The speed for LZMA/LZMA2 compressing was increased
+ by 8% for fastest/fast compression levels and
+ by 3% for normal/maximum compression levels.
+- Previous versions of 7-Zip could work incorrectly in "Large memory pages" mode in
+ Windows 10 because of some BUG with "Large Pages" in Windows 10.
+ Now 7-Zip doesn't use "Large Pages" on Windows 10 up to revision 1709 (16299).
+- The BUG was fixed in Lzma2Enc.c
+ Lzma2Enc_Encode2() function worked incorretly,
+ if (inStream == NULL) and the number of block threads is more than 1.
+
+
+18.03 beta 2018-03-04
+-------------------------
+- Asm\x86\LzmaDecOpt.asm: new optimized LZMA decoder written in asm
+ for x64 with about 30% higher speed than main version of LZMA decoder written in C.
+- The speed for single-thread LZMA/LZMA2 decoder written in C was increased by 3%.
+- 7-Zip now can use multi-threading for 7z/LZMA2 decoding,
+ if there are multiple independent data chunks in LZMA2 stream.
+- 7-Zip now can use multi-threading for xz decoding,
+ if there are multiple blocks in xz stream.
+
+
+18.01 2019-01-28
+-------------------------
+- The BUG in 17.01 - 18.00 beta was fixed:
+ XzDec.c : random block unpacking and XzUnpacker_IsBlockFinished()
+ didn't work correctly for xz archives without checksum (CRC).
+
+
+18.00 beta 2019-01-10
+-------------------------
+- The BUG in xz encoder was fixed:
+ There was memory leak of 16 KB for each file compressed with
+ xz compression method, if additional filter was used.
+
+
+17.01 beta 2017-08-28
+-------------------------
+- Minor speed optimization for LZMA2 (xz and 7z) multi-threading compression.
+ 7-Zip now uses additional memory buffers for multi-block LZMA2 compression.
+ CPU utilization was slightly improved.
+- 7-zip now creates multi-block xz archives by default. Block size can be
+ specified with -ms[Size]{m|g} switch.
+- xz decoder now can unpack random block from multi-block xz archives.
+- 7-Zip command line: @listfile now doesn't work after -- switch.
+ Use -i@listfile before -- switch instead.
+- The BUGs were fixed:
+ 7-Zip 17.00 beta crashed for commands that write anti-item to 7z archive.
+
+
+17.00 beta 2017-04-29
+-------------------------
+- NewHandler.h / NewHandler.cpp:
+ now it redefines operator new() only for old MSVC compilers (_MSC_VER < 1900).
+- C/7zTypes.h : the names of variables in interface structures were changed (vt).
+- Some bugs were fixed. 7-Zip could crash in some cases.
+- Some internal changes in code.
+
+
+16.04 2016-10-04
+-------------------------
+- The bug was fixed in DllSecur.c.
+
+
+16.03 2016-09-28
+-------------------------
+- SFX modules now use some protection against DLL preloading attack.
+- Some bugs in 7z code were fixed.
+
+
+16.02 2016-05-21
+-------------------------
+- The BUG in 16.00 - 16.01 was fixed:
+ Split Handler (SplitHandler.cpp) returned incorrect
+ total size value (kpidSize) for split archives.
+
+
+16.01 2016-05-19
+-------------------------
+- Some internal changes to reduce the number of compiler warnings.
+
+
+16.00 2016-05-10
+-------------------------
+- Some bugs were fixed.
+
+
+15.12 2015-11-19
+-------------------------
+- The BUG in C version of 7z decoder was fixed:
+ 7zDec.c : SzDecodeLzma2()
+ 7z decoder could mistakenly report about decoding error for some 7z archives
+ that use LZMA2 compression method.
+ The probability to get that mistaken decoding error report was about
+ one error per 16384 solid blocks for solid blocks larger than 16 KB (compressed size).
+- The BUG (in 9.26-15.11) in C version of 7z decoder was fixed:
+ 7zArcIn.c : SzReadHeader2()
+ 7z decoder worked incorrectly for 7z archives that contain
+ empty solid blocks, that can be placed to 7z archive, if some file is
+ unavailable for reading during archive creation.
+
+
+15.09 beta 2015-10-16
+-------------------------
+- The BUG in LZMA / LZMA2 encoding code was fixed.
+ The BUG in LzFind.c::MatchFinder_ReadBlock() function.
+ If input data size is larger than (4 GiB - dictionary_size),
+ the following code worked incorrectly:
+ - LZMA : LzmaEnc_MemEncode(), LzmaEncode() : LZMA encoding functions
+ for compressing from memory to memory.
+ That BUG is not related to LZMA encoder version that works via streams.
+ - LZMA2 : multi-threaded version of LZMA2 encoder worked incorrectly, if
+ default value of chunk size (CLzma2EncProps::blockSize) is changed
+ to value larger than (4 GiB - dictionary_size).
+
+
+9.38 beta 2015-01-03
+-------------------------
+- The BUG in 9.31-9.37 was fixed:
+ IArchiveGetRawProps interface was disabled for 7z archives.
+- The BUG in 9.26-9.36 was fixed:
+ Some code in CPP\7zip\Archive\7z\ worked correctly only under Windows.
+
+
+9.36 beta 2014-12-26
+-------------------------
+- The BUG in command line version was fixed:
+ 7-Zip created temporary archive in current folder during update archive
+ operation, if -w{Path} switch was not specified.
+ The fixed 7-Zip creates temporary archive in folder that contains updated archive.
+- The BUG in 9.33-9.35 was fixed:
+ 7-Zip silently ignored file reading errors during 7z or gz archive creation,
+ and the created archive contained only part of file that was read before error.
+ The fixed 7-Zip stops archive creation and it reports about error.
+
+
+9.35 beta 2014-12-07
+-------------------------
+- 7zr.exe now support AES encryption.
+- SFX mudules were added to LZMA SDK
+- Some bugs were fixed.
+
+
+9.21 beta 2011-04-11
+-------------------------
+- New class FString for file names at file systems.
+- Speed optimization in CRC code for big-endian CPUs.
+- The BUG in Lzma2Dec.c was fixed:
+ Lzma2Decode function didn't work.
+
+
+9.18 beta 2010-11-02
+-------------------------
+- New small SFX module for installers (SfxSetup).
+
+
+9.12 beta 2010-03-24
+-------------------------
+- The BUG in LZMA SDK 9.* was fixed: LZMA2 codec didn't work,
+ if more than 10 threads were used (or more than 20 threads in some modes).
+
+
+9.11 beta 2010-03-15
+-------------------------
+- PPMd compression method support
+
+
+9.09 2009-12-12
+-------------------------
+- The bug was fixed:
+ Utf16_To_Utf8 funstions in UTFConvert.cpp and 7zMain.c
+ incorrectly converted surrogate characters (the code >= 0x10000) to UTF-8.
+- Some bugs were fixed
+
+
+9.06 2009-08-17
+-------------------------
+- Some changes in ANSI-C 7z Decoder interfaces.
+
+
+9.04 2009-05-30
+-------------------------
+- LZMA2 compression method support
+- xz format support
+
+
+4.65 2009-02-03
+-------------------------
+- Some minor fixes
+
+
+4.63 2008-12-31
+-------------------------
+- Some minor fixes
+
+
+4.61 beta 2008-11-23
+-------------------------
+- The bug in ANSI-C LZMA Decoder was fixed:
+ If encoded stream was corrupted, decoder could access memory
+ outside of allocated range.
+- Some changes in ANSI-C 7z Decoder interfaces.
+- LZMA SDK is placed in the public domain.
+
+
+4.60 beta 2008-08-19
+-------------------------
+- Some minor fixes.
+
+
+4.59 beta 2008-08-13
+-------------------------
+- The bug was fixed:
+ LZMA Encoder in fast compression mode could access memory outside of
+ allocated range in some rare cases.
+
+
+4.58 beta 2008-05-05
+-------------------------
+- ANSI-C LZMA Decoder was rewritten for speed optimizations.
+- ANSI-C LZMA Encoder was included to LZMA SDK.
+- C++ LZMA code now is just wrapper over ANSI-C code.
+
+
+4.57 2007-12-12
+-------------------------
+- Speed optimizations in ++ LZMA Decoder.
+- Small changes for more compatibility with some C/C++ compilers.
+
+
+4.49 beta 2007-07-05
+-------------------------
+- .7z ANSI-C Decoder:
+ - now it supports BCJ and BCJ2 filters
+ - now it supports files larger than 4 GB.
+ - now it supports "Last Write Time" field for files.
+- C++ code for .7z archives compressing/decompressing from 7-zip
+ was included to LZMA SDK.
+
+
+4.43 2006-06-04
+-------------------------
+- Small changes for more compatibility with some C/C++ compilers.
+
+
+4.42 2006-05-15
+-------------------------
+- Small changes in .h files in ANSI-C version.
+
+
+4.39 beta 2006-04-14
+-------------------------
+- The bug in versions 4.33b:4.38b was fixed:
+ C++ version of LZMA encoder could not correctly compress
+ files larger than 2 GB with HC4 match finder (-mfhc4).
+
+
+4.37 beta 2005-04-06
+-------------------------
+- Fixes in C++ code: code could no be compiled if _NO_EXCEPTIONS was defined.
+
+
+4.35 beta 2005-03-02
+-------------------------
+- The bug was fixed in C++ version of LZMA Decoder:
+ If encoded stream was corrupted, decoder could access memory
+ outside of allocated range.
+
+
+4.34 beta 2006-02-27
+-------------------------
+- Compressing speed and memory requirements for compressing were increased
+- LZMA now can use only these match finders: HC4, BT2, BT3, BT4
+
+
+4.32 2005-12-09
+-------------------------
+- Java version of LZMA SDK was included
+
+
+4.30 2005-11-20
+-------------------------
+- Compression ratio was improved in -a2 mode
+- Speed optimizations for compressing in -a2 mode
+- -fb switch now supports values up to 273
+- The bug in 7z_C (7zIn.c) was fixed:
+ It used Alloc/Free functions from different memory pools.
+ So if program used two memory pools, it worked incorrectly.
+- 7z_C: .7z format supporting was improved
+- LZMA# SDK (C#.NET version) was included
+
+
+4.27 (Updated) 2005-09-21
+-------------------------
+- Some GUIDs/interfaces in C++ were changed.
+ IStream.h:
+ ISequentialInStream::Read now works as old ReadPart
+ ISequentialOutStream::Write now works as old WritePart
+
+
+4.27 2005-08-07
+-------------------------
+- The bug in LzmaDecodeSize.c was fixed:
+ if _LZMA_IN_CB and _LZMA_OUT_READ were defined,
+ decompressing worked incorrectly.
+
+
+4.26 2005-08-05
+-------------------------
+- Fixes in 7z_C code and LzmaTest.c:
+ previous versions could work incorrectly,
+ if malloc(0) returns 0
+
+
+4.23 2005-06-29
+-------------------------
+- Small fixes in C++ code
+
+
+4.22 2005-06-10
+-------------------------
+- Small fixes
+
+
+4.21 2005-06-08
+-------------------------
+- Interfaces for ANSI-C LZMA Decoder (LzmaDecode.c) were changed
+- New additional version of ANSI-C LZMA Decoder with zlib-like interface:
+ - LzmaStateDecode.h
+ - LzmaStateDecode.c
+ - LzmaStateTest.c
+- ANSI-C LZMA Decoder now can decompress files larger than 4 GB
+
+
+4.17 2005-04-18
+-------------------------
+- New example for RAM->RAM compressing/decompressing:
+ LZMA + BCJ (filter for x86 code):
+ - LzmaRam.h
+ - LzmaRam.cpp
+ - LzmaRamDecode.h
+ - LzmaRamDecode.c
+ - -f86 switch for lzma.exe
+
+
+4.16 2005-03-29
+-------------------------
+- The bug was fixed in LzmaDecode.c (ANSI-C LZMA Decoder):
+ If _LZMA_OUT_READ was defined, and if encoded stream was corrupted,
+ decoder could access memory outside of allocated range.
+- Speed optimization of ANSI-C LZMA Decoder (now it's about 20% faster).
+ Old version of LZMA Decoder now is in file LzmaDecodeSize.c.
+ LzmaDecodeSize.c can provide slightly smaller code than LzmaDecode.c
+- Small speed optimization in LZMA C++ code
+- filter for SPARC's code was added
+- Simplified version of .7z ANSI-C Decoder was included
+
+
+4.06 2004-09-05
+-------------------------
+- The bug in v4.05 was fixed:
+ LZMA-Encoder didn't release output stream in some cases.
+
+
+4.05 2004-08-25
+-------------------------
+- Source code of filters for x86, IA-64, ARM, ARM-Thumb
+ and PowerPC code was included to SDK
+- Some internal minor changes
+
+
+4.04 2004-07-28
+-------------------------
+- More compatibility with some C++ compilers
+
+
+4.03 2004-06-18
+-------------------------
+- "Benchmark" command was added. It measures compressing
+ and decompressing speed and shows rating values.
+ Also it checks hardware errors.
+
+
+4.02 2004-06-10
+-------------------------
+- C++ LZMA Encoder/Decoder code now is more portable
+ and it can be compiled by GCC on Linux.
+
+
+4.01 2004-02-15
+-------------------------
+- Some detection of data corruption was enabled.
+ LzmaDecode.c / RangeDecoderReadByte
+ .....
+ {
+ rd->ExtraBytes = 1;
+ return 0xFF;
+ }
+
+
+4.00 2004-02-13
+-------------------------
+- Original version of LZMA SDK
+
+
+
+HISTORY of the LZMA
+-------------------
+ 2001-2008: Improvements to LZMA compressing/decompressing code,
+ keeping compatibility with original LZMA format
+ 1996-2001: Development of LZMA compression format
+
+ Some milestones:
+
+ 2001-08-30: LZMA compression was added to 7-Zip
+ 1999-01-02: First version of 7-Zip was released
+
+
+End of document
diff --git a/src/Common/lzma/lzma-sdk.txt b/src/Common/lzma/lzma-sdk.txt
new file mode 100644
index 00000000..9621c8d5
--- /dev/null
+++ b/src/Common/lzma/lzma-sdk.txt
@@ -0,0 +1,404 @@
+LZMA SDK 21.07
+--------------
+
+LZMA SDK provides the documentation, samples, header files,
+libraries, and tools you need to develop applications that
+use 7z / LZMA / LZMA2 / XZ compression.
+
+LZMA is an improved version of famous LZ77 compression algorithm.
+It was improved in way of maximum increasing of compression ratio,
+keeping high decompression speed and low memory requirements for
+decompressing.
+
+LZMA2 is a LZMA based compression method. LZMA2 provides better
+multithreading support for compression than LZMA and some other improvements.
+
+7z is a file format for data compression and file archiving.
+7z is a main file format for 7-Zip compression program (www.7-zip.org).
+7z format supports different compression methods: LZMA, LZMA2 and others.
+7z also supports AES-256 based encryption.
+
+XZ is a file format for data compression that uses LZMA2 compression.
+XZ format provides additional features: SHA/CRC check, filters for
+improved compression ratio, splitting to blocks and streams,
+
+
+
+LICENSE
+-------
+
+LZMA SDK is written and placed in the public domain by Igor Pavlov.
+
+Some code in LZMA SDK is based on public domain code from another developers:
+ 1) PPMd var.H (2001): Dmitry Shkarin
+ 2) SHA-256: Wei Dai (Crypto++ library)
+
+Anyone is free to copy