mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-28 15:57:03 -05:00
Compare commits
352 Commits
v1.31.0
...
disassembl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abd21637ce | ||
|
|
5b1f5c0dd8 | ||
|
|
fcdaf4685b | ||
|
|
2a55cd8a4f | ||
|
|
f71fa2f704 | ||
|
|
9afbfec64e | ||
|
|
ec7e89b5cf | ||
|
|
e6ad54b53b | ||
|
|
768982b67a | ||
|
|
4fd3167bb3 | ||
|
|
866cb5706d | ||
|
|
2cf642a2a4 | ||
|
|
f26076fb90 | ||
|
|
519d965a36 | ||
|
|
a50bb39978 | ||
|
|
8ee234e5a6 | ||
|
|
e370fdb0fc | ||
|
|
09904b77eb | ||
|
|
5e32b693f3 | ||
|
|
cceac20197 | ||
|
|
540e8458a5 | ||
|
|
80984f28ec | ||
|
|
56064df8d5 | ||
|
|
df7cc1fefd | ||
|
|
23fc232c47 | ||
|
|
37ce37862a | ||
|
|
75e26458cc | ||
|
|
e75fcadd8f | ||
|
|
2483c421d2 | ||
|
|
abf6e37938 | ||
|
|
eae73b3113 | ||
|
|
cbf82d7476 | ||
|
|
4ddd293210 | ||
|
|
813a95d283 | ||
|
|
c02c27b63d | ||
|
|
f6d4d5ab22 | ||
|
|
284f8534ab | ||
|
|
8e7716ebcc | ||
|
|
1b665fa1b3 | ||
|
|
9cbfaed5fe | ||
|
|
494223fff6 | ||
|
|
af77b8dfc4 | ||
|
|
47b6826ac4 | ||
|
|
64be4e692c | ||
|
|
8e8a926ad9 | ||
|
|
9306017f01 | ||
|
|
55c0170791 | ||
|
|
671b032125 | ||
|
|
f79fd0edbc | ||
|
|
8d20277a62 | ||
|
|
88032a85cd | ||
|
|
c821967633 | ||
|
|
7e660450ed | ||
|
|
e5f36ca08d | ||
|
|
d8249b3a7c | ||
|
|
3c36ef2c69 | ||
|
|
b050039e35 | ||
|
|
920c6f6507 | ||
|
|
96a3a74e08 | ||
|
|
fb00f688a8 | ||
|
|
d6d379108b | ||
|
|
d34ad33c3c | ||
|
|
8bdb39983e | ||
|
|
59b363d9b2 | ||
|
|
71df45a347 | ||
|
|
0b06b1e1e8 | ||
|
|
45a3ea18d0 | ||
|
|
951d74e24b | ||
|
|
445dba85ac | ||
|
|
d50533bbaf | ||
|
|
eafeac4e7b | ||
|
|
58c3b95c84 | ||
|
|
5a58ed5114 | ||
|
|
b619744093 | ||
|
|
32276b820f | ||
|
|
74e246feed | ||
|
|
de4ea4081a | ||
|
|
af18501726 | ||
|
|
ae24ccdfe6 | ||
|
|
095da62250 | ||
|
|
909f4b7fe8 | ||
|
|
c89a870fe9 | ||
|
|
fc23efdb25 | ||
|
|
3da209b562 | ||
|
|
9e0b02f86e | ||
|
|
a4e14497a5 | ||
|
|
5daf725ee3 | ||
|
|
ffbf409174 | ||
|
|
8b3c297514 | ||
|
|
2f8481f5e2 | ||
|
|
448d792988 | ||
|
|
1e98e641bb | ||
|
|
4b13cd666b | ||
|
|
836d66a150 | ||
|
|
de3e92e21b | ||
|
|
f9073ee8ee | ||
|
|
bd59bcda2c | ||
|
|
0e9302ff08 | ||
|
|
69bdebeb98 | ||
|
|
7b25d97ea2 | ||
|
|
9a33110ac3 | ||
|
|
99aae87cd2 | ||
|
|
ee681b5053 | ||
|
|
981ae5067c | ||
|
|
60b640d9f5 | ||
|
|
7a1efa8b9a | ||
|
|
a3f74098f2 | ||
|
|
8f4839d8ff | ||
|
|
3b01dcf230 | ||
|
|
37f9f5619c | ||
|
|
331716dd48 | ||
|
|
14f728ab76 | ||
|
|
1249eb3261 | ||
|
|
98e0a62e6e | ||
|
|
2d45dce075 | ||
|
|
e7bfa483f8 | ||
|
|
36a352b096 | ||
|
|
1f05deddc8 | ||
|
|
cec925bcdc | ||
|
|
3bd779a607 | ||
|
|
4a44cddcea | ||
|
|
bf53ee8246 | ||
|
|
f75d5dba84 | ||
|
|
2036dc91e6 | ||
|
|
39252dfe48 | ||
|
|
77c326d300 | ||
|
|
164e52207e | ||
|
|
1f7e2f5ed3 | ||
|
|
0bace013a1 | ||
|
|
1df8d19399 | ||
|
|
75df797b41 | ||
|
|
1136556a0d | ||
|
|
1331b0691f | ||
|
|
21057d51e1 | ||
|
|
f00daf171b | ||
|
|
22eee94436 | ||
|
|
0105ed447f | ||
|
|
dd2ecb3dd9 | ||
|
|
a51f9fd90c | ||
|
|
e32def409a | ||
|
|
657744cc28 | ||
|
|
a561cee54b | ||
|
|
2c0553f8fd | ||
|
|
13b72c8f93 | ||
|
|
73454905e8 | ||
|
|
8e58f469b0 | ||
|
|
5ec7826273 | ||
|
|
1f109ff59b | ||
|
|
10217b5530 | ||
|
|
43f1cc7bd0 | ||
|
|
5e523f4cd8 | ||
|
|
b78435c881 | ||
|
|
33e20df511 | ||
|
|
53c04a934e | ||
|
|
46d3402705 | ||
|
|
1ff4d76ae7 | ||
|
|
273573ce68 | ||
|
|
d3ed34d5eb | ||
|
|
375c74abe5 | ||
|
|
e0264a3459 | ||
|
|
1f73a87327 | ||
|
|
27f420c8ea | ||
|
|
29dd3d5fc3 | ||
|
|
0e671b1569 | ||
|
|
2c374e9761 | ||
|
|
f0465c63ed | ||
|
|
b04cb7648e | ||
|
|
46b1b0ba17 | ||
|
|
60e3a657f0 | ||
|
|
3d04669ef0 | ||
|
|
9fb60a8ab0 | ||
|
|
17540b0120 | ||
|
|
af77819913 | ||
|
|
1c8af096de | ||
|
|
7f35d81722 | ||
|
|
26f873a364 | ||
|
|
b101d11821 | ||
|
|
50a1956d92 | ||
|
|
5a4f31bfa5 | ||
|
|
7405219fb8 | ||
|
|
30ce4b6e3c | ||
|
|
7d53636e10 | ||
|
|
aa93bcb142 | ||
|
|
2073793fcd | ||
|
|
388523a4ea | ||
|
|
ec4942174b | ||
|
|
01f7a09012 | ||
|
|
c35ea228e4 | ||
|
|
498d8c1d65 | ||
|
|
3aacf0f1fb | ||
|
|
4fc2fb7a6f | ||
|
|
d12f5016e4 | ||
|
|
f1e0960a26 | ||
|
|
0f5d659ce2 | ||
|
|
a64aa6941d | ||
|
|
66cac8350e | ||
|
|
384c2a7701 | ||
|
|
ad4e7c3355 | ||
|
|
ea5d4ca3ae | ||
|
|
87e7f817c1 | ||
|
|
3af1840c6a | ||
|
|
e5ff04be29 | ||
|
|
da851c3c10 | ||
|
|
d160aeec4b | ||
|
|
e18275c1c0 | ||
|
|
1ca71ec30d | ||
|
|
759351cec0 | ||
|
|
ef320b74b0 | ||
|
|
6e6c5c4cb7 | ||
|
|
669e1921a4 | ||
|
|
924b4a9436 | ||
|
|
f49b5efac4 | ||
|
|
8581ab9eb3 | ||
|
|
7efe9acefb | ||
|
|
94f3664dbc | ||
|
|
d1f8053fbb | ||
|
|
713ce86e24 | ||
|
|
7efdcfd888 | ||
|
|
988a674617 | ||
|
|
4e4cdcdf61 | ||
|
|
0388bbdc6d | ||
|
|
30d47fd51b | ||
|
|
2e45069882 | ||
|
|
3b2cf5b851 | ||
|
|
4d456f1bc0 | ||
|
|
d6ba41c2d9 | ||
|
|
c9a728c318 | ||
|
|
4c2fe8e03c | ||
|
|
ec95c260bb | ||
|
|
e7eaa2b194 | ||
|
|
fe59ce3e60 | ||
|
|
45fb046a9a | ||
|
|
055e18058f | ||
|
|
fa5e32496c | ||
|
|
44a1efffa0 | ||
|
|
c839ee7d13 | ||
|
|
c7c01c1f24 | ||
|
|
615596dfe9 | ||
|
|
407ec1ceb6 | ||
|
|
eefdbe7ef1 | ||
|
|
cd6a62dd27 | ||
|
|
4e6af607e8 | ||
|
|
363b07fc0c | ||
|
|
a719627be6 | ||
|
|
f14f77b4f0 | ||
|
|
a92aa58be8 | ||
|
|
9617212ef1 | ||
|
|
4af66f7d3d | ||
|
|
c7cee59a77 | ||
|
|
7002e3bbf3 | ||
|
|
c37c53369b | ||
|
|
e827ad4b8d | ||
|
|
2fee380459 | ||
|
|
94ad6e6072 | ||
|
|
a980097d64 | ||
|
|
b2774bf472 | ||
|
|
44ce81211e | ||
|
|
c444ad9280 | ||
|
|
80ca6bf177 | ||
|
|
a0178ebab9 | ||
|
|
e63af24626 | ||
|
|
f94c23d64d | ||
|
|
bffc229fa8 | ||
|
|
aae5586b5c | ||
|
|
4f2d14e220 | ||
|
|
58189e5403 | ||
|
|
215e1ffdc8 | ||
|
|
9fdd4670b7 | ||
|
|
03af1687d9 | ||
|
|
cb2aee0ed7 | ||
|
|
e92f937587 | ||
|
|
73d7cc7c12 | ||
|
|
8cd0561e71 | ||
|
|
1b54a8858e | ||
|
|
c3825fff65 | ||
|
|
c51db87c34 | ||
|
|
beca8033cf | ||
|
|
72f2f0877d | ||
|
|
79f18d12e6 | ||
|
|
7fe9a768d4 | ||
|
|
f114239f51 | ||
|
|
c46e445a04 | ||
|
|
d91334abcd | ||
|
|
5227887dbf | ||
|
|
d07d36f784 | ||
|
|
c9cd7ad4a6 | ||
|
|
b4ee02b725 | ||
|
|
79e25b0889 | ||
|
|
5d50a3927e | ||
|
|
7769b556f7 | ||
|
|
58870f3057 | ||
|
|
8821f75e6b | ||
|
|
88b2f60291 | ||
|
|
c49aad6cd3 | ||
|
|
afceb34729 | ||
|
|
93c8a45de0 | ||
|
|
1f208dbb21 | ||
|
|
4e9cbd14eb | ||
|
|
da1b53420f | ||
|
|
5a71cc2d61 | ||
|
|
b98b60a126 | ||
|
|
929e0e64a5 | ||
|
|
48a1e93cfe | ||
|
|
b908965048 | ||
|
|
afa149f2db | ||
|
|
6c3c2849fa | ||
|
|
6cbfb00cca | ||
|
|
7b22c49329 | ||
|
|
c7c05e2621 | ||
|
|
7fc2ff3002 | ||
|
|
bb36000dd9 | ||
|
|
19ef188f7b | ||
|
|
23e1c714d6 | ||
|
|
a07b678a61 | ||
|
|
6cf3bfb89f | ||
|
|
85515a729f | ||
|
|
d36e299c35 | ||
|
|
9e5e3e94a3 | ||
|
|
4db10f1c8b | ||
|
|
5faf1380d7 | ||
|
|
baa5c34b55 | ||
|
|
d19d812ccb | ||
|
|
e2b7427e7b | ||
|
|
44ae942de4 | ||
|
|
e14efc6ca2 | ||
|
|
f982ff62e4 | ||
|
|
5b8947c36b | ||
|
|
07a274fe4c | ||
|
|
081c581b8c | ||
|
|
1c88c3a8bd | ||
|
|
eb41622a38 | ||
|
|
13c9b80bca | ||
|
|
c72853596f | ||
|
|
e57c9ff4f6 | ||
|
|
ed8c0794bb | ||
|
|
d7bf3746f7 | ||
|
|
6c773c0135 | ||
|
|
a06752b349 | ||
|
|
d15bd4771d | ||
|
|
a62ede7840 | ||
|
|
bcab657a06 | ||
|
|
9dbae2051b | ||
|
|
7400b9ce8a | ||
|
|
4436e8a589 | ||
|
|
e241adab0e | ||
|
|
51880fc2a8 | ||
|
|
89bffbd1bc | ||
|
|
e80c7bff1c | ||
|
|
b3ef615158 | ||
|
|
25ddaa08dc | ||
|
|
fb48eb91d6 | ||
|
|
865d7e9b20 |
@@ -65,4 +65,5 @@ readability-*,
|
||||
-readability-redundant-access-specifiers,
|
||||
-readability-function-cognitive-complexity,
|
||||
-readability-identifier-naming,
|
||||
-readability-qualified-auto'
|
||||
*-include-cleaner,
|
||||
-readability-qualified-auto'
|
||||
|
||||
5
.dockerignore
Normal file
5
.dockerignore
Normal file
@@ -0,0 +1,5 @@
|
||||
cmake-build-*/
|
||||
build*/
|
||||
|
||||
local/
|
||||
**/Dockerfile
|
||||
7
.github/workflows/analysis.yml
vendored
7
.github/workflows/analysis.yml
vendored
@@ -28,8 +28,8 @@ jobs:
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: ${{ runner.os }}-analysis-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-analysis-${{ secrets.CACHE_VERSION }}-build
|
||||
key: ${{ runner.os }}-analysis-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-analysis-build
|
||||
max-size: 50M
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: ${{ runner.os }}-analysis-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
key: ${{ runner.os }}-analysis-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
@@ -46,6 +46,7 @@ jobs:
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
set -x
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
|
||||
193
.github/workflows/build.yml
vendored
193
.github/workflows/build.yml
vendored
@@ -30,8 +30,8 @@ jobs:
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
id: cache-ccache
|
||||
with:
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-ccache-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-ccache
|
||||
key: ${{ runner.os }}-ccache-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-ccache
|
||||
max-size: 1G
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
key: ${{ runner.os }}-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: 🟦 Install msys2
|
||||
uses: msys2/setup-msys2@v2
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
- name: ⬇️ Install .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '7.0.x'
|
||||
dotnet-version: '8.0.100'
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
@@ -72,13 +72,14 @@ jobs:
|
||||
# Windows cmake build
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
set -x
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
cmake -G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DIMHEX_GENERATE_PACKAGE=ON \
|
||||
-DIMHEX_USE_DEFAULT_BUILD_SETTINGS=ON \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
|
||||
@@ -96,6 +97,7 @@ jobs:
|
||||
- name: ⬆️ Upload Windows Installer
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: Windows Installer x86_64
|
||||
path: |
|
||||
imhex-*.msi
|
||||
@@ -103,6 +105,7 @@ jobs:
|
||||
- name: ⬆️ Upload Portable ZIP
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: Windows Portable x86_64
|
||||
path: |
|
||||
build/install/*
|
||||
@@ -110,6 +113,7 @@ jobs:
|
||||
- name: ⬇️ Download Mesa3D for NoGPU version
|
||||
shell: bash
|
||||
run: |
|
||||
set -x
|
||||
echo "NoGPU version Powered by Mesa 3D : https://fdossena.com/?p=mesa%2Findex.frag" > build/install/MESA.md
|
||||
curl https://werwolv.net/downloads/mesa/MesaForWindows-x64-latest.7z -L -o mesa.7z
|
||||
7z e mesa.7z
|
||||
@@ -118,15 +122,17 @@ jobs:
|
||||
- name: ⬆️ Upload NoGPU Portable ZIP
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: Windows Portable NoGPU x86_64
|
||||
path: |
|
||||
build/install/*
|
||||
|
||||
# MacOS build
|
||||
macos:
|
||||
runs-on: macos-11
|
||||
runs-on: macos-12
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- suffix: "-NoGPU"
|
||||
@@ -134,7 +140,7 @@ jobs:
|
||||
- suffix: ""
|
||||
custom_glfw: false
|
||||
|
||||
name: 🍎 macOS 11.0${{matrix.suffix}}
|
||||
name: 🍎 macOS 12.0${{matrix.suffix}}
|
||||
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
@@ -149,8 +155,8 @@ jobs:
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: ${{ runner.os }}${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-ccache-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-ccache
|
||||
key: ${{ runner.os }}${{ matrix.suffix }}-ccache-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}${{ matrix.suffix }}-ccache
|
||||
max-size: 1G
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
@@ -158,10 +164,12 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: ${{ runner.os }}-${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
key: ${{ runner.os }}-${{ matrix.suffix }}-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
set -x
|
||||
brew reinstall python || brew link --overwrite python
|
||||
brew bundle --no-lock --file dist/Brewfile
|
||||
rm -rf /usr/local/Cellar/capstone
|
||||
|
||||
@@ -173,7 +181,7 @@ jobs:
|
||||
- name: ⬇️ Install .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '7.0.x'
|
||||
dotnet-version: '8.0.100'
|
||||
|
||||
- name: 🧰 Checkout glfw
|
||||
if: ${{matrix.custom_glfw}}
|
||||
@@ -186,6 +194,7 @@ jobs:
|
||||
- name: ⬇️ Patch and install custom glfw
|
||||
if: ${{matrix.custom_glfw}}
|
||||
run: |
|
||||
set -x
|
||||
cd glfw
|
||||
git apply ../dist/macOS/0001-glfw-SW.patch
|
||||
|
||||
@@ -205,6 +214,7 @@ jobs:
|
||||
# MacOS cmake build
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
set -x
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
|
||||
@@ -214,8 +224,7 @@ jobs:
|
||||
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
|
||||
cmake -G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
|
||||
-DCREATE_BUNDLE=ON \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DIMHEX_GENERATE_PACKAGE=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
@@ -231,12 +240,54 @@ jobs:
|
||||
- name: ⬆️ Upload DMG
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: macOS DMG${{matrix.suffix}} x86_64
|
||||
path: build/*.dmg
|
||||
|
||||
macos-arm64:
|
||||
runs-on: ubuntu-22.04
|
||||
name: 🍎 macOS 12.1 arm64
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: 📁 Restore docker /cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: cache
|
||||
key: build-macos-arm64-cache
|
||||
|
||||
- name: 🐳 Inject /cache into docker
|
||||
uses: reproducible-containers/buildkit-cache-dance@v2.1.2 # Doesn't work with a MacOS runner ?
|
||||
with:
|
||||
cache-source: cache
|
||||
cache-target: /cache
|
||||
|
||||
- name: 🛠️ Build using docker
|
||||
run: |
|
||||
docker buildx build . -f dist/macOS/arm64.Dockerfile --progress=plain --build-arg 'JOBS=4' --build-arg "BUILD_TYPE=$(BUILD_TYPE)" --build-context imhex=$(pwd) --output out
|
||||
|
||||
- name: ⬆️ Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: macOS ZIP arm64
|
||||
path: out/
|
||||
|
||||
# See https://github.com/actions/cache/issues/342#issuecomment-1711054115
|
||||
- name: 🗑️ Delete old cache
|
||||
continue-on-error: true
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh extension install actions/gh-actions-cache
|
||||
gh actions-cache delete "build-macos-arm64-cache" --confirm
|
||||
|
||||
# Ubuntu build
|
||||
ubuntu:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: Ubuntu
|
||||
@@ -263,8 +314,8 @@ jobs:
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: Ubuntu-${{matrix.release_num}}-${{ secrets.CACHE_VERSION }}-ccache-${{ github.run_id }}
|
||||
restore-keys: Ubuntu-${{matrix.release_num}}-${{ secrets.CACHE_VERSION }}-ccache
|
||||
key: Ubuntu-${{matrix.release_num}}-ccache-${{ github.run_id }}
|
||||
restore-keys: Ubuntu-${{matrix.release_num}}-ccache
|
||||
max-size: 1G
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
@@ -272,7 +323,7 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: Ubuntu-${{matrix.release_num}}-${{ secrets.CACHE_VERSION }}-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
key: Ubuntu-${{matrix.release_num}}-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
@@ -282,15 +333,19 @@ jobs:
|
||||
- name: ⬇️ Install .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '7.0.x'
|
||||
dotnet-version: '8.0.100'
|
||||
|
||||
- name: 🏔️ Set Environment variables
|
||||
run: |
|
||||
echo COMMIT_SHA_SHORT=$(git rev-parse --short HEAD) >> $GITHUB_ENV
|
||||
echo COMMIT_SHA_LONG=$(git rev-parse HEAD) >> $GITHUB_ENV
|
||||
echo COMMIT_BRANCH=$(git rev-parse --abbrev-ref HEAD) >> $GITHUB_ENV
|
||||
|
||||
# Ubuntu cmake build
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
set -x
|
||||
git config --global --add safe.directory '*'
|
||||
echo COMMIT_SHA_SHORT=$(git rev-parse --short HEAD) >> $GITHUB_ENV
|
||||
echo COMMIT_SHA_LONG=$(git rev-parse HEAD) >> $GITHUB_ENV
|
||||
echo COMMIT_BRANCH=$(git rev-parse --abbrev-ref HEAD) >> $GITHUB_ENV
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-12 CXX=g++-12 cmake -G "Ninja" \
|
||||
@@ -300,7 +355,7 @@ jobs:
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_COMMIT_HASH_SHORT="${{ env.COMMIT_SHA_SHORT }}" \
|
||||
-DIMHEX_COMMIT_HASH_LONG="${{ env.COMMIT_SHA_LONG}}" \
|
||||
-DIMHEX_COMMIT_HASH_LONG="${{ env.COMMIT_SHA_LONG }}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${{ env.COMMIT_BRANCH }}" \
|
||||
-DIMHEX_ENABLE_LTO=ON \
|
||||
-DIMHEX_USE_GTK_FILE_PICKER=ON \
|
||||
@@ -321,6 +376,7 @@ jobs:
|
||||
- name: ⬆️ Upload DEB
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: Ubuntu ${{ matrix.release_num }} DEB x86_64
|
||||
path: '*.deb'
|
||||
|
||||
@@ -329,76 +385,43 @@ jobs:
|
||||
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: appimage-${{ secrets.CACHE_VERSION }}-ccache-${{ github.run_id }}
|
||||
restore-keys: appimage-${{ secrets.CACHE_VERSION }}-ccache
|
||||
max-size: 1G
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
- name: 📁 Restore docker /cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
build-appimage/CMakeCache.txt
|
||||
key: appimage-${{ secrets.CACHE_VERSION }}-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
path: cache
|
||||
key: appimage-ccache-${{ github.run_id }}
|
||||
restore-keys: appimage-cache
|
||||
|
||||
- name: 🐳 Inject /cache into docker
|
||||
uses: reproducible-containers/buildkit-cache-dance@v2.1.2
|
||||
with:
|
||||
cache-source: cache
|
||||
cache-target: /cache
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
- name: 🛠️ Build using docker
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo bash dist/get_deps_debian.sh
|
||||
docker buildx build . -f dist/appimage/Dockerfile --progress=plain --build-arg "BUILD_TYPE=$BUILD_TYPE" \
|
||||
--build-arg "GIT_COMMIT_HASH=$GITHUB_SHA" --build-arg "GIT_BRANCH=${GITHUB_REF##*/}" --output out
|
||||
|
||||
sudo apt install -y python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fuse ninja-build
|
||||
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: 🛠️ Build
|
||||
run: |
|
||||
mkdir -p build-appimage
|
||||
cd build-appimage
|
||||
CC=gcc-12 CXX=g++-12 cmake -G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
|
||||
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||
-DIMHEX_ENABLE_LTO=ON \
|
||||
-DIMHEX_PLUGINS_IN_SHARE=ON \
|
||||
..
|
||||
DESTDIR=AppDir ninja install
|
||||
|
||||
- name: 📦 Bundle AppImage
|
||||
run: |
|
||||
cd build-appimage
|
||||
export VERSION=${{env.IMHEX_VERSION}}
|
||||
appimage-builder --recipe ../dist/AppImageBuilder.yml
|
||||
|
||||
- name: ⬆️ Upload AppImage
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: Linux AppImage x86_64
|
||||
path: 'build-appimage/*.AppImage'
|
||||
path: 'out/*.AppImage'
|
||||
|
||||
- name: ⬆️ Upload AppImage zsync
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: Linux AppImage zsync x86_64
|
||||
path: 'build-appimage/*.AppImage.zsync'
|
||||
path: 'out/*.AppImage.zsync'
|
||||
|
||||
# ArchLinux build
|
||||
archlinux-build:
|
||||
@@ -429,13 +452,13 @@ jobs:
|
||||
- name: ⬇️ Install .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '7.0.x'
|
||||
dotnet-version: '8.0.100'
|
||||
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: archlinux-${{ secrets.CACHE_VERSION }}-ccache-${{ github.run_id }}
|
||||
restore-keys: archlinux-${{ secrets.CACHE_VERSION }}-ccache
|
||||
key: archlinux-ccache-${{ github.run_id }}
|
||||
restore-keys: archlinux-ccache
|
||||
max-size: 1G
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
@@ -443,11 +466,12 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: archlinux-${{ secrets.CACHE_VERSION }}-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
key: archlinux-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
# ArchLinux cmake build
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
set -x
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc CXX=g++ cmake -G "Ninja" \
|
||||
@@ -480,6 +504,7 @@ jobs:
|
||||
# makepkg doesn't want to run as root, so I had to chmod 777 all over
|
||||
- name: 📦 Package ArchLinux .pkg.tar.zst
|
||||
run: |
|
||||
set -x
|
||||
cd build
|
||||
|
||||
# the name is a small trick to make makepkg recognize it as the source
|
||||
@@ -497,6 +522,7 @@ jobs:
|
||||
- name: ⬆️ Upload imhex-archlinux.pkg.tar.zst
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: ArchLinux .pkg.tar.zst x86_64
|
||||
path: |
|
||||
build/imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
|
||||
@@ -504,6 +530,7 @@ jobs:
|
||||
# RPM distro builds
|
||||
rpm-build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: Fedora
|
||||
@@ -544,12 +571,13 @@ jobs:
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /var/cache/dnf
|
||||
key: ${{ matrix.mock_release }}-${{secrets.CACHE_VERSION }}-dnf-${{ github.run_id }}
|
||||
key: ${{ matrix.mock_release }}-dnf-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
${{ matrix.mock_release }}-${{secrets.CACHE_VERSION }}-dnf-
|
||||
${{ matrix.mock_release }}-dnf-
|
||||
|
||||
- name: ⬇️ Update all packages and install dependencies
|
||||
run: |
|
||||
set -x
|
||||
dnf upgrade --disablerepo="*" --enablerepo="fedora,updates" -y
|
||||
dnf install --disablerepo="*" --enablerepo="fedora,updates" -y \
|
||||
fedpkg \
|
||||
@@ -558,13 +586,13 @@ jobs:
|
||||
- name: ⬇️ Install .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: '7.0.x'
|
||||
dotnet-version: '8.0.100'
|
||||
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.5
|
||||
with:
|
||||
key: ${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-rpm-${{ github.run_id }}
|
||||
restore-keys: ${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-rpm
|
||||
key: ${{ matrix.mock_release }}-rpm-${{ github.run_id }}
|
||||
restore-keys: ${{ matrix.mock_release }}-rpm
|
||||
max-size: 1G
|
||||
|
||||
- name: 📜 Set version variable
|
||||
@@ -605,9 +633,9 @@ jobs:
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /var/cache/mock
|
||||
key: ${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-mock-${{ github.run_id }}
|
||||
key: ${{ matrix.mock_release }}-mock-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
${{ matrix.mock_release }}-${{ secrets.CACHE_VERSION }}-mock
|
||||
${{ matrix.mock_release }}-mock
|
||||
|
||||
# Fedora cmake build (in imhex.spec)
|
||||
- name: 📦 Build RPM
|
||||
@@ -622,6 +650,7 @@ jobs:
|
||||
- name: ⬆️ Upload RPM
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: ${{ matrix.name }} ${{ matrix.release_num }} RPM x86_64
|
||||
path: |
|
||||
imhex-${{env.IMHEX_VERSION}}-${{matrix.name}}-${{matrix.release_num}}-x86_64.rpm
|
||||
|
||||
79
.github/workflows/build_web.yml
vendored
Normal file
79
.github/workflows/build_web.yml
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
name: Build for the web
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["*"]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
|
||||
permissions:
|
||||
pages: write
|
||||
id-token: write
|
||||
actions: write
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
name: 🌍 WebAssembly
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: 📁 Restore docker /cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: cache
|
||||
key: build-web-cache
|
||||
|
||||
- name: 🐳 Inject /cache into docker
|
||||
uses: reproducible-containers/buildkit-cache-dance@v2.1.2
|
||||
with:
|
||||
cache-source: cache
|
||||
cache-target: /cache
|
||||
|
||||
- name: 🛠️ Build using docker
|
||||
run: |
|
||||
docker buildx build . -f dist/web/Dockerfile --progress=plain --build-arg 'JOBS=4' --output out
|
||||
|
||||
- name: 🔨 Fix permissions
|
||||
run: |
|
||||
chmod -c -R +rX "out/" | while read line; do
|
||||
echo "::warning title=Invalid file permissions automatically fixed::$line"
|
||||
done
|
||||
|
||||
- name: ⬆️ Upload artifacts
|
||||
uses: actions/upload-pages-artifact@v2
|
||||
with:
|
||||
path: out/
|
||||
|
||||
# See https://github.com/actions/cache/issues/342#issuecomment-1711054115
|
||||
- name: 🗑️ Delete old cache
|
||||
continue-on-error: true
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh extension install actions/gh-actions-cache
|
||||
gh actions-cache delete "build-web-cache" --confirm
|
||||
|
||||
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
|
||||
name: 📃 Deploy to GitHub Pages
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
if: ${{ github.ref == 'refs/heads/master' && github.event.repository.fork == false }}
|
||||
needs: build
|
||||
|
||||
steps:
|
||||
- name: 🌍 Deploy
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v2
|
||||
7
.github/workflows/release.yml
vendored
7
.github/workflows/release.yml
vendored
@@ -21,6 +21,7 @@ jobs:
|
||||
|
||||
- name: 📜 Verify version and set version variable
|
||||
run: |
|
||||
set -x
|
||||
project_version=`cat ImHex/VERSION`
|
||||
tag_version="${{github.event.release.tag_name}}"
|
||||
tag_version="${tag_version:1}"
|
||||
@@ -64,6 +65,7 @@ jobs:
|
||||
|
||||
- name: 📜 Verify version and set version variable
|
||||
run: |
|
||||
set -x
|
||||
project_version=`cat ImHex/VERSION`
|
||||
tag_version="${{github.event.release.tag_name}}"
|
||||
tag_version="${tag_version:1}"
|
||||
@@ -87,7 +89,8 @@ jobs:
|
||||
skip_unpack: true
|
||||
|
||||
- name: 🗜️ Unzip files when needed
|
||||
run: |
|
||||
run: |
|
||||
set -x
|
||||
for zipfile in ./*.zip
|
||||
do
|
||||
if [ `zipinfo -1 "$zipfile" | wc -l` -eq 1 ];
|
||||
@@ -112,6 +115,7 @@ jobs:
|
||||
|
||||
- name: ✒️ Prepare PKGBUILD
|
||||
run: |
|
||||
set -x
|
||||
cp ImHex/dist/Arch/PKGBUILD .
|
||||
|
||||
hash=`md5sum imhex-${{ env.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst | cut -d ' ' -f 1`
|
||||
@@ -150,6 +154,7 @@ jobs:
|
||||
WINGET_GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.WINGET_GITHUB_TOKEN != '' }}"
|
||||
run: |
|
||||
set -x
|
||||
$tagname = $env:GITHUB_REF.Replace("refs/tags/", "")
|
||||
$version = $tagname.Replace("v", "")
|
||||
$url = "https://github.com/WerWolv/ImHex/releases/download/${tagname}/imhex-${version}-Windows-x86_64.msi"
|
||||
|
||||
7
.github/workflows/tests.yml
vendored
7
.github/workflows/tests.yml
vendored
@@ -25,8 +25,8 @@ jobs:
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2
|
||||
with:
|
||||
key: ${{ runner.os }}-tests-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-tests-${{ secrets.CACHE_VERSION }}-build
|
||||
key: ${{ runner.os }}-tests-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-tests-build
|
||||
max-size: 50M
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: ${{ runner.os }}-tests-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
key: ${{ runner.os }}-tests-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
@@ -44,6 +44,7 @@ jobs:
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
set -x
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
|
||||
29
.gitmodules
vendored
29
.gitmodules
vendored
@@ -1,30 +1,35 @@
|
||||
[submodule "lib/external/nativefiledialog"]
|
||||
path = lib/external/nativefiledialog
|
||||
[submodule "lib/third_party/nativefiledialog"]
|
||||
path = lib/third_party/nativefiledialog
|
||||
url = https://github.com/btzy/nativefiledialog-extended
|
||||
ignore = dirty
|
||||
[submodule "lib/external/yara/yara"]
|
||||
path = lib/external/yara/yara
|
||||
[submodule "lib/third_party/yara/yara"]
|
||||
path = lib/third_party/yara/yara
|
||||
url = https://github.com/VirusTotal/yara
|
||||
ignore = dirty
|
||||
[submodule "lib/external/xdgpp"]
|
||||
path = lib/external/xdgpp
|
||||
[submodule "lib/third_party/xdgpp"]
|
||||
path = lib/third_party/xdgpp
|
||||
url = https://git.sr.ht/~danyspin97/xdgpp
|
||||
ignore = dirty
|
||||
[submodule "lib/external/fmt"]
|
||||
path = lib/external/fmt
|
||||
[submodule "lib/third_party/fmt"]
|
||||
path = lib/third_party/fmt
|
||||
url = https://github.com/fmtlib/fmt
|
||||
ignore = dirty
|
||||
[submodule "lib/external/capstone"]
|
||||
path = lib/external/capstone
|
||||
[submodule "lib/third_party/capstone"]
|
||||
path = lib/third_party/capstone
|
||||
url = https://github.com/capstone-engine/capstone
|
||||
ignore = dirty
|
||||
[submodule "lib/third_party/jthread/jthread"]
|
||||
path = lib/third_party/jthread/jthread
|
||||
url = https://github.com/josuttis/jthread
|
||||
ignore = dirty
|
||||
|
||||
[submodule "lib/external/libromfs"]
|
||||
path = lib/external/libromfs
|
||||
url = https://github.com/WerWolv/libromfs
|
||||
ignore = dirty
|
||||
[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
|
||||
url = https://github.com/WerWolv/libwolv
|
||||
|
||||
|
||||
@@ -13,6 +13,9 @@ option(IMHEX_BUNDLE_DOTNET "Bundle .NET runtime" ON)
|
||||
option(IMHEX_ENABLE_LTO "Enables Link Time Optimizations if possible" OFF)
|
||||
option(IMHEX_USE_DEFAULT_BUILD_SETTINGS "Use default build settings" OFF)
|
||||
option(IMHEX_STRICT_WARNINGS "Enable most available warnings and treat them as errors" ON)
|
||||
option(IMHEX_STATIC_LINK_PLUGINS "Statically link all plugins into the main executable" OFF)
|
||||
option(IMHEX_GENERATE_PACKAGE "Specify if a native package should be built. Only usable on Windows and MacOS" OFF)
|
||||
option(IMHEX_ENABLE_UNITY_BUILD "Enables building ImHex as a unity build." OFF)
|
||||
|
||||
# Basic compiler and cmake configurations
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
@@ -52,9 +55,10 @@ setUninstallTarget()
|
||||
addBundledLibraries()
|
||||
|
||||
# Add ImHex sources
|
||||
add_custom_target(imhex_all ALL)
|
||||
|
||||
add_subdirectory(lib/libimhex)
|
||||
add_subdirectory(main)
|
||||
add_custom_target(imhex_all ALL DEPENDS main libimhex)
|
||||
|
||||
# Add unit tests
|
||||
enable_testing()
|
||||
|
||||
@@ -15,3 +15,5 @@ To install plugins, simply download the relevant `.hexplug` file and drop it in
|
||||
- Adds support for Discord Rich Presence
|
||||
|
||||
### Third-Party Plugins
|
||||
- [Pcap Plugin](https://github.com/Professor-plum/ImHex-Plugin-Pcap)
|
||||
- Adds support for reading packet capture files
|
||||
|
||||
12
README.md
12
README.md
@@ -33,6 +33,12 @@
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a title="Use the Web version of ImHex right in your browser!" href="https://web.imhex.werwolv.net">
|
||||
<img alt="Use the Web version of ImHex right in your browser!" src="resources/dist/common/try_online_banner.png">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Supporting
|
||||
|
||||
If you like my work, please consider supporting me on GitHub Sponsors, Patreon or PayPal. Thanks a lot!
|
||||
@@ -132,7 +138,7 @@ The Pattern Language is the completely custom programming language developed for
|
||||
It allows you to define structures and data types in a C-like syntax and then use them to parse and highlight a file's content.
|
||||
|
||||
- Source Code: [Link](https://github.com/WerWolv/PatternLanguage/)
|
||||
- Documentation: [Link](https://imhex.werwolv.net/docs/)
|
||||
- Documentation: [Link](https://docs.werwolv.net/pattern-language/)
|
||||
|
||||
## Database
|
||||
|
||||
@@ -188,11 +194,11 @@ To develop plugins for ImHex, use one of the following two templates projects to
|
||||
|
||||
### Contributors
|
||||
|
||||
- [Mary](https://github.com/Thog) for her immense help porting ImHex to MacOS and help during development
|
||||
- [Mary](https://github.com/marysaka) for her immense help porting ImHex to MacOS and help during development
|
||||
- [Roblabla](https://github.com/Roblabla) for adding MSI Installer support to ImHex
|
||||
- [jam1garner](https://github.com/jam1garner) and [raytwo](https://github.com/raytwo) for their help with adding Rust support to plugins
|
||||
- [Mailaender](https://github.com/Mailaender) for getting ImHex onto Flathub
|
||||
- [iTrooz](https://github.com/iTrooz) for many improvements related to release packaging and the GitHub Action runners.
|
||||
- [iTrooz](https://github.com/iTrooz) for many improvements and new features to Imhex
|
||||
- Everybody else who has reported issues on Discord or GitHub that I had great conversations with :)
|
||||
|
||||
### Dependencies
|
||||
|
||||
@@ -7,4 +7,4 @@ If you built ImHex yourself and experience issues that are not present in the ve
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Any critical vulnearabilities can be reported through Discord @WerWolv#1337
|
||||
Any critical vulnerabilities can be reported through Discord (@werwolv).
|
||||
|
||||
@@ -30,6 +30,10 @@ macro(addDefines)
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-MinSizeRel)
|
||||
add_compile_definitions(NDEBUG)
|
||||
endif ()
|
||||
|
||||
if (IMHEX_STATIC_LINK_PLUGINS)
|
||||
add_compile_definitions(IMHEX_STATIC_LINK_PLUGINS)
|
||||
endif ()
|
||||
endmacro()
|
||||
|
||||
function(addDefineToSource SOURCE DEFINE)
|
||||
@@ -54,6 +58,8 @@ macro(detectOS)
|
||||
set(PLUGINS_INSTALL_LOCATION "plugins")
|
||||
enable_language(OBJC)
|
||||
enable_language(OBJCXX)
|
||||
elseif (EMSCRIPTEN)
|
||||
add_compile_definitions(OS_WEB)
|
||||
elseif (UNIX AND NOT APPLE)
|
||||
add_compile_definitions(OS_LINUX)
|
||||
include(GNUInstallDirs)
|
||||
@@ -83,17 +89,14 @@ endmacro()
|
||||
|
||||
|
||||
macro(configurePackingResources)
|
||||
option (CREATE_PACKAGE "Create a package with CPack" OFF)
|
||||
|
||||
if (APPLE)
|
||||
option (CREATE_BUNDLE "Create a bundle on macOS" OFF)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
set(APPLICATION_TYPE)
|
||||
if (NOT (CMAKE_BUILD_TYPE STREQUAL "Debug"))
|
||||
set(APPLICATION_TYPE WIN32)
|
||||
endif ()
|
||||
|
||||
set(IMHEX_ICON "${IMHEX_BASE_FOLDER}/resources/resource.rc")
|
||||
|
||||
if (CREATE_PACKAGE)
|
||||
if (IMHEX_GENERATE_PACKAGE)
|
||||
set(CPACK_GENERATOR "WIX")
|
||||
set(CPACK_PACKAGE_NAME "ImHex")
|
||||
set(CPACK_PACKAGE_VENDOR "WerWolv")
|
||||
@@ -111,7 +114,7 @@ macro(configurePackingResources)
|
||||
elseif (APPLE)
|
||||
set (IMHEX_ICON "${IMHEX_BASE_FOLDER}/resources/dist/macos/AppIcon.icns")
|
||||
|
||||
if (CREATE_BUNDLE)
|
||||
if (IMHEX_GENERATE_PACKAGE)
|
||||
set(APPLICATION_TYPE MACOSX_BUNDLE)
|
||||
set_source_files_properties(${IMHEX_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
||||
set(MACOSX_BUNDLE_ICON_FILE "AppIcon.icns")
|
||||
@@ -126,10 +129,13 @@ macro(configurePackingResources)
|
||||
string(TIMESTAMP CURR_YEAR "%Y")
|
||||
set(MACOSX_BUNDLE_COPYRIGHT "Copyright © 2020 - ${CURR_YEAR} WerWolv. All rights reserved." )
|
||||
if ("${CMAKE_GENERATOR}" STREQUAL "Xcode")
|
||||
set (IMHEX_BUNDLE_PATH "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/ImHex.app")
|
||||
set (IMHEX_BUNDLE_PATH "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/imhex.app")
|
||||
else ()
|
||||
set (IMHEX_BUNDLE_PATH "${CMAKE_BINARY_DIR}/ImHex.app")
|
||||
set (IMHEX_BUNDLE_PATH "${CMAKE_BINARY_DIR}/imhex.app")
|
||||
endif()
|
||||
|
||||
set(PLUGINS_INSTALL_LOCATION "${IMHEX_BUNDLE_PATH}/Contents/MacOS/plugins")
|
||||
set(CMAKE_INSTALL_LIBDIR "${IMHEX_BUNDLE_PATH}/Contents/Frameworks")
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
@@ -153,11 +159,9 @@ macro(createPackage)
|
||||
|
||||
install(FILES "${PLUGIN_LOCATION}/../${plugin}.hexplug" DESTINATION "${PLUGINS_INSTALL_LOCATION}" PERMISSIONS ${LIBRARY_PERMISSIONS})
|
||||
else ()
|
||||
if (WIN32)
|
||||
install(TARGETS ${plugin} RUNTIME DESTINATION ${PLUGINS_INSTALL_LOCATION})
|
||||
elseif (APPLE)
|
||||
if (CREATE_BUNDLE)
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY $<TARGET_FILE_DIR:main>/${PLUGINS_INSTALL_LOCATION})
|
||||
if (APPLE)
|
||||
if (IMHEX_GENERATE_PACKAGE)
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PLUGINS_INSTALL_LOCATION})
|
||||
else ()
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
endif ()
|
||||
@@ -226,7 +230,7 @@ macro(createPackage)
|
||||
|
||||
endif()
|
||||
|
||||
if (CREATE_BUNDLE)
|
||||
if (IMHEX_GENERATE_PACKAGE AND APPLE)
|
||||
include(PostprocessBundle)
|
||||
|
||||
set_target_properties(libimhex PROPERTIES SOVERSION ${IMHEX_VERSION})
|
||||
@@ -251,17 +255,18 @@ macro(createPackage)
|
||||
|
||||
# Enforce DragNDrop packaging.
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
|
||||
set (CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/resources/dist/macos/AppIcon.icns" )
|
||||
set (CPACK_BUNDLE_PLIST "${CMAKE_BINARY_DIR}/imhex.app/Contents/Info.plist")
|
||||
else()
|
||||
install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
if(WIN32) # Forwarder is only needed on Windows
|
||||
install(TARGETS imhex-forwarder BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(TARGETS main-forwarder BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (CREATE_PACKAGE)
|
||||
if (IMHEX_GENERATE_PACKAGE)
|
||||
set (CPACK_BUNDLE_NAME "ImHex")
|
||||
set (CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/resources/dist/macos/AppIcon.icns" )
|
||||
set (CPACK_BUNDLE_PLIST "${CMAKE_BINARY_DIR}/ImHex.app/Contents/Info.plist")
|
||||
|
||||
include(CPack)
|
||||
endif()
|
||||
@@ -348,8 +353,8 @@ endmacro()
|
||||
|
||||
macro(setDefaultBuiltTypeIfUnset)
|
||||
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Using Release build type as it was left unset" FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release")
|
||||
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Using RelWithDebInfo build type as it was left unset" FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "RelWithDebInfo")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
@@ -366,9 +371,9 @@ function(detectBadClone)
|
||||
return()
|
||||
endif()
|
||||
|
||||
file (GLOB EXTERNAL_DIRS "lib/external/*")
|
||||
file (GLOB EXTERNAL_DIRS "lib/external/*" "lib/third_party/*")
|
||||
foreach (EXTERNAL_DIR ${EXTERNAL_DIRS})
|
||||
file(GLOB RESULT "${EXTERNAL_DIR}/*")
|
||||
file(GLOB_RECURSE RESULT "${EXTERNAL_DIR}/*")
|
||||
list(LENGTH RESULT ENTRY_COUNT)
|
||||
if(ENTRY_COUNT LESS_EQUAL 1)
|
||||
message(FATAL_ERROR "External dependency ${EXTERNAL_DIR} is empty!\nMake sure to correctly clone ImHex using the --recurse-submodules git option or initialize the submodules manually.")
|
||||
@@ -434,19 +439,35 @@ endfunction()
|
||||
|
||||
macro(setupCompilerFlags target)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
|
||||
# Define strict compilation flags
|
||||
if (IMHEX_STRICT_WARNINGS)
|
||||
set(IMHEX_COMMON_FLAGS "-Wall -Wextra -Wpedantic -Werror")
|
||||
set(IMHEX_COMMON_FLAGS "${IMHEX_COMMON_FLAGS} -Wall -Wextra -Wpedantic -Werror")
|
||||
endif()
|
||||
|
||||
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-array-bounds")
|
||||
set(IMHEX_CXX_FLAGS "-fexceptions -frtti")
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
set(IMHEX_C_FLAGS "${IMHEX_C_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow -Wno-dangling-reference")
|
||||
endif()
|
||||
|
||||
# Disable some warnings
|
||||
set(IMHEX_C_CXX_FLAGS "-Wno-array-bounds -Wno-deprecated-declarations")
|
||||
|
||||
if (IMHEX_ENABLE_UNITY_BUILD AND WIN32)
|
||||
set(IMHEX_COMMON_FLAGS "${IMHEX_COMMON_FLAGS} -Wa,-mbig-obj")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${IMHEX_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${IMHEX_CXX_FLAGS} ${IMHEX_C_FLAGS}")
|
||||
# Disable some warnings for gcc
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
set(IMHEX_C_CXX_FLAGS "${IMHEX_C_CXX_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow -Wno-dangling-reference")
|
||||
endif()
|
||||
|
||||
# Define emscripten-specific disabled warnings
|
||||
if (EMSCRIPTEN)
|
||||
set(IMHEX_C_CXX_FLAGS "${IMHEX_C_CXX_FLAGS} -pthread -Wno-dollar-in-identifier-extension -Wno-pthreads-mem-growth")
|
||||
endif ()
|
||||
|
||||
# Set actual CMake flags
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${IMHEX_COMMON_FLAGS} ${IMHEX_C_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${IMHEX_COMMON_FLAGS} ${IMHEX_C_CXX_FLAGS} ${IMHEX_CXX_FLAGS}")
|
||||
set(CMAKE_OBJC_FLAGS "${CMAKE_OBJC_FLAGS} ${IMHEX_COMMON_FLAGS}")
|
||||
endmacro()
|
||||
|
||||
@@ -466,28 +487,31 @@ endmacro()
|
||||
macro(addBundledLibraries)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
set(EXTERN_LIBS_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/lib/external")
|
||||
set(EXTERNAL_LIBS_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/lib/external")
|
||||
set(THIRD_PARTY_LIBS_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/lib/third_party")
|
||||
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/imgui)
|
||||
set_target_properties(imgui PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/imgui)
|
||||
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/microtar EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/microtar EXCLUDE_FROM_ALL)
|
||||
set_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/libwolv EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(${EXTERNAL_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_property(TARGET libwolv-containers PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-net PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-math_eval PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(XDGPP_INCLUDE_DIRS "${EXTERN_LIBS_FOLDER}/xdgpp")
|
||||
set(XDGPP_INCLUDE_DIRS "${THIRD_PARTY_LIBS_FOLDER}/xdgpp")
|
||||
set(FPHSA_NAME_MISMATCHED ON CACHE BOOL "")
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
if(NOT USE_SYSTEM_FMT)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/fmt EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/fmt EXCLUDE_FROM_ALL)
|
||||
set_target_properties(fmt PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(FMT_LIBRARIES fmt::fmt-header-only)
|
||||
else()
|
||||
@@ -501,35 +525,39 @@ macro(addBundledLibraries)
|
||||
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)
|
||||
if (NOT EMSCRIPTEN)
|
||||
# curl
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBCURL REQUIRED IMPORTED_TARGET libcurl>=7.60.0)
|
||||
|
||||
# nfd
|
||||
if (NOT USE_SYSTEM_NFD)
|
||||
add_subdirectory(${THIRD_PARTY_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()
|
||||
endif()
|
||||
|
||||
if(NOT USE_SYSTEM_NLOHMANN_JSON)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/nlohmann_json EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(${THIRD_PARTY_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()
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBCURL REQUIRED IMPORTED_TARGET libcurl>=7.60.0)
|
||||
|
||||
if (NOT USE_SYSTEM_LLVM)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/llvm-demangle EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(${THIRD_PARTY_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)
|
||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/yara EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libyara PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(YARA_LIBRARIES libyara)
|
||||
else()
|
||||
@@ -538,7 +566,7 @@ macro(addBundledLibraries)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_MINIAUDIO)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/miniaudio EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/miniaudio EXCLUDE_FROM_ALL)
|
||||
set_target_properties(miniaudio PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(MINIAUDIO_LIBRARIES miniaudio)
|
||||
else()
|
||||
@@ -546,22 +574,34 @@ macro(addBundledLibraries)
|
||||
pkg_check_modules(miniaudio REQUIRED IMPORTED_TARGET miniaudio)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_JTHREAD)
|
||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/jthread EXCLUDE_FROM_ALL)
|
||||
set(JTHREAD_LIBRARIES jthread)
|
||||
else()
|
||||
find_path(JOSUTTIS_JTHREAD_INCLUDE_DIRS "condition_variable_any2.hpp")
|
||||
include_directories(${JOSUTTIS_JTHREAD_INCLUDE_DIRS})
|
||||
|
||||
add_library(jthread INTERFACE)
|
||||
target_include_directories(jthread INTERFACE ${JOSUTTIS_JTHREAD_INCLUDE_DIRS})
|
||||
set(JTHREAD_LIBRARIES jthread)
|
||||
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)
|
||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/capstone EXCLUDE_FROM_ALL)
|
||||
set_target_properties(capstone PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
target_compile_options(capstone PRIVATE -Wno-unused-function)
|
||||
set(CAPSTONE_LIBRARIES "capstone")
|
||||
set(CAPSTONE_INCLUDE_DIRS ${EXTERN_LIBS_FOLDER}/capstone/include)
|
||||
set(CAPSTONE_INCLUDE_DIRS ${THIRD_PARTY_LIBS_FOLDER}/capstone/include)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_search_module(CAPSTONE 4.0.2 REQUIRED capstone)
|
||||
endif()
|
||||
|
||||
set(LIBPL_BUILD_CLI_AS_EXECUTABLE OFF)
|
||||
add_subdirectory(${EXTERN_LIBS_FOLDER}/pattern_language EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(${EXTERNAL_LIBS_FOLDER}/pattern_language EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libpl PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
find_package(mbedTLS 3.4.0 REQUIRED)
|
||||
@@ -598,6 +638,12 @@ macro(addBundledLibraries)
|
||||
endif ()
|
||||
endmacro()
|
||||
|
||||
function(enableUnityBuild TARGET)
|
||||
if (IMHEX_ENABLE_UNITY_BUILD)
|
||||
set_target_properties(${TARGET} PROPERTIES UNITY_BUILD ON UNITY_BUILD_MODE BATCH)
|
||||
endif ()
|
||||
endfunction()
|
||||
|
||||
function(generatePDBs)
|
||||
if (NOT WIN32 OR CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
return()
|
||||
@@ -611,12 +657,12 @@ function(generatePDBs)
|
||||
)
|
||||
FetchContent_Populate(cv2pdb)
|
||||
|
||||
set(PDBS_TO_GENERATE main imhex-forwarder libimhex ${PLUGINS})
|
||||
set(PDBS_TO_GENERATE main main-forwarder libimhex ${PLUGINS})
|
||||
add_custom_target(pdbs)
|
||||
foreach (PDB ${PDBS_TO_GENERATE})
|
||||
if (PDB STREQUAL "main")
|
||||
set(GENERATED_PDB imhex)
|
||||
elseif (PDB STREQUAL "imhex-forwarder")
|
||||
elseif (PDB STREQUAL "main-forwarder")
|
||||
set(GENERATED_PDB imhex-gui)
|
||||
elseif (PDB STREQUAL "libimhex")
|
||||
set(GENERATED_PDB libimhex)
|
||||
@@ -637,5 +683,13 @@ function(generatePDBs)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb DESTINATION ".")
|
||||
endforeach ()
|
||||
|
||||
endfunction()
|
||||
|
||||
function(generateSDKDirectory)
|
||||
set(SDK_PATH "./sdk")
|
||||
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/libimhex/include DESTINATION "${SDK_PATH}")
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/cmake/modules/ImHexPlugin.cmake DESTINATION "${SDK_PATH}/cmake/modules")
|
||||
install(TARGETS libimhex ARCHIVE DESTINATION "${SDK_PATH}/lib")
|
||||
install(TARGETS libimhex RUNTIME DESTINATION "${SDK_PATH}/lib")
|
||||
endfunction()
|
||||
@@ -16,7 +16,7 @@ if (NOT DOTNET_EXECUTABLE)
|
||||
set(DOTNET_EXECUTABLE dotnet)
|
||||
endif ()
|
||||
|
||||
set(CORECLR_VERSION "7.0")
|
||||
set(CORECLR_VERSION "8.0")
|
||||
|
||||
execute_process(COMMAND ${DOTNET_EXECUTABLE} "--list-runtimes" OUTPUT_VARIABLE CORECLR_LIST_RUNTIMES_OUTPUT OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if (CORECLR_LIST_RUNTIMES_OUTPUT STREQUAL "")
|
||||
@@ -75,7 +75,7 @@ find_file(CoreClrEmbed_SHARED_LIBRARY nethost.dll nethost.so libnethost.so netho
|
||||
|
||||
if (CoreClrEmbed_INCLUDE_DIR AND CoreClrEmbed_LIBRARY)
|
||||
set(CoreClrEmbed_FOUND TRUE)
|
||||
set(CoreClrEmbed_LIBRARIES "${CoreClrEmbed_LIBRARY}")
|
||||
set(CoreClrEmbed_SHARED_LIBRARIES "${CoreClrEmbed_SHARED_LIBRARY}")
|
||||
set(CoreClrEmbed_INCLUDE_DIRS "${CoreClrEmbed_INCLUDE_DIR}")
|
||||
set(CoreClrEmbed_LIBRARIES "${CoreClrEmbed_LIBRARY}" CACHE STRING "CoreClrEmbed libraries" FORCE)
|
||||
set(CoreClrEmbed_SHARED_LIBRARIES "${CoreClrEmbed_SHARED_LIBRARY}" CACHE STRING "CoreClrEmbed shared libraries" FORCE)
|
||||
set(CoreClrEmbed_INCLUDE_DIRS "${CoreClrEmbed_INCLUDE_DIR}" CACHE STRING "CoreClrEmbed include directories" FORCE)
|
||||
endif()
|
||||
@@ -4,23 +4,36 @@ macro(add_imhex_plugin)
|
||||
set(oneValueArgs NAME)
|
||||
set(multiValueArgs SOURCES INCLUDES LIBRARIES)
|
||||
cmake_parse_arguments(IMHEX_PLUGIN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
|
||||
if (IMHEX_STATIC_LINK_PLUGINS)
|
||||
set(IMHEX_PLUGIN_LIBRARY_TYPE STATIC)
|
||||
|
||||
target_link_libraries(libimhex PUBLIC ${IMHEX_PLUGIN_NAME})
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/dist/web/plugin-bundle.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/plugin-bundle.cpp @ONLY)
|
||||
target_sources(main PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/plugin-bundle.cpp)
|
||||
else()
|
||||
set(IMHEX_PLUGIN_LIBRARY_TYPE MODULE)
|
||||
endif()
|
||||
|
||||
# Define new project for plugin
|
||||
project(${IMHEX_PLUGIN_NAME})
|
||||
|
||||
# Create a new shared library for the plugin source code
|
||||
add_library(${IMHEX_PLUGIN_NAME} SHARED ${IMHEX_PLUGIN_SOURCES})
|
||||
add_library(${IMHEX_PLUGIN_NAME} ${IMHEX_PLUGIN_LIBRARY_TYPE} ${IMHEX_PLUGIN_SOURCES})
|
||||
|
||||
# Add include directories and link libraries
|
||||
target_include_directories(${IMHEX_PLUGIN_NAME} PRIVATE ${IMHEX_PLUGIN_INCLUDES})
|
||||
target_include_directories(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_INCLUDES})
|
||||
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE libimhex ${FMT_LIBRARIES} ${IMHEX_PLUGIN_LIBRARIES})
|
||||
|
||||
# Add IMHEX_PROJECT_NAME and IMHEX_VERSION define
|
||||
target_compile_definitions(${IMHEX_PLUGIN_NAME} PRIVATE IMHEX_PROJECT_NAME="${IMHEX_PLUGIN_NAME}")
|
||||
target_compile_definitions(${IMHEX_PLUGIN_NAME} PRIVATE IMHEX_VERSION="${IMHEX_VERSION_STRING}")
|
||||
target_compile_definitions(${IMHEX_PLUGIN_NAME} PRIVATE IMHEX_PLUGIN_NAME=${IMHEX_PLUGIN_NAME})
|
||||
|
||||
# Enable required compiler flags
|
||||
set_target_properties(${IMHEX_PLUGIN_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
enableUnityBuild(${IMHEX_PLUGIN_NAME})
|
||||
setupCompilerFlags(${IMHEX_PLUGIN_NAME})
|
||||
|
||||
# Configure build properties
|
||||
@@ -33,7 +46,7 @@ macro(add_imhex_plugin)
|
||||
)
|
||||
|
||||
# Setup a romfs for the plugin
|
||||
set(LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/romfs)
|
||||
list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/romfs)
|
||||
set(LIBROMFS_PROJECT_NAME ${IMHEX_PLUGIN_NAME})
|
||||
add_subdirectory(${IMHEX_BASE_FOLDER}/lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs)
|
||||
set_target_properties(${LIBROMFS_LIBRARY} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
@@ -42,3 +55,9 @@ macro(add_imhex_plugin)
|
||||
# Add the new plugin to the main dependency list so it gets built by default
|
||||
add_dependencies(imhex_all ${IMHEX_PLUGIN_NAME})
|
||||
endmacro()
|
||||
|
||||
macro(add_romfs_resource input output)
|
||||
configure_file(${input} ${CMAKE_CURRENT_BINARY_DIR}/romfs/${output} COPYONLY)
|
||||
|
||||
list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/romfs)
|
||||
endmacro()
|
||||
@@ -24,6 +24,12 @@ if(CMAKE_GENERATOR)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# IMHEX PATCH BEGIN
|
||||
# The function defined above doesn't keep in mind that if we are cross-compiling to MacOS, APPLE must be 1,
|
||||
# so we force it here (where else would this script be run anyway ? This seems to be MacOS-specific code)
|
||||
SET(APPLE 1)
|
||||
# IMHEX PATCHE END
|
||||
|
||||
get_filename_component(BUNDLE_PATH "${BUNDLE_PATH}" ABSOLUTE)
|
||||
message(STATUS "Fixing up application bundle: ${BUNDLE_PATH}")
|
||||
|
||||
|
||||
5
dist/AppImageBuilder.yml
vendored
5
dist/AppImageBuilder.yml
vendored
@@ -20,7 +20,7 @@ AppDir:
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates universe
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy multiverse
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates multiverse
|
||||
- sourceline: deb http://.archive.ubuntu.com/ubuntu/ jammy-backports main restricted
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-backports main restricted
|
||||
universe multiverse
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security main restricted
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security universe
|
||||
@@ -38,8 +38,6 @@ AppDir:
|
||||
- libtinfo6:amd64
|
||||
files:
|
||||
include:
|
||||
- /lib/x86_64-linux-gnu/libGLX.so.0
|
||||
- /lib/x86_64-linux-gnu/libGLdispatch.so.0
|
||||
- /lib/x86_64-linux-gnu/libLLVM-13.so.1
|
||||
- /lib/x86_64-linux-gnu/libOpenGL.so.0
|
||||
- /lib/x86_64-linux-gnu/libX11.so.6
|
||||
@@ -77,7 +75,6 @@ AppDir:
|
||||
- /lib/x86_64-linux-gnu/libgdk-3.so.0
|
||||
- /lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0
|
||||
- /lib/x86_64-linux-gnu/libgio-2.0.so.0
|
||||
- /lib/x86_64-linux-gnu/libglapi.so.0
|
||||
- /lib/x86_64-linux-gnu/libglfw.so.3
|
||||
- /lib/x86_64-linux-gnu/libglib-2.0.so.0
|
||||
- /lib/x86_64-linux-gnu/libgmodule-2.0.so.0
|
||||
|
||||
2
dist/Arch/PKGBUILD
vendored
2
dist/Arch/PKGBUILD
vendored
@@ -25,5 +25,5 @@ package() {
|
||||
|
||||
install -d "$pkgdir/usr/share/imhex"
|
||||
cp -r "$srcdir/usr/share/imhex/"{constants,encodings,includes,magic,patterns} "$pkgdir/usr/share/imhex"
|
||||
cp -r "$srcdir/usr/share/"{applications,licenses} "$pkgdir/usr/share"
|
||||
cp -r "$srcdir/usr/share/"{applications,licenses,pixmaps} "$pkgdir/usr/share"
|
||||
}
|
||||
|
||||
85
dist/appimage/Dockerfile
vendored
Normal file
85
dist/appimage/Dockerfile
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
FROM ubuntu:22.04 as build
|
||||
|
||||
# Used to invalidate layer cache but not mount cache
|
||||
# See https://github.com/moby/moby/issues/41715#issuecomment-733976493
|
||||
ARG UNIQUEKEY 1
|
||||
|
||||
COPY dist/get_deps_debian.sh /tmp
|
||||
RUN --mount=type=cache,target=/var/apt/cache <<EOF
|
||||
# Install apt dependencies
|
||||
set -xe
|
||||
|
||||
apt update
|
||||
|
||||
# general deps
|
||||
apt install -y ccache git wget
|
||||
# appimage tools deps
|
||||
apt install -y python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fuse ninja-build
|
||||
apt install -y squashfs-tools zsync
|
||||
|
||||
# imhex deps
|
||||
/tmp/get_deps_debian.sh
|
||||
EOF
|
||||
|
||||
RUN --mount=type=cache,target=/cache <<EOF
|
||||
# Download appimage-builder
|
||||
set -xe
|
||||
|
||||
mkdir -p /cache/bin
|
||||
wget -nc https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /cache/bin/appimagetool || true
|
||||
chmod +x /cache/bin/appimagetool
|
||||
|
||||
pip3 install git+https://github.com/AppImageCrafters/appimage-builder@f38699e
|
||||
EOF
|
||||
|
||||
ENV PATH="/cache/bin/:${PATH}"
|
||||
|
||||
# Copy Imhex source
|
||||
COPY . /imhex
|
||||
|
||||
ARG LTO=ON
|
||||
ARG BUILD_TYPE=RelWithDebInfo
|
||||
ARG GIT_COMMIT_HASH
|
||||
ARG GIT_BRANCH
|
||||
WORKDIR /build
|
||||
SHELL ["bash", "-c"] # Ubuntu sh doesnt support string substitution
|
||||
RUN <<EOF
|
||||
# Prepare ImHex build
|
||||
set -xe
|
||||
|
||||
CC=gcc-12 CXX=g++-12 cmake -G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_COMMIT_HASH_SHORT="${GIT_COMMIT_HASH::7}" \
|
||||
-DIMHEX_COMMIT_HASH_LONG="${GIT_COMMIT_HASH}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${GIT_BRANCH}" \
|
||||
-DIMHEX_ENABLE_LTO=${LTO} \
|
||||
-DIMHEX_PLUGINS_IN_SHARE=ON \
|
||||
/imhex
|
||||
EOF
|
||||
|
||||
ENV CCACHE_DIR /cache/ccache
|
||||
RUN --mount=type=cache,target=/cache <<EOF
|
||||
# Build Imhex
|
||||
set -xe
|
||||
|
||||
ccache -zs
|
||||
DESTDIR=AppDir ninja install
|
||||
ccache -s
|
||||
EOF
|
||||
|
||||
RUN <<EOF
|
||||
# Package ImHex as AppImage
|
||||
set -xe
|
||||
|
||||
export VERSION=$(cat /imhex/VERSION)
|
||||
appimage-builder --recipe /imhex/dist/AppImageBuilder.yml
|
||||
EOF
|
||||
|
||||
FROM scratch
|
||||
|
||||
# Copy build artifact
|
||||
COPY --from=build /build/*.AppImage /build/*.AppImage.zsync ./
|
||||
48
dist/compiling/docker.md
vendored
Normal file
48
dist/compiling/docker.md
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
For a TLDR of commands see [How to build](#How-to-build)
|
||||
|
||||
# Introduction
|
||||
|
||||
The original CI we used (vanilla Github Actions) was great for specifying what steps to execute to build packages. It could even do some custom steps with reusable actions. But it had problem: no local reproducibility. This meant that:
|
||||
- We couldn't test code properly locally, we were dependent on GitHub to do it
|
||||
- If something was wrong and we had to debug the build script, it was *long and painful* because we had to wait for Github runners to finish builds, and couldn't quickly iterate
|
||||
|
||||
To solve this, we are now trying to move the CI build script to docker containers (so using Dockerfiles)
|
||||
|
||||
# How to build
|
||||
|
||||
Commands are available in the [CI](../../.github/workflows/build.yml) and you should prefer copying them from there.
|
||||
But here is a general command that should work for every build we have:
|
||||
```
|
||||
docker buildx build . -f <DOCKERFILE_PATH> --progress plain --build-arg 'JOBS=4' --build-arg 'BUILD_TYPE=Debug' --build-context imhex=$(pwd) --output local
|
||||
```
|
||||
|
||||
where `<DOCKERFILE_PATH>` should be replaced by the wanted Dockerfile base d on the build you want to do:
|
||||
|
||||
| Wanted build | Dockerfile path |
|
||||
|--------------|-----------------------------|
|
||||
| MacOS M1 | dist/macOS/arm64.Dockerfile |
|
||||
| AppImage | dist/appimage/Dockerfile |
|
||||
| Web version | dist/web/Dockerfile |
|
||||
|
||||
We'll explain this command in the next section
|
||||
|
||||
# Useful knowledge about Docker builds
|
||||
|
||||
Docker-based builds work with a Dockerfile. You run the Dockerfile, it builds the package.
|
||||
|
||||
We are using a base environment (often given to us by dockerhub) (e.g. ubuntu:22.04) which is really just a root filesystem, and we then run shell commands in that env, just like a shell script
|
||||
|
||||
Docker-based builds have two kind of caches used:
|
||||
- layer cache, which mean that if a layer (instruction) hasn't been changed, and previous layers haven't changed, it will not be run again
|
||||
- a `COPY` layer will be invalidated if one of the file copied has changed
|
||||
- mount cache, which are per-instructions mounts that will be cached and restored in the next run. Mounts on different folders will not collide
|
||||
|
||||
Docker cache tends to grow very quickly when constantly making changes in the Dockerfile and rebuilding (a.k.a debugging what's going on), you can clear it with something like `docker system prune -a`
|
||||
|
||||
In the command saw earlier:
|
||||
- `.` is the base folder that the Dockerfile will be allowed to see
|
||||
- `-f <path>` is to specify the Dockerfile path
|
||||
- `--progress plain` is to allow you to see the output of instructions
|
||||
- `--build-arg <key>=<value>` is to allow to to specify arguments to the build (like -DKEY=VALUE in CMake)
|
||||
- `--build-context key=<folder>` is to specify folders other than the base folder that the Dockerfile is allowed to see
|
||||
- `--output <path>` is the path to write the output package to. If not specified, Docker will create an image as the output (probably not what you want)
|
||||
5
dist/compiling/macos.md
vendored
5
dist/compiling/macos.md
vendored
@@ -1,6 +1,6 @@
|
||||
### Compiling ImHex on macOS
|
||||
|
||||
On macOS, ImHex is built through regular GCC and AppleClang.
|
||||
On macOS, ImHex is built through regular GCC and LLVM clang.
|
||||
|
||||
1. Clone the repo using `git clone https://github.com/WerWolv/ImHex --recurse-submodules`
|
||||
2. Install all the dependencies using `brew bundle --no-lock --file dist/Brewfile`
|
||||
@@ -17,8 +17,7 @@ PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/p
|
||||
MACOSX_DEPLOYMENT_TARGET="10.15" \
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCREATE_BUNDLE=ON \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DIMHEX_GENERATE_PACKAGE=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
|
||||
165
dist/macOS/arm64.Dockerfile
vendored
Normal file
165
dist/macOS/arm64.Dockerfile
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
# This base image is also known as "crosscompile". See arm64.crosscompile.Dockerfile
|
||||
FROM ghcr.io/itrooz/macos-crosscompile:clang17-nosdk as build
|
||||
|
||||
ENV MACOSX_DEPLOYMENT_TARGET 12.1
|
||||
|
||||
# -- DOWNLOADING STUFF
|
||||
|
||||
## Install make
|
||||
RUN --mount=type=cache,target=/var/lib/apt/lists/ apt update && apt install -y make
|
||||
|
||||
## fix environment
|
||||
### add install_name_tool for cmake command that won't have the right env set (see PostprocessBundle.cmake function postprocess_bundle())
|
||||
RUN cp /osxcross/build/cctools-port/cctools/misc/install_name_tool /usr/bin/install_name_tool
|
||||
### a cmake thing wants 'otool' and not '' apparently
|
||||
RUN cp /osxcross/target/bin/aarch64-apple-darwin23-otool /usr/bin/otool
|
||||
|
||||
## Clone glfw
|
||||
RUN <<EOF
|
||||
set -xe
|
||||
if [ "$CUSTOM_GLFW" ]; then
|
||||
git clone https://github.com/glfw/glfw /mnt/glfw
|
||||
fi
|
||||
EOF
|
||||
|
||||
RUN --mount=type=cache,target=/cache <<EOF
|
||||
## Download SDK is missing (it may have been removed from the image)
|
||||
set -xe
|
||||
if [ ! -d /osxcross/target/SDK/MacOSX14.0.sdk ]; then
|
||||
wget https://github.com/joseluisq/macosx-sdks/releases/download/14.0/MacOSX14.0.sdk.tar.xz -O /cache/MacOSX14.0.sdk.tar.xz -nc || true
|
||||
mkdir -p /osxcross/target/SDK
|
||||
tar -C /osxcross/target/SDK -xf /cache/MacOSX14.0.sdk.tar.xz
|
||||
fi
|
||||
EOF
|
||||
|
||||
|
||||
## Download libmagic
|
||||
### Clone libmagic
|
||||
RUN git clone https://github.com/file/file /mnt/file
|
||||
### Download libmagic dependencies
|
||||
RUN --mount=type=cache,target=/var/lib/apt/lists/ apt install -y libtool autoconf
|
||||
|
||||
# -- DOWNLOADING + BUILDING STUFF
|
||||
|
||||
ENV VCPKG_DEFAULT_BINARY_CACHE /cache/vcpkg
|
||||
RUN --mount=type=cache,target=/cache <<EOF
|
||||
## Install dependencies with vcpkg
|
||||
set -xe
|
||||
|
||||
mkdir -p $VCPKG_DEFAULT_BINARY_CACHE
|
||||
|
||||
vcpkg install --triplet=arm-osx-mytriplet curl
|
||||
vcpkg install --triplet=arm-osx-mytriplet mbedtls
|
||||
vcpkg install --triplet=arm-osx-mytriplet freetype
|
||||
vcpkg install --triplet=arm-osx-mytriplet josuttis-jthread
|
||||
EOF
|
||||
|
||||
## Install glfw3 dep
|
||||
ARG CUSTOM_GLFW
|
||||
RUN --mount=type=cache,target=/cache <<EOF
|
||||
set -xe
|
||||
if [ "$CUSTOM_GLFW" ]; then
|
||||
echo "Flag confirmation: using custom GLFW for software rendering"
|
||||
else
|
||||
echo "Flag confirmation: using system GLFW"
|
||||
vcpkg install --triplet=arm-osx-mytriplet glfw3
|
||||
fi
|
||||
EOF
|
||||
|
||||
# -- BUILDING STUFF
|
||||
ARG JOBS 1
|
||||
ARG BUILD_TYPE Debug
|
||||
|
||||
## Build libmagic
|
||||
RUN --mount=type=cache,target=/cache <<EOF
|
||||
ccache -zs
|
||||
set -xe
|
||||
|
||||
cd /mnt/file
|
||||
autoreconf -is
|
||||
|
||||
# when cross-compiling, libmagic needs to have an the same version installed in the system.
|
||||
# So we install it normally first
|
||||
./configure --prefix /usr
|
||||
make -j $JOBS install
|
||||
|
||||
# Now, we cross-compile it and install it in the libraries folder
|
||||
CC=/osxcross/target/bin/aarch64-apple-darwin23-clang CXX=/osxcross/target/bin/aarch64-apple-darwin23-clang++ ./configure --prefix /vcpkg/installed/arm-osx-mytriplet --host $OSXCROSS_HOST
|
||||
make -j $JOBS
|
||||
make install
|
||||
|
||||
ccache -s
|
||||
|
||||
EOF
|
||||
|
||||
## Patch glfw
|
||||
COPY --from=imhex /dist/macOS/0001-glfw-SW.patch /tmp
|
||||
RUN <<EOF
|
||||
set -xe
|
||||
if [ "$CUSTOM_GLFW" ]; then
|
||||
cd /mnt/glfw
|
||||
git apply /tmp/0001-glfw-SW.patch
|
||||
fi
|
||||
EOF
|
||||
|
||||
## Build glfw
|
||||
RUN --mount=type=cache,target=/cache <<EOF
|
||||
set -xe
|
||||
if [ "$CUSTOM_GLFW" ]; then
|
||||
ccache -zs
|
||||
|
||||
cd /mnt/glfw
|
||||
mkdir build
|
||||
cd build
|
||||
CC=o64-gcc CXX=o64-g++ cmake -G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DBUILD_SHARED_LIBS=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_INSTALL_PREFIX=/vcpkg/installed/arm-osx-mytriplet \
|
||||
-DVCPKG_TARGET_TRIPLET=arm-osx-mytriplet -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/osxcross/target/toolchain.cmake -DCMAKE_OSX_SYSROOT=/osxcross/target/SDK/MacOSX14.0.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \
|
||||
..
|
||||
ninja -j $JOBS install
|
||||
|
||||
ccache -s
|
||||
fi
|
||||
EOF
|
||||
|
||||
# Build ImHex
|
||||
## Copy ImHex
|
||||
COPY --from=imhex / /mnt/ImHex
|
||||
## Patch ImHex with hacks
|
||||
# COPY toolchain.cmake.2 /osxcross/target/toolchain.cmake
|
||||
# Configure ImHex build
|
||||
RUN --mount=type=cache,target=/cache --mount=type=cache,target=/mnt/ImHex/build/_deps \
|
||||
cd /mnt/ImHex && \
|
||||
# compilers
|
||||
CC=o64-clang CXX=o64-clang++ OBJC=/osxcross/target/bin/aarch64-apple-darwin23-clang OBJCXX=/osxcross/target/bin/aarch64-apple-darwin23-clang++ \
|
||||
cmake -G "Ninja" \
|
||||
`# ccache flags` \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_OBJC_COMPILER_LAUNCHER=ccache -DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
`# MacOS cross-compiling flags` \
|
||||
-DVCPKG_TARGET_TRIPLET=arm-osx-mytriplet -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/osxcross/target/toolchain.cmake -DCMAKE_OSX_SYSROOT=/osxcross/target/SDK/MacOSX14.0.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \
|
||||
`# Override compilers for code generators` \
|
||||
-DNATIVE_CMAKE_C_COMPILER=/usr/bin/clang -DNATIVE_CMAKE_CXX_COMPILER=/usr/bin/clang++ \
|
||||
`# Normal ImHex flags` \
|
||||
-DIMHEX_GENERATE_PACKAGE=ON -DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
`# other flags` \
|
||||
-DIMHEX_STRICT_WARNINGS=OFF \
|
||||
-B build
|
||||
## Build ImHex
|
||||
RUN --mount=type=cache,target=/cache --mount=type=cache,target=/mnt/ImHex/build/_deps <<EOF
|
||||
ccache -zs
|
||||
set -xe
|
||||
|
||||
cd /mnt/ImHex
|
||||
cmake --build build --parallel $JOBS
|
||||
|
||||
ccache -s
|
||||
EOF
|
||||
|
||||
|
||||
FROM scratch
|
||||
COPY --from=build /mnt/ImHex/build/imhex.app imhex.app
|
||||
96
dist/macOS/arm64.crosscompile.Dockerfile
vendored
Normal file
96
dist/macOS/arm64.crosscompile.Dockerfile
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
# This image is is provided for reference, but a (probably more up to date) image should be available at https://github.com/iTrooz/macos-crosscompile
|
||||
FROM ubuntu:22.04
|
||||
|
||||
ENV PATH $PATH:/osxcross/target/bin
|
||||
ENV LD_LIBRARY_PATH /osxcross/target/lib
|
||||
ENV OSXCROSS_SDK /osxcross/target/SDK/MacOSX14.0.sdk
|
||||
ENV OSXCROSS_TARGET darwin23
|
||||
ENV OSXCROSS_TARGET_DIR /osxcross/target
|
||||
ENV OSXCROSS_HOST aarch64-apple-darwin23
|
||||
|
||||
# -- DOWNLOADING STUFF
|
||||
|
||||
# Install common stuff
|
||||
RUN --mount=type=cache,target=/var/lib/apt/lists/ export DEBIAN_FRONTEND=noninteractive &&\
|
||||
export TZ=Etc/UTC &&\
|
||||
dpkg --add-architecture i386 &&\
|
||||
apt update &&\
|
||||
apt -y install lsb-release build-essential python3 python3-pip git wget zip unzip pkg-config curl ninja-build software-properties-common gnupg libssl-dev ccache
|
||||
|
||||
# Install clang 17
|
||||
RUN --mount=type=cache,target=/var/lib/apt/lists/ wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && ./llvm.sh 17 &&\
|
||||
ln -s /usr/bin/clang-17 /usr/bin/clang &&\
|
||||
ln -s /usr/bin/clang++-17 /usr/bin/clang++
|
||||
|
||||
# Install vcpkg
|
||||
RUN cd / &&\
|
||||
git clone --depth 1 https://github.com/Microsoft/vcpkg.git vcpkg &&\
|
||||
cd /vcpkg &&\
|
||||
./bootstrap-vcpkg.sh -disableMetrics &&\
|
||||
ln -s /vcpkg/vcpkg /usr/bin/ &&\
|
||||
vcpkg install vcpkg-cmake &&\
|
||||
ln -s /vcpkg/downloads/tools/cmake-*/cmake-*/bin/cmake /usr/bin/
|
||||
|
||||
RUN --mount=type=cache,target=/cache <<EOF
|
||||
## Clone osxcross
|
||||
set -xe
|
||||
git clone https://github.com/tpoechtrager/osxcross /cache/osxcross || true
|
||||
cd /cache/osxcross
|
||||
git pull
|
||||
cp -r /cache/osxcross /osxcross
|
||||
EOF
|
||||
|
||||
RUN --mount=type=cache,target=/cache <<EOF
|
||||
## Download SDK
|
||||
set -xe
|
||||
wget https://github.com/joseluisq/macosx-sdks/releases/download/14.0/MacOSX14.0.sdk.tar.xz -O /cache/MacOSX14.0.sdk.tar.xz -nc || true
|
||||
cp /cache/MacOSX14.0.sdk.tar.xz /osxcross/tarballs
|
||||
EOF
|
||||
|
||||
# Init stuff
|
||||
## setup ccache dir
|
||||
ENV CCACHE_DIR /cache/ccache
|
||||
|
||||
# Install triplet file
|
||||
COPY arm-osx-mytriplet.cmake /vcpkg/triplets/community
|
||||
|
||||
# -- BUILDING STUFF
|
||||
ARG JOBS 1
|
||||
|
||||
# Install osxcross
|
||||
## Build cross-compiler clang-17
|
||||
RUN --mount=type=cache,target=/cache <<EOF
|
||||
set -xe
|
||||
ccache -zs
|
||||
|
||||
cd /osxcross
|
||||
UNATTENDED=1 CC=/usr/lib/ccache/clang-17 CXX=/usr/lib/ccache/clang++-17 ./build.sh
|
||||
|
||||
ccache -s
|
||||
EOF
|
||||
# Not needed, because we don't use gcc for cross-compiling anymore
|
||||
# ## Install dependencies for gcc-13
|
||||
# RUN apt install -y gcc g++ zlib1g-dev libmpc-dev libmpfr-dev libgmp-dev
|
||||
# ## Build cross-compiler gcc-13
|
||||
# RUN --mount=type=cache,target=/cache <<EOF
|
||||
# set -xe
|
||||
# ccache -zs
|
||||
|
||||
# cd /osxcross
|
||||
# UNATTENDED=1 CC=/usr/lib/ccache/gcc CXX=/usr/lib/ccache/g++ GCC_VERSION=13.2.0 ./build_gcc.sh
|
||||
|
||||
# ccache -s
|
||||
# EOF
|
||||
|
||||
ARG DELETE_SDK=1
|
||||
RUN <<EOF
|
||||
# Conditionally delete the SDK from the image
|
||||
set -xe
|
||||
|
||||
if [ "$DELETE_SDK" ]; then
|
||||
rm -r /osxcross/target/SDK
|
||||
echo "Deleted the SDK from the image"
|
||||
else
|
||||
echo "NOT deleting the SDK from the image"
|
||||
fi
|
||||
EOF
|
||||
12
dist/rpm/imhex.spec
vendored
12
dist/rpm/imhex.spec
vendored
@@ -61,7 +61,7 @@ same time ImHex is completely free and open source under the GPLv2 language.
|
||||
%prep
|
||||
%autosetup -n ImHex
|
||||
# remove bundled libs we aren't using
|
||||
rm -rf lib/external/{curl,fmt,llvm,nlohmann_json,yara}
|
||||
rm -rf lib/third_party/{fmt,nlohmann_json,yara}
|
||||
|
||||
%build
|
||||
%if 0%{?rhel}
|
||||
@@ -109,11 +109,11 @@ rm -f %{buildroot}%{_metainfodir}/net.werwolv.%{name}.appdata.xml
|
||||
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/xdgpp/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/xdgpp-LICENSE
|
||||
cp -a lib/third_party/nativefiledialog/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/nativefiledialog-LICENSE
|
||||
cp -a lib/third_party/capstone/LICENSE.TXT %{buildroot}%{_datadir}/licenses/%{name}/capstone-LICENSE
|
||||
cp -a lib/third_party/capstone/suite/regress/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/capstone-regress-LICENSE
|
||||
cp -a lib/third_party/microtar/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/microtar-LICENSE
|
||||
cp -a lib/third_party/xdgpp/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/xdgpp-LICENSE
|
||||
|
||||
|
||||
%files
|
||||
|
||||
89
dist/web/Dockerfile
vendored
Normal file
89
dist/web/Dockerfile
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
FROM emscripten/emsdk:latest as build
|
||||
|
||||
# Used to invalidate layer cache but not mount cache
|
||||
# See https://github.com/moby/moby/issues/41715#issuecomment-733976493
|
||||
ARG UNIQUEKEY 1
|
||||
|
||||
RUN apt update
|
||||
RUN apt install -y git ccache autoconf automake libtool cmake pkg-config
|
||||
|
||||
RUN <<EOF
|
||||
# Install vcpkg
|
||||
# Note: we are a patch on the libmagic port
|
||||
set -xe
|
||||
|
||||
git clone https://github.com/microsoft/vcpkg /vcpkg
|
||||
/vcpkg/bootstrap-vcpkg.sh
|
||||
sed -i 's/vcpkg_install_make(${EXTRA_ARGS})/vcpkg_install_make(${EXTRA_ARGS} SUBPATH src)/g' /vcpkg/ports/libmagic/portfile.cmake
|
||||
EOF
|
||||
|
||||
# Patch vcpkg build instructions to add -pthread
|
||||
RUN <<EOF
|
||||
set -xe
|
||||
|
||||
echo '
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
||||
' >> /emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake
|
||||
EOF
|
||||
|
||||
ENV VCPKG_DEFAULT_BINARY_CACHE /cache/vcpkg
|
||||
RUN --mount=type=cache,target=/cache <<EOF
|
||||
# Install dependencies with vcpkg
|
||||
set -xe
|
||||
|
||||
mkdir -p $VCPKG_DEFAULT_BINARY_CACHE
|
||||
|
||||
/vcpkg/vcpkg install --triplet=wasm32-emscripten libmagic
|
||||
/vcpkg/vcpkg install --triplet=wasm32-emscripten freetype
|
||||
/vcpkg/vcpkg install --triplet=wasm32-emscripten mbedtls
|
||||
EOF
|
||||
|
||||
# Build ImHex
|
||||
ARG JOBS=4
|
||||
ENV CCACHE_DIR /cache/ccache
|
||||
|
||||
RUN mkdir /build
|
||||
WORKDIR /build
|
||||
RUN --mount=type=cache,target=/cache \
|
||||
--mount=type=bind,source=.,target=/imhex <<EOF
|
||||
|
||||
set -xe
|
||||
ccache -zs
|
||||
|
||||
cmake /imhex \
|
||||
-DIMHEX_OFFLINE_BUILD=ON \
|
||||
-DIMHEX_STATIC_LINK_PLUGINS=ON \
|
||||
-DNATIVE_CMAKE_C_COMPILER=gcc \
|
||||
-DNATIVE_CMAKE_CXX_COMPILER=g++ \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake \
|
||||
-DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake \
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
make -j $JOBS
|
||||
|
||||
cp /imhex/dist/web/source/* /build
|
||||
ccache -s
|
||||
EOF
|
||||
|
||||
FROM scratch
|
||||
COPY --from=build [ \
|
||||
# ImHex \
|
||||
"/build/imhex.wasm", \
|
||||
"/build/imhex.js", \
|
||||
"/build/imhex.worker.js", \
|
||||
\
|
||||
# Static files \
|
||||
"/build/index.html", \
|
||||
"/build/style.css", \
|
||||
"/build/wasm-config.js", \
|
||||
"/build/enable-threads.js", \
|
||||
"/build/favicon.ico", \
|
||||
"/build/icon.png", \
|
||||
"/build/manifest.json", \
|
||||
\
|
||||
# Destination \
|
||||
"./" \
|
||||
]
|
||||
11
dist/web/plugin-bundle.cpp.in
vendored
Normal file
11
dist/web/plugin-bundle.cpp.in
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
extern "C" void forceLinkPlugin_@IMHEX_PLUGIN_NAME@();
|
||||
|
||||
struct StaticLoad {
|
||||
StaticLoad() {
|
||||
forceLinkPlugin_@IMHEX_PLUGIN_NAME@();
|
||||
}
|
||||
};
|
||||
|
||||
static StaticLoad staticLoad;
|
||||
15
dist/web/serve.py
vendored
Normal file
15
dist/web/serve.py
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import http.server
|
||||
import os
|
||||
|
||||
class MyHttpRequestHandler(http.server.SimpleHTTPRequestHandler):
|
||||
|
||||
def end_headers(self):
|
||||
self.send_header("Cross-Origin-Embedder-Policy", "require-corp")
|
||||
self.send_header("Cross-Origin-Opener-Policy", "same-origin")
|
||||
http.server.SimpleHTTPRequestHandler.end_headers(self)
|
||||
|
||||
if __name__ == '__main__':
|
||||
os.chdir(".")
|
||||
httpd = http.server.HTTPServer(("localhost", 9090), MyHttpRequestHandler)
|
||||
print(f"Serving {os.getcwd()} on http://{httpd.server_address[0]}:{httpd.server_address[1]}")
|
||||
httpd.serve_forever()
|
||||
79
dist/web/source/enable-threads.js
vendored
Normal file
79
dist/web/source/enable-threads.js
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
// NOTE: This file creates a service worker that cross-origin-isolates the page (read more here: https://web.dev/coop-coep/) which allows us to use wasm threads.
|
||||
// Normally you would set the COOP and COEP headers on the server to do this, but Github Pages doesn't allow this, so this is a hack to do that.
|
||||
|
||||
/* Edited version of: coi-serviceworker v0.1.6 - Guido Zuidhof, licensed under MIT */
|
||||
// From here: https://github.com/gzuidhof/coi-serviceworker
|
||||
if(typeof window === 'undefined') {
|
||||
self.addEventListener("install", () => self.skipWaiting());
|
||||
self.addEventListener("activate", e => e.waitUntil(self.clients.claim()));
|
||||
|
||||
async function handleFetch(request) {
|
||||
if(request.cache === "only-if-cached" && request.mode !== "same-origin") {
|
||||
return;
|
||||
}
|
||||
|
||||
if(request.mode === "no-cors") { // We need to set `credentials` to "omit" for no-cors requests, per this comment: https://bugs.chromium.org/p/chromium/issues/detail?id=1309901#c7
|
||||
request = new Request(request.url, {
|
||||
cache: request.cache,
|
||||
credentials: "omit",
|
||||
headers: request.headers,
|
||||
integrity: request.integrity,
|
||||
destination: request.destination,
|
||||
keepalive: request.keepalive,
|
||||
method: request.method,
|
||||
mode: request.mode,
|
||||
redirect: request.redirect,
|
||||
referrer: request.referrer,
|
||||
referrerPolicy: request.referrerPolicy,
|
||||
signal: request.signal,
|
||||
});
|
||||
}
|
||||
|
||||
let r = await fetch(request).catch(e => console.error(e));
|
||||
|
||||
if(r.status === 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
const headers = new Headers(r.headers);
|
||||
headers.set("Cross-Origin-Embedder-Policy", "require-corp"); // or: require-corp
|
||||
headers.set("Cross-Origin-Opener-Policy", "same-origin");
|
||||
|
||||
return new Response(r.body, { status: r.status, statusText: r.statusText, headers });
|
||||
}
|
||||
|
||||
self.addEventListener("fetch", function(e) {
|
||||
e.respondWith(handleFetch(e.request)); // respondWith must be executed synchonously (but can be passed a Promise)
|
||||
});
|
||||
|
||||
} else {
|
||||
(async function() {
|
||||
if(window.crossOriginIsolated !== false) return;
|
||||
|
||||
if (!('serviceWorker' in navigator)) {
|
||||
alert("Your browser doesn't support service workers.\nIf you're using Firefox, you need to not be in a private window.")
|
||||
}
|
||||
|
||||
let registration = await navigator.serviceWorker.register(window.document.currentScript.src).catch(e => console.error("COOP/COEP Service Worker failed to register:", e));
|
||||
if(registration) {
|
||||
console.log("COOP/COEP Service Worker registered", registration.scope);
|
||||
|
||||
registration.addEventListener("updatefound", () => {
|
||||
console.log("Reloading page to make use of updated COOP/COEP Service Worker.");
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
// If the registration is active, but it's not controlling the page
|
||||
if(registration.active && !navigator.serviceWorker.controller) {
|
||||
console.log("Reloading page to make use of COOP/COEP Service Worker.");
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
// Code to deregister:
|
||||
// let registrations = await navigator.serviceWorker.getRegistrations();
|
||||
// for(let registration of registrations) {
|
||||
// await registration.unregister();
|
||||
// }
|
||||
BIN
dist/web/source/favicon.ico
vendored
Normal file
BIN
dist/web/source/favicon.ico
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 157 KiB |
74
dist/web/source/index.html
vendored
Normal file
74
dist/web/source/index.html
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
<!doctype html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
|
||||
<!-- Primary Meta Tags -->
|
||||
<title>ImHex Web - Online Hex Editor</title>
|
||||
<meta name="title" content="ImHex">
|
||||
<meta name="description" content="A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://imhex.werwolv.net/">
|
||||
<meta property="og:title" content="ImHex Web - Online Hex Editor">
|
||||
<meta property="og:description">
|
||||
<meta name="description" content="A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.">
|
||||
<meta property="og:image" content="https://imhex.werwolv.net/assets/splash_wasm.png">
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image">
|
||||
<meta property="twitter:url" content="https://imhex.werwolv.net/">
|
||||
<meta property="twitter:title" content="ImHex Web - Online Hex Editor">
|
||||
<meta property="twitter:description"
|
||||
content="A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.">
|
||||
<meta property="twitter:image" content="https://imhex.werwolv.net/assets/splash_wasm.png">
|
||||
|
||||
<meta name="viewport" content="width=device-width">
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Organization",
|
||||
"alumni": "WerWolv",
|
||||
"email": "hey@werwolv.net",
|
||||
"founder": "WerWolv",
|
||||
"slogan": "A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.",
|
||||
"url": "https://imhex.werwolv.net",
|
||||
"logo": "https://imhex.werwolv.net/assets/logos/logo.png"
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "SoftwareApplication",
|
||||
"name": "ImHex Web",
|
||||
"operatingSystem": "Windows, MacOS, Linux",
|
||||
"applicationCategory": "DeveloperApplication",
|
||||
"offers": {
|
||||
"@type": "Offer",
|
||||
"price": "0",
|
||||
"priceCurrency": "USD"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<title>ImHex Web</title>
|
||||
<script src="enable-threads.js"></script>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<p id="loading_text">ImHex is loading...</p>
|
||||
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
|
||||
|
||||
<script type="text/javascript" src="wasm-config.js"></script>
|
||||
<script async type="text/javascript" src="imhex.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
20
dist/web/source/manifest.json
vendored
Normal file
20
dist/web/source/manifest.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "ImHex",
|
||||
"description": "🔍 A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.",
|
||||
"background_color": "#0F0F0F",
|
||||
"theme_color": "#0F0F0F",
|
||||
"categories": [
|
||||
"education",
|
||||
"productivity",
|
||||
"utilities"
|
||||
],
|
||||
"icons": [
|
||||
{
|
||||
"src": "icon.png",
|
||||
"type": "image/png",
|
||||
"sizes": "640x640"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone"
|
||||
}
|
||||
36
dist/web/source/style.css
vendored
Normal file
36
dist/web/source/style.css
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
html, body {
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #121212;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.emscripten {
|
||||
padding-right: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: none;
|
||||
border: 0px none;
|
||||
}
|
||||
|
||||
.canvas_full_screen {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#loading_text {
|
||||
color: #F0F0F0;
|
||||
font-size: 30px;
|
||||
font-family: monospace;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
70
dist/web/source/wasm-config.js
vendored
Normal file
70
dist/web/source/wasm-config.js
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
function glfwSetCursorCustom(wnd, shape) {
|
||||
let body = document.getElementsByTagName("body")[0]
|
||||
switch (shape) {
|
||||
case 0x00036001: // GLFW_ARROW_CURSOR
|
||||
body.style.cursor = "default";
|
||||
break;
|
||||
case 0x00036002: // GLFW_IBEAM_CURSOR
|
||||
body.style.cursor = "text";
|
||||
break;
|
||||
case 0x00036003: // GLFW_CROSSHAIR_CURSOR
|
||||
body.style.cursor = "crosshair";
|
||||
break;
|
||||
case 0x00036004: // GLFW_HAND_CURSOR
|
||||
body.style.cursor = "pointer";
|
||||
break;
|
||||
case 0x00036005: // GLFW_HRESIZE_CURSOR
|
||||
body.style.cursor = "ew-resize";
|
||||
break;
|
||||
case 0x00036006: // GLFW_VRESIZE_CURSOR
|
||||
body.style.cursor = "ns-resize";
|
||||
break;
|
||||
default:
|
||||
body.style.cursor = "default";
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function glfwCreateStandardCursorCustom(shape) {
|
||||
return shape
|
||||
}
|
||||
|
||||
var Module = {
|
||||
preRun: [],
|
||||
postRun: [],
|
||||
onRuntimeInitialized: function() {
|
||||
// Triggered when the wasm module is loaded and ready to use.
|
||||
document.getElementById("loading_text").style.display = "none"
|
||||
document.getElementById("canvas").style.display = "initial"
|
||||
},
|
||||
print: (function() { })(),
|
||||
printErr: function(text) { },
|
||||
canvas: (function() {
|
||||
let canvas = document.getElementById('canvas');
|
||||
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
|
||||
// application robust, you may want to override this behavior before shipping!
|
||||
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
|
||||
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
|
||||
|
||||
return canvas;
|
||||
})(),
|
||||
setStatus: function(text) { },
|
||||
totalDependencies: 0,
|
||||
monitorRunDependencies: function(left) { },
|
||||
instantiateWasm: function(imports, successCallback) {
|
||||
imports.env.glfwSetCursor = glfwSetCursorCustom
|
||||
imports.env.glfwCreateStandardCursor = glfwCreateStandardCursorCustom
|
||||
instantiateAsync(wasmBinary, wasmBinaryFile, imports, (result) => successCallback(result.instance, result.module));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
window.addEventListener('resize', js_resizeCanvas, false);
|
||||
function js_resizeCanvas() {
|
||||
let canvas = document.getElementById('canvas');
|
||||
canvas.width = Math.min(document.documentElement.clientWidth, window.innerWidth || 0);
|
||||
canvas.height = Math.min(document.documentElement.clientHeight, window.innerHeight || 0);
|
||||
|
||||
canvas.classList.add("canvas_full_screen")
|
||||
}
|
||||
1
lib/external/capstone
vendored
1
lib/external/capstone
vendored
Submodule lib/external/capstone deleted from 650e85dcf2
1
lib/external/fmt
vendored
1
lib/external/fmt
vendored
Submodule lib/external/fmt deleted from f5e54359df
41
lib/external/imgui/CMakeLists.txt
vendored
41
lib/external/imgui/CMakeLists.txt
vendored
@@ -1,41 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(imgui)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(Freetype REQUIRED)
|
||||
find_package(OpenGL REQUIRED)
|
||||
pkg_search_module(GLFW REQUIRED glfw3)
|
||||
|
||||
add_library(imgui OBJECT
|
||||
source/imgui.cpp
|
||||
source/imgui_demo.cpp
|
||||
source/imgui_draw.cpp
|
||||
include/misc/freetype/imgui_freetype.cpp # TODO move source and includes in the same directory
|
||||
source/imgui_impl_glfw.cpp
|
||||
source/imgui_impl_opengl3.cpp
|
||||
source/imgui_tables.cpp
|
||||
source/imgui_widgets.cpp
|
||||
|
||||
source/TextEditor.cpp
|
||||
|
||||
source/imnodes.cpp
|
||||
|
||||
source/implot.cpp
|
||||
source/implot_items.cpp
|
||||
source/implot_demo.cpp
|
||||
|
||||
source/fonts/fontawesome_font.c
|
||||
source/fonts/codicons_font.c
|
||||
source/fonts/unifont_font.c
|
||||
)
|
||||
|
||||
target_compile_definitions(imgui PUBLIC IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||
target_compile_options(imgui PRIVATE -Wno-stringop-overflow)
|
||||
|
||||
target_compile_definitions(imgui PUBLIC IMGUI_USER_CONFIG="imgui_config.h")
|
||||
|
||||
target_include_directories(imgui PUBLIC include ${FREETYPE_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS} ${OpenGL_INCLUDE_DIRS})
|
||||
target_link_directories(imgui PUBLIC ${GLFW_LIBRARY_DIRS} ${OpenGL_LIBRARY_DIRS})
|
||||
target_link_libraries(imgui PUBLIC Freetype::Freetype ${GLFW_LIBRARIES} ${OPENGL_LIBRARIES})
|
||||
9
lib/external/imgui/include/imgui_config.h
vendored
9
lib/external/imgui/include/imgui_config.h
vendored
@@ -1,9 +0,0 @@
|
||||
// ImGui config (check imconfig.h for more information about these definitions)
|
||||
#pragma once
|
||||
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
#define IMGUI_DISABLE_OBSOLETE_KEYIO
|
||||
#define IMGUI_ENABLE_FREETYPE
|
||||
#define ImDrawIdx unsigned int
|
||||
#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
|
||||
1095
lib/external/imgui/source/fonts/codicons_font.c
vendored
1095
lib/external/imgui/source/fonts/codicons_font.c
vendored
File diff suppressed because it is too large
Load Diff
3025
lib/external/imgui/source/fonts/fontawesome_font.c
vendored
3025
lib/external/imgui/source/fonts/fontawesome_font.c
vendored
File diff suppressed because it is too large
Load Diff
116170
lib/external/imgui/source/fonts/unifont_font.c
vendored
116170
lib/external/imgui/source/fonts/unifont_font.c
vendored
File diff suppressed because it is too large
Load Diff
2
lib/external/libromfs
vendored
2
lib/external/libromfs
vendored
Submodule lib/external/libromfs updated: 31b331c02a...04ba8ba5cd
2
lib/external/libwolv
vendored
2
lib/external/libwolv
vendored
Submodule lib/external/libwolv updated: 094d87ca30...e4891c89b6
@@ -1,122 +0,0 @@
|
||||
//===--- StringView.h ----------------*- mode:c++;eval:(read-only-mode) -*-===//
|
||||
// Do not edit! See README.txt.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// FIXME: Use std::string_view instead when we support C++17.
|
||||
// There are two copies of this file in the source tree. The one under
|
||||
// libcxxabi is the original and the one under llvm is the copy. Use
|
||||
// cp-to-llvm.sh to update the copy. See README.txt for more details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEMANGLE_STRINGVIEW_H
|
||||
#define LLVM_DEMANGLE_STRINGVIEW_H
|
||||
|
||||
#include "DemangleConfig.h"
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
DEMANGLE_NAMESPACE_BEGIN
|
||||
|
||||
class StringView {
|
||||
const char *First;
|
||||
const char *Last;
|
||||
|
||||
public:
|
||||
static const size_t npos = ~size_t(0);
|
||||
|
||||
template <size_t N>
|
||||
StringView(const char (&Str)[N]) : First(Str), Last(Str + N - 1) {}
|
||||
StringView(const char *First_, const char *Last_)
|
||||
: First(First_), Last(Last_) {}
|
||||
StringView(const char *First_, size_t Len)
|
||||
: First(First_), Last(First_ + Len) {}
|
||||
StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}
|
||||
StringView() : First(nullptr), Last(nullptr) {}
|
||||
|
||||
StringView substr(size_t Pos, size_t Len = npos) const {
|
||||
assert(Pos <= size());
|
||||
if (Len > size() - Pos)
|
||||
Len = size() - Pos;
|
||||
return StringView(begin() + Pos, Len);
|
||||
}
|
||||
|
||||
size_t find(char C, size_t From = 0) const {
|
||||
// Avoid calling memchr with nullptr.
|
||||
if (From < size()) {
|
||||
// Just forward to memchr, which is faster than a hand-rolled loop.
|
||||
if (const void *P = ::memchr(First + From, C, size() - From))
|
||||
return size_t(static_cast<const char *>(P) - First);
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
StringView dropFront(size_t N = 1) const {
|
||||
if (N >= size())
|
||||
N = size();
|
||||
return StringView(First + N, Last);
|
||||
}
|
||||
|
||||
StringView dropBack(size_t N = 1) const {
|
||||
if (N >= size())
|
||||
N = size();
|
||||
return StringView(First, Last - N);
|
||||
}
|
||||
|
||||
char front() const {
|
||||
assert(!empty());
|
||||
return *begin();
|
||||
}
|
||||
|
||||
char back() const {
|
||||
assert(!empty());
|
||||
return *(end() - 1);
|
||||
}
|
||||
|
||||
char popFront() {
|
||||
assert(!empty());
|
||||
return *First++;
|
||||
}
|
||||
|
||||
bool consumeFront(char C) {
|
||||
if (!startsWith(C))
|
||||
return false;
|
||||
*this = dropFront(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool consumeFront(StringView S) {
|
||||
if (!startsWith(S))
|
||||
return false;
|
||||
*this = dropFront(S.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool startsWith(char C) const { return !empty() && *begin() == C; }
|
||||
|
||||
bool startsWith(StringView Str) const {
|
||||
if (Str.size() > size())
|
||||
return false;
|
||||
return std::strncmp(Str.begin(), begin(), Str.size()) == 0;
|
||||
}
|
||||
|
||||
const char &operator[](size_t Idx) const { return *(begin() + Idx); }
|
||||
|
||||
const char *begin() const { return First; }
|
||||
const char *end() const { return Last; }
|
||||
size_t size() const { return static_cast<size_t>(Last - First); }
|
||||
bool empty() const { return First == Last; }
|
||||
};
|
||||
|
||||
inline bool operator==(const StringView &LHS, const StringView &RHS) {
|
||||
return LHS.size() == RHS.size() &&
|
||||
std::strncmp(LHS.begin(), RHS.begin(), LHS.size()) == 0;
|
||||
}
|
||||
|
||||
DEMANGLE_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
1
lib/external/nativefiledialog
vendored
1
lib/external/nativefiledialog
vendored
Submodule lib/external/nativefiledialog deleted from 800f58283f
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
Submodule lib/external/pattern_language updated: ff92cf631a...b5de2d2f8a
1
lib/external/yara/yara
vendored
1
lib/external/yara/yara
vendored
Submodule lib/external/yara/yara deleted from d1ff3ecc46
@@ -5,17 +5,17 @@ set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
set(LIBIMHEX_SOURCES
|
||||
source/api/event.cpp
|
||||
source/api/imhex_api.cpp
|
||||
source/api/content_registry.cpp
|
||||
source/api/task.cpp
|
||||
source/api/keybinding.cpp
|
||||
source/api/event_manager.cpp
|
||||
source/api/task_manager.cpp
|
||||
source/api/shortcut_manager.cpp
|
||||
source/api/plugin_manager.cpp
|
||||
source/api/localization.cpp
|
||||
source/api/project_file_manager.cpp
|
||||
source/api/theme_manager.cpp
|
||||
source/api/layout_manager.cpp
|
||||
source/api/achievement_manager.cpp
|
||||
source/api/localization_manager.cpp
|
||||
|
||||
source/data_processor/attribute.cpp
|
||||
source/data_processor/link.cpp
|
||||
@@ -27,14 +27,18 @@ set(LIBIMHEX_SOURCES
|
||||
source/helpers/magic.cpp
|
||||
source/helpers/crypto.cpp
|
||||
source/helpers/http_requests.cpp
|
||||
source/helpers/http_requests_native.cpp
|
||||
source/helpers/http_requests_emscripten.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/debugging.cpp
|
||||
|
||||
source/providers/provider.cpp
|
||||
source/providers/undo/stack.cpp
|
||||
|
||||
source/ui/imgui_imhex_extensions.cpp
|
||||
source/ui/view.cpp
|
||||
@@ -58,8 +62,14 @@ endif ()
|
||||
|
||||
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||
|
||||
add_library(libimhex SHARED ${LIBIMHEX_SOURCES})
|
||||
if (IMHEX_STATIC_LINK_PLUGINS)
|
||||
add_library(libimhex STATIC ${LIBIMHEX_SOURCES})
|
||||
else()
|
||||
add_library(libimhex SHARED ${LIBIMHEX_SOURCES})
|
||||
endif()
|
||||
|
||||
set_target_properties(libimhex PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
enableUnityBuild(libimhex)
|
||||
setupCompilerFlags(libimhex)
|
||||
|
||||
include(GenerateExportHeader)
|
||||
@@ -68,6 +78,13 @@ generate_export_header(libimhex)
|
||||
target_include_directories(libimhex PUBLIC include ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIR} ${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 (NOT EMSCRIPTEN)
|
||||
# curl is only used in non-emscripten builds
|
||||
target_include_directories(libimhex PUBLIC ${CURL_INCLUDE_DIRS})
|
||||
target_link_libraries(libimhex PUBLIC ${LIBCURL_LIBRARIES})
|
||||
endif()
|
||||
|
||||
|
||||
if (WIN32)
|
||||
set_target_properties(libimhex PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
|
||||
target_link_options(libimhex PRIVATE -Wl,--export-all-symbols)
|
||||
@@ -77,7 +94,7 @@ elseif (APPLE)
|
||||
endif ()
|
||||
|
||||
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} plcli libpl libpl-gen ${MINIAUDIO_LIBRARIES} libwolv-utils libwolv-io libwolv-hash libwolv-net libwolv-containers)
|
||||
target_link_libraries(libimhex PUBLIC dl ${IMGUI_LIBRARIES} ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${MBEDTLS_LIBRARIES} ${LIBBACKTRACE_LIBRARIES} plcli libpl libpl-gen ${MINIAUDIO_LIBRARIES} ${JTHREAD_LIBRARIES} wolv::utils wolv::io wolv::hash wolv::net wolv::containers wolv::math_eval)
|
||||
|
||||
set_property(TARGET libimhex PROPERTY INTERPROCEDURAL_OPTIMIZATION FALSE)
|
||||
|
||||
@@ -119,4 +136,6 @@ if ((NOT GIT_COMMIT_HASH_SHORT STREQUAL "") AND (NOT GIT_COMMIT_HASH_LONG STREQU
|
||||
addDefineToSource(source/api/imhex_api.cpp "GIT_BRANCH=\"${GIT_BRANCH}\"")
|
||||
endif ()
|
||||
|
||||
addDefineToSource(source/api/imhex_api.cpp "IMHEX_VERSION=\"${IMHEX_VERSION_STRING}\"")
|
||||
addDefineToSource(source/api/imhex_api.cpp "IMHEX_VERSION=\"${IMHEX_VERSION_STRING}\"")
|
||||
|
||||
add_dependencies(imhex_all libimhex)
|
||||
@@ -1,14 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <span>
|
||||
|
||||
#include <hex/api/event.hpp>
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
@@ -141,14 +143,14 @@ namespace hex {
|
||||
* @brief Returns the icon of the achievement
|
||||
* @return Icon of the achievement
|
||||
*/
|
||||
[[nodiscard]] const ImGui::Texture &getIcon() const {
|
||||
[[nodiscard]] const ImGuiExt::Texture &getIcon() const {
|
||||
if (this->m_iconData.empty())
|
||||
return this->m_icon;
|
||||
|
||||
if (this->m_icon.isValid())
|
||||
return m_icon;
|
||||
|
||||
this->m_icon = ImGui::Texture(reinterpret_cast<const u8*>(this->m_iconData.data()), this->m_iconData.size());
|
||||
this->m_icon = ImGuiExt::Texture(this->m_iconData.data(), this->m_iconData.size());
|
||||
|
||||
return this->m_icon;
|
||||
}
|
||||
@@ -281,7 +283,7 @@ namespace hex {
|
||||
std::function<void(Achievement &)> m_clickCallback;
|
||||
|
||||
std::vector<u8> m_iconData;
|
||||
mutable ImGui::Texture m_icon;
|
||||
mutable ImGuiExt::Texture m_icon;
|
||||
|
||||
u32 m_progress = 0;
|
||||
u32 m_maxProgress = 1;
|
||||
@@ -350,7 +352,7 @@ namespace hex {
|
||||
*/
|
||||
template<std::derived_from<Achievement> T = Achievement>
|
||||
static Achievement& addTemporaryAchievement(auto && ... args) {
|
||||
auto &achievement = addAchievement(std::forward<decltype(args)>(args)...);
|
||||
auto &achievement = addAchievement<T>(std::forward<decltype(args)>(args)...);
|
||||
|
||||
achievement.m_temporary = true;
|
||||
|
||||
@@ -405,6 +407,12 @@ namespace hex {
|
||||
*/
|
||||
static void clearTemporary();
|
||||
|
||||
/**
|
||||
* \brief Returns the current progress of all achievements
|
||||
* \return A pair containing the number of unlocked achievements and the total number of achievements
|
||||
*/
|
||||
static std::pair<u32, u32> getProgress();
|
||||
|
||||
private:
|
||||
static void achievementAdded();
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -56,7 +56,7 @@ namespace hex {
|
||||
};
|
||||
|
||||
template<typename... Params>
|
||||
struct Event : public EventBase {
|
||||
struct Event : EventBase {
|
||||
using Callback = std::function<void(Params...)>;
|
||||
|
||||
explicit Event(Callback func) noexcept : m_func(std::move(func)) { }
|
||||
@@ -91,6 +91,8 @@ namespace hex {
|
||||
*/
|
||||
template<impl::EventType E>
|
||||
static EventList::iterator subscribe(typename E::Callback function) {
|
||||
std::scoped_lock lock(getEventMutex());
|
||||
|
||||
auto &events = getEvents();
|
||||
return events.insert(events.end(), std::make_pair(E::Id, std::make_unique<E>(function)));
|
||||
}
|
||||
@@ -103,7 +105,20 @@ namespace hex {
|
||||
*/
|
||||
template<impl::EventType E>
|
||||
static void subscribe(void *token, typename E::Callback function) {
|
||||
getTokenStore().insert(std::make_pair(token, subscribe<E>(function)));
|
||||
std::scoped_lock lock(getEventMutex());
|
||||
|
||||
if (getTokenStore().contains(token)) {
|
||||
auto&& [begin, end] = getTokenStore().equal_range(token);
|
||||
auto eventRegistered = std::any_of(begin, end, [&](auto &item) {
|
||||
return item.second->first == E::Id;
|
||||
});
|
||||
if (eventRegistered) {
|
||||
log::fatal("The token '{}' has already registered the same event ('{}')", token, wolv::type::getTypeName<E>());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
getTokenStore().insert({ token, subscribe<E>(function) });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,6 +126,8 @@ namespace hex {
|
||||
* @param token Token returned by subscribe
|
||||
*/
|
||||
static void unsubscribe(const EventList::iterator &token) noexcept {
|
||||
std::scoped_lock lock(getEventMutex());
|
||||
|
||||
getEvents().erase(token);
|
||||
}
|
||||
|
||||
@@ -121,6 +138,8 @@ namespace hex {
|
||||
*/
|
||||
template<impl::EventType E>
|
||||
static void unsubscribe(void *token) noexcept {
|
||||
std::scoped_lock lock(getEventMutex());
|
||||
|
||||
auto &tokenStore = getTokenStore();
|
||||
auto iter = std::find_if(tokenStore.begin(), tokenStore.end(), [&](auto &item) {
|
||||
return item.first == token && item.second->first == E::Id;
|
||||
@@ -140,9 +159,15 @@ namespace hex {
|
||||
*/
|
||||
template<impl::EventType E>
|
||||
static void post(auto &&...args) noexcept {
|
||||
std::scoped_lock lock(getEventMutex());
|
||||
|
||||
for (const auto &[id, event] : getEvents()) {
|
||||
if (id == E::Id) {
|
||||
(*static_cast<E *const>(event.get()))(std::forward<decltype(args)>(args)...);
|
||||
try {
|
||||
(*static_cast<E *const>(event.get()))(std::forward<decltype(args)>(args)...);
|
||||
} catch (const std::exception &e) {
|
||||
log::error("Event '{}' threw {}: {}", wolv::type::getTypeName<decltype(e)>(), wolv::type::getTypeName<E>(), e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,13 +181,16 @@ namespace hex {
|
||||
* @brief Unsubscribe all subscribers from all events
|
||||
*/
|
||||
static void clear() noexcept {
|
||||
std::scoped_lock lock(getEventMutex());
|
||||
|
||||
getEvents().clear();
|
||||
getTokenStore().clear();
|
||||
}
|
||||
|
||||
private:
|
||||
static std::map<void *, EventList::iterator>& getTokenStore();
|
||||
static std::multimap<void *, EventList::iterator>& getTokenStore();
|
||||
static EventList& getEvents();
|
||||
static std::recursive_mutex& getEventMutex();
|
||||
};
|
||||
|
||||
/* Default Events */
|
||||
@@ -213,6 +241,11 @@ namespace hex {
|
||||
EVENT_DEF(EventStoreContentRemoved, const std::fs::path&);
|
||||
EVENT_DEF(EventImHexClosing);
|
||||
EVENT_DEF(EventAchievementUnlocked, const Achievement&);
|
||||
EVENT_DEF(EventSearchBoxClicked);
|
||||
|
||||
EVENT_DEF(EventProviderDataModified, prv::Provider *, u64, u64, const u8*);
|
||||
EVENT_DEF(EventProviderDataInserted, prv::Provider *, u64, u64);
|
||||
EVENT_DEF(EventProviderDataRemoved, prv::Provider *, u64, u64);
|
||||
|
||||
/**
|
||||
* @brief Called when a project has been loaded
|
||||
@@ -223,9 +256,12 @@ namespace hex {
|
||||
EVENT_DEF_NO_LOG(EventFrameEnd);
|
||||
EVENT_DEF_NO_LOG(EventSetTaskBarIconState, u32, u32, u32);
|
||||
|
||||
EVENT_DEF(RequestAddInitTask, std::string, bool, std::function<bool()>);
|
||||
EVENT_DEF(RequestAddExitTask, std::string, std::function<bool()>);
|
||||
EVENT_DEF(RequestOpenWindow, std::string);
|
||||
EVENT_DEF(RequestSelectionChange, Region);
|
||||
EVENT_DEF(RequestAddBookmark, Region, std::string, std::string, color_t);
|
||||
EVENT_DEF(RequestAddBookmark, Region, std::string, std::string, color_t, u64*);
|
||||
EVENT_DEF(RequestRemoveBookmark, u64);
|
||||
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
|
||||
EVENT_DEF(RequestLoadPatternLanguageFile, std::fs::path);
|
||||
EVENT_DEF(RequestSavePatternLanguageFile, std::fs::path);
|
||||
@@ -2,20 +2,18 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
#include <map>
|
||||
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
#include <hex/api/keybinding.hpp>
|
||||
|
||||
#include <wolv/io/fs.hpp>
|
||||
|
||||
using ImGuiID = unsigned int;
|
||||
struct ImVec2;
|
||||
struct ImFontAtlas;
|
||||
struct ImFont;
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -58,7 +56,7 @@ namespace hex {
|
||||
color_t m_color = 0x00;
|
||||
};
|
||||
|
||||
struct ProviderRegion : public Region {
|
||||
struct ProviderRegion : Region {
|
||||
prv::Provider *provider;
|
||||
|
||||
[[nodiscard]] prv::Provider *getProvider() const { return this->provider; }
|
||||
@@ -77,7 +75,7 @@ namespace hex {
|
||||
std::map<u32, Tooltip> &getTooltips();
|
||||
std::map<u32, TooltipFunction> &getTooltipFunctions();
|
||||
|
||||
void setCurrentSelection(std::optional<ProviderRegion> region);
|
||||
void setCurrentSelection(const std::optional<ProviderRegion> ®ion);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,6 +213,7 @@ namespace hex {
|
||||
std::string comment;
|
||||
u32 color;
|
||||
bool locked;
|
||||
u64 id;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -224,8 +223,25 @@ namespace hex {
|
||||
* @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
|
||||
* @return Bookmark ID
|
||||
*/
|
||||
void add(u64 address, size_t size, const std::string &name, const std::string &comment, color_t color = 0x00000000);
|
||||
u64 add(u64 address, size_t size, const std::string &name, const std::string &comment, color_t color = 0x00000000);
|
||||
|
||||
/**
|
||||
* @brief Adds a new bookmark
|
||||
* @param region The region 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
|
||||
* @return Bookmark ID
|
||||
*/
|
||||
u64 add(Region region, const std::string &name, const std::string &comment, color_t color = 0x00000000);
|
||||
|
||||
/**
|
||||
* @brief Removes a bookmark
|
||||
* @param id The ID of the bookmark to remove
|
||||
*/
|
||||
void remove(u64 id);
|
||||
|
||||
}
|
||||
|
||||
@@ -239,7 +255,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
void resetClosingProvider();
|
||||
prv::Provider* getClosingProvider();
|
||||
const std::vector<prv::Provider*>& getClosingProviders();
|
||||
|
||||
}
|
||||
|
||||
@@ -320,6 +336,7 @@ namespace hex {
|
||||
* @brief Creates a new provider using its unlocalized name and add it to the list of providers
|
||||
* @param unlocalizedName The unlocalized name of the provider to create
|
||||
* @param skipLoadInterface Whether to skip the provider's loading interface (see property documentation)
|
||||
* @param select Whether to select the provider after adding it
|
||||
*/
|
||||
prv::Provider* createProvider(const std::string &unlocalizedName, bool skipLoadInterface = false, bool select = true);
|
||||
|
||||
@@ -342,14 +359,12 @@ namespace hex {
|
||||
|
||||
void setBorderlessWindowMode(bool enabled);
|
||||
|
||||
void setCustomFontPath(const std::fs::path &path);
|
||||
void setFontSize(float size);
|
||||
|
||||
void setGPUVendor(const std::string &vendor);
|
||||
|
||||
void setPortableVersion(bool enabled);
|
||||
|
||||
void addInitArgument(const std::string &key, const std::string &value = { });
|
||||
|
||||
}
|
||||
|
||||
struct ProgramArguments {
|
||||
@@ -447,21 +462,6 @@ namespace hex {
|
||||
*/
|
||||
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
|
||||
*/
|
||||
std::filesystem::path &getCustomFontPath();
|
||||
|
||||
/**
|
||||
* @brief Gets the current font size
|
||||
* @return The current font size
|
||||
*/
|
||||
float getFontSize();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets if ImHex should follow the system theme
|
||||
* @param enabled Whether to follow the system theme
|
||||
@@ -522,7 +522,7 @@ namespace hex {
|
||||
* @brief Gets the current ImHex version
|
||||
* @return ImHex version
|
||||
*/
|
||||
std::string getImHexVersion();
|
||||
std::string getImHexVersion(bool withBuildType = true);
|
||||
|
||||
/**
|
||||
* @brief Gets the current git commit hash
|
||||
@@ -536,6 +536,26 @@ namespace hex {
|
||||
* @return Git commit branch
|
||||
*/
|
||||
std::string getCommitBranch();
|
||||
|
||||
/**
|
||||
* @brief Checks if ImHex was built in debug mode
|
||||
* @return True if ImHex was built in debug mode, false otherwise
|
||||
*/
|
||||
bool isDebugBuild();
|
||||
|
||||
enum class UpdateType {
|
||||
Stable,
|
||||
Nightly
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Triggers the update process
|
||||
* @param updateType The update channel
|
||||
* @return If the update process was successfully started
|
||||
*/
|
||||
bool updateImHex(UpdateType updateType);
|
||||
|
||||
void addStartupTask(const std::string &name, bool async, const std::function<bool()> &function);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -558,6 +578,63 @@ namespace hex {
|
||||
void registerHandler(const std::string &eventName, const impl::MessagingHandler &handler);
|
||||
}
|
||||
|
||||
namespace Fonts {
|
||||
|
||||
struct GlyphRange { u16 begin, end; };
|
||||
struct Offset { float x, y; };
|
||||
|
||||
struct Font {
|
||||
std::string name;
|
||||
std::vector<u8> fontData;
|
||||
std::vector<GlyphRange> glyphRanges;
|
||||
Offset offset;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::vector<Font>& getFonts();
|
||||
|
||||
void setCustomFontPath(const std::fs::path &path);
|
||||
void setFontSize(float size);
|
||||
void setFontAtlas(ImFontAtlas *fontAtlas);
|
||||
|
||||
void setFonts(ImFont *bold, ImFont *italic);
|
||||
}
|
||||
|
||||
GlyphRange glyph(const char *glyph);
|
||||
GlyphRange glyph(u32 codepoint);
|
||||
GlyphRange range(const char *glyphBegin, const char *glyphEnd);
|
||||
GlyphRange range(u32 codepointBegin, u32 codepointEnd);
|
||||
|
||||
void loadFont(const std::fs::path &path, const std::vector<GlyphRange> &glyphRanges = {}, Offset offset = {}, u32 flags = 0);
|
||||
void loadFont(const std::string &name, const std::span<const u8> &data, const std::vector<GlyphRange> &glyphRanges = {}, Offset offset = {}, u32 flags = 0);
|
||||
|
||||
constexpr static float DefaultFontSize = 13.0;
|
||||
|
||||
ImFont* Bold();
|
||||
ImFont* Italic();
|
||||
|
||||
/**
|
||||
* @brief Gets the current custom font path
|
||||
* @return The current custom font path
|
||||
*/
|
||||
std::filesystem::path &getCustomFontPath();
|
||||
|
||||
/**
|
||||
* @brief Gets the current font size
|
||||
* @return The current font size
|
||||
*/
|
||||
float getFontSize();
|
||||
|
||||
/**
|
||||
* @brief Gets the current font atlas
|
||||
* @return Current font atlas
|
||||
*/
|
||||
ImFontAtlas* getFontAtlas();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <imgui.h>
|
||||
|
||||
namespace hex {
|
||||
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class LanguageDefinition {
|
||||
public:
|
||||
explicit LanguageDefinition(std::map<std::string, std::string> &&entries);
|
||||
|
||||
[[nodiscard]] const std::map<std::string, std::string> &getEntries() const;
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> m_entries;
|
||||
};
|
||||
|
||||
class LangEntry {
|
||||
public:
|
||||
explicit LangEntry(const char *unlocalizedString);
|
||||
explicit LangEntry(std::string unlocalizedString);
|
||||
explicit LangEntry(std::string_view unlocalizedString);
|
||||
|
||||
operator std::string() const;
|
||||
operator std::string_view() const;
|
||||
operator const char *() const;
|
||||
|
||||
[[nodiscard]] const std::string &get() const;
|
||||
|
||||
static void loadLanguage(const std::string &language);
|
||||
static const std::map<std::string, std::string> &getSupportedLanguages();
|
||||
|
||||
static void setFallbackLanguage(const std::string &language);
|
||||
static const std::string &getFallbackLanguage();
|
||||
|
||||
static void resetLanguageStrings();
|
||||
|
||||
static const std::string &getSelectedLanguage();
|
||||
|
||||
private:
|
||||
std::string m_unlocalizedString;
|
||||
};
|
||||
|
||||
std::string operator+(const std::string &&left, const LangEntry &&right);
|
||||
std::string operator+(const LangEntry &&left, const std::string &&right);
|
||||
std::string operator+(const std::string_view &&left, const LangEntry &&right);
|
||||
std::string operator+(const LangEntry &&left, const std::string_view &&right);
|
||||
std::string operator+(const char *left, const LangEntry &&right);
|
||||
std::string operator+(const LangEntry &&left, const char *right);
|
||||
std::string operator+(const LangEntry &&left, const LangEntry &&right);
|
||||
|
||||
inline LangEntry operator""_lang(const char *string, size_t) {
|
||||
return LangEntry(string);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
struct fmt::formatter<hex::LangEntry> : fmt::formatter<std::string_view> {
|
||||
template<typename FormatContext>
|
||||
auto format(const hex::LangEntry &entry, FormatContext &ctx) {
|
||||
return fmt::formatter<std::string_view>::format(entry.get(), ctx);
|
||||
}
|
||||
};
|
||||
71
lib/libimhex/include/hex/api/localization_manager.hpp
Normal file
71
lib/libimhex/include/hex/api/localization_manager.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace LocalizationManager {
|
||||
|
||||
class LanguageDefinition {
|
||||
public:
|
||||
explicit LanguageDefinition(std::map<std::string, std::string> &&entries);
|
||||
|
||||
[[nodiscard]] const std::map<std::string, std::string> &getEntries() const;
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> m_entries;
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
void setFallbackLanguage(const std::string &language);
|
||||
void resetLanguageStrings();
|
||||
}
|
||||
|
||||
void loadLanguage(const std::string &language);
|
||||
|
||||
[[nodiscard]] const std::map<std::string, std::string> &getSupportedLanguages();
|
||||
[[nodiscard]] const std::string &getFallbackLanguage();
|
||||
[[nodiscard]] const std::string &getSelectedLanguage();
|
||||
}
|
||||
|
||||
class Lang {
|
||||
public:
|
||||
explicit Lang(const char *unlocalizedString);
|
||||
explicit Lang(std::string unlocalizedString);
|
||||
explicit Lang(std::string_view unlocalizedString);
|
||||
|
||||
[[nodiscard]] operator std::string() const;
|
||||
[[nodiscard]] operator std::string_view() const;
|
||||
[[nodiscard]] operator const char *() const;
|
||||
|
||||
[[nodiscard]] const std::string &get() const;
|
||||
|
||||
private:
|
||||
std::string m_unlocalizedString;
|
||||
};
|
||||
|
||||
[[nodiscard]] std::string operator+(const std::string &&left, const Lang &&right);
|
||||
[[nodiscard]] std::string operator+(const Lang &&left, const std::string &&right);
|
||||
[[nodiscard]] std::string operator+(const std::string_view &&left, const Lang &&right);
|
||||
[[nodiscard]] std::string operator+(const Lang &&left, const std::string_view &&right);
|
||||
[[nodiscard]] std::string operator+(const char *left, const Lang &&right);
|
||||
[[nodiscard]] std::string operator+(const Lang &&left, const char *right);
|
||||
[[nodiscard]] std::string operator+(const Lang &&left, const Lang &&right);
|
||||
|
||||
[[nodiscard]] inline Lang operator""_lang(const char *string, size_t) {
|
||||
return Lang(string);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
struct fmt::formatter<hex::Lang> : fmt::formatter<std::string_view> {
|
||||
template<typename FormatContext>
|
||||
auto format(const hex::Lang &entry, FormatContext &ctx) {
|
||||
return fmt::formatter<std::string_view>::format(entry.get(), ctx);
|
||||
}
|
||||
};
|
||||
@@ -1,18 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <span>
|
||||
#include <string>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#include <wolv/io/fs.hpp>
|
||||
|
||||
struct ImGuiContext;
|
||||
|
||||
@@ -24,9 +16,31 @@ namespace hex {
|
||||
std::function<void(const std::vector<std::string>&)> callback;
|
||||
};
|
||||
|
||||
struct PluginFunctions {
|
||||
using InitializePluginFunc = void (*)();
|
||||
using GetPluginNameFunc = const char *(*)();
|
||||
using GetPluginAuthorFunc = const char *(*)();
|
||||
using GetPluginDescriptionFunc = const char *(*)();
|
||||
using GetCompatibleVersionFunc = const char *(*)();
|
||||
using SetImGuiContextFunc = void (*)(ImGuiContext *);
|
||||
using IsBuiltinPluginFunc = bool (*)();
|
||||
using GetSubCommandsFunc = void* (*)();
|
||||
|
||||
InitializePluginFunc initializePluginFunction = nullptr;
|
||||
GetPluginNameFunc getPluginNameFunction = nullptr;
|
||||
GetPluginAuthorFunc getPluginAuthorFunction = nullptr;
|
||||
GetPluginDescriptionFunc getPluginDescriptionFunction = nullptr;
|
||||
GetCompatibleVersionFunc getCompatibleVersionFunction = nullptr;
|
||||
SetImGuiContextFunc setImGuiContextFunction = nullptr;
|
||||
IsBuiltinPluginFunc isBuiltinPluginFunction = nullptr;
|
||||
GetSubCommandsFunc getSubCommandsFunction = nullptr;
|
||||
};
|
||||
|
||||
class Plugin {
|
||||
public:
|
||||
explicit Plugin(const std::fs::path &path);
|
||||
explicit Plugin(PluginFunctions functions);
|
||||
|
||||
Plugin(const Plugin &) = delete;
|
||||
Plugin(Plugin &&other) noexcept;
|
||||
~Plugin();
|
||||
@@ -46,40 +60,19 @@ namespace hex {
|
||||
[[nodiscard]] std::span<SubCommand> getSubCommands() const;
|
||||
|
||||
private:
|
||||
using InitializePluginFunc = void (*)();
|
||||
using GetPluginNameFunc = const char *(*)();
|
||||
using GetPluginAuthorFunc = const char *(*)();
|
||||
using GetPluginDescriptionFunc = const char *(*)();
|
||||
using GetCompatibleVersionFunc = const char *(*)();
|
||||
using SetImGuiContextFunc = void (*)(ImGuiContext *);
|
||||
using IsBuiltinPluginFunc = bool (*)();
|
||||
using GetSubCommandsFunc = void* (*)();
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
HMODULE m_handle = nullptr;
|
||||
#else
|
||||
void *m_handle = nullptr;
|
||||
#endif
|
||||
uintptr_t m_handle = 0;
|
||||
std::fs::path m_path;
|
||||
|
||||
mutable bool m_initialized = false;
|
||||
|
||||
InitializePluginFunc m_initializePluginFunction = nullptr;
|
||||
GetPluginNameFunc m_getPluginNameFunction = nullptr;
|
||||
GetPluginAuthorFunc m_getPluginAuthorFunction = nullptr;
|
||||
GetPluginDescriptionFunc m_getPluginDescriptionFunction = nullptr;
|
||||
GetCompatibleVersionFunc m_getCompatibleVersionFunction = nullptr;
|
||||
SetImGuiContextFunc m_setImGuiContextFunction = nullptr;
|
||||
IsBuiltinPluginFunc m_isBuiltinPluginFunction = nullptr;
|
||||
GetSubCommandsFunc m_getSubCommandsFunction = nullptr;
|
||||
PluginFunctions m_functions = {};
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] auto getPluginFunction(const std::string &symbol) {
|
||||
return reinterpret_cast<T>(this->getPluginFunction(symbol));
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] void *getPluginFunction(const std::string &symbol);
|
||||
[[nodiscard]] void *getPluginFunction(const std::string &symbol) const;
|
||||
};
|
||||
|
||||
class PluginManager {
|
||||
@@ -90,7 +83,10 @@ namespace hex {
|
||||
static void unload();
|
||||
static void reload();
|
||||
|
||||
static const std::vector<Plugin> &getPlugins();
|
||||
static void addPlugin(PluginFunctions functions);
|
||||
|
||||
static std::vector<Plugin> &getPlugins();
|
||||
static std::vector<std::fs::path> &getPluginPaths();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,15 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
#include <hex/helpers/tar.hpp>
|
||||
|
||||
/**
|
||||
@@ -21,6 +11,10 @@
|
||||
*/
|
||||
namespace hex {
|
||||
|
||||
namespace prv {
|
||||
class Provider;
|
||||
}
|
||||
|
||||
class ProjectFile {
|
||||
public:
|
||||
struct Handler {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
@@ -133,13 +133,14 @@ namespace hex {
|
||||
|
||||
class Key {
|
||||
public:
|
||||
constexpr Key() = default;
|
||||
constexpr Key(Keys key) : m_key(static_cast<u32>(key)) { }
|
||||
|
||||
auto operator<=>(const Key &) const = default;
|
||||
|
||||
[[nodiscard]] constexpr u32 getKeyCode() const { return this->m_key; }
|
||||
private:
|
||||
u32 m_key;
|
||||
u32 m_key = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -160,8 +161,15 @@ namespace hex {
|
||||
public:
|
||||
Shortcut() = default;
|
||||
Shortcut(Keys key) : m_keys({ key }) { }
|
||||
explicit Shortcut(std::set<Key> keys) : m_keys(std::move(keys)) { }
|
||||
Shortcut(const Shortcut &other) = default;
|
||||
Shortcut(Shortcut &&) noexcept = default;
|
||||
|
||||
const static inline auto None = Keys(0);
|
||||
Shortcut& operator=(const Shortcut &other) = default;
|
||||
|
||||
Shortcut& operator=(Shortcut &&) noexcept = default;
|
||||
|
||||
constexpr static inline auto None = Keys(0);
|
||||
|
||||
Shortcut operator+(const Key &other) const {
|
||||
Shortcut result = *this;
|
||||
@@ -181,7 +189,15 @@ namespace hex {
|
||||
}
|
||||
|
||||
bool operator==(const Shortcut &other) const {
|
||||
return this->m_keys == other.m_keys;
|
||||
auto thisKeys = this->m_keys;
|
||||
auto otherKeys = other.m_keys;
|
||||
|
||||
thisKeys.erase(CurrentView);
|
||||
thisKeys.erase(AllowWhileTyping);
|
||||
otherKeys.erase(CurrentView);
|
||||
otherKeys.erase(AllowWhileTyping);
|
||||
|
||||
return thisKeys == otherKeys;
|
||||
}
|
||||
|
||||
bool isLocal() const {
|
||||
@@ -351,6 +367,8 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::set<Key>& getKeys() const { return this->m_keys; }
|
||||
|
||||
private:
|
||||
friend Shortcut operator+(const Key &lhs, const Key &rhs);
|
||||
|
||||
@@ -370,21 +388,29 @@ namespace hex {
|
||||
*/
|
||||
class ShortcutManager {
|
||||
public:
|
||||
using Callback = std::function<void()>;
|
||||
struct ShortcutEntry {
|
||||
Shortcut shortcut;
|
||||
std::string unlocalizedName;
|
||||
Callback callback;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Add a global shortcut. Global shortcuts can be triggered regardless of what view is currently focused
|
||||
* @param shortcut The shortcut to add.
|
||||
* @param unlocalizedName The unlocalized name of the shortcut
|
||||
* @param callback The callback to call when the shortcut is triggered.
|
||||
*/
|
||||
static void addGlobalShortcut(const Shortcut &shortcut, const std::function<void()> &callback);
|
||||
static void addGlobalShortcut(const Shortcut &shortcut, const std::string &unlocalizedName, const Callback &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 unlocalizedName The unlocalized name of the shortcut
|
||||
* @param callback The callback to call when the shortcut is triggered.
|
||||
*/
|
||||
static void addShortcut(View *view, const Shortcut &shortcut, const std::function<void()> &callback);
|
||||
static void addShortcut(View *view, const Shortcut &shortcut, const std::string &unlocalizedName, const Callback &callback);
|
||||
|
||||
|
||||
/**
|
||||
@@ -413,6 +439,16 @@ namespace hex {
|
||||
* @brief Clear all shortcuts
|
||||
*/
|
||||
static void clearShortcuts();
|
||||
|
||||
static void resumeShortcuts();
|
||||
static void pauseShortcuts();
|
||||
|
||||
[[nodiscard]] static std::optional<Shortcut> getPreviousShortcut();
|
||||
|
||||
[[nodiscard]] static std::vector<ShortcutEntry> getGlobalShortcuts();
|
||||
[[nodiscard]] static std::vector<ShortcutEntry> getViewShortcuts(View *view);
|
||||
|
||||
[[nodiscard]] static bool updateShortcut(const Shortcut &oldShortcut, const Shortcut &newShortcut, View *view = nullptr);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -5,13 +5,13 @@
|
||||
#include <cstdio>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <condition_variable>
|
||||
|
||||
#include <jthread.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class TaskHolder;
|
||||
@@ -110,16 +110,11 @@ namespace hex {
|
||||
|
||||
[[nodiscard]] u32 getProgress() const;
|
||||
|
||||
void interrupt();
|
||||
void interrupt() const;
|
||||
private:
|
||||
std::weak_ptr<Task> m_task;
|
||||
};
|
||||
|
||||
struct Timer {
|
||||
std::chrono::time_point<std::chrono::steady_clock> elapseTime;
|
||||
std::function<void()> callback;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The Task Manager is responsible for running and managing asynchronous tasks
|
||||
*/
|
||||
@@ -161,20 +156,12 @@ namespace hex {
|
||||
*/
|
||||
static void runWhenTasksFinished(const std::function<void()> &function);
|
||||
|
||||
/**
|
||||
* @brief Creates a callback that will be executed after the given time
|
||||
* @param duration Time to wait
|
||||
* @param function Function to be executed
|
||||
*/
|
||||
static void doAfter(std::chrono::duration<i64> duration, const std::function<void()> &function);
|
||||
|
||||
static void collectGarbage();
|
||||
|
||||
static size_t getRunningTaskCount();
|
||||
static size_t getRunningBackgroundTaskCount();
|
||||
|
||||
static std::list<std::shared_ptr<Task>> &getRunningTasks();
|
||||
static std::list<Timer> &getTimers();
|
||||
static void runDeferredCalls();
|
||||
|
||||
private:
|
||||
@@ -1,2 +1,4 @@
|
||||
constexpr static const auto ImHexApiURL = "https://api.werwolv.net/imhex";
|
||||
constexpr static const auto GitHubApiURL = "https://api.github.com/repos/WerWolv/ImHex";
|
||||
#pragma once
|
||||
|
||||
constexpr static auto ImHexApiURL = "https://api.werwolv.net/imhex";
|
||||
constexpr static auto GitHubApiURL = "https://api.github.com/repos/WerWolv/ImHex";
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <map>
|
||||
@@ -66,6 +65,8 @@ namespace hex::dp {
|
||||
|
||||
friend class Node;
|
||||
void setParentNode(Node *node) { this->m_parentNode = node; }
|
||||
|
||||
static int s_idCounter;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
namespace hex::dp {
|
||||
|
||||
class Link {
|
||||
@@ -19,6 +17,8 @@ namespace hex::dp {
|
||||
private:
|
||||
int m_id;
|
||||
int m_from, m_to;
|
||||
|
||||
static int s_idCounter;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <hex/helpers/intrinsics.hpp>
|
||||
@@ -6,7 +7,6 @@
|
||||
|
||||
#include <set>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
@@ -87,6 +87,8 @@ namespace hex::dp {
|
||||
prv::Overlay *m_overlay = nullptr;
|
||||
ImVec2 m_position;
|
||||
|
||||
static int s_idCounter;
|
||||
|
||||
Attribute& getAttribute(u32 index) {
|
||||
if (index >= this->getAttributes().size())
|
||||
throw std::runtime_error("Attribute index out of bounds!");
|
||||
@@ -109,6 +111,10 @@ namespace hex::dp {
|
||||
throwNodeError("Recursion detected!");
|
||||
}
|
||||
|
||||
void unmarkInputProcessed(u32 index) {
|
||||
this->m_processedInputs.erase(index);
|
||||
}
|
||||
|
||||
protected:
|
||||
[[noreturn]] void throwNodeError(const std::string &message) {
|
||||
throw NodeError { this, message };
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
|
||||
@@ -18,6 +16,7 @@ namespace hex {
|
||||
template<typename T>
|
||||
class ICloneable {
|
||||
public:
|
||||
virtual ~ICloneable() = default;
|
||||
[[nodiscard]] virtual std::unique_ptr<T> clone() const = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -16,9 +15,9 @@ namespace hex::crypt {
|
||||
void initialize();
|
||||
void exit();
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
std::array<u8, 16> md5(prv::Provider *&data, u64 offset, size_t size);
|
||||
std::array<u8, 20> sha1(prv::Provider *&data, u64 offset, size_t size);
|
||||
|
||||
47
lib/libimhex/include/hex/helpers/debugging.hpp
Normal file
47
lib/libimhex/include/hex/helpers/debugging.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <wolv/utils/preproc.hpp>
|
||||
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
|
||||
#if defined(DEBUG)
|
||||
#define DBG_DEFINE_DEBUG_VARIABLE(type, name) \
|
||||
static type name; \
|
||||
hex::dbg::impl::drawDebugVariable(name, WOLV_STRINGIFY(name));
|
||||
#else
|
||||
#define DBG_DEFINE_DEBUG_VARIABLE(type, name) \
|
||||
static_assert(false, "Debug variables are only intended for use during development.");
|
||||
#endif
|
||||
|
||||
namespace hex::dbg {
|
||||
|
||||
namespace impl {
|
||||
bool &getDebugWindowState();
|
||||
|
||||
template<typename T>
|
||||
static void drawDebugVariable(T &variable, std::string_view name) {
|
||||
if (!getDebugWindowState())
|
||||
return;
|
||||
|
||||
if (ImGui::Begin("Debug Variables", &getDebugWindowState(), ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
using Type = std::remove_cvref_t<T>;
|
||||
if constexpr (std::same_as<Type, bool>) {
|
||||
ImGui::Checkbox(name.data(), &variable);
|
||||
} else if constexpr (std::integral<Type> || std::floating_point<Type>) {
|
||||
ImGui::InputScalar(name.data(), ImGuiExt::getImGuiDataType<Type>(), &variable);
|
||||
} else if constexpr (std::same_as<Type, ImVec2>) {
|
||||
ImGui::InputFloat2(name.data(), &variable.x);
|
||||
} else if constexpr (std::same_as<Type, std::string>) {
|
||||
ImGui::InputText(name.data(), variable);
|
||||
} else if constexpr (std::same_as<Type, ImColor>) {
|
||||
ImGui::ColorEdit4(name.data(), &variable.Value.x, ImGuiColorEditFlags_AlphaBar);
|
||||
} else {
|
||||
static_assert(hex::always_false<Type>::value, "Unsupported type");
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,9 +28,11 @@ namespace hex {
|
||||
BPF = CS_ARCH_BPF,
|
||||
SH = CS_ARCH_SH,
|
||||
TRICORE = CS_ARCH_TRICORE,
|
||||
MAX = TRICORE,
|
||||
# else
|
||||
MAX = EVM,
|
||||
#endif
|
||||
|
||||
MAX = TRICORE,
|
||||
MIN = ARM
|
||||
};
|
||||
|
||||
@@ -40,11 +42,11 @@ namespace hex {
|
||||
return static_cast<cs_arch>(architecture);
|
||||
}
|
||||
|
||||
static inline bool isSupported(Architecture architecture) {
|
||||
static bool isSupported(Architecture architecture) {
|
||||
return cs_support(toCapstoneArchitecture(architecture));
|
||||
}
|
||||
|
||||
constexpr static auto ArchitectureNames = [](){
|
||||
constexpr static auto ArchitectureNames = []{
|
||||
std::array<const char *, static_cast<u32>(Architecture::MAX) + 1> names = { };
|
||||
|
||||
names[CS_ARCH_ARM] = "ARM";
|
||||
@@ -72,7 +74,7 @@ namespace hex {
|
||||
return names;
|
||||
}();
|
||||
|
||||
static inline i32 getArchitectureSupportedCount() {
|
||||
static i32 getArchitectureSupportedCount() {
|
||||
static i32 supportedCount = -1;
|
||||
|
||||
if (supportedCount != -1) {
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
#include <vector>
|
||||
#include <span>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
#include <wolv/io/fs.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -22,12 +20,12 @@ namespace hex {
|
||||
|
||||
EncodingFile();
|
||||
EncodingFile(const EncodingFile &other);
|
||||
EncodingFile(EncodingFile &&other);
|
||||
EncodingFile(EncodingFile &&other) noexcept;
|
||||
EncodingFile(Type type, const std::fs::path &path);
|
||||
EncodingFile(Type type, const std::string &path);
|
||||
EncodingFile(Type type, const std::string &content);
|
||||
|
||||
EncodingFile& operator=(const EncodingFile &other);
|
||||
EncodingFile& operator=(EncodingFile &&other);
|
||||
EncodingFile& operator=(EncodingFile &&other) noexcept;
|
||||
|
||||
[[nodiscard]] std::pair<std::string_view, size_t> getEncodingFor(std::span<u8> buffer) const;
|
||||
[[nodiscard]] size_t getEncodingLengthFor(std::span<u8> buffer) const;
|
||||
|
||||
@@ -2,24 +2,12 @@
|
||||
|
||||
#include <string_view>
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/chrono.h>
|
||||
|
||||
namespace hex {
|
||||
|
||||
template<typename... Args>
|
||||
inline std::string format(std::string_view format, Args... args) {
|
||||
std::string format(std::string_view format, Args... args) {
|
||||
return fmt::format(fmt::runtime(format), args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void print(std::string_view format, Args... args) {
|
||||
fmt::print(fmt::runtime(format), args...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline void println(std::string_view format, Args... args) {
|
||||
fmt::print(fmt::runtime(format), args...);
|
||||
fmt::print("\n");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,14 +2,11 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
|
||||
#include <nfd.hpp>
|
||||
|
||||
#include <wolv/io/fs.hpp>
|
||||
|
||||
namespace hex::fs {
|
||||
@@ -20,8 +17,15 @@ namespace hex::fs {
|
||||
Folder
|
||||
};
|
||||
|
||||
struct ItemFilter {
|
||||
// Human-friendly name
|
||||
std::string name;
|
||||
// Extensions that constitute this filter
|
||||
std::string spec;
|
||||
};
|
||||
|
||||
void setFileBrowserErrorCallback(const std::function<void(const std::string&)> &callback);
|
||||
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath = {}, bool multiple = false);
|
||||
bool openFileBrowser(DialogMode mode, const std::vector<ItemFilter> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath = {}, bool multiple = false);
|
||||
|
||||
void openFileExternal(const std::fs::path &filePath);
|
||||
void openFolderExternal(const std::fs::path &dirPath);
|
||||
@@ -53,7 +57,7 @@ namespace hex::fs {
|
||||
|
||||
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting = false);
|
||||
|
||||
// temporarily expose these for the migration function
|
||||
// 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);
|
||||
}
|
||||
@@ -7,17 +7,18 @@
|
||||
#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>
|
||||
#if defined(OS_WEB)
|
||||
#include <emscripten/fetch.h>
|
||||
|
||||
using curl_off_t = long;
|
||||
#else
|
||||
#include <curl/curl.h>
|
||||
#endif
|
||||
|
||||
typedef void CURL;
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -67,29 +68,12 @@ namespace hex {
|
||||
HttpRequest(const HttpRequest&) = delete;
|
||||
HttpRequest& operator=(const HttpRequest&) = delete;
|
||||
|
||||
HttpRequest(HttpRequest &&other) noexcept {
|
||||
this->m_curl = other.m_curl;
|
||||
other.m_curl = nullptr;
|
||||
HttpRequest(HttpRequest &&other) noexcept;
|
||||
|
||||
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);
|
||||
}
|
||||
HttpRequest& operator=(HttpRequest &&other) noexcept;
|
||||
|
||||
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);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
static void setProxy(std::string proxy);
|
||||
static void setProxyState(bool enabled);
|
||||
static void setProxyUrl(std::string proxy);
|
||||
|
||||
void setMethod(std::string method) {
|
||||
this->m_method = std::move(method);
|
||||
@@ -120,173 +104,28 @@ namespace hex {
|
||||
}
|
||||
|
||||
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;
|
||||
std::future<Result<T>> downloadFile(const std::fs::path &path);
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
std::future<Result<std::vector<u8>>> downloadFile();
|
||||
|
||||
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", const std::fs::path &fileName = "data.bin") {
|
||||
return std::async(std::launch::async, [this, data = std::move(data), mimeName, fileName]{
|
||||
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());
|
||||
auto fileNameStr = wolv::util::toUTF8String(fileName.filename());
|
||||
curl_mime_filename(part, fileNameStr.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);
|
||||
});
|
||||
}
|
||||
std::future<Result<T>> uploadFile(const std::fs::path &path, const std::string &mimeName = "filename");
|
||||
|
||||
template<typename T = std::string>
|
||||
std::future<Result<T>> execute() {
|
||||
return std::async(std::launch::async, [this] {
|
||||
std::future<Result<T>> uploadFile(std::vector<u8> data, const std::string &mimeName = "filename", const std::fs::path &fileName = "data.bin");
|
||||
|
||||
std::vector<u8> responseData;
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData);
|
||||
template<typename T = std::string>
|
||||
std::future<Result<T>> execute();
|
||||
|
||||
return this->executeImpl<T>(responseData);
|
||||
});
|
||||
}
|
||||
static std::string urlEncode(const std::string &input);
|
||||
|
||||
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 {};
|
||||
}
|
||||
static std::string urlDecode(const std::string &input);
|
||||
|
||||
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));
|
||||
checkProxyErrors();
|
||||
|
||||
return { };
|
||||
}
|
||||
}
|
||||
|
||||
long statusCode = 0;
|
||||
curl_easy_getinfo(this->m_curl, CURLINFO_RESPONSE_CODE, &statusCode);
|
||||
|
||||
return Result<T>(statusCode, { data.begin(), data.end() });
|
||||
}
|
||||
Result<T> executeImpl(std::vector<u8> &data);
|
||||
|
||||
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);
|
||||
@@ -296,18 +135,29 @@ namespace hex {
|
||||
static void checkProxyErrors();
|
||||
|
||||
private:
|
||||
#if defined(OS_WEB)
|
||||
emscripten_fetch_attr_t m_attr;
|
||||
#else
|
||||
CURL *m_curl;
|
||||
#endif
|
||||
|
||||
std::mutex m_transmissionMutex;
|
||||
|
||||
std::string m_method;
|
||||
std::string m_url;
|
||||
std::string m_body;
|
||||
std::promise<std::vector<u8>> m_promise;
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if defined(OS_WEB)
|
||||
#include <hex/helpers/http_requests_emscripten.hpp>
|
||||
#else
|
||||
#include <hex/helpers/http_requests_native.hpp>
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include <future>
|
||||
|
||||
#include <emscripten/fetch.h>
|
||||
|
||||
namespace hex {
|
||||
template<typename T>
|
||||
std::future<HttpRequest::Result<T>> HttpRequest::downloadFile(const std::fs::path &path) {
|
||||
return std::async(std::launch::async, [this, path] {
|
||||
std::vector<u8> response;
|
||||
|
||||
// Execute the request
|
||||
auto result = this->executeImpl<T>(response);
|
||||
|
||||
// Write the result to the file
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||
file.writeBuffer(reinterpret_cast<const u8*>(result.getData().data()), result.getData().size());
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(const std::fs::path &path, const std::string &mimeName) {
|
||||
hex::unused(path, mimeName);
|
||||
throw std::logic_error("Not implemented");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(std::vector<u8> data, const std::string &mimeName, const std::fs::path &fileName) {
|
||||
hex::unused(data, mimeName, fileName);
|
||||
throw std::logic_error("Not implemented");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::future<HttpRequest::Result<T>> HttpRequest::execute() {
|
||||
return std::async(std::launch::async, [this] {
|
||||
std::vector<u8> responseData;
|
||||
|
||||
return this->executeImpl<T>(responseData);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
HttpRequest::Result<T> HttpRequest::executeImpl(std::vector<u8> &data) {
|
||||
strcpy(this->m_attr.requestMethod, this->m_method.c_str());
|
||||
this->m_attr.attributes = EMSCRIPTEN_FETCH_SYNCHRONOUS | EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
|
||||
|
||||
if (!this->m_body.empty()) {
|
||||
this->m_attr.requestData = this->m_body.c_str();
|
||||
this->m_attr.requestDataSize = this->m_body.size();
|
||||
}
|
||||
|
||||
std::vector<const char*> headers;
|
||||
for (auto it = this->m_headers.begin(); it != this->m_headers.end(); it++) {
|
||||
headers.push_back(it->first.c_str());
|
||||
headers.push_back(it->second.c_str());
|
||||
}
|
||||
headers.push_back(nullptr);
|
||||
this->m_attr.requestHeaders = headers.data();
|
||||
|
||||
// Send request
|
||||
emscripten_fetch_t* fetch = emscripten_fetch(&this->m_attr, this->m_url.c_str());
|
||||
|
||||
data.resize(fetch->numBytes);
|
||||
std::copy(fetch->data, fetch->data + fetch->numBytes, data.begin());
|
||||
|
||||
return Result<T>(fetch->status, { data.begin(), data.end() });
|
||||
}
|
||||
|
||||
}
|
||||
145
lib/libimhex/include/hex/helpers/http_requests_native.hpp
Normal file
145
lib/libimhex/include/hex/helpers/http_requests_native.hpp
Normal file
@@ -0,0 +1,145 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <future>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
template<typename T>
|
||||
std::future<HttpRequest::Result<T>> HttpRequest::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);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(const std::fs::path &path, const std::string &mimeName) {
|
||||
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 handle = static_cast<FILE*>(arg);
|
||||
|
||||
return fread(buffer, size, nitems, handle);
|
||||
},
|
||||
[](void *arg, curl_off_t offset, int origin) -> int {
|
||||
auto handle = static_cast<FILE*>(arg);
|
||||
|
||||
if (fseek(handle, offset, origin) != 0)
|
||||
return CURL_SEEKFUNC_CANTSEEK;
|
||||
else
|
||||
return CURL_SEEKFUNC_OK;
|
||||
},
|
||||
[](void *arg) {
|
||||
auto handle = static_cast<FILE*>(arg);
|
||||
|
||||
fclose(handle);
|
||||
},
|
||||
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::future<HttpRequest::Result<T>> HttpRequest::uploadFile(std::vector<u8> data, const std::string &mimeName, const std::fs::path &fileName) {
|
||||
return std::async(std::launch::async, [this, data = std::move(data), mimeName, fileName]{
|
||||
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());
|
||||
auto fileNameStr = wolv::util::toUTF8String(fileName.filename());
|
||||
curl_mime_filename(part, fileNameStr.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::future<HttpRequest::Result<T>> HttpRequest::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);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
HttpRequest::Result<T> HttpRequest::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));
|
||||
checkProxyErrors();
|
||||
|
||||
return { };
|
||||
}
|
||||
}
|
||||
|
||||
long statusCode = 0;
|
||||
curl_easy_getinfo(this->m_curl, CURLINFO_RESPONSE_CODE, &statusCode);
|
||||
|
||||
return Result<T>(statusCode, { data.begin(), data.end() });
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace hex {
|
||||
|
||||
inline void unused(auto && ... x) {
|
||||
void unused(auto && ... x) {
|
||||
((void)x, ...);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,19 +4,19 @@ namespace hex::literals {
|
||||
|
||||
/* Byte literals */
|
||||
|
||||
constexpr static inline unsigned long long operator""_Bytes(unsigned long long bytes) noexcept {
|
||||
constexpr static unsigned long long operator""_Bytes(unsigned long long bytes) noexcept {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
constexpr static inline unsigned long long operator""_KiB(unsigned long long kiB) noexcept {
|
||||
constexpr static unsigned long long operator""_KiB(unsigned long long kiB) noexcept {
|
||||
return operator""_Bytes(kiB * 1024);
|
||||
}
|
||||
|
||||
constexpr static inline unsigned long long operator""_MiB(unsigned long long MiB) noexcept {
|
||||
constexpr static unsigned long long operator""_MiB(unsigned long long MiB) noexcept {
|
||||
return operator""_KiB(MiB * 1024);
|
||||
}
|
||||
|
||||
constexpr static inline unsigned long long operator""_GiB(unsigned long long GiB) noexcept {
|
||||
constexpr static unsigned long long operator""_GiB(unsigned long long GiB) noexcept {
|
||||
return operator""_MiB(GiB * 1024);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <fmt/color.h>
|
||||
#include <fmt/chrono.h>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
|
||||
@@ -19,6 +17,7 @@ namespace hex::log {
|
||||
wolv::io::File& getFile();
|
||||
bool isRedirected();
|
||||
[[maybe_unused]] void redirectToFile();
|
||||
[[maybe_unused]] void enableColorPrinting();
|
||||
|
||||
extern std::mutex g_loggerMutex;
|
||||
|
||||
@@ -29,29 +28,10 @@ namespace hex::log {
|
||||
};
|
||||
|
||||
std::vector<LogEntry>& getLogEntries();
|
||||
}
|
||||
|
||||
namespace {
|
||||
[[maybe_unused]] void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level);
|
||||
|
||||
|
||||
[[maybe_unused]] void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level) {
|
||||
const auto now = fmt::localtime(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()));
|
||||
|
||||
fmt::print(dest, "[{0:%H:%M:%S}] ", now);
|
||||
|
||||
if (impl::isRedirected())
|
||||
fmt::print(dest, "{0} ", level);
|
||||
else
|
||||
fmt::print(dest, ts, "{0} ", level);
|
||||
|
||||
fmt::print(dest, "[{0}] ", IMHEX_PROJECT_NAME);
|
||||
|
||||
constexpr static auto ProjectNameLength = std::char_traits<char>::length(IMHEX_PROJECT_NAME);
|
||||
fmt::print(dest, "{}", std::string(ProjectNameLength > 10 ? 0 : 10 - ProjectNameLength, ' '));
|
||||
}
|
||||
|
||||
template<typename... T>
|
||||
[[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) {
|
||||
[[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto && ... args) {
|
||||
std::scoped_lock lock(impl::g_loggerMutex);
|
||||
|
||||
auto dest = impl::getDestination();
|
||||
@@ -66,28 +46,47 @@ namespace hex::log {
|
||||
|
||||
}
|
||||
|
||||
[[maybe_unused]] void debug(const std::string &fmt, auto &&...args) {
|
||||
[[maybe_unused]] void debug(const std::string &fmt, auto && ... args) {
|
||||
#if defined(DEBUG)
|
||||
hex::log::print(fg(fmt::color::light_green) | fmt::emphasis::bold, "[DEBUG]", fmt, args...);
|
||||
hex::log::impl::print(fg(fmt::color::light_green) | fmt::emphasis::bold, "[DEBUG]", fmt, args...);
|
||||
#else
|
||||
impl::getLogEntries().push_back({ IMHEX_PROJECT_NAME, "[DEBUG]", fmt::format(fmt::runtime(fmt), args...) });
|
||||
#endif
|
||||
}
|
||||
|
||||
[[maybe_unused]] void info(const std::string &fmt, auto &&...args) {
|
||||
hex::log::print(fg(fmt::color::cadet_blue) | fmt::emphasis::bold, "[INFO] ", fmt, args...);
|
||||
[[maybe_unused]] void info(const std::string &fmt, auto && ... args) {
|
||||
hex::log::impl::print(fg(fmt::color::cadet_blue) | fmt::emphasis::bold, "[INFO] ", fmt, args...);
|
||||
}
|
||||
|
||||
[[maybe_unused]] void warn(const std::string &fmt, auto &&...args) {
|
||||
hex::log::print(fg(fmt::color::orange) | fmt::emphasis::bold, "[WARN] ", fmt, args...);
|
||||
[[maybe_unused]] void warn(const std::string &fmt, auto && ... args) {
|
||||
hex::log::impl::print(fg(fmt::color::orange) | fmt::emphasis::bold, "[WARN] ", fmt, args...);
|
||||
}
|
||||
|
||||
[[maybe_unused]] void error(const std::string &fmt, auto &&...args) {
|
||||
hex::log::print(fg(fmt::color::red) | fmt::emphasis::bold, "[ERROR]", fmt, args...);
|
||||
[[maybe_unused]] void error(const std::string &fmt, auto && ... args) {
|
||||
hex::log::impl::print(fg(fmt::color::red) | fmt::emphasis::bold, "[ERROR]", fmt, args...);
|
||||
}
|
||||
|
||||
[[maybe_unused]] void fatal(const std::string &fmt, auto &&...args) {
|
||||
hex::log::print(fg(fmt::color::purple) | fmt::emphasis::bold, "[FATAL]", fmt, args...);
|
||||
[[maybe_unused]] void fatal(const std::string &fmt, auto && ... args) {
|
||||
hex::log::impl::print(fg(fmt::color::purple) | fmt::emphasis::bold, "[FATAL]", fmt, args...);
|
||||
}
|
||||
|
||||
|
||||
[[maybe_unused]] void print(const std::string &fmt, auto && ... args) {
|
||||
std::scoped_lock lock(impl::g_loggerMutex);
|
||||
|
||||
auto dest = impl::getDestination();
|
||||
auto message = fmt::format(fmt::runtime(fmt), args...);
|
||||
fmt::print(dest, "{}", message);
|
||||
fflush(dest);
|
||||
}
|
||||
|
||||
[[maybe_unused]] void println(const std::string &fmt, auto && ... args) {
|
||||
std::scoped_lock lock(impl::g_loggerMutex);
|
||||
|
||||
auto dest = impl::getDestination();
|
||||
auto message = fmt::format(fmt::runtime(fmt), args...);
|
||||
fmt::print(dest, "{}\n", message);
|
||||
fflush(dest);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,11 +9,12 @@
|
||||
#include <span>
|
||||
#include <string>
|
||||
|
||||
#include <imgui_impl_opengl3_loader.h>
|
||||
#include <opengl_support.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
namespace hex::gl {
|
||||
|
||||
namespace {
|
||||
namespace impl {
|
||||
|
||||
template<typename T>
|
||||
GLuint getType() {
|
||||
@@ -21,8 +22,10 @@ namespace hex::gl {
|
||||
return GL_FLOAT;
|
||||
else if constexpr (std::is_same_v<T, u32>)
|
||||
return GL_UNSIGNED_INT;
|
||||
else
|
||||
else {
|
||||
static_assert(hex::always_false<T>::value, "Unsupported type");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -41,30 +44,30 @@ namespace hex::gl {
|
||||
|
||||
[[nodiscard]] size_t size() const { return this->m_data.size(); }
|
||||
|
||||
auto operator+(const Vector<T, Size>& other) {
|
||||
auto operator+(const Vector& 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 operator-(const Vector& 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) {
|
||||
auto dot(const Vector& 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) {
|
||||
auto cross(const Vector& 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] });
|
||||
return Vector({ 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() {
|
||||
@@ -75,7 +78,7 @@ namespace hex::gl {
|
||||
return copy;
|
||||
}
|
||||
|
||||
auto operator==(const Vector<T, Size>& other) {
|
||||
auto operator==(const Vector& other) {
|
||||
for (size_t i = 0; i < Size; i++)
|
||||
if (this->m_data[i] != other[i])
|
||||
return false;
|
||||
@@ -160,7 +163,7 @@ namespace hex::gl {
|
||||
void addBuffer(u32 index, const Buffer<T> &buffer) const {
|
||||
glEnableVertexAttribArray(index);
|
||||
buffer.bind();
|
||||
glVertexAttribPointer(index, 3, getType<T>(), GL_FALSE, 3 * sizeof(T), nullptr);
|
||||
glVertexAttribPointer(index, 3, impl::getType<T>(), GL_FALSE, 3 * sizeof(T), nullptr);
|
||||
buffer.unbind();
|
||||
}
|
||||
|
||||
@@ -168,7 +171,7 @@ namespace hex::gl {
|
||||
void unbind() const;
|
||||
|
||||
private:
|
||||
GLuint m_array;
|
||||
GLuint m_array = 0;
|
||||
};
|
||||
|
||||
class Texture {
|
||||
|
||||
@@ -4,11 +4,14 @@
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <expected>
|
||||
|
||||
#include <wolv/utils/expected.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
using Patches = std::map<u64, u8>;
|
||||
namespace prv {
|
||||
class Provider;
|
||||
}
|
||||
|
||||
enum class IPSError {
|
||||
AddressOutOfRange,
|
||||
@@ -18,9 +21,22 @@ namespace hex {
|
||||
MissingEOF
|
||||
};
|
||||
|
||||
std::expected<std::vector<u8>, IPSError> generateIPSPatch(const Patches &patches);
|
||||
std::expected<std::vector<u8>, IPSError> generateIPS32Patch(const Patches &patches);
|
||||
class Patches {
|
||||
public:
|
||||
Patches() = default;
|
||||
Patches(std::map<u64, u8> &&patches) : m_patches(std::move(patches)) {}
|
||||
|
||||
std::expected<Patches, IPSError> loadIPSPatch(const std::vector<u8> &ipsPatch);
|
||||
std::expected<Patches, IPSError> loadIPS32Patch(const std::vector<u8> &ipsPatch);
|
||||
static wolv::util::Expected<Patches, IPSError> fromProvider(hex::prv::Provider *provider);
|
||||
static wolv::util::Expected<Patches, IPSError> fromIPSPatch(const std::vector<u8> &ipsPatch);
|
||||
static wolv::util::Expected<Patches, IPSError> fromIPS32Patch(const std::vector<u8> &ipsPatch);
|
||||
|
||||
wolv::util::Expected<std::vector<u8>, IPSError> toIPSPatch() const;
|
||||
wolv::util::Expected<std::vector<u8>, IPSError> toIPS32Patch() const;
|
||||
|
||||
const auto& get() const { return this->m_patches; }
|
||||
auto& get() { return this->m_patches; }
|
||||
|
||||
private:
|
||||
std::map<u64, u8> m_patches;
|
||||
};
|
||||
}
|
||||
@@ -30,7 +30,7 @@ namespace hex {
|
||||
* @brief get the error string explaining the error that occured when opening the file.
|
||||
* This error is a combination of the tar error and the native file open error
|
||||
*/
|
||||
std::string getOpenErrorString();
|
||||
std::string getOpenErrorString() const;
|
||||
|
||||
[[nodiscard]] std::vector<u8> readVector(const std::fs::path &path);
|
||||
[[nodiscard]] std::string readString(const std::fs::path &path);
|
||||
@@ -52,7 +52,7 @@ namespace hex {
|
||||
|
||||
bool m_valid = false;
|
||||
|
||||
// these will be updated when the constructor is called
|
||||
// These will be updated when the constructor is called
|
||||
int m_tarOpenErrno = MTAR_ESUCCESS;
|
||||
int m_fileOpenErrno = 0;
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace hex {
|
||||
|
||||
struct Region {
|
||||
u64 address;
|
||||
size_t size;
|
||||
u64 size;
|
||||
|
||||
[[nodiscard]] constexpr bool isWithin(const Region &other) const {
|
||||
if (*this == Invalid() || other == Invalid())
|
||||
@@ -44,7 +44,12 @@ namespace hex {
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u64 getStartAddress() const { return this->address; }
|
||||
[[nodiscard]] constexpr u64 getEndAddress() const { return this->address + this->size - 1;}
|
||||
[[nodiscard]] constexpr u64 getEndAddress() const {
|
||||
if (this->size == 0)
|
||||
return this->address;
|
||||
else
|
||||
return this->address + this->size - 1;
|
||||
}
|
||||
[[nodiscard]] constexpr size_t getSize() const { return this->size; }
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(const Region &other) const {
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/intrinsics.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
@@ -19,10 +18,20 @@
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#if defined(OS_MACOS)
|
||||
#include <hex/helpers/utils_macos.hpp>
|
||||
#elif defined(OS_LINUX)
|
||||
#include <hex/helpers/utils_linux.hpp>
|
||||
#endif
|
||||
|
||||
struct ImVec2;
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace prv {
|
||||
class Provider;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] std::vector<T> sampleData(const std::vector<T> &data, size_t count) {
|
||||
size_t stride = std::max(1.0, double(data.size()) / count);
|
||||
@@ -59,13 +68,14 @@ namespace hex {
|
||||
[[nodiscard]] std::string toByteString(u64 bytes);
|
||||
[[nodiscard]] std::string makePrintable(u8 c);
|
||||
|
||||
void runCommand(const std::string &command);
|
||||
void startProgram(const std::string &command);
|
||||
int executeCommand(const std::string &command);
|
||||
void openWebpage(std::string url);
|
||||
|
||||
[[nodiscard]] std::string encodeByteString(const std::vector<u8> &bytes);
|
||||
[[nodiscard]] std::vector<u8> decodeByteString(const std::string &string);
|
||||
|
||||
[[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const std::unsigned_integral auto &value) {
|
||||
[[nodiscard]] constexpr u64 extract(u8 from, u8 to, const std::unsigned_integral auto &value) {
|
||||
if (from < to) std::swap(from, to);
|
||||
|
||||
using ValueType = std::remove_cvref_t<decltype(value)>;
|
||||
@@ -89,13 +99,13 @@ namespace hex {
|
||||
return (value & mask) >> to;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr inline i128 signExtend(size_t numBits, i128 value) {
|
||||
[[nodiscard]] constexpr i128 signExtend(size_t numBits, i128 value) {
|
||||
i128 mask = 1ULL << (numBits - 1);
|
||||
return (value ^ mask) - mask;
|
||||
}
|
||||
|
||||
template<std::integral T>
|
||||
[[nodiscard]] constexpr inline T swapBitOrder(size_t numBits, T value) {
|
||||
[[nodiscard]] constexpr T swapBitOrder(size_t numBits, T value) {
|
||||
T result = 0x00;
|
||||
|
||||
for (size_t bit = 0; bit < numBits; bit++) {
|
||||
@@ -106,14 +116,14 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr inline size_t strnlen(const char *s, size_t n) {
|
||||
[[nodiscard]] constexpr size_t strnlen(const char *s, size_t n) {
|
||||
size_t i = 0;
|
||||
while (i < n && s[i] != '\x00') i++;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
template<size_t Size>
|
||||
template<size_t>
|
||||
struct SizeTypeImpl { };
|
||||
|
||||
template<>
|
||||
@@ -214,7 +224,7 @@ namespace hex {
|
||||
|
||||
[[nodiscard]] inline std::vector<u8> parseByteString(const std::string &string) {
|
||||
auto byteString = std::string(string);
|
||||
byteString.erase(std::remove(byteString.begin(), byteString.end(), ' '), byteString.end());
|
||||
std::erase(byteString, ' ');
|
||||
|
||||
if ((byteString.length() % 2) != 0) return {};
|
||||
|
||||
@@ -229,11 +239,11 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string toBinaryString(std::unsigned_integral auto number) {
|
||||
[[nodiscard]] std::string toBinaryString(std::unsigned_integral auto number) {
|
||||
if (number == 0) return "0";
|
||||
|
||||
std::string result;
|
||||
for (i16 bit = hex::bit_width(number) - 1; bit >= 0; bit--)
|
||||
for (i16 bit = hex::bit_width(number) - 1; bit >= 0; bit -= 1)
|
||||
result += (number & (0b1 << bit)) == 0 ? '0' : '1';
|
||||
|
||||
return result;
|
||||
@@ -286,4 +296,7 @@ namespace hex {
|
||||
|
||||
[[nodiscard]] std::optional<std::fs::path> getInitialFilePath();
|
||||
|
||||
[[nodiscard]] std::string generateHexView(u64 offset, u64 size, prv::Provider *provider);
|
||||
[[nodiscard]] std::string generateHexView(u64 offset, const std::vector<u8> &data);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/plugin_manager.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/plugin_manager.hpp>
|
||||
|
||||
#include <wolv/utils/string.hpp>
|
||||
#include <wolv/utils/preproc.hpp>
|
||||
|
||||
#if defined (IMHEX_STATIC_LINK_PLUGINS)
|
||||
#define IMHEX_PLUGIN_VISIBILITY_PREFIX static
|
||||
#else
|
||||
#define IMHEX_PLUGIN_VISIBILITY_PREFIX extern "C" [[gnu::visibility("default")]]
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This macro is used to define all the required entry points for a plugin.
|
||||
@@ -16,16 +23,29 @@
|
||||
*/
|
||||
#define IMHEX_PLUGIN_SETUP(name, author, description) IMHEX_PLUGIN_SETUP_IMPL(name, author, description)
|
||||
|
||||
#define IMHEX_PLUGIN_SETUP_IMPL(name, author, description) \
|
||||
extern "C" [[gnu::visibility("default")]] const char *getPluginName() { return name; } \
|
||||
extern "C" [[gnu::visibility("default")]] const char *getPluginAuthor() { return author; } \
|
||||
extern "C" [[gnu::visibility("default")]] const char *getPluginDescription() { return description; } \
|
||||
extern "C" [[gnu::visibility("default")]] const char *getCompatibleVersion() { return IMHEX_VERSION; } \
|
||||
extern "C" [[gnu::visibility("default")]] void setImGuiContext(ImGuiContext *ctx) { \
|
||||
ImGui::SetCurrentContext(ctx); \
|
||||
GImGui = ctx; \
|
||||
} \
|
||||
extern "C" [[gnu::visibility("default")]] void initializePlugin()
|
||||
#define IMHEX_PLUGIN_SETUP_IMPL(name, author, description) \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getPluginName() { return name; } \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getPluginAuthor() { return author; } \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getPluginDescription() { return description; } \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getCompatibleVersion() { return IMHEX_VERSION; } \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void setImGuiContext(ImGuiContext *ctx) { \
|
||||
ImGui::SetCurrentContext(ctx); \
|
||||
GImGui = ctx; \
|
||||
} \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void initializePlugin(); \
|
||||
extern "C" [[gnu::visibility("default")]] void WOLV_TOKEN_CONCAT(forceLinkPlugin_, IMHEX_PLUGIN_NAME)() { \
|
||||
hex::PluginManager::addPlugin(hex::PluginFunctions { \
|
||||
initializePlugin, \
|
||||
getPluginName, \
|
||||
getPluginAuthor, \
|
||||
getPluginDescription, \
|
||||
getCompatibleVersion, \
|
||||
setImGuiContext, \
|
||||
nullptr, \
|
||||
nullptr \
|
||||
}); \
|
||||
} \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void initializePlugin()
|
||||
|
||||
/**
|
||||
* This macro is used to define subcommands defined by the plugin
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/helpers/literals.hpp>
|
||||
|
||||
@@ -20,7 +17,7 @@ namespace hex::prv {
|
||||
public:
|
||||
using BufferedReader::BufferedReader;
|
||||
|
||||
ProviderReader(Provider *provider, size_t bufferSize = 0x100000) : BufferedReader(provider, provider->getActualSize(), bufferSize) {
|
||||
explicit ProviderReader(Provider *provider, size_t bufferSize = 0x100000) : BufferedReader(provider, provider->getActualSize(), bufferSize) {
|
||||
this->setEndAddress(provider->getBaseAddress() + provider->getActualSize() - 1);
|
||||
this->seek(provider->getBaseAddress());
|
||||
}
|
||||
|
||||
@@ -6,13 +6,15 @@
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/providers/overlay.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
|
||||
#include <hex/providers/undo_redo/stack.hpp>
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
@@ -106,7 +108,7 @@ namespace hex::prv {
|
||||
* @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);
|
||||
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.
|
||||
@@ -114,7 +116,7 @@ namespace hex::prv {
|
||||
* @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);
|
||||
void write(u64 offset, const void *buffer, size_t size);
|
||||
|
||||
/**
|
||||
* @brief Read data from this provider, without applying overlays and patches
|
||||
@@ -154,25 +156,21 @@ namespace hex::prv {
|
||||
*/
|
||||
[[nodiscard]] virtual std::string getName() const = 0;
|
||||
|
||||
void resize(size_t newSize);
|
||||
void insert(u64 offset, size_t size);
|
||||
void remove(u64 offset, size_t size);
|
||||
|
||||
|
||||
virtual void resize(size_t newSize);
|
||||
virtual void insert(u64 offset, size_t size);
|
||||
virtual void remove(u64 offset, size_t size);
|
||||
virtual void resizeRaw(size_t newSize) { hex::unused(newSize); }
|
||||
virtual void insertRaw(u64 offset, size_t size) { hex::unused(offset, size); }
|
||||
virtual void removeRaw(u64 offset, size_t size) { hex::unused(offset, size); }
|
||||
|
||||
virtual void save();
|
||||
virtual void saveAs(const std::fs::path &path);
|
||||
|
||||
|
||||
void applyOverlays(u64 offset, void *buffer, size_t size);
|
||||
|
||||
[[nodiscard]] std::map<u64, u8> &getPatches();
|
||||
[[nodiscard]] const std::map<u64, u8> &getPatches() const;
|
||||
void applyPatches();
|
||||
|
||||
[[nodiscard]] Overlay *newOverlay();
|
||||
void deleteOverlay(Overlay *overlay);
|
||||
[[nodiscard]] const std::list<std::unique_ptr<Overlay>> &getOverlays();
|
||||
void applyOverlays(u64 offset, void *buffer, size_t size) const;
|
||||
[[nodiscard]] const std::list<std::unique_ptr<Overlay>> &getOverlays() const;
|
||||
|
||||
[[nodiscard]] size_t getPageSize() const;
|
||||
void setPageSize(size_t pageSize);
|
||||
@@ -190,9 +188,6 @@ namespace hex::prv {
|
||||
[[nodiscard]] virtual std::vector<Description> getDataDescription() const;
|
||||
[[nodiscard]] virtual std::variant<std::string, i128> queryInformation(const std::string &category, const std::string &argument);
|
||||
|
||||
void addPatch(u64 offset, const void *buffer, size_t size, bool createUndo = false);
|
||||
void createUndoPoint();
|
||||
|
||||
void undo();
|
||||
void redo();
|
||||
|
||||
@@ -212,7 +207,7 @@ namespace hex::prv {
|
||||
[[nodiscard]] u32 getID() const;
|
||||
void setID(u32 id);
|
||||
|
||||
[[nodiscard]] virtual nlohmann::json storeSettings(nlohmann::json settings = { }) const;
|
||||
[[nodiscard]] virtual nlohmann::json storeSettings(nlohmann::json settings) const;
|
||||
virtual void loadSettings(const nlohmann::json &settings);
|
||||
|
||||
void markDirty(bool dirty = true) { this->m_dirty = dirty; }
|
||||
@@ -226,12 +221,19 @@ namespace hex::prv {
|
||||
void setErrorMessage(const std::string &errorMessage) { this->m_errorMessage = errorMessage; }
|
||||
[[nodiscard]] const std::string& getErrorMessage() const { return this->m_errorMessage; }
|
||||
|
||||
template<std::derived_from<undo::Operation> T>
|
||||
bool addUndoableOperation(auto && ... args) {
|
||||
return this->m_undoRedoStack.add<T>(std::forward<decltype(args)...>(args)...);
|
||||
}
|
||||
|
||||
[[nodiscard]] undo::Stack& getUndoStack() { return this->m_undoRedoStack; }
|
||||
|
||||
protected:
|
||||
u32 m_currPage = 0;
|
||||
u64 m_baseAddress = 0;
|
||||
|
||||
std::list<std::map<u64, u8>> m_patches;
|
||||
decltype(m_patches)::iterator m_currPatches;
|
||||
undo::Stack m_undoRedoStack;
|
||||
|
||||
std::list<std::unique_ptr<Overlay>> m_overlays;
|
||||
|
||||
u32 m_id;
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/api/event_manager.hpp>
|
||||
|
||||
#include <concepts>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace prv {
|
||||
class Provider;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class PerProvider {
|
||||
public:
|
||||
@@ -17,7 +19,7 @@ namespace hex {
|
||||
PerProvider(const PerProvider&) = delete;
|
||||
PerProvider(PerProvider&&) = delete;
|
||||
PerProvider& operator=(const PerProvider&) = delete;
|
||||
PerProvider& operator=(PerProvider&&) = delete;
|
||||
PerProvider& operator=(PerProvider &&) = delete;
|
||||
|
||||
PerProvider(T data) : m_data({ { ImHexApi::Provider::get(), std::move(data) } }) { this->onCreate(); }
|
||||
|
||||
@@ -83,18 +85,18 @@ namespace hex {
|
||||
this->m_data.clear();
|
||||
});
|
||||
|
||||
// moves the data of this PerProvider instance from one provider to another
|
||||
// Moves the data of this PerProvider instance from one provider to another
|
||||
EventManager::subscribe<MovePerProviderData>(this, [this](prv::Provider *from, prv::Provider *to) {
|
||||
// get the value from the old provider, (removes it from the map)
|
||||
// Get the value from the old provider, (removes it from the map)
|
||||
auto node = m_data.extract(from);
|
||||
|
||||
// ensure the value existed
|
||||
// Ensure the value existed
|
||||
if (node.empty()) return;
|
||||
|
||||
// delete the value from the new provider, that we want to replace
|
||||
// Delete the value from the new provider, that we want to replace
|
||||
this->m_data.erase(to);
|
||||
|
||||
// re-insert it with the key of the new provider
|
||||
// Re-insert it with the key of the new provider
|
||||
node.key() = to;
|
||||
this->m_data.insert(std::move(node));
|
||||
});
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
|
||||
namespace hex::prv {
|
||||
class Provider;
|
||||
}
|
||||
|
||||
namespace hex::prv::undo {
|
||||
|
||||
class Operation : public ICloneable<Operation> {
|
||||
public:
|
||||
virtual ~Operation() = default;
|
||||
|
||||
virtual void undo(Provider *provider) = 0;
|
||||
virtual void redo(Provider *provider) = 0;
|
||||
|
||||
[[nodiscard]] virtual Region getRegion() const = 0;
|
||||
|
||||
[[nodiscard]] virtual std::string format() const = 0;
|
||||
[[nodiscard]] virtual std::vector<std::string> formatContent() const {
|
||||
return { };
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual bool shouldHighlight() const { return true; }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/providers/undo_redo/operations/operation.hpp>
|
||||
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
namespace hex::prv::undo {
|
||||
|
||||
class OperationGroup : public Operation {
|
||||
public:
|
||||
explicit OperationGroup(std::string unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
|
||||
|
||||
OperationGroup(const OperationGroup &other) {
|
||||
for (const auto &operation : other.m_operations)
|
||||
this->m_operations.emplace_back(operation->clone());
|
||||
}
|
||||
|
||||
void undo(Provider *provider) override {
|
||||
for (auto &operation : this->m_operations)
|
||||
operation->undo(provider);
|
||||
}
|
||||
|
||||
void redo(Provider *provider) override {
|
||||
for (auto &operation : this->m_operations)
|
||||
operation->redo(provider);
|
||||
}
|
||||
|
||||
void addOperation(std::unique_ptr<Operation> &&newOperation) {
|
||||
auto newRegion = newOperation->getRegion();
|
||||
if (newRegion.getStartAddress() < this->m_startAddress)
|
||||
this->m_startAddress = newRegion.getStartAddress();
|
||||
if (newRegion.getEndAddress() > this->m_endAddress)
|
||||
this->m_endAddress = newRegion.getEndAddress();
|
||||
|
||||
if (this->m_formattedContent.size() <= 10)
|
||||
this->m_formattedContent.emplace_back(newOperation->format());
|
||||
else
|
||||
this->m_formattedContent.back() = hex::format("[{}x] ...", (this->m_operations.size() - 10) + 1);
|
||||
|
||||
this->m_operations.emplace_back(std::move(newOperation));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string format() const override {
|
||||
return hex::format("{}", Lang(this->m_unlocalizedName));
|
||||
}
|
||||
|
||||
[[nodiscard]] Region getRegion() const override {
|
||||
return Region { this->m_startAddress, (this->m_endAddress - this->m_startAddress) + 1 };
|
||||
}
|
||||
|
||||
std::unique_ptr<Operation> clone() const override {
|
||||
return std::make_unique<OperationGroup>(*this);
|
||||
}
|
||||
|
||||
std::vector<std::string> formatContent() const override {
|
||||
return this->m_formattedContent;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_unlocalizedName;
|
||||
std::vector<std::unique_ptr<Operation>> m_operations;
|
||||
|
||||
u64 m_startAddress = std::numeric_limits<u64>::max();
|
||||
u64 m_endAddress = std::numeric_limits<u64>::min();
|
||||
std::vector<std::string> m_formattedContent;
|
||||
};
|
||||
|
||||
}
|
||||
63
lib/libimhex/include/hex/providers/undo_redo/stack.hpp
Normal file
63
lib/libimhex/include/hex/providers/undo_redo/stack.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/providers/undo_redo/operations/operation.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
namespace hex::prv {
|
||||
class Provider;
|
||||
}
|
||||
|
||||
namespace hex::prv::undo {
|
||||
|
||||
using Patches = std::map<u64, u8>;
|
||||
|
||||
class Stack {
|
||||
public:
|
||||
explicit Stack(Provider *provider);
|
||||
|
||||
void undo(u32 count = 1);
|
||||
void redo(u32 count = 1);
|
||||
|
||||
void groupOperations(u32 count, const std::string &unlocalizedName);
|
||||
void apply(const Stack &otherStack);
|
||||
|
||||
[[nodiscard]] bool canUndo() const;
|
||||
[[nodiscard]] bool canRedo() const;
|
||||
|
||||
template<std::derived_from<Operation> T>
|
||||
bool add(auto && ... args) {
|
||||
return this->add(std::make_unique<T>(std::forward<decltype(args)>(args)...));
|
||||
}
|
||||
|
||||
bool add(std::unique_ptr<Operation> &&operation);
|
||||
|
||||
const std::vector<std::unique_ptr<Operation>> &getAppliedOperations() const {
|
||||
return this->m_undoStack;
|
||||
}
|
||||
|
||||
const std::vector<std::unique_ptr<Operation>> &getUndoneOperations() const {
|
||||
return this->m_redoStack;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
this->m_undoStack.clear();
|
||||
this->m_redoStack.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] Operation* getLastOperation() const {
|
||||
return this->m_undoStack.back().get();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<Operation>> m_undoStack, m_redoStack;
|
||||
Provider *m_provider;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include<vector>
|
||||
#include<string>
|
||||
#include<functional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
namespace hex::subcommands {
|
||||
|
||||
/**
|
||||
* @brief Internal method - takes all the arguments ImHex received from the command line,
|
||||
* and determine which subcommands to run, with which arguments.
|
||||
@@ -27,4 +28,5 @@ namespace hex::subcommands {
|
||||
* @brief Register the handler for this specific command name
|
||||
*/
|
||||
void registerSubCommand(const std::string &cmdName, const ForwardCommandHandler &handler);
|
||||
|
||||
}
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <span>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
@@ -27,8 +26,30 @@ enum ImGuiCustomCol {
|
||||
ImGuiCustomCol_ToolbarPurple,
|
||||
ImGuiCustomCol_ToolbarBrown,
|
||||
|
||||
ImGuiCustomCol_LoggerDebug,
|
||||
ImGuiCustomCol_LoggerInfo,
|
||||
ImGuiCustomCol_LoggerWarning,
|
||||
ImGuiCustomCol_LoggerError,
|
||||
ImGuiCustomCol_LoggerFatal,
|
||||
|
||||
ImGuiCustomCol_AchievementUnlocked,
|
||||
|
||||
ImGuiCustomCol_FindHighlight,
|
||||
|
||||
ImGuiCustomCol_DiffAdded,
|
||||
ImGuiCustomCol_DiffRemoved,
|
||||
ImGuiCustomCol_DiffChanged,
|
||||
|
||||
ImGuiCustomCol_AdvancedEncodingASCII,
|
||||
ImGuiCustomCol_AdvancedEncodingSingleChar,
|
||||
ImGuiCustomCol_AdvancedEncodingMultiChar,
|
||||
ImGuiCustomCol_AdvancedEncodingUnknown,
|
||||
|
||||
ImGuiCustomCol_Highlight,
|
||||
|
||||
ImGuiCustomCol_Patches,
|
||||
ImGuiCustomCol_PatternSelected,
|
||||
|
||||
ImGuiCustomCol_IEEEToolSign,
|
||||
ImGuiCustomCol_IEEEToolExp,
|
||||
ImGuiCustomCol_IEEEToolMantissa,
|
||||
@@ -44,7 +65,7 @@ enum ImGuiCustomStyle {
|
||||
ImGuiCustomStyle_COUNT
|
||||
};
|
||||
|
||||
namespace ImGui {
|
||||
namespace ImGuiExt {
|
||||
|
||||
class Texture {
|
||||
public:
|
||||
@@ -90,6 +111,7 @@ namespace ImGui {
|
||||
bool Hyperlink(const char *label, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
|
||||
bool BulletHyperlink(const char *label, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
|
||||
bool DescriptionButton(const char *label, const char *description, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
|
||||
bool DescriptionButtonProgress(const char *label, const char *description, float fraction, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
|
||||
|
||||
void HelpHover(const char *text);
|
||||
|
||||
@@ -128,7 +150,7 @@ namespace ImGui {
|
||||
ImVec4 GetCustomColorVec4(ImGuiCustomCol idx, float alpha_mul = 1.0F);
|
||||
|
||||
inline ImHexCustomData::Styles& GetCustomStyle() {
|
||||
auto &customData = *static_cast<ImHexCustomData *>(GImGui->IO.UserData);
|
||||
auto &customData = *static_cast<ImHexCustomData *>(ImGui::GetIO().UserData);
|
||||
|
||||
return customData.styles;
|
||||
}
|
||||
@@ -177,7 +199,7 @@ namespace ImGui {
|
||||
}
|
||||
|
||||
inline void TextFormattedWrappedSelectable(const std::string &fmt, auto &&...args) {
|
||||
//Manually wrap text, using the letter M (generally the widest character in non-monospaced fonts) to calculate the character width to use.
|
||||
// Manually wrap text, using the letter M (generally the widest character in non-monospaced fonts) to calculate the character width to use.
|
||||
auto text = wolv::util::wrapMonospacedString(
|
||||
hex::format(fmt, std::forward<decltype(args)>(args)...),
|
||||
ImGui::CalcTextSize("M").x,
|
||||
@@ -205,18 +227,13 @@ namespace ImGui {
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
void TextUnformattedCentered(const char *text);
|
||||
inline void TextFormattedCentered(const std::string &fmt, auto &&...args) {
|
||||
auto text = hex::format(fmt, std::forward<decltype(args)>(args)...);
|
||||
auto availableSpace = ImGui::GetContentRegionAvail();
|
||||
auto textSize = ImGui::CalcTextSize(text.c_str(), nullptr, false, availableSpace.x * 0.75F);
|
||||
|
||||
ImGui::SetCursorPos(((availableSpace - textSize) / 2.0F));
|
||||
|
||||
ImGui::PushTextWrapPos(availableSpace.x * 0.75F);
|
||||
ImGui::TextFormattedWrapped("{}", text);
|
||||
ImGui::PopTextWrapPos();
|
||||
TextUnformattedCentered(text.c_str());
|
||||
}
|
||||
|
||||
|
||||
inline void TextFormattedCenteredHorizontal(const std::string &fmt, auto &&...args) {
|
||||
auto text = hex::format(fmt, std::forward<decltype(args)>(args)...);
|
||||
auto availableSpace = ImGui::GetContentRegionAvail();
|
||||
@@ -225,15 +242,11 @@ namespace ImGui {
|
||||
ImGui::SetCursorPosX(((availableSpace - textSize) / 2.0F).x);
|
||||
|
||||
ImGui::PushTextWrapPos(availableSpace.x * 0.75F);
|
||||
ImGui::TextFormattedWrapped("{}", text);
|
||||
ImGuiExt::TextFormattedWrapped("{}", text);
|
||||
ImGui::PopTextWrapPos();
|
||||
}
|
||||
|
||||
bool InputText(const char* label, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputTextIcon(const char* label, const char *icon, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputText(const char *label, std::u8string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputTextMultiline(const char* label, std::string &buffer, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputTextWithHint(const char *label, const char *hint, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
|
||||
bool InputScalarCallback(const char* label, ImGuiDataType data_type, void* p_data, const char* format, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data);
|
||||
|
||||
@@ -241,9 +254,64 @@ namespace ImGui {
|
||||
|
||||
bool BitCheckbox(const char* label, bool* v);
|
||||
|
||||
bool DimmedButton(const char* label);
|
||||
bool DimmedIconButton(const char *symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0));
|
||||
bool DimmedButton(const char* label, ImVec2 size = ImVec2(0, 0));
|
||||
bool DimmedIconButton(const char *symbol, ImVec4 color, ImVec2 size = ImVec2(0, 0));
|
||||
bool DimmedButtonToggle(const char *icon, bool *v, ImVec2 size);
|
||||
bool DimmedIconToggle(const char *icon, bool *v);
|
||||
|
||||
void TextOverlay(const char *text, ImVec2 pos);
|
||||
|
||||
bool BeginBox();
|
||||
void EndBox();
|
||||
|
||||
void BeginSubWindow(const char *label, ImVec2 size = ImVec2(0, 0), ImGuiChildFlags flags = ImGuiChildFlags_None);
|
||||
void EndSubWindow();
|
||||
|
||||
void ConfirmButtons(const char *textLeft, const char *textRight, const auto &leftButtonCallback, const auto &rightButtonCallback) {
|
||||
auto width = ImGui::GetWindowWidth();
|
||||
ImGui::SetCursorPosX(width / 9);
|
||||
if (ImGui::Button(textLeft, ImVec2(width / 3, 0)))
|
||||
leftButtonCallback();
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(width / 9 * 5);
|
||||
if (ImGui::Button(textRight, ImVec2(width / 3, 0)))
|
||||
rightButtonCallback();
|
||||
}
|
||||
template<typename T>
|
||||
constexpr ImGuiDataType getImGuiDataType() {
|
||||
if constexpr (std::same_as<T, u8>) return ImGuiDataType_U8;
|
||||
else if constexpr (std::same_as<T, u16>) return ImGuiDataType_U16;
|
||||
else if constexpr (std::same_as<T, u32>) return ImGuiDataType_U32;
|
||||
else if constexpr (std::same_as<T, u64>) return ImGuiDataType_U64;
|
||||
else if constexpr (std::same_as<T, i8>) return ImGuiDataType_S8;
|
||||
else if constexpr (std::same_as<T, i16>) return ImGuiDataType_S16;
|
||||
else if constexpr (std::same_as<T, i32>) return ImGuiDataType_S32;
|
||||
else if constexpr (std::same_as<T, i64>) return ImGuiDataType_S64;
|
||||
else if constexpr (std::same_as<T, float>) return ImGuiDataType_Float;
|
||||
else if constexpr (std::same_as<T, double>) return ImGuiDataType_Double;
|
||||
else static_assert(hex::always_false<T>::value, "Invalid data type!");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr const char *getFormatLengthSpecifier() {
|
||||
if constexpr (std::same_as<T, u8>) return "hh";
|
||||
else if constexpr (std::same_as<T, u16>) return "h";
|
||||
else if constexpr (std::same_as<T, u32>) return "l";
|
||||
else if constexpr (std::same_as<T, u64>) return "ll";
|
||||
else if constexpr (std::same_as<T, i8>) return "hh";
|
||||
else if constexpr (std::same_as<T, i16>) return "h";
|
||||
else if constexpr (std::same_as<T, i32>) return "l";
|
||||
else if constexpr (std::same_as<T, i64>) return "ll";
|
||||
else static_assert(hex::always_false<T>::value, "Invalid data type!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// these functions are exception because they just allow conversion from string to char*, they do not really add anything
|
||||
namespace ImGui {
|
||||
bool InputText(const char* label, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputText(const char *label, std::u8string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputTextMultiline(const char* label, std::string &buffer, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputTextWithHint(const char *label, const char *hint, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
|
||||
}
|
||||
@@ -4,13 +4,12 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <hex/api/task.hpp>
|
||||
#include <hex/api/task_manager.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
|
||||
@@ -10,59 +10,174 @@
|
||||
#include <fonts/codicons_font.h>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
#include <hex/api/shortcut_manager.hpp>
|
||||
#include <hex/api/event_manager.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/providers/provider_data.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <hex/api/localization.hpp>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace hex {
|
||||
|
||||
class View {
|
||||
explicit View(std::string unlocalizedName);
|
||||
public:
|
||||
explicit View(std::string unlocalizedViewName);
|
||||
virtual ~View() = default;
|
||||
|
||||
virtual void drawContent() = 0;
|
||||
virtual void drawAlwaysVisible() { }
|
||||
[[nodiscard]] virtual bool isAvailable() const;
|
||||
[[nodiscard]] virtual bool shouldProcess() const { return this->isAvailable() && this->getWindowOpenState(); }
|
||||
/**
|
||||
* @brief Draws the view
|
||||
* @note Do not override this method. Override drawContent() instead
|
||||
*/
|
||||
virtual void draw() = 0;
|
||||
|
||||
/**
|
||||
* @brief Draws the content of the view
|
||||
*/
|
||||
virtual void drawContent() = 0;
|
||||
|
||||
/**
|
||||
* @brief Draws content that should always be visible, even if the view is not open
|
||||
*/
|
||||
virtual void drawAlwaysVisibleContent() { }
|
||||
|
||||
/**
|
||||
* @brief Whether or not the view window should be drawn
|
||||
* @return True if the view window should be drawn, false otherwise
|
||||
*/
|
||||
[[nodiscard]] virtual bool shouldDraw() const;
|
||||
|
||||
/**
|
||||
* @brief Whether or not the entire view should be processed
|
||||
* If this returns false, the view will not be drawn and no shortcuts will be handled. This includes things
|
||||
* drawn in the drawAlwaysVisibleContent() function.
|
||||
* @return True if the view should be processed, false otherwise
|
||||
*/
|
||||
[[nodiscard]] virtual bool shouldProcess() const;
|
||||
|
||||
/**
|
||||
* @brief Whether or not the view should have an entry in the view menu
|
||||
* @return True if the view should have an entry in the view menu, false otherwise
|
||||
*/
|
||||
[[nodiscard]] virtual bool hasViewMenuItemEntry() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the minimum size of the view window
|
||||
* @return The minimum size of the view window
|
||||
*/
|
||||
[[nodiscard]] virtual ImVec2 getMinSize() const;
|
||||
|
||||
/**
|
||||
* @brief Gets the maximum size of the view window
|
||||
* @return The maximum size of the view window
|
||||
*/
|
||||
[[nodiscard]] virtual ImVec2 getMaxSize() const;
|
||||
|
||||
/**
|
||||
* @brief Gets additional window flags for the view window
|
||||
* @return Additional window flags for the view window
|
||||
*/
|
||||
[[nodiscard]] virtual ImGuiWindowFlags getWindowFlags() const;
|
||||
|
||||
|
||||
|
||||
[[nodiscard]] bool &getWindowOpenState();
|
||||
[[nodiscard]] const bool &getWindowOpenState() const;
|
||||
|
||||
[[nodiscard]] const std::string &getUnlocalizedName() const;
|
||||
[[nodiscard]] std::string getName() const;
|
||||
|
||||
static void confirmButtons(const std::string &textLeft, const std::string &textRight, const std::function<void()> &leftButtonFn, const std::function<void()> &rightButtonFn);
|
||||
[[nodiscard]] bool didWindowJustOpen();
|
||||
void setWindowJustOpened(bool state);
|
||||
|
||||
static void discardNavigationRequests();
|
||||
|
||||
static inline std::string toWindowName(const std::string &unlocalizedName) {
|
||||
return LangEntry(unlocalizedName) + "###" + unlocalizedName;
|
||||
}
|
||||
[[nodiscard]] static std::string toWindowName(const std::string &unlocalizedName);
|
||||
|
||||
static ImFontAtlas *getFontAtlas();
|
||||
static void setFontAtlas(ImFontAtlas *atlas);
|
||||
|
||||
static ImFontConfig getFontConfig();
|
||||
static void setFontConfig(ImFontConfig config);
|
||||
public:
|
||||
class Window;
|
||||
class Special;
|
||||
class Floating;
|
||||
class Modal;
|
||||
|
||||
private:
|
||||
std::string m_unlocalizedViewName;
|
||||
bool m_windowOpen = false;
|
||||
std::map<Shortcut, std::function<void()>> m_shortcuts;
|
||||
std::map<Shortcut, ShortcutManager::ShortcutEntry> m_shortcuts;
|
||||
bool m_windowJustOpened = false;
|
||||
|
||||
friend class ShortcutManager;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief A view that draws a regular window. This should be the default for most views
|
||||
*/
|
||||
class View::Window : public View {
|
||||
public:
|
||||
explicit Window(std::string unlocalizedName) : View(std::move(unlocalizedName)) {}
|
||||
|
||||
void draw() final {
|
||||
if (this->shouldDraw()) {
|
||||
ImGui::SetNextWindowSizeConstraints(this->getMinSize(), this->getMaxSize());
|
||||
if (ImGui::Begin(View::toWindowName(this->getUnlocalizedName()).c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse | this->getWindowFlags())) {
|
||||
this->drawContent();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A view that doesn't handle any window creation and just draws its content.
|
||||
* This should be used if you intend to draw your own special window
|
||||
*/
|
||||
class View::Special : public View {
|
||||
public:
|
||||
explicit Special(std::string unlocalizedName) : View(std::move(unlocalizedName)) {}
|
||||
|
||||
void draw() final {
|
||||
if (this->shouldDraw()) {
|
||||
ImGui::SetNextWindowSizeConstraints(this->getMinSize(), this->getMaxSize());
|
||||
this->drawContent();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A view that draws a floating window. These are the same as regular windows but cannot be docked
|
||||
*/
|
||||
class View::Floating : public View::Window {
|
||||
public:
|
||||
explicit Floating(std::string unlocalizedName) : Window(std::move(unlocalizedName)) {}
|
||||
|
||||
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const { return ImGuiWindowFlags_NoDocking; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A view that draws a modal window. The window will always be drawn on top and will block input to other windows
|
||||
*/
|
||||
class View::Modal : public View {
|
||||
public:
|
||||
explicit Modal(std::string unlocalizedName) : View(std::move(unlocalizedName)) {}
|
||||
|
||||
void draw() final {
|
||||
if (this->shouldDraw()) {
|
||||
ImGui::SetNextWindowSizeConstraints(this->getMinSize(), this->getMaxSize());
|
||||
|
||||
if (this->getWindowOpenState())
|
||||
ImGui::OpenPopup(View::toWindowName(this->getUnlocalizedName()).c_str());
|
||||
|
||||
if (ImGui::BeginPopupModal(View::toWindowName(this->getUnlocalizedName()).c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize | this->getWindowFlags())) {
|
||||
this->drawContent();
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
|
||||
#include <hex/api/task.hpp>
|
||||
#include <hex/api/task_manager.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <hex/api/achievement_manager.hpp>
|
||||
#include <hex/api/event_manager.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@@ -128,6 +129,8 @@ namespace hex {
|
||||
|
||||
if (achievement->isUnlocked())
|
||||
EventManager::post<EventAchievementUnlocked>(*achievement);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +158,22 @@ namespace hex {
|
||||
getAchievementNodes(false).clear();
|
||||
}
|
||||
|
||||
std::pair<u32, u32> AchievementManager::getProgress() {
|
||||
u32 unlocked = 0;
|
||||
u32 total = 0;
|
||||
|
||||
for (auto &[categoryName, achievements] : getAchievements()) {
|
||||
for (auto &[achievementName, achievement] : achievements) {
|
||||
total += 1;
|
||||
if (achievement->isUnlocked()) {
|
||||
unlocked += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { unlocked, total };
|
||||
}
|
||||
|
||||
void AchievementManager::achievementAdded() {
|
||||
getAchievementStartNodes(false).clear();
|
||||
getAchievementNodes(false).clear();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/api/shortcut_manager.hpp>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
@@ -8,6 +9,11 @@
|
||||
|
||||
#include <filesystem>
|
||||
#include <thread>
|
||||
#include <jthread.hpp>
|
||||
|
||||
#if defined(OS_WEB)
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@@ -18,27 +24,18 @@ namespace hex {
|
||||
|
||||
namespace ContentRegistry::Settings {
|
||||
|
||||
constexpr auto SettingsFile = "settings.json";
|
||||
[[maybe_unused]] constexpr auto SettingsFile = "settings.json";
|
||||
|
||||
namespace impl {
|
||||
|
||||
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) {
|
||||
nlohmann::json& getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &defaultValue) {
|
||||
auto &settings = getSettingsData();
|
||||
|
||||
if (!settings.contains(unlocalizedCategory)) return {};
|
||||
if (!settings[unlocalizedCategory].contains(unlocalizedName)) return {};
|
||||
if (!settings.contains(unlocalizedCategory))
|
||||
settings[unlocalizedCategory] = {};
|
||||
|
||||
if (!settings[unlocalizedCategory].contains(unlocalizedName))
|
||||
settings[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
|
||||
return settings[unlocalizedCategory][unlocalizedName];
|
||||
}
|
||||
@@ -49,175 +46,338 @@ namespace hex {
|
||||
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 defined(OS_WEB)
|
||||
void load() {
|
||||
char *data = (char *) MAIN_THREAD_EM_ASM_INT({
|
||||
let data = localStorage.getItem("config");
|
||||
return data ? stringToNewUTF8(data) : null;
|
||||
});
|
||||
|
||||
if (file.isValid()) {
|
||||
getSettingsData() = nlohmann::json::parse(file.readString());
|
||||
loaded = true;
|
||||
if (data == nullptr) {
|
||||
store();
|
||||
} else {
|
||||
getSettingsData() = nlohmann::json::parse(data);
|
||||
}
|
||||
}
|
||||
|
||||
void store() {
|
||||
auto data = getSettingsData().dump();
|
||||
MAIN_THREAD_EM_ASM({
|
||||
localStorage.setItem("config", UTF8ToString($0));
|
||||
}, data.c_str());
|
||||
}
|
||||
|
||||
void clear() {
|
||||
MAIN_THREAD_EM_ASM({
|
||||
localStorage.removeItem("config");
|
||||
});
|
||||
}
|
||||
#else
|
||||
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() {
|
||||
// During a crash settings can be empty, causing them to be overwritten.
|
||||
if(getSettingsData().empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
wolv::io::fs::remove(dir / SettingsFile);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
static T* insertOrGetEntry(std::vector<T> &vector, const std::string &unlocalizedName) {
|
||||
T *foundEntry = nullptr;
|
||||
for (auto &entry : vector) {
|
||||
if (entry.unlocalizedName == unlocalizedName) {
|
||||
foundEntry = &entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!loaded)
|
||||
store();
|
||||
}
|
||||
|
||||
void store() {
|
||||
// During a crash settings can be empty, causing them to be overwritten.
|
||||
if(getSettingsData().empty()) {
|
||||
return;
|
||||
if (foundEntry == nullptr) {
|
||||
if (unlocalizedName.empty())
|
||||
foundEntry = &*vector.emplace(vector.begin(), unlocalizedName);
|
||||
else
|
||||
foundEntry = &vector.emplace_back(unlocalizedName);
|
||||
}
|
||||
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Create);
|
||||
return foundEntry;
|
||||
}
|
||||
|
||||
if (file.isValid()) {
|
||||
file.writeString(getSettingsData().dump(4));
|
||||
break;
|
||||
std::vector<Category> &getSettings() {
|
||||
static std::vector<Category> categories;
|
||||
|
||||
return categories;
|
||||
}
|
||||
|
||||
Widgets::Widget* add(const std::string &unlocalizedCategory, const std::string &unlocalizedSubCategory, const std::string &unlocalizedName, std::unique_ptr<Widgets::Widget> &&widget) {
|
||||
const auto category = insertOrGetEntry(getSettings(), unlocalizedCategory);
|
||||
const auto subCategory = insertOrGetEntry(category->subCategories, unlocalizedSubCategory);
|
||||
const auto entry = insertOrGetEntry(subCategory->entries, unlocalizedName);
|
||||
|
||||
entry->widget = std::move(widget);
|
||||
entry->widget->load(getSetting(unlocalizedCategory, unlocalizedName, entry->widget->store()));
|
||||
entry->widget->onChanged();
|
||||
|
||||
return entry->widget.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void setCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedDescription) {
|
||||
const auto category = insertOrGetEntry(impl::getSettings(), unlocalizedCategory);
|
||||
|
||||
category->unlocalizedDescription = unlocalizedDescription;
|
||||
}
|
||||
|
||||
nlohmann::json read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &defaultValue) {
|
||||
auto setting = impl::getSetting(unlocalizedCategory, unlocalizedName, defaultValue);
|
||||
|
||||
if (setting.is_number() && defaultValue.is_boolean())
|
||||
setting = setting.get<int>() != 0;
|
||||
if (setting.is_null())
|
||||
setting = defaultValue;
|
||||
|
||||
return setting;
|
||||
}
|
||||
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &value) {
|
||||
impl::getSetting(unlocalizedCategory, unlocalizedName, value) = value;
|
||||
}
|
||||
|
||||
namespace Widgets {
|
||||
|
||||
bool Checkbox::draw(const std::string &name) {
|
||||
return ImGui::Checkbox(name.c_str(), &this->m_value);
|
||||
}
|
||||
|
||||
void Checkbox::load(const nlohmann::json &data) {
|
||||
if (data.is_number()) {
|
||||
this->m_value = data.get<int>() != 0;
|
||||
} else if (data.is_boolean()) {
|
||||
this->m_value = data.get<bool>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for checkbox!");
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json Checkbox::store() {
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
|
||||
bool SliderInteger::draw(const std::string &name) {
|
||||
return ImGui::SliderInt(name.c_str(), &this->m_value, this->m_min, this->m_max);
|
||||
}
|
||||
|
||||
void SliderInteger::load(const nlohmann::json &data) {
|
||||
if (data.is_number_integer()) {
|
||||
this->m_value = data.get<int>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for slider!");
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json SliderInteger::store() {
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
|
||||
bool SliderFloat::draw(const std::string &name) {
|
||||
return ImGui::SliderFloat(name.c_str(), &this->m_value, this->m_min, this->m_max);
|
||||
}
|
||||
|
||||
void SliderFloat::load(const nlohmann::json &data) {
|
||||
if (data.is_number()) {
|
||||
this->m_value = data.get<float>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for slider!");
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json SliderFloat::store() {
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
|
||||
ColorPicker::ColorPicker(ImColor defaultColor) {
|
||||
this->m_value = {
|
||||
defaultColor.Value.x,
|
||||
defaultColor.Value.y,
|
||||
defaultColor.Value.z,
|
||||
defaultColor.Value.w
|
||||
};
|
||||
}
|
||||
|
||||
bool ColorPicker::draw(const std::string &name) {
|
||||
return ImGui::ColorEdit4(name.c_str(), this->m_value.data(), ImGuiColorEditFlags_NoInputs);
|
||||
}
|
||||
|
||||
void ColorPicker::load(const nlohmann::json &data) {
|
||||
if (data.is_number()) {
|
||||
ImColor color(data.get<u32>());
|
||||
this->m_value = { color.Value.x, color.Value.y, color.Value.z, color.Value.w };
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for color picker!");
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json ColorPicker::store() {
|
||||
const ImColor color(this->m_value[0], this->m_value[1], this->m_value[2], this->m_value[3]);
|
||||
|
||||
return static_cast<ImU32>(color);
|
||||
}
|
||||
|
||||
ImColor ColorPicker::getColor() const {
|
||||
return { this->m_value[0], this->m_value[1], this->m_value[2], this->m_value[3] };
|
||||
}
|
||||
|
||||
|
||||
bool DropDown::draw(const std::string &name) {
|
||||
const char *preview = "";
|
||||
if (static_cast<size_t>(this->m_value) < this->m_items.size())
|
||||
preview = this->m_items[this->m_value].c_str();
|
||||
|
||||
bool changed = false;
|
||||
if (ImGui::BeginCombo(name.c_str(), Lang(preview))) {
|
||||
|
||||
int index = 0;
|
||||
for (const auto &item : this->m_items) {
|
||||
const bool selected = index == this->m_value;
|
||||
|
||||
if (ImGui::Selectable(Lang(item), selected)) {
|
||||
this->m_value = index;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (selected)
|
||||
ImGui::SetItemDefaultFocus();
|
||||
|
||||
index += 1;
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void DropDown::load(const nlohmann::json &data) {
|
||||
this->m_value = 0;
|
||||
|
||||
int defaultItemIndex = 0;
|
||||
|
||||
int index = 0;
|
||||
for (const auto &item : this->m_settingsValues) {
|
||||
if (item == this->m_defaultItem)
|
||||
defaultItemIndex = index;
|
||||
|
||||
if (item == data) {
|
||||
this->m_value = index;
|
||||
return;
|
||||
}
|
||||
|
||||
index += 1;
|
||||
}
|
||||
|
||||
this->m_value = defaultItemIndex;
|
||||
}
|
||||
|
||||
nlohmann::json DropDown::store() {
|
||||
if (this->m_value == -1)
|
||||
return this->m_defaultItem;
|
||||
if (static_cast<size_t>(this->m_value) >= this->m_items.size())
|
||||
return this->m_defaultItem;
|
||||
|
||||
return this->m_settingsValues[this->m_value];
|
||||
}
|
||||
|
||||
const nlohmann::json& DropDown::getValue() const {
|
||||
return this->m_settingsValues[this->m_value];
|
||||
}
|
||||
|
||||
|
||||
bool TextBox::draw(const std::string &name) {
|
||||
return ImGui::InputText(name.c_str(), this->m_value);
|
||||
}
|
||||
|
||||
void TextBox::load(const nlohmann::json &data) {
|
||||
if (data.is_string()) {
|
||||
this->m_value = data.get<std::string>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for text box!");
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
wolv::io::fs::remove(dir / SettingsFile);
|
||||
nlohmann::json TextBox::store() {
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
|
||||
bool FilePicker::draw(const std::string &name) {
|
||||
bool changed = false;
|
||||
if (ImGui::InputText("##font_path", this->m_value)) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGuiExt::IconButton(ICON_VS_FOLDER_OPENED, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
|
||||
return fs::openFileBrowser(fs::DialogMode::Open, { { "TTF Font", "ttf" }, { "OTF Font", "otf" } },
|
||||
[&](const std::fs::path &path) {
|
||||
this->m_value = wolv::util::toUTF8String(path);
|
||||
});
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGuiExt::TextFormatted("{}", name);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void FilePicker::load(const nlohmann::json &data) {
|
||||
if (data.is_string()) {
|
||||
this->m_value = data.get<std::string>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for file picker!");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
return found;
|
||||
nlohmann::json FilePicker::store() {
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
|
||||
|
||||
auto &json = impl::getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
if (!json[unlocalizedCategory].contains(unlocalizedName) || !json[unlocalizedCategory][unlocalizedName].is_number())
|
||||
json[unlocalizedCategory][unlocalizedName] = int(defaultValue);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
|
||||
|
||||
auto &json = impl::getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
if (!json[unlocalizedCategory].contains(unlocalizedName) || !json[unlocalizedCategory][unlocalizedName].is_string())
|
||||
json[unlocalizedCategory][unlocalizedName] = std::string(defaultValue);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
impl::getCategoryEntry(unlocalizedCategory)->second.emplace_back(impl::Entry { unlocalizedName, requiresRestart, callback });
|
||||
|
||||
auto &json = impl::getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
if (!json[unlocalizedCategory].contains(unlocalizedName) || !json[unlocalizedCategory][unlocalizedName].is_array())
|
||||
json[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
}
|
||||
|
||||
void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription) {
|
||||
impl::getCategoryDescriptions()[unlocalizedCategory] = unlocalizedCategoryDescription;
|
||||
}
|
||||
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value) {
|
||||
auto &json = impl::getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
|
||||
json[unlocalizedCategory][unlocalizedName] = value;
|
||||
}
|
||||
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &value) {
|
||||
auto &json = impl::getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
|
||||
json[unlocalizedCategory][unlocalizedName] = value;
|
||||
}
|
||||
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &value) {
|
||||
auto &json = impl::getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
|
||||
json[unlocalizedCategory][unlocalizedName] = value;
|
||||
}
|
||||
|
||||
|
||||
i64 read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue) {
|
||||
auto &json = impl::getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
return defaultValue;
|
||||
if (!json[unlocalizedCategory].contains(unlocalizedName))
|
||||
return defaultValue;
|
||||
|
||||
if (!json[unlocalizedCategory][unlocalizedName].is_number())
|
||||
json[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
|
||||
return json[unlocalizedCategory][unlocalizedName].get<i64>();
|
||||
}
|
||||
|
||||
std::string read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue) {
|
||||
auto &json = impl::getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
return defaultValue;
|
||||
if (!json[unlocalizedCategory].contains(unlocalizedName))
|
||||
return defaultValue;
|
||||
|
||||
if (!json[unlocalizedCategory][unlocalizedName].is_string())
|
||||
json[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
|
||||
return json[unlocalizedCategory][unlocalizedName].get<std::string>();
|
||||
}
|
||||
|
||||
std::vector<std::string> read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue) {
|
||||
auto &json = impl::getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
return defaultValue;
|
||||
if (!json[unlocalizedCategory].contains(unlocalizedName))
|
||||
return defaultValue;
|
||||
|
||||
if (!json[unlocalizedCategory][unlocalizedName].is_array())
|
||||
json[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
|
||||
if (!json[unlocalizedCategory][unlocalizedName].array().empty() && !json[unlocalizedCategory][unlocalizedName][0].is_string())
|
||||
json[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
|
||||
return json[unlocalizedCategory][unlocalizedName].get<std::vector<std::string>>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -226,13 +386,13 @@ namespace hex {
|
||||
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);
|
||||
|
||||
impl::getEntries().push_back(ContentRegistry::CommandPaletteCommands::impl::Entry { type, command, unlocalizedDescription, displayCallback, executeCallback });
|
||||
impl::getEntries().push_back(impl::Entry { type, command, unlocalizedDescription, displayCallback, executeCallback });
|
||||
}
|
||||
|
||||
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 });
|
||||
impl::getHandlers().push_back(impl::Handler { type, command, queryCallback, displayCallback });
|
||||
}
|
||||
|
||||
namespace impl {
|
||||
@@ -295,11 +455,11 @@ namespace hex {
|
||||
|
||||
runtime.setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude) | fs::getDefaultPaths(fs::ImHexPath::Patterns));
|
||||
|
||||
for (const auto &func : impl::getFunctions()) {
|
||||
if (func.dangerous)
|
||||
runtime.addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
for (const auto &[ns, name, paramCount, callback, dangerous] : impl::getFunctions()) {
|
||||
if (dangerous)
|
||||
runtime.addDangerousFunction(ns, name, paramCount, callback);
|
||||
else
|
||||
runtime.addFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
runtime.addFunction(ns, name, paramCount, callback);
|
||||
}
|
||||
|
||||
for (const auto &[name, callback] : impl::getPragmas()) {
|
||||
@@ -337,12 +497,12 @@ namespace hex {
|
||||
}
|
||||
|
||||
|
||||
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, u32 parameterCount) {
|
||||
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, pl::api::FunctionParameterCount parameterCount) {
|
||||
log::debug("Registered new pattern visualizer function: {}", name);
|
||||
impl::getVisualizers()[name] = impl::Visualizer { parameterCount, function };
|
||||
}
|
||||
|
||||
void addInlineVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, u32 parameterCount) {
|
||||
void addInlineVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, pl::api::FunctionParameterCount parameterCount) {
|
||||
log::debug("Registered new inline pattern visualizer function: {}", name);
|
||||
impl::getInlineVisualizers()[name] = impl::Visualizer { parameterCount, function };
|
||||
}
|
||||
@@ -350,14 +510,14 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::map<std::string, impl::Visualizer> &getVisualizers() {
|
||||
static std::map<std::string, impl::Visualizer> visualizers;
|
||||
std::map<std::string, Visualizer> &getVisualizers() {
|
||||
static std::map<std::string, Visualizer> visualizers;
|
||||
|
||||
return visualizers;
|
||||
}
|
||||
|
||||
std::map<std::string, impl::Visualizer> &getInlineVisualizers() {
|
||||
static std::map<std::string, impl::Visualizer> visualizers;
|
||||
std::map<std::string, Visualizer> &getInlineVisualizers() {
|
||||
static std::map<std::string, Visualizer> visualizers;
|
||||
|
||||
return visualizers;
|
||||
}
|
||||
@@ -368,8 +528,8 @@ namespace hex {
|
||||
return pragmas;
|
||||
}
|
||||
|
||||
std::vector<impl::FunctionDefinition> &getFunctions() {
|
||||
static std::vector<impl::FunctionDefinition> functions;
|
||||
std::vector<FunctionDefinition> &getFunctions() {
|
||||
static std::vector<FunctionDefinition> functions;
|
||||
|
||||
return functions;
|
||||
}
|
||||
@@ -395,7 +555,7 @@ namespace hex {
|
||||
void impl::add(std::unique_ptr<View> &&view) {
|
||||
log::debug("Registered new view: {}", view->getUnlocalizedName());
|
||||
|
||||
impl::getEntries().insert({ view->getUnlocalizedName(), std::move(view) });
|
||||
getEntries().insert({ view->getUnlocalizedName(), std::move(view) });
|
||||
}
|
||||
|
||||
View* getViewByName(const std::string &unlocalizedName) {
|
||||
@@ -445,8 +605,8 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::vector<impl::Entry> &getEntries() {
|
||||
static std::vector<impl::Entry> entries;
|
||||
std::vector<Entry> &getEntries() {
|
||||
static std::vector<Entry> entries;
|
||||
|
||||
return entries;
|
||||
}
|
||||
@@ -458,7 +618,7 @@ namespace hex {
|
||||
|
||||
namespace ContentRegistry::DataProcessorNode {
|
||||
|
||||
void impl::add(const impl::Entry &entry) {
|
||||
void impl::add(const Entry &entry) {
|
||||
log::debug("Registered new data processor node type: [{}]: {}", entry.category, entry.name);
|
||||
|
||||
getEntries().push_back(entry);
|
||||
@@ -470,8 +630,8 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::vector<impl::Entry> &getEntries() {
|
||||
static std::vector<impl::Entry> nodes;
|
||||
std::vector<Entry> &getEntries() {
|
||||
static std::vector<Entry> nodes;
|
||||
|
||||
return nodes;
|
||||
}
|
||||
@@ -505,7 +665,7 @@ namespace hex {
|
||||
const auto &fallback = data["fallback"];
|
||||
|
||||
if (fallback.is_boolean() && fallback.get<bool>())
|
||||
LangEntry::setFallbackLanguage(code.get<std::string>());
|
||||
LocalizationManager::impl::setFallbackLanguage(code.get<std::string>());
|
||||
}
|
||||
|
||||
impl::getLanguages().insert({ code.get<std::string>(), hex::format("{} ({})", language.get<std::string>(), country.get<std::string>()) });
|
||||
@@ -531,8 +691,8 @@ namespace hex {
|
||||
return languages;
|
||||
}
|
||||
|
||||
std::map<std::string, std::vector<LanguageDefinition>> &getLanguageDefinitions() {
|
||||
static std::map<std::string, std::vector<LanguageDefinition>> definitions;
|
||||
std::map<std::string, std::vector<LocalizationManager::LanguageDefinition>> &getLanguageDefinitions() {
|
||||
static std::map<std::string, std::vector<LocalizationManager::LanguageDefinition>> definitions;
|
||||
|
||||
return definitions;
|
||||
}
|
||||
@@ -554,13 +714,15 @@ namespace hex {
|
||||
log::debug("Added new menu item to menu {} with priority {}", wolv::util::combineStrings(unlocalizedMainMenuNames, " -> "), priority);
|
||||
|
||||
impl::getMenuItems().insert({
|
||||
priority, { unlocalizedMainMenuNames, shortcut, function, enabledCallback }
|
||||
priority, impl::MenuItem { unlocalizedMainMenuNames, std::make_unique<Shortcut>(shortcut), view, function, enabledCallback }
|
||||
});
|
||||
|
||||
if (shortcut.isLocal() && view != nullptr)
|
||||
ShortcutManager::addShortcut(view, shortcut, function);
|
||||
else
|
||||
ShortcutManager::addGlobalShortcut(shortcut, function);
|
||||
if (shortcut != Shortcut::None) {
|
||||
if (shortcut.isLocal() && view != nullptr)
|
||||
ShortcutManager::addShortcut(view, shortcut, unlocalizedMainMenuNames.back(), function);
|
||||
else
|
||||
ShortcutManager::addGlobalShortcut(shortcut, unlocalizedMainMenuNames.back(), function);
|
||||
}
|
||||
}
|
||||
|
||||
void addMenuItemSubMenu(std::vector<std::string> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback) {
|
||||
@@ -568,14 +730,14 @@ namespace hex {
|
||||
|
||||
unlocalizedMainMenuNames.emplace_back(impl::SubMenuValue);
|
||||
impl::getMenuItems().insert({
|
||||
priority, { unlocalizedMainMenuNames, {}, function, enabledCallback }
|
||||
priority, impl::MenuItem { unlocalizedMainMenuNames, std::make_unique<Shortcut>(), nullptr, function, enabledCallback }
|
||||
});
|
||||
}
|
||||
|
||||
void addMenuItemSeparator(std::vector<std::string> unlocalizedMainMenuNames, u32 priority) {
|
||||
unlocalizedMainMenuNames.emplace_back(impl::SeparatorValue);
|
||||
impl::getMenuItems().insert({
|
||||
priority, { unlocalizedMainMenuNames, {}, []{}, []{ return true; } }
|
||||
priority, impl::MenuItem { unlocalizedMainMenuNames, std::make_unique<Shortcut>(), nullptr, []{}, []{ return true; } }
|
||||
});
|
||||
}
|
||||
|
||||
@@ -591,8 +753,8 @@ namespace hex {
|
||||
impl::getToolbarItems().push_back(function);
|
||||
}
|
||||
|
||||
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function) {
|
||||
impl::getSidebarItems().push_back({ icon, function });
|
||||
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function, const impl::EnabledCallback &enabledCallback) {
|
||||
impl::getSidebarItems().push_back({ icon, function, enabledCallback });
|
||||
}
|
||||
|
||||
void addTitleBarButton(const std::string &icon, const std::string &unlocalizedTooltip, const impl::ClickCallback &function) {
|
||||
@@ -601,39 +763,39 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::multimap<u32, impl::MainMenuItem> &getMainMenuItems() {
|
||||
static std::multimap<u32, impl::MainMenuItem> items;
|
||||
std::multimap<u32, MainMenuItem> &getMainMenuItems() {
|
||||
static std::multimap<u32, MainMenuItem> items;
|
||||
|
||||
return items;
|
||||
}
|
||||
std::multimap<u32, impl::MenuItem> &getMenuItems() {
|
||||
static std::multimap<u32, impl::MenuItem> items;
|
||||
std::multimap<u32, MenuItem> &getMenuItems() {
|
||||
static std::multimap<u32, MenuItem> items;
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
std::vector<impl::DrawCallback> &getWelcomeScreenEntries() {
|
||||
static std::vector<impl::DrawCallback> entries;
|
||||
std::vector<DrawCallback> &getWelcomeScreenEntries() {
|
||||
static std::vector<DrawCallback> entries;
|
||||
|
||||
return entries;
|
||||
}
|
||||
std::vector<impl::DrawCallback> &getFooterItems() {
|
||||
static std::vector<impl::DrawCallback> items;
|
||||
std::vector<DrawCallback> &getFooterItems() {
|
||||
static std::vector<DrawCallback> items;
|
||||
|
||||
return items;
|
||||
}
|
||||
std::vector<impl::DrawCallback> &getToolbarItems() {
|
||||
static std::vector<impl::DrawCallback> items;
|
||||
std::vector<DrawCallback> &getToolbarItems() {
|
||||
static std::vector<DrawCallback> items;
|
||||
|
||||
return items;
|
||||
}
|
||||
std::vector<impl::SidebarItem> &getSidebarItems() {
|
||||
static std::vector<impl::SidebarItem> items;
|
||||
std::vector<SidebarItem> &getSidebarItems() {
|
||||
static std::vector<SidebarItem> items;
|
||||
|
||||
return items;
|
||||
}
|
||||
std::vector<impl::TitleBarButton> &getTitleBarButtons() {
|
||||
static std::vector<impl::TitleBarButton> buttons;
|
||||
std::vector<TitleBarButton> &getTitleBarButtons() {
|
||||
static std::vector<TitleBarButton> buttons;
|
||||
|
||||
return buttons;
|
||||
}
|
||||
@@ -644,21 +806,33 @@ namespace hex {
|
||||
|
||||
namespace ContentRegistry::Provider {
|
||||
|
||||
void impl::addProviderName(const std::string &unlocalizedName) {
|
||||
log::debug("Registered new provider: {}", unlocalizedName);
|
||||
|
||||
getEntries().push_back(unlocalizedName);
|
||||
}
|
||||
|
||||
|
||||
namespace impl {
|
||||
|
||||
void add(const std::string &typeName, ProviderCreationFunction creationFunction) {
|
||||
(void)EventManager::subscribe<RequestCreateProvider>([expectedName = typeName, creationFunction](const std::string &name, bool skipLoadInterface, bool selectProvider, prv::Provider **provider) {
|
||||
if (name != expectedName) return;
|
||||
|
||||
prv::Provider *newProvider = creationFunction();
|
||||
|
||||
ImHexApi::Provider::add(newProvider, skipLoadInterface, selectProvider);
|
||||
|
||||
if (provider != nullptr)
|
||||
*provider = newProvider;
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<std::string> &getEntries() {
|
||||
static std::vector<std::string> providerNames;
|
||||
|
||||
return providerNames;
|
||||
}
|
||||
|
||||
void addProviderName(const std::string &unlocalizedName) {
|
||||
log::debug("Registered new provider: {}", unlocalizedName);
|
||||
|
||||
getEntries().push_back(unlocalizedName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -674,8 +848,8 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::vector<impl::Entry> &getEntries() {
|
||||
static std::vector<impl::Entry> entries;
|
||||
std::vector<Entry> &getEntries() {
|
||||
static std::vector<Entry> entries;
|
||||
|
||||
return entries;
|
||||
}
|
||||
@@ -695,8 +869,8 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::vector<impl::Entry> &getEntries() {
|
||||
static std::vector<impl::Entry> entries;
|
||||
std::vector<Entry> &getEntries() {
|
||||
static std::vector<Entry> entries;
|
||||
|
||||
return entries;
|
||||
}
|
||||
@@ -725,8 +899,8 @@ namespace hex {
|
||||
};
|
||||
|
||||
ImGui::PushID(reinterpret_cast<void*>(address));
|
||||
ImGui::InputScalarCallback("##editing_input", dataType, data, format, flags | TextInputFlags | ImGuiInputTextFlags_CallbackEdit, [](ImGuiInputTextCallbackData *data) -> int {
|
||||
auto &userData = *reinterpret_cast<UserData*>(data->UserData);
|
||||
ImGuiExt::InputScalarCallback("##editing_input", dataType, data, format, flags | TextInputFlags | ImGuiInputTextFlags_CallbackEdit, [](ImGuiInputTextCallbackData *data) -> int {
|
||||
auto &userData = *static_cast<UserData*>(data->UserData);
|
||||
|
||||
if (data->BufTextLen >= userData.maxChars)
|
||||
userData.editingDone = true;
|
||||
@@ -755,7 +929,7 @@ namespace hex {
|
||||
|
||||
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);
|
||||
auto &userData = *static_cast<UserData*>(data->UserData);
|
||||
|
||||
userData.data->resize(data->BufSize);
|
||||
|
||||
@@ -830,7 +1004,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
for (auto &service : getServices()) {
|
||||
service.thread.detach();
|
||||
if (service.thread.joinable())
|
||||
service.thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -841,7 +1016,7 @@ namespace hex {
|
||||
|
||||
impl::getServices().push_back(impl::Service {
|
||||
unlocalizedName,
|
||||
std::jthread([callback](const std::stop_token &stopToken){
|
||||
std::jthread([callback = auto(callback)](const std::stop_token &stopToken){
|
||||
while (!stopToken.stop_requested()) {
|
||||
callback();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
@@ -872,4 +1047,92 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
namespace ContentRegistry::Experiments {
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::map<std::string, Experiment> &getExperiments() {
|
||||
static std::map<std::string, Experiment> experiments;
|
||||
|
||||
return experiments;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void addExperiment(const std::string &experimentName, const std::string &unlocalizedName, const std::string &unlocalizedDescription) {
|
||||
auto &experiments = impl::getExperiments();
|
||||
|
||||
if (experiments.contains(experimentName)) {
|
||||
log::error("Experiment with name '{}' already exists!", experimentName);
|
||||
return;
|
||||
}
|
||||
|
||||
experiments[experimentName] = impl::Experiment {
|
||||
.unlocalizedName = unlocalizedName,
|
||||
.unlocalizedDescription = unlocalizedDescription,
|
||||
.enabled = false
|
||||
};
|
||||
}
|
||||
|
||||
void enableExperiement(const std::string &experimentName, bool enabled) {
|
||||
auto &experiments = impl::getExperiments();
|
||||
|
||||
if (!experiments.contains(experimentName)) {
|
||||
log::error("Experiment with name '{}' does not exist!", experimentName);
|
||||
return;
|
||||
}
|
||||
|
||||
experiments[experimentName].enabled = enabled;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isExperimentEnabled(const std::string &experimentName) {
|
||||
auto &experiments = impl::getExperiments();
|
||||
|
||||
if (!experiments.contains(experimentName)) {
|
||||
log::error("Experiment with name '{}' does not exist!", experimentName);
|
||||
return false;
|
||||
}
|
||||
|
||||
return experiments[experimentName].enabled;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace ContentRegistry::Reports {
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::vector<ReportGenerator> &getGenerators() {
|
||||
static std::vector<ReportGenerator> generators;
|
||||
|
||||
return generators;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void addReportProvider(impl::Callback callback) {
|
||||
impl::getGenerators().push_back(impl::ReportGenerator { std::move(callback ) });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace ContentRegistry::Disassembler {
|
||||
|
||||
namespace impl {
|
||||
|
||||
|
||||
std::vector<std::unique_ptr<Architecture>>& getArchitectures() {
|
||||
static std::vector<std::unique_ptr<Architecture>> architectures;
|
||||
|
||||
return architectures;
|
||||
}
|
||||
|
||||
void add(std::unique_ptr<Architecture> &&architecture) {
|
||||
getArchitectures().emplace_back(std::move(architecture));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
#include <hex/api/event.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
std::map<void *, EventManager::EventList::iterator>& EventManager::getTokenStore() {
|
||||
static std::map<void *, EventManager::EventList::iterator> tokenStore;
|
||||
|
||||
return tokenStore;
|
||||
}
|
||||
|
||||
EventManager::EventList& EventManager::getEvents() {
|
||||
static EventManager::EventList events;
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
24
lib/libimhex/source/api/event_manager.cpp
Normal file
24
lib/libimhex/source/api/event_manager.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include <hex/api/event_manager.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
std::multimap<void *, EventManager::EventList::iterator>& EventManager::getTokenStore() {
|
||||
static std::multimap<void *, EventManager::EventList::iterator> tokenStore;
|
||||
|
||||
return tokenStore;
|
||||
}
|
||||
|
||||
EventManager::EventList& EventManager::getEvents() {
|
||||
static EventManager::EventList events;
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
std::recursive_mutex& EventManager::getEventMutex() {
|
||||
static std::recursive_mutex mutex;
|
||||
|
||||
return mutex;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,24 +1,22 @@
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <hex/api/event.hpp>
|
||||
#include <hex/api/task.hpp>
|
||||
#include <hex/api/event_manager.hpp>
|
||||
#include <hex/api/task_manager.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
#include <utility>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <imgui_internal.h>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#else
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
@@ -69,7 +67,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
static std::optional<ProviderRegion> s_currentSelection;
|
||||
void setCurrentSelection(std::optional<ProviderRegion> region) {
|
||||
void setCurrentSelection(const std::optional<ProviderRegion> ®ion) {
|
||||
s_currentSelection = region;
|
||||
}
|
||||
|
||||
@@ -204,12 +202,19 @@ namespace hex {
|
||||
|
||||
namespace ImHexApi::Bookmarks {
|
||||
|
||||
void add(Region region, const std::string &name, const std::string &comment, u32 color) {
|
||||
EventManager::post<RequestAddBookmark>(region, name, comment, color);
|
||||
u64 add(Region region, const std::string &name, const std::string &comment, u32 color) {
|
||||
u64 id = 0;
|
||||
EventManager::post<RequestAddBookmark>(region, name, comment, color, &id);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void add(u64 address, size_t size, const std::string &name, const std::string &comment, u32 color) {
|
||||
add(Region { address, size }, name, comment, color);
|
||||
u64 add(u64 address, size_t size, const std::string &name, const std::string &comment, u32 color) {
|
||||
return add(Region { address, size }, name, comment, color);
|
||||
}
|
||||
|
||||
void remove(u64 id) {
|
||||
EventManager::post<RequestRemoveBookmark>(id);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -222,13 +227,13 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
static prv::Provider *s_closingProvider = nullptr;
|
||||
static std::vector<prv::Provider*> s_closingProviders;
|
||||
void resetClosingProvider() {
|
||||
s_closingProvider = nullptr;
|
||||
s_closingProviders.clear();
|
||||
}
|
||||
|
||||
prv::Provider* getClosingProvider() {
|
||||
return s_closingProvider;
|
||||
const std::vector<prv::Provider*>& getClosingProviders() {
|
||||
return s_closingProviders;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -300,7 +305,7 @@ namespace hex {
|
||||
return;
|
||||
|
||||
if (!noQuestions) {
|
||||
impl::s_closingProvider = provider;
|
||||
impl::s_closingProviders.push_back(provider);
|
||||
|
||||
bool shouldClose = true;
|
||||
EventManager::post<EventProviderClosing>(provider, &shouldClose);
|
||||
@@ -312,10 +317,38 @@ namespace hex {
|
||||
if (it == s_providers.end())
|
||||
return;
|
||||
|
||||
if (!s_providers.empty() && it - s_providers.begin() == s_currentProvider)
|
||||
setCurrentProvider(0);
|
||||
if (!s_providers.empty()) {
|
||||
if (it == s_providers.begin()) {
|
||||
// If the first provider is being closed, select the one that's the first one now
|
||||
setCurrentProvider(0);
|
||||
}
|
||||
else if (std::distance(s_providers.begin(), it) == s_currentProvider) {
|
||||
// If the current provider is being closed, select the one that's before it
|
||||
setCurrentProvider(s_currentProvider - 1);
|
||||
}
|
||||
else {
|
||||
// If any other provider is being closed, find the current provider in the list again and select it again
|
||||
auto currentProvider = get();
|
||||
auto currentIt = std::find(s_providers.begin(), s_providers.end(), currentProvider);
|
||||
|
||||
if (currentIt != s_providers.end()) {
|
||||
auto newIndex = std::distance(s_providers.begin(), currentIt);
|
||||
|
||||
if (s_currentProvider == newIndex)
|
||||
newIndex -= 1;
|
||||
|
||||
setCurrentProvider(newIndex);
|
||||
} else {
|
||||
// If the current provider is not in the list anymore, select the first one
|
||||
setCurrentProvider(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s_providers.erase(it);
|
||||
if (s_currentProvider >= i64(s_providers.size()))
|
||||
setCurrentProvider(0);
|
||||
|
||||
if (s_providers.empty())
|
||||
EventManager::post<EventProviderChanged>(provider, nullptr);
|
||||
|
||||
@@ -324,6 +357,7 @@ namespace hex {
|
||||
|
||||
TaskManager::runWhenTasksFinished([provider] {
|
||||
EventManager::post<EventProviderDeleted>(provider);
|
||||
std::erase(impl::s_closingProviders, provider);
|
||||
delete provider;
|
||||
});
|
||||
}
|
||||
@@ -342,7 +376,7 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
// default to true means we forward to ourselves by default
|
||||
// Default to true means we forward to ourselves by default
|
||||
static bool s_isMainInstance = true;
|
||||
|
||||
void setMainInstanceStatus(bool status) {
|
||||
@@ -381,15 +415,6 @@ namespace hex {
|
||||
s_borderlessWindowMode = enabled;
|
||||
}
|
||||
|
||||
static std::fs::path s_customFontPath;
|
||||
void setCustomFontPath(const std::fs::path &path) {
|
||||
s_customFontPath = path;
|
||||
}
|
||||
|
||||
static float s_fontSize = DefaultFontSize;
|
||||
void setFontSize(float size) {
|
||||
s_fontSize = size;
|
||||
}
|
||||
|
||||
static std::string s_gpuVendor;
|
||||
void setGPUVendor(const std::string &vendor) {
|
||||
@@ -448,7 +473,10 @@ namespace hex {
|
||||
|
||||
|
||||
ImVec2 getMainWindowPosition() {
|
||||
return impl::s_mainWindowPos;
|
||||
if ((ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) != ImGuiConfigFlags_None)
|
||||
return impl::s_mainWindowPos;
|
||||
else
|
||||
return { 0, 0 };
|
||||
}
|
||||
|
||||
ImVec2 getMainWindowSize() {
|
||||
@@ -470,18 +498,8 @@ namespace hex {
|
||||
return initArgs;
|
||||
}
|
||||
|
||||
std::fs::path &getCustomFontPath() {
|
||||
return impl::s_customFontPath;
|
||||
}
|
||||
|
||||
float getFontSize() {
|
||||
return impl::s_fontSize;
|
||||
}
|
||||
|
||||
|
||||
static bool s_systemThemeDetection;
|
||||
|
||||
|
||||
void enableSystemThemeDetection(bool enabled) {
|
||||
s_systemThemeDetection = enabled;
|
||||
|
||||
@@ -519,6 +537,8 @@ namespace hex {
|
||||
return "Linux";
|
||||
#elif defined(OS_MACOS)
|
||||
return "macOS";
|
||||
#elif defined(OS_WEB)
|
||||
return "Web";
|
||||
#else
|
||||
return "Unknown";
|
||||
#endif
|
||||
@@ -531,7 +551,7 @@ namespace hex {
|
||||
::GetVersionExA(&info);
|
||||
|
||||
return hex::format("{}.{}.{}", info.dwMajorVersion, info.dwMinorVersion, info.dwBuildNumber);
|
||||
#elif defined(OS_LINUX) || defined(OS_MACOS)
|
||||
#elif defined(OS_LINUX) || defined(OS_MACOS) || defined(OS_WEB)
|
||||
struct utsname details;
|
||||
|
||||
if (uname(&details) != 0) {
|
||||
@@ -563,7 +583,7 @@ namespace hex {
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
#elif defined(OS_LINUX) || defined(OS_MACOS)
|
||||
#elif defined(OS_LINUX) || defined(OS_MACOS) || defined(OS_WEB)
|
||||
struct utsname details;
|
||||
|
||||
if (uname(&details) != 0) {
|
||||
@@ -576,9 +596,14 @@ namespace hex {
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string getImHexVersion() {
|
||||
std::string getImHexVersion(bool withBuildType) {
|
||||
#if defined IMHEX_VERSION
|
||||
return IMHEX_VERSION;
|
||||
if (withBuildType)
|
||||
return IMHEX_VERSION;
|
||||
else {
|
||||
auto version = std::string(IMHEX_VERSION);
|
||||
return version.substr(0, version.find('-'));
|
||||
}
|
||||
#else
|
||||
return "Unknown";
|
||||
#endif
|
||||
@@ -609,6 +634,56 @@ namespace hex {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isDebugBuild() {
|
||||
#if defined DEBUG
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool updateImHex(UpdateType updateType) {
|
||||
// Get the path of the updater executable
|
||||
std::fs::path executablePath;
|
||||
|
||||
for (const auto &entry : std::fs::directory_iterator(wolv::io::fs::getExecutablePath()->parent_path())) {
|
||||
if (entry.path().filename().string().starts_with("imhex-updater")) {
|
||||
executablePath = entry.path();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (executablePath.empty() || !wolv::io::fs::exists(executablePath))
|
||||
return false;
|
||||
|
||||
std::string updateTypeString;
|
||||
switch (updateType) {
|
||||
case UpdateType::Stable:
|
||||
updateTypeString = "latest";
|
||||
break;
|
||||
case UpdateType::Nightly:
|
||||
updateTypeString = "nightly";
|
||||
break;
|
||||
}
|
||||
|
||||
EventManager::subscribe<EventImHexClosing>([executablePath, updateTypeString] {
|
||||
hex::executeCommand(
|
||||
hex::format("{} {}",
|
||||
wolv::util::toUTF8String(executablePath),
|
||||
updateTypeString
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
ImHexApi::System::closeImHex();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void addStartupTask(const std::string &name, bool async, const std::function<bool()> &function) {
|
||||
EventManager::post<RequestAddInitTask>(name, async, function);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace ImHexApi::Messaging {
|
||||
@@ -643,4 +718,121 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
namespace ImHexApi::Fonts {
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::vector<Font>& getFonts() {
|
||||
static std::vector<Font> fonts;
|
||||
|
||||
return fonts;
|
||||
}
|
||||
|
||||
static std::fs::path s_customFontPath;
|
||||
void setCustomFontPath(const std::fs::path &path) {
|
||||
s_customFontPath = path;
|
||||
}
|
||||
|
||||
static float s_fontSize = DefaultFontSize;
|
||||
void setFontSize(float size) {
|
||||
s_fontSize = size;
|
||||
}
|
||||
|
||||
static std::unique_ptr<ImFontAtlas> s_fontAtlas;
|
||||
void setFontAtlas(ImFontAtlas* fontAtlas) {
|
||||
s_fontAtlas = std::unique_ptr<ImFontAtlas>(fontAtlas);
|
||||
}
|
||||
|
||||
static ImFont *s_boldFont = nullptr;
|
||||
static ImFont *s_italicFont = nullptr;
|
||||
void setFonts(ImFont *bold, ImFont *italic) {
|
||||
s_boldFont = bold;
|
||||
s_italicFont = italic;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
GlyphRange glyph(const char *glyph) {
|
||||
u32 codepoint;
|
||||
ImTextCharFromUtf8(&codepoint, glyph, nullptr);
|
||||
|
||||
return {
|
||||
.begin = u16(codepoint),
|
||||
.end = u16(codepoint)
|
||||
};
|
||||
}
|
||||
GlyphRange glyph(u32 codepoint) {
|
||||
return {
|
||||
.begin = u16(codepoint),
|
||||
.end = u16(codepoint)
|
||||
};
|
||||
}
|
||||
GlyphRange range(const char *glyphBegin, const char *glyphEnd) {
|
||||
u32 codepointBegin, codepointEnd;
|
||||
ImTextCharFromUtf8(&codepointBegin, glyphBegin, nullptr);
|
||||
ImTextCharFromUtf8(&codepointEnd, glyphEnd, nullptr);
|
||||
|
||||
return {
|
||||
.begin = u16(codepointBegin),
|
||||
.end = u16(codepointEnd)
|
||||
};
|
||||
}
|
||||
|
||||
GlyphRange range(u32 codepointBegin, u32 codepointEnd) {
|
||||
return {
|
||||
.begin = u16(codepointBegin),
|
||||
.end = u16(codepointEnd)
|
||||
};
|
||||
}
|
||||
|
||||
void loadFont(const std::fs::path &path, const std::vector<GlyphRange> &glyphRanges, Offset offset, u32 flags) {
|
||||
wolv::io::File fontFile(path, wolv::io::File::Mode::Read);
|
||||
if (!fontFile.isValid()) {
|
||||
log::error("Failed to load font from file '{}'", wolv::util::toUTF8String(path));
|
||||
return;
|
||||
}
|
||||
|
||||
impl::getFonts().emplace_back(Font {
|
||||
wolv::util::toUTF8String(path.filename()),
|
||||
fontFile.readVector(),
|
||||
glyphRanges,
|
||||
offset,
|
||||
flags
|
||||
});
|
||||
}
|
||||
|
||||
void loadFont(const std::string &name, const std::span<const u8> &data, const std::vector<GlyphRange> &glyphRanges, Offset offset, u32 flags) {
|
||||
impl::getFonts().emplace_back(Font {
|
||||
name,
|
||||
{ data.begin(), data.end() },
|
||||
glyphRanges,
|
||||
offset,
|
||||
flags
|
||||
});
|
||||
}
|
||||
|
||||
std::fs::path &getCustomFontPath() {
|
||||
return impl::s_customFontPath;
|
||||
}
|
||||
|
||||
float getFontSize() {
|
||||
return impl::s_fontSize;
|
||||
}
|
||||
|
||||
ImFontAtlas* getFontAtlas() {
|
||||
return impl::s_fontAtlas.get();
|
||||
}
|
||||
|
||||
ImFont* Bold() {
|
||||
return impl::s_boldFont;
|
||||
}
|
||||
|
||||
ImFont* Italic() {
|
||||
return impl::s_italicFont;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
#include <hex/api/keybinding.hpp>
|
||||
#include <imgui.h>
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace {
|
||||
|
||||
std::map<Shortcut, std::function<void()>> s_globalShortcuts;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const std::function<void()> &callback) {
|
||||
s_globalShortcuts.insert({ shortcut, callback });
|
||||
}
|
||||
|
||||
void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const std::function<void()> &callback) {
|
||||
view->m_shortcuts.insert({ shortcut + CurrentView, callback });
|
||||
}
|
||||
|
||||
static Shortcut getShortcut(bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode) {
|
||||
Shortcut pressedShortcut;
|
||||
|
||||
if (ctrl)
|
||||
pressedShortcut += CTRL;
|
||||
if (alt)
|
||||
pressedShortcut += ALT;
|
||||
if (shift)
|
||||
pressedShortcut += SHIFT;
|
||||
if (super)
|
||||
pressedShortcut += SUPER;
|
||||
if (focused)
|
||||
pressedShortcut += CurrentView;
|
||||
|
||||
pressedShortcut += static_cast<Keys>(keyCode);
|
||||
|
||||
return pressedShortcut;
|
||||
}
|
||||
|
||||
void ShortcutManager::process(const std::unique_ptr<View> ¤tView, bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode) {
|
||||
Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, focused, keyCode);
|
||||
|
||||
if (currentView->m_shortcuts.contains(pressedShortcut + AllowWhileTyping)) {
|
||||
currentView->m_shortcuts[pressedShortcut + AllowWhileTyping]();
|
||||
} else if (currentView->m_shortcuts.contains(pressedShortcut)) {
|
||||
if (!ImGui::GetIO().WantTextInput)
|
||||
currentView->m_shortcuts[pressedShortcut]();
|
||||
}
|
||||
}
|
||||
|
||||
void ShortcutManager::processGlobals(bool ctrl, bool alt, bool shift, bool super, u32 keyCode) {
|
||||
Shortcut pressedShortcut = getShortcut(ctrl, alt, shift, super, false, keyCode);
|
||||
|
||||
if (s_globalShortcuts.contains(pressedShortcut + AllowWhileTyping)) {
|
||||
s_globalShortcuts[pressedShortcut + AllowWhileTyping]();
|
||||
} else if (s_globalShortcuts.contains(pressedShortcut)) {
|
||||
if (!ImGui::GetIO().WantTextInput)
|
||||
s_globalShortcuts[pressedShortcut]();
|
||||
}
|
||||
}
|
||||
|
||||
void ShortcutManager::clearShortcuts() {
|
||||
s_globalShortcuts.clear();
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user