mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-04-02 05:27:41 -05:00
Compare commits
340 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc8245ce4c | ||
|
|
1b88b3704d | ||
|
|
6dbaac4283 | ||
|
|
180a27fdc9 | ||
|
|
c02465b892 | ||
|
|
f503a89f98 | ||
|
|
f94e5488d4 | ||
|
|
87621e9337 | ||
|
|
3219ba68de | ||
|
|
5d608603cb | ||
|
|
7336c8dddc | ||
|
|
c91e3875d4 | ||
|
|
0181325b64 | ||
|
|
11f55a7561 | ||
|
|
9bb3a92e12 | ||
|
|
3e9ba8c636 | ||
|
|
4faebf435c | ||
|
|
749823e044 | ||
|
|
608c9e2e7a | ||
|
|
96ee544538 | ||
|
|
7ea7c531e2 | ||
|
|
969a37877a | ||
|
|
3cb8e37182 | ||
|
|
3e4c4430d5 | ||
|
|
4ad66365d0 | ||
|
|
39276e123e | ||
|
|
0f9434740f | ||
|
|
7ed153a47b | ||
|
|
c9d673ce40 | ||
|
|
0be610f1cd | ||
|
|
f75aa1f1b0 | ||
|
|
5ef58cdf76 | ||
|
|
511375feb5 | ||
|
|
8119929ece | ||
|
|
e1620966e5 | ||
|
|
a5b0a8614a | ||
|
|
e28f2dfea1 | ||
|
|
0dcfeaefb3 | ||
|
|
3bd4a3ba8b | ||
|
|
7e9b23de7d | ||
|
|
a758676b0d | ||
|
|
636ed0095d | ||
|
|
14341d611d | ||
|
|
07565eea63 | ||
|
|
c006062540 | ||
|
|
e685d65be8 | ||
|
|
ab67e274b2 | ||
|
|
7656fd7a4e | ||
|
|
60a2b30e91 | ||
|
|
7ec7e562d1 | ||
|
|
c50d52d0a6 | ||
|
|
2b765617ce | ||
|
|
79cdf51588 | ||
|
|
7b048d9b96 | ||
|
|
d96fc6d41b | ||
|
|
610f109e2a | ||
|
|
609afebc55 | ||
|
|
3bd9ab6349 | ||
|
|
5027f36d95 | ||
|
|
a5498995ff | ||
|
|
f40b5d9811 | ||
|
|
d00fae03a9 | ||
|
|
3c4e1b2f27 | ||
|
|
6e5d6810e7 | ||
|
|
4afd5a7905 | ||
|
|
6709baa710 | ||
|
|
aa1bf0b764 | ||
|
|
a7327290ea | ||
|
|
857e90a37b | ||
|
|
aaeebd3fe9 | ||
|
|
0a7a190b04 | ||
|
|
21d922113d | ||
|
|
b0876e1c35 | ||
|
|
18bc5de169 | ||
|
|
0321743f1e | ||
|
|
f2af90fe06 | ||
|
|
2f511ec4fa | ||
|
|
0649e0dcd3 | ||
|
|
0b21e30e44 | ||
|
|
ceeaca1a4b | ||
|
|
2da89f4b9b | ||
|
|
49371398bc | ||
|
|
2e73d74cea | ||
|
|
688471fd61 | ||
|
|
ea482ff0f5 | ||
|
|
5c9d0e29c2 | ||
|
|
8f07f0f8ae | ||
|
|
4f17a96707 | ||
|
|
b0ab8698ec | ||
|
|
ab41899cc2 | ||
|
|
50c3cf8272 | ||
|
|
1d2b8ac1f3 | ||
|
|
0b29719fe9 | ||
|
|
5a6e5d2255 | ||
|
|
82111617a4 | ||
|
|
0574387ee1 | ||
|
|
2d1381860d | ||
|
|
82f5900759 | ||
|
|
e44eb2aa8e | ||
|
|
34e12e2515 | ||
|
|
980e4cad06 | ||
|
|
5680b90549 | ||
|
|
bec655a8c6 | ||
|
|
0c8b3e31e7 | ||
|
|
a33c7135d1 | ||
|
|
13a3942f8f | ||
|
|
1bdc1d7241 | ||
|
|
fe9026b68d | ||
|
|
b0028b0e51 | ||
|
|
f54617e92f | ||
|
|
306690762c | ||
|
|
58a0fe8109 | ||
|
|
1e39f4354f | ||
|
|
e1b12546da | ||
|
|
1b28bf1474 | ||
|
|
8245f3d4c9 | ||
|
|
5fc8e710a5 | ||
|
|
b8636a8589 | ||
|
|
bb8b4afb85 | ||
|
|
d5b1ef7875 | ||
|
|
6c122e5fbe | ||
|
|
7ae814f7fb | ||
|
|
bdc51dd8a5 | ||
|
|
04a5efc7a3 | ||
|
|
99a736df27 | ||
|
|
535aeb5e39 | ||
|
|
07bef10092 | ||
|
|
c32515bc44 | ||
|
|
1690cd2740 | ||
|
|
52925c99e8 | ||
|
|
1367e9cebe | ||
|
|
3e87022da1 | ||
|
|
143fe36d35 | ||
|
|
18d5fd5d3e | ||
|
|
2829bf2640 | ||
|
|
ffafb05d3d | ||
|
|
cf72b5ec5c | ||
|
|
803b99f2a9 | ||
|
|
86b49f34d9 | ||
|
|
7e144b136b | ||
|
|
aa7c5422c0 | ||
|
|
5512585cc5 | ||
|
|
013eaae715 | ||
|
|
349b5da810 | ||
|
|
e7494be5e7 | ||
|
|
320629931c | ||
|
|
87d0aae608 | ||
|
|
391c8acfe4 | ||
|
|
dc77d81e1b | ||
|
|
00c9a92977 | ||
|
|
af4dd9f5b0 | ||
|
|
09f1b56964 | ||
|
|
f9a08f5c11 | ||
|
|
e79664256a | ||
|
|
70f3014390 | ||
|
|
b4d0f984a4 | ||
|
|
d4ad457af1 | ||
|
|
cb5d197700 | ||
|
|
78e66f8959 | ||
|
|
f562260e42 | ||
|
|
21f38974a8 | ||
|
|
dfca7e923c | ||
|
|
6913598de4 | ||
|
|
ac858b37ed | ||
|
|
80edaea392 | ||
|
|
9c9ac23818 | ||
|
|
51e615095e | ||
|
|
d92e7d19cc | ||
|
|
248b93f41a | ||
|
|
c73f33aac2 | ||
|
|
7c18ad49ae | ||
|
|
5f713882d4 | ||
|
|
1698f1599b | ||
|
|
24e584c77b | ||
|
|
a5568d09d8 | ||
|
|
7a4f909c68 | ||
|
|
89aee456c6 | ||
|
|
4cf92103d8 | ||
|
|
e3b1ebb826 | ||
|
|
3658d8d96e | ||
|
|
6c047f01f9 | ||
|
|
fc105ecc3d | ||
|
|
649f6c28bf | ||
|
|
867972b7f5 | ||
|
|
efe3227ef2 | ||
|
|
aab8c88a96 | ||
|
|
af18ca011b | ||
|
|
24106b860a | ||
|
|
60efb6973b | ||
|
|
cffd55bdda | ||
|
|
88e767aaaf | ||
|
|
d6cda43618 | ||
|
|
3b229cd5cb | ||
|
|
72c4dbdb2f | ||
|
|
4da18d3630 | ||
|
|
2f04cfd5c6 | ||
|
|
8195db6d4c | ||
|
|
722f6315c4 | ||
|
|
173ed5475c | ||
|
|
1460044e91 | ||
|
|
06a7b6e446 | ||
|
|
28b7b4b7f1 | ||
|
|
8930adf532 | ||
|
|
f44b8a5618 | ||
|
|
6a9f79628e | ||
|
|
245c56ba8a | ||
|
|
98846421f6 | ||
|
|
0aaeeffff7 | ||
|
|
c2823facc2 | ||
|
|
fabb1596e5 | ||
|
|
725e32250b | ||
|
|
5fa264ea18 | ||
|
|
5e175b118d | ||
|
|
635173e55a | ||
|
|
eb2ed6852c | ||
|
|
2296766746 | ||
|
|
13be499510 | ||
|
|
fec5c567e1 | ||
|
|
8ef863cae1 | ||
|
|
9463105172 | ||
|
|
bb4819bce4 | ||
|
|
15be24db62 | ||
|
|
e7e2af9f91 | ||
|
|
8c5fd021f7 | ||
|
|
1a1ba19770 | ||
|
|
f95214d8fe | ||
|
|
631cfce2f8 | ||
|
|
45649264f9 | ||
|
|
0fd3cb0c4a | ||
|
|
3cfec69020 | ||
|
|
cec62d23b0 | ||
|
|
f3f0dda3d4 | ||
|
|
be16b66ac0 | ||
|
|
b9059aaa01 | ||
|
|
57a62d0544 | ||
|
|
d82f0e952f | ||
|
|
8731b7582b | ||
|
|
e6959dc572 | ||
|
|
a36b4d65e3 | ||
|
|
060ff56f9d | ||
|
|
0a0c0c0d07 | ||
|
|
17c4e405a6 | ||
|
|
53afa6ea43 | ||
|
|
a182e8daf2 | ||
|
|
a4dfaba03f | ||
|
|
6e23560e80 | ||
|
|
39e8d557e8 | ||
|
|
677c989664 | ||
|
|
c9342d90fb | ||
|
|
0693bb8d51 | ||
|
|
5cd3c305d0 | ||
|
|
e00b59c393 | ||
|
|
7c1e33dde6 | ||
|
|
367bd76046 | ||
|
|
1a1bf98905 | ||
|
|
4c1a24058c | ||
|
|
294e95caf8 | ||
|
|
031884c327 | ||
|
|
466dacaab4 | ||
|
|
1f8645fd43 | ||
|
|
880568cc60 | ||
|
|
f10fb56042 | ||
|
|
64be6d89ee | ||
|
|
5442c32a3f | ||
|
|
4ee53701e6 | ||
|
|
5097a223e3 | ||
|
|
7cdba75bef | ||
|
|
0312027ca8 | ||
|
|
c726c96286 | ||
|
|
5a2b2e0813 | ||
|
|
4271b2e9fd | ||
|
|
13ef4c04d1 | ||
|
|
96c3bb1e38 | ||
|
|
a0b36925ed | ||
|
|
daadc2ea71 | ||
|
|
ec2934b4b8 | ||
|
|
3a840c4ced | ||
|
|
bd190d2b65 | ||
|
|
9b05a36529 | ||
|
|
d9a498e8ec | ||
|
|
7d86b277a7 | ||
|
|
d463b3235e | ||
|
|
5a8433ede4 | ||
|
|
00a5fd2d7c | ||
|
|
55f9faea10 | ||
|
|
fb2e668589 | ||
|
|
0dafb3d230 | ||
|
|
e958934a22 | ||
|
|
069221757f | ||
|
|
505c1bc274 | ||
|
|
cdd5d33e89 | ||
|
|
f661f4d1d6 | ||
|
|
f435191585 | ||
|
|
00c2d7ea71 | ||
|
|
cddcc1e85d | ||
|
|
91928b45d8 | ||
|
|
277c83e6d8 | ||
|
|
0017cd2e40 | ||
|
|
774803492c | ||
|
|
83a9655772 | ||
|
|
58324b4539 | ||
|
|
09b7794d71 | ||
|
|
9e3fe9beb1 | ||
|
|
ff525fe750 | ||
|
|
94977ad216 | ||
|
|
64e34e42b8 | ||
|
|
21dc65f42a | ||
|
|
279e085887 | ||
|
|
d84dfa2c42 | ||
|
|
bf8089dc7e | ||
|
|
e48761b5c0 | ||
|
|
35437c0300 | ||
|
|
6cecc12d04 | ||
|
|
dec4231d49 | ||
|
|
fb1d12ebf3 | ||
|
|
b19276a3e9 | ||
|
|
5ccbfc1ff8 | ||
|
|
d3d6a8a838 | ||
|
|
ac83bbeb0e | ||
|
|
8cb76a26c1 | ||
|
|
20da22d59e | ||
|
|
d9fa4b452c | ||
|
|
6216d72aa6 | ||
|
|
851f132188 | ||
|
|
3067ff08ec | ||
|
|
07fd86fc9d | ||
|
|
504037c115 | ||
|
|
0fad21a980 | ||
|
|
8afd698284 | ||
|
|
9ec7b90192 | ||
|
|
08f0fff34b | ||
|
|
2c1073eda9 | ||
|
|
c9348f0651 | ||
|
|
accb461c08 | ||
|
|
75adcc0a96 | ||
|
|
61ce88ba9b | ||
|
|
4b451fd1d3 | ||
|
|
a87190960f | ||
|
|
45558027a6 | ||
|
|
e426606542 |
68
.clang-tidy
Normal file
68
.clang-tidy
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# Generated from CLion Inspection settings
|
||||||
|
---
|
||||||
|
Checks: '-*,
|
||||||
|
mpi-*,
|
||||||
|
bugprone-*,
|
||||||
|
-bugprone-signal-handler,
|
||||||
|
-bugprone-narrowing-conversions,
|
||||||
|
-bugprone-redundant-branch-condition,
|
||||||
|
-bugprone-exception-escape,
|
||||||
|
-bugprone-shared-ptr-array-mismatch,
|
||||||
|
-bugprone-implicit-widening-of-multiplication-result,
|
||||||
|
-bugprone-signed-char-misuse,
|
||||||
|
-bugprone-unhandled-exception-at-new,
|
||||||
|
-bugprone-infinite-loop,
|
||||||
|
-bugprone-easily-swappable-parameters,
|
||||||
|
cert-err52-cpp,
|
||||||
|
cert-err60-cpp,
|
||||||
|
cert-err34-c,
|
||||||
|
cert-str34-c,
|
||||||
|
cert-dcl21-cpp,
|
||||||
|
cert-msc50-cpp,
|
||||||
|
cert-msc51-cpp,
|
||||||
|
cert-dcl58-cpp,
|
||||||
|
cert-flp30-c,
|
||||||
|
cppcoreguidelines-avoid-const-or-ref-data-members,
|
||||||
|
cppcoreguidelines-pro-type-member-init,
|
||||||
|
cppcoreguidelines-slicing,
|
||||||
|
cppcoreguidelines-interfaces-global-init,
|
||||||
|
cppcoreguidelines-pro-type-static-cast-downcast,
|
||||||
|
cppcoreguidelines-narrowing-conversions,
|
||||||
|
google-default-arguments,
|
||||||
|
google-runtime-operator,
|
||||||
|
google-explicit-constructor,
|
||||||
|
hicpp-multiway-paths-covered,
|
||||||
|
hicpp-exception-baseclass,
|
||||||
|
misc-*,
|
||||||
|
-misc-definitions-in-headers,
|
||||||
|
-misc-unused-parameters,
|
||||||
|
-misc-unused-alias-decls,
|
||||||
|
-misc-use-anonymous-namespace,
|
||||||
|
-misc-misleading-identifier,
|
||||||
|
-misc-confusable-identifiers,
|
||||||
|
-misc-misleading-bidirectional,
|
||||||
|
-misc-static-assert,
|
||||||
|
-misc-no-recursion,
|
||||||
|
-misc-const-correctness,
|
||||||
|
modernize-*,
|
||||||
|
-modernize-use-trailing-return-type,
|
||||||
|
openmp-use-default-none,
|
||||||
|
performance-*,
|
||||||
|
-performance-no-int-to-ptr,
|
||||||
|
portability-*,
|
||||||
|
-portability-restrict-system-includes,
|
||||||
|
readability-*,
|
||||||
|
-readability-redundant-preprocessor,
|
||||||
|
-readability-named-parameter,
|
||||||
|
-readability-function-size,
|
||||||
|
-readability-use-anyofallof,
|
||||||
|
-readability-identifier-length,
|
||||||
|
-readability-magic-numbers,
|
||||||
|
-readability-braces-around-statements,
|
||||||
|
-readability-suspicious-call-argument,
|
||||||
|
-readability-isolate-declaration,
|
||||||
|
-readability-else-after-return,
|
||||||
|
-readability-redundant-access-specifiers,
|
||||||
|
-readability-function-cognitive-complexity,
|
||||||
|
-readability-identifier-naming,
|
||||||
|
-readability-qualified-auto'
|
||||||
150
.github/workflows/build.yml
vendored
150
.github/workflows/build.yml
vendored
@@ -70,19 +70,22 @@ jobs:
|
|||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
|
|
||||||
cmake -G "MinGW Makefiles" \
|
cmake -G "MinGW Makefiles" \
|
||||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||||
-DCREATE_PACKAGE=ON \
|
-DCREATE_PACKAGE=ON \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||||
|
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
|
||||||
|
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
|
||||||
|
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||||
..
|
..
|
||||||
mingw32-make -j4 install
|
mingw32-make -j4 install
|
||||||
cpack
|
cpack
|
||||||
mv imhex-*.msi ../imhex-${{env.IMHEX_VERSION}}-Windows-x86_64.msi
|
mv ImHex-*.msi ../imhex-${{env.IMHEX_VERSION}}-Windows-x86_64.msi
|
||||||
|
|
||||||
echo "ImHex checks for the existence of this file to determine if it is running in portable mode. You should not delete this file" > $PWD/install/PORTABLE
|
echo "ImHex checks for the existence of this file to determine if it is running in portable mode. You should not delete this file" > $PWD/install/PORTABLE
|
||||||
|
|
||||||
@@ -179,12 +182,15 @@ jobs:
|
|||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
|
|
||||||
cmake \
|
cmake \
|
||||||
-DBUILD_SHARED_LIBS=ON \
|
-DBUILD_SHARED_LIBS=ON \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
|
||||||
|
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
|
||||||
|
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||||
..
|
..
|
||||||
make -j 4 install
|
make -j 4 install
|
||||||
|
|
||||||
@@ -193,23 +199,26 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
|
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
|
||||||
CXX=$(brew --prefix gcc@12)/bin/g++-12 \
|
CXX=$(brew --prefix gcc@12)/bin/g++-12 \
|
||||||
OBJC=$(brew --prefix llvm)/bin/clang \
|
OBJC=$(brew --prefix llvm)/bin/clang \
|
||||||
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
|
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
|
||||||
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
|
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
|
||||||
MACOSX_DEPLOYMENT_TARGET="10.10" \
|
MACOSX_DEPLOYMENT_TARGET="10.10" \
|
||||||
cmake \
|
cmake \
|
||||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
-DCREATE_BUNDLE=ON \
|
-DCREATE_BUNDLE=ON \
|
||||||
-DCREATE_PACKAGE=ON \
|
-DCREATE_PACKAGE=ON \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||||
-DCMAKE_OSX_DEPLOYMENT_TARGET="10.10" \
|
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
|
||||||
-DCPACK_PACKAGE_FILE_NAME="imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}-x86_64" \
|
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
|
||||||
|
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||||
|
-DCMAKE_OSX_DEPLOYMENT_TARGET="10.10" \
|
||||||
|
-DCPACK_PACKAGE_FILE_NAME="imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}-x86_64" \
|
||||||
..
|
..
|
||||||
make -j4 package
|
make -j4 package
|
||||||
|
|
||||||
@@ -254,13 +263,16 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
CC=gcc-12 CXX=g++-12 cmake \
|
CC=gcc-12 CXX=g++-12 cmake \
|
||||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||||
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
|
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
|
||||||
|
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
|
||||||
|
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||||
|
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
|
||||||
..
|
..
|
||||||
make -j 4 install DESTDIR=DebDir
|
make -j 4 install DESTDIR=DebDir
|
||||||
|
|
||||||
@@ -324,15 +336,18 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir -p build-appimage
|
mkdir -p build-appimage
|
||||||
cd build-appimage
|
cd build-appimage
|
||||||
CC=gcc-12 CXX=g++-12 cmake \
|
CC=gcc-12 CXX=g++-12 cmake \
|
||||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||||
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
|
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
|
||||||
-DIMHEX_PLUGINS_IN_SHARE=ON \
|
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
|
||||||
-DIMHEX_USE_BUNDLED_CA=ON \
|
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||||
|
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
|
||||||
|
-DIMHEX_PLUGINS_IN_SHARE=ON \
|
||||||
|
-DIMHEX_USE_BUNDLED_CA=ON \
|
||||||
..
|
..
|
||||||
make -j 4 install DESTDIR=AppDir
|
make -j 4 install DESTDIR=AppDir
|
||||||
|
|
||||||
@@ -399,18 +414,21 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
CC=gcc CXX=g++ cmake \
|
CC=gcc CXX=g++ cmake \
|
||||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DUSE_SYSTEM_CURL=ON \
|
-DUSE_SYSTEM_CURL=ON \
|
||||||
-DUSE_SYSTEM_FMT=ON \
|
-DUSE_SYSTEM_FMT=ON \
|
||||||
-DUSE_SYSTEM_YARA=ON \
|
-DUSE_SYSTEM_YARA=ON \
|
||||||
-DUSE_SYSTEM_NLOHMANN_JSON=ON \
|
-DUSE_SYSTEM_NLOHMANN_JSON=ON \
|
||||||
-DUSE_SYSTEM_CAPSTONE=OFF \
|
-DUSE_SYSTEM_CAPSTONE=OFF \
|
||||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||||
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
|
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
|
||||||
|
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
|
||||||
|
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||||
|
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
|
||||||
..
|
..
|
||||||
make -j 4 install DESTDIR=installDir
|
make -j 4 install DESTDIR=installDir
|
||||||
|
|
||||||
@@ -456,6 +474,10 @@ jobs:
|
|||||||
mock_release: rawhide
|
mock_release: rawhide
|
||||||
release_num: rawhide
|
release_num: rawhide
|
||||||
mock_config: fedora-rawhide
|
mock_config: fedora-rawhide
|
||||||
|
- name: Fedora
|
||||||
|
mock_release: f38
|
||||||
|
release_num: 38
|
||||||
|
mock_config: fedora-38
|
||||||
- name: Fedora
|
- name: Fedora
|
||||||
mock_release: f37
|
mock_release: f37
|
||||||
release_num: 37
|
release_num: 37
|
||||||
@@ -515,7 +537,7 @@ jobs:
|
|||||||
- name: 🗜️ Create tarball from sources with dependencies
|
- name: 🗜️ Create tarball from sources with dependencies
|
||||||
run: tar --exclude-vcs -czf $GITHUB_WORKSPACE/imhex-$IMHEX_VERSION.tar.gz ImHex
|
run: tar --exclude-vcs -czf $GITHUB_WORKSPACE/imhex-$IMHEX_VERSION.tar.gz ImHex
|
||||||
|
|
||||||
- name: "✒️ Modify spec file: set version, use latest pattern language, enable online build"
|
- name: ✒️ Modify spec file
|
||||||
run: |
|
run: |
|
||||||
sed -i \
|
sed -i \
|
||||||
-e 's/Version: [0-9]*\.[0-9]*\.[0-9]*$/Version: ${{env.IMHEX_VERSION}}/g' \
|
-e 's/Version: [0-9]*\.[0-9]*\.[0-9]*$/Version: ${{env.IMHEX_VERSION}}/g' \
|
||||||
@@ -546,9 +568,9 @@ jobs:
|
|||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: /var/cache/mock
|
path: /var/cache/mock
|
||||||
key: ${{ matrix.mock_release }}-${{secrets.CACHE_VERSION }}-mock-${{ github.run_id }}
|
key: ${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-mock-${{ github.run_id }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ matrix.mock_release }}-${{secrets.CACHE_VERSION }}-mock-
|
${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-mock-
|
||||||
|
|
||||||
# Fedora cmake build (in imhex.spec)
|
# Fedora cmake build (in imhex.spec)
|
||||||
- name: 📦 Build RPM
|
- name: 📦 Build RPM
|
||||||
|
|||||||
122
.github/workflows/release.yml
vendored
122
.github/workflows/release.yml
vendored
@@ -9,9 +9,66 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release-common:
|
release-update-repos:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: Release Common
|
name: Release Update Repos
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: 📜 Verify version and set version variable
|
||||||
|
run: |
|
||||||
|
project_version=`cat ImHex/VERSION`
|
||||||
|
tag_version="${{github.event.release.tag_name}}"
|
||||||
|
tag_version="${tag_version:1}"
|
||||||
|
if [ "$project_version" != "$tag_version" ]; then
|
||||||
|
echo "::warning::$project_version and $tag_version are not the same ! Refusing to populate release"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "IMHEX_VERSION=$project_version" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: 🎫 Create PatternLanguage release
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
env:
|
||||||
|
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||||
|
with:
|
||||||
|
tag: ImHex-v${{ env.IMHEX_VERSION }}
|
||||||
|
repo: PatternLanguage
|
||||||
|
token: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
|
||||||
|
- name: 🎫 Create ImHex-Patterns release
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
env:
|
||||||
|
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||||
|
with:
|
||||||
|
tag: ImHex-v${{ env.IMHEX_VERSION }}
|
||||||
|
repo: ImHex-Patterns
|
||||||
|
token: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
|
||||||
|
- name: ✉️ Update C++ Plugin Template
|
||||||
|
uses: peter-evans/repository-dispatch@v2
|
||||||
|
env:
|
||||||
|
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
repository: WerWolv/ImHex-Cpp-Plugin-Template
|
||||||
|
event-type: update_submodule
|
||||||
|
|
||||||
|
- name: ✉️ Update Rust Plugin Template
|
||||||
|
uses: peter-evans/repository-dispatch@v2
|
||||||
|
env:
|
||||||
|
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
repository: WerWolv/ImHex-Rust-Plugin-Template
|
||||||
|
event-type: update_submodule
|
||||||
|
|
||||||
|
release-upload-artifacts:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: Release Upload Artifacts
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 🧰 Checkout
|
- name: 🧰 Checkout
|
||||||
@@ -60,8 +117,8 @@ jobs:
|
|||||||
|
|
||||||
- name: 🟩 Rename artifacts when needed
|
- name: 🟩 Rename artifacts when needed
|
||||||
run: |
|
run: |
|
||||||
mv "Windows Portable x86_64.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable-x86_64.zip
|
mv "Windows Portable x86_64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-x86_64.zip
|
||||||
mv "Windows Portable NoGPU x86_64.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable-NoGPU-x86_64.zip
|
mv "Windows Portable NoGPU x86_64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-NoGPU-x86_64.zip
|
||||||
|
|
||||||
- name: ⬆️ Upload everything to release
|
- name: ⬆️ Upload everything to release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
@@ -72,14 +129,13 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cp ImHex/dist/Arch/PKGBUILD .
|
cp ImHex/dist/Arch/PKGBUILD .
|
||||||
|
|
||||||
hash=`md5sum imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst-x86_64 | cut -d ' ' -f 1`
|
hash=`md5sum imhex-${{ env.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst | cut -d ' ' -f 1`
|
||||||
|
|
||||||
sed -i 's/%version%/${{env.IMHEX_VERSION}}/g' PKGBUILD
|
sed -i 's/%version%/${{ env.IMHEX_VERSION }}/g' PKGBUILD
|
||||||
sed -i "s/(SKIP)/($hash)/g" PKGBUILD
|
sed -i "s/(SKIP)/($hash)/g" PKGBUILD
|
||||||
|
|
||||||
- name: ⬆️ Publish AUR package
|
- name: ⬆️ Publish AUR package
|
||||||
|
|
||||||
# I couldn't make the condition in the env directly for some reason
|
|
||||||
env:
|
env:
|
||||||
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||||
if: "${{ env.AUR_SSH_PRIVATE_KEY != '' }}"
|
if: "${{ env.AUR_SSH_PRIVATE_KEY != '' }}"
|
||||||
@@ -91,58 +147,18 @@ jobs:
|
|||||||
commit_username: iTrooz
|
commit_username: iTrooz
|
||||||
commit_email: itrooz@protonmail.com
|
commit_email: itrooz@protonmail.com
|
||||||
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||||
commit_message: Bump to version ${{env.IMHEX_VERSION}}
|
commit_message: Bump to version ${{ env.IMHEX_VERSION }}
|
||||||
ssh_keyscan_types: rsa,dsa,ecdsa,ed25519
|
ssh_keyscan_types: rsa,dsa,ecdsa,ed25519
|
||||||
|
|
||||||
- name: 🎫 Create PatternLanguage release
|
release-update-winget:
|
||||||
uses: ncipollo/release-action@v1
|
name: Release update winget package
|
||||||
env:
|
needs: release-upload-artifacts
|
||||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
runs-on: windows-latest
|
||||||
if: "${{ env.RELEASE_TOKEN != '' }}"
|
|
||||||
with:
|
|
||||||
tag: ImHex-v${{env.IMHEX_VERSION}}
|
|
||||||
repo: PatternLanguage
|
|
||||||
token: ${{ secrets.RELEASE_TOKEN }}
|
|
||||||
|
|
||||||
- name: 🎫 Create ImHex-Patterns release
|
|
||||||
uses: ncipollo/release-action@v1
|
|
||||||
env:
|
|
||||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
||||||
if: "${{ env.RELEASE_TOKEN != '' }}"
|
|
||||||
with:
|
|
||||||
tag: ImHex-v${{env.IMHEX_VERSION}}
|
|
||||||
repo: ImHex-Patterns
|
|
||||||
token: ${{ secrets.RELEASE_TOKEN }}
|
|
||||||
|
|
||||||
- name: ✉️ Update C++ Plugin Template
|
|
||||||
uses: peter-evans/repository-dispatch@v2
|
|
||||||
env:
|
|
||||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
||||||
if: "${{ env.RELEASE_TOKEN != '' }}"
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.RELEASE_TOKEN }}
|
|
||||||
repository: WerWolv/ImHex-Cpp-Plugin-Template
|
|
||||||
event_type: update_submodule
|
|
||||||
|
|
||||||
- name: ✉️ Update Rust Plugin Template
|
|
||||||
uses: peter-evans/repository-dispatch@v2
|
|
||||||
env:
|
|
||||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
||||||
if: "${{ env.RELEASE_TOKEN != '' }}"
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.RELEASE_TOKEN }}
|
|
||||||
repository: WerWolv/ImHex-Rust-Plugin-Template
|
|
||||||
event_type: update_submodule
|
|
||||||
|
|
||||||
release-windows:
|
|
||||||
name: Release Windows
|
|
||||||
needs: release-common
|
|
||||||
runs-on: windows-2022
|
|
||||||
steps:
|
steps:
|
||||||
- name: ⬇️ Download dependencies
|
- name: ⬇️ Download dependencies
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
iwr https://github.com/microsoft/winget-create/releases/download/v1.1.2.0/wingetcreate.exe -OutFile wingetcreate.exe
|
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
|
||||||
- name: ⬆️ Update winget manifest
|
- name: ⬆️ Update winget manifest
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
env:
|
env:
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,3 +8,4 @@ venv/
|
|||||||
*.mgc
|
*.mgc
|
||||||
imgui.ini
|
imgui.ini
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
./CMakeUserPresets.json
|
||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -29,3 +29,6 @@
|
|||||||
[submodule "lib/external/pattern_language"]
|
[submodule "lib/external/pattern_language"]
|
||||||
path = lib/external/pattern_language
|
path = lib/external/pattern_language
|
||||||
url = https://github.com/WerWolv/PatternLanguage
|
url = https://github.com/WerWolv/PatternLanguage
|
||||||
|
[submodule "lib/external/libwolv"]
|
||||||
|
path = lib/external/libwolv
|
||||||
|
url = https://github.com/WerWolv/libwolv
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ option(IMHEX_IGNORE_BAD_CLONE "Disable the bad clone prevention checks" OFF)
|
|||||||
option(IMHEX_PATTERNS_PULL_MASTER "Download latest files from master branch of the ImHex-Patterns repo" OFF)
|
option(IMHEX_PATTERNS_PULL_MASTER "Download latest files from master branch of the ImHex-Patterns repo" OFF)
|
||||||
option(IMHEX_IGNORE_BAD_COMPILER "Allow compiling with an unsupported compiler" OFF)
|
option(IMHEX_IGNORE_BAD_COMPILER "Allow compiling with an unsupported compiler" OFF)
|
||||||
option(IMHEX_USE_GTK_FILE_PICKER "Use GTK file picker instead of xdg-desktop-portals" OFF)
|
option(IMHEX_USE_GTK_FILE_PICKER "Use GTK file picker instead of xdg-desktop-portals" OFF)
|
||||||
|
option(IMHEX_DISABLE_STACKTRACE "Disables support for printing stack traces" OFF)
|
||||||
|
option(IMHEX_DISABLE_UPDATE_CHECK "Disables built-in update check" OFF)
|
||||||
|
|
||||||
# Basic compiler and cmake configurations
|
# Basic compiler and cmake configurations
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
@@ -40,7 +42,7 @@ set(PLUGINS
|
|||||||
# Add various defines
|
# Add various defines
|
||||||
detectOS()
|
detectOS()
|
||||||
detectArch()
|
detectArch()
|
||||||
addVersionDefines()
|
addDefines()
|
||||||
configurePackingResources()
|
configurePackingResources()
|
||||||
setUninstallTarget()
|
setUninstallTarget()
|
||||||
addBundledLibraries()
|
addBundledLibraries()
|
||||||
@@ -48,7 +50,7 @@ addBundledLibraries()
|
|||||||
# Add ImHex sources
|
# Add ImHex sources
|
||||||
add_subdirectory(lib/libimhex)
|
add_subdirectory(lib/libimhex)
|
||||||
add_subdirectory(main)
|
add_subdirectory(main)
|
||||||
add_custom_target(imhex ALL DEPENDS main libimhex)
|
add_custom_target(imhex_all ALL DEPENDS main libimhex)
|
||||||
|
|
||||||
# Add unit tests
|
# Add unit tests
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|||||||
47
CMakePresets.json
Normal file
47
CMakePresets.json
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"cmakeMinimumRequired": {
|
||||||
|
"major": 3,
|
||||||
|
"minor": 20,
|
||||||
|
"patch": 0
|
||||||
|
},
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "base",
|
||||||
|
"displayName": "Base",
|
||||||
|
"description": "Base configuration for all builds",
|
||||||
|
"hidden": true,
|
||||||
|
"binaryDir": "${sourceDir}/build/${presetName}",
|
||||||
|
"generator": "Ninja",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Debug",
|
||||||
|
"CMAKE_C_COMPILER": "gcc",
|
||||||
|
"CMAKE_CXX_COMPILER": "g++",
|
||||||
|
"CMAKE_C_COMPILER_LAUNCHER": "ccache",
|
||||||
|
"CMAKE_CXX_COMPILER_LAUNCHER": "ccache",
|
||||||
|
"CMAKE_C_FLAGS": "-fuse-ld=lld",
|
||||||
|
"CMAKE_CXX_FLAGS": "-fuse-ld=lld",
|
||||||
|
"IMHEX_PATTERNS_PULL_MASTER": "ON",
|
||||||
|
"CMAKE_INSTALL_PREFIX": "./install",
|
||||||
|
"USE_SYSTEM_CURL": "ON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "x86_64",
|
||||||
|
"displayName": "x86_64 Build",
|
||||||
|
"description": "x86_64 build",
|
||||||
|
"inherits": [ "base" ]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buildPresets": [
|
||||||
|
{
|
||||||
|
"name": "x86_64",
|
||||||
|
"description": "x86_64 build",
|
||||||
|
"configurePreset": "x86_64",
|
||||||
|
"targets": [ "imhex_all" ]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"testPresets": [
|
||||||
|
|
||||||
|
]
|
||||||
|
}
|
||||||
128
CODE_OF_CONDUCT.md
Normal file
128
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
We as members, contributors, and leaders pledge to make participation in our
|
||||||
|
community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||||
|
identity and expression, level of experience, education, socio-economic status,
|
||||||
|
nationality, personal appearance, race, religion, or sexual identity
|
||||||
|
and orientation.
|
||||||
|
|
||||||
|
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||||
|
diverse, inclusive, and healthy community.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to a positive environment for our
|
||||||
|
community include:
|
||||||
|
|
||||||
|
* Demonstrating empathy and kindness toward other people
|
||||||
|
* Being respectful of differing opinions, viewpoints, and experiences
|
||||||
|
* Giving and gracefully accepting constructive feedback
|
||||||
|
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||||
|
and learning from the experience
|
||||||
|
* Focusing on what is best not just for us as individuals, but for the
|
||||||
|
overall community
|
||||||
|
|
||||||
|
Examples of unacceptable behavior include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery, and sexual attention or
|
||||||
|
advances of any kind
|
||||||
|
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or email
|
||||||
|
address, without their explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Enforcement Responsibilities
|
||||||
|
|
||||||
|
Community leaders are responsible for clarifying and enforcing our standards of
|
||||||
|
acceptable behavior and will take appropriate and fair corrective action in
|
||||||
|
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||||
|
or harmful.
|
||||||
|
|
||||||
|
Community leaders have the right and responsibility to remove, edit, or reject
|
||||||
|
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||||
|
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||||
|
decisions when appropriate.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies within all community spaces, and also applies when
|
||||||
|
an individual is officially representing the community in public spaces.
|
||||||
|
Examples of representing our community include using an official e-mail address,
|
||||||
|
posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported to the community leaders responsible for enforcement at
|
||||||
|
Discord @WerWolv#1337.
|
||||||
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
reporter of any incident.
|
||||||
|
|
||||||
|
## Enforcement Guidelines
|
||||||
|
|
||||||
|
Community leaders will follow these Community Impact Guidelines in determining
|
||||||
|
the consequences for any action they deem in violation of this Code of Conduct:
|
||||||
|
|
||||||
|
### 1. Correction
|
||||||
|
|
||||||
|
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||||
|
unprofessional or unwelcome in the community.
|
||||||
|
|
||||||
|
**Consequence**: A private, written warning from community leaders, providing
|
||||||
|
clarity around the nature of the violation and an explanation of why the
|
||||||
|
behavior was inappropriate. A public apology may be requested.
|
||||||
|
|
||||||
|
### 2. Warning
|
||||||
|
|
||||||
|
**Community Impact**: A violation through a single incident or series
|
||||||
|
of actions.
|
||||||
|
|
||||||
|
**Consequence**: A warning with consequences for continued behavior. No
|
||||||
|
interaction with the people involved, including unsolicited interaction with
|
||||||
|
those enforcing the Code of Conduct, for a specified period of time. This
|
||||||
|
includes avoiding interactions in community spaces as well as external channels
|
||||||
|
like social media. Violating these terms may lead to a temporary or
|
||||||
|
permanent ban.
|
||||||
|
|
||||||
|
### 3. Temporary Ban
|
||||||
|
|
||||||
|
**Community Impact**: A serious violation of community standards, including
|
||||||
|
sustained inappropriate behavior.
|
||||||
|
|
||||||
|
**Consequence**: A temporary ban from any sort of interaction or public
|
||||||
|
communication with the community for a specified period of time. No public or
|
||||||
|
private interaction with the people involved, including unsolicited interaction
|
||||||
|
with those enforcing the Code of Conduct, is allowed during this period.
|
||||||
|
Violating these terms may lead to a permanent ban.
|
||||||
|
|
||||||
|
### 4. Permanent Ban
|
||||||
|
|
||||||
|
**Community Impact**: Demonstrating a pattern of violation of community
|
||||||
|
standards, including sustained inappropriate behavior, harassment of an
|
||||||
|
individual, or aggression toward or disparagement of classes of individuals.
|
||||||
|
|
||||||
|
**Consequence**: A permanent ban from any sort of public interaction within
|
||||||
|
the community.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||||
|
version 2.0, available at
|
||||||
|
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||||
|
|
||||||
|
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||||
|
enforcement ladder](https://github.com/mozilla/diversity).
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|
||||||
|
For answers to common questions about this code of conduct, see the FAQ at
|
||||||
|
https://www.contributor-covenant.org/faq. Translations are available at
|
||||||
|
https://www.contributor-covenant.org/translations.
|
||||||
@@ -25,6 +25,9 @@
|
|||||||
<a title="Translation" href="https://weblate.werwolv.net/projects/imhex/">
|
<a title="Translation" href="https://weblate.werwolv.net/projects/imhex/">
|
||||||
<img alt="Translation" src="https://img.shields.io/weblate/progress/imhex?logo=weblate&logoColor=%23FFFFFF&server=https%3A%2F%2Fweblate.werwolv.net&style=for-the-badge">
|
<img alt="Translation" src="https://img.shields.io/weblate/progress/imhex?logo=weblate&logoColor=%23FFFFFF&server=https%3A%2F%2Fweblate.werwolv.net&style=for-the-badge">
|
||||||
</a>
|
</a>
|
||||||
|
<a title="Documentation" href="https://imhex.werwolv.net/docs">
|
||||||
|
<img alt="Documentation" src="https://img.shields.io/badge/Docs-Available-brightgreen?logo=gitbook&logoColor=%23FFFFFF&style=for-the-badge">
|
||||||
|
</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Supporting
|
## Supporting
|
||||||
|
|||||||
10
SECURITY.md
Normal file
10
SECURITY.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
Supported is generally only the latest version that can be downloaded from the Release tab. If you have issues, you might get instructed to use the Nightly release version instead.
|
||||||
|
If you built ImHex yourself and experience issues that are not present in the version built by GitHub, you're on your own.
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
Any critical vulnearabilities can be reported through Discord @WerWolv#1337
|
||||||
@@ -1,37 +1,58 @@
|
|||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
|
|
||||||
if(IMHEX_STRIP_RELEASE)
|
if(IMHEX_STRIP_RELEASE)
|
||||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")
|
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")
|
|
||||||
|
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||||
set(CPACK_STRIP_FILES TRUE)
|
set(CPACK_STRIP_FILES TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||||
|
add_link_options($<$<CONFIG:RELEASE>:-s>)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
macro(addVersionDefines)
|
macro(addDefines)
|
||||||
if (NOT IMHEX_VERSION)
|
if (NOT IMHEX_VERSION)
|
||||||
message(FATAL_ERROR "IMHEX_VERSION is not defined")
|
message(FATAL_ERROR "IMHEX_VERSION is not defined")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (IS_DIRECTORY "${CMAKE_SOURCE_DIR}/.git")
|
if (DEFINED IMHEX_COMMIT_HASH_LONG AND DEFINED IMHEX_COMMIT_HASH_SHORT AND DEFINED IMHEX_COMMIT_BRANCH)
|
||||||
|
add_compile_definitions(
|
||||||
|
GIT_COMMIT_HASH_LONG="${IMHEX_COMMIT_HASH_LONG}"
|
||||||
|
IMHEX_COMMIT_HASH_SHORT="${IMHEX_COMMIT_HASH_SHORT}"
|
||||||
|
GIT_BRANCH="${IMHEX_COMMIT_BRANCH}"
|
||||||
|
)
|
||||||
|
else()
|
||||||
# Get the current working branch
|
# Get the current working branch
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND git rev-parse --abbrev-ref HEAD
|
COMMAND git rev-parse --abbrev-ref HEAD
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
OUTPUT_VARIABLE GIT_BRANCH
|
OUTPUT_VARIABLE GIT_BRANCH
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
RESULT_VARIABLE RESULT_BRANCH
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get the latest abbreviated commit hash of the working branch
|
# Get the latest abbreviated commit hash of the working branch
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND git log -1 --format=%h
|
COMMAND git log -1 --format=%h --abbrev=7
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
OUTPUT_VARIABLE GIT_COMMIT_HASH
|
OUTPUT_VARIABLE GIT_COMMIT_HASH_SHORT
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
RESULT_VARIABLE RESULT_HASH_SHORT
|
||||||
)
|
)
|
||||||
|
|
||||||
add_compile_definitions(GIT_COMMIT_HASH="${GIT_COMMIT_HASH}" GIT_BRANCH="${GIT_BRANCH}")
|
execute_process(
|
||||||
|
COMMAND git log -1 --format=%H
|
||||||
|
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||||
|
OUTPUT_VARIABLE GIT_COMMIT_HASH_LONG
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
RESULT_VARIABLE RESULT_HASH_LONG
|
||||||
|
)
|
||||||
|
|
||||||
|
if (RESULT_BRANCH EQUAL 0 AND RESULT_HASH_LONG EQUAL 0 AND RESULT_HASH_SHORT EQUAL 0)
|
||||||
|
add_compile_definitions(
|
||||||
|
GIT_COMMIT_HASH_SHORT="${GIT_COMMIT_HASH_SHORT}"
|
||||||
|
GIT_COMMIT_HASH_LONG="${GIT_COMMIT_HASH_LONG}"
|
||||||
|
GIT_BRANCH="${GIT_BRANCH}")
|
||||||
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -DPROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} -DPROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR} -DPROJECT_VERSION_PATCH=${PROJECT_VERSION_PATCH} ")
|
set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -DPROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} -DPROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR} -DPROJECT_VERSION_PATCH=${PROJECT_VERSION_PATCH} ")
|
||||||
@@ -39,17 +60,23 @@ macro(addVersionDefines)
|
|||||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION})
|
set(IMHEX_VERSION_STRING ${IMHEX_VERSION})
|
||||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING})
|
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING})
|
||||||
|
add_compile_definitions(NDEBUG)
|
||||||
elseif (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
elseif (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-Debug)
|
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-Debug)
|
||||||
add_compile_definitions(DEBUG _GLIBCXX_DEBUG _GLIBCXX_VERBOSE)
|
add_compile_definitions(DEBUG _GLIBCXX_DEBUG _GLIBCXX_VERBOSE)
|
||||||
elseif (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
elseif (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
||||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-RelWithDebInfo)
|
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-RelWithDebInfo)
|
||||||
|
add_compile_definitions(NDEBUG)
|
||||||
elseif (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
|
elseif (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
|
||||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-MinSizeRel)
|
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-MinSizeRel)
|
||||||
|
add_compile_definitions(NDEBUG)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
add_compile_definitions(IMHEX_VERSION="${IMHEX_VERSION_STRING}")
|
add_compile_definitions(IMHEX_VERSION="${IMHEX_VERSION_STRING}")
|
||||||
|
|
||||||
|
if (NOT IMHEX_DISABLE_UPDATE_CHECK)
|
||||||
|
add_compile_definitions(HEX_UPDATE_CHECK)
|
||||||
|
endif()
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
# Detect current OS / System
|
# Detect current OS / System
|
||||||
@@ -60,7 +87,9 @@ macro(detectOS)
|
|||||||
set(CMAKE_INSTALL_LIBDIR ".")
|
set(CMAKE_INSTALL_LIBDIR ".")
|
||||||
set(PLUGINS_INSTALL_LOCATION "plugins")
|
set(PLUGINS_INSTALL_LOCATION "plugins")
|
||||||
|
|
||||||
SET(IMHEX_USE_BUNDLED_CA ON)
|
if (NOT USE_SYSTEM_CURL)
|
||||||
|
SET(IMHEX_USE_BUNDLED_CA ON)
|
||||||
|
endif ()
|
||||||
elseif (APPLE)
|
elseif (APPLE)
|
||||||
add_compile_definitions(OS_MACOS)
|
add_compile_definitions(OS_MACOS)
|
||||||
set(CMAKE_INSTALL_BINDIR ".")
|
set(CMAKE_INSTALL_BINDIR ".")
|
||||||
@@ -114,7 +143,7 @@ macro(configurePackingResources)
|
|||||||
|
|
||||||
if (CREATE_PACKAGE)
|
if (CREATE_PACKAGE)
|
||||||
set(CPACK_GENERATOR "WIX")
|
set(CPACK_GENERATOR "WIX")
|
||||||
set(CPACK_PACKAGE_NAME "imhex")
|
set(CPACK_PACKAGE_NAME "ImHex")
|
||||||
set(CPACK_PACKAGE_VENDOR "WerWolv")
|
set(CPACK_PACKAGE_VENDOR "WerWolv")
|
||||||
set(CPACK_WIX_UPGRADE_GUID "05000E99-9659-42FD-A1CF-05C554B39285")
|
set(CPACK_WIX_UPGRADE_GUID "05000E99-9659-42FD-A1CF-05C554B39285")
|
||||||
set(CPACK_WIX_PRODUCT_ICON "${PROJECT_SOURCE_DIR}/resources/dist/windows/icon.ico")
|
set(CPACK_WIX_PRODUCT_ICON "${PROJECT_SOURCE_DIR}/resources/dist/windows/icon.ico")
|
||||||
@@ -139,7 +168,7 @@ macro(configurePackingResources)
|
|||||||
set(MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/resources/dist/macos/Info.plist.in")
|
set(MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/resources/dist/macos/Info.plist.in")
|
||||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
||||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "net.WerWolv.ImHex")
|
set(MACOSX_BUNDLE_GUI_IDENTIFIER "net.WerWolv.ImHex")
|
||||||
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}-${GIT_COMMIT_HASH}")
|
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}-${GIT_COMMIT_HASH_SHORT}")
|
||||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
|
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
|
||||||
|
|
||||||
string(TIMESTAMP CURR_YEAR "%Y")
|
string(TIMESTAMP CURR_YEAR "%Y")
|
||||||
@@ -185,7 +214,7 @@ macro(createPackage)
|
|||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
add_dependencies(imhex ${plugin})
|
add_dependencies(imhex_all ${plugin})
|
||||||
endif ()
|
endif ()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
@@ -256,7 +285,7 @@ macro(createPackage)
|
|||||||
set_property(TARGET main PROPERTY MACOSX_BUNDLE_INFO_PLIST ${MACOSX_BUNDLE_INFO_PLIST})
|
set_property(TARGET main PROPERTY MACOSX_BUNDLE_INFO_PLIST ${MACOSX_BUNDLE_INFO_PLIST})
|
||||||
|
|
||||||
# Fix rpath
|
# Fix rpath
|
||||||
add_custom_command(TARGET imhex POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $<TARGET_FILE:main>)
|
add_custom_command(TARGET imhex_all POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $<TARGET_FILE:main>)
|
||||||
|
|
||||||
# FIXME: Remove this once we move/integrate the plugins directory.
|
# FIXME: Remove this once we move/integrate the plugins directory.
|
||||||
add_custom_target(build-time-make-plugins-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${IMHEX_BUNDLE_PATH}/Contents/MacOS/plugins")
|
add_custom_target(build-time-make-plugins-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${IMHEX_BUNDLE_PATH}/Contents/MacOS/plugins")
|
||||||
@@ -269,7 +298,7 @@ macro(createPackage)
|
|||||||
install(FILES $<TARGET_FILE:main> DESTINATION "${IMHEX_BUNDLE_PATH}")
|
install(FILES $<TARGET_FILE:main> DESTINATION "${IMHEX_BUNDLE_PATH}")
|
||||||
|
|
||||||
# Update library references to make the bundle portable
|
# Update library references to make the bundle portable
|
||||||
postprocess_bundle(imhex main)
|
postprocess_bundle(imhex_all main)
|
||||||
|
|
||||||
# Enforce DragNDrop packaging.
|
# Enforce DragNDrop packaging.
|
||||||
set(CPACK_GENERATOR "DragNDrop")
|
set(CPACK_GENERATOR "DragNDrop")
|
||||||
@@ -384,7 +413,7 @@ endfunction()
|
|||||||
|
|
||||||
macro(setupCompilerWarnings target)
|
macro(setupCompilerWarnings target)
|
||||||
set(IMHEX_COMMON_FLAGS "-Wall -Wextra -Wpedantic -Werror")
|
set(IMHEX_COMMON_FLAGS "-Wall -Wextra -Wpedantic -Werror")
|
||||||
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow")
|
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow -Wno-array-bounds -Wno-dangling-reference")
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${IMHEX_C_FLAGS}")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${IMHEX_C_FLAGS}")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${IMHEX_C_FLAGS}")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${IMHEX_C_FLAGS}")
|
||||||
@@ -416,8 +445,13 @@ macro(addBundledLibraries)
|
|||||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/microtar EXCLUDE_FROM_ALL)
|
add_subdirectory(${EXTERN_LIBS_FOLDER}/microtar EXCLUDE_FROM_ALL)
|
||||||
set_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
set_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/intervaltree EXCLUDE_FROM_ALL)
|
add_subdirectory(${EXTERN_LIBS_FOLDER}/libwolv EXCLUDE_FROM_ALL)
|
||||||
set_target_properties(intervaltree PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
set_property(TARGET libwolv-types PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||||
|
set_property(TARGET libwolv-utils PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||||
|
set_property(TARGET libwolv-io PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||||
|
set_property(TARGET libwolv-hash PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||||
|
set_property(TARGET libwolv-containers PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||||
|
set_property(TARGET libwolv-net PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
set(XDGPP_INCLUDE_DIRS "${EXTERN_LIBS_FOLDER}/xdgpp")
|
set(XDGPP_INCLUDE_DIRS "${EXTERN_LIBS_FOLDER}/xdgpp")
|
||||||
set(CURL_USE_MBEDTLS ON)
|
set(CURL_USE_MBEDTLS ON)
|
||||||
@@ -459,6 +493,7 @@ macro(addBundledLibraries)
|
|||||||
if(NOT USE_SYSTEM_CURL)
|
if(NOT USE_SYSTEM_CURL)
|
||||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/curl EXCLUDE_FROM_ALL)
|
add_subdirectory(${EXTERN_LIBS_FOLDER}/curl EXCLUDE_FROM_ALL)
|
||||||
set_target_properties(libcurl PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
set_target_properties(libcurl PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||||
|
target_compile_options(libcurl PRIVATE -Wno-deprecated-declarations)
|
||||||
set(LIBCURL_LIBRARIES libcurl)
|
set(LIBCURL_LIBRARIES libcurl)
|
||||||
else()
|
else()
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
@@ -515,25 +550,27 @@ macro(addBundledLibraries)
|
|||||||
set(MAGIC_INCLUDE_DIRS ${MAGIC_INCLUDEDIR})
|
set(MAGIC_INCLUDE_DIRS ${MAGIC_INCLUDEDIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WIN32)
|
if (NOT IMHEX_DISABLE_STACKTRACE)
|
||||||
message(STATUS "StackWalk enabled!")
|
if (WIN32)
|
||||||
set(LIBBACKTRACE_LIBRARIES DbgHelp.lib)
|
message(STATUS "StackWalk enabled!")
|
||||||
else ()
|
set(LIBBACKTRACE_LIBRARIES DbgHelp.lib)
|
||||||
find_package(Backtrace)
|
else ()
|
||||||
if (${Backtrace_FOUND})
|
find_package(Backtrace)
|
||||||
message(STATUS "Backtrace enabled! Header: ${Backtrace_HEADER}")
|
if (${Backtrace_FOUND})
|
||||||
|
message(STATUS "Backtrace enabled! Header: ${Backtrace_HEADER}")
|
||||||
|
|
||||||
if (Backtrace_HEADER STREQUAL "execinfo.h")
|
if (Backtrace_HEADER STREQUAL "execinfo.h")
|
||||||
set(LIBBACKTRACE_LIBRARIES)
|
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
|
||||||
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
|
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
|
||||||
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
|
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
|
||||||
add_compile_definitions(HEX_HAS_EXECINFO)
|
add_compile_definitions(HEX_HAS_EXECINFO)
|
||||||
elseif (Backtrace_HEADER STREQUAL "backtrace.h")
|
elseif (Backtrace_HEADER STREQUAL "backtrace.h")
|
||||||
set(LIBBACKTRACE_LIBRARIES backtrace)
|
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
|
||||||
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
|
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
|
||||||
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
|
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
|
||||||
add_compile_definitions(HEX_HAS_BACKTRACE)
|
add_compile_definitions(HEX_HAS_BACKTRACE)
|
||||||
endif ()
|
endif ()
|
||||||
endif()
|
endif()
|
||||||
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|||||||
2
dist/Arch/PKGBUILD
vendored
2
dist/Arch/PKGBUILD
vendored
@@ -1,4 +1,4 @@
|
|||||||
# Maintainer: iTrooz_ <itrooz at protonmail dot com>
|
# Maintainer: iTrooz_ <aur at itrooz dot fr>
|
||||||
# Contributor: Morten Linderud <foxboron@archlinux.org>
|
# Contributor: Morten Linderud <foxboron@archlinux.org>
|
||||||
|
|
||||||
pkgname=imhex-bin
|
pkgname=imhex-bin
|
||||||
|
|||||||
2
dist/Dockerfile
vendored
2
dist/Dockerfile
vendored
@@ -1,6 +1,6 @@
|
|||||||
FROM archlinux:latest
|
FROM archlinux:latest
|
||||||
|
|
||||||
LABEL maintainer="hey@werwolv.net" = WerWolv
|
LABEL maintainer="hey@werwolv.net WerWolv"
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
RUN pacman -Syy --needed --noconfirm
|
RUN pacman -Syy --needed --noconfirm
|
||||||
|
|||||||
8
dist/rpm/imhex.spec
vendored
8
dist/rpm/imhex.spec
vendored
@@ -4,7 +4,7 @@ Release: 0%{?dist}
|
|||||||
Summary: A hex editor for reverse engineers and programmers
|
Summary: A hex editor for reverse engineers and programmers
|
||||||
|
|
||||||
License: GPL-2.0-only AND Zlib AND MIT AND Apache-2.0
|
License: GPL-2.0-only AND Zlib AND MIT AND Apache-2.0
|
||||||
# imhex is gplv2. capstone is custom. nativefiledialog is Zlib. intervaltree is MIT
|
# imhex is gplv2. capstone is custom. nativefiledialog is Zlib.
|
||||||
# see license dir for full breakdown
|
# see license dir for full breakdown
|
||||||
URL: https://imhex.werwolv.net/
|
URL: https://imhex.werwolv.net/
|
||||||
# We need the archive with deps bundled
|
# We need the archive with deps bundled
|
||||||
@@ -36,9 +36,6 @@ Provides: bundled(imgui)
|
|||||||
Provides: bundled(libromfs)
|
Provides: bundled(libromfs)
|
||||||
Provides: bundled(microtar)
|
Provides: bundled(microtar)
|
||||||
Provides: bundled(libpl)
|
Provides: bundled(libpl)
|
||||||
# ImHex modified upstream intervaltree so we have to package it
|
|
||||||
# https://github.com/ekg/intervaltree
|
|
||||||
Provides: bundled(intervaltree) = 0.1
|
|
||||||
Provides: bundled(xdgpp)
|
Provides: bundled(xdgpp)
|
||||||
|
|
||||||
# ftbfs on these arches. armv7hl might compile when capstone 5.x
|
# ftbfs on these arches. armv7hl might compile when capstone 5.x
|
||||||
@@ -115,7 +112,6 @@ cp -a lib/external/nativefiledialog/LICENSE %{buildroot}%{
|
|||||||
cp -a lib/external/capstone/LICENSE.TXT %{buildroot}%{_datadir}/licenses/%{name}/capstone-LICENSE
|
cp -a lib/external/capstone/LICENSE.TXT %{buildroot}%{_datadir}/licenses/%{name}/capstone-LICENSE
|
||||||
cp -a lib/external/capstone/suite/regress/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/capstone-regress-LICENSE
|
cp -a lib/external/capstone/suite/regress/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/capstone-regress-LICENSE
|
||||||
cp -a lib/external/microtar/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/microtar-LICENSE
|
cp -a lib/external/microtar/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/microtar-LICENSE
|
||||||
cp -a lib/external/pattern_language/external/intervaltree/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/pattern-language-intervaltree-LICENSE
|
|
||||||
cp -a lib/external/xdgpp/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/xdgpp-LICENSE
|
cp -a lib/external/xdgpp/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/xdgpp-LICENSE
|
||||||
|
|
||||||
|
|
||||||
@@ -131,5 +127,3 @@ cp -a lib/external/xdgpp/LICENSE %{buildroot}%{
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
* Thu Jan 01 1970 ImHex GitHub CI - 0.0.0-0
|
|
||||||
- Build Package
|
|
||||||
|
|||||||
2
lib/external/curl
vendored
2
lib/external/curl
vendored
Submodule lib/external/curl updated: c12fb3ddaf...b16d1fa8ee
2
lib/external/fmt
vendored
2
lib/external/fmt
vendored
Submodule lib/external/fmt updated: a33701196a...a0b8a92e3d
5
lib/external/imgui/CMakeLists.txt
vendored
5
lib/external/imgui/CMakeLists.txt
vendored
@@ -33,10 +33,9 @@ add_library(imgui OBJECT
|
|||||||
source/fonts/unifont_font.c
|
source/fonts/unifont_font.c
|
||||||
)
|
)
|
||||||
|
|
||||||
add_compile_definitions(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
target_compile_definitions(imgui PUBLIC IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||||
|
target_compile_options(imgui PRIVATE -Wno-stringop-overflow)
|
||||||
|
|
||||||
target_include_directories(imgui PUBLIC include ${FREETYPE_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS} ${OpenGL_INCLUDE_DIRS})
|
target_include_directories(imgui PUBLIC include ${FREETYPE_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS} ${OpenGL_INCLUDE_DIRS})
|
||||||
|
|
||||||
target_link_directories(imgui PUBLIC ${GLFW_LIBRARY_DIRS} ${OpenGL_LIBRARY_DIRS})
|
target_link_directories(imgui PUBLIC ${GLFW_LIBRARY_DIRS} ${OpenGL_LIBRARY_DIRS})
|
||||||
|
|
||||||
target_link_libraries(imgui PUBLIC Freetype::Freetype ${GLFW_LIBRARIES} ${OPENGL_LIBRARIES})
|
target_link_libraries(imgui PUBLIC Freetype::Freetype ${GLFW_LIBRARIES} ${OPENGL_LIBRARIES})
|
||||||
|
|||||||
27
lib/external/imgui/source/TextEditor.cpp
vendored
27
lib/external/imgui/source/TextEditor.cpp
vendored
@@ -314,7 +314,7 @@ TextEditor::Coordinates TextEditor::FindWordStart(const Coordinates &aFrom) cons
|
|||||||
while (cindex > 0 && isspace(line[cindex].mChar))
|
while (cindex > 0 && isspace(line[cindex].mChar))
|
||||||
--cindex;
|
--cindex;
|
||||||
|
|
||||||
auto cstart = (PaletteIndex)line[cindex].mColorIndex;
|
auto cstart = line[cindex].mChar;
|
||||||
while (cindex > 0) {
|
while (cindex > 0) {
|
||||||
auto c = line[cindex].mChar;
|
auto c = line[cindex].mChar;
|
||||||
if ((c & 0xC0) != 0x80) // not UTF code sequence 10xxxxxx
|
if ((c & 0xC0) != 0x80) // not UTF code sequence 10xxxxxx
|
||||||
@@ -323,8 +323,15 @@ TextEditor::Coordinates TextEditor::FindWordStart(const Coordinates &aFrom) cons
|
|||||||
cindex++;
|
cindex++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (cstart != (PaletteIndex)line[size_t(cindex - 1)].mColorIndex)
|
|
||||||
|
if (isalnum(cstart) || cstart == '_') {
|
||||||
|
if (!isalnum(c) && c != '_') {
|
||||||
|
cindex++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
--cindex;
|
--cindex;
|
||||||
}
|
}
|
||||||
@@ -632,10 +639,24 @@ void TextEditor::HandleKeyboardInputs() {
|
|||||||
MoveEnd(shift);
|
MoveEnd(shift);
|
||||||
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
|
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
|
||||||
Delete();
|
Delete();
|
||||||
|
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete))) {
|
||||||
|
auto wordStart = GetCursorPosition();
|
||||||
|
MoveRight();
|
||||||
|
auto wordEnd = FindWordEnd(GetCursorPosition());
|
||||||
|
SetSelection(wordStart, wordEnd);
|
||||||
|
Backspace();
|
||||||
|
}
|
||||||
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
|
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
|
||||||
Backspace();
|
Backspace();
|
||||||
|
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace))) {
|
||||||
|
auto wordEnd = GetCursorPosition();
|
||||||
|
MoveLeft();
|
||||||
|
auto wordStart = FindWordStart(GetCursorPosition());
|
||||||
|
SetSelection(wordStart, wordEnd);
|
||||||
|
Backspace();
|
||||||
|
}
|
||||||
else if (!ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
|
else if (!ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
|
||||||
mOverwrite ^= true;
|
mOverwrite = !mOverwrite;
|
||||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
|
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
|
||||||
Copy();
|
Copy();
|
||||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C)))
|
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C)))
|
||||||
|
|||||||
42
lib/external/imgui/source/imgui_impl_glfw.cpp
vendored
42
lib/external/imgui/source/imgui_impl_glfw.cpp
vendored
@@ -750,12 +750,41 @@ static void ImGui_ImplGlfw_UpdateMouseCursor()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// IMHEX PATCH BEGIN
|
// IMHEX PATCH BEGIN
|
||||||
if (!bd->BorderlessWindow) {
|
/*if (!bd->BorderlessWindow) {*/
|
||||||
// Show OS mouse cursor
|
// Show OS mouse cursor
|
||||||
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
|
// FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here.
|
||||||
glfwSetCursor(window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
|
#if defined(_WIN32)
|
||||||
|
switch (imgui_cursor) {
|
||||||
|
case ImGuiMouseCursor_Hand:
|
||||||
|
SetCursor(LoadCursor(nullptr, IDC_HAND));
|
||||||
|
break;
|
||||||
|
case ImGuiMouseCursor_ResizeEW:
|
||||||
|
SetCursor(LoadCursor(nullptr, IDC_SIZEWE));
|
||||||
|
break;
|
||||||
|
case ImGuiMouseCursor_ResizeNS:
|
||||||
|
SetCursor(LoadCursor(nullptr, IDC_SIZENS));
|
||||||
|
break;
|
||||||
|
case ImGuiMouseCursor_ResizeNWSE:
|
||||||
|
SetCursor(LoadCursor(nullptr, IDC_SIZENWSE));
|
||||||
|
break;
|
||||||
|
case ImGuiMouseCursor_ResizeNESW:
|
||||||
|
SetCursor(LoadCursor(nullptr, IDC_SIZENESW));
|
||||||
|
break;
|
||||||
|
case ImGuiMouseCursor_ResizeAll:
|
||||||
|
SetCursor(LoadCursor(nullptr, IDC_SIZEALL));
|
||||||
|
break;
|
||||||
|
case ImGuiMouseCursor_NotAllowed:
|
||||||
|
SetCursor(LoadCursor(nullptr, IDC_NO));
|
||||||
|
break;
|
||||||
|
case ImGuiMouseCursor_TextInput:
|
||||||
|
SetCursor(LoadCursor(nullptr, IDC_IBEAM));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
glfwSetCursor(window, bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow]);
|
||||||
|
#endif
|
||||||
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||||
}
|
/*}*/
|
||||||
// IMHEX PATCH END
|
// IMHEX PATCH END
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -820,7 +849,12 @@ static void ImGui_ImplGlfw_UpdateMonitors()
|
|||||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||||
int monitors_count = 0;
|
int monitors_count = 0;
|
||||||
GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count);
|
GLFWmonitor** glfw_monitors = glfwGetMonitors(&monitors_count);
|
||||||
platform_io.Monitors.resize(0);
|
|
||||||
|
// IMHEX PATCH BEGIN
|
||||||
|
if (monitors_count > 0)
|
||||||
|
platform_io.Monitors.resize(0);
|
||||||
|
// IMHEX PATCH END
|
||||||
|
|
||||||
for (int n = 0; n < monitors_count; n++)
|
for (int n = 0; n < monitors_count; n++)
|
||||||
{
|
{
|
||||||
ImGuiPlatformMonitor monitor;
|
ImGuiPlatformMonitor monitor;
|
||||||
|
|||||||
6
lib/external/imgui/source/imgui_widgets.cpp
vendored
6
lib/external/imgui/source/imgui_widgets.cpp
vendored
@@ -1565,8 +1565,8 @@ void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_exc
|
|||||||
width_excess += items[n].Width - width_rounded;
|
width_excess += items[n].Width - width_rounded;
|
||||||
items[n].Width = width_rounded;
|
items[n].Width = width_rounded;
|
||||||
}
|
}
|
||||||
while (width_excess > 0.0f)
|
while (width_excess >= 1.0f)
|
||||||
for (int n = 0; n < count; n++)
|
for (int n = 0; n < count && width_excess >= 1.0f; n++)
|
||||||
if (items[n].Width + 1.0f <= items[n].InitialWidth)
|
if (items[n].Width + 1.0f <= items[n].InitialWidth)
|
||||||
{
|
{
|
||||||
items[n].Width += 1.0f;
|
items[n].Width += 1.0f;
|
||||||
@@ -7638,7 +7638,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
|||||||
width_excess = (section_0_w + section_2_w) - tab_bar->BarRect.GetWidth(); // Excess used to shrink leading/trailing section
|
width_excess = (section_0_w + section_2_w) - tab_bar->BarRect.GetWidth(); // Excess used to shrink leading/trailing section
|
||||||
|
|
||||||
// With ImGuiTabBarFlags_FittingPolicyScroll policy, we will only shrink leading/trailing if the central section is not visible anymore
|
// With ImGuiTabBarFlags_FittingPolicyScroll policy, we will only shrink leading/trailing if the central section is not visible anymore
|
||||||
if (width_excess > 0.0f && ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible))
|
if (width_excess >= 1.0f && ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible))
|
||||||
{
|
{
|
||||||
int shrink_data_count = (central_section_is_visible ? sections[1].TabCount : sections[0].TabCount + sections[2].TabCount);
|
int shrink_data_count = (central_section_is_visible ? sections[1].TabCount : sections[0].TabCount + sections[2].TabCount);
|
||||||
int shrink_data_offset = (central_section_is_visible ? sections[0].TabCount + sections[2].TabCount : 0);
|
int shrink_data_offset = (central_section_is_visible ? sections[0].TabCount + sections[2].TabCount : 0);
|
||||||
|
|||||||
9
lib/external/intervaltree/CMakeLists.txt
vendored
9
lib/external/intervaltree/CMakeLists.txt
vendored
@@ -1,9 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
|
||||||
project(intervaltree)
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD20)
|
|
||||||
|
|
||||||
add_library(intervaltree INTERFACE)
|
|
||||||
|
|
||||||
target_include_directories(intervaltree INTERFACE include)
|
|
||||||
target_compile_options(intervaltree INTERFACE "-DUSE_INTERVAL_TREE_NAMESPACE")
|
|
||||||
19
lib/external/intervaltree/LICENSE
vendored
19
lib/external/intervaltree/LICENSE
vendored
@@ -1,19 +0,0 @@
|
|||||||
Copyright (c) 2011 Erik Garrison
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
37
lib/external/intervaltree/README.md
vendored
37
lib/external/intervaltree/README.md
vendored
@@ -1,37 +0,0 @@
|
|||||||
# intervaltree
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
An interval tree can be used to efficiently find a set of numeric intervals overlapping or containing another interval.
|
|
||||||
|
|
||||||
This library provides a basic implementation of an interval tree using C++ templates, allowing the insertion of arbitrary types into the tree.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
Add `#include "IntervalTree.h"` to the source files in which you will use the interval tree.
|
|
||||||
|
|
||||||
To make an IntervalTree to contain objects of class T, use:
|
|
||||||
|
|
||||||
```c++
|
|
||||||
vector<Interval<T> > intervals;
|
|
||||||
T a, b, c;
|
|
||||||
intervals.push_back(Interval<T>(2, 10, a));
|
|
||||||
intervals.push_back(Interval<T>(3, 4, b));
|
|
||||||
intervals.push_back(Interval<T>(20, 100, c));
|
|
||||||
IntervalTree<T> tree;
|
|
||||||
tree = IntervalTree<T>(intervals);
|
|
||||||
```
|
|
||||||
|
|
||||||
Now, it's possible to query the tree and obtain a set of intervals which are contained within the start and stop coordinates.
|
|
||||||
|
|
||||||
```c++
|
|
||||||
vector<Interval<T> > results;
|
|
||||||
tree.findContained(start, stop, results);
|
|
||||||
cout << "found " << results.size() << " overlapping intervals" << endl;
|
|
||||||
```
|
|
||||||
|
|
||||||
The function IntervalTree::findOverlapping provides a method to find all those intervals which are contained or partially overlap the interval (start, stop).
|
|
||||||
|
|
||||||
### Author: Erik Garrison <erik.garrison@gmail.com>
|
|
||||||
|
|
||||||
### License: MIT
|
|
||||||
325
lib/external/intervaltree/include/IntervalTree.h
vendored
325
lib/external/intervaltree/include/IntervalTree.h
vendored
@@ -1,325 +0,0 @@
|
|||||||
#ifndef __INTERVAL_TREE_H
|
|
||||||
#define __INTERVAL_TREE_H
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <iostream>
|
|
||||||
#include <memory>
|
|
||||||
#include <cassert>
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
#ifdef USE_INTERVAL_TREE_NAMESPACE
|
|
||||||
namespace interval_tree {
|
|
||||||
#endif
|
|
||||||
template <class Scalar, typename Value>
|
|
||||||
class Interval {
|
|
||||||
public:
|
|
||||||
Scalar start;
|
|
||||||
Scalar stop;
|
|
||||||
Value value;
|
|
||||||
Interval(const Scalar& s, const Scalar& e, const Value& v)
|
|
||||||
: start(std::min(s, e))
|
|
||||||
, stop(std::max(s, e))
|
|
||||||
, value(v)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class Scalar, typename Value>
|
|
||||||
Value intervalStart(const Interval<Scalar,Value>& i) {
|
|
||||||
return i.start;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Scalar, typename Value>
|
|
||||||
Value intervalStop(const Interval<Scalar, Value>& i) {
|
|
||||||
return i.stop;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Scalar, typename Value>
|
|
||||||
std::ostream& operator<<(std::ostream& out, const Interval<Scalar, Value>& i) {
|
|
||||||
out << "Interval(" << i.start << ", " << i.stop << "): " << i.value;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Scalar, class Value>
|
|
||||||
class IntervalTree {
|
|
||||||
public:
|
|
||||||
typedef Interval<Scalar, Value> interval;
|
|
||||||
typedef std::vector<interval> interval_vector;
|
|
||||||
|
|
||||||
|
|
||||||
struct IntervalStartCmp {
|
|
||||||
bool operator()(const interval& a, const interval& b) {
|
|
||||||
return a.start < b.start;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IntervalStopCmp {
|
|
||||||
bool operator()(const interval& a, const interval& b) {
|
|
||||||
return a.stop < b.stop;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
IntervalTree()
|
|
||||||
: left(nullptr)
|
|
||||||
, right(nullptr)
|
|
||||||
, center(0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~IntervalTree() = default;
|
|
||||||
|
|
||||||
std::unique_ptr<IntervalTree> clone() const {
|
|
||||||
return std::unique_ptr<IntervalTree>(new IntervalTree(*this));
|
|
||||||
}
|
|
||||||
|
|
||||||
IntervalTree(const IntervalTree& other)
|
|
||||||
: intervals(other.intervals),
|
|
||||||
left(other.left ? other.left->clone() : nullptr),
|
|
||||||
right(other.right ? other.right->clone() : nullptr),
|
|
||||||
center(other.center)
|
|
||||||
{}
|
|
||||||
|
|
||||||
IntervalTree& operator=(IntervalTree&&) = default;
|
|
||||||
IntervalTree(IntervalTree&&) = default;
|
|
||||||
|
|
||||||
IntervalTree& operator=(const IntervalTree& other) {
|
|
||||||
center = other.center;
|
|
||||||
intervals = other.intervals;
|
|
||||||
left = other.left ? other.left->clone() : nullptr;
|
|
||||||
right = other.right ? other.right->clone() : nullptr;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
IntervalTree(
|
|
||||||
interval_vector&& ivals,
|
|
||||||
std::size_t depth = 16,
|
|
||||||
std::size_t minbucket = 64,
|
|
||||||
std::size_t maxbucket = 512,
|
|
||||||
Scalar leftextent = 0,
|
|
||||||
Scalar rightextent = 0)
|
|
||||||
: left(nullptr)
|
|
||||||
, right(nullptr)
|
|
||||||
{
|
|
||||||
--depth;
|
|
||||||
const auto minmaxStop = std::minmax_element(ivals.begin(), ivals.end(),
|
|
||||||
IntervalStopCmp());
|
|
||||||
const auto minmaxStart = std::minmax_element(ivals.begin(), ivals.end(),
|
|
||||||
IntervalStartCmp());
|
|
||||||
if (!ivals.empty()) {
|
|
||||||
center = (minmaxStart.first->start + minmaxStop.second->stop) / 2;
|
|
||||||
}
|
|
||||||
if (leftextent == 0 && rightextent == 0) {
|
|
||||||
// sort intervals by start
|
|
||||||
std::sort(ivals.begin(), ivals.end(), IntervalStartCmp());
|
|
||||||
} else {
|
|
||||||
assert(std::is_sorted(ivals.begin(), ivals.end(), IntervalStartCmp()));
|
|
||||||
}
|
|
||||||
if (depth == 0 || (ivals.size() < minbucket && ivals.size() < maxbucket)) {
|
|
||||||
std::sort(ivals.begin(), ivals.end(), IntervalStartCmp());
|
|
||||||
intervals = std::move(ivals);
|
|
||||||
assert(is_valid().first);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
Scalar leftp = 0;
|
|
||||||
Scalar rightp = 0;
|
|
||||||
|
|
||||||
if (leftextent || rightextent) {
|
|
||||||
leftp = leftextent;
|
|
||||||
rightp = rightextent;
|
|
||||||
} else {
|
|
||||||
leftp = ivals.front().start;
|
|
||||||
rightp = std::max_element(ivals.begin(), ivals.end(),
|
|
||||||
IntervalStopCmp())->stop;
|
|
||||||
}
|
|
||||||
|
|
||||||
interval_vector lefts;
|
|
||||||
interval_vector rights;
|
|
||||||
|
|
||||||
for (typename interval_vector::const_iterator i = ivals.begin();
|
|
||||||
i != ivals.end(); ++i) {
|
|
||||||
const interval& interval = *i;
|
|
||||||
if (interval.stop < center) {
|
|
||||||
lefts.push_back(interval);
|
|
||||||
} else if (interval.start > center) {
|
|
||||||
rights.push_back(interval);
|
|
||||||
} else {
|
|
||||||
assert(interval.start <= center);
|
|
||||||
assert(center <= interval.stop);
|
|
||||||
intervals.push_back(interval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lefts.empty()) {
|
|
||||||
left.reset(new IntervalTree(std::move(lefts),
|
|
||||||
depth, minbucket, maxbucket,
|
|
||||||
leftp, center));
|
|
||||||
}
|
|
||||||
if (!rights.empty()) {
|
|
||||||
right.reset(new IntervalTree(std::move(rights),
|
|
||||||
depth, minbucket, maxbucket,
|
|
||||||
center, rightp));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(is_valid().first);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call f on all intervals near the range [start, stop]:
|
|
||||||
template <class UnaryFunction>
|
|
||||||
void visit_near(const Scalar& start, const Scalar& stop, UnaryFunction f) const {
|
|
||||||
if (!intervals.empty() && ! (stop < intervals.front().start)) {
|
|
||||||
for (auto & i : intervals) {
|
|
||||||
f(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (left && start <= center) {
|
|
||||||
left->visit_near(start, stop, f);
|
|
||||||
}
|
|
||||||
if (right && stop >= center) {
|
|
||||||
right->visit_near(start, stop, f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call f on all intervals crossing pos
|
|
||||||
template <class UnaryFunction>
|
|
||||||
void visit_overlapping(const Scalar& pos, UnaryFunction f) const {
|
|
||||||
visit_overlapping(pos, pos, f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call f on all intervals overlapping [start, stop]
|
|
||||||
template <class UnaryFunction>
|
|
||||||
void visit_overlapping(const Scalar& start, const Scalar& stop, UnaryFunction f) const {
|
|
||||||
auto filterF = [&](const interval& interval) {
|
|
||||||
if (interval.stop >= start && interval.start <= stop) {
|
|
||||||
// Only apply f if overlapping
|
|
||||||
f(interval);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
visit_near(start, stop, filterF);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call f on all intervals contained within [start, stop]
|
|
||||||
template <class UnaryFunction>
|
|
||||||
void visit_contained(const Scalar& start, const Scalar& stop, UnaryFunction f) const {
|
|
||||||
auto filterF = [&](const interval& interval) {
|
|
||||||
if (start <= interval.start && interval.stop <= stop) {
|
|
||||||
f(interval);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
visit_near(start, stop, filterF);
|
|
||||||
}
|
|
||||||
|
|
||||||
interval_vector findOverlapping(const Scalar& start, const Scalar& stop) const {
|
|
||||||
interval_vector result;
|
|
||||||
visit_overlapping(start, stop,
|
|
||||||
[&](const interval& interval) {
|
|
||||||
result.emplace_back(interval);
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
interval_vector findContained(const Scalar& start, const Scalar& stop) const {
|
|
||||||
interval_vector result;
|
|
||||||
visit_contained(start, stop,
|
|
||||||
[&](const interval& interval) {
|
|
||||||
result.push_back(interval);
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
bool empty() const {
|
|
||||||
if (left && !left->empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!intervals.empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (right && !right->empty()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class UnaryFunction>
|
|
||||||
void visit_all(UnaryFunction f) const {
|
|
||||||
if (left) {
|
|
||||||
left->visit_all(f);
|
|
||||||
}
|
|
||||||
std::for_each(intervals.begin(), intervals.end(), f);
|
|
||||||
if (right) {
|
|
||||||
right->visit_all(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<Scalar, Scalar> extentBruitForce() const {
|
|
||||||
struct Extent {
|
|
||||||
std::pair<Scalar, Scalar> x = {std::numeric_limits<Scalar>::max(),
|
|
||||||
std::numeric_limits<Scalar>::min() };
|
|
||||||
void operator()(const interval & interval) {
|
|
||||||
x.first = std::min(x.first, interval.start);
|
|
||||||
x.second = std::max(x.second, interval.stop);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Extent extent;
|
|
||||||
|
|
||||||
visit_all([&](const interval & interval) { extent(interval); });
|
|
||||||
return extent.x;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check all constraints.
|
|
||||||
// If first is false, second is invalid.
|
|
||||||
std::pair<bool, std::pair<Scalar, Scalar>> is_valid() const {
|
|
||||||
const auto minmaxStop = std::minmax_element(intervals.begin(), intervals.end(),
|
|
||||||
IntervalStopCmp());
|
|
||||||
const auto minmaxStart = std::minmax_element(intervals.begin(), intervals.end(),
|
|
||||||
IntervalStartCmp());
|
|
||||||
|
|
||||||
std::pair<bool, std::pair<Scalar, Scalar>> result = {true, { std::numeric_limits<Scalar>::max(),
|
|
||||||
std::numeric_limits<Scalar>::min() }};
|
|
||||||
if (!intervals.empty()) {
|
|
||||||
result.second.first = std::min(result.second.first, minmaxStart.first->start);
|
|
||||||
result.second.second = std::min(result.second.second, minmaxStop.second->stop);
|
|
||||||
}
|
|
||||||
if (left) {
|
|
||||||
auto valid = left->is_valid();
|
|
||||||
result.first &= valid.first;
|
|
||||||
result.second.first = std::min(result.second.first, valid.second.first);
|
|
||||||
result.second.second = std::min(result.second.second, valid.second.second);
|
|
||||||
if (!result.first) { return result; }
|
|
||||||
if (valid.second.second >= center) {
|
|
||||||
result.first = false;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (right) {
|
|
||||||
auto valid = right->is_valid();
|
|
||||||
result.first &= valid.first;
|
|
||||||
result.second.first = std::min(result.second.first, valid.second.first);
|
|
||||||
result.second.second = std::min(result.second.second, valid.second.second);
|
|
||||||
if (!result.first) { return result; }
|
|
||||||
if (valid.second.first <= center) {
|
|
||||||
result.first = false;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!std::is_sorted(intervals.begin(), intervals.end(), IntervalStartCmp())) {
|
|
||||||
result.first = false;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
left.reset();
|
|
||||||
right.reset();
|
|
||||||
intervals.clear();
|
|
||||||
center = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
interval_vector intervals;
|
|
||||||
std::unique_ptr<IntervalTree> left;
|
|
||||||
std::unique_ptr<IntervalTree> right;
|
|
||||||
Scalar center;
|
|
||||||
};
|
|
||||||
#ifdef USE_INTERVAL_TREE_NAMESPACE
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
2
lib/external/libromfs
vendored
2
lib/external/libromfs
vendored
Submodule lib/external/libromfs updated: 40cd303e92...80b9adea20
1
lib/external/libwolv
vendored
Submodule
1
lib/external/libwolv
vendored
Submodule
Submodule lib/external/libwolv added at 433d230331
2
lib/external/nativefiledialog
vendored
2
lib/external/nativefiledialog
vendored
Submodule lib/external/nativefiledialog updated: 6efc824070...7909f55d91
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
Submodule lib/external/pattern_language updated: 565df62329...dd7f676fef
27
lib/external/yara/CMakeLists.txt
vendored
27
lib/external/yara/CMakeLists.txt
vendored
@@ -34,6 +34,8 @@ set(LIBYARA_INCLUDES
|
|||||||
${LIBYARA_SOURCE_PATH}/include/yara/types.h
|
${LIBYARA_SOURCE_PATH}/include/yara/types.h
|
||||||
${LIBYARA_SOURCE_PATH}/include/yara/utils.h
|
${LIBYARA_SOURCE_PATH}/include/yara/utils.h
|
||||||
${LIBYARA_SOURCE_PATH}/crypto.h
|
${LIBYARA_SOURCE_PATH}/crypto.h
|
||||||
|
${LIBYARA_SOURCE_PATH}/tlshc/tlsh_impl.h
|
||||||
|
${LIBYARA_SOURCE_PATH}/tlshc/tlsh_util.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LIBYARA_SOURCE
|
set(LIBYARA_SOURCE
|
||||||
@@ -66,6 +68,7 @@ set(LIBYARA_SOURCE
|
|||||||
${LIBYARA_SOURCE_PATH}/scan.c
|
${LIBYARA_SOURCE_PATH}/scan.c
|
||||||
${LIBYARA_SOURCE_PATH}/scanner.c
|
${LIBYARA_SOURCE_PATH}/scanner.c
|
||||||
${LIBYARA_SOURCE_PATH}/sizedstr.c
|
${LIBYARA_SOURCE_PATH}/sizedstr.c
|
||||||
|
${LIBYARA_SOURCE_PATH}/simple_str.c
|
||||||
${LIBYARA_SOURCE_PATH}/stack.c
|
${LIBYARA_SOURCE_PATH}/stack.c
|
||||||
${LIBYARA_SOURCE_PATH}/stopwatch.c
|
${LIBYARA_SOURCE_PATH}/stopwatch.c
|
||||||
${LIBYARA_SOURCE_PATH}/strutils.c
|
${LIBYARA_SOURCE_PATH}/strutils.c
|
||||||
@@ -78,6 +81,9 @@ set(LIBYARA_SOURCE
|
|||||||
${LIBYARA_SOURCE_PATH}/hex_grammar.c
|
${LIBYARA_SOURCE_PATH}/hex_grammar.c
|
||||||
${LIBYARA_SOURCE_PATH}/re_grammar.c
|
${LIBYARA_SOURCE_PATH}/re_grammar.c
|
||||||
${LIBYARA_SOURCE_PATH}/proc/none.c
|
${LIBYARA_SOURCE_PATH}/proc/none.c
|
||||||
|
${LIBYARA_SOURCE_PATH}/tlshc/tlsh.c
|
||||||
|
${LIBYARA_SOURCE_PATH}/tlshc/tlsh_impl.c
|
||||||
|
${LIBYARA_SOURCE_PATH}/tlshc/tlsh_util.c
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LIBYARA_MODULES
|
set(LIBYARA_MODULES
|
||||||
@@ -91,6 +97,7 @@ set(LIBYARA_MODULES
|
|||||||
${LIBYARA_SOURCE_PATH}/modules/math/math.c
|
${LIBYARA_SOURCE_PATH}/modules/math/math.c
|
||||||
${LIBYARA_SOURCE_PATH}/modules/pe/pe.c
|
${LIBYARA_SOURCE_PATH}/modules/pe/pe.c
|
||||||
${LIBYARA_SOURCE_PATH}/modules/pe/pe_utils.c
|
${LIBYARA_SOURCE_PATH}/modules/pe/pe_utils.c
|
||||||
|
${LIBYARA_SOURCE_PATH}/modules/string/string.c
|
||||||
${LIBYARA_SOURCE_PATH}/modules/tests/tests.c
|
${LIBYARA_SOURCE_PATH}/modules/tests/tests.c
|
||||||
${LIBYARA_SOURCE_PATH}/modules/time/time.c
|
${LIBYARA_SOURCE_PATH}/modules/time/time.c
|
||||||
)
|
)
|
||||||
@@ -101,17 +108,13 @@ add_library(libyara STATIC ${LIBYARA_SOURCE} ${LIBYARA_INCLUDES} ${LIBYARA_MODUL
|
|||||||
set_property(TARGET libyara PROPERTY POSITION_INDEPENDENT_CODE ON)
|
set_property(TARGET libyara PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
# Add mbedtls crypto wrappers
|
# Add mbedtls crypto wrappers
|
||||||
target_compile_definitions(libyara PRIVATE HAVE_MBEDTLS)
|
target_compile_definitions(libyara PRIVATE
|
||||||
|
HAVE_MBEDTLS
|
||||||
|
USE_NO_PROC BUCKETS_256 CHECKSUM_3B
|
||||||
|
HASH_MODULE DOTNET_MODULE MAGIC_MODULE MACHO_MODULE DEX_MODULE
|
||||||
|
)
|
||||||
|
|
||||||
target_compile_definitions(libyara PRIVATE USE_NO_PROC)
|
target_compile_options(libyara PRIVATE -Wno-shift-count-overflow -Wno-stringop-overflow)
|
||||||
|
|
||||||
target_compile_definitions(libyara PRIVATE HASH_MODULE)
|
|
||||||
target_compile_definitions(libyara PRIVATE DOTNET_MODULE)
|
|
||||||
target_compile_definitions(libyara PRIVATE MAGIC_MODULE)
|
|
||||||
target_compile_definitions(libyara PRIVATE MACHO_MODULE)
|
|
||||||
target_compile_definitions(libyara PRIVATE DEX_MODULE)
|
|
||||||
|
|
||||||
target_compile_options(libyara PRIVATE "-Wno-shift-count-overflow")
|
|
||||||
|
|
||||||
target_include_directories(
|
target_include_directories(
|
||||||
libyara
|
libyara
|
||||||
@@ -128,6 +131,6 @@ else ()
|
|||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
configure_file(${LIBYARA_SOURCE_PATH}/yara.pc.in
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/yara/yara.pc.in
|
||||||
${LIBYARA_SOURCE_PATH}/yara.pc @ONLY)
|
${CMAKE_CURRENT_SOURCE_DIR}/yara/yara.pc @ONLY)
|
||||||
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
||||||
|
|||||||
2
lib/external/yara/yara
vendored
2
lib/external/yara/yara
vendored
Submodule lib/external/yara/yara updated: ba94b4f8eb...96790e56fc
@@ -5,39 +5,39 @@ set(CMAKE_CXX_STANDARD 23)
|
|||||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||||
|
|
||||||
set(LIBIMHEX_SOURCES
|
set(LIBIMHEX_SOURCES
|
||||||
source/api/event.cpp
|
source/api/event.cpp
|
||||||
source/api/imhex_api.cpp
|
source/api/imhex_api.cpp
|
||||||
source/api/content_registry.cpp
|
source/api/content_registry.cpp
|
||||||
source/api/task.cpp
|
source/api/task.cpp
|
||||||
source/api/keybinding.cpp
|
source/api/keybinding.cpp
|
||||||
source/api/plugin_manager.cpp
|
source/api/plugin_manager.cpp
|
||||||
source/api/localization.cpp
|
source/api/localization.cpp
|
||||||
source/api/project_file_manager.cpp
|
source/api/project_file_manager.cpp
|
||||||
source/api/theme_manager.cpp
|
source/api/theme_manager.cpp
|
||||||
|
source/api/layout_manager.cpp
|
||||||
|
|
||||||
source/data_processor/attribute.cpp
|
source/data_processor/attribute.cpp
|
||||||
source/data_processor/link.cpp
|
source/data_processor/link.cpp
|
||||||
source/data_processor/node.cpp
|
source/data_processor/node.cpp
|
||||||
|
|
||||||
source/helpers/utils.cpp
|
source/helpers/utils.cpp
|
||||||
source/helpers/fs.cpp
|
source/helpers/fs.cpp
|
||||||
source/helpers/magic.cpp
|
source/helpers/magic.cpp
|
||||||
source/helpers/crypto.cpp
|
source/helpers/crypto.cpp
|
||||||
source/helpers/net.cpp
|
source/helpers/http_requests.cpp
|
||||||
source/helpers/opengl.cpp
|
source/helpers/opengl.cpp
|
||||||
source/helpers/file.cpp
|
source/helpers/patches.cpp
|
||||||
source/helpers/socket.cpp
|
source/helpers/encoding_file.cpp
|
||||||
source/helpers/patches.cpp
|
source/helpers/logger.cpp
|
||||||
source/helpers/encoding_file.cpp
|
source/helpers/stacktrace.cpp
|
||||||
source/helpers/logger.cpp
|
source/helpers/tar.cpp
|
||||||
source/helpers/stacktrace.cpp
|
|
||||||
source/helpers/tar.cpp
|
|
||||||
|
|
||||||
source/providers/provider.cpp
|
source/providers/provider.cpp
|
||||||
|
|
||||||
source/ui/imgui_imhex_extensions.cpp
|
source/ui/imgui_imhex_extensions.cpp
|
||||||
source/ui/view.cpp
|
source/ui/view.cpp
|
||||||
)
|
source/ui/popup.cpp
|
||||||
|
)
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(OSX_11_0_SDK_PATH /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk)
|
set(OSX_11_0_SDK_PATH /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk)
|
||||||
@@ -49,9 +49,7 @@ if (APPLE)
|
|||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES}
|
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/utils_macos.m)
|
||||||
source/helpers/fs_macos.m
|
|
||||||
source/helpers/utils_macos.m)
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||||
@@ -72,4 +70,4 @@ elseif (APPLE)
|
|||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
target_link_libraries(libimhex PRIVATE ${FMT_LIBRARIES})
|
target_link_libraries(libimhex PRIVATE ${FMT_LIBRARIES})
|
||||||
target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${LIBBACKTRACE_LIBRARIES} libpl intervaltree ${MINIAUDIO_LIBRARIES})
|
target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${LIBBACKTRACE_LIBRARIES} libpl ${MINIAUDIO_LIBRARIES} libwolv-utils libwolv-io libwolv-hash libwolv-net libwolv-containers)
|
||||||
|
|||||||
@@ -2,6 +2,3 @@
|
|||||||
|
|
||||||
#include <hex/helpers/types.hpp>
|
#include <hex/helpers/types.hpp>
|
||||||
#include <hex/helpers/intrinsics.hpp>
|
#include <hex/helpers/intrinsics.hpp>
|
||||||
|
|
||||||
constexpr static const auto ImHexApiURL = "https://api.werwolv.net/imhex";
|
|
||||||
constexpr static const auto GitHubApiURL = "https://api.github.com/repos/WerWolv/ImHex";
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <span>
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <thread>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -41,87 +42,206 @@ namespace hex {
|
|||||||
|
|
||||||
/* Settings Registry. Allows adding of new entries into the ImHex preferences window. */
|
/* Settings Registry. Allows adding of new entries into the ImHex preferences window. */
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
using Callback = std::function<bool(const std::string &, nlohmann::json &)>;
|
|
||||||
|
|
||||||
struct Entry {
|
namespace impl {
|
||||||
std::string name;
|
using Callback = std::function<bool(const std::string &, nlohmann::json &)>;
|
||||||
bool requiresRestart;
|
|
||||||
Callback callback;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Category {
|
struct Entry {
|
||||||
std::string name;
|
std::string name;
|
||||||
size_t slot = 0;
|
bool requiresRestart;
|
||||||
|
Callback callback;
|
||||||
|
};
|
||||||
|
|
||||||
bool operator<(const Category &other) const {
|
struct Category {
|
||||||
return name < other.name;
|
std::string name;
|
||||||
}
|
size_t slot = 0;
|
||||||
|
|
||||||
explicit operator const std::string &() const {
|
bool operator<(const Category &other) const {
|
||||||
return name;
|
return name < other.name;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
void load();
|
explicit operator const std::string &() const {
|
||||||
void store();
|
return name;
|
||||||
void clear();
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const Callback &callback, bool requiresRestart = false);
|
void load();
|
||||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback, bool requiresRestart = false);
|
void store();
|
||||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const Callback &callback, bool requiresRestart = false);
|
void clear();
|
||||||
|
|
||||||
|
std::map<Category, std::vector<Entry>> &getEntries();
|
||||||
|
std::map<std::string, std::string> &getCategoryDescriptions();
|
||||||
|
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName);
|
||||||
|
nlohmann::json &getSettingsData();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new integer setting entry
|
||||||
|
* @param unlocalizedCategory The category of the setting
|
||||||
|
* @param unlocalizedName The name of the setting
|
||||||
|
* @param defaultValue The default value of the setting
|
||||||
|
* @param callback The callback that will be called when the settings item in the preferences window is rendered
|
||||||
|
* @param requiresRestart Whether the setting requires a restart to take effect
|
||||||
|
*/
|
||||||
|
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const impl::Callback &callback, bool requiresRestart = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new string setting entry
|
||||||
|
* @param unlocalizedCategory The category of the setting
|
||||||
|
* @param unlocalizedName The name of the setting
|
||||||
|
* @param defaultValue The default value of the setting
|
||||||
|
* @param callback The callback that will be called when the settings item in the preferences window is rendered
|
||||||
|
* @param requiresRestart Whether the setting requires a restart to take effect
|
||||||
|
*/
|
||||||
|
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const impl::Callback &callback, bool requiresRestart = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new string list setting entry
|
||||||
|
* @param unlocalizedCategory The category of the setting
|
||||||
|
* @param unlocalizedName The name of the setting
|
||||||
|
* @param defaultValue The default value of the setting
|
||||||
|
* @param callback The callback that will be called when the settings item in the preferences window is rendered
|
||||||
|
* @param requiresRestart Whether the setting requires a restart to take effect
|
||||||
|
*/
|
||||||
|
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const impl::Callback &callback, bool requiresRestart = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a description to a given category
|
||||||
|
* @param unlocalizedCategory The name of the category
|
||||||
|
* @param unlocalizedCategoryDescription The description of the category
|
||||||
|
*/
|
||||||
void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription);
|
void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a integer value to the settings file
|
||||||
|
* @param unlocalizedCategory The category of the setting
|
||||||
|
* @param unlocalizedName The name of the setting
|
||||||
|
* @param value The value to write
|
||||||
|
*/
|
||||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value);
|
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a string value to the settings file
|
||||||
|
* @param unlocalizedCategory The category of the setting
|
||||||
|
* @param unlocalizedName The name of the setting
|
||||||
|
* @param value The value to write
|
||||||
|
*/
|
||||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &value);
|
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Writes a string list value to the settings file
|
||||||
|
* @param unlocalizedCategory The category of the setting
|
||||||
|
* @param unlocalizedName The name of the setting
|
||||||
|
* @param value The value to write
|
||||||
|
*/
|
||||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &value);
|
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads an integer value from the settings file
|
||||||
|
* @param unlocalizedCategory The category of the setting
|
||||||
|
* @param unlocalizedName The name of the setting
|
||||||
|
* @param defaultValue The default value of the setting
|
||||||
|
* @return The value of the setting
|
||||||
|
*/
|
||||||
i64 read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue);
|
i64 read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads a string value from the settings file
|
||||||
|
* @param unlocalizedCategory The category of the setting
|
||||||
|
* @param unlocalizedName The name of the setting
|
||||||
|
* @param defaultValue The default value of the setting
|
||||||
|
* @return The value of the setting
|
||||||
|
*/
|
||||||
std::string read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue);
|
std::string read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reads a string list value from the settings file
|
||||||
|
* @param unlocalizedCategory The category of the setting
|
||||||
|
* @param unlocalizedName The name of the setting
|
||||||
|
* @param defaultValue The default value of the setting
|
||||||
|
* @return The value of the setting
|
||||||
|
*/
|
||||||
std::vector<std::string> read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue = {});
|
std::vector<std::string> read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue = {});
|
||||||
|
|
||||||
std::map<Category, std::vector<Entry>> &getEntries();
|
|
||||||
std::map<std::string, std::string> &getCategoryDescriptions();
|
|
||||||
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName);
|
|
||||||
nlohmann::json &getSettingsData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Command Palette Command Registry. Allows adding of new commands to the command palette */
|
/* Command Palette Command Registry. Allows adding of new commands to the command palette */
|
||||||
namespace CommandPaletteCommands {
|
namespace CommandPaletteCommands {
|
||||||
|
|
||||||
enum class Type : u32
|
enum class Type : u32 {
|
||||||
{
|
|
||||||
SymbolCommand,
|
SymbolCommand,
|
||||||
KeywordCommand
|
KeywordCommand
|
||||||
};
|
};
|
||||||
|
|
||||||
using DisplayCallback = std::function<std::string(std::string)>;
|
namespace impl {
|
||||||
using ExecuteCallback = std::function<void(std::string)>;
|
|
||||||
|
|
||||||
struct Entry {
|
struct QueryResult {
|
||||||
Type type;
|
std::string name;
|
||||||
std::string command;
|
std::function<void(std::string)> callback;
|
||||||
std::string unlocalizedDescription;
|
};
|
||||||
DisplayCallback displayCallback;
|
|
||||||
ExecuteCallback executeCallback;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
using DisplayCallback = std::function<std::string(std::string)>;
|
||||||
|
using ExecuteCallback = std::function<void(std::string)>;
|
||||||
|
using QueryCallback = std::function<std::vector<QueryResult>(std::string)>;
|
||||||
|
|
||||||
|
struct Entry {
|
||||||
|
Type type;
|
||||||
|
std::string command;
|
||||||
|
std::string unlocalizedDescription;
|
||||||
|
DisplayCallback displayCallback;
|
||||||
|
ExecuteCallback executeCallback;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Handler {
|
||||||
|
Type type;
|
||||||
|
std::string command;
|
||||||
|
QueryCallback queryCallback;
|
||||||
|
DisplayCallback displayCallback;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<impl::Entry> &getEntries();
|
||||||
|
std::vector<impl::Handler> &getHandlers();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new command to the command palette
|
||||||
|
* @param type The type of the command
|
||||||
|
* @param command The command to add
|
||||||
|
* @param unlocalizedDescription The description of the command
|
||||||
|
* @param displayCallback The callback that will be called when the command is displayed in the command palette
|
||||||
|
* @param executeCallback The callback that will be called when the command is executed
|
||||||
|
*/
|
||||||
void add(
|
void add(
|
||||||
Type type,
|
Type type,
|
||||||
const std::string &command,
|
const std::string &command,
|
||||||
const std::string &unlocalizedDescription,
|
const std::string &unlocalizedDescription,
|
||||||
const DisplayCallback &displayCallback,
|
const impl::DisplayCallback &displayCallback,
|
||||||
const ExecuteCallback &executeCallback = [](auto) {});
|
const impl::ExecuteCallback &executeCallback = [](auto) {});
|
||||||
std::vector<Entry> &getEntries();
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new command handler to the command palette
|
||||||
|
* @param type The type of the command
|
||||||
|
* @param command The command to add
|
||||||
|
* @param unlocalizedDescription The description of the command
|
||||||
|
* @param queryCallback The callback that will be called when the command palette wants to load the name and callback items
|
||||||
|
* @param displayCallback The callback that will be called when the command is displayed in the command palette
|
||||||
|
*/
|
||||||
|
void addHandler(
|
||||||
|
Type type,
|
||||||
|
const std::string &command,
|
||||||
|
const impl::QueryCallback &queryCallback,
|
||||||
|
const impl::DisplayCallback &displayCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pattern Language Function Registry. Allows adding of new functions that may be used inside the pattern language */
|
/* Pattern Language Function Registry. Allows adding of new functions that may be used inside the pattern language */
|
||||||
namespace PatternLanguage {
|
namespace PatternLanguage {
|
||||||
|
|
||||||
using VisualizerFunctionCallback = std::function<void(pl::ptrn::Pattern&, pl::ptrn::Iteratable&, bool, std::span<const pl::core::Token::Literal>)>;
|
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
|
using VisualizerFunctionCallback = std::function<void(pl::ptrn::Pattern&, pl::ptrn::IIterable&, bool, std::span<const pl::core::Token::Literal>)>;
|
||||||
|
|
||||||
struct FunctionDefinition {
|
struct FunctionDefinition {
|
||||||
pl::api::Namespace ns;
|
pl::api::Namespace ns;
|
||||||
std::string name;
|
std::string name;
|
||||||
@@ -138,20 +258,64 @@ namespace hex {
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::map<std::string, Visualizer> &getVisualizers();
|
std::map<std::string, Visualizer> &getVisualizers();
|
||||||
|
std::map<std::string, pl::api::PragmaHandler> &getPragmas();
|
||||||
|
std::vector<impl::FunctionDefinition> &getFunctions();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides access to the current provider's pattern language runtime
|
||||||
|
* @return Runtime
|
||||||
|
*/
|
||||||
|
pl::PatternLanguage& getRuntime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides access to the current provider's pattern language runtime's lock
|
||||||
|
* @return Lock
|
||||||
|
*/
|
||||||
|
std::mutex& getRuntimeLock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures the pattern language runtime using ImHex's default settings
|
||||||
|
* @param runtime The pattern language runtime to configure
|
||||||
|
* @param provider The provider to use for data access
|
||||||
|
*/
|
||||||
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider);
|
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new pragma to the pattern language
|
||||||
|
* @param name The name of the pragma
|
||||||
|
* @param handler The handler that will be called when the pragma is encountered
|
||||||
|
*/
|
||||||
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler);
|
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new function to the pattern language
|
||||||
|
* @param ns The namespace of the function
|
||||||
|
* @param name The name of the function
|
||||||
|
* @param parameterCount The amount of parameters the function takes
|
||||||
|
* @param func The function callback
|
||||||
|
*/
|
||||||
void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func);
|
void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new dangerous function to the pattern language
|
||||||
|
* @note Dangerous functions are functions that require the user to explicitly allow them to be used
|
||||||
|
* @param ns The namespace of the function
|
||||||
|
* @param name The name of the function
|
||||||
|
* @param parameterCount The amount of parameters the function takes
|
||||||
|
* @param func The function callback
|
||||||
|
*/
|
||||||
void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func);
|
void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func);
|
||||||
|
|
||||||
void addVisualizer(const std::string &name, const VisualizerFunctionCallback &func, u32 parameterCount);
|
/**
|
||||||
|
* @brief Adds a new visualizer to the pattern language
|
||||||
std::map<std::string, pl::api::PragmaHandler> &getPragmas();
|
* @note Visualizers are extensions to the [[hex::visualize]] attribute, used to visualize data
|
||||||
std::vector<impl::FunctionDefinition> &getFunctions();
|
* @param name The name of the visualizer
|
||||||
|
* @param func The function callback
|
||||||
|
* @param parameterCount The amount of parameters the function takes
|
||||||
|
*/
|
||||||
|
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &func, u32 parameterCount);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,19 +324,28 @@ namespace hex {
|
|||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
void add(View *view);
|
void add(std::unique_ptr<View> &&view);
|
||||||
|
std::map<std::string, std::unique_ptr<View>> &getEntries();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new view to ImHex
|
||||||
|
* @tparam T The custom view class that extends View
|
||||||
|
* @tparam Args Arguments types
|
||||||
|
* @param args Arguments passed to the constructor of the view
|
||||||
|
*/
|
||||||
template<std::derived_from<View> T, typename... Args>
|
template<std::derived_from<View> T, typename... Args>
|
||||||
void add(Args &&...args) {
|
void add(Args &&...args) {
|
||||||
return impl::add(new T(std::forward<Args>(args)...));
|
return impl::add(std::make_unique<T>(std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, View *> &getEntries();
|
/**
|
||||||
|
* @brief Gets a view by its unlocalized name
|
||||||
View *getViewByName(const std::string &unlocalizedName);
|
* @param unlocalizedName The unlocalized name of the view
|
||||||
|
* @return The view if it exists, nullptr otherwise
|
||||||
|
*/
|
||||||
|
View* getViewByName(const std::string &unlocalizedName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tools Registry. Allows adding new entries to the tools window */
|
/* Tools Registry. Allows adding new entries to the tools window */
|
||||||
@@ -188,11 +361,16 @@ namespace hex {
|
|||||||
bool detached;
|
bool detached;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::vector<impl::Entry> &getEntries();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new tool to the tools window
|
||||||
|
* @param unlocalizedName The unlocalized name of the tool
|
||||||
|
* @param function The function that will be called to draw the tool
|
||||||
|
*/
|
||||||
void add(const std::string &unlocalizedName, const impl::Callback &function);
|
void add(const std::string &unlocalizedName, const impl::Callback &function);
|
||||||
|
|
||||||
std::vector<impl::Entry> &getEntries();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Data Inspector Registry. Allows adding of new types to the data inspector */
|
/* Data Inspector Registry. Allows adding of new types to the data inspector */
|
||||||
@@ -219,12 +397,28 @@ namespace hex {
|
|||||||
std::optional<impl::EditingFunction> editingFunction;
|
std::optional<impl::EditingFunction> editingFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::vector<impl::Entry> &getEntries();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new entry to the data inspector
|
||||||
|
* @param unlocalizedName The unlocalized name of the entry
|
||||||
|
* @param requiredSize The minimum required number of bytes available for the entry to appear
|
||||||
|
* @param displayGeneratorFunction The function that will be called to generate the display function
|
||||||
|
* @param editingFunction The function that will be called to edit the data
|
||||||
|
*/
|
||||||
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
|
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
|
||||||
void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
|
|
||||||
|
|
||||||
std::vector<impl::Entry> &getEntries();
|
/**
|
||||||
|
* @brief Adds a new entry to the data inspector
|
||||||
|
* @param unlocalizedName The unlocalized name of the entry
|
||||||
|
* @param requiredSize The minimum required number of bytes available for the entry to appear
|
||||||
|
* @param maxSize The maximum number of bytes to read from the data
|
||||||
|
* @param displayGeneratorFunction The function that will be called to generate the display function
|
||||||
|
* @param editingFunction The function that will be called to edit the data
|
||||||
|
*/
|
||||||
|
void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Data Processor Node Registry. Allows adding new processor nodes to be used in the data processor */
|
/* Data Processor Node Registry. Allows adding new processor nodes to be used in the data processor */
|
||||||
@@ -242,15 +436,24 @@ namespace hex {
|
|||||||
|
|
||||||
void add(const Entry &entry);
|
void add(const Entry &entry);
|
||||||
|
|
||||||
|
std::vector<impl::Entry> &getEntries();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new node to the data processor
|
||||||
|
* @tparam T The custom node class that extends dp::Node
|
||||||
|
* @tparam Args Arguments types
|
||||||
|
* @param unlocalizedCategory The unlocalized category name of the node
|
||||||
|
* @param unlocalizedName The unlocalized name of the node
|
||||||
|
* @param args Arguments passed to the constructor of the node
|
||||||
|
*/
|
||||||
template<std::derived_from<dp::Node> T, typename... Args>
|
template<std::derived_from<dp::Node> T, typename... Args>
|
||||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, Args &&...args) {
|
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, Args &&...args) {
|
||||||
add(impl::Entry {
|
add(impl::Entry {
|
||||||
unlocalizedCategory.c_str(),
|
unlocalizedCategory.c_str(),
|
||||||
unlocalizedName.c_str(),
|
unlocalizedName.c_str(),
|
||||||
[=] {
|
[=, ...args = std::forward<Args>(args)] mutable {
|
||||||
auto node = std::make_unique<T>(std::forward<Args>(args)...);
|
auto node = std::make_unique<T>(std::forward<Args>(args)...);
|
||||||
node->setUnlocalizedName(unlocalizedName);
|
node->setUnlocalizedName(unlocalizedName);
|
||||||
return node;
|
return node;
|
||||||
@@ -258,18 +461,29 @@ namespace hex {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a separator to the data processor right click menu
|
||||||
|
*/
|
||||||
void addSeparator();
|
void addSeparator();
|
||||||
|
|
||||||
std::vector<impl::Entry> &getEntries();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Language Registry. Allows together with the LangEntry class and the _lang user defined literal to add new languages */
|
/* Language Registry. Allows together with the LangEntry class and the _lang user defined literal to add new languages */
|
||||||
namespace Language {
|
namespace Language {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Loads localization information from json data
|
||||||
|
* @param data The language data
|
||||||
|
*/
|
||||||
void addLocalization(const nlohmann::json &data);
|
void addLocalization(const nlohmann::json &data);
|
||||||
|
|
||||||
std::map<std::string, std::string> &getLanguages();
|
namespace impl {
|
||||||
std::map<std::string, std::vector<LanguageDefinition>> &getLanguageDefinitions();
|
|
||||||
|
std::map<std::string, std::string> &getLanguages();
|
||||||
|
std::map<std::string, std::vector<LanguageDefinition>> &getLanguageDefinitions();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Interface Registry. Allows adding new items to various interfaces */
|
/* Interface Registry. Allows adding new items to various interfaces */
|
||||||
@@ -277,22 +491,20 @@ namespace hex {
|
|||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
using DrawCallback = std::function<void()>;
|
using DrawCallback = std::function<void()>;
|
||||||
using LayoutFunction = std::function<void(u32)>;
|
using MenuCallback = std::function<void()>;
|
||||||
using ClickCallback = std::function<void()>;
|
using EnabledCallback = std::function<bool()>;
|
||||||
|
using ClickCallback = std::function<void()>;
|
||||||
struct Layout {
|
|
||||||
std::string unlocalizedName;
|
|
||||||
LayoutFunction callback;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MainMenuItem {
|
struct MainMenuItem {
|
||||||
std::string unlocalizedName;
|
std::string unlocalizedName;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MenuItem {
|
struct MenuItem {
|
||||||
std::string unlocalizedName;
|
std::vector<std::string> unlocalizedNames;
|
||||||
DrawCallback callback;
|
Shortcut shortcut;
|
||||||
|
MenuCallback callback;
|
||||||
|
EnabledCallback enabledCallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SidebarItem {
|
struct SidebarItem {
|
||||||
@@ -306,29 +518,89 @@ namespace hex {
|
|||||||
ClickCallback callback;
|
ClickCallback callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr static auto SeparatorValue = "$SEPARATOR$";
|
||||||
|
constexpr static auto SubMenuValue = "$SUBMENU$";
|
||||||
|
|
||||||
|
std::multimap<u32, impl::MainMenuItem> &getMainMenuItems();
|
||||||
|
std::multimap<u32, impl::MenuItem> &getMenuItems();
|
||||||
|
|
||||||
|
std::vector<impl::DrawCallback> &getWelcomeScreenEntries();
|
||||||
|
std::vector<impl::DrawCallback> &getFooterItems();
|
||||||
|
std::vector<impl::DrawCallback> &getToolbarItems();
|
||||||
|
std::vector<impl::SidebarItem> &getSidebarItems();
|
||||||
|
std::vector<impl::TitleBarButton> &getTitleBarButtons();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new top-level main menu entry
|
||||||
|
* @param unlocalizedName The unlocalized name of the entry
|
||||||
|
* @param priority The priority of the entry. Lower values are displayed first
|
||||||
|
*/
|
||||||
void registerMainMenuItem(const std::string &unlocalizedName, u32 priority);
|
void registerMainMenuItem(const std::string &unlocalizedName, u32 priority);
|
||||||
void addMenuItem(const std::string &unlocalizedMainMenuName, u32 priority, const impl::DrawCallback &function);
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new main menu entry
|
||||||
|
* @param unlocalizedMainMenuNames The unlocalized names of the main menu entries
|
||||||
|
* @param priority The priority of the entry. Lower values are displayed first
|
||||||
|
* @param shortcut The shortcut to use for the entry
|
||||||
|
* @param function The function to call when the entry is clicked
|
||||||
|
* @param enabledCallback The function to call to determine if the entry is enabled
|
||||||
|
* @param view The view to use for the entry. If nullptr, the shortcut will work globally
|
||||||
|
*/
|
||||||
|
void addMenuItem(const std::vector<std::string> &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback = []{ return true; }, View *view = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new main menu sub-menu entry
|
||||||
|
* @param unlocalizedMainMenuNames The unlocalized names of the main menu entries
|
||||||
|
* @param priority The priority of the entry. Lower values are displayed first
|
||||||
|
* @param function The function to call when the entry is clicked
|
||||||
|
* @param enabledCallback The function to call to determine if the entry is enabled
|
||||||
|
* @param view The view to use for the entry. If nullptr, the shortcut will work globally
|
||||||
|
*/
|
||||||
|
void addMenuItemSubMenu(std::vector<std::string> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback = []{ return true; });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new main menu separator
|
||||||
|
* @param unlocalizedMainMenuNames The unlocalized names of the main menu entries
|
||||||
|
* @param priority The priority of the entry. Lower values are displayed first
|
||||||
|
*/
|
||||||
|
void addMenuItemSeparator(std::vector<std::string> unlocalizedMainMenuNames, u32 priority);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new welcome screen entry
|
||||||
|
* @param function The function to call to draw the entry
|
||||||
|
*/
|
||||||
void addWelcomeScreenEntry(const impl::DrawCallback &function);
|
void addWelcomeScreenEntry(const impl::DrawCallback &function);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new footer item
|
||||||
|
* @param function The function to call to draw the item
|
||||||
|
*/
|
||||||
void addFooterItem(const impl::DrawCallback &function);
|
void addFooterItem(const impl::DrawCallback &function);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new toolbar item
|
||||||
|
* @param function The function to call to draw the item
|
||||||
|
*/
|
||||||
void addToolbarItem(const impl::DrawCallback &function);
|
void addToolbarItem(const impl::DrawCallback &function);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new sidebar item
|
||||||
|
* @param icon The icon to use for the item
|
||||||
|
* @param function The function to call to draw the item
|
||||||
|
*/
|
||||||
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function);
|
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new title bar button
|
||||||
|
* @param icon The icon to use for the button
|
||||||
|
* @param unlocalizedTooltip The unlocalized tooltip to use for the button
|
||||||
|
* @param function The function to call when the button is clicked
|
||||||
|
*/
|
||||||
void addTitleBarButton(const std::string &icon, const std::string &unlocalizedTooltip, const impl::ClickCallback &function);
|
void addTitleBarButton(const std::string &icon, const std::string &unlocalizedTooltip, const impl::ClickCallback &function);
|
||||||
|
|
||||||
void addLayout(const std::string &unlocalizedName, const impl::LayoutFunction &function);
|
|
||||||
|
|
||||||
std::multimap<u32, impl::MainMenuItem> &getMainMenuItems();
|
|
||||||
std::multimap<u32, impl::MenuItem> &getMenuItems();
|
|
||||||
|
|
||||||
std::vector<impl::DrawCallback> &getWelcomeScreenEntries();
|
|
||||||
std::vector<impl::DrawCallback> &getFooterItems();
|
|
||||||
std::vector<impl::DrawCallback> &getToolbarItems();
|
|
||||||
std::vector<impl::SidebarItem> &getSidebarItems();
|
|
||||||
std::vector<impl::TitleBarButton> &getTitleBarButtons();
|
|
||||||
|
|
||||||
std::vector<impl::Layout> &getLayouts();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Provider Registry. Allows adding new data providers to be created from the UI */
|
/* Provider Registry. Allows adding new data providers to be created from the UI */
|
||||||
@@ -338,8 +610,15 @@ namespace hex {
|
|||||||
|
|
||||||
void addProviderName(const std::string &unlocalizedName);
|
void addProviderName(const std::string &unlocalizedName);
|
||||||
|
|
||||||
|
std::vector<std::string> &getEntries();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new provider to the list of providers
|
||||||
|
* @tparam T The provider type that extends hex::prv::Provider
|
||||||
|
* @param addToList Whether to display the provider in the Other Providers list in the welcome screen and File menu
|
||||||
|
*/
|
||||||
template<std::derived_from<hex::prv::Provider> T>
|
template<std::derived_from<hex::prv::Provider> T>
|
||||||
void add(bool addToList = true) {
|
void add(bool addToList = true) {
|
||||||
auto typeName = T().getTypeName();
|
auto typeName = T().getTypeName();
|
||||||
@@ -359,10 +638,9 @@ namespace hex {
|
|||||||
impl::addProviderName(typeName);
|
impl::addProviderName(typeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> &getEntries();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Data Formatter Registry. Allows adding formatters that are used in the Copy-As menu for example */
|
||||||
namespace DataFormatter {
|
namespace DataFormatter {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
@@ -373,32 +651,45 @@ namespace hex {
|
|||||||
Callback callback;
|
Callback callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::vector<impl::Entry> &getEntries();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(const std::string &unlocalizedName, const impl::Callback &callback);
|
|
||||||
|
|
||||||
std::vector<impl::Entry> &getEntries();
|
/**
|
||||||
|
* @brief Adds a new data formatter
|
||||||
|
* @param unlocalizedName The unlocalized name of the formatter
|
||||||
|
* @param callback The function to call to format the data
|
||||||
|
*/
|
||||||
|
void add(const std::string &unlocalizedName, const impl::Callback &callback);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* File Handler Registry. Allows adding handlers for opening files specific file types */
|
||||||
namespace FileHandler {
|
namespace FileHandler {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
using Callback = std::function<bool(std::filesystem::path)>;
|
using Callback = std::function<bool(std::fs::path)>;
|
||||||
struct Entry {
|
struct Entry {
|
||||||
std::vector<std::string> extensions;
|
std::vector<std::string> extensions;
|
||||||
Callback callback;
|
Callback callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::vector<impl::Entry> &getEntries();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new file handler
|
||||||
|
* @param extensions The file extensions to handle
|
||||||
|
* @param callback The function to call to handle the file
|
||||||
|
*/
|
||||||
void add(const std::vector<std::string> &extensions, const impl::Callback &callback);
|
void add(const std::vector<std::string> &extensions, const impl::Callback &callback);
|
||||||
|
|
||||||
std::vector<impl::Entry> &getEntries();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hex Editor Registry. Allows adding new functionality to the hex editor */
|
||||||
namespace HexEditor {
|
namespace HexEditor {
|
||||||
|
|
||||||
class DataVisualizer {
|
class DataVisualizer {
|
||||||
@@ -417,7 +708,8 @@ namespace hex {
|
|||||||
protected:
|
protected:
|
||||||
const static int TextInputFlags;
|
const static int TextInputFlags;
|
||||||
|
|
||||||
bool drawDefaultEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const;
|
bool drawDefaultScalarEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const;
|
||||||
|
bool drawDefaultTextEditingTextBox(u64 address, std::string &data, ImGuiInputTextFlags flags) const;
|
||||||
private:
|
private:
|
||||||
u16 m_bytesPerCell;
|
u16 m_bytesPerCell;
|
||||||
u16 m_maxCharsPerCell;
|
u16 m_maxCharsPerCell;
|
||||||
@@ -431,6 +723,12 @@ namespace hex {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new cell data visualizer
|
||||||
|
* @tparam T The data visualizer type that extends hex::DataVisualizer
|
||||||
|
* @param unlocalizedName The unlocalized name of the data visualizer
|
||||||
|
* @param args The arguments to pass to the constructor of the data visualizer
|
||||||
|
*/
|
||||||
template<std::derived_from<DataVisualizer> T, typename... Args>
|
template<std::derived_from<DataVisualizer> T, typename... Args>
|
||||||
void addDataVisualizer(const std::string &unlocalizedName, Args &&...args) {
|
void addDataVisualizer(const std::string &unlocalizedName, Args &&...args) {
|
||||||
return impl::addDataVisualizer(unlocalizedName, new T(std::forward<Args>(args)...));
|
return impl::addDataVisualizer(unlocalizedName, new T(std::forward<Args>(args)...));
|
||||||
@@ -438,6 +736,7 @@ namespace hex {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hash Registry. Allows adding new hashes to the Hash view */
|
||||||
namespace Hashes {
|
namespace Hashes {
|
||||||
|
|
||||||
class Hash {
|
class Hash {
|
||||||
@@ -503,12 +802,47 @@ namespace hex {
|
|||||||
void add(Hash* hash);
|
void add(Hash* hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new hash
|
||||||
|
* @tparam T The hash type that extends hex::Hash
|
||||||
|
* @param args The arguments to pass to the constructor of the hash
|
||||||
|
*/
|
||||||
template<typename T, typename ... Args>
|
template<typename T, typename ... Args>
|
||||||
void add(Args && ... args) {
|
void add(Args && ... args) {
|
||||||
impl::add(new T(std::forward<Args>(args)...));
|
impl::add(new T(std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace BackgroundServices {
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
using Callback = std::function<void()>;
|
||||||
|
|
||||||
|
struct Service {
|
||||||
|
std::string name;
|
||||||
|
std::jthread thread;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Service> &getServices();
|
||||||
|
void stopServices();
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerService(const std::string &unlocalizedName, const impl::Callback &callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CommunicationInterface {
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
using NetworkCallback = std::function<nlohmann::json(const nlohmann::json &)>;
|
||||||
|
|
||||||
|
std::map<std::string, NetworkCallback> &getNetworkEndpoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerNetworkEndpoint(const std::string &endpoint, const impl::NetworkCallback &callback);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,73 +9,110 @@
|
|||||||
|
|
||||||
#include <hex/api/imhex_api.hpp>
|
#include <hex/api/imhex_api.hpp>
|
||||||
#include <hex/helpers/fs.hpp>
|
#include <hex/helpers/fs.hpp>
|
||||||
|
#include <hex/helpers/logger.hpp>
|
||||||
|
|
||||||
#define EVENT_DEF(event_name, ...) \
|
#include <wolv/types/type_name.hpp>
|
||||||
struct event_name final : public hex::Event<__VA_ARGS__> { \
|
|
||||||
constexpr static auto id = [] { return hex::EventId(); }(); \
|
#define EVENT_DEF_IMPL(event_name, should_log, ...) \
|
||||||
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
|
struct event_name final : public hex::impl::Event<__VA_ARGS__> { \
|
||||||
|
constexpr static auto Id = [] { return hex::impl::EventId(); }(); \
|
||||||
|
constexpr static auto ShouldLog = (should_log); \
|
||||||
|
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define EVENT_DEF(event_name, ...) EVENT_DEF_IMPL(event_name, true, __VA_ARGS__)
|
||||||
|
#define EVENT_DEF_NO_LOG(event_name, ...) EVENT_DEF_IMPL(event_name, false, __VA_ARGS__)
|
||||||
|
|
||||||
struct GLFWwindow;
|
struct GLFWwindow;
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
class EventId {
|
namespace impl {
|
||||||
public:
|
|
||||||
explicit constexpr EventId(const char *func = __builtin_FUNCTION(), u32 line = __builtin_LINE()) {
|
class EventId {
|
||||||
this->m_hash = line ^ 987654321;
|
public:
|
||||||
for (auto c : std::string_view(func)) {
|
explicit constexpr EventId(const char *func = __builtin_FUNCTION(), u32 line = __builtin_LINE()) {
|
||||||
this->m_hash = (this->m_hash >> 5) | (this->m_hash << 27);
|
this->m_hash = line ^ 987654321;
|
||||||
this->m_hash ^= c;
|
for (auto c : std::string_view(func)) {
|
||||||
|
this->m_hash = (this->m_hash >> 5) | (this->m_hash << 27);
|
||||||
|
this->m_hash ^= c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
constexpr bool operator==(const EventId &rhs) const = default;
|
constexpr bool operator==(const EventId &rhs) const = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u32 m_hash;
|
u32 m_hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EventBase {
|
struct EventBase {
|
||||||
EventBase() noexcept = default;
|
EventBase() noexcept = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Params>
|
template<typename... Params>
|
||||||
struct Event : public EventBase {
|
struct Event : public EventBase {
|
||||||
using Callback = std::function<void(Params...)>;
|
using Callback = std::function<void(Params...)>;
|
||||||
|
|
||||||
explicit Event(Callback func) noexcept : m_func(std::move(func)) { }
|
explicit Event(Callback func) noexcept : m_func(std::move(func)) { }
|
||||||
|
|
||||||
void operator()(Params... params) const noexcept {
|
void operator()(Params... params) const noexcept {
|
||||||
this->m_func(params...);
|
this->m_func(params...);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Callback m_func;
|
Callback m_func;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The EventManager allows subscribing to and posting events to different parts of the program.
|
||||||
|
* To create a new event, use the EVENT_DEF macro. This will create a new event type with the given name and parameters
|
||||||
|
*/
|
||||||
class EventManager {
|
class EventManager {
|
||||||
public:
|
public:
|
||||||
using EventList = std::list<std::pair<EventId, EventBase *>>;
|
using EventList = std::list<std::pair<impl::EventId, impl::EventBase *>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Subscribes to an event
|
||||||
|
* @tparam E Event
|
||||||
|
* @param function Function to call when the event is posted
|
||||||
|
* @return Token to unsubscribe from the event
|
||||||
|
*/
|
||||||
template<typename E>
|
template<typename E>
|
||||||
static EventList::iterator subscribe(typename E::Callback function) {
|
static EventList::iterator subscribe(typename E::Callback function) {
|
||||||
return s_events.insert(s_events.end(), std::make_pair(E::id, new E(function)));
|
return s_events.insert(s_events.end(), std::make_pair(E::Id, new E(function)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Subscribes to an event
|
||||||
|
* @tparam E Event
|
||||||
|
* @param token Unique token to register the event to. Later required to unsubscribe again
|
||||||
|
* @param function Function to call when the event is posted
|
||||||
|
*/
|
||||||
template<typename E>
|
template<typename E>
|
||||||
static void subscribe(void *token, typename E::Callback function) {
|
static void subscribe(void *token, typename E::Callback function) {
|
||||||
s_tokenStore.insert(std::make_pair(token, subscribe<E>(function)));
|
s_tokenStore.insert(std::make_pair(token, subscribe<E>(function)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unsubscribe(EventList::iterator iter) noexcept {
|
/**
|
||||||
s_events.remove(*iter);
|
* @brief Unsubscribes from an event
|
||||||
|
* @param token Token returned by subscribe
|
||||||
|
*/
|
||||||
|
static void unsubscribe(const EventList::iterator &token) noexcept {
|
||||||
|
s_events.erase(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unsubscribes from an event
|
||||||
|
* @tparam E Event
|
||||||
|
* @param token Token passed to subscribe
|
||||||
|
*/
|
||||||
template<typename E>
|
template<typename E>
|
||||||
static void unsubscribe(void *token) noexcept {
|
static void unsubscribe(void *token) noexcept {
|
||||||
auto iter = std::find_if(s_tokenStore.begin(), s_tokenStore.end(), [&](auto &item) {
|
auto iter = std::find_if(s_tokenStore.begin(), s_tokenStore.end(), [&](auto &item) {
|
||||||
return item.first == token && item.second->first == E::id;
|
return item.first == token && item.second->first == E::Id;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (iter != s_tokenStore.end()) {
|
if (iter != s_tokenStore.end()) {
|
||||||
@@ -85,14 +122,28 @@ namespace hex {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Posts an event to all subscribers of it
|
||||||
|
* @tparam E Event
|
||||||
|
* @param args Arguments to pass to the event
|
||||||
|
*/
|
||||||
template<typename E>
|
template<typename E>
|
||||||
static void post(auto &&...args) noexcept {
|
static void post(auto &&...args) noexcept {
|
||||||
for (const auto &[id, event] : s_events) {
|
for (const auto &[id, event] : s_events) {
|
||||||
if (id == E::id)
|
if (id == E::Id) {
|
||||||
(*static_cast<E *const>(event))(std::forward<decltype(args)>(args)...);
|
(*static_cast<E *const>(event))(std::forward<decltype(args)>(args)...);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined (DEBUG)
|
||||||
|
if (E::ShouldLog)
|
||||||
|
log::debug("Event posted: '{}'", wolv::type::getTypeName<E>());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unsubscribe all subscribers from all events
|
||||||
|
*/
|
||||||
static void clear() noexcept {
|
static void clear() noexcept {
|
||||||
s_events.clear();
|
s_events.clear();
|
||||||
s_tokenStore.clear();
|
s_tokenStore.clear();
|
||||||
@@ -112,33 +163,61 @@ namespace hex {
|
|||||||
EVENT_DEF(EventSettingsChanged);
|
EVENT_DEF(EventSettingsChanged);
|
||||||
EVENT_DEF(EventAbnormalTermination, int);
|
EVENT_DEF(EventAbnormalTermination, int);
|
||||||
EVENT_DEF(EventOSThemeChanged);
|
EVENT_DEF(EventOSThemeChanged);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called when the provider is created.
|
||||||
|
* This event is responsible for (optionally) initializing the provider and calling EventProviderOpened
|
||||||
|
* (although the event can also be called manually without problem)
|
||||||
|
*/
|
||||||
EVENT_DEF(EventProviderCreated, prv::Provider *);
|
EVENT_DEF(EventProviderCreated, prv::Provider *);
|
||||||
EVENT_DEF(EventProviderChanged, prv::Provider *, prv::Provider *);
|
EVENT_DEF(EventProviderChanged, prv::Provider *, prv::Provider *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Called as a continuation of EventProviderCreated
|
||||||
|
* this event is normally called immediately after EventProviderCreated successfully initialized the provider.
|
||||||
|
* If no initialization (Provider::skipLoadInterface() has been set), this event should be called manually
|
||||||
|
* If skipLoadInterface failed, this event is not called
|
||||||
|
*
|
||||||
|
* @note this is not related to Provider::open()
|
||||||
|
*/
|
||||||
EVENT_DEF(EventProviderOpened, prv::Provider *);
|
EVENT_DEF(EventProviderOpened, prv::Provider *);
|
||||||
EVENT_DEF(EventProviderClosing, prv::Provider *, bool *);
|
EVENT_DEF(EventProviderClosing, prv::Provider *, bool *);
|
||||||
EVENT_DEF(EventProviderClosed, prv::Provider *);
|
EVENT_DEF(EventProviderClosed, prv::Provider *);
|
||||||
EVENT_DEF(EventProviderDeleted, prv::Provider *);
|
EVENT_DEF(EventProviderDeleted, prv::Provider *);
|
||||||
EVENT_DEF(EventFrameBegin);
|
EVENT_DEF(EventProviderSaved, prv::Provider *);
|
||||||
EVENT_DEF(EventFrameEnd);
|
|
||||||
EVENT_DEF(EventWindowInitialized);
|
EVENT_DEF(EventWindowInitialized);
|
||||||
EVENT_DEF(EventSetTaskBarIconState, u32, u32, u32);
|
EVENT_DEF(EventBookmarkCreated, ImHexApi::Bookmarks::Entry&);
|
||||||
|
EVENT_DEF(EventPatchCreated, u64, u8, u8);
|
||||||
|
EVENT_DEF(EventPatternExecuted, const std::string&);
|
||||||
|
EVENT_DEF(EventPatternEditorChanged, const std::string&);
|
||||||
|
EVENT_DEF(EventStoreContentDownloaded, const std::fs::path&);
|
||||||
|
EVENT_DEF(EventStoreContentRemoved, const std::fs::path&);
|
||||||
|
EVENT_DEF(EventImHexClosing);
|
||||||
|
|
||||||
|
EVENT_DEF_NO_LOG(EventFrameBegin);
|
||||||
|
EVENT_DEF_NO_LOG(EventFrameEnd);
|
||||||
|
EVENT_DEF_NO_LOG(EventSetTaskBarIconState, u32, u32, u32);
|
||||||
|
|
||||||
EVENT_DEF(RequestOpenWindow, std::string);
|
EVENT_DEF(RequestOpenWindow, std::string);
|
||||||
EVENT_DEF(RequestSelectionChange, Region);
|
EVENT_DEF(RequestSelectionChange, Region);
|
||||||
EVENT_DEF(RequestAddBookmark, Region, std::string, std::string, color_t);
|
EVENT_DEF(RequestAddBookmark, Region, std::string, std::string, color_t);
|
||||||
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
|
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
|
||||||
|
EVENT_DEF(RequestLoadPatternLanguageFile, std::fs::path);
|
||||||
|
EVENT_DEF(RequestSavePatternLanguageFile, std::fs::path);
|
||||||
EVENT_DEF(RequestUpdateWindowTitle);
|
EVENT_DEF(RequestUpdateWindowTitle);
|
||||||
EVENT_DEF(RequestCloseImHex, bool);
|
EVENT_DEF(RequestCloseImHex, bool);
|
||||||
EVENT_DEF(RequestRestartImHex);
|
EVENT_DEF(RequestRestartImHex);
|
||||||
EVENT_DEF(RequestOpenFile, std::fs::path);
|
EVENT_DEF(RequestOpenFile, std::fs::path);
|
||||||
EVENT_DEF(RequestChangeTheme, std::string);
|
EVENT_DEF(RequestChangeTheme, std::string);
|
||||||
EVENT_DEF(RequestOpenPopup, std::string);
|
EVENT_DEF(RequestOpenPopup, std::string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a provider from it's unlocalized name, and add it to the provider list
|
||||||
|
*/
|
||||||
EVENT_DEF(RequestCreateProvider, std::string, bool, hex::prv::Provider **);
|
EVENT_DEF(RequestCreateProvider, std::string, bool, hex::prv::Provider **);
|
||||||
|
EVENT_DEF(RequestInitThemeHandlers);
|
||||||
|
|
||||||
EVENT_DEF(RequestShowInfoPopup, std::string);
|
EVENT_DEF(RequestOpenInfoPopup, const std::string);
|
||||||
EVENT_DEF(RequestShowErrorPopup, std::string);
|
EVENT_DEF(RequestOpenErrorPopup, const std::string);
|
||||||
EVENT_DEF(RequestShowFatalErrorPopup, std::string);
|
EVENT_DEF(RequestOpenFatalPopup, const std::string);
|
||||||
EVENT_DEF(RequestShowYesNoQuestionPopup, std::string, std::function<void()>, std::function<void()>);
|
|
||||||
EVENT_DEF(RequestShowFileChooserPopup, std::vector<std::fs::path>, std::vector<nfdfilteritem_t>, std::function<void(std::fs::path)>, bool);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -8,12 +8,12 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
#include <hex/helpers/concepts.hpp>
|
#include <hex/helpers/concepts.hpp>
|
||||||
#include <hex/api/task.hpp>
|
|
||||||
#include <hex/api/keybinding.hpp>
|
#include <hex/api/keybinding.hpp>
|
||||||
|
|
||||||
|
#include <wolv/io/fs.hpp>
|
||||||
|
|
||||||
using ImGuiID = unsigned int;
|
using ImGuiID = unsigned int;
|
||||||
struct ImVec2;
|
struct ImVec2;
|
||||||
|
|
||||||
@@ -25,13 +25,7 @@ namespace hex {
|
|||||||
|
|
||||||
namespace ImHexApi {
|
namespace ImHexApi {
|
||||||
|
|
||||||
namespace Common {
|
/* Functions to query information from the Hex Editor and interact with it */
|
||||||
|
|
||||||
void closeImHex(bool noQuestions = false);
|
|
||||||
void restartImHex();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace HexEditor {
|
namespace HexEditor {
|
||||||
|
|
||||||
using TooltipFunction = std::function<void(u64, const u8*, size_t)>;
|
using TooltipFunction = std::function<void(u64, const u8*, size_t)>;
|
||||||
@@ -86,32 +80,132 @@ namespace hex {
|
|||||||
void setCurrentSelection(std::optional<ProviderRegion> region);
|
void setCurrentSelection(std::optional<ProviderRegion> region);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a background color highlighting to the Hex Editor
|
||||||
|
* @param region The region to highlight
|
||||||
|
* @param color The color to use for the highlighting
|
||||||
|
* @return Unique ID used to remove the highlighting again later
|
||||||
|
*/
|
||||||
u32 addBackgroundHighlight(const Region ®ion, color_t color);
|
u32 addBackgroundHighlight(const Region ®ion, color_t color);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes a background color highlighting from the Hex Editor
|
||||||
|
* @param id The ID of the highlighting to remove
|
||||||
|
*/
|
||||||
void removeBackgroundHighlight(u32 id);
|
void removeBackgroundHighlight(u32 id);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a foreground color highlighting to the Hex Editor
|
||||||
|
* @param region The region to highlight
|
||||||
|
* @param color The color to use for the highlighting
|
||||||
|
* @return Unique ID used to remove the highlighting again later
|
||||||
|
*/
|
||||||
u32 addForegroundHighlight(const Region ®ion, color_t color);
|
u32 addForegroundHighlight(const Region ®ion, color_t color);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes a foreground color highlighting from the Hex Editor
|
||||||
|
* @param id The ID of the highlighting to remove
|
||||||
|
*/
|
||||||
void removeForegroundHighlight(u32 id);
|
void removeForegroundHighlight(u32 id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a hover tooltip to the Hex Editor
|
||||||
|
* @param region The region to add the tooltip to
|
||||||
|
* @param value Text to display in the tooltip
|
||||||
|
* @param color The color of the tooltip
|
||||||
|
* @return Unique ID used to remove the tooltip again later
|
||||||
|
*/
|
||||||
u32 addTooltip(Region region, std::string value, color_t color);
|
u32 addTooltip(Region region, std::string value, color_t color);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes a hover tooltip from the Hex Editor
|
||||||
|
* @param id The ID of the tooltip to remove
|
||||||
|
*/
|
||||||
void removeTooltip(u32 id);
|
void removeTooltip(u32 id);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a background color highlighting to the Hex Editor using a callback function
|
||||||
|
* @param function Function that draws the highlighting based on the hovered region
|
||||||
|
* @return Unique ID used to remove the highlighting again later
|
||||||
|
*/
|
||||||
u32 addTooltipProvider(TooltipFunction function);
|
u32 addTooltipProvider(TooltipFunction function);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes a background color highlighting from the Hex Editor
|
||||||
|
* @param id The ID of the highlighting to remove
|
||||||
|
*/
|
||||||
void removeTooltipProvider(u32 id);
|
void removeTooltipProvider(u32 id);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a background color highlighting to the Hex Editor using a callback function
|
||||||
|
* @param function Function that draws the highlighting based on the hovered region
|
||||||
|
* @return Unique ID used to remove the highlighting again later
|
||||||
|
*/
|
||||||
u32 addBackgroundHighlightingProvider(const impl::HighlightingFunction &function);
|
u32 addBackgroundHighlightingProvider(const impl::HighlightingFunction &function);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes a background color highlighting from the Hex Editor
|
||||||
|
* @param id The ID of the highlighting to remove
|
||||||
|
*/
|
||||||
void removeBackgroundHighlightingProvider(u32 id);
|
void removeBackgroundHighlightingProvider(u32 id);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a foreground color highlighting to the Hex Editor using a callback function
|
||||||
|
* @param function Function that draws the highlighting based on the hovered region
|
||||||
|
* @return Unique ID used to remove the highlighting again later
|
||||||
|
*/
|
||||||
u32 addForegroundHighlightingProvider(const impl::HighlightingFunction &function);
|
u32 addForegroundHighlightingProvider(const impl::HighlightingFunction &function);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes a foreground color highlighting from the Hex Editor
|
||||||
|
* @param id The ID of the highlighting to remove
|
||||||
|
*/
|
||||||
void removeForegroundHighlightingProvider(u32 id);
|
void removeForegroundHighlightingProvider(u32 id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if there's a valid selection in the Hex Editor right now
|
||||||
|
*/
|
||||||
bool isSelectionValid();
|
bool isSelectionValid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clears the current selection in the Hex Editor
|
||||||
|
*/
|
||||||
|
void clearSelection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current selection in the Hex Editor
|
||||||
|
* @return The current selection
|
||||||
|
*/
|
||||||
std::optional<ProviderRegion> getSelection();
|
std::optional<ProviderRegion> getSelection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the current selection in the Hex Editor
|
||||||
|
* @param region The region to select
|
||||||
|
* @param provider The provider to select the region in
|
||||||
|
*/
|
||||||
void setSelection(const Region ®ion, prv::Provider *provider = nullptr);
|
void setSelection(const Region ®ion, prv::Provider *provider = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the current selection in the Hex Editor
|
||||||
|
* @param region The region to select
|
||||||
|
*/
|
||||||
void setSelection(const ProviderRegion ®ion);
|
void setSelection(const ProviderRegion ®ion);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the current selection in the Hex Editor
|
||||||
|
* @param address The address to select
|
||||||
|
* @param size The size of the selection
|
||||||
|
* @param provider The provider to select the region in
|
||||||
|
*/
|
||||||
void setSelection(u64 address, size_t size, prv::Provider *provider = nullptr);
|
void setSelection(u64 address, size_t size, prv::Provider *provider = nullptr);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Functions to interact with Bookmarks */
|
||||||
namespace Bookmarks {
|
namespace Bookmarks {
|
||||||
|
|
||||||
struct Entry {
|
struct Entry {
|
||||||
@@ -123,10 +217,23 @@ namespace hex {
|
|||||||
bool locked;
|
bool locked;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a new bookmark
|
||||||
|
* @param address The address of the bookmark
|
||||||
|
* @param size The size of the bookmark
|
||||||
|
* @param name The name of the bookmark
|
||||||
|
* @param comment The comment of the bookmark
|
||||||
|
* @param color The color of the bookmark or 0x00 for the default color
|
||||||
|
*/
|
||||||
void add(u64 address, size_t size, const std::string &name, const std::string &comment, color_t color = 0x00000000);
|
void add(u64 address, size_t size, const std::string &name, const std::string &comment, color_t color = 0x00000000);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper methods about the providers
|
||||||
|
* @note the "current provider" or "currently selected provider" refers to the currently selected provider in the UI;
|
||||||
|
* the provider the user is actually editing.
|
||||||
|
*/
|
||||||
namespace Provider {
|
namespace Provider {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
@@ -136,30 +243,82 @@ namespace hex {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the currently selected data provider
|
||||||
|
* @return The currently selected data provider, or nullptr is there is none
|
||||||
|
*/
|
||||||
prv::Provider *get();
|
prv::Provider *get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets a list of all currently loaded data providers
|
||||||
|
* @return The currently loaded data providers
|
||||||
|
*/
|
||||||
const std::vector<prv::Provider *> &getProviders();
|
const std::vector<prv::Provider *> &getProviders();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the currently selected data provider
|
||||||
|
* @param index Index of the provider to select
|
||||||
|
*/
|
||||||
void setCurrentProvider(u32 index);
|
void setCurrentProvider(u32 index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks whether the currently selected data provider is valid
|
||||||
|
* @return Whether the currently selected data provider is valid
|
||||||
|
*/
|
||||||
bool isValid();
|
bool isValid();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Marks the **currently selected** data provider as dirty
|
||||||
|
*/
|
||||||
void markDirty();
|
void markDirty();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Marks **all data providers** as clean
|
||||||
|
*/
|
||||||
void resetDirty();
|
void resetDirty();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks whether **any of the data providers** is dirty
|
||||||
|
* @return Whether any data provider is dirty
|
||||||
|
*/
|
||||||
bool isDirty();
|
bool isDirty();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a newly created provider to the list of providers, and mark it as the selected one.
|
||||||
|
* @param provider The provider to add
|
||||||
|
* @param skipLoadInterface Whether to skip the provider's loading interface (see property documentation)
|
||||||
|
*/
|
||||||
void add(prv::Provider *provider, bool skipLoadInterface = false);
|
void add(prv::Provider *provider, bool skipLoadInterface = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a new provider and adds it to the list of providers
|
||||||
|
* @tparam T The type of the provider to create
|
||||||
|
* @param args Arguments to pass to the provider's constructor
|
||||||
|
*/
|
||||||
template<std::derived_from<prv::Provider> T>
|
template<std::derived_from<prv::Provider> T>
|
||||||
void add(auto &&...args) {
|
void add(auto &&...args) {
|
||||||
add(new T(std::forward<decltype(args)>(args)...));
|
add(new T(std::forward<decltype(args)>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes a provider from the list of providers
|
||||||
|
* @param provider The provider to remove
|
||||||
|
* @param noQuestions Whether to skip asking the user for confirmation
|
||||||
|
*/
|
||||||
void remove(prv::Provider *provider, bool noQuestions = false);
|
void remove(prv::Provider *provider, bool noQuestions = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a new provider using its unlocalized name and add it to the list of providers
|
||||||
|
* @param unlocalizedName The unlocalized name of the provider to create
|
||||||
|
* @param skipLoadInterface Whether to skip the provider's loading interface (see property documentation)
|
||||||
|
*/
|
||||||
prv::Provider* createProvider(const std::string &unlocalizedName, bool skipLoadInterface = false);
|
prv::Provider* createProvider(const std::string &unlocalizedName, bool skipLoadInterface = false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Functions to interact with various ImHex system settings */
|
||||||
namespace System {
|
namespace System {
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
@@ -175,7 +334,7 @@ namespace hex {
|
|||||||
|
|
||||||
void setBorderlessWindowMode(bool enabled);
|
void setBorderlessWindowMode(bool enabled);
|
||||||
|
|
||||||
void setCustomFontPath(const std::filesystem::path &path);
|
void setCustomFontPath(const std::fs::path &path);
|
||||||
void setFontSize(float size);
|
void setFontSize(float size);
|
||||||
|
|
||||||
void setGPUVendor(const std::string &vendor);
|
void setGPUVendor(const std::string &vendor);
|
||||||
@@ -203,37 +362,148 @@ namespace hex {
|
|||||||
Error
|
Error
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Closes ImHex
|
||||||
|
* @param noQuestions Whether to skip asking the user for confirmation
|
||||||
|
*/
|
||||||
|
void closeImHex(bool noQuestions = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Restarts ImHex
|
||||||
|
*/
|
||||||
|
void restartImHex();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the progress bar in the task bar
|
||||||
|
* @param state The state of the progress bar
|
||||||
|
* @param type The type of the progress bar progress
|
||||||
|
* @param progress The progress of the progress bar
|
||||||
|
*/
|
||||||
void setTaskBarProgress(TaskProgressState state, TaskProgressType type, u32 progress);
|
void setTaskBarProgress(TaskProgressState state, TaskProgressType type, u32 progress);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current program arguments
|
||||||
|
* @return The current program arguments
|
||||||
|
*/
|
||||||
const ProgramArguments &getProgramArguments();
|
const ProgramArguments &getProgramArguments();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets a program argument
|
||||||
|
* @param index The index of the argument to get
|
||||||
|
* @return The argument at the given index
|
||||||
|
*/
|
||||||
std::optional<std::u8string> getProgramArgument(int index);
|
std::optional<std::u8string> getProgramArgument(int index);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current target FPS
|
||||||
|
* @return The current target FPS
|
||||||
|
*/
|
||||||
float getTargetFPS();
|
float getTargetFPS();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the target FPS
|
||||||
|
* @param fps The target FPS
|
||||||
|
*/
|
||||||
void setTargetFPS(float fps);
|
void setTargetFPS(float fps);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current global scale
|
||||||
|
* @return The current global scale
|
||||||
|
*/
|
||||||
float getGlobalScale();
|
float getGlobalScale();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current native scale
|
||||||
|
* @return The current native scale
|
||||||
|
*/
|
||||||
float getNativeScale();
|
float getNativeScale();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current main window position
|
||||||
|
* @return Position of the main window
|
||||||
|
*/
|
||||||
ImVec2 getMainWindowPosition();
|
ImVec2 getMainWindowPosition();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current main window size
|
||||||
|
* @return Size of the main window
|
||||||
|
*/
|
||||||
ImVec2 getMainWindowSize();
|
ImVec2 getMainWindowSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current main dock space ID
|
||||||
|
* @return ID of the main dock space
|
||||||
|
*/
|
||||||
ImGuiID getMainDockSpaceId();
|
ImGuiID getMainDockSpaceId();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if borderless window mode is enabled currently
|
||||||
|
* @return Whether borderless window mode is enabled
|
||||||
|
*/
|
||||||
bool isBorderlessWindowModeEnabled();
|
bool isBorderlessWindowModeEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the init arguments passed to ImHex from the splash screen
|
||||||
|
* @return Init arguments
|
||||||
|
*/
|
||||||
std::map<std::string, std::string> &getInitArguments();
|
std::map<std::string, std::string> &getInitArguments();
|
||||||
|
|
||||||
constexpr static float DefaultFontSize = 13.0;
|
constexpr static float DefaultFontSize = 13.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current custom font path
|
||||||
|
* @return The current custom font path
|
||||||
|
*/
|
||||||
const std::filesystem::path &getCustomFontPath();
|
const std::filesystem::path &getCustomFontPath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current font size
|
||||||
|
* @return The current font size
|
||||||
|
*/
|
||||||
float getFontSize();
|
float getFontSize();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets if ImHex should follow the system theme
|
||||||
|
* @param enabled Whether to follow the system theme
|
||||||
|
*/
|
||||||
void enableSystemThemeDetection(bool enabled);
|
void enableSystemThemeDetection(bool enabled);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if ImHex follows the system theme
|
||||||
|
* @return Whether ImHex follows the system theme
|
||||||
|
*/
|
||||||
bool usesSystemThemeDetection();
|
bool usesSystemThemeDetection();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the currently set additional folder paths
|
||||||
|
* @return The currently set additional folder paths
|
||||||
|
*/
|
||||||
const std::vector<std::filesystem::path> &getAdditionalFolderPaths();
|
const std::vector<std::filesystem::path> &getAdditionalFolderPaths();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the additional folder paths
|
||||||
|
* @param paths The additional folder paths
|
||||||
|
*/
|
||||||
void setAdditionalFolderPaths(const std::vector<std::filesystem::path> &paths);
|
void setAdditionalFolderPaths(const std::vector<std::filesystem::path> &paths);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the current GPU vendor
|
||||||
|
* @return The current GPU vendor
|
||||||
|
*/
|
||||||
const std::string &getGPUVendor();
|
const std::string &getGPUVendor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if ImHex is running in portable mode
|
||||||
|
* @return Whether ImHex is running in portable mode
|
||||||
|
*/
|
||||||
bool isPortableVersion();
|
bool isPortableVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
struct ImGuiWindow;
|
struct ImGuiWindow;
|
||||||
|
|
||||||
@@ -136,15 +138,31 @@ namespace hex {
|
|||||||
|
|
||||||
auto operator<=>(const Key &) const = default;
|
auto operator<=>(const Key &) const = default;
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr u32 getKeyCode() const { return this->m_key; }
|
||||||
private:
|
private:
|
||||||
u32 m_key;
|
u32 m_key;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
constexpr static auto CTRL = Key(static_cast<Keys>(0x0100'0000));
|
||||||
|
constexpr static auto ALT = Key(static_cast<Keys>(0x0200'0000));
|
||||||
|
constexpr static auto SHIFT = Key(static_cast<Keys>(0x0400'0000));
|
||||||
|
constexpr static auto SUPER = Key(static_cast<Keys>(0x0800'0000));
|
||||||
|
constexpr static auto CurrentView = Key(static_cast<Keys>(0x1000'0000));
|
||||||
|
|
||||||
|
#if defined (OS_MACOS)
|
||||||
|
constexpr static auto CTRLCMD = SUPER;
|
||||||
|
#else
|
||||||
|
constexpr static auto CTRLCMD = CTRL;
|
||||||
|
#endif
|
||||||
|
|
||||||
class Shortcut {
|
class Shortcut {
|
||||||
public:
|
public:
|
||||||
Shortcut() = default;
|
Shortcut() = default;
|
||||||
Shortcut(Keys key) : m_keys({ key }) { }
|
Shortcut(Keys key) : m_keys({ key }) { }
|
||||||
|
|
||||||
|
const static inline auto None = Keys(0);
|
||||||
|
|
||||||
Shortcut operator+(const Key &other) const {
|
Shortcut operator+(const Key &other) const {
|
||||||
Shortcut result = *this;
|
Shortcut result = *this;
|
||||||
result.m_keys.insert(other);
|
result.m_keys.insert(other);
|
||||||
@@ -166,6 +184,173 @@ namespace hex {
|
|||||||
return this->m_keys == other.m_keys;
|
return this->m_keys == other.m_keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isLocal() const {
|
||||||
|
return this->m_keys.contains(CurrentView);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string toString() const {
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
#if defined(OS_MACOS)
|
||||||
|
constexpr static auto CTRL_NAME = "CTRL";
|
||||||
|
constexpr static auto ALT_NAME = "OPT";
|
||||||
|
constexpr static auto SHIFT_NAME = "SHIFT";
|
||||||
|
constexpr static auto SUPER_NAME = "CMD";
|
||||||
|
#else
|
||||||
|
constexpr static auto CTRL_NAME = "CTRL";
|
||||||
|
constexpr static auto ALT_NAME = "ALT";
|
||||||
|
constexpr static auto SHIFT_NAME = "SHIFT";
|
||||||
|
constexpr static auto SUPER_NAME = "SUPER";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
constexpr static auto Concatination = " + ";
|
||||||
|
|
||||||
|
auto keys = this->m_keys;
|
||||||
|
if (keys.erase(CTRL) > 0) {
|
||||||
|
result += CTRL_NAME;
|
||||||
|
result += Concatination;
|
||||||
|
}
|
||||||
|
if (keys.erase(ALT) > 0) {
|
||||||
|
result += ALT_NAME;
|
||||||
|
result += Concatination;
|
||||||
|
}
|
||||||
|
if (keys.erase(SHIFT) > 0) {
|
||||||
|
result += SHIFT_NAME;
|
||||||
|
result += Concatination;
|
||||||
|
}
|
||||||
|
if (keys.erase(SUPER) > 0) {
|
||||||
|
result += SUPER_NAME;
|
||||||
|
result += Concatination;
|
||||||
|
}
|
||||||
|
keys.erase(CurrentView);
|
||||||
|
|
||||||
|
for (const auto &key : keys) {
|
||||||
|
switch (Keys(key.getKeyCode())) {
|
||||||
|
case Keys::Space: result += "SPACE"; break;
|
||||||
|
case Keys::Apostrophe: result += "'"; break;
|
||||||
|
case Keys::Comma: result += ","; break;
|
||||||
|
case Keys::Minus: result += "-"; break;
|
||||||
|
case Keys::Period: result += "."; break;
|
||||||
|
case Keys::Slash: result += "/"; break;
|
||||||
|
case Keys::Num0: result += "0"; break;
|
||||||
|
case Keys::Num1: result += "1"; break;
|
||||||
|
case Keys::Num2: result += "2"; break;
|
||||||
|
case Keys::Num3: result += "3"; break;
|
||||||
|
case Keys::Num4: result += "4"; break;
|
||||||
|
case Keys::Num5: result += "5"; break;
|
||||||
|
case Keys::Num6: result += "6"; break;
|
||||||
|
case Keys::Num7: result += "7"; break;
|
||||||
|
case Keys::Num8: result += "8"; break;
|
||||||
|
case Keys::Num9: result += "9"; break;
|
||||||
|
case Keys::Semicolon: result += ";"; break;
|
||||||
|
case Keys::Equals: result += "="; break;
|
||||||
|
case Keys::A: result += "A"; break;
|
||||||
|
case Keys::B: result += "B"; break;
|
||||||
|
case Keys::C: result += "C"; break;
|
||||||
|
case Keys::D: result += "D"; break;
|
||||||
|
case Keys::E: result += "E"; break;
|
||||||
|
case Keys::F: result += "F"; break;
|
||||||
|
case Keys::G: result += "G"; break;
|
||||||
|
case Keys::H: result += "H"; break;
|
||||||
|
case Keys::I: result += "I"; break;
|
||||||
|
case Keys::J: result += "J"; break;
|
||||||
|
case Keys::K: result += "K"; break;
|
||||||
|
case Keys::L: result += "L"; break;
|
||||||
|
case Keys::M: result += "M"; break;
|
||||||
|
case Keys::N: result += "N"; break;
|
||||||
|
case Keys::O: result += "O"; break;
|
||||||
|
case Keys::P: result += "P"; break;
|
||||||
|
case Keys::Q: result += "Q"; break;
|
||||||
|
case Keys::R: result += "R"; break;
|
||||||
|
case Keys::S: result += "S"; break;
|
||||||
|
case Keys::T: result += "T"; break;
|
||||||
|
case Keys::U: result += "U"; break;
|
||||||
|
case Keys::V: result += "V"; break;
|
||||||
|
case Keys::W: result += "W"; break;
|
||||||
|
case Keys::X: result += "X"; break;
|
||||||
|
case Keys::Y: result += "Y"; break;
|
||||||
|
case Keys::Z: result += "Z"; break;
|
||||||
|
case Keys::LeftBracket: result += "["; break;
|
||||||
|
case Keys::Backslash: result += "\\"; break;
|
||||||
|
case Keys::RightBracket: result += "]"; break;
|
||||||
|
case Keys::GraveAccent: result += "`"; break;
|
||||||
|
case Keys::World1: result += "WORLD1"; break;
|
||||||
|
case Keys::World2: result += "WORLD2"; break;
|
||||||
|
case Keys::Escape: result += "ESC"; break;
|
||||||
|
case Keys::Enter: result += "ENTER"; break;
|
||||||
|
case Keys::Tab: result += "TAB"; break;
|
||||||
|
case Keys::Backspace: result += "BACKSPACE"; break;
|
||||||
|
case Keys::Insert: result += "INSERT"; break;
|
||||||
|
case Keys::Delete: result += "DELETE"; break;
|
||||||
|
case Keys::Right: result += "RIGHT"; break;
|
||||||
|
case Keys::Left: result += "LEFT"; break;
|
||||||
|
case Keys::Down: result += "DOWN"; break;
|
||||||
|
case Keys::Up: result += "UP"; break;
|
||||||
|
case Keys::PageUp: result += "PAGEUP"; break;
|
||||||
|
case Keys::PageDown: result += "PAGEDOWN"; break;
|
||||||
|
case Keys::Home: result += "HOME"; break;
|
||||||
|
case Keys::End: result += "END"; break;
|
||||||
|
case Keys::CapsLock: result += "CAPSLOCK"; break;
|
||||||
|
case Keys::ScrollLock: result += "SCROLLLOCK"; break;
|
||||||
|
case Keys::NumLock: result += "NUMLOCK"; break;
|
||||||
|
case Keys::PrintScreen: result += "PRINTSCREEN"; break;
|
||||||
|
case Keys::Pause: result += "PAUSE"; break;
|
||||||
|
case Keys::F1: result += "F1"; break;
|
||||||
|
case Keys::F2: result += "F2"; break;
|
||||||
|
case Keys::F3: result += "F3"; break;
|
||||||
|
case Keys::F4: result += "F4"; break;
|
||||||
|
case Keys::F5: result += "F5"; break;
|
||||||
|
case Keys::F6: result += "F6"; break;
|
||||||
|
case Keys::F7: result += "F7"; break;
|
||||||
|
case Keys::F8: result += "F8"; break;
|
||||||
|
case Keys::F9: result += "F9"; break;
|
||||||
|
case Keys::F10: result += "F10"; break;
|
||||||
|
case Keys::F11: result += "F11"; break;
|
||||||
|
case Keys::F12: result += "F12"; break;
|
||||||
|
case Keys::F13: result += "F13"; break;
|
||||||
|
case Keys::F14: result += "F14"; break;
|
||||||
|
case Keys::F15: result += "F15"; break;
|
||||||
|
case Keys::F16: result += "F16"; break;
|
||||||
|
case Keys::F17: result += "F17"; break;
|
||||||
|
case Keys::F18: result += "F18"; break;
|
||||||
|
case Keys::F19: result += "F19"; break;
|
||||||
|
case Keys::F20: result += "F20"; break;
|
||||||
|
case Keys::F21: result += "F21"; break;
|
||||||
|
case Keys::F22: result += "F22"; break;
|
||||||
|
case Keys::F23: result += "F23"; break;
|
||||||
|
case Keys::F24: result += "F24"; break;
|
||||||
|
case Keys::F25: result += "F25"; break;
|
||||||
|
case Keys::KeyPad0: result += "KP0"; break;
|
||||||
|
case Keys::KeyPad1: result += "KP1"; break;
|
||||||
|
case Keys::KeyPad2: result += "KP2"; break;
|
||||||
|
case Keys::KeyPad3: result += "KP3"; break;
|
||||||
|
case Keys::KeyPad4: result += "KP4"; break;
|
||||||
|
case Keys::KeyPad5: result += "KP5"; break;
|
||||||
|
case Keys::KeyPad6: result += "KP6"; break;
|
||||||
|
case Keys::KeyPad7: result += "KP7"; break;
|
||||||
|
case Keys::KeyPad8: result += "KP8"; break;
|
||||||
|
case Keys::KeyPad9: result += "KP9"; break;
|
||||||
|
case Keys::KeyPadDecimal: result += "KPDECIMAL"; break;
|
||||||
|
case Keys::KeyPadDivide: result += "KPDIVIDE"; break;
|
||||||
|
case Keys::KeyPadMultiply: result += "KPMULTIPLY"; break;
|
||||||
|
case Keys::KeyPadSubtract: result += "KPSUBTRACT"; break;
|
||||||
|
case Keys::KeyPadAdd: result += "KPADD"; break;
|
||||||
|
case Keys::KeyPadEnter: result += "KPENTER"; break;
|
||||||
|
case Keys::KeyPadEqual: result += "KPEQUAL"; break;
|
||||||
|
case Keys::Menu: result += "MENU"; break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result += " + ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.ends_with(" + "))
|
||||||
|
result = result.substr(0, result.size() - 3);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend Shortcut operator+(const Key &lhs, const Key &rhs);
|
friend Shortcut operator+(const Key &lhs, const Key &rhs);
|
||||||
|
|
||||||
@@ -179,37 +364,54 @@ namespace hex {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static auto CTRL = Key(static_cast<Keys>(0x1000'0000));
|
/**
|
||||||
constexpr static auto ALT = Key(static_cast<Keys>(0x2000'0000));
|
* @brief The ShortcutManager handles global and view-specific shortcuts.
|
||||||
constexpr static auto SHIFT = Key(static_cast<Keys>(0x4000'0000));
|
* New shortcuts can be constructed using the + operator on Key objects. For example: CTRL + ALT + Keys::A
|
||||||
constexpr static auto SUPER = Key(static_cast<Keys>(0x8000'0000));
|
*/
|
||||||
|
|
||||||
#if defined(OS_MACOS)
|
|
||||||
constexpr static auto CTRLCMD = SUPER;
|
|
||||||
|
|
||||||
constexpr static auto CTRL_NAME = "CTRL";
|
|
||||||
constexpr static auto ALT_NAME = "OPT";
|
|
||||||
constexpr static auto SHIFT_NAME = "SHIFT";
|
|
||||||
constexpr static auto SUPER_NAME = "CMD";
|
|
||||||
constexpr static auto CTRLCMD_NAME = SUPER_NAME;
|
|
||||||
#else
|
|
||||||
constexpr static auto CTRLCMD = CTRL;
|
|
||||||
|
|
||||||
constexpr static auto CTRL_NAME = "CTRL";
|
|
||||||
constexpr static auto ALT_NAME = "ALT";
|
|
||||||
constexpr static auto SHIFT_NAME = "SHIFT";
|
|
||||||
constexpr static auto SUPER_NAME = "SUPER";
|
|
||||||
constexpr static auto CTRLCMD_NAME = CTRL_NAME;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class ShortcutManager {
|
class ShortcutManager {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add a global shortcut. Global shortcuts can be triggered regardless of what view is currently focused
|
||||||
|
* @param shortcut The shortcut to add.
|
||||||
|
* @param callback The callback to call when the shortcut is triggered.
|
||||||
|
*/
|
||||||
static void addGlobalShortcut(const Shortcut &shortcut, const std::function<void()> &callback);
|
static void addGlobalShortcut(const Shortcut &shortcut, const std::function<void()> &callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add a view-specific shortcut. View-specific shortcuts can only be triggered when the specified view is focused.
|
||||||
|
* @param view The view to add the shortcut to.
|
||||||
|
* @param shortcut The shortcut to add.
|
||||||
|
* @param callback The callback to call when the shortcut is triggered.
|
||||||
|
*/
|
||||||
static void addShortcut(View *view, const Shortcut &shortcut, const std::function<void()> &callback);
|
static void addShortcut(View *view, const Shortcut &shortcut, const std::function<void()> &callback);
|
||||||
|
|
||||||
static void process(View *currentView, bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode);
|
|
||||||
|
/**
|
||||||
|
* @brief Process a key event. This should be called from the main loop.
|
||||||
|
* @param currentView Current view to process
|
||||||
|
* @param ctrl Whether the CTRL key is pressed
|
||||||
|
* @param alt Whether the ALT key is pressed
|
||||||
|
* @param shift Whether the SHIFT key is pressed
|
||||||
|
* @param super Whether the SUPER key is pressed
|
||||||
|
* @param focused Whether the current view is focused
|
||||||
|
* @param keyCode The key code of the key that was pressed
|
||||||
|
*/
|
||||||
|
static void process(const std::unique_ptr<View> ¤tView, bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Process a key event. This should be called from the main loop.
|
||||||
|
* @param ctrl Whether the CTRL key is pressed
|
||||||
|
* @param alt Whether the ALT key is pressed
|
||||||
|
* @param shift Whether the SHIFT key is pressed
|
||||||
|
* @param super Whether the SUPER key is pressed
|
||||||
|
* @param keyCode The key code of the key that was pressed
|
||||||
|
*/
|
||||||
static void processGlobals(bool ctrl, bool alt, bool shift, bool super, u32 keyCode);
|
static void processGlobals(bool ctrl, bool alt, bool shift, bool super, u32 keyCode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear all shortcuts
|
||||||
|
*/
|
||||||
static void clearShortcuts();
|
static void clearShortcuts();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
39
lib/libimhex/include/hex/api/layout_manager.hpp
Normal file
39
lib/libimhex/include/hex/api/layout_manager.hpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hex.hpp>
|
||||||
|
#include <hex/helpers/fs.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
#include <nlohmann/json_fwd.hpp>
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
namespace hex {
|
||||||
|
|
||||||
|
class LayoutManager {
|
||||||
|
public:
|
||||||
|
struct Layout {
|
||||||
|
std::string name;
|
||||||
|
std::fs::path path;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void save(const std::string &name);
|
||||||
|
static void load(const std::fs::path &path);
|
||||||
|
static void loadString(const std::string &content);
|
||||||
|
|
||||||
|
static std::vector<Layout> getLayouts();
|
||||||
|
|
||||||
|
static void process();
|
||||||
|
static void reload();
|
||||||
|
static void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
LayoutManager() = default;
|
||||||
|
|
||||||
|
static std::optional<std::fs::path> s_layoutPathToLoad;
|
||||||
|
static std::optional<std::string> s_layoutStringToLoad;
|
||||||
|
static std::vector<Layout> s_layouts;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
class LanguageDefinition {
|
class LanguageDefinition {
|
||||||
@@ -57,3 +59,11 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct fmt::formatter<hex::LangEntry> : fmt::formatter<std::string_view> {
|
||||||
|
template<typename FormatContext>
|
||||||
|
auto format(const hex::LangEntry &entry, FormatContext &ctx) {
|
||||||
|
return fmt::formatter<std::string_view>::format(entry, ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -14,42 +14,104 @@
|
|||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Project file manager
|
||||||
|
*
|
||||||
|
* The project file manager is used to load and store project files. It is used by all features of ImHex
|
||||||
|
* that want to store any data to a Project File.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class ProjectFile {
|
class ProjectFile {
|
||||||
public:
|
public:
|
||||||
struct Handler {
|
struct Handler {
|
||||||
using Function = std::function<bool(const std::fs::path &, Tar &tar)>;
|
using Function = std::function<bool(const std::fs::path &, Tar &tar)>;
|
||||||
std::fs::path basePath;
|
|
||||||
bool required;
|
std::fs::path basePath; //< Base path for where to store the files in the project file
|
||||||
Function load, store;
|
bool required; //< If true, ImHex will display an error if this handler fails to load or store data
|
||||||
|
Function load, store; //< Functions to load and store data
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ProviderHandler {
|
struct ProviderHandler {
|
||||||
using Function = std::function<bool(prv::Provider *provider, const std::fs::path &, Tar &tar)>;
|
using Function = std::function<bool(prv::Provider *provider, const std::fs::path &, Tar &tar)>;
|
||||||
std::fs::path basePath;
|
|
||||||
bool required;
|
std::fs::path basePath; //< Base path for where to store the files in the project file
|
||||||
Function load, store;
|
bool required; //< If true, ImHex will display an error if this handler fails to load or store data
|
||||||
|
Function load, store; //< Functions to load and store data
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Load a project file
|
||||||
|
*
|
||||||
|
* @param filePath Path to the project file
|
||||||
|
* @return true if the project file was loaded successfully
|
||||||
|
* @return false if the project file was not loaded successfully
|
||||||
|
*/
|
||||||
static bool load(const std::fs::path &filePath);
|
static bool load(const std::fs::path &filePath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Store a project file
|
||||||
|
*
|
||||||
|
* @param filePath Path to the project file
|
||||||
|
* @return true if the project file was stored successfully
|
||||||
|
* @return false if the project file was not stored successfully
|
||||||
|
*/
|
||||||
static bool store(std::optional<std::fs::path> filePath = std::nullopt);
|
static bool store(std::optional<std::fs::path> filePath = std::nullopt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if a project file is currently loaded
|
||||||
|
*
|
||||||
|
* @return true if a project file is currently loaded
|
||||||
|
* @return false if no project file is currently loaded
|
||||||
|
*/
|
||||||
static bool hasPath();
|
static bool hasPath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clear the currently loaded project file
|
||||||
|
*/
|
||||||
static void clearPath();
|
static void clearPath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the path to the currently loaded project file
|
||||||
|
* @return Path to the currently loaded project file
|
||||||
|
*/
|
||||||
static std::fs::path getPath();
|
static std::fs::path getPath();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the path to the currently loaded project file
|
||||||
|
* @param path Path to the currently loaded project file
|
||||||
|
*/
|
||||||
static void setPath(const std::fs::path &path);
|
static void setPath(const std::fs::path &path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register a handler for storing and loading global data from a project file
|
||||||
|
*
|
||||||
|
* @param handler The handler to register
|
||||||
|
*/
|
||||||
static void registerHandler(const Handler &handler) {
|
static void registerHandler(const Handler &handler) {
|
||||||
getHandlers().push_back(handler);
|
getHandlers().push_back(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Register a handler for storing and loading per-provider data from a project file
|
||||||
|
*
|
||||||
|
* @param handler The handler to register
|
||||||
|
*/
|
||||||
static void registerPerProviderHandler(const ProviderHandler &handler) {
|
static void registerPerProviderHandler(const ProviderHandler &handler) {
|
||||||
getProviderHandlers().push_back(handler);
|
getProviderHandlers().push_back(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the list of registered handlers
|
||||||
|
* @return List of registered handlers
|
||||||
|
*/
|
||||||
static std::vector<Handler>& getHandlers() {
|
static std::vector<Handler>& getHandlers() {
|
||||||
return s_handlers;
|
return s_handlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the list of registered per-provider handlers
|
||||||
|
* @return List of registered per-provider handlers
|
||||||
|
*/
|
||||||
static std::vector<ProviderHandler>& getProviderHandlers() {
|
static std::vector<ProviderHandler>& getProviderHandlers() {
|
||||||
return s_providerHandlers;
|
return s_providerHandlers;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ namespace hex {
|
|||||||
class TaskHolder;
|
class TaskHolder;
|
||||||
class TaskManager;
|
class TaskManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A type representing a running asynchronous task
|
||||||
|
*/
|
||||||
class Task {
|
class Task {
|
||||||
public:
|
public:
|
||||||
Task() = default;
|
Task() = default;
|
||||||
@@ -26,14 +29,38 @@ namespace hex {
|
|||||||
Task(Task &&other) noexcept;
|
Task(Task &&other) noexcept;
|
||||||
~Task();
|
~Task();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Updates the current process value of the task
|
||||||
|
* @param value Current value
|
||||||
|
*/
|
||||||
void update(u64 value = 0);
|
void update(u64 value = 0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the maximum value of the task
|
||||||
|
* @param value Maximum value of the task
|
||||||
|
*/
|
||||||
void setMaxValue(u64 value);
|
void setMaxValue(u64 value);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Interrupts the task
|
||||||
|
* For regular Tasks, this just throws an exception to stop the task.
|
||||||
|
* If a custom interrupt callback is set, an exception is thrown and the callback is called.
|
||||||
|
*/
|
||||||
|
void interrupt();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets a callback that is called when the task is interrupted
|
||||||
|
* @param callback Callback to be called
|
||||||
|
*/
|
||||||
|
void setInterruptCallback(std::function<void()> callback);
|
||||||
|
|
||||||
[[nodiscard]] bool isBackgroundTask() const;
|
[[nodiscard]] bool isBackgroundTask() const;
|
||||||
[[nodiscard]] bool isFinished() const;
|
[[nodiscard]] bool isFinished() const;
|
||||||
[[nodiscard]] bool hadException() const;
|
[[nodiscard]] bool hadException() const;
|
||||||
[[nodiscard]] bool wasInterrupted() const;
|
[[nodiscard]] bool wasInterrupted() const;
|
||||||
[[nodiscard]] bool shouldInterrupt() const;
|
[[nodiscard]] bool shouldInterrupt() const;
|
||||||
|
|
||||||
void clearException();
|
void clearException();
|
||||||
[[nodiscard]] std::string getExceptionMessage() const;
|
[[nodiscard]] std::string getExceptionMessage() const;
|
||||||
|
|
||||||
@@ -41,10 +68,6 @@ namespace hex {
|
|||||||
[[nodiscard]] u64 getValue() const;
|
[[nodiscard]] u64 getValue() const;
|
||||||
[[nodiscard]] u64 getMaxValue() const;
|
[[nodiscard]] u64 getMaxValue() const;
|
||||||
|
|
||||||
void interrupt();
|
|
||||||
|
|
||||||
void setInterruptCallback(std::function<void()> callback);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void finish();
|
void finish();
|
||||||
void interruption();
|
void interruption();
|
||||||
@@ -72,6 +95,9 @@ namespace hex {
|
|||||||
friend class TaskManager;
|
friend class TaskManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A type holding a weak reference to a Task
|
||||||
|
*/
|
||||||
class TaskHolder {
|
class TaskHolder {
|
||||||
public:
|
public:
|
||||||
TaskHolder() = default;
|
TaskHolder() = default;
|
||||||
@@ -82,11 +108,16 @@ namespace hex {
|
|||||||
[[nodiscard]] bool wasInterrupted() const;
|
[[nodiscard]] bool wasInterrupted() const;
|
||||||
[[nodiscard]] bool shouldInterrupt() const;
|
[[nodiscard]] bool shouldInterrupt() const;
|
||||||
|
|
||||||
|
[[nodiscard]] u32 getProgress() const;
|
||||||
|
|
||||||
void interrupt();
|
void interrupt();
|
||||||
private:
|
private:
|
||||||
std::weak_ptr<Task> m_task;
|
std::weak_ptr<Task> m_task;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Task Manager is responsible for running and managing asynchronous tasks
|
||||||
|
*/
|
||||||
class TaskManager {
|
class TaskManager {
|
||||||
public:
|
public:
|
||||||
TaskManager() = delete;
|
TaskManager() = delete;
|
||||||
@@ -96,19 +127,45 @@ namespace hex {
|
|||||||
|
|
||||||
constexpr static auto NoProgress = 0;
|
constexpr static auto NoProgress = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a new asynchronous task that gets displayed in the Task Manager in the footer
|
||||||
|
* @param name Name of the task
|
||||||
|
* @param maxValue Maximum value of the task
|
||||||
|
* @param function Function to be executed
|
||||||
|
* @return A TaskHolder holding a weak reference to the task
|
||||||
|
*/
|
||||||
static TaskHolder createTask(std::string name, u64 maxValue, std::function<void(Task &)> function);
|
static TaskHolder createTask(std::string name, u64 maxValue, std::function<void(Task &)> function);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a new asynchronous task that does not get displayed in the Task Manager
|
||||||
|
* @param name Name of the task
|
||||||
|
* @param function Function to be executed
|
||||||
|
* @return A TaskHolder holding a weak reference to the task
|
||||||
|
*/
|
||||||
static TaskHolder createBackgroundTask(std::string name, std::function<void(Task &)> function);
|
static TaskHolder createBackgroundTask(std::string name, std::function<void(Task &)> function);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a new synchronous task that will execute the given function at the start of the next frame
|
||||||
|
* @param function Function to be executed
|
||||||
|
*/
|
||||||
|
static void doLater(const std::function<void()> &function);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a callback that will be executed when all tasks are finished
|
||||||
|
* @param function Function to be executed
|
||||||
|
*/
|
||||||
|
static void runWhenTasksFinished(const std::function<void()> &function);
|
||||||
|
|
||||||
|
|
||||||
static void collectGarbage();
|
static void collectGarbage();
|
||||||
|
|
||||||
static size_t getRunningTaskCount();
|
static size_t getRunningTaskCount();
|
||||||
static size_t getRunningBackgroundTaskCount();
|
static size_t getRunningBackgroundTaskCount();
|
||||||
static std::list<std::shared_ptr<Task>> &getRunningTasks();
|
|
||||||
|
|
||||||
static void doLater(const std::function<void()> &function);
|
static std::list<std::shared_ptr<Task>> &getRunningTasks();
|
||||||
static void runDeferredCalls();
|
static void runDeferredCalls();
|
||||||
|
|
||||||
static void runWhenTasksFinished(const std::function<void()> &function);
|
|
||||||
private:
|
private:
|
||||||
static std::mutex s_deferredCallsMutex, s_tasksFinishedMutex;
|
static std::mutex s_deferredCallsMutex, s_tasksFinishedMutex;
|
||||||
|
|
||||||
|
|||||||
@@ -4,34 +4,92 @@
|
|||||||
#include <hex/helpers/fs.hpp>
|
#include <hex/helpers/fs.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
#include <nlohmann/json_fwd.hpp>
|
#include <nlohmann/json_fwd.hpp>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
namespace hex::api {
|
namespace hex {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The Theme Manager takes care of loading and applying themes
|
||||||
|
*/
|
||||||
class ThemeManager {
|
class ThemeManager {
|
||||||
public:
|
public:
|
||||||
constexpr static auto NativeTheme = "Native";
|
constexpr static auto NativeTheme = "Native";
|
||||||
|
|
||||||
|
using ColorMap = std::map<std::string, u32>;
|
||||||
|
|
||||||
|
struct Style {
|
||||||
|
std::variant<ImVec2*, float*> value;
|
||||||
|
float min;
|
||||||
|
float max;
|
||||||
|
bool needsScaling;
|
||||||
|
};
|
||||||
|
using StyleMap = std::map<std::string, Style>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Changes the current theme to the one with the given name
|
||||||
|
* @param name Name of the theme to change to
|
||||||
|
*/
|
||||||
static void changeTheme(std::string name);
|
static void changeTheme(std::string name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a theme from json data
|
||||||
|
* @param content JSON data of the theme
|
||||||
|
*/
|
||||||
static void addTheme(const std::string &content);
|
static void addTheme(const std::string &content);
|
||||||
static void addThemeHandler(const std::string &name, const std::function<void(std::string, std::string)> &handler);
|
|
||||||
static void addStyleHandler(const std::string &name, const std::function<void(std::string, std::string)> &handler);
|
/**
|
||||||
|
* @brief Adds a theme handler to handle color values loaded from a theme file
|
||||||
|
* @param name Name of the handler
|
||||||
|
* @param colorMap Map of color names to their respective constants
|
||||||
|
* @param getFunction Function to get the color value of a constant
|
||||||
|
* @param setFunction Function to set the color value of a constant
|
||||||
|
*/
|
||||||
|
static void addThemeHandler(const std::string &name, const ColorMap &colorMap, const std::function<ImColor(u32)> &getFunction, const std::function<void(u32, ImColor)> &setFunction);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a style handler to handle style values loaded from a theme file
|
||||||
|
* @param name Name of the handler
|
||||||
|
* @param styleMap Map of style names to their respective constants
|
||||||
|
*/
|
||||||
|
static void addStyleHandler(const std::string &name, const StyleMap &styleMap);
|
||||||
|
|
||||||
|
|
||||||
static std::vector<std::string> getThemeNames();
|
static std::vector<std::string> getThemeNames();
|
||||||
static const std::string &getThemeImagePostfix();
|
static const std::string &getThemeImagePostfix();
|
||||||
|
|
||||||
static std::optional<ImColor> parseColorString(const std::string &colorString);
|
static std::optional<ImColor> parseColorString(const std::string &colorString);
|
||||||
|
|
||||||
|
static nlohmann::json exportCurrentTheme(const std::string &name);
|
||||||
|
|
||||||
static void reset();
|
static void reset();
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct ThemeHandler {
|
||||||
|
ColorMap colorMap;
|
||||||
|
std::function<ImColor(u32)> getFunction;
|
||||||
|
std::function<void(u32, ImColor)> setFunction;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StyleHandler {
|
||||||
|
StyleMap styleMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::map<std::string, ThemeHandler>& getThemeHandlers() { return s_themeHandlers; }
|
||||||
|
static std::map<std::string, StyleHandler>& getStyleHandlers() { return s_styleHandlers; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ThemeManager() = default;
|
ThemeManager() = default;
|
||||||
|
|
||||||
|
|
||||||
static std::map<std::string, nlohmann::json> s_themes;
|
static std::map<std::string, nlohmann::json> s_themes;
|
||||||
static std::map<std::string, std::function<void(std::string, std::string)>> s_themeHandlers, s_styleHandlers;
|
static std::map<std::string, ThemeHandler> s_themeHandlers;
|
||||||
|
static std::map<std::string, StyleHandler> s_styleHandlers;
|
||||||
static std::string s_imagePostfix;
|
static std::string s_imagePostfix;
|
||||||
|
static std::string s_currTheme;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
2
lib/libimhex/include/hex/api_urls.hpp
Normal file
2
lib/libimhex/include/hex/api_urls.hpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
constexpr static const auto ImHexApiURL = "https://api.werwolv.net/imhex";
|
||||||
|
constexpr static const auto GitHubApiURL = "https://api.github.com/repos/WerWolv/ImHex";
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <hex/data_processor/attribute.hpp>
|
#include <hex/data_processor/attribute.hpp>
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <span>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ namespace hex::dp {
|
|||||||
const i128& getIntegerOnInput(u32 index);
|
const i128& getIntegerOnInput(u32 index);
|
||||||
const long double& getFloatOnInput(u32 index);
|
const long double& getFloatOnInput(u32 index);
|
||||||
|
|
||||||
void setBufferOnOutput(u32 index, const std::vector<u8> &data);
|
void setBufferOnOutput(u32 index, std::span<const u8> data);
|
||||||
void setIntegerOnOutput(u32 index, i128 integer);
|
void setIntegerOnOutput(u32 index, i128 integer);
|
||||||
void setFloatOnOutput(u32 index, long double floatingPoint);
|
void setFloatOnOutput(u32 index, long double floatingPoint);
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace hex {
|
|||||||
concept has_size = sizeof(T) == Size;
|
concept has_size = sizeof(T) == Size;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class Cloneable {
|
class ICloneable {
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] virtual std::unique_ptr<T> clone() const = 0;
|
[[nodiscard]] virtual std::unique_ptr<T> clone() const = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,25 +8,28 @@ namespace hex {
|
|||||||
|
|
||||||
enum class Architecture : i32
|
enum class Architecture : i32
|
||||||
{
|
{
|
||||||
ARM,
|
ARM = CS_ARCH_ARM,
|
||||||
ARM64,
|
ARM64 = CS_ARCH_ARM64,
|
||||||
MIPS,
|
MIPS = CS_ARCH_MIPS,
|
||||||
X86,
|
X86 = CS_ARCH_X86,
|
||||||
PPC,
|
PPC = CS_ARCH_PPC,
|
||||||
SPARC,
|
SPARC = CS_ARCH_SPARC,
|
||||||
SYSZ,
|
SYSZ = CS_ARCH_SYSZ,
|
||||||
XCORE,
|
XCORE = CS_ARCH_XCORE,
|
||||||
M68K,
|
M68K = CS_ARCH_M68K,
|
||||||
TMS320C64X,
|
TMS320C64X = CS_ARCH_TMS320C64X,
|
||||||
M680X,
|
M680X = CS_ARCH_M680X,
|
||||||
EVM,
|
EVM = CS_ARCH_EVM,
|
||||||
MOS65XX,
|
|
||||||
WASM,
|
|
||||||
BPF,
|
|
||||||
RISCV,
|
|
||||||
|
|
||||||
MAX,
|
#if CS_API_MAJOR >= 5
|
||||||
MIN = ARM
|
WASM = CS_ARCH_WASM,
|
||||||
|
RISCV = CS_ARCH_RISCV,
|
||||||
|
MOS65XX = CS_ARCH_MOS65XX,
|
||||||
|
BPF = CS_ARCH_BPF,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MAX = CS_ARCH_MAX,
|
||||||
|
MIN = ARM
|
||||||
};
|
};
|
||||||
|
|
||||||
class Disassembler {
|
class Disassembler {
|
||||||
@@ -39,7 +42,31 @@ namespace hex {
|
|||||||
return cs_support(toCapstoneArchitecture(architecture));
|
return cs_support(toCapstoneArchitecture(architecture));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static const char *const ArchitectureNames[] = { "ARM32", "ARM64", "MIPS", "x86", "PowerPC", "Sparc", "SystemZ", "XCore", "68K", "TMS320C64x", "680X", "Ethereum", "MOS65XX", "WebAssembly", "Berkeley Packet Filter", "RISC-V" };
|
constexpr static auto ArchitectureNames = [](){
|
||||||
|
std::array<const char *, static_cast<u32>(Architecture::MAX)> names = { };
|
||||||
|
|
||||||
|
names[CS_ARCH_ARM] = "ARM";
|
||||||
|
names[CS_ARCH_ARM64] = "AArch64";
|
||||||
|
names[CS_ARCH_MIPS] = "MIPS";
|
||||||
|
names[CS_ARCH_X86] = "Intel x86";
|
||||||
|
names[CS_ARCH_PPC] = "PowerPC";
|
||||||
|
names[CS_ARCH_SPARC] = "SPARC";
|
||||||
|
names[CS_ARCH_SYSZ] = "SystemZ";
|
||||||
|
names[CS_ARCH_XCORE] = "XCore";
|
||||||
|
names[CS_ARCH_M68K] = "Motorola 68K";
|
||||||
|
names[CS_ARCH_TMS320C64X] = "TMS320C64x";
|
||||||
|
names[CS_ARCH_M680X] = "M680X";
|
||||||
|
names[CS_ARCH_EVM] = "Ethereum Virtual Machine";
|
||||||
|
|
||||||
|
#if CS_API_MAJOR >= 5
|
||||||
|
names[CS_ARCH_WASM] = "WebAssembly";
|
||||||
|
names[CS_ARCH_RISCV] = "RISC-V";
|
||||||
|
names[CS_ARCH_MOS65XX] = "MOS Technology 65xx";
|
||||||
|
names[CS_ARCH_BPF] = "Berkeley Packet Filter";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return names;
|
||||||
|
}();
|
||||||
|
|
||||||
static inline i32 getArchitectureSupportedCount() {
|
static inline i32 getArchitectureSupportedCount() {
|
||||||
static i32 supportedCount = -1;
|
static i32 supportedCount = -1;
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
#include <span>
|
#include <span>
|
||||||
|
|
||||||
#include <hex/helpers/fs.hpp>
|
#include <hex/helpers/fs.hpp>
|
||||||
#include <hex/helpers/file.hpp>
|
|
||||||
|
#include <wolv/io/file.hpp>
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
@@ -21,17 +22,22 @@ namespace hex {
|
|||||||
|
|
||||||
EncodingFile() = default;
|
EncodingFile() = default;
|
||||||
EncodingFile(Type type, const std::fs::path &path);
|
EncodingFile(Type type, const std::fs::path &path);
|
||||||
|
EncodingFile(Type type, const std::string &path);
|
||||||
|
|
||||||
[[nodiscard]] std::pair<std::string_view, size_t> getEncodingFor(std::span<u8> buffer) const;
|
[[nodiscard]] std::pair<std::string_view, size_t> getEncodingFor(std::span<u8> buffer) const;
|
||||||
|
[[nodiscard]] size_t getEncodingLengthFor(std::span<u8> buffer) const;
|
||||||
[[nodiscard]] size_t getLongestSequence() const { return this->m_longestSequence; }
|
[[nodiscard]] size_t getLongestSequence() const { return this->m_longestSequence; }
|
||||||
|
|
||||||
[[nodiscard]] bool valid() const { return this->m_valid; }
|
[[nodiscard]] bool valid() const { return this->m_valid; }
|
||||||
|
|
||||||
|
[[nodiscard]] const std::string& getTableContent() const { return this->m_tableContent; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void parseThingyFile(fs::File &file);
|
void parse(const std::string &content);
|
||||||
|
|
||||||
bool m_valid = false;
|
bool m_valid = false;
|
||||||
|
|
||||||
|
std::string m_tableContent;
|
||||||
std::map<size_t, std::map<std::vector<u8>, std::string>> m_mapping;
|
std::map<size_t, std::map<std::vector<u8>, std::string>> m_mapping;
|
||||||
size_t m_longestSequence = 0;
|
size_t m_longestSequence = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <hex.hpp>
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <hex/helpers/fs.hpp>
|
|
||||||
|
|
||||||
#if defined(OS_MACOS)
|
|
||||||
#define off64_t off_t
|
|
||||||
#define fopen64 fopen
|
|
||||||
#define fseeko64 fseek
|
|
||||||
#define ftello64 ftell
|
|
||||||
#define ftruncate64 ftruncate
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace hex::fs {
|
|
||||||
|
|
||||||
class File {
|
|
||||||
public:
|
|
||||||
enum class Mode
|
|
||||||
{
|
|
||||||
Read,
|
|
||||||
Write,
|
|
||||||
Create
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit File(const std::fs::path &path, Mode mode) noexcept;
|
|
||||||
File() noexcept;
|
|
||||||
File(const File &) = delete;
|
|
||||||
File(File &&other) noexcept;
|
|
||||||
|
|
||||||
~File();
|
|
||||||
|
|
||||||
File &operator=(File &&other) noexcept;
|
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] bool isValid() const {
|
|
||||||
return this->m_file != nullptr && fs::exists(this->m_path) && !fs::isDirectory(this->m_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
void seek(u64 offset);
|
|
||||||
void close();
|
|
||||||
|
|
||||||
size_t readBuffer(u8 *buffer, size_t size);
|
|
||||||
std::vector<u8> readBytes(size_t numBytes = 0);
|
|
||||||
std::string readString(size_t numBytes = 0);
|
|
||||||
std::u8string readU8String(size_t numBytes = 0);
|
|
||||||
|
|
||||||
void write(const u8 *buffer, size_t size);
|
|
||||||
void write(const std::vector<u8> &bytes);
|
|
||||||
void write(const std::string &string);
|
|
||||||
void write(const std::u8string &string);
|
|
||||||
|
|
||||||
[[nodiscard]] size_t getSize() const;
|
|
||||||
void setSize(u64 size);
|
|
||||||
|
|
||||||
void flush();
|
|
||||||
bool remove();
|
|
||||||
|
|
||||||
auto getHandle() { return this->m_file; }
|
|
||||||
const std::fs::path &getPath() { return this->m_path; }
|
|
||||||
|
|
||||||
void disableBuffering();
|
|
||||||
|
|
||||||
private:
|
|
||||||
FILE *m_file;
|
|
||||||
std::fs::path m_path;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -10,80 +10,17 @@
|
|||||||
|
|
||||||
#include <nfd.hpp>
|
#include <nfd.hpp>
|
||||||
|
|
||||||
namespace std::fs {
|
#include <wolv/io/fs.hpp>
|
||||||
using namespace std::filesystem;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace hex::fs {
|
namespace hex::fs {
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
static inline bool exists(const std::fs::path &path) {
|
|
||||||
std::error_code error;
|
|
||||||
return std::filesystem::exists(path, error) && !error;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
static inline bool createDirectories(const std::fs::path &path) {
|
|
||||||
std::error_code error;
|
|
||||||
return std::filesystem::create_directories(path, error) && !error;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
static inline bool isRegularFile(const std::fs::path &path) {
|
|
||||||
std::error_code error;
|
|
||||||
return std::filesystem::is_regular_file(path, error) && !error;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
static inline bool copyFile(const std::fs::path &from, const std::fs::path &to, std::fs::copy_options = std::fs::copy_options::none) {
|
|
||||||
std::error_code error;
|
|
||||||
return std::filesystem::copy_file(from, to, error) && !error;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
static inline bool isDirectory(const std::fs::path &path) {
|
|
||||||
std::error_code error;
|
|
||||||
return std::filesystem::is_directory(path, error) && !error;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
static inline bool remove(const std::fs::path &path) {
|
|
||||||
std::error_code error;
|
|
||||||
return std::filesystem::remove(path, error) && !error;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
static inline bool removeAll(const std::fs::path &path) {
|
|
||||||
std::error_code error;
|
|
||||||
return std::filesystem::remove_all(path, error) && !error;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
static inline uintmax_t getFileSize(const std::fs::path &path) {
|
|
||||||
std::error_code error;
|
|
||||||
auto size = std::filesystem::file_size(path, error);
|
|
||||||
|
|
||||||
if (error) return 0;
|
|
||||||
else return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool isSubPath(const std::fs::path& base, const std::fs::path& destination) {
|
|
||||||
const auto relative = std::fs::relative(destination, base).u8string();
|
|
||||||
|
|
||||||
return relative.size() == 1 || (relative[0] != '.' && relative[1] != '.');
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isPathWritable(const std::fs::path &path);
|
|
||||||
|
|
||||||
std::fs::path toShortPath(const std::fs::path &path);
|
|
||||||
|
|
||||||
enum class DialogMode {
|
enum class DialogMode {
|
||||||
Open,
|
Open,
|
||||||
Save,
|
Save,
|
||||||
Folder
|
Folder
|
||||||
};
|
};
|
||||||
|
|
||||||
void setFileBrowserErrorCallback(const std::function<void()> &callback);
|
void setFileBrowserErrorCallback(const std::function<void(const std::string&)> &callback);
|
||||||
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath = {}, bool multiple = false);
|
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath = {}, bool multiple = false);
|
||||||
|
|
||||||
enum class ImHexPath : u32 {
|
enum class ImHexPath : u32 {
|
||||||
@@ -103,12 +40,16 @@ namespace hex::fs {
|
|||||||
Themes,
|
Themes,
|
||||||
Libraries,
|
Libraries,
|
||||||
Nodes,
|
Nodes,
|
||||||
|
Layouts,
|
||||||
|
|
||||||
END
|
END
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<std::fs::path> getExecutablePath();
|
bool isPathWritable(const std::fs::path &path);
|
||||||
|
|
||||||
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting = false);
|
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting = false);
|
||||||
|
|
||||||
|
// temporarily expose these for the migration function
|
||||||
|
std::vector<std::fs::path> getDataPaths();
|
||||||
|
std::vector<std::fs::path> appendPath(std::vector<std::fs::path> paths, const std::fs::path &folder);
|
||||||
}
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#if defined(OS_MACOS)
|
|
||||||
|
|
||||||
#include <hex/helpers/fs.hpp>
|
|
||||||
|
|
||||||
extern "C" char * getMacExecutableDirectoryPath();
|
|
||||||
extern "C" char * getMacApplicationSupportDirectoryPath();
|
|
||||||
|
|
||||||
extern "C" void macFree(void *ptr);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
325
lib/libimhex/include/hex/helpers/http_requests.hpp
Normal file
325
lib/libimhex/include/hex/helpers/http_requests.hpp
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hex.hpp>
|
||||||
|
|
||||||
|
#include <future>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
#include <hex/helpers/logger.hpp>
|
||||||
|
#include <hex/helpers/fmt.hpp>
|
||||||
|
|
||||||
|
#include <wolv/io/file.hpp>
|
||||||
|
#include <wolv/utils/core.hpp>
|
||||||
|
#include <wolv/utils/guards.hpp>
|
||||||
|
#include <wolv/utils/string.hpp>
|
||||||
|
|
||||||
|
#include <mbedtls/ssl.h>
|
||||||
|
|
||||||
|
namespace hex {
|
||||||
|
|
||||||
|
class HttpRequest {
|
||||||
|
public:
|
||||||
|
|
||||||
|
class ResultBase {
|
||||||
|
public:
|
||||||
|
ResultBase() = default;
|
||||||
|
explicit ResultBase(u32 statusCode) : m_statusCode(statusCode), m_valid(true) { }
|
||||||
|
|
||||||
|
[[nodiscard]] u32 getStatusCode() const {
|
||||||
|
return this->m_statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool isSuccess() const {
|
||||||
|
return this->getStatusCode() == 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool isValid() const {
|
||||||
|
return this->m_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
u32 m_statusCode = 0;
|
||||||
|
bool m_valid = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Result : public ResultBase {
|
||||||
|
public:
|
||||||
|
Result() = default;
|
||||||
|
Result(u32 statusCode, T data) : ResultBase(statusCode), m_data(std::move(data)) { }
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const T& getData() const {
|
||||||
|
return this->m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpRequest(std::string method, std::string url);
|
||||||
|
~HttpRequest();
|
||||||
|
|
||||||
|
HttpRequest(const HttpRequest&) = delete;
|
||||||
|
HttpRequest& operator=(const HttpRequest&) = delete;
|
||||||
|
|
||||||
|
HttpRequest(HttpRequest &&other) noexcept {
|
||||||
|
this->m_curl = other.m_curl;
|
||||||
|
other.m_curl = nullptr;
|
||||||
|
|
||||||
|
this->m_method = std::move(other.m_method);
|
||||||
|
this->m_url = std::move(other.m_url);
|
||||||
|
this->m_headers = std::move(other.m_headers);
|
||||||
|
this->m_body = std::move(other.m_body);
|
||||||
|
|
||||||
|
this->m_caCert = std::move(other.m_caCert);
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpRequest& operator=(HttpRequest &&other) noexcept {
|
||||||
|
this->m_curl = other.m_curl;
|
||||||
|
other.m_curl = nullptr;
|
||||||
|
|
||||||
|
this->m_method = std::move(other.m_method);
|
||||||
|
this->m_url = std::move(other.m_url);
|
||||||
|
this->m_headers = std::move(other.m_headers);
|
||||||
|
this->m_body = std::move(other.m_body);
|
||||||
|
|
||||||
|
this->m_caCert = std::move(other.m_caCert);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setCACert(std::string data) {
|
||||||
|
HttpRequest::s_caCertData = std::move(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setProxy(std::string proxy) {
|
||||||
|
HttpRequest::s_proxyUrl = std::move(proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMethod(std::string method) {
|
||||||
|
this->m_method = std::move(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setUrl(std::string url) {
|
||||||
|
this->m_url = std::move(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addHeader(std::string key, std::string value) {
|
||||||
|
this->m_headers[std::move(key)] = std::move(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBody(std::string body) {
|
||||||
|
this->m_body = std::move(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTimeout(u32 timeout) {
|
||||||
|
this->m_timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
float getProgress() const {
|
||||||
|
return this->m_progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancel() {
|
||||||
|
this->m_canceled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T = std::string>
|
||||||
|
std::future<Result<T>> downloadFile(const std::fs::path &path) {
|
||||||
|
return std::async(std::launch::async, [this, path] {
|
||||||
|
std::vector<u8> response;
|
||||||
|
|
||||||
|
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToFile);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &file);
|
||||||
|
|
||||||
|
return this->executeImpl<T>(response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::future<Result<std::vector<u8>>> downloadFile() {
|
||||||
|
return std::async(std::launch::async, [this] {
|
||||||
|
std::vector<u8> response;
|
||||||
|
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &response);
|
||||||
|
|
||||||
|
return this->executeImpl<std::vector<u8>>(response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T = std::string>
|
||||||
|
std::future<Result<T>> uploadFile(const std::fs::path &path, const std::string &mimeName = "filename") {
|
||||||
|
return std::async(std::launch::async, [this, path, mimeName]{
|
||||||
|
auto fileName = wolv::util::toUTF8String(path.filename());
|
||||||
|
|
||||||
|
curl_mime *mime = curl_mime_init(this->m_curl);
|
||||||
|
curl_mimepart *part = curl_mime_addpart(mime);
|
||||||
|
|
||||||
|
wolv::io::File file(path, wolv::io::File::Mode::Read);
|
||||||
|
|
||||||
|
curl_mime_data_cb(part, file.getSize(),
|
||||||
|
[](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
|
||||||
|
auto file = static_cast<FILE*>(arg);
|
||||||
|
|
||||||
|
return fread(buffer, size, nitems, file);
|
||||||
|
},
|
||||||
|
[](void *arg, curl_off_t offset, int origin) -> int {
|
||||||
|
auto file = static_cast<FILE*>(arg);
|
||||||
|
|
||||||
|
if (fseek(file, offset, origin) != 0)
|
||||||
|
return CURL_SEEKFUNC_CANTSEEK;
|
||||||
|
else
|
||||||
|
return CURL_SEEKFUNC_OK;
|
||||||
|
},
|
||||||
|
[](void *arg) {
|
||||||
|
auto file = static_cast<FILE*>(arg);
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
},
|
||||||
|
file.getHandle());
|
||||||
|
curl_mime_filename(part, fileName.c_str());
|
||||||
|
curl_mime_name(part, mimeName.c_str());
|
||||||
|
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_MIMEPOST, mime);
|
||||||
|
|
||||||
|
std::vector<u8> responseData;
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData);
|
||||||
|
|
||||||
|
return this->executeImpl<T>(responseData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
template<typename T = std::string>
|
||||||
|
std::future<Result<T>> uploadFile(std::vector<u8> data, const std::string &mimeName = "filename") {
|
||||||
|
return std::async(std::launch::async, [this, data = std::move(data), mimeName]{
|
||||||
|
curl_mime *mime = curl_mime_init(this->m_curl);
|
||||||
|
curl_mimepart *part = curl_mime_addpart(mime);
|
||||||
|
|
||||||
|
curl_mime_data(part, reinterpret_cast<const char *>(data.data()), data.size());
|
||||||
|
curl_mime_filename(part, "data.bin");
|
||||||
|
curl_mime_name(part, mimeName.c_str());
|
||||||
|
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_MIMEPOST, mime);
|
||||||
|
|
||||||
|
std::vector<u8> responseData;
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData);
|
||||||
|
|
||||||
|
return this->executeImpl<T>(responseData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T = std::string>
|
||||||
|
std::future<Result<T>> execute() {
|
||||||
|
return std::async(std::launch::async, [this] {
|
||||||
|
|
||||||
|
std::vector<u8> responseData;
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData);
|
||||||
|
|
||||||
|
return this->executeImpl<T>(responseData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string urlEncode(const std::string &input) {
|
||||||
|
auto escapedString = curl_easy_escape(this->m_curl, input.c_str(), std::strlen(input.c_str()));
|
||||||
|
|
||||||
|
if (escapedString != nullptr) {
|
||||||
|
std::string output = escapedString;
|
||||||
|
curl_free(escapedString);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string urlDecode(const std::string &input) {
|
||||||
|
auto unescapedString = curl_easy_unescape(this->m_curl, input.c_str(), std::strlen(input.c_str()), nullptr);
|
||||||
|
|
||||||
|
if (unescapedString != nullptr) {
|
||||||
|
std::string output = unescapedString;
|
||||||
|
curl_free(unescapedString);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setDefaultConfig();
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Result<T> executeImpl(std::vector<u8> &data) {
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_URL, this->m_url.c_str());
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_CUSTOMREQUEST, this->m_method.c_str());
|
||||||
|
|
||||||
|
setDefaultConfig();
|
||||||
|
|
||||||
|
if (!this->m_body.empty()) {
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_POSTFIELDS, this->m_body.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_slist *headers = nullptr;
|
||||||
|
headers = curl_slist_append(headers, "Cache-Control: no-cache");
|
||||||
|
ON_SCOPE_EXIT { curl_slist_free_all(headers); };
|
||||||
|
|
||||||
|
for (auto &[key, value] : this->m_headers) {
|
||||||
|
std::string header = hex::format("{}: {}", key, value);
|
||||||
|
headers = curl_slist_append(headers, header.c_str());
|
||||||
|
}
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_HTTPHEADER, headers);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(this->m_transmissionMutex);
|
||||||
|
|
||||||
|
auto result = curl_easy_perform(this->m_curl);
|
||||||
|
if (result != CURLE_OK){
|
||||||
|
char *url = nullptr;
|
||||||
|
curl_easy_getinfo(this->m_curl, CURLINFO_EFFECTIVE_URL, &url);
|
||||||
|
log::error("Http request '{0} {1}' failed with error {2}: '{3}'", this->m_method, url, u32(result), curl_easy_strerror(result));
|
||||||
|
if (!HttpRequest::s_proxyUrl.empty()){
|
||||||
|
log::info("A custom proxy '{0}' is in use. Is it working correctly?", HttpRequest::s_proxyUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long statusCode = 0;
|
||||||
|
curl_easy_getinfo(this->m_curl, CURLINFO_RESPONSE_CODE, &statusCode);
|
||||||
|
|
||||||
|
return Result<T>(statusCode, { data.begin(), data.end() });
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] static CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userData);
|
||||||
|
static size_t writeToVector(void *contents, size_t size, size_t nmemb, void *userdata);
|
||||||
|
static size_t writeToFile(void *contents, size_t size, size_t nmemb, void *userdata);
|
||||||
|
static int progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CURL *m_curl;
|
||||||
|
|
||||||
|
std::mutex m_transmissionMutex;
|
||||||
|
|
||||||
|
std::string m_method;
|
||||||
|
std::string m_url;
|
||||||
|
std::string m_body;
|
||||||
|
std::map<std::string, std::string> m_headers;
|
||||||
|
u32 m_timeout = 1000;
|
||||||
|
|
||||||
|
std::atomic<float> m_progress = 0.0F;
|
||||||
|
std::atomic<bool> m_canceled = false;
|
||||||
|
|
||||||
|
[[maybe_unused]] std::unique_ptr<mbedtls_x509_crt> m_caCert;
|
||||||
|
static std::string s_caCertData, s_proxyUrl;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ namespace hex::log {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
[[maybe_unused]] void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level) {
|
[[maybe_unused]] void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level) {
|
||||||
const auto now = fmt::localtime(std::chrono::system_clock::now());
|
const auto now = fmt::localtime(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()));
|
||||||
|
|
||||||
fmt::print(dest, "[{0:%H:%M:%S}] ", now);
|
fmt::print(dest, "[{0:%H:%M:%S}] ", now);
|
||||||
|
|
||||||
@@ -31,9 +31,6 @@ namespace hex::log {
|
|||||||
|
|
||||||
template<typename... T>
|
template<typename... T>
|
||||||
[[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) {
|
[[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) {
|
||||||
static std::mutex logMutex;
|
|
||||||
std::scoped_lock lock(logMutex);
|
|
||||||
|
|
||||||
auto dest = getDestination();
|
auto dest = getDestination();
|
||||||
|
|
||||||
printPrefix(dest, ts, level);
|
printPrefix(dest, ts, level);
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <hex.hpp>
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <future>
|
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
#include <nlohmann/json_fwd.hpp>
|
|
||||||
#include <curl/curl.h>
|
|
||||||
#include <curl/system.h>
|
|
||||||
#include <mbedtls/ssl.h>
|
|
||||||
|
|
||||||
#include <hex/helpers/fs.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
namespace hex {
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct Response {
|
|
||||||
i32 code;
|
|
||||||
T body;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct Response<void> {
|
|
||||||
i32 code;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Net {
|
|
||||||
public:
|
|
||||||
Net();
|
|
||||||
~Net();
|
|
||||||
|
|
||||||
constexpr static u32 DefaultTimeout = 2'000;
|
|
||||||
|
|
||||||
std::future<Response<std::string>> getString(const std::string &url, u32 timeout = DefaultTimeout, const std::map<std::string, std::string> &extraHeaders = {}, const std::string &body = {});
|
|
||||||
std::future<Response<nlohmann::json>> getJson(const std::string &url, u32 timeout = DefaultTimeout, const std::map<std::string, std::string> &extraHeaders = {}, const std::string &body = {});
|
|
||||||
|
|
||||||
std::future<Response<nlohmann::json>> postJson(const std::string &url, u32 timeout = DefaultTimeout, const std::map<std::string, std::string> &extraHeaders = {}, const std::string &body = {});
|
|
||||||
|
|
||||||
std::future<Response<std::string>> uploadFile(const std::string &url, const std::fs::path &filePath, u32 timeout = DefaultTimeout);
|
|
||||||
std::future<Response<void>> downloadFile(const std::string &url, const std::fs::path &filePath, u32 timeout = DefaultTimeout);
|
|
||||||
|
|
||||||
[[nodiscard]] std::string encode(const std::string &input);
|
|
||||||
[[nodiscard]] std::string decode(const std::string &input);
|
|
||||||
|
|
||||||
[[nodiscard]] float getProgress() const { return this->m_progress; }
|
|
||||||
|
|
||||||
void cancel() { this->m_shouldCancel = true; }
|
|
||||||
|
|
||||||
static void setProxy(const std::string &url);
|
|
||||||
static void setCACert(const std::string &content);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void setCommonSettings(std::string &response, const std::string &url, u32 timeout = 2000, const std::map<std::string, std::string> &extraHeaders = {}, const std::string &body = {});
|
|
||||||
std::optional<i32> execute();
|
|
||||||
|
|
||||||
friend int progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow);
|
|
||||||
friend CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userData);
|
|
||||||
|
|
||||||
private:
|
|
||||||
CURL *m_ctx;
|
|
||||||
mbedtls_x509_crt m_caCert;
|
|
||||||
curl_slist *m_headers = nullptr;
|
|
||||||
|
|
||||||
std::mutex m_transmissionActive;
|
|
||||||
float m_progress = 0.0F;
|
|
||||||
bool m_shouldCancel = false;
|
|
||||||
|
|
||||||
static std::string s_proxyUrl;
|
|
||||||
static std::string s_caCert;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -75,6 +75,13 @@ namespace hex::gl {
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto operator==(const Vector<T, Size>& other) {
|
||||||
|
for (size_t i = 0; i < Size; i++)
|
||||||
|
if (this->m_data[i] != other[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<T, Size> m_data;
|
std::array<T, Size> m_data;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <hex.hpp>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#if defined(OS_WINDOWS)
|
|
||||||
#include <winsock2.h>
|
|
||||||
#include <ws2tcpip.h>
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
#define SOCKET_NONE INVALID_SOCKET
|
|
||||||
#else
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <netinet/ip.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
|
|
||||||
#define SOCKET_NONE -1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace hex {
|
|
||||||
|
|
||||||
class Socket {
|
|
||||||
public:
|
|
||||||
Socket() = default;
|
|
||||||
Socket(const Socket &) = delete;
|
|
||||||
Socket(Socket &&other) noexcept;
|
|
||||||
|
|
||||||
Socket(const std::string &address, u16 port);
|
|
||||||
~Socket();
|
|
||||||
|
|
||||||
void connect(const std::string &address, u16 port);
|
|
||||||
void disconnect();
|
|
||||||
|
|
||||||
[[nodiscard]] bool isConnected() const;
|
|
||||||
|
|
||||||
[[nodiscard]] std::string readString(size_t size = 0x1000) const;
|
|
||||||
[[nodiscard]] std::vector<u8> readBytes(size_t size = 0x1000) const;
|
|
||||||
|
|
||||||
void writeString(const std::string &string) const;
|
|
||||||
void writeBytes(const std::vector<u8> &bytes) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_connected = false;
|
|
||||||
#if defined(OS_WINDOWS)
|
|
||||||
SOCKET m_socket = SOCKET_NONE;
|
|
||||||
#else
|
|
||||||
int m_socket = SOCKET_NONE;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -26,11 +26,11 @@ namespace hex {
|
|||||||
|
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
[[nodiscard]] std::vector<u8> read(const std::fs::path &path);
|
[[nodiscard]] std::vector<u8> readVector(const std::fs::path &path);
|
||||||
[[nodiscard]] std::string readString(const std::fs::path &path);
|
[[nodiscard]] std::string readString(const std::fs::path &path);
|
||||||
|
|
||||||
void write(const std::fs::path &path, const std::vector<u8> &data);
|
void writeVector(const std::fs::path &path, const std::vector<u8> &data);
|
||||||
void write(const std::fs::path &path, const std::string &data);
|
void writeString(const std::fs::path &path, const std::string &data);
|
||||||
|
|
||||||
[[nodiscard]] std::vector<std::fs::path> listEntries(const std::fs::path &basePath = "/");
|
[[nodiscard]] std::vector<std::fs::path> listEntries(const std::fs::path &basePath = "/");
|
||||||
[[nodiscard]] bool contains(const std::fs::path &path);
|
[[nodiscard]] bool contains(const std::fs::path &path);
|
||||||
@@ -42,6 +42,7 @@ namespace hex {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
mtar_t m_ctx = { };
|
mtar_t m_ctx = { };
|
||||||
|
std::fs::path m_path;
|
||||||
|
|
||||||
bool m_valid = false;
|
bool m_valid = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,14 +19,24 @@
|
|||||||
#include <variant>
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#define TOKEN_CONCAT_IMPL(x, y) x##y
|
|
||||||
#define TOKEN_CONCAT(x, y) TOKEN_CONCAT_IMPL(x, y)
|
|
||||||
#define ANONYMOUS_VARIABLE(prefix) TOKEN_CONCAT(prefix, __COUNTER__)
|
|
||||||
|
|
||||||
struct ImVec2;
|
struct ImVec2;
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::vector<T> sampleData(const std::vector<T> &data, size_t count) {
|
||||||
|
size_t stride = std::max(1.0, double(data.size()) / count);
|
||||||
|
|
||||||
|
std::vector<T> result;
|
||||||
|
result.reserve(count);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < data.size(); i += stride) {
|
||||||
|
result.push_back(data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
float operator""_scaled(long double value);
|
float operator""_scaled(long double value);
|
||||||
float operator""_scaled(unsigned long long value);
|
float operator""_scaled(unsigned long long value);
|
||||||
ImVec2 scaled(const ImVec2 &vector);
|
ImVec2 scaled(const ImVec2 &vector);
|
||||||
@@ -44,6 +54,7 @@ namespace hex {
|
|||||||
std::string to_string(u128 value);
|
std::string to_string(u128 value);
|
||||||
std::string to_string(i128 value);
|
std::string to_string(i128 value);
|
||||||
|
|
||||||
|
std::optional<u8> parseBinaryString(const std::string &string);
|
||||||
std::string toByteString(u64 bytes);
|
std::string toByteString(u64 bytes);
|
||||||
std::string makePrintable(u8 c);
|
std::string makePrintable(u8 c);
|
||||||
|
|
||||||
@@ -101,11 +112,6 @@ namespace hex {
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class... Ts>
|
|
||||||
struct overloaded : Ts... { using Ts::operator()...; };
|
|
||||||
template<class... Ts>
|
|
||||||
overloaded(Ts...) -> overloaded<Ts...>;
|
|
||||||
|
|
||||||
template<size_t Size>
|
template<size_t Size>
|
||||||
struct SizeTypeImpl { };
|
struct SizeTypeImpl { };
|
||||||
|
|
||||||
@@ -205,14 +211,6 @@ namespace hex {
|
|||||||
|
|
||||||
std::string toEngineeringString(double value);
|
std::string toEngineeringString(double value);
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
std::vector<u8> toBytes(T value) {
|
|
||||||
std::vector<u8> bytes(sizeof(T));
|
|
||||||
std::memcpy(bytes.data(), &value, sizeof(T));
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline std::vector<u8> parseByteString(const std::string &string) {
|
inline std::vector<u8> parseByteString(const std::string &string) {
|
||||||
auto byteString = std::string(string);
|
auto byteString = std::string(string);
|
||||||
byteString.erase(std::remove(byteString.begin(), byteString.end(), ' '), byteString.end());
|
byteString.erase(std::remove(byteString.begin(), byteString.end(), ' '), byteString.end());
|
||||||
@@ -240,26 +238,6 @@ namespace hex {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline void trimLeft(std::basic_string<T> &s) {
|
|
||||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
|
|
||||||
return !std::isspace(ch) && ch >= 0x20;
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline void trimRight(std::basic_string<T> &s) {
|
|
||||||
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
|
|
||||||
return !std::isspace(ch) && ch >= 0x20;
|
|
||||||
}).base(), s.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
inline void trim(std::basic_string<T> &s) {
|
|
||||||
trimLeft(s);
|
|
||||||
trimRight(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
float float16ToFloat32(u16 float16);
|
float float16ToFloat32(u16 float16);
|
||||||
|
|
||||||
inline bool equalsIgnoreCase(const std::string &left, const std::string &right) {
|
inline bool equalsIgnoreCase(const std::string &left, const std::string &right) {
|
||||||
@@ -276,13 +254,6 @@ namespace hex {
|
|||||||
return iter != a.end();
|
return iter != a.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> requires requires(T t) { t.u8string(); }
|
|
||||||
std::string toUTF8String(const T &value) {
|
|
||||||
auto result = value.u8string();
|
|
||||||
|
|
||||||
return { result.begin(), result.end() };
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename... VariantTypes>
|
template<typename T, typename... VariantTypes>
|
||||||
T get_or(const std::variant<VariantTypes...> &variant, T alt) {
|
T get_or(const std::variant<VariantTypes...> &variant, T alt) {
|
||||||
const T *value = std::get_if<T>(&variant);
|
const T *value = std::get_if<T>(&variant);
|
||||||
@@ -312,89 +283,6 @@ namespace hex {
|
|||||||
return string.substr(0, maxLength - 3) + "...";
|
return string.substr(0, maxLength - 3) + "...";
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace scope_guard {
|
std::optional<std::fs::path> getInitialFilePath();
|
||||||
|
|
||||||
#define SCOPE_GUARD ::hex::scope_guard::ScopeGuardOnExit() + [&]()
|
|
||||||
#define ON_SCOPE_EXIT [[maybe_unused]] auto ANONYMOUS_VARIABLE(SCOPE_EXIT_) = SCOPE_GUARD
|
|
||||||
|
|
||||||
template<class F>
|
|
||||||
class ScopeGuard {
|
|
||||||
private:
|
|
||||||
F m_func;
|
|
||||||
bool m_active;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit constexpr ScopeGuard(F func) : m_func(std::move(func)), m_active(true) { }
|
|
||||||
~ScopeGuard() {
|
|
||||||
if (this->m_active) { this->m_func(); }
|
|
||||||
}
|
|
||||||
void release() { this->m_active = false; }
|
|
||||||
|
|
||||||
ScopeGuard(ScopeGuard &&other) noexcept : m_func(std::move(other.m_func)), m_active(other.m_active) {
|
|
||||||
other.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
ScopeGuard &operator=(ScopeGuard &&) = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class ScopeGuardOnExit
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F &&f) {
|
|
||||||
return ScopeGuard<F>(std::forward<F>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace first_time_exec {
|
|
||||||
|
|
||||||
#define FIRST_TIME [[maybe_unused]] static auto ANONYMOUS_VARIABLE(FIRST_TIME_) = ::hex::first_time_exec::FirstTimeExecutor() + [&]()
|
|
||||||
|
|
||||||
template<class F>
|
|
||||||
class FirstTimeExecute {
|
|
||||||
public:
|
|
||||||
explicit constexpr FirstTimeExecute(F func) { func(); }
|
|
||||||
|
|
||||||
FirstTimeExecute &operator=(FirstTimeExecute &&) = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class FirstTimeExecutor
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
constexpr FirstTimeExecute<F> operator+(FirstTimeExecutor, F &&f) {
|
|
||||||
return FirstTimeExecute<F>(std::forward<F>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace final_cleanup {
|
|
||||||
|
|
||||||
#define FINAL_CLEANUP [[maybe_unused]] static auto ANONYMOUS_VARIABLE(ON_EXIT_) = ::hex::final_cleanup::FinalCleanupExecutor() + [&]()
|
|
||||||
|
|
||||||
template<class F>
|
|
||||||
class FinalCleanupExecute {
|
|
||||||
F m_func;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit constexpr FinalCleanupExecute(F func) : m_func(func) { }
|
|
||||||
constexpr ~FinalCleanupExecute() { this->m_func(); }
|
|
||||||
|
|
||||||
FinalCleanupExecute &operator=(FinalCleanupExecute &&) = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class FinalCleanupExecutor
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename F>
|
|
||||||
constexpr FinalCleanupExecute<F> operator+(FinalCleanupExecutor, F &&f) {
|
|
||||||
return FinalCleanupExecute<F>(std::forward<F>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
#include <hex.hpp>
|
#include <hex.hpp>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This macro is used to define all the required entry points for a plugin.
|
||||||
|
* Name, Author and Description will be displayed in the in the plugin list on the Welcome screen.
|
||||||
|
*/
|
||||||
#define IMHEX_PLUGIN_SETUP(name, author, description) IMHEX_PLUGIN_SETUP_IMPL(name, author, description)
|
#define IMHEX_PLUGIN_SETUP(name, author, description) IMHEX_PLUGIN_SETUP_IMPL(name, author, description)
|
||||||
|
|
||||||
#define IMHEX_PLUGIN_SETUP_IMPL(name, author, description) \
|
#define IMHEX_PLUGIN_SETUP_IMPL(name, author, description) \
|
||||||
|
|||||||
@@ -6,279 +6,24 @@
|
|||||||
#include <hex/providers/provider.hpp>
|
#include <hex/providers/provider.hpp>
|
||||||
#include <hex/helpers/literals.hpp>
|
#include <hex/helpers/literals.hpp>
|
||||||
|
|
||||||
|
#include <wolv/io/buffered_reader.hpp>
|
||||||
|
|
||||||
namespace hex::prv {
|
namespace hex::prv {
|
||||||
|
|
||||||
using namespace hex::literals;
|
using namespace hex::literals;
|
||||||
|
|
||||||
class BufferedReader {
|
inline void providerReaderFunction(Provider *provider, void *buffer, u64 address, size_t size) {
|
||||||
|
provider->read(address, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProviderReader : public wolv::io::BufferedReader<prv::Provider, providerReaderFunction> {
|
||||||
public:
|
public:
|
||||||
explicit BufferedReader(Provider *provider, size_t bufferSize = 16_MiB)
|
using BufferedReader::BufferedReader;
|
||||||
: m_provider(provider), m_bufferAddress(provider->getBaseAddress()), m_maxBufferSize(bufferSize),
|
|
||||||
m_startAddress(provider->getBaseAddress()), m_endAddress(provider->getBaseAddress() + provider->getActualSize() - 1LLU),
|
|
||||||
m_buffer(bufferSize) {
|
|
||||||
|
|
||||||
|
ProviderReader(Provider *provider, size_t bufferSize = 0x100000) : BufferedReader(provider, provider->getActualSize(), bufferSize) {
|
||||||
|
this->setEndAddress(provider->getBaseAddress() + provider->getActualSize() - 1);
|
||||||
|
this->seek(provider->getBaseAddress());
|
||||||
}
|
}
|
||||||
|
|
||||||
void seek(u64 address) {
|
|
||||||
this->m_startAddress = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setEndAddress(u64 address) {
|
|
||||||
if (address >= this->m_provider->getActualSize())
|
|
||||||
address = this->m_provider->getActualSize() - 1;
|
|
||||||
|
|
||||||
this->m_endAddress = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] std::vector<u8> read(u64 address, size_t size) {
|
|
||||||
if (size > this->m_buffer.size()) {
|
|
||||||
std::vector<u8> result;
|
|
||||||
result.resize(size);
|
|
||||||
|
|
||||||
this->m_provider->read(address, result.data(), result.size());
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->updateBuffer(address, size);
|
|
||||||
|
|
||||||
auto result = &this->m_buffer[address - this->m_bufferAddress];
|
|
||||||
|
|
||||||
return { result, result + std::min(size, this->m_buffer.size()) };
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] std::vector<u8> readReverse(u64 address, size_t size) {
|
|
||||||
if (size > this->m_buffer.size()) {
|
|
||||||
std::vector<u8> result;
|
|
||||||
result.resize(size);
|
|
||||||
|
|
||||||
this->m_provider->read(address, result.data(), result.size());
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->updateBuffer(address - std::min<u64>(address, this->m_buffer.size()), size);
|
|
||||||
|
|
||||||
auto result = &this->m_buffer[address - this->m_bufferAddress];
|
|
||||||
|
|
||||||
return { result, result + std::min(size, this->m_buffer.size()) };
|
|
||||||
}
|
|
||||||
|
|
||||||
class Iterator {
|
|
||||||
public:
|
|
||||||
using iterator_category = std::forward_iterator_tag;
|
|
||||||
using difference_type = std::ptrdiff_t;
|
|
||||||
using value_type = u8;
|
|
||||||
using pointer = const value_type*;
|
|
||||||
using reference = const value_type&;
|
|
||||||
|
|
||||||
Iterator(BufferedReader *reader, u64 address) : m_reader(reader), m_address(address) {}
|
|
||||||
|
|
||||||
Iterator& operator++() {
|
|
||||||
this->m_address++;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator operator++(int) {
|
|
||||||
auto copy = *this;
|
|
||||||
this->m_address++;
|
|
||||||
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator& operator--() {
|
|
||||||
this->m_address--;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator operator--(int) {
|
|
||||||
auto copy = *this;
|
|
||||||
this->m_address--;
|
|
||||||
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator& operator+=(i64 offset) {
|
|
||||||
this->m_address += offset;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator& operator-=(i64 offset) {
|
|
||||||
this->m_address -= offset;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type operator*() const {
|
|
||||||
return (*this)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] u64 getAddress() const {
|
|
||||||
return this->m_address;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setAddress(u64 address) {
|
|
||||||
this->m_address = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
difference_type operator-(const Iterator &other) const {
|
|
||||||
return this->m_address - other.m_address;
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator operator+(i64 offset) const {
|
|
||||||
return { this->m_reader, this->m_address + offset };
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type operator[](i64 offset) const {
|
|
||||||
auto result = this->m_reader->read(this->m_address + offset, 1);
|
|
||||||
if (result.empty())
|
|
||||||
return 0x00;
|
|
||||||
|
|
||||||
return result[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator== (const Iterator& left, const Iterator& right) { return left.m_address == right.m_address; };
|
|
||||||
friend bool operator!= (const Iterator& left, const Iterator& right) { return left.m_address != right.m_address; };
|
|
||||||
friend bool operator> (const Iterator& left, const Iterator& right) { return left.m_address > right.m_address; };
|
|
||||||
friend bool operator< (const Iterator& left, const Iterator& right) { return left.m_address < right.m_address; };
|
|
||||||
friend bool operator>= (const Iterator& left, const Iterator& right) { return left.m_address >= right.m_address; };
|
|
||||||
friend bool operator<= (const Iterator& left, const Iterator& right) { return left.m_address <= right.m_address; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
BufferedReader *m_reader;
|
|
||||||
u64 m_address;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ReverseIterator {
|
|
||||||
public:
|
|
||||||
using iterator_category = std::forward_iterator_tag;
|
|
||||||
using difference_type = std::ptrdiff_t;
|
|
||||||
using value_type = u8;
|
|
||||||
using pointer = const value_type*;
|
|
||||||
using reference = const value_type&;
|
|
||||||
|
|
||||||
ReverseIterator(BufferedReader *reader, u64 address) : m_reader(reader), m_address(address) {}
|
|
||||||
|
|
||||||
ReverseIterator& operator++() {
|
|
||||||
this->m_address--;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReverseIterator operator++(int) {
|
|
||||||
auto copy = *this;
|
|
||||||
this->m_address--;
|
|
||||||
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReverseIterator& operator--() {
|
|
||||||
this->m_address++;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReverseIterator operator--(int) {
|
|
||||||
auto copy = *this;
|
|
||||||
this->m_address++;
|
|
||||||
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReverseIterator& operator+=(i64 offset) {
|
|
||||||
this->m_address -= offset;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReverseIterator& operator-=(i64 offset) {
|
|
||||||
this->m_address += offset;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type operator*() const {
|
|
||||||
return (*this)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] u64 getAddress() const {
|
|
||||||
return this->m_address;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setAddress(u64 address) {
|
|
||||||
this->m_address = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
difference_type operator-(const ReverseIterator &other) const {
|
|
||||||
return other.m_address - this->m_address;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReverseIterator operator+(i64 offset) const {
|
|
||||||
return { this->m_reader, this->m_address - offset };
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type operator[](i64 offset) const {
|
|
||||||
auto result = this->m_reader->readReverse(this->m_address - offset, 1);
|
|
||||||
if (result.empty())
|
|
||||||
return 0x00;
|
|
||||||
|
|
||||||
return result[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
friend bool operator== (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address == right.m_address; };
|
|
||||||
friend bool operator!= (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address != right.m_address; };
|
|
||||||
friend bool operator> (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address > right.m_address; };
|
|
||||||
friend bool operator< (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address < right.m_address; };
|
|
||||||
friend bool operator>= (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address >= right.m_address; };
|
|
||||||
friend bool operator<= (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address <= right.m_address; };
|
|
||||||
|
|
||||||
private:
|
|
||||||
BufferedReader *m_reader;
|
|
||||||
u64 m_address = 0x00;
|
|
||||||
};
|
|
||||||
|
|
||||||
Iterator begin() {
|
|
||||||
return { this, this->m_startAddress };
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterator end() {
|
|
||||||
return { this, this->m_endAddress + 1 };
|
|
||||||
}
|
|
||||||
|
|
||||||
ReverseIterator rbegin() {
|
|
||||||
return { this, this->m_startAddress };
|
|
||||||
}
|
|
||||||
|
|
||||||
ReverseIterator rend() {
|
|
||||||
return { this, 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void updateBuffer(u64 address, size_t size) {
|
|
||||||
if (!this->m_bufferValid || address < this->m_bufferAddress || address + size > (this->m_bufferAddress + this->m_buffer.size())) {
|
|
||||||
const auto remainingBytes = (this->m_endAddress - address) + 1;
|
|
||||||
if (remainingBytes < this->m_maxBufferSize)
|
|
||||||
this->m_buffer.resize(remainingBytes);
|
|
||||||
else
|
|
||||||
this->m_buffer.resize(this->m_maxBufferSize);
|
|
||||||
|
|
||||||
this->m_provider->read(address, this->m_buffer.data(), this->m_buffer.size());
|
|
||||||
this->m_bufferAddress = address;
|
|
||||||
this->m_bufferValid = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Provider *m_provider;
|
|
||||||
|
|
||||||
u64 m_bufferAddress = 0x00;
|
|
||||||
size_t m_maxBufferSize;
|
|
||||||
bool m_bufferValid = false;
|
|
||||||
u64 m_startAddress = 0x00, m_endAddress;
|
|
||||||
std::vector<u8> m_buffer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
namespace hex::prv {
|
namespace hex::prv {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Represent the data source for a tab in the UI
|
||||||
|
*/
|
||||||
class Provider {
|
class Provider {
|
||||||
public:
|
public:
|
||||||
constexpr static size_t PageSize = 0x1000'0000;
|
constexpr static size_t PageSize = 0x1000'0000;
|
||||||
@@ -29,7 +32,21 @@ namespace hex::prv {
|
|||||||
[[nodiscard]] virtual bool isResizable() const = 0;
|
[[nodiscard]] virtual bool isResizable() const = 0;
|
||||||
[[nodiscard]] virtual bool isSavable() const = 0;
|
[[nodiscard]] virtual bool isSavable() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read data from this provider, applying overlays and patches
|
||||||
|
* @param offset offset to start reading the data
|
||||||
|
* @param buffer buffer to write read data
|
||||||
|
* @param size number of bytes to read
|
||||||
|
* @param overlays apply overlays and patches is true. Same as readRaw() if false
|
||||||
|
*/
|
||||||
virtual void read(u64 offset, void *buffer, size_t size, bool overlays = true);
|
virtual void read(u64 offset, void *buffer, size_t size, bool overlays = true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write data to the patches of this provider. Will not directly modify provider.
|
||||||
|
* @param offset offset to start writing the data
|
||||||
|
* @param buffer buffer to take data to write from
|
||||||
|
* @param size number of bytes to write
|
||||||
|
*/
|
||||||
virtual void write(u64 offset, const void *buffer, size_t size);
|
virtual void write(u64 offset, const void *buffer, size_t size);
|
||||||
|
|
||||||
virtual void resize(size_t newSize);
|
virtual void resize(size_t newSize);
|
||||||
@@ -39,7 +56,19 @@ namespace hex::prv {
|
|||||||
virtual void save();
|
virtual void save();
|
||||||
virtual void saveAs(const std::fs::path &path);
|
virtual void saveAs(const std::fs::path &path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read data from this provider, without applying overlays and patches
|
||||||
|
* @param offset offset to start reading the data
|
||||||
|
* @param buffer buffer to write read data
|
||||||
|
* @param size number of bytes to read
|
||||||
|
*/
|
||||||
virtual void readRaw(u64 offset, void *buffer, size_t size) = 0;
|
virtual void readRaw(u64 offset, void *buffer, size_t size) = 0;
|
||||||
|
/**
|
||||||
|
* @brief Write data directly to this provider
|
||||||
|
* @param offset offset to start writing the data
|
||||||
|
* @param buffer buffer to take data to write from
|
||||||
|
* @param size number of bytes to write
|
||||||
|
*/
|
||||||
virtual void writeRaw(u64 offset, const void *buffer, size_t size) = 0;
|
virtual void writeRaw(u64 offset, const void *buffer, size_t size) = 0;
|
||||||
[[nodiscard]] virtual size_t getActualSize() const = 0;
|
[[nodiscard]] virtual size_t getActualSize() const = 0;
|
||||||
|
|
||||||
@@ -67,6 +96,13 @@ namespace hex::prv {
|
|||||||
[[nodiscard]] virtual std::vector<std::pair<std::string, std::string>> getDataDescription() const = 0;
|
[[nodiscard]] virtual std::vector<std::pair<std::string, std::string>> getDataDescription() const = 0;
|
||||||
[[nodiscard]] virtual std::variant<std::string, i128> queryInformation(const std::string &category, const std::string &argument);
|
[[nodiscard]] virtual std::variant<std::string, i128> queryInformation(const std::string &category, const std::string &argument);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Opens this provider
|
||||||
|
* the return value of this function allows to ensure the provider is available,
|
||||||
|
* so calling Provider::isAvailable() just after a call to open() that returned true is dedundant.
|
||||||
|
* @note This is not related to the EventProviderOpened event
|
||||||
|
* @return true if the provider was opened sucessfully, else false
|
||||||
|
*/
|
||||||
[[nodiscard]] virtual bool open() = 0;
|
[[nodiscard]] virtual bool open() = 0;
|
||||||
virtual void close() = 0;
|
virtual void close() = 0;
|
||||||
|
|
||||||
@@ -84,7 +120,7 @@ namespace hex::prv {
|
|||||||
|
|
||||||
[[nodiscard]] virtual bool hasLoadInterface() const;
|
[[nodiscard]] virtual bool hasLoadInterface() const;
|
||||||
[[nodiscard]] virtual bool hasInterface() const;
|
[[nodiscard]] virtual bool hasInterface() const;
|
||||||
virtual void drawLoadInterface();
|
virtual bool drawLoadInterface();
|
||||||
virtual void drawInterface();
|
virtual void drawInterface();
|
||||||
|
|
||||||
[[nodiscard]] u32 getID() const;
|
[[nodiscard]] u32 getID() const;
|
||||||
@@ -103,19 +139,36 @@ namespace hex::prv {
|
|||||||
void skipLoadInterface() { this->m_skipLoadInterface = true; }
|
void skipLoadInterface() { this->m_skipLoadInterface = true; }
|
||||||
[[nodiscard]] bool shouldSkipLoadInterface() const { return this->m_skipLoadInterface; }
|
[[nodiscard]] bool shouldSkipLoadInterface() const { return this->m_skipLoadInterface; }
|
||||||
|
|
||||||
|
void setErrorMessage(const std::string &errorMessage) { this->m_errorMessage = errorMessage; }
|
||||||
|
[[nodiscard]] const std::string& getErrorMessage() const { return this->m_errorMessage; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
u32 m_currPage = 0;
|
u32 m_currPage = 0;
|
||||||
u64 m_baseAddress = 0;
|
u64 m_baseAddress = 0;
|
||||||
|
|
||||||
u32 m_patchTreeOffset = 0;
|
|
||||||
std::list<std::map<u64, u8>> m_patches;
|
std::list<std::map<u64, u8>> m_patches;
|
||||||
|
decltype(m_patches)::iterator m_currPatches;
|
||||||
std::list<Overlay *> m_overlays;
|
std::list<Overlay *> m_overlays;
|
||||||
|
|
||||||
u32 m_id;
|
u32 m_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief true if there is any data that needs to be saved
|
||||||
|
*/
|
||||||
bool m_dirty = false;
|
bool m_dirty = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Control whetever to skip provider initialization
|
||||||
|
* initialization may be asking the user for information related to the provider,
|
||||||
|
* e.g. a process ID for the process memory provider
|
||||||
|
* this is used mainly when restoring a provider with already known initialization information
|
||||||
|
* for example when loading a project or loading a provider from the "recent" lsit
|
||||||
|
*
|
||||||
|
*/
|
||||||
bool m_skipLoadInterface = false;
|
bool m_skipLoadInterface = false;
|
||||||
|
|
||||||
|
std::string m_errorMessage;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static u32 s_idCounter;
|
static u32 s_idCounter;
|
||||||
};
|
};
|
||||||
|
|||||||
78
lib/libimhex/include/hex/providers/provider_data.hpp
Normal file
78
lib/libimhex/include/hex/providers/provider_data.hpp
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hex/api/imhex_api.hpp>
|
||||||
|
#include <hex/api/event.hpp>
|
||||||
|
#include <hex/providers/provider.hpp>
|
||||||
|
|
||||||
|
#include <concepts>
|
||||||
|
#include <map>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace hex {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class PerProvider {
|
||||||
|
public:
|
||||||
|
PerProvider() { this->onCreate(); }
|
||||||
|
PerProvider(const PerProvider&) = delete;
|
||||||
|
PerProvider(PerProvider&&) = delete;
|
||||||
|
PerProvider& operator=(const PerProvider&) = delete;
|
||||||
|
PerProvider& operator=(PerProvider&&) = delete;
|
||||||
|
|
||||||
|
PerProvider(T data) : m_data({ { ImHexApi::Provider::get(), std::move(data) } }) { this->onCreate(); }
|
||||||
|
|
||||||
|
~PerProvider() = default;
|
||||||
|
|
||||||
|
T* operator->() {
|
||||||
|
return &this->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
const T* operator->() const {
|
||||||
|
return &this->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
T& get(prv::Provider *provider = ImHexApi::Provider::get()) {
|
||||||
|
return this->m_data[provider];
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& get(prv::Provider *provider = ImHexApi::Provider::get()) const {
|
||||||
|
return this->m_data[provider];
|
||||||
|
}
|
||||||
|
|
||||||
|
T& operator*() {
|
||||||
|
return this->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& operator*() const {
|
||||||
|
return this->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
PerProvider& operator=(T data) {
|
||||||
|
this->m_data = std::move(data);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator T&() {
|
||||||
|
return this->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onCreate() {
|
||||||
|
(void)EventManager::subscribe<EventProviderOpened>([this](prv::Provider *provider) {
|
||||||
|
this->m_data.emplace(provider, T());
|
||||||
|
});
|
||||||
|
|
||||||
|
(void)EventManager::subscribe<EventProviderDeleted>([this](prv::Provider *provider){
|
||||||
|
this->m_data.erase(provider);
|
||||||
|
});
|
||||||
|
|
||||||
|
EventManager::subscribe<EventImHexClosing>([this] {
|
||||||
|
this->m_data.clear();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<prv::Provider *, T> m_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -26,6 +26,10 @@ enum ImGuiCustomCol {
|
|||||||
|
|
||||||
ImGuiCustomCol_Highlight,
|
ImGuiCustomCol_Highlight,
|
||||||
|
|
||||||
|
ImGuiCustomCol_IEEEToolSign,
|
||||||
|
ImGuiCustomCol_IEEEToolExp,
|
||||||
|
ImGuiCustomCol_IEEEToolMantissa,
|
||||||
|
|
||||||
ImGuiCustomCol_COUNT
|
ImGuiCustomCol_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -75,6 +79,8 @@ namespace ImGui {
|
|||||||
bool BulletHyperlink(const char *label, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
|
bool BulletHyperlink(const char *label, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
|
||||||
bool DescriptionButton(const char *label, const char *description, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
|
bool DescriptionButton(const char *label, const char *description, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
|
||||||
|
|
||||||
|
void HelpHover(const char *text);
|
||||||
|
|
||||||
void UnderlinedText(const char *label, ImColor color = ImGui::GetStyleColorVec4(ImGuiCol_Text), const ImVec2 &size_arg = ImVec2(0, 0));
|
void UnderlinedText(const char *label, ImColor color = ImGui::GetStyleColorVec4(ImGuiCol_Text), const ImVec2 &size_arg = ImVec2(0, 0));
|
||||||
|
|
||||||
void TextSpinner(const char *label);
|
void TextSpinner(const char *label);
|
||||||
@@ -151,4 +157,7 @@ namespace ImGui {
|
|||||||
|
|
||||||
bool BitCheckbox(const char* label, bool* v);
|
bool BitCheckbox(const char* label, bool* v);
|
||||||
|
|
||||||
|
bool DimmedButton(const char* label);
|
||||||
|
bool DimmedIconButton(const char *symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0));
|
||||||
|
|
||||||
}
|
}
|
||||||
92
lib/libimhex/include/hex/ui/popup.hpp
Normal file
92
lib/libimhex/include/hex/ui/popup.hpp
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hex.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
#include <hex/helpers/utils.hpp>
|
||||||
|
|
||||||
|
#include <hex/api/task.hpp>
|
||||||
|
|
||||||
|
namespace hex {
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
|
||||||
|
class PopupBase {
|
||||||
|
public:
|
||||||
|
explicit PopupBase(std::string unlocalizedName, bool closeButton, bool modal)
|
||||||
|
: m_unlocalizedName(std::move(unlocalizedName)), m_closeButton(closeButton), m_modal(modal) { }
|
||||||
|
|
||||||
|
virtual ~PopupBase() = default;
|
||||||
|
|
||||||
|
virtual void drawContent() = 0;
|
||||||
|
[[nodiscard]] virtual ImGuiWindowFlags getFlags() const { return ImGuiWindowFlags_None; }
|
||||||
|
|
||||||
|
[[nodiscard]] virtual ImVec2 getMinSize() const {
|
||||||
|
return { 0, 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] virtual ImVec2 getMaxSize() const {
|
||||||
|
return { 0, 0 };
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static std::vector<std::unique_ptr<PopupBase>> &getOpenPopups() {
|
||||||
|
return s_openPopups;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const std::string &getUnlocalizedName() const {
|
||||||
|
return this->m_unlocalizedName;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool hasCloseButton() const {
|
||||||
|
return this->m_closeButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool isModal() const {
|
||||||
|
return this->m_modal;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close() {
|
||||||
|
this->m_close = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool shouldClose() const {
|
||||||
|
return this->m_close;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static std::vector<std::unique_ptr<PopupBase>> s_openPopups;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::string m_unlocalizedName;
|
||||||
|
bool m_closeButton, m_modal;
|
||||||
|
std::atomic<bool> m_close = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Popup : public impl::PopupBase {
|
||||||
|
protected:
|
||||||
|
explicit Popup(std::string unlocalizedName, bool closeButton = true, bool modal = true) : PopupBase(std::move(unlocalizedName), closeButton, modal) { }
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<typename ...Args>
|
||||||
|
static void open(Args && ... args) {
|
||||||
|
static std::mutex mutex;
|
||||||
|
std::lock_guard lock(mutex);
|
||||||
|
|
||||||
|
auto popup = std::make_unique<T>(std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
s_openPopups.emplace_back(std::move(popup));
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <hex/api/imhex_api.hpp>
|
#include <hex/api/imhex_api.hpp>
|
||||||
#include <hex/api/event.hpp>
|
#include <hex/api/event.hpp>
|
||||||
#include <hex/providers/provider.hpp>
|
#include <hex/providers/provider.hpp>
|
||||||
|
#include <hex/providers/provider_data.hpp>
|
||||||
#include <hex/helpers/utils.hpp>
|
#include <hex/helpers/utils.hpp>
|
||||||
|
|
||||||
#include <hex/api/localization.hpp>
|
#include <hex/api/localization.hpp>
|
||||||
@@ -34,13 +35,6 @@ namespace hex {
|
|||||||
[[nodiscard]] virtual bool isAvailable() const;
|
[[nodiscard]] virtual bool isAvailable() const;
|
||||||
[[nodiscard]] virtual bool shouldProcess() const { return this->isAvailable() && this->getWindowOpenState(); }
|
[[nodiscard]] virtual bool shouldProcess() const { return this->isAvailable() && this->getWindowOpenState(); }
|
||||||
|
|
||||||
static void showInfoPopup(const std::string &message);
|
|
||||||
static void showErrorPopup(const std::string &message);
|
|
||||||
static void showFatalPopup(const std::string &message);
|
|
||||||
static void showYesNoQuestionPopup(const std::string &message, const std::function<void()> &yesCallback, const std::function<void()> &noCallback);
|
|
||||||
|
|
||||||
static void showFileChooserPopup(const std::vector<std::fs::path> &paths, const std::vector<nfdfilteritem_t> &validExtensions, bool multiple, const std::function<void(std::fs::path)> &callback);
|
|
||||||
|
|
||||||
[[nodiscard]] virtual bool hasViewMenuItemEntry() const;
|
[[nodiscard]] virtual bool hasViewMenuItemEntry() const;
|
||||||
[[nodiscard]] virtual ImVec2 getMinSize() const;
|
[[nodiscard]] virtual ImVec2 getMinSize() const;
|
||||||
[[nodiscard]] virtual ImVec2 getMaxSize() const;
|
[[nodiscard]] virtual ImVec2 getMaxSize() const;
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
#include <hex/api/content_registry.hpp>
|
#include <hex/api/content_registry.hpp>
|
||||||
|
|
||||||
#include <hex/helpers/fs.hpp>
|
#include <hex/helpers/fs.hpp>
|
||||||
#include <hex/helpers/file.hpp>
|
|
||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
|
|
||||||
#include <hex/ui/view.hpp>
|
#include <hex/ui/view.hpp>
|
||||||
|
#include <hex/data_processor/node.hpp>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <thread>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include <hex/data_processor/node.hpp>
|
#include <wolv/io/file.hpp>
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
@@ -19,58 +19,89 @@ namespace hex {
|
|||||||
|
|
||||||
constexpr auto SettingsFile = "settings.json";
|
constexpr auto SettingsFile = "settings.json";
|
||||||
|
|
||||||
void load() {
|
namespace impl {
|
||||||
bool loaded = false;
|
|
||||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
|
||||||
fs::File file(dir / SettingsFile, fs::File::Mode::Read);
|
|
||||||
|
|
||||||
if (file.isValid()) {
|
std::map<Category, std::vector<Entry>> &getEntries() {
|
||||||
getSettingsData() = nlohmann::json::parse(file.readString());
|
static std::map<Category, std::vector<Entry>> entries;
|
||||||
loaded = true;
|
|
||||||
break;
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, std::string> &getCategoryDescriptions() {
|
||||||
|
static std::map<std::string, std::string> descriptions;
|
||||||
|
|
||||||
|
return descriptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName) {
|
||||||
|
auto &settings = getSettingsData();
|
||||||
|
|
||||||
|
if (!settings.contains(unlocalizedCategory)) return {};
|
||||||
|
if (!settings[unlocalizedCategory].contains(unlocalizedName)) return {};
|
||||||
|
|
||||||
|
return settings[unlocalizedCategory][unlocalizedName];
|
||||||
|
}
|
||||||
|
|
||||||
|
nlohmann::json &getSettingsData() {
|
||||||
|
static nlohmann::json settings;
|
||||||
|
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load() {
|
||||||
|
bool loaded = false;
|
||||||
|
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||||
|
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Read);
|
||||||
|
|
||||||
|
if (file.isValid()) {
|
||||||
|
getSettingsData() = nlohmann::json::parse(file.readString());
|
||||||
|
loaded = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!loaded)
|
||||||
|
store();
|
||||||
|
}
|
||||||
|
|
||||||
|
void store() {
|
||||||
|
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||||
|
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Create);
|
||||||
|
|
||||||
|
if (file.isValid()) {
|
||||||
|
file.writeString(getSettingsData().dump(4));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!loaded)
|
void clear() {
|
||||||
store();
|
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||||
}
|
wolv::io::fs::remove(dir / SettingsFile);
|
||||||
|
|
||||||
void store() {
|
|
||||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
|
||||||
fs::File file(dir / SettingsFile, fs::File::Mode::Create);
|
|
||||||
|
|
||||||
if (file.isValid()) {
|
|
||||||
file.write(getSettingsData().dump(4));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
static auto getCategoryEntry(const std::string &unlocalizedCategory) {
|
||||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
auto &entries = getEntries();
|
||||||
hex::fs::remove(dir / SettingsFile);
|
const size_t curSlot = entries.size();
|
||||||
}
|
auto found = entries.find(Category { unlocalizedCategory });
|
||||||
}
|
|
||||||
|
|
||||||
static auto getCategoryEntry(const std::string &unlocalizedCategory) {
|
if (found == entries.end()) {
|
||||||
auto &entries = getEntries();
|
auto [iter, _] = entries.emplace(Category { unlocalizedCategory, curSlot }, std::vector<Entry> {});
|
||||||
const size_t curSlot = entries.size();
|
return iter;
|
||||||
auto found = entries.find(Category { unlocalizedCategory });
|
}
|
||||||
|
|
||||||
if (found == entries.end()) {
|
return found;
|
||||||
auto [iter, _] = entries.emplace(Category { unlocalizedCategory, curSlot }, std::vector<Entry> {});
|
|
||||||
return iter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const Callback &callback, bool requiresRestart) {
|
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const impl::Callback &callback, bool requiresRestart) {
|
||||||
log::debug("Registered new integer setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
|
log::debug("Registered new integer setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
|
||||||
|
|
||||||
getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback });
|
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
|
||||||
|
|
||||||
auto &json = getSettingsData();
|
auto &json = impl::getSettingsData();
|
||||||
|
|
||||||
if (!json.contains(unlocalizedCategory))
|
if (!json.contains(unlocalizedCategory))
|
||||||
json[unlocalizedCategory] = nlohmann::json::object();
|
json[unlocalizedCategory] = nlohmann::json::object();
|
||||||
@@ -78,12 +109,12 @@ namespace hex {
|
|||||||
json[unlocalizedCategory][unlocalizedName] = int(defaultValue);
|
json[unlocalizedCategory][unlocalizedName] = int(defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback, bool requiresRestart) {
|
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const impl::Callback &callback, bool requiresRestart) {
|
||||||
log::debug("Registered new string setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
|
log::debug("Registered new string setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
|
||||||
|
|
||||||
getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback });
|
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
|
||||||
|
|
||||||
auto &json = getSettingsData();
|
auto &json = impl::getSettingsData();
|
||||||
|
|
||||||
if (!json.contains(unlocalizedCategory))
|
if (!json.contains(unlocalizedCategory))
|
||||||
json[unlocalizedCategory] = nlohmann::json::object();
|
json[unlocalizedCategory] = nlohmann::json::object();
|
||||||
@@ -91,12 +122,12 @@ namespace hex {
|
|||||||
json[unlocalizedCategory][unlocalizedName] = std::string(defaultValue);
|
json[unlocalizedCategory][unlocalizedName] = std::string(defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const Callback &callback, bool requiresRestart) {
|
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const impl::Callback &callback, bool requiresRestart) {
|
||||||
log::debug("Registered new string array setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
|
log::debug("Registered new string array setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
|
||||||
|
|
||||||
getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback });
|
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
|
||||||
|
|
||||||
auto &json = getSettingsData();
|
auto &json = impl::getSettingsData();
|
||||||
|
|
||||||
if (!json.contains(unlocalizedCategory))
|
if (!json.contains(unlocalizedCategory))
|
||||||
json[unlocalizedCategory] = nlohmann::json::object();
|
json[unlocalizedCategory] = nlohmann::json::object();
|
||||||
@@ -105,11 +136,11 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription) {
|
void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription) {
|
||||||
getCategoryDescriptions()[unlocalizedCategory] = unlocalizedCategoryDescription;
|
impl::getCategoryDescriptions()[unlocalizedCategory] = unlocalizedCategoryDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value) {
|
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value) {
|
||||||
auto &json = getSettingsData();
|
auto &json = impl::getSettingsData();
|
||||||
|
|
||||||
if (!json.contains(unlocalizedCategory))
|
if (!json.contains(unlocalizedCategory))
|
||||||
json[unlocalizedCategory] = nlohmann::json::object();
|
json[unlocalizedCategory] = nlohmann::json::object();
|
||||||
@@ -118,7 +149,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &value) {
|
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &value) {
|
||||||
auto &json = getSettingsData();
|
auto &json = impl::getSettingsData();
|
||||||
|
|
||||||
if (!json.contains(unlocalizedCategory))
|
if (!json.contains(unlocalizedCategory))
|
||||||
json[unlocalizedCategory] = nlohmann::json::object();
|
json[unlocalizedCategory] = nlohmann::json::object();
|
||||||
@@ -127,7 +158,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &value) {
|
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &value) {
|
||||||
auto &json = getSettingsData();
|
auto &json = impl::getSettingsData();
|
||||||
|
|
||||||
if (!json.contains(unlocalizedCategory))
|
if (!json.contains(unlocalizedCategory))
|
||||||
json[unlocalizedCategory] = nlohmann::json::object();
|
json[unlocalizedCategory] = nlohmann::json::object();
|
||||||
@@ -137,7 +168,7 @@ namespace hex {
|
|||||||
|
|
||||||
|
|
||||||
i64 read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue) {
|
i64 read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue) {
|
||||||
auto &json = getSettingsData();
|
auto &json = impl::getSettingsData();
|
||||||
|
|
||||||
if (!json.contains(unlocalizedCategory))
|
if (!json.contains(unlocalizedCategory))
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
@@ -151,7 +182,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue) {
|
std::string read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue) {
|
||||||
auto &json = getSettingsData();
|
auto &json = impl::getSettingsData();
|
||||||
|
|
||||||
if (!json.contains(unlocalizedCategory))
|
if (!json.contains(unlocalizedCategory))
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
@@ -165,7 +196,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue) {
|
std::vector<std::string> read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue) {
|
||||||
auto &json = getSettingsData();
|
auto &json = impl::getSettingsData();
|
||||||
|
|
||||||
if (!json.contains(unlocalizedCategory))
|
if (!json.contains(unlocalizedCategory))
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
@@ -181,49 +212,37 @@ namespace hex {
|
|||||||
return json[unlocalizedCategory][unlocalizedName].get<std::vector<std::string>>();
|
return json[unlocalizedCategory][unlocalizedName].get<std::vector<std::string>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::map<Category, std::vector<Entry>> &getEntries() {
|
|
||||||
static std::map<Category, std::vector<Entry>> entries;
|
|
||||||
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<std::string, std::string> &getCategoryDescriptions() {
|
|
||||||
static std::map<std::string, std::string> descriptions;
|
|
||||||
|
|
||||||
return descriptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName) {
|
|
||||||
auto &settings = getSettingsData();
|
|
||||||
|
|
||||||
if (!settings.contains(unlocalizedCategory)) return {};
|
|
||||||
if (!settings[unlocalizedCategory].contains(unlocalizedName)) return {};
|
|
||||||
|
|
||||||
return settings[unlocalizedCategory][unlocalizedName];
|
|
||||||
}
|
|
||||||
|
|
||||||
nlohmann::json &getSettingsData() {
|
|
||||||
static nlohmann::json settings;
|
|
||||||
|
|
||||||
return settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace ContentRegistry::CommandPaletteCommands {
|
namespace ContentRegistry::CommandPaletteCommands {
|
||||||
|
|
||||||
void add(Type type, const std::string &command, const std::string &unlocalizedDescription, const DisplayCallback &displayCallback, const ExecuteCallback &executeCallback) {
|
void add(Type type, const std::string &command, const std::string &unlocalizedDescription, const impl::DisplayCallback &displayCallback, const impl::ExecuteCallback &executeCallback) {
|
||||||
log::debug("Registered new command palette command: {}", command);
|
log::debug("Registered new command palette command: {}", command);
|
||||||
|
|
||||||
getEntries().push_back(ContentRegistry::CommandPaletteCommands::Entry { type, command, unlocalizedDescription, displayCallback, executeCallback });
|
impl::getEntries().push_back(ContentRegistry::CommandPaletteCommands::impl::Entry { type, command, unlocalizedDescription, displayCallback, executeCallback });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Entry> &getEntries() {
|
void addHandler(Type type, const std::string &command, const impl::QueryCallback &queryCallback, const impl::DisplayCallback &displayCallback) {
|
||||||
static std::vector<Entry> commands;
|
log::debug("Registered new command palette command handler: {}", command);
|
||||||
|
|
||||||
|
impl::getHandlers().push_back(ContentRegistry::CommandPaletteCommands::impl::Handler { type, command, queryCallback, displayCallback });
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
|
||||||
|
std::vector<Entry> &getEntries() {
|
||||||
|
static std::vector<Entry> commands;
|
||||||
|
|
||||||
|
return commands;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Handler> &getHandlers() {
|
||||||
|
static std::vector<Handler> commands;
|
||||||
|
|
||||||
|
return commands;
|
||||||
|
}
|
||||||
|
|
||||||
return commands;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -241,6 +260,18 @@ namespace hex {
|
|||||||
return functionName;
|
return functionName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pl::PatternLanguage& getRuntime() {
|
||||||
|
static PerProvider<pl::PatternLanguage> runtime;
|
||||||
|
|
||||||
|
return *runtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::mutex& getRuntimeLock() {
|
||||||
|
static std::mutex runtimeLock;
|
||||||
|
|
||||||
|
return runtimeLock;
|
||||||
|
}
|
||||||
|
|
||||||
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider) {
|
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider) {
|
||||||
runtime.reset();
|
runtime.reset();
|
||||||
|
|
||||||
@@ -258,14 +289,14 @@ namespace hex {
|
|||||||
|
|
||||||
runtime.setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude) | fs::getDefaultPaths(fs::ImHexPath::Patterns));
|
runtime.setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude) | fs::getDefaultPaths(fs::ImHexPath::Patterns));
|
||||||
|
|
||||||
for (const auto &func : getFunctions()) {
|
for (const auto &func : impl::getFunctions()) {
|
||||||
if (func.dangerous)
|
if (func.dangerous)
|
||||||
runtime.addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback);
|
runtime.addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||||
else
|
else
|
||||||
runtime.addFunction(func.ns, func.name, func.parameterCount, func.callback);
|
runtime.addFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &[name, callback] : getPragmas()) {
|
for (const auto &[name, callback] : impl::getPragmas()) {
|
||||||
runtime.addPragma(name, callback);
|
runtime.addPragma(name, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,13 +307,13 @@ namespace hex {
|
|||||||
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
|
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
|
||||||
log::debug("Registered new pattern language pragma: {}", name);
|
log::debug("Registered new pattern language pragma: {}", name);
|
||||||
|
|
||||||
getPragmas()[name] = handler;
|
impl::getPragmas()[name] = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) {
|
void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) {
|
||||||
log::debug("Registered new pattern language function: {}", getFunctionName(ns, name));
|
log::debug("Registered new pattern language function: {}", getFunctionName(ns, name));
|
||||||
|
|
||||||
getFunctions().push_back({
|
impl::getFunctions().push_back({
|
||||||
ns, name,
|
ns, name,
|
||||||
parameterCount, func,
|
parameterCount, func,
|
||||||
false
|
false
|
||||||
@@ -292,7 +323,7 @@ namespace hex {
|
|||||||
void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) {
|
void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) {
|
||||||
log::debug("Registered new dangerous pattern language function: {}", getFunctionName(ns, name));
|
log::debug("Registered new dangerous pattern language function: {}", getFunctionName(ns, name));
|
||||||
|
|
||||||
getFunctions().push_back({
|
impl::getFunctions().push_back({
|
||||||
ns, name,
|
ns, name,
|
||||||
parameterCount, func,
|
parameterCount, func,
|
||||||
true
|
true
|
||||||
@@ -300,51 +331,61 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::map<std::string, impl::Visualizer> &impl::getVisualizers() {
|
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, u32 parameterCount) {
|
||||||
static std::map<std::string, impl::Visualizer> visualizers;
|
|
||||||
|
|
||||||
return visualizers;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addVisualizer(const std::string &name, const VisualizerFunctionCallback &function, u32 parameterCount) {
|
|
||||||
log::debug("Registered new pattern visualizer function: {}", name);
|
log::debug("Registered new pattern visualizer function: {}", name);
|
||||||
impl::getVisualizers()[name] = impl::Visualizer { parameterCount, function };
|
impl::getVisualizers()[name] = impl::Visualizer { parameterCount, function };
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, pl::api::PragmaHandler> &getPragmas() {
|
|
||||||
static std::map<std::string, pl::api::PragmaHandler> pragmas;
|
|
||||||
|
|
||||||
return pragmas;
|
namespace impl {
|
||||||
|
|
||||||
|
std::map<std::string, impl::Visualizer> &getVisualizers() {
|
||||||
|
static std::map<std::string, impl::Visualizer> visualizers;
|
||||||
|
|
||||||
|
return visualizers;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, pl::api::PragmaHandler> &getPragmas() {
|
||||||
|
static std::map<std::string, pl::api::PragmaHandler> pragmas;
|
||||||
|
|
||||||
|
return pragmas;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<impl::FunctionDefinition> &getFunctions() {
|
||||||
|
static std::vector<impl::FunctionDefinition> functions;
|
||||||
|
|
||||||
|
return functions;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<impl::FunctionDefinition> &getFunctions() {
|
|
||||||
static std::vector<impl::FunctionDefinition> functions;
|
|
||||||
|
|
||||||
return functions;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
namespace ContentRegistry::Views {
|
namespace ContentRegistry::Views {
|
||||||
|
|
||||||
void impl::add(View *view) {
|
namespace impl {
|
||||||
|
|
||||||
|
std::map<std::string, std::unique_ptr<View>> &getEntries() {
|
||||||
|
static std::map<std::string, std::unique_ptr<View>> views;
|
||||||
|
|
||||||
|
return views;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void impl::add(std::unique_ptr<View> &&view) {
|
||||||
log::debug("Registered new view: {}", view->getUnlocalizedName());
|
log::debug("Registered new view: {}", view->getUnlocalizedName());
|
||||||
|
|
||||||
getEntries().insert({ view->getUnlocalizedName(), view });
|
impl::getEntries().insert({ view->getUnlocalizedName(), std::move(view) });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, View *> &getEntries() {
|
View* getViewByName(const std::string &unlocalizedName) {
|
||||||
static std::map<std::string, View *> views;
|
auto &views = impl::getEntries();
|
||||||
|
|
||||||
return views;
|
|
||||||
}
|
|
||||||
|
|
||||||
View *getViewByName(const std::string &unlocalizedName) {
|
|
||||||
auto &views = getEntries();
|
|
||||||
|
|
||||||
if (views.contains(unlocalizedName))
|
if (views.contains(unlocalizedName))
|
||||||
return views[unlocalizedName];
|
return views[unlocalizedName].get();
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -356,13 +397,17 @@ namespace hex {
|
|||||||
void add(const std::string &unlocalizedName, const impl::Callback &function) {
|
void add(const std::string &unlocalizedName, const impl::Callback &function) {
|
||||||
log::debug("Registered new tool: {}", unlocalizedName);
|
log::debug("Registered new tool: {}", unlocalizedName);
|
||||||
|
|
||||||
getEntries().emplace_back(impl::Entry { unlocalizedName, function, false });
|
impl::getEntries().emplace_back(impl::Entry { unlocalizedName, function, false });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<impl::Entry> &getEntries() {
|
namespace impl {
|
||||||
static std::vector<impl::Entry> entries;
|
|
||||||
|
std::vector<Entry> &getEntries() {
|
||||||
|
static std::vector<Entry> tools;
|
||||||
|
|
||||||
|
return tools;
|
||||||
|
}
|
||||||
|
|
||||||
return entries;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -372,21 +417,26 @@ namespace hex {
|
|||||||
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
|
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
|
||||||
log::debug("Registered new data inspector format: {}", unlocalizedName);
|
log::debug("Registered new data inspector format: {}", unlocalizedName);
|
||||||
|
|
||||||
getEntries().push_back({ unlocalizedName, requiredSize, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
|
impl::getEntries().push_back({ unlocalizedName, requiredSize, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
|
void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
|
||||||
log::debug("Registered new data inspector format: {}", unlocalizedName);
|
log::debug("Registered new data inspector format: {}", unlocalizedName);
|
||||||
|
|
||||||
getEntries().push_back({ unlocalizedName, requiredSize, maxSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
|
impl::getEntries().push_back({ unlocalizedName, requiredSize, maxSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<impl::Entry> &getEntries() {
|
namespace impl {
|
||||||
static std::vector<impl::Entry> entries;
|
|
||||||
|
std::vector<impl::Entry> &getEntries() {
|
||||||
|
static std::vector<impl::Entry> entries;
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
return entries;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ContentRegistry::DataProcessorNode {
|
namespace ContentRegistry::DataProcessorNode {
|
||||||
@@ -398,13 +448,17 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void addSeparator() {
|
void addSeparator() {
|
||||||
getEntries().push_back({ "", "", [] { return nullptr; } });
|
impl::getEntries().push_back({ "", "", [] { return nullptr; } });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<impl::Entry> &getEntries() {
|
namespace impl {
|
||||||
static std::vector<impl::Entry> nodes;
|
|
||||||
|
std::vector<impl::Entry> &getEntries() {
|
||||||
|
static std::vector<impl::Entry> nodes;
|
||||||
|
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
return nodes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -437,7 +491,7 @@ namespace hex {
|
|||||||
LangEntry::setFallbackLanguage(code.get<std::string>());
|
LangEntry::setFallbackLanguage(code.get<std::string>());
|
||||||
}
|
}
|
||||||
|
|
||||||
getLanguages().insert({ code.get<std::string>(), hex::format("{} ({})", language.get<std::string>(), country.get<std::string>()) });
|
impl::getLanguages().insert({ code.get<std::string>(), hex::format("{} ({})", language.get<std::string>(), country.get<std::string>()) });
|
||||||
|
|
||||||
std::map<std::string, std::string> translationDefinitions;
|
std::map<std::string, std::string> translationDefinitions;
|
||||||
for (auto &[key, value] : translations.items()) {
|
for (auto &[key, value] : translations.items()) {
|
||||||
@@ -449,20 +503,25 @@ namespace hex {
|
|||||||
translationDefinitions[key] = value.get<std::string>();
|
translationDefinitions[key] = value.get<std::string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
getLanguageDefinitions()[code.get<std::string>()].emplace_back(std::move(translationDefinitions));
|
impl::getLanguageDefinitions()[code.get<std::string>()].emplace_back(std::move(translationDefinitions));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, std::string> &getLanguages() {
|
namespace impl {
|
||||||
static std::map<std::string, std::string> languages;
|
|
||||||
|
std::map<std::string, std::string> &getLanguages() {
|
||||||
|
static std::map<std::string, std::string> languages;
|
||||||
|
|
||||||
|
return languages;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, std::vector<LanguageDefinition>> &getLanguageDefinitions() {
|
||||||
|
static std::map<std::string, std::vector<LanguageDefinition>> definitions;
|
||||||
|
|
||||||
|
return definitions;
|
||||||
|
}
|
||||||
|
|
||||||
return languages;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, std::vector<LanguageDefinition>> &getLanguageDefinitions() {
|
|
||||||
static std::map<std::string, std::vector<LanguageDefinition>> definitions;
|
|
||||||
|
|
||||||
return definitions;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -471,85 +530,97 @@ namespace hex {
|
|||||||
void registerMainMenuItem(const std::string &unlocalizedName, u32 priority) {
|
void registerMainMenuItem(const std::string &unlocalizedName, u32 priority) {
|
||||||
log::debug("Registered new main menu item: {}", unlocalizedName);
|
log::debug("Registered new main menu item: {}", unlocalizedName);
|
||||||
|
|
||||||
getMainMenuItems().insert({ priority, { unlocalizedName } });
|
impl::getMainMenuItems().insert({ priority, { unlocalizedName } });
|
||||||
}
|
}
|
||||||
|
|
||||||
void addMenuItem(const std::string &unlocalizedMainMenuName, u32 priority, const impl::DrawCallback &function) {
|
void addMenuItem(const std::vector<std::string> &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, View *view) {
|
||||||
log::debug("Added new menu item to menu {} with priority {}", unlocalizedMainMenuName, priority);
|
log::debug("Added new menu item to menu {} with priority {}", wolv::util::combineStrings(unlocalizedMainMenuNames, " -> "), priority);
|
||||||
|
|
||||||
getMenuItems().insert({
|
impl::getMenuItems().insert({
|
||||||
priority, {unlocalizedMainMenuName, function}
|
priority, { unlocalizedMainMenuNames, shortcut, function, enabledCallback }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (shortcut.isLocal() && view != nullptr)
|
||||||
|
ShortcutManager::addShortcut(view, shortcut, function);
|
||||||
|
else
|
||||||
|
ShortcutManager::addGlobalShortcut(shortcut, function);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addMenuItemSubMenu(std::vector<std::string> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback) {
|
||||||
|
log::debug("Added new menu item sub menu to menu {} with priority {}", wolv::util::combineStrings(unlocalizedMainMenuNames, " -> "), priority);
|
||||||
|
|
||||||
|
unlocalizedMainMenuNames.emplace_back(impl::SubMenuValue);
|
||||||
|
impl::getMenuItems().insert({
|
||||||
|
priority, { unlocalizedMainMenuNames, {}, function, enabledCallback }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void addMenuItemSeparator(std::vector<std::string> unlocalizedMainMenuNames, u32 priority) {
|
||||||
|
unlocalizedMainMenuNames.emplace_back(impl::SeparatorValue);
|
||||||
|
impl::getMenuItems().insert({
|
||||||
|
priority, { unlocalizedMainMenuNames, {}, []{}, []{ return true; } }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void addWelcomeScreenEntry(const impl::DrawCallback &function) {
|
void addWelcomeScreenEntry(const impl::DrawCallback &function) {
|
||||||
getWelcomeScreenEntries().push_back(function);
|
impl::getWelcomeScreenEntries().push_back(function);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addFooterItem(const impl::DrawCallback &function) {
|
void addFooterItem(const impl::DrawCallback &function) {
|
||||||
getFooterItems().push_back(function);
|
impl::getFooterItems().push_back(function);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addToolbarItem(const impl::DrawCallback &function) {
|
void addToolbarItem(const impl::DrawCallback &function) {
|
||||||
getToolbarItems().push_back(function);
|
impl::getToolbarItems().push_back(function);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function) {
|
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function) {
|
||||||
getSidebarItems().push_back({ icon, function });
|
impl::getSidebarItems().push_back({ icon, function });
|
||||||
}
|
}
|
||||||
|
|
||||||
void addTitleBarButton(const std::string &icon, const std::string &unlocalizedTooltip, const impl::ClickCallback &function) {
|
void addTitleBarButton(const std::string &icon, const std::string &unlocalizedTooltip, const impl::ClickCallback &function) {
|
||||||
getTitleBarButtons().push_back({ icon, unlocalizedTooltip, function });
|
impl::getTitleBarButtons().push_back({ icon, unlocalizedTooltip, function });
|
||||||
}
|
}
|
||||||
|
|
||||||
void addLayout(const std::string &unlocalizedName, const impl::LayoutFunction &function) {
|
namespace impl {
|
||||||
log::debug("Added new layout: {}", unlocalizedName);
|
|
||||||
|
|
||||||
getLayouts().push_back({ unlocalizedName, function });
|
std::multimap<u32, impl::MainMenuItem> &getMainMenuItems() {
|
||||||
}
|
static std::multimap<u32, impl::MainMenuItem> items;
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
std::multimap<u32, impl::MenuItem> &getMenuItems() {
|
||||||
|
static std::multimap<u32, impl::MenuItem> items;
|
||||||
|
|
||||||
std::multimap<u32, impl::MainMenuItem> &getMainMenuItems() {
|
return items;
|
||||||
static std::multimap<u32, impl::MainMenuItem> items;
|
}
|
||||||
|
|
||||||
return items;
|
std::vector<impl::DrawCallback> &getWelcomeScreenEntries() {
|
||||||
}
|
static std::vector<impl::DrawCallback> entries;
|
||||||
std::multimap<u32, impl::MenuItem> &getMenuItems() {
|
|
||||||
static std::multimap<u32, impl::MenuItem> items;
|
|
||||||
|
|
||||||
return items;
|
return entries;
|
||||||
}
|
}
|
||||||
|
std::vector<impl::DrawCallback> &getFooterItems() {
|
||||||
|
static std::vector<impl::DrawCallback> items;
|
||||||
|
|
||||||
std::vector<impl::DrawCallback> &getWelcomeScreenEntries() {
|
return items;
|
||||||
static std::vector<impl::DrawCallback> entries;
|
}
|
||||||
|
std::vector<impl::DrawCallback> &getToolbarItems() {
|
||||||
|
static std::vector<impl::DrawCallback> items;
|
||||||
|
|
||||||
return entries;
|
return items;
|
||||||
}
|
}
|
||||||
std::vector<impl::DrawCallback> &getFooterItems() {
|
std::vector<impl::SidebarItem> &getSidebarItems() {
|
||||||
static std::vector<impl::DrawCallback> items;
|
static std::vector<impl::SidebarItem> items;
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
std::vector<impl::DrawCallback> &getToolbarItems() {
|
std::vector<impl::TitleBarButton> &getTitleBarButtons() {
|
||||||
static std::vector<impl::DrawCallback> items;
|
static std::vector<impl::TitleBarButton> buttons;
|
||||||
|
|
||||||
return items;
|
return buttons;
|
||||||
}
|
}
|
||||||
std::vector<impl::SidebarItem> &getSidebarItems() {
|
|
||||||
static std::vector<impl::SidebarItem> items;
|
|
||||||
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
std::vector<impl::TitleBarButton> &getTitleBarButtons() {
|
|
||||||
static std::vector<impl::TitleBarButton> buttons;
|
|
||||||
|
|
||||||
return buttons;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<impl::Layout> &getLayouts() {
|
|
||||||
static std::vector<impl::Layout> layouts;
|
|
||||||
|
|
||||||
return layouts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -562,12 +633,18 @@ namespace hex {
|
|||||||
getEntries().push_back(unlocalizedName);
|
getEntries().push_back(unlocalizedName);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> &getEntries() {
|
|
||||||
static std::vector<std::string> providerNames;
|
|
||||||
|
|
||||||
return providerNames;
|
namespace impl {
|
||||||
|
|
||||||
|
std::vector<std::string> &getEntries() {
|
||||||
|
static std::vector<std::string> providerNames;
|
||||||
|
|
||||||
|
return providerNames;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ContentRegistry::DataFormatter {
|
namespace ContentRegistry::DataFormatter {
|
||||||
@@ -575,13 +652,17 @@ namespace hex {
|
|||||||
void add(const std::string &unlocalizedName, const impl::Callback &callback) {
|
void add(const std::string &unlocalizedName, const impl::Callback &callback) {
|
||||||
log::debug("Registered new data formatter: {}", unlocalizedName);
|
log::debug("Registered new data formatter: {}", unlocalizedName);
|
||||||
|
|
||||||
getEntries().push_back({ unlocalizedName, callback });
|
impl::getEntries().push_back({ unlocalizedName, callback });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<impl::Entry> &getEntries() {
|
namespace impl {
|
||||||
static std::vector<impl::Entry> entries;
|
|
||||||
|
std::vector<impl::Entry> &getEntries() {
|
||||||
|
static std::vector<impl::Entry> entries;
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
return entries;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -592,13 +673,17 @@ namespace hex {
|
|||||||
for (const auto &extension : extensions)
|
for (const auto &extension : extensions)
|
||||||
log::debug("Registered new data handler for extensions: {}", extension);
|
log::debug("Registered new data handler for extensions: {}", extension);
|
||||||
|
|
||||||
getEntries().push_back({ extensions, callback });
|
impl::getEntries().push_back({ extensions, callback });
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<impl::Entry> &getEntries() {
|
namespace impl {
|
||||||
static std::vector<impl::Entry> entries;
|
|
||||||
|
std::vector<impl::Entry> &getEntries() {
|
||||||
|
static std::vector<impl::Entry> entries;
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
return entries;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -607,7 +692,7 @@ namespace hex {
|
|||||||
|
|
||||||
const int DataVisualizer::TextInputFlags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoHorizontalScroll;
|
const int DataVisualizer::TextInputFlags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoHorizontalScroll;
|
||||||
|
|
||||||
bool DataVisualizer::drawDefaultEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const {
|
bool DataVisualizer::drawDefaultScalarEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const {
|
||||||
struct UserData {
|
struct UserData {
|
||||||
u8 *data;
|
u8 *data;
|
||||||
i32 maxChars;
|
i32 maxChars;
|
||||||
@@ -636,29 +721,127 @@ namespace hex {
|
|||||||
return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Escape);
|
return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Escape);
|
||||||
}
|
}
|
||||||
|
|
||||||
void impl::addDataVisualizer(const std::string &unlocalizedName, DataVisualizer *visualizer) {
|
bool DataVisualizer::drawDefaultTextEditingTextBox(u64 address, std::string &data, ImGuiInputTextFlags flags) const {
|
||||||
getVisualizers().insert({ unlocalizedName, visualizer });
|
struct UserData {
|
||||||
|
std::string *data;
|
||||||
|
i32 maxChars;
|
||||||
|
|
||||||
|
bool editingDone;
|
||||||
|
};
|
||||||
|
|
||||||
|
UserData userData = {
|
||||||
|
.data = &data,
|
||||||
|
.maxChars = this->getMaxCharsPerCell(),
|
||||||
|
|
||||||
|
.editingDone = false
|
||||||
|
};
|
||||||
|
|
||||||
|
ImGui::PushID(reinterpret_cast<void*>(address));
|
||||||
|
ImGui::InputText("##editing_input", data.data(), data.size() + 1, flags | TextInputFlags | ImGuiInputTextFlags_CallbackEdit, [](ImGuiInputTextCallbackData *data) -> int {
|
||||||
|
auto &userData = *reinterpret_cast<UserData*>(data->UserData);
|
||||||
|
|
||||||
|
userData.data->resize(data->BufSize);
|
||||||
|
|
||||||
|
if (data->BufTextLen >= userData.maxChars)
|
||||||
|
userData.editingDone = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}, &userData);
|
||||||
|
ImGui::PopID();
|
||||||
|
|
||||||
|
return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Escape);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
|
||||||
|
void addDataVisualizer(const std::string &unlocalizedName, DataVisualizer *visualizer) {
|
||||||
|
getVisualizers().insert({ unlocalizedName, visualizer });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, DataVisualizer*> &getVisualizers() {
|
||||||
|
static std::map<std::string, DataVisualizer*> visualizers;
|
||||||
|
|
||||||
|
return visualizers;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, DataVisualizer*> &impl::getVisualizers() {
|
|
||||||
static std::map<std::string, DataVisualizer*> visualizers;
|
|
||||||
|
|
||||||
return visualizers;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace ContentRegistry::Hashes {
|
namespace ContentRegistry::Hashes {
|
||||||
|
|
||||||
std::vector<Hash *> &impl::getHashes() {
|
namespace impl {
|
||||||
static std::vector<Hash *> hashes;
|
|
||||||
|
std::vector<Hash *> &getHashes() {
|
||||||
|
static std::vector<Hash *> hashes;
|
||||||
|
|
||||||
|
return hashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(Hash *hash) {
|
||||||
|
getHashes().push_back(hash);
|
||||||
|
}
|
||||||
|
|
||||||
return hashes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void impl::add(Hash *hash) {
|
}
|
||||||
getHashes().push_back(hash);
|
|
||||||
|
namespace ContentRegistry::BackgroundServices {
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
|
||||||
|
std::vector<Service> &getServices() {
|
||||||
|
static std::vector<Service> services;
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopServices() {
|
||||||
|
for (auto &service : getServices()) {
|
||||||
|
service.thread.request_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &service : getServices()) {
|
||||||
|
service.thread.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerService(const std::string &unlocalizedName, const impl::Callback &callback) {
|
||||||
|
log::debug("Registered new background service: {}", unlocalizedName);
|
||||||
|
|
||||||
|
impl::getServices().push_back(impl::Service {
|
||||||
|
unlocalizedName,
|
||||||
|
std::jthread([callback](const std::stop_token &stopToken){
|
||||||
|
while (!stopToken.stop_requested()) {
|
||||||
|
callback();
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ContentRegistry::CommunicationInterface {
|
||||||
|
|
||||||
|
namespace impl {
|
||||||
|
|
||||||
|
std::map<std::string, NetworkCallback> &getNetworkEndpoints() {
|
||||||
|
static std::map<std::string, NetworkCallback> endpoints;
|
||||||
|
|
||||||
|
return endpoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerNetworkEndpoint(const std::string &endpoint, const impl::NetworkCallback &callback) {
|
||||||
|
log::debug("Registered new network endpoint: {}", endpoint);
|
||||||
|
|
||||||
|
impl::getNetworkEndpoints().insert({ endpoint, callback });
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <hex/api/content_registry.hpp>
|
#include <hex/api/content_registry.hpp>
|
||||||
|
|
||||||
#include <hex/api/event.hpp>
|
#include <hex/api/event.hpp>
|
||||||
|
#include <hex/api/task.hpp>
|
||||||
#include <hex/providers/provider.hpp>
|
#include <hex/providers/provider.hpp>
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@@ -19,19 +20,6 @@
|
|||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
namespace ImHexApi::Common {
|
|
||||||
|
|
||||||
void closeImHex(bool noQuestions) {
|
|
||||||
EventManager::post<RequestCloseImHex>(noQuestions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void restartImHex() {
|
|
||||||
EventManager::post<RequestRestartImHex>();
|
|
||||||
EventManager::post<RequestCloseImHex>(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace ImHexApi::HexEditor {
|
namespace ImHexApi::HexEditor {
|
||||||
|
|
||||||
@@ -190,6 +178,10 @@ namespace hex {
|
|||||||
return impl::s_currentSelection;
|
return impl::s_currentSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clearSelection() {
|
||||||
|
impl::s_currentSelection.reset();
|
||||||
|
}
|
||||||
|
|
||||||
void setSelection(const Region ®ion, prv::Provider *provider) {
|
void setSelection(const Region ®ion, prv::Provider *provider) {
|
||||||
setSelection(ProviderRegion { region, provider == nullptr ? Provider::get() : provider });
|
setSelection(ProviderRegion { region, provider == nullptr ? Provider::get() : provider });
|
||||||
}
|
}
|
||||||
@@ -310,8 +302,6 @@ namespace hex {
|
|||||||
if (it == s_providers.end())
|
if (it == s_providers.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
EventManager::post<EventProviderDeleted>(provider);
|
|
||||||
|
|
||||||
if (!s_providers.empty() && it - s_providers.begin() == s_currentProvider)
|
if (!s_providers.empty() && it - s_providers.begin() == s_currentProvider)
|
||||||
setCurrentProvider(0);
|
setCurrentProvider(0);
|
||||||
|
|
||||||
@@ -323,6 +313,7 @@ namespace hex {
|
|||||||
EventManager::post<EventProviderClosed>(provider);
|
EventManager::post<EventProviderClosed>(provider);
|
||||||
|
|
||||||
TaskManager::runWhenTasksFinished([provider] {
|
TaskManager::runWhenTasksFinished([provider] {
|
||||||
|
EventManager::post<EventProviderDeleted>(provider);
|
||||||
delete provider;
|
delete provider;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -408,6 +399,14 @@ namespace hex {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void closeImHex(bool noQuestions) {
|
||||||
|
EventManager::post<RequestCloseImHex>(noQuestions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void restartImHex() {
|
||||||
|
EventManager::post<RequestRestartImHex>();
|
||||||
|
EventManager::post<RequestCloseImHex>(false);
|
||||||
|
}
|
||||||
|
|
||||||
void setTaskBarProgress(TaskProgressState state, TaskProgressType type, u32 progress) {
|
void setTaskBarProgress(TaskProgressState state, TaskProgressType type, u32 progress) {
|
||||||
EventManager::post<EventSetTaskBarIconState>(u32(state), u32(type), progress);
|
EventManager::post<EventSetTaskBarIconState>(u32(state), u32(type), progress);
|
||||||
@@ -433,7 +432,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static float s_targetFPS = 60.0F;
|
static float s_targetFPS = 14.0F;
|
||||||
|
|
||||||
float getTargetFPS() {
|
float getTargetFPS() {
|
||||||
return s_targetFPS;
|
return s_targetFPS;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace hex {
|
|||||||
view->m_shortcuts.insert({ shortcut, callback });
|
view->m_shortcuts.insert({ shortcut, callback });
|
||||||
}
|
}
|
||||||
|
|
||||||
static Shortcut getShortcut(bool ctrl, bool alt, bool shift, bool super, u32 keyCode) {
|
static Shortcut getShortcut(bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode) {
|
||||||
Shortcut pressedShortcut;
|
Shortcut pressedShortcut;
|
||||||
|
|
||||||
if (ctrl)
|
if (ctrl)
|
||||||
@@ -26,21 +26,23 @@ namespace hex {
|
|||||||
pressedShortcut += SHIFT;
|
pressedShortcut += SHIFT;
|
||||||
if (super)
|
if (super)
|
||||||
pressedShortcut += SUPER;
|
pressedShortcut += SUPER;
|
||||||
|
if (focused)
|
||||||
|
pressedShortcut += CurrentView;
|
||||||
|
|
||||||
pressedShortcut += static_cast<Keys>(keyCode);
|
pressedShortcut += static_cast<Keys>(keyCode);
|
||||||
|
|
||||||
return pressedShortcut;
|
return pressedShortcut;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShortcutManager::process(View *currentView, bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode) {
|
void ShortcutManager::process(const std::unique_ptr<View> ¤tView, bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode) {
|
||||||
Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, keyCode);
|
Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, focused, keyCode);
|
||||||
|
|
||||||
if (focused && currentView->m_shortcuts.contains(pressedShortcut))
|
if (currentView->m_shortcuts.contains(pressedShortcut))
|
||||||
currentView->m_shortcuts[pressedShortcut]();
|
currentView->m_shortcuts[pressedShortcut]();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShortcutManager::processGlobals(bool ctrl, bool alt, bool shift, bool super, u32 keyCode) {
|
void ShortcutManager::processGlobals(bool ctrl, bool alt, bool shift, bool super, u32 keyCode) {
|
||||||
Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, keyCode);
|
Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, false, keyCode);
|
||||||
|
|
||||||
if (ShortcutManager::s_globalShortcuts.contains(pressedShortcut))
|
if (ShortcutManager::s_globalShortcuts.contains(pressedShortcut))
|
||||||
ShortcutManager::s_globalShortcuts[pressedShortcut]();
|
ShortcutManager::s_globalShortcuts[pressedShortcut]();
|
||||||
|
|||||||
83
lib/libimhex/source/api/layout_manager.cpp
Normal file
83
lib/libimhex/source/api/layout_manager.cpp
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
#include <hex/api/layout_manager.hpp>
|
||||||
|
|
||||||
|
#include <hex/helpers/fs.hpp>
|
||||||
|
#include <wolv/utils/string.hpp>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
namespace hex {
|
||||||
|
|
||||||
|
std::optional<std::fs::path> LayoutManager::s_layoutPathToLoad;
|
||||||
|
std::optional<std::string> LayoutManager::s_layoutStringToLoad;
|
||||||
|
std::vector<LayoutManager::Layout> LayoutManager::s_layouts;
|
||||||
|
|
||||||
|
void LayoutManager::load(const std::fs::path &path) {
|
||||||
|
s_layoutPathToLoad = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::loadString(const std::string &content) {
|
||||||
|
s_layoutStringToLoad = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::save(const std::string &name) {
|
||||||
|
auto fileName = name;
|
||||||
|
fileName = wolv::util::replaceStrings(fileName, " ", "_");
|
||||||
|
std::transform(fileName.begin(), fileName.end(), fileName.begin(), tolower);
|
||||||
|
fileName += ".hexlyt";
|
||||||
|
|
||||||
|
const auto path = hex::fs::getDefaultPaths(fs::ImHexPath::Layouts).front() / fileName;
|
||||||
|
ImGui::SaveIniSettingsToDisk(wolv::util::toUTF8String(path).c_str());
|
||||||
|
|
||||||
|
LayoutManager::reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<LayoutManager::Layout> LayoutManager::getLayouts() {
|
||||||
|
return s_layouts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::process() {
|
||||||
|
if (s_layoutPathToLoad.has_value()) {
|
||||||
|
ImGui::LoadIniSettingsFromDisk(wolv::util::toUTF8String(*s_layoutPathToLoad).c_str());
|
||||||
|
s_layoutPathToLoad = std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_layoutStringToLoad.has_value()) {
|
||||||
|
ImGui::LoadIniSettingsFromMemory(s_layoutStringToLoad->c_str());
|
||||||
|
s_layoutStringToLoad = std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::reload() {
|
||||||
|
s_layouts.clear();
|
||||||
|
|
||||||
|
for (const auto &directory : hex::fs::getDefaultPaths(fs::ImHexPath::Layouts)) {
|
||||||
|
for (const auto &entry : std::fs::directory_iterator(directory)) {
|
||||||
|
const auto &path = entry.path();
|
||||||
|
|
||||||
|
if (path.extension() != ".hexlyt")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto name = path.stem().string();
|
||||||
|
name = wolv::util::replaceStrings(name, "_", " ");
|
||||||
|
for (size_t i = 0; i < name.size(); i++) {
|
||||||
|
if (i == 0 || name[i - 1] == '_')
|
||||||
|
name[i] = char(std::toupper(name[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
s_layouts.push_back({
|
||||||
|
name,
|
||||||
|
path
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LayoutManager::reset() {
|
||||||
|
s_layoutPathToLoad.reset();
|
||||||
|
s_layoutStringToLoad.reset();
|
||||||
|
s_layouts.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -76,7 +76,7 @@ namespace hex {
|
|||||||
void LangEntry::loadLanguage(const std::string &language) {
|
void LangEntry::loadLanguage(const std::string &language) {
|
||||||
LangEntry::s_currStrings.clear();
|
LangEntry::s_currStrings.clear();
|
||||||
|
|
||||||
auto &definitions = ContentRegistry::Language::getLanguageDefinitions();
|
auto &definitions = ContentRegistry::Language::impl::getLanguageDefinitions();
|
||||||
|
|
||||||
if (!definitions.contains(language))
|
if (!definitions.contains(language))
|
||||||
return;
|
return;
|
||||||
@@ -92,7 +92,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const std::map<std::string, std::string> &LangEntry::getSupportedLanguages() {
|
const std::map<std::string, std::string> &LangEntry::getSupportedLanguages() {
|
||||||
return ContentRegistry::Language::getLanguages();
|
return ContentRegistry::Language::impl::getLanguages();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LangEntry::setFallbackLanguage(const std::string &language) {
|
void LangEntry::setFallbackLanguage(const std::string &language) {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
#include <hex/helpers/utils.hpp>
|
#include <hex/helpers/utils.hpp>
|
||||||
|
|
||||||
|
#include <wolv/utils/string.hpp>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
|
||||||
@@ -17,7 +19,7 @@ namespace hex {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
this->m_handle = dlopen(hex::toUTF8String(path).c_str(), RTLD_LAZY);
|
this->m_handle = dlopen(wolv::util::toUTF8String(path).c_str(), RTLD_LAZY);
|
||||||
|
|
||||||
if (this->m_handle == nullptr) {
|
if (this->m_handle == nullptr) {
|
||||||
log::error("dlopen failed: {}!", dlerror());
|
log::error("dlopen failed: {}!", dlerror());
|
||||||
@@ -69,7 +71,7 @@ namespace hex {
|
|||||||
bool Plugin::initializePlugin() const {
|
bool Plugin::initializePlugin() const {
|
||||||
const auto requestedVersion = getCompatibleVersion();
|
const auto requestedVersion = getCompatibleVersion();
|
||||||
if (requestedVersion != IMHEX_VERSION) {
|
if (requestedVersion != IMHEX_VERSION) {
|
||||||
log::error("Refused to load plugin '{}' which was built for a different version of ImHex: '{}'", hex::toUTF8String(this->m_path.filename()), requestedVersion);
|
log::error("Refused to load plugin '{}' which was built for a different version of ImHex: '{}'", wolv::util::toUTF8String(this->m_path.filename()), requestedVersion);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +147,7 @@ namespace hex {
|
|||||||
std::vector<Plugin> PluginManager::s_plugins;
|
std::vector<Plugin> PluginManager::s_plugins;
|
||||||
|
|
||||||
bool PluginManager::load(const std::fs::path &pluginFolder) {
|
bool PluginManager::load(const std::fs::path &pluginFolder) {
|
||||||
if (!fs::exists(pluginFolder))
|
if (!wolv::io::fs::exists(pluginFolder))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
PluginManager::s_pluginFolder = pluginFolder;
|
PluginManager::s_pluginFolder = pluginFolder;
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
|
|
||||||
#include <hex/providers/provider.hpp>
|
#include <hex/providers/provider.hpp>
|
||||||
|
|
||||||
|
#include <wolv/utils/guards.hpp>
|
||||||
|
#include <wolv/io/fs.hpp>
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
constexpr static auto MetadataHeaderMagic = "HEX";
|
constexpr static auto MetadataHeaderMagic = "HEX";
|
||||||
@@ -24,7 +27,7 @@ namespace hex {
|
|||||||
ProjectFile::s_currProjectPath = originalPath;
|
ProjectFile::s_currProjectPath = originalPath;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!fs::exists(filePath) || !fs::isRegularFile(filePath))
|
if (!wolv::io::fs::exists(filePath) || !wolv::io::fs::isRegularFile(filePath))
|
||||||
return false;
|
return false;
|
||||||
if (filePath.extension() != ".hexproj")
|
if (filePath.extension() != ".hexproj")
|
||||||
return false;
|
return false;
|
||||||
@@ -37,7 +40,7 @@ namespace hex {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
{
|
{
|
||||||
const auto metadataContent = tar.read(MetadataPath);
|
const auto metadataContent = tar.readVector(MetadataPath);
|
||||||
|
|
||||||
if (!std::string(metadataContent.begin(), metadataContent.end()).starts_with(MetadataHeaderMagic))
|
if (!std::string(metadataContent.begin(), metadataContent.end()).starts_with(MetadataHeaderMagic))
|
||||||
return false;
|
return false;
|
||||||
@@ -106,29 +109,33 @@ namespace hex {
|
|||||||
bool result = true;
|
bool result = true;
|
||||||
for (const auto &handler : ProjectFile::getHandlers()) {
|
for (const auto &handler : ProjectFile::getHandlers()) {
|
||||||
try {
|
try {
|
||||||
if (!handler.store(handler.basePath, tar))
|
if (!handler.store(handler.basePath, tar) && handler.required)
|
||||||
result = false;
|
result = false;
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
log::info("{}", e.what());
|
log::info("{}", e.what());
|
||||||
result = false;
|
|
||||||
|
if (handler.required)
|
||||||
|
result = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
||||||
const auto basePath = std::fs::path(std::to_string(provider->getID()));
|
const auto basePath = std::fs::path(std::to_string(provider->getID()));
|
||||||
for (const auto &handler: ProjectFile::getProviderHandlers()) {
|
for (const auto &handler: ProjectFile::getProviderHandlers()) {
|
||||||
try {
|
try {
|
||||||
if (!handler.store(provider, basePath / handler.basePath, tar))
|
if (!handler.store(provider, basePath / handler.basePath, tar) && handler.required)
|
||||||
result = false;
|
result = false;
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
log::info("{}", e.what());
|
log::info("{}", e.what());
|
||||||
result = false;
|
|
||||||
|
if (handler.required)
|
||||||
|
result = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const auto metadataContent = hex::format("{}\n{}", MetadataHeaderMagic, IMHEX_VERSION);
|
const auto metadataContent = hex::format("{}\n{}", MetadataHeaderMagic, IMHEX_VERSION);
|
||||||
tar.write(MetadataPath, metadataContent);
|
tar.writeString(MetadataPath, metadataContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImHexApi::Provider::resetDirty();
|
ImHexApi::Provider::resetDirty();
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace hex {
|
|||||||
void Task::update(u64 value) {
|
void Task::update(u64 value) {
|
||||||
this->m_currValue = value;
|
this->m_currValue = value;
|
||||||
|
|
||||||
if (this->m_shouldInterrupt)
|
if (this->m_shouldInterrupt) [[unlikely]]
|
||||||
throw TaskInterruptor();
|
throw TaskInterruptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,6 +165,14 @@ namespace hex {
|
|||||||
task->interrupt();
|
task->interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 TaskHolder::getProgress() const {
|
||||||
|
if (this->m_task.expired())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
auto task = this->m_task.lock();
|
||||||
|
return (u32)((task->getValue() * 100) / task->getMaxValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void TaskManager::init() {
|
void TaskManager::init() {
|
||||||
for (u32 i = 0; i < std::thread::hardware_concurrency(); i++)
|
for (u32 i = 0; i < std::thread::hardware_concurrency(); i++)
|
||||||
@@ -184,7 +192,6 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TaskManager::runner(const std::stop_token &stopToken) {
|
void TaskManager::runner(const std::stop_token &stopToken) {
|
||||||
std::mutex mutex;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
std::shared_ptr<Task> task;
|
std::shared_ptr<Task> task;
|
||||||
{
|
{
|
||||||
@@ -239,12 +246,13 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TaskManager::collectGarbage() {
|
void TaskManager::collectGarbage() {
|
||||||
std::unique_lock lock1(s_queueMutex);
|
{
|
||||||
std::unique_lock lock2(s_deferredCallsMutex);
|
std::unique_lock lock1(s_queueMutex);
|
||||||
|
std::erase_if(s_tasks, [](const auto &task) { return task->isFinished() && !task->hadException(); });
|
||||||
std::erase_if(s_tasks, [](const auto &task) { return task->isFinished() && !task->hadException(); });
|
}
|
||||||
|
|
||||||
if (s_tasks.empty()) {
|
if (s_tasks.empty()) {
|
||||||
|
std::unique_lock lock2(s_deferredCallsMutex);
|
||||||
for (auto &call : s_tasksFinishedCallbacks)
|
for (auto &call : s_tasksFinishedCallbacks)
|
||||||
call();
|
call();
|
||||||
s_tasksFinishedCallbacks.clear();
|
s_tasksFinishedCallbacks.clear();
|
||||||
|
|||||||
@@ -1,22 +1,25 @@
|
|||||||
#include <hex/api/theme_manager.hpp>
|
#include <hex/api/theme_manager.hpp>
|
||||||
|
#include <hex/api/imhex_api.hpp>
|
||||||
|
|
||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
#include <hex/helpers/utils.hpp>
|
#include <hex/helpers/utils.hpp>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
namespace hex::api {
|
namespace hex {
|
||||||
|
|
||||||
std::map<std::string, nlohmann::json> ThemeManager::s_themes;
|
std::map<std::string, nlohmann::json> ThemeManager::s_themes;
|
||||||
std::map<std::string, std::function<void(std::string, std::string)>> ThemeManager::s_themeHandlers, ThemeManager::s_styleHandlers;
|
std::map<std::string, ThemeManager::ThemeHandler> ThemeManager::s_themeHandlers;
|
||||||
|
std::map<std::string, ThemeManager::StyleHandler> ThemeManager::s_styleHandlers;
|
||||||
std::string ThemeManager::s_imagePostfix;
|
std::string ThemeManager::s_imagePostfix;
|
||||||
|
std::string ThemeManager::s_currTheme;
|
||||||
|
|
||||||
void ThemeManager::addThemeHandler(const std::string &name, const std::function<void(std::string, std::string)> &handler) {
|
void ThemeManager::addThemeHandler(const std::string &name, const ColorMap &colorMap, const std::function<ImColor(u32)> &getFunction, const std::function<void(u32, ImColor)> &setFunction) {
|
||||||
s_themeHandlers[name] = handler;
|
s_themeHandlers[name] = { colorMap, getFunction, setFunction };
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThemeManager::addStyleHandler(const std::string &name, const std::function<void(std::string, std::string)> &handler) {
|
void ThemeManager::addStyleHandler(const std::string &name, const StyleMap &styleMap) {
|
||||||
s_styleHandlers[name] = handler;
|
s_styleHandlers[name] = { styleMap };
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThemeManager::addTheme(const std::string &content) {
|
void ThemeManager::addTheme(const std::string &content) {
|
||||||
@@ -29,6 +32,9 @@ namespace hex::api {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::optional<ImColor> ThemeManager::parseColorString(const std::string &colorString) {
|
std::optional<ImColor> ThemeManager::parseColorString(const std::string &colorString) {
|
||||||
|
if (colorString == "auto")
|
||||||
|
return ImVec4(0, 0, 0, -1);
|
||||||
|
|
||||||
if (colorString.length() != 9 || colorString[0] != '#')
|
if (colorString.length() != 9 || colorString[0] != '#')
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|
||||||
@@ -46,9 +52,48 @@ namespace hex::api {
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (color == 0x00000000)
|
||||||
|
return ImVec4(0, 0, 0, -1);
|
||||||
|
|
||||||
return ImColor(hex::changeEndianess(color, std::endian::big));
|
return ImColor(hex::changeEndianess(color, std::endian::big));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nlohmann::json ThemeManager::exportCurrentTheme(const std::string &name) {
|
||||||
|
nlohmann::json theme = {
|
||||||
|
{ "name", name },
|
||||||
|
{ "image_postfix", s_imagePostfix },
|
||||||
|
{ "colors", {} },
|
||||||
|
{ "styles", {} },
|
||||||
|
{ "base", s_currTheme }
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto &[type, handler] : s_themeHandlers) {
|
||||||
|
theme["colors"][type] = {};
|
||||||
|
|
||||||
|
for (const auto &[key, value] : handler.colorMap) {
|
||||||
|
auto color = handler.getFunction(value);
|
||||||
|
theme["colors"][type][key] = fmt::format("#{:08X}", hex::changeEndianess(u32(color), std::endian::big));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &[type, handler] : s_styleHandlers) {
|
||||||
|
theme["styles"][type] = {};
|
||||||
|
|
||||||
|
for (const auto &[key, style] : handler.styleMap) {
|
||||||
|
if (std::holds_alternative<float*>(style.value))
|
||||||
|
theme["styles"][type][key] = *std::get<float*>(style.value);
|
||||||
|
else if (std::holds_alternative<ImVec2*>(style.value)) {
|
||||||
|
theme["styles"][type][key] = {
|
||||||
|
std::get<ImVec2*>(style.value)->x,
|
||||||
|
std::get<ImVec2*>(style.value)->y
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
|
||||||
void ThemeManager::changeTheme(std::string name) {
|
void ThemeManager::changeTheme(std::string name) {
|
||||||
if (!s_themes.contains(name)) {
|
if (!s_themes.contains(name)) {
|
||||||
if (s_themes.empty()) {
|
if (s_themes.empty()) {
|
||||||
@@ -64,7 +109,8 @@ namespace hex::api {
|
|||||||
|
|
||||||
if (theme.contains("base")) {
|
if (theme.contains("base")) {
|
||||||
if (theme["base"].is_string()) {
|
if (theme["base"].is_string()) {
|
||||||
changeTheme(theme["base"].get<std::string>());
|
if (theme["base"] != name)
|
||||||
|
changeTheme(theme["base"].get<std::string>());
|
||||||
} else {
|
} else {
|
||||||
hex::log::error("Theme '{}' has invalid base theme!", name);
|
hex::log::error("Theme '{}' has invalid base theme!", name);
|
||||||
}
|
}
|
||||||
@@ -77,19 +123,53 @@ namespace hex::api {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &[key, value] : content.items())
|
const auto &handler = s_themeHandlers[type];
|
||||||
s_themeHandlers[type](key, value.get<std::string>());
|
for (const auto &[key, value] : content.items()) {
|
||||||
|
if (!handler.colorMap.contains(key)) {
|
||||||
|
log::warn("No color found for '{}.{}'", type, key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto color = parseColorString(value.get<std::string>());
|
||||||
|
if (!color.has_value()) {
|
||||||
|
log::warn("Invalid color '{}' for '{}.{}'", value.get<std::string>(), type, key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_themeHandlers[type].setFunction(s_themeHandlers[type].colorMap.at(key), color.value());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theme.contains("styles")) {
|
if (theme.contains("styles")) {
|
||||||
for (const auto&[key, value] : theme["styles"].items()) {
|
for (const auto&[type, content] : theme["styles"].items()) {
|
||||||
if (!s_styleHandlers.contains(key)) {
|
if (!s_styleHandlers.contains(type)) {
|
||||||
log::warn("No style handler found for '{}'", key);
|
log::warn("No style handler found for '{}'", type);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_styleHandlers[key](name, value.get<std::string>());
|
auto &handler = s_styleHandlers[type];
|
||||||
|
for (const auto &[key, value] : content.items()) {
|
||||||
|
if (!handler.styleMap.contains(key))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto &style = handler.styleMap.at(key);
|
||||||
|
const float scale = style.needsScaling ? 1_scaled : 1.0F;
|
||||||
|
|
||||||
|
if (value.is_number_float()) {
|
||||||
|
if (auto newValue = std::get_if<float*>(&style.value); newValue != nullptr)
|
||||||
|
**newValue = value.get<float>() * scale;
|
||||||
|
else
|
||||||
|
log::warn("Style variable '{}' was of type ImVec2 but a float was expected.", name);
|
||||||
|
} else if (value.is_array() && value.size() == 2 && value[0].is_number_float() && value[1].is_number_float()) {
|
||||||
|
if (auto newValue = std::get_if<ImVec2*>(&style.value); newValue != nullptr)
|
||||||
|
**newValue = ImVec2(value[0].get<float>() * scale, value[1].get<float>() * scale);
|
||||||
|
else
|
||||||
|
log::warn("Style variable '{}' was of type float but a ImVec2 was expected.", name);
|
||||||
|
} else {
|
||||||
|
hex::log::error("Theme '{}' has invalid style value for '{}.{}'!", name, type, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +180,8 @@ namespace hex::api {
|
|||||||
hex::log::error("Theme '{}' has invalid image postfix!", name);
|
hex::log::error("Theme '{}' has invalid image postfix!", name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s_currTheme = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &ThemeManager::getThemeImagePostfix() {
|
const std::string &ThemeManager::getThemeImagePostfix() {
|
||||||
@@ -119,6 +201,7 @@ namespace hex::api {
|
|||||||
ThemeManager::s_styleHandlers.clear();
|
ThemeManager::s_styleHandlers.clear();
|
||||||
ThemeManager::s_themeHandlers.clear();
|
ThemeManager::s_themeHandlers.clear();
|
||||||
ThemeManager::s_imagePostfix.clear();
|
ThemeManager::s_imagePostfix.clear();
|
||||||
|
ThemeManager::s_currTheme.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ namespace hex::dp {
|
|||||||
return *reinterpret_cast<long double *>(outputData.data());
|
return *reinterpret_cast<long double *>(outputData.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::setBufferOnOutput(u32 index, const std::vector<u8> &data) {
|
void Node::setBufferOnOutput(u32 index, std::span<const u8> data) {
|
||||||
if (index >= this->getAttributes().size())
|
if (index >= this->getAttributes().size())
|
||||||
throwNodeError("Attribute index out of bounds!");
|
throwNodeError("Attribute index out of bounds!");
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ namespace hex::dp {
|
|||||||
if (attribute.getIOType() != Attribute::IOType::Out)
|
if (attribute.getIOType() != Attribute::IOType::Out)
|
||||||
throwNodeError("Tried to set output data of an input attribute!");
|
throwNodeError("Tried to set output data of an input attribute!");
|
||||||
|
|
||||||
attribute.getOutputData() = data;
|
attribute.getOutputData() = { data.begin(), data.end() };
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::setIntegerOnOutput(u32 index, i128 integer) {
|
void Node::setIntegerOnOutput(u32 index, i128 integer) {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#include <hex/helpers/crypto.hpp>
|
#include <hex/helpers/crypto.hpp>
|
||||||
|
|
||||||
#include <hex/providers/provider.hpp>
|
#include <hex/providers/provider.hpp>
|
||||||
#include <hex/helpers/utils.hpp>
|
|
||||||
#include <hex/helpers/concepts.hpp>
|
#include <wolv/utils/guards.hpp>
|
||||||
|
|
||||||
#include <mbedtls/version.h>
|
#include <mbedtls/version.h>
|
||||||
#include <mbedtls/base64.h>
|
#include <mbedtls/base64.h>
|
||||||
@@ -11,13 +11,10 @@
|
|||||||
#include <mbedtls/sha1.h>
|
#include <mbedtls/sha1.h>
|
||||||
#include <mbedtls/sha256.h>
|
#include <mbedtls/sha256.h>
|
||||||
#include <mbedtls/sha512.h>
|
#include <mbedtls/sha512.h>
|
||||||
#include <mbedtls/aes.h>
|
|
||||||
#include <mbedtls/cipher.h>
|
#include <mbedtls/cipher.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <span>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <algorithm>
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
|
|||||||
@@ -2,13 +2,28 @@
|
|||||||
|
|
||||||
#include <hex/helpers/utils.hpp>
|
#include <hex/helpers/utils.hpp>
|
||||||
|
|
||||||
|
#include <wolv/io/file.hpp>
|
||||||
|
#include <wolv/utils/string.hpp>
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
EncodingFile::EncodingFile(Type type, const std::fs::path &path) {
|
EncodingFile::EncodingFile(Type type, const std::fs::path &path) {
|
||||||
auto file = fs::File(path, fs::File::Mode::Read);
|
auto file = wolv::io::File(path, wolv::io::File::Mode::Read);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Type::Thingy:
|
case Type::Thingy:
|
||||||
parseThingyFile(file);
|
parse(file.readString());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
EncodingFile::EncodingFile(Type type, const std::string &content) {
|
||||||
|
switch (type) {
|
||||||
|
case Type::Thingy:
|
||||||
|
parse(content);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
@@ -23,7 +38,7 @@ namespace hex {
|
|||||||
|
|
||||||
if (size > buffer.size()) continue;
|
if (size > buffer.size()) continue;
|
||||||
|
|
||||||
auto key = std::vector<u8>(buffer.begin(), buffer.begin() + size);
|
std::vector<u8> key(buffer.begin(), buffer.begin() + size);
|
||||||
if (mapping.contains(key))
|
if (mapping.contains(key))
|
||||||
return { mapping.at(key), size };
|
return { mapping.at(key), size };
|
||||||
}
|
}
|
||||||
@@ -31,8 +46,23 @@ namespace hex {
|
|||||||
return { ".", 1 };
|
return { ".", 1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncodingFile::parseThingyFile(fs::File &file) {
|
size_t EncodingFile::getEncodingLengthFor(std::span<u8> buffer) const {
|
||||||
for (const auto &line : splitString(file.readString(), "\n")) {
|
for (auto riter = this->m_mapping.crbegin(); riter != this->m_mapping.crend(); ++riter) {
|
||||||
|
const auto &[size, mapping] = *riter;
|
||||||
|
|
||||||
|
if (size > buffer.size()) continue;
|
||||||
|
|
||||||
|
std::vector<u8> key(buffer.begin(), buffer.begin() + size);
|
||||||
|
if (mapping.contains(key))
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EncodingFile::parse(const std::string &content) {
|
||||||
|
this->m_tableContent = content;
|
||||||
|
for (const auto &line : splitString(this->m_tableContent, "\n")) {
|
||||||
|
|
||||||
std::string from, to;
|
std::string from, to;
|
||||||
{
|
{
|
||||||
@@ -51,15 +81,17 @@ namespace hex {
|
|||||||
if (fromBytes.empty()) continue;
|
if (fromBytes.empty()) continue;
|
||||||
|
|
||||||
if (to.length() > 1)
|
if (to.length() > 1)
|
||||||
hex::trim(to);
|
to = wolv::util::trim(to);
|
||||||
if (to.empty())
|
if (to.empty())
|
||||||
to = " ";
|
to = " ";
|
||||||
|
|
||||||
if (!this->m_mapping.contains(fromBytes.size()))
|
if (!this->m_mapping.contains(fromBytes.size()))
|
||||||
this->m_mapping.insert({ fromBytes.size(), {} });
|
this->m_mapping.insert({ fromBytes.size(), {} });
|
||||||
this->m_mapping[fromBytes.size()].insert({ fromBytes, to });
|
|
||||||
|
|
||||||
this->m_longestSequence = std::max(this->m_longestSequence, fromBytes.size());
|
auto keySize = fromBytes.size();
|
||||||
|
this->m_mapping[keySize].insert({ std::move(fromBytes), to });
|
||||||
|
|
||||||
|
this->m_longestSequence = std::max(this->m_longestSequence, keySize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,171 +0,0 @@
|
|||||||
#include <hex/helpers/file.hpp>
|
|
||||||
|
|
||||||
#include <hex/helpers/utils.hpp>
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
namespace hex::fs {
|
|
||||||
|
|
||||||
File::File(const std::fs::path &path, Mode mode) noexcept : m_path(path) {
|
|
||||||
#if defined(OS_WINDOWS)
|
|
||||||
if (mode == File::Mode::Read)
|
|
||||||
this->m_file = _wfopen(path.c_str(), L"rb");
|
|
||||||
else if (mode == File::Mode::Write)
|
|
||||||
this->m_file = _wfopen(path.c_str(), L"r+b");
|
|
||||||
|
|
||||||
if (mode == File::Mode::Create || (mode == File::Mode::Write && this->m_file == nullptr))
|
|
||||||
this->m_file = _wfopen(path.c_str(), L"w+b");
|
|
||||||
#else
|
|
||||||
if (mode == File::Mode::Read)
|
|
||||||
this->m_file = fopen64(hex::toUTF8String(path).c_str(), "rb");
|
|
||||||
else if (mode == File::Mode::Write)
|
|
||||||
this->m_file = fopen64(hex::toUTF8String(path).c_str(), "r+b");
|
|
||||||
|
|
||||||
if (mode == File::Mode::Create || (mode == File::Mode::Write && this->m_file == nullptr))
|
|
||||||
this->m_file = fopen64(hex::toUTF8String(path).c_str(), "w+b");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
File::File() noexcept {
|
|
||||||
this->m_file = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
File::File(File &&other) noexcept {
|
|
||||||
this->m_file = other.m_file;
|
|
||||||
other.m_file = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
File::~File() {
|
|
||||||
this->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
File &File::operator=(File &&other) noexcept {
|
|
||||||
this->m_file = other.m_file;
|
|
||||||
other.m_file = nullptr;
|
|
||||||
|
|
||||||
this->m_path = std::move(other.m_path);
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void File::seek(u64 offset) {
|
|
||||||
fseeko64(this->m_file, offset, SEEK_SET);
|
|
||||||
}
|
|
||||||
|
|
||||||
void File::close() {
|
|
||||||
if (isValid()) {
|
|
||||||
std::fclose(this->m_file);
|
|
||||||
this->m_file = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t File::readBuffer(u8 *buffer, size_t size) {
|
|
||||||
if (!isValid()) return 0;
|
|
||||||
|
|
||||||
return fread(buffer, size, 1, this->m_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<u8> File::readBytes(size_t numBytes) {
|
|
||||||
if (!isValid()) return {};
|
|
||||||
|
|
||||||
auto size = numBytes == 0 ? getSize() : numBytes;
|
|
||||||
if (size == 0) return {};
|
|
||||||
|
|
||||||
std::vector<u8> bytes(size);
|
|
||||||
auto bytesRead = fread(bytes.data(), 1, bytes.size(), this->m_file);
|
|
||||||
|
|
||||||
bytes.resize(bytesRead);
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string File::readString(size_t numBytes) {
|
|
||||||
if (!isValid()) return {};
|
|
||||||
|
|
||||||
if (getSize() == 0) return {};
|
|
||||||
|
|
||||||
auto bytes = readBytes(numBytes);
|
|
||||||
|
|
||||||
if (bytes.empty())
|
|
||||||
return "";
|
|
||||||
|
|
||||||
auto cString = reinterpret_cast<const char *>(bytes.data());
|
|
||||||
return { cString, hex::strnlen(cString, bytes.size()) };
|
|
||||||
}
|
|
||||||
|
|
||||||
std::u8string File::readU8String(size_t numBytes) {
|
|
||||||
if (!isValid()) return {};
|
|
||||||
|
|
||||||
if (getSize() == 0) return {};
|
|
||||||
|
|
||||||
auto bytes = readBytes(numBytes);
|
|
||||||
|
|
||||||
if (bytes.empty())
|
|
||||||
return u8"";
|
|
||||||
|
|
||||||
auto cString = reinterpret_cast<const char8_t *>(bytes.data());
|
|
||||||
return { cString, hex::strnlen(reinterpret_cast<const char*>(bytes.data()), bytes.size()) };
|
|
||||||
}
|
|
||||||
|
|
||||||
void File::write(const u8 *buffer, size_t size) {
|
|
||||||
if (!isValid()) return;
|
|
||||||
|
|
||||||
std::fwrite(buffer, size, 1, this->m_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void File::write(const std::vector<u8> &bytes) {
|
|
||||||
if (!isValid()) return;
|
|
||||||
|
|
||||||
std::fwrite(bytes.data(), 1, bytes.size(), this->m_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void File::write(const std::string &string) {
|
|
||||||
if (!isValid()) return;
|
|
||||||
|
|
||||||
std::fwrite(string.data(), string.size(), 1, this->m_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void File::write(const std::u8string &string) {
|
|
||||||
if (!isValid()) return;
|
|
||||||
|
|
||||||
std::fwrite(string.data(), string.size(), 1, this->m_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t File::getSize() const {
|
|
||||||
if (!isValid()) return 0;
|
|
||||||
|
|
||||||
auto startPos = ftello64(this->m_file);
|
|
||||||
fseeko64(this->m_file, 0, SEEK_END);
|
|
||||||
auto size = ftello64(this->m_file);
|
|
||||||
fseeko64(this->m_file, startPos, SEEK_SET);
|
|
||||||
|
|
||||||
if (size < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void File::setSize(u64 size) {
|
|
||||||
if (!isValid()) return;
|
|
||||||
|
|
||||||
auto result = ftruncate64(fileno(this->m_file), size);
|
|
||||||
hex::unused(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void File::flush() {
|
|
||||||
std::fflush(this->m_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool File::remove() {
|
|
||||||
this->close();
|
|
||||||
return std::remove(hex::toUTF8String(this->m_path).c_str()) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void File::disableBuffering() {
|
|
||||||
if (!isValid()) return;
|
|
||||||
|
|
||||||
std::setvbuf(this->m_file, nullptr, _IONBF, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -2,11 +2,7 @@
|
|||||||
|
|
||||||
#include <hex/api/content_registry.hpp>
|
#include <hex/api/content_registry.hpp>
|
||||||
#include <hex/api/project_file_manager.hpp>
|
#include <hex/api/project_file_manager.hpp>
|
||||||
|
#include <hex/helpers/logger.hpp>
|
||||||
#include <hex/helpers/fs_macos.hpp>
|
|
||||||
#include <hex/helpers/file.hpp>
|
|
||||||
#include <hex/helpers/intrinsics.hpp>
|
|
||||||
#include <hex/helpers/utils.hpp>
|
|
||||||
|
|
||||||
#include <xdg.hpp>
|
#include <xdg.hpp>
|
||||||
|
|
||||||
@@ -21,68 +17,25 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include <wolv/io/file.hpp>
|
||||||
|
#include <wolv/io/fs.hpp>
|
||||||
|
|
||||||
namespace hex::fs {
|
namespace hex::fs {
|
||||||
|
|
||||||
std::optional<std::fs::path> getExecutablePath() {
|
static std::function<void(const std::string&)> s_fileBrowserErrorCallback;
|
||||||
#if defined(OS_WINDOWS)
|
void setFileBrowserErrorCallback(const std::function<void(const std::string&)> &callback) {
|
||||||
std::wstring exePath(MAX_PATH, '\0');
|
|
||||||
if (GetModuleFileNameW(nullptr, exePath.data(), exePath.length()) == 0)
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
hex::trim(exePath);
|
|
||||||
|
|
||||||
return exePath;
|
|
||||||
#elif defined(OS_LINUX)
|
|
||||||
std::string exePath(PATH_MAX, '\0');
|
|
||||||
if (readlink("/proc/self/exe", exePath.data(), PATH_MAX) < 0)
|
|
||||||
return std::nullopt;
|
|
||||||
|
|
||||||
hex::trim(exePath);
|
|
||||||
|
|
||||||
return exePath;
|
|
||||||
#elif defined(OS_MACOS)
|
|
||||||
std::string exePath;
|
|
||||||
|
|
||||||
{
|
|
||||||
auto string = getMacExecutableDirectoryPath();
|
|
||||||
exePath = string;
|
|
||||||
macFree(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
hex::trim(exePath);
|
|
||||||
|
|
||||||
return exePath;
|
|
||||||
#else
|
|
||||||
return std::nullopt;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool isPathWritable(const std::fs::path &path) {
|
|
||||||
constexpr static auto TestFileName = "__imhex__tmp__";
|
|
||||||
{
|
|
||||||
File file(path / TestFileName, File::Mode::Read);
|
|
||||||
if (file.isValid()) {
|
|
||||||
if (!file.remove())
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
File file(path / TestFileName, File::Mode::Create);
|
|
||||||
bool result = file.isValid();
|
|
||||||
if (!file.remove())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::function<void()> s_fileBrowserErrorCallback;
|
|
||||||
void setFileBrowserErrorCallback(const std::function<void()> &callback) {
|
|
||||||
s_fileBrowserErrorCallback = callback;
|
s_fileBrowserErrorCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath, bool multiple) {
|
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath, bool multiple) {
|
||||||
NFD::Init();
|
NFD::ClearError();
|
||||||
|
|
||||||
|
if (NFD::Init() != NFD_OKAY) {
|
||||||
|
log::error("NFD init returned an error: {}", NFD::GetError());
|
||||||
|
if (s_fileBrowserErrorCallback != nullptr)
|
||||||
|
s_fileBrowserErrorCallback(NFD::GetError() ? NFD::GetError() : "No details");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
NFD::UniquePathU8 outPath;
|
NFD::UniquePathU8 outPath;
|
||||||
NFD::UniquePathSet outPaths;
|
NFD::UniquePathSet outPaths;
|
||||||
@@ -119,8 +72,9 @@ namespace hex::fs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (result == NFD_ERROR) {
|
} else if (result == NFD_ERROR) {
|
||||||
|
log::error("Requested file dialog returned an error: {}", NFD::GetError());
|
||||||
if (s_fileBrowserErrorCallback != nullptr)
|
if (s_fileBrowserErrorCallback != nullptr)
|
||||||
s_fileBrowserErrorCallback();
|
s_fileBrowserErrorCallback(NFD::GetError() ? NFD::GetError() : "No details");
|
||||||
}
|
}
|
||||||
|
|
||||||
NFD::Quit();
|
NFD::Quit();
|
||||||
@@ -128,7 +82,7 @@ namespace hex::fs {
|
|||||||
return result == NFD_OKAY;
|
return result == NFD_OKAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<std::fs::path> getDataPaths() {
|
std::vector<std::fs::path> getDataPaths() {
|
||||||
std::vector<std::fs::path> paths;
|
std::vector<std::fs::path> paths;
|
||||||
|
|
||||||
#if defined(OS_WINDOWS)
|
#if defined(OS_WINDOWS)
|
||||||
@@ -143,14 +97,7 @@ namespace hex::fs {
|
|||||||
|
|
||||||
#elif defined(OS_MACOS)
|
#elif defined(OS_MACOS)
|
||||||
|
|
||||||
std::fs::path applicationSupportDirPath;
|
paths.push_back(wolv::io::fs::getApplicationSupportDirectoryPath());
|
||||||
{
|
|
||||||
auto string = getMacApplicationSupportDirectoryPath();
|
|
||||||
applicationSupportDirPath = std::string(string);
|
|
||||||
macFree(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
paths.push_back(applicationSupportDirPath);
|
|
||||||
|
|
||||||
#elif defined(OS_LINUX)
|
#elif defined(OS_LINUX)
|
||||||
|
|
||||||
@@ -166,12 +113,12 @@ namespace hex::fs {
|
|||||||
|
|
||||||
#if defined(OS_MACOS)
|
#if defined(OS_MACOS)
|
||||||
|
|
||||||
if (auto executablePath = fs::getExecutablePath(); executablePath.has_value())
|
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value())
|
||||||
paths.push_back(*executablePath);
|
paths.push_back(*executablePath);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
if (auto executablePath = fs::getExecutablePath(); executablePath.has_value())
|
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value())
|
||||||
paths.push_back(executablePath->parent_path());
|
paths.push_back(executablePath->parent_path());
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -193,17 +140,7 @@ namespace hex::fs {
|
|||||||
#elif defined(OS_MACOS)
|
#elif defined(OS_MACOS)
|
||||||
return getDataPaths();
|
return getDataPaths();
|
||||||
#elif defined(OS_LINUX)
|
#elif defined(OS_LINUX)
|
||||||
std::vector<std::fs::path> paths;
|
return {xdg::ConfigHomeDir() / "imhex"};
|
||||||
|
|
||||||
paths.push_back(xdg::DataHomeDir());
|
|
||||||
|
|
||||||
auto dataDirs = xdg::DataDirs();
|
|
||||||
std::copy(dataDirs.begin(), dataDirs.end(), std::back_inserter(paths));
|
|
||||||
|
|
||||||
for (auto &path : paths)
|
|
||||||
path = path / "imhex";
|
|
||||||
|
|
||||||
return paths;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,7 +176,7 @@ namespace hex::fs {
|
|||||||
result = appendPath(getDataPaths(), "encodings");
|
result = appendPath(getDataPaths(), "encodings");
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Logs:
|
case ImHexPath::Logs:
|
||||||
result = appendPath(getConfigPaths(), "logs");
|
result = appendPath(getDataPaths(), "logs");
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Plugins:
|
case ImHexPath::Plugins:
|
||||||
result = appendPath(getPluginPaths(), "plugins");
|
result = appendPath(getPluginPaths(), "plugins");
|
||||||
@@ -277,17 +214,38 @@ namespace hex::fs {
|
|||||||
case ImHexPath::Themes:
|
case ImHexPath::Themes:
|
||||||
result = appendPath(getDataPaths(), "themes");
|
result = appendPath(getDataPaths(), "themes");
|
||||||
break;
|
break;
|
||||||
|
case ImHexPath::Layouts:
|
||||||
|
result = appendPath(getDataPaths(), "layouts");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!listNonExisting) {
|
if (!listNonExisting) {
|
||||||
result.erase(std::remove_if(result.begin(), result.end(), [](const auto &path) {
|
result.erase(std::remove_if(result.begin(), result.end(), [](const auto &path) {
|
||||||
return !fs::isDirectory(path);
|
return !wolv::io::fs::isDirectory(path);
|
||||||
}), result.end());
|
}), result.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isPathWritable(const std::fs::path &path) {
|
||||||
|
constexpr static auto TestFileName = "__imhex__tmp__";
|
||||||
|
{
|
||||||
|
wolv::io::File file(path / TestFileName, wolv::io::File::Mode::Read);
|
||||||
|
if (file.isValid()) {
|
||||||
|
if (!file.remove())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wolv::io::File file(path / TestFileName, wolv::io::File::Mode::Create);
|
||||||
|
bool result = file.isValid();
|
||||||
|
if (!file.remove())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::fs::path toShortPath(const std::fs::path &path) {
|
std::fs::path toShortPath(const std::fs::path &path) {
|
||||||
#if defined(OS_WINDOWS)
|
#if defined(OS_WINDOWS)
|
||||||
size_t size = GetShortPathNameW(path.c_str(), nullptr, 0);
|
size_t size = GetShortPathNameW(path.c_str(), nullptr, 0);
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
#if defined(OS_MACOS)
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
char* getMacExecutableDirectoryPath(void) {
|
|
||||||
@autoreleasepool {
|
|
||||||
const char *pathString = [[[[[NSBundle mainBundle] executableURL] URLByDeletingLastPathComponent] path] UTF8String];
|
|
||||||
|
|
||||||
char *result = malloc(strlen(pathString) + 1);
|
|
||||||
strcpy(result, pathString);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char* getMacApplicationSupportDirectoryPath(void) {
|
|
||||||
@autoreleasepool {
|
|
||||||
NSError* error = nil;
|
|
||||||
NSURL* dirUrl = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory
|
|
||||||
inDomain:NSUserDomainMask
|
|
||||||
appropriateForURL:nil
|
|
||||||
create:YES
|
|
||||||
error:&error];
|
|
||||||
|
|
||||||
if (error != nil) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *pathString = [[[dirUrl URLByAppendingPathComponent:(@"imhex")] path] UTF8String];
|
|
||||||
|
|
||||||
char *result = malloc(strlen(pathString) + 1);
|
|
||||||
strcpy(result, pathString);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void macFree(void *ptr) {
|
|
||||||
free(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
97
lib/libimhex/source/helpers/http_requests.cpp
Normal file
97
lib/libimhex/source/helpers/http_requests.cpp
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#include <hex/helpers/http_requests.hpp>
|
||||||
|
|
||||||
|
namespace hex {
|
||||||
|
|
||||||
|
std::string HttpRequest::s_caCertData;
|
||||||
|
std::string HttpRequest::s_proxyUrl;
|
||||||
|
|
||||||
|
HttpRequest::HttpRequest(std::string method, std::string url) : m_method(std::move(method)), m_url(std::move(url)) {
|
||||||
|
AT_FIRST_TIME {
|
||||||
|
curl_global_init(CURL_GLOBAL_ALL);
|
||||||
|
};
|
||||||
|
|
||||||
|
AT_FINAL_CLEANUP {
|
||||||
|
curl_global_cleanup();
|
||||||
|
};
|
||||||
|
|
||||||
|
this->m_curl = curl_easy_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpRequest::~HttpRequest() {
|
||||||
|
curl_easy_cleanup(this->m_curl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpRequest::setDefaultConfig() {
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_USERAGENT, "ImHex/1.0");
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_DEFAULT_PROTOCOL, "https");
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_SSL_VERIFYPEER, 1L);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_SSL_VERIFYHOST, 2L);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_TIMEOUT_MS, 0L);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_CONNECTTIMEOUT_MS, this->m_timeout);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_NOSIGNAL, 1L);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_NOPROGRESS, 0L);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_XFERINFODATA, this);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_XFERINFOFUNCTION, progressCallback);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_PROXY, s_proxyUrl.c_str());
|
||||||
|
|
||||||
|
#if defined(IMHEX_USE_BUNDLED_CA)
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_CAINFO, nullptr);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_CAPATH, nullptr);
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_SSLCERTTYPE, "PEM");
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_SSL_CTX_FUNCTION, sslCtxFunction);
|
||||||
|
|
||||||
|
this->m_caCert = std::make_unique<mbedtls_x509_crt>();
|
||||||
|
curl_easy_setopt(this->m_curl, CURLOPT_SSL_CTX_DATA, this->m_caCert.get());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode HttpRequest::sslCtxFunction(CURL *ctx, void *sslctx, void *userData) {
|
||||||
|
hex::unused(ctx, userData);
|
||||||
|
|
||||||
|
auto *cfg = static_cast<mbedtls_ssl_config *>(sslctx);
|
||||||
|
|
||||||
|
auto crt = static_cast<mbedtls_x509_crt*>(userData);
|
||||||
|
mbedtls_x509_crt_init(crt);
|
||||||
|
|
||||||
|
mbedtls_x509_crt_parse(crt, reinterpret_cast<const u8 *>(HttpRequest::s_caCertData.data()), HttpRequest::s_caCertData.size());
|
||||||
|
|
||||||
|
mbedtls_ssl_conf_ca_chain(cfg, crt, nullptr);
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HttpRequest::writeToVector(void *contents, size_t size, size_t nmemb, void *userdata) {
|
||||||
|
auto &response = *reinterpret_cast<std::vector<u8>*>(userdata);
|
||||||
|
auto startSize = response.size();
|
||||||
|
|
||||||
|
response.resize(startSize + size * nmemb);
|
||||||
|
std::memcpy(response.data() + startSize, contents, size * nmemb);
|
||||||
|
|
||||||
|
return size * nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t HttpRequest::writeToFile(void *contents, size_t size, size_t nmemb, void *userdata) {
|
||||||
|
auto &file = *reinterpret_cast<wolv::io::File*>(userdata);
|
||||||
|
|
||||||
|
file.writeBuffer(reinterpret_cast<const u8*>(contents), size * nmemb);
|
||||||
|
|
||||||
|
return size * nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HttpRequest::progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow) {
|
||||||
|
auto &request = *static_cast<HttpRequest *>(contents);
|
||||||
|
|
||||||
|
if (dlTotal > 0)
|
||||||
|
request.m_progress = float(dlNow) / dlTotal;
|
||||||
|
else if (ulTotal > 0)
|
||||||
|
request.m_progress = float(ulNow) / ulTotal;
|
||||||
|
else
|
||||||
|
request.m_progress = 0.0F;
|
||||||
|
|
||||||
|
return request.m_canceled ? CURLE_ABORTED_BY_CALLBACK : CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,13 +1,12 @@
|
|||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
#include <hex/helpers/file.hpp>
|
|
||||||
#include <hex/helpers/fs.hpp>
|
#include <hex/helpers/fs.hpp>
|
||||||
#include <hex/helpers/fmt.hpp>
|
#include <hex/helpers/fmt.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
#include <wolv/io/file.hpp>
|
||||||
|
|
||||||
namespace hex::log {
|
namespace hex::log {
|
||||||
|
|
||||||
static fs::File g_loggerFile;
|
static wolv::io::File g_loggerFile;
|
||||||
|
|
||||||
FILE *getDestination() {
|
FILE *getDestination() {
|
||||||
if (g_loggerFile.isValid())
|
if (g_loggerFile.isValid())
|
||||||
@@ -24,8 +23,8 @@ namespace hex::log {
|
|||||||
if (g_loggerFile.isValid()) return;
|
if (g_loggerFile.isValid()) return;
|
||||||
|
|
||||||
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Logs, true)) {
|
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Logs, true)) {
|
||||||
fs::createDirectories(path);
|
wolv::io::fs::createDirectories(path);
|
||||||
g_loggerFile = fs::File(path / hex::format("{0:%Y%m%d_%H%M%S}.log", fmt::localtime(std::chrono::system_clock::now())), fs::File::Mode::Create);
|
g_loggerFile = wolv::io::File(path / hex::format("{0:%Y%m%d_%H%M%S}.log", fmt::localtime(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()))), wolv::io::File::Mode::Create);
|
||||||
g_loggerFile.disableBuffering();
|
g_loggerFile.disableBuffering();
|
||||||
|
|
||||||
if (g_loggerFile.isValid()) break;
|
if (g_loggerFile.isValid()) break;
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
#include <hex/helpers/utils.hpp>
|
#include <hex/helpers/utils.hpp>
|
||||||
#include <hex/helpers/fs.hpp>
|
#include <hex/helpers/fs.hpp>
|
||||||
|
|
||||||
|
#include <wolv/utils/guards.hpp>
|
||||||
|
#include <wolv/utils/string.hpp>
|
||||||
|
|
||||||
#include <hex/providers/provider.hpp>
|
#include <hex/providers/provider.hpp>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
@@ -25,9 +28,11 @@ namespace hex::magic {
|
|||||||
|
|
||||||
std::error_code error;
|
std::error_code error;
|
||||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
|
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
|
||||||
for (const auto &entry : std::fs::directory_iterator(dir, error)) {
|
for (const auto &entry : std::fs::recursive_directory_iterator(dir, error)) {
|
||||||
if (entry.is_regular_file() && ((sourceFiles && entry.path().extension().empty()) || (!sourceFiles && entry.path().extension() == ".mgc"))) {
|
auto path = std::fs::absolute(entry.path());
|
||||||
magicFiles += hex::toUTF8String(fs::toShortPath(entry.path())) + MAGIC_PATH_SEPARATOR;
|
|
||||||
|
if (entry.is_regular_file() && ((sourceFiles && path.extension().empty()) || (!sourceFiles && path.extension() == ".mgc"))) {
|
||||||
|
magicFiles += wolv::util::toUTF8String(wolv::io::fs::toShortPath(path)) + MAGIC_PATH_SEPARATOR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,304 +0,0 @@
|
|||||||
#include <hex/helpers/net.hpp>
|
|
||||||
|
|
||||||
#include <hex/helpers/utils.hpp>
|
|
||||||
#include <hex/helpers/file.hpp>
|
|
||||||
#include <hex/helpers/logger.hpp>
|
|
||||||
|
|
||||||
#include <hex/api/content_registry.hpp>
|
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
namespace hex {
|
|
||||||
|
|
||||||
Net::Net() {
|
|
||||||
FIRST_TIME {
|
|
||||||
curl_global_sslset(CURLSSLBACKEND_MBEDTLS, nullptr, nullptr);
|
|
||||||
curl_global_init(CURL_GLOBAL_ALL);
|
|
||||||
};
|
|
||||||
|
|
||||||
FINAL_CLEANUP {
|
|
||||||
curl_global_cleanup();
|
|
||||||
};
|
|
||||||
|
|
||||||
this->m_ctx = curl_easy_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
Net::~Net() {
|
|
||||||
curl_easy_cleanup(this->m_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t writeToString(void *contents, size_t size, size_t nmemb, void *userdata) {
|
|
||||||
static_cast<std::string *>(userdata)->append((char *)contents, size * nmemb);
|
|
||||||
return size * nmemb;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t writeToFile(void *contents, size_t size, size_t nmemb, void *userdata) {
|
|
||||||
FILE *file = static_cast<FILE *>(userdata);
|
|
||||||
|
|
||||||
return fwrite(contents, size, nmemb, file);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
|
||||||
CURLcode sslCtxFunction(CURL *ctx, void *sslctx, void *userData) {
|
|
||||||
hex::unused(ctx, userData);
|
|
||||||
|
|
||||||
auto *cfg = static_cast<mbedtls_ssl_config *>(sslctx);
|
|
||||||
|
|
||||||
auto crt = static_cast<mbedtls_x509_crt*>(userData);
|
|
||||||
mbedtls_x509_crt_init(crt);
|
|
||||||
|
|
||||||
mbedtls_x509_crt_parse(crt, reinterpret_cast<const u8 *>(Net::s_caCert.data()), Net::s_caCert.size());
|
|
||||||
|
|
||||||
mbedtls_ssl_conf_ca_chain(cfg, crt, nullptr);
|
|
||||||
|
|
||||||
return CURLE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow) {
|
|
||||||
auto &net = *static_cast<Net *>(contents);
|
|
||||||
|
|
||||||
if (dlTotal > 0)
|
|
||||||
net.m_progress = float(dlNow) / dlTotal;
|
|
||||||
else if (ulTotal > 0)
|
|
||||||
net.m_progress = float(ulNow) / ulTotal;
|
|
||||||
else
|
|
||||||
net.m_progress = 0.0F;
|
|
||||||
|
|
||||||
return net.m_shouldCancel ? CURLE_ABORTED_BY_CALLBACK : CURLE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Net::setCommonSettings(std::string &response, const std::string &url, u32 timeout, const std::map<std::string, std::string> &extraHeaders, const std::string &body) {
|
|
||||||
this->m_headers = curl_slist_append(this->m_headers, "Cache-Control: no-cache");
|
|
||||||
|
|
||||||
if (!extraHeaders.empty())
|
|
||||||
for (const auto &[key, value] : extraHeaders) {
|
|
||||||
std::string entry = key;
|
|
||||||
entry += ": ";
|
|
||||||
entry += value;
|
|
||||||
|
|
||||||
this->m_headers = curl_slist_append(this->m_headers, entry.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!body.empty())
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_POSTFIELDS, body.c_str());
|
|
||||||
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_URL, url.c_str());
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_FOLLOWLOCATION, 1L);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_HTTPHEADER, this->m_headers);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_USERAGENT, "ImHex/1.0");
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_DEFAULT_PROTOCOL, "https");
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_WRITEFUNCTION, writeToString);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_VERIFYPEER, 1L);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_VERIFYHOST, 2L);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_WRITEDATA, &response);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_TIMEOUT_MS, 0L);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_CONNECTTIMEOUT_MS, timeout);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_XFERINFODATA, this);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_XFERINFOFUNCTION, progressCallback);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_NOSIGNAL, 1L);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_NOPROGRESS, 0L);
|
|
||||||
|
|
||||||
#if defined(IMHEX_USE_BUNDLED_CA)
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_CAINFO, nullptr);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_CAPATH, nullptr);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_SSLCERTTYPE, "PEM");
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_FUNCTION, sslCtxFunction);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_DATA, &this->m_caCert);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_PROXY, Net::s_proxyUrl.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<i32> Net::execute() {
|
|
||||||
CURLcode result = curl_easy_perform(this->m_ctx);
|
|
||||||
if (result != CURLE_OK){
|
|
||||||
char *url = nullptr;
|
|
||||||
curl_easy_getinfo(this->m_ctx, CURLINFO_EFFECTIVE_URL, &url);
|
|
||||||
log::error("Net request '{0}' failed with error {1}: '{2}'", url, u32(result), curl_easy_strerror(result));
|
|
||||||
if(!Net::s_proxyUrl.empty()){
|
|
||||||
log::info("A custom proxy '{}' is in use. Is it working correctly?", Net::s_proxyUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
long responseCode = 0;
|
|
||||||
curl_easy_getinfo(this->m_ctx, CURLINFO_RESPONSE_CODE, &responseCode);
|
|
||||||
|
|
||||||
curl_slist_free_all(this->m_headers);
|
|
||||||
this->m_headers = nullptr;
|
|
||||||
this->m_progress = 0.0F;
|
|
||||||
this->m_shouldCancel = false;
|
|
||||||
|
|
||||||
if (result != CURLE_OK)
|
|
||||||
return std::nullopt;
|
|
||||||
else
|
|
||||||
return i32(responseCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::future<Response<std::string>> Net::getString(const std::string &url, u32 timeout, const std::map<std::string, std::string> &extraHeaders, const std::string &body) {
|
|
||||||
this->m_transmissionActive.lock();
|
|
||||||
|
|
||||||
return std::async(std::launch::async, [=, this] {
|
|
||||||
std::string response;
|
|
||||||
|
|
||||||
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
|
|
||||||
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "GET");
|
|
||||||
setCommonSettings(response, url, timeout, extraHeaders, body);
|
|
||||||
|
|
||||||
auto responseCode = execute();
|
|
||||||
|
|
||||||
return Response<std::string> { responseCode.value_or(0), response };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::future<Response<nlohmann::json>> Net::getJson(const std::string &url, u32 timeout, const std::map<std::string, std::string> &extraHeaders, const std::string &body) {
|
|
||||||
this->m_transmissionActive.lock();
|
|
||||||
|
|
||||||
return std::async(std::launch::async, [=, this] {
|
|
||||||
std::string response;
|
|
||||||
|
|
||||||
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
|
|
||||||
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "GET");
|
|
||||||
setCommonSettings(response, url, timeout, extraHeaders, body);
|
|
||||||
|
|
||||||
auto responseCode = execute();
|
|
||||||
if (!responseCode.has_value())
|
|
||||||
return Response<nlohmann::json> { 0, { } };
|
|
||||||
else
|
|
||||||
return Response<nlohmann::json> { responseCode.value_or(0), nlohmann::json::parse(response, nullptr, false, true) };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::future<Response<nlohmann::json>> Net::postJson(const std::string &url, u32 timeout, const std::map<std::string, std::string> &extraHeaders, const std::string &body) {
|
|
||||||
this->m_transmissionActive.lock();
|
|
||||||
|
|
||||||
return std::async(std::launch::async, [=, this] {
|
|
||||||
std::string response;
|
|
||||||
|
|
||||||
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
|
|
||||||
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "POST");
|
|
||||||
setCommonSettings(response, url, timeout, extraHeaders, body);
|
|
||||||
|
|
||||||
auto responseCode = execute();
|
|
||||||
if (!responseCode.has_value())
|
|
||||||
return Response<nlohmann::json> { 0, { } };
|
|
||||||
else
|
|
||||||
return Response<nlohmann::json> { responseCode.value_or(0), nlohmann::json::parse(response, nullptr, false, true) };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::future<Response<std::string>> Net::uploadFile(const std::string &url, const std::fs::path &filePath, u32 timeout) {
|
|
||||||
this->m_transmissionActive.lock();
|
|
||||||
|
|
||||||
return std::async(std::launch::async, [=, this] {
|
|
||||||
std::string response;
|
|
||||||
|
|
||||||
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
|
|
||||||
|
|
||||||
fs::File file(filePath, fs::File::Mode::Read);
|
|
||||||
if (!file.isValid())
|
|
||||||
return Response<std::string> { 400, {} };
|
|
||||||
|
|
||||||
curl_mime *mime = curl_mime_init(this->m_ctx);
|
|
||||||
curl_mimepart *part = curl_mime_addpart(mime);
|
|
||||||
|
|
||||||
auto fileName = hex::toUTF8String(filePath.filename());
|
|
||||||
curl_mime_data_cb(part, file.getSize(),
|
|
||||||
[](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
|
|
||||||
auto file = static_cast<FILE*>(arg);
|
|
||||||
|
|
||||||
return fread(buffer, size, nitems, file);
|
|
||||||
},
|
|
||||||
[](void *arg, curl_off_t offset, int origin) -> int {
|
|
||||||
auto file = static_cast<FILE*>(arg);
|
|
||||||
|
|
||||||
if (fseek(file, offset, origin) != 0)
|
|
||||||
return CURL_SEEKFUNC_CANTSEEK;
|
|
||||||
else
|
|
||||||
return CURL_SEEKFUNC_OK;
|
|
||||||
},
|
|
||||||
[](void *arg) {
|
|
||||||
auto file = static_cast<FILE*>(arg);
|
|
||||||
|
|
||||||
fclose(file);
|
|
||||||
},
|
|
||||||
file.getHandle());
|
|
||||||
curl_mime_filename(part, fileName.c_str());
|
|
||||||
curl_mime_name(part, "file");
|
|
||||||
|
|
||||||
setCommonSettings(response, url, timeout);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_MIMEPOST, mime);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "POST");
|
|
||||||
|
|
||||||
auto responseCode = execute();
|
|
||||||
|
|
||||||
return Response<std::string> { responseCode.value_or(0), response };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::future<Response<void>> Net::downloadFile(const std::string &url, const std::fs::path &filePath, u32 timeout) {
|
|
||||||
this->m_transmissionActive.lock();
|
|
||||||
|
|
||||||
return std::async(std::launch::async, [=, this] {
|
|
||||||
std::string response;
|
|
||||||
|
|
||||||
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
|
|
||||||
|
|
||||||
fs::File file(filePath, fs::File::Mode::Create);
|
|
||||||
if (!file.isValid())
|
|
||||||
return Response<void> { 400 };
|
|
||||||
|
|
||||||
setCommonSettings(response, url, timeout);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_CUSTOMREQUEST, "GET");
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_WRITEFUNCTION, writeToFile);
|
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_WRITEDATA, file.getHandle());
|
|
||||||
auto responseCode = execute();
|
|
||||||
|
|
||||||
return Response<void> { responseCode.value_or(0) };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Net::encode(const std::string &input) {
|
|
||||||
auto escapedString = curl_easy_escape(this->m_ctx, input.c_str(), std::strlen(input.c_str()));
|
|
||||||
|
|
||||||
if (escapedString != nullptr) {
|
|
||||||
std::string output = escapedString;
|
|
||||||
curl_free(escapedString);
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Net::decode(const std::string &input) {
|
|
||||||
auto unescapedString = curl_easy_unescape(this->m_ctx, input.c_str(), std::strlen(input.c_str()), nullptr);
|
|
||||||
|
|
||||||
if (unescapedString != nullptr) {
|
|
||||||
std::string output = unescapedString;
|
|
||||||
curl_free(unescapedString);
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Net::s_proxyUrl;
|
|
||||||
void Net::setProxy(const std::string &url) {
|
|
||||||
Net::s_proxyUrl = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Net::s_caCert;
|
|
||||||
void Net::setCACert(const std::string &content) {
|
|
||||||
Net::s_caCert = content;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
#include <hex/helpers/utils.hpp>
|
#include <hex/helpers/utils.hpp>
|
||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
|
|
||||||
|
#include <wolv/utils/guards.hpp>
|
||||||
|
|
||||||
namespace hex::gl {
|
namespace hex::gl {
|
||||||
|
|
||||||
Shader::Shader(std::string_view vertexSource, std::string_view fragmentSource) {
|
Shader::Shader(std::string_view vertexSource, std::string_view fragmentSource) {
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
#include <hex/helpers/socket.hpp>
|
|
||||||
|
|
||||||
#include <hex/helpers/utils.hpp>
|
|
||||||
#include <hex/helpers/logger.hpp>
|
|
||||||
|
|
||||||
namespace hex {
|
|
||||||
|
|
||||||
Socket::Socket(const std::string &address, u16 port) {
|
|
||||||
#if defined(OS_WINDOWS)
|
|
||||||
FIRST_TIME {
|
|
||||||
WSAData wsa;
|
|
||||||
WSAStartup(MAKEWORD(2, 2), &wsa);
|
|
||||||
};
|
|
||||||
|
|
||||||
FINAL_CLEANUP {
|
|
||||||
WSACleanup();
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
this->connect(address, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
Socket::Socket(Socket &&other) noexcept {
|
|
||||||
this->m_socket = other.m_socket;
|
|
||||||
this->m_connected = other.m_connected;
|
|
||||||
|
|
||||||
other.m_socket = SOCKET_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
Socket::~Socket() {
|
|
||||||
this->disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Socket::writeBytes(const std::vector<u8> &bytes) const {
|
|
||||||
if (!this->isConnected()) return;
|
|
||||||
|
|
||||||
::send(this->m_socket, reinterpret_cast<const char *>(bytes.data()), bytes.size(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Socket::writeString(const std::string &string) const {
|
|
||||||
if (!this->isConnected()) return;
|
|
||||||
|
|
||||||
::send(this->m_socket, string.c_str(), string.length(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<u8> Socket::readBytes(size_t size) const {
|
|
||||||
std::vector<u8> data;
|
|
||||||
data.resize(size);
|
|
||||||
|
|
||||||
auto receivedSize = ::recv(this->m_socket, reinterpret_cast<char *>(data.data()), size, 0);
|
|
||||||
|
|
||||||
if (receivedSize < 0)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
data.resize(receivedSize);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Socket::readString(size_t size) const {
|
|
||||||
auto bytes = readBytes(size);
|
|
||||||
|
|
||||||
std::string result;
|
|
||||||
std::copy(bytes.begin(), bytes.end(), std::back_inserter(result));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Socket::isConnected() const {
|
|
||||||
return this->m_connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Socket::connect(const std::string &address, u16 port) {
|
|
||||||
this->m_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
||||||
if (this->m_socket == SOCKET_NONE)
|
|
||||||
return;
|
|
||||||
|
|
||||||
sockaddr_in client = { };
|
|
||||||
|
|
||||||
client.sin_family = AF_INET;
|
|
||||||
client.sin_port = htons(port);
|
|
||||||
|
|
||||||
#if defined(OS_WINDOWS)
|
|
||||||
client.sin_addr.S_un.S_addr = ::inet_addr(address.c_str());
|
|
||||||
#else
|
|
||||||
client.sin_addr.s_addr = ::inet_addr(address.c_str());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
this->m_connected = ::connect(this->m_socket, reinterpret_cast<sockaddr *>(&client), sizeof(client)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Socket::disconnect() {
|
|
||||||
if (this->m_socket != SOCKET_NONE) {
|
|
||||||
#if defined(OS_WINDOWS)
|
|
||||||
closesocket(this->m_socket);
|
|
||||||
#else
|
|
||||||
close(this->m_socket);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
this->m_connected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -94,75 +94,82 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(HEX_HAS_EXECINFO) && __has_include(BACKTRACE_HEADER)
|
#elif defined(HEX_HAS_EXECINFO)
|
||||||
|
|
||||||
#include BACKTRACE_HEADER
|
#if __has_include(BACKTRACE_HEADER)
|
||||||
#include <llvm/Demangle/Demangle.h>
|
|
||||||
#include <hex/helpers/logger.hpp>
|
|
||||||
#include <hex/helpers/utils.hpp>
|
|
||||||
|
|
||||||
namespace hex::stacktrace {
|
#include BACKTRACE_HEADER
|
||||||
|
#include <llvm/Demangle/Demangle.h>
|
||||||
|
#include <hex/helpers/logger.hpp>
|
||||||
|
#include <hex/helpers/utils.hpp>
|
||||||
|
|
||||||
void initialize() {
|
namespace hex::stacktrace {
|
||||||
|
|
||||||
}
|
void initialize() {
|
||||||
|
|
||||||
std::vector<StackFrame> getStackTrace() {
|
|
||||||
static std::vector<StackFrame> result;
|
|
||||||
|
|
||||||
std::array<void*, 128> addresses;
|
|
||||||
auto count = backtrace(addresses.data(), addresses.size());
|
|
||||||
auto functions = backtrace_symbols(addresses.data(), count);
|
|
||||||
|
|
||||||
for (i32 i = 0; i < count; i++)
|
|
||||||
result.push_back(StackFrame { "", functions[i], 0 });
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(HEX_HAS_BACKTRACE) && __has_include(BACKTRACE_HEADER)
|
|
||||||
|
|
||||||
#include BACKTRACE_HEADER
|
|
||||||
#include <llvm/Demangle/Demangle.h>
|
|
||||||
#include <hex/helpers/logger.hpp>
|
|
||||||
#include <hex/helpers/utils.hpp>
|
|
||||||
|
|
||||||
namespace hex::stacktrace {
|
|
||||||
|
|
||||||
static struct backtrace_state *s_backtraceState;
|
|
||||||
|
|
||||||
|
|
||||||
void initialize() {
|
|
||||||
if (auto executablePath = fs::getExecutablePath(); executablePath.has_value()) {
|
|
||||||
static std::string path = executablePath->string();
|
|
||||||
s_backtraceState = backtrace_create_state(path.c_str(), 1, [](void *, const char *msg, int) { log::error("{}", msg); }, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<StackFrame> getStackTrace() {
|
|
||||||
static std::vector<StackFrame> result;
|
|
||||||
|
|
||||||
result.clear();
|
|
||||||
if (s_backtraceState != nullptr) {
|
|
||||||
backtrace_full(s_backtraceState, 0, [](void *, uintptr_t, const char *fileName, int lineNumber, const char *function) -> int {
|
|
||||||
if (fileName == nullptr)
|
|
||||||
fileName = "??";
|
|
||||||
if (function == nullptr)
|
|
||||||
function = "??";
|
|
||||||
|
|
||||||
result.push_back(StackFrame { std::fs::path(fileName).filename().string(), llvm::demangle(function), u32(lineNumber) });
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}, nullptr, nullptr);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
std::vector<StackFrame> getStackTrace() {
|
||||||
|
static std::vector<StackFrame> result;
|
||||||
|
|
||||||
|
std::array<void*, 128> addresses;
|
||||||
|
auto count = backtrace(addresses.data(), addresses.size());
|
||||||
|
auto functions = backtrace_symbols(addresses.data(), count);
|
||||||
|
|
||||||
|
for (i32 i = 0; i < count; i++)
|
||||||
|
result.push_back(StackFrame { "", functions[i], 0 });
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(HEX_HAS_BACKTRACE)
|
||||||
|
|
||||||
|
#if __has_include(BACKTRACE_HEADER)
|
||||||
|
|
||||||
|
#include BACKTRACE_HEADER
|
||||||
|
#include <llvm/Demangle/Demangle.h>
|
||||||
|
#include <hex/helpers/logger.hpp>
|
||||||
|
#include <hex/helpers/utils.hpp>
|
||||||
|
|
||||||
|
namespace hex::stacktrace {
|
||||||
|
|
||||||
|
static struct backtrace_state *s_backtraceState;
|
||||||
|
|
||||||
|
|
||||||
|
void initialize() {
|
||||||
|
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value()) {
|
||||||
|
static std::string path = executablePath->string();
|
||||||
|
s_backtraceState = backtrace_create_state(path.c_str(), 1, [](void *, const char *msg, int) { log::error("{}", msg); }, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<StackFrame> getStackTrace() {
|
||||||
|
static std::vector<StackFrame> result;
|
||||||
|
|
||||||
|
result.clear();
|
||||||
|
if (s_backtraceState != nullptr) {
|
||||||
|
backtrace_full(s_backtraceState, 0, [](void *, uintptr_t, const char *fileName, int lineNumber, const char *function) -> int {
|
||||||
|
if (fileName == nullptr)
|
||||||
|
fileName = "??";
|
||||||
|
if (function == nullptr)
|
||||||
|
function = "??";
|
||||||
|
|
||||||
|
result.push_back(StackFrame { std::fs::path(fileName).filename().string(), llvm::demangle(function), u32(lineNumber) });
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}, nullptr, nullptr);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#include <hex/helpers/tar.hpp>
|
#include <hex/helpers/tar.hpp>
|
||||||
#include <hex/helpers/literals.hpp>
|
#include <hex/helpers/literals.hpp>
|
||||||
#include <hex/helpers/file.hpp>
|
|
||||||
#include <hex/helpers/fs.hpp>
|
#include <hex/helpers/fs.hpp>
|
||||||
|
#include <hex/helpers/logger.hpp>
|
||||||
|
|
||||||
|
#include <wolv/io/file.hpp>
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
@@ -12,11 +14,11 @@ namespace hex {
|
|||||||
|
|
||||||
// Explicitly create file so a short path gets generated
|
// Explicitly create file so a short path gets generated
|
||||||
if (mode == Mode::Create) {
|
if (mode == Mode::Create) {
|
||||||
fs::File file(path, fs::File::Mode::Create);
|
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||||
file.flush();
|
file.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto shortPath = hex::fs::toShortPath(path);
|
auto shortPath = wolv::io::fs::toShortPath(path);
|
||||||
if (mode == Tar::Mode::Read)
|
if (mode == Tar::Mode::Read)
|
||||||
error = mtar_open(&this->m_ctx, shortPath.string().c_str(), "r");
|
error = mtar_open(&this->m_ctx, shortPath.string().c_str(), "r");
|
||||||
else if (mode == Tar::Mode::Write)
|
else if (mode == Tar::Mode::Write)
|
||||||
@@ -26,6 +28,7 @@ namespace hex {
|
|||||||
else
|
else
|
||||||
error = MTAR_EFAILURE;
|
error = MTAR_EFAILURE;
|
||||||
|
|
||||||
|
this->m_path = path;
|
||||||
this->m_valid = (error == MTAR_ESUCCESS);
|
this->m_valid = (error == MTAR_ESUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,6 +38,7 @@ namespace hex {
|
|||||||
|
|
||||||
Tar::Tar(hex::Tar &&other) noexcept {
|
Tar::Tar(hex::Tar &&other) noexcept {
|
||||||
this->m_ctx = other.m_ctx;
|
this->m_ctx = other.m_ctx;
|
||||||
|
this->m_path = other.m_path;
|
||||||
this->m_valid = other.m_valid;
|
this->m_valid = other.m_valid;
|
||||||
|
|
||||||
other.m_ctx = { };
|
other.m_ctx = { };
|
||||||
@@ -45,6 +49,8 @@ namespace hex {
|
|||||||
this->m_ctx = other.m_ctx;
|
this->m_ctx = other.m_ctx;
|
||||||
other.m_ctx = { };
|
other.m_ctx = { };
|
||||||
|
|
||||||
|
this->m_path = other.m_path;
|
||||||
|
|
||||||
this->m_valid = other.m_valid;
|
this->m_valid = other.m_valid;
|
||||||
other.m_valid = false;
|
other.m_valid = false;
|
||||||
|
|
||||||
@@ -58,7 +64,7 @@ namespace hex {
|
|||||||
mtar_header_t header;
|
mtar_header_t header;
|
||||||
while (mtar_read_header(&this->m_ctx, &header) != MTAR_ENULLRECORD) {
|
while (mtar_read_header(&this->m_ctx, &header) != MTAR_ENULLRECORD) {
|
||||||
std::fs::path path = header.name;
|
std::fs::path path = header.name;
|
||||||
if (header.name != PaxHeaderName && fs::isSubPath(basePath, path)) {
|
if (header.name != PaxHeaderName && wolv::io::fs::isSubPath(basePath, path)) {
|
||||||
result.emplace_back(header.name);
|
result.emplace_back(header.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,14 +89,19 @@ namespace hex {
|
|||||||
this->m_valid = false;
|
this->m_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> Tar::read(const std::fs::path &path) {
|
std::vector<u8> Tar::readVector(const std::fs::path &path) {
|
||||||
mtar_header_t header;
|
mtar_header_t header;
|
||||||
|
|
||||||
auto fixedPath = path.string();
|
auto fixedPath = path.string();
|
||||||
#if defined(OS_WINDOWS)
|
#if defined(OS_WINDOWS)
|
||||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
||||||
#endif
|
#endif
|
||||||
mtar_find(&this->m_ctx, fixedPath.c_str(), &header);
|
int ret = mtar_find(&this->m_ctx, fixedPath.c_str(), &header);
|
||||||
|
if(ret != MTAR_ESUCCESS){
|
||||||
|
log::debug("Failed to read vector from path {} in tarred file {}: {}",
|
||||||
|
path.string(), this->m_path.string(), mtar_strerror(ret));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<u8> result(header.size, 0x00);
|
std::vector<u8> result(header.size, 0x00);
|
||||||
mtar_read_data(&this->m_ctx, result.data(), result.size());
|
mtar_read_data(&this->m_ctx, result.data(), result.size());
|
||||||
@@ -99,11 +110,11 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string Tar::readString(const std::fs::path &path) {
|
std::string Tar::readString(const std::fs::path &path) {
|
||||||
auto result = this->read(path);
|
auto result = this->readVector(path);
|
||||||
return { result.begin(), result.end() };
|
return { result.begin(), result.end() };
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tar::write(const std::fs::path &path, const std::vector<u8> &data) {
|
void Tar::writeVector(const std::fs::path &path, const std::vector<u8> &data) {
|
||||||
if (path.has_parent_path()) {
|
if (path.has_parent_path()) {
|
||||||
std::fs::path pathPart;
|
std::fs::path pathPart;
|
||||||
for (const auto &part : path.parent_path()) {
|
for (const auto &part : path.parent_path()) {
|
||||||
@@ -125,21 +136,21 @@ namespace hex {
|
|||||||
mtar_write_data(&this->m_ctx, data.data(), data.size());
|
mtar_write_data(&this->m_ctx, data.data(), data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tar::write(const std::fs::path &path, const std::string &data) {
|
void Tar::writeString(const std::fs::path &path, const std::string &data) {
|
||||||
this->write(path, std::vector<u8>(data.begin(), data.end()));
|
this->writeVector(path, { data.begin(), data.end() });
|
||||||
}
|
}
|
||||||
|
|
||||||
static void writeFile(mtar_t *ctx, mtar_header_t *header, const std::fs::path &path) {
|
static void writeFile(mtar_t *ctx, mtar_header_t *header, const std::fs::path &path) {
|
||||||
constexpr static u64 BufferSize = 1_MiB;
|
constexpr static u64 BufferSize = 1_MiB;
|
||||||
|
|
||||||
fs::File outputFile(path, fs::File::Mode::Create);
|
wolv::io::File outputFile(path, wolv::io::File::Mode::Create);
|
||||||
|
|
||||||
std::vector<u8> buffer;
|
std::vector<u8> buffer;
|
||||||
for (u64 offset = 0; offset < header->size; offset += BufferSize) {
|
for (u64 offset = 0; offset < header->size; offset += BufferSize) {
|
||||||
buffer.resize(std::min<u64>(BufferSize, header->size - offset));
|
buffer.resize(std::min<u64>(BufferSize, header->size - offset));
|
||||||
|
|
||||||
mtar_read_data(ctx, buffer.data(), buffer.size());
|
mtar_read_data(ctx, buffer.data(), buffer.size());
|
||||||
outputFile.write(buffer);
|
outputFile.writeVector(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
|
|
||||||
#include <hex/api/imhex_api.hpp>
|
#include <hex/api/imhex_api.hpp>
|
||||||
|
#include <hex/api/event.hpp>
|
||||||
|
|
||||||
#include <hex/helpers/fmt.hpp>
|
#include <hex/helpers/fmt.hpp>
|
||||||
|
|
||||||
@@ -66,6 +67,25 @@ namespace hex {
|
|||||||
return { data + index + 1 };
|
return { data + index + 1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<u8> parseBinaryString(const std::string &string) {
|
||||||
|
if (string.empty())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
u8 byte = 0x00;
|
||||||
|
for (char c : string) {
|
||||||
|
byte <<= 1;
|
||||||
|
|
||||||
|
if (c == '1')
|
||||||
|
byte |= 0b01;
|
||||||
|
else if (c == '0')
|
||||||
|
byte |= 0b00;
|
||||||
|
else
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return byte;
|
||||||
|
}
|
||||||
|
|
||||||
std::string toByteString(u64 bytes) {
|
std::string toByteString(u64 bytes) {
|
||||||
double value = bytes;
|
double value = bytes;
|
||||||
u8 unitIndex = 0;
|
u8 unitIndex = 0;
|
||||||
@@ -482,4 +502,13 @@ namespace hex {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::optional<std::fs::path> fileToOpen;
|
||||||
|
extern "C" void openFile(const char *path) {
|
||||||
|
fileToOpen = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<std::fs::path> getInitialFilePath() {
|
||||||
|
return fileToOpen;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,11 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
void openFile(const char *path);
|
||||||
|
|
||||||
void openWebpageMacos(const char *url) {
|
void openWebpageMacos(const char *url) {
|
||||||
CFURLRef urlRef = CFURLCreateWithBytes(NULL, (uint8_t*)(url), strlen(url), kCFStringEncodingASCII, NULL);
|
CFURLRef urlRef = CFURLCreateWithBytes(NULL, (uint8_t*)(url), strlen(url), kCFStringEncodingASCII, NULL);
|
||||||
LSOpenCFURLRef(urlRef, NULL);
|
LSOpenCFURLRef(urlRef, NULL);
|
||||||
@@ -30,4 +35,21 @@
|
|||||||
return [[NSScreen mainScreen] backingScaleFactor];
|
return [[NSScreen mainScreen] backingScaleFactor];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@interface HexDocument : NSDocument
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation HexDocument
|
||||||
|
|
||||||
|
- (BOOL) readFromURL:(NSURL *)url ofType:(NSString *)typeName error:(NSError **)outError {
|
||||||
|
NSString* urlString = [url absoluteString];
|
||||||
|
const char* utf8String = [urlString UTF8String];
|
||||||
|
|
||||||
|
openFile(utf8String);
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
#include <hex/helpers/magic.hpp>
|
#include <hex/helpers/magic.hpp>
|
||||||
|
#include <wolv/io/file.hpp>
|
||||||
|
|
||||||
namespace hex::prv {
|
namespace hex::prv {
|
||||||
|
|
||||||
@@ -16,6 +17,7 @@ namespace hex::prv {
|
|||||||
|
|
||||||
Provider::Provider() : m_id(s_idCounter++) {
|
Provider::Provider() : m_id(s_idCounter++) {
|
||||||
this->m_patches.emplace_back();
|
this->m_patches.emplace_back();
|
||||||
|
this->m_currPatches = this->m_patches.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
Provider::~Provider() {
|
Provider::~Provider() {
|
||||||
@@ -34,9 +36,33 @@ namespace hex::prv {
|
|||||||
this->markDirty();
|
this->markDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Provider::save() { }
|
void Provider::save() {
|
||||||
|
EventManager::post<EventProviderSaved>(this);
|
||||||
|
}
|
||||||
void Provider::saveAs(const std::fs::path &path) {
|
void Provider::saveAs(const std::fs::path &path) {
|
||||||
hex::unused(path);
|
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||||
|
|
||||||
|
if (file.isValid()) {
|
||||||
|
std::vector<u8> buffer(std::min<size_t>(0xFF'FFFF, this->getActualSize()), 0x00);
|
||||||
|
size_t bufferSize = 0;
|
||||||
|
|
||||||
|
for (u64 offset = 0; offset < this->getActualSize(); offset += bufferSize) {
|
||||||
|
bufferSize = buffer.size();
|
||||||
|
|
||||||
|
auto [region, valid] = this->getRegionValidity(offset + this->getBaseAddress());
|
||||||
|
if (!valid)
|
||||||
|
offset = region.getEndAddress() + 1;
|
||||||
|
|
||||||
|
auto [newRegion, newValid] = this->getRegionValidity(offset + this->getBaseAddress());
|
||||||
|
bufferSize = std::min<size_t>(bufferSize, (newRegion.getEndAddress() - offset) + 1);
|
||||||
|
bufferSize = std::min<size_t>(bufferSize, this->getActualSize() - offset);
|
||||||
|
|
||||||
|
this->read(offset + this->getBaseAddress(), buffer.data(), bufferSize, true);
|
||||||
|
file.writeBuffer(buffer.data(), bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
EventManager::post<EventProviderSaved>(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Provider::resize(size_t newSize) {
|
void Provider::resize(size_t newSize) {
|
||||||
@@ -95,25 +121,21 @@ namespace hex::prv {
|
|||||||
|
|
||||||
|
|
||||||
std::map<u64, u8> &Provider::getPatches() {
|
std::map<u64, u8> &Provider::getPatches() {
|
||||||
auto iter = this->m_patches.end();
|
return *this->m_currPatches;
|
||||||
for (u32 i = 0; i < this->m_patchTreeOffset + 1; i++)
|
|
||||||
iter--;
|
|
||||||
|
|
||||||
return *(iter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<u64, u8> &Provider::getPatches() const {
|
const std::map<u64, u8> &Provider::getPatches() const {
|
||||||
auto iter = this->m_patches.end();
|
return *this->m_currPatches;
|
||||||
for (u32 i = 0; i < this->m_patchTreeOffset + 1; i++)
|
|
||||||
iter--;
|
|
||||||
|
|
||||||
return *(iter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Provider::applyPatches() {
|
void Provider::applyPatches() {
|
||||||
for (auto &[patchAddress, patch] : getPatches()) {
|
for (auto &[patchAddress, patch] : getPatches()) {
|
||||||
this->writeRaw(patchAddress - this->getBaseAddress(), &patch, 1);
|
this->writeRaw(patchAddress - this->getBaseAddress(), &patch, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this->isWritable())
|
||||||
|
return;
|
||||||
|
|
||||||
this->markDirty();
|
this->markDirty();
|
||||||
|
|
||||||
this->m_patches.emplace_back();
|
this->m_patches.emplace_back();
|
||||||
@@ -175,17 +197,14 @@ namespace hex::prv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Provider::addPatch(u64 offset, const void *buffer, size_t size, bool createUndo) {
|
void Provider::addPatch(u64 offset, const void *buffer, size_t size, bool createUndo) {
|
||||||
if (this->m_patchTreeOffset > 0) {
|
if (createUndo) {
|
||||||
auto iter = this->m_patches.end();
|
// Delete all patches after the current one if a modification is made while
|
||||||
for (u32 i = 0; i < this->m_patchTreeOffset; i++)
|
// the current patch list is not at the end of the undo stack
|
||||||
iter--;
|
if (std::next(this->m_currPatches) != this->m_patches.end())
|
||||||
|
this->m_patches.erase(std::next(this->m_currPatches), this->m_patches.end());
|
||||||
|
|
||||||
this->m_patches.erase(iter, this->m_patches.end());
|
|
||||||
this->m_patchTreeOffset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (createUndo)
|
|
||||||
createUndoPoint();
|
createUndoPoint();
|
||||||
|
}
|
||||||
|
|
||||||
for (u64 i = 0; i < size; i++) {
|
for (u64 i = 0; i < size; i++) {
|
||||||
u8 patch = reinterpret_cast<const u8 *>(buffer)[i];
|
u8 patch = reinterpret_cast<const u8 *>(buffer)[i];
|
||||||
@@ -196,31 +215,35 @@ namespace hex::prv {
|
|||||||
getPatches().erase(offset + i);
|
getPatches().erase(offset + i);
|
||||||
else
|
else
|
||||||
getPatches()[offset + i] = patch;
|
getPatches()[offset + i] = patch;
|
||||||
|
|
||||||
|
EventManager::post<EventPatchCreated>(offset, originalValue, patch);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->markDirty();
|
this->markDirty();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Provider::createUndoPoint() {
|
void Provider::createUndoPoint() {
|
||||||
this->m_patches.push_back(getPatches());
|
this->m_patches.push_back(getPatches());
|
||||||
|
this->m_currPatches = std::prev(this->m_patches.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Provider::undo() {
|
void Provider::undo() {
|
||||||
if (canUndo())
|
if (canUndo())
|
||||||
this->m_patchTreeOffset++;
|
this->m_currPatches--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Provider::redo() {
|
void Provider::redo() {
|
||||||
if (canRedo())
|
if (canRedo())
|
||||||
this->m_patchTreeOffset--;
|
this->m_currPatches++;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Provider::canUndo() const {
|
bool Provider::canUndo() const {
|
||||||
return this->m_patchTreeOffset < this->m_patches.size() - 1;
|
return this->m_currPatches != this->m_patches.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Provider::canRedo() const {
|
bool Provider::canRedo() const {
|
||||||
return this->m_patchTreeOffset > 0;
|
return std::next(this->m_currPatches) != this->m_patches.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Provider::hasFilePicker() const {
|
bool Provider::hasFilePicker() const {
|
||||||
@@ -239,7 +262,8 @@ namespace hex::prv {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Provider::drawLoadInterface() {
|
bool Provider::drawLoadInterface() {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Provider::drawInterface() {
|
void Provider::drawInterface() {
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
#include <hex/api/imhex_api.hpp>
|
#include <hex/api/imhex_api.hpp>
|
||||||
|
|
||||||
|
#include <fonts/codicons_font.h>
|
||||||
|
|
||||||
namespace ImGui {
|
namespace ImGui {
|
||||||
|
|
||||||
Texture::Texture(const ImU8 *buffer, int size, int width, int height) {
|
Texture::Texture(const ImU8 *buffer, int size, int width, int height) {
|
||||||
@@ -263,6 +265,29 @@ namespace ImGui {
|
|||||||
return pressed;
|
return pressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HelpHover(const char *text) {
|
||||||
|
const auto iconColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive);
|
||||||
|
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, ImGui::GetStyle().FramePadding.y));
|
||||||
|
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, iconColor);
|
||||||
|
ImGui::Button(ICON_VS_INFO);
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
|
||||||
|
ImGui::SetNextWindowSizeConstraints(ImVec2(ImGui::GetTextLineHeight() * 25, 0), ImVec2(ImGui::GetTextLineHeight() * 25, FLT_MAX));
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::TextFormattedWrapped("{}", text);
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
}
|
||||||
|
|
||||||
void UnderlinedText(const char *label, ImColor color, const ImVec2 &size_arg) {
|
void UnderlinedText(const char *label, ImColor color, const ImVec2 &size_arg) {
|
||||||
ImGuiWindow *window = GetCurrentWindow();
|
ImGuiWindow *window = GetCurrentWindow();
|
||||||
|
|
||||||
@@ -344,6 +369,10 @@ namespace ImGui {
|
|||||||
colors[ImGuiCustomCol_ToolbarBrown] = ImColor(219, 179, 119);
|
colors[ImGuiCustomCol_ToolbarBrown] = ImColor(219, 179, 119);
|
||||||
|
|
||||||
colors[ImGuiCustomCol_Highlight] = ImColor(77, 198, 155);
|
colors[ImGuiCustomCol_Highlight] = ImColor(77, 198, 155);
|
||||||
|
|
||||||
|
colors[ImGuiCustomCol_IEEEToolSign] = ImColor(93, 93, 127);
|
||||||
|
colors[ImGuiCustomCol_IEEEToolExp] = ImColor(93, 127, 93);
|
||||||
|
colors[ImGuiCustomCol_IEEEToolMantissa] = ImColor(127, 93, 93);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyleCustomColorsLight() {
|
void StyleCustomColorsLight() {
|
||||||
@@ -362,6 +391,10 @@ namespace ImGui {
|
|||||||
colors[ImGuiCustomCol_ToolbarBrown] = ImColor(219, 179, 119);
|
colors[ImGuiCustomCol_ToolbarBrown] = ImColor(219, 179, 119);
|
||||||
|
|
||||||
colors[ImGuiCustomCol_Highlight] = ImColor(41, 151, 112);
|
colors[ImGuiCustomCol_Highlight] = ImColor(41, 151, 112);
|
||||||
|
|
||||||
|
colors[ImGuiCustomCol_IEEEToolSign] = ImColor(187, 187, 255);
|
||||||
|
colors[ImGuiCustomCol_IEEEToolExp] = ImColor(187, 255, 187);
|
||||||
|
colors[ImGuiCustomCol_IEEEToolMantissa] = ImColor(255, 187,187);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyleCustomColorsClassic() {
|
void StyleCustomColorsClassic() {
|
||||||
@@ -380,6 +413,9 @@ namespace ImGui {
|
|||||||
colors[ImGuiCustomCol_ToolbarBrown] = ImColor(219, 179, 119);
|
colors[ImGuiCustomCol_ToolbarBrown] = ImColor(219, 179, 119);
|
||||||
|
|
||||||
colors[ImGuiCustomCol_Highlight] = ImColor(77, 198, 155);
|
colors[ImGuiCustomCol_Highlight] = ImColor(77, 198, 155);
|
||||||
|
colors[ImGuiCustomCol_IEEEToolSign] = ImColor(93, 93, 127);
|
||||||
|
colors[ImGuiCustomCol_IEEEToolExp] = ImColor(93, 127, 93);
|
||||||
|
colors[ImGuiCustomCol_IEEEToolMantissa] = ImColor(127, 93, 93);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenPopupInWindow(const char *window_name, const char *popup_name) {
|
void OpenPopupInWindow(const char *window_name, const char *popup_name) {
|
||||||
@@ -500,7 +536,7 @@ namespace ImGui {
|
|||||||
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered
|
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered
|
||||||
: ImGuiCol_Button);
|
: ImGuiCol_Button);
|
||||||
RenderNavHighlight(bb, id);
|
RenderNavHighlight(bb, id);
|
||||||
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
|
RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
|
||||||
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb);
|
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb);
|
||||||
|
|
||||||
PopStyleColor();
|
PopStyleColor();
|
||||||
@@ -698,4 +734,34 @@ namespace ImGui {
|
|||||||
return pressed;
|
return pressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DimmedButton(const char* label){
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetCustomColorU32(ImGuiCustomCol_DescButtonHovered));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetCustomColorU32(ImGuiCustomCol_DescButton));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetColorU32(ImGuiCol_ButtonActive));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetCustomColorU32(ImGuiCustomCol_DescButtonActive));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1);
|
||||||
|
|
||||||
|
bool res = ImGui::Button(label);
|
||||||
|
|
||||||
|
ImGui::PopStyleColor(4);
|
||||||
|
ImGui::PopStyleVar(1);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DimmedIconButton(const char *symbol, ImVec4 color, ImVec2 size_arg){
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetCustomColorU32(ImGuiCustomCol_DescButtonHovered));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetCustomColorU32(ImGuiCustomCol_DescButton));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetColorU32(ImGuiCol_ButtonActive));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetCustomColorU32(ImGuiCustomCol_DescButtonActive));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1);
|
||||||
|
|
||||||
|
bool res = IconButton(symbol, color, size_arg);
|
||||||
|
|
||||||
|
ImGui::PopStyleColor(4);
|
||||||
|
ImGui::PopStyleVar(1);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
7
lib/libimhex/source/ui/popup.cpp
Normal file
7
lib/libimhex/source/ui/popup.cpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include <hex/ui/popup.hpp>
|
||||||
|
|
||||||
|
namespace hex::impl {
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<PopupBase>> PopupBase::s_openPopups;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -17,33 +17,6 @@ namespace hex {
|
|||||||
return ImHexApi::Provider::isValid() && ImHexApi::Provider::get()->isAvailable();
|
return ImHexApi::Provider::isValid() && ImHexApi::Provider::get()->isAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void View::showInfoPopup(const std::string &message) {
|
|
||||||
EventManager::post<RequestShowInfoPopup>(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void View::showErrorPopup(const std::string &message) {
|
|
||||||
EventManager::post<RequestShowErrorPopup>(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void View::showFatalPopup(const std::string &message) {
|
|
||||||
EventManager::post<RequestShowFatalErrorPopup>(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void View::showYesNoQuestionPopup(const std::string &message, const std::function<void()> &yesCallback, const std::function<void()> &noCallback) {
|
|
||||||
EventManager::post<RequestShowYesNoQuestionPopup>(message, yesCallback, noCallback);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void View::showFileChooserPopup(const std::vector<std::fs::path> &paths, const std::vector<nfdfilteritem_t> &validExtensions, bool multiple, const std::function<void(std::fs::path)> &callback) {
|
|
||||||
if (paths.empty()) {
|
|
||||||
fs::openFileBrowser(fs::DialogMode::Open, validExtensions, [callback](const auto &path) {
|
|
||||||
callback(path);
|
|
||||||
}, {}, multiple);
|
|
||||||
} else {
|
|
||||||
EventManager::post<RequestShowFileChooserPopup>(paths, validExtensions, callback, multiple);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool View::hasViewMenuItemEntry() const {
|
bool View::hasViewMenuItemEntry() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,9 +40,7 @@ namespace hex {
|
|||||||
void exitGLFW();
|
void exitGLFW();
|
||||||
void exitImGui();
|
void exitImGui();
|
||||||
|
|
||||||
friend void *ImHexSettingsHandler_ReadOpenFn(ImGuiContext *ctx, ImGuiSettingsHandler *, const char *);
|
void registerEventHandlers();
|
||||||
friend void ImHexSettingsHandler_ReadLine(ImGuiContext *, ImGuiSettingsHandler *handler, void *, const char *line);
|
|
||||||
friend void ImHexSettingsHandler_WriteAll(ImGuiContext *ctx, ImGuiSettingsHandler *handler, ImGuiTextBuffer *buf);
|
|
||||||
|
|
||||||
GLFWwindow *m_window = nullptr;
|
GLFWwindow *m_window = nullptr;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "init/splash_window.hpp"
|
#include "init/splash_window.hpp"
|
||||||
|
|
||||||
#include <hex/api/imhex_api.hpp>
|
#include <hex/api/imhex_api.hpp>
|
||||||
|
#include <hex/api/task.hpp>
|
||||||
|
|
||||||
#include <hex/helpers/utils.hpp>
|
#include <hex/helpers/utils.hpp>
|
||||||
#include <hex/helpers/utils_macos.hpp>
|
#include <hex/helpers/utils_macos.hpp>
|
||||||
#include <hex/helpers/fmt.hpp>
|
#include <hex/helpers/fmt.hpp>
|
||||||
@@ -14,9 +16,12 @@
|
|||||||
#include <hex/ui/imgui_imhex_extensions.h>
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
#include <imgui_impl_glfw.h>
|
#include <imgui_impl_glfw.h>
|
||||||
#include <imgui_impl_opengl3.h>
|
#include <imgui_impl_opengl3.h>
|
||||||
|
#include <imgui_impl_opengl3_loader.h>
|
||||||
#include <fonts/fontawesome_font.h>
|
#include <fonts/fontawesome_font.h>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#include <wolv/utils/guards.hpp>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@@ -90,44 +95,54 @@ namespace hex::init {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WindowSplash::loop() {
|
bool WindowSplash::loop() {
|
||||||
|
// Load splash screen image from romfs
|
||||||
auto splash = romfs::get("splash.png");
|
auto splash = romfs::get("splash.png");
|
||||||
ImGui::Texture splashTexture = ImGui::Texture(reinterpret_cast<const ImU8 *>(splash.data()), splash.size());
|
ImGui::Texture splashTexture = ImGui::Texture(reinterpret_cast<const ImU8 *>(splash.data()), splash.size());
|
||||||
|
|
||||||
|
// If the image couldn't be loaded correctly, something went wrong during the build process
|
||||||
|
// Close the application since this would lead to errors later on anyway.
|
||||||
if (!splashTexture.isValid()) {
|
if (!splashTexture.isValid()) {
|
||||||
log::fatal("Could not load splash screen image!");
|
log::fatal("Could not load splash screen image!");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Launch init tasks in background
|
||||||
auto tasksSucceeded = processTasksAsync();
|
auto tasksSucceeded = processTasksAsync();
|
||||||
|
|
||||||
auto scale = ImHexApi::System::getGlobalScale();
|
auto scale = ImHexApi::System::getGlobalScale();
|
||||||
|
|
||||||
|
// Splash window rendering loop
|
||||||
while (!glfwWindowShouldClose(this->m_window)) {
|
while (!glfwWindowShouldClose(this->m_window)) {
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
|
|
||||||
|
// Start a new ImGui frame
|
||||||
ImGui_ImplOpenGL3_NewFrame();
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
ImGui_ImplGlfw_NewFrame();
|
ImGui_ImplGlfw_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
// Draw the splash screen background
|
||||||
|
auto drawList = ImGui::GetForegroundDrawList();
|
||||||
{
|
{
|
||||||
std::lock_guard guard(this->m_progressMutex);
|
|
||||||
|
|
||||||
auto drawList = ImGui::GetForegroundDrawList();
|
|
||||||
|
|
||||||
drawList->AddImage(splashTexture, ImVec2(0, 0), splashTexture.getSize() * scale);
|
drawList->AddImage(splashTexture, ImVec2(0, 0), splashTexture.getSize() * scale);
|
||||||
|
|
||||||
drawList->AddText(ImVec2(15, 120) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("WerWolv 2020 - {0}", &__DATE__[7]).c_str());
|
drawList->AddText(ImVec2(15, 120) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("WerWolv 2020 - {0}", &__DATE__[7]).c_str());
|
||||||
|
|
||||||
#if defined(DEBUG) && defined(GIT_BRANCH) && defined(GIT_COMMIT_HASH)
|
#if defined(DEBUG) && defined(GIT_BRANCH) && defined(GIT_COMMIT_HASH_SHORT)
|
||||||
drawList->AddText(ImVec2(15, 140) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("{0} : {1} {2}@{3}", IMHEX_VERSION, ICON_FA_CODE_BRANCH, GIT_BRANCH, GIT_COMMIT_HASH).c_str());
|
drawList->AddText(ImVec2(15, 140) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("{0} : {1} {2}@{3}", IMHEX_VERSION, ICON_FA_CODE_BRANCH, GIT_BRANCH, GIT_COMMIT_HASH_SHORT).c_str());
|
||||||
#else
|
#else
|
||||||
drawList->AddText(ImVec2(15, 140) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("{0}", IMHEX_VERSION).c_str());
|
drawList->AddText(ImVec2(15, 140) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("{0}", IMHEX_VERSION).c_str());
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the task progress bar
|
||||||
|
{
|
||||||
|
std::lock_guard guard(this->m_progressMutex);
|
||||||
drawList->AddRectFilled(ImVec2(0, splashTexture.getSize().y - 5) * scale, ImVec2(splashTexture.getSize().x * this->m_progress, splashTexture.getSize().y) * scale, 0xFFFFFFFF);
|
drawList->AddRectFilled(ImVec2(0, splashTexture.getSize().y - 5) * scale, ImVec2(splashTexture.getSize().x * this->m_progress, splashTexture.getSize().y) * scale, 0xFFFFFFFF);
|
||||||
drawList->AddText(ImVec2(15, splashTexture.getSize().y - 25) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("[{}] {}...", "|/-\\"[ImU32(ImGui::GetTime() * 15) % 4], this->m_currTaskName).c_str());
|
drawList->AddText(ImVec2(15, splashTexture.getSize().y - 25) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("[{}] {}...", "|/-\\"[ImU32(ImGui::GetTime() * 15) % 4], this->m_currTaskName).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Render the frame
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
int displayWidth, displayHeight;
|
int displayWidth, displayHeight;
|
||||||
glfwGetFramebufferSize(this->m_window, &displayWidth, &displayHeight);
|
glfwGetFramebufferSize(this->m_window, &displayWidth, &displayHeight);
|
||||||
@@ -138,6 +153,7 @@ namespace hex::init {
|
|||||||
|
|
||||||
glfwSwapBuffers(this->m_window);
|
glfwSwapBuffers(this->m_window);
|
||||||
|
|
||||||
|
// Check if all background tasks have finished so the splash screen can be closed
|
||||||
if (tasksSucceeded.wait_for(0s) == std::future_status::ready) {
|
if (tasksSucceeded.wait_for(0s) == std::future_status::ready) {
|
||||||
return tasksSucceeded.get();
|
return tasksSucceeded.get();
|
||||||
}
|
}
|
||||||
@@ -147,20 +163,25 @@ namespace hex::init {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void centerWindow(GLFWwindow *window) {
|
static void centerWindow(GLFWwindow *window) {
|
||||||
|
// Get the primary monitor
|
||||||
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
|
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
|
||||||
if (!monitor)
|
if (!monitor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Get information about the monitor
|
||||||
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
|
const GLFWvidmode *mode = glfwGetVideoMode(monitor);
|
||||||
if (!mode)
|
if (!mode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Get the position of the monitor's viewport on the virtual screen
|
||||||
int monitorX, monitorY;
|
int monitorX, monitorY;
|
||||||
glfwGetMonitorPos(monitor, &monitorX, &monitorY);
|
glfwGetMonitorPos(monitor, &monitorX, &monitorY);
|
||||||
|
|
||||||
|
// Get the window size
|
||||||
int windowWidth, windowHeight;
|
int windowWidth, windowHeight;
|
||||||
glfwGetWindowSize(window, &windowWidth, &windowHeight);
|
glfwGetWindowSize(window, &windowWidth, &windowHeight);
|
||||||
|
|
||||||
|
// Center the splash screen on the monitor
|
||||||
glfwSetWindowPos(window, monitorX + (mode->width - windowWidth) / 2, monitorY + (mode->height - windowHeight) / 2);
|
glfwSetWindowPos(window, monitorX + (mode->width - windowWidth) / 2, monitorY + (mode->height - windowHeight) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,22 +195,25 @@ namespace hex::init {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configure used OpenGL version
|
||||||
#if defined(OS_MACOS)
|
#if defined(OS_MACOS)
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
|
||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE);
|
||||||
#else
|
#else
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Make splash screen non-resizable, undecorated and transparent
|
||||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
||||||
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
|
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
|
||||||
glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
|
glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
|
||||||
glfwWindowHint(GLFW_FLOATING, GLFW_FALSE);
|
glfwWindowHint(GLFW_FLOATING, GLFW_FALSE);
|
||||||
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_FALSE);
|
|
||||||
|
|
||||||
|
// Create the splash screen window
|
||||||
this->m_window = glfwCreateWindow(1, 400, "Starting ImHex...", nullptr, nullptr);
|
this->m_window = glfwCreateWindow(1, 400, "Starting ImHex...", nullptr, nullptr);
|
||||||
if (this->m_window == nullptr) {
|
if (this->m_window == nullptr) {
|
||||||
log::fatal("Failed to create GLFW window!");
|
log::fatal("Failed to create GLFW window!");
|
||||||
@@ -223,6 +247,7 @@ namespace hex::init {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WindowSplash::initImGui() {
|
void WindowSplash::initImGui() {
|
||||||
|
// Initialize ImGui
|
||||||
IMGUI_CHECKVERSION();
|
IMGUI_CHECKVERSION();
|
||||||
GImGui = ImGui::CreateContext();
|
GImGui = ImGui::CreateContext();
|
||||||
ImGui::StyleColorsDark();
|
ImGui::StyleColorsDark();
|
||||||
@@ -239,31 +264,36 @@ namespace hex::init {
|
|||||||
|
|
||||||
ImGui::GetStyle().ScaleAllSizes(ImHexApi::System::getGlobalScale());
|
ImGui::GetStyle().ScaleAllSizes(ImHexApi::System::getGlobalScale());
|
||||||
|
|
||||||
io.Fonts->Clear();
|
// Load fonts necessary for the splash screen
|
||||||
|
{
|
||||||
|
io.Fonts->Clear();
|
||||||
|
|
||||||
ImFontConfig cfg;
|
ImFontConfig cfg;
|
||||||
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
|
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
|
||||||
cfg.SizePixels = 13.0_scaled;
|
cfg.SizePixels = 13.0_scaled;
|
||||||
io.Fonts->AddFontDefault(&cfg);
|
io.Fonts->AddFontDefault(&cfg);
|
||||||
|
|
||||||
cfg.MergeMode = true;
|
cfg.MergeMode = true;
|
||||||
|
|
||||||
ImWchar fontAwesomeRange[] = {
|
ImWchar fontAwesomeRange[] = {
|
||||||
ICON_MIN_FA, ICON_MAX_FA, 0
|
ICON_MIN_FA, ICON_MAX_FA, 0
|
||||||
};
|
};
|
||||||
std::uint8_t *px;
|
std::uint8_t *px;
|
||||||
int w, h;
|
int w, h;
|
||||||
io.Fonts->AddFontFromMemoryCompressedTTF(font_awesome_compressed_data, font_awesome_compressed_size, 11.0_scaled, &cfg, fontAwesomeRange);
|
io.Fonts->AddFontFromMemoryCompressedTTF(font_awesome_compressed_data, font_awesome_compressed_size, 11.0_scaled, &cfg, fontAwesomeRange);
|
||||||
io.Fonts->GetTexDataAsRGBA32(&px, &w, &h);
|
io.Fonts->GetTexDataAsAlpha8(&px, &w, &h);
|
||||||
|
|
||||||
// Create new font atlas
|
// Create new font atlas
|
||||||
GLuint tex;
|
GLuint tex;
|
||||||
glGenTextures(1, &tex);
|
glGenTextures(1, &tex);
|
||||||
glBindTexture(GL_TEXTURE_2D, tex);
|
glBindTexture(GL_TEXTURE_2D, tex);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA8, GL_UNSIGNED_INT, px);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, px);
|
||||||
io.Fonts->SetTexID(reinterpret_cast<ImTextureID>(tex));
|
io.Fonts->SetTexID(reinterpret_cast<ImTextureID>(tex));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't save window settings for the splash screen
|
||||||
io.IniFilename = nullptr;
|
io.IniFilename = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,60 +1,104 @@
|
|||||||
#include "init/tasks.hpp"
|
#include "init/tasks.hpp"
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <imgui_freetype.h>
|
|
||||||
#include <romfs/romfs.hpp>
|
#include <romfs/romfs.hpp>
|
||||||
|
|
||||||
|
#include <hex/helpers/http_requests.hpp>
|
||||||
|
#include <hex/helpers/fs.hpp>
|
||||||
|
#include <hex/helpers/logger.hpp>
|
||||||
|
|
||||||
|
#include <hex/api_urls.hpp>
|
||||||
#include <hex/api/content_registry.hpp>
|
#include <hex/api/content_registry.hpp>
|
||||||
#include <hex/api/project_file_manager.hpp>
|
#include <hex/api/project_file_manager.hpp>
|
||||||
#include <hex/api/theme_manager.hpp>
|
#include <hex/api/theme_manager.hpp>
|
||||||
|
#include <hex/api/plugin_manager.hpp>
|
||||||
|
#include <hex/api/layout_manager.hpp>
|
||||||
|
|
||||||
#include <hex/ui/view.hpp>
|
#include <hex/ui/view.hpp>
|
||||||
#include <hex/helpers/net.hpp>
|
#include <hex/ui/popup.hpp>
|
||||||
#include <hex/helpers/fs.hpp>
|
|
||||||
#include <hex/helpers/logger.hpp>
|
|
||||||
|
|
||||||
#include <fonts/fontawesome_font.h>
|
#include <fonts/fontawesome_font.h>
|
||||||
#include <fonts/codicons_font.h>
|
#include <fonts/codicons_font.h>
|
||||||
#include <fonts/unifont_font.h>
|
#include <fonts/unifont_font.h>
|
||||||
|
|
||||||
#include <hex/api/plugin_manager.hpp>
|
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include <wolv/io/fs.hpp>
|
||||||
|
#include <wolv/io/file.hpp>
|
||||||
|
|
||||||
namespace hex::init {
|
namespace hex::init {
|
||||||
|
|
||||||
using namespace std::literals::string_literals;
|
using namespace std::literals::string_literals;
|
||||||
|
|
||||||
|
#if defined(HEX_UPDATE_CHECK)
|
||||||
static bool checkForUpdates() {
|
static bool checkForUpdates() {
|
||||||
// documentation of the value above the setting definition
|
|
||||||
int showCheckForUpdates = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.check_for_updates", 2);
|
int showCheckForUpdates = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.check_for_updates", 2);
|
||||||
|
|
||||||
|
// Check if we should check for updates
|
||||||
if (showCheckForUpdates == 1){
|
if (showCheckForUpdates == 1){
|
||||||
hex::Net net;
|
HttpRequest request("GET", GitHubApiURL + "/releases/latest"s);
|
||||||
|
request.setTimeout(2000);
|
||||||
|
|
||||||
auto releases = net.getJson(GitHubApiURL + "/releases/latest"s, 2000).get();
|
// Query the GitHub API for the latest release version
|
||||||
if (releases.code != 200)
|
auto response = request.execute().get();
|
||||||
|
if (response.getStatusCode() != 200)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!releases.body.contains("tag_name") || !releases.body["tag_name"].is_string())
|
nlohmann::json releases;
|
||||||
|
try {
|
||||||
|
releases = nlohmann::json::parse(response.getData());
|
||||||
|
} catch (std::exception &e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the response is valid
|
||||||
|
if (!releases.contains("tag_name") || !releases["tag_name"].is_string())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// Convert the current version string to a format that can be compared to the latest release
|
||||||
auto versionString = std::string(IMHEX_VERSION);
|
auto versionString = std::string(IMHEX_VERSION);
|
||||||
size_t versionLength = std::min(versionString.find_first_of('-'), versionString.length());
|
size_t versionLength = std::min(versionString.find_first_of('-'), versionString.length());
|
||||||
auto currVersion = "v" + versionString.substr(0, versionLength);
|
auto currVersion = "v" + versionString.substr(0, versionLength);
|
||||||
auto latestVersion = releases.body["tag_name"].get<std::string_view>();
|
|
||||||
|
|
||||||
|
// Get the latest release version string
|
||||||
|
auto latestVersion = releases["tag_name"].get<std::string_view>();
|
||||||
|
|
||||||
|
// Check if the latest release is different from the current version
|
||||||
if (latestVersion != currVersion)
|
if (latestVersion != currVersion)
|
||||||
ImHexApi::System::impl::addInitArgument("update-available", latestVersion.data());
|
ImHexApi::System::impl::addInitArgument("update-available", latestVersion.data());
|
||||||
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool setupEnvironment() {
|
bool setupEnvironment() {
|
||||||
hex::log::debug("Using romfs: '{}'", romfs::name());
|
hex::log::debug("Using romfs: '{}'", romfs::name());
|
||||||
|
|
||||||
Net::setCACert(std::string(romfs::get("cacert.pem").string()));
|
// Load the SSL certificate
|
||||||
|
constexpr static auto CaCertFileName = "cacert.pem";
|
||||||
|
|
||||||
|
// Look for a custom certificate in the config folder
|
||||||
|
std::fs::path caCertPath;
|
||||||
|
for (const auto &folder : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||||
|
for (const auto &file : std::fs::directory_iterator(folder)) {
|
||||||
|
if (file.path().filename() == CaCertFileName) {
|
||||||
|
caCertPath = file.path();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a custom certificate was found, use it, otherwise use the one from the romfs
|
||||||
|
std::string caCertData;
|
||||||
|
if (!caCertPath.empty())
|
||||||
|
caCertData = wolv::io::File(caCertPath, wolv::io::File::Mode::Read).readString();
|
||||||
|
else
|
||||||
|
caCertData = std::string(romfs::get(CaCertFileName).string());
|
||||||
|
|
||||||
|
HttpRequest::setCACert(caCertData);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -64,13 +108,13 @@ namespace hex::init {
|
|||||||
|
|
||||||
using enum fs::ImHexPath;
|
using enum fs::ImHexPath;
|
||||||
|
|
||||||
// Create all folders
|
// Try to create all default directories
|
||||||
for (u32 path = 0; path < u32(fs::ImHexPath::END); path++) {
|
for (u32 path = 0; path < u32(fs::ImHexPath::END); path++) {
|
||||||
for (auto &folder : fs::getDefaultPaths(static_cast<fs::ImHexPath>(path), true)) {
|
for (auto &folder : fs::getDefaultPaths(static_cast<fs::ImHexPath>(path), true)) {
|
||||||
try {
|
try {
|
||||||
fs::createDirectories(folder);
|
wolv::io::fs::createDirectories(folder);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
log::error("Failed to create folder {}!", hex::toUTF8String(folder));
|
log::error("Failed to create folder {}!", wolv::util::toUTF8String(folder));
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,68 +126,129 @@ namespace hex::init {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool migrateConfig(){
|
||||||
|
|
||||||
|
// Check if there is a new config in folder
|
||||||
|
auto configPaths = hex::fs::getDefaultPaths(hex::fs::ImHexPath::Config, false);
|
||||||
|
|
||||||
|
// There should always be exactly one config path on Linux
|
||||||
|
std::fs::path newConfigPath = configPaths[0];
|
||||||
|
wolv::io::File newConfigFile(newConfigPath / "settings.json", wolv::io::File::Mode::Read);
|
||||||
|
if (!newConfigFile.isValid()) {
|
||||||
|
|
||||||
|
// find an old config
|
||||||
|
std::fs::path oldConfigPath;
|
||||||
|
for (const auto &dir : hex::fs::appendPath(hex::fs::getDataPaths(), "config")) {
|
||||||
|
wolv::io::File oldConfigFile(dir / "settings.json", wolv::io::File::Mode::Read);
|
||||||
|
if (oldConfigFile.isValid()) {
|
||||||
|
oldConfigPath = dir;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!oldConfigPath.empty()) {
|
||||||
|
log::info("Found config file in {}! Migrating to {}", oldConfigPath.string(), newConfigPath.string());
|
||||||
|
|
||||||
|
std::fs::rename(oldConfigPath / "settings.json", newConfigPath / "settings.json");
|
||||||
|
wolv::io::File oldIniFile(oldConfigPath / "interface.ini", wolv::io::File::Mode::Read);
|
||||||
|
if (oldIniFile.isValid()) {
|
||||||
|
std::fs::rename(oldConfigPath / "interface.ini", newConfigPath / "interface.ini");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fs::remove(oldConfigPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool loadFontsImpl(bool loadUnicode) {
|
static bool loadFontsImpl(bool loadUnicode) {
|
||||||
float fontSize = ImHexApi::System::getFontSize();
|
float fontSize = ImHexApi::System::getFontSize();
|
||||||
|
|
||||||
const auto &fontFile = ImHexApi::System::getCustomFontPath();
|
const auto &fontFile = ImHexApi::System::getCustomFontPath();
|
||||||
|
|
||||||
|
// Setup basic font configuration
|
||||||
auto fonts = IM_NEW(ImFontAtlas)();
|
auto fonts = IM_NEW(ImFontAtlas)();
|
||||||
ImFontConfig cfg = {};
|
ImFontConfig cfg = {};
|
||||||
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
|
cfg.OversampleH = cfg.OversampleV = 2, cfg.PixelSnapH = true;
|
||||||
cfg.SizePixels = fontSize;
|
cfg.SizePixels = fontSize;
|
||||||
|
|
||||||
|
fonts->Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;
|
||||||
|
|
||||||
|
// Configure font glyph ranges that should be loaded from the default font and unifont
|
||||||
ImVector<ImWchar> ranges;
|
ImVector<ImWchar> ranges;
|
||||||
{
|
{
|
||||||
ImFontGlyphRangesBuilder glyphRangesBuilder;
|
ImFontGlyphRangesBuilder glyphRangesBuilder;
|
||||||
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesDefault());
|
|
||||||
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesJapanese());
|
|
||||||
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesChineseFull());
|
|
||||||
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesCyrillic());
|
|
||||||
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesKorean());
|
|
||||||
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesThai());
|
|
||||||
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesVietnamese());
|
|
||||||
|
|
||||||
{
|
{
|
||||||
constexpr static ImWchar controlCodeRange[] = { 0x0000, 0x001F, 0 };
|
constexpr static ImWchar controlCodeRange[] = { 0x0001, 0x001F, 0 };
|
||||||
constexpr static ImWchar extendedAsciiRange[] = { 0x007F, 0x00FF, 0 };
|
constexpr static ImWchar extendedAsciiRange[] = { 0x007F, 0x00FF, 0 };
|
||||||
|
|
||||||
glyphRangesBuilder.AddRanges(controlCodeRange);
|
glyphRangesBuilder.AddRanges(controlCodeRange);
|
||||||
|
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesDefault());
|
||||||
glyphRangesBuilder.AddRanges(extendedAsciiRange);
|
glyphRangesBuilder.AddRanges(extendedAsciiRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (loadUnicode) {
|
||||||
|
constexpr static ImWchar fullRange[] = { 0x0100, 0xFFEF, 0 };
|
||||||
|
|
||||||
|
glyphRangesBuilder.AddRanges(fullRange);
|
||||||
|
} else {
|
||||||
|
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesJapanese());
|
||||||
|
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesChineseFull());
|
||||||
|
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesCyrillic());
|
||||||
|
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesKorean());
|
||||||
|
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesThai());
|
||||||
|
glyphRangesBuilder.AddRanges(fonts->GetGlyphRangesVietnamese());
|
||||||
|
}
|
||||||
|
|
||||||
glyphRangesBuilder.BuildRanges(&ranges);
|
glyphRangesBuilder.BuildRanges(&ranges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Glyph range for font awesome icons
|
||||||
ImWchar fontAwesomeRange[] = {
|
ImWchar fontAwesomeRange[] = {
|
||||||
ICON_MIN_FA, ICON_MAX_FA, 0
|
ICON_MIN_FA, ICON_MAX_FA, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Glyph range for codicons icons
|
||||||
ImWchar codiconsRange[] = {
|
ImWchar codiconsRange[] = {
|
||||||
ICON_MIN_VS, ICON_MAX_VS, 0
|
ICON_MIN_VS, ICON_MAX_VS, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Load main font
|
||||||
|
// If a custom font has been specified, load it, otherwise load the default ImGui font
|
||||||
if (fontFile.empty()) {
|
if (fontFile.empty()) {
|
||||||
// Load default font if no custom one has been specified
|
|
||||||
|
|
||||||
fonts->Clear();
|
fonts->Clear();
|
||||||
fonts->AddFontDefault(&cfg);
|
fonts->AddFontDefault(&cfg);
|
||||||
} else {
|
} else {
|
||||||
// Load custom font
|
fonts->AddFontFromFileTTF(wolv::util::toUTF8String(fontFile).c_str(), 0, &cfg, ranges.Data);
|
||||||
fonts->AddFontFromFileTTF(hex::toUTF8String(fontFile).c_str(), 0, &cfg, ranges.Data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Merge all fonts into one big font atlas
|
||||||
cfg.MergeMode = true;
|
cfg.MergeMode = true;
|
||||||
|
|
||||||
|
// Add font awesome and codicons icons to font atlas
|
||||||
fonts->AddFontFromMemoryCompressedTTF(font_awesome_compressed_data, font_awesome_compressed_size, 0, &cfg, fontAwesomeRange);
|
fonts->AddFontFromMemoryCompressedTTF(font_awesome_compressed_data, font_awesome_compressed_size, 0, &cfg, fontAwesomeRange);
|
||||||
fonts->AddFontFromMemoryCompressedTTF(codicons_compressed_data, codicons_compressed_size, 0, &cfg, codiconsRange);
|
fonts->AddFontFromMemoryCompressedTTF(codicons_compressed_data, codicons_compressed_size, 0, &cfg, codiconsRange);
|
||||||
|
|
||||||
|
// Add unifont if unicode support is enabled
|
||||||
if (loadUnicode)
|
if (loadUnicode)
|
||||||
fonts->AddFontFromMemoryCompressedTTF(unifont_compressed_data, unifont_compressed_size, 0, &cfg, ranges.Data);
|
fonts->AddFontFromMemoryCompressedTTF(unifont_compressed_data, unifont_compressed_size, 0, &cfg, ranges.Data);
|
||||||
|
|
||||||
|
// Try to build the font atlas
|
||||||
if (!fonts->Build()) {
|
if (!fonts->Build()) {
|
||||||
|
// The main reason the font atlas failed to build is that the font is too big for the GPU to handle
|
||||||
|
// If unicode support is enabled, therefor try to load the font atlas without unicode support
|
||||||
|
// If that still didn't work, there's probably something else going on with the graphics drivers
|
||||||
|
// Especially Intel GPU drivers are known to have various bugs
|
||||||
|
|
||||||
if (loadUnicode) {
|
if (loadUnicode) {
|
||||||
log::error("Failed to build font atlas! Disabling Unicode support.");
|
log::error("Failed to build font atlas! Disabling Unicode support.");
|
||||||
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.enable_unicode", false);
|
|
||||||
IM_DELETE(fonts);
|
IM_DELETE(fonts);
|
||||||
|
|
||||||
|
// Disable unicode support in settings
|
||||||
|
ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.enable_unicode", false);
|
||||||
|
|
||||||
|
// Try to load the font atlas again
|
||||||
return loadFontsImpl(false);
|
return loadFontsImpl(false);
|
||||||
} else {
|
} else {
|
||||||
log::error("Failed to build font atlas! Check your Graphics driver!");
|
log::error("Failed to build font atlas! Check your Graphics driver!");
|
||||||
@@ -151,6 +256,7 @@ namespace hex::init {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configure ImGui to use the font atlas
|
||||||
View::setFontAtlas(fonts);
|
View::setFontAtlas(fonts);
|
||||||
View::setFontConfig(cfg);
|
View::setFontConfig(cfg);
|
||||||
|
|
||||||
@@ -162,11 +268,15 @@ namespace hex::init {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool deleteSharedData() {
|
bool deleteSharedData() {
|
||||||
EventManager::clear();
|
// This function is called when ImHex is closed. It deletes all shared data that was created by plugins
|
||||||
|
// This is a bit of a hack but necessary because when ImHex gets closed, all plugins are unloaded in order for
|
||||||
|
// destructors to be called correctly. To prevent crashes when ImHex exits, we need to delete all shared data
|
||||||
|
|
||||||
|
EventManager::post<EventImHexClosing>();
|
||||||
|
|
||||||
while (ImHexApi::Provider::isValid())
|
while (ImHexApi::Provider::isValid())
|
||||||
ImHexApi::Provider::remove(ImHexApi::Provider::get());
|
ImHexApi::Provider::remove(ImHexApi::Provider::get());
|
||||||
ContentRegistry::Provider::getEntries().clear();
|
ContentRegistry::Provider::impl::getEntries().clear();
|
||||||
|
|
||||||
ImHexApi::System::getInitArguments().clear();
|
ImHexApi::System::getInitArguments().clear();
|
||||||
ImHexApi::HexEditor::impl::getBackgroundHighlights().clear();
|
ImHexApi::HexEditor::impl::getBackgroundHighlights().clear();
|
||||||
@@ -176,50 +286,53 @@ namespace hex::init {
|
|||||||
ImHexApi::HexEditor::impl::getTooltips().clear();
|
ImHexApi::HexEditor::impl::getTooltips().clear();
|
||||||
ImHexApi::HexEditor::impl::getTooltipFunctions().clear();
|
ImHexApi::HexEditor::impl::getTooltipFunctions().clear();
|
||||||
|
|
||||||
ContentRegistry::Settings::getEntries().clear();
|
ContentRegistry::Settings::impl::getEntries().clear();
|
||||||
ContentRegistry::Settings::getSettingsData().clear();
|
ContentRegistry::Settings::impl::getSettingsData().clear();
|
||||||
|
|
||||||
ContentRegistry::CommandPaletteCommands::getEntries().clear();
|
ContentRegistry::CommandPaletteCommands::impl::getEntries().clear();
|
||||||
|
ContentRegistry::CommandPaletteCommands::impl::getHandlers().clear();
|
||||||
|
|
||||||
ContentRegistry::PatternLanguage::getFunctions().clear();
|
ContentRegistry::PatternLanguage::impl::getFunctions().clear();
|
||||||
ContentRegistry::PatternLanguage::getPragmas().clear();
|
ContentRegistry::PatternLanguage::impl::getPragmas().clear();
|
||||||
ContentRegistry::PatternLanguage::impl::getVisualizers().clear();
|
ContentRegistry::PatternLanguage::impl::getVisualizers().clear();
|
||||||
|
|
||||||
{
|
ContentRegistry::Views::impl::getEntries().clear();
|
||||||
auto &views = ContentRegistry::Views::getEntries();
|
impl::PopupBase::getOpenPopups().clear();
|
||||||
for (auto &[name, view] : views)
|
|
||||||
delete view;
|
|
||||||
views.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ContentRegistry::Tools::getEntries().clear();
|
ContentRegistry::Tools::impl::getEntries().clear();
|
||||||
ContentRegistry::DataInspector::getEntries().clear();
|
ContentRegistry::DataInspector::impl::getEntries().clear();
|
||||||
|
|
||||||
ContentRegistry::Language::getLanguages().clear();
|
ContentRegistry::Language::impl::getLanguages().clear();
|
||||||
ContentRegistry::Language::getLanguageDefinitions().clear();
|
ContentRegistry::Language::impl::getLanguageDefinitions().clear();
|
||||||
LangEntry::resetLanguageStrings();
|
LangEntry::resetLanguageStrings();
|
||||||
|
|
||||||
ContentRegistry::Interface::getWelcomeScreenEntries().clear();
|
ContentRegistry::Interface::impl::getWelcomeScreenEntries().clear();
|
||||||
ContentRegistry::Interface::getFooterItems().clear();
|
ContentRegistry::Interface::impl::getFooterItems().clear();
|
||||||
ContentRegistry::Interface::getToolbarItems().clear();
|
ContentRegistry::Interface::impl::getToolbarItems().clear();
|
||||||
ContentRegistry::Interface::getMainMenuItems().clear();
|
ContentRegistry::Interface::impl::getMainMenuItems().clear();
|
||||||
ContentRegistry::Interface::getMenuItems().clear();
|
ContentRegistry::Interface::impl::getMenuItems().clear();
|
||||||
ContentRegistry::Interface::getSidebarItems().clear();
|
ContentRegistry::Interface::impl::getSidebarItems().clear();
|
||||||
ContentRegistry::Interface::getTitleBarButtons().clear();
|
ContentRegistry::Interface::impl::getTitleBarButtons().clear();
|
||||||
ContentRegistry::Interface::getLayouts().clear();
|
|
||||||
|
|
||||||
ShortcutManager::clearShortcuts();
|
ShortcutManager::clearShortcuts();
|
||||||
|
|
||||||
TaskManager::getRunningTasks().clear();
|
TaskManager::getRunningTasks().clear();
|
||||||
|
|
||||||
ContentRegistry::DataProcessorNode::getEntries().clear();
|
ContentRegistry::DataProcessorNode::impl::getEntries().clear();
|
||||||
|
|
||||||
ContentRegistry::DataFormatter::getEntries().clear();
|
ContentRegistry::DataFormatter::impl::getEntries().clear();
|
||||||
ContentRegistry::FileHandler::getEntries().clear();
|
ContentRegistry::FileHandler::impl::getEntries().clear();
|
||||||
ContentRegistry::Hashes::impl::getHashes().clear();
|
ContentRegistry::Hashes::impl::getHashes().clear();
|
||||||
|
|
||||||
api::ThemeManager::reset();
|
ContentRegistry::BackgroundServices::impl::stopServices();
|
||||||
|
ContentRegistry::BackgroundServices::impl::getServices().clear();
|
||||||
|
|
||||||
|
ContentRegistry::CommunicationInterface::impl::getNetworkEndpoints().clear();
|
||||||
|
|
||||||
|
LayoutManager::reset();
|
||||||
|
|
||||||
|
ThemeManager::reset();
|
||||||
|
|
||||||
{
|
{
|
||||||
auto &visualizers = ContentRegistry::HexEditor::impl::getVisualizers();
|
auto &visualizers = ContentRegistry::HexEditor::impl::getVisualizers();
|
||||||
@@ -233,16 +346,21 @@ namespace hex::init {
|
|||||||
|
|
||||||
fs::setFileBrowserErrorCallback(nullptr);
|
fs::setFileBrowserErrorCallback(nullptr);
|
||||||
|
|
||||||
|
EventManager::clear();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool loadPlugins() {
|
bool loadPlugins() {
|
||||||
|
// Load plugins
|
||||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Plugins)) {
|
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Plugins)) {
|
||||||
PluginManager::load(dir);
|
PluginManager::load(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get loaded plugins
|
||||||
auto &plugins = PluginManager::getPlugins();
|
auto &plugins = PluginManager::getPlugins();
|
||||||
|
|
||||||
|
// If no plugins were loaded, ImHex wasn't installed properly. This will trigger an error popup later on
|
||||||
if (plugins.empty()) {
|
if (plugins.empty()) {
|
||||||
log::error("No plugins found!");
|
log::error("No plugins found!");
|
||||||
|
|
||||||
@@ -250,7 +368,8 @@ namespace hex::init {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto shouldLoadPlugin = [executablePath = hex::fs::getExecutablePath()](const Plugin &plugin) {
|
const auto shouldLoadPlugin = [executablePath = wolv::io::fs::getExecutablePath()](const Plugin &plugin) {
|
||||||
|
// In debug builds, ignore all plugins that are not part of the executable directory
|
||||||
#if !defined(DEBUG)
|
#if !defined(DEBUG)
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
@@ -258,12 +377,14 @@ namespace hex::init {
|
|||||||
if (!executablePath.has_value())
|
if (!executablePath.has_value())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// In debug builds, ignore all plugins that are not part of the executable directory
|
// Check if the plugin is somewhere in the same directory tree as the executable
|
||||||
return !std::fs::relative(plugin.getPath(), executablePath->parent_path()).string().starts_with("..");
|
return !std::fs::relative(plugin.getPath(), executablePath->parent_path()).string().starts_with("..");
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 builtinPlugins = 0;
|
u32 builtinPlugins = 0;
|
||||||
u32 loadErrors = 0;
|
u32 loadErrors = 0;
|
||||||
|
|
||||||
|
// Load the builtin plugin first, so it can initialize everything that's necessary for ImHex to work
|
||||||
for (const auto &plugin : plugins) {
|
for (const auto &plugin : plugins) {
|
||||||
if (!plugin.isBuiltinPlugin()) continue;
|
if (!plugin.isBuiltinPlugin()) continue;
|
||||||
|
|
||||||
@@ -272,15 +393,18 @@ namespace hex::init {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure there's only one built-in plugin
|
||||||
builtinPlugins++;
|
builtinPlugins++;
|
||||||
if (builtinPlugins > 1) continue;
|
if (builtinPlugins > 1) continue;
|
||||||
|
|
||||||
|
// Initialize the plugin
|
||||||
if (!plugin.initializePlugin()) {
|
if (!plugin.initializePlugin()) {
|
||||||
log::error("Failed to initialize plugin {}", hex::toUTF8String(plugin.getPath().filename()));
|
log::error("Failed to initialize plugin {}", wolv::util::toUTF8String(plugin.getPath().filename()));
|
||||||
loadErrors++;
|
loadErrors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load all other plugins
|
||||||
for (const auto &plugin : plugins) {
|
for (const auto &plugin : plugins) {
|
||||||
if (plugin.isBuiltinPlugin()) continue;
|
if (plugin.isBuiltinPlugin()) continue;
|
||||||
|
|
||||||
@@ -289,18 +413,22 @@ namespace hex::init {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize the plugin
|
||||||
if (!plugin.initializePlugin()) {
|
if (!plugin.initializePlugin()) {
|
||||||
log::error("Failed to initialize plugin {}", hex::toUTF8String(plugin.getPath().filename()));
|
log::error("Failed to initialize plugin {}", wolv::util::toUTF8String(plugin.getPath().filename()));
|
||||||
loadErrors++;
|
loadErrors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If no plugins were loaded successfully, ImHex wasn't installed properly. This will trigger an error popup later on
|
||||||
if (loadErrors == plugins.size()) {
|
if (loadErrors == plugins.size()) {
|
||||||
log::error("No plugins loaded successfully!");
|
log::error("No plugins loaded successfully!");
|
||||||
ImHexApi::System::impl::addInitArgument("no-plugins");
|
ImHexApi::System::impl::addInitArgument("no-plugins");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ImHex requires exactly one built-in plugin
|
||||||
|
// If no built-in plugin or more than one was found, something's wrong and we can't continue
|
||||||
if (builtinPlugins == 0) {
|
if (builtinPlugins == 0) {
|
||||||
log::error("Built-in plugin not found!");
|
log::error("Built-in plugin not found!");
|
||||||
ImHexApi::System::impl::addInitArgument("no-builtin-plugin");
|
ImHexApi::System::impl::addInitArgument("no-builtin-plugin");
|
||||||
@@ -314,6 +442,27 @@ namespace hex::init {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool clearOldLogs() {
|
||||||
|
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Logs, true)) {
|
||||||
|
std::vector<std::filesystem::directory_entry> files;
|
||||||
|
|
||||||
|
for (const auto& file : std::filesystem::directory_iterator(path))
|
||||||
|
files.push_back(file);
|
||||||
|
|
||||||
|
if (files.size() <= 10)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
std::sort(files.begin(), files.end(), [](const auto& a, const auto& b) {
|
||||||
|
return std::filesystem::last_write_time(a) > std::filesystem::last_write_time(b);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (auto it = files.begin() + 10; it != files.end(); it++)
|
||||||
|
std::filesystem::remove(it->path());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool unloadPlugins() {
|
bool unloadPlugins() {
|
||||||
PluginManager::unload();
|
PluginManager::unload();
|
||||||
|
|
||||||
@@ -322,12 +471,15 @@ namespace hex::init {
|
|||||||
|
|
||||||
bool loadSettings() {
|
bool loadSettings() {
|
||||||
try {
|
try {
|
||||||
ContentRegistry::Settings::load();
|
// Try to load settings from file
|
||||||
|
ContentRegistry::Settings::impl::load();
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
|
// If that fails, create a new settings file
|
||||||
|
|
||||||
log::error("Failed to load configuration! {}", e.what());
|
log::error("Failed to load configuration! {}", e.what());
|
||||||
|
|
||||||
ContentRegistry::Settings::clear();
|
ContentRegistry::Settings::impl::clear();
|
||||||
ContentRegistry::Settings::store();
|
ContentRegistry::Settings::impl::store();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -337,7 +489,7 @@ namespace hex::init {
|
|||||||
|
|
||||||
bool storeSettings() {
|
bool storeSettings() {
|
||||||
try {
|
try {
|
||||||
ContentRegistry::Settings::store();
|
ContentRegistry::Settings::impl::store();
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
log::error("Failed to store configuration! {}", e.what());
|
log::error("Failed to store configuration! {}", e.what());
|
||||||
return false;
|
return false;
|
||||||
@@ -349,9 +501,14 @@ namespace hex::init {
|
|||||||
return {
|
return {
|
||||||
{ "Setting up environment", setupEnvironment, false },
|
{ "Setting up environment", setupEnvironment, false },
|
||||||
{ "Creating directories", createDirectories, false },
|
{ "Creating directories", createDirectories, false },
|
||||||
|
#if defined(OS_LINUX)
|
||||||
|
{ "Migrate config to .config", migrateConfig, false },
|
||||||
|
#endif
|
||||||
{ "Loading settings", loadSettings, false },
|
{ "Loading settings", loadSettings, false },
|
||||||
{ "Loading plugins", loadPlugins, false },
|
{ "Loading plugins", loadPlugins, false },
|
||||||
|
#if defined(HEX_UPDATE_CHECK)
|
||||||
{ "Checking for updates", checkForUpdates, true },
|
{ "Checking for updates", checkForUpdates, true },
|
||||||
|
#endif
|
||||||
{ "Loading fonts", loadFonts, true },
|
{ "Loading fonts", loadFonts, true },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -361,6 +518,7 @@ namespace hex::init {
|
|||||||
{ "Saving settings...", storeSettings, false },
|
{ "Saving settings...", storeSettings, false },
|
||||||
{ "Cleaning up shared data...", deleteSharedData, false },
|
{ "Cleaning up shared data...", deleteSharedData, false },
|
||||||
{ "Unloading plugins...", unloadPlugins, false },
|
{ "Unloading plugins...", unloadPlugins, false },
|
||||||
|
{ "Clearing old logs...", clearOldLogs, false },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#include <hex.hpp>
|
#include <hex.hpp>
|
||||||
|
|
||||||
#include <hex/helpers/utils.hpp>
|
|
||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
|
|
||||||
#include "window.hpp"
|
#include "window.hpp"
|
||||||
@@ -8,25 +7,29 @@
|
|||||||
#include "init/splash_window.hpp"
|
#include "init/splash_window.hpp"
|
||||||
#include "init/tasks.hpp"
|
#include "init/tasks.hpp"
|
||||||
|
|
||||||
|
#include <hex/api/task.hpp>
|
||||||
#include <hex/api/project_file_manager.hpp>
|
#include <hex/api/project_file_manager.hpp>
|
||||||
|
|
||||||
|
#include <wolv/io/fs.hpp>
|
||||||
|
#include <wolv/utils/guards.hpp>
|
||||||
|
|
||||||
int main(int argc, char **argv, char **envp) {
|
int main(int argc, char **argv, char **envp) {
|
||||||
using namespace hex;
|
using namespace hex;
|
||||||
ImHexApi::System::impl::setProgramArguments(argc, argv, envp);
|
ImHexApi::System::impl::setProgramArguments(argc, argv, envp);
|
||||||
|
|
||||||
bool shouldRestart = false;
|
|
||||||
|
|
||||||
// Check if ImHex is installed in portable mode
|
// Check if ImHex is installed in portable mode
|
||||||
{
|
{
|
||||||
if (const auto executablePath = fs::getExecutablePath(); executablePath.has_value()) {
|
if (const auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value()) {
|
||||||
const auto flagFile = executablePath->parent_path() / "PORTABLE";
|
const auto flagFile = executablePath->parent_path() / "PORTABLE";
|
||||||
|
|
||||||
if (fs::exists(flagFile) && fs::isRegularFile(flagFile))
|
if (wolv::io::fs::exists(flagFile) && wolv::io::fs::isRegularFile(flagFile))
|
||||||
ImHexApi::System::impl::setPortableVersion(true);
|
ImHexApi::System::impl::setPortableVersion(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool shouldRestart = false;
|
||||||
do {
|
do {
|
||||||
|
// Register an event to handle restarting of ImHex
|
||||||
EventManager::subscribe<RequestRestartImHex>([&]{ shouldRestart = true; });
|
EventManager::subscribe<RequestRestartImHex>([&]{ shouldRestart = true; });
|
||||||
shouldRestart = false;
|
shouldRestart = false;
|
||||||
|
|
||||||
@@ -38,15 +41,17 @@ int main(int argc, char **argv, char **envp) {
|
|||||||
|
|
||||||
init::WindowSplash splashWindow;
|
init::WindowSplash splashWindow;
|
||||||
|
|
||||||
|
// Add initialization tasks to run
|
||||||
TaskManager::init();
|
TaskManager::init();
|
||||||
for (const auto &[name, task, async] : init::getInitTasks())
|
for (const auto &[name, task, async] : init::getInitTasks())
|
||||||
splashWindow.addStartupTask(name, task, async);
|
splashWindow.addStartupTask(name, task, async);
|
||||||
|
|
||||||
|
// Draw the splash window while tasks are running
|
||||||
if (!splashWindow.loop())
|
if (!splashWindow.loop())
|
||||||
ImHexApi::System::getInitArguments().insert({ "tasks-failed", {} });
|
ImHexApi::System::getInitArguments().insert({ "tasks-failed", {} });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up
|
// Clean up everything after the main window is closed
|
||||||
ON_SCOPE_EXIT {
|
ON_SCOPE_EXIT {
|
||||||
for (const auto &[name, task, async] : init::getExitTasks())
|
for (const auto &[name, task, async] : init::getExitTasks())
|
||||||
task();
|
task();
|
||||||
@@ -65,7 +70,12 @@ int main(int argc, char **argv, char **envp) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open file that has been requested to be opened through other, OS-specific means
|
||||||
|
if (auto path = hex::getInitialFilePath(); path.has_value()) {
|
||||||
|
EventManager::post<RequestOpenFile>(path.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the main window
|
||||||
window.loop();
|
window.loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,10 @@
|
|||||||
#include <hex/helpers/utils.hpp>
|
#include <hex/helpers/utils.hpp>
|
||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
|
|
||||||
|
#include <wolv/utils/core.hpp>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <cstdio>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@@ -24,6 +27,12 @@ namespace hex {
|
|||||||
setenv("LD_LIBRARY_PATH", hex::format("{};{}", hex::getEnvironmentVariable("LD_LIBRARY_PATH").value_or(""), path.string().c_str()).c_str(), true);
|
setenv("LD_LIBRARY_PATH", hex::format("{};{}", hex::getEnvironmentVariable("LD_LIBRARY_PATH").value_or(""), path.string().c_str()).c_str(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Various libraries sadly directly print to stderr with no way to disable it
|
||||||
|
// We redirect stderr to /dev/null to prevent this
|
||||||
|
wolv::util::unused(freopen("/dev/null", "w", stderr));
|
||||||
|
setvbuf(stderr, nullptr, _IONBF, 0);
|
||||||
|
|
||||||
|
// Redirect stdout to log file if we're not running in a terminal
|
||||||
if (!isatty(STDOUT_FILENO)) {
|
if (!isatty(STDOUT_FILENO)) {
|
||||||
log::redirectToFile();
|
log::redirectToFile();
|
||||||
}
|
}
|
||||||
@@ -39,6 +48,7 @@ namespace hex {
|
|||||||
std::array<char, 128> buffer = { 0 };
|
std::array<char, 128> buffer = { 0 };
|
||||||
std::string result;
|
std::string result;
|
||||||
|
|
||||||
|
// Ask GNOME for the current theme
|
||||||
// TODO: In the future maybe support more DEs instead of just GNOME
|
// TODO: In the future maybe support more DEs instead of just GNOME
|
||||||
FILE *pipe = popen("gsettings get org.gnome.desktop.interface gtk-theme 2>&1", "r");
|
FILE *pipe = popen("gsettings get org.gnome.desktop.interface gtk-theme 2>&1", "r");
|
||||||
if (pipe == nullptr) return;
|
if (pipe == nullptr) return;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <cstdio>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <imgui_impl_glfw.h>
|
#include <imgui_impl_glfw.h>
|
||||||
@@ -23,6 +24,12 @@ namespace hex {
|
|||||||
setenv("LD_LIBRARY_PATH", hex::format("{};{}", hex::getEnvironmentVariable("LD_LIBRARY_PATH").value_or(""), path.string().c_str()).c_str(), true);
|
setenv("LD_LIBRARY_PATH", hex::format("{};{}", hex::getEnvironmentVariable("LD_LIBRARY_PATH").value_or(""), path.string().c_str()).c_str(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Various libraries sadly directly print to stderr with no way to disable it
|
||||||
|
// We redirect stderr to /dev/null to prevent this
|
||||||
|
freopen("/dev/null", "w", stderr);
|
||||||
|
setvbuf(stderr, nullptr, _IONBF, 0);
|
||||||
|
|
||||||
|
// Redirect stdout to log file if we're not running in a terminal
|
||||||
if (!isatty(STDOUT_FILENO)) {
|
if (!isatty(STDOUT_FILENO)) {
|
||||||
log::redirectToFile();
|
log::redirectToFile();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#include <wrl/client.h>
|
#include <wrl/client.h>
|
||||||
|
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
#include <imgui_impl_glfw.h>
|
#include <imgui_impl_glfw.h>
|
||||||
|
|
||||||
@@ -31,13 +32,14 @@ namespace hex {
|
|||||||
|
|
||||||
static LONG_PTR g_oldWndProc;
|
static LONG_PTR g_oldWndProc;
|
||||||
static float g_titleBarHeight;
|
static float g_titleBarHeight;
|
||||||
static ImGuiMouseCursor g_mouseCursorIcon;
|
|
||||||
static Microsoft::WRL::ComPtr<ITaskbarList4> g_taskbarList;
|
static Microsoft::WRL::ComPtr<ITaskbarList4> g_taskbarList;
|
||||||
|
|
||||||
|
// Custom Window procedure for receiving OS events
|
||||||
static LRESULT commonWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
static LRESULT commonWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||||
switch (uMsg) {
|
switch (uMsg) {
|
||||||
case WM_COPYDATA:
|
case WM_COPYDATA: {
|
||||||
{
|
// Handle opening files in existing instance
|
||||||
|
|
||||||
auto message = reinterpret_cast<COPYDATASTRUCT *>(lParam);
|
auto message = reinterpret_cast<COPYDATASTRUCT *>(lParam);
|
||||||
if (message == nullptr) break;
|
if (message == nullptr) break;
|
||||||
|
|
||||||
@@ -45,12 +47,12 @@ namespace hex {
|
|||||||
if (data == nullptr) break;
|
if (data == nullptr) break;
|
||||||
|
|
||||||
std::fs::path path = data;
|
std::fs::path path = data;
|
||||||
log::info("Opening file in existing instance: {}", hex::toUTF8String(path));
|
log::info("Opening file in existing instance: {}", wolv::util::toUTF8String(path));
|
||||||
EventManager::post<RequestOpenFile>(path);
|
EventManager::post<RequestOpenFile>(path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case WM_SETTINGCHANGE:
|
case WM_SETTINGCHANGE: {
|
||||||
{
|
// Handle Windows theme changes
|
||||||
if (lParam == 0) break;
|
if (lParam == 0) break;
|
||||||
|
|
||||||
if (LPCTSTR(lParam) == std::string_view("ImmersiveColorSet")) {
|
if (LPCTSTR(lParam) == std::string_view("ImmersiveColorSet")) {
|
||||||
@@ -66,120 +68,96 @@ namespace hex {
|
|||||||
return CallWindowProc((WNDPROC)g_oldWndProc, hwnd, uMsg, wParam, lParam);
|
return CallWindowProc((WNDPROC)g_oldWndProc, hwnd, uMsg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Custom window procedure for borderless window
|
||||||
static LRESULT borderlessWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
static LRESULT borderlessWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||||
switch (uMsg) {
|
switch (uMsg) {
|
||||||
|
case WM_MOUSELAST:
|
||||||
|
break;
|
||||||
case WM_NCACTIVATE:
|
case WM_NCACTIVATE:
|
||||||
case WM_NCPAINT:
|
case WM_NCPAINT:
|
||||||
|
// Handle Windows Aero Snap
|
||||||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||||
case WM_NCCALCSIZE:
|
case WM_NCCALCSIZE: {
|
||||||
{
|
// Handle window resizing
|
||||||
RECT &rect = *reinterpret_cast<RECT *>(lParam);
|
|
||||||
RECT client = rect;
|
|
||||||
|
|
||||||
CallWindowProc((WNDPROC)g_oldWndProc, hwnd, uMsg, wParam, lParam);
|
RECT &rect = *reinterpret_cast<RECT *>(lParam);
|
||||||
|
RECT client = rect;
|
||||||
|
|
||||||
if (IsMaximized(hwnd)) {
|
CallWindowProc((WNDPROC)g_oldWndProc, hwnd, uMsg, wParam, lParam);
|
||||||
WINDOWINFO windowInfo = { };
|
|
||||||
windowInfo.cbSize = sizeof(WINDOWINFO);
|
|
||||||
|
|
||||||
GetWindowInfo(hwnd, &windowInfo);
|
if (IsMaximized(hwnd)) {
|
||||||
rect = RECT {
|
WINDOWINFO windowInfo = { };
|
||||||
.left = static_cast<LONG>(client.left + windowInfo.cyWindowBorders),
|
windowInfo.cbSize = sizeof(WINDOWINFO);
|
||||||
.top = static_cast<LONG>(client.top + windowInfo.cyWindowBorders),
|
GetWindowInfo(hwnd, &windowInfo);
|
||||||
.right = static_cast<LONG>(client.right - windowInfo.cyWindowBorders),
|
|
||||||
.bottom = static_cast<LONG>(client.bottom - windowInfo.cyWindowBorders) + 1
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
rect = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
rect = RECT {
|
||||||
}
|
.left = static_cast<LONG>(client.left + windowInfo.cyWindowBorders),
|
||||||
case WM_SETCURSOR:
|
.top = static_cast<LONG>(client.top + windowInfo.cyWindowBorders),
|
||||||
{
|
.right = static_cast<LONG>(client.right - windowInfo.cyWindowBorders),
|
||||||
auto cursorPos = LOWORD(lParam);
|
.bottom = static_cast<LONG>(client.bottom - windowInfo.cyWindowBorders) + 1
|
||||||
|
|
||||||
switch (cursorPos) {
|
|
||||||
case HTRIGHT:
|
|
||||||
case HTLEFT:
|
|
||||||
g_mouseCursorIcon = ImGuiMouseCursor_ResizeEW;
|
|
||||||
break;
|
|
||||||
case HTTOP:
|
|
||||||
case HTBOTTOM:
|
|
||||||
g_mouseCursorIcon = ImGuiMouseCursor_ResizeNS;
|
|
||||||
break;
|
|
||||||
case HTTOPLEFT:
|
|
||||||
case HTBOTTOMRIGHT:
|
|
||||||
g_mouseCursorIcon = ImGuiMouseCursor_ResizeNWSE;
|
|
||||||
break;
|
|
||||||
case HTTOPRIGHT:
|
|
||||||
case HTBOTTOMLEFT:
|
|
||||||
g_mouseCursorIcon = ImGuiMouseCursor_ResizeNESW;
|
|
||||||
break;
|
|
||||||
case HTCAPTION:
|
|
||||||
case HTCLIENT:
|
|
||||||
g_mouseCursorIcon = ImGuiMouseCursor_None;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
case WM_NCHITTEST:
|
|
||||||
{
|
|
||||||
POINT cursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
|
||||||
|
|
||||||
const POINT border {
|
|
||||||
static_cast<LONG>((::GetSystemMetrics(SM_CXFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * ImHexApi::System::getGlobalScale() / 1.5F),
|
|
||||||
static_cast<LONG>((::GetSystemMetrics(SM_CYFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * ImHexApi::System::getGlobalScale() / 1.5F)
|
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
rect = client;
|
||||||
|
}
|
||||||
|
|
||||||
RECT window;
|
return 0;
|
||||||
if (!::GetWindowRect(hwnd, &window)) {
|
}
|
||||||
return HTNOWHERE;
|
case WM_NCHITTEST: {
|
||||||
}
|
// Handle window resizing and moving
|
||||||
|
|
||||||
constexpr static auto RegionClient = 0b0000;
|
POINT cursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||||||
constexpr static auto RegionLeft = 0b0001;
|
|
||||||
constexpr static auto RegionRight = 0b0010;
|
|
||||||
constexpr static auto RegionTop = 0b0100;
|
|
||||||
constexpr static auto RegionBottom = 0b1000;
|
|
||||||
|
|
||||||
const auto result =
|
const POINT border {
|
||||||
RegionLeft * (cursor.x < (window.left + border.x)) |
|
static_cast<LONG>((::GetSystemMetrics(SM_CXFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * ImHexApi::System::getGlobalScale()),
|
||||||
RegionRight * (cursor.x >= (window.right - border.x)) |
|
static_cast<LONG>((::GetSystemMetrics(SM_CYFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * ImHexApi::System::getGlobalScale())
|
||||||
RegionTop * (cursor.y < (window.top + border.y)) |
|
};
|
||||||
RegionBottom * (cursor.y >= (window.bottom - border.y));
|
|
||||||
|
|
||||||
if (result != 0 && (ImGui::IsItemHovered() || ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId)))
|
RECT window;
|
||||||
break;
|
if (!::GetWindowRect(hwnd, &window)) {
|
||||||
|
return HTNOWHERE;
|
||||||
|
}
|
||||||
|
|
||||||
switch (result) {
|
constexpr static auto RegionClient = 0b0000;
|
||||||
case RegionLeft:
|
constexpr static auto RegionLeft = 0b0001;
|
||||||
return HTLEFT;
|
constexpr static auto RegionRight = 0b0010;
|
||||||
case RegionRight:
|
constexpr static auto RegionTop = 0b0100;
|
||||||
return HTRIGHT;
|
constexpr static auto RegionBottom = 0b1000;
|
||||||
case RegionTop:
|
|
||||||
return HTTOP;
|
const auto result =
|
||||||
case RegionBottom:
|
RegionLeft * (cursor.x < (window.left + border.x)) |
|
||||||
return HTBOTTOM;
|
RegionRight * (cursor.x >= (window.right - border.x)) |
|
||||||
case RegionTop | RegionLeft:
|
RegionTop * (cursor.y < (window.top + border.y)) |
|
||||||
return HTTOPLEFT;
|
RegionBottom * (cursor.y >= (window.bottom - border.y));
|
||||||
case RegionTop | RegionRight:
|
|
||||||
return HTTOPRIGHT;
|
if (result != 0 && (ImGui::IsAnyItemHovered() || ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId))) {
|
||||||
case RegionBottom | RegionLeft:
|
|
||||||
return HTBOTTOMLEFT;
|
|
||||||
case RegionBottom | RegionRight:
|
|
||||||
return HTBOTTOMRIGHT;
|
|
||||||
case RegionClient:
|
|
||||||
default:
|
|
||||||
if ((cursor.y < (window.top + g_titleBarHeight * 2)) && !(ImGui::IsAnyItemHovered() || ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId)))
|
|
||||||
return HTCAPTION;
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (result) {
|
||||||
|
case RegionLeft:
|
||||||
|
return HTLEFT;
|
||||||
|
case RegionRight:
|
||||||
|
return HTRIGHT;
|
||||||
|
case RegionTop:
|
||||||
|
return HTTOP;
|
||||||
|
case RegionBottom:
|
||||||
|
return HTBOTTOM;
|
||||||
|
case RegionTop | RegionLeft:
|
||||||
|
return HTTOPLEFT;
|
||||||
|
case RegionTop | RegionRight:
|
||||||
|
return HTTOPRIGHT;
|
||||||
|
case RegionBottom | RegionLeft:
|
||||||
|
return HTBOTTOMLEFT;
|
||||||
|
case RegionBottom | RegionRight:
|
||||||
|
return HTBOTTOMRIGHT;
|
||||||
|
case RegionClient:
|
||||||
|
default:
|
||||||
|
if ((cursor.y < (window.top + g_titleBarHeight * 2)) && !(ImGui::IsAnyItemHovered() || ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId)))
|
||||||
|
return HTCAPTION;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -197,16 +175,26 @@ namespace hex {
|
|||||||
AddDllDirectory(path.c_str());
|
AddDllDirectory(path.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach to parent console if one exists
|
// Various libraries sadly directly print to stderr with no way to disable it
|
||||||
if (AttachConsole(ATTACH_PARENT_PROCESS)) {
|
// We redirect stderr to NUL to prevent this
|
||||||
|
freopen("NUL:", "w", stderr);
|
||||||
|
setvbuf(stderr, nullptr, _IONBF, 0);
|
||||||
|
|
||||||
// Redirect cin, cout and cerr to that console
|
// Attach to parent console if one exists
|
||||||
|
bool result = AttachConsole(ATTACH_PARENT_PROCESS) == TRUE;
|
||||||
|
|
||||||
|
#if defined(DEBUG)
|
||||||
|
if (::GetLastError() == ERROR_INVALID_HANDLE) {
|
||||||
|
result = AllocConsole() == TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
// Redirect stdin and stdout to that new console
|
||||||
freopen("CONIN$", "r", stdin);
|
freopen("CONIN$", "r", stdin);
|
||||||
freopen("CONOUT$", "w", stdout);
|
freopen("CONOUT$", "w", stdout);
|
||||||
freopen("CONOUT$", "w", stderr);
|
|
||||||
setvbuf(stdin, nullptr, _IONBF, 0);
|
setvbuf(stdin, nullptr, _IONBF, 0);
|
||||||
setvbuf(stdout, nullptr, _IONBF, 0);
|
setvbuf(stdout, nullptr, _IONBF, 0);
|
||||||
setvbuf(stderr, nullptr, _IONBF, 0);
|
|
||||||
|
|
||||||
fmt::print("\n");
|
fmt::print("\n");
|
||||||
|
|
||||||
@@ -215,8 +203,8 @@ namespace hex {
|
|||||||
auto hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE);
|
auto hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
if (hConsole != INVALID_HANDLE_VALUE) {
|
if (hConsole != INVALID_HANDLE_VALUE) {
|
||||||
DWORD mode = 0;
|
DWORD mode = 0;
|
||||||
if (::GetConsoleMode(hConsole, &mode)) {
|
if (::GetConsoleMode(hConsole, &mode) == TRUE) {
|
||||||
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
|
mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT;
|
||||||
::SetConsoleMode(hConsole, mode);
|
::SetConsoleMode(hConsole, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,25 +217,33 @@ namespace hex {
|
|||||||
constexpr static auto UniqueMutexId = "ImHex/a477ea68-e334-4d07-a439-4f159c683763";
|
constexpr static auto UniqueMutexId = "ImHex/a477ea68-e334-4d07-a439-4f159c683763";
|
||||||
|
|
||||||
HANDLE globalMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, UniqueMutexId);
|
HANDLE globalMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, UniqueMutexId);
|
||||||
if (!globalMutex) {
|
if (globalMutex == nullptr) {
|
||||||
|
// If no ImHex instance is running, create a new global mutex
|
||||||
globalMutex = CreateMutex(nullptr, FALSE, UniqueMutexId);
|
globalMutex = CreateMutex(nullptr, FALSE, UniqueMutexId);
|
||||||
} else {
|
} else {
|
||||||
|
// If an ImHex instance is already running, send the file path to it and exit
|
||||||
|
|
||||||
if (ImHexApi::System::getProgramArguments().argc > 1) {
|
if (ImHexApi::System::getProgramArguments().argc > 1) {
|
||||||
|
// Find the ImHex Window and send the file path as a message to it
|
||||||
::EnumWindows([](HWND hWnd, LPARAM) -> BOOL {
|
::EnumWindows([](HWND hWnd, LPARAM) -> BOOL {
|
||||||
auto &programArgs = ImHexApi::System::getProgramArguments();
|
auto &programArgs = ImHexApi::System::getProgramArguments();
|
||||||
|
|
||||||
|
// Get the window name
|
||||||
auto length = ::GetWindowTextLength(hWnd);
|
auto length = ::GetWindowTextLength(hWnd);
|
||||||
std::string windowName(length + 1, '\x00');
|
std::string windowName(length + 1, '\x00');
|
||||||
::GetWindowText(hWnd, windowName.data(), windowName.size());
|
::GetWindowText(hWnd, windowName.data(), windowName.size());
|
||||||
|
|
||||||
if (::IsWindowVisible(hWnd) && length != 0) {
|
// Check if the window is visible and if it's an ImHex window
|
||||||
|
if (::IsWindowVisible(hWnd) == TRUE && length != 0) {
|
||||||
if (windowName.starts_with("ImHex")) {
|
if (windowName.starts_with("ImHex")) {
|
||||||
|
// Create the message
|
||||||
COPYDATASTRUCT message = {
|
COPYDATASTRUCT message = {
|
||||||
.dwData = 0,
|
.dwData = 0,
|
||||||
.cbData = static_cast<DWORD>(std::strlen(programArgs.argv[1])) + 1,
|
.cbData = static_cast<DWORD>(std::strlen(programArgs.argv[1])) + 1,
|
||||||
.lpData = programArgs.argv[1]
|
.lpData = programArgs.argv[1]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Send the message
|
||||||
SendMessage(hWnd, WM_COPYDATA, reinterpret_cast<WPARAM>(hWnd), reinterpret_cast<LPARAM>(&message));
|
SendMessage(hWnd, WM_COPYDATA, reinterpret_cast<WPARAM>(hWnd), reinterpret_cast<LPARAM>(&message));
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -255,8 +251,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
},
|
}, 0);
|
||||||
0);
|
|
||||||
|
|
||||||
std::exit(0);
|
std::exit(0);
|
||||||
}
|
}
|
||||||
@@ -271,7 +266,7 @@ namespace hex {
|
|||||||
|
|
||||||
ImGui_ImplGlfw_SetBorderlessWindowMode(borderlessWindowMode);
|
ImGui_ImplGlfw_SetBorderlessWindowMode(borderlessWindowMode);
|
||||||
|
|
||||||
|
// Set up the correct window procedure based on the borderless window mode state
|
||||||
if (borderlessWindowMode) {
|
if (borderlessWindowMode) {
|
||||||
g_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)borderlessWindowProc);
|
g_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)borderlessWindowProc);
|
||||||
|
|
||||||
@@ -287,7 +282,7 @@ namespace hex {
|
|||||||
g_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)commonWindowProc);
|
g_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)commonWindowProc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Catch heap corruption
|
// Add a custom exception handler to detect heap corruptions
|
||||||
{
|
{
|
||||||
::AddVectoredExceptionHandler(TRUE, [](PEXCEPTION_POINTERS exception) -> LONG {
|
::AddVectoredExceptionHandler(TRUE, [](PEXCEPTION_POINTERS exception) -> LONG {
|
||||||
if ((exception->ExceptionRecord->ExceptionCode & 0xF000'0000) == 0xC000'0000) {
|
if ((exception->ExceptionRecord->ExceptionCode & 0xF000'0000) == 0xC000'0000) {
|
||||||
@@ -302,40 +297,42 @@ namespace hex {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED))) {
|
// Set up a taskbar progress handler
|
||||||
CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER, IID_ITaskbarList4, &g_taskbarList);
|
{
|
||||||
|
if (SUCCEEDED(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED))) {
|
||||||
|
CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER, IID_ITaskbarList4, &g_taskbarList);
|
||||||
|
}
|
||||||
|
|
||||||
|
EventManager::subscribe<EventSetTaskBarIconState>([hwnd](u32 state, u32 type, u32 progress){
|
||||||
|
using enum ImHexApi::System::TaskProgressState;
|
||||||
|
switch (ImHexApi::System::TaskProgressState(state)) {
|
||||||
|
case Reset:
|
||||||
|
g_taskbarList->SetProgressState(hwnd, TBPF_NOPROGRESS);
|
||||||
|
g_taskbarList->SetProgressValue(hwnd, 0, 0);
|
||||||
|
break;
|
||||||
|
case Flash:
|
||||||
|
FlashWindow(hwnd, true);
|
||||||
|
break;
|
||||||
|
case Progress:
|
||||||
|
g_taskbarList->SetProgressState(hwnd, TBPF_INDETERMINATE);
|
||||||
|
g_taskbarList->SetProgressValue(hwnd, progress, 100);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
using enum ImHexApi::System::TaskProgressType;
|
||||||
|
switch (ImHexApi::System::TaskProgressType(type)) {
|
||||||
|
case Normal:
|
||||||
|
g_taskbarList->SetProgressState(hwnd, TBPF_NORMAL);
|
||||||
|
break;
|
||||||
|
case Warning:
|
||||||
|
g_taskbarList->SetProgressState(hwnd, TBPF_PAUSED);
|
||||||
|
break;
|
||||||
|
case Error:
|
||||||
|
g_taskbarList->SetProgressState(hwnd, TBPF_ERROR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EventManager::subscribe<EventSetTaskBarIconState>([hwnd](u32 state, u32 type, u32 progress){
|
|
||||||
using enum ImHexApi::System::TaskProgressState;
|
|
||||||
switch (ImHexApi::System::TaskProgressState(state)) {
|
|
||||||
case Reset:
|
|
||||||
g_taskbarList->SetProgressState(hwnd, TBPF_NOPROGRESS);
|
|
||||||
g_taskbarList->SetProgressValue(hwnd, 0, 0);
|
|
||||||
break;
|
|
||||||
case Flash:
|
|
||||||
FlashWindow(hwnd, true);
|
|
||||||
break;
|
|
||||||
case Progress:
|
|
||||||
g_taskbarList->SetProgressState(hwnd, TBPF_INDETERMINATE);
|
|
||||||
g_taskbarList->SetProgressValue(hwnd, progress, 100);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
using enum ImHexApi::System::TaskProgressType;
|
|
||||||
switch (ImHexApi::System::TaskProgressType(type)) {
|
|
||||||
case Normal:
|
|
||||||
g_taskbarList->SetProgressState(hwnd, TBPF_NORMAL);
|
|
||||||
break;
|
|
||||||
case Warning:
|
|
||||||
g_taskbarList->SetProgressState(hwnd, TBPF_PAUSED);
|
|
||||||
break;
|
|
||||||
case Error:
|
|
||||||
g_taskbarList->SetProgressState(hwnd, TBPF_ERROR);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::beginNativeWindowFrame() {
|
void Window::beginNativeWindowFrame() {
|
||||||
@@ -345,47 +342,11 @@ namespace hex {
|
|||||||
void Window::endNativeWindowFrame() {
|
void Window::endNativeWindowFrame() {
|
||||||
if (!ImHexApi::System::isBorderlessWindowModeEnabled())
|
if (!ImHexApi::System::isBorderlessWindowModeEnabled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (g_mouseCursorIcon != ImGuiMouseCursor_None) {
|
|
||||||
ImGui::SetMouseCursor(g_mouseCursorIcon);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ImGui::GetMouseCursor()) {
|
|
||||||
case ImGuiMouseCursor_Arrow:
|
|
||||||
SetCursor(LoadCursor(nullptr, IDC_ARROW));
|
|
||||||
break;
|
|
||||||
case ImGuiMouseCursor_Hand:
|
|
||||||
SetCursor(LoadCursor(nullptr, IDC_HAND));
|
|
||||||
break;
|
|
||||||
case ImGuiMouseCursor_ResizeEW:
|
|
||||||
SetCursor(LoadCursor(nullptr, IDC_SIZEWE));
|
|
||||||
break;
|
|
||||||
case ImGuiMouseCursor_ResizeNS:
|
|
||||||
SetCursor(LoadCursor(nullptr, IDC_SIZENS));
|
|
||||||
break;
|
|
||||||
case ImGuiMouseCursor_ResizeNWSE:
|
|
||||||
SetCursor(LoadCursor(nullptr, IDC_SIZENWSE));
|
|
||||||
break;
|
|
||||||
case ImGuiMouseCursor_ResizeNESW:
|
|
||||||
SetCursor(LoadCursor(nullptr, IDC_SIZENESW));
|
|
||||||
break;
|
|
||||||
case ImGuiMouseCursor_ResizeAll:
|
|
||||||
SetCursor(LoadCursor(nullptr, IDC_SIZEALL));
|
|
||||||
break;
|
|
||||||
case ImGuiMouseCursor_NotAllowed:
|
|
||||||
SetCursor(LoadCursor(nullptr, IDC_NO));
|
|
||||||
break;
|
|
||||||
case ImGuiMouseCursor_TextInput:
|
|
||||||
SetCursor(LoadCursor(nullptr, IDC_IBEAM));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
case ImGuiMouseCursor_None:
|
|
||||||
SetCursor(LoadCursor(nullptr, IDC_ARROW));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::drawTitleBar() {
|
void Window::drawTitleBar() {
|
||||||
|
// In borderless window mode, we draw our own title bar
|
||||||
|
|
||||||
if (!ImHexApi::System::isBorderlessWindowModeEnabled()) return;
|
if (!ImHexApi::System::isBorderlessWindowModeEnabled()) return;
|
||||||
|
|
||||||
auto startX = ImGui::GetCursorPosX();
|
auto startX = ImGui::GetCursorPosX();
|
||||||
@@ -397,8 +358,9 @@ namespace hex {
|
|||||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetColorU32(ImGuiCol_ScrollbarGrabActive));
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetColorU32(ImGuiCol_ScrollbarGrabActive));
|
||||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetColorU32(ImGuiCol_ScrollbarGrabHovered));
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetColorU32(ImGuiCol_ScrollbarGrabHovered));
|
||||||
|
|
||||||
auto &titleBarButtons = ContentRegistry::Interface::getTitleBarButtons();
|
auto &titleBarButtons = ContentRegistry::Interface::impl::getTitleBarButtons();
|
||||||
|
|
||||||
|
// Draw custom title bar buttons
|
||||||
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * (4 + titleBarButtons.size()));
|
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * (4 + titleBarButtons.size()));
|
||||||
for (const auto &[icon, tooltip, callback] : titleBarButtons) {
|
for (const auto &[icon, tooltip, callback] : titleBarButtons) {
|
||||||
if (ImGui::TitleBarButton(icon.c_str(), buttonSize)) {
|
if (ImGui::TitleBarButton(icon.c_str(), buttonSize)) {
|
||||||
@@ -407,6 +369,7 @@ namespace hex {
|
|||||||
ImGui::InfoTooltip(LangEntry(tooltip));
|
ImGui::InfoTooltip(LangEntry(tooltip));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw minimize, restore and maximize buttons
|
||||||
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * 3);
|
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * 3);
|
||||||
if (ImGui::TitleBarButton(ICON_VS_CHROME_MINIMIZE, buttonSize))
|
if (ImGui::TitleBarButton(ICON_VS_CHROME_MINIMIZE, buttonSize))
|
||||||
glfwIconifyWindow(this->m_window);
|
glfwIconifyWindow(this->m_window);
|
||||||
@@ -421,9 +384,9 @@ namespace hex {
|
|||||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, 0xFF7A70F1);
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, 0xFF7A70F1);
|
||||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, 0xFF2311E8);
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, 0xFF2311E8);
|
||||||
|
|
||||||
|
// Draw close button
|
||||||
if (ImGui::TitleBarButton(ICON_VS_CHROME_CLOSE, buttonSize)) {
|
if (ImGui::TitleBarButton(ICON_VS_CHROME_CLOSE, buttonSize)) {
|
||||||
ImHexApi::Common::closeImHex();
|
ImHexApi::System::closeImHex();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::PopStyleColor(5);
|
ImGui::PopStyleColor(5);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user