From b80be10c4dc2c1f27917cd68a2c4c47819ee5fe5 Mon Sep 17 00:00:00 2001
From: Amos <48657826+Mauler125@users.noreply.github.com>
Date: Thu, 6 Jan 2022 15:08:39 +0100
Subject: [PATCH] Compile LZHAM with the solution. Fix missing detours files
for sdklauncher
---
r5dev/core/stdafx.h | 7 +-
r5dev/dedicated.vcxproj | 115 +-
r5dev/dedicated.vcxproj.filters | 168 +-
r5dev/r5dev.vcxproj | 115 +-
r5dev/r5dev.vcxproj.filters | 168 +-
r5dev/sdklauncher.vcxproj | 23 +-
r5dev/sdklauncher.vcxproj.filters | 27 +
r5dev/thirdparty/detours/src/creatwth.cpp | 1783 +++++++++++++++
r5dev/thirdparty/detours/src/uimports.cpp | 335 +++
r5dev/thirdparty/lzham/include/lzham_assert.h | 40 +
.../thirdparty/lzham/include/lzham_checksum.h | 13 +
r5dev/thirdparty/lzham/include/lzham_config.h | 23 +
r5dev/thirdparty/lzham/include/lzham_core.h | 170 ++
.../thirdparty/lzham/include/lzham_helpers.h | 54 +
.../lzham/include/lzham_huffman_codes.h | 14 +
r5dev/thirdparty/lzham/include/lzham_lzbase.h | 45 +
.../lzham/include/lzham_match_accel.h | 146 ++
r5dev/thirdparty/lzham/include/lzham_math.h | 113 +
r5dev/thirdparty/lzham/include/lzham_mem.h | 112 +
.../lzham/include/lzham_null_threading.h | 97 +
.../thirdparty/lzham/include/lzham_platform.h | 284 +++
.../lzham/include/lzham_polar_codes.h | 14 +
.../lzham/include/lzham_prefix_coding.h | 144 ++
.../lzham/include/lzham_pthreads_threading.h | 383 ++++
.../lzham/include/lzham_symbol_codec.h | 556 +++++
.../lzham/include/lzham_threading.h | 12 +
r5dev/thirdparty/lzham/include/lzham_timer.h | 99 +
r5dev/thirdparty/lzham/include/lzham_traits.h | 137 ++
r5dev/thirdparty/lzham/include/lzham_types.h | 74 +
r5dev/thirdparty/lzham/include/lzham_utils.h | 58 +
r5dev/thirdparty/lzham/include/lzham_vector.h | 588 +++++
.../lzham/include/lzham_win32_threading.h | 368 +++
r5dev/thirdparty/lzham/libs/lzhamcomp_x64.lib | Bin 556410 -> 0 bytes
.../thirdparty/lzham/libs/lzhamcomp_x64D.lib | Bin 824648 -> 0 bytes
.../thirdparty/lzham/libs/lzhamdecomp_x64.lib | Bin 599642 -> 0 bytes
.../lzham/libs/lzhamdecomp_x64D.lib | Bin 588216 -> 0 bytes
r5dev/thirdparty/lzham/libs/lzhamlib_x64.lib | Bin 26576 -> 0 bytes
r5dev/thirdparty/lzham/libs/lzhamlib_x64D.lib | Bin 24960 -> 0 bytes
r5dev/thirdparty/lzham/lzham_api.cpp | 179 ++
r5dev/thirdparty/lzham/lzham_assert.cpp | 66 +
r5dev/thirdparty/lzham/lzham_checksum.cpp | 73 +
.../thirdparty/lzham/lzham_huffman_codes.cpp | 390 ++++
r5dev/thirdparty/lzham/lzham_lzbase.cpp | 71 +
r5dev/thirdparty/lzham/lzham_match_accel.cpp | 562 +++++
r5dev/thirdparty/lzham/lzham_mem.cpp | 272 +++
r5dev/thirdparty/lzham/lzham_platform.cpp | 146 ++
r5dev/thirdparty/lzham/lzham_polar_codes.cpp | 414 ++++
.../thirdparty/lzham/lzham_prefix_coding.cpp | 350 +++
.../lzham/lzham_pthreads_threading.cpp | 227 ++
r5dev/thirdparty/lzham/lzham_symbol_codec.cpp | 1453 ++++++++++++
r5dev/thirdparty/lzham/lzham_timer.cpp | 147 ++
r5dev/thirdparty/lzham/lzham_vector.cpp | 74 +
.../lzham/lzham_win32_threading.cpp | 220 ++
r5dev/thirdparty/lzham/lzhamcomp/lzham_comp.h | 38 +
.../lzham/lzhamcomp/lzham_lzcomp.cpp | 611 +++++
.../lzham/lzhamcomp/lzham_lzcomp_internal.cpp | 1972 +++++++++++++++++
.../lzham/lzhamcomp/lzham_lzcomp_internal.h | 481 ++++
.../lzham/lzhamcomp/lzham_lzcomp_state.cpp | 1463 ++++++++++++
.../lzham/lzhamdecomp/lzham_decomp.h | 37 +
.../lzham/lzhamdecomp/lzham_lzdecomp.cpp | 1590 +++++++++++++
.../lzham/lzhamdecomp/lzham_lzdecompbase.cpp | 46 +
.../lzham/lzhamdecomp/lzham_lzdecompbase.h | 90 +
62 files changed, 17238 insertions(+), 19 deletions(-)
create mode 100644 r5dev/thirdparty/detours/src/creatwth.cpp
create mode 100644 r5dev/thirdparty/detours/src/uimports.cpp
create mode 100644 r5dev/thirdparty/lzham/include/lzham_assert.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_checksum.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_config.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_core.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_helpers.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_huffman_codes.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_lzbase.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_match_accel.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_math.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_mem.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_null_threading.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_platform.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_polar_codes.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_prefix_coding.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_pthreads_threading.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_symbol_codec.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_threading.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_timer.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_traits.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_types.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_utils.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_vector.h
create mode 100644 r5dev/thirdparty/lzham/include/lzham_win32_threading.h
delete mode 100644 r5dev/thirdparty/lzham/libs/lzhamcomp_x64.lib
delete mode 100644 r5dev/thirdparty/lzham/libs/lzhamcomp_x64D.lib
delete mode 100644 r5dev/thirdparty/lzham/libs/lzhamdecomp_x64.lib
delete mode 100644 r5dev/thirdparty/lzham/libs/lzhamdecomp_x64D.lib
delete mode 100644 r5dev/thirdparty/lzham/libs/lzhamlib_x64.lib
delete mode 100644 r5dev/thirdparty/lzham/libs/lzhamlib_x64D.lib
create mode 100644 r5dev/thirdparty/lzham/lzham_api.cpp
create mode 100644 r5dev/thirdparty/lzham/lzham_assert.cpp
create mode 100644 r5dev/thirdparty/lzham/lzham_checksum.cpp
create mode 100644 r5dev/thirdparty/lzham/lzham_huffman_codes.cpp
create mode 100644 r5dev/thirdparty/lzham/lzham_lzbase.cpp
create mode 100644 r5dev/thirdparty/lzham/lzham_match_accel.cpp
create mode 100644 r5dev/thirdparty/lzham/lzham_mem.cpp
create mode 100644 r5dev/thirdparty/lzham/lzham_platform.cpp
create mode 100644 r5dev/thirdparty/lzham/lzham_polar_codes.cpp
create mode 100644 r5dev/thirdparty/lzham/lzham_prefix_coding.cpp
create mode 100644 r5dev/thirdparty/lzham/lzham_pthreads_threading.cpp
create mode 100644 r5dev/thirdparty/lzham/lzham_symbol_codec.cpp
create mode 100644 r5dev/thirdparty/lzham/lzham_timer.cpp
create mode 100644 r5dev/thirdparty/lzham/lzham_vector.cpp
create mode 100644 r5dev/thirdparty/lzham/lzham_win32_threading.cpp
create mode 100644 r5dev/thirdparty/lzham/lzhamcomp/lzham_comp.h
create mode 100644 r5dev/thirdparty/lzham/lzhamcomp/lzham_lzcomp.cpp
create mode 100644 r5dev/thirdparty/lzham/lzhamcomp/lzham_lzcomp_internal.cpp
create mode 100644 r5dev/thirdparty/lzham/lzhamcomp/lzham_lzcomp_internal.h
create mode 100644 r5dev/thirdparty/lzham/lzhamcomp/lzham_lzcomp_state.cpp
create mode 100644 r5dev/thirdparty/lzham/lzhamdecomp/lzham_decomp.h
create mode 100644 r5dev/thirdparty/lzham/lzhamdecomp/lzham_lzdecomp.cpp
create mode 100644 r5dev/thirdparty/lzham/lzhamdecomp/lzham_lzdecompbase.cpp
create mode 100644 r5dev/thirdparty/lzham/lzhamdecomp/lzham_lzdecompbase.h
diff --git a/r5dev/core/stdafx.h b/r5dev/core/stdafx.h
index 1637be75..ee52eac0 100644
--- a/r5dev/core/stdafx.h
+++ b/r5dev/core/stdafx.h
@@ -36,6 +36,11 @@
#include "thirdparty/imgui/include/imgui_impl_win32.h"
#endif // !DEDICATED
+#if !defined(SDKLAUNCHER)
+#include "thirdparty/lzham/include/lzham_types.h"
+#include "thirdparty/lzham/include/lzham.h"
+#endif // !SDKLAUNCHER
+
#include "thirdparty/spdlog/include/spdlog.h"
#include "thirdparty/spdlog/include/sinks/basic_file_sink.h"
#include "thirdparty/spdlog/include/sinks/stdout_sinks.h"
@@ -57,4 +62,4 @@ namespace
MODULE g_mRadAudioDecoderDll = MODULE("binkawin64.dll");
MODULE g_mRadAudioSystemDll = MODULE("mileswin64.dll");
}
-#endif // SDKLAUNCHER
+#endif // !SDKLAUNCHER
diff --git a/r5dev/dedicated.vcxproj b/r5dev/dedicated.vcxproj
index 30414412..017a8898 100644
--- a/r5dev/dedicated.vcxproj
+++ b/r5dev/dedicated.vcxproj
@@ -135,7 +135,7 @@
Console
true
- lzhamlib_x64D.lib;lzhamcomp_x64D.lib;lzhamdecomp_x64D.lib;d3d11.lib;bcrypt.lib;%(AdditionalDependencies)
+ d3d11.lib;bcrypt.lib;%(AdditionalDependencies)
del "..\..\..\$(ProjectName)" && copy /Y "$(TargetPath)" "..\..\..\
@@ -162,7 +162,7 @@
true
true
true
- lzhamlib_x64.lib;lzhamcomp_x64.lib;lzhamdecomp_x64.lib;d3d11.lib;bcrypt.lib;%(AdditionalDependencies)
+ d3d11.lib;bcrypt.lib;%(AdditionalDependencies)
del "..\..\..\$(ProjectName)" && copy /Y "$(TargetPath)" "..\..\..\
@@ -215,7 +215,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -360,6 +387,10 @@
+
+ NotUsing
+ NotUsing
+
NotUsing
NotUsing
@@ -372,6 +403,86 @@
NotUsing
NotUsing
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
diff --git a/r5dev/dedicated.vcxproj.filters b/r5dev/dedicated.vcxproj.filters
index 3bee9887..c110b5a1 100644
--- a/r5dev/dedicated.vcxproj.filters
+++ b/r5dev/dedicated.vcxproj.filters
@@ -97,6 +97,18 @@
{8288ba1a-7609-42ef-af3b-850727635a99}
+
+ {8736d047-b4af-4c17-99ee-454cc96ec1ba}
+
+
+ {e84ad150-2358-4146-971a-02c5f045437c}
+
+
+ {eb98cd2b-4508-43a0-95e1-feacc7c83a8d}
+
+
+ {463e0739-1e5f-47a0-94d1-6cf5b6bf3ea6}
+
@@ -540,12 +552,6 @@
sdk\public\include
-
- thirdparty\lzham\include
-
-
- thirdparty\lzham\include
-
sdk\mathlib
@@ -564,6 +570,93 @@
windows
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\lzhamcomp\include
+
+
+ thirdparty\lzham\lzhamcomp\include
+
+
+ thirdparty\lzham\lzhamdecomp\include
+
+
+ thirdparty\lzham\lzhamdecomp\include
+
@@ -701,6 +794,69 @@
thirdparty\detours
+
+ thirdparty\detours
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham\lzhamcomp
+
+
+ thirdparty\lzham\lzhamcomp
+
+
+ thirdparty\lzham\lzhamcomp
+
+
+ thirdparty\lzham\lzhamdecomp
+
+
+ thirdparty\lzham\lzhamdecomp
+
diff --git a/r5dev/r5dev.vcxproj b/r5dev/r5dev.vcxproj
index dcab8624..8d942be3 100644
--- a/r5dev/r5dev.vcxproj
+++ b/r5dev/r5dev.vcxproj
@@ -58,6 +58,10 @@
+
+ NotUsing
+ NotUsing
+
NotUsing
NotUsing
@@ -106,6 +110,86 @@
NotUsing
NotUsing
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
@@ -192,7 +276,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -452,7 +563,7 @@
true
false
r5dev.def
- lzhamlib_x64D.lib;lzhamcomp_x64D.lib;lzhamdecomp_x64D.lib;d3d11.lib;bcrypt.lib;%(AdditionalDependencies)
+ d3d11.lib;bcrypt.lib;%(AdditionalDependencies)
copy /Y "$(TargetPath)" "..\..\..\bin\$(TargetFileName)"
@@ -488,7 +599,7 @@
true
false
r5dev.def
- lzhamlib_x64.lib;lzhamcomp_x64.lib;lzhamdecomp_x64.lib;d3d11.lib;bcrypt.lib;%(AdditionalDependencies)
+ d3d11.lib;bcrypt.lib;%(AdditionalDependencies)
copy /Y "$(TargetPath)" "..\..\..\$(TargetFileName)" && del "..\..\..\r5apexsdkd64.dll" && rename "..\..\..\$(TargetFileName)" "r5apexsdkd64.dll"
diff --git a/r5dev/r5dev.vcxproj.filters b/r5dev/r5dev.vcxproj.filters
index 4bd5cd1c..818da70f 100644
--- a/r5dev/r5dev.vcxproj.filters
+++ b/r5dev/r5dev.vcxproj.filters
@@ -127,6 +127,18 @@
{f52dfb17-f5bd-4258-91a2-500587bee708}
+
+ {f450ee50-7010-49e2-9f91-05a74fcb6a8b}
+
+
+ {11645361-fd70-462f-ab8b-8a78283a5fc7}
+
+
+ {785353c2-6417-4213-b55f-3007a0b79801}
+
+
+ {5beb12b5-0422-4337-9be6-2e6c0a05a69b}
+
@@ -321,6 +333,69 @@
thirdparty\detours
+
+ thirdparty\detours
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham
+
+
+ thirdparty\lzham\lzhamcomp
+
+
+ thirdparty\lzham\lzhamcomp
+
+
+ thirdparty\lzham\lzhamcomp
+
+
+ thirdparty\lzham\lzhamdecomp
+
+
+ thirdparty\lzham\lzhamdecomp
+
@@ -836,12 +911,6 @@
sdk\public\include
-
- thirdparty\lzham\include
-
-
- thirdparty\lzham\include
-
sdk\mathlib
@@ -872,6 +941,93 @@
sdk\milessdk
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\include
+
+
+ thirdparty\lzham\lzhamcomp\include
+
+
+ thirdparty\lzham\lzhamcomp\include
+
+
+ thirdparty\lzham\lzhamdecomp\include
+
+
+ thirdparty\lzham\lzhamdecomp\include
+
diff --git a/r5dev/sdklauncher.vcxproj b/r5dev/sdklauncher.vcxproj
index 99e6e9fb..d5260590 100644
--- a/r5dev/sdklauncher.vcxproj
+++ b/r5dev/sdklauncher.vcxproj
@@ -140,7 +140,7 @@
Console
true
- detours.lib;%(AdditionalDependencies)
+ %(AdditionalDependencies)
del "..\..\..\r5reloaded.exe" && copy /Y "$(TargetPath)" "..\..\..\$(TargetFileName)"
@@ -174,7 +174,7 @@
true
true
true
- detours.lib;%(AdditionalDependencies)
+ %(AdditionalDependencies)
del "..\..\..\r5reloaded.exe" && copy /Y "$(TargetPath)" "..\..\..\$(TargetFileName)"
@@ -186,6 +186,22 @@
Create
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
+
+ NotUsing
+ NotUsing
+
@@ -198,6 +214,9 @@
+
+
+
diff --git a/r5dev/sdklauncher.vcxproj.filters b/r5dev/sdklauncher.vcxproj.filters
index 5a7f2de0..70394cc2 100644
--- a/r5dev/sdklauncher.vcxproj.filters
+++ b/r5dev/sdklauncher.vcxproj.filters
@@ -13,6 +13,12 @@
{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+ {82b18787-373d-42ce-8d8d-1e3adba8d3a0}
+
+
+ {dc968871-7ca2-452b-a5b1-350a12dd54aa}
+
@@ -21,6 +27,18 @@
Source Files
+
+ Detours Files
+
+
+ Detours Files
+
+
+ Detours Files
+
+
+ Detours Files
+
@@ -37,6 +55,15 @@
Header Files
+
+ Detours Files\include
+
+
+ Detours Files\include
+
+
+ Detours Files\include
+
diff --git a/r5dev/thirdparty/detours/src/creatwth.cpp b/r5dev/thirdparty/detours/src/creatwth.cpp
new file mode 100644
index 00000000..f6720d7b
--- /dev/null
+++ b/r5dev/thirdparty/detours/src/creatwth.cpp
@@ -0,0 +1,1783 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// Create a process with a DLL (creatwth.cpp of detours.lib)
+//
+// Microsoft Research Detours Package, Version 4.0.1
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+
+// #define DETOUR_DEBUG 1
+#define DETOURS_INTERNAL
+#include "../include/detours.h"
+#include
+
+#if DETOURS_VERSION != 0x4c0c1 // 0xMAJORcMINORcPATCH
+#error detours.h version mismatch
+#endif
+
+#define IMPORT_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT]
+#define BOUND_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT]
+#define CLR_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR]
+#define IAT_DIRECTORY OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT]
+
+//////////////////////////////////////////////////////////////////////////////
+//
+const GUID DETOUR_EXE_HELPER_GUID = { /* ea0251b9-5cde-41b5-98d0-2af4a26b0fee */
+ 0xea0251b9, 0x5cde, 0x41b5,
+ { 0x98, 0xd0, 0x2a, 0xf4, 0xa2, 0x6b, 0x0f, 0xee }};
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Enumerate through modules in the target process.
+//
+static PVOID LoadNtHeaderFromProcess(_In_ HANDLE hProcess,
+ _In_ HMODULE hModule,
+ _Out_ PIMAGE_NT_HEADERS32 pNtHeader)
+{
+ ZeroMemory(pNtHeader, sizeof(*pNtHeader));
+ PBYTE pbModule = (PBYTE)hModule;
+
+ if (pbModule == NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return NULL;
+ }
+
+ MEMORY_BASIC_INFORMATION mbi;
+ ZeroMemory(&mbi, sizeof(mbi));
+
+ if (VirtualQueryEx(hProcess, hModule, &mbi, sizeof(mbi)) == 0) {
+ return NULL;
+ }
+
+ IMAGE_DOS_HEADER idh;
+ if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
+ DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n",
+ pbModule, pbModule + sizeof(idh), GetLastError()));
+ return NULL;
+ }
+
+ if (idh.e_magic != IMAGE_DOS_SIGNATURE ||
+ (DWORD)idh.e_lfanew > mbi.RegionSize ||
+ (DWORD)idh.e_lfanew < sizeof(idh)) {
+
+ SetLastError(ERROR_BAD_EXE_FORMAT);
+ return NULL;
+ }
+
+ if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew,
+ pNtHeader, sizeof(*pNtHeader), NULL)) {
+ DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p:%p) failed: %lu\n",
+ pbModule + idh.e_lfanew,
+ pbModule + idh.e_lfanew + sizeof(*pNtHeader),
+ pbModule,
+ GetLastError()));
+ return NULL;
+ }
+
+ if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
+ SetLastError(ERROR_BAD_EXE_FORMAT);
+ return NULL;
+ }
+
+ return pbModule + idh.e_lfanew;
+}
+
+static HMODULE EnumerateModulesInProcess(_In_ HANDLE hProcess,
+ _In_opt_ HMODULE hModuleLast,
+ _Out_ PIMAGE_NT_HEADERS32 pNtHeader,
+ _Out_opt_ PVOID *pRemoteNtHeader)
+{
+ ZeroMemory(pNtHeader, sizeof(*pNtHeader));
+ if (pRemoteNtHeader) {
+ *pRemoteNtHeader = NULL;
+ }
+
+ PBYTE pbLast = (PBYTE)hModuleLast + MM_ALLOCATION_GRANULARITY;
+
+ MEMORY_BASIC_INFORMATION mbi;
+ ZeroMemory(&mbi, sizeof(mbi));
+
+ // Find the next memory region that contains a mapped PE image.
+ //
+
+ for (;; pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) {
+ if (VirtualQueryEx(hProcess, (PVOID)pbLast, &mbi, sizeof(mbi)) == 0) {
+ break;
+ }
+
+ // Usermode address space has such an unaligned region size always at the
+ // end and only at the end.
+ //
+ if ((mbi.RegionSize & 0xfff) == 0xfff) {
+ break;
+ }
+ if (((PBYTE)mbi.BaseAddress + mbi.RegionSize) < pbLast) {
+ break;
+ }
+
+ // Skip uncommitted regions and guard pages.
+ //
+ if ((mbi.State != MEM_COMMIT) ||
+ ((mbi.Protect & 0xff) == PAGE_NOACCESS) ||
+ (mbi.Protect & PAGE_GUARD)) {
+ continue;
+ }
+
+ PVOID remoteHeader
+ = LoadNtHeaderFromProcess(hProcess, (HMODULE)pbLast, pNtHeader);
+ if (remoteHeader) {
+ if (pRemoteNtHeader) {
+ *pRemoteNtHeader = remoteHeader;
+ }
+
+ return (HMODULE)pbLast;
+ }
+ }
+ return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Find payloads in target process.
+//
+
+static PVOID FindDetourSectionInRemoteModule(_In_ HANDLE hProcess,
+ _In_ HMODULE hModule,
+ _In_ const IMAGE_NT_HEADERS32 *pNtHeader,
+ _In_ PVOID pRemoteNtHeader)
+{
+ if (pNtHeader->FileHeader.SizeOfOptionalHeader == 0) {
+ SetLastError(ERROR_EXE_MARKED_INVALID);
+ return NULL;
+ }
+
+ PIMAGE_SECTION_HEADER pRemoteSectionHeaders
+ = (PIMAGE_SECTION_HEADER)((PBYTE)pRemoteNtHeader
+ + sizeof(pNtHeader->Signature)
+ + sizeof(pNtHeader->FileHeader)
+ + pNtHeader->FileHeader.SizeOfOptionalHeader);
+
+ IMAGE_SECTION_HEADER header;
+ for (DWORD n = 0; n < pNtHeader->FileHeader.NumberOfSections; ++n) {
+ if (!ReadProcessMemory(hProcess, pRemoteSectionHeaders + n, &header, sizeof(header), NULL)) {
+ DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %lu\n",
+ pRemoteSectionHeaders + n,
+ (PBYTE)(pRemoteSectionHeaders + n) + sizeof(header),
+ GetLastError()));
+
+ return NULL;
+ }
+
+ if (strcmp((PCHAR)header.Name, ".detour") == 0) {
+ if (header.VirtualAddress == 0 ||
+ header.SizeOfRawData == 0) {
+
+ break;
+ }
+
+ SetLastError(NO_ERROR);
+ return (PBYTE)hModule + header.VirtualAddress;
+ }
+ }
+
+ SetLastError(ERROR_EXE_MARKED_INVALID);
+ return NULL;
+}
+
+static PVOID FindPayloadInRemoteDetourSection(_In_ HANDLE hProcess,
+ _In_ REFGUID rguid,
+ _Out_opt_ DWORD *pcbData,
+ _In_ PVOID pvRemoteDetoursSection)
+{
+ if (pcbData) {
+ *pcbData = 0;
+ }
+
+ PBYTE pbData = (PBYTE)pvRemoteDetoursSection;
+
+ DETOUR_SECTION_HEADER header;
+ if (!ReadProcessMemory(hProcess, pbData, &header, sizeof(header), NULL)) {
+ DETOUR_TRACE(("ReadProcessMemory(dsh@%p..%p) failed: %lu\n",
+ pbData,
+ pbData + sizeof(header),
+ GetLastError()));
+ return NULL;
+ }
+
+ if (header.cbHeaderSize < sizeof(DETOUR_SECTION_HEADER) ||
+ header.nSignature != DETOUR_SECTION_HEADER_SIGNATURE) {
+ SetLastError(ERROR_EXE_MARKED_INVALID);
+ return NULL;
+ }
+
+ if (header.nDataOffset == 0) {
+ header.nDataOffset = header.cbHeaderSize;
+ }
+
+ for (PVOID pvSection = pbData + header.nDataOffset; pvSection < pbData + header.cbDataSize;) {
+ DETOUR_SECTION_RECORD section;
+ if (!ReadProcessMemory(hProcess, pvSection, §ion, sizeof(section), NULL)) {
+ DETOUR_TRACE(("ReadProcessMemory(dsr@%p..%p) failed: %lu\n",
+ pvSection,
+ (PBYTE)pvSection + sizeof(section),
+ GetLastError()));
+ return NULL;
+ }
+
+ if (DetourAreSameGuid(section.guid, rguid)) {
+ if (pcbData) {
+ *pcbData = section.cbBytes - sizeof(section);
+ }
+ SetLastError(NO_ERROR);
+ return (DETOUR_SECTION_RECORD *)pvSection + 1;
+ }
+
+ pvSection = (PBYTE)pvSection + section.cbBytes;
+ }
+
+ return NULL;
+}
+
+_Success_(return != NULL)
+PVOID WINAPI DetourFindRemotePayload(_In_ HANDLE hProcess,
+ _In_ REFGUID rguid,
+ _Out_opt_ DWORD *pcbData)
+{
+ if (hProcess == NULL) {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return NULL;
+ }
+
+ IMAGE_NT_HEADERS32 header;
+ PVOID pvRemoteHeader;
+ for (HMODULE hMod = NULL; (hMod = EnumerateModulesInProcess(hProcess, hMod, &header, &pvRemoteHeader)) != NULL;) {
+ PVOID pvData = FindDetourSectionInRemoteModule(hProcess, hMod, &header, pvRemoteHeader);
+ if (pvData != NULL) {
+ pvData = FindPayloadInRemoteDetourSection(hProcess, rguid, pcbData, pvData);
+ if (pvData != NULL) {
+ return pvData;
+ }
+ }
+ }
+
+ SetLastError(ERROR_MOD_NOT_FOUND);
+ return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Find a region of memory in which we can create a replacement import table.
+//
+static PBYTE FindAndAllocateNearBase(HANDLE hProcess, PBYTE pbModule, PBYTE pbBase, DWORD cbAlloc)
+{
+ MEMORY_BASIC_INFORMATION mbi;
+ ZeroMemory(&mbi, sizeof(mbi));
+
+ PBYTE pbLast = pbBase;
+ for (;; pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) {
+
+ ZeroMemory(&mbi, sizeof(mbi));
+ if (VirtualQueryEx(hProcess, (PVOID)pbLast, &mbi, sizeof(mbi)) == 0) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ break;
+ }
+ DETOUR_TRACE(("VirtualQueryEx(%p) failed: %lu\n",
+ pbLast, GetLastError()));
+ break;
+ }
+ // Usermode address space has such an unaligned region size always at the
+ // end and only at the end.
+ //
+ if ((mbi.RegionSize & 0xfff) == 0xfff) {
+ break;
+ }
+
+ // Skip anything other than a pure free region.
+ //
+ if (mbi.State != MEM_FREE) {
+ continue;
+ }
+
+ // Use the max of mbi.BaseAddress and pbBase, in case mbi.BaseAddress < pbBase.
+ PBYTE pbAddress = (PBYTE)mbi.BaseAddress > pbBase ? (PBYTE)mbi.BaseAddress : pbBase;
+
+ // Round pbAddress up to the nearest MM allocation boundary.
+ const DWORD_PTR mmGranularityMinusOne = (DWORD_PTR)(MM_ALLOCATION_GRANULARITY -1);
+ pbAddress = (PBYTE)(((DWORD_PTR)pbAddress + mmGranularityMinusOne) & ~mmGranularityMinusOne);
+
+#ifdef _WIN64
+ // The offset from pbModule to any replacement import must fit into 32 bits.
+ // For simplicity, we check that the offset to the last byte fits into 32 bits,
+ // instead of the largest offset we'll actually use. The values are very similar.
+ const size_t GB4 = ((((size_t)1) << 32) - 1);
+ if ((size_t)(pbAddress + cbAlloc - 1 - pbModule) > GB4) {
+ DETOUR_TRACE(("FindAndAllocateNearBase(1) failing due to distance >4GB %p\n", pbAddress));
+ return NULL;
+ }
+#else
+ UNREFERENCED_PARAMETER(pbModule);
+#endif
+
+ DETOUR_TRACE(("Free region %p..%p\n",
+ mbi.BaseAddress,
+ (PBYTE)mbi.BaseAddress + mbi.RegionSize));
+
+ for (; pbAddress < (PBYTE)mbi.BaseAddress + mbi.RegionSize; pbAddress += MM_ALLOCATION_GRANULARITY) {
+ PBYTE pbAlloc = (PBYTE)VirtualAllocEx(hProcess, pbAddress, cbAlloc,
+ MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ if (pbAlloc == NULL) {
+ DETOUR_TRACE(("VirtualAllocEx(%p) failed: %lu\n", pbAddress, GetLastError()));
+ continue;
+ }
+#ifdef _WIN64
+ // The offset from pbModule to any replacement import must fit into 32 bits.
+ if ((size_t)(pbAddress + cbAlloc - 1 - pbModule) > GB4) {
+ DETOUR_TRACE(("FindAndAllocateNearBase(2) failing due to distance >4GB %p\n", pbAddress));
+ return NULL;
+ }
+#endif
+ DETOUR_TRACE(("[%p..%p] Allocated for import table.\n",
+ pbAlloc, pbAlloc + cbAlloc));
+ return pbAlloc;
+ }
+ }
+ return NULL;
+}
+
+static inline DWORD PadToDword(DWORD dw)
+{
+ return (dw + 3) & ~3u;
+}
+
+static inline DWORD PadToDwordPtr(DWORD dw)
+{
+ return (dw + 7) & ~7u;
+}
+
+static inline HRESULT ReplaceOptionalSizeA(_Inout_z_count_(cchDest) LPSTR pszDest,
+ _In_ size_t cchDest,
+ _In_z_ LPCSTR pszSize)
+{
+ if (cchDest == 0 || pszDest == NULL || pszSize == NULL ||
+ pszSize[0] == '\0' || pszSize[1] == '\0' || pszSize[2] != '\0') {
+
+ // can not write into empty buffer or with string other than two chars.
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ for (; cchDest >= 2; cchDest--, pszDest++) {
+ if (pszDest[0] == '?' && pszDest[1] == '?') {
+ pszDest[0] = pszSize[0];
+ pszDest[1] = pszSize[1];
+ break;
+ }
+ }
+
+ return S_OK;
+}
+
+static BOOL RecordExeRestore(HANDLE hProcess, HMODULE hModule, DETOUR_EXE_RESTORE& der)
+{
+ // Save the various headers for DetourRestoreAfterWith.
+ ZeroMemory(&der, sizeof(der));
+ der.cb = sizeof(der);
+
+ der.pidh = (PBYTE)hModule;
+ der.cbidh = sizeof(der.idh);
+ if (!ReadProcessMemory(hProcess, der.pidh, &der.idh, sizeof(der.idh), NULL)) {
+ DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n",
+ der.pidh, der.pidh + der.cbidh, GetLastError()));
+ return FALSE;
+ }
+ DETOUR_TRACE(("IDH: %p..%p\n", der.pidh, der.pidh + der.cbidh));
+
+ // We read the NT header in two passes to get the full size.
+ // First we read just the Signature and FileHeader.
+ der.pinh = der.pidh + der.idh.e_lfanew;
+ der.cbinh = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader);
+ if (!ReadProcessMemory(hProcess, der.pinh, &der.inh, der.cbinh, NULL)) {
+ DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n",
+ der.pinh, der.pinh + der.cbinh, GetLastError()));
+ return FALSE;
+ }
+
+ // Second we read the OptionalHeader and Section headers.
+ der.cbinh = (FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +
+ der.inh.FileHeader.SizeOfOptionalHeader +
+ der.inh.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER));
+
+ if (der.cbinh > sizeof(der.raw)) {
+ return FALSE;
+ }
+
+ if (!ReadProcessMemory(hProcess, der.pinh, &der.inh, der.cbinh, NULL)) {
+ DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n",
+ der.pinh, der.pinh + der.cbinh, GetLastError()));
+ return FALSE;
+ }
+ DETOUR_TRACE(("INH: %p..%p\n", der.pinh, der.pinh + der.cbinh));
+
+ // Third, we read the CLR header
+
+ if (der.inh.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ if (der.inh32.CLR_DIRECTORY.VirtualAddress != 0 &&
+ der.inh32.CLR_DIRECTORY.Size != 0) {
+
+ DETOUR_TRACE(("CLR32.VirtAddr=%08lx, CLR.Size=%lu\n",
+ der.inh32.CLR_DIRECTORY.VirtualAddress,
+ der.inh32.CLR_DIRECTORY.Size));
+
+ der.pclr = ((PBYTE)hModule) + der.inh32.CLR_DIRECTORY.VirtualAddress;
+ }
+ }
+ else if (der.inh.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ if (der.inh64.CLR_DIRECTORY.VirtualAddress != 0 &&
+ der.inh64.CLR_DIRECTORY.Size != 0) {
+
+ DETOUR_TRACE(("CLR64.VirtAddr=%08lx, CLR.Size=%lu\n",
+ der.inh64.CLR_DIRECTORY.VirtualAddress,
+ der.inh64.CLR_DIRECTORY.Size));
+
+ der.pclr = ((PBYTE)hModule) + der.inh64.CLR_DIRECTORY.VirtualAddress;
+ }
+ }
+
+ if (der.pclr != 0) {
+ der.cbclr = sizeof(der.clr);
+ if (!ReadProcessMemory(hProcess, der.pclr, &der.clr, der.cbclr, NULL)) {
+ DETOUR_TRACE(("ReadProcessMemory(clr@%p..%p) failed: %lu\n",
+ der.pclr, der.pclr + der.cbclr, GetLastError()));
+ return FALSE;
+ }
+ DETOUR_TRACE(("CLR: %p..%p\n", der.pclr, der.pclr + der.cbclr));
+ }
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+#if DETOURS_32BIT
+#define DWORD_XX DWORD32
+#define IMAGE_NT_HEADERS_XX IMAGE_NT_HEADERS32
+#define IMAGE_NT_OPTIONAL_HDR_MAGIC_XX IMAGE_NT_OPTIONAL_HDR32_MAGIC
+#define IMAGE_ORDINAL_FLAG_XX IMAGE_ORDINAL_FLAG32
+#define IMAGE_THUNK_DATAXX IMAGE_THUNK_DATA32
+#define UPDATE_IMPORTS_XX UpdateImports32
+#define DETOURS_BITS_XX 32
+#include "uimports.cpp"
+#undef DETOUR_EXE_RESTORE_FIELD_XX
+#undef DWORD_XX
+#undef IMAGE_NT_HEADERS_XX
+#undef IMAGE_NT_OPTIONAL_HDR_MAGIC_XX
+#undef IMAGE_ORDINAL_FLAG_XX
+#undef UPDATE_IMPORTS_XX
+#endif // DETOURS_32BIT
+
+#if DETOURS_64BIT
+#define DWORD_XX DWORD64
+#define IMAGE_NT_HEADERS_XX IMAGE_NT_HEADERS64
+#define IMAGE_NT_OPTIONAL_HDR_MAGIC_XX IMAGE_NT_OPTIONAL_HDR64_MAGIC
+#define IMAGE_ORDINAL_FLAG_XX IMAGE_ORDINAL_FLAG64
+#define IMAGE_THUNK_DATAXX IMAGE_THUNK_DATA64
+#define UPDATE_IMPORTS_XX UpdateImports64
+#define DETOURS_BITS_XX 64
+#include "uimports.cpp"
+#undef DETOUR_EXE_RESTORE_FIELD_XX
+#undef DWORD_XX
+#undef IMAGE_NT_HEADERS_XX
+#undef IMAGE_NT_OPTIONAL_HDR_MAGIC_XX
+#undef IMAGE_ORDINAL_FLAG_XX
+#undef UPDATE_IMPORTS_XX
+#endif // DETOURS_64BIT
+
+//////////////////////////////////////////////////////////////////////////////
+//
+#if DETOURS_64BIT
+
+C_ASSERT(sizeof(IMAGE_NT_HEADERS64) == sizeof(IMAGE_NT_HEADERS32) + 16);
+
+static BOOL UpdateFrom32To64(HANDLE hProcess, HMODULE hModule, WORD machine,
+ DETOUR_EXE_RESTORE& der)
+{
+ IMAGE_DOS_HEADER idh;
+ IMAGE_NT_HEADERS32 inh32;
+ IMAGE_NT_HEADERS64 inh64;
+ IMAGE_SECTION_HEADER sects[32];
+ PBYTE pbModule = (PBYTE)hModule;
+ DWORD n;
+
+ ZeroMemory(&inh32, sizeof(inh32));
+ ZeroMemory(&inh64, sizeof(inh64));
+ ZeroMemory(sects, sizeof(sects));
+
+ DETOUR_TRACE(("UpdateFrom32To64(%04x)\n", machine));
+ //////////////////////////////////////////////////////// Read old headers.
+ //
+ if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
+ DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n",
+ pbModule, pbModule + sizeof(idh), GetLastError()));
+ return FALSE;
+ }
+ DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p)\n",
+ pbModule, pbModule + sizeof(idh)));
+
+ PBYTE pnh = pbModule + idh.e_lfanew;
+ if (!ReadProcessMemory(hProcess, pnh, &inh32, sizeof(inh32), NULL)) {
+ DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n",
+ pnh, pnh + sizeof(inh32), GetLastError()));
+ return FALSE;
+ }
+ DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p)\n", pnh, pnh + sizeof(inh32)));
+
+ if (inh32.FileHeader.NumberOfSections > (sizeof(sects)/sizeof(sects[0]))) {
+ return FALSE;
+ }
+
+ PBYTE psects = pnh +
+ FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +
+ inh32.FileHeader.SizeOfOptionalHeader;
+ ULONG cb = inh32.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
+ if (!ReadProcessMemory(hProcess, psects, §s, cb, NULL)) {
+ DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %lu\n",
+ psects, psects + cb, GetLastError()));
+ return FALSE;
+ }
+ DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p)\n", psects, psects + cb));
+
+ ////////////////////////////////////////////////////////// Convert header.
+ //
+ inh64.Signature = inh32.Signature;
+ inh64.FileHeader = inh32.FileHeader;
+ inh64.FileHeader.Machine = machine;
+ inh64.FileHeader.SizeOfOptionalHeader = sizeof(IMAGE_OPTIONAL_HEADER64);
+
+ inh64.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
+ inh64.OptionalHeader.MajorLinkerVersion = inh32.OptionalHeader.MajorLinkerVersion;
+ inh64.OptionalHeader.MinorLinkerVersion = inh32.OptionalHeader.MinorLinkerVersion;
+ inh64.OptionalHeader.SizeOfCode = inh32.OptionalHeader.SizeOfCode;
+ inh64.OptionalHeader.SizeOfInitializedData = inh32.OptionalHeader.SizeOfInitializedData;
+ inh64.OptionalHeader.SizeOfUninitializedData = inh32.OptionalHeader.SizeOfUninitializedData;
+ inh64.OptionalHeader.AddressOfEntryPoint = inh32.OptionalHeader.AddressOfEntryPoint;
+ inh64.OptionalHeader.BaseOfCode = inh32.OptionalHeader.BaseOfCode;
+ inh64.OptionalHeader.ImageBase = inh32.OptionalHeader.ImageBase;
+ inh64.OptionalHeader.SectionAlignment = inh32.OptionalHeader.SectionAlignment;
+ inh64.OptionalHeader.FileAlignment = inh32.OptionalHeader.FileAlignment;
+ inh64.OptionalHeader.MajorOperatingSystemVersion
+ = inh32.OptionalHeader.MajorOperatingSystemVersion;
+ inh64.OptionalHeader.MinorOperatingSystemVersion
+ = inh32.OptionalHeader.MinorOperatingSystemVersion;
+ inh64.OptionalHeader.MajorImageVersion = inh32.OptionalHeader.MajorImageVersion;
+ inh64.OptionalHeader.MinorImageVersion = inh32.OptionalHeader.MinorImageVersion;
+ inh64.OptionalHeader.MajorSubsystemVersion = inh32.OptionalHeader.MajorSubsystemVersion;
+ inh64.OptionalHeader.MinorSubsystemVersion = inh32.OptionalHeader.MinorSubsystemVersion;
+ inh64.OptionalHeader.Win32VersionValue = inh32.OptionalHeader.Win32VersionValue;
+ inh64.OptionalHeader.SizeOfImage = inh32.OptionalHeader.SizeOfImage;
+ inh64.OptionalHeader.SizeOfHeaders = inh32.OptionalHeader.SizeOfHeaders;
+ inh64.OptionalHeader.CheckSum = inh32.OptionalHeader.CheckSum;
+ inh64.OptionalHeader.Subsystem = inh32.OptionalHeader.Subsystem;
+ inh64.OptionalHeader.DllCharacteristics = inh32.OptionalHeader.DllCharacteristics;
+ inh64.OptionalHeader.SizeOfStackReserve = inh32.OptionalHeader.SizeOfStackReserve;
+ inh64.OptionalHeader.SizeOfStackCommit = inh32.OptionalHeader.SizeOfStackCommit;
+ inh64.OptionalHeader.SizeOfHeapReserve = inh32.OptionalHeader.SizeOfHeapReserve;
+ inh64.OptionalHeader.SizeOfHeapCommit = inh32.OptionalHeader.SizeOfHeapCommit;
+ inh64.OptionalHeader.LoaderFlags = inh32.OptionalHeader.LoaderFlags;
+ inh64.OptionalHeader.NumberOfRvaAndSizes = inh32.OptionalHeader.NumberOfRvaAndSizes;
+ for (n = 0; n < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; n++) {
+ inh64.OptionalHeader.DataDirectory[n] = inh32.OptionalHeader.DataDirectory[n];
+ }
+
+ /////////////////////////////////////////////////////// Write new headers.
+ //
+ DWORD dwProtect = 0;
+ if (!DetourVirtualProtectSameExecuteEx(hProcess, pbModule, inh64.OptionalHeader.SizeOfHeaders,
+ PAGE_EXECUTE_READWRITE, &dwProtect)) {
+ return FALSE;
+ }
+
+ if (!WriteProcessMemory(hProcess, pnh, &inh64, sizeof(inh64), NULL)) {
+ DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p) failed: %lu\n",
+ pnh, pnh + sizeof(inh64), GetLastError()));
+ return FALSE;
+ }
+ DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p)\n", pnh, pnh + sizeof(inh64)));
+
+ psects = pnh +
+ FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +
+ inh64.FileHeader.SizeOfOptionalHeader;
+ cb = inh64.FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
+ if (!WriteProcessMemory(hProcess, psects, §s, cb, NULL)) {
+ DETOUR_TRACE(("WriteProcessMemory(ish@%p..%p) failed: %lu\n",
+ psects, psects + cb, GetLastError()));
+ return FALSE;
+ }
+ DETOUR_TRACE(("WriteProcessMemory(ish@%p..%p)\n", psects, psects + cb));
+
+ // Record the updated headers.
+ if (!RecordExeRestore(hProcess, hModule, der)) {
+ return FALSE;
+ }
+
+ // Remove the import table.
+ if (der.pclr != NULL && (der.clr.Flags & COMIMAGE_FLAGS_ILONLY)) {
+ inh64.IMPORT_DIRECTORY.VirtualAddress = 0;
+ inh64.IMPORT_DIRECTORY.Size = 0;
+
+ if (!WriteProcessMemory(hProcess, pnh, &inh64, sizeof(inh64), NULL)) {
+ DETOUR_TRACE(("WriteProcessMemory(inh@%p..%p) failed: %lu\n",
+ pnh, pnh + sizeof(inh64), GetLastError()));
+ return FALSE;
+ }
+ }
+
+ DWORD dwOld = 0;
+ if (!VirtualProtectEx(hProcess, pbModule, inh64.OptionalHeader.SizeOfHeaders,
+ dwProtect, &dwOld)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+#endif // DETOURS_64BIT
+
+typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
+
+static BOOL IsWow64ProcessHelper(HANDLE hProcess,
+ PBOOL Wow64Process)
+{
+#ifdef _X86_
+ if (Wow64Process == NULL) {
+ return FALSE;
+ }
+
+ // IsWow64Process is not available on all supported versions of Windows.
+ //
+ HMODULE hKernel32 = LoadLibraryW(L"KERNEL32.DLL");
+ if (hKernel32 == NULL) {
+ DETOUR_TRACE(("LoadLibraryW failed: %lu\n", GetLastError()));
+ return FALSE;
+ }
+
+ LPFN_ISWOW64PROCESS pfnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(
+ hKernel32, "IsWow64Process");
+
+ if (pfnIsWow64Process == NULL) {
+ DETOUR_TRACE(("GetProcAddress failed: %lu\n", GetLastError()));
+ return FALSE;
+ }
+ return pfnIsWow64Process(hProcess, Wow64Process);
+#else
+ return IsWow64Process(hProcess, Wow64Process);
+#endif
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess,
+ _In_reads_(nDlls) LPCSTR *rlpDlls,
+ _In_ DWORD nDlls)
+{
+ // Find the next memory region that contains a mapped PE image.
+ //
+ BOOL bIs32BitProcess;
+ BOOL bIs64BitOS = FALSE;
+ HMODULE hModule = NULL;
+ HMODULE hLast = NULL;
+
+ DETOUR_TRACE(("DetourUpdateProcessWithDll(%p,dlls=%lu)\n", hProcess, nDlls));
+
+ for (;;) {
+ IMAGE_NT_HEADERS32 inh;
+
+ if ((hLast = EnumerateModulesInProcess(hProcess, hLast, &inh, NULL)) == NULL) {
+ break;
+ }
+
+ DETOUR_TRACE(("%p machine=%04x magic=%04x\n",
+ hLast, inh.FileHeader.Machine, inh.OptionalHeader.Magic));
+
+ if ((inh.FileHeader.Characteristics & IMAGE_FILE_DLL) == 0) {
+ hModule = hLast;
+ DETOUR_TRACE(("%p Found EXE\n", hLast));
+ }
+ }
+
+ if (hModule == NULL) {
+ SetLastError(ERROR_INVALID_OPERATION);
+ return FALSE;
+ }
+
+ // Determine if the target process is 32bit or 64bit. This is a two-stop process:
+ //
+ // 1. First, determine if we're running on a 64bit operating system.
+ // - If we're running 64bit code (i.e. _WIN64 is defined), this is trivially true.
+ // - If we're running 32bit code (i.e. _WIN64 is not defined), test if
+ // we're running under Wow64. If so, it implies that the operating system
+ // is 64bit.
+ //
+#ifdef _WIN64
+ bIs64BitOS = TRUE;
+#else
+ if (!IsWow64ProcessHelper(GetCurrentProcess(), &bIs64BitOS)) {
+ return FALSE;
+ }
+#endif
+
+ // 2. With the operating system bitness known, we can now consider the target process:
+ // - If we're running on a 64bit OS, the target process is 32bit in case
+ // it is running under Wow64. Otherwise, it's 64bit, running natively
+ // (without Wow64).
+ // - If we're running on a 32bit OS, the target process must be 32bit, too.
+ //
+ if (bIs64BitOS) {
+ if (!IsWow64ProcessHelper(hProcess, &bIs32BitProcess)) {
+ return FALSE;
+ }
+ } else {
+ bIs32BitProcess = TRUE;
+ }
+
+ DETOUR_TRACE((" 32BitProcess=%d\n", bIs32BitProcess));
+
+ return DetourUpdateProcessWithDllEx(hProcess,
+ hModule,
+ bIs32BitProcess,
+ rlpDlls,
+ nDlls);
+}
+
+BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess,
+ _In_ HMODULE hModule,
+ _In_ BOOL bIs32BitProcess,
+ _In_reads_(nDlls) LPCSTR *rlpDlls,
+ _In_ DWORD nDlls)
+{
+ // Find the next memory region that contains a mapped PE image.
+ //
+ BOOL bIs32BitExe = FALSE;
+
+ DETOUR_TRACE(("DetourUpdateProcessWithDllEx(%p,%p,dlls=%lu)\n", hProcess, hModule, nDlls));
+
+ IMAGE_NT_HEADERS32 inh;
+
+ if (hModule == NULL || !LoadNtHeaderFromProcess(hProcess, hModule, &inh)) {
+ SetLastError(ERROR_INVALID_OPERATION);
+ return FALSE;
+ }
+
+ if (inh.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
+ && inh.FileHeader.Machine != 0) {
+
+ bIs32BitExe = TRUE;
+ }
+
+ DETOUR_TRACE((" 32BitExe=%d\n", bIs32BitExe));
+
+ if (hModule == NULL) {
+ SetLastError(ERROR_INVALID_OPERATION);
+ return FALSE;
+ }
+
+ // Save the various headers for DetourRestoreAfterWith.
+ //
+ DETOUR_EXE_RESTORE der;
+
+ if (!RecordExeRestore(hProcess, hModule, der)) {
+ return FALSE;
+ }
+
+#if defined(DETOURS_64BIT)
+ // Try to convert a neutral 32-bit managed binary to a 64-bit managed binary.
+ if (bIs32BitExe && !bIs32BitProcess) {
+ if (!der.pclr // Native binary
+ || (der.clr.Flags & COMIMAGE_FLAGS_ILONLY) == 0 // Or mixed-mode MSIL
+ || (der.clr.Flags & COMIMAGE_FLAGS_32BITREQUIRED) != 0) { // Or 32BIT Required MSIL
+
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ if (!UpdateFrom32To64(hProcess, hModule,
+#if defined(DETOURS_X64)
+ IMAGE_FILE_MACHINE_AMD64,
+#elif defined(DETOURS_IA64)
+ IMAGE_FILE_MACHINE_IA64,
+#elif defined(DETOURS_ARM64)
+ IMAGE_FILE_MACHINE_ARM64,
+#else
+#error Must define one of DETOURS_X64 or DETOURS_IA64 or DETOURS_ARM64 on 64-bit.
+#endif
+ der)) {
+ return FALSE;
+ }
+ bIs32BitExe = FALSE;
+ }
+#endif // DETOURS_64BIT
+
+ // Now decide if we can insert the detour.
+
+#if defined(DETOURS_32BIT)
+ if (bIs32BitProcess) {
+ // 32-bit native or 32-bit managed process on any platform.
+ if (!UpdateImports32(hProcess, hModule, rlpDlls, nDlls)) {
+ return FALSE;
+ }
+ }
+ else {
+ // 64-bit native or 64-bit managed process.
+ //
+ // Can't detour a 64-bit process with 32-bit code.
+ // Note: This happens for 32-bit PE binaries containing only
+ // manage code that have been marked as 64-bit ready.
+ //
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+#elif defined(DETOURS_64BIT)
+ if (bIs32BitProcess || bIs32BitExe) {
+ // Can't detour a 32-bit process with 64-bit code.
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ else {
+ // 64-bit native or 64-bit managed process on any platform.
+ if (!UpdateImports64(hProcess, hModule, rlpDlls, nDlls)) {
+ return FALSE;
+ }
+ }
+#else
+#pragma Must define one of DETOURS_32BIT or DETOURS_64BIT.
+#endif // DETOURS_64BIT
+
+ /////////////////////////////////////////////////// Update the CLR header.
+ //
+ if (der.pclr != NULL) {
+ DETOUR_CLR_HEADER clr;
+ CopyMemory(&clr, &der.clr, sizeof(clr));
+ clr.Flags &= ~COMIMAGE_FLAGS_ILONLY; // Clear the IL_ONLY flag.
+
+ DWORD dwProtect;
+ if (!DetourVirtualProtectSameExecuteEx(hProcess, der.pclr, sizeof(clr), PAGE_READWRITE, &dwProtect)) {
+ DETOUR_TRACE(("VirtualProtectEx(clr) write failed: %lu\n", GetLastError()));
+ return FALSE;
+ }
+
+ if (!WriteProcessMemory(hProcess, der.pclr, &clr, sizeof(clr), NULL)) {
+ DETOUR_TRACE(("WriteProcessMemory(clr) failed: %lu\n", GetLastError()));
+ return FALSE;
+ }
+
+ if (!VirtualProtectEx(hProcess, der.pclr, sizeof(clr), dwProtect, &dwProtect)) {
+ DETOUR_TRACE(("VirtualProtectEx(clr) restore failed: %lu\n", GetLastError()));
+ return FALSE;
+ }
+ DETOUR_TRACE(("CLR: %p..%p\n", der.pclr, der.pclr + der.cbclr));
+
+#if DETOURS_64BIT
+ if (der.clr.Flags & COMIMAGE_FLAGS_32BITREQUIRED) { // Is the 32BIT Required Flag set?
+ // X64 never gets here because the process appears as a WOW64 process.
+ // However, on IA64, it doesn't appear to be a WOW process.
+ DETOUR_TRACE(("CLR Requires 32-bit\n"));
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+#endif // DETOURS_64BIT
+ }
+
+ //////////////////////////////// Save the undo data to the target process.
+ //
+ if (!DetourCopyPayloadToProcess(hProcess, DETOUR_EXE_RESTORE_GUID, &der, sizeof(der))) {
+ DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %lu\n", GetLastError()));
+ return FALSE;
+ }
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+BOOL WINAPI DetourCreateProcessWithDllA(_In_opt_ LPCSTR lpApplicationName,
+ _Inout_opt_ LPSTR lpCommandLine,
+ _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ _In_ BOOL bInheritHandles,
+ _In_ DWORD dwCreationFlags,
+ _In_opt_ LPVOID lpEnvironment,
+ _In_opt_ LPCSTR lpCurrentDirectory,
+ _In_ LPSTARTUPINFOA lpStartupInfo,
+ _Out_ LPPROCESS_INFORMATION lpProcessInformation,
+ _In_ LPCSTR lpDllName,
+ _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA)
+{
+ DWORD dwMyCreationFlags = (dwCreationFlags | CREATE_SUSPENDED);
+ PROCESS_INFORMATION pi;
+ BOOL fResult = FALSE;
+
+ if (pfCreateProcessA == NULL) {
+ pfCreateProcessA = CreateProcessA;
+ }
+
+ fResult = pfCreateProcessA(lpApplicationName,
+ lpCommandLine,
+ lpProcessAttributes,
+ lpThreadAttributes,
+ bInheritHandles,
+ dwMyCreationFlags,
+ lpEnvironment,
+ lpCurrentDirectory,
+ lpStartupInfo,
+ &pi);
+
+ if (lpProcessInformation != NULL) {
+ CopyMemory(lpProcessInformation, &pi, sizeof(pi));
+ }
+
+ if (!fResult) {
+ return FALSE;
+ }
+
+ LPCSTR rlpDlls[2];
+ DWORD nDlls = 0;
+ if (lpDllName != NULL) {
+ rlpDlls[nDlls++] = lpDllName;
+ }
+
+ if (!DetourUpdateProcessWithDll(pi.hProcess, rlpDlls, nDlls)) {
+ TerminateProcess(pi.hProcess, ~0u);
+ return FALSE;
+ }
+
+ if (!(dwCreationFlags & CREATE_SUSPENDED)) {
+ ResumeThread(pi.hThread);
+ }
+ return TRUE;
+}
+
+
+BOOL WINAPI DetourCreateProcessWithDllW(_In_opt_ LPCWSTR lpApplicationName,
+ _Inout_opt_ LPWSTR lpCommandLine,
+ _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ _In_ BOOL bInheritHandles,
+ _In_ DWORD dwCreationFlags,
+ _In_opt_ LPVOID lpEnvironment,
+ _In_opt_ LPCWSTR lpCurrentDirectory,
+ _In_ LPSTARTUPINFOW lpStartupInfo,
+ _Out_ LPPROCESS_INFORMATION lpProcessInformation,
+ _In_ LPCSTR lpDllName,
+ _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW)
+{
+ DWORD dwMyCreationFlags = (dwCreationFlags | CREATE_SUSPENDED);
+ PROCESS_INFORMATION pi;
+
+ if (pfCreateProcessW == NULL) {
+ pfCreateProcessW = CreateProcessW;
+ }
+
+ BOOL fResult = pfCreateProcessW(lpApplicationName,
+ lpCommandLine,
+ lpProcessAttributes,
+ lpThreadAttributes,
+ bInheritHandles,
+ dwMyCreationFlags,
+ lpEnvironment,
+ lpCurrentDirectory,
+ lpStartupInfo,
+ &pi);
+
+ if (lpProcessInformation) {
+ CopyMemory(lpProcessInformation, &pi, sizeof(pi));
+ }
+
+ if (!fResult) {
+ return FALSE;
+ }
+
+ LPCSTR rlpDlls[2];
+ DWORD nDlls = 0;
+ if (lpDllName != NULL) {
+ rlpDlls[nDlls++] = lpDllName;
+ }
+
+ if (!DetourUpdateProcessWithDll(pi.hProcess, rlpDlls, nDlls)) {
+ TerminateProcess(pi.hProcess, ~0u);
+ return FALSE;
+ }
+
+ if (!(dwCreationFlags & CREATE_SUSPENDED)) {
+ ResumeThread(pi.hThread);
+ }
+ return TRUE;
+}
+
+BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess,
+ _In_ REFGUID rguid,
+ _In_reads_bytes_(cbData) LPCVOID pvData,
+ _In_ DWORD cbData)
+{
+ return DetourCopyPayloadToProcessEx(hProcess, rguid, pvData, cbData) != NULL;
+}
+
+_Success_(return != NULL)
+PVOID WINAPI DetourCopyPayloadToProcessEx(_In_ HANDLE hProcess,
+ _In_ REFGUID rguid,
+ _In_reads_bytes_(cbData) LPCVOID pvData,
+ _In_ DWORD cbData)
+{
+ if (hProcess == NULL) {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return NULL;
+ }
+
+ DWORD cbTotal = (sizeof(IMAGE_DOS_HEADER) +
+ sizeof(IMAGE_NT_HEADERS) +
+ sizeof(IMAGE_SECTION_HEADER) +
+ sizeof(DETOUR_SECTION_HEADER) +
+ sizeof(DETOUR_SECTION_RECORD) +
+ cbData);
+
+ PBYTE pbBase = (PBYTE)VirtualAllocEx(hProcess, NULL, cbTotal,
+ MEM_COMMIT, PAGE_READWRITE);
+ if (pbBase == NULL) {
+ DETOUR_TRACE(("VirtualAllocEx(%lu) failed: %lu\n", cbTotal, GetLastError()));
+ return NULL;
+ }
+
+ // As you can see in the following code,
+ // the memory layout of the payload range "[pbBase, pbBase+cbTotal]" is a PE executable file,
+ // so DetourFreePayload can use "DetourGetContainingModule(Payload pointer)" to get the above "pbBase" pointer,
+ // pbBase: the memory block allocated by VirtualAllocEx will be released in DetourFreePayload by VirtualFree.
+
+ PBYTE pbTarget = pbBase;
+ IMAGE_DOS_HEADER idh;
+ IMAGE_NT_HEADERS inh;
+ IMAGE_SECTION_HEADER ish;
+ DETOUR_SECTION_HEADER dsh;
+ DETOUR_SECTION_RECORD dsr;
+ SIZE_T cbWrote = 0;
+
+ ZeroMemory(&idh, sizeof(idh));
+ idh.e_magic = IMAGE_DOS_SIGNATURE;
+ idh.e_lfanew = sizeof(idh);
+ if (!WriteProcessMemory(hProcess, pbTarget, &idh, sizeof(idh), &cbWrote) ||
+ cbWrote != sizeof(idh)) {
+ DETOUR_TRACE(("WriteProcessMemory(idh) failed: %lu\n", GetLastError()));
+ return NULL;
+ }
+ pbTarget += sizeof(idh);
+
+ ZeroMemory(&inh, sizeof(inh));
+ inh.Signature = IMAGE_NT_SIGNATURE;
+ inh.FileHeader.SizeOfOptionalHeader = sizeof(inh.OptionalHeader);
+ inh.FileHeader.Characteristics = IMAGE_FILE_DLL;
+ inh.FileHeader.NumberOfSections = 1;
+ inh.OptionalHeader.Magic = IMAGE_NT_OPTIONAL_HDR_MAGIC;
+ if (!WriteProcessMemory(hProcess, pbTarget, &inh, sizeof(inh), &cbWrote) ||
+ cbWrote != sizeof(inh)) {
+ return NULL;
+ }
+ pbTarget += sizeof(inh);
+
+ ZeroMemory(&ish, sizeof(ish));
+ memcpy(ish.Name, ".detour", sizeof(ish.Name));
+ ish.VirtualAddress = (DWORD)((pbTarget + sizeof(ish)) - pbBase);
+ ish.SizeOfRawData = (sizeof(DETOUR_SECTION_HEADER) +
+ sizeof(DETOUR_SECTION_RECORD) +
+ cbData);
+ if (!WriteProcessMemory(hProcess, pbTarget, &ish, sizeof(ish), &cbWrote) ||
+ cbWrote != sizeof(ish)) {
+ return NULL;
+ }
+ pbTarget += sizeof(ish);
+
+ ZeroMemory(&dsh, sizeof(dsh));
+ dsh.cbHeaderSize = sizeof(dsh);
+ dsh.nSignature = DETOUR_SECTION_HEADER_SIGNATURE;
+ dsh.nDataOffset = sizeof(DETOUR_SECTION_HEADER);
+ dsh.cbDataSize = (sizeof(DETOUR_SECTION_HEADER) +
+ sizeof(DETOUR_SECTION_RECORD) +
+ cbData);
+ if (!WriteProcessMemory(hProcess, pbTarget, &dsh, sizeof(dsh), &cbWrote) ||
+ cbWrote != sizeof(dsh)) {
+ return NULL;
+ }
+ pbTarget += sizeof(dsh);
+
+ ZeroMemory(&dsr, sizeof(dsr));
+ dsr.cbBytes = cbData + sizeof(DETOUR_SECTION_RECORD);
+ dsr.nReserved = 0;
+ dsr.guid = rguid;
+ if (!WriteProcessMemory(hProcess, pbTarget, &dsr, sizeof(dsr), &cbWrote) ||
+ cbWrote != sizeof(dsr)) {
+ return NULL;
+ }
+ pbTarget += sizeof(dsr);
+
+ if (!WriteProcessMemory(hProcess, pbTarget, pvData, cbData, &cbWrote) ||
+ cbWrote != cbData) {
+ return NULL;
+ }
+
+ DETOUR_TRACE(("Copied %lu byte payload into target process at %p\n",
+ cbData, pbTarget));
+
+ SetLastError(NO_ERROR);
+ return pbTarget;
+}
+
+static BOOL s_fSearchedForHelper = FALSE;
+static PDETOUR_EXE_HELPER s_pHelper = NULL;
+
+VOID CALLBACK DetourFinishHelperProcess(_In_ HWND,
+ _In_ HINSTANCE,
+ _In_ LPSTR,
+ _In_ INT)
+{
+ LPCSTR * rlpDlls = NULL;
+ DWORD Result = 9900;
+ DWORD cOffset = 0;
+ DWORD cSize = 0;
+ HANDLE hProcess = NULL;
+
+ if (s_pHelper == NULL) {
+ DETOUR_TRACE(("DetourFinishHelperProcess called with s_pHelper = NULL.\n"));
+ Result = 9905;
+ goto Cleanup;
+ }
+
+ hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, s_pHelper->pid);
+ if (hProcess == NULL) {
+ DETOUR_TRACE(("OpenProcess(pid=%lu) failed: %lu\n",
+ s_pHelper->pid, GetLastError()));
+ Result = 9901;
+ goto Cleanup;
+ }
+
+ rlpDlls = new NOTHROW LPCSTR [s_pHelper->nDlls];
+ cSize = s_pHelper->cb - sizeof(DETOUR_EXE_HELPER);
+ for (DWORD n = 0; n < s_pHelper->nDlls; n++) {
+ size_t cchDest = 0;
+ HRESULT hr = StringCchLengthA(&s_pHelper->rDlls[cOffset], cSize - cOffset, &cchDest);
+ if (!SUCCEEDED(hr)) {
+ Result = 9902;
+ goto Cleanup;
+ }
+
+ rlpDlls[n] = &s_pHelper->rDlls[cOffset];
+ cOffset += (DWORD)cchDest + 1;
+ }
+
+ if (!DetourUpdateProcessWithDll(hProcess, rlpDlls, s_pHelper->nDlls)) {
+ DETOUR_TRACE(("DetourUpdateProcessWithDll(pid=%lu) failed: %lu\n",
+ s_pHelper->pid, GetLastError()));
+ Result = 9903;
+ goto Cleanup;
+ }
+ Result = 0;
+
+ Cleanup:
+ if (rlpDlls != NULL) {
+ delete[] rlpDlls;
+ rlpDlls = NULL;
+ }
+
+ // Note: s_pHelper is allocated as part of injecting the payload in DetourCopyPayloadToProcess(..),
+ // it's a fake section and not data allocated by the system PE loader.
+
+ // Delete the payload after execution to release the memory occupied by it
+ if (s_pHelper != NULL) {
+ DetourFreePayload(s_pHelper);
+ s_pHelper = NULL;
+ }
+
+ ExitProcess(Result);
+}
+
+BOOL WINAPI DetourIsHelperProcess(VOID)
+{
+ PVOID pvData;
+ DWORD cbData;
+
+ if (s_fSearchedForHelper) {
+ return (s_pHelper != NULL);
+ }
+
+ s_fSearchedForHelper = TRUE;
+ pvData = DetourFindPayloadEx(DETOUR_EXE_HELPER_GUID, &cbData);
+
+ if (pvData == NULL || cbData < sizeof(DETOUR_EXE_HELPER)) {
+ return FALSE;
+ }
+
+ s_pHelper = (PDETOUR_EXE_HELPER)pvData;
+ if (s_pHelper->cb < sizeof(*s_pHelper)) {
+ s_pHelper = NULL;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static
+BOOL WINAPI AllocExeHelper(_Out_ PDETOUR_EXE_HELPER *pHelper,
+ _In_ DWORD dwTargetPid,
+ _In_ DWORD nDlls,
+ _In_reads_(nDlls) LPCSTR *rlpDlls)
+{
+ PDETOUR_EXE_HELPER Helper = NULL;
+ BOOL Result = FALSE;
+ _Field_range_(0, cSize - 4) DWORD cOffset = 0;
+ DWORD cSize = 4;
+
+ if (pHelper == NULL) {
+ goto Cleanup;
+ }
+ *pHelper = NULL;
+
+ if (nDlls < 1 || nDlls > 4096) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto Cleanup;
+ }
+
+ for (DWORD n = 0; n < nDlls; n++) {
+ HRESULT hr;
+ size_t cchDest = 0;
+
+ hr = StringCchLengthA(rlpDlls[n], 4096, &cchDest);
+ if (!SUCCEEDED(hr)) {
+ goto Cleanup;
+ }
+
+ cSize += (DWORD)cchDest + 1;
+ }
+
+ Helper = (PDETOUR_EXE_HELPER) new NOTHROW BYTE[sizeof(DETOUR_EXE_HELPER) + cSize];
+ if (Helper == NULL) {
+ goto Cleanup;
+ }
+
+ Helper->cb = sizeof(DETOUR_EXE_HELPER) + cSize;
+ Helper->pid = dwTargetPid;
+ Helper->nDlls = nDlls;
+
+ for (DWORD n = 0; n < nDlls; n++) {
+ HRESULT hr;
+ size_t cchDest = 0;
+
+ if (cOffset > 0x10000 || cSize > 0x10000 || cOffset + 2 >= cSize) {
+ goto Cleanup;
+ }
+
+ if (cOffset + 2 >= cSize || cOffset + 65536 < cSize) {
+ goto Cleanup;
+ }
+
+ _Analysis_assume_(cOffset + 1 < cSize);
+ _Analysis_assume_(cOffset < 0x10000);
+ _Analysis_assume_(cSize < 0x10000);
+
+ PCHAR psz = &Helper->rDlls[cOffset];
+
+ hr = StringCchCopyA(psz, cSize - cOffset, rlpDlls[n]);
+ if (!SUCCEEDED(hr)) {
+ goto Cleanup;
+ }
+
+// REVIEW 28020 The expression '1<=_Param_(2)& &_Param_(2)<=2147483647' is not true at this call.
+// REVIEW 28313 Analysis will not proceed past this point because of annotation evaluation. The annotation expression *_Param_(3)<_Param_(2)&&*_Param_(3)<=stringLength$(_Param_(1)) cannot be true under any assumptions at this point in the program.
+#pragma warning(suppress:28020 28313)
+ hr = StringCchLengthA(psz, cSize - cOffset, &cchDest);
+ if (!SUCCEEDED(hr)) {
+ goto Cleanup;
+ }
+
+ // Replace "32." with "64." or "64." with "32."
+
+ for (DWORD c = (DWORD)cchDest + 1; c > 3; c--) {
+#if DETOURS_32BIT
+ if (psz[c - 3] == '3' && psz[c - 2] == '2' && psz[c - 1] == '.') {
+ psz[c - 3] = '6'; psz[c - 2] = '4';
+ break;
+ }
+#else
+ if (psz[c - 3] == '6' && psz[c - 2] == '4' && psz[c - 1] == '.') {
+ psz[c - 3] = '3'; psz[c - 2] = '2';
+ break;
+ }
+#endif
+ }
+
+ cOffset += (DWORD)cchDest + 1;
+ }
+
+ *pHelper = Helper;
+ Helper = NULL;
+ Result = TRUE;
+
+ Cleanup:
+ if (Helper != NULL) {
+ delete[] (PBYTE)Helper;
+ Helper = NULL;
+ }
+ return Result;
+}
+
+static
+VOID WINAPI FreeExeHelper(PDETOUR_EXE_HELPER *pHelper)
+{
+ if (*pHelper != NULL) {
+ delete[] (PBYTE)*pHelper;
+ *pHelper = NULL;
+ }
+}
+
+BOOL WINAPI DetourProcessViaHelperA(_In_ DWORD dwTargetPid,
+ _In_ LPCSTR lpDllName,
+ _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA)
+{
+ return DetourProcessViaHelperDllsA(dwTargetPid, 1, &lpDllName, pfCreateProcessA);
+}
+
+
+BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid,
+ _In_ DWORD nDlls,
+ _In_reads_(nDlls) LPCSTR *rlpDlls,
+ _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA)
+{
+ BOOL Result = FALSE;
+ PROCESS_INFORMATION pi;
+ STARTUPINFOA si;
+ CHAR szExe[MAX_PATH];
+ CHAR szCommand[MAX_PATH];
+ PDETOUR_EXE_HELPER helper = NULL;
+ HRESULT hr;
+ DWORD nLen = GetEnvironmentVariableA("WINDIR", szExe, ARRAYSIZE(szExe));
+
+ DETOUR_TRACE(("DetourProcessViaHelperDlls(pid=%lu,dlls=%lu)\n", dwTargetPid, nDlls));
+ if (nDlls < 1 || nDlls > 4096) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto Cleanup;
+ }
+ if (!AllocExeHelper(&helper, dwTargetPid, nDlls, rlpDlls)) {
+ goto Cleanup;
+ }
+
+ if (nLen == 0 || nLen >= ARRAYSIZE(szExe)) {
+ goto Cleanup;
+ }
+
+#if DETOURS_OPTION_BITS
+#if DETOURS_32BIT
+ hr = StringCchCatA(szExe, ARRAYSIZE(szExe), "\\sysnative\\rundll32.exe");
+#else // !DETOURS_32BIT
+ hr = StringCchCatA(szExe, ARRAYSIZE(szExe), "\\syswow64\\rundll32.exe");
+#endif // !DETOURS_32BIT
+#else // DETOURS_OPTIONS_BITS
+ hr = StringCchCatA(szExe, ARRAYSIZE(szExe), "\\system32\\rundll32.exe");
+#endif // DETOURS_OPTIONS_BITS
+ if (!SUCCEEDED(hr)) {
+ goto Cleanup;
+ }
+
+ //for East Asia languages and so on, like Chinese, print format with "%hs" can not work fine before user call _tsetlocale(LC_ALL,_T(".ACP"));
+ //so we can't use "%hs" in format string, because the dll that contain this code would inject to any process, even not call _tsetlocale(LC_ALL,_T(".ACP")) before
+ hr = StringCchPrintfA(szCommand, ARRAYSIZE(szCommand),
+ "rundll32.exe \"%s\",#1", &helper->rDlls[0]);
+ if (!SUCCEEDED(hr)) {
+ goto Cleanup;
+ }
+
+ ZeroMemory(&pi, sizeof(pi));
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+
+ DETOUR_TRACE(("DetourProcessViaHelperDlls(\"%hs\", \"%hs\")\n", szExe, szCommand));
+ if (pfCreateProcessA(szExe, szCommand, NULL, NULL, FALSE, CREATE_SUSPENDED,
+ NULL, NULL, &si, &pi)) {
+
+ if (!DetourCopyPayloadToProcess(pi.hProcess,
+ DETOUR_EXE_HELPER_GUID,
+ helper, helper->cb)) {
+ DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %lu\n", GetLastError()));
+ TerminateProcess(pi.hProcess, ~0u);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ goto Cleanup;
+ }
+
+ ResumeThread(pi.hThread);
+ WaitForSingleObject(pi.hProcess, INFINITE);
+
+ DWORD dwResult = 500;
+ GetExitCodeProcess(pi.hProcess, &dwResult);
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+
+ if (dwResult != 0) {
+ DETOUR_TRACE(("Rundll32.exe failed: result=%lu\n", dwResult));
+ goto Cleanup;
+ }
+ Result = TRUE;
+ }
+ else {
+ DETOUR_TRACE(("CreateProcess failed: %lu\n", GetLastError()));
+ goto Cleanup;
+ }
+
+ Cleanup:
+ FreeExeHelper(&helper);
+ return Result;
+}
+
+BOOL WINAPI DetourProcessViaHelperW(_In_ DWORD dwTargetPid,
+ _In_ LPCSTR lpDllName,
+ _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW)
+{
+ return DetourProcessViaHelperDllsW(dwTargetPid, 1, &lpDllName, pfCreateProcessW);
+}
+
+BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid,
+ _In_ DWORD nDlls,
+ _In_reads_(nDlls) LPCSTR *rlpDlls,
+ _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW)
+{
+ BOOL Result = FALSE;
+ PROCESS_INFORMATION pi;
+ STARTUPINFOW si;
+ WCHAR szExe[MAX_PATH];
+ WCHAR szCommand[MAX_PATH];
+ PDETOUR_EXE_HELPER helper = NULL;
+ HRESULT hr;
+ WCHAR szDllName[MAX_PATH];
+ int cchWrittenWideChar;
+ DWORD nLen = GetEnvironmentVariableW(L"WINDIR", szExe, ARRAYSIZE(szExe));
+
+ DETOUR_TRACE(("DetourProcessViaHelperDlls(pid=%lu,dlls=%lu)\n", dwTargetPid, nDlls));
+ if (nDlls < 1 || nDlls > 4096) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto Cleanup;
+ }
+ if (!AllocExeHelper(&helper, dwTargetPid, nDlls, rlpDlls)) {
+ goto Cleanup;
+ }
+
+ if (nLen == 0 || nLen >= ARRAYSIZE(szExe)) {
+ goto Cleanup;
+ }
+
+#if DETOURS_OPTION_BITS
+#if DETOURS_32BIT
+ hr = StringCchCatW(szExe, ARRAYSIZE(szExe), L"\\sysnative\\rundll32.exe");
+#else // !DETOURS_32BIT
+ hr = StringCchCatW(szExe, ARRAYSIZE(szExe), L"\\syswow64\\rundll32.exe");
+#endif // !DETOURS_32BIT
+#else // DETOURS_OPTIONS_BITS
+ hr = StringCchCatW(szExe, ARRAYSIZE(szExe), L"\\system32\\rundll32.exe");
+#endif // DETOURS_OPTIONS_BITS
+ if (!SUCCEEDED(hr)) {
+ goto Cleanup;
+ }
+
+ //for East Asia languages and so on, like Chinese, print format with "%hs" can not work fine before user call _tsetlocale(LC_ALL,_T(".ACP"));
+ //so we can't use "%hs" in format string, because the dll that contain this code would inject to any process, even not call _tsetlocale(LC_ALL,_T(".ACP")) before
+
+ cchWrittenWideChar = MultiByteToWideChar(CP_ACP, 0, &helper->rDlls[0], -1, szDllName, ARRAYSIZE(szDllName));
+ if (cchWrittenWideChar >= ARRAYSIZE(szDllName) || cchWrittenWideChar <= 0) {
+ goto Cleanup;
+ }
+ hr = StringCchPrintfW(szCommand, ARRAYSIZE(szCommand),
+ L"rundll32.exe \"%s\",#1", szDllName);
+ if (!SUCCEEDED(hr)) {
+ goto Cleanup;
+ }
+
+ ZeroMemory(&pi, sizeof(pi));
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+
+ DETOUR_TRACE(("DetourProcessViaHelperDlls(\"%ls\", \"%ls\")\n", szExe, szCommand));
+ if (pfCreateProcessW(szExe, szCommand, NULL, NULL, FALSE, CREATE_SUSPENDED,
+ NULL, NULL, &si, &pi)) {
+
+ if (!DetourCopyPayloadToProcess(pi.hProcess,
+ DETOUR_EXE_HELPER_GUID,
+ helper, helper->cb)) {
+ DETOUR_TRACE(("DetourCopyPayloadToProcess failed: %lu\n", GetLastError()));
+ TerminateProcess(pi.hProcess, ~0u);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ goto Cleanup;
+ }
+
+ ResumeThread(pi.hThread);
+ WaitForSingleObject(pi.hProcess, INFINITE);
+
+ DWORD dwResult = 500;
+ GetExitCodeProcess(pi.hProcess, &dwResult);
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+
+ if (dwResult != 0) {
+ DETOUR_TRACE(("Rundll32.exe failed: result=%lu\n", dwResult));
+ goto Cleanup;
+ }
+ Result = TRUE;
+ }
+ else {
+ DETOUR_TRACE(("CreateProcess failed: %lu\n", GetLastError()));
+ goto Cleanup;
+ }
+
+ Cleanup:
+ FreeExeHelper(&helper);
+ return Result;
+}
+
+BOOL WINAPI DetourCreateProcessWithDllExA(_In_opt_ LPCSTR lpApplicationName,
+ _Inout_opt_ LPSTR lpCommandLine,
+ _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ _In_ BOOL bInheritHandles,
+ _In_ DWORD dwCreationFlags,
+ _In_opt_ LPVOID lpEnvironment,
+ _In_opt_ LPCSTR lpCurrentDirectory,
+ _In_ LPSTARTUPINFOA lpStartupInfo,
+ _Out_ LPPROCESS_INFORMATION lpProcessInformation,
+ _In_ LPCSTR lpDllName,
+ _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA)
+{
+ if (pfCreateProcessA == NULL) {
+ pfCreateProcessA = CreateProcessA;
+ }
+
+ PROCESS_INFORMATION backup;
+ if (lpProcessInformation == NULL) {
+ lpProcessInformation = &backup;
+ ZeroMemory(&backup, sizeof(backup));
+ }
+
+ if (!pfCreateProcessA(lpApplicationName,
+ lpCommandLine,
+ lpProcessAttributes,
+ lpThreadAttributes,
+ bInheritHandles,
+ dwCreationFlags | CREATE_SUSPENDED,
+ lpEnvironment,
+ lpCurrentDirectory,
+ lpStartupInfo,
+ lpProcessInformation)) {
+ return FALSE;
+ }
+
+ LPCSTR szDll = lpDllName;
+
+ if (!DetourUpdateProcessWithDll(lpProcessInformation->hProcess, &szDll, 1) &&
+ !DetourProcessViaHelperA(lpProcessInformation->dwProcessId,
+ lpDllName,
+ pfCreateProcessA)) {
+
+ TerminateProcess(lpProcessInformation->hProcess, ~0u);
+ CloseHandle(lpProcessInformation->hProcess);
+ CloseHandle(lpProcessInformation->hThread);
+ return FALSE;
+ }
+
+ if (!(dwCreationFlags & CREATE_SUSPENDED)) {
+ ResumeThread(lpProcessInformation->hThread);
+ }
+
+ if (lpProcessInformation == &backup) {
+ CloseHandle(lpProcessInformation->hProcess);
+ CloseHandle(lpProcessInformation->hThread);
+ }
+
+ return TRUE;
+}
+
+BOOL WINAPI DetourCreateProcessWithDllExW(_In_opt_ LPCWSTR lpApplicationName,
+ _Inout_opt_ LPWSTR lpCommandLine,
+ _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ _In_ BOOL bInheritHandles,
+ _In_ DWORD dwCreationFlags,
+ _In_opt_ LPVOID lpEnvironment,
+ _In_opt_ LPCWSTR lpCurrentDirectory,
+ _In_ LPSTARTUPINFOW lpStartupInfo,
+ _Out_ LPPROCESS_INFORMATION lpProcessInformation,
+ _In_ LPCSTR lpDllName,
+ _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW)
+{
+ if (pfCreateProcessW == NULL) {
+ pfCreateProcessW = CreateProcessW;
+ }
+
+ PROCESS_INFORMATION backup;
+ if (lpProcessInformation == NULL) {
+ lpProcessInformation = &backup;
+ ZeroMemory(&backup, sizeof(backup));
+ }
+
+ if (!pfCreateProcessW(lpApplicationName,
+ lpCommandLine,
+ lpProcessAttributes,
+ lpThreadAttributes,
+ bInheritHandles,
+ dwCreationFlags | CREATE_SUSPENDED,
+ lpEnvironment,
+ lpCurrentDirectory,
+ lpStartupInfo,
+ lpProcessInformation)) {
+ return FALSE;
+ }
+
+
+ LPCSTR sz = lpDllName;
+
+ if (!DetourUpdateProcessWithDll(lpProcessInformation->hProcess, &sz, 1) &&
+ !DetourProcessViaHelperW(lpProcessInformation->dwProcessId,
+ lpDllName,
+ pfCreateProcessW)) {
+
+ TerminateProcess(lpProcessInformation->hProcess, ~0u);
+ CloseHandle(lpProcessInformation->hProcess);
+ CloseHandle(lpProcessInformation->hThread);
+ return FALSE;
+ }
+
+ if (!(dwCreationFlags & CREATE_SUSPENDED)) {
+ ResumeThread(lpProcessInformation->hThread);
+ }
+
+ if (lpProcessInformation == &backup) {
+ CloseHandle(lpProcessInformation->hProcess);
+ CloseHandle(lpProcessInformation->hThread);
+ }
+ return TRUE;
+}
+
+BOOL WINAPI DetourCreateProcessWithDllsA(_In_opt_ LPCSTR lpApplicationName,
+ _Inout_opt_ LPSTR lpCommandLine,
+ _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ _In_ BOOL bInheritHandles,
+ _In_ DWORD dwCreationFlags,
+ _In_opt_ LPVOID lpEnvironment,
+ _In_opt_ LPCSTR lpCurrentDirectory,
+ _In_ LPSTARTUPINFOA lpStartupInfo,
+ _Out_ LPPROCESS_INFORMATION lpProcessInformation,
+ _In_ DWORD nDlls,
+ _In_reads_(nDlls) LPCSTR *rlpDlls,
+ _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA)
+{
+ if (pfCreateProcessA == NULL) {
+ pfCreateProcessA = CreateProcessA;
+ }
+
+ PROCESS_INFORMATION backup;
+ if (lpProcessInformation == NULL) {
+ lpProcessInformation = &backup;
+ ZeroMemory(&backup, sizeof(backup));
+ }
+
+ if (!pfCreateProcessA(lpApplicationName,
+ lpCommandLine,
+ lpProcessAttributes,
+ lpThreadAttributes,
+ bInheritHandles,
+ dwCreationFlags | CREATE_SUSPENDED,
+ lpEnvironment,
+ lpCurrentDirectory,
+ lpStartupInfo,
+ lpProcessInformation)) {
+ return FALSE;
+ }
+
+ if (!DetourUpdateProcessWithDll(lpProcessInformation->hProcess, rlpDlls, nDlls) &&
+ !DetourProcessViaHelperDllsA(lpProcessInformation->dwProcessId,
+ nDlls,
+ rlpDlls,
+ pfCreateProcessA)) {
+
+ TerminateProcess(lpProcessInformation->hProcess, ~0u);
+ CloseHandle(lpProcessInformation->hProcess);
+ CloseHandle(lpProcessInformation->hThread);
+ return FALSE;
+ }
+
+ if (!(dwCreationFlags & CREATE_SUSPENDED)) {
+ ResumeThread(lpProcessInformation->hThread);
+ }
+
+ if (lpProcessInformation == &backup) {
+ CloseHandle(lpProcessInformation->hProcess);
+ CloseHandle(lpProcessInformation->hThread);
+ }
+
+ return TRUE;
+}
+
+BOOL WINAPI DetourCreateProcessWithDllsW(_In_opt_ LPCWSTR lpApplicationName,
+ _Inout_opt_ LPWSTR lpCommandLine,
+ _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ _In_ BOOL bInheritHandles,
+ _In_ DWORD dwCreationFlags,
+ _In_opt_ LPVOID lpEnvironment,
+ _In_opt_ LPCWSTR lpCurrentDirectory,
+ _In_ LPSTARTUPINFOW lpStartupInfo,
+ _Out_ LPPROCESS_INFORMATION lpProcessInformation,
+ _In_ DWORD nDlls,
+ _In_reads_(nDlls) LPCSTR *rlpDlls,
+ _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW)
+{
+ if (pfCreateProcessW == NULL) {
+ pfCreateProcessW = CreateProcessW;
+ }
+
+ PROCESS_INFORMATION backup;
+ if (lpProcessInformation == NULL) {
+ lpProcessInformation = &backup;
+ ZeroMemory(&backup, sizeof(backup));
+ }
+
+ if (!pfCreateProcessW(lpApplicationName,
+ lpCommandLine,
+ lpProcessAttributes,
+ lpThreadAttributes,
+ bInheritHandles,
+ dwCreationFlags | CREATE_SUSPENDED,
+ lpEnvironment,
+ lpCurrentDirectory,
+ lpStartupInfo,
+ lpProcessInformation)) {
+ return FALSE;
+ }
+
+
+ if (!DetourUpdateProcessWithDll(lpProcessInformation->hProcess, rlpDlls, nDlls) &&
+ !DetourProcessViaHelperDllsW(lpProcessInformation->dwProcessId,
+ nDlls,
+ rlpDlls,
+ pfCreateProcessW)) {
+
+ TerminateProcess(lpProcessInformation->hProcess, ~0u);
+ CloseHandle(lpProcessInformation->hProcess);
+ CloseHandle(lpProcessInformation->hThread);
+ return FALSE;
+ }
+
+ if (!(dwCreationFlags & CREATE_SUSPENDED)) {
+ ResumeThread(lpProcessInformation->hThread);
+ }
+
+ if (lpProcessInformation == &backup) {
+ CloseHandle(lpProcessInformation->hProcess);
+ CloseHandle(lpProcessInformation->hThread);
+ }
+ return TRUE;
+}
+
+//
+///////////////////////////////////////////////////////////////// End of File.
diff --git a/r5dev/thirdparty/detours/src/uimports.cpp b/r5dev/thirdparty/detours/src/uimports.cpp
new file mode 100644
index 00000000..cd1fe0f8
--- /dev/null
+++ b/r5dev/thirdparty/detours/src/uimports.cpp
@@ -0,0 +1,335 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// Add DLLs to a module import table (uimports.cpp of detours.lib)
+//
+// Microsoft Research Detours Package, Version 4.0.1
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+// Note that this file is included into creatwth.cpp one or more times
+// (once for each supported module format).
+//
+
+#include "../include/detours.h"
+
+#if DETOURS_VERSION != 0x4c0c1 // 0xMAJORcMINORcPATCH
+#error detours.h version mismatch
+#endif
+
+// UpdateImports32 aka UpdateImports64
+static BOOL UPDATE_IMPORTS_XX(HANDLE hProcess,
+ HMODULE hModule,
+ __in_ecount(nDlls) LPCSTR *plpDlls,
+ DWORD nDlls)
+{
+ BOOL fSucceeded = FALSE;
+ DWORD cbNew = 0;
+
+ BYTE * pbNew = NULL;
+ DWORD i;
+ SIZE_T cbRead;
+ DWORD n;
+
+ PBYTE pbModule = (PBYTE)hModule;
+
+ IMAGE_DOS_HEADER idh;
+ ZeroMemory(&idh, sizeof(idh));
+ if (!ReadProcessMemory(hProcess, pbModule, &idh, sizeof(idh), &cbRead)
+ || cbRead < sizeof(idh)) {
+
+ DETOUR_TRACE(("ReadProcessMemory(idh@%p..%p) failed: %lu\n",
+ pbModule, pbModule + sizeof(idh), GetLastError()));
+
+ finish:
+ if (pbNew != NULL) {
+ delete[] pbNew;
+ pbNew = NULL;
+ }
+ return fSucceeded;
+ }
+
+ IMAGE_NT_HEADERS_XX inh;
+ ZeroMemory(&inh, sizeof(inh));
+
+ if (!ReadProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), &cbRead)
+ || cbRead < sizeof(inh)) {
+ DETOUR_TRACE(("ReadProcessMemory(inh@%p..%p) failed: %lu\n",
+ pbModule + idh.e_lfanew,
+ pbModule + idh.e_lfanew + sizeof(inh),
+ GetLastError()));
+ goto finish;
+ }
+
+ if (inh.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC_XX) {
+ DETOUR_TRACE(("Wrong size image (%04x != %04x).\n",
+ inh.OptionalHeader.Magic, IMAGE_NT_OPTIONAL_HDR_MAGIC_XX));
+ SetLastError(ERROR_INVALID_BLOCK);
+ goto finish;
+ }
+
+ // Zero out the bound table so loader doesn't use it instead of our new table.
+ inh.BOUND_DIRECTORY.VirtualAddress = 0;
+ inh.BOUND_DIRECTORY.Size = 0;
+
+ // Find the size of the mapped file.
+ DWORD dwSec = idh.e_lfanew +
+ FIELD_OFFSET(IMAGE_NT_HEADERS_XX, OptionalHeader) +
+ inh.FileHeader.SizeOfOptionalHeader;
+
+ for (i = 0; i < inh.FileHeader.NumberOfSections; i++) {
+ IMAGE_SECTION_HEADER ish;
+ ZeroMemory(&ish, sizeof(ish));
+
+ if (!ReadProcessMemory(hProcess, pbModule + dwSec + sizeof(ish) * i, &ish,
+ sizeof(ish), &cbRead)
+ || cbRead < sizeof(ish)) {
+
+ DETOUR_TRACE(("ReadProcessMemory(ish@%p..%p) failed: %lu\n",
+ pbModule + dwSec + sizeof(ish) * i,
+ pbModule + dwSec + sizeof(ish) * (i + 1),
+ GetLastError()));
+ goto finish;
+ }
+
+ DETOUR_TRACE(("ish[%lu] : va=%08lx sr=%lu\n", i, ish.VirtualAddress, ish.SizeOfRawData));
+
+ // If the linker didn't suggest an IAT in the data directories, the
+ // loader will look for the section of the import directory to be used
+ // for this instead. Since we put out new IMPORT_DIRECTORY outside any
+ // section boundary, the loader will not find it. So we provide one
+ // explicitly to avoid the search.
+ //
+ if (inh.IAT_DIRECTORY.VirtualAddress == 0 &&
+ inh.IMPORT_DIRECTORY.VirtualAddress >= ish.VirtualAddress &&
+ inh.IMPORT_DIRECTORY.VirtualAddress < ish.VirtualAddress + ish.SizeOfRawData) {
+
+ inh.IAT_DIRECTORY.VirtualAddress = ish.VirtualAddress;
+ inh.IAT_DIRECTORY.Size = ish.SizeOfRawData;
+ }
+ }
+
+ if (inh.IMPORT_DIRECTORY.VirtualAddress != 0 && inh.IMPORT_DIRECTORY.Size == 0) {
+
+ // Don't worry about changing the PE file,
+ // because the load information of the original PE header has been saved and will be restored.
+ // The change here is just for the following code to work normally
+
+ PIMAGE_IMPORT_DESCRIPTOR pImageImport = (PIMAGE_IMPORT_DESCRIPTOR)(pbModule + inh.IMPORT_DIRECTORY.VirtualAddress);
+
+ do {
+ IMAGE_IMPORT_DESCRIPTOR ImageImport;
+ if (!ReadProcessMemory(hProcess, pImageImport, &ImageImport, sizeof(ImageImport), NULL)) {
+ DETOUR_TRACE(("ReadProcessMemory failed: %lu\n", GetLastError()));
+ goto finish;
+ }
+ inh.IMPORT_DIRECTORY.Size += sizeof(IMAGE_IMPORT_DESCRIPTOR);
+ if (!ImageImport.Name) {
+ break;
+ }
+ ++pImageImport;
+ } while (TRUE);
+
+ DWORD dwLastError = GetLastError();
+ OutputDebugString(TEXT("[This PE file has an import table, but the import table size is marked as 0. This is an error.")
+ TEXT("If it is not repaired, the launched program will not work properly, Detours has automatically repaired its import table size for you! ! !]\r\n"));
+ if (GetLastError() != dwLastError) {
+ SetLastError(dwLastError);
+ }
+ }
+
+ DETOUR_TRACE((" Imports: %p..%p\n",
+ pbModule + inh.IMPORT_DIRECTORY.VirtualAddress,
+ pbModule + inh.IMPORT_DIRECTORY.VirtualAddress +
+ inh.IMPORT_DIRECTORY.Size));
+
+ // Calculate new import directory size. Note that since inh is from another
+ // process, inh could have been corrupted. We need to protect against
+ // integer overflow in allocation calculations.
+ DWORD nOldDlls = inh.IMPORT_DIRECTORY.Size / sizeof(IMAGE_IMPORT_DESCRIPTOR);
+ DWORD obRem;
+ if (DWordMult(sizeof(IMAGE_IMPORT_DESCRIPTOR), nDlls, &obRem) != S_OK) {
+ DETOUR_TRACE(("too many new DLLs.\n"));
+ goto finish;
+ }
+ DWORD obOld;
+ if (DWordAdd(obRem, sizeof(IMAGE_IMPORT_DESCRIPTOR) * nOldDlls, &obOld) != S_OK) {
+ DETOUR_TRACE(("DLL entries overflow.\n"));
+ goto finish;
+ }
+ DWORD obTab = PadToDwordPtr(obOld);
+ // Check for integer overflow.
+ if (obTab < obOld) {
+ DETOUR_TRACE(("DLL entries padding overflow.\n"));
+ goto finish;
+ }
+ DWORD stSize;
+ if (DWordMult(sizeof(DWORD_XX) * 4, nDlls, &stSize) != S_OK) {
+ DETOUR_TRACE(("String table overflow.\n"));
+ goto finish;
+ }
+ DWORD obDll;
+ if (DWordAdd(obTab, stSize, &obDll) != S_OK) {
+ DETOUR_TRACE(("Import table size overflow\n"));
+ goto finish;
+ }
+ DWORD obStr = obDll;
+ cbNew = obStr;
+ for (n = 0; n < nDlls; n++) {
+ if (DWordAdd(cbNew, PadToDword((DWORD)strlen(plpDlls[n]) + 1), &cbNew) != S_OK) {
+ DETOUR_TRACE(("Overflow adding string table entry\n"));
+ goto finish;
+ }
+ }
+ pbNew = new BYTE [cbNew];
+ if (pbNew == NULL) {
+ DETOUR_TRACE(("new BYTE [cbNew] failed.\n"));
+ goto finish;
+ }
+ ZeroMemory(pbNew, cbNew);
+
+ PBYTE pbBase = pbModule;
+ PBYTE pbNext = pbBase
+ + inh.OptionalHeader.BaseOfCode
+ + inh.OptionalHeader.SizeOfCode
+ + inh.OptionalHeader.SizeOfInitializedData
+ + inh.OptionalHeader.SizeOfUninitializedData;
+ if (pbBase < pbNext) {
+ pbBase = pbNext;
+ }
+ DETOUR_TRACE(("pbBase = %p\n", pbBase));
+
+ PBYTE pbNewIid = FindAndAllocateNearBase(hProcess, pbModule, pbBase, cbNew);
+ if (pbNewIid == NULL) {
+ DETOUR_TRACE(("FindAndAllocateNearBase failed.\n"));
+ goto finish;
+ }
+
+ PIMAGE_IMPORT_DESCRIPTOR piid = (PIMAGE_IMPORT_DESCRIPTOR)pbNew;
+ IMAGE_THUNK_DATAXX *pt = NULL;
+
+ DWORD obBase = (DWORD)(pbNewIid - pbModule);
+ DWORD dwProtect = 0;
+
+ if (inh.IMPORT_DIRECTORY.VirtualAddress != 0) {
+ // Read the old import directory if it exists.
+ DETOUR_TRACE(("IMPORT_DIRECTORY perms=%lx\n", dwProtect));
+
+ if (!ReadProcessMemory(hProcess,
+ pbModule + inh.IMPORT_DIRECTORY.VirtualAddress,
+ &piid[nDlls],
+ nOldDlls * sizeof(IMAGE_IMPORT_DESCRIPTOR), &cbRead)
+ || cbRead < nOldDlls * sizeof(IMAGE_IMPORT_DESCRIPTOR)) {
+
+ DETOUR_TRACE(("ReadProcessMemory(imports) failed: %lu\n", GetLastError()));
+ goto finish;
+ }
+ }
+
+ for (n = 0; n < nDlls; n++) {
+ HRESULT hrRet = StringCchCopyA((char*)pbNew + obStr, cbNew - obStr, plpDlls[n]);
+ if (FAILED(hrRet)) {
+ DETOUR_TRACE(("StringCchCopyA failed: %08lx\n", hrRet));
+ goto finish;
+ }
+
+ // After copying the string, we patch up the size "??" bits if any.
+ hrRet = ReplaceOptionalSizeA((char*)pbNew + obStr,
+ cbNew - obStr,
+ DETOURS_STRINGIFY(DETOURS_BITS_XX));
+ if (FAILED(hrRet)) {
+ DETOUR_TRACE(("ReplaceOptionalSizeA failed: %08lx\n", hrRet));
+ goto finish;
+ }
+
+ DWORD nOffset = obTab + (sizeof(IMAGE_THUNK_DATAXX) * (4 * n));
+ piid[n].OriginalFirstThunk = obBase + nOffset;
+
+ // We need 2 thunks for the import table and 2 thunks for the IAT.
+ // One for an ordinal import and one to mark the end of the list.
+ pt = ((IMAGE_THUNK_DATAXX*)(pbNew + nOffset));
+ pt[0].u1.Ordinal = IMAGE_ORDINAL_FLAG_XX + 1;
+ pt[1].u1.Ordinal = 0;
+
+ nOffset = obTab + (sizeof(IMAGE_THUNK_DATAXX) * ((4 * n) + 2));
+ piid[n].FirstThunk = obBase + nOffset;
+ pt = ((IMAGE_THUNK_DATAXX*)(pbNew + nOffset));
+ pt[0].u1.Ordinal = IMAGE_ORDINAL_FLAG_XX + 1;
+ pt[1].u1.Ordinal = 0;
+ piid[n].TimeDateStamp = 0;
+ piid[n].ForwarderChain = 0;
+ piid[n].Name = obBase + obStr;
+
+ obStr += PadToDword((DWORD)strlen(plpDlls[n]) + 1);
+ }
+ _Analysis_assume_(obStr <= cbNew);
+
+#if 0
+ for (i = 0; i < nDlls + nOldDlls; i++) {
+ DETOUR_TRACE(("%8d. Look=%08x Time=%08x Fore=%08x Name=%08x Addr=%08x\n",
+ i,
+ piid[i].OriginalFirstThunk,
+ piid[i].TimeDateStamp,
+ piid[i].ForwarderChain,
+ piid[i].Name,
+ piid[i].FirstThunk));
+ if (piid[i].OriginalFirstThunk == 0 && piid[i].FirstThunk == 0) {
+ break;
+ }
+ }
+#endif
+
+ if (!WriteProcessMemory(hProcess, pbNewIid, pbNew, obStr, NULL)) {
+ DETOUR_TRACE(("WriteProcessMemory(iid) failed: %lu\n", GetLastError()));
+ goto finish;
+ }
+
+ DETOUR_TRACE(("obBaseBef = %08lx..%08lx\n",
+ inh.IMPORT_DIRECTORY.VirtualAddress,
+ inh.IMPORT_DIRECTORY.VirtualAddress + inh.IMPORT_DIRECTORY.Size));
+ DETOUR_TRACE(("obBaseAft = %08lx..%08lx\n", obBase, obBase + obStr));
+
+ // In this case the file didn't have an import directory in first place,
+ // so we couldn't fix the missing IAT above. We still need to explicitly
+ // provide an IAT to prevent to loader from looking for one.
+ //
+ if (inh.IAT_DIRECTORY.VirtualAddress == 0) {
+ inh.IAT_DIRECTORY.VirtualAddress = obBase;
+ inh.IAT_DIRECTORY.Size = cbNew;
+ }
+
+ inh.IMPORT_DIRECTORY.VirtualAddress = obBase;
+ inh.IMPORT_DIRECTORY.Size = cbNew;
+
+ /////////////////////// Update the NT header for the new import directory.
+ //
+ if (!DetourVirtualProtectSameExecuteEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders,
+ PAGE_EXECUTE_READWRITE, &dwProtect)) {
+ DETOUR_TRACE(("VirtualProtectEx(inh) write failed: %lu\n", GetLastError()));
+ goto finish;
+ }
+
+ inh.OptionalHeader.CheckSum = 0;
+
+ if (!WriteProcessMemory(hProcess, pbModule, &idh, sizeof(idh), NULL)) {
+ DETOUR_TRACE(("WriteProcessMemory(idh) failed: %lu\n", GetLastError()));
+ goto finish;
+ }
+ DETOUR_TRACE(("WriteProcessMemory(idh:%p..%p)\n", pbModule, pbModule + sizeof(idh)));
+
+ if (!WriteProcessMemory(hProcess, pbModule + idh.e_lfanew, &inh, sizeof(inh), NULL)) {
+ DETOUR_TRACE(("WriteProcessMemory(inh) failed: %lu\n", GetLastError()));
+ goto finish;
+ }
+ DETOUR_TRACE(("WriteProcessMemory(inh:%p..%p)\n",
+ pbModule + idh.e_lfanew,
+ pbModule + idh.e_lfanew + sizeof(inh)));
+
+ if (!VirtualProtectEx(hProcess, pbModule, inh.OptionalHeader.SizeOfHeaders,
+ dwProtect, &dwProtect)) {
+ DETOUR_TRACE(("VirtualProtectEx(idh) restore failed: %lu\n", GetLastError()));
+ goto finish;
+ }
+
+ fSucceeded = TRUE;
+ goto finish;
+}
diff --git a/r5dev/thirdparty/lzham/include/lzham_assert.h b/r5dev/thirdparty/lzham/include/lzham_assert.h
new file mode 100644
index 00000000..d8a68515
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_assert.h
@@ -0,0 +1,40 @@
+// File: lzham_assert.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+const unsigned int LZHAM_FAIL_EXCEPTION_CODE = 256U;
+void lzham_enable_fail_exceptions(bool enabled);
+
+void lzham_assert(const char* pExp, const char* pFile, unsigned line);
+void lzham_fail(const char* pExp, const char* pFile, unsigned line);
+
+#ifdef NDEBUG
+ #define LZHAM_ASSERT(x) ((void)0)
+#else
+ #define LZHAM_ASSERT(_exp) (void)( (!!(_exp)) || (lzham_assert(#_exp, __FILE__, __LINE__), 0) )
+ #define LZHAM_ASSERTS_ENABLED 1
+#endif
+
+#define LZHAM_VERIFY(_exp) (void)( (!!(_exp)) || (lzham_assert(#_exp, __FILE__, __LINE__), 0) )
+
+#define LZHAM_FAIL(msg) do { lzham_fail(#msg, __FILE__, __LINE__); } while(0)
+
+#define LZHAM_ASSERT_OPEN_RANGE(x, l, h) LZHAM_ASSERT((x >= l) && (x < h))
+#define LZHAM_ASSERT_CLOSED_RANGE(x, l, h) LZHAM_ASSERT((x >= l) && (x <= h))
+
+void lzham_trace(const char* pFmt, va_list args);
+void lzham_trace(const char* pFmt, ...);
+
+// Borrowed from boost libraries.
+template struct assume_failure;
+template <> struct assume_failure { enum { blah = 1 }; };
+template struct assume_try { };
+
+#define LZHAM_JOINER_FINAL(a, b) a##b
+#define LZHAM_JOINER(a, b) LZHAM_JOINER_FINAL(a, b)
+#define LZHAM_JOIN(a, b) LZHAM_JOINER(a, b)
+#if defined(__GNUC__)
+ #define LZHAM_ASSUME(p) typedef assume_try < sizeof(assume_failure< (bool)(p) > ) > LZHAM_JOIN(assume_typedef, __COUNTER__) __attribute__((unused))
+#else
+ #define LZHAM_ASSUME(p) typedef assume_try < sizeof(assume_failure< (bool)(p) > ) > LZHAM_JOIN(assume_typedef, __COUNTER__)
+#endif
diff --git a/r5dev/thirdparty/lzham/include/lzham_checksum.h b/r5dev/thirdparty/lzham/include/lzham_checksum.h
new file mode 100644
index 00000000..515f3389
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_checksum.h
@@ -0,0 +1,13 @@
+// File: lzham_checksum.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+namespace lzham
+{
+ const uint cInitAdler32 = 1U;
+ uint adler32(const void* pBuf, size_t buflen, uint adler32 = cInitAdler32);
+
+ const uint cInitCRC32 = 0U;
+ uint crc32(uint crc, const lzham_uint8 *ptr, size_t buf_len);
+
+} // namespace lzham
diff --git a/r5dev/thirdparty/lzham/include/lzham_config.h b/r5dev/thirdparty/lzham/include/lzham_config.h
new file mode 100644
index 00000000..e250c7ce
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_config.h
@@ -0,0 +1,23 @@
+// File: lzham_config.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+#ifdef _DEBUG
+ #define LZHAM_BUILD_DEBUG
+
+ #ifndef DEBUG
+ #define DEBUG
+ #endif
+#else
+ #define LZHAM_BUILD_RELEASE
+
+ #ifndef NDEBUG
+ #define NDEBUG
+ #endif
+
+ #ifdef DEBUG
+ #error DEBUG cannot be defined in LZHAM_BUILD_RELEASE
+ #endif
+#endif
+#define LZHAM_BUFFERED_PRINTF 0
+#define LZHAM_PERF_SECTIONS 0
\ No newline at end of file
diff --git a/r5dev/thirdparty/lzham/include/lzham_core.h b/r5dev/thirdparty/lzham/include/lzham_core.h
new file mode 100644
index 00000000..3d4f3d3e
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_core.h
@@ -0,0 +1,170 @@
+// File: lzham_core.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+#include "core/stdafx.h"
+
+#if defined(_MSC_VER)
+ #pragma warning (disable: 4127) // conditional expression is constant
+#endif
+
+#if defined(_XBOX) && !defined(LZHAM_ANSI_CPLUSPLUS)
+ // X360
+ #include
+ #define _HAS_EXCEPTIONS 0
+ #define NOMINMAX
+
+ #define LZHAM_PLATFORM_X360 1
+ #define LZHAM_USE_WIN32_API 1
+ #define LZHAM_USE_WIN32_ATOMIC_FUNCTIONS 1
+ #define LZHAM_64BIT_POINTERS 0
+ #define LZHAM_CPU_HAS_64BIT_REGISTERS 1
+ #define LZHAM_BIG_ENDIAN_CPU 1
+ #define LZHAM_USE_UNALIGNED_INT_LOADS 1
+ #define LZHAM_RESTRICT __restrict
+ #define LZHAM_FORCE_INLINE __forceinline
+ #define LZHAM_NOTE_UNUSED(x) (void)x
+
+#elif defined(WIN32) && !defined(LZHAM_ANSI_CPLUSPLUS)
+ // MSVC or MinGW, x86 or x64, Win32 API's for threading and Win32 Interlocked API's or GCC built-ins for atomic ops.
+ #ifdef NDEBUG
+ // Ensure checked iterators are disabled.
+ #define _SECURE_SCL 0
+ #define _HAS_ITERATOR_DEBUGGING 0
+ #endif
+ #ifndef _DLL
+ // If we're using the DLL form of the run-time libs, we're also going to be enabling exceptions because we'll be building CLR apps.
+ // Otherwise, we disable exceptions for a small speed boost.
+ //#define _HAS_EXCEPTIONS 0
+ #endif
+ #define NOMINMAX
+
+ #ifndef _WIN32_WINNT
+ #define _WIN32_WINNT 0x500
+ #endif
+
+ #ifndef WIN32_LEAN_AND_MEAN
+ #define WIN32_LEAN_AND_MEAN
+ #endif
+
+ #include
+
+ #define LZHAM_USE_WIN32_API 1
+
+ #if defined(__MINGW32__) || defined(__MINGW64__)
+ #define LZHAM_USE_GCC_ATOMIC_BUILTINS 1
+ #else
+ #define LZHAM_USE_WIN32_ATOMIC_FUNCTIONS 1
+ #endif
+
+ #define LZHAM_PLATFORM_PC 1
+
+ #ifdef _WIN64
+ #define LZHAM_PLATFORM_PC_X64 1
+ #define LZHAM_64BIT_POINTERS 1
+ #define LZHAM_CPU_HAS_64BIT_REGISTERS 1
+ #define LZHAM_LITTLE_ENDIAN_CPU 1
+ #else
+ #define LZHAM_PLATFORM_PC_X86 1
+ #define LZHAM_64BIT_POINTERS 0
+ #define LZHAM_CPU_HAS_64BIT_REGISTERS 0
+ #define LZHAM_LITTLE_ENDIAN_CPU 1
+ #endif
+
+ #define LZHAM_USE_UNALIGNED_INT_LOADS 1
+ #define LZHAM_RESTRICT __restrict
+ #define LZHAM_FORCE_INLINE __forceinline
+
+ #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__)
+ #define LZHAM_USE_MSVC_INTRINSICS 1
+ #endif
+
+ #define LZHAM_NOTE_UNUSED(x) (void)x
+
+#elif defined(__GNUC__) && !defined(LZHAM_ANSI_CPLUSPLUS)
+ // GCC x86 or x64, pthreads for threading and GCC built-ins for atomic ops.
+ #define LZHAM_PLATFORM_PC 1
+
+ #if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
+ #define LZHAM_PLATFORM_PC_X64 1
+ #define LZHAM_64BIT_POINTERS 1
+ #define LZHAM_CPU_HAS_64BIT_REGISTERS 1
+ #else
+ #define LZHAM_PLATFORM_PC_X86 1
+ #define LZHAM_64BIT_POINTERS 0
+ #define LZHAM_CPU_HAS_64BIT_REGISTERS 0
+ #endif
+
+ #define LZHAM_USE_UNALIGNED_INT_LOADS 1
+
+ #define LZHAM_LITTLE_ENDIAN_CPU 1
+
+ #define LZHAM_USE_PTHREADS_API 1
+ #define LZHAM_USE_GCC_ATOMIC_BUILTINS 1
+
+ #define LZHAM_RESTRICT
+
+ #if defined(__clang__)
+ #define LZHAM_FORCE_INLINE inline
+ #else
+ #define LZHAM_FORCE_INLINE inline __attribute__((__always_inline__,__gnu_inline__))
+ #endif
+
+ #define LZHAM_NOTE_UNUSED(x) (void)x
+#else
+ // Vanilla ANSI-C/C++
+ // No threading support, unaligned loads are NOT okay.
+ #if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__)
+ #define LZHAM_64BIT_POINTERS 1
+ #define LZHAM_CPU_HAS_64BIT_REGISTERS 1
+ #else
+ #define LZHAM_64BIT_POINTERS 0
+ #define LZHAM_CPU_HAS_64BIT_REGISTERS 0
+ #endif
+
+ #define LZHAM_USE_UNALIGNED_INT_LOADS 0
+
+ #if __BIG_ENDIAN__
+ #define LZHAM_BIG_ENDIAN_CPU 1
+ #else
+ #define LZHAM_LITTLE_ENDIAN_CPU 1
+ #endif
+
+ #define LZHAM_USE_GCC_ATOMIC_BUILTINS 0
+ #define LZHAM_USE_WIN32_ATOMIC_FUNCTIONS 0
+
+ #define LZHAM_RESTRICT
+ #define LZHAM_FORCE_INLINE inline
+
+ #define LZHAM_NOTE_UNUSED(x) (void)x
+#endif
+
+#if LZHAM_LITTLE_ENDIAN_CPU
+ const bool c_lzham_little_endian_platform = true;
+#else
+ const bool c_lzham_little_endian_platform = false;
+#endif
+
+const bool c_lzham_big_endian_platform = !c_lzham_little_endian_platform;
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "lzham.h"
+#include "lzham_config.h"
+#include "lzham_types.h"
+#include "lzham_assert.h"
+#include "lzham_platform.h"
+
+#include "lzham_helpers.h"
+#include "lzham_traits.h"
+#include "lzham_mem.h"
+#include "lzham_math.h"
+#include "lzham_utils.h"
+#include "lzham_vector.h"
diff --git a/r5dev/thirdparty/lzham/include/lzham_helpers.h b/r5dev/thirdparty/lzham/include/lzham_helpers.h
new file mode 100644
index 00000000..11e0a119
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_helpers.h
@@ -0,0 +1,54 @@
+// File: lzham_helpers.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+#define LZHAM_NO_COPY_OR_ASSIGNMENT_OP(c) c(const c&); c& operator= (const c&);
+
+namespace lzham
+{
+ namespace helpers
+ {
+ template struct rel_ops
+ {
+ friend inline bool operator!=(const T& x, const T& y) { return (!(x == y)); }
+ friend inline bool operator> (const T& x, const T& y) { return (y < x); }
+ friend inline bool operator<=(const T& x, const T& y) { return (!(y < x)); }
+ friend inline bool operator>=(const T& x, const T& y) { return (!(x < y)); }
+ };
+
+ template
+ inline T* construct(T* p)
+ {
+ return new (static_cast(p)) T;
+ }
+
+ template
+ inline T* construct(T* p, const U& init)
+ {
+ return new (static_cast(p)) T(init);
+ }
+
+ template
+ inline void construct_array(T* p, uint n);
+
+ template
+ inline void construct_array(T* p, uint n, const U& init)
+ {
+ T* q = p + n;
+ for ( ; p != q; ++p)
+ new (static_cast(p)) T(init);
+ }
+
+ template
+ inline void destruct(T* p)
+ {
+ LZHAM_NOTE_UNUSED(p);
+ p->~T();
+ }
+
+ template
+ inline void destruct_array(T* p, uint n);
+
+ } // namespace helpers
+
+} // namespace lzham
diff --git a/r5dev/thirdparty/lzham/include/lzham_huffman_codes.h b/r5dev/thirdparty/lzham/include/lzham_huffman_codes.h
new file mode 100644
index 00000000..caab1a68
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_huffman_codes.h
@@ -0,0 +1,14 @@
+// File: lzham_huffman_codes.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+namespace lzham
+{
+ //const uint cHuffmanMaxSupportedSyms = 600;
+ const uint cHuffmanMaxSupportedSyms = 1024;
+
+ uint get_generate_huffman_codes_table_size();
+
+ bool generate_huffman_codes(void* pContext, uint num_syms, const uint16* pFreq, uint8* pCodesizes, uint& max_code_size, uint& total_freq_ret);
+
+} // namespace lzham
diff --git a/r5dev/thirdparty/lzham/include/lzham_lzbase.h b/r5dev/thirdparty/lzham/include/lzham_lzbase.h
new file mode 100644
index 00000000..8904ddd4
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_lzbase.h
@@ -0,0 +1,45 @@
+// File: lzham_lzbase.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+#include "../lzhamdecomp/lzham_lzdecompbase.h"
+
+//#define LZHAM_LZVERIFY
+//#define LZHAM_DISABLE_RAW_BLOCKS
+
+namespace lzham
+{
+ struct CLZBase : CLZDecompBase
+ {
+ uint8 m_slot_tab0[4096];
+ uint8 m_slot_tab1[512];
+ uint8 m_slot_tab2[256];
+
+ void init_slot_tabs();
+
+ inline void compute_lzx_position_slot(uint dist, uint& slot, uint& ofs)
+ {
+ uint s;
+ if (dist < 0x1000)
+ s = m_slot_tab0[dist];
+ else if (dist < 0x100000)
+ s = m_slot_tab1[dist >> 11];
+ else if (dist < 0x1000000)
+ s = m_slot_tab2[dist >> 16];
+ else if (dist < 0x2000000)
+ s = 48 + ((dist - 0x1000000) >> 23);
+ else if (dist < 0x4000000)
+ s = 50 + ((dist - 0x2000000) >> 24);
+ else
+ s = 52 + ((dist - 0x4000000) >> 25);
+
+ ofs = (dist - m_lzx_position_base[s]) & m_lzx_position_extra_mask[s];
+ slot = s;
+
+ LZHAM_ASSERT(s < m_num_lzx_slots);
+ LZHAM_ASSERT((m_lzx_position_base[slot] + ofs) == dist);
+ LZHAM_ASSERT(ofs < (1U << m_lzx_position_extra_bits[slot]));
+ }
+ };
+
+} // namespace lzham
diff --git a/r5dev/thirdparty/lzham/include/lzham_match_accel.h b/r5dev/thirdparty/lzham/include/lzham_match_accel.h
new file mode 100644
index 00000000..384ea7dd
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_match_accel.h
@@ -0,0 +1,146 @@
+// File: lzham_match_accel.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+#include "lzham_lzbase.h"
+#include "lzham_threading.h"
+
+namespace lzham
+{
+ const uint cMatchAccelMaxSupportedProbes = 128;
+
+ struct node
+ {
+ uint m_left;
+ uint m_right;
+ };
+
+ LZHAM_DEFINE_BITWISE_MOVABLE(node);
+
+#pragma pack(push, 1)
+ struct dict_match
+ {
+ uint m_dist;
+ uint16 m_len;
+
+ inline uint get_dist() const { return m_dist & 0x7FFFFFFF; }
+ inline uint get_len() const { return m_len + 2; }
+ inline bool is_last() const { return (int)m_dist < 0; }
+ };
+#pragma pack(pop)
+
+ LZHAM_DEFINE_BITWISE_MOVABLE(dict_match);
+
+ class search_accelerator
+ {
+ public:
+ search_accelerator();
+
+ // If all_matches is true, the match finder returns all found matches with no filtering.
+ // Otherwise, the finder will tend to return lists of matches with mostly unique lengths.
+ // For each length, it will discard matches with worse distances (in the coding sense).
+ bool init(CLZBase* pLZBase, task_pool* pPool, uint max_helper_threads, uint max_dict_size, uint max_matches, bool all_matches, uint max_probes);
+
+ void reset();
+ void flush();
+
+ inline uint get_max_dict_size() const { return m_max_dict_size; }
+ inline uint get_max_dict_size_mask() const { return m_max_dict_size_mask; }
+ inline uint get_cur_dict_size() const { return m_cur_dict_size; }
+
+ inline uint get_lookahead_pos() const { return m_lookahead_pos; }
+ inline uint get_lookahead_size() const { return m_lookahead_size; }
+
+ inline uint get_char(int delta_pos) const { return m_dict[(m_lookahead_pos + delta_pos) & m_max_dict_size_mask]; }
+ inline uint get_char(uint cur_dict_pos, int delta_pos) const { return m_dict[(cur_dict_pos + delta_pos) & m_max_dict_size_mask]; }
+ inline const uint8* get_ptr(uint pos) const { return &m_dict[pos]; }
+
+ uint get_max_helper_threads() const { return m_max_helper_threads; }
+
+ inline uint operator[](uint pos) const { return m_dict[pos]; }
+
+ uint get_max_add_bytes() const;
+ bool add_bytes_begin(uint num_bytes, const uint8* pBytes);
+ inline atomic32_t get_num_completed_helper_threads() const { return m_num_completed_helper_threads; }
+ void add_bytes_end();
+
+ // Returns the lookahead's raw position/size/dict_size at the time add_bytes_begin() is called.
+ inline uint get_fill_lookahead_pos() const { return m_fill_lookahead_pos; }
+ inline uint get_fill_lookahead_size() const { return m_fill_lookahead_size; }
+ inline uint get_fill_dict_size() const { return m_fill_dict_size; }
+
+ uint get_len2_match(uint lookahead_ofs);
+ dict_match* find_matches(uint lookahead_ofs, bool spin = true);
+
+ void advance_bytes(uint num_bytes);
+
+ LZHAM_FORCE_INLINE uint get_match_len(uint lookahead_ofs, int dist, uint max_match_len, uint start_match_len = 0) const
+ {
+ LZHAM_ASSERT(lookahead_ofs < m_lookahead_size);
+ LZHAM_ASSERT(start_match_len <= max_match_len);
+ LZHAM_ASSERT(max_match_len <= (get_lookahead_size() - lookahead_ofs));
+
+ const int find_dict_size = m_cur_dict_size + lookahead_ofs;
+ if (dist > find_dict_size)
+ return 0;
+
+ const uint comp_pos = static_cast((m_lookahead_pos + lookahead_ofs - dist) & m_max_dict_size_mask);
+ const uint lookahead_pos = (m_lookahead_pos + lookahead_ofs) & m_max_dict_size_mask;
+
+ const uint8* pComp = &m_dict[comp_pos];
+ const uint8* pLookahead = &m_dict[lookahead_pos];
+
+ uint match_len;
+ for (match_len = start_match_len; match_len < max_match_len; match_len++)
+ if (pComp[match_len] != pLookahead[match_len])
+ break;
+
+ return match_len;
+ }
+
+ public:
+ CLZBase* m_pLZBase;
+ task_pool* m_pTask_pool;
+ uint m_max_helper_threads;
+
+ uint m_max_dict_size;
+ uint m_max_dict_size_mask;
+
+ uint m_lookahead_pos;
+ uint m_lookahead_size;
+
+ uint m_cur_dict_size;
+
+ lzham::vector m_dict;
+
+ enum { cHashSize = 65536 };
+ lzham::vector m_hash;
+ lzham::vector m_nodes;
+
+ lzham::vector m_matches;
+ lzham::vector m_match_refs;
+
+ lzham::vector m_hash_thread_index;
+
+ enum { cDigramHashSize = 4096 };
+ lzham::vector m_digram_hash;
+ lzham::vector m_digram_next;
+
+ uint m_fill_lookahead_pos;
+ uint m_fill_lookahead_size;
+ uint m_fill_dict_size;
+
+ uint m_max_probes;
+ uint m_max_matches;
+
+ bool m_all_matches;
+
+ volatile atomic32_t m_next_match_ref;
+
+ volatile atomic32_t m_num_completed_helper_threads;
+
+ void find_all_matches_callback(uint64 data, void* pData_ptr);
+ bool find_all_matches(uint num_bytes);
+ bool find_len2_matches();
+ };
+
+} // namespace lzham
diff --git a/r5dev/thirdparty/lzham/include/lzham_math.h b/r5dev/thirdparty/lzham/include/lzham_math.h
new file mode 100644
index 00000000..299f299b
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_math.h
@@ -0,0 +1,113 @@
+// File: lzham_math.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+#if defined(LZHAM_USE_MSVC_INTRINSICS) && !defined(__MINGW32__)
+ #include
+ #if defined(_MSC_VER)
+ #pragma intrinsic(_BitScanReverse)
+ #endif
+#endif
+
+namespace lzham
+{
+ namespace math
+ {
+ // Yes I know these should probably be pass by ref, not val:
+ // http://www.stepanovpapers.com/notes.pdf
+ // Just don't use them on non-simple (non built-in) types!
+ template inline T minimum(T a, T b) { return (a < b) ? a : b; }
+
+ template inline T minimum(T a, T b, T c) { return minimum(minimum(a, b), c); }
+
+ template inline T maximum(T a, T b) { return (a > b) ? a : b; }
+
+ template inline T maximum(T a, T b, T c) { return maximum(maximum(a, b), c); }
+
+ template inline T clamp(T value, T low, T high) { return (value < low) ? low : ((value > high) ? high : value); }
+
+ inline bool is_power_of_2(uint32 x) { return x && ((x & (x - 1U)) == 0U); }
+ inline bool is_power_of_2(uint64 x) { return x && ((x & (x - 1U)) == 0U); }
+
+ template inline T align_up_pointer(T p, uint alignment)
+ {
+ LZHAM_ASSERT(is_power_of_2(alignment));
+ ptr_bits_t q = reinterpret_cast(p);
+ q = (q + alignment - 1) & (~((uint_ptr)alignment - 1));
+ return reinterpret_cast(q);
+ }
+
+ // From "Hackers Delight"
+ // val remains unchanged if it is already a power of 2.
+ inline uint32 next_pow2(uint32 val)
+ {
+ val--;
+ val |= val >> 16;
+ val |= val >> 8;
+ val |= val >> 4;
+ val |= val >> 2;
+ val |= val >> 1;
+ return val + 1;
+ }
+
+ // val remains unchanged if it is already a power of 2.
+ inline uint64 next_pow2(uint64 val)
+ {
+ val--;
+ val |= val >> 32;
+ val |= val >> 16;
+ val |= val >> 8;
+ val |= val >> 4;
+ val |= val >> 2;
+ val |= val >> 1;
+ return val + 1;
+ }
+
+ inline uint floor_log2i(uint v)
+ {
+ uint l = 0;
+ while (v > 1U)
+ {
+ v >>= 1;
+ l++;
+ }
+ return l;
+ }
+
+ inline uint ceil_log2i(uint v)
+ {
+ uint l = floor_log2i(v);
+ if ((l != cIntBits) && (v > (1U << l)))
+ l++;
+ return l;
+ }
+
+ // Returns the total number of bits needed to encode v.
+ // This needs to be fast - it's used heavily when determining Polar codelengths.
+ inline uint total_bits(uint v)
+ {
+ unsigned long l = 0;
+#if defined(__MINGW32__)
+ if (v)
+ {
+ l = 32 -__builtin_clz(v);
+ }
+#elif defined(LZHAM_USE_MSVC_INTRINSICS)
+ if (_BitScanReverse(&l, v))
+ {
+ l++;
+ }
+#else
+ while (v > 0U)
+ {
+ v >>= 1;
+ l++;
+ }
+#endif
+ return l;
+ }
+
+ }
+
+} // namespace lzham
+
diff --git a/r5dev/thirdparty/lzham/include/lzham_mem.h b/r5dev/thirdparty/lzham/include/lzham_mem.h
new file mode 100644
index 00000000..d258efff
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_mem.h
@@ -0,0 +1,112 @@
+// File: lzham_mem.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+namespace lzham
+{
+ void lzham_mem_init();
+
+ void* lzham_malloc(size_t size, size_t* pActual_size = NULL);
+ void* lzham_realloc(void* p, size_t size, size_t* pActual_size = NULL, bool movable = true);
+ void lzham_free(void* p);
+ size_t lzham_msize(void* p);
+
+ template
+ inline T* lzham_new()
+ {
+ T* p = static_cast(lzham_malloc(sizeof(T)));
+ if (!p) return NULL;
+ if (LZHAM_IS_SCALAR_TYPE(T))
+ return p;
+ return helpers::construct(p);
+ }
+
+ template
+ inline T* lzham_new(const A& init0)
+ {
+ T* p = static_cast(lzham_malloc(sizeof(T)));
+ if (!p) return NULL;
+ return new (static_cast(p)) T(init0);
+ }
+
+ template
+ inline T* lzham_new(const A& init0, const B& init1)
+ {
+ T* p = static_cast(lzham_malloc(sizeof(T)));
+ if (!p) return NULL;
+ return new (static_cast(p)) T(init0, init1);
+ }
+
+ template
+ inline T* lzham_new(const A& init0, const B& init1, const C& init2)
+ {
+ T* p = static_cast(lzham_malloc(sizeof(T)));
+ if (!p) return NULL;
+ return new (static_cast(p)) T(init0, init1, init2);
+ }
+
+ template
+ inline T* lzham_new(const A& init0, const B& init1, const C& init2, const D& init3)
+ {
+ T* p = static_cast(lzham_malloc(sizeof(T)));
+ if (!p) return NULL;
+ return new (static_cast(p)) T(init0, init1, init2, init3);
+ }
+
+ template
+ inline T* lzham_new_array(uint32 num)
+ {
+ if (!num) num = 1;
+
+ uint8* q = static_cast(lzham_malloc(LZHAM_MIN_ALLOC_ALIGNMENT + sizeof(T) * num));
+ if (!q)
+ return NULL;
+
+ T* p = reinterpret_cast(q + LZHAM_MIN_ALLOC_ALIGNMENT);
+
+ reinterpret_cast(p)[-1] = num;
+ reinterpret_cast(p)[-2] = ~num;
+
+ if (!LZHAM_IS_SCALAR_TYPE(T))
+ {
+ helpers::construct_array(p, num);
+ }
+ return p;
+ }
+
+ template
+ inline void lzham_delete(T* p)
+ {
+ if (p)
+ {
+ if (!LZHAM_IS_SCALAR_TYPE(T))
+ {
+ helpers::destruct(p);
+ }
+ lzham_free(p);
+ }
+ }
+
+ template
+ inline void lzham_delete_array(T* p)
+ {
+ if (p)
+ {
+ const uint32 num = reinterpret_cast(p)[-1];
+ const uint32 num_check = reinterpret_cast(p)[-2];
+ LZHAM_ASSERT(num && (num == ~num_check));
+ if (num == ~num_check)
+ {
+ if (!LZHAM_IS_SCALAR_TYPE(T))
+ {
+ helpers::destruct_array(p, num);
+ }
+
+ lzham_free(reinterpret_cast(p) - LZHAM_MIN_ALLOC_ALIGNMENT);
+ }
+ }
+ }
+
+ void lzham_print_mem_stats();
+
+} // namespace lzham
diff --git a/r5dev/thirdparty/lzham/include/lzham_null_threading.h b/r5dev/thirdparty/lzham/include/lzham_null_threading.h
new file mode 100644
index 00000000..00fb0337
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_null_threading.h
@@ -0,0 +1,97 @@
+// File: lzham_task_pool_null.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+namespace lzham
+{
+ class semaphore
+ {
+ LZHAM_NO_COPY_OR_ASSIGNMENT_OP(semaphore);
+
+ public:
+ inline semaphore(long initialCount = 0, long maximumCount = 1, const char* pName = NULL)
+ {
+ initialCount, maximumCount, pName;
+ }
+
+ inline ~semaphore()
+ {
+ }
+
+ inline void release(long releaseCount = 1, long *pPreviousCount = NULL)
+ {
+ releaseCount, pPreviousCount;
+ }
+
+ inline bool wait(uint32 milliseconds = UINT32_MAX)
+ {
+ milliseconds;
+ return true;
+ }
+ };
+
+ class task_pool
+ {
+ public:
+ inline task_pool() { }
+ inline task_pool(uint num_threads) { num_threads; }
+ inline ~task_pool() { }
+
+ inline bool init(uint num_threads) { num_threads; return true; }
+ inline void deinit();
+
+ inline uint get_num_threads() const { return 0; }
+ inline uint get_num_outstanding_tasks() const { return 0; }
+
+ // C-style task callback
+ typedef void (*task_callback_func)(uint64 data, void* pData_ptr);
+ inline bool queue_task(task_callback_func pFunc, uint64 data = 0, void* pData_ptr = NULL)
+ {
+ pFunc(data, pData_ptr);
+ return true;
+ }
+
+ class executable_task
+ {
+ public:
+ virtual void execute_task(uint64 data, void* pData_ptr) = 0;
+ };
+
+ // It's the caller's responsibility to delete pObj within the execute_task() method, if needed!
+ inline bool queue_task(executable_task* pObj, uint64 data = 0, void* pData_ptr = NULL)
+ {
+ pObj->execute_task(data, pData_ptr);
+ return true;
+ }
+
+ template
+ inline bool queue_object_task(S* pObject, T pObject_method, uint64 data = 0, void* pData_ptr = NULL)
+ {
+ (pObject->*pObject_method)(data, pData_ptr);
+ return true;
+ }
+
+ template
+ inline bool queue_multiple_object_tasks(S* pObject, T pObject_method, uint64 first_data, uint num_tasks, void* pData_ptr = NULL)
+ {
+ for (uint i = 0; i < num_tasks; i++)
+ {
+ (pObject->*pObject_method)(first_data + i, pData_ptr);
+ }
+ return true;
+ }
+
+ void join() { }
+ };
+
+ inline void lzham_sleep(unsigned int milliseconds)
+ {
+ milliseconds;
+ }
+
+ inline uint lzham_get_max_helper_threads()
+ {
+ return 0;
+ }
+
+} // namespace lzham
diff --git a/r5dev/thirdparty/lzham/include/lzham_platform.h b/r5dev/thirdparty/lzham/include/lzham_platform.h
new file mode 100644
index 00000000..0cc58beb
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_platform.h
@@ -0,0 +1,284 @@
+// File: lzham_platform.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+bool lzham_is_debugger_present(void);
+void lzham_debug_break(void);
+void lzham_output_debug_string(const char* p);
+
+// actually in lzham_assert.cpp
+void lzham_assert(const char* pExp, const char* pFile, unsigned line);
+void lzham_fail(const char* pExp, const char* pFile, unsigned line);
+
+#ifdef WIN32
+ #define LZHAM_BREAKPOINT DebuggerBreak();
+ #define LZHAM_BUILTIN_EXPECT(c, v) c
+#elif defined(__GNUC__)
+ #define LZHAM_BREAKPOINT asm("int $3");
+ #define LZHAM_BUILTIN_EXPECT(c, v) __builtin_expect(c, v)
+#else
+ #define LZHAM_BREAKPOINT
+ #define LZHAM_BUILTIN_EXPECT(c, v) c
+#endif
+
+#if defined(__GNUC__) && LZHAM_PLATFORM_PC
+extern __inline__ __attribute__((__always_inline__,__gnu_inline__)) void lzham_yield_processor()
+{
+ __asm__ __volatile__("pause");
+}
+#elif LZHAM_PLATFORM_X360
+#define lzham_yield_processor() \
+ YieldProcessor(); \
+ __asm { or r0, r0, r0 } \
+ YieldProcessor(); \
+ __asm { or r1, r1, r1 } \
+ YieldProcessor(); \
+ __asm { or r0, r0, r0 } \
+ YieldProcessor(); \
+ __asm { or r1, r1, r1 } \
+ YieldProcessor(); \
+ __asm { or r0, r0, r0 } \
+ YieldProcessor(); \
+ __asm { or r1, r1, r1 } \
+ YieldProcessor(); \
+ __asm { or r0, r0, r0 } \
+ YieldProcessor(); \
+ __asm { or r1, r1, r1 }
+#else
+LZHAM_FORCE_INLINE void lzham_yield_processor()
+{
+#if LZHAM_USE_MSVC_INTRINSICS
+ #if LZHAM_PLATFORM_PC_X64
+ _mm_pause();
+ #else
+ YieldProcessor();
+ #endif
+#else
+ // No implementation
+#endif
+}
+#endif
+
+#ifndef _MSC_VER
+ int sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, ...);
+ int vsprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, va_list args);
+#endif
+
+#if LZHAM_PLATFORM_X360
+ #define LZHAM_MEMORY_EXPORT_BARRIER MemoryBarrier();
+#else
+ // Barriers shouldn't be necessary on x86/x64.
+ // TODO: Should use __sync_synchronize() on other platforms that support GCC.
+ #define LZHAM_MEMORY_EXPORT_BARRIER
+#endif
+
+#if LZHAM_PLATFORM_X360
+ #define LZHAM_MEMORY_IMPORT_BARRIER MemoryBarrier();
+#else
+ // Barriers shouldn't be necessary on x86/x64.
+ // TODO: Should use __sync_synchronize() on other platforms that support GCC.
+ #define LZHAM_MEMORY_IMPORT_BARRIER
+#endif
+
+// Note: It's very important that LZHAM_READ_BIG_ENDIAN_UINT32() is fast on the target platform.
+// This is used to read every DWORD from the input stream.
+
+#if LZHAM_USE_UNALIGNED_INT_LOADS
+ #if LZHAM_BIG_ENDIAN_CPU
+ #define LZHAM_READ_BIG_ENDIAN_UINT32(p) *reinterpret_cast(p)
+ #else
+ #if defined(LZHAM_USE_MSVC_INTRINSICS)
+ #define LZHAM_READ_BIG_ENDIAN_UINT32(p) _byteswap_ulong(*reinterpret_cast(p))
+ #elif defined(__GNUC__)
+ #define LZHAM_READ_BIG_ENDIAN_UINT32(p) __builtin_bswap32(*reinterpret_cast(p))
+ #else
+ #define LZHAM_READ_BIG_ENDIAN_UINT32(p) utils::swap32(*reinterpret_cast(p))
+ #endif
+ #endif
+#else
+ #define LZHAM_READ_BIG_ENDIAN_UINT32(p) ((reinterpret_cast(p)[0] << 24) | (reinterpret_cast(p)[1] << 16) | (reinterpret_cast(p)[2] << 8) | (reinterpret_cast(p)[3]))
+#endif
+
+#if LZHAM_USE_WIN32_ATOMIC_FUNCTIONS
+ extern "C" __int64 _InterlockedCompareExchange64(__int64 volatile * Destination, __int64 Exchange, __int64 Comperand);
+ #if defined(_MSC_VER)
+ #pragma intrinsic(_InterlockedCompareExchange64)
+ #endif
+#endif // LZHAM_USE_WIN32_ATOMIC_FUNCTIONS
+
+namespace lzham
+{
+#if LZHAM_USE_WIN32_ATOMIC_FUNCTIONS
+ typedef LONG atomic32_t;
+ typedef LONGLONG atomic64_t;
+
+ // Returns the original value.
+ inline atomic32_t atomic_compare_exchange32(atomic32_t volatile *pDest, atomic32_t exchange, atomic32_t comparand)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ return InterlockedCompareExchange(pDest, exchange, comparand);
+ }
+
+ // Returns the original value.
+ inline atomic64_t atomic_compare_exchange64(atomic64_t volatile *pDest, atomic64_t exchange, atomic64_t comparand)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 7) == 0);
+ return _InterlockedCompareExchange64(pDest, exchange, comparand);
+ }
+
+ // Returns the resulting incremented value.
+ inline atomic32_t atomic_increment32(atomic32_t volatile *pDest)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ return InterlockedIncrement(pDest);
+ }
+
+ // Returns the resulting decremented value.
+ inline atomic32_t atomic_decrement32(atomic32_t volatile *pDest)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ return InterlockedDecrement(pDest);
+ }
+
+ // Returns the original value.
+ inline atomic32_t atomic_exchange32(atomic32_t volatile *pDest, atomic32_t val)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ return InterlockedExchange(pDest, val);
+ }
+
+ // Returns the resulting value.
+ inline atomic32_t atomic_add32(atomic32_t volatile *pDest, atomic32_t val)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ return InterlockedExchangeAdd(pDest, val) + val;
+ }
+
+ // Returns the original value.
+ inline atomic32_t atomic_exchange_add(atomic32_t volatile *pDest, atomic32_t val)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ return InterlockedExchangeAdd(pDest, val);
+ }
+#elif LZHAM_USE_GCC_ATOMIC_BUILTINS
+ typedef long atomic32_t;
+ typedef long long atomic64_t;
+
+ // Returns the original value.
+ inline atomic32_t atomic_compare_exchange32(atomic32_t volatile *pDest, atomic32_t exchange, atomic32_t comparand)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ return __sync_val_compare_and_swap(pDest, comparand, exchange);
+ }
+
+ // Returns the original value.
+ inline atomic64_t atomic_compare_exchange64(atomic64_t volatile *pDest, atomic64_t exchange, atomic64_t comparand)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 7) == 0);
+ return __sync_val_compare_and_swap(pDest, comparand, exchange);
+ }
+
+ // Returns the resulting incremented value.
+ inline atomic32_t atomic_increment32(atomic32_t volatile *pDest)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ return __sync_add_and_fetch(pDest, 1);
+ }
+
+ // Returns the resulting decremented value.
+ inline atomic32_t atomic_decrement32(atomic32_t volatile *pDest)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ return __sync_sub_and_fetch(pDest, 1);
+ }
+
+ // Returns the original value.
+ inline atomic32_t atomic_exchange32(atomic32_t volatile *pDest, atomic32_t val)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ return __sync_lock_test_and_set(pDest, val);
+ }
+
+ // Returns the resulting value.
+ inline atomic32_t atomic_add32(atomic32_t volatile *pDest, atomic32_t val)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ return __sync_add_and_fetch(pDest, val);
+ }
+
+ // Returns the original value.
+ inline atomic32_t atomic_exchange_add(atomic32_t volatile *pDest, atomic32_t val)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ return __sync_fetch_and_add(pDest, val);
+ }
+#else
+ #define LZHAM_NO_ATOMICS 1
+
+ // Atomic ops not supported - but try to do something reasonable. Assumes no threading at all.
+ typedef long atomic32_t;
+ typedef long long atomic64_t;
+
+ inline atomic32_t atomic_compare_exchange32(atomic32_t volatile *pDest, atomic32_t exchange, atomic32_t comparand)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ atomic32_t cur = *pDest;
+ if (cur == comparand)
+ *pDest = exchange;
+ return cur;
+ }
+
+ inline atomic64_t atomic_compare_exchange64(atomic64_t volatile *pDest, atomic64_t exchange, atomic64_t comparand)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 7) == 0);
+ atomic64_t cur = *pDest;
+ if (cur == comparand)
+ *pDest = exchange;
+ return cur;
+ }
+
+ inline atomic32_t atomic_increment32(atomic32_t volatile *pDest)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ return (*pDest += 1);
+ }
+
+ inline atomic32_t atomic_decrement32(atomic32_t volatile *pDest)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ return (*pDest -= 1);
+ }
+
+ inline atomic32_t atomic_exchange32(atomic32_t volatile *pDest, atomic32_t val)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ atomic32_t cur = *pDest;
+ *pDest = val;
+ return cur;
+ }
+
+ inline atomic32_t atomic_add32(atomic32_t volatile *pDest, atomic32_t val)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ return (*pDest += val);
+ }
+
+ inline atomic32_t atomic_exchange_add(atomic32_t volatile *pDest, atomic32_t val)
+ {
+ LZHAM_ASSERT((reinterpret_cast(pDest) & 3) == 0);
+ atomic32_t cur = *pDest;
+ *pDest += val;
+ return cur;
+ }
+
+#endif
+
+#if LZHAM_BUFFERED_PRINTF
+ void lzham_buffered_printf(const char *format, ...);
+ void lzham_flush_buffered_printf();
+#else
+ inline void lzham_buffered_printf(const char *format, ...) { (void)format; }
+ inline void lzham_flush_buffered_printf() { }
+#endif
+
+} // namespace lzham
diff --git a/r5dev/thirdparty/lzham/include/lzham_polar_codes.h b/r5dev/thirdparty/lzham/include/lzham_polar_codes.h
new file mode 100644
index 00000000..c478d9d6
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_polar_codes.h
@@ -0,0 +1,14 @@
+// File: lzham_polar_codes.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+namespace lzham
+{
+ //const uint cPolarMaxSupportedSyms = 600;
+ const uint cPolarMaxSupportedSyms = 1024;
+
+ uint get_generate_polar_codes_table_size();
+
+ bool generate_polar_codes(void* pContext, uint num_syms, const uint16* pFreq, uint8* pCodesizes, uint& max_code_size, uint& total_freq_ret);
+
+} // namespace lzham
diff --git a/r5dev/thirdparty/lzham/include/lzham_prefix_coding.h b/r5dev/thirdparty/lzham/include/lzham_prefix_coding.h
new file mode 100644
index 00000000..a22903d6
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_prefix_coding.h
@@ -0,0 +1,144 @@
+// File: lzham_prefix_coding.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+namespace lzham
+{
+ namespace prefix_coding
+ {
+ const uint cMaxExpectedCodeSize = 16;
+ const uint cMaxSupportedSyms = 1024;
+ const uint cMaxTableBits = 11;
+
+ bool limit_max_code_size(uint num_syms, uint8* pCodesizes, uint max_code_size);
+
+ bool generate_codes(uint num_syms, const uint8* pCodesizes, uint16* pCodes);
+
+ class decoder_tables
+ {
+ public:
+ inline decoder_tables() :
+ m_table_shift(0), m_table_max_code(0), m_decode_start_code_size(0), m_cur_lookup_size(0), m_lookup(NULL), m_cur_sorted_symbol_order_size(0), m_sorted_symbol_order(NULL)
+ {
+ }
+
+ inline decoder_tables(const decoder_tables& other) :
+ m_table_shift(0), m_table_max_code(0), m_decode_start_code_size(0), m_cur_lookup_size(0), m_lookup(NULL), m_cur_sorted_symbol_order_size(0), m_sorted_symbol_order(NULL)
+ {
+ *this = other;
+ }
+
+ inline decoder_tables& operator= (const decoder_tables& rhs)
+ {
+ assign(rhs);
+ return *this;
+ }
+
+ inline bool assign(const decoder_tables& rhs)
+ {
+ if (this == &rhs)
+ return true;
+
+ uint32* pCur_lookup = m_lookup;
+ uint16* pCur_sorted_symbol_order = m_sorted_symbol_order;
+
+ memcpy(this, &rhs, sizeof(*this));
+
+ if ((pCur_lookup) && (pCur_sorted_symbol_order) && (rhs.m_cur_lookup_size == m_cur_lookup_size) && (rhs.m_cur_sorted_symbol_order_size == m_cur_sorted_symbol_order_size))
+ {
+ m_lookup = pCur_lookup;
+ m_sorted_symbol_order = pCur_sorted_symbol_order;
+
+ memcpy(m_lookup, rhs.m_lookup, sizeof(m_lookup[0]) * m_cur_lookup_size);
+ memcpy(m_sorted_symbol_order, rhs.m_sorted_symbol_order, sizeof(m_sorted_symbol_order[0]) * m_cur_sorted_symbol_order_size);
+ }
+ else
+ {
+ lzham_delete_array(pCur_lookup);
+ m_lookup = NULL;
+
+ if (rhs.m_lookup)
+ {
+ m_lookup = lzham_new_array(m_cur_lookup_size);
+ if (!m_lookup)
+ return false;
+ memcpy(m_lookup, rhs.m_lookup, sizeof(m_lookup[0]) * m_cur_lookup_size);
+ }
+
+ lzham_delete_array(pCur_sorted_symbol_order);
+ m_sorted_symbol_order = NULL;
+
+ if (rhs.m_sorted_symbol_order)
+ {
+ m_sorted_symbol_order = lzham_new_array(m_cur_sorted_symbol_order_size);
+ if (!m_sorted_symbol_order)
+ return false;
+ memcpy(m_sorted_symbol_order, rhs.m_sorted_symbol_order, sizeof(m_sorted_symbol_order[0]) * m_cur_sorted_symbol_order_size);
+ }
+ }
+
+ return true;
+ }
+
+ inline void clear()
+ {
+ if (m_lookup)
+ {
+ lzham_delete_array(m_lookup);
+ m_lookup = 0;
+ m_cur_lookup_size = 0;
+ }
+
+ if (m_sorted_symbol_order)
+ {
+ lzham_delete_array(m_sorted_symbol_order);
+ m_sorted_symbol_order = NULL;
+ m_cur_sorted_symbol_order_size = 0;
+ }
+ }
+
+ inline ~decoder_tables()
+ {
+ if (m_lookup)
+ lzham_delete_array(m_lookup);
+
+ if (m_sorted_symbol_order)
+ lzham_delete_array(m_sorted_symbol_order);
+ }
+
+ // DO NOT use any complex classes here - it is bitwise copied.
+
+ uint m_num_syms;
+ uint m_total_used_syms;
+ uint m_table_bits;
+ uint m_table_shift;
+ uint m_table_max_code;
+ uint m_decode_start_code_size;
+
+ uint8 m_min_code_size;
+ uint8 m_max_code_size;
+
+ uint m_max_codes[cMaxExpectedCodeSize + 1];
+ int m_val_ptrs[cMaxExpectedCodeSize + 1];
+
+ uint m_cur_lookup_size;
+ uint32* m_lookup;
+
+ uint m_cur_sorted_symbol_order_size;
+ uint16* m_sorted_symbol_order;
+
+ inline uint get_unshifted_max_code(uint len) const
+ {
+ LZHAM_ASSERT( (len >= 1) && (len <= cMaxExpectedCodeSize) );
+ uint k = m_max_codes[len - 1];
+ if (!k)
+ return UINT_MAX;
+ return (k - 1) >> (16 - len);
+ }
+ };
+
+ bool generate_decoder_tables(uint num_syms, const uint8* pCodesizes, decoder_tables* pTables, uint table_bits);
+
+ } // namespace prefix_coding
+
+} // namespace lzham
diff --git a/r5dev/thirdparty/lzham/include/lzham_pthreads_threading.h b/r5dev/thirdparty/lzham/include/lzham_pthreads_threading.h
new file mode 100644
index 00000000..fe1de038
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_pthreads_threading.h
@@ -0,0 +1,383 @@
+// File: lzham_task_pool_pthreads.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+#if LZHAM_USE_PTHREADS_API
+
+#if LZHAM_NO_ATOMICS
+#error No atomic operations defined in lzham_platform.h!
+#endif
+
+#include
+#include
+#include
+
+namespace lzham
+{
+ class semaphore
+ {
+ LZHAM_NO_COPY_OR_ASSIGNMENT_OP(semaphore);
+
+ public:
+ inline semaphore(long initialCount = 0, long maximumCount = 1, const char* pName = NULL)
+ {
+ LZHAM_NOTE_UNUSED(maximumCount), LZHAM_NOTE_UNUSED(pName);
+ LZHAM_ASSERT(maximumCount >= initialCount);
+ if (sem_init(&m_sem, 0, initialCount))
+ {
+ LZHAM_FAIL("semaphore: sem_init() failed");
+ }
+ }
+
+ inline ~semaphore()
+ {
+ sem_destroy(&m_sem);
+ }
+
+ inline void release(long releaseCount = 1)
+ {
+ LZHAM_ASSERT(releaseCount >= 1);
+
+ int status = 0;
+#ifdef WIN32
+ if (1 == releaseCount)
+ status = sem_post(&m_sem);
+ else
+ status = sem_post_multiple(&m_sem, releaseCount);
+#else
+ while (releaseCount > 0)
+ {
+ status = sem_post(&m_sem);
+ if (status)
+ break;
+ releaseCount--;
+ }
+#endif
+
+ if (status)
+ {
+ LZHAM_FAIL("semaphore: sem_post() or sem_post_multiple() failed");
+ }
+ }
+
+ inline bool wait(uint32 milliseconds = UINT32_MAX)
+ {
+ int status;
+ if (milliseconds == UINT32_MAX)
+ {
+ status = sem_wait(&m_sem);
+ }
+ else
+ {
+ struct timespec interval;
+ interval.tv_sec = milliseconds / 1000;
+ interval.tv_nsec = (milliseconds % 1000) * 1000000L;
+ status = sem_timedwait(&m_sem, &interval);
+ }
+
+ if (status)
+ {
+ if (errno != ETIMEDOUT)
+ {
+ LZHAM_FAIL("semaphore: sem_wait() or sem_timedwait() failed");
+ }
+ return false;
+ }
+
+ return true;
+ }
+
+ private:
+ sem_t m_sem;
+ };
+
+ class spinlock
+ {
+ public:
+ inline spinlock()
+ {
+ if (pthread_spin_init(&m_spinlock, 0))
+ {
+ LZHAM_FAIL("spinlock: pthread_spin_init() failed");
+ }
+ }
+
+ inline ~spinlock()
+ {
+ pthread_spin_destroy(&m_spinlock);
+ }
+
+ inline void lock()
+ {
+ if (pthread_spin_lock(&m_spinlock))
+ {
+ LZHAM_FAIL("spinlock: pthread_spin_lock() failed");
+ }
+ }
+
+ inline void unlock()
+ {
+ if (pthread_spin_unlock(&m_spinlock))
+ {
+ LZHAM_FAIL("spinlock: pthread_spin_unlock() failed");
+ }
+ }
+
+ private:
+ pthread_spinlock_t m_spinlock;
+ };
+
+ template
+ class tsstack
+ {
+ public:
+ inline tsstack() : m_top(0)
+ {
+ }
+
+ inline ~tsstack()
+ {
+ }
+
+ inline void clear()
+ {
+ m_spinlock.lock();
+ m_top = 0;
+ m_spinlock.unlock();
+ }
+
+ inline bool try_push(const T& obj)
+ {
+ bool result = false;
+ m_spinlock.lock();
+ if (m_top < (int)cMaxSize)
+ {
+ m_stack[m_top++] = obj;
+ result = true;
+ }
+ m_spinlock.unlock();
+ return result;
+ }
+
+ inline bool pop(T& obj)
+ {
+ bool result = false;
+ m_spinlock.lock();
+ if (m_top > 0)
+ {
+ obj = m_stack[--m_top];
+ result = true;
+ }
+ m_spinlock.unlock();
+ return result;
+ }
+
+ private:
+ spinlock m_spinlock;
+ T m_stack[cMaxSize];
+ int m_top;
+ };
+
+ class task_pool
+ {
+ public:
+ task_pool();
+ task_pool(uint num_threads);
+ ~task_pool();
+
+ enum { cMaxThreads = LZHAM_MAX_HELPER_THREADS };
+ bool init(uint num_threads);
+ void deinit();
+
+ inline uint get_num_threads() const { return m_num_threads; }
+ inline uint get_num_outstanding_tasks() const { return m_num_outstanding_tasks; }
+
+ // C-style task callback
+ typedef void (*task_callback_func)(uint64 data, void* pData_ptr);
+ bool queue_task(task_callback_func pFunc, uint64 data = 0, void* pData_ptr = NULL);
+
+ class executable_task
+ {
+ public:
+ virtual void execute_task(uint64 data, void* pData_ptr) = 0;
+ };
+
+ // It's the caller's responsibility to delete pObj within the execute_task() method, if needed!
+ bool queue_task(executable_task* pObj, uint64 data = 0, void* pData_ptr = NULL);
+
+ template
+ inline bool queue_object_task(S* pObject, T pObject_method, uint64 data = 0, void* pData_ptr = NULL);
+
+ template
+ inline bool queue_multiple_object_tasks(S* pObject, T pObject_method, uint64 first_data, uint num_tasks, void* pData_ptr = NULL);
+
+ void join();
+
+ private:
+ struct task
+ {
+ inline task() : m_data(0), m_pData_ptr(NULL), m_pObj(NULL), m_flags(0) { }
+
+ uint64 m_data;
+ void* m_pData_ptr;
+
+ union
+ {
+ task_callback_func m_callback;
+ executable_task* m_pObj;
+ };
+
+ uint m_flags;
+ };
+
+ tsstack m_task_stack;
+
+ uint m_num_threads;
+ pthread_t m_threads[cMaxThreads];
+
+ semaphore m_tasks_available;
+
+ enum task_flags
+ {
+ cTaskFlagObject = 1
+ };
+
+ volatile atomic32_t m_num_outstanding_tasks;
+ volatile atomic32_t m_exit_flag;
+
+ void process_task(task& tsk);
+
+ static void* thread_func(void *pContext);
+ };
+
+ enum object_task_flags
+ {
+ cObjectTaskFlagDefault = 0,
+ cObjectTaskFlagDeleteAfterExecution = 1
+ };
+
+ template
+ class object_task : public task_pool::executable_task
+ {
+ public:
+ object_task(uint flags = cObjectTaskFlagDefault) :
+ m_pObject(NULL),
+ m_pMethod(NULL),
+ m_flags(flags)
+ {
+ }
+
+ typedef void (T::*object_method_ptr)(uint64 data, void* pData_ptr);
+
+ object_task(T* pObject, object_method_ptr pMethod, uint flags = cObjectTaskFlagDefault) :
+ m_pObject(pObject),
+ m_pMethod(pMethod),
+ m_flags(flags)
+ {
+ LZHAM_ASSERT(pObject && pMethod);
+ }
+
+ void init(T* pObject, object_method_ptr pMethod, uint flags = cObjectTaskFlagDefault)
+ {
+ LZHAM_ASSERT(pObject && pMethod);
+
+ m_pObject = pObject;
+ m_pMethod = pMethod;
+ m_flags = flags;
+ }
+
+ T* get_object() const { return m_pObject; }
+ object_method_ptr get_method() const { return m_pMethod; }
+
+ virtual void execute_task(uint64 data, void* pData_ptr)
+ {
+ (m_pObject->*m_pMethod)(data, pData_ptr);
+
+ if (m_flags & cObjectTaskFlagDeleteAfterExecution)
+ lzham_delete(this);
+ }
+
+ protected:
+ T* m_pObject;
+
+ object_method_ptr m_pMethod;
+
+ uint m_flags;
+ };
+
+ template
+ inline bool task_pool::queue_object_task(S* pObject, T pObject_method, uint64 data, void* pData_ptr)
+ {
+ object_task *pTask = lzham_new< object_task >(pObject, pObject_method, cObjectTaskFlagDeleteAfterExecution);
+ if (!pTask)
+ return false;
+ return queue_task(pTask, data, pData_ptr);
+ }
+
+ template
+ inline bool task_pool::queue_multiple_object_tasks(S* pObject, T pObject_method, uint64 first_data, uint num_tasks, void* pData_ptr)
+ {
+ LZHAM_ASSERT(m_num_threads);
+ LZHAM_ASSERT(pObject);
+ LZHAM_ASSERT(num_tasks);
+ if (!num_tasks)
+ return true;
+
+ bool status = true;
+
+ uint i;
+ for (i = 0; i < num_tasks; i++)
+ {
+ task tsk;
+
+ tsk.m_pObj = lzham_new< object_task >(pObject, pObject_method, cObjectTaskFlagDeleteAfterExecution);
+ if (!tsk.m_pObj)
+ {
+ status = false;
+ break;
+ }
+
+ tsk.m_data = first_data + i;
+ tsk.m_pData_ptr = pData_ptr;
+ tsk.m_flags = cTaskFlagObject;
+
+ if (!m_task_stack.try_push(tsk))
+ {
+ status = false;
+ break;
+ }
+ }
+
+ if (i)
+ {
+ atomic_add32(&m_num_outstanding_tasks, i);
+
+ m_tasks_available.release(i);
+ }
+
+ return status;
+ }
+
+ inline void lzham_sleep(unsigned int milliseconds)
+ {
+#ifdef WIN32
+ struct timespec interval;
+ interval.tv_sec = milliseconds / 1000;
+ interval.tv_nsec = (milliseconds % 1000) * 1000000L;
+ pthread_delay_np(&interval);
+#else
+ while (milliseconds)
+ {
+ int msecs_to_sleep = LZHAM_MIN(milliseconds, 1000);
+ usleep(msecs_to_sleep * 1000);
+ milliseconds -= msecs_to_sleep;
+ }
+#endif
+ }
+
+ // TODO: Implement
+ uint lzham_get_max_helper_threads();
+
+} // namespace lzham
+
+#endif // LZHAM_USE_PTHREADS_API
diff --git a/r5dev/thirdparty/lzham/include/lzham_symbol_codec.h b/r5dev/thirdparty/lzham/include/lzham_symbol_codec.h
new file mode 100644
index 00000000..824a4c74
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_symbol_codec.h
@@ -0,0 +1,556 @@
+// File: lzham_symbol_codec.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+#include "lzham_prefix_coding.h"
+
+namespace lzham
+{
+ class symbol_codec;
+ class adaptive_arith_data_model;
+
+ const uint cSymbolCodecArithMinLen = 0x01000000U;
+ const uint cSymbolCodecArithMaxLen = 0xFFFFFFFFU;
+
+ const uint cSymbolCodecArithProbBits = 11;
+ const uint cSymbolCodecArithProbScale = 1 << cSymbolCodecArithProbBits;
+ const uint cSymbolCodecArithProbHalfScale = 1 << (cSymbolCodecArithProbBits - 1);
+ const uint cSymbolCodecArithProbMoveBits = 5;
+
+ typedef uint64 bit_cost_t;
+ const uint32 cBitCostScaleShift = 24;
+ const uint32 cBitCostScale = (1U << cBitCostScaleShift);
+ const bit_cost_t cBitCostMax = UINT64_MAX;
+
+ inline bit_cost_t convert_to_scaled_bitcost(uint bits) { LZHAM_ASSERT(bits <= 255); uint32 scaled_bits = bits << cBitCostScaleShift; return static_cast(scaled_bits); }
+
+ extern uint32 g_prob_cost[cSymbolCodecArithProbScale];
+
+ class raw_quasi_adaptive_huffman_data_model
+ {
+ public:
+ raw_quasi_adaptive_huffman_data_model(bool encoding = true, uint total_syms = 0, bool fast_encoding = false, bool use_polar_codes = false);
+ raw_quasi_adaptive_huffman_data_model(const raw_quasi_adaptive_huffman_data_model& other);
+ ~raw_quasi_adaptive_huffman_data_model();
+
+ bool assign(const raw_quasi_adaptive_huffman_data_model& rhs);
+ raw_quasi_adaptive_huffman_data_model& operator= (const raw_quasi_adaptive_huffman_data_model& rhs);
+
+ void clear();
+
+ bool init(bool encoding, uint total_syms, bool fast_encoding, bool use_polar_codes, const uint16 *pInitial_sym_freq = NULL);
+ bool reset();
+
+ inline uint get_total_syms() const { return m_total_syms; }
+
+ void rescale();
+ void reset_update_rate();
+
+ bool update(uint sym);
+
+ inline bit_cost_t get_cost(uint sym) const { return convert_to_scaled_bitcost(m_code_sizes[sym]); }
+
+ public:
+ lzham::vector m_initial_sym_freq;
+
+ lzham::vector m_sym_freq;
+
+ lzham::vector m_codes;
+ lzham::vector m_code_sizes;
+
+ prefix_coding::decoder_tables* m_pDecode_tables;
+
+ uint m_total_syms;
+
+ uint m_max_cycle;
+ uint m_update_cycle;
+ uint m_symbols_until_update;
+
+ uint m_total_count;
+
+ uint8 m_decoder_table_bits;
+ bool m_encoding;
+ bool m_fast_updating;
+ bool m_use_polar_codes;
+
+ bool update();
+
+ friend class symbol_codec;
+ };
+
+ struct quasi_adaptive_huffman_data_model : public raw_quasi_adaptive_huffman_data_model
+ {
+#if LZHAM_64BIT_POINTERS
+ // Ensures sizeof(quasi_adaptive_huffman_data_model) is 128 bytes on x64 (it's 64 on x86).
+ char m_unused_alignment[128 - sizeof(raw_quasi_adaptive_huffman_data_model)];
+#endif
+ };
+
+ class adaptive_bit_model
+ {
+ public:
+ adaptive_bit_model();
+ adaptive_bit_model(float prob0);
+ adaptive_bit_model(const adaptive_bit_model& other);
+
+ inline adaptive_bit_model& operator= (const adaptive_bit_model& rhs) { m_bit_0_prob = rhs.m_bit_0_prob; return *this; }
+
+ inline void clear() { m_bit_0_prob = 1U << (cSymbolCodecArithProbBits - 1); }
+
+ void set_probability_0(float prob0);
+
+ inline void update(uint bit)
+ {
+ if (!bit)
+ m_bit_0_prob += ((cSymbolCodecArithProbScale - m_bit_0_prob) >> cSymbolCodecArithProbMoveBits);
+ else
+ m_bit_0_prob -= (m_bit_0_prob >> cSymbolCodecArithProbMoveBits);
+ LZHAM_ASSERT(m_bit_0_prob >= 1);
+ LZHAM_ASSERT(m_bit_0_prob < cSymbolCodecArithProbScale);
+ }
+
+ inline bit_cost_t get_cost(uint bit) const { return g_prob_cost[bit ? (cSymbolCodecArithProbScale - m_bit_0_prob) : m_bit_0_prob]; }
+
+ public:
+ uint16 m_bit_0_prob;
+
+ friend class symbol_codec;
+ friend class adaptive_arith_data_model;
+ };
+
+ // This class is not actually used by LZHAM - it's only here for comparison/experimental purposes.
+ class adaptive_arith_data_model
+ {
+ public:
+ adaptive_arith_data_model(bool encoding = true, uint total_syms = 0);
+ adaptive_arith_data_model(const adaptive_arith_data_model& other);
+ ~adaptive_arith_data_model();
+
+ adaptive_arith_data_model& operator= (const adaptive_arith_data_model& rhs);
+
+ void clear();
+
+ bool init(bool encoding, uint total_syms);
+ bool init(bool encoding, uint total_syms, bool fast_encoding, bool use_polar_codes = false) { LZHAM_NOTE_UNUSED(fast_encoding), LZHAM_NOTE_UNUSED(use_polar_codes); return init(encoding, total_syms); }
+ void reset();
+
+ void reset_update_rate();
+
+ bool update(uint sym);
+
+ uint get_total_syms() const { return m_total_syms; }
+ bit_cost_t get_cost(uint sym) const;
+
+ public:
+ uint m_total_syms;
+ typedef lzham::vector adaptive_bit_model_vector;
+ adaptive_bit_model_vector m_probs;
+
+ friend class symbol_codec;
+ };
+
+#if LZHAM_CPU_HAS_64BIT_REGISTERS
+ #define LZHAM_SYMBOL_CODEC_USE_64_BIT_BUFFER 1
+#else
+ #define LZHAM_SYMBOL_CODEC_USE_64_BIT_BUFFER 0
+#endif
+
+ class symbol_codec
+ {
+ public:
+ symbol_codec();
+
+ void reset();
+
+ // clear() is like reset(), except it also frees all memory.
+ void clear();
+
+ // Encoding
+ bool start_encoding(uint expected_file_size);
+ bool encode_bits(uint bits, uint num_bits);
+ bool encode_arith_init();
+ bool encode_align_to_byte();
+ bool encode(uint sym, quasi_adaptive_huffman_data_model& model);
+ bool encode(uint bit, adaptive_bit_model& model, bool update_model = true);
+ bool encode(uint sym, adaptive_arith_data_model& model);
+
+ inline uint encode_get_total_bits_written() const { return m_total_bits_written; }
+
+ bool stop_encoding(bool support_arith);
+
+ const lzham::vector& get_encoding_buf() const { return m_output_buf; }
+ lzham::vector& get_encoding_buf() { return m_output_buf; }
+
+ // Decoding
+
+ typedef void (*need_bytes_func_ptr)(size_t num_bytes_consumed, void *pPrivate_data, const uint8* &pBuf, size_t &buf_size, bool &eof_flag);
+
+ bool start_decoding(const uint8* pBuf, size_t buf_size, bool eof_flag = true, need_bytes_func_ptr pNeed_bytes_func = NULL, void *pPrivate_data = NULL);
+
+ inline void decode_set_input_buffer(const uint8* pBuf, size_t buf_size, const uint8* pBuf_next, bool eof_flag)
+ {
+ m_pDecode_buf = pBuf;
+ m_pDecode_buf_next = pBuf_next;
+ m_decode_buf_size = buf_size;
+ m_pDecode_buf_end = pBuf + buf_size;
+ m_decode_buf_eof = eof_flag;
+ }
+ inline uint64 decode_get_bytes_consumed() const { return m_pDecode_buf_next - m_pDecode_buf; }
+ inline uint64 decode_get_bits_remaining() const { return ((m_pDecode_buf_end - m_pDecode_buf_next) << 3) + m_bit_count; }
+
+ void start_arith_decoding();
+ uint decode_bits(uint num_bits);
+ uint decode_peek_bits(uint num_bits);
+ void decode_remove_bits(uint num_bits);
+ void decode_align_to_byte();
+ int decode_remove_byte_from_bit_buf();
+ uint decode(quasi_adaptive_huffman_data_model& model);
+ uint decode(adaptive_bit_model& model, bool update_model = true);
+ uint decode(adaptive_arith_data_model& model);
+ uint64 stop_decoding();
+
+ uint get_total_model_updates() const { return m_total_model_updates; }
+
+ public:
+ const uint8* m_pDecode_buf;
+ const uint8* m_pDecode_buf_next;
+ const uint8* m_pDecode_buf_end;
+ size_t m_decode_buf_size;
+ bool m_decode_buf_eof;
+
+ need_bytes_func_ptr m_pDecode_need_bytes_func;
+ void* m_pDecode_private_data;
+
+#if LZHAM_SYMBOL_CODEC_USE_64_BIT_BUFFER
+ typedef uint64 bit_buf_t;
+ enum { cBitBufSize = 64 };
+#else
+ typedef uint32 bit_buf_t;
+ enum { cBitBufSize = 32 };
+#endif
+
+ bit_buf_t m_bit_buf;
+ int m_bit_count;
+
+ uint m_total_model_updates;
+
+ lzham::vector m_output_buf;
+ lzham::vector m_arith_output_buf;
+
+ struct output_symbol
+ {
+ uint m_bits;
+
+ enum
+ {
+ cArithSym = -1,
+ cAlignToByteSym = -2,
+ cArithInit = -3
+ };
+ int16 m_num_bits;
+
+ uint16 m_arith_prob0;
+ };
+ lzham::vector m_output_syms;
+
+ uint m_total_bits_written;
+
+ uint m_arith_base;
+ uint m_arith_value;
+ uint m_arith_length;
+ uint m_arith_total_bits;
+
+ quasi_adaptive_huffman_data_model* m_pSaved_huff_model;
+ void* m_pSaved_model;
+ uint m_saved_node_index;
+
+ bool put_bits_init(uint expected_size);
+ bool record_put_bits(uint bits, uint num_bits);
+
+ void arith_propagate_carry();
+ bool arith_renorm_enc_interval();
+ void arith_start_encoding();
+ bool arith_stop_encoding();
+
+ bool put_bits(uint bits, uint num_bits);
+ bool put_bits_align_to_byte();
+ bool flush_bits();
+ bool assemble_output_buf();
+
+ uint get_bits(uint num_bits);
+ void remove_bits(uint num_bits);
+
+ void decode_need_bytes();
+
+ enum
+ {
+ cNull,
+ cEncoding,
+ cDecoding
+ } m_mode;
+ };
+
+// Optional macros for faster decompression. These macros implement the symbol_codec class's decode functionality.
+// This is hard to debug (and just plain ugly), but using these macros eliminate function calls, and they place the most important
+// member variables on the stack so they're hopefully put in registers (avoiding horrible load hit stores on some CPU's).
+// The user must define the LZHAM_DECODE_NEEDS_BYTES macro, which is invoked when the decode buffer is exhausted.
+
+#define LZHAM_SYMBOL_CODEC_DECODE_DECLARE(codec) \
+ uint arith_value = 0; \
+ uint arith_length = 0; \
+ symbol_codec::bit_buf_t bit_buf = 0; \
+ int bit_count = 0; \
+ const uint8* pDecode_buf_next = NULL;
+
+#define LZHAM_SYMBOL_CODEC_DECODE_BEGIN(codec) \
+ arith_value = codec.m_arith_value; \
+ arith_length = codec.m_arith_length; \
+ bit_buf = codec.m_bit_buf; \
+ bit_count = codec.m_bit_count; \
+ pDecode_buf_next = codec.m_pDecode_buf_next;
+
+#define LZHAM_SYMBOL_CODEC_DECODE_END(codec) \
+ codec.m_arith_value = arith_value; \
+ codec.m_arith_length = arith_length; \
+ codec.m_bit_buf = bit_buf; \
+ codec.m_bit_count = bit_count; \
+ codec.m_pDecode_buf_next = pDecode_buf_next;
+
+// The user must declare the LZHAM_DECODE_NEEDS_BYTES macro.
+
+#define LZHAM_SYMBOL_CODEC_DECODE_GET_BITS(codec, result, num_bits) \
+{ \
+ while (LZHAM_BUILTIN_EXPECT(bit_count < (int)(num_bits), 0)) \
+ { \
+ uint r; \
+ if (LZHAM_BUILTIN_EXPECT(pDecode_buf_next == codec.m_pDecode_buf_end, 0)) \
+ { \
+ if (LZHAM_BUILTIN_EXPECT(!codec.m_decode_buf_eof, 1)) \
+ { \
+ LZHAM_SYMBOL_CODEC_DECODE_END(codec) \
+ LZHAM_DECODE_NEEDS_BYTES \
+ LZHAM_SYMBOL_CODEC_DECODE_BEGIN(codec) \
+ } \
+ r = 0; \
+ if (LZHAM_BUILTIN_EXPECT(pDecode_buf_next < codec.m_pDecode_buf_end, 1)) r = *pDecode_buf_next++; \
+ } \
+ else \
+ r = *pDecode_buf_next++; \
+ bit_count += 8; \
+ bit_buf |= (static_cast(r) << (symbol_codec::cBitBufSize - bit_count)); \
+ } \
+ result = (num_bits) ? static_cast(bit_buf >> (symbol_codec::cBitBufSize - (num_bits))) : 0; \
+ bit_buf <<= (num_bits); \
+ bit_count -= (num_bits); \
+}
+
+#define LZHAM_SYMBOL_CODEC_DECODE_ARITH_BIT(codec, result, model) \
+{ \
+ adaptive_bit_model *pModel; \
+ pModel = &model; \
+ while (LZHAM_BUILTIN_EXPECT(arith_length < cSymbolCodecArithMinLen, 0)) \
+ { \
+ uint c; codec.m_pSaved_model = pModel; \
+ LZHAM_SYMBOL_CODEC_DECODE_GET_BITS(codec, c, 8); \
+ pModel = static_cast(codec.m_pSaved_model); \
+ arith_value = (arith_value << 8) | c; \
+ arith_length <<= 8; \
+ } \
+ uint x = pModel->m_bit_0_prob * (arith_length >> cSymbolCodecArithProbBits); \
+ result = (arith_value >= x); \
+ if (!result) \
+ { \
+ pModel->m_bit_0_prob += ((cSymbolCodecArithProbScale - pModel->m_bit_0_prob) >> cSymbolCodecArithProbMoveBits); \
+ arith_length = x; \
+ } \
+ else \
+ { \
+ pModel->m_bit_0_prob -= (pModel->m_bit_0_prob >> cSymbolCodecArithProbMoveBits); \
+ arith_value -= x; \
+ arith_length -= x; \
+ } \
+}
+
+#define LZHAM_SYMBOL_CODEC_DECODE_ADAPTIVE_ARITHMETIC(codec, result, model) \
+{ \
+ adaptive_arith_data_model *pArith_data_model; \
+ pArith_data_model = &model; \
+ uint node_index; \
+ node_index = 1; \
+ do \
+ { \
+ while (LZHAM_BUILTIN_EXPECT(arith_length < cSymbolCodecArithMinLen, 0)) \
+ { \
+ uint c; codec.m_saved_node_index = node_index; codec.m_pSaved_model = pArith_data_model; \
+ LZHAM_SYMBOL_CODEC_DECODE_GET_BITS(codec, c, 8); \
+ node_index = codec.m_saved_node_index; pArith_data_model = static_cast(codec.m_pSaved_model); \
+ arith_value = (arith_value << 8) | c; \
+ arith_length <<= 8; \
+ } \
+ adaptive_bit_model *pBit_model; pBit_model = &pArith_data_model->m_probs[node_index]; \
+ uint x = pBit_model->m_bit_0_prob * (arith_length >> cSymbolCodecArithProbBits); \
+ uint bit; bit = (arith_value >= x); \
+ if (!bit) \
+ { \
+ pBit_model->m_bit_0_prob += ((cSymbolCodecArithProbScale - pBit_model->m_bit_0_prob) >> cSymbolCodecArithProbMoveBits); \
+ arith_length = x; \
+ } \
+ else \
+ { \
+ pBit_model->m_bit_0_prob -= (pBit_model->m_bit_0_prob >> cSymbolCodecArithProbMoveBits); \
+ arith_value -= x; \
+ arith_length -= x; \
+ } \
+ node_index = (node_index << 1) + bit; \
+ } while (node_index < pArith_data_model->m_total_syms); \
+ result = node_index - pArith_data_model->m_total_syms; \
+}
+
+#if LZHAM_SYMBOL_CODEC_USE_64_BIT_BUFFER
+#define LZHAM_SYMBOL_CODEC_DECODE_ADAPTIVE_HUFFMAN(codec, result, model) \
+{ \
+ quasi_adaptive_huffman_data_model* pModel; const prefix_coding::decoder_tables* pTables; \
+ pModel = &model; pTables = model.m_pDecode_tables; \
+ if (LZHAM_BUILTIN_EXPECT(bit_count < 24, 0)) \
+ { \
+ uint c; \
+ pDecode_buf_next += sizeof(uint32); \
+ if (LZHAM_BUILTIN_EXPECT(pDecode_buf_next >= codec.m_pDecode_buf_end, 0)) \
+ { \
+ pDecode_buf_next -= sizeof(uint32); \
+ while (bit_count < 24) \
+ { \
+ if (!codec.m_decode_buf_eof) \
+ { \
+ codec.m_pSaved_huff_model = pModel; \
+ LZHAM_SYMBOL_CODEC_DECODE_END(codec) \
+ LZHAM_DECODE_NEEDS_BYTES \
+ LZHAM_SYMBOL_CODEC_DECODE_BEGIN(codec) \
+ pModel = codec.m_pSaved_huff_model; pTables = pModel->m_pDecode_tables; \
+ } \
+ c = 0; if (pDecode_buf_next < codec.m_pDecode_buf_end) c = *pDecode_buf_next++; \
+ bit_count += 8; \
+ bit_buf |= (static_cast(c) << (symbol_codec::cBitBufSize - bit_count)); \
+ } \
+ } \
+ else \
+ { \
+ c = LZHAM_READ_BIG_ENDIAN_UINT32(pDecode_buf_next - sizeof(uint32)); \
+ bit_count += 32; \
+ bit_buf |= (static_cast(c) << (symbol_codec::cBitBufSize - bit_count)); \
+ } \
+ } \
+ uint k = static_cast((bit_buf >> (symbol_codec::cBitBufSize - 16)) + 1); \
+ uint len; \
+ if (LZHAM_BUILTIN_EXPECT(k <= pTables->m_table_max_code, 1)) \
+ { \
+ uint32 t = pTables->m_lookup[bit_buf >> (symbol_codec::cBitBufSize - pTables->m_table_bits)]; \
+ result = t & UINT16_MAX; \
+ len = t >> 16; \
+ } \
+ else \
+ { \
+ len = pTables->m_decode_start_code_size; \
+ for ( ; ; ) \
+ { \
+ if (LZHAM_BUILTIN_EXPECT(k <= pTables->m_max_codes[len - 1], 0)) \
+ break; \
+ len++; \
+ } \
+ int val_ptr = pTables->m_val_ptrs[len - 1] + static_cast(bit_buf >> (symbol_codec::cBitBufSize - len)); \
+ if (((uint)val_ptr >= pModel->m_total_syms)) val_ptr = 0; \
+ result = pTables->m_sorted_symbol_order[val_ptr]; \
+ } \
+ bit_buf <<= len; \
+ bit_count -= len; \
+ uint freq = pModel->m_sym_freq[result]; \
+ freq++; \
+ pModel->m_sym_freq[result] = static_cast(freq); \
+ LZHAM_ASSERT(freq <= UINT16_MAX); \
+ if (LZHAM_BUILTIN_EXPECT(--pModel->m_symbols_until_update == 0, 0)) \
+ { \
+ pModel->update(); \
+ } \
+}
+#else
+#define LZHAM_SYMBOL_CODEC_DECODE_ADAPTIVE_HUFFMAN(codec, result, model) \
+{ \
+ quasi_adaptive_huffman_data_model* pModel; const prefix_coding::decoder_tables* pTables; \
+ pModel = &model; pTables = model.m_pDecode_tables; \
+ while (LZHAM_BUILTIN_EXPECT(bit_count < (symbol_codec::cBitBufSize - 8), 1)) \
+ { \
+ uint c; \
+ if (LZHAM_BUILTIN_EXPECT(pDecode_buf_next == codec.m_pDecode_buf_end, 0)) \
+ { \
+ if (LZHAM_BUILTIN_EXPECT(!codec.m_decode_buf_eof, 1)) \
+ { \
+ codec.m_pSaved_huff_model = pModel; \
+ LZHAM_SYMBOL_CODEC_DECODE_END(codec) \
+ LZHAM_DECODE_NEEDS_BYTES \
+ LZHAM_SYMBOL_CODEC_DECODE_BEGIN(codec) \
+ pModel = codec.m_pSaved_huff_model; pTables = pModel->m_pDecode_tables; \
+ } \
+ c = 0; if (LZHAM_BUILTIN_EXPECT(pDecode_buf_next < codec.m_pDecode_buf_end, 1)) c = *pDecode_buf_next++; \
+ } \
+ else \
+ c = *pDecode_buf_next++; \
+ bit_count += 8; \
+ bit_buf |= (static_cast(c) << (symbol_codec::cBitBufSize - bit_count)); \
+ } \
+ uint k = static_cast((bit_buf >> (symbol_codec::cBitBufSize - 16)) + 1); \
+ uint len; \
+ if (LZHAM_BUILTIN_EXPECT(k <= pTables->m_table_max_code, 1)) \
+ { \
+ uint32 t = pTables->m_lookup[bit_buf >> (symbol_codec::cBitBufSize - pTables->m_table_bits)]; \
+ result = t & UINT16_MAX; \
+ len = t >> 16; \
+ } \
+ else \
+ { \
+ len = pTables->m_decode_start_code_size; \
+ for ( ; ; ) \
+ { \
+ if (LZHAM_BUILTIN_EXPECT(k <= pTables->m_max_codes[len - 1], 0)) \
+ break; \
+ len++; \
+ } \
+ int val_ptr = pTables->m_val_ptrs[len - 1] + static_cast(bit_buf >> (symbol_codec::cBitBufSize - len)); \
+ if (LZHAM_BUILTIN_EXPECT(((uint)val_ptr >= pModel->m_total_syms), 0)) val_ptr = 0; \
+ result = pTables->m_sorted_symbol_order[val_ptr]; \
+ } \
+ bit_buf <<= len; \
+ bit_count -= len; \
+ uint freq = pModel->m_sym_freq[result]; \
+ freq++; \
+ pModel->m_sym_freq[result] = static_cast(freq); \
+ LZHAM_ASSERT(freq <= UINT16_MAX); \
+ if (LZHAM_BUILTIN_EXPECT(--pModel->m_symbols_until_update == 0, 0)) \
+ { \
+ pModel->update(); \
+ } \
+}
+#endif
+
+#define LZHAM_SYMBOL_CODEC_DECODE_ALIGN_TO_BYTE(codec) if (bit_count & 7) { int dummy_result; LZHAM_NOTE_UNUSED(dummy_result); LZHAM_SYMBOL_CODEC_DECODE_GET_BITS(codec, dummy_result, bit_count & 7); }
+
+#define LZHAM_SYMBOL_CODEC_DECODE_REMOVE_BYTE_FROM_BIT_BUF(codec, result) \
+{ \
+ result = -1; \
+ if (bit_count >= 8) \
+ { \
+ result = static_cast(bit_buf >> (symbol_codec::cBitBufSize - 8)); \
+ bit_buf <<= 8; \
+ bit_count -= 8; \
+ } \
+}
+
+#define LZHAM_SYMBOL_CODEC_DECODE_ARITH_START(codec) \
+{ \
+ for ( arith_value = 0, arith_length = 0; arith_length < 4; ++arith_length ) \
+ { \
+ uint val; LZHAM_SYMBOL_CODEC_DECODE_GET_BITS(codec, val, 8); \
+ arith_value = (arith_value << 8) | val; \
+ } \
+ arith_length = cSymbolCodecArithMaxLen; \
+}
+
+} // namespace lzham
diff --git a/r5dev/thirdparty/lzham/include/lzham_threading.h b/r5dev/thirdparty/lzham/include/lzham_threading.h
new file mode 100644
index 00000000..b8a1dbef
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_threading.h
@@ -0,0 +1,12 @@
+// File: lzham_threading.h
+// See Copyright Notice and license at the end of include/lzham.h
+
+#if LZHAM_USE_WIN32_API
+ #include "lzham_win32_threading.h"
+#elif LZHAM_USE_PTHREADS_API
+ #include "lzham_pthreads_threading.h"
+#else
+ #include "lzham_null_threading.h"
+#endif
+
+
diff --git a/r5dev/thirdparty/lzham/include/lzham_timer.h b/r5dev/thirdparty/lzham/include/lzham_timer.h
new file mode 100644
index 00000000..a522430a
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_timer.h
@@ -0,0 +1,99 @@
+// File: lzham_timer.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+namespace lzham
+{
+ typedef unsigned long long timer_ticks;
+
+ class lzham_timer
+ {
+ public:
+ lzham_timer();
+ lzham_timer(timer_ticks start_ticks);
+
+ void start();
+ void start(timer_ticks start_ticks);
+
+ void stop();
+
+ double get_elapsed_secs() const;
+ inline double get_elapsed_ms() const { return get_elapsed_secs() * 1000.0f; }
+ timer_ticks get_elapsed_us() const;
+
+ static void init();
+ static inline timer_ticks get_ticks_per_sec() { return g_freq; }
+ static timer_ticks get_init_ticks();
+ static timer_ticks get_ticks();
+ static double ticks_to_secs(timer_ticks ticks);
+ static inline double ticks_to_ms(timer_ticks ticks) { return ticks_to_secs(ticks) * 1000.0f; }
+ static inline double get_secs() { return ticks_to_secs(get_ticks()); }
+ static inline double get_ms() { return ticks_to_ms(get_ticks()); }
+
+ private:
+ static timer_ticks g_init_ticks;
+ static timer_ticks g_freq;
+ static double g_inv_freq;
+
+ timer_ticks m_start_time;
+ timer_ticks m_stop_time;
+
+ bool m_started : 1;
+ bool m_stopped : 1;
+ };
+
+ enum var_args_t { cVarArgs };
+
+#if LZHAM_PERF_SECTIONS
+ class scoped_perf_section
+ {
+ public:
+ inline scoped_perf_section() :
+ m_start_ticks(lzham_timer::get_ticks())
+ {
+ m_name[0] = '?';
+ m_name[1] = '\0';
+ }
+
+ inline scoped_perf_section(const char *pName) :
+ m_start_ticks(lzham_timer::get_ticks())
+ {
+ strcpy_s(m_name, pName);
+
+ lzham_buffered_printf("Thread: 0x%08X, BEGIN Time: %3.3fms, Section: %s\n", GetCurrentThreadId(), lzham_timer::ticks_to_ms(m_start_ticks), m_name);
+ }
+
+ inline scoped_perf_section(var_args_t, const char *pName, ...) :
+ m_start_ticks(lzham_timer::get_ticks())
+ {
+ va_list args;
+ va_start(args, pName);
+ vsprintf_s(m_name, sizeof(m_name), pName, args);
+ va_end(args);
+
+ lzham_buffered_printf("Thread: 0x%08X, BEGIN Time: %3.3fms, Section: %s\n", GetCurrentThreadId(), lzham_timer::ticks_to_ms(m_start_ticks), m_name);
+ }
+
+ inline ~scoped_perf_section()
+ {
+ double end_ms = lzham_timer::get_ms();
+ double start_ms = lzham_timer::ticks_to_ms(m_start_ticks);
+
+ lzham_buffered_printf("Thread: 0x%08X, END Time: %3.3fms, Total: %3.3fms, Section: %s\n", GetCurrentThreadId(), end_ms, end_ms - start_ms, m_name);
+ }
+
+ private:
+ char m_name[64];
+ timer_ticks m_start_ticks;
+ };
+#else
+ class scoped_perf_section
+ {
+ public:
+ inline scoped_perf_section() { }
+ inline scoped_perf_section(const char *pName) { (void)pName; }
+ inline scoped_perf_section(var_args_t, const char *pName, ...) { (void)pName; }
+ };
+#endif // LZHAM_PERF_SECTIONS
+
+} // namespace lzham
diff --git a/r5dev/thirdparty/lzham/include/lzham_traits.h b/r5dev/thirdparty/lzham/include/lzham_traits.h
new file mode 100644
index 00000000..fbb68ce6
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_traits.h
@@ -0,0 +1,137 @@
+// File: lzham_traits.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+namespace lzham
+{
+ template
+ struct scalar_type
+ {
+ enum { cFlag = false };
+ static inline void construct(T* p) { helpers::construct(p); }
+ static inline void construct(T* p, const T& init) { helpers::construct(p, init); }
+ static inline void construct_array(T* p, uint n) { helpers::construct_array(p, n); }
+ static inline void destruct(T* p) { helpers::destruct(p); }
+ static inline void destruct_array(T* p, uint n) { helpers::destruct_array(p, n); }
+ };
+
+ template struct scalar_type
+ {
+ enum { cFlag = true };
+ static inline void construct(T** p) { memset(p, 0, sizeof(T*)); }
+ static inline void construct(T** p, T* init) { *p = init; }
+ static inline void construct_array(T** p, uint n) { memset(p, 0, sizeof(T*) * n); }
+ static inline void destruct(T** p) { LZHAM_NOTE_UNUSED(p); }
+ static inline void destruct_array(T** p, uint n) { LZHAM_NOTE_UNUSED(p); LZHAM_NOTE_UNUSED(n); }
+ };
+
+#define LZHAM_DEFINE_BUILT_IN_TYPE(X) \
+ template<> struct scalar_type { \
+ enum { cFlag = true }; \
+ static inline void construct(X* p) { memset(p, 0, sizeof(X)); } \
+ static inline void construct(X* p, const X& init) { memcpy(p, &init, sizeof(X)); } \
+ static inline void construct_array(X* p, uint n) { memset(p, 0, sizeof(X) * n); } \
+ static inline void destruct(X* p) { LZHAM_NOTE_UNUSED(p); } \
+ static inline void destruct_array(X* p, uint n) { LZHAM_NOTE_UNUSED(p); LZHAM_NOTE_UNUSED(n); } };
+
+ LZHAM_DEFINE_BUILT_IN_TYPE(bool)
+ LZHAM_DEFINE_BUILT_IN_TYPE(char)
+ LZHAM_DEFINE_BUILT_IN_TYPE(unsigned char)
+ LZHAM_DEFINE_BUILT_IN_TYPE(short)
+ LZHAM_DEFINE_BUILT_IN_TYPE(unsigned short)
+ LZHAM_DEFINE_BUILT_IN_TYPE(int)
+ LZHAM_DEFINE_BUILT_IN_TYPE(unsigned int)
+ LZHAM_DEFINE_BUILT_IN_TYPE(long)
+ LZHAM_DEFINE_BUILT_IN_TYPE(unsigned long)
+ LZHAM_DEFINE_BUILT_IN_TYPE(float)
+ LZHAM_DEFINE_BUILT_IN_TYPE(double)
+ LZHAM_DEFINE_BUILT_IN_TYPE(long double)
+ #if defined(WIN32)
+ LZHAM_DEFINE_BUILT_IN_TYPE(__int64)
+ LZHAM_DEFINE_BUILT_IN_TYPE(unsigned __int64)
+ #endif
+
+#undef LZHAM_DEFINE_BUILT_IN_TYPE
+
+// See: http://erdani.org/publications/cuj-2004-06.pdf
+
+ template
+ struct bitwise_movable { enum { cFlag = false }; };
+
+// Defines type Q as bitwise movable.
+#define LZHAM_DEFINE_BITWISE_MOVABLE(Q) template<> struct bitwise_movable { enum { cFlag = true }; };
+
+ template
+ struct bitwise_copyable { enum { cFlag = false }; };
+
+ // Defines type Q as bitwise copyable.
+#define LZHAM_DEFINE_BITWISE_COPYABLE(Q) template<> struct bitwise_copyable { enum { cFlag = true }; };
+
+#define LZHAM_IS_POD(T) __is_pod(T)
+
+#define LZHAM_IS_SCALAR_TYPE(T) (scalar_type::cFlag)
+
+#define LZHAM_IS_BITWISE_COPYABLE(T) ((scalar_type::cFlag) || (bitwise_copyable::cFlag) || LZHAM_IS_POD(T))
+
+#define LZHAM_IS_BITWISE_MOVABLE(T) (LZHAM_IS_BITWISE_COPYABLE(T) || (bitwise_movable::cFlag))
+
+#define LZHAM_HAS_DESTRUCTOR(T) ((!scalar_type::cFlag) && (!__is_pod(T)))
+
+ // From yasli_traits.h:
+ // Credit goes to Boost;
+ // also found in the C++ Templates book by Vandevoorde and Josuttis
+
+ typedef char (&yes_t)[1];
+ typedef char (&no_t)[2];
+
+ template yes_t class_test(int U::*);
+ template no_t class_test(...);
+
+ template struct is_class
+ {
+ enum { value = (sizeof(class_test(0)) == sizeof(yes_t)) };
+ };
+
+ template struct is_pointer
+ {
+ enum { value = false };
+ };
+
+ template struct is_pointer
+ {
+ enum { value = true };
+ };
+
+ LZHAM_DEFINE_BITWISE_COPYABLE(empty_type);
+ LZHAM_DEFINE_BITWISE_MOVABLE(empty_type);
+
+ namespace helpers
+ {
+ template
+ inline void construct_array(T* p, uint n)
+ {
+ if (LZHAM_IS_SCALAR_TYPE(T))
+ {
+ memset(p, 0, sizeof(T) * n);
+ }
+ else
+ {
+ T* q = p + n;
+ for ( ; p != q; ++p)
+ new (static_cast(p)) T;
+ }
+ }
+
+ template
+ inline void destruct_array(T* p, uint n)
+ {
+ if ( LZHAM_HAS_DESTRUCTOR(T) )
+ {
+ T* q = p + n;
+ for ( ; p != q; ++p)
+ p->~T();
+ }
+ }
+ }
+
+} // namespace lzham
diff --git a/r5dev/thirdparty/lzham/include/lzham_types.h b/r5dev/thirdparty/lzham/include/lzham_types.h
new file mode 100644
index 00000000..a0227e8a
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_types.h
@@ -0,0 +1,74 @@
+// File: types.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+namespace lzham
+{
+ typedef unsigned char uint8;
+ typedef signed char int8;
+ typedef unsigned char uint8;
+ typedef unsigned short uint16;
+ typedef signed short int16;
+ typedef unsigned int uint32;
+ typedef uint32 uint;
+ typedef signed int int32;
+
+ #ifdef __GNUC__
+ typedef unsigned long long uint64;
+ typedef long long int64;
+ #else
+ typedef unsigned __int64 uint64;
+ typedef signed __int64 int64;
+ #endif
+
+ const uint8 UINT8_MIN = 0;
+ //const uint8 UINT8_MAX = 0xFFU;
+ const uint16 UINT16_MIN = 0;
+ //const uint16 UINT16_MAX = 0xFFFFU;
+ const uint32 UINT32_MIN = 0;
+ //const uint32 UINT32_MAX = 0xFFFFFFFFU;
+ const uint64 UINT64_MIN = 0;
+ //const uint64 UINT64_MAX = 0xFFFFFFFFFFFFFFFFULL; //0xFFFFFFFFFFFFFFFFui64;
+
+ //const int8 INT8_MIN = -128;
+ //const int8 INT8_MAX = 127;
+ //const int16 INT16_MIN = -32768;
+ //const int16 INT16_MAX = 32767;
+ //const int32 INT32_MIN = (-2147483647 - 1);
+ //const int32 INT32_MAX = 2147483647;
+ //const int64 INT64_MIN = (int64)0x8000000000000000ULL; //(-9223372036854775807i64 - 1);
+ //const int64 INT64_MAX = (int64)0x7FFFFFFFFFFFFFFFULL; //9223372036854775807i64;
+
+#if LZHAM_64BIT_POINTERS
+ typedef uint64 uint_ptr;
+ typedef uint64 uint32_ptr;
+ typedef int64 signed_size_t;
+ typedef uint64 ptr_bits_t;
+ const ptr_bits_t PTR_BITS_XOR = 0xDB0DD4415C87DCF7ULL;
+#else
+ typedef unsigned int uint_ptr;
+ typedef unsigned int uint32_ptr;
+ typedef signed int signed_size_t;
+ typedef uint32 ptr_bits_t;
+ const ptr_bits_t PTR_BITS_XOR = 0x5C87DCF7UL;
+#endif
+
+ enum
+ {
+ cInvalidIndex = -1
+ };
+
+ const uint cIntBits = sizeof(uint) * CHAR_BIT;
+
+ template struct int_traits { enum { cMin = INT_MIN, cMax = INT_MAX, cSigned = true }; };
+ template<> struct int_traits { enum { cMin = INT8_MIN, cMax = INT8_MAX, cSigned = true }; };
+ template<> struct int_traits { enum { cMin = INT16_MIN, cMax = INT16_MAX, cSigned = true }; };
+ template<> struct int_traits { enum { cMin = INT32_MIN, cMax = INT32_MAX, cSigned = true }; };
+
+ template<> struct int_traits { enum { cMin = 0, cMax = UINT_MAX, cSigned = false }; };
+ template<> struct int_traits { enum { cMin = 0, cMax = UINT8_MAX, cSigned = false }; };
+ template<> struct int_traits { enum { cMin = 0, cMax = UINT16_MAX, cSigned = false }; };
+
+ struct empty_type { };
+
+} // namespace lzham
diff --git a/r5dev/thirdparty/lzham/include/lzham_utils.h b/r5dev/thirdparty/lzham/include/lzham_utils.h
new file mode 100644
index 00000000..0e8f5e8b
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_utils.h
@@ -0,0 +1,58 @@
+// File: lzham_utils.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+#define LZHAM_GET_ALIGNMENT(v) ((!sizeof(v)) ? 1 : (__alignof(v) ? __alignof(v) : sizeof(uint32)))
+
+#define LZHAM_MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define LZHAM_MAX(a, b) (((a) < (b)) ? (b) : (a))
+
+template T decay_array_to_subtype(T (&a)[N]);
+#define LZHAM_ARRAY_SIZE(X) (sizeof(X) / sizeof(decay_array_to_subtype(X)))
+
+namespace lzham
+{
+ namespace utils
+ {
+ template inline void swap(T& l, T& r)
+ {
+ T temp(l);
+ l = r;
+ r = temp;
+ }
+
+ template inline void zero_object(T& obj)
+ {
+ memset(&obj, 0, sizeof(obj));
+ }
+
+ static inline uint32 swap32(uint32 x) { return ((x << 24U) | ((x << 8U) & 0x00FF0000U) | ((x >> 8U) & 0x0000FF00U) | (x >> 24U)); }
+
+ inline uint count_leading_zeros16(uint v)
+ {
+ LZHAM_ASSERT(v < 0x10000);
+
+ uint temp;
+ uint n = 16;
+
+ temp = v >> 8;
+ if (temp) { n -= 8; v = temp; }
+
+ temp = v >> 4;
+ if (temp) { n -= 4; v = temp; }
+
+ temp = v >> 2;
+ if (temp) { n -= 2; v = temp; }
+
+ temp = v >> 1;
+ if (temp) { n -= 1; v = temp; }
+
+ if (v & 1) n--;
+
+ return n;
+ }
+
+ } // namespace utils
+
+} // namespace lzham
+
diff --git a/r5dev/thirdparty/lzham/include/lzham_vector.h b/r5dev/thirdparty/lzham/include/lzham_vector.h
new file mode 100644
index 00000000..90f3236d
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_vector.h
@@ -0,0 +1,588 @@
+// File: lzham_vector.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+namespace lzham
+{
+ struct elemental_vector
+ {
+ void* m_p;
+ uint m_size;
+ uint m_capacity;
+
+ typedef void (*object_mover)(void* pDst, void* pSrc, uint num);
+
+ bool increase_capacity(uint min_new_capacity, bool grow_hint, uint element_size, object_mover pRelocate, bool nofail);
+ };
+
+ template
+ class vector : public helpers::rel_ops< vector >
+ {
+ public:
+ typedef T* iterator;
+ typedef const T* const_iterator;
+ typedef T value_type;
+ typedef T& reference;
+ typedef const T& const_reference;
+ typedef T* pointer;
+ typedef const T* const_pointer;
+
+ inline vector() :
+ m_p(NULL),
+ m_size(0),
+ m_capacity(0)
+ {
+ }
+
+ inline vector(uint n, const T& init) :
+ m_p(NULL),
+ m_size(0),
+ m_capacity(0)
+ {
+ increase_capacity(n, false);
+ helpers::construct_array(m_p, n, init);
+ m_size = n;
+ }
+
+ inline vector(const vector& other) :
+ m_p(NULL),
+ m_size(0),
+ m_capacity(0)
+ {
+ increase_capacity(other.m_size, false);
+
+ m_size = other.m_size;
+
+ if (LZHAM_IS_BITWISE_COPYABLE(T))
+ memcpy(m_p, other.m_p, m_size * sizeof(T));
+ else
+ {
+ T* pDst = m_p;
+ const T* pSrc = other.m_p;
+ for (uint i = m_size; i > 0; i--)
+ helpers::construct(pDst++, *pSrc++);
+ }
+ }
+
+ inline explicit vector(uint size) :
+ m_p(NULL),
+ m_size(0),
+ m_capacity(0)
+ {
+ try_resize(size);
+ }
+
+ inline ~vector()
+ {
+ if (m_p)
+ {
+ scalar_type::destruct_array(m_p, m_size);
+ lzham_free(m_p);
+ }
+ }
+
+ inline vector& operator= (const vector& other)
+ {
+ if (this == &other)
+ return *this;
+
+ if (m_capacity >= other.m_size)
+ try_resize(0);
+ else
+ {
+ clear();
+ if (!increase_capacity(other.m_size, false))
+ {
+ LZHAM_FAIL("lzham::vector operator=: Out of memory!");
+ return *this;
+ }
+ }
+
+ if (LZHAM_IS_BITWISE_COPYABLE(T))
+ memcpy(m_p, other.m_p, other.m_size * sizeof(T));
+ else
+ {
+ T* pDst = m_p;
+ const T* pSrc = other.m_p;
+ for (uint i = other.m_size; i > 0; i--)
+ helpers::construct(pDst++, *pSrc++);
+ }
+
+ m_size = other.m_size;
+
+ return *this;
+ }
+
+ inline const T* begin() const { return m_p; }
+ T* begin() { return m_p; }
+
+ inline const T* end() const { return m_p + m_size; }
+ T* end() { return m_p + m_size; }
+
+ inline bool empty() const { return !m_size; }
+ inline uint size() const { return m_size; }
+ inline uint size_in_bytes() const { return m_size * sizeof(T); }
+ inline uint capacity() const { return m_capacity; }
+
+ // operator[] will assert on out of range indices, but in final builds there is (and will never be) any range checking on this method.
+ inline const T& operator[] (uint i) const { LZHAM_ASSERT(i < m_size); return m_p[i]; }
+ inline T& operator[] (uint i) { LZHAM_ASSERT(i < m_size); return m_p[i]; }
+
+ // at() always includes range checking, even in final builds, unlike operator [].
+ // The first element is returned if the index is out of range.
+ inline const T& at(uint i) const { LZHAM_ASSERT(i < m_size); return (i >= m_size) ? m_p[0] : m_p[i]; }
+ inline T& at(uint i) { LZHAM_ASSERT(i < m_size); return (i >= m_size) ? m_p[0] : m_p[i]; }
+
+ inline const T& front() const { LZHAM_ASSERT(m_size); return m_p[0]; }
+ inline T& front() { LZHAM_ASSERT(m_size); return m_p[0]; }
+
+ inline const T& back() const { LZHAM_ASSERT(m_size); return m_p[m_size - 1]; }
+ inline T& back() { LZHAM_ASSERT(m_size); return m_p[m_size - 1]; }
+
+ inline const T* get_ptr() const { return m_p; }
+ inline T* get_ptr() { return m_p; }
+
+ inline void clear()
+ {
+ if (m_p)
+ {
+ scalar_type::destruct_array(m_p, m_size);
+ lzham_free(m_p);
+ m_p = NULL;
+ m_size = 0;
+ m_capacity = 0;
+ }
+ }
+
+ inline void clear_no_destruction()
+ {
+ if (m_p)
+ {
+ lzham_free(m_p);
+ m_p = NULL;
+ m_size = 0;
+ m_capacity = 0;
+ }
+ }
+
+ inline bool try_reserve(uint new_capacity)
+ {
+ return increase_capacity(new_capacity, true, true);
+ }
+
+ inline bool try_resize(uint new_size, bool grow_hint = false)
+ {
+ if (m_size != new_size)
+ {
+ if (new_size < m_size)
+ scalar_type::destruct_array(m_p + new_size, m_size - new_size);
+ else
+ {
+ if (new_size > m_capacity)
+ {
+ if (!increase_capacity(new_size, (new_size == (m_size + 1)) || grow_hint, true))
+ return false;
+ }
+
+ scalar_type::construct_array(m_p + m_size, new_size - m_size);
+ }
+
+ m_size = new_size;
+ }
+
+ return true;
+ }
+
+ inline bool try_resize_no_construct(uint new_size, bool grow_hint = false)
+ {
+ if (new_size > m_capacity)
+ {
+ if (!increase_capacity(new_size, (new_size == (m_size + 1)) || grow_hint, true))
+ return false;
+ }
+
+ m_size = new_size;
+
+ return true;
+ }
+
+ inline T* try_enlarge(uint i)
+ {
+ uint cur_size = m_size;
+ if (!try_resize(cur_size + i, true))
+ return NULL;
+ return get_ptr() + cur_size;
+ }
+
+ inline bool try_push_back(const T& obj)
+ {
+ LZHAM_ASSERT(!m_p || (&obj < m_p) || (&obj >= (m_p + m_size)));
+
+ if (m_size >= m_capacity)
+ {
+ if (!increase_capacity(m_size + 1, true, true))
+ return false;
+ }
+
+ scalar_type::construct(m_p + m_size, obj);
+ m_size++;
+
+ return true;
+ }
+
+ inline void pop_back()
+ {
+ LZHAM_ASSERT(m_size);
+
+ if (m_size)
+ {
+ m_size--;
+ scalar_type::destruct(&m_p[m_size]);
+ }
+ }
+
+ inline bool insert(uint index, const T* p, uint n)
+ {
+ LZHAM_ASSERT(index <= m_size);
+ if (!n)
+ return true;
+
+ const uint orig_size = m_size;
+ if (!try_resize(m_size + n, true))
+ return false;
+
+ const uint num_to_move = orig_size - index;
+ if (num_to_move)
+ {
+ if (LZHAM_IS_BITWISE_COPYABLE(T))
+ memmove(m_p + index + n, m_p + index, sizeof(T) * num_to_move);
+ else
+ {
+ const T* pSrc = m_p + orig_size - 1;
+ T* pDst = const_cast(pSrc) + n;
+
+ for (uint i = 0; i < num_to_move; i++)
+ {
+ LZHAM_ASSERT((pDst - m_p) < (int)m_size);
+ *pDst-- = *pSrc--;
+ }
+ }
+ }
+
+ T* pDst = m_p + index;
+
+ if (LZHAM_IS_BITWISE_COPYABLE(T))
+ memcpy(pDst, p, sizeof(T) * n);
+ else
+ {
+ for (uint i = 0; i < n; i++)
+ {
+ LZHAM_ASSERT((pDst - m_p) < (int)m_size);
+ *pDst++ = *p++;
+ }
+ }
+
+ return true;
+ }
+
+ // push_front() isn't going to be very fast - it's only here for usability.
+ inline bool try_push_front(const T& obj)
+ {
+ return insert(0, &obj, 1);
+ }
+
+ bool append(const vector& other)
+ {
+ if (other.m_size)
+ return insert(m_size, &other[0], other.m_size);
+ return true;
+ }
+
+ bool append(const T* p, uint n)
+ {
+ if (n)
+ return insert(m_size, p, n);
+ return true;
+ }
+
+ inline void erase(uint start, uint n)
+ {
+ LZHAM_ASSERT((start + n) <= m_size);
+ if ((start + n) > m_size)
+ return;
+
+ if (!n)
+ return;
+
+ const uint num_to_move = m_size - (start + n);
+
+ T* pDst = m_p + start;
+
+ const T* pSrc = m_p + start + n;
+
+ if (LZHAM_IS_BITWISE_COPYABLE(T))
+ memmove(pDst, pSrc, num_to_move * sizeof(T));
+ else
+ {
+ T* pDst_end = pDst + num_to_move;
+
+ while (pDst != pDst_end)
+ *pDst++ = *pSrc++;
+
+ scalar_type::destruct_array(pDst_end, n);
+ }
+
+ m_size -= n;
+ }
+
+ inline void erase(uint index)
+ {
+ erase(index, 1);
+ }
+
+ inline void erase(T* p)
+ {
+ LZHAM_ASSERT((p >= m_p) && (p < (m_p + m_size)));
+ erase(static_cast(p - m_p));
+ }
+
+ void erase_unordered(uint index)
+ {
+ LZHAM_ASSERT(index < m_size);
+
+ if ((index + 1) < m_size)
+ (*this)[index] = back();
+
+ pop_back();
+ }
+
+ inline bool operator== (const vector& rhs) const
+ {
+ if (m_size != rhs.m_size)
+ return false;
+ else if (m_size)
+ {
+ if (scalar_type::cFlag)
+ return memcmp(m_p, rhs.m_p, sizeof(T) * m_size) == 0;
+ else
+ {
+ const T* pSrc = m_p;
+ const T* pDst = rhs.m_p;
+ for (uint i = m_size; i; i--)
+ if (!(*pSrc++ == *pDst++))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ inline bool operator< (const vector& rhs) const
+ {
+ const uint min_size = math::minimum(m_size, rhs.m_size);
+
+ const T* pSrc = m_p;
+ const T* pSrc_end = m_p + min_size;
+ const T* pDst = rhs.m_p;
+
+ while ((pSrc < pSrc_end) && (*pSrc == *pDst))
+ {
+ pSrc++;
+ pDst++;
+ }
+
+ if (pSrc < pSrc_end)
+ return *pSrc < *pDst;
+
+ return m_size < rhs.m_size;
+ }
+
+ inline void swap(vector& other)
+ {
+ utils::swap(m_p, other.m_p);
+ utils::swap(m_size, other.m_size);
+ utils::swap(m_capacity, other.m_capacity);
+ }
+
+ inline void sort()
+ {
+ std::sort(begin(), end());
+ }
+
+ inline void unique()
+ {
+ if (!empty())
+ {
+ sort();
+
+ resize(std::unique(begin(), end()) - begin());
+ }
+ }
+
+ inline void reverse()
+ {
+ uint j = m_size >> 1;
+ for (uint i = 0; i < j; i++)
+ utils::swap(m_p[i], m_p[m_size - 1 - i]);
+ }
+
+ inline int find(const T& key) const
+ {
+ const T* p = m_p;
+ const T* p_end = m_p + m_size;
+
+ uint index = 0;
+
+ while (p != p_end)
+ {
+ if (key == *p)
+ return index;
+
+ p++;
+ index++;
+ }
+
+ return cInvalidIndex;
+ }
+
+ inline int find_sorted(const T& key) const
+ {
+ if (m_size)
+ {
+ // Uniform binary search - Knuth Algorithm 6.2.1 U, unrolled twice.
+ int i = ((m_size + 1) >> 1) - 1;
+ int m = m_size;
+
+ for ( ; ; )
+ {
+ LZHAM_ASSERT_OPEN_RANGE(i, 0, (int)m_size);
+ const T* pKey_i = m_p + i;
+ int cmp = key < *pKey_i;
+ if ((!cmp) && (key == *pKey_i)) return i;
+ m >>= 1;
+ if (!m) break;
+ cmp = -cmp;
+ i += (((m + 1) >> 1) ^ cmp) - cmp;
+
+ LZHAM_ASSERT_OPEN_RANGE(i, 0, (int)m_size);
+ pKey_i = m_p + i;
+ cmp = key < *pKey_i;
+ if ((!cmp) && (key == *pKey_i)) return i;
+ m >>= 1;
+ if (!m) break;
+ cmp = -cmp;
+ i += (((m + 1) >> 1) ^ cmp) - cmp;
+ }
+ }
+
+ return cInvalidIndex;
+ }
+
+ template
+ inline int find_sorted(const T& key, Q less_than) const
+ {
+ if (m_size)
+ {
+ // Uniform binary search - Knuth Algorithm 6.2.1 U, unrolled twice.
+ int i = ((m_size + 1) >> 1) - 1;
+ int m = m_size;
+
+ for ( ; ; )
+ {
+ LZHAM_ASSERT_OPEN_RANGE(i, 0, (int)m_size);
+ const T* pKey_i = m_p + i;
+ int cmp = less_than(key, *pKey_i);
+ if ((!cmp) && (!less_than(*pKey_i, key))) return i;
+ m >>= 1;
+ if (!m) break;
+ cmp = -cmp;
+ i += (((m + 1) >> 1) ^ cmp) - cmp;
+
+ LZHAM_ASSERT_OPEN_RANGE(i, 0, (int)m_size);
+ pKey_i = m_p + i;
+ cmp = less_than(key, *pKey_i);
+ if ((!cmp) && (!less_than(*pKey_i, key))) return i;
+ m >>= 1;
+ if (!m) break;
+ cmp = -cmp;
+ i += (((m + 1) >> 1) ^ cmp) - cmp;
+ }
+ }
+
+ return cInvalidIndex;
+ }
+
+ inline uint count_occurences(const T& key) const
+ {
+ uint c = 0;
+
+ const T* p = m_p;
+ const T* p_end = m_p + m_size;
+
+ while (p != p_end)
+ {
+ if (key == *p)
+ c++;
+
+ p++;
+ }
+
+ return c;
+ }
+
+ inline void set_all(const T& o)
+ {
+ if ((sizeof(T) == 1) && (scalar_type::cFlag))
+ memset(m_p, *reinterpret_cast(&o), m_size);
+ else
+ {
+ T* pDst = m_p;
+ T* pDst_end = pDst + m_size;
+ while (pDst != pDst_end)
+ *pDst++ = o;
+ }
+ }
+
+ private:
+ T* m_p;
+ uint m_size;
+ uint m_capacity;
+
+ template struct is_vector { enum { cFlag = false }; };
+ template struct is_vector< vector > { enum { cFlag = true }; };
+
+ static void object_mover(void* pDst_void, void* pSrc_void, uint num)
+ {
+ T* pSrc = static_cast(pSrc_void);
+ T* const pSrc_end = pSrc + num;
+ T* pDst = static_cast(pDst_void);
+
+ while (pSrc != pSrc_end)
+ {
+ new (static_cast(pDst)) T(*pSrc);
+ pSrc->~T();
+ pSrc++;
+ pDst++;
+ }
+ }
+
+ inline bool increase_capacity(uint min_new_capacity, bool grow_hint, bool nofail = false)
+ {
+ return reinterpret_cast(this)->increase_capacity(
+ min_new_capacity, grow_hint, sizeof(T),
+ (LZHAM_IS_BITWISE_MOVABLE(T) || (is_vector::cFlag)) ? NULL : object_mover, nofail);
+ }
+ };
+
+ template struct bitwise_movable< vector > { enum { cFlag = true }; };
+
+ extern void vector_test();
+
+ template
+ inline void swap(vector& a, vector& b)
+ {
+ a.swap(b);
+ }
+
+} // namespace lzham
+
diff --git a/r5dev/thirdparty/lzham/include/lzham_win32_threading.h b/r5dev/thirdparty/lzham/include/lzham_win32_threading.h
new file mode 100644
index 00000000..64125ac1
--- /dev/null
+++ b/r5dev/thirdparty/lzham/include/lzham_win32_threading.h
@@ -0,0 +1,368 @@
+// File: lzham_task_pool_win32.h
+// See Copyright Notice and license at the end of include/lzham.h
+#pragma once
+
+#if LZHAM_USE_WIN32_API
+
+#if LZHAM_NO_ATOMICS
+#error No atomic operations defined in lzham_platform.h!
+#endif
+
+namespace lzham
+{
+ class semaphore
+ {
+ LZHAM_NO_COPY_OR_ASSIGNMENT_OP(semaphore);
+
+ public:
+ semaphore(long initialCount = 0, long maximumCount = 1, const char* pName = NULL)
+ {
+ m_handle = CreateSemaphoreA(NULL, initialCount, maximumCount, pName);
+ if (NULL == m_handle)
+ {
+ LZHAM_FAIL("semaphore: CreateSemaphore() failed");
+ }
+ }
+
+ ~semaphore()
+ {
+ if (m_handle)
+ {
+ CloseHandle(m_handle);
+ m_handle = NULL;
+ }
+ }
+
+ inline HANDLE get_handle(void) const { return m_handle; }
+
+ void release(long releaseCount = 1)
+ {
+ if (0 == ReleaseSemaphore(m_handle, releaseCount, NULL))
+ {
+ LZHAM_FAIL("semaphore: ReleaseSemaphore() failed");
+ }
+ }
+
+ bool wait(uint32 milliseconds = UINT32_MAX)
+ {
+ LZHAM_ASSUME(INFINITE == UINT32_MAX);
+
+ DWORD result = WaitForSingleObject(m_handle, milliseconds);
+
+ if (WAIT_FAILED == result)
+ {
+ LZHAM_FAIL("semaphore: WaitForSingleObject() failed");
+ }
+
+ return WAIT_OBJECT_0 == result;
+ }
+
+ private:
+ HANDLE m_handle;
+ };
+
+ template
+ class tsstack
+ {
+ public:
+ inline tsstack(bool use_freelist = true) :
+ m_use_freelist(use_freelist)
+ {
+ LZHAM_VERIFY(((ptr_bits_t)this & (LZHAM_GET_ALIGNMENT(tsstack) - 1)) == 0);
+ InitializeSListHead(&m_stack_head);
+ InitializeSListHead(&m_freelist_head);
+ }
+
+ inline ~tsstack()
+ {
+ clear();
+ }
+
+ inline void clear()
+ {
+ for ( ; ; )
+ {
+ node* pNode = (node*)InterlockedPopEntrySList(&m_stack_head);
+ if (!pNode)
+ break;
+
+ LZHAM_MEMORY_IMPORT_BARRIER
+
+ helpers::destruct(&pNode->m_obj);
+
+ lzham_free(pNode);
+ }
+
+ flush_freelist();
+ }
+
+ inline void flush_freelist()
+ {
+ if (!m_use_freelist)
+ return;
+
+ for ( ; ; )
+ {
+ node* pNode = (node*)InterlockedPopEntrySList(&m_freelist_head);
+ if (!pNode)
+ break;
+
+ LZHAM_MEMORY_IMPORT_BARRIER
+
+ lzham_free(pNode);
+ }
+ }
+
+ inline bool try_push(const T& obj)
+ {
+ node* pNode = alloc_node();
+ if (!pNode)
+ return false;
+
+ helpers::construct(&pNode->m_obj, obj);
+
+ LZHAM_MEMORY_EXPORT_BARRIER
+
+ InterlockedPushEntrySList(&m_stack_head, &pNode->m_slist_entry);
+
+ return true;
+ }
+
+ inline bool pop(T& obj)
+ {
+ node* pNode = (node*)InterlockedPopEntrySList(&m_stack_head);
+ if (!pNode)
+ return false;
+
+ LZHAM_MEMORY_IMPORT_BARRIER
+
+ obj = pNode->m_obj;
+
+ helpers::destruct(&pNode->m_obj);
+
+ free_node(pNode);
+
+ return true;
+ }
+
+ private:
+ SLIST_HEADER m_stack_head;
+ SLIST_HEADER m_freelist_head;
+
+ struct node
+ {
+ SLIST_ENTRY m_slist_entry;
+ T m_obj;
+ };
+
+ bool m_use_freelist;
+
+ inline node* alloc_node()
+ {
+ node* pNode = m_use_freelist ? (node*)InterlockedPopEntrySList(&m_freelist_head) : NULL;
+
+ if (!pNode)
+ pNode = (node*)lzham_malloc(sizeof(node));
+
+ return pNode;
+ }
+
+ inline void free_node(node* pNode)
+ {
+ if (m_use_freelist)
+ InterlockedPushEntrySList(&m_freelist_head, &pNode->m_slist_entry);
+ else
+ lzham_free(pNode);
+ }
+ };
+
+ class task_pool
+ {
+ public:
+ task_pool();
+ task_pool(uint num_threads);
+ ~task_pool();
+
+ enum { cMaxThreads = LZHAM_MAX_HELPER_THREADS };
+ bool init(uint num_threads);
+ void deinit();
+
+ inline uint get_num_threads() const { return m_num_threads; }
+ inline uint get_num_outstanding_tasks() const { return m_num_outstanding_tasks; }
+
+ // C-style task callback
+ typedef void (*task_callback_func)(uint64 data, void* pData_ptr);
+ bool queue_task(task_callback_func pFunc, uint64 data = 0, void* pData_ptr = NULL);
+
+ class executable_task
+ {
+ public:
+ virtual void execute_task(uint64 data, void* pData_ptr) = 0;
+ };
+
+ // It's the caller's responsibility to delete pObj within the execute_task() method, if needed!
+ bool queue_task(executable_task* pObj, uint64 data = 0, void* pData_ptr = NULL);
+
+ template
+ inline bool queue_object_task(S* pObject, T pObject_method, uint64 data = 0, void* pData_ptr = NULL);
+
+ template
+ inline bool queue_multiple_object_tasks(S* pObject, T pObject_method, uint64 first_data, uint num_tasks, void* pData_ptr = NULL);
+
+ void join();
+
+ private:
+ struct task
+ {
+ //inline task() : m_data(0), m_pData_ptr(NULL), m_pObj(NULL), m_flags(0) { }
+
+ uint64 m_data;
+ void* m_pData_ptr;
+
+ union
+ {
+ task_callback_func m_callback;
+ executable_task* m_pObj;
+ };
+
+ uint m_flags;
+ };
+
+ tsstack m_task_stack;
+
+ uint m_num_threads;
+ HANDLE m_threads[cMaxThreads];
+
+ semaphore m_tasks_available;
+
+ enum task_flags
+ {
+ cTaskFlagObject = 1
+ };
+
+ volatile atomic32_t m_num_outstanding_tasks;
+ volatile atomic32_t m_exit_flag;
+
+ void process_task(task& tsk);
+
+ static unsigned __stdcall thread_func(void* pContext);
+ };
+
+ enum object_task_flags
+ {
+ cObjectTaskFlagDefault = 0,
+ cObjectTaskFlagDeleteAfterExecution = 1
+ };
+
+ template
+ class object_task : public task_pool::executable_task
+ {
+ public:
+ object_task(uint flags = cObjectTaskFlagDefault) :
+ m_pObject(NULL),
+ m_pMethod(NULL),
+ m_flags(flags)
+ {
+ }
+
+ typedef void (T::*object_method_ptr)(uint64 data, void* pData_ptr);
+
+ object_task(T* pObject, object_method_ptr pMethod, uint flags = cObjectTaskFlagDefault) :
+ m_pObject(pObject),
+ m_pMethod(pMethod),
+ m_flags(flags)
+ {
+ LZHAM_ASSERT(pObject && pMethod);
+ }
+
+ void init(T* pObject, object_method_ptr pMethod, uint flags = cObjectTaskFlagDefault)
+ {
+ LZHAM_ASSERT(pObject && pMethod);
+
+ m_pObject = pObject;
+ m_pMethod = pMethod;
+ m_flags = flags;
+ }
+
+ T* get_object() const { return m_pObject; }
+ object_method_ptr get_method() const { return m_pMethod; }
+
+ virtual void execute_task(uint64 data, void* pData_ptr)
+ {
+ (m_pObject->*m_pMethod)(data, pData_ptr);
+
+ if (m_flags & cObjectTaskFlagDeleteAfterExecution)
+ lzham_delete(this);
+ }
+
+ protected:
+ T* m_pObject;
+
+ object_method_ptr m_pMethod;
+
+ uint m_flags;
+ };
+
+ template
+ inline bool task_pool::queue_object_task(S* pObject, T pObject_method, uint64 data, void* pData_ptr)
+ {
+ object_task *pTask = lzham_new< object_task >(pObject, pObject_method, cObjectTaskFlagDeleteAfterExecution);
+ if (!pTask)
+ return false;
+ return queue_task(pTask, data, pData_ptr);
+ }
+
+ template
+ inline bool task_pool::queue_multiple_object_tasks(S* pObject, T pObject_method, uint64 first_data, uint num_tasks, void* pData_ptr)
+ {
+ LZHAM_ASSERT(m_num_threads);
+ LZHAM_ASSERT(pObject);
+ LZHAM_ASSERT(num_tasks);
+ if (!num_tasks)
+ return true;
+
+ bool status = true;
+
+ uint i;
+ for (i = 0; i < num_tasks; i++)
+ {
+ task tsk;
+
+ tsk.m_pObj = lzham_new< object_task >(pObject, pObject_method, cObjectTaskFlagDeleteAfterExecution);
+ if (!tsk.m_pObj)
+ {
+ status = false;
+ break;
+ }
+
+ tsk.m_data = first_data + i;
+ tsk.m_pData_ptr = pData_ptr;
+ tsk.m_flags = cTaskFlagObject;
+
+ if (!m_task_stack.try_push(tsk))
+ {
+ status = false;
+ break;
+ }
+ }
+
+ if (i)
+ {
+ atomic_add32(&m_num_outstanding_tasks, i);
+
+ m_tasks_available.release(i);
+ }
+
+ return status;
+ }
+
+ inline void lzham_sleep(unsigned int milliseconds)
+ {
+ Sleep(milliseconds);
+ }
+
+ uint lzham_get_max_helper_threads();
+
+} // namespace lzham
+
+#endif // LZHAM_USE_WIN32_API
diff --git a/r5dev/thirdparty/lzham/libs/lzhamcomp_x64.lib b/r5dev/thirdparty/lzham/libs/lzhamcomp_x64.lib
deleted file mode 100644
index 7f5d6e43e27fe022626fa4eceaa19b0d22bb128a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 556410
zcmeFadth8uwLg9)nWiCWo1~PsV1cv^5MFK4rlk$g%;Y&~Cl8vm1gK1>$)pM7MP||$
zpe=2Im=;k{qN1Xr;sq5IwID*utDvALsEDs#FMb8ldns_e2xz~b&wiafuOtP3-#>oe
z?`co=I%}`J_TFo+z4qFVIcNR_;lcKj%
ziw-+Z^@9J;ZqKVbo&P`F-uo+^|98jBAnWZN&j0B<+w&LaUvO7+_jSiY(VqTTC>Gun
z^;HEgtqeyazMdUj;a;Ebq8h)yt?g2$LOh3hx;KT|`+EllBhhGxDK*_C{^lBgTXRk2
zI!S1V2Ev2k-l)OU+|2l8TGJEe&}`GI?T#?Ol=fE2BfqlSKlffx+&+SZAs#xTUY~
zUtE?@@@Om^8;XWvk`Jm@1Ad`3_*1i_K6Uw)ylaL!_s*W7XczNLok6HK(%V0{ebU*a
zZ4TB#Rj0B>RH}Yie3m;x9g)tSa4b?E*USN=QX=0GipB;b)RMqBNiCVAP8-0LCjHt-
zG-9b(%JgZHx*|%MDqW5>eH{~|Op{+_|B#)OYLXTb8
zq?;gJ4vEEMQ9_}f{`PPWTCtD0OT{Tvsob6mPa7?}1RG*3#-#_mTWeI214wEJC=
za7QFHwObAh45G)TD+tTl-ro^{acS?4Leo;_F8QJV7%CJP$of+1wg?`AZ=9%3l%ODQ@9*pE
z-aLd(HNF^`Al%V`ZqEMN2jQo!d|MzuO|j&@WGUsoUZ%xEXpN{`WE(7hZzKeD625{K
zkK4Uv6XNeWK@*B~VW`lBQ0hlp(~ByZL)7
zgnBsANo7pm%L4Tfj1q&?#q||MTO#c=Xpk3-XFGbT=95yuz9qhTA-v6l=+)cbW39Es
zrM|!yi$w;ZJ}GmSZDEvcXrP1j7K#??>W-og^e8mP_%>{-udfd^mayM#j>JNPk@iR*
z6q_9{BvdbL%6cju)AV-t9byJT=RM~_H3aLu6g~u;pMcMcR8P&f;G+ga%@Rcv>BU>Igz9QqLzZ)ad>a~82Wo446=n2@
z&`_bR-F@I94O(~K=8CeexSXr%e2tBPrpo4Ok#kiv(iK}|$EUj2p1uGbfv>22u
z+3JdAonhnAR0VvE)y-@C!OCV9J)Xf@_)(ajrQ+Z+SmSFB`kQL~mHuP~7l*rJwf%!F
zD0xq$N$4$QBNCr?4DGbMQY2Yh_Ab(tRQO>&C#@2`71V>ZOOGLmOtIvcQl%t*890q|I~CHeotU3=
z#K)(jJMLen7h2#`H43*DeoU+z!&tauOSrE+;uB0lo8)3l^585y^ki>M57bzq=?JxV
z!Mz`^FuEC%XK71)a#qfUZSO~uj?V`3qqsT=Zz&bm^d;_z^eqYX3LTm-L-^?l8NyA`
zRqw%q)`T1?1qZlvsS0T^8;lHCg^ErfhPHYPsqm2l0aKdJp`M;&;Sev!cz$uJfliiM
zD-!kV7~4X5PO>HF9*$dQcr>D_kv>lACLk3hTOZxtyQ#kiO#~a^6Y~qJGaOrCLvZ@w
z^e$a0r{qqBSjCv26m4|r{)L5*D<@8c6hSD`ziEO3q!B|pWrSW&%IuYxB1jil8W3ex
z{^doICQ;5RIhUdBnjjOgkc?Swhw2Yvs2Ja_$bJNx!C0ujQ_cz|$|bD|NfVJgKNznF
za`{`zf8sSAIqX2Q;av&Qq@Ga<+wG1%Y8cZ&*|MbqEL$o=)%qH3$W*j`2AS*(ot+vb
zLKoj2k5`>#(xt7Cmcci<1j&Y8w2N4T5UUDl)IBtbrAe{yS6lCE4A#~KYwF-y9T4QIA?sG_7|nP}BGj5KK+8C_So!Pl_H-&oaH)#Sr!BmS+8Y#!us*0tCS+lR9s-d#B
zvc8JWd!@eDMg}UDG4DuUY4Q?iAP}q%tf|B_B}EbrK_a1+PQnUmz*kjY+wAu@G$tnp
zKZtYL1T3m+eYHV<-D)rai`piA*NU8F4VMKYeYyb4sxhwU2UM!1$5g*^jjyqCO=aVn
z)v{Spfcjwn){13i70Wht$E-G9wk3*5nQCxM=;CH!r8PATtNpe0U=m;3>N+1Rs7b
z*|@r)!58et+8i5`7Ad*aYwCP;%{6sR&DGEOgZ{0~6@ppH8$*zM3_a_5P-y-zU{lSqtc$>zaZ!
zt9AeC!|Xv=R_sm*>ygmgurO(oSFQ0iHNik)iCrg8nPhONuN}R;LvVCcV?Aq4Rc)ZM
z8skHFo3_Y;gDwI6DNY@Y_M6m|0bfI1W8>EM#ZM1*yS3ZPAs6B`NR^Q0a)*@zi9KN8-Zy@>f>17kY{Lv*Z`zHQ2y<_)kPCkp8y8ZRk*K?iFgMOt
z+d2`AgtTo!_8~oRc13zH+fZ9;Tsjf^qL;{l(&)*W%I3zJCY+6uiIcYD61M`ESFf%Q
z)HGndfZonfG;W@V>E{1UJA6E9Ro&=oYOcgQvq@}Fimg%XiH1144#haz8Fy=RapF;H
z>!fumaA}D=XI)shF=x@D#rQAUjceD7w=FMQtadad78|?V@mPet!NrrJCYxiUHk-!B
zm`u3JlT9O?W^wFovPly3SSHI^Y#(HYcMFj
zRvlB8>o~(x^^;4txGWyWC(14E%0|B1;suirf)6E>&zE1~ODx~3DBn-Lj&m?ea-4+#
zbd`&E7$@xJG7aDlknfW!Z&r!?{1^MzufMn@u=_8CySHaMd3!#Fh`{iVgZsa^Z?@wE
z_usb;rQvKkx>XAJUPD73Sp0U923-^)4zw1p06&<|)K1k0A4!=bNFoR#c
zkM$1@zXrt7qeq=Bqk-Lz7G4&*+<&=0^vHU|&Bg6?Jh@p;?vkk`Sp!oxdJkv3TDZ8n
zrq;hM*cz;_EXU!(_TJbc1aav8o{qk7ZzL)sYW?-W`r3y2mIi-oRiJ!9sA_F%sHL^K
zzA04S(iFP5zPcvV(p-au%=((OEfw<}YIyc4Q7AnS*wagN|F!M(`2
zpnyvMjKe19b$F2s+k3)&n+tKKhvy>;OP4GvS%d^kcMa~@PIf^dLSaP9%Xy|{1s(-{
zC?3Cb37%(yJ^?Rir=jH(549ETIH!QNI1XPOp@HQu0+`1exY?jAcfM!MDYZp+{eA9<
zSA6Zr3;V;dTOH?h-~+gws`3pr+vJI~4Oph>-_Y9CJ=norqU{?Xwde*kw#YoZ!3+ix
z(gOenaareVu*-6S1&dHFEx!#YK&?|(z^wFjuLcmF1zL5*SFyZYoPsq!cL32T&dmHm
zO^vYFg?-FmhO?^RZ1D3q92NQOFIY_hh-gX46I
zGz~~oDxSBBJY-x~H&HW@N0$|UigUU})6=hMn33jjCi)}GD)~gax;tYcAKDQ~!?La_
zC=>>0pf$Wn)@6;!r^v~Gq%)kRg4d8{CvJUd*-i%{rjW-Wq&48Lr+m22!d->?Y}~cD
zsmzz+X8h$U>_j*N_aN>(+}Gkh0r&N|IY2>$ocXvZw;J5%;AZ>hiXKBK$JvL!tU@ki
zEukFeHiNs};8ER}=`5;n4~B>+pU-*ywIj6?q_ujf;^1Pm7fn7hoXisnQObq5
zp)T>y841rG=SYr|kx#=v&Few!JX9s;Bw=^Jg3;RV;fFmM!R{MT4ac{Y%{cKMlR^|wQtVk+HAEm1>^F+!W4F)
z&t%P}y`GMnqXpZMauw~E&~7_nHrWo8Bik(p?Epm-?V#n)xB}d?YBNRXIA4bRGbnSX
zy`j6WftxtNNS||rIFF|tYtHdF?@p#BJ}|U75+9c*cvNF8tEGEKB-p=siR5##pijno
ziARP3EMPMQb(Q%Zol5>F#u5?DO+)7jXX*)4o$QPlN(=`X}
zSJvzkmF!N1>>8Eq(2K#UMOKit$IrN$IxBfdoll}J(A9XFW_f0Xo?B!sH&&e^J5a9-
zRj>EGw|b>5OuE{!Zu3;#IPTS|x_v4G<;Kb6YR-3B@T-@G@Zgn^!S&&uA=6K$v2MvU
zLI>Vag6jSIp?0{@E{)SVarS8Kf
z34ASgVp_KkNbQz!XnRUU#OwZmwyvVvN(In3@K_t(DpAz^OsBo3sa8JsSvF<mvGdygqbG9`D;?Ktkx_ddzVm`&d
z$l0BU%bY#MIY-s(TotmCuN~pvd-+FQ^r_sC{X6fW2{!=GD
zm*;h+0J0ap_?+qC(igA4J>2#HF{E)9y*S&*^!QYU!56PTo|t$V&b=}{TzZ-X=#l=P
z{8;BD__UIqYhjrlE{pN{uSK8jldEI)!W1JjJ@h;&h4(-Iz*@-%528gFidNCpCqiH_
zH|)eOUKW*<5Q7yWaKLZaIog^F^6BjEiKyp)f@ZTPNn4zih+ovxv!$2Y>sT7uEPwQB
z<_2kBU9h-JuRqIm(TP@2OG{QRFDWH0S5RA>UtJ`G`$pNG8}7ZppapeC%e27$j4G~ZKnY@<|koRmKan)6jRWP_%nqt@IC
znpYGZRU#D~7X(g#hg(4}7gxG`525#61e&?jQCw8@RQygvMw>u$^&COw%u7R;i;V8V
zYRq>}lyvFx<>dVd&=jhr@pN<{uvr3{k4!+<0tR0J&08!Ou5|paN8G%V9p?+Ud9k~t
zsxQU+rlKJouT*qrLw?z(IL^{SK|-6Jl8$0~1vDA+C0)AmG5st>BPmn!qka^D?wkqu
zRik{%L9=6_w-N<+OgR8
z22A&7Eh2!VTfB5>9MXfQ6Je*~F08!RgAe1_zLzOmplQX9MZ(So>w9n#bQ~5&$ke)0
z@gv=F1r`y&RCLU@eiC$S-_^=yXs)UFk?v#sV_m7}nD3af8JaX5-C4>Oj7P`%etHsg
zESfi=pQp-~B7SKSbmaGJA^uobDt@f*G}U)CX*#+;u+v&sDmvD8ANr+zrJ`fLg9-gZ
z&{@t6c?`hbx2%EgH%g8)tDw{UqeWt|U=Nl5brT$mizJ5SNJV!$?9kPqd0(rfJ1Gs_
z6X191I_&;&`wACTEET_fp!>$f7%wjoWTIcCqI(eo+OI+L5C;-mr{hjVSAqfj{4mDq
zD+HNSo`&u@)Z-gHj-`QllsOMK_(XHQAi7T&Lxbj4}-y@c|8`Wlq)gOZN=n2O(TfRFBUoTgop4(2~4-8=9;M?iDKeo1#r
z8oDynqv>PFmjt-d>A^hEy$zZ7{dZzs^XClxjZ_CA@n=T1};
z2Nia&EY90|8{m;z@BYA%-G85vcf)>09jY#(DRB^%LG>A4K(CGw%_^de;Yeft-X~*o
zN7m2Uf9cV^FXVmvk-b05yXE2R7xMO2gVAtx(Tb7UX?w@EXTPM#cfaX-$OkyD^3CCE
zib{rqMZS^RSs<()shx`;Fj6~j?^vujFtWZd0A_pM0r7_#z265r=h^>Q`F!3De+C4~
zw!m;}Q8SK7?0(amcf-#mvaIyi_r2N~aY}zCG7Rh;%iHq+qUwha;h=@UH4Oi=e%Is8
zs8?|Kh`{9KXXWKL=KJ#sZa9Fn2tWJ;LKLO2e)xvxi8^${VFbMLE*>M{jgs(&Q5Ak3
z;ohUMg~8#!t3w=n#$sptSAMW0nggkcLHLy^LDac8u)npaSmzBYVBdb_B#i(AQ79dj
z{yH%HJdSW|)JHh>pb%rYz0QB*??C|_2kAU4p!WfKL_k*odQ?ES0(wk9Z1{@>bPu4%
z1#|$=ApwaaA>VS3gskV$7AQ>YJSajab1wF#Pz)ttIdUhVw^0SH`f-
z8`v+V^DpKcWq4AQfz8n=pk??wM?lbUoCBa-s|*f4jFK0n
zCgnw+LCI^X*O|H`vm|3c*QSJmf?Bo(p`aUs(C)6l{tZ;s4MoNGLD0H}hh*7DvKdnt
z7=EjM_|=-yCk6IqNUVhAJrndl#O)QQ1zH7Ehrd4(kcYXimARv#R+NtIzNV_mDu;Up1`G5Oc|Ti0K_j%S&Qe~^V}VJ1F-
z_NJM*?*X(X&Np3;=itZ#MK^<>VeiqrJwrqcA8KGP>ju30LFzXX6@dDYJdwu|z=4rZ+=+A}*B^kq11lenUJ^L-nZU{?>W3c>
z=2aaDWPaivLvn`F`_q6-6uID1F#=Sd9(f9D7M^YS6c
zzoztWuS{$3ywPyxc``fLnw&!-W2VAEtD;eafkT2VQ9B>JhqVumERL1>X=?U<1K5VW
zf6d$bWkDIA9fyt|@XyO!%n0niiON~O>mP6goFDK{eO~2X1AG4(I~gar{KGi@^&?Rw
zo%0@?@cLD(v