mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-28 15:57:03 -05:00
Compare commits
412 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 | ||
|
|
4d60942fea | ||
|
|
3003dea409 | ||
|
|
0b18930017 | ||
|
|
54ef5785cd | ||
|
|
d084ec78e9 | ||
|
|
a59c17aa83 | ||
|
|
6281adc7c3 | ||
|
|
5cc01ae89d | ||
|
|
303dd28c7c | ||
|
|
dd87dc7046 | ||
|
|
235a64deef | ||
|
|
89a96c6d25 | ||
|
|
4f0e5b99a8 | ||
|
|
f75f3f4661 | ||
|
|
b936a28921 | ||
|
|
d02507ae4b | ||
|
|
0b576adcf8 | ||
|
|
22ff033b5e | ||
|
|
b1edede53a | ||
|
|
3877f0853d | ||
|
|
9af8a0113a | ||
|
|
0d01f0c9d7 | ||
|
|
9911166c24 | ||
|
|
01736d6409 | ||
|
|
4ea8971adf | ||
|
|
8da072b602 | ||
|
|
f6823d5f13 | ||
|
|
941c7ee61d | ||
|
|
fd259dcde3 | ||
|
|
79ecf7fa59 | ||
|
|
4c761df181 | ||
|
|
94dc688324 | ||
|
|
357dd883db | ||
|
|
3bad5e1d9c | ||
|
|
d09982d99f | ||
|
|
fe7eb582a4 | ||
|
|
c76b4bc9e9 | ||
|
|
55d7d7c026 | ||
|
|
6b645192d4 | ||
|
|
d6bb408078 | ||
|
|
434ced44f0 | ||
|
|
c6e1f45dc3 | ||
|
|
c861bf9a5e | ||
|
|
86be1ef1ec | ||
|
|
c4d52da924 | ||
|
|
a142d4fe20 | ||
|
|
197e86f327 | ||
|
|
b1aa58d446 | ||
|
|
60a178f75e | ||
|
|
6799263317 | ||
|
|
9b80486285 | ||
|
|
3254376d28 | ||
|
|
29c1a0cb78 | ||
|
|
800ffb5e56 | ||
|
|
1cf9f7e990 | ||
|
|
d928325fdf | ||
|
|
b3556c7c91 | ||
|
|
4b112321d2 | ||
|
|
fee1b985c0 | ||
|
|
111eabb84c | ||
|
|
f9bb4d828a | ||
|
|
434b7649c3 | ||
|
|
fc44dd4592 | ||
|
|
8ea0e9ce9c | ||
|
|
94cd83e0dc | ||
|
|
27790532f8 | ||
|
|
90d9c91717 | ||
|
|
32ed2c30c0 | ||
|
|
cf9df6e36d | ||
|
|
915106f360 | ||
|
|
a51e4afb05 | ||
|
|
c30f8fa459 | ||
|
|
46221e936f | ||
|
|
c86891e0c3 | ||
|
|
acf6b839e5 | ||
|
|
1f50e834fc | ||
|
|
6322dbf46a | ||
|
|
0e1aeee3fb | ||
|
|
173f279ac8 | ||
|
|
89e0df86a2 | ||
|
|
7ba9349de2 | ||
|
|
15fb288a5b | ||
|
|
f17e04273d | ||
|
|
76d47bf856 | ||
|
|
d4967018c2 | ||
|
|
8e759d9b5f | ||
|
|
a9cebed903 | ||
|
|
58a70f6ad8 | ||
|
|
05c8158716 | ||
|
|
17b0f2ae77 | ||
|
|
b54e6ea531 | ||
|
|
b702ad4190 | ||
|
|
4fb544d59d | ||
|
|
e37a73ae58 | ||
|
|
c5d2739a39 | ||
|
|
def40c908e | ||
|
|
ef12798fe2 | ||
|
|
c747c15567 | ||
|
|
48a57cd981 | ||
|
|
3ddef07284 | ||
|
|
a65f0a5238 | ||
|
|
ca68150970 | ||
|
|
92f0aa9593 | ||
|
|
b368b9c6d1 | ||
|
|
7e17059154 | ||
|
|
e078d810de | ||
|
|
62bf877046 | ||
|
|
1b56c7ffae | ||
|
|
f7e22ce651 | ||
|
|
b9c2b1de5f | ||
|
|
0c302da0db | ||
|
|
45492365be | ||
|
|
b497e9d867 | ||
|
|
2840935f3d | ||
|
|
69c0e6ee6e | ||
|
|
78b07e0a46 | ||
|
|
5a865774d1 | ||
|
|
8d9667c2e0 | ||
|
|
1f6acc101f | ||
|
|
0d91db68db | ||
|
|
825e788646 | ||
|
|
f3815673c0 | ||
|
|
b070092a64 | ||
|
|
25ede7ad18 | ||
|
|
03d216f116 | ||
|
|
b1cab5ccd2 | ||
|
|
04d0458ae7 | ||
|
|
3b5d54dd96 | ||
|
|
87571450f4 | ||
|
|
766fd626f2 | ||
|
|
be1f711fda | ||
|
|
ef3627321c | ||
|
|
dbcb13f473 | ||
|
|
c1359a71d6 | ||
|
|
b1a26d02c1 | ||
|
|
ceae23eab1 | ||
|
|
ab29303c2e | ||
|
|
ed831c6fc9 | ||
|
|
d86be9d9b3 | ||
|
|
c26bed894b | ||
|
|
27cf5953ae | ||
|
|
d0b3a60a09 | ||
|
|
15f2376c62 | ||
|
|
efeeea37f6 | ||
|
|
5726e52df2 | ||
|
|
a1b596adc0 | ||
|
|
763196f0cc | ||
|
|
ff9048fcf0 | ||
|
|
7d9c86f584 | ||
|
|
6129360b06 | ||
|
|
3c5e91b611 | ||
|
|
e529a79ddb | ||
|
|
45bb9e6706 | ||
|
|
e6d14507e2 | ||
|
|
9a5881fc47 | ||
|
|
f7dd28002e | ||
|
|
496b0ec41d | ||
|
|
02df578939 | ||
|
|
eb4a1e2692 | ||
|
|
e6bec7d2b2 | ||
|
|
80f3bbb0af | ||
|
|
3a117b3bed | ||
|
|
ff91335011 | ||
|
|
01917439dd | ||
|
|
f21c80c48a | ||
|
|
3dc42b711c | ||
|
|
4b2863ca14 | ||
|
|
fe1b4b45b5 | ||
|
|
a20d6aa2b2 | ||
|
|
78e52a0fe3 | ||
|
|
b4b507ecc9 | ||
|
|
d7d19d7594 | ||
|
|
90df4413c3 | ||
|
|
4cd6646cca | ||
|
|
87ed0d31d4 | ||
|
|
921bdd9e3b | ||
|
|
1f51a603f0 | ||
|
|
5fbbdb8e3c | ||
|
|
745da6ba45 | ||
|
|
ad71e612a3 | ||
|
|
85823e8e5d | ||
|
|
b4fa8bebe9 | ||
|
|
7859a9bb1f | ||
|
|
696d8d1d54 | ||
|
|
6e8d3e0d7f | ||
|
|
6a0422fb27 | ||
|
|
26898feb62 | ||
|
|
0311feee9b | ||
|
|
cf601586fc | ||
|
|
f7b988906e | ||
|
|
5777a6d401 | ||
|
|
4807ca0057 | ||
|
|
f1aeec309e | ||
|
|
4b8e275254 | ||
|
|
4b6a75fb60 | ||
|
|
d463491026 | ||
|
|
df3d5e38ce | ||
|
|
4e22d636d3 | ||
|
|
e71841b871 | ||
|
|
e272c5d000 | ||
|
|
0d7740773e | ||
|
|
e4fbb1b640 | ||
|
|
986252d97f | ||
|
|
e0c1fc81e3 | ||
|
|
ee94e9d619 | ||
|
|
264da1ed78 | ||
|
|
ce37c795a7 | ||
|
|
ed2297ab7f | ||
|
|
ae5d8c9aad | ||
|
|
603ff9256c | ||
|
|
a966cab155 | ||
|
|
978dd65528 | ||
|
|
6502920047 | ||
|
|
ed97757dde | ||
|
|
da8ec1565e | ||
|
|
ad85a4a0e3 | ||
|
|
f9a7cdf4dd | ||
|
|
a5296bab95 | ||
|
|
bda7a2b351 | ||
|
|
f23351f11c | ||
|
|
e3f2541fde | ||
|
|
94723dbba3 | ||
|
|
6e0b92a4de | ||
|
|
13a61f5249 | ||
|
|
1347f81236 | ||
|
|
ab93894442 | ||
|
|
8ed6c2094b | ||
|
|
42d7f1ca67 | ||
|
|
cf51e04777 | ||
|
|
8398c12f74 | ||
|
|
2a345e770e | ||
|
|
b3fcf71982 | ||
|
|
3b94a42783 | ||
|
|
453ddaf0d6 | ||
|
|
d4ff36fde0 | ||
|
|
6239858d0a | ||
|
|
1dd873462e | ||
|
|
825c613d64 | ||
|
|
4aa314b3ab | ||
|
|
8e696e3fc4 | ||
|
|
217cf799c2 | ||
|
|
b10a59661e | ||
|
|
0f028db856 | ||
|
|
c194588118 | ||
|
|
398dc8101f | ||
|
|
13cb330711 | ||
|
|
c0740822a3 | ||
|
|
340e627af9 | ||
|
|
3089a710bd | ||
|
|
7d0474335a | ||
|
|
3d5190f51a | ||
|
|
de2de1e1d7 | ||
|
|
91a4f52f67 |
8
.github/workflows/analysis.yml
vendored
8
.github/workflows/analysis.yml
vendored
@@ -28,8 +28,8 @@ jobs:
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
|
||||
key: ${{ runner.os }}-analysis-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-analysis-${{ secrets.CACHE_VERSION }}-build
|
||||
max-size: 50M
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
@@ -37,8 +37,8 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
key: ${{ runner.os }}-analysis-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
|
||||
377
.github/workflows/build.yml
vendored
377
.github/workflows/build.yml
vendored
@@ -58,6 +58,7 @@ jobs:
|
||||
mbedtls:p
|
||||
freetype:p
|
||||
dlfcn:p
|
||||
libbacktrace:p
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
@@ -69,57 +70,50 @@ jobs:
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
cmake -G "MinGW Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
cmake -G "MinGW Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||
..
|
||||
mingw32-make -j4 install
|
||||
cpack
|
||||
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
|
||||
mv ImHex-*.msi ../imhex-${{env.IMHEX_VERSION}}-Windows-x86_64.msi
|
||||
|
||||
#- name: 🗝️ Sign Windows Installer
|
||||
# if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
# shell: powershell
|
||||
# env:
|
||||
# WIN_SIGN_CERT: ${{ secrets.WIN_SIGN_CERT }}
|
||||
# WIN_SIGN_PW: ${{ secrets.WIN_SIGN_PW }}
|
||||
# run: |
|
||||
# $buffer = [System.Convert]::FromBase64String($env:WIN_SIGN_CERT)
|
||||
# $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::New($buffer, $env:WIN_SIGN_PW)
|
||||
# Get-ChildItem -Path ./build -Filter *.msi -Recurse | Set-AuthenticodeSignature -HashAlgorithm SHA256 -Certificate $certificate -TimestampServer http://timestamp.digicert.com
|
||||
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
|
||||
|
||||
- name: ⬆️ Upload Windows Installer
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Installer
|
||||
name: Windows Installer x86_64
|
||||
path: |
|
||||
build/*.msi
|
||||
imhex-*.msi
|
||||
|
||||
- name: ⬆️ Upload Portable ZIP
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Portable
|
||||
name: Windows Portable x86_64
|
||||
path: |
|
||||
build/install/*
|
||||
|
||||
|
||||
- name: ⬇️ Download Mesa3D for NoGPU version
|
||||
shell: bash
|
||||
run: |
|
||||
echo "NoGPU version Powered by Mesa 3D : https://fdossena.com/?p=mesa%2Findex.frag" > build/install/MESA.md
|
||||
curl https://downloads.fdossena.com/geth.php?r=mesa64-latest -L -o mesa.7z
|
||||
curl https://werwolv.net/downloads/mesa/MesaForWindows-x64-latest.7z -L -o mesa.7z
|
||||
7z e mesa.7z
|
||||
mv opengl32.dll build/install
|
||||
|
||||
- name: ⬆️ Upload NoGPU Portable ZIP
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Portable NoGPU
|
||||
name: Windows Portable NoGPU x86_64
|
||||
path: |
|
||||
build/install/*
|
||||
|
||||
@@ -134,7 +128,7 @@ jobs:
|
||||
custom_glfw: true
|
||||
- suffix: ""
|
||||
custom_glfw: false
|
||||
|
||||
|
||||
name: 🍎 macOS 11.0${{matrix.suffix}}
|
||||
|
||||
steps:
|
||||
@@ -146,7 +140,7 @@ jobs:
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
|
||||
|
||||
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
@@ -154,7 +148,6 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-build
|
||||
max-size: 50M
|
||||
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@@ -172,7 +165,6 @@ jobs:
|
||||
run: |
|
||||
brew install glfw
|
||||
|
||||
|
||||
- name: 🧰 Checkout glfw
|
||||
if: ${{matrix.custom_glfw}}
|
||||
uses: actions/checkout@v3
|
||||
@@ -189,12 +181,14 @@ jobs:
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
cmake \
|
||||
-DBUILD_SHARED_LIBS=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
cmake \
|
||||
-DBUILD_SHARED_LIBS=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||
..
|
||||
make -j 4 install
|
||||
|
||||
@@ -203,30 +197,32 @@ jobs:
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
|
||||
CXX=$(brew --prefix gcc@12)/bin/g++-12 \
|
||||
OBJC=$(brew --prefix llvm)/bin/clang \
|
||||
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
|
||||
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
|
||||
CXX=$(brew --prefix gcc@12)/bin/g++-12 \
|
||||
OBJC=$(brew --prefix llvm)/bin/clang \
|
||||
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
|
||||
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
|
||||
MACOSX_DEPLOYMENT_TARGET="10.10" \
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCREATE_BUNDLE=ON \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET="10.10" \
|
||||
-DCPACK_PACKAGE_FILE_NAME="imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}" \
|
||||
MACOSX_DEPLOYMENT_TARGET="10.10" \
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCREATE_BUNDLE=ON \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
|
||||
-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
|
||||
|
||||
- name: ⬆️ Upload DMG
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: macOS DMG${{matrix.suffix}}
|
||||
name: macOS DMG${{matrix.suffix}} x86_64
|
||||
path: build/*.dmg
|
||||
|
||||
# Ubuntu build
|
||||
@@ -246,30 +242,18 @@ jobs:
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
|
||||
max-size: 50M
|
||||
|
||||
- name: 📜 Restore other caches
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
build-appimage/CMakeCache.txt
|
||||
.flatpak-builder
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo rm -rf /opt/ghc
|
||||
sudo rm -rf "/usr/local/share/boost"
|
||||
sudo rm -rf "$AGENT_TOOLSDIRECTORY"
|
||||
|
||||
sudo apt update
|
||||
sudo bash dist/get_deps_debian.sh
|
||||
|
||||
sudo apt install -y python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fuse
|
||||
sudo wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /usr/local/bin/appimagetool
|
||||
sudo chmod +x /usr/local/bin/appimagetool
|
||||
sudo pip3 install appimage-builder
|
||||
|
||||
# Ubuntu cmake build
|
||||
- name: 🛠️ Build
|
||||
@@ -281,9 +265,10 @@ jobs:
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
|
||||
..
|
||||
make -j 4 install DESTDIR=DebDir
|
||||
|
||||
@@ -291,23 +276,59 @@ jobs:
|
||||
run: |
|
||||
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
|
||||
|
||||
#- name: 📦 Bundle Flatpak
|
||||
# run: |
|
||||
# sudo apt install flatpak flatpak-builder
|
||||
# flatpak --user remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
# flatpak --user install -y flathub org.freedesktop.Platform//20.08
|
||||
# flatpak --user install -y flathub org.freedesktop.Sdk//20.08
|
||||
# flatpak-builder --jobs=4 --repo=imhex _flatpak dist/net.werwolv.ImHex.yaml --ccache --keep-build-dirs
|
||||
# flatpak build-bundle imhex imhex.flatpak net.werwolv.ImHex stable
|
||||
|
||||
- name: 📦 Bundle DEB
|
||||
run: |
|
||||
cp -r build/DEBIAN build/DebDir
|
||||
dpkg-deb -Zgzip --build build/DebDir
|
||||
mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}-Ubuntu-22.04.deb
|
||||
mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}-Ubuntu-22.04-x86_64.deb
|
||||
|
||||
- name: ⬆️ Upload DEB
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Ubuntu 22.04 DEB x86_64
|
||||
path: '*.deb'
|
||||
|
||||
# AppImage build
|
||||
appimage:
|
||||
runs-on: ubuntu-22.04
|
||||
name: ⬇️ AppImage
|
||||
steps:
|
||||
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: ${{ runner.os }}-appimage-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-appimage-${{ secrets.CACHE_VERSION }}-build
|
||||
max-size: 50M
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
build-appimage/CMakeCache.txt
|
||||
key: ${{ runner.os }}-appimage-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo bash dist/get_deps_debian.sh
|
||||
|
||||
sudo apt install -y python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fuse
|
||||
sudo wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /usr/local/bin/appimagetool
|
||||
sudo chmod +x /usr/local/bin/appimagetool
|
||||
sudo pip3 install git+https://github.com/iTrooz/appimage-builder@dpkg-package-versions
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
|
||||
|
||||
# AppImage cmake build
|
||||
- name: 🛠️ Reconfigure build for AppImage
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
mkdir -p build-appimage
|
||||
cd build-appimage
|
||||
@@ -316,9 +337,10 @@ jobs:
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
|
||||
-DIMHEX_PLUGINS_IN_SHARE=ON \
|
||||
-DIMHEX_USE_BUNDLED_CA=ON \
|
||||
..
|
||||
@@ -330,36 +352,23 @@ jobs:
|
||||
export VERSION=${{env.IMHEX_VERSION}}
|
||||
appimage-builder --recipe ../dist/AppImageBuilder.yml
|
||||
|
||||
#- name: ⬆️ Upload Flatpak
|
||||
# uses: actions/upload-artifact@v3
|
||||
# with:
|
||||
# name: Linux Flatpak
|
||||
# path: |
|
||||
# imhex.flatpak
|
||||
|
||||
- name: ⬆️ Upload DEB
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Ubuntu 22.04 DEB
|
||||
path: '*.deb'
|
||||
|
||||
- name: ⬆️ Upload AppImage
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Linux AppImage
|
||||
name: Linux AppImage x86_64
|
||||
path: 'build-appimage/*.AppImage'
|
||||
|
||||
|
||||
- name: ⬆️ Upload AppImage zsync
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Linux AppImage zsync
|
||||
name: Linux AppImage zsync x86_64
|
||||
path: 'build-appimage/*.AppImage.zsync'
|
||||
|
||||
# ArchLinux build
|
||||
archlinux-build:
|
||||
name: 🐧 ArchLinux
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
|
||||
container:
|
||||
image: archlinux:base-devel
|
||||
|
||||
@@ -371,7 +380,7 @@ jobs:
|
||||
- name: ⬇️ Install setup dependencies
|
||||
run: |
|
||||
pacman -Syu git ccache --noconfirm
|
||||
|
||||
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
@@ -387,14 +396,14 @@ jobs:
|
||||
key: archlinux-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: archlinux-${{ secrets.CACHE_VERSION }}-build
|
||||
max-size: 50M
|
||||
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: archlinux-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
|
||||
# ArchLinux cmake build
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
@@ -405,21 +414,22 @@ jobs:
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DUSE_SYSTEM_CURL=ON \
|
||||
-DUSE_SYSTEM_FMT=ON \
|
||||
-DUSE_SYSTEM_YARA=ON \
|
||||
-DUSE_SYSTEM_NLOHMANN_JSON=ON \
|
||||
-DUSE_SYSTEM_CAPSTONE=OFF \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_COMMIT_HASH="${GITHUB_SHA::7}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON \
|
||||
..
|
||||
make -j 4 install DESTDIR=installDir
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
|
||||
|
||||
|
||||
- name: ✒️ Prepare PKGBUILD
|
||||
run: |
|
||||
cp dist/Arch/PKGBUILD build
|
||||
@@ -429,91 +439,146 @@ jobs:
|
||||
- name: 📦 Package ArchLinux .pkg.tar.zst
|
||||
run: |
|
||||
cd build
|
||||
|
||||
|
||||
# the name is a small trick to make makepkg recognize it as the source
|
||||
# else, it would try to download the file from the release
|
||||
tar -cvf imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst -C installDir .
|
||||
|
||||
tar -cvf imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst -C installDir .
|
||||
|
||||
chmod -R 777 .
|
||||
|
||||
|
||||
sudo -u nobody makepkg
|
||||
|
||||
# Replace the old file
|
||||
rm imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst
|
||||
mv *.pkg.tar.zst imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst
|
||||
|
||||
rm imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
|
||||
mv *.pkg.tar.zst imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
|
||||
|
||||
- name: ⬆️ Upload imhex-archlinux.pkg.tar.zst
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ArchLinux .pkg.tar.zst
|
||||
name: ArchLinux .pkg.tar.zst x86_64
|
||||
path: |
|
||||
build/imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst
|
||||
build/imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
|
||||
|
||||
# Fedora build
|
||||
fedora-build:
|
||||
# RPM distro builds
|
||||
rpm-build:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- docker_image: fedora:latest
|
||||
release: Latest
|
||||
- docker_image: fedora:rawhide
|
||||
release: Rawhide
|
||||
- name: Fedora
|
||||
mock_release: rawhide
|
||||
release_num: rawhide
|
||||
mock_config: fedora-rawhide
|
||||
- name: Fedora
|
||||
mock_release: f38
|
||||
release_num: 38
|
||||
mock_config: fedora-38
|
||||
- name: Fedora
|
||||
mock_release: f37
|
||||
release_num: 37
|
||||
mock_config: fedora-37
|
||||
- name: Fedora
|
||||
mock_release: f36
|
||||
release_num: 36
|
||||
mock_config: fedora-36
|
||||
- name: RHEL-AlmaLinux
|
||||
mock_release: epel9
|
||||
release_num: 9
|
||||
mock_config: "alma+epel-9"
|
||||
|
||||
|
||||
name: 🐧 Fedora ${{ matrix.release }}
|
||||
name: 🐧 ${{ matrix.name }} ${{ matrix.release_num }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
|
||||
container:
|
||||
image: "${{ matrix.docker_image }}"
|
||||
image: "fedora:latest"
|
||||
options: --privileged
|
||||
|
||||
steps:
|
||||
- name: ⬇️ Update all packages
|
||||
run: |
|
||||
dnf upgrade -y
|
||||
- name: ⬇️ Install git-core
|
||||
run: dnf install --disablerepo="*" --enablerepo="fedora" git-core -y
|
||||
|
||||
- name: ⬇️ Install setup dependencies
|
||||
run: |
|
||||
dnf install -y \
|
||||
ccache \
|
||||
desktop-file-utils \
|
||||
fmt-devel \
|
||||
git \
|
||||
json-devel \
|
||||
libcurl-devel \
|
||||
llvm-devel \
|
||||
mbedtls-devel \
|
||||
rpm-build \
|
||||
yara-devel
|
||||
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: ImHex
|
||||
submodules: recursive
|
||||
|
||||
- name: ⬇️ Install ImHex dependencies
|
||||
- name: 📜 Setup DNF Cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /var/cache/dnf
|
||||
key: ${{ matrix.mock_release }}-${{secrets.CACHE_VERSION }}-dnf-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
${{ matrix.mock_release }}-${{secrets.CACHE_VERSION }}-dnf-
|
||||
|
||||
- name: ⬇️ Update all packages and install dependencies
|
||||
run: |
|
||||
dist/get_deps_fedora.sh
|
||||
dnf upgrade --disablerepo="*" --enablerepo="fedora,updates" -y
|
||||
dnf install --disablerepo="*" --enablerepo="fedora,updates" -y \
|
||||
fedpkg \
|
||||
ccache
|
||||
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
uses: hendrikmuhs/ccache-action@v1.2.5
|
||||
with:
|
||||
key: fedora-${{ matrix.release }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: fedora-${{ matrix.release }}-${{ secrets.CACHE_VERSION }}-build
|
||||
max-size: 50M
|
||||
|
||||
key: rpm-${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: rpm-${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-build
|
||||
max-size: 1G
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
|
||||
|
||||
echo "IMHEX_VERSION=`cat ImHex/VERSION`" >> $GITHUB_ENV
|
||||
|
||||
- name: 🗜️ Create tarball from sources with dependencies
|
||||
run: tar --exclude-vcs -czf $GITHUB_WORKSPACE/imhex-$IMHEX_VERSION.tar.gz ImHex
|
||||
|
||||
- name: ✒️ Modify spec file
|
||||
run: |
|
||||
sed -i \
|
||||
-e 's/Version: [0-9]*\.[0-9]*\.[0-9]*$/Version: ${{env.IMHEX_VERSION}}/g' \
|
||||
-e 's/IMHEX_OFFLINE_BUILD=ON/IMHEX_OFFLINE_BUILD=OFF/g' \
|
||||
-e '/IMHEX_OFFLINE_BUILD=OFF/a -D IMHEX_PATTERNS_PULL_MASTER=ON \\' \
|
||||
-e '/BuildRequires: cmake/a BuildRequires: git-core' \
|
||||
-e '/%files/a %{_datadir}/%{name}/' \
|
||||
$GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec
|
||||
|
||||
- name: 📜 Fix ccache on EL9
|
||||
if: matrix.mock_release == 'epel9'
|
||||
run: sed -i '/\. \/opt\/rh\/gcc-toolset-12\/enable/a PATH=/usr/lib64/ccache:$PATH' $GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec
|
||||
|
||||
- name: 🟩 Copy spec file to build root
|
||||
run: mv $GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec $GITHUB_WORKSPACE/imhex.spec
|
||||
|
||||
- name: 📜 Enable ccache for mock
|
||||
run: |
|
||||
cat <<EOT > $GITHUB_WORKSPACE/mock.cfg
|
||||
include('${{ matrix.mock_config }}-x86_64.cfg')
|
||||
config_opts['plugin_conf']['ccache_enable'] = True
|
||||
config_opts['plugin_conf']['ccache_opts']['max_cache_size'] = '1G'
|
||||
config_opts['plugin_conf']['ccache_opts']['compress'] = True
|
||||
config_opts['plugin_conf']['ccache_opts']['dir'] = "$GITHUB_WORKSPACE/.ccache"
|
||||
EOT
|
||||
|
||||
- name: 📜 Setup Mock Cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /var/cache/mock
|
||||
key: ${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-mock-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-mock-
|
||||
|
||||
# Fedora cmake build (in imhex.spec)
|
||||
- name: 📦 Build RPM
|
||||
run: |
|
||||
rpmbuild -ba --define "_version ${{env.IMHEX_VERSION}}" --define "_src_path $GITHUB_WORKSPACE" --define "_build_type $BUILD_TYPE" $GITHUB_WORKSPACE/dist/rpm/imhex.spec
|
||||
mv ~/rpmbuild/RPMS/x86_64/*.rpm imhex-${{env.IMHEX_VERSION}}-Fedora-${{matrix.release}}.rpm
|
||||
|
||||
fedpkg --path $GITHUB_WORKSPACE --release ${{ matrix.mock_release }} mockbuild --enable-network -N --root $GITHUB_WORKSPACE/mock.cfg extra_args -- -v
|
||||
|
||||
- name: 🟩 Move and rename finished RPM
|
||||
run: |
|
||||
mv $GITHUB_WORKSPACE/results_imhex/${{env.IMHEX_VERSION}}/*/imhex-${{env.IMHEX_VERSION}}-0.*.x86_64.rpm \
|
||||
$GITHUB_WORKSPACE/imhex-${{env.IMHEX_VERSION}}-${{matrix.name}}-${{matrix.release_num}}-x86_64.rpm
|
||||
|
||||
- name: ⬆️ Upload RPM
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Fedora ${{ matrix.release }} RPM
|
||||
name: ${{ matrix.name }} ${{ matrix.release_num }} RPM x86_64
|
||||
path: |
|
||||
imhex-${{env.IMHEX_VERSION}}-Fedora-${{matrix.release}}.rpm
|
||||
imhex-${{env.IMHEX_VERSION}}-${{matrix.name}}-${{matrix.release_num}}-x86_64.rpm
|
||||
|
||||
116
.github/workflows/release.yml
vendored
116
.github/workflows/release.yml
vendored
@@ -9,9 +9,54 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
release-common:
|
||||
release-update-repos:
|
||||
runs-on: ubuntu-latest
|
||||
name: Release Common
|
||||
name: Release Update Repos
|
||||
|
||||
steps:
|
||||
- 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:
|
||||
- name: 🧰 Checkout
|
||||
@@ -34,7 +79,7 @@ jobs:
|
||||
|
||||
- name: 🗜️ Create tarball from sources with dependencies
|
||||
run: tar --exclude-vcs -czvf Full.Sources.tar.gz ImHex
|
||||
|
||||
|
||||
- name: ⬇️ Download artifacts from latest workflow
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
@@ -43,7 +88,7 @@ jobs:
|
||||
branch: ${{ github.event.release.target_commitish }}
|
||||
workflow_conclusion: success
|
||||
skip_unpack: true
|
||||
|
||||
|
||||
- name: 🗜️ Unzip files when needed
|
||||
run: |
|
||||
for zipfile in ./*.zip
|
||||
@@ -60,8 +105,8 @@ jobs:
|
||||
|
||||
- name: 🟩 Rename artifacts when needed
|
||||
run: |
|
||||
mv "Windows Portable.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable.zip
|
||||
mv "Windows Portable NoGPU.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable-NoGPU.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
|
||||
|
||||
- name: ⬆️ Upload everything to release
|
||||
uses: softprops/action-gh-release@v1
|
||||
@@ -72,14 +117,13 @@ jobs:
|
||||
run: |
|
||||
cp ImHex/dist/Arch/PKGBUILD .
|
||||
|
||||
hash=`md5sum imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst | 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/(SKIP)/($hash)/g" PKGBUILD
|
||||
|
||||
- name: ⬆️ Publish AUR package
|
||||
|
||||
# I couldn't make the condition in the env directly for some reason
|
||||
|
||||
env:
|
||||
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||
if: "${{ env.AUR_SSH_PRIVATE_KEY != '' }}"
|
||||
@@ -94,57 +138,15 @@ jobs:
|
||||
commit_message: Bump to version ${{env.IMHEX_VERSION}}
|
||||
ssh_keyscan_types: rsa,dsa,ecdsa,ed25519
|
||||
|
||||
- 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: mvasigh/dispatch-action@main
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
repo: ImHex-Cpp-Plugin-Template
|
||||
owner: WerWolv
|
||||
event_type: update_submodule
|
||||
|
||||
- name: ✉️ Update Rust Plugin Template
|
||||
uses: mvasigh/dispatch-action@main
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
repo: ImHex-Rust-Plugin-Template
|
||||
owner: WerWolv
|
||||
event_type: update_submodule
|
||||
|
||||
release-windows:
|
||||
name: Release Windows
|
||||
needs: release-common
|
||||
runs-on: windows-2022
|
||||
release-update-winget:
|
||||
name: Release update winget package
|
||||
needs: release-upload-artifacts
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: ⬇️ Download dependencies
|
||||
shell: pwsh
|
||||
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
|
||||
shell: pwsh
|
||||
env:
|
||||
@@ -153,7 +155,7 @@ jobs:
|
||||
run: |
|
||||
$tagname = $env:GITHUB_REF.Replace("refs/tags/", "")
|
||||
$version = $tagname.Replace("v", "")
|
||||
$url = "https://github.com/WerWolv/ImHex/releases/download/${tagname}/imhex-${version}-win64.msi"
|
||||
$url = "https://github.com/WerWolv/ImHex/releases/download/${tagname}/imhex-${version}-Windows-x86_64.msi"
|
||||
.\wingetcreate.exe update WerWolv.ImHex -u $url --version $version
|
||||
if ($version -notmatch "-") {
|
||||
.\wingetcreate.exe submit .\manifests\w\WerWolv\ImHex\${version}\ --token $env:WINGET_GITHUB_TOKEN
|
||||
|
||||
13
.github/workflows/tests.yml
vendored
13
.github/workflows/tests.yml
vendored
@@ -25,18 +25,18 @@ jobs:
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
|
||||
key: ${{ runner.os }}-tests-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-tests-${{ secrets.CACHE_VERSION }}-build
|
||||
max-size: 50M
|
||||
|
||||
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
key: ${{ runner.os }}-tests-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
@@ -48,14 +48,13 @@ jobs:
|
||||
cd build
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
|
||||
-DIMHEX_OFFLINE_BUILD=ON \
|
||||
..
|
||||
make -j4 unit_tests install
|
||||
make -j4 unit_tests
|
||||
|
||||
- name: 🧪 Perform Unit Tests
|
||||
run: |
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -2,13 +2,9 @@
|
||||
.idea/
|
||||
|
||||
cmake-build-*/
|
||||
|
||||
build-linux/
|
||||
build*/
|
||||
venv/
|
||||
|
||||
*.mgc
|
||||
imgui.ini
|
||||
.DS_Store
|
||||
plugins/.rustc_info.json
|
||||
|
||||
**/target
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -29,3 +29,6 @@
|
||||
[submodule "lib/external/pattern_language"]
|
||||
path = lib/external/pattern_language
|
||||
url = https://github.com/WerWolv/PatternLanguage
|
||||
[submodule "lib/external/libwolv"]
|
||||
path = lib/external/libwolv
|
||||
url = https://github.com/WerWolv/libwolv
|
||||
|
||||
8
.idea/.gitignore
generated
vendored
8
.idea/.gitignore
generated
vendored
@@ -1,8 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/../../../../../:\_Dev\Cpp\HexEditor\.idea/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
1
.idea/.name
generated
1
.idea/.name
generated
@@ -1 +0,0 @@
|
||||
imhex
|
||||
14
.idea/deployment.xml
generated
14
.idea/deployment.xml
generated
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PublishConfigData" remoteFilesAllowedToDisappearOnAutoupload="false">
|
||||
<serverData>
|
||||
<paths name="WSL (e494f5fa-cb38-49f1-b2cb-b9524b92ed51)">
|
||||
<serverdata>
|
||||
<mappings>
|
||||
<mapping local="$PROJECT_DIR$" web="/" />
|
||||
</mappings>
|
||||
</serverdata>
|
||||
</paths>
|
||||
</serverData>
|
||||
</component>
|
||||
</project>
|
||||
2
.idea/imhex.iml
generated
2
.idea/imhex.iml
generated
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
||||
4
.idea/misc.xml
generated
4
.idea/misc.xml
generated
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/imhex.iml" filepath="$PROJECT_DIR$/.idea/imhex.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
16
.idea/vcs.xml
generated
16
.idea/vcs.xml
generated
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/capstone" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/curl" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/fmt" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/libromfs" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/nativefiledialog" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language/external/cli11" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language/external/fmt" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/xdgpp" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/yara/yara" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -8,6 +8,8 @@ option(IMHEX_OFFLINE_BUILD "Enable offline build" OFF)
|
||||
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_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_DISABLE_STACKTRACE "Disables support for printing stack traces" OFF)
|
||||
|
||||
# Basic compiler and cmake configurations
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
@@ -19,7 +21,11 @@ include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
|
||||
# Setup project
|
||||
loadVersion(IMHEX_VERSION)
|
||||
setVariableInParent(IMHEX_VERSION ${IMHEX_VERSION})
|
||||
project(imhex VERSION ${IMHEX_VERSION})
|
||||
project(imhex
|
||||
LANGUAGES C CXX VERSION ${IMHEX_VERSION}
|
||||
DESCRIPTION "The ImHex Hex Editor"
|
||||
HOMEPAGE_URL "https://imhex.werwolv.net"
|
||||
)
|
||||
|
||||
# Make sure project is configured correctly
|
||||
setDefaultBuiltTypeIfUnset()
|
||||
@@ -38,11 +44,12 @@ detectArch()
|
||||
addVersionDefines()
|
||||
configurePackingResources()
|
||||
setUninstallTarget()
|
||||
addBundledLibraries()
|
||||
|
||||
# Add ImHex sources
|
||||
add_subdirectory(lib/libimhex)
|
||||
add_subdirectory(main)
|
||||
add_custom_target(imhex_all ALL DEPENDS main)
|
||||
add_custom_target(imhex_all ALL DEPENDS main libimhex)
|
||||
|
||||
# Add unit tests
|
||||
enable_testing()
|
||||
|
||||
67
HACKING.md
Normal file
67
HACKING.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Hacking guide
|
||||
|
||||
## Introduction
|
||||
|
||||
This document is a guide for developers who want to contribute to ImHex in any way. It contains information about the codebase, the build process and the general workflow.
|
||||
|
||||
## Codebase
|
||||
|
||||
ImHex is written in C++ and usually uses the latest compiler and standard library features available in gcc on all supported OSes. At the time of writing this is C++23.
|
||||
|
||||
### Structure
|
||||
|
||||
- `main`: Contains the main application code
|
||||
- Important to understand here is that the main ImHex application is basically just an empty shell.
|
||||
- All it does is create a Window and a OpenGL context using GLFW, load all available plugins, properly configure ImGui and render it to the screen.
|
||||
- Everything else is done inside of plugins. ImHex comes with a few plugins by default, most notably the `builtin` plugin which contains the majority of the application code.
|
||||
- In most cases, this code doesn't need to be modified. Most features should be self-contained inside a plugin.
|
||||
- `lib`
|
||||
- `libimhex`: Contains all helper utilities as well as various APIs for plugins to interact with ImHex.
|
||||
- The library's main purpose is for Dependency Inversion. The ImHex main application as well as libimhex do not know about the existence of plugins at build time. Plugins and the main application instead link against libimhex and use it as a common API to interact with each other.
|
||||
- Since libimhex is a doesn't know about the existence of plugins, it cannot depend on any of them. This includes localizations and things that get registered by plugins after launch.
|
||||
- Even if the builtin plugin is technically always available, it is still a plugin and should be treated that way.
|
||||
- All important APIs can be found in the `hex/api` include directory and are documented in the respective header file.
|
||||
- `external`: All libraries that need custom patches or aren't typically available in package managers go into here.
|
||||
- If you'd like to add new features to the Pattern language, please make a PR to https://github.com/WerWolv/PatternLanguage instead. ImHex usually depends on the latest commit of the master branch of this repo.
|
||||
- `plugins`
|
||||
- `builtin`: The builtin plugin. Contains the majority of the application code.
|
||||
- It's the heart of ImHex's functionality. It contains most of the default views, providers, etc. so if you want to add new functionality to ImHex, this is the place to start.
|
||||
- `tests`: Contains all unit tests for ImHex. These are run automatically by the CI and should be kept up to date, especially when adding new helper functions to libimhex.
|
||||
|
||||
### RomFS
|
||||
|
||||
ImHex uses a custom library called [libromfs](https://github.com/WerWolv/libromfs). It's a simple static library which uses CMake's code generation feature to embed files into the binary at compile time so they can be accessed at runtime.
|
||||
All plugins have a `romfs` folder which contains all files that should be embedded into the binary. Resources that need to be embedded into the main application (this is usually not necessary), go into the `resources/romfs` folder.
|
||||
When adding, changing files or removing files, make sure to re-run CMake to update the generated code. Otherwise, the changes might not be reflected in the binary.
|
||||
|
||||
## Development Environment
|
||||
|
||||
I personally use CLion for development since it makes configuring and building the project very easy on all platforms.
|
||||
|
||||
### Windows
|
||||
- Install MSYS2 from https://www.msys2.org/ and use the `dist/get_deps_msys2.sh` script to install all dependencies.
|
||||
### Linux
|
||||
- Install all dependencies using one of the `dist/get_deps_*.sh` scripts depending on your distribution or install them manually with your package manager.
|
||||
### macOS
|
||||
- Install all dependencies using brew and the `dist/Brewfile` script.
|
||||
|
||||
## Making Changes
|
||||
|
||||
### Adding new features to ImHex
|
||||
|
||||
If you'd like to add new features, the best way to start is by joining our Discord and telling us about your idea. We can then discuss the best way to implement it and how it should be integrated into ImHex or if it should be done in a separate plugin.
|
||||
|
||||
There are standalone plugin templates that use ImHex as a submodule. You can find them here:
|
||||
- https://github.com/WerWolv/ImHex-Cpp-Plugin-Template
|
||||
- https://github.com/WerWolv/ImHex-Rust-Plugin-Template
|
||||
|
||||
### Adding a new language
|
||||
|
||||
If you'd like to support a new language in ImHex, the best way is by using the `dist/langtool.py` tool. It will create the necessary file for you and help you fill them out.
|
||||
First, run the tool with `python3 dist/langtool.py create plugins/builtin/romfs/lang <iso_code>` where `<iso_code>` is the ISO 639-1 code of your language. This will create a new file in the language directory.
|
||||
Afterwards follow the prompts of the program to populate the entire file. Once you're done, rerun cmake and rebuild ImHex. Your language should now be available in the settings.
|
||||
|
||||
### Updating an existing language
|
||||
|
||||
If you'd like to add missing keys to an existing language, you can also use the `dist/langtool.py` tool. Run it with `python3 dist/langtool.py translate plugins/builtin/romfs/lang <iso_code>` where `<iso_code>` is the ISO 639-1 code of the language.
|
||||
This will one by one list all the missing translation keys that are present in the default translation file, and you can fill them in with the correct translation for your language.
|
||||
53
INSTALL.md
53
INSTALL.md
@@ -6,6 +6,55 @@ The easiest way to install ImHex is to download the latest release from the [Git
|
||||
|
||||
There's also a NoGPU version available for users who don't have a GPU or want to run ImHex in a VM without GPU passthrough.
|
||||
|
||||
### Windows
|
||||
|
||||
#### Installer
|
||||
Simply run the installer to install ImHex on your system
|
||||
|
||||
#### Portable
|
||||
Extract the zip file to any location on your system.
|
||||
|
||||
### macOS
|
||||
Simply use the drag-n-drop dmg package to install ImHex on your system. It's possible that you need to allow the app to run in the security settings.
|
||||
|
||||
### Linux
|
||||
|
||||
#### AppImage
|
||||
To run the AppImage, make sure it's executable. Then simply run it.
|
||||
|
||||
```bash
|
||||
chmod +x imhex-*.AppImage
|
||||
./imhex-*.AppImage
|
||||
```
|
||||
|
||||
#### Flatpak
|
||||
To install the Flatpak, make sure you have the Flathub repository added to your system. Then simply run the following command:
|
||||
|
||||
```bash
|
||||
flatpak install flathub net.werwolv.ImHex
|
||||
```
|
||||
|
||||
#### Ubuntu DEB Package
|
||||
To install the DEB package, simply run the following command:
|
||||
|
||||
```bash
|
||||
sudo apt install ./imhex-*.deb
|
||||
```
|
||||
|
||||
#### Arch Linux
|
||||
To install the Arch Linux package, simply run the following command:
|
||||
|
||||
```bash
|
||||
sudo pacman -U imhex-*.pkg.tar.zst
|
||||
```
|
||||
|
||||
#### Fedora / RHEL / AlmaLinux RPM Package
|
||||
To install the RPM package, simply run the following command:
|
||||
|
||||
```bash
|
||||
sudo dnf install ./imhex-*.rpm
|
||||
```
|
||||
|
||||
## Nightly Builds
|
||||
|
||||
The GitHub Actions CI builds a new release package on every commit made to repository. These builds are available on the [GitHub Actions page](https://github.com/WerWolv/ImHex/actions?query=workflow%3A%22Build%22).
|
||||
@@ -24,10 +73,10 @@ ImHex is also available on various package managers. The officially supported on
|
||||
|
||||
### Windows
|
||||
|
||||
- **Cocolatey**
|
||||
- **Chocolatey**
|
||||
- [imhex](https://community.chocolatey.org/packages/imhex) (Thanks to @Jarcho)
|
||||
- `choco install imhex`
|
||||
- **winget**
|
||||
- **Winget**
|
||||
- [WerWolv.ImHex](https://github.com/microsoft/winget-pkgs/tree/master/manifests/w/WerWolv/ImHex)
|
||||
- `winget install WerWolv.ImHex`
|
||||
|
||||
|
||||
38
README.md
38
README.md
@@ -1,11 +1,33 @@
|
||||
<a href="https://imhex.werwolv.net"><h1 align="center" ><img height="100px" src="resources/projects/logo_text.svg"></h1></a>
|
||||
<a href="https://imhex.werwolv.net">
|
||||
<h1 align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./resources/projects/logo_text_light.svg">
|
||||
<img height="100px" src="./resources/projects/logo_text_dark.svg">
|
||||
</picture>
|
||||
</h1>
|
||||
</a>
|
||||
|
||||
<p align="center">A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</p>
|
||||
|
||||
<p align="center">
|
||||
<a title="'Build' workflow Status" href="https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild"><img alt="'Build' workflow Status" src="https://img.shields.io/github/workflow/status/WerWolv/ImHex/Build?longCache=true&style=for-the-badge&label=Build&logoColor=fff&logo=GitHub%20Actions"></a>
|
||||
<a title="Discord Server" href="https://discord.gg/X63jZ36xBY"><img alt="Discord Server" src="https://img.shields.io/discord/789833418631675954?label=Discord&logo=Discord&style=for-the-badge"></a>
|
||||
<a title="Total Downloads" href="https://github.com/WerWolv/ImHex/releases/latest"><img alt="Total Downloads" src="https://img.shields.io/github/downloads/WerWolv/ImHex/total?longCache=true&style=for-the-badge&label=Downloads&logoColor=fff&logo=GitHub"></a>
|
||||
<a title="'Build' workflow Status" href="https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild">
|
||||
<img alt="'Build' workflow Status" src="https://img.shields.io/github/actions/workflow/status/WerWolv/ImHex/build.yml?longCache=true&style=for-the-badge&label=Build&logoColor=fff&logo=GitHub%20Actions&branch=master">
|
||||
</a>
|
||||
<a title="Discord Server" href="https://discord.gg/X63jZ36xBY">
|
||||
<img alt="Discord Server" src="https://img.shields.io/discord/789833418631675954?label=Discord&logo=Discord&logoColor=fff&style=for-the-badge">
|
||||
</a>
|
||||
<a title="Total Downloads" href="https://github.com/WerWolv/ImHex/releases/latest">
|
||||
<img alt="Total Downloads" src="https://img.shields.io/github/downloads/WerWolv/ImHex/total?longCache=true&style=for-the-badge&label=Downloads&logoColor=fff&logo=GitHub">
|
||||
</a>
|
||||
<a title="Code Quality" href="https://www.codefactor.io/repository/github/werwolv/imhex">
|
||||
<img alt="Code Quality" src="https://img.shields.io/codefactor/grade/github/WerWolv/ImHex?longCache=true&style=for-the-badge&label=Code%20Quality&logoColor=fff&logo=CodeFactor&branch=master">
|
||||
</a>
|
||||
<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">
|
||||
</a>
|
||||
<a title="Documentation" href="https://imhex.werwolv.net/docs">
|
||||
<img alt="Documentation" src="https://img.shields.io/badge/Docs-Available-green?logo=gitbook&logoColor=%23FFFFFF&style=for-the-badge">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Supporting
|
||||
@@ -120,10 +142,12 @@ For format patterns, libraries, magic and constant files, check out the [ImHex-P
|
||||
|
||||
To use ImHex, the following minimal system requirements need to be met:
|
||||
|
||||
- **OS**: Windows 7 or higher, macOS 10.15 (Catalina) or higher, "Modern" Linux (Ubuntu 22.04, Fedora Stable/Rawhide, and Arch Linux have official packages, other distributions can use the AppImage)
|
||||
- **OS**: Windows 7 or higher, macOS 10.15 (Catalina) or higher, "Modern" Linux (Ubuntu 22.04, Fedora 36/37, RHEL/AlmaLinux 9, and Arch Linux have official packages, other and older distributions can use the AppImage)
|
||||
- **CPU**: x86_64 (64 Bit)
|
||||
- **GPU**: OpenGL 3.0 or higher (preferable a dedicated GPU and not Intel HD Graphics)
|
||||
- **RAM**: 512MB, more may be required for more complicated analysis
|
||||
- **GPU**: OpenGL 3.0 or higher
|
||||
- Intel HD drivers are really buggy and often cause graphic artifacts
|
||||
- In case you don't have a GPU available, there are software rendered releases available for Windows and macOS
|
||||
- **RAM**: 256MB, more may be required for more complicated analysis
|
||||
- **Storage**: 100MB
|
||||
|
||||
## Installing
|
||||
|
||||
@@ -14,13 +14,16 @@ macro(addVersionDefines)
|
||||
message(FATAL_ERROR "IMHEX_VERSION is not defined")
|
||||
endif ()
|
||||
|
||||
if (IS_DIRECTORY "${CMAKE_SOURCE_DIR}/.git")
|
||||
if (DEFINED IMHEX_COMMIT_HASH AND DEFINED IMHEX_COMMIT_BRANCH)
|
||||
add_compile_definitions(GIT_COMMIT_HASH="${IMHEX_COMMIT_HASH}" GIT_BRANCH="${IMHEX_COMMIT_BRANCH}")
|
||||
else()
|
||||
# Get the current working branch
|
||||
execute_process(
|
||||
COMMAND git rev-parse --abbrev-ref HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_BRANCH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
RESULT_VARIABLE RESULT_BRANCH
|
||||
)
|
||||
|
||||
# Get the latest abbreviated commit hash of the working branch
|
||||
@@ -29,9 +32,12 @@ macro(addVersionDefines)
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_COMMIT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
RESULT_VARIABLE RESULT_HASH
|
||||
)
|
||||
|
||||
add_compile_definitions(GIT_COMMIT_HASH="${GIT_COMMIT_HASH}" GIT_BRANCH="${GIT_BRANCH}")
|
||||
if (RESULT_BRANCH EQUAL 0 AND RESULT_HASH EQUAL 0)
|
||||
add_compile_definitions(GIT_COMMIT_HASH="${GIT_COMMIT_HASH}" GIT_BRANCH="${GIT_BRANCH}")
|
||||
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} ")
|
||||
@@ -41,7 +47,7 @@ macro(addVersionDefines)
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING})
|
||||
elseif (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-Debug)
|
||||
add_compile_definitions(DEBUG)
|
||||
add_compile_definitions(DEBUG _GLIBCXX_DEBUG _GLIBCXX_VERBOSE)
|
||||
elseif (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-RelWithDebInfo)
|
||||
elseif (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
|
||||
@@ -52,31 +58,6 @@ macro(addVersionDefines)
|
||||
|
||||
endmacro()
|
||||
|
||||
macro(configurePython)
|
||||
set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
|
||||
set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
|
||||
|
||||
# Enforce that we use non system Python 3 on macOS.
|
||||
set(Python_FIND_FRAMEWORK NEVER)
|
||||
|
||||
find_package(Python COMPONENTS Development REQUIRED)
|
||||
if(Python_VERSION LESS 3)
|
||||
message(STATUS ${PYTHON_VERSION_MAJOR_MINOR})
|
||||
message(FATAL_ERROR "No valid version of Python 3 was found.")
|
||||
endif()
|
||||
|
||||
string(REPLACE "." ";" PYTHON_VERSION_MAJOR_MINOR ${Python_VERSION})
|
||||
|
||||
list(LENGTH PYTHON_VERSION_MAJOR_MINOR PYTHON_VERSION_COMPONENT_COUNT)
|
||||
|
||||
if (PYTHON_VERSION_COMPONENT_COUNT EQUAL 3)
|
||||
list(REMOVE_AT PYTHON_VERSION_MAJOR_MINOR 2)
|
||||
endif ()
|
||||
list(JOIN PYTHON_VERSION_MAJOR_MINOR "." PYTHON_VERSION_MAJOR_MINOR)
|
||||
|
||||
add_compile_definitions(PYTHON_VERSION_MAJOR_MINOR="${PYTHON_VERSION_MAJOR_MINOR}")
|
||||
endmacro()
|
||||
|
||||
# Detect current OS / System
|
||||
macro(detectOS)
|
||||
if (WIN32)
|
||||
@@ -85,7 +66,9 @@ macro(detectOS)
|
||||
set(CMAKE_INSTALL_LIBDIR ".")
|
||||
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)
|
||||
add_compile_definitions(OS_MACOS)
|
||||
set(CMAKE_INSTALL_BINDIR ".")
|
||||
@@ -135,12 +118,11 @@ macro(configurePackingResources)
|
||||
if (WIN32)
|
||||
set(APPLICATION_TYPE)
|
||||
set(IMHEX_ICON "${IMHEX_BASE_FOLDER}/resources/resource.rc")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--allow-multiple-definition")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-subsystem,windows")
|
||||
|
||||
if (CREATE_PACKAGE)
|
||||
set(CPACK_GENERATOR "WIX")
|
||||
set(CPACK_PACKAGE_NAME "imhex")
|
||||
set(CPACK_PACKAGE_NAME "ImHex")
|
||||
set(CPACK_PACKAGE_VENDOR "WerWolv")
|
||||
set(CPACK_WIX_UPGRADE_GUID "05000E99-9659-42FD-A1CF-05C554B39285")
|
||||
set(CPACK_WIX_PRODUCT_ICON "${PROJECT_SOURCE_DIR}/resources/dist/windows/icon.ico")
|
||||
@@ -223,7 +205,6 @@ macro(createPackage)
|
||||
|
||||
# Grab all dynamically linked dependencies.
|
||||
INSTALL(CODE "set(CMAKE_INSTALL_BINDIR \"${CMAKE_INSTALL_BINDIR}\")")
|
||||
INSTALL(CODE "get_filename_component(PY_PARENT \"${Python_LIBRARIES}\" DIRECTORY)")
|
||||
INSTALL(CODE "LIST(APPEND DEP_FOLDERS \${PY_PARENT})")
|
||||
install(CODE [[
|
||||
file(GET_RUNTIME_DEPENDENCIES
|
||||
@@ -334,6 +315,7 @@ function(loadVersion version)
|
||||
set(VERSION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/VERSION")
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${VERSION_FILE})
|
||||
file(READ "${VERSION_FILE}" read_version)
|
||||
string(STRIP ${read_version} read_version)
|
||||
set(${version} ${read_version} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
@@ -390,7 +372,9 @@ function(downloadImHexPatternsFiles dest)
|
||||
GIT_TAG master
|
||||
)
|
||||
|
||||
FetchContent_Populate(imhex_patterns)
|
||||
message(STATUS "Downloading ImHex-Patterns repo branch ${PATTERNS_BRANCH}...")
|
||||
FetchContent_MakeAvailable(imhex_patterns)
|
||||
message(STATUS "Finished downloading ImHex-Patterns")
|
||||
|
||||
else ()
|
||||
# Maybe patterns are cloned to a subdirectory
|
||||
@@ -407,8 +391,8 @@ function(downloadImHexPatternsFiles dest)
|
||||
endfunction()
|
||||
|
||||
macro(setupCompilerWarnings target)
|
||||
set(IMHEX_COMMON_FLAGS "-Wall -Wextra -Werror")
|
||||
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow")
|
||||
set(IMHEX_COMMON_FLAGS "-Wall -Wextra -Wpedantic -Werror")
|
||||
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow -Wno-array-bounds")
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${IMHEX_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${IMHEX_C_FLAGS}")
|
||||
@@ -426,4 +410,147 @@ macro(setUninstallTarget)
|
||||
add_custom_target(uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
endif()
|
||||
endmacro()
|
||||
endmacro()
|
||||
|
||||
macro(addBundledLibraries)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
set(EXTERN_LIBS_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/lib/external")
|
||||
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/imgui)
|
||||
set_target_properties(imgui PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/microtar EXCLUDE_FROM_ALL)
|
||||
set_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/intervaltree EXCLUDE_FROM_ALL)
|
||||
set_target_properties(intervaltree PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/libwolv EXCLUDE_FROM_ALL)
|
||||
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(XDGPP_INCLUDE_DIRS "${EXTERN_LIBS_FOLDER}/xdgpp")
|
||||
set(CURL_USE_MBEDTLS ON)
|
||||
set(BUILD_CURL_EXE OFF)
|
||||
set(FPHSA_NAME_MISMATCHED ON CACHE BOOL "")
|
||||
|
||||
if(NOT USE_SYSTEM_FMT)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/fmt EXCLUDE_FROM_ALL)
|
||||
set_target_properties(fmt PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(FMT_LIBRARIES fmt::fmt-header-only)
|
||||
else()
|
||||
find_package(fmt 8.0.0 REQUIRED)
|
||||
set(FMT_LIBRARIES fmt::fmt)
|
||||
endif()
|
||||
|
||||
if (IMHEX_USE_GTK_FILE_PICKER)
|
||||
set(NFD_PORTAL OFF CACHE BOOL "Use Portals for Linux file dialogs" FORCE)
|
||||
else ()
|
||||
set(NFD_PORTAL ON CACHE BOOL "Use GTK for Linux file dialogs" FORCE)
|
||||
endif ()
|
||||
|
||||
if (NOT USE_SYSTEM_NFD)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/nativefiledialog EXCLUDE_FROM_ALL)
|
||||
set_target_properties(nfd PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(NFD_LIBRARIES nfd)
|
||||
else()
|
||||
find_package(nfd)
|
||||
set(NFD_LIBRARIES nfd)
|
||||
endif()
|
||||
|
||||
if(NOT USE_SYSTEM_NLOHMANN_JSON)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/nlohmann_json EXCLUDE_FROM_ALL)
|
||||
set(NLOHMANN_JSON_LIBRARIES nlohmann_json)
|
||||
else()
|
||||
find_package(nlohmann_json 3.10.2 REQUIRED)
|
||||
set(NLOHMANN_JSON_LIBRARIES nlohmann_json::nlohmann_json)
|
||||
endif()
|
||||
|
||||
if(NOT USE_SYSTEM_CURL)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/curl EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libcurl PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(LIBCURL_LIBRARIES libcurl)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBCURL REQUIRED IMPORTED_TARGET libcurl>=7.76.1)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_LLVM)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/llvm-demangle EXCLUDE_FROM_ALL)
|
||||
set_target_properties(LLVMDemangle PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
else()
|
||||
find_package(LLVM REQUIRED Demangle)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_YARA)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/yara EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libyara PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(YARA_LIBRARIES libyara)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(YARA REQUIRED IMPORTED_TARGET yara)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_MINIAUDIO)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/miniaudio EXCLUDE_FROM_ALL)
|
||||
set_target_properties(miniaudio PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(MINIAUDIO_LIBRARIES miniaudio)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(miniaudio REQUIRED IMPORTED_TARGET miniaudio)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_CAPSTONE)
|
||||
set(CAPSTONE_BUILD_STATIC_RUNTIME OFF CACHE BOOL "Disable shared library building")
|
||||
set(CAPSTONE_BUILD_SHARED OFF CACHE BOOL "Disable shared library building")
|
||||
set(CAPSTONE_BUILD_TESTS OFF CACHE BOOL "Disable tests")
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/capstone EXCLUDE_FROM_ALL)
|
||||
set_target_properties(capstone PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(CAPSTONE_LIBRARIES "capstone")
|
||||
set(CAPSTONE_INCLUDE_DIRS ${EXTERN_LIBS_FOLDER}/capstone/include)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_search_module(CAPSTONE 4.0.2 REQUIRED capstone)
|
||||
endif()
|
||||
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/pattern_language EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libpl PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
find_package(mbedTLS 2.26.0 REQUIRED)
|
||||
|
||||
pkg_search_module(MAGIC libmagic>=5.39)
|
||||
if(NOT MAGIC_FOUND)
|
||||
find_library(MAGIC 5.39 magic REQUIRED)
|
||||
else()
|
||||
set(MAGIC_INCLUDE_DIRS ${MAGIC_INCLUDEDIR})
|
||||
endif()
|
||||
|
||||
if (NOT IMHEX_DISABLE_STACKTRACE)
|
||||
if (WIN32)
|
||||
message(STATUS "StackWalk enabled!")
|
||||
set(LIBBACKTRACE_LIBRARIES DbgHelp.lib)
|
||||
else ()
|
||||
find_package(Backtrace)
|
||||
if (${Backtrace_FOUND})
|
||||
message(STATUS "Backtrace enabled! Header: ${Backtrace_HEADER}")
|
||||
|
||||
if (Backtrace_HEADER STREQUAL "execinfo.h")
|
||||
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
|
||||
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
|
||||
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
|
||||
add_compile_definitions(HEX_HAS_EXECINFO)
|
||||
elseif (Backtrace_HEADER STREQUAL "backtrace.h")
|
||||
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
|
||||
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
|
||||
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
|
||||
add_compile_definitions(HEX_HAS_BACKTRACE)
|
||||
endif ()
|
||||
endif()
|
||||
endif ()
|
||||
endif ()
|
||||
endmacro()
|
||||
|
||||
91
cmake/modules/FindBacktrace.cmake
Normal file
91
cmake/modules/FindBacktrace.cmake
Normal file
@@ -0,0 +1,91 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
FindBacktrace
|
||||
-------------
|
||||
|
||||
Find provider for `backtrace(3) <https://man7.org/linux/man-pages/man3/backtrace.3.html>`__.
|
||||
|
||||
Checks if OS supports ``backtrace(3)`` via either ``libc`` or custom library.
|
||||
This module defines the following variables:
|
||||
|
||||
``Backtrace_HEADER``
|
||||
The header file needed for ``backtrace(3)``. Cached.
|
||||
Could be forcibly set by user.
|
||||
``Backtrace_INCLUDE_DIRS``
|
||||
The include directories needed to use ``backtrace(3)`` header.
|
||||
``Backtrace_LIBRARIES``
|
||||
The libraries (linker flags) needed to use ``backtrace(3)``, if any.
|
||||
``Backtrace_FOUND``
|
||||
Is set if and only if ``backtrace(3)`` support detected.
|
||||
|
||||
The following cache variables are also available to set or use:
|
||||
|
||||
``Backtrace_LIBRARY``
|
||||
The external library providing backtrace, if any.
|
||||
``Backtrace_INCLUDE_DIR``
|
||||
The directory holding the ``backtrace(3)`` header.
|
||||
|
||||
Typical usage is to generate of header file using :command:`configure_file`
|
||||
with the contents like the following::
|
||||
|
||||
#cmakedefine01 Backtrace_FOUND
|
||||
#if Backtrace_FOUND
|
||||
# include <${Backtrace_HEADER}>
|
||||
#endif
|
||||
|
||||
And then reference that generated header file in actual source.
|
||||
#]=======================================================================]
|
||||
|
||||
include(CMakePushCheckState)
|
||||
include(CheckSymbolExists)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
|
||||
|
||||
# List of variables to be provided to find_package_handle_standard_args()
|
||||
set(_Backtrace_STD_ARGS Backtrace_INCLUDE_DIR)
|
||||
|
||||
if(Backtrace_HEADER)
|
||||
set(_Backtrace_HEADER_TRY "${Backtrace_HEADER}")
|
||||
else(Backtrace_HEADER)
|
||||
set(_Backtrace_HEADER_TRY "execinfo.h")
|
||||
endif(Backtrace_HEADER)
|
||||
|
||||
find_path(Backtrace_INCLUDE_DIR "${_Backtrace_HEADER_TRY}")
|
||||
set(Backtrace_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
|
||||
|
||||
if (NOT DEFINED Backtrace_LIBRARY)
|
||||
# First, check if we already have backtrace(), e.g., in libc
|
||||
cmake_push_check_state(RESET)
|
||||
set(CMAKE_REQUIRED_INCLUDES ${Backtrace_INCLUDE_DIRS})
|
||||
set(CMAKE_REQUIRED_QUIET ${Backtrace_FIND_QUIETLY})
|
||||
check_symbol_exists("backtrace" "${_Backtrace_HEADER_TRY}" _Backtrace_SYM_FOUND)
|
||||
cmake_pop_check_state()
|
||||
endif()
|
||||
|
||||
if(_Backtrace_SYM_FOUND)
|
||||
# Avoid repeating the message() call below each time CMake is run.
|
||||
if(NOT Backtrace_FIND_QUIETLY AND NOT DEFINED Backtrace_LIBRARY)
|
||||
message(STATUS "backtrace facility detected in default set of libraries")
|
||||
endif()
|
||||
set(Backtrace_LIBRARY "" CACHE FILEPATH "Library providing backtrace(3), empty for default set of libraries")
|
||||
else()
|
||||
# Check for external library, for non-glibc systems
|
||||
if(Backtrace_INCLUDE_DIR)
|
||||
# OpenBSD has libbacktrace renamed to libexecinfo
|
||||
find_library(Backtrace_LIBRARY "execinfo")
|
||||
else() # respect user wishes
|
||||
set(_Backtrace_HEADER_TRY "backtrace.h")
|
||||
find_path(Backtrace_INCLUDE_DIR ${_Backtrace_HEADER_TRY})
|
||||
find_library(Backtrace_LIBRARY "backtrace")
|
||||
endif()
|
||||
|
||||
# Prepend list with library path as it's more common practice
|
||||
set(_Backtrace_STD_ARGS Backtrace_LIBRARY ${_Backtrace_STD_ARGS})
|
||||
endif()
|
||||
|
||||
set(Backtrace_LIBRARIES ${Backtrace_LIBRARY})
|
||||
set(Backtrace_HEADER "${_Backtrace_HEADER_TRY}" CACHE STRING "Header providing backtrace(3) facility")
|
||||
|
||||
find_package_handle_standard_args(Backtrace FOUND_VAR Backtrace_FOUND REQUIRED_VARS ${_Backtrace_STD_ARGS})
|
||||
mark_as_advanced(Backtrace_HEADER Backtrace_INCLUDE_DIR Backtrace_LIBRARY)
|
||||
611
cmake/modules/FindPackageHandleStandardArgs.cmake
Normal file
611
cmake/modules/FindPackageHandleStandardArgs.cmake
Normal file
@@ -0,0 +1,611 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
FindPackageHandleStandardArgs
|
||||
-----------------------------
|
||||
|
||||
This module provides functions intended to be used in :ref:`Find Modules`
|
||||
implementing :command:`find_package(<PackageName>)` calls.
|
||||
|
||||
.. command:: find_package_handle_standard_args
|
||||
|
||||
This command handles the ``REQUIRED``, ``QUIET`` and version-related
|
||||
arguments of :command:`find_package`. It also sets the
|
||||
``<PackageName>_FOUND`` variable. The package is considered found if all
|
||||
variables listed contain valid results, e.g. valid filepaths.
|
||||
|
||||
There are two signatures:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package_handle_standard_args(<PackageName>
|
||||
(DEFAULT_MSG|<custom-failure-message>)
|
||||
<required-var>...
|
||||
)
|
||||
|
||||
find_package_handle_standard_args(<PackageName>
|
||||
[FOUND_VAR <result-var>]
|
||||
[REQUIRED_VARS <required-var>...]
|
||||
[VERSION_VAR <version-var>]
|
||||
[HANDLE_VERSION_RANGE]
|
||||
[HANDLE_COMPONENTS]
|
||||
[CONFIG_MODE]
|
||||
[NAME_MISMATCHED]
|
||||
[REASON_FAILURE_MESSAGE <reason-failure-message>]
|
||||
[FAIL_MESSAGE <custom-failure-message>]
|
||||
)
|
||||
|
||||
The ``<PackageName>_FOUND`` variable will be set to ``TRUE`` if all
|
||||
the variables ``<required-var>...`` are valid and any optional
|
||||
constraints are satisfied, and ``FALSE`` otherwise. A success or
|
||||
failure message may be displayed based on the results and on
|
||||
whether the ``REQUIRED`` and/or ``QUIET`` option was given to
|
||||
the :command:`find_package` call.
|
||||
|
||||
The options are:
|
||||
|
||||
``(DEFAULT_MSG|<custom-failure-message>)``
|
||||
In the simple signature this specifies the failure message.
|
||||
Use ``DEFAULT_MSG`` to ask for a default message to be computed
|
||||
(recommended). Not valid in the full signature.
|
||||
|
||||
``FOUND_VAR <result-var>``
|
||||
.. deprecated:: 3.3
|
||||
|
||||
Specifies either ``<PackageName>_FOUND`` or
|
||||
``<PACKAGENAME>_FOUND`` as the result variable. This exists only
|
||||
for compatibility with older versions of CMake and is now ignored.
|
||||
Result variables of both names are always set for compatibility.
|
||||
|
||||
``REQUIRED_VARS <required-var>...``
|
||||
Specify the variables which are required for this package.
|
||||
These may be named in the generated failure message asking the
|
||||
user to set the missing variable values. Therefore these should
|
||||
typically be cache entries such as ``FOO_LIBRARY`` and not output
|
||||
variables like ``FOO_LIBRARIES``.
|
||||
|
||||
.. versionchanged:: 3.18
|
||||
If ``HANDLE_COMPONENTS`` is specified, this option can be omitted.
|
||||
|
||||
``VERSION_VAR <version-var>``
|
||||
Specify the name of a variable that holds the version of the package
|
||||
that has been found. This version will be checked against the
|
||||
(potentially) specified required version given to the
|
||||
:command:`find_package` call, including its ``EXACT`` option.
|
||||
The default messages include information about the required
|
||||
version and the version which has been actually found, both
|
||||
if the version is ok or not.
|
||||
|
||||
``HANDLE_VERSION_RANGE``
|
||||
.. versionadded:: 3.19
|
||||
|
||||
Enable handling of a version range, if one is specified. Without this
|
||||
option, a developer warning will be displayed if a version range is
|
||||
specified.
|
||||
|
||||
``HANDLE_COMPONENTS``
|
||||
Enable handling of package components. In this case, the command
|
||||
will report which components have been found and which are missing,
|
||||
and the ``<PackageName>_FOUND`` variable will be set to ``FALSE``
|
||||
if any of the required components (i.e. not the ones listed after
|
||||
the ``OPTIONAL_COMPONENTS`` option of :command:`find_package`) are
|
||||
missing.
|
||||
|
||||
``CONFIG_MODE``
|
||||
Specify that the calling find module is a wrapper around a
|
||||
call to ``find_package(<PackageName> NO_MODULE)``. This implies
|
||||
a ``VERSION_VAR`` value of ``<PackageName>_VERSION``. The command
|
||||
will automatically check whether the package configuration file
|
||||
was found.
|
||||
|
||||
``REASON_FAILURE_MESSAGE <reason-failure-message>``
|
||||
.. versionadded:: 3.16
|
||||
|
||||
Specify a custom message of the reason for the failure which will be
|
||||
appended to the default generated message.
|
||||
|
||||
``FAIL_MESSAGE <custom-failure-message>``
|
||||
Specify a custom failure message instead of using the default
|
||||
generated message. Not recommended.
|
||||
|
||||
``NAME_MISMATCHED``
|
||||
.. versionadded:: 3.17
|
||||
|
||||
Indicate that the ``<PackageName>`` does not match
|
||||
``${CMAKE_FIND_PACKAGE_NAME}``. This is usually a mistake and raises a
|
||||
warning, but it may be intentional for usage of the command for components
|
||||
of a larger package.
|
||||
|
||||
Example for the simple signature:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package_handle_standard_args(LibXml2 DEFAULT_MSG
|
||||
LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)
|
||||
|
||||
The ``LibXml2`` package is considered to be found if both
|
||||
``LIBXML2_LIBRARY`` and ``LIBXML2_INCLUDE_DIR`` are valid.
|
||||
Then also ``LibXml2_FOUND`` is set to ``TRUE``. If it is not found
|
||||
and ``REQUIRED`` was used, it fails with a
|
||||
:command:`message(FATAL_ERROR)`, independent whether ``QUIET`` was
|
||||
used or not. If it is found, success will be reported, including
|
||||
the content of the first ``<required-var>``. On repeated CMake runs,
|
||||
the same message will not be printed again.
|
||||
|
||||
.. note::
|
||||
|
||||
If ``<PackageName>`` does not match ``CMAKE_FIND_PACKAGE_NAME`` for the
|
||||
calling module, a warning that there is a mismatch is given. The
|
||||
``FPHSA_NAME_MISMATCHED`` variable may be set to bypass the warning if using
|
||||
the old signature and the ``NAME_MISMATCHED`` argument using the new
|
||||
signature. To avoid forcing the caller to require newer versions of CMake for
|
||||
usage, the variable's value will be used if defined when the
|
||||
``NAME_MISMATCHED`` argument is not passed for the new signature (but using
|
||||
both is an error)..
|
||||
|
||||
Example for the full signature:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package_handle_standard_args(LibArchive
|
||||
REQUIRED_VARS LibArchive_LIBRARY LibArchive_INCLUDE_DIR
|
||||
VERSION_VAR LibArchive_VERSION)
|
||||
|
||||
In this case, the ``LibArchive`` package is considered to be found if
|
||||
both ``LibArchive_LIBRARY`` and ``LibArchive_INCLUDE_DIR`` are valid.
|
||||
Also the version of ``LibArchive`` will be checked by using the version
|
||||
contained in ``LibArchive_VERSION``. Since no ``FAIL_MESSAGE`` is given,
|
||||
the default messages will be printed.
|
||||
|
||||
Another example for the full signature:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package(Automoc4 QUIET NO_MODULE HINTS /opt/automoc4)
|
||||
find_package_handle_standard_args(Automoc4 CONFIG_MODE)
|
||||
|
||||
In this case, a ``FindAutmoc4.cmake`` module wraps a call to
|
||||
``find_package(Automoc4 NO_MODULE)`` and adds an additional search
|
||||
directory for ``automoc4``. Then the call to
|
||||
``find_package_handle_standard_args`` produces a proper success/failure
|
||||
message.
|
||||
|
||||
.. command:: find_package_check_version
|
||||
|
||||
.. versionadded:: 3.19
|
||||
|
||||
Helper function which can be used to check if a ``<version>`` is valid
|
||||
against version-related arguments of :command:`find_package`.
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package_check_version(<version> <result-var>
|
||||
[HANDLE_VERSION_RANGE]
|
||||
[RESULT_MESSAGE_VARIABLE <message-var>]
|
||||
)
|
||||
|
||||
The ``<result-var>`` will hold a boolean value giving the result of the check.
|
||||
|
||||
The options are:
|
||||
|
||||
``HANDLE_VERSION_RANGE``
|
||||
Enable handling of a version range, if one is specified. Without this
|
||||
option, a developer warning will be displayed if a version range is
|
||||
specified.
|
||||
|
||||
``RESULT_MESSAGE_VARIABLE <message-var>``
|
||||
Specify a variable to get back a message describing the result of the check.
|
||||
|
||||
Example for the usage:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package_check_version(1.2.3 result HANDLE_VERSION_RANGE
|
||||
RESULT_MESSAGE_VARIABLE reason)
|
||||
if (result)
|
||||
message (STATUS "${reason}")
|
||||
else()
|
||||
message (FATAL_ERROR "${reason}")
|
||||
endif()
|
||||
#]=======================================================================]
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake)
|
||||
|
||||
|
||||
cmake_policy(PUSH)
|
||||
# numbers and boolean constants
|
||||
cmake_policy (SET CMP0012 NEW)
|
||||
# IN_LIST operator
|
||||
cmake_policy (SET CMP0057 NEW)
|
||||
|
||||
|
||||
# internal helper macro
|
||||
macro(_FPHSA_FAILURE_MESSAGE _msg)
|
||||
set (__msg "${_msg}")
|
||||
if (FPHSA_REASON_FAILURE_MESSAGE)
|
||||
string(APPEND __msg "\n Reason given by package: ${FPHSA_REASON_FAILURE_MESSAGE}\n")
|
||||
endif()
|
||||
if (${_NAME}_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "${__msg}")
|
||||
else ()
|
||||
if (NOT ${_NAME}_FIND_QUIETLY)
|
||||
message(STATUS "${__msg}")
|
||||
endif ()
|
||||
endif ()
|
||||
endmacro()
|
||||
|
||||
|
||||
# internal helper macro to generate the failure message when used in CONFIG_MODE:
|
||||
macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE)
|
||||
# <PackageName>_CONFIG is set, but FOUND is false, this means that some other of the REQUIRED_VARS was not found:
|
||||
if(${_NAME}_CONFIG)
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: missing:${MISSING_VARS} (found ${${_NAME}_CONFIG} ${VERSION_MSG})")
|
||||
else()
|
||||
# If _CONSIDERED_CONFIGS is set, the config-file has been found, but no suitable version.
|
||||
# List them all in the error message:
|
||||
if(${_NAME}_CONSIDERED_CONFIGS)
|
||||
set(configsText "")
|
||||
list(LENGTH ${_NAME}_CONSIDERED_CONFIGS configsCount)
|
||||
math(EXPR configsCount "${configsCount} - 1")
|
||||
foreach(currentConfigIndex RANGE ${configsCount})
|
||||
list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename)
|
||||
list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version)
|
||||
string(APPEND configsText "\n ${filename} (version ${version})")
|
||||
endforeach()
|
||||
if (${_NAME}_NOT_FOUND_MESSAGE)
|
||||
if (FPHSA_REASON_FAILURE_MESSAGE)
|
||||
string(PREPEND FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}\n ")
|
||||
else()
|
||||
set(FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}")
|
||||
endif()
|
||||
else()
|
||||
string(APPEND configsText "\n")
|
||||
endif()
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:${configsText}")
|
||||
|
||||
else()
|
||||
# Simple case: No Config-file was found at all:
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: found neither ${_NAME}Config.cmake nor ${_NAME_LOWER}-config.cmake ${VERSION_MSG}")
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
||||
function(FIND_PACKAGE_CHECK_VERSION version result)
|
||||
cmake_parse_arguments (PARSE_ARGV 2 FPCV "HANDLE_VERSION_RANGE;NO_AUTHOR_WARNING_VERSION_RANGE" "RESULT_MESSAGE_VARIABLE" "")
|
||||
|
||||
if (FPCV_UNPARSED_ARGUMENTS)
|
||||
message (FATAL_ERROR "find_package_check_version(): ${FPCV_UNPARSED_ARGUMENTS}: unexpected arguments")
|
||||
endif()
|
||||
if ("RESULT_MESSAGE_VARIABLE" IN_LIST FPCV_KEYWORDS_MISSING_VALUES)
|
||||
message (FATAL_ERROR "find_package_check_version(): RESULT_MESSAGE_VARIABLE expects an argument")
|
||||
endif()
|
||||
|
||||
set (${result} FALSE PARENT_SCOPE)
|
||||
if (FPCV_RESULT_MESSAGE_VARIABLE)
|
||||
unset (${FPCV_RESULT_MESSAGE_VARIABLE} PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if (_CMAKE_FPHSA_PACKAGE_NAME)
|
||||
set (package "${_CMAKE_FPHSA_PACKAGE_NAME}")
|
||||
elseif (CMAKE_FIND_PACKAGE_NAME)
|
||||
set (package "${CMAKE_FIND_PACKAGE_NAME}")
|
||||
else()
|
||||
message (FATAL_ERROR "find_package_check_version(): Cannot be used outside a 'Find Module'")
|
||||
endif()
|
||||
|
||||
if (NOT FPCV_NO_AUTHOR_WARNING_VERSION_RANGE
|
||||
AND ${package}_FIND_VERSION_RANGE AND NOT FPCV_HANDLE_VERSION_RANGE)
|
||||
message(AUTHOR_WARNING
|
||||
"`find_package()` specify a version range but the option "
|
||||
"HANDLE_VERSION_RANGE` is not passed to `find_package_check_version()`. "
|
||||
"Only the lower endpoint of the range will be used.")
|
||||
endif()
|
||||
|
||||
|
||||
set (version_ok FALSE)
|
||||
unset (version_msg)
|
||||
|
||||
if (FPCV_HANDLE_VERSION_RANGE AND ${package}_FIND_VERSION_RANGE)
|
||||
if ((${package}_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE"
|
||||
AND version VERSION_GREATER_EQUAL ${package}_FIND_VERSION_MIN)
|
||||
AND ((${package}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE"
|
||||
AND version VERSION_LESS_EQUAL ${package}_FIND_VERSION_MAX)
|
||||
OR (${package}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE"
|
||||
AND version VERSION_LESS ${package}_FIND_VERSION_MAX)))
|
||||
set (version_ok TRUE)
|
||||
set(version_msg "(found suitable version \"${version}\", required range is \"${${package}_FIND_VERSION_RANGE}\")")
|
||||
else()
|
||||
set(version_msg "Found unsuitable version \"${version}\", required range is \"${${package}_FIND_VERSION_RANGE}\"")
|
||||
endif()
|
||||
elseif (DEFINED ${package}_FIND_VERSION)
|
||||
if(${package}_FIND_VERSION_EXACT) # exact version required
|
||||
# count the dots in the version string
|
||||
string(REGEX REPLACE "[^.]" "" version_dots "${version}")
|
||||
# add one dot because there is one dot more than there are components
|
||||
string(LENGTH "${version_dots}." version_dots)
|
||||
if (version_dots GREATER ${package}_FIND_VERSION_COUNT)
|
||||
# Because of the C++ implementation of find_package() ${package}_FIND_VERSION_COUNT
|
||||
# is at most 4 here. Therefore a simple lookup table is used.
|
||||
if (${package}_FIND_VERSION_COUNT EQUAL 1)
|
||||
set(version_regex "[^.]*")
|
||||
elseif (${package}_FIND_VERSION_COUNT EQUAL 2)
|
||||
set(version_regex "[^.]*\\.[^.]*")
|
||||
elseif (${package}_FIND_VERSION_COUNT EQUAL 3)
|
||||
set(version_regex "[^.]*\\.[^.]*\\.[^.]*")
|
||||
else()
|
||||
set(version_regex "[^.]*\\.[^.]*\\.[^.]*\\.[^.]*")
|
||||
endif()
|
||||
string(REGEX REPLACE "^(${version_regex})\\..*" "\\1" version_head "${version}")
|
||||
if (NOT ${package}_FIND_VERSION VERSION_EQUAL version_head)
|
||||
set(version_msg "Found unsuitable version \"${version}\", but required is exact version \"${${package}_FIND_VERSION}\"")
|
||||
else ()
|
||||
set(version_ok TRUE)
|
||||
set(version_msg "(found suitable exact version \"${_FOUND_VERSION}\")")
|
||||
endif ()
|
||||
else ()
|
||||
if (NOT ${package}_FIND_VERSION VERSION_EQUAL version)
|
||||
set(version_msg "Found unsuitable version \"${version}\", but required is exact version \"${${package}_FIND_VERSION}\"")
|
||||
else ()
|
||||
set(version_ok TRUE)
|
||||
set(version_msg "(found suitable exact version \"${version}\")")
|
||||
endif ()
|
||||
endif ()
|
||||
else() # minimum version
|
||||
if (${package}_FIND_VERSION VERSION_GREATER version)
|
||||
set(version_msg "Found unsuitable version \"${version}\", but required is at least \"${${package}_FIND_VERSION}\"")
|
||||
else()
|
||||
set(version_ok TRUE)
|
||||
set(version_msg "(found suitable version \"${version}\", minimum required is \"${${package}_FIND_VERSION}\")")
|
||||
endif()
|
||||
endif()
|
||||
else ()
|
||||
set(version_ok TRUE)
|
||||
set(version_msg "(found version \"${version}\")")
|
||||
endif()
|
||||
|
||||
set (${result} ${version_ok} PARENT_SCOPE)
|
||||
if (FPCV_RESULT_MESSAGE_VARIABLE)
|
||||
set (${FPCV_RESULT_MESSAGE_VARIABLE} "${version_msg}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG)
|
||||
|
||||
# Set up the arguments for `cmake_parse_arguments`.
|
||||
set(options CONFIG_MODE HANDLE_COMPONENTS NAME_MISMATCHED HANDLE_VERSION_RANGE)
|
||||
set(oneValueArgs FAIL_MESSAGE REASON_FAILURE_MESSAGE VERSION_VAR FOUND_VAR)
|
||||
set(multiValueArgs REQUIRED_VARS)
|
||||
|
||||
# Check whether we are in 'simple' or 'extended' mode:
|
||||
set(_KEYWORDS_FOR_EXTENDED_MODE ${options} ${oneValueArgs} ${multiValueArgs} )
|
||||
list(FIND _KEYWORDS_FOR_EXTENDED_MODE "${_FIRST_ARG}" INDEX)
|
||||
|
||||
unset(FPHSA_NAME_MISMATCHED_override)
|
||||
if (DEFINED FPHSA_NAME_MISMATCHED)
|
||||
# If the variable NAME_MISMATCHED variable is set, error if it is passed as
|
||||
# an argument. The former is for old signatures, the latter is for new
|
||||
# signatures.
|
||||
list(FIND ARGN "NAME_MISMATCHED" name_mismatched_idx)
|
||||
if (NOT name_mismatched_idx EQUAL "-1")
|
||||
message(FATAL_ERROR
|
||||
"The `NAME_MISMATCHED` argument may only be specified by the argument or "
|
||||
"the variable, not both.")
|
||||
endif ()
|
||||
|
||||
# But use the variable if it is not an argument to avoid forcing minimum
|
||||
# CMake version bumps for calling modules.
|
||||
set(FPHSA_NAME_MISMATCHED_override "${FPHSA_NAME_MISMATCHED}")
|
||||
endif ()
|
||||
|
||||
if(${INDEX} EQUAL -1)
|
||||
set(FPHSA_FAIL_MESSAGE ${_FIRST_ARG})
|
||||
set(FPHSA_REQUIRED_VARS ${ARGN})
|
||||
set(FPHSA_VERSION_VAR)
|
||||
else()
|
||||
cmake_parse_arguments(FPHSA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${_FIRST_ARG} ${ARGN})
|
||||
|
||||
if(FPHSA_UNPARSED_ARGUMENTS)
|
||||
message(FATAL_ERROR "Unknown keywords given to FIND_PACKAGE_HANDLE_STANDARD_ARGS(): \"${FPHSA_UNPARSED_ARGUMENTS}\"")
|
||||
endif()
|
||||
|
||||
if(NOT FPHSA_FAIL_MESSAGE)
|
||||
set(FPHSA_FAIL_MESSAGE "DEFAULT_MSG")
|
||||
endif()
|
||||
|
||||
# In config-mode, we rely on the variable <PackageName>_CONFIG, which is set by find_package()
|
||||
# when it successfully found the config-file, including version checking:
|
||||
if(FPHSA_CONFIG_MODE)
|
||||
list(INSERT FPHSA_REQUIRED_VARS 0 ${_NAME}_CONFIG)
|
||||
list(REMOVE_DUPLICATES FPHSA_REQUIRED_VARS)
|
||||
set(FPHSA_VERSION_VAR ${_NAME}_VERSION)
|
||||
endif()
|
||||
|
||||
if(NOT FPHSA_REQUIRED_VARS AND NOT FPHSA_HANDLE_COMPONENTS)
|
||||
message(FATAL_ERROR "No REQUIRED_VARS specified for FIND_PACKAGE_HANDLE_STANDARD_ARGS()")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (DEFINED FPHSA_NAME_MISMATCHED_override)
|
||||
set(FPHSA_NAME_MISMATCHED "${FPHSA_NAME_MISMATCHED_override}")
|
||||
endif ()
|
||||
|
||||
if (DEFINED CMAKE_FIND_PACKAGE_NAME
|
||||
AND NOT FPHSA_NAME_MISMATCHED
|
||||
AND NOT _NAME STREQUAL CMAKE_FIND_PACKAGE_NAME)
|
||||
message(AUTHOR_WARNING
|
||||
"The package name passed to `find_package_handle_standard_args` "
|
||||
"(${_NAME}) does not match the name of the calling package "
|
||||
"(${CMAKE_FIND_PACKAGE_NAME}). This can lead to problems in calling "
|
||||
"code that expects `find_package` result variables (e.g., `_FOUND`) "
|
||||
"to follow a certain pattern.")
|
||||
endif ()
|
||||
|
||||
if (${_NAME}_FIND_VERSION_RANGE AND NOT FPHSA_HANDLE_VERSION_RANGE)
|
||||
message(AUTHOR_WARNING
|
||||
"`find_package()` specify a version range but the module ${_NAME} does "
|
||||
"not support this capability. Only the lower endpoint of the range "
|
||||
"will be used.")
|
||||
endif()
|
||||
|
||||
# to propagate package name to FIND_PACKAGE_CHECK_VERSION
|
||||
set(_CMAKE_FPHSA_PACKAGE_NAME "${_NAME}")
|
||||
|
||||
# now that we collected all arguments, process them
|
||||
|
||||
if("x${FPHSA_FAIL_MESSAGE}" STREQUAL "xDEFAULT_MSG")
|
||||
set(FPHSA_FAIL_MESSAGE "Could NOT find ${_NAME}")
|
||||
endif()
|
||||
|
||||
if (FPHSA_REQUIRED_VARS)
|
||||
list(GET FPHSA_REQUIRED_VARS 0 _FIRST_REQUIRED_VAR)
|
||||
endif()
|
||||
|
||||
string(TOUPPER ${_NAME} _NAME_UPPER)
|
||||
string(TOLOWER ${_NAME} _NAME_LOWER)
|
||||
|
||||
if(FPHSA_FOUND_VAR)
|
||||
set(_FOUND_VAR_UPPER ${_NAME_UPPER}_FOUND)
|
||||
set(_FOUND_VAR_MIXED ${_NAME}_FOUND)
|
||||
if(FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_MIXED OR FPHSA_FOUND_VAR STREQUAL _FOUND_VAR_UPPER)
|
||||
set(_FOUND_VAR ${FPHSA_FOUND_VAR})
|
||||
else()
|
||||
message(FATAL_ERROR "The argument for FOUND_VAR is \"${FPHSA_FOUND_VAR}\", but only \"${_FOUND_VAR_MIXED}\" and \"${_FOUND_VAR_UPPER}\" are valid names.")
|
||||
endif()
|
||||
else()
|
||||
set(_FOUND_VAR ${_NAME_UPPER}_FOUND)
|
||||
endif()
|
||||
|
||||
# collect all variables which were not found, so they can be printed, so the
|
||||
# user knows better what went wrong (#6375)
|
||||
set(MISSING_VARS "")
|
||||
set(DETAILS "")
|
||||
# check if all passed variables are valid
|
||||
set(FPHSA_FOUND_${_NAME} TRUE)
|
||||
foreach(_CURRENT_VAR ${FPHSA_REQUIRED_VARS})
|
||||
if(NOT ${_CURRENT_VAR})
|
||||
set(FPHSA_FOUND_${_NAME} FALSE)
|
||||
string(APPEND MISSING_VARS " ${_CURRENT_VAR}")
|
||||
else()
|
||||
string(APPEND DETAILS "[${${_CURRENT_VAR}}]")
|
||||
endif()
|
||||
endforeach()
|
||||
if(FPHSA_FOUND_${_NAME})
|
||||
set(${_NAME}_FOUND TRUE)
|
||||
set(${_NAME_UPPER}_FOUND TRUE)
|
||||
else()
|
||||
set(${_NAME}_FOUND FALSE)
|
||||
set(${_NAME_UPPER}_FOUND FALSE)
|
||||
endif()
|
||||
|
||||
# component handling
|
||||
unset(FOUND_COMPONENTS_MSG)
|
||||
unset(MISSING_COMPONENTS_MSG)
|
||||
|
||||
if(FPHSA_HANDLE_COMPONENTS)
|
||||
foreach(comp ${${_NAME}_FIND_COMPONENTS})
|
||||
if(${_NAME}_${comp}_FOUND)
|
||||
|
||||
if(NOT DEFINED FOUND_COMPONENTS_MSG)
|
||||
set(FOUND_COMPONENTS_MSG "found components:")
|
||||
endif()
|
||||
string(APPEND FOUND_COMPONENTS_MSG " ${comp}")
|
||||
|
||||
else()
|
||||
|
||||
if(NOT DEFINED MISSING_COMPONENTS_MSG)
|
||||
set(MISSING_COMPONENTS_MSG "missing components:")
|
||||
endif()
|
||||
string(APPEND MISSING_COMPONENTS_MSG " ${comp}")
|
||||
|
||||
if(${_NAME}_FIND_REQUIRED_${comp})
|
||||
set(${_NAME}_FOUND FALSE)
|
||||
string(APPEND MISSING_VARS " ${comp}")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
endforeach()
|
||||
set(COMPONENT_MSG "${FOUND_COMPONENTS_MSG} ${MISSING_COMPONENTS_MSG}")
|
||||
string(APPEND DETAILS "[c${COMPONENT_MSG}]")
|
||||
endif()
|
||||
|
||||
# version handling:
|
||||
set(VERSION_MSG "")
|
||||
set(VERSION_OK TRUE)
|
||||
|
||||
# check that the version variable is not empty to avoid emitting a misleading
|
||||
# message (i.e. `Found unsuitable version ""`)
|
||||
if (DEFINED ${_NAME}_FIND_VERSION)
|
||||
if(DEFINED ${FPHSA_VERSION_VAR})
|
||||
if(NOT "${${FPHSA_VERSION_VAR}}" STREQUAL "")
|
||||
set(_FOUND_VERSION ${${FPHSA_VERSION_VAR}})
|
||||
if (FPHSA_HANDLE_VERSION_RANGE)
|
||||
set (FPCV_HANDLE_VERSION_RANGE HANDLE_VERSION_RANGE)
|
||||
else()
|
||||
set(FPCV_HANDLE_VERSION_RANGE NO_AUTHOR_WARNING_VERSION_RANGE)
|
||||
endif()
|
||||
find_package_check_version ("${_FOUND_VERSION}" VERSION_OK RESULT_MESSAGE_VARIABLE VERSION_MSG
|
||||
${FPCV_HANDLE_VERSION_RANGE})
|
||||
else()
|
||||
set(VERSION_OK FALSE)
|
||||
endif()
|
||||
endif()
|
||||
if("${${FPHSA_VERSION_VAR}}" STREQUAL "")
|
||||
# if the package was not found, but a version was given, add that to the output:
|
||||
if(${_NAME}_FIND_VERSION_EXACT)
|
||||
set(VERSION_MSG "(Required is exact version \"${${_NAME}_FIND_VERSION}\")")
|
||||
elseif (FPHSA_HANDLE_VERSION_RANGE AND ${_NAME}_FIND_VERSION_RANGE)
|
||||
set(VERSION_MSG "(Required is version range \"${${_NAME}_FIND_VERSION_RANGE}\")")
|
||||
else()
|
||||
set(VERSION_MSG "(Required is at least version \"${${_NAME}_FIND_VERSION}\")")
|
||||
endif()
|
||||
endif()
|
||||
else ()
|
||||
# Check with DEFINED as the found version may be 0.
|
||||
if(DEFINED ${FPHSA_VERSION_VAR})
|
||||
set(VERSION_MSG "(found version \"${${FPHSA_VERSION_VAR}}\")")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
if(VERSION_OK)
|
||||
string(APPEND DETAILS "[v${${FPHSA_VERSION_VAR}}(${${_NAME}_FIND_VERSION})]")
|
||||
else()
|
||||
set(${_NAME}_FOUND FALSE)
|
||||
endif()
|
||||
|
||||
|
||||
# print the result:
|
||||
if (${_NAME}_FOUND)
|
||||
FIND_PACKAGE_MESSAGE(${_NAME} "Found ${_NAME}: ${${_FIRST_REQUIRED_VAR}} ${VERSION_MSG} ${COMPONENT_MSG}" "${DETAILS}")
|
||||
else ()
|
||||
|
||||
if(FPHSA_CONFIG_MODE)
|
||||
_FPHSA_HANDLE_FAILURE_CONFIG_MODE()
|
||||
else()
|
||||
if(NOT VERSION_OK)
|
||||
set(RESULT_MSG)
|
||||
if (_FIRST_REQUIRED_VAR)
|
||||
string (APPEND RESULT_MSG "found ${${_FIRST_REQUIRED_VAR}}")
|
||||
endif()
|
||||
if (COMPONENT_MSG)
|
||||
if (RESULT_MSG)
|
||||
string (APPEND RESULT_MSG ", ")
|
||||
endif()
|
||||
string (APPEND RESULT_MSG "${FOUND_COMPONENTS_MSG}")
|
||||
endif()
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE}: ${VERSION_MSG} (${RESULT_MSG})")
|
||||
else()
|
||||
_FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} (missing:${MISSING_VARS}) ${VERSION_MSG}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endif ()
|
||||
|
||||
set(${_NAME}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE)
|
||||
set(${_NAME_UPPER}_FOUND ${${_NAME}_FOUND} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
cmake_policy(POP)
|
||||
48
cmake/modules/FindPackageMessage.cmake
Normal file
48
cmake/modules/FindPackageMessage.cmake
Normal file
@@ -0,0 +1,48 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
FindPackageMessage
|
||||
------------------
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
find_package_message(<name> "message for user" "find result details")
|
||||
|
||||
This function is intended to be used in FindXXX.cmake modules files.
|
||||
It will print a message once for each unique find result. This is
|
||||
useful for telling the user where a package was found. The first
|
||||
argument specifies the name (XXX) of the package. The second argument
|
||||
specifies the message to display. The third argument lists details
|
||||
about the find result so that if they change the message will be
|
||||
displayed again. The macro also obeys the QUIET argument to the
|
||||
find_package command.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
if(X11_FOUND)
|
||||
find_package_message(X11 "Found X11: ${X11_X11_LIB}"
|
||||
"[${X11_X11_LIB}][${X11_INCLUDE_DIR}]")
|
||||
else()
|
||||
...
|
||||
endif()
|
||||
#]=======================================================================]
|
||||
|
||||
function(find_package_message pkg msg details)
|
||||
# Avoid printing a message repeatedly for the same find result.
|
||||
if(NOT ${pkg}_FIND_QUIETLY)
|
||||
string(REPLACE "\n" "" details "${details}")
|
||||
set(DETAILS_VAR FIND_PACKAGE_MESSAGE_DETAILS_${pkg})
|
||||
if(NOT "${details}" STREQUAL "${${DETAILS_VAR}}")
|
||||
# The message has not yet been printed.
|
||||
message(STATUS "${msg}")
|
||||
|
||||
# Save the find details in the cache to avoid printing the same
|
||||
# message again.
|
||||
set("${DETAILS_VAR}" "${details}"
|
||||
CACHE INTERNAL "Details about finding ${pkg}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
@@ -46,7 +46,7 @@ endfunction()
|
||||
|
||||
include(BundleUtilities)
|
||||
set(BU_CHMOD_BUNDLE_ITEMS ON)
|
||||
fixup_bundle("${BUNDLE_PATH}" "${extra_libs}" "${extra_dirs}" IGNORE_ITEM "Python")
|
||||
fixup_bundle("${BUNDLE_PATH}" "${extra_libs}" "${extra_dirs}")
|
||||
|
||||
if (CODE_SIGN_CERTIFICATE_ID)
|
||||
# Hack around Apple Silicon signing bugs by copying the real app, signing it and moving it back.
|
||||
|
||||
5
dist/AppImageBuilder.yml
vendored
5
dist/AppImageBuilder.yml
vendored
@@ -107,7 +107,6 @@ AppDir:
|
||||
- /lib/x86_64-linux-gnu/libpcre2-8.so.0
|
||||
- /lib/x86_64-linux-gnu/libpixman-1.so.0
|
||||
- /lib/x86_64-linux-gnu/libpng16.so.16
|
||||
- /lib/x86_64-linux-gnu/libpython3.10.so.1.0
|
||||
- /lib/x86_64-linux-gnu/libsasl2.so.2
|
||||
- /lib/x86_64-linux-gnu/libsensors.so.5
|
||||
- /lib/x86_64-linux-gnu/libstdc++.so.6
|
||||
@@ -136,5 +135,5 @@ AppDir:
|
||||
- usr/share/doc/*/TODO.*
|
||||
AppImage:
|
||||
arch: x86_64
|
||||
update-information: gh-releases-zsync|WerWolv|ImHex|latest|imhex-*.AppImage.zsync
|
||||
file_name: imhex-{{VERSION}}.AppImage
|
||||
update-information: gh-releases-zsync|WerWolv|ImHex|latest|imhex-*-x86_64.AppImage.zsync
|
||||
file_name: imhex-{{VERSION}}-x86_64.AppImage
|
||||
|
||||
6
dist/Arch/PKGBUILD
vendored
6
dist/Arch/PKGBUILD
vendored
@@ -1,4 +1,4 @@
|
||||
# Maintainer: iTrooz_ <itrooz at protonmail dot com>
|
||||
# Maintainer: iTrooz_ <hey at itrooz dot fr>
|
||||
# Contributor: Morten Linderud <foxboron@archlinux.org>
|
||||
|
||||
pkgname=imhex-bin
|
||||
@@ -8,11 +8,11 @@ pkgdesc="A Hex Editor for Reverse Engineers, Programmers and people who value th
|
||||
arch=("x86_64")
|
||||
url="https://github.com/WerWolv/ImHex"
|
||||
license=('GPL2')
|
||||
depends=(glfw mbedtls python freetype2 libglvnd dbus xdg-desktop-portal curl fmt yara nlohmann-json)
|
||||
depends=(glfw mbedtls freetype2 libglvnd dbus xdg-desktop-portal curl fmt yara nlohmann-json)
|
||||
makedepends=(git)
|
||||
provides=(imhex)
|
||||
conflicts=(imhex)
|
||||
source=("$url/releases/download/v$pkgver/imhex-$pkgver-ArchLinux.pkg.tar.zst")
|
||||
source=("$url/releases/download/v$pkgver/imhex-$pkgver-ArchLinux-x86_64.pkg.tar.zst")
|
||||
md5sums=(SKIP)
|
||||
|
||||
package() {
|
||||
|
||||
2
dist/Brewfile
vendored
2
dist/Brewfile
vendored
@@ -2,9 +2,9 @@ brew "mbedtls"
|
||||
brew "nlohmann-json"
|
||||
brew "cmake"
|
||||
brew "ccache"
|
||||
brew "python3"
|
||||
brew "freetype2"
|
||||
brew "libmagic"
|
||||
brew "pkg-config"
|
||||
brew "gcc@12"
|
||||
brew "llvm"
|
||||
brew "glfw"
|
||||
|
||||
2
dist/DEBIAN/control.in
vendored
2
dist/DEBIAN/control.in
vendored
@@ -4,7 +4,7 @@ Section: editors
|
||||
Priority: optional
|
||||
Architecture: amd64
|
||||
License: GNU GPL-2
|
||||
Depends: libglfw3, libmagic1, libmbedtls14, libpython3.10, libfreetype6, libopengl0, libdbus-1-3, xdg-desktop-portal
|
||||
Depends: libglfw3, libmagic1, libmbedtls14, libfreetype6, libopengl0, libdbus-1-3, xdg-desktop-portal
|
||||
Maintainer: WerWolv <hey@werwolv.net>
|
||||
Description: ImHex Hex Editor
|
||||
A Hex Editor for Reverse Engineers, Programmers and
|
||||
|
||||
3
dist/Dockerfile
vendored
3
dist/Dockerfile
vendored
@@ -1,6 +1,6 @@
|
||||
FROM archlinux:latest
|
||||
|
||||
LABEL maintainer="hey@werwolv.net" = WerWolv
|
||||
LABEL maintainer="hey@werwolv.net WerWolv"
|
||||
|
||||
# Install dependencies
|
||||
RUN pacman -Syy --needed --noconfirm
|
||||
@@ -13,7 +13,6 @@ RUN pacman -S --needed --noconfirm \
|
||||
glfw-x11 \
|
||||
file \
|
||||
mbedtls \
|
||||
python3 \
|
||||
freetype2 \
|
||||
dbus \
|
||||
xdg-desktop-portal
|
||||
|
||||
7
dist/ImHex-9999.ebuild
vendored
7
dist/ImHex-9999.ebuild
vendored
@@ -9,20 +9,15 @@ HOMEPAGE="https://github.com/WerWolv/ImHex"
|
||||
SRC_URI=""
|
||||
EGIT_REPO_URI="https://github.com/WerWolv/ImHex.git"
|
||||
|
||||
PYTHON_COMPAT=( python3_{6,7,8,9} )
|
||||
|
||||
inherit git-r3 python-single-r1 cmake
|
||||
inherit git-r3 cmake
|
||||
|
||||
LICENSE="GPL-2"
|
||||
SLOT="0"
|
||||
KEYWORDS="~amd64"
|
||||
IUSE=""
|
||||
|
||||
REQUIRED_USE="${PYTHON_REQUIRED_USE}"
|
||||
|
||||
DEPEND=""
|
||||
RDEPEND="${DEPEND}
|
||||
${PYTHON_DEPS}
|
||||
media-libs/glfw
|
||||
sys-apps/file
|
||||
dev-libs/mbedtls
|
||||
|
||||
1
dist/get_deps_archlinux.sh
vendored
1
dist/get_deps_archlinux.sh
vendored
@@ -7,7 +7,6 @@ pacman -S $@ --needed \
|
||||
glfw \
|
||||
file \
|
||||
mbedtls \
|
||||
python3 \
|
||||
freetype2 \
|
||||
dbus \
|
||||
xdg-desktop-portal \
|
||||
|
||||
1
dist/get_deps_debian.sh
vendored
1
dist/get_deps_debian.sh
vendored
@@ -19,7 +19,6 @@ apt install -y \
|
||||
libglm-dev \
|
||||
libmagic-dev \
|
||||
libmbedtls-dev \
|
||||
python3-dev \
|
||||
libfreetype-dev \
|
||||
libdbus-1-dev \
|
||||
xdg-desktop-portal
|
||||
|
||||
3
dist/get_deps_fedora.sh
vendored
3
dist/get_deps_fedora.sh
vendored
@@ -10,5 +10,4 @@ dnf install -y \
|
||||
mesa-libGL-devel \
|
||||
glfw-devel \
|
||||
lld \
|
||||
mbedtls-devel \
|
||||
python3-devel
|
||||
mbedtls-devel
|
||||
1
dist/get_deps_msys2.sh
vendored
1
dist/get_deps_msys2.sh
vendored
@@ -9,6 +9,5 @@ pacman -S --needed --noconfirm \
|
||||
mingw-w64-x86_64-glfw \
|
||||
mingw-w64-x86_64-file \
|
||||
mingw-w64-x86_64-mbedtls \
|
||||
mingw-w64-x86_64-python \
|
||||
mingw-w64-x86_64-freetype \
|
||||
mingw-w64-x86_64-dlfcn
|
||||
|
||||
104
dist/langtool.py
vendored
Normal file
104
dist/langtool.py
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import json
|
||||
|
||||
DEFAULT_LANG = "en_US"
|
||||
INVALID_TRANSLATION = ""
|
||||
|
||||
|
||||
def handle_missing_key(command, lang_data, key, value):
|
||||
if command == "check":
|
||||
print(f"Error: Translation {lang_data['code']} is missing translation for key '{key}'")
|
||||
exit(2)
|
||||
elif command == "translate" or command == "create":
|
||||
print(f"Key \033[1m'{key}': '{value}'\033[0m is missing in translation '{lang_data['code']}'")
|
||||
new_value = input("Enter translation: ")
|
||||
lang_data["translations"][key] = new_value
|
||||
elif command == "update":
|
||||
lang_data["translations"][key] = INVALID_TRANSLATION
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 3:
|
||||
print(f"Usage: {Path(sys.argv[0]).name} <check|translate|update|create> <lang folder path> <language>")
|
||||
return 1
|
||||
|
||||
command = sys.argv[1]
|
||||
if command not in ["check", "translate", "update", "create"]:
|
||||
print(f"Unknown command: {command}")
|
||||
return 1
|
||||
|
||||
print(f"Using langtool in {command} mode")
|
||||
|
||||
lang_folder_path = Path(sys.argv[2])
|
||||
if not lang_folder_path.exists():
|
||||
print(f"Error: {lang_folder_path} does not exist")
|
||||
return 1
|
||||
|
||||
if not lang_folder_path.is_dir():
|
||||
print(f"Error: {lang_folder_path} is not a folder")
|
||||
return 1
|
||||
|
||||
lang = sys.argv[3] if len(sys.argv) > 3 else ""
|
||||
|
||||
print(f"Processing language files in {lang_folder_path}...")
|
||||
|
||||
default_lang_file_path = lang_folder_path / Path(DEFAULT_LANG + ".json")
|
||||
if not default_lang_file_path.exists():
|
||||
print(f"Error: Default language file {default_lang_file_path} does not exist")
|
||||
return 1
|
||||
|
||||
print(f"Using file '{default_lang_file_path.name}' as template language file")
|
||||
|
||||
with default_lang_file_path.open("r", encoding="utf-8") as default_lang_file:
|
||||
default_lang_data = json.load(default_lang_file)
|
||||
|
||||
if command == "create" and lang != "":
|
||||
lang_file_path = lang_folder_path / Path(lang + ".json")
|
||||
if lang_file_path.exists():
|
||||
print(f"Error: Language file {lang_file_path} already exists")
|
||||
return 1
|
||||
|
||||
print(f"Creating new language file '{lang_file_path.name}'")
|
||||
|
||||
with lang_file_path.open("w", encoding="utf-8") as new_lang_file:
|
||||
new_lang_data = {
|
||||
"code": lang,
|
||||
"language": input("Enter language: "),
|
||||
"country": input("Enter country: "),
|
||||
"translations": {}
|
||||
}
|
||||
json.dump(new_lang_data, new_lang_file, indent=4, ensure_ascii=False)
|
||||
|
||||
for additional_lang_file_path in lang_folder_path.glob("*.json"):
|
||||
if not lang == "" and not additional_lang_file_path.stem == lang:
|
||||
continue
|
||||
|
||||
if additional_lang_file_path.name.startswith(DEFAULT_LANG):
|
||||
continue
|
||||
|
||||
print(f"\nProcessing file '{additional_lang_file_path.name}'\n----------------------------\n")
|
||||
|
||||
with additional_lang_file_path.open("r+", encoding="utf-8") as additional_lang_file:
|
||||
additional_lang_data = json.load(additional_lang_file)
|
||||
|
||||
for key, value in default_lang_data["translations"].items():
|
||||
if key not in additional_lang_data["translations"] or additional_lang_data["translations"][key] == INVALID_TRANSLATION:
|
||||
handle_missing_key(command, additional_lang_data, key, value)
|
||||
|
||||
keys_to_remove = []
|
||||
for key, value in additional_lang_data["translations"].items():
|
||||
if key not in default_lang_data["translations"]:
|
||||
keys_to_remove.append(key)
|
||||
|
||||
for key in keys_to_remove:
|
||||
additional_lang_data["translations"].pop(key)
|
||||
print(f"Removed unused key '{key}' from translation '{additional_lang_data['code']}'")
|
||||
|
||||
additional_lang_file.seek(0)
|
||||
additional_lang_file.truncate()
|
||||
json.dump(additional_lang_data, additional_lang_file, indent=4, sort_keys=True, ensure_ascii=False)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
||||
2
dist/msys2/PKGBUILD
vendored
2
dist/msys2/PKGBUILD
vendored
@@ -7,7 +7,6 @@ pkgdesc="${_realname}: a Hex Editor for Reverse Engineers, Programmers and peopl
|
||||
arch=('any')
|
||||
url="https://github.com/WerWolv/ImHex"
|
||||
license=('GPLv2')
|
||||
depends=("${MINGW_PACKAGE_PREFIX}-python")
|
||||
makedepends=("${MINGW_PACKAGE_PREFIX}-gcc"
|
||||
"${MINGW_PACKAGE_PREFIX}-lld"
|
||||
"${MINGW_PACKAGE_PREFIX}-cmake"
|
||||
@@ -17,7 +16,6 @@ makedepends=("${MINGW_PACKAGE_PREFIX}-gcc"
|
||||
"${MINGW_PACKAGE_PREFIX}-file"
|
||||
"${MINGW_PACKAGE_PREFIX}-mbedtls"
|
||||
"${MINGW_PACKAGE_PREFIX}-polly"
|
||||
"${MINGW_PACKAGE_PREFIX}-python"
|
||||
"${MINGW_PACKAGE_PREFIX}-freetype")
|
||||
|
||||
source=()
|
||||
|
||||
115
dist/rpm/imhex.spec
vendored
115
dist/rpm/imhex.spec
vendored
@@ -1,13 +1,14 @@
|
||||
# ftbfs without this
|
||||
%global _lto_cflags %{nil}
|
||||
|
||||
Name: imhex
|
||||
Version: %{_version}
|
||||
Version: 1.26.2
|
||||
Release: 0%{?dist}
|
||||
Summary: A hex editor for reverse engineers and programmers
|
||||
|
||||
License: GPL-2.0-only
|
||||
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
|
||||
# see license dir for full breakdown
|
||||
URL: https://imhex.werwolv.net/
|
||||
# We need the archive with deps bundled
|
||||
Source0: https://github.com/WerWolv/%{name}/releases/download/v%{version}/Full.Sources.tar.gz#/%{name}-%{version}.tar.gz
|
||||
|
||||
BuildRequires: cmake
|
||||
BuildRequires: desktop-file-utils
|
||||
@@ -16,17 +17,36 @@ BuildRequires: file-devel
|
||||
BuildRequires: freetype-devel
|
||||
BuildRequires: fmt-devel
|
||||
BuildRequires: gcc-c++
|
||||
BuildRequires: mesa-libGL-devel
|
||||
BuildRequires: libappstream-glib
|
||||
BuildRequires: libglvnd-devel
|
||||
BuildRequires: glfw-devel
|
||||
BuildRequires: json-devel
|
||||
BuildRequires: libcurl-devel
|
||||
BuildRequires: llvm-devel
|
||||
BuildRequires: mbedtls-devel
|
||||
BuildRequires: python3-devel
|
||||
%if 0%{?fedora} >= 37
|
||||
BuildRequires: yara-devel
|
||||
BuildRequires: nativefiledialog-extended-devel
|
||||
%if 0%{?rhel}
|
||||
BuildRequires: gcc-toolset-12
|
||||
%endif
|
||||
|
||||
Provides: bundled(gnulib)
|
||||
Provides: bundled(capstone) = 5.0-rc2
|
||||
Provides: bundled(imgui)
|
||||
Provides: bundled(libromfs)
|
||||
Provides: bundled(microtar)
|
||||
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)
|
||||
|
||||
# ftbfs on these arches. armv7hl might compile when capstone 5.x
|
||||
# is released upstream and we can build against it
|
||||
# [7:02 PM] WerWolv: We're not supporting 32 bit anyways soooo
|
||||
# [11:38 AM] WerWolv: Officially supported are x86_64 and aarch64
|
||||
ExclusiveArch: x86_64 %{arm64} ppc64le
|
||||
|
||||
|
||||
%description
|
||||
ImHex is a Hex Editor, a tool to display, decode and analyze binary data to
|
||||
@@ -41,26 +61,26 @@ same time ImHex is completely free and open source under the GPLv2 language.
|
||||
|
||||
|
||||
%prep
|
||||
# don't use the setup macro since we're pulling from git
|
||||
cp -r %{_src_path}/* %{_builddir}/
|
||||
|
||||
%autosetup -n ImHex
|
||||
# remove bundled libs we aren't using
|
||||
rm -rf lib/external/{curl,fmt,llvm,nlohmann_json,yara}
|
||||
|
||||
%build
|
||||
%cmake \
|
||||
-DCMAKE_BUILD_TYPE=%{_build_type} \
|
||||
-D USE_SYSTEM_NLOHMANN_JSON=ON \
|
||||
-D USE_SYSTEM_FMT=ON \
|
||||
-D USE_SYSTEM_CURL=ON \
|
||||
-D USE_SYSTEM_LLVM=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-D IMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
%if 0%{?fedora} >= 37
|
||||
-D USE_SYSTEM_YARA=ON \
|
||||
# if fedora <= 36 get updated to yara 4.2.x then they should \
|
||||
# be able to build against system libs \
|
||||
# https://bugzilla.redhat.com/show_bug.cgi?id=2112508 \
|
||||
%if 0%{?rhel}
|
||||
. /opt/rh/gcc-toolset-12/enable
|
||||
%set_build_flags
|
||||
CXXFLAGS+=" -std=gnu++2b"
|
||||
%endif
|
||||
%cmake \
|
||||
-D CMAKE_BUILD_TYPE=Release \
|
||||
-D IMHEX_STRIP_RELEASE=OFF \
|
||||
-D IMHEX_OFFLINE_BUILD=ON \
|
||||
-D USE_SYSTEM_NLOHMANN_JSON=ON \
|
||||
-D USE_SYSTEM_FMT=ON \
|
||||
-D USE_SYSTEM_CURL=ON \
|
||||
-D USE_SYSTEM_LLVM=ON \
|
||||
-D USE_SYSTEM_YARA=ON \
|
||||
-D USE_SYSTEM_NFD=ON \
|
||||
# when capstone >= 5.x is released we should be able to build against \
|
||||
# system libs of it \
|
||||
# -D USE_SYSTEM_CAPSTONE=ON
|
||||
@@ -68,23 +88,46 @@ cp -r %{_src_path}/* %{_builddir}/
|
||||
%cmake_build
|
||||
|
||||
|
||||
%check
|
||||
%if 0%{?rhel}
|
||||
. /opt/rh/gcc-toolset-12/enable
|
||||
%set_build_flags
|
||||
CXXFLAGS+=" -std=gnu++2b"
|
||||
%endif
|
||||
# build binaries required for tests
|
||||
%cmake_build --target unit_tests
|
||||
%ctest --exclude-regex '(Helpers/StoreAPI|Helpers/TipsAPI|Helpers/ContentAPI)'
|
||||
# Helpers/*API exclude tests that require network access
|
||||
|
||||
|
||||
%install
|
||||
%cmake_install
|
||||
desktop-file-validate %{buildroot}%{_datadir}/applications/imhex.desktop
|
||||
desktop-file-validate %{buildroot}%{_datadir}/applications/%{name}.desktop
|
||||
|
||||
# this is a symlink for the old appdata name that we don't need
|
||||
rm -f %{buildroot}%{_metainfodir}/net.werwolv.%{name}.appdata.xml
|
||||
|
||||
# AppData
|
||||
appstream-util validate-relax --nonet %{buildroot}%{_metainfodir}/net.werwolv.%{name}.metainfo.xml
|
||||
|
||||
# install licenses
|
||||
cp -a lib/external/nativefiledialog/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/nativefiledialog-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/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
|
||||
|
||||
|
||||
%files
|
||||
%dir %{_datadir}/licenses/imhex
|
||||
%license %{_datadir}/licenses/imhex/LICENSE
|
||||
%license %{_datadir}/licenses/%{name}/
|
||||
%doc README.md
|
||||
%{_bindir}/imhex
|
||||
%dir %{_datadir}/imhex
|
||||
%{_datadir}/imhex/*
|
||||
%{_datadir}/pixmaps/imhex.png
|
||||
%{_datadir}/applications/imhex.desktop
|
||||
%{_prefix}/lib64/libimhex.so.%{_version}
|
||||
%{_prefix}/lib64/imhex/plugins/*
|
||||
%{_metainfodir}/net.werwolv.imhex.metainfo.xml
|
||||
%{_metainfodir}/net.werwolv.imhex.appdata.xml
|
||||
%{_datadir}/pixmaps/%{name}.png
|
||||
%{_datadir}/applications/%{name}.desktop
|
||||
%{_libdir}/libimhex.so*
|
||||
%{_libdir}/%{name}/
|
||||
%{_metainfodir}/net.werwolv.%{name}.metainfo.xml
|
||||
|
||||
|
||||
%changelog
|
||||
|
||||
2
lib/external/curl
vendored
2
lib/external/curl
vendored
Submodule lib/external/curl updated: 93d092867f...b16d1fa8ee
14
lib/external/imgui/CMakeLists.txt
vendored
14
lib/external/imgui/CMakeLists.txt
vendored
@@ -8,10 +8,6 @@ find_package(Freetype REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
pkg_search_module(GLFW REQUIRED glfw3)
|
||||
|
||||
if (UNIX)
|
||||
find_package(OpenGL REQUIRED)
|
||||
endif ()
|
||||
|
||||
add_library(imgui OBJECT
|
||||
source/imgui.cpp
|
||||
source/imgui_demo.cpp
|
||||
@@ -39,12 +35,8 @@ add_library(imgui OBJECT
|
||||
|
||||
add_compile_definitions(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||
|
||||
target_include_directories(imgui PUBLIC include ${FREETYPE_INCLUDE_DIRS} ${GLFW_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})
|
||||
target_link_directories(imgui PUBLIC ${GLFW_LIBRARY_DIRS} ${OpenGL_LIBRARY_DIRS})
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(imgui PUBLIC Freetype::Freetype glfw3 opengl32.lib)
|
||||
elseif (UNIX)
|
||||
target_link_libraries(imgui PUBLIC Freetype::Freetype glfw OpenGL::GL)
|
||||
endif()
|
||||
target_link_libraries(imgui PUBLIC Freetype::Freetype ${GLFW_LIBRARIES} ${OPENGL_LIBRARIES})
|
||||
|
||||
6
lib/external/imgui/include/TextEditor.h
vendored
6
lib/external/imgui/include/TextEditor.h
vendored
@@ -188,8 +188,8 @@ public:
|
||||
void SetLanguageDefinition(const LanguageDefinition& aLanguageDef);
|
||||
const LanguageDefinition& GetLanguageDefinition() const { return mLanguageDefinition; }
|
||||
|
||||
const Palette& GetPalette() const { return mPaletteBase; }
|
||||
void SetPalette(const Palette& aValue);
|
||||
static const Palette& GetPalette() { return sPaletteBase; }
|
||||
static void SetPalette(const Palette& aValue);
|
||||
|
||||
void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; }
|
||||
void SetBreakpoints(const Breakpoints& aMarkers) { mBreakpoints = aMarkers; }
|
||||
@@ -372,7 +372,7 @@ private:
|
||||
bool mIgnoreImGuiChild;
|
||||
bool mShowWhitespaces;
|
||||
|
||||
Palette mPaletteBase;
|
||||
static Palette sPaletteBase;
|
||||
Palette mPalette;
|
||||
LanguageDefinition mLanguageDefinition;
|
||||
RegexList mRegexList;
|
||||
|
||||
6767
lib/external/imgui/include/imgui_impl_opengl3_loader.h
vendored
6767
lib/external/imgui/include/imgui_impl_opengl3_loader.h
vendored
File diff suppressed because it is too large
Load Diff
40
lib/external/imgui/source/TextEditor.cpp
vendored
40
lib/external/imgui/source/TextEditor.cpp
vendored
@@ -21,9 +21,10 @@ bool equals(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Bi
|
||||
return first1 == last1 && first2 == last2;
|
||||
}
|
||||
|
||||
TextEditor::Palette TextEditor::sPaletteBase = TextEditor::GetDarkPalette();
|
||||
|
||||
TextEditor::TextEditor()
|
||||
: mLineSpacing(1.0f), mUndoIndex(0), mTabSize(4), mOverwrite(false), mReadOnly(false), mWithinRender(false), mScrollToCursor(false), mScrollToTop(false), mTextChanged(false), mColorizerEnabled(true), mTextStart(20.0f), mLeftMargin(10), mCursorPositionChanged(false), mColorRangeMin(0), mColorRangeMax(0), mSelectionMode(SelectionMode::Normal), mCheckComments(true), mLastClick(-1.0f), mHandleKeyboardInputs(true), mHandleMouseInputs(true), mIgnoreImGuiChild(false), mShowWhitespaces(true), mStartTime(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()) {
|
||||
SetPalette(GetDarkPalette());
|
||||
SetLanguageDefinition(LanguageDefinition::HLSL());
|
||||
mLines.push_back(Line());
|
||||
}
|
||||
@@ -42,7 +43,7 @@ void TextEditor::SetLanguageDefinition(const LanguageDefinition &aLanguageDef) {
|
||||
}
|
||||
|
||||
void TextEditor::SetPalette(const Palette &aValue) {
|
||||
mPaletteBase = aValue;
|
||||
sPaletteBase = aValue;
|
||||
}
|
||||
|
||||
std::string TextEditor::GetText(const Coordinates &aStart, const Coordinates &aEnd) const {
|
||||
@@ -313,7 +314,7 @@ TextEditor::Coordinates TextEditor::FindWordStart(const Coordinates &aFrom) cons
|
||||
while (cindex > 0 && isspace(line[cindex].mChar))
|
||||
--cindex;
|
||||
|
||||
auto cstart = (PaletteIndex)line[cindex].mColorIndex;
|
||||
auto cstart = line[cindex].mChar;
|
||||
while (cindex > 0) {
|
||||
auto c = line[cindex].mChar;
|
||||
if ((c & 0xC0) != 0x80) // not UTF code sequence 10xxxxxx
|
||||
@@ -322,8 +323,15 @@ TextEditor::Coordinates TextEditor::FindWordStart(const Coordinates &aFrom) cons
|
||||
cindex++;
|
||||
break;
|
||||
}
|
||||
if (cstart != (PaletteIndex)line[size_t(cindex - 1)].mColorIndex)
|
||||
|
||||
if (isalnum(cstart) || cstart == '_') {
|
||||
if (!isalnum(c) && c != '_') {
|
||||
cindex++;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
--cindex;
|
||||
}
|
||||
@@ -631,10 +639,24 @@ void TextEditor::HandleKeyboardInputs() {
|
||||
MoveEnd(shift);
|
||||
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_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)))
|
||||
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)))
|
||||
mOverwrite ^= true;
|
||||
mOverwrite = !mOverwrite;
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
|
||||
Copy();
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C)))
|
||||
@@ -740,7 +762,7 @@ void TextEditor::Render() {
|
||||
|
||||
/* Update palette with the current alpha from style */
|
||||
for (int i = 0; i < (int)PaletteIndex::Max; ++i) {
|
||||
auto color = ImGui::ColorConvertU32ToFloat4(mPaletteBase[i]);
|
||||
auto color = ImGui::ColorConvertU32ToFloat4(sPaletteBase[i]);
|
||||
color.w *= ImGui::GetStyle().Alpha;
|
||||
mPalette[i] = ImGui::ColorConvertFloat4ToU32(color);
|
||||
}
|
||||
@@ -2040,7 +2062,9 @@ void TextEditor::ColorizeInternal() {
|
||||
}
|
||||
}
|
||||
}
|
||||
line[currentIndex].mPreprocessor = withinPreproc;
|
||||
if (currentIndex < line.size())
|
||||
line[currentIndex].mPreprocessor = withinPreproc;
|
||||
|
||||
currentIndex += UTF8CharLength(c);
|
||||
if (currentIndex >= (int)line.size()) {
|
||||
currentIndex = 0;
|
||||
@@ -2120,7 +2144,7 @@ void TextEditor::EnsureCursorVisible() {
|
||||
if (len + mTextStart < left + 4)
|
||||
ImGui::SetScrollX(std::max(0.0f, len + mTextStart - 4));
|
||||
if (len + mTextStart > right - 4)
|
||||
ImGui::SetScrollX(std::max(0.0f, len + mTextStart + 4 - width));
|
||||
ImGui::SetScrollX(std::max(0.0f, len + mTextStart + 4 - width + mCharAdvance.x * 2));
|
||||
}
|
||||
|
||||
int TextEditor::GetPageSize() const {
|
||||
|
||||
@@ -820,7 +820,12 @@ static void ImGui_ImplGlfw_UpdateMonitors()
|
||||
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
||||
int monitors_count = 0;
|
||||
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++)
|
||||
{
|
||||
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;
|
||||
items[n].Width = width_rounded;
|
||||
}
|
||||
while (width_excess > 0.0f)
|
||||
for (int n = 0; n < count; n++)
|
||||
while (width_excess >= 1.0f)
|
||||
for (int n = 0; n < count && width_excess >= 1.0f; n++)
|
||||
if (items[n].Width + 1.0f <= items[n].InitialWidth)
|
||||
{
|
||||
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
|
||||
|
||||
// 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_offset = (central_section_is_visible ? sections[0].TabCount + sections[2].TabCount : 0);
|
||||
|
||||
2
lib/external/libromfs
vendored
2
lib/external/libromfs
vendored
Submodule lib/external/libromfs updated: 53a6bf5b7a...40cd303e92
1
lib/external/libwolv
vendored
Submodule
1
lib/external/libwolv
vendored
Submodule
Submodule lib/external/libwolv added at 34d36a2f33
12
lib/external/miniaudio/CMakeLists.txt
vendored
Normal file
12
lib/external/miniaudio/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(miniaudio)
|
||||
|
||||
add_library(miniaudio STATIC
|
||||
source/miniaudio.c
|
||||
)
|
||||
|
||||
target_include_directories(miniaudio PUBLIC include)
|
||||
|
||||
if (APPLE)
|
||||
set_source_files_properties(source/miniaudio.c PROPERTIES LANGUAGE OBJC)
|
||||
endif ()
|
||||
47
lib/external/miniaudio/LICENSE
vendored
Normal file
47
lib/external/miniaudio/LICENSE
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
This software is available as a choice of the following licenses. Choose
|
||||
whichever you prefer.
|
||||
|
||||
===============================================================================
|
||||
ALTERNATIVE 1 - Public Domain (www.unlicense.org)
|
||||
===============================================================================
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
|
||||
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 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.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
===============================================================================
|
||||
ALTERNATIVE 2 - MIT No Attribution
|
||||
===============================================================================
|
||||
Copyright 2020 David Reid
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
7509
lib/external/miniaudio/include/miniaudio.h
vendored
Normal file
7509
lib/external/miniaudio/include/miniaudio.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
80169
lib/external/miniaudio/source/miniaudio.c
vendored
Normal file
80169
lib/external/miniaudio/source/miniaudio.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
lib/external/nativefiledialog
vendored
2
lib/external/nativefiledialog
vendored
Submodule lib/external/nativefiledialog updated: d4df2b6ad5...7909f55d91
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
Submodule lib/external/pattern_language updated: 239b26b573...c5e7c9e624
36
lib/external/yara/CMakeLists.txt
vendored
36
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/utils.h
|
||||
${LIBYARA_SOURCE_PATH}/crypto.h
|
||||
${LIBYARA_SOURCE_PATH}/tlshc/tlsh_impl.h
|
||||
${LIBYARA_SOURCE_PATH}/tlshc/tlsh_util.h
|
||||
)
|
||||
|
||||
set(LIBYARA_SOURCE
|
||||
@@ -66,6 +68,7 @@ set(LIBYARA_SOURCE
|
||||
${LIBYARA_SOURCE_PATH}/scan.c
|
||||
${LIBYARA_SOURCE_PATH}/scanner.c
|
||||
${LIBYARA_SOURCE_PATH}/sizedstr.c
|
||||
${LIBYARA_SOURCE_PATH}/simple_str.c
|
||||
${LIBYARA_SOURCE_PATH}/stack.c
|
||||
${LIBYARA_SOURCE_PATH}/stopwatch.c
|
||||
${LIBYARA_SOURCE_PATH}/strutils.c
|
||||
@@ -78,6 +81,9 @@ set(LIBYARA_SOURCE
|
||||
${LIBYARA_SOURCE_PATH}/hex_grammar.c
|
||||
${LIBYARA_SOURCE_PATH}/re_grammar.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
|
||||
@@ -91,27 +97,29 @@ set(LIBYARA_MODULES
|
||||
${LIBYARA_SOURCE_PATH}/modules/math/math.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/pe/pe.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/time/time.c
|
||||
)
|
||||
|
||||
# Add mbedtls crypto wrappers
|
||||
add_compile_definitions("HAVE_MBEDTLS")
|
||||
|
||||
add_compile_definitions("USE_NO_PROC")
|
||||
|
||||
add_compile_definitions("HASH_MODULE")
|
||||
add_compile_definitions("DOTNET_MODULE")
|
||||
add_compile_definitions("MAGIC_MODULE")
|
||||
add_compile_definitions("MACHO_MODULE")
|
||||
add_compile_definitions("DEX_MODULE")
|
||||
|
||||
find_package(mbedTLS 2.26.0 REQUIRED)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-shift-count-overflow")
|
||||
add_library(libyara STATIC ${LIBYARA_SOURCE} ${LIBYARA_INCLUDES} ${LIBYARA_MODULES})
|
||||
set_property(TARGET libyara PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
# Add mbedtls crypto wrappers
|
||||
target_compile_definitions(libyara PRIVATE HAVE_MBEDTLS)
|
||||
|
||||
target_compile_definitions(libyara PRIVATE USE_NO_PROC BUCKETS_256 CHECKSUM_3B)
|
||||
|
||||
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(
|
||||
libyara
|
||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/yara> $<BUILD_INTERFACE:${LIBYARA_SOURCE_PATH}/include> $<INSTALL_INTERFACE:include>
|
||||
@@ -127,6 +135,6 @@ else ()
|
||||
endif ()
|
||||
|
||||
include(GNUInstallDirs)
|
||||
configure_file(${LIBYARA_SOURCE_PATH}/yara.pc.in
|
||||
${LIBYARA_SOURCE_PATH}/yara.pc @ONLY)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/yara/yara.pc.in
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/yara/yara.pc @ONLY)
|
||||
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
@@ -1,115 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(libimhex)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/imgui ${CMAKE_CURRENT_BINARY_DIR}/external/imgui)
|
||||
set_target_properties(imgui PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/microtar ${CMAKE_CURRENT_BINARY_DIR}/external/microtar EXCLUDE_FROM_ALL)
|
||||
set_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(LIBROMFS_RESOURCE_LOCATION ${IMHEX_BASE_FOLDER}/resources/romfs)
|
||||
set(LIBROMFS_PROJECT_NAME imhex)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/external/libromfs EXCLUDE_FROM_ALL)
|
||||
set_target_properties(${LIBROMFS_LIBRARY} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/intervaltree ${CMAKE_CURRENT_BINARY_DIR}/external/intervaltree EXCLUDE_FROM_ALL)
|
||||
set_target_properties(intervaltree PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(XDGPP_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../external/xdgpp")
|
||||
set(CURL_USE_MBEDTLS ON)
|
||||
set(BUILD_CURL_EXE OFF)
|
||||
set(FPHSA_NAME_MISMATCHED ON CACHE BOOL "")
|
||||
|
||||
# Find packages
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
if (NOT USE_SYSTEM_NFD)
|
||||
set(NFD_PORTAL ON CACHE BOOL "Use Portals for Linux file dialogs" FORCE)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/nativefiledialog ${CMAKE_CURRENT_BINARY_DIR}/external/nativefiledialog EXCLUDE_FROM_ALL)
|
||||
set_target_properties(nfd PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(NFD_LIBRARIES nfd)
|
||||
else()
|
||||
find_package(nfd)
|
||||
set(NFD_LIBRARIES nfd)
|
||||
endif()
|
||||
|
||||
if(NOT USE_SYSTEM_NLOHMANN_JSON)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/nlohmann_json ${CMAKE_CURRENT_BINARY_DIR}/external/nlohmann_json EXCLUDE_FROM_ALL)
|
||||
set(NLOHMANN_JSON_LIBRARIES nlohmann_json)
|
||||
else()
|
||||
find_package(nlohmann_json 3.10.2 REQUIRED)
|
||||
set(NLOHMANN_JSON_LIBRARIES nlohmann_json::nlohmann_json)
|
||||
endif()
|
||||
|
||||
if(NOT USE_SYSTEM_FMT)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/fmt ${CMAKE_CURRENT_BINARY_DIR}/external/fmt EXCLUDE_FROM_ALL)
|
||||
set_target_properties(fmt PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(FMT_LIBRARIES fmt-header-only)
|
||||
else()
|
||||
find_package(fmt 8.0.0 REQUIRED)
|
||||
set(FMT_LIBRARIES fmt::fmt)
|
||||
endif()
|
||||
|
||||
if(NOT USE_SYSTEM_CURL)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/curl ${CMAKE_CURRENT_BINARY_DIR}/external/curl EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libcurl PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(LIBCURL_LIBRARIES libcurl)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBCURL REQUIRED IMPORTED_TARGET libcurl>=7.76.1)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_LLVM)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/llvm-demangle ${CMAKE_CURRENT_BINARY_DIR}/external/llvm-demangle EXCLUDE_FROM_ALL)
|
||||
set_target_properties(LLVMDemangle PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
else()
|
||||
find_package(LLVM REQUIRED Demangle)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_YARA)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/yara ${CMAKE_CURRENT_BINARY_DIR}/external/yara EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libyara PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(YARA_LIBRARIES libyara)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(YARA REQUIRED IMPORTED_TARGET yara)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_CAPSTONE)
|
||||
set(CAPSTONE_BUILD_STATIC_RUNTIME OFF CACHE BOOL "Disable shared library building")
|
||||
set(CAPSTONE_BUILD_SHARED OFF CACHE BOOL "Disable shared library building")
|
||||
set(CAPSTONE_BUILD_TESTS OFF CACHE BOOL "Disable tests")
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/capstone ${CMAKE_CURRENT_BINARY_DIR}/external/capstone EXCLUDE_FROM_ALL)
|
||||
set_target_properties(capstone PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(CAPSTONE_LIBRARIES "capstone")
|
||||
set(CAPSTONE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../external/capstone/include)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_search_module(CAPSTONE 4.0.2 REQUIRED capstone)
|
||||
endif()
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/pattern_language ${CMAKE_CURRENT_BINARY_DIR}/external/pattern_language EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libpl PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
find_package(mbedTLS 2.26.0 REQUIRED)
|
||||
configurePython()
|
||||
|
||||
pkg_search_module(MAGIC libmagic>=5.39)
|
||||
if(NOT MAGIC_FOUND)
|
||||
find_library(MAGIC 5.39 magic REQUIRED)
|
||||
else()
|
||||
set(MAGIC_INCLUDE_DIRS ${MAGIC_INCLUDEDIR})
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
|
||||
if (WIN32)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--export-all-symbols")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
set(LIBIMHEX_SOURCES
|
||||
@@ -121,6 +13,7 @@ set(LIBIMHEX_SOURCES
|
||||
source/api/plugin_manager.cpp
|
||||
source/api/localization.cpp
|
||||
source/api/project_file_manager.cpp
|
||||
source/api/theme_manager.cpp
|
||||
|
||||
source/data_processor/attribute.cpp
|
||||
source/data_processor/link.cpp
|
||||
@@ -130,14 +23,13 @@ set(LIBIMHEX_SOURCES
|
||||
source/helpers/fs.cpp
|
||||
source/helpers/magic.cpp
|
||||
source/helpers/crypto.cpp
|
||||
source/helpers/net.cpp
|
||||
source/helpers/file.cpp
|
||||
source/helpers/socket.cpp
|
||||
source/helpers/http_requests.cpp
|
||||
source/helpers/opengl.cpp
|
||||
source/helpers/patches.cpp
|
||||
source/helpers/encoding_file.cpp
|
||||
source/helpers/logger.cpp
|
||||
source/helpers/stacktrace.cpp
|
||||
source/helpers/tar.cpp
|
||||
source/helpers/types.cpp
|
||||
|
||||
source/providers/provider.cpp
|
||||
|
||||
@@ -155,9 +47,7 @@ if (APPLE)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES}
|
||||
source/helpers/fs_macos.m
|
||||
source/helpers/utils_macos.m)
|
||||
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/utils_macos.m)
|
||||
endif ()
|
||||
|
||||
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||
@@ -166,13 +56,16 @@ add_library(libimhex SHARED ${LIBIMHEX_SOURCES})
|
||||
set_target_properties(libimhex PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
setupCompilerWarnings(libimhex)
|
||||
|
||||
target_include_directories(libimhex PUBLIC include ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${Python_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${YARA_INCLUDE_DIRS})
|
||||
|
||||
target_include_directories(libimhex PUBLIC include ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${YARA_INCLUDE_DIRS} ${LIBBACKTRACE_INCLUDE_DIRS})
|
||||
target_link_directories(libimhex PUBLIC ${MBEDTLS_LIBRARY_DIR} ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS})
|
||||
|
||||
if (APPLE)
|
||||
if (WIN32)
|
||||
target_link_options(libimhex PRIVATE -Wl,--export-all-symbols)
|
||||
elseif (APPLE)
|
||||
find_library(FOUNDATION NAMES Foundation)
|
||||
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
|
||||
endif ()
|
||||
|
||||
target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libpl intervaltree)
|
||||
target_link_libraries(libimhex PRIVATE libromfs-imhex)
|
||||
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} libwolv-utils libwolv-io libwolv-hash)
|
||||
@@ -9,9 +9,10 @@
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
@@ -40,78 +41,197 @@ namespace hex {
|
||||
|
||||
/* Settings Registry. Allows adding of new entries into the ImHex preferences window. */
|
||||
namespace Settings {
|
||||
using Callback = std::function<bool(const std::string &, nlohmann::json &)>;
|
||||
|
||||
struct Entry {
|
||||
std::string name;
|
||||
bool requiresRestart;
|
||||
Callback callback;
|
||||
};
|
||||
namespace impl {
|
||||
using Callback = std::function<bool(const std::string &, nlohmann::json &)>;
|
||||
|
||||
struct Category {
|
||||
std::string name;
|
||||
size_t slot = 0;
|
||||
struct Entry {
|
||||
std::string name;
|
||||
bool requiresRestart;
|
||||
Callback callback;
|
||||
};
|
||||
|
||||
bool operator<(const Category &other) const {
|
||||
return name < other.name;
|
||||
}
|
||||
struct Category {
|
||||
std::string name;
|
||||
size_t slot = 0;
|
||||
|
||||
explicit operator const std::string &() const {
|
||||
return name;
|
||||
}
|
||||
};
|
||||
bool operator<(const Category &other) const {
|
||||
return name < other.name;
|
||||
}
|
||||
|
||||
void load();
|
||||
void store();
|
||||
void clear();
|
||||
explicit operator const std::string &() const {
|
||||
return name;
|
||||
}
|
||||
};
|
||||
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const Callback &callback, bool requiresRestart = false);
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback, bool requiresRestart = false);
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const Callback &callback, bool requiresRestart = false);
|
||||
void load();
|
||||
void store();
|
||||
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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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::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 */
|
||||
namespace CommandPaletteCommands {
|
||||
|
||||
enum class Type : u32
|
||||
{
|
||||
enum class Type : u32 {
|
||||
SymbolCommand,
|
||||
KeywordCommand
|
||||
};
|
||||
|
||||
using DisplayCallback = std::function<std::string(std::string)>;
|
||||
using ExecuteCallback = std::function<void(std::string)>;
|
||||
namespace impl {
|
||||
|
||||
struct Entry {
|
||||
Type type;
|
||||
std::string command;
|
||||
std::string unlocalizedDescription;
|
||||
DisplayCallback displayCallback;
|
||||
ExecuteCallback executeCallback;
|
||||
};
|
||||
struct QueryResult {
|
||||
std::string name;
|
||||
std::function<void(std::string)> callback;
|
||||
};
|
||||
|
||||
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(
|
||||
Type type,
|
||||
const std::string &command,
|
||||
const std::string &unlocalizedDescription,
|
||||
const DisplayCallback &displayCallback,
|
||||
const ExecuteCallback &executeCallback = [](auto) {});
|
||||
std::vector<Entry> &getEntries();
|
||||
const impl::DisplayCallback &displayCallback,
|
||||
const impl::ExecuteCallback &executeCallback = [](auto) {});
|
||||
|
||||
/**
|
||||
* @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 */
|
||||
@@ -119,6 +239,8 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
using VisualizerFunctionCallback = std::function<void(pl::ptrn::Pattern&, pl::ptrn::Iteratable&, bool, std::span<const pl::core::Token::Literal>)>;
|
||||
|
||||
struct FunctionDefinition {
|
||||
pl::api::Namespace ns;
|
||||
std::string name;
|
||||
@@ -129,17 +251,58 @@ namespace hex {
|
||||
bool dangerous;
|
||||
};
|
||||
|
||||
struct Visualizer {
|
||||
u32 parameterCount;
|
||||
VisualizerFunctionCallback callback;
|
||||
};
|
||||
|
||||
std::map<std::string, Visualizer> &getVisualizers();
|
||||
std::map<std::string, pl::api::PragmaHandler> &getPragmas();
|
||||
std::vector<impl::FunctionDefinition> &getFunctions();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
std::map<std::string, pl::api::PragmaHandler> &getPragmas();
|
||||
std::vector<impl::FunctionDefinition> &getFunctions();
|
||||
/**
|
||||
* @brief Adds a new visualizer to the pattern language
|
||||
* @note Visualizers are extensions to the [[hex::visualize]] attribute, used to visualize data
|
||||
* @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);
|
||||
|
||||
}
|
||||
|
||||
@@ -149,18 +312,27 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
void add(View *view);
|
||||
std::map<std::string, 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>
|
||||
void add(Args &&...args) {
|
||||
return impl::add(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
std::map<std::string, View *> &getEntries();
|
||||
|
||||
/**
|
||||
* @brief Gets a view by its unlocalized name
|
||||
* @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 */
|
||||
@@ -176,11 +348,16 @@ namespace hex {
|
||||
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);
|
||||
|
||||
std::vector<impl::Entry> &getEntries();
|
||||
}
|
||||
|
||||
/* Data Inspector Registry. Allows adding of new types to the data inspector */
|
||||
@@ -207,12 +384,28 @@ namespace hex {
|
||||
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, 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 */
|
||||
@@ -230,9 +423,18 @@ namespace hex {
|
||||
|
||||
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>
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, Args &&...args) {
|
||||
add(impl::Entry {
|
||||
@@ -246,19 +448,29 @@ namespace hex {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a separator to the data processor right click menu
|
||||
*/
|
||||
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 */
|
||||
namespace Language {
|
||||
void registerLanguage(const std::string &name, const std::string &languageCode);
|
||||
void addLocalizations(const std::string &languageCode, const LanguageDefinition &definition);
|
||||
|
||||
std::map<std::string, std::string> &getLanguages();
|
||||
std::map<std::string, std::vector<LanguageDefinition>> &getLanguageDefinitions();
|
||||
/**
|
||||
* @brief Loads localization information from json data
|
||||
* @param data The language data
|
||||
*/
|
||||
void addLocalization(const nlohmann::json &data);
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::map<std::string, std::string> &getLanguages();
|
||||
std::map<std::string, std::vector<LanguageDefinition>> &getLanguageDefinitions();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Interface Registry. Allows adding new items to various interfaces */
|
||||
@@ -266,9 +478,11 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
using DrawCallback = std::function<void()>;
|
||||
using LayoutFunction = std::function<void(u32)>;
|
||||
using ClickCallback = std::function<void()>;
|
||||
using DrawCallback = std::function<void()>;
|
||||
using MenuCallback = std::function<void()>;
|
||||
using EnabledCallback = std::function<bool()>;
|
||||
using LayoutFunction = std::function<void(u32)>;
|
||||
using ClickCallback = std::function<void()>;
|
||||
|
||||
struct Layout {
|
||||
std::string unlocalizedName;
|
||||
@@ -280,8 +494,10 @@ namespace hex {
|
||||
};
|
||||
|
||||
struct MenuItem {
|
||||
std::string unlocalizedName;
|
||||
DrawCallback callback;
|
||||
std::vector<std::string> unlocalizedNames;
|
||||
Shortcut shortcut;
|
||||
MenuCallback callback;
|
||||
EnabledCallback enabledCallback;
|
||||
};
|
||||
|
||||
struct SidebarItem {
|
||||
@@ -295,29 +511,99 @@ namespace hex {
|
||||
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();
|
||||
|
||||
std::vector<impl::Layout> &getLayouts();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 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);
|
||||
|
||||
/**
|
||||
* @brief Adds a new footer item
|
||||
* @param function The function to call to draw the item
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Adds a new layout definition to the Layout menu
|
||||
* @param unlocalizedName The unlocalized name of the layout
|
||||
* @param function The function to call to setup the layout
|
||||
*/
|
||||
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 */
|
||||
@@ -327,8 +613,15 @@ namespace hex {
|
||||
|
||||
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>
|
||||
void add(bool addToList = true) {
|
||||
auto typeName = T().getTypeName();
|
||||
@@ -348,10 +641,9 @@ namespace hex {
|
||||
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 impl {
|
||||
@@ -362,32 +654,45 @@ namespace hex {
|
||||
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 impl {
|
||||
|
||||
using Callback = std::function<bool(std::filesystem::path)>;
|
||||
using Callback = std::function<bool(std::fs::path)>;
|
||||
struct Entry {
|
||||
std::vector<std::string> extensions;
|
||||
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);
|
||||
|
||||
std::vector<impl::Entry> &getEntries();
|
||||
|
||||
}
|
||||
|
||||
/* Hex Editor Registry. Allows adding new functionality to the hex editor */
|
||||
namespace HexEditor {
|
||||
|
||||
class DataVisualizer {
|
||||
@@ -406,7 +711,8 @@ namespace hex {
|
||||
protected:
|
||||
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:
|
||||
u16 m_bytesPerCell;
|
||||
u16 m_maxCharsPerCell;
|
||||
@@ -420,6 +726,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>
|
||||
void addDataVisualizer(const std::string &unlocalizedName, Args &&...args) {
|
||||
return impl::addDataVisualizer(unlocalizedName, new T(std::forward<Args>(args)...));
|
||||
@@ -427,6 +739,7 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
/* Hash Registry. Allows adding new hashes to the Hash view */
|
||||
namespace Hashes {
|
||||
|
||||
class Hash {
|
||||
@@ -437,11 +750,12 @@ namespace hex {
|
||||
public:
|
||||
using Callback = std::function<std::vector<u8>(const Region&, prv::Provider *)>;
|
||||
|
||||
Function(const Hash *type, std::string name, Callback callback)
|
||||
Function(Hash *type, std::string name, Callback callback)
|
||||
: m_type(type), m_name(std::move(name)), m_callback(std::move(callback)) {
|
||||
|
||||
}
|
||||
|
||||
[[nodiscard]] Hash *getType() { return this->m_type; }
|
||||
[[nodiscard]] const Hash *getType() const { return this->m_type; }
|
||||
[[nodiscard]] const std::string &getName() const { return this->m_name; }
|
||||
|
||||
@@ -458,7 +772,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
private:
|
||||
const Hash *m_type;
|
||||
Hash *m_type;
|
||||
std::string m_name;
|
||||
Callback m_callback;
|
||||
|
||||
@@ -468,12 +782,15 @@ namespace hex {
|
||||
virtual void draw() { }
|
||||
[[nodiscard]] virtual Function create(std::string name) = 0;
|
||||
|
||||
[[nodiscard]] virtual nlohmann::json store() const = 0;
|
||||
virtual void load(const nlohmann::json &json) = 0;
|
||||
|
||||
[[nodiscard]] const std::string &getUnlocalizedName() const {
|
||||
return this->m_unlocalizedName;
|
||||
}
|
||||
|
||||
protected:
|
||||
[[nodiscard]] Function create(const std::string &name, const Function::Callback &callback) const {
|
||||
[[nodiscard]] Function create(const std::string &name, const Function::Callback &callback) {
|
||||
return { this, name, callback };
|
||||
}
|
||||
|
||||
@@ -488,6 +805,12 @@ namespace hex {
|
||||
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>
|
||||
void add(Args && ... args) {
|
||||
impl::add(new T(std::forward<Args>(args)...));
|
||||
|
||||
@@ -10,68 +10,98 @@
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#define EVENT_DEF(event_name, ...) \
|
||||
struct event_name final : public hex::Event<__VA_ARGS__> { \
|
||||
constexpr static auto id = [] { return hex::EventId(); }(); \
|
||||
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
|
||||
#define EVENT_DEF(event_name, ...) \
|
||||
struct event_name final : public hex::impl::Event<__VA_ARGS__> { \
|
||||
constexpr static auto id = [] { return hex::impl::EventId(); }(); \
|
||||
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
|
||||
}
|
||||
|
||||
struct GLFWwindow;
|
||||
|
||||
namespace hex {
|
||||
|
||||
class EventId {
|
||||
public:
|
||||
explicit constexpr EventId(const char *func = __builtin_FUNCTION(), u32 line = __builtin_LINE()) {
|
||||
this->m_hash = line ^ 987654321;
|
||||
for (auto c : std::string_view(func)) {
|
||||
this->m_hash = (this->m_hash >> 5) | (this->m_hash << 27);
|
||||
this->m_hash ^= c;
|
||||
namespace impl {
|
||||
|
||||
class EventId {
|
||||
public:
|
||||
explicit constexpr EventId(const char *func = __builtin_FUNCTION(), u32 line = __builtin_LINE()) {
|
||||
this->m_hash = line ^ 987654321;
|
||||
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:
|
||||
u32 m_hash;
|
||||
};
|
||||
private:
|
||||
u32 m_hash;
|
||||
};
|
||||
|
||||
struct EventBase {
|
||||
EventBase() noexcept = default;
|
||||
};
|
||||
struct EventBase {
|
||||
EventBase() noexcept = default;
|
||||
};
|
||||
|
||||
template<typename... Params>
|
||||
struct Event : public EventBase {
|
||||
using Callback = std::function<void(Params...)>;
|
||||
template<typename... Params>
|
||||
struct Event : public EventBase {
|
||||
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 {
|
||||
this->m_func(params...);
|
||||
}
|
||||
void operator()(Params... params) const noexcept {
|
||||
this->m_func(params...);
|
||||
}
|
||||
|
||||
private:
|
||||
Callback m_func;
|
||||
};
|
||||
private:
|
||||
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 {
|
||||
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>
|
||||
static EventList::iterator subscribe(typename E::Callback 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>
|
||||
static void subscribe(void *token, typename E::Callback 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.remove(*token);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unsubscribes from an event
|
||||
* @tparam E Event
|
||||
* @param token Token passed to subscribe
|
||||
*/
|
||||
template<typename E>
|
||||
static void unsubscribe(void *token) noexcept {
|
||||
auto iter = std::find_if(s_tokenStore.begin(), s_tokenStore.end(), [&](auto &item) {
|
||||
@@ -80,9 +110,16 @@ namespace hex {
|
||||
|
||||
if (iter != s_tokenStore.end()) {
|
||||
s_events.remove(*iter->second);
|
||||
s_tokenStore.erase(iter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Posts an event to all subscribers of it
|
||||
* @tparam E Event
|
||||
* @param args Arguments to pass to the event
|
||||
*/
|
||||
template<typename E>
|
||||
static void post(auto &&...args) noexcept {
|
||||
for (const auto &[id, event] : s_events) {
|
||||
@@ -91,6 +128,9 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unsubscribe all subscribers from all events
|
||||
*/
|
||||
static void clear() noexcept {
|
||||
s_events.clear();
|
||||
s_tokenStore.clear();
|
||||
@@ -119,23 +159,27 @@ namespace hex {
|
||||
EVENT_DEF(EventFrameBegin);
|
||||
EVENT_DEF(EventFrameEnd);
|
||||
EVENT_DEF(EventWindowInitialized);
|
||||
EVENT_DEF(EventSetTaskBarIconState, u32, u32, u32);
|
||||
|
||||
EVENT_DEF(RequestOpenWindow, std::string);
|
||||
EVENT_DEF(RequestSelectionChange, Region);
|
||||
EVENT_DEF(RequestAddBookmark, Region, std::string, std::string, color_t);
|
||||
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
|
||||
EVENT_DEF(RequestChangeWindowTitle, std::string);
|
||||
EVENT_DEF(RequestLoadPatternLanguageFile, std::fs::path);
|
||||
EVENT_DEF(RequestSavePatternLanguageFile, std::fs::path);
|
||||
EVENT_DEF(RequestUpdateWindowTitle);
|
||||
EVENT_DEF(RequestCloseImHex, bool);
|
||||
EVENT_DEF(RequestRestartImHex);
|
||||
EVENT_DEF(RequestOpenFile, std::fs::path);
|
||||
EVENT_DEF(RequestChangeTheme, u32);
|
||||
EVENT_DEF(RequestChangeTheme, std::string);
|
||||
EVENT_DEF(RequestOpenPopup, std::string);
|
||||
EVENT_DEF(RequestCreateProvider, std::string, bool, hex::prv::Provider **);
|
||||
EVENT_DEF(RequestInitThemeHandlers);
|
||||
|
||||
EVENT_DEF(RequestShowInfoPopup, std::string);
|
||||
EVENT_DEF(RequestShowErrorPopup, std::string);
|
||||
EVENT_DEF(RequestShowFatalErrorPopup, 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)>);
|
||||
EVENT_DEF(RequestShowFileChooserPopup, std::vector<std::fs::path>, std::vector<nfdfilteritem_t>, std::function<void(std::fs::path)>, bool);
|
||||
|
||||
}
|
||||
@@ -8,12 +8,13 @@
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
#include <map>
|
||||
#include <filesystem>
|
||||
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
#include <hex/api/task.hpp>
|
||||
#include <hex/api/keybinding.hpp>
|
||||
|
||||
#include <wolv/io/fs.hpp>
|
||||
|
||||
using ImGuiID = unsigned int;
|
||||
struct ImVec2;
|
||||
|
||||
@@ -25,13 +26,7 @@ namespace hex {
|
||||
|
||||
namespace ImHexApi {
|
||||
|
||||
namespace Common {
|
||||
|
||||
void closeImHex(bool noQuestions = false);
|
||||
void restartImHex();
|
||||
|
||||
}
|
||||
|
||||
/* Functions to query information from the Hex Editor and interact with it */
|
||||
namespace HexEditor {
|
||||
|
||||
using TooltipFunction = std::function<void(u64, const u8*, size_t)>;
|
||||
@@ -86,32 +81,127 @@ namespace hex {
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Removes a background color highlighting from the Hex Editor
|
||||
* @param id The ID of the highlighting to remove
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Removes a foreground color highlighting from the Hex Editor
|
||||
* @param id The ID of the highlighting to remove
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Removes a hover tooltip from the Hex Editor
|
||||
* @param id The ID of the tooltip to remove
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Removes a background color highlighting from the Hex Editor
|
||||
* @param id The ID of the highlighting to remove
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Removes a background color highlighting from the Hex Editor
|
||||
* @param id The ID of the highlighting to remove
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Removes a foreground color highlighting from the Hex Editor
|
||||
* @param id The ID of the highlighting to remove
|
||||
*/
|
||||
void removeForegroundHighlightingProvider(u32 id);
|
||||
|
||||
/**
|
||||
* @brief Checks if there's a valid selection in the Hex Editor right now
|
||||
*/
|
||||
bool isSelectionValid();
|
||||
|
||||
/**
|
||||
* @brief Gets the current selection in the Hex Editor
|
||||
* @return The current selection
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Sets the current selection in the Hex Editor
|
||||
* @param region The region to select
|
||||
*/
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
/* Functions to interact with Bookmarks */
|
||||
namespace Bookmarks {
|
||||
|
||||
struct Entry {
|
||||
@@ -123,10 +213,19 @@ namespace hex {
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
/* Functions to interact with the loaded data provider */
|
||||
namespace Provider {
|
||||
|
||||
namespace impl {
|
||||
@@ -136,30 +235,82 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the currently selected data provider
|
||||
* @return The currently selected data provider
|
||||
*/
|
||||
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();
|
||||
|
||||
/**
|
||||
* @brief Sets the currently selected data provider
|
||||
* @param index Index of the provider to select
|
||||
*/
|
||||
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();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Marks the currently selected data provider as dirty
|
||||
*/
|
||||
void markDirty();
|
||||
|
||||
/**
|
||||
* @brief Marks the currently selected data provider as clean
|
||||
*/
|
||||
void resetDirty();
|
||||
|
||||
/**
|
||||
* @brief Checks whether the currently selected data provider is dirty
|
||||
* @return Whether the currently selected data provider is dirty
|
||||
*/
|
||||
bool isDirty();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Adds a newly created provider to the list of providers
|
||||
* @param provider The provider to add
|
||||
* @param skipLoadInterface Whether to skip loading the provider's loading interface
|
||||
*/
|
||||
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>
|
||||
void add(auto &&...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);
|
||||
|
||||
/**
|
||||
* @brief Creates a new provider using its unlocalized name
|
||||
* @param unlocalizedName The unlocalized name of the provider to create
|
||||
* @param skipLoadInterface Whether to skip loading the provider's loading interface
|
||||
*/
|
||||
prv::Provider* createProvider(const std::string &unlocalizedName, bool skipLoadInterface = false);
|
||||
|
||||
}
|
||||
|
||||
/* Functions to interact with various ImHex system settings */
|
||||
namespace System {
|
||||
|
||||
namespace impl {
|
||||
@@ -175,7 +326,7 @@ namespace hex {
|
||||
|
||||
void setBorderlessWindowMode(bool enabled);
|
||||
|
||||
void setCustomFontPath(const std::filesystem::path &path);
|
||||
void setCustomFontPath(const std::fs::path &path);
|
||||
void setFontSize(float size);
|
||||
|
||||
void setGPUVendor(const std::string &vendor);
|
||||
@@ -191,44 +342,160 @@ namespace hex {
|
||||
char **envp;
|
||||
};
|
||||
|
||||
enum class Theme {
|
||||
Dark = 1,
|
||||
Light = 2,
|
||||
Classic = 3
|
||||
enum class TaskProgressState {
|
||||
Reset,
|
||||
Progress,
|
||||
Flash
|
||||
};
|
||||
|
||||
enum class TaskProgressType {
|
||||
Normal,
|
||||
Warning,
|
||||
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);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets the current program arguments
|
||||
* @return The current program arguments
|
||||
*/
|
||||
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);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets the current target FPS
|
||||
* @return The current target FPS
|
||||
*/
|
||||
float getTargetFPS();
|
||||
|
||||
/**
|
||||
* @brief Sets the target FPS
|
||||
* @param fps The target FPS
|
||||
*/
|
||||
void setTargetFPS(float fps);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets the current global scale
|
||||
* @return The current global scale
|
||||
*/
|
||||
float getGlobalScale();
|
||||
|
||||
/**
|
||||
* @brief Gets the current native scale
|
||||
* @return The current native scale
|
||||
*/
|
||||
float getNativeScale();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets the current main window position
|
||||
* @return Position of the main window
|
||||
*/
|
||||
ImVec2 getMainWindowPosition();
|
||||
|
||||
/**
|
||||
* @brief Gets the current main window size
|
||||
* @return Size of the main window
|
||||
*/
|
||||
ImVec2 getMainWindowSize();
|
||||
|
||||
/**
|
||||
* @brief Gets the current main dock space ID
|
||||
* @return ID of the main dock space
|
||||
*/
|
||||
ImGuiID getMainDockSpaceId();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Checks if borderless window mode is enabled currently
|
||||
* @return Whether borderless window mode is enabled
|
||||
*/
|
||||
bool isBorderlessWindowModeEnabled();
|
||||
|
||||
/**
|
||||
* @brief Gets the init arguments passed to ImHex from the splash screen
|
||||
* @return Init arguments
|
||||
*/
|
||||
std::map<std::string, std::string> &getInitArguments();
|
||||
|
||||
constexpr static float DefaultFontSize = 13.0;
|
||||
|
||||
/**
|
||||
* @brief Gets the current custom font path
|
||||
* @return The current custom font path
|
||||
*/
|
||||
const std::filesystem::path &getCustomFontPath();
|
||||
|
||||
/**
|
||||
* @brief Gets the current font size
|
||||
* @return The current font size
|
||||
*/
|
||||
float getFontSize();
|
||||
|
||||
void setTheme(Theme theme);
|
||||
Theme getTheme();
|
||||
|
||||
/**
|
||||
* @brief Sets if ImHex should follow the system theme
|
||||
* @param enabled Whether to follow the system theme
|
||||
*/
|
||||
void enableSystemThemeDetection(bool enabled);
|
||||
|
||||
/**
|
||||
* @brief Checks if ImHex follows the system theme
|
||||
* @return Whether ImHex follows the system theme
|
||||
*/
|
||||
bool usesSystemThemeDetection();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets the currently set additional folder paths
|
||||
* @return The currently set additional folder paths
|
||||
*/
|
||||
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);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets the current GPU vendor
|
||||
* @return The current GPU vendor
|
||||
*/
|
||||
const std::string &getGPUVendor();
|
||||
|
||||
/**
|
||||
* @brief Checks if ImHex is running in portable mode
|
||||
* @return Whether ImHex is running in portable mode
|
||||
*/
|
||||
bool isPortableVersion();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
struct ImGuiWindow;
|
||||
|
||||
@@ -136,15 +137,31 @@ namespace hex {
|
||||
|
||||
auto operator<=>(const Key &) const = default;
|
||||
|
||||
[[nodiscard]] constexpr u32 getKeyCode() const { return this->m_key; }
|
||||
private:
|
||||
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 {
|
||||
public:
|
||||
Shortcut() = default;
|
||||
Shortcut(Keys key) : m_keys({ key }) { }
|
||||
|
||||
const static inline auto None = Keys(0);
|
||||
|
||||
Shortcut operator+(const Key &other) const {
|
||||
Shortcut result = *this;
|
||||
result.m_keys.insert(other);
|
||||
@@ -166,6 +183,173 @@ namespace hex {
|
||||
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:
|
||||
friend Shortcut operator+(const Key &lhs, const Key &rhs);
|
||||
|
||||
@@ -179,19 +363,54 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr static auto CTRL = Key(static_cast<Keys>(0x1000'0000));
|
||||
constexpr static auto ALT = Key(static_cast<Keys>(0x2000'0000));
|
||||
constexpr static auto SHIFT = Key(static_cast<Keys>(0x4000'0000));
|
||||
constexpr static auto SUPER = Key(static_cast<Keys>(0x8000'0000));
|
||||
|
||||
/**
|
||||
* @brief The ShortcutManager handles global and view-specific shortcuts.
|
||||
* New shortcuts can be constructed using the + operator on Key objects. For example: CTRL + ALT + Keys::A
|
||||
*/
|
||||
class ShortcutManager {
|
||||
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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
|
||||
/**
|
||||
* @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(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 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);
|
||||
|
||||
/**
|
||||
* @brief Clear all shortcuts
|
||||
*/
|
||||
static void clearShortcuts();
|
||||
|
||||
private:
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace hex {
|
||||
|
||||
class LanguageDefinition {
|
||||
public:
|
||||
LanguageDefinition(std::initializer_list<std::pair<std::string, std::string>> entries);
|
||||
explicit LanguageDefinition(std::map<std::string, std::string> &&entries);
|
||||
|
||||
[[nodiscard]] const std::map<std::string, std::string> &getEntries() const;
|
||||
|
||||
|
||||
@@ -14,37 +14,104 @@
|
||||
|
||||
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 {
|
||||
public:
|
||||
struct Handler {
|
||||
using Function = std::function<bool(const std::fs::path &, Tar &tar)>;
|
||||
std::fs::path basePath;
|
||||
bool required;
|
||||
Function load, store;
|
||||
|
||||
std::fs::path basePath; //< Base path for where to store the files in the project file
|
||||
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 {
|
||||
using Function = std::function<bool(prv::Provider *provider, const std::fs::path &, Tar &tar)>;
|
||||
std::fs::path basePath;
|
||||
bool required;
|
||||
Function load, store;
|
||||
|
||||
std::fs::path basePath; //< Base path for where to store the files in the project file
|
||||
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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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();
|
||||
|
||||
/**
|
||||
* @brief Clear the currently loaded project file
|
||||
*/
|
||||
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();
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
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) {
|
||||
getProviderHandlers().push_back(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the list of registered handlers
|
||||
* @return List of registered handlers
|
||||
*/
|
||||
static std::vector<Handler>& getHandlers() {
|
||||
return s_handlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the list of registered per-provider handlers
|
||||
* @return List of registered per-provider handlers
|
||||
*/
|
||||
static std::vector<ProviderHandler>& getProviderHandlers() {
|
||||
return s_providerHandlers;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@ namespace hex {
|
||||
class TaskHolder;
|
||||
class TaskManager;
|
||||
|
||||
/**
|
||||
* @brief A type representing a running asynchronous task
|
||||
*/
|
||||
class Task {
|
||||
public:
|
||||
Task() = default;
|
||||
@@ -26,14 +29,38 @@ namespace hex {
|
||||
Task(Task &&other) noexcept;
|
||||
~Task();
|
||||
|
||||
/**
|
||||
* @brief Updates the current process value of the task
|
||||
* @param value Current value
|
||||
*/
|
||||
void update(u64 value = 0);
|
||||
|
||||
/**
|
||||
* @brief Sets the maximum value of the task
|
||||
* @param value Maximum value of the task
|
||||
*/
|
||||
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 isFinished() const;
|
||||
[[nodiscard]] bool hadException() const;
|
||||
[[nodiscard]] bool wasInterrupted() const;
|
||||
[[nodiscard]] bool shouldInterrupt() const;
|
||||
|
||||
void clearException();
|
||||
[[nodiscard]] std::string getExceptionMessage() const;
|
||||
|
||||
@@ -41,10 +68,6 @@ namespace hex {
|
||||
[[nodiscard]] u64 getValue() const;
|
||||
[[nodiscard]] u64 getMaxValue() const;
|
||||
|
||||
void interrupt();
|
||||
|
||||
void setInterruptCallback(std::function<void()> callback);
|
||||
|
||||
private:
|
||||
void finish();
|
||||
void interruption();
|
||||
@@ -72,6 +95,9 @@ namespace hex {
|
||||
friend class TaskManager;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A type holding a weak reference to a Task
|
||||
*/
|
||||
class TaskHolder {
|
||||
public:
|
||||
TaskHolder() = default;
|
||||
@@ -87,6 +113,9 @@ namespace hex {
|
||||
std::weak_ptr<Task> m_task;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The Task Manager is responsible for running and managing asynchronous tasks
|
||||
*/
|
||||
class TaskManager {
|
||||
public:
|
||||
TaskManager() = delete;
|
||||
@@ -96,22 +125,52 @@ namespace hex {
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
|
||||
/**
|
||||
* @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 size_t getRunningTaskCount();
|
||||
static std::list<std::shared_ptr<Task>> &getRunningTasks();
|
||||
static size_t getRunningBackgroundTaskCount();
|
||||
|
||||
static void doLater(const std::function<void()> &function);
|
||||
static std::list<std::shared_ptr<Task>> &getRunningTasks();
|
||||
static void runDeferredCalls();
|
||||
|
||||
private:
|
||||
static std::mutex s_deferredCallsMutex;
|
||||
static std::mutex s_deferredCallsMutex, s_tasksFinishedMutex;
|
||||
|
||||
static std::list<std::shared_ptr<Task>> s_tasks;
|
||||
static std::list<std::shared_ptr<Task>> s_taskQueue;
|
||||
static std::list<std::function<void()>> s_deferredCalls;
|
||||
static std::list<std::function<void()>> s_tasksFinishedCallbacks;
|
||||
|
||||
static std::mutex s_queueMutex;
|
||||
static std::condition_variable s_jobCondVar;
|
||||
|
||||
95
lib/libimhex/include/hex/api/theme_manager.hpp
Normal file
95
lib/libimhex/include/hex/api/theme_manager.hpp
Normal file
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <imgui.h>
|
||||
|
||||
namespace hex {
|
||||
|
||||
/**
|
||||
* @brief The Theme Manager takes care of loading and applying themes
|
||||
*/
|
||||
class ThemeManager {
|
||||
public:
|
||||
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);
|
||||
|
||||
/**
|
||||
* @brief Adds a theme from json data
|
||||
* @param content JSON data of the theme
|
||||
*/
|
||||
static void addTheme(const std::string &content);
|
||||
|
||||
/**
|
||||
* @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 const std::string &getThemeImagePostfix();
|
||||
|
||||
static std::optional<ImColor> parseColorString(const std::string &colorString);
|
||||
|
||||
static nlohmann::json exportCurrentTheme(const std::string &name);
|
||||
|
||||
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:
|
||||
ThemeManager() = default;
|
||||
|
||||
|
||||
static std::map<std::string, nlohmann::json> s_themes;
|
||||
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_currTheme;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -38,9 +38,18 @@ namespace hex::dp {
|
||||
void removeConnectedAttribute(int linkId) { this->m_connectedAttributes.erase(linkId); }
|
||||
[[nodiscard]] std::map<int, Attribute *> &getConnectedAttributes() { return this->m_connectedAttributes; }
|
||||
|
||||
[[nodiscard]] Node *getParentNode() { return this->m_parentNode; }
|
||||
[[nodiscard]] Node *getParentNode() const { return this->m_parentNode; }
|
||||
|
||||
[[nodiscard]] std::optional<std::vector<u8>> &getOutputData() { return this->m_outputData; }
|
||||
[[nodiscard]] std::vector<u8>& getOutputData() {
|
||||
if (!this->m_outputData.empty())
|
||||
return this->m_outputData;
|
||||
else
|
||||
return this->m_defaultData;
|
||||
}
|
||||
|
||||
void clearOutputData() { this->m_outputData.clear(); }
|
||||
|
||||
[[nodiscard]] std::vector<u8>& getDefaultData() { return this->m_defaultData; }
|
||||
|
||||
static void setIdCounter(int id) {
|
||||
if (id > Attribute::s_idCounter)
|
||||
@@ -55,7 +64,8 @@ namespace hex::dp {
|
||||
std::map<int, Attribute *> m_connectedAttributes;
|
||||
Node *m_parentNode = nullptr;
|
||||
|
||||
std::optional<std::vector<u8>> m_outputData;
|
||||
std::vector<u8> m_outputData;
|
||||
std::vector<u8> m_defaultData;
|
||||
|
||||
friend class Node;
|
||||
void setParentNode(Node *node) { this->m_parentNode = node; }
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace hex::dp {
|
||||
Link(int from, int to);
|
||||
|
||||
[[nodiscard]] int getId() const { return this->m_id; }
|
||||
void setID(int id) { this->m_id = id; }
|
||||
void setId(int id) { this->m_id = id; }
|
||||
|
||||
[[nodiscard]] int getFromId() const { return this->m_from; }
|
||||
[[nodiscard]] int getToId() const { return this->m_to; }
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <hex/data_processor/attribute.hpp>
|
||||
|
||||
#include <set>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
@@ -31,7 +32,10 @@ namespace hex::dp {
|
||||
void setUnlocalizedName(const std::string &unlocalizedName) { this->m_unlocalizedName = unlocalizedName; }
|
||||
|
||||
[[nodiscard]] const std::string &getUnlocalizedTitle() const { return this->m_unlocalizedTitle; }
|
||||
void setUnlocalizedTitle(std::string title) { this->m_unlocalizedTitle = std::move(title); }
|
||||
|
||||
[[nodiscard]] std::vector<Attribute> &getAttributes() { return this->m_attributes; }
|
||||
[[nodiscard]] const std::vector<Attribute> &getAttributes() const { return this->m_attributes; }
|
||||
|
||||
void setCurrentOverlay(prv::Overlay *overlay) {
|
||||
this->m_overlay = overlay;
|
||||
@@ -40,8 +44,8 @@ namespace hex::dp {
|
||||
virtual void drawNode() { }
|
||||
virtual void process() = 0;
|
||||
|
||||
virtual void store(nlohmann::json &j) { hex::unused(j); }
|
||||
virtual void load(nlohmann::json &j) { hex::unused(j); }
|
||||
virtual void store(nlohmann::json &j) const { hex::unused(j); }
|
||||
virtual void load(const nlohmann::json &j) { hex::unused(j); }
|
||||
|
||||
struct NodeError {
|
||||
Node *node;
|
||||
@@ -50,7 +54,7 @@ namespace hex::dp {
|
||||
|
||||
void resetOutputData() {
|
||||
for (auto &attribute : this->m_attributes)
|
||||
attribute.getOutputData().reset();
|
||||
attribute.clearOutputData();
|
||||
}
|
||||
|
||||
void resetProcessedInputs() {
|
||||
@@ -70,6 +74,14 @@ namespace hex::dp {
|
||||
Node::s_idCounter = id;
|
||||
}
|
||||
|
||||
const std::vector<u8>& getBufferOnInput(u32 index);
|
||||
const i128& getIntegerOnInput(u32 index);
|
||||
const long double& getFloatOnInput(u32 index);
|
||||
|
||||
void setBufferOnOutput(u32 index, std::span<const u8> data);
|
||||
void setIntegerOnOutput(u32 index, i128 integer);
|
||||
void setFloatOnOutput(u32 index, long double floatingPoint);
|
||||
|
||||
private:
|
||||
int m_id;
|
||||
std::string m_unlocalizedTitle, m_unlocalizedName;
|
||||
@@ -80,11 +92,15 @@ namespace hex::dp {
|
||||
|
||||
static int s_idCounter;
|
||||
|
||||
Attribute *getConnectedInputAttribute(u32 index) {
|
||||
Attribute& getAttribute(u32 index) {
|
||||
if (index >= this->getAttributes().size())
|
||||
throw std::runtime_error("Attribute index out of bounds!");
|
||||
|
||||
auto &connectedAttribute = this->getAttributes()[index].getConnectedAttributes();
|
||||
return this->getAttributes()[index];
|
||||
}
|
||||
|
||||
Attribute *getConnectedInputAttribute(u32 index) {
|
||||
const auto &connectedAttribute = this->getAttribute(index).getConnectedAttributes();
|
||||
|
||||
if (connectedAttribute.empty())
|
||||
return nullptr;
|
||||
@@ -103,15 +119,14 @@ namespace hex::dp {
|
||||
throw NodeError { this, message };
|
||||
}
|
||||
|
||||
std::vector<u8> getBufferOnInput(u32 index);
|
||||
i128 getIntegerOnInput(u32 index);
|
||||
long double getFloatOnInput(u32 index);
|
||||
|
||||
void setBufferOnOutput(u32 index, const std::vector<u8> &data);
|
||||
void setIntegerOnOutput(u32 index, i128 integer);
|
||||
void setFloatOnOutput(u32 index, long double floatingPoint);
|
||||
|
||||
void setOverlayData(u64 address, const std::vector<u8> &data);
|
||||
|
||||
void setAttributes(std::vector<Attribute> attributes) {
|
||||
this->m_attributes = std::move(attributes);
|
||||
|
||||
for (auto &attr : this->m_attributes)
|
||||
attr.setParentNode(this);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -16,7 +16,7 @@ namespace hex::crypt {
|
||||
void initialize();
|
||||
void exit();
|
||||
|
||||
u16 crc8(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut);
|
||||
u8 crc8(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut);
|
||||
u16 crc16(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut);
|
||||
u32 crc32(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut);
|
||||
|
||||
|
||||
@@ -20,10 +20,16 @@ namespace hex {
|
||||
TMS320C64X,
|
||||
M680X,
|
||||
EVM,
|
||||
MOS65XX,
|
||||
WASM,
|
||||
#if defined(CS_MODE_RISCV32)
|
||||
RISCV,
|
||||
#endif
|
||||
#if defined(CS_MODE_MOS65XX_6502)
|
||||
MOS65XX,
|
||||
#endif
|
||||
#if defined(CS_MODE_BPF_CLASSIC)
|
||||
BPF,
|
||||
RISCV,
|
||||
#endif
|
||||
|
||||
MAX,
|
||||
MIN = ARM
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
#include <map>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <span>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -20,17 +22,22 @@ namespace hex {
|
||||
|
||||
EncodingFile() = default;
|
||||
EncodingFile(Type type, const std::fs::path &path);
|
||||
EncodingFile(Type type, const std::string &path);
|
||||
|
||||
[[nodiscard]] std::pair<std::string_view, size_t> getEncodingFor(const std::vector<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]] bool valid() const { return this->m_valid; }
|
||||
|
||||
[[nodiscard]] const std::string& getTableContent() const { return this->m_tableContent; }
|
||||
|
||||
private:
|
||||
void parseThingyFile(fs::File &file);
|
||||
void parse(const std::string &content);
|
||||
|
||||
bool m_valid = false;
|
||||
|
||||
std::string m_tableContent;
|
||||
std::map<size_t, std::map<std::vector<u8>, std::string>> m_mapping;
|
||||
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,87 +10,23 @@
|
||||
|
||||
#include <nfd.hpp>
|
||||
|
||||
namespace std::fs {
|
||||
using namespace std::filesystem;
|
||||
}
|
||||
#include <wolv/io/fs.hpp>
|
||||
|
||||
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 {
|
||||
Open,
|
||||
Save,
|
||||
Folder
|
||||
};
|
||||
|
||||
void setFileBrowserErrorCallback(const std::function<void()> &callback);
|
||||
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath = {});
|
||||
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);
|
||||
|
||||
enum class ImHexPath : u32 {
|
||||
Patterns = 0,
|
||||
PatternsInclude,
|
||||
Magic,
|
||||
Python,
|
||||
Plugins,
|
||||
Yara,
|
||||
Config,
|
||||
@@ -101,12 +37,18 @@ namespace hex::fs {
|
||||
Recent,
|
||||
Scripts,
|
||||
Inspectors,
|
||||
Themes,
|
||||
Libraries,
|
||||
Nodes,
|
||||
|
||||
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);
|
||||
|
||||
// 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
|
||||
338
lib/libimhex/include/hex/helpers/http_requests.hpp
Normal file
338
lib/libimhex/include/hex/helpers/http_requests.hpp
Normal file
@@ -0,0 +1,338 @@
|
||||
#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) : 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() {
|
||||
curl_easy_cleanup(this->m_curl);
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -2,10 +2,6 @@
|
||||
|
||||
namespace hex {
|
||||
|
||||
[[noreturn]] inline void unreachable() {
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
inline void unused(auto && ... x) {
|
||||
((void)x, ...);
|
||||
}
|
||||
|
||||
@@ -17,8 +17,10 @@ namespace hex::magic {
|
||||
|
||||
bool compile();
|
||||
std::string getDescription(const std::vector<u8> &data);
|
||||
std::string getDescription(prv::Provider *provider, size_t size = 5_MiB);
|
||||
std::string getDescription(prv::Provider *provider, size_t size = 100_KiB);
|
||||
std::string getMIMEType(const std::vector<u8> &data);
|
||||
std::string getMIMEType(prv::Provider *provider, size_t size = 5_MiB);
|
||||
std::string getMIMEType(prv::Provider *provider, size_t size = 100_KiB);
|
||||
|
||||
bool isValidMIMEType(const std::string &mimeType);
|
||||
|
||||
}
|
||||
@@ -1,74 +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/system.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
using CURL = void;
|
||||
struct curl_slist;
|
||||
|
||||
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);
|
||||
std::future<Response<nlohmann::json>> getJson(const std::string &url, u32 timeout = DefaultTimeout);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
216
lib/libimhex/include/hex/helpers/opengl.hpp
Normal file
216
lib/libimhex/include/hex/helpers/opengl.hpp
Normal file
@@ -0,0 +1,216 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <span>
|
||||
#include <string>
|
||||
|
||||
#include <imgui_impl_opengl3_loader.h>
|
||||
|
||||
namespace hex::gl {
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename T>
|
||||
GLuint getType() {
|
||||
if constexpr (std::is_same_v<T, float>)
|
||||
return GL_FLOAT;
|
||||
else if constexpr (std::is_same_v<T, u32>)
|
||||
return GL_UNSIGNED_INT;
|
||||
else
|
||||
static_assert(hex::always_false<T>::value, "Unsupported type");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename T, size_t Size>
|
||||
class Vector {
|
||||
public:
|
||||
Vector() = default;
|
||||
Vector(std::array<T, Size> data) : m_data(data) { }
|
||||
|
||||
T &operator[](size_t index) { return this->m_data[index]; }
|
||||
const T &operator[](size_t index) const { return this->m_data[index]; }
|
||||
|
||||
T *data() { return this->m_data.data(); }
|
||||
const T *data() const { return this->m_data.data(); }
|
||||
|
||||
[[nodiscard]] size_t size() const { return this->m_data.size(); }
|
||||
|
||||
auto operator+(const Vector<T, Size>& other) {
|
||||
auto copy = *this;
|
||||
for (size_t i = 0; i < Size; i++)
|
||||
copy[i] += other[i];
|
||||
return copy;
|
||||
}
|
||||
|
||||
auto operator-(const Vector<T, Size>& other) {
|
||||
auto copy = *this;
|
||||
for (size_t i = 0; i < Size; i++)
|
||||
copy[i] -= other[i];
|
||||
return copy;
|
||||
}
|
||||
|
||||
auto dot(const Vector<T, Size>& other) {
|
||||
T result = 0;
|
||||
for (size_t i = 0; i < Size; i++)
|
||||
result += this->m_data[i] * other[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
auto cross(const Vector<T, Size>& other) {
|
||||
static_assert(Size == 3, "Cross product is only defined for 3D vectors");
|
||||
return Vector<T, Size>({ this->m_data[1] * other[2] - this->m_data[2] * other[1], this->m_data[2] * other[0] - this->m_data[0] * other[2], this->m_data[0] * other[1] - this->m_data[1] * other[0] });
|
||||
}
|
||||
|
||||
auto normalize() {
|
||||
auto copy = *this;
|
||||
auto length = std::sqrt(copy.dot(copy));
|
||||
for (size_t i = 0; i < Size; i++)
|
||||
copy[i] /= length;
|
||||
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:
|
||||
std::array<T, Size> m_data;
|
||||
};
|
||||
|
||||
|
||||
class Shader {
|
||||
public:
|
||||
Shader() = default;
|
||||
Shader(std::string_view vertexSource, std::string_view fragmentSource);
|
||||
~Shader();
|
||||
|
||||
Shader(const Shader&) = delete;
|
||||
Shader(Shader&& other) noexcept;
|
||||
|
||||
Shader& operator=(const Shader&) = delete;
|
||||
Shader& operator=(Shader&& other) noexcept;
|
||||
|
||||
void bind() const;
|
||||
void unbind() const;
|
||||
|
||||
void setUniform(std::string_view name, const float &value);
|
||||
void setUniform(std::string_view name, const Vector<float, 3> &value);
|
||||
|
||||
private:
|
||||
void compile(GLuint shader, std::string_view source);
|
||||
GLint getUniformLocation(std::string_view name);
|
||||
|
||||
private:
|
||||
GLuint m_program = 0;
|
||||
std::map<std::string, GLint> m_uniforms;
|
||||
};
|
||||
|
||||
enum class BufferType {
|
||||
Vertex = GL_ARRAY_BUFFER,
|
||||
Index = GL_ELEMENT_ARRAY_BUFFER
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Buffer {
|
||||
public:
|
||||
Buffer() = default;
|
||||
Buffer(BufferType type, std::span<T> data);
|
||||
~Buffer();
|
||||
Buffer(const Buffer&) = delete;
|
||||
Buffer(Buffer&& other) noexcept;
|
||||
|
||||
Buffer& operator=(const Buffer&) = delete;
|
||||
Buffer& operator=(Buffer&& other) noexcept;
|
||||
|
||||
void bind() const;
|
||||
void unbind() const;
|
||||
|
||||
void draw() const;
|
||||
|
||||
size_t getSize() const;
|
||||
private:
|
||||
GLuint m_buffer = 0;
|
||||
size_t m_size = 0;
|
||||
GLuint m_type = 0;
|
||||
};
|
||||
|
||||
extern template class Buffer<float>;
|
||||
extern template class Buffer<u32>;
|
||||
|
||||
class VertexArray {
|
||||
public:
|
||||
VertexArray();
|
||||
~VertexArray();
|
||||
VertexArray(const VertexArray&) = delete;
|
||||
VertexArray(VertexArray&& other) noexcept;
|
||||
|
||||
VertexArray& operator=(const VertexArray&) = delete;
|
||||
VertexArray& operator=(VertexArray&& other) noexcept;
|
||||
|
||||
template<typename T>
|
||||
void addBuffer(u32 index, const Buffer<T> &buffer) const {
|
||||
glEnableVertexAttribArray(index);
|
||||
buffer.bind();
|
||||
glVertexAttribPointer(index, 3, getType<T>(), GL_FALSE, 3 * sizeof(T), nullptr);
|
||||
buffer.unbind();
|
||||
}
|
||||
|
||||
void bind() const;
|
||||
void unbind() const;
|
||||
|
||||
private:
|
||||
GLuint m_array;
|
||||
};
|
||||
|
||||
class Texture {
|
||||
public:
|
||||
Texture(u32 width, u32 height);
|
||||
~Texture();
|
||||
Texture(const Texture&) = delete;
|
||||
Texture(Texture&& other) noexcept;
|
||||
|
||||
Texture& operator=(const Texture&) = delete;
|
||||
Texture& operator=(Texture&& other) noexcept;
|
||||
|
||||
void bind() const;
|
||||
void unbind() const;
|
||||
|
||||
GLuint getTexture() const;
|
||||
u32 getWidth() const;
|
||||
u32 getHeight() const;
|
||||
|
||||
GLuint release();
|
||||
private:
|
||||
GLuint m_texture;
|
||||
u32 m_width, m_height;
|
||||
};
|
||||
|
||||
class FrameBuffer {
|
||||
public:
|
||||
FrameBuffer();
|
||||
~FrameBuffer();
|
||||
FrameBuffer(const FrameBuffer&) = delete;
|
||||
FrameBuffer(FrameBuffer&& other) noexcept;
|
||||
|
||||
FrameBuffer& operator=(const FrameBuffer&) = delete;
|
||||
FrameBuffer& operator=(FrameBuffer&& other) noexcept;
|
||||
|
||||
void bind() const;
|
||||
void unbind() const;
|
||||
|
||||
void attachTexture(const Texture &texture) const;
|
||||
|
||||
private:
|
||||
GLuint m_frameBuffer, m_renderBuffer;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -4,14 +4,23 @@
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <expected>
|
||||
|
||||
namespace hex {
|
||||
|
||||
using Patches = std::map<u64, u8>;
|
||||
|
||||
std::vector<u8> generateIPSPatch(const Patches &patches);
|
||||
std::vector<u8> generateIPS32Patch(const Patches &patches);
|
||||
enum class IPSError {
|
||||
AddressOutOfRange,
|
||||
PatchTooLarge,
|
||||
InvalidPatchHeader,
|
||||
InvalidPatchFormat,
|
||||
MissingEOF
|
||||
};
|
||||
|
||||
Patches loadIPSPatch(const std::vector<u8> &ipsPatch);
|
||||
Patches loadIPS32Patch(const std::vector<u8> &ipsPatch);
|
||||
std::expected<std::vector<u8>, IPSError> generateIPSPatch(const Patches &patches);
|
||||
std::expected<std::vector<u8>, IPSError> generateIPS32Patch(const Patches &patches);
|
||||
|
||||
std::expected<Patches, IPSError> loadIPSPatch(const std::vector<u8> &ipsPatch);
|
||||
std::expected<Patches, IPSError> loadIPS32Patch(const std::vector<u8> &ipsPatch);
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
|
||||
}
|
||||
20
lib/libimhex/include/hex/helpers/stacktrace.hpp
Normal file
20
lib/libimhex/include/hex/helpers/stacktrace.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace hex::stacktrace {
|
||||
|
||||
struct StackFrame {
|
||||
std::string file;
|
||||
std::string function;
|
||||
u32 line;
|
||||
};
|
||||
|
||||
void initialize();
|
||||
|
||||
std::vector<StackFrame> getStackTrace();
|
||||
|
||||
}
|
||||
@@ -26,11 +26,11 @@ namespace hex {
|
||||
|
||||
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);
|
||||
|
||||
void write(const std::fs::path &path, const std::vector<u8> &data);
|
||||
void write(const std::fs::path &path, const std::string &data);
|
||||
void writeVector(const std::fs::path &path, const std::vector<u8> &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]] bool contains(const std::fs::path &path);
|
||||
|
||||
@@ -23,14 +23,33 @@ namespace hex {
|
||||
u64 address;
|
||||
size_t size;
|
||||
|
||||
[[nodiscard]] bool isWithin(const Region &other) const;
|
||||
[[nodiscard]] bool overlaps(const Region &other) const;
|
||||
[[nodiscard]] constexpr bool isWithin(const Region &other) const {
|
||||
if (*this == Invalid() || other == Invalid())
|
||||
return false;
|
||||
|
||||
[[nodiscard]] u64 getStartAddress() const;
|
||||
[[nodiscard]] u64 getEndAddress() const;
|
||||
[[nodiscard]] size_t getSize() const;
|
||||
if (this->getStartAddress() >= other.getStartAddress() && this->getEndAddress() <= other.getEndAddress())
|
||||
return true;
|
||||
|
||||
bool operator==(const Region &other) const;
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool overlaps(const Region &other) const {
|
||||
if (*this == Invalid() || other == Invalid())
|
||||
return false;
|
||||
|
||||
if (this->getEndAddress() >= other.getStartAddress() && this->getStartAddress() <= other.getEndAddress())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u64 getStartAddress() const { return this->address; }
|
||||
[[nodiscard]] constexpr u64 getEndAddress() const { return this->address + this->size - 1;}
|
||||
[[nodiscard]] constexpr size_t getSize() const { return this->size; }
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(const Region &other) const {
|
||||
return this->address == other.address && this->size == other.size;
|
||||
}
|
||||
|
||||
constexpr static Region Invalid() {
|
||||
return { 0, 0 };
|
||||
|
||||
@@ -19,14 +19,24 @@
|
||||
#include <variant>
|
||||
#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;
|
||||
|
||||
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(unsigned long long value);
|
||||
ImVec2 scaled(const ImVec2 &vector);
|
||||
@@ -44,6 +54,7 @@ namespace hex {
|
||||
std::string to_string(u128 value);
|
||||
std::string to_string(i128 value);
|
||||
|
||||
std::optional<u8> parseBinaryString(const std::string &string);
|
||||
std::string toByteString(u64 bytes);
|
||||
std::string makePrintable(u8 c);
|
||||
|
||||
@@ -101,11 +112,6 @@ namespace hex {
|
||||
return i;
|
||||
}
|
||||
|
||||
template<class... Ts>
|
||||
struct overloaded : Ts... { using Ts::operator()...; };
|
||||
template<class... Ts>
|
||||
overloaded(Ts...) -> overloaded<Ts...>;
|
||||
|
||||
template<size_t Size>
|
||||
struct SizeTypeImpl { };
|
||||
|
||||
@@ -205,14 +211,6 @@ namespace hex {
|
||||
|
||||
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) {
|
||||
auto byteString = std::string(string);
|
||||
byteString.erase(std::remove(byteString.begin(), byteString.end(), ' '), byteString.end());
|
||||
@@ -240,26 +238,6 @@ namespace hex {
|
||||
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);
|
||||
|
||||
inline bool equalsIgnoreCase(const std::string &left, const std::string &right) {
|
||||
@@ -276,13 +254,6 @@ namespace hex {
|
||||
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>
|
||||
T get_or(const std::variant<VariantTypes...> &variant, T alt) {
|
||||
const T *value = std::get_if<T>(&variant);
|
||||
@@ -312,89 +283,4 @@ namespace hex {
|
||||
return string.substr(0, maxLength - 3) + "...";
|
||||
}
|
||||
|
||||
namespace scope_guard {
|
||||
|
||||
#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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
|
||||
#if defined(OS_MACOS)
|
||||
|
||||
#include <string>
|
||||
extern "C" {
|
||||
|
||||
extern "C" void openWebpageMacos(const char *url);
|
||||
extern "C" bool isMacosSystemDarkModeEnabled();
|
||||
void openWebpageMacos(const char *url);
|
||||
bool isMacosSystemDarkModeEnabled();
|
||||
float getBackingScaleFactor();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6,279 +6,21 @@
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/helpers/literals.hpp>
|
||||
|
||||
#include <wolv/io/buffered_reader.hpp>
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
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:
|
||||
explicit BufferedReader(Provider *provider, size_t bufferSize = 16_MiB)
|
||||
: m_provider(provider), m_bufferAddress(provider->getBaseAddress()), m_maxBufferSize(bufferSize),
|
||||
m_startAddress(provider->getBaseAddress()), m_endAddress(provider->getBaseAddress() + provider->getActualSize() - 1),
|
||||
m_buffer(bufferSize) {
|
||||
using BufferedReader::BufferedReader;
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
ProviderReader(Provider *provider, size_t bufferSize = 0x100000) : BufferedReader(provider, provider->getActualSize(), bufferSize) { }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
/**
|
||||
* @brief Represent the data source for a tab
|
||||
*/
|
||||
class Provider {
|
||||
public:
|
||||
constexpr static size_t PageSize = 0x1000'0000;
|
||||
@@ -29,7 +32,21 @@ namespace hex::prv {
|
||||
[[nodiscard]] virtual bool isResizable() 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);
|
||||
|
||||
/**
|
||||
* @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 resize(size_t newSize);
|
||||
@@ -39,7 +56,19 @@ namespace hex::prv {
|
||||
virtual void save();
|
||||
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;
|
||||
/**
|
||||
* @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;
|
||||
[[nodiscard]] virtual size_t getActualSize() const = 0;
|
||||
|
||||
@@ -64,7 +93,8 @@ namespace hex::prv {
|
||||
[[nodiscard]] virtual std::optional<u32> getPageOfAddress(u64 address) const;
|
||||
|
||||
[[nodiscard]] virtual std::string getName() const = 0;
|
||||
[[nodiscard]] virtual std::vector<std::pair<std::string, std::string>> getDataInformation() 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 bool open() = 0;
|
||||
virtual void close() = 0;
|
||||
@@ -83,7 +113,7 @@ namespace hex::prv {
|
||||
|
||||
[[nodiscard]] virtual bool hasLoadInterface() const;
|
||||
[[nodiscard]] virtual bool hasInterface() const;
|
||||
virtual void drawLoadInterface();
|
||||
virtual bool drawLoadInterface();
|
||||
virtual void drawInterface();
|
||||
|
||||
[[nodiscard]] u32 getID() const;
|
||||
@@ -102,6 +132,9 @@ namespace hex::prv {
|
||||
void skipLoadInterface() { this->m_skipLoadInterface = true; }
|
||||
[[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:
|
||||
u32 m_currPage = 0;
|
||||
u64 m_baseAddress = 0;
|
||||
@@ -115,6 +148,8 @@ namespace hex::prv {
|
||||
bool m_dirty = false;
|
||||
bool m_skipLoadInterface = false;
|
||||
|
||||
std::string m_errorMessage;
|
||||
|
||||
private:
|
||||
static u32 s_idCounter;
|
||||
};
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace ImGui {
|
||||
Texture() = default;
|
||||
Texture(const ImU8 *buffer, int size, int width = 0, int height = 0);
|
||||
explicit Texture(const char *path);
|
||||
Texture(unsigned int texture, int width, int height);
|
||||
Texture(const Texture&) = delete;
|
||||
Texture(Texture&& other) noexcept;
|
||||
|
||||
@@ -48,7 +49,7 @@ namespace ImGui {
|
||||
return this->m_textureId != nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr operator ImTextureID() {
|
||||
[[nodiscard]] constexpr operator ImTextureID() const noexcept {
|
||||
return this->m_textureId;
|
||||
}
|
||||
|
||||
@@ -87,7 +88,7 @@ namespace ImGui {
|
||||
bool ToolBarButton(const char *symbol, ImVec4 color);
|
||||
bool IconButton(const char *symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0));
|
||||
|
||||
bool InputIntegerPrefix(const char* label, const char *prefix, void *value, ImGuiDataType type, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputIntegerPrefix(const char* label, const char *prefix, void *value, ImGuiDataType type, const char *format, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputHexadecimal(const char* label, u32 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputHexadecimal(const char* label, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace hex {
|
||||
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, const std::function<void(std::fs::path)> &callback);
|
||||
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 ImVec2 getMinSize() const;
|
||||
|
||||
62
lib/libimhex/include/hex/ui/widgets.hpp
Normal file
62
lib/libimhex/include/hex/ui/widgets.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
|
||||
#include <hex/api/task.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
namespace hex::ui {
|
||||
|
||||
template<typename T>
|
||||
class SearchableWidget {
|
||||
public:
|
||||
SearchableWidget(const std::function<bool(const std::string&, const T&)> &comparator) : m_comparator(comparator) {
|
||||
|
||||
}
|
||||
|
||||
const std::vector<const T*> &draw(const auto &entries) {
|
||||
if (this->m_filteredEntries.empty() && this->m_searchBuffer.empty()) {
|
||||
for (auto &entry : entries)
|
||||
this->m_filteredEntries.push_back(&entry);
|
||||
}
|
||||
|
||||
if (ImGui::InputText("##search", this->m_searchBuffer)) {
|
||||
this->m_pendingUpdate = true;
|
||||
}
|
||||
|
||||
if (this->m_pendingUpdate && !this->m_updateTask.isRunning()) {
|
||||
this->m_pendingUpdate = false;
|
||||
this->m_filteredEntries.clear();
|
||||
this->m_filteredEntries.reserve(entries.size());
|
||||
|
||||
this->m_updateTask = TaskManager::createBackgroundTask("Searching", [this, &entries, searchBuffer = this->m_searchBuffer](Task&) {
|
||||
for (auto &entry : entries) {
|
||||
if (searchBuffer.empty() || this->m_comparator(searchBuffer, entry))
|
||||
this->m_filteredEntries.push_back(&entry);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return this->m_filteredEntries;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
this->m_filteredEntries.clear();
|
||||
}
|
||||
private:
|
||||
std::atomic<bool> m_pendingUpdate = false;
|
||||
TaskHolder m_updateTask;
|
||||
|
||||
std::string m_searchBuffer;
|
||||
std::vector<const T*> m_filteredEntries;
|
||||
std::function<bool(const std::string&, const T&)> m_comparator;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/data_processor/node.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <hex/data_processor/node.hpp>
|
||||
#include <wolv/io/file.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -19,58 +18,89 @@ namespace hex {
|
||||
|
||||
constexpr auto SettingsFile = "settings.json";
|
||||
|
||||
void load() {
|
||||
bool loaded = false;
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
fs::File file(dir / SettingsFile, fs::File::Mode::Read);
|
||||
namespace impl {
|
||||
|
||||
if (file.isValid()) {
|
||||
getSettingsData() = nlohmann::json::parse(file.readString());
|
||||
loaded = true;
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
store();
|
||||
}
|
||||
|
||||
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() {
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
wolv::io::fs::remove(dir / SettingsFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
hex::fs::remove(dir / SettingsFile);
|
||||
}
|
||||
}
|
||||
static auto getCategoryEntry(const std::string &unlocalizedCategory) {
|
||||
auto &entries = getEntries();
|
||||
const size_t curSlot = entries.size();
|
||||
auto found = entries.find(Category { unlocalizedCategory });
|
||||
|
||||
static auto getCategoryEntry(const std::string &unlocalizedCategory) {
|
||||
auto &entries = getEntries();
|
||||
const size_t curSlot = entries.size();
|
||||
auto found = entries.find(Category { unlocalizedCategory });
|
||||
if (found == entries.end()) {
|
||||
auto [iter, _] = entries.emplace(Category { unlocalizedCategory, curSlot }, std::vector<Entry> {});
|
||||
return iter;
|
||||
}
|
||||
|
||||
if (found == entries.end()) {
|
||||
auto [iter, _] = entries.emplace(Category { unlocalizedCategory, curSlot }, std::vector<Entry> {});
|
||||
return iter;
|
||||
return found;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
@@ -78,12 +108,12 @@ namespace hex {
|
||||
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);
|
||||
|
||||
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))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
@@ -91,12 +121,12 @@ namespace hex {
|
||||
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);
|
||||
|
||||
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))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
@@ -105,11 +135,11 @@ namespace hex {
|
||||
}
|
||||
|
||||
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) {
|
||||
auto &json = getSettingsData();
|
||||
auto &json = impl::getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
@@ -118,7 +148,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
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))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
@@ -127,7 +157,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
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))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
@@ -137,7 +167,7 @@ namespace hex {
|
||||
|
||||
|
||||
i64 read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue) {
|
||||
auto &json = getSettingsData();
|
||||
auto &json = impl::getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
return defaultValue;
|
||||
@@ -151,7 +181,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
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))
|
||||
return defaultValue;
|
||||
@@ -165,7 +195,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
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))
|
||||
return defaultValue;
|
||||
@@ -181,49 +211,37 @@ namespace hex {
|
||||
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 {
|
||||
|
||||
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);
|
||||
|
||||
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() {
|
||||
static std::vector<Entry> commands;
|
||||
void addHandler(Type type, const std::string &command, const impl::QueryCallback &queryCallback, const impl::DisplayCallback &displayCallback) {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -245,21 +263,27 @@ namespace hex {
|
||||
runtime.reset();
|
||||
|
||||
if (provider != nullptr) {
|
||||
runtime.setDataSource([provider](u64 offset, u8 *buffer, size_t size) {
|
||||
provider->read(offset, buffer, size);
|
||||
}, provider->getBaseAddress(), provider->getActualSize());
|
||||
runtime.setDataSource(provider->getBaseAddress(), provider->getActualSize(),
|
||||
[provider](u64 offset, u8 *buffer, size_t size) {
|
||||
provider->read(offset, buffer, size);
|
||||
},
|
||||
[provider](u64 offset, const u8 *buffer, size_t size) {
|
||||
if (provider->isWritable())
|
||||
provider->write(offset, buffer, size);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
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)
|
||||
runtime.addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
else
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -270,13 +294,13 @@ namespace hex {
|
||||
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
|
||||
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) {
|
||||
log::debug("Registered new pattern language function: {}", getFunctionName(ns, name));
|
||||
|
||||
getFunctions().push_back({
|
||||
impl::getFunctions().push_back({
|
||||
ns, name,
|
||||
parameterCount, func,
|
||||
false
|
||||
@@ -286,44 +310,66 @@ namespace hex {
|
||||
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));
|
||||
|
||||
getFunctions().push_back({
|
||||
impl::getFunctions().push_back({
|
||||
ns, name,
|
||||
parameterCount, func,
|
||||
true
|
||||
});
|
||||
}
|
||||
|
||||
std::map<std::string, pl::api::PragmaHandler> &getPragmas() {
|
||||
static std::map<std::string, pl::api::PragmaHandler> pragmas;
|
||||
|
||||
return pragmas;
|
||||
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, u32 parameterCount) {
|
||||
log::debug("Registered new pattern visualizer function: {}", name);
|
||||
impl::getVisualizers()[name] = impl::Visualizer { parameterCount, function };
|
||||
}
|
||||
|
||||
std::vector<impl::FunctionDefinition> &getFunctions() {
|
||||
static std::vector<impl::FunctionDefinition> functions;
|
||||
|
||||
return functions;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace ContentRegistry::Views {
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::map<std::string, View *> &getEntries() {
|
||||
static std::map<std::string, View *> views;
|
||||
|
||||
return views;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void impl::add(View *view) {
|
||||
log::debug("Registered new view: {}", view->getUnlocalizedName());
|
||||
|
||||
getEntries().insert({ view->getUnlocalizedName(), view });
|
||||
}
|
||||
|
||||
std::map<std::string, View *> &getEntries() {
|
||||
static std::map<std::string, View *> views;
|
||||
|
||||
return views;
|
||||
impl::getEntries().insert({ view->getUnlocalizedName(), view });
|
||||
}
|
||||
|
||||
View *getViewByName(const std::string &unlocalizedName) {
|
||||
auto &views = getEntries();
|
||||
auto &views = impl::getEntries();
|
||||
|
||||
if (views.contains(unlocalizedName))
|
||||
return views[unlocalizedName];
|
||||
@@ -338,13 +384,17 @@ namespace hex {
|
||||
void add(const std::string &unlocalizedName, const impl::Callback &function) {
|
||||
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() {
|
||||
static std::vector<impl::Entry> entries;
|
||||
namespace impl {
|
||||
|
||||
std::vector<Entry> &getEntries() {
|
||||
static std::vector<Entry> tools;
|
||||
|
||||
return tools;
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -354,21 +404,26 @@ namespace hex {
|
||||
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);
|
||||
|
||||
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) {
|
||||
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() {
|
||||
static std::vector<impl::Entry> entries;
|
||||
namespace impl {
|
||||
|
||||
std::vector<impl::Entry> &getEntries() {
|
||||
static std::vector<impl::Entry> entries;
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
namespace ContentRegistry::DataProcessorNode {
|
||||
@@ -380,42 +435,80 @@ namespace hex {
|
||||
}
|
||||
|
||||
void addSeparator() {
|
||||
getEntries().push_back({ "", "", [] { return nullptr; } });
|
||||
impl::getEntries().push_back({ "", "", [] { return nullptr; } });
|
||||
}
|
||||
|
||||
std::vector<impl::Entry> &getEntries() {
|
||||
static std::vector<impl::Entry> nodes;
|
||||
namespace impl {
|
||||
|
||||
std::vector<impl::Entry> &getEntries() {
|
||||
static std::vector<impl::Entry> nodes;
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace ContentRegistry::Language {
|
||||
|
||||
void registerLanguage(const std::string &name, const std::string &languageCode) {
|
||||
log::debug("Registered new language: {} ({})", name, languageCode);
|
||||
void addLocalization(const nlohmann::json &data) {
|
||||
if (!data.is_object())
|
||||
return;
|
||||
|
||||
getLanguages().insert({ languageCode, name });
|
||||
if (!data.contains("code") || !data.contains("country") || !data.contains("language") || !data.contains("translations")) {
|
||||
log::error("Localization data is missing required fields!");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto &code = data["code"];
|
||||
const auto &country = data["country"];
|
||||
const auto &language = data["language"];
|
||||
const auto &translations = data["translations"];
|
||||
|
||||
if (!code.is_string() || !country.is_string() || !language.is_string() || !translations.is_object()) {
|
||||
log::error("Localization data has invalid fields!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.contains("fallback")) {
|
||||
const auto &fallback = data["fallback"];
|
||||
|
||||
if (fallback.is_boolean() && fallback.get<bool>())
|
||||
LangEntry::setFallbackLanguage(code.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;
|
||||
for (auto &[key, value] : translations.items()) {
|
||||
if (!value.is_string()) {
|
||||
log::error("Localization data has invalid fields!");
|
||||
continue;
|
||||
}
|
||||
|
||||
translationDefinitions[key] = value.get<std::string>();
|
||||
}
|
||||
|
||||
impl::getLanguageDefinitions()[code.get<std::string>()].emplace_back(std::move(translationDefinitions));
|
||||
}
|
||||
|
||||
void addLocalizations(const std::string &languageCode, const LanguageDefinition &definition) {
|
||||
log::debug("Registered new localization for language {} with {} entries", languageCode, definition.getEntries().size());
|
||||
namespace impl {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
getLanguageDefinitions()[languageCode].push_back(definition);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -424,85 +517,109 @@ namespace hex {
|
||||
void registerMainMenuItem(const std::string &unlocalizedName, u32 priority) {
|
||||
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) {
|
||||
log::debug("Added new menu item to menu {} with priority {}", unlocalizedMainMenuName, priority);
|
||||
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 {}", wolv::util::combineStrings(unlocalizedMainMenuNames, " -> "), priority);
|
||||
|
||||
getMenuItems().insert({
|
||||
priority, {unlocalizedMainMenuName, function}
|
||||
impl::getMenuItems().insert({
|
||||
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) {
|
||||
getWelcomeScreenEntries().push_back(function);
|
||||
impl::getWelcomeScreenEntries().push_back(function);
|
||||
}
|
||||
|
||||
void addFooterItem(const impl::DrawCallback &function) {
|
||||
getFooterItems().push_back(function);
|
||||
impl::getFooterItems().push_back(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) {
|
||||
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) {
|
||||
getTitleBarButtons().push_back({ icon, unlocalizedTooltip, function });
|
||||
impl::getTitleBarButtons().push_back({ icon, unlocalizedTooltip, function });
|
||||
}
|
||||
|
||||
void addLayout(const std::string &unlocalizedName, const impl::LayoutFunction &function) {
|
||||
log::debug("Added new layout: {}", unlocalizedName);
|
||||
|
||||
getLayouts().push_back({ unlocalizedName, function });
|
||||
impl::getLayouts().push_back({ unlocalizedName, function });
|
||||
}
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::multimap<u32, impl::MainMenuItem> &getMainMenuItems() {
|
||||
static std::multimap<u32, impl::MainMenuItem> items;
|
||||
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;
|
||||
return items;
|
||||
}
|
||||
std::multimap<u32, impl::MenuItem> &getMenuItems() {
|
||||
static std::multimap<u32, impl::MenuItem> items;
|
||||
|
||||
return items;
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
std::vector<impl::DrawCallback> &getWelcomeScreenEntries() {
|
||||
static std::vector<impl::DrawCallback> entries;
|
||||
std::vector<impl::DrawCallback> &getWelcomeScreenEntries() {
|
||||
static std::vector<impl::DrawCallback> entries;
|
||||
|
||||
return entries;
|
||||
}
|
||||
std::vector<impl::DrawCallback> &getFooterItems() {
|
||||
static std::vector<impl::DrawCallback> items;
|
||||
return entries;
|
||||
}
|
||||
std::vector<impl::DrawCallback> &getFooterItems() {
|
||||
static std::vector<impl::DrawCallback> items;
|
||||
|
||||
return items;
|
||||
}
|
||||
std::vector<impl::DrawCallback> &getToolbarItems() {
|
||||
static std::vector<impl::DrawCallback> items;
|
||||
return items;
|
||||
}
|
||||
std::vector<impl::DrawCallback> &getToolbarItems() {
|
||||
static std::vector<impl::DrawCallback> items;
|
||||
|
||||
return items;
|
||||
}
|
||||
std::vector<impl::SidebarItem> &getSidebarItems() {
|
||||
static std::vector<impl::SidebarItem> items;
|
||||
return items;
|
||||
}
|
||||
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 items;
|
||||
}
|
||||
std::vector<impl::TitleBarButton> &getTitleBarButtons() {
|
||||
static std::vector<impl::TitleBarButton> buttons;
|
||||
|
||||
return buttons;
|
||||
}
|
||||
return buttons;
|
||||
}
|
||||
|
||||
std::vector<impl::Layout> &getLayouts() {
|
||||
static std::vector<impl::Layout> layouts;
|
||||
std::vector<impl::Layout> &getLayouts() {
|
||||
static std::vector<impl::Layout> layouts;
|
||||
|
||||
return layouts;
|
||||
}
|
||||
|
||||
return layouts;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -515,12 +632,18 @@ namespace hex {
|
||||
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 {
|
||||
@@ -528,13 +651,17 @@ namespace hex {
|
||||
void add(const std::string &unlocalizedName, const impl::Callback &callback) {
|
||||
log::debug("Registered new data formatter: {}", unlocalizedName);
|
||||
|
||||
getEntries().push_back({ unlocalizedName, callback });
|
||||
impl::getEntries().push_back({ unlocalizedName, callback });
|
||||
}
|
||||
|
||||
std::vector<impl::Entry> &getEntries() {
|
||||
static std::vector<impl::Entry> entries;
|
||||
namespace impl {
|
||||
|
||||
std::vector<impl::Entry> &getEntries() {
|
||||
static std::vector<impl::Entry> entries;
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -545,13 +672,17 @@ namespace hex {
|
||||
for (const auto &extension : extensions)
|
||||
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() {
|
||||
static std::vector<impl::Entry> entries;
|
||||
namespace impl {
|
||||
|
||||
std::vector<impl::Entry> &getEntries() {
|
||||
static std::vector<impl::Entry> entries;
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -560,7 +691,7 @@ namespace hex {
|
||||
|
||||
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 {
|
||||
u8 *data;
|
||||
i32 maxChars;
|
||||
@@ -589,29 +720,69 @@ namespace hex {
|
||||
return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Escape);
|
||||
}
|
||||
|
||||
void impl::addDataVisualizer(const std::string &unlocalizedName, DataVisualizer *visualizer) {
|
||||
getVisualizers().insert({ unlocalizedName, visualizer });
|
||||
bool DataVisualizer::drawDefaultTextEditingTextBox(u64 address, std::string &data, ImGuiInputTextFlags flags) const {
|
||||
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 {
|
||||
|
||||
std::vector<Hash *> &impl::getHashes() {
|
||||
static std::vector<Hash *> hashes;
|
||||
namespace impl {
|
||||
|
||||
return hashes;
|
||||
}
|
||||
std::vector<Hash *> &getHashes() {
|
||||
static std::vector<Hash *> hashes;
|
||||
|
||||
return hashes;
|
||||
}
|
||||
|
||||
void add(Hash *hash) {
|
||||
getHashes().push_back(hash);
|
||||
}
|
||||
|
||||
void impl::add(Hash *hash) {
|
||||
getHashes().push_back(hash);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,19 +19,6 @@
|
||||
|
||||
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 {
|
||||
|
||||
@@ -312,17 +299,19 @@ namespace hex {
|
||||
|
||||
EventManager::post<EventProviderDeleted>(provider);
|
||||
|
||||
s_providers.erase(it);
|
||||
if (!s_providers.empty() && it - s_providers.begin() == s_currentProvider)
|
||||
setCurrentProvider(0);
|
||||
|
||||
s_providers.erase(it);
|
||||
if (s_providers.empty())
|
||||
EventManager::post<EventProviderChanged>(provider, nullptr);
|
||||
else if (it - s_providers.begin() == s_currentProvider)
|
||||
setCurrentProvider(0);
|
||||
|
||||
provider->close();
|
||||
EventManager::post<EventProviderClosed>(provider);
|
||||
|
||||
delete provider;
|
||||
TaskManager::runWhenTasksFinished([provider] {
|
||||
delete provider;
|
||||
});
|
||||
}
|
||||
|
||||
prv::Provider* createProvider(const std::string &unlocalizedName, bool skipLoadInterface) {
|
||||
@@ -406,6 +395,18 @@ 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) {
|
||||
EventManager::post<EventSetTaskBarIconState>(u32(state), u32(type), progress);
|
||||
}
|
||||
|
||||
const ProgramArguments &getProgramArguments() {
|
||||
return impl::s_programArguments;
|
||||
@@ -478,19 +479,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
|
||||
static Theme s_theme;
|
||||
static bool s_systemThemeDetection;
|
||||
|
||||
void setTheme(Theme theme) {
|
||||
s_theme = theme;
|
||||
|
||||
EventManager::post<EventSettingsChanged>();
|
||||
}
|
||||
|
||||
Theme getTheme() {
|
||||
return s_theme;
|
||||
}
|
||||
|
||||
|
||||
void enableSystemThemeDetection(bool enabled) {
|
||||
s_systemThemeDetection = enabled;
|
||||
|
||||
@@ -7,9 +7,14 @@ namespace hex {
|
||||
std::string LangEntry::s_fallbackLanguage;
|
||||
std::map<std::string, std::string> LangEntry::s_currStrings;
|
||||
|
||||
LanguageDefinition::LanguageDefinition(std::initializer_list<std::pair<std::string, std::string>> entries) {
|
||||
for (const auto &pair : entries)
|
||||
this->m_entries.insert(pair);
|
||||
LanguageDefinition::LanguageDefinition(std::map<std::string, std::string> &&entries) {
|
||||
for (const auto &[key, value] : entries) {
|
||||
if (value.empty())
|
||||
continue;
|
||||
|
||||
this->m_entries.insert({ key, value });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const std::map<std::string, std::string> &LanguageDefinition::getEntries() const {
|
||||
@@ -71,7 +76,7 @@ namespace hex {
|
||||
void LangEntry::loadLanguage(const std::string &language) {
|
||||
LangEntry::s_currStrings.clear();
|
||||
|
||||
auto &definitions = ContentRegistry::Language::getLanguageDefinitions();
|
||||
auto &definitions = ContentRegistry::Language::impl::getLanguageDefinitions();
|
||||
|
||||
if (!definitions.contains(language))
|
||||
return;
|
||||
@@ -87,7 +92,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <system_error>
|
||||
|
||||
@@ -17,7 +19,7 @@ namespace hex {
|
||||
return;
|
||||
}
|
||||
#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) {
|
||||
log::error("dlopen failed: {}!", dlerror());
|
||||
@@ -69,7 +71,7 @@ namespace hex {
|
||||
bool Plugin::initializePlugin() const {
|
||||
const auto requestedVersion = getCompatibleVersion();
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -145,7 +147,7 @@ namespace hex {
|
||||
std::vector<Plugin> PluginManager::s_plugins;
|
||||
|
||||
bool PluginManager::load(const std::fs::path &pluginFolder) {
|
||||
if (!fs::exists(pluginFolder))
|
||||
if (!wolv::io::fs::exists(pluginFolder))
|
||||
return false;
|
||||
|
||||
PluginManager::s_pluginFolder = pluginFolder;
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <wolv/utils/guards.hpp>
|
||||
#include <wolv/io/fs.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
constexpr static auto MetadataHeaderMagic = "HEX";
|
||||
@@ -17,7 +20,14 @@ namespace hex {
|
||||
std::fs::path ProjectFile::s_currProjectPath;
|
||||
|
||||
bool ProjectFile::load(const std::fs::path &filePath) {
|
||||
if (!fs::exists(filePath) || !fs::isRegularFile(filePath))
|
||||
auto originalPath = ProjectFile::s_currProjectPath;
|
||||
|
||||
ProjectFile::s_currProjectPath = filePath;
|
||||
auto resetPath = SCOPE_GUARD {
|
||||
ProjectFile::s_currProjectPath = originalPath;
|
||||
};
|
||||
|
||||
if (!wolv::io::fs::exists(filePath) || !wolv::io::fs::isRegularFile(filePath))
|
||||
return false;
|
||||
if (filePath.extension() != ".hexproj")
|
||||
return false;
|
||||
@@ -30,23 +40,26 @@ namespace hex {
|
||||
return false;
|
||||
|
||||
{
|
||||
const auto metadataContent = tar.read(MetadataPath);
|
||||
const auto metadataContent = tar.readVector(MetadataPath);
|
||||
|
||||
if (!std::string(metadataContent.begin(), metadataContent.end()).starts_with(MetadataHeaderMagic))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
||||
auto providers = auto(ImHexApi::Provider::getProviders());
|
||||
for (const auto &provider : providers) {
|
||||
ImHexApi::Provider::remove(provider);
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
for (const auto &handler : ProjectFile::getHandlers()) {
|
||||
try {
|
||||
if (!handler.load(handler.basePath, tar))
|
||||
if (!handler.load(handler.basePath, tar)) {
|
||||
log::warn("Project file handler for {} failed to load {}", filePath.string(), handler.basePath.string());
|
||||
result = false;
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
log::info("{}", e.what());
|
||||
log::warn("Project file handler for {} failed to load {}: {}", filePath.string(), handler.basePath.string(), e.what());
|
||||
result = false;
|
||||
}
|
||||
|
||||
@@ -72,15 +85,23 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
ProjectFile::s_currProjectPath = filePath;
|
||||
resetPath.release();
|
||||
EventManager::post<RequestUpdateWindowTitle>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProjectFile::store(std::optional<std::fs::path> filePath) {
|
||||
auto originalPath = ProjectFile::s_currProjectPath;
|
||||
|
||||
if (!filePath.has_value())
|
||||
filePath = ProjectFile::s_currProjectPath;
|
||||
|
||||
ProjectFile::s_currProjectPath = filePath.value();
|
||||
auto resetPath = SCOPE_GUARD {
|
||||
ProjectFile::s_currProjectPath = originalPath;
|
||||
};
|
||||
|
||||
Tar tar(*filePath, Tar::Mode::Create);
|
||||
if (!tar.isValid())
|
||||
return false;
|
||||
@@ -110,12 +131,29 @@ namespace hex {
|
||||
|
||||
{
|
||||
const auto metadataContent = hex::format("{}\n{}", MetadataHeaderMagic, IMHEX_VERSION);
|
||||
tar.write(MetadataPath, metadataContent);
|
||||
tar.writeString(MetadataPath, metadataContent);
|
||||
}
|
||||
|
||||
ImHexApi::Provider::resetDirty();
|
||||
resetPath.release();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ProjectFile::hasPath() {
|
||||
return !ProjectFile::s_currProjectPath.empty();
|
||||
}
|
||||
|
||||
void ProjectFile::clearPath() {
|
||||
ProjectFile::s_currProjectPath.clear();
|
||||
}
|
||||
|
||||
std::fs::path ProjectFile::getPath() {
|
||||
return ProjectFile::s_currProjectPath;
|
||||
}
|
||||
|
||||
void ProjectFile::setPath(const std::fs::path &path) {
|
||||
ProjectFile::s_currProjectPath = path;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,10 +8,11 @@
|
||||
|
||||
namespace hex {
|
||||
|
||||
std::mutex TaskManager::s_deferredCallsMutex;
|
||||
std::mutex TaskManager::s_deferredCallsMutex, TaskManager::s_tasksFinishedMutex;
|
||||
|
||||
std::list<std::shared_ptr<Task>> TaskManager::s_tasks, TaskManager::s_taskQueue;
|
||||
std::list<std::function<void()>> TaskManager::s_deferredCalls;
|
||||
std::list<std::function<void()>> TaskManager::s_tasksFinishedCallbacks;
|
||||
|
||||
std::mutex TaskManager::s_queueMutex;
|
||||
std::condition_variable TaskManager::s_jobCondVar;
|
||||
@@ -46,7 +47,7 @@ namespace hex {
|
||||
void Task::update(u64 value) {
|
||||
this->m_currValue = value;
|
||||
|
||||
if (this->m_shouldInterrupt)
|
||||
if (this->m_shouldInterrupt) [[unlikely]]
|
||||
throw TaskInterruptor();
|
||||
}
|
||||
|
||||
@@ -238,8 +239,16 @@ namespace hex {
|
||||
}
|
||||
|
||||
void TaskManager::collectGarbage() {
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
std::unique_lock lock1(s_queueMutex);
|
||||
std::unique_lock lock2(s_deferredCallsMutex);
|
||||
|
||||
std::erase_if(s_tasks, [](const auto &task) { return task->isFinished() && !task->hadException(); });
|
||||
|
||||
if (s_tasks.empty()) {
|
||||
for (auto &call : s_tasksFinishedCallbacks)
|
||||
call();
|
||||
s_tasksFinishedCallbacks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
std::list<std::shared_ptr<Task>> &TaskManager::getRunningTasks() {
|
||||
@@ -254,6 +263,14 @@ namespace hex {
|
||||
});
|
||||
}
|
||||
|
||||
size_t TaskManager::getRunningBackgroundTaskCount() {
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
|
||||
return std::count_if(s_tasks.begin(), s_tasks.end(), [](const auto &task){
|
||||
return task->isBackgroundTask();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void TaskManager::doLater(const std::function<void()> &function) {
|
||||
std::scoped_lock lock(s_deferredCallsMutex);
|
||||
@@ -270,4 +287,10 @@ namespace hex {
|
||||
s_deferredCalls.clear();
|
||||
}
|
||||
|
||||
void TaskManager::runWhenTasksFinished(const std::function<void()> &function) {
|
||||
std::scoped_lock lock(s_tasksFinishedMutex);
|
||||
|
||||
s_tasksFinishedCallbacks.push_back(function);
|
||||
}
|
||||
|
||||
}
|
||||
207
lib/libimhex/source/api/theme_manager.cpp
Normal file
207
lib/libimhex/source/api/theme_manager.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
#include <hex/api/theme_manager.hpp>
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
std::map<std::string, nlohmann::json> ThemeManager::s_themes;
|
||||
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_currTheme;
|
||||
|
||||
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] = { colorMap, getFunction, setFunction };
|
||||
}
|
||||
|
||||
void ThemeManager::addStyleHandler(const std::string &name, const StyleMap &styleMap) {
|
||||
s_styleHandlers[name] = { styleMap };
|
||||
}
|
||||
|
||||
void ThemeManager::addTheme(const std::string &content) {
|
||||
auto theme = nlohmann::json::parse(content);
|
||||
if (theme.contains("name") && theme.contains("colors")) {
|
||||
s_themes[theme["name"].get<std::string>()] = theme;
|
||||
} else {
|
||||
hex::log::error("Invalid theme file");
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<ImColor> ThemeManager::parseColorString(const std::string &colorString) {
|
||||
if (colorString == "auto")
|
||||
return ImVec4(0, 0, 0, -1);
|
||||
|
||||
if (colorString.length() != 9 || colorString[0] != '#')
|
||||
return std::nullopt;
|
||||
|
||||
u32 color = 0;
|
||||
|
||||
for (u32 i = 1; i < 9; i++) {
|
||||
color <<= 4;
|
||||
if (colorString[i] >= '0' && colorString[i] <= '9')
|
||||
color |= colorString[i] - '0';
|
||||
else if (colorString[i] >= 'A' && colorString[i] <= 'F')
|
||||
color |= colorString[i] - 'A' + 10;
|
||||
else if (colorString[i] >= 'a' && colorString[i] <= 'f')
|
||||
color |= colorString[i] - 'a' + 10;
|
||||
else
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (color == 0x00000000)
|
||||
return ImVec4(0, 0, 0, -1);
|
||||
|
||||
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) {
|
||||
if (!s_themes.contains(name)) {
|
||||
if (s_themes.empty()) {
|
||||
return;
|
||||
} else {
|
||||
const std::string &defaultTheme = s_themes.begin()->first;
|
||||
hex::log::error("Theme '{}' does not exist, using default theme '{}' instead!", name, defaultTheme);
|
||||
name = defaultTheme;
|
||||
}
|
||||
}
|
||||
|
||||
const auto &theme = s_themes[name];
|
||||
|
||||
if (theme.contains("base")) {
|
||||
if (theme["base"].is_string()) {
|
||||
if (theme["base"] != name)
|
||||
changeTheme(theme["base"].get<std::string>());
|
||||
} else {
|
||||
hex::log::error("Theme '{}' has invalid base theme!", name);
|
||||
}
|
||||
}
|
||||
|
||||
if (theme.contains("colors")) {
|
||||
for (const auto&[type, content] : theme["colors"].items()) {
|
||||
if (!s_themeHandlers.contains(type)) {
|
||||
log::warn("No theme handler found for '{}'", type);
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto &handler = s_themeHandlers[type];
|
||||
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")) {
|
||||
for (const auto&[type, content] : theme["styles"].items()) {
|
||||
if (!s_styleHandlers.contains(type)) {
|
||||
log::warn("No style handler found for '{}'", type);
|
||||
continue;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (theme.contains("image_postfix")) {
|
||||
if (theme["image_postfix"].is_string()) {
|
||||
s_imagePostfix = theme["image_postfix"].get<std::string>();
|
||||
} else {
|
||||
hex::log::error("Theme '{}' has invalid image postfix!", name);
|
||||
}
|
||||
}
|
||||
|
||||
s_currTheme = name;
|
||||
}
|
||||
|
||||
const std::string &ThemeManager::getThemeImagePostfix() {
|
||||
return s_imagePostfix;
|
||||
}
|
||||
|
||||
std::vector<std::string> ThemeManager::getThemeNames() {
|
||||
std::vector<std::string> themeNames;
|
||||
for (const auto &[name, theme] : s_themes)
|
||||
themeNames.push_back(name);
|
||||
|
||||
return themeNames;
|
||||
}
|
||||
|
||||
void ThemeManager::reset() {
|
||||
ThemeManager::s_themes.clear();
|
||||
ThemeManager::s_styleHandlers.clear();
|
||||
ThemeManager::s_themeHandlers.clear();
|
||||
ThemeManager::s_imagePostfix.clear();
|
||||
ThemeManager::s_currTheme.clear();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@ namespace hex::dp {
|
||||
attr.setParentNode(this);
|
||||
}
|
||||
|
||||
std::vector<u8> Node::getBufferOnInput(u32 index) {
|
||||
const std::vector<u8>& Node::getBufferOnInput(u32 index) {
|
||||
auto attribute = this->getConnectedInputAttribute(index);
|
||||
|
||||
if (attribute == nullptr)
|
||||
@@ -28,61 +28,65 @@ namespace hex::dp {
|
||||
|
||||
auto &outputData = attribute->getOutputData();
|
||||
|
||||
if (!outputData.has_value())
|
||||
if (outputData.empty())
|
||||
throwNodeError("No data available at connected attribute");
|
||||
|
||||
return outputData.value();
|
||||
return outputData;
|
||||
}
|
||||
|
||||
i128 Node::getIntegerOnInput(u32 index) {
|
||||
const i128& Node::getIntegerOnInput(u32 index) {
|
||||
auto attribute = this->getConnectedInputAttribute(index);
|
||||
|
||||
if (attribute == nullptr)
|
||||
throwNodeError(hex::format("Nothing connected to input '{0}'", LangEntry(this->m_attributes[index].getUnlocalizedName())));
|
||||
auto &outputData = [&] -> std::vector<u8>& {
|
||||
if (attribute != nullptr) {
|
||||
if (attribute->getType() != Attribute::Type::Integer)
|
||||
throwNodeError("Tried to read integer from non-integer attribute");
|
||||
|
||||
if (attribute->getType() != Attribute::Type::Integer)
|
||||
throwNodeError("Tried to read integer from non-integer attribute");
|
||||
markInputProcessed(index);
|
||||
attribute->getParentNode()->process();
|
||||
|
||||
markInputProcessed(index);
|
||||
attribute->getParentNode()->process();
|
||||
return attribute->getOutputData();
|
||||
} else {
|
||||
return this->getAttribute(index).getOutputData();
|
||||
}
|
||||
}();
|
||||
|
||||
auto &outputData = attribute->getOutputData();
|
||||
|
||||
if (!outputData.has_value())
|
||||
if (outputData.empty())
|
||||
throwNodeError("No data available at connected attribute");
|
||||
|
||||
if (outputData->size() < sizeof(u64))
|
||||
if (outputData.size() < sizeof(i128))
|
||||
throwNodeError("Not enough data provided for integer");
|
||||
|
||||
return *reinterpret_cast<i64 *>(outputData->data());
|
||||
return *reinterpret_cast<i128 *>(outputData.data());
|
||||
}
|
||||
|
||||
long double Node::getFloatOnInput(u32 index) {
|
||||
const long double& Node::getFloatOnInput(u32 index) {
|
||||
auto attribute = this->getConnectedInputAttribute(index);
|
||||
|
||||
if (attribute == nullptr)
|
||||
throwNodeError(hex::format("Nothing connected to input '{0}'", LangEntry(this->m_attributes[index].getUnlocalizedName())));
|
||||
auto &outputData = [&] -> std::vector<u8>& {
|
||||
if (attribute != nullptr) {
|
||||
if (attribute->getType() != Attribute::Type::Float)
|
||||
throwNodeError("Tried to read integer from non-float attribute");
|
||||
|
||||
if (attribute->getType() != Attribute::Type::Float)
|
||||
throwNodeError("Tried to read float from non-float attribute");
|
||||
markInputProcessed(index);
|
||||
attribute->getParentNode()->process();
|
||||
|
||||
markInputProcessed(index);
|
||||
attribute->getParentNode()->process();
|
||||
return attribute->getOutputData();
|
||||
} else {
|
||||
return this->getAttribute(index).getOutputData();
|
||||
}
|
||||
}();
|
||||
|
||||
auto &outputData = attribute->getOutputData();
|
||||
|
||||
if (!outputData.has_value())
|
||||
if (outputData.empty())
|
||||
throwNodeError("No data available at connected attribute");
|
||||
|
||||
if (outputData->size() < sizeof(long double))
|
||||
if (outputData.size() < sizeof(long double))
|
||||
throwNodeError("Not enough data provided for float");
|
||||
|
||||
long double result = 0;
|
||||
std::memcpy(&result, outputData->data(), sizeof(long double));
|
||||
return result;
|
||||
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())
|
||||
throwNodeError("Attribute index out of bounds!");
|
||||
|
||||
@@ -91,7 +95,7 @@ namespace hex::dp {
|
||||
if (attribute.getIOType() != Attribute::IOType::Out)
|
||||
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) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <hex/helpers/crypto.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/base64.h>
|
||||
@@ -11,13 +11,10 @@
|
||||
#include <mbedtls/sha1.h>
|
||||
#include <mbedtls/sha256.h>
|
||||
#include <mbedtls/sha512.h>
|
||||
#include <mbedtls/aes.h>
|
||||
#include <mbedtls/cipher.h>
|
||||
|
||||
#include <array>
|
||||
#include <span>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <bit>
|
||||
@@ -157,7 +154,7 @@ namespace hex::crypt {
|
||||
return crc.checksum();
|
||||
}
|
||||
|
||||
u16 crc8(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorOut, bool reflectIn, bool reflectOut) {
|
||||
u8 crc8(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorOut, bool reflectIn, bool reflectOut) {
|
||||
return calcCrc<8>(data, offset, size, polynomial, init, xorOut, reflectIn, reflectOut);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,16 @@
|
||||
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
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) {
|
||||
case Type::Thingy:
|
||||
parseThingyFile(file);
|
||||
parse(file.readString());
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@@ -17,13 +20,25 @@ namespace hex {
|
||||
this->m_valid = true;
|
||||
}
|
||||
|
||||
std::pair<std::string_view, size_t> EncodingFile::getEncodingFor(const std::vector<u8> &buffer) const {
|
||||
EncodingFile::EncodingFile(Type type, const std::string &content) {
|
||||
switch (type) {
|
||||
case Type::Thingy:
|
||||
parse(content);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
this->m_valid = true;
|
||||
}
|
||||
|
||||
std::pair<std::string_view, size_t> EncodingFile::getEncodingFor(std::span<u8> buffer) const {
|
||||
for (auto riter = this->m_mapping.crbegin(); riter != this->m_mapping.crend(); ++riter) {
|
||||
const auto &[size, mapping] = *riter;
|
||||
|
||||
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))
|
||||
return { mapping.at(key), size };
|
||||
}
|
||||
@@ -31,8 +46,23 @@ namespace hex {
|
||||
return { ".", 1 };
|
||||
}
|
||||
|
||||
void EncodingFile::parseThingyFile(fs::File &file) {
|
||||
for (const auto &line : splitString(file.readString(), "\n")) {
|
||||
size_t EncodingFile::getEncodingLengthFor(std::span<u8> buffer) const {
|
||||
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;
|
||||
{
|
||||
@@ -51,15 +81,17 @@ namespace hex {
|
||||
if (fromBytes.empty()) continue;
|
||||
|
||||
if (to.length() > 1)
|
||||
hex::trim(to);
|
||||
to = wolv::util::trim(to);
|
||||
if (to.empty())
|
||||
to = " ";
|
||||
|
||||
if (!this->m_mapping.contains(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 ?: getSize();
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +1,8 @@
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/helpers/fs_macos.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
#include <hex/helpers/intrinsics.hpp>
|
||||
#include <hex/helpers/net.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <xdg.hpp>
|
||||
|
||||
@@ -20,93 +17,64 @@
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
#include <wolv/io/fs.hpp>
|
||||
|
||||
namespace hex::fs {
|
||||
|
||||
std::optional<std::fs::path> getExecutablePath() {
|
||||
#if defined(OS_WINDOWS)
|
||||
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) {
|
||||
static std::function<void(const std::string&)> s_fileBrowserErrorCallback;
|
||||
void setFileBrowserErrorCallback(const std::function<void(const std::string&)> &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) {
|
||||
NFD::Init();
|
||||
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::ClearError();
|
||||
|
||||
nfdchar_t *outPath = nullptr;
|
||||
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::UniquePathSet outPaths;
|
||||
nfdresult_t result;
|
||||
switch (mode) {
|
||||
case DialogMode::Open:
|
||||
result = NFD::OpenDialog(outPath, validExtensions.data(), validExtensions.size(), defaultPath.c_str());
|
||||
if (multiple)
|
||||
result = NFD::OpenDialogMultiple(outPaths, validExtensions.data(), validExtensions.size(), defaultPath.empty() ? nullptr : defaultPath.c_str());
|
||||
else
|
||||
result = NFD::OpenDialog(outPath, validExtensions.data(), validExtensions.size(), defaultPath.empty() ? nullptr : defaultPath.c_str());
|
||||
break;
|
||||
case DialogMode::Save:
|
||||
result = NFD::SaveDialog(outPath, validExtensions.data(), validExtensions.size(), defaultPath.c_str());
|
||||
result = NFD::SaveDialog(outPath, validExtensions.data(), validExtensions.size(), defaultPath.empty() ? nullptr : defaultPath.c_str());
|
||||
break;
|
||||
case DialogMode::Folder:
|
||||
result = NFD::PickFolder(outPath, defaultPath.c_str());
|
||||
result = NFD::PickFolder(outPath, defaultPath.empty() ? nullptr : defaultPath.c_str());
|
||||
break;
|
||||
default:
|
||||
hex::unreachable();
|
||||
std::unreachable();
|
||||
}
|
||||
|
||||
if (result == NFD_OKAY){
|
||||
if(outPath != nullptr) {
|
||||
callback(reinterpret_cast<char8_t*>(outPath));
|
||||
NFD::FreePath(outPath);
|
||||
callback(reinterpret_cast<char8_t*>(outPath.get()));
|
||||
}
|
||||
} else if (result==NFD_ERROR) {
|
||||
if (outPaths != nullptr) {
|
||||
nfdpathsetsize_t numPaths = 0;
|
||||
if (NFD::PathSet::Count(outPaths, numPaths) == NFD_OKAY) {
|
||||
for (size_t i = 0; i < numPaths; i++) {
|
||||
NFD::UniquePathSetPath path;
|
||||
if (NFD::PathSet::GetPath(outPaths, i, path) == NFD_OKAY)
|
||||
callback(reinterpret_cast<char8_t*>(path.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (result == NFD_ERROR) {
|
||||
log::error("Requested file dialog returned an error: {}", NFD::GetError());
|
||||
if (s_fileBrowserErrorCallback != nullptr)
|
||||
s_fileBrowserErrorCallback();
|
||||
s_fileBrowserErrorCallback(NFD::GetError() ? NFD::GetError() : "No details");
|
||||
}
|
||||
|
||||
NFD::Quit();
|
||||
@@ -114,7 +82,7 @@ namespace hex::fs {
|
||||
return result == NFD_OKAY;
|
||||
}
|
||||
|
||||
static std::vector<std::fs::path> getDataPaths() {
|
||||
std::vector<std::fs::path> getDataPaths() {
|
||||
std::vector<std::fs::path> paths;
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
@@ -129,14 +97,7 @@ namespace hex::fs {
|
||||
|
||||
#elif defined(OS_MACOS)
|
||||
|
||||
std::fs::path applicationSupportDirPath;
|
||||
{
|
||||
auto string = getMacApplicationSupportDirectoryPath();
|
||||
applicationSupportDirPath = std::string(string);
|
||||
macFree(string);
|
||||
}
|
||||
|
||||
paths.push_back(applicationSupportDirPath);
|
||||
paths.push_back(wolv::io::fs::getApplicationSupportDirectoryPath());
|
||||
|
||||
#elif defined(OS_LINUX)
|
||||
|
||||
@@ -152,12 +113,12 @@ namespace hex::fs {
|
||||
|
||||
#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);
|
||||
|
||||
#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());
|
||||
|
||||
#endif
|
||||
@@ -166,6 +127,10 @@ namespace hex::fs {
|
||||
auto additionalDirs = ImHexApi::System::getAdditionalFolderPaths();
|
||||
std::copy(additionalDirs.begin(), additionalDirs.end(), std::back_inserter(paths));
|
||||
|
||||
if (ProjectFile::hasPath()) {
|
||||
paths.push_back(ProjectFile::getPath().parent_path());
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
@@ -175,21 +140,11 @@ namespace hex::fs {
|
||||
#elif defined(OS_MACOS)
|
||||
return getDataPaths();
|
||||
#elif defined(OS_LINUX)
|
||||
std::vector<std::fs::path> paths;
|
||||
|
||||
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;
|
||||
return {xdg::ConfigHomeDir() / "imhex"};
|
||||
#endif
|
||||
}
|
||||
|
||||
constexpr std::vector<std::fs::path> appendPath(std::vector<std::fs::path> paths, const std::fs::path &folder) {
|
||||
std::vector<std::fs::path> appendPath(std::vector<std::fs::path> paths, const std::fs::path &folder) {
|
||||
for (auto &path : paths)
|
||||
path = path / folder;
|
||||
|
||||
@@ -221,11 +176,14 @@ namespace hex::fs {
|
||||
result = appendPath(getDataPaths(), "encodings");
|
||||
break;
|
||||
case ImHexPath::Logs:
|
||||
result = appendPath(getConfigPaths(), "logs");
|
||||
result = appendPath(getDataPaths(), "logs");
|
||||
break;
|
||||
case ImHexPath::Plugins:
|
||||
result = appendPath(getPluginPaths(), "plugins");
|
||||
break;
|
||||
case ImHexPath::Libraries:
|
||||
result = appendPath(getPluginPaths(), "lib");
|
||||
break;
|
||||
case ImHexPath::Resources:
|
||||
result = appendPath(getDataPaths(), "resources");
|
||||
break;
|
||||
@@ -238,9 +196,6 @@ namespace hex::fs {
|
||||
case ImHexPath::PatternsInclude:
|
||||
result = appendPath(getDataPaths(), "includes");
|
||||
break;
|
||||
case ImHexPath::Python:
|
||||
result = appendPath(getDataPaths(), "python");
|
||||
break;
|
||||
case ImHexPath::Yara:
|
||||
result = appendPath(getDataPaths(), "yara");
|
||||
break;
|
||||
@@ -253,17 +208,41 @@ namespace hex::fs {
|
||||
case ImHexPath::Inspectors:
|
||||
result = appendPath(getDefaultPaths(ImHexPath::Scripts), "inspectors");
|
||||
break;
|
||||
case ImHexPath::Nodes:
|
||||
result = appendPath(getDefaultPaths(ImHexPath::Scripts), "nodes");
|
||||
break;
|
||||
case ImHexPath::Themes:
|
||||
result = appendPath(getDataPaths(), "themes");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!listNonExisting) {
|
||||
result.erase(std::remove_if(result.begin(), result.end(), [](const auto &path) {
|
||||
return !fs::isDirectory(path);
|
||||
return !wolv::io::fs::isDirectory(path);
|
||||
}), result.end());
|
||||
}
|
||||
|
||||
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) {
|
||||
#if defined(OS_WINDOWS)
|
||||
size_t size = GetShortPathNameW(path.c_str(), nullptr, 0);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user