mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-28 07:47:03 -05:00
Compare commits
486 Commits
v1.33.2
...
releases/v
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
811214ddb7 | ||
|
|
cb406ea357 | ||
|
|
edb1a8876b | ||
|
|
2757075a10 | ||
|
|
8a4599feea | ||
|
|
f8f47012c4 | ||
|
|
32e2ccbca0 | ||
|
|
4d1e29d747 | ||
|
|
22dc3c6589 | ||
|
|
1c2bb0c049 | ||
|
|
5d53417683 | ||
|
|
c79321b550 | ||
|
|
0785270dfa | ||
|
|
84999d5c06 | ||
|
|
a0ca0e8596 | ||
|
|
1d99f8534d | ||
|
|
cfbc6e085a | ||
|
|
a45d30edca | ||
|
|
5a053aa146 | ||
|
|
d5a69d9201 | ||
|
|
dd0204f31d | ||
|
|
3b799388c2 | ||
|
|
c7c4ecad6d | ||
|
|
6784678ff0 | ||
|
|
dd8e7025d0 | ||
|
|
c2f661f021 | ||
|
|
c6fc26e2e7 | ||
|
|
3a99d53ba5 | ||
|
|
5fced6bb63 | ||
|
|
67930cf65d | ||
|
|
b305adb286 | ||
|
|
cbcf7b78e9 | ||
|
|
c922d9ceec | ||
|
|
ad235fad25 | ||
|
|
dffb7e95e3 | ||
|
|
916c1b7d4b | ||
|
|
2743b04f50 | ||
|
|
dbe8bfd75f | ||
|
|
c6c599c75b | ||
|
|
c2b7b4a11e | ||
|
|
495255484e | ||
|
|
b92b0922d5 | ||
|
|
ac1a28311c | ||
|
|
01d1938fea | ||
|
|
802694ec68 | ||
|
|
2aef5e4eef | ||
|
|
9a0a4d47dc | ||
|
|
96b7366d53 | ||
|
|
90ac96298a | ||
|
|
a6e5040e8f | ||
|
|
19e5aafc85 | ||
|
|
77301fd018 | ||
|
|
ed56b3dd12 | ||
|
|
91f6aae9ef | ||
|
|
b642c493d7 | ||
|
|
a950796306 | ||
|
|
8672a2cfe0 | ||
|
|
301e8c5a96 | ||
|
|
699a91c46b | ||
|
|
e43016735d | ||
|
|
d9cecbbb5f | ||
|
|
6e186e7d6a | ||
|
|
af3680649c | ||
|
|
82f1d08dd7 | ||
|
|
b1b54a5fe7 | ||
|
|
ced3af3935 | ||
|
|
e5c782ebe9 | ||
|
|
7d42742684 | ||
|
|
41820311cc | ||
|
|
e132adad5d | ||
|
|
2132e5adbf | ||
|
|
e2d55446fe | ||
|
|
1dfce6a5c2 | ||
|
|
a84db9821c | ||
|
|
ec080ad69f | ||
|
|
75cc9e4d84 | ||
|
|
d241a3ed5f | ||
|
|
682aab8b23 | ||
|
|
474862b4af | ||
|
|
dd02ec7a8e | ||
|
|
1eadb77722 | ||
|
|
95f71bcb10 | ||
|
|
e1a4707569 | ||
|
|
5a10613dd2 | ||
|
|
c6a569ed88 | ||
|
|
de24453fb9 | ||
|
|
d7c5c84110 | ||
|
|
95166ccfb8 | ||
|
|
c56667b0dd | ||
|
|
f754560bca | ||
|
|
b54bb6cd56 | ||
|
|
b03b159907 | ||
|
|
bb7e6c9775 | ||
|
|
4bc724791d | ||
|
|
ba7c10f4b1 | ||
|
|
c1561c7b6a | ||
|
|
91a0be2d78 | ||
|
|
1f27530241 | ||
|
|
e236872af3 | ||
|
|
3d301c4202 | ||
|
|
a5aaa60d29 | ||
|
|
d4a2de3b23 | ||
|
|
e85746ddba | ||
|
|
a002eb1bc1 | ||
|
|
7d4486f407 | ||
|
|
a9915579a0 | ||
|
|
65dfd4da0f | ||
|
|
b93fd523aa | ||
|
|
24621e6612 | ||
|
|
1b383bdcf1 | ||
|
|
f47b357b23 | ||
|
|
f9b778ecb8 | ||
|
|
f36d9831bb | ||
|
|
b60a262b58 | ||
|
|
beef0fff33 | ||
|
|
24f535474a | ||
|
|
2e3f523f32 | ||
|
|
c5f5973a9d | ||
|
|
5d59b8599d | ||
|
|
3bfb0096e6 | ||
|
|
ca5763650b | ||
|
|
bf7beab0ab | ||
|
|
9b594d81bd | ||
|
|
6a26c6002b | ||
|
|
4fa64500af | ||
|
|
085737af15 | ||
|
|
3e347fb6d4 | ||
|
|
80cb126200 | ||
|
|
f49715c7a0 | ||
|
|
deee76e455 | ||
|
|
33885b863a | ||
|
|
3ce9dbb278 | ||
|
|
bee4b906fb | ||
|
|
b3b79b3ee8 | ||
|
|
bd085dd495 | ||
|
|
bf518b3590 | ||
|
|
32a8fcb84d | ||
|
|
4fd65403c0 | ||
|
|
ecf871a6f1 | ||
|
|
531c049bb0 | ||
|
|
99716eff1e | ||
|
|
74205d5438 | ||
|
|
0136877978 | ||
|
|
fb7d40ddbe | ||
|
|
c761054805 | ||
|
|
55e24b5e23 | ||
|
|
9cff5b8af4 | ||
|
|
41b2523005 | ||
|
|
2ef256ee74 | ||
|
|
e954d49c29 | ||
|
|
041bf47ff4 | ||
|
|
53ced98529 | ||
|
|
cb475c471d | ||
|
|
bf82690c80 | ||
|
|
72a3a1acab | ||
|
|
18e2b0eaa2 | ||
|
|
b80a6152b3 | ||
|
|
ffe3dae7b2 | ||
|
|
d7845ec690 | ||
|
|
8531a67519 | ||
|
|
af59b9d2ca | ||
|
|
08bb69c048 | ||
|
|
6fb32d20b3 | ||
|
|
ea09bfe8ea | ||
|
|
c0dde570e4 | ||
|
|
6fd3fa77ed | ||
|
|
ff20f81cfd | ||
|
|
de8465a8f4 | ||
|
|
4540e1b561 | ||
|
|
789d469477 | ||
|
|
4797512207 | ||
|
|
348fe27a3c | ||
|
|
c217b1b100 | ||
|
|
0e757e5fb1 | ||
|
|
72d5707d33 | ||
|
|
a491b85737 | ||
|
|
d9d85cbfcc | ||
|
|
283fe46230 | ||
|
|
2c00aa5def | ||
|
|
984438e98d | ||
|
|
cf34c4bd95 | ||
|
|
bab1d2e27e | ||
|
|
d1b6a21e86 | ||
|
|
3049590b68 | ||
|
|
8a289d2e4f | ||
|
|
7a81fa7ac5 | ||
|
|
fbf59b6f0b | ||
|
|
0ab200f77f | ||
|
|
a91e40d731 | ||
|
|
e553fbc86c | ||
|
|
b4a810c374 | ||
|
|
0e97914d94 | ||
|
|
a5c250c811 | ||
|
|
08c2f3fc15 | ||
|
|
63f66662ce | ||
|
|
89eee104ab | ||
|
|
92b1234ddb | ||
|
|
0b0bf90e0b | ||
|
|
974c4ba040 | ||
|
|
4e2c1d20b4 | ||
|
|
e5b83d0ddf | ||
|
|
bdaf1e4151 | ||
|
|
751eff0edf | ||
|
|
666dc7dccb | ||
|
|
a172e89620 | ||
|
|
ecb9537c4e | ||
|
|
bba4cf9578 | ||
|
|
bfdb9b4019 | ||
|
|
bad37d0940 | ||
|
|
62f5640678 | ||
|
|
71c1bcde0d | ||
|
|
e9b492a287 | ||
|
|
9b9b1aa6cc | ||
|
|
2cb673fd81 | ||
|
|
d5eb6b5bbc | ||
|
|
1e48277566 | ||
|
|
ec748f4a64 | ||
|
|
22f1713739 | ||
|
|
f0e135530a | ||
|
|
125d6a3e2a | ||
|
|
d078f9d847 | ||
|
|
6b6a6ae5f0 | ||
|
|
1d6676f059 | ||
|
|
1e91505e6e | ||
|
|
9e2f228d9a | ||
|
|
7a1d163450 | ||
|
|
22e717d778 | ||
|
|
2546c042dc | ||
|
|
b54f46de30 | ||
|
|
94bc279bd8 | ||
|
|
2f7c2e79d2 | ||
|
|
2ed5381f5a | ||
|
|
964d98dd7b | ||
|
|
0571dae9b7 | ||
|
|
563bf78f03 | ||
|
|
cf480d95db | ||
|
|
44331506b2 | ||
|
|
f6953fd829 | ||
|
|
663b99ed64 | ||
|
|
0ef3be1851 | ||
|
|
0453a23b12 | ||
|
|
7a14e3dac4 | ||
|
|
275774a10a | ||
|
|
a6277533e8 | ||
|
|
1426424899 | ||
|
|
85fa1b2122 | ||
|
|
c28522b7ef | ||
|
|
d90a04990b | ||
|
|
027ff793ed | ||
|
|
c69d3bc7f4 | ||
|
|
ca17054a1e | ||
|
|
6a9e07729f | ||
|
|
ceeda6de3b | ||
|
|
17ab059b12 | ||
|
|
dedd99f30c | ||
|
|
add94c5926 | ||
|
|
a239edc759 | ||
|
|
ff569417fc | ||
|
|
240bb299f0 | ||
|
|
e2dd12416c | ||
|
|
2a726c7136 | ||
|
|
62aea46c61 | ||
|
|
09bffb6745 | ||
|
|
3c91cb09e3 | ||
|
|
881a379fb4 | ||
|
|
90a67af887 | ||
|
|
d727100304 | ||
|
|
543fcf5447 | ||
|
|
e9b140b75c | ||
|
|
92a9843ef7 | ||
|
|
12528d6e6e | ||
|
|
8fae55487a | ||
|
|
973af4650c | ||
|
|
5f192d5dc7 | ||
|
|
ec39546fed | ||
|
|
ea0cafa229 | ||
|
|
978fa17932 | ||
|
|
6602e800ac | ||
|
|
fdf9209605 | ||
|
|
8a3739ee1c | ||
|
|
89f360d1a7 | ||
|
|
d7ddf991a9 | ||
|
|
19c02be673 | ||
|
|
adbcc48de7 | ||
|
|
a5eb031401 | ||
|
|
10351c5bdc | ||
|
|
5bc60d4b63 | ||
|
|
32a659a477 | ||
|
|
40c4dbc20e | ||
|
|
f2b4e49ff3 | ||
|
|
39dd67af78 | ||
|
|
337ec6bca6 | ||
|
|
2994e69c08 | ||
|
|
49987b8793 | ||
|
|
0f5e125992 | ||
|
|
57857559f5 | ||
|
|
4eba620bee | ||
|
|
964a2e990e | ||
|
|
761bc941a8 | ||
|
|
aa5a3ed080 | ||
|
|
6fbbf899b0 | ||
|
|
1df0eea6c6 | ||
|
|
ef99e9d6f8 | ||
|
|
a685d2e97d | ||
|
|
df04acc1b9 | ||
|
|
f510faa1da | ||
|
|
3ad2c74519 | ||
|
|
0e58204501 | ||
|
|
f847807df5 | ||
|
|
81982aa821 | ||
|
|
08fc393451 | ||
|
|
a7033b68f7 | ||
|
|
3794aa425d | ||
|
|
a1ea8dfd84 | ||
|
|
79e1df1af2 | ||
|
|
fd61e757f0 | ||
|
|
7ec245925a | ||
|
|
f913cd742f | ||
|
|
cc7a0db35c | ||
|
|
6f11873d7e | ||
|
|
4b1b52caf0 | ||
|
|
e9ebfe36b0 | ||
|
|
43149498cf | ||
|
|
43070a1f5b | ||
|
|
f135bd86ac | ||
|
|
0bd8c5d115 | ||
|
|
9de10df90d | ||
|
|
46ed6e2487 | ||
|
|
d81d409051 | ||
|
|
5f75c8684f | ||
|
|
5d08499d20 | ||
|
|
4115184952 | ||
|
|
e6a14977b9 | ||
|
|
a449f7a5e3 | ||
|
|
51302cfd88 | ||
|
|
696612385a | ||
|
|
edf047dde8 | ||
|
|
166cd6c426 | ||
|
|
51010096bb | ||
|
|
4e5a7ba483 | ||
|
|
92803c1536 | ||
|
|
cc593fb6c4 | ||
|
|
aeabc0c436 | ||
|
|
32ad8ddb53 | ||
|
|
f084bc4147 | ||
|
|
cb1dcc2c9f | ||
|
|
8030de7af2 | ||
|
|
dd5ddbcc0f | ||
|
|
f587710d1c | ||
|
|
99142525b6 | ||
|
|
2d9ef1142d | ||
|
|
547169ea78 | ||
|
|
8d08ab20ec | ||
|
|
966a780432 | ||
|
|
99abc4e78a | ||
|
|
ce1d581c3f | ||
|
|
b31ae6e690 | ||
|
|
e984fde966 | ||
|
|
5d0b474a7e | ||
|
|
d09f2c4f26 | ||
|
|
dd20a16d3a | ||
|
|
7d22b71e86 | ||
|
|
567ccbfc3a | ||
|
|
ca40775678 | ||
|
|
4916e5542a | ||
|
|
ac8ec2b622 | ||
|
|
9b9f7e2a1d | ||
|
|
28ea91e6c3 | ||
|
|
0d58307e82 | ||
|
|
c8ca84ede9 | ||
|
|
ed2939c39e | ||
|
|
d36bd253e8 | ||
|
|
4615dce0a9 | ||
|
|
7ce8aa3638 | ||
|
|
9236b92dc1 | ||
|
|
05ffcab911 | ||
|
|
61b9c0970b | ||
|
|
3b3701135f | ||
|
|
f5987fde5a | ||
|
|
e56b34f174 | ||
|
|
0fb43ccc2b | ||
|
|
48db4df028 | ||
|
|
86a0693081 | ||
|
|
6295c1d0c3 | ||
|
|
35d29c8e30 | ||
|
|
ca78c4c2fc | ||
|
|
f276409cde | ||
|
|
682f7bee72 | ||
|
|
43bec6a636 | ||
|
|
6eb9c750a7 | ||
|
|
31c93c8c5c | ||
|
|
5aa1046541 | ||
|
|
0f4504476a | ||
|
|
3897245a7e | ||
|
|
373db3de95 | ||
|
|
a1437658af | ||
|
|
f4ec69021d | ||
|
|
6012f20fb3 | ||
|
|
95da957f73 | ||
|
|
642722bdb1 | ||
|
|
cbc31f3c18 | ||
|
|
f2309ba079 | ||
|
|
246ed15d6d | ||
|
|
88756c83c7 | ||
|
|
cf320266df | ||
|
|
47e7e80afe | ||
|
|
0d880babfb | ||
|
|
28ba34f1bf | ||
|
|
e786cb8180 | ||
|
|
458584d778 | ||
|
|
2c711ea206 | ||
|
|
7b25be51a5 | ||
|
|
45b05a4846 | ||
|
|
6972736abf | ||
|
|
3798654f92 | ||
|
|
fdf01dfb50 | ||
|
|
876f091244 | ||
|
|
2988561f01 | ||
|
|
fbfc319ac1 | ||
|
|
9b1417f32d | ||
|
|
c727762940 | ||
|
|
e3565d5bcb | ||
|
|
a3f550c585 | ||
|
|
c610d804b1 | ||
|
|
3d592dbc79 | ||
|
|
0186f2f456 | ||
|
|
d817a813b0 | ||
|
|
1d219ba511 | ||
|
|
285afb6d4b | ||
|
|
ca3708df71 | ||
|
|
c2aafb14c2 | ||
|
|
d4d1acb555 | ||
|
|
d1a59f8c1b | ||
|
|
2fd17f97b6 | ||
|
|
45a3bdffe0 | ||
|
|
f050c69ccd | ||
|
|
c31a2551f1 | ||
|
|
90e93492a7 | ||
|
|
54266bf63b | ||
|
|
ba12f7aec9 | ||
|
|
deafb6fe08 | ||
|
|
091be1440a | ||
|
|
030aee17f5 | ||
|
|
bbbf836374 | ||
|
|
f1b91ef360 | ||
|
|
f6c59b456f | ||
|
|
8f3f941600 | ||
|
|
e561f49e80 | ||
|
|
2ff884fd11 | ||
|
|
296af748ee | ||
|
|
0cb10fcc34 | ||
|
|
4a67ea0b29 | ||
|
|
8e94acc98f | ||
|
|
39cda3764b | ||
|
|
97f5175c84 | ||
|
|
78f8e5055e | ||
|
|
735d896260 | ||
|
|
cb7a6596ba | ||
|
|
fdaa56fd86 | ||
|
|
667b940feb | ||
|
|
bb3de7d510 | ||
|
|
7bdde15796 | ||
|
|
c412ba66d8 | ||
|
|
dd62bee264 | ||
|
|
f886eac7b5 | ||
|
|
623079ca40 | ||
|
|
ce9bd796d6 | ||
|
|
d5f323a2cd | ||
|
|
40592a93ac | ||
|
|
dc1a5a860c | ||
|
|
f7b431902d | ||
|
|
686d47a59e | ||
|
|
eaa4688182 | ||
|
|
72645aa800 | ||
|
|
7044fc8004 | ||
|
|
9e8c780d66 | ||
|
|
e1795d687f | ||
|
|
607f7cba8d | ||
|
|
2572e23928 | ||
|
|
60921031bd | ||
|
|
77550d902c | ||
|
|
41935781fb | ||
|
|
47362559ef | ||
|
|
032ef0722d | ||
|
|
6e32f03a6b | ||
|
|
5731dcf135 |
5
.github/codecov.yml
vendored
Normal file
5
.github/codecov.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
comment: false
|
||||
ignore:
|
||||
- "lib/third_party" # Third party libraries should be ignored
|
||||
- "lib/external" # Our own libraries should be checked in their own repositories
|
||||
- "tests" # https://about.codecov.io/blog/should-i-include-test-files-in-code-coverage-calculations/
|
||||
98
.github/workflows/build.yml
vendored
98
.github/workflows/build.yml
vendored
@@ -2,7 +2,10 @@ name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["*"]
|
||||
branches:
|
||||
- 'master'
|
||||
- 'releases/**'
|
||||
- 'tests/**'
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -73,7 +76,7 @@ jobs:
|
||||
-DIMHEX_REPLACE_DWARF_WITH_PDB=ON \
|
||||
-DDOTNET_EXECUTABLE="C:/Program Files/dotnet/dotnet.exe" \
|
||||
..
|
||||
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
cd build
|
||||
@@ -104,7 +107,7 @@ jobs:
|
||||
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
|
||||
curl https://downloads.fdossena.com/geth.php?r=mesa64-latest -L -o mesa.7z
|
||||
7z e mesa.7z
|
||||
mv opengl32.dll build/install
|
||||
|
||||
@@ -150,15 +153,14 @@ jobs:
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
set -x
|
||||
brew reinstall python || brew link --overwrite python
|
||||
brew reinstall python || brew link --overwrite python || true
|
||||
brew bundle --no-lock --file dist/Brewfile
|
||||
rm -rf /usr/local/Cellar/capstone
|
||||
|
||||
- name: ⬇️ Install classic glfw
|
||||
if: ${{! matrix.custom_glfw}}
|
||||
run: |
|
||||
brew install glfw
|
||||
brew install glfw || true
|
||||
|
||||
- name: ⬇️ Install .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
@@ -171,7 +173,7 @@ jobs:
|
||||
with:
|
||||
repository: glfw/glfw
|
||||
path: glfw
|
||||
|
||||
|
||||
# GLFW custom build (to allow software rendering)
|
||||
- name: ⬇️ Patch and install custom glfw
|
||||
if: ${{matrix.custom_glfw}}
|
||||
@@ -211,21 +213,45 @@ jobs:
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_INSTALL_PREFIX="./install" \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||
-DCPACK_PACKAGE_FILE_NAME="imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}-x86_64" \
|
||||
..
|
||||
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: cd build && ninja package
|
||||
run: cd build && ninja install
|
||||
|
||||
- name: ✒️ Fix Signature
|
||||
run: |
|
||||
set -x
|
||||
cd build/install
|
||||
mv imhex.app ImHex.app
|
||||
codesign --remove-signature ImHex.app
|
||||
codesign --force --deep --sign - ImHex.app
|
||||
|
||||
- name: 📁 Fix permissions
|
||||
run: |
|
||||
set -x
|
||||
cd build/install
|
||||
chmod -R 755 ImHex.app/
|
||||
|
||||
- name: 📦 Create DMG
|
||||
run: |
|
||||
set -x
|
||||
mkdir bundle
|
||||
mv build/install/ImHex.app bundle
|
||||
cd bundle
|
||||
ln -s /Applications Applications
|
||||
cd ..
|
||||
hdiutil create -volname "ImHex" -srcfolder bundle -ov -format UDZO imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}-x86_64.dmg
|
||||
|
||||
- name: ⬆️ Upload DMG
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: macOS DMG${{matrix.suffix}} x86_64
|
||||
path: build/*.dmg
|
||||
path: ./*.dmg
|
||||
|
||||
macos-arm64-build:
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -237,7 +263,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
- name: 📁 Restore docker /cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
@@ -285,15 +311,15 @@ jobs:
|
||||
path: out
|
||||
|
||||
- name: 🗑️ Delete artifact
|
||||
uses: geekyeggo/delete-artifact@v4
|
||||
uses: geekyeggo/delete-artifact@v5
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
name: macos_arm64_intermediate
|
||||
|
||||
- name: ✒️ Fix Signature
|
||||
run: |
|
||||
set -x
|
||||
cd out
|
||||
mv imhex.app ImHex.app
|
||||
codesign --remove-signature ImHex.app
|
||||
codesign --force --deep --sign - ImHex.app
|
||||
|
||||
@@ -319,17 +345,15 @@ jobs:
|
||||
if-no-files-found: error
|
||||
name: macOS DMG arm64
|
||||
path: ./*.dmg
|
||||
|
||||
|
||||
# Ubuntu build
|
||||
ubuntu:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: Ubuntu
|
||||
release_num: 22.04
|
||||
- name: Ubuntu
|
||||
release_num: 23.04
|
||||
- release_num: 22.04
|
||||
- release_num: 24.04
|
||||
|
||||
name: 🐧 Ubuntu ${{ matrix.release_num }}
|
||||
runs-on: ubuntu-latest
|
||||
@@ -384,9 +408,9 @@ jobs:
|
||||
-DIMHEX_USE_GTK_FILE_PICKER=ON \
|
||||
-DDOTNET_EXECUTABLE="dotnet" \
|
||||
..
|
||||
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: cd build && DESTDIR=DebDir ninja install
|
||||
run: cd build && DESTDIR=DebDir ninja install
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
@@ -421,7 +445,7 @@ jobs:
|
||||
path: cache
|
||||
key: appimage-ccache-${{ github.run_id }}
|
||||
restore-keys: appimage-cache
|
||||
|
||||
|
||||
- name: 🐳 Inject /cache into docker
|
||||
uses: reproducible-containers/buildkit-cache-dance@v2
|
||||
with:
|
||||
@@ -507,9 +531,9 @@ jobs:
|
||||
-DIMHEX_ENABLE_LTO=ON \
|
||||
-DIMHEX_USE_GTK_FILE_PICKER=ON \
|
||||
..
|
||||
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: cd build && DESTDIR=installDir ninja install
|
||||
run: cd build && DESTDIR=installDir ninja install
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
@@ -557,14 +581,14 @@ jobs:
|
||||
mock_release: rawhide
|
||||
release_num: rawhide
|
||||
mock_config: fedora-rawhide
|
||||
- name: Fedora
|
||||
mock_release: f40
|
||||
release_num: 40
|
||||
mock_config: fedora-40
|
||||
- name: Fedora
|
||||
mock_release: f39
|
||||
release_num: 39
|
||||
mock_config: fedora-39
|
||||
- name: Fedora
|
||||
mock_release: f38
|
||||
release_num: 38
|
||||
mock_config: fedora-38
|
||||
- name: RHEL-AlmaLinux
|
||||
mock_release: epel9
|
||||
release_num: 9
|
||||
@@ -625,11 +649,11 @@ jobs:
|
||||
- name: ✒️ Modify spec file
|
||||
run: |
|
||||
sed -i \
|
||||
-e 's/Version: [0-9]*\.[0-9]*\.[0-9]*$/Version: ${{env.IMHEX_VERSION}}/g' \
|
||||
-e 's/IMHEX_OFFLINE_BUILD=ON/IMHEX_OFFLINE_BUILD=OFF/g' \
|
||||
-e '/IMHEX_OFFLINE_BUILD=OFF/a -D IMHEX_PATTERNS_PULL_MASTER=ON \\' \
|
||||
-e '/BuildRequires: cmake/a BuildRequires: git-core' \
|
||||
-e '/%files/a %{_datadir}/%{name}/' \
|
||||
-e 's/Version: VERSION$/Version: ${{env.IMHEX_VERSION}}/g' \
|
||||
-e 's/IMHEX_OFFLINE_BUILD=ON/IMHEX_OFFLINE_BUILD=OFF/g' \
|
||||
-e '/IMHEX_OFFLINE_BUILD=OFF/a -D IMHEX_PATTERNS_PULL_MASTER=ON \\' \
|
||||
-e '/BuildRequires: cmake/a BuildRequires: git-core' \
|
||||
-e '/%files/a %{_datadir}/%{name}/' \
|
||||
$GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec
|
||||
|
||||
- name: 📜 Fix ccache on EL9
|
||||
@@ -649,14 +673,6 @@ jobs:
|
||||
config_opts['plugin_conf']['ccache_opts']['dir'] = "$GITHUB_WORKSPACE/.ccache"
|
||||
EOT
|
||||
|
||||
- name: 📜 Setup Mock Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /var/cache/mock
|
||||
key: ${{ matrix.mock_release }}-mock-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
${{ matrix.mock_release }}-mock
|
||||
|
||||
# Fedora cmake build (in imhex.spec)
|
||||
- name: 📦 Build RPM
|
||||
run: |
|
||||
|
||||
7
.github/workflows/build_web.yml
vendored
7
.github/workflows/build_web.yml
vendored
@@ -2,7 +2,10 @@ name: Build for the web
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["*"]
|
||||
branches:
|
||||
- 'master'
|
||||
- 'releases/**'
|
||||
- 'tests/**'
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -29,7 +32,7 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: cache
|
||||
key: web-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
key: web-cache-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: 🐳 Inject /cache into docker
|
||||
uses: reproducible-containers/buildkit-cache-dance@v2
|
||||
|
||||
4
.github/workflows/release.yml
vendored
4
.github/workflows/release.yml
vendored
@@ -90,7 +90,7 @@ jobs:
|
||||
run: tar --exclude-vcs -czvf Full.Sources.tar.gz ImHex
|
||||
|
||||
- name: ⬇️ Download artifacts from latest workflow
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
uses: dawidd6/action-download-artifact@v3
|
||||
with:
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
workflow: build.yml
|
||||
@@ -119,7 +119,7 @@ jobs:
|
||||
mv "Windows Portable NoGPU x86_64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-NoGPU-x86_64.zip
|
||||
|
||||
- name: ⬆️ Upload everything to release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@4634c16e79c963813287e889244c50009e7f0981
|
||||
with:
|
||||
files: '*'
|
||||
|
||||
|
||||
51
.github/workflows/tests.yml
vendored
51
.github/workflows/tests.yml
vendored
@@ -2,9 +2,14 @@ name: "Unit Tests"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
branches:
|
||||
- 'master'
|
||||
- 'releases/**'
|
||||
- 'tests/**'
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
branches:
|
||||
- 'master'
|
||||
- 'releases/**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -29,39 +34,51 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-tests-build
|
||||
max-size: 50M
|
||||
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: ${{ runner.os }}-tests-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo bash dist/get_deps_debian.sh
|
||||
sudo apt install gcovr -y
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
set -x
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
|
||||
-DIMHEX_OFFLINE_BUILD=ON \
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DIMHEX_ENABLE_UNIT_TESTS=ON \
|
||||
-DIMHEX_ENABLE_PLUGIN_TESTS=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all --coverage" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all --coverage" \
|
||||
-DIMHEX_OFFLINE_BUILD=ON \
|
||||
..
|
||||
make -j4 unit_tests
|
||||
|
||||
- name: 🧪 Perform plcli Integration Tests
|
||||
run: |
|
||||
cd lib/external/pattern_language
|
||||
python tests/integration/integration.py ../../../build/imhex --pl
|
||||
|
||||
- name: 🧪 Perform Unit Tests
|
||||
run: |
|
||||
cd build
|
||||
ctest --output-on-failure
|
||||
|
||||
# Generate report from all gcov .gcda files
|
||||
- name: 🧪 Generate coverage report
|
||||
run: |
|
||||
gcovr --gcov-executable /usr/bin/gcov-12 -r . build --xml coverage_report.xml --verbose
|
||||
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
fail_ci_if_error: true
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
file: coverage_report.xml
|
||||
|
||||
langs:
|
||||
name: 🧪 Langs
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
.vscode/
|
||||
.idea/
|
||||
.kdev4/
|
||||
|
||||
cmake-build-*/
|
||||
build*/
|
||||
@@ -7,7 +8,8 @@ local/
|
||||
venv/
|
||||
|
||||
*.mgc
|
||||
*.kdev4
|
||||
imgui.ini
|
||||
.DS_Store
|
||||
./CMakeUserPresets.json
|
||||
Brewfile.lock.json
|
||||
CMakeUserPresets.json
|
||||
Brewfile.lock.json
|
||||
|
||||
13
.gitmodules
vendored
13
.gitmodules
vendored
@@ -22,6 +22,14 @@
|
||||
path = lib/third_party/jthread/jthread
|
||||
url = https://github.com/josuttis/jthread
|
||||
ignore = dirty
|
||||
[submodule "lib/third_party/edlib"]
|
||||
path = lib/third_party/edlib
|
||||
url = https://github.com/Martinsos/edlib
|
||||
ignore = dirty
|
||||
[submodule "lib/third_party/lunasvg"]
|
||||
path = lib/third_party/lunasvg
|
||||
url = https://github.com/sammycage/lunasvg
|
||||
ignore = dirty
|
||||
|
||||
[submodule "lib/external/libromfs"]
|
||||
path = lib/external/libromfs
|
||||
@@ -35,7 +43,4 @@
|
||||
|
||||
[submodule "lib/third_party/HashLibPlus"]
|
||||
path = lib/third_party/HashLibPlus
|
||||
url = https://github.com/WerWolv/HashLibPlus
|
||||
[submodule "lib/third_party/edlib"]
|
||||
path = lib/third_party/edlib
|
||||
url = https://github.com/Martinsos/edlib
|
||||
url = https://github.com/WerWolv/HashLibPlus
|
||||
@@ -19,24 +19,36 @@ option(IMHEX_ENABLE_UNITY_BUILD "Enables building ImHex as a unity build
|
||||
option(IMHEX_GENERATE_PDBS "Enable generating PDB files in non-debug builds (Windows only)" OFF)
|
||||
option(IMHEX_REPLACE_DWARF_WITH_PDB "Remove DWARF information from binaries when generating PDBS (Windows only)" OFF)
|
||||
option(IMHEX_ENABLE_STD_ASSERTS "Enable debug asserts in the C++ std library. (Breaks Plugin ABI!)" OFF)
|
||||
option(IMHEX_ENABLE_UNIT_TESTS "Enable building unit tests" OFF)
|
||||
option(IMHEX_ENABLE_PRECOMPILED_HEADERS "Enable precompiled headers" OFF)
|
||||
option(IMHEX_COMPRESS_DEBUG_INFO "Compress debug information" ON )
|
||||
|
||||
set(IMHEX_BASE_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
|
||||
|
||||
# Optional IDE support
|
||||
include("${IMHEX_BASE_FOLDER}/cmake/ide_helpers.cmake")
|
||||
|
||||
# Basic compiler and cmake configurations
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
|
||||
set(IMHEX_BASE_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
|
||||
include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
|
||||
|
||||
# Setup project
|
||||
loadVersion(IMHEX_VERSION)
|
||||
loadVersion(IMHEX_VERSION IMHEX_VERSION_PLAIN)
|
||||
setVariableInParent(IMHEX_VERSION ${IMHEX_VERSION})
|
||||
configureCMake()
|
||||
|
||||
project(imhex
|
||||
LANGUAGES C CXX
|
||||
VERSION ${IMHEX_VERSION}
|
||||
VERSION ${IMHEX_VERSION_PLAIN}
|
||||
DESCRIPTION "The ImHex Hex Editor"
|
||||
HOMEPAGE_URL "https://imhex.werwolv.net"
|
||||
)
|
||||
configureProject()
|
||||
|
||||
# Add ImHex sources
|
||||
add_custom_target(imhex_all ALL)
|
||||
|
||||
# Make sure project is configured correctly
|
||||
setDefaultBuiltTypeIfUnset()
|
||||
@@ -54,17 +66,22 @@ configurePackingResources()
|
||||
setUninstallTarget()
|
||||
addBundledLibraries()
|
||||
|
||||
# Add ImHex sources
|
||||
add_custom_target(imhex_all ALL)
|
||||
|
||||
add_subdirectory(lib/libimhex)
|
||||
add_subdirectory(main)
|
||||
addPluginDirectories()
|
||||
|
||||
# Add unit tests
|
||||
enable_testing()
|
||||
add_subdirectory(tests EXCLUDE_FROM_ALL)
|
||||
if (IMHEX_ENABLE_UNIT_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(tests EXCLUDE_FROM_ALL)
|
||||
endif ()
|
||||
|
||||
# Configure more resources that will be added to the install package
|
||||
createPackage()
|
||||
generatePDBs()
|
||||
generateSDKDirectory()
|
||||
generateSDKDirectory()
|
||||
|
||||
# Handle package generation
|
||||
createPackage()
|
||||
|
||||
# Accomodate IDEs with FOLDER support
|
||||
tweakTargetsForIDESupport()
|
||||
|
||||
@@ -28,6 +28,23 @@
|
||||
"displayName": "x86_64 Build",
|
||||
"description": "x86_64 build",
|
||||
"inherits": [ "base" ]
|
||||
},
|
||||
{
|
||||
"name": "xcode",
|
||||
"inherits": [ "base" ],
|
||||
|
||||
"displayName": "Xcode",
|
||||
"description": "Xcode with external compiler override",
|
||||
"generator": "Xcode",
|
||||
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "clang",
|
||||
|
||||
"CMAKE_CXX_COMPILER": "clang++",
|
||||
"CMAKE_CXX_FLAGS": "-fexperimental-library -Wno-shorten-64-to-32 -Wno-deprecated-declarations",
|
||||
|
||||
"IMHEX_IDE_HELPERS_OVERRIDE_XCODE_COMPILER": "ON"
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
|
||||
38
README.md
38
README.md
@@ -1,14 +1,16 @@
|
||||
<a href="https://imhex.werwolv.net">
|
||||
<h1 align="center">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./resources/projects/logo_text_light.svg">
|
||||
<img height="100px" src="./resources/projects/logo_text_dark.svg">
|
||||
<img height="300px" style="margin: 0; padding: 0" src="./resources/dist/common/logo/ImHexLogoSVGBG.svg">
|
||||
</picture>
|
||||
</h1>
|
||||
</a>
|
||||
|
||||
<p align="center">A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</p>
|
||||
|
||||
<p align="center">
|
||||
A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.
|
||||
<br>
|
||||
<a href="https://itinerarium.github.io/phoneme-synthesis/?w=/'ˈɪmhɛks/"><strong>/ˈɪmhɛks/</strong></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a title="'Build' workflow Status" href="https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild"><img alt="'Build' workflow Status" src="https://img.shields.io/github/actions/workflow/status/WerWolv/ImHex/build.yml?longCache=true&style=for-the-badge&label=Build&logoColor=fff&logo=GitHub%20Actions&branch=master"></a>
|
||||
<a title="Discord Server" href="https://discord.gg/X63jZ36xBY"><img alt="Discord Server" src="https://img.shields.io/discord/789833418631675954?label=Discord&logo=Discord&logoColor=fff&style=for-the-badge"></a>
|
||||
@@ -109,7 +111,7 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
<details>
|
||||
<summary><strong>Data Inspector</strong></summary>
|
||||
|
||||
- Interpreting data as many different types with endianess, decimal, hexadecimal and octal support and bit inversion
|
||||
- Interpreting data as many different types with endianness, decimal, hexadecimal and octal support and bit inversion
|
||||
- Unsigned and signed integers (8, 16, 24, 32, 48, 64 bit)
|
||||
- Floats (16, 32, 64 bit)
|
||||
- Signed and Unsigned LEB128
|
||||
@@ -158,7 +160,7 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
- Numeric Value search
|
||||
- Search for signed/unsigned integers and floats
|
||||
- Search for ranges of values
|
||||
- Option to specify size and endianess
|
||||
- Option to specify size and endianness
|
||||
- Option to ignore unaligned values
|
||||
</details>
|
||||
<details>
|
||||
@@ -316,7 +318,8 @@ To use ImHex, the following minimal system requirements need to be met.
|
||||
|
||||
- **OS**:
|
||||
- **Windows**: Windows 7 or higher (Windows 10/11 recommended)
|
||||
- **macOS**: macOS 11 (Big Sur) or higher,
|
||||
- **macOS**: macOS 12.1 (Monterey) or higher,
|
||||
- Lower versions are supported, but you'll need to compile ImHex yourself
|
||||
- **Linux**: "Modern" Linux. The following distributions have official releases available. Other distros are supported through the AppImage and Flatpak releases.
|
||||
- Ubuntu 22.04/23.04
|
||||
- Fedora 36/37
|
||||
@@ -358,24 +361,29 @@ To develop plugins for ImHex, use the following template project to get started.
|
||||
|
||||
### Contributors
|
||||
|
||||
- [iTrooz](https://github.com/iTrooz) for getting ImHex onto the Web as well as hundreds of contributions in every part of the project
|
||||
- [jumanji144](https://github.com/jumanji144) for huge contributions to the Pattern Language and ImHex's infrastructure
|
||||
- [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 and new features to Imhex
|
||||
- Everybody else who has reported issues on Discord or GitHub that I had great conversations with :)
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Thanks a lot to ocornut for their amazing [Dear ImGui](https://github.com/ocornut/imgui) which is used for building the entire interface
|
||||
- Thanks to ocornut as well for their hex editor view used as base for this project.
|
||||
- Thanks to BalazsJako for their incredible [ImGuiColorTextEdit](https://github.com/BalazsJako/ImGuiColorTextEdit) used for the pattern language syntax highlighting
|
||||
- Thanks to nlohmann for their [json](https://github.com/nlohmann/json) library used for project files
|
||||
- Thanks to aquynh for [capstone](https://github.com/aquynh/capstone) which is the base of the disassembly window
|
||||
- Thanks to epezent for [ImPlot](https://github.com/epezent/implot) used to plot data in various places
|
||||
- Thanks to Nelarius for [ImNodes](https://github.com/Nelarius/imnodes) used as base for the data processor
|
||||
- Thanks to BalazsJako for [ImGuiColorTextEdit](https://github.com/BalazsJako/ImGuiColorTextEdit) used for the pattern language syntax highlighting
|
||||
- Thanks to nlohmann for their [json](https://github.com/nlohmann/json) library used for configuration files
|
||||
- Thanks to vitaut for their [libfmt](https://github.com/fmtlib/fmt) library which makes formatting and logging so much better
|
||||
- Thanks to btzy for [nativefiledialog-extended](https://github.com/btzy/nativefiledialog-extended) and their great support, used for handling file dialogs on all platforms
|
||||
- Thanks to danyspin97 for [xdgpp](https://sr.ht/~danyspin97/xdgpp) used to handle folder paths on Linux
|
||||
- Thanks to aquynh for [capstone](https://github.com/aquynh/capstone) which is the base of the disassembly window
|
||||
- Thanks to rxi for [microtar](https://github.com/rxi/microtar) used for extracting downloaded store assets
|
||||
- Thanks to btzy for [nativefiledialog-extended](https://github.com/btzy/nativefiledialog-extended)
|
||||
- Thanks to danyspin97 for [xdgpp](https://sr.ht/~danyspin97/xdgpp)
|
||||
- Thanks to VirusTotal for [Yara](https://github.com/VirusTotal/yara) used by the Yara plugin
|
||||
- Thanks to Martinsos for [edlib](https://github.com/Martinsos/edlib) used for sequence searching in the diffing view
|
||||
- Thanks to ron4fun for [HashLibPlus](https://github.com/ron4fun/HashLibPlus) which implements every hashing algorithm under the sun
|
||||
- Thanks to mackron for [miniaudio](https://github.com/mackron/miniaudio) used to play audio files
|
||||
- Thanks to all other groups and organizations whose libraries are used in ImHex
|
||||
|
||||
### License
|
||||
|
||||
@@ -46,6 +46,9 @@ function(addDefineToSource SOURCE DEFINE)
|
||||
APPEND
|
||||
PROPERTY COMPILE_DEFINITIONS "${DEFINE}"
|
||||
)
|
||||
|
||||
# Disable precompiled headers for this file
|
||||
set_source_files_properties(${SOURCE} PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
|
||||
endfunction()
|
||||
|
||||
# Detect current OS / System
|
||||
@@ -56,6 +59,7 @@ macro(detectOS)
|
||||
set(CMAKE_INSTALL_LIBDIR ".")
|
||||
set(PLUGINS_INSTALL_LOCATION "plugins")
|
||||
add_compile_definitions(WIN32_LEAN_AND_MEAN)
|
||||
add_compile_definitions(UNICODE)
|
||||
elseif (APPLE)
|
||||
add_compile_definitions(OS_MACOS)
|
||||
set(CMAKE_INSTALL_BINDIR ".")
|
||||
@@ -67,6 +71,9 @@ macro(detectOS)
|
||||
add_compile_definitions(OS_WEB)
|
||||
elseif (UNIX AND NOT APPLE)
|
||||
add_compile_definitions(OS_LINUX)
|
||||
if (BSD AND BSD STREQUAL "FreeBSD")
|
||||
add_compile_definitions(OS_FREEBSD)
|
||||
endif()
|
||||
include(GNUInstallDirs)
|
||||
|
||||
if(IMHEX_PLUGINS_IN_SHARE)
|
||||
@@ -86,6 +93,8 @@ macro(detectOS)
|
||||
endmacro()
|
||||
|
||||
macro(configurePackingResources)
|
||||
set(LIBRARY_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
|
||||
if (WIN32)
|
||||
if (NOT (CMAKE_BUILD_TYPE STREQUAL "Debug"))
|
||||
set(APPLICATION_TYPE WIN32)
|
||||
@@ -139,21 +148,17 @@ macro(configurePackingResources)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(createPackage)
|
||||
set(LIBRARY_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
|
||||
macro(addPluginDirectories)
|
||||
file(MAKE_DIRECTORY "plugins")
|
||||
foreach (plugin IN LISTS PLUGINS)
|
||||
add_subdirectory("plugins/${plugin}")
|
||||
if (TARGET ${plugin})
|
||||
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${IMHEX_MAIN_OUTPUT_DIRECTORY}/plugins")
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${IMHEX_MAIN_OUTPUT_DIRECTORY}/plugins")
|
||||
|
||||
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 ()
|
||||
else ()
|
||||
if (WIN32)
|
||||
@@ -172,9 +177,9 @@ macro(createPackage)
|
||||
add_dependencies(imhex_all ${plugin})
|
||||
endif ()
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
set_target_properties(libimhex PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
macro(createPackage)
|
||||
if (WIN32)
|
||||
# Install binaries directly in the prefix, usually C:\Program Files\ImHex.
|
||||
set(CMAKE_INSTALL_BINDIR ".")
|
||||
@@ -211,7 +216,6 @@ macro(createPackage)
|
||||
endforeach()
|
||||
]])
|
||||
|
||||
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}" PERMISSIONS ${LIBRARY_PERMISSIONS})
|
||||
downloadImHexPatternsFiles("./")
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
|
||||
@@ -222,7 +226,6 @@ macro(createPackage)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_INSTALL_PREFIX}/share/licenses/imhex)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dist/imhex.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/icon.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps RENAME imhex.png)
|
||||
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}" PERMISSIONS ${LIBRARY_PERMISSIONS})
|
||||
downloadImHexPatternsFiles("./share/imhex")
|
||||
|
||||
# install AppStream file
|
||||
@@ -243,17 +246,15 @@ macro(createPackage)
|
||||
set_property(TARGET main PROPERTY MACOSX_BUNDLE_INFO_PLIST ${MACOSX_BUNDLE_INFO_PLIST})
|
||||
|
||||
# Fix rpath
|
||||
add_custom_command(TARGET imhex_all POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $<TARGET_FILE:main> || true)
|
||||
install(CODE "execute_process(COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath \"@executable_path/../Frameworks/\" $<TARGET_FILE:main>)")
|
||||
|
||||
add_custom_target(build-time-make-plugins-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${IMHEX_BUNDLE_PATH}/Contents/MacOS/plugins")
|
||||
add_custom_target(build-time-make-resources-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${IMHEX_BUNDLE_PATH}/Contents/Resources")
|
||||
|
||||
downloadImHexPatternsFiles("${IMHEX_BUNDLE_PATH}/Contents/MacOS")
|
||||
downloadImHexPatternsFiles("${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}/Contents/MacOS")
|
||||
|
||||
install(FILES ${IMHEX_ICON} DESTINATION "${IMHEX_BUNDLE_PATH}/Contents/Resources")
|
||||
install(FILES ${IMHEX_ICON} DESTINATION "${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}/Contents/Resources")
|
||||
install(TARGETS main BUNDLE DESTINATION ".")
|
||||
install(FILES $<TARGET_FILE:main> DESTINATION "${IMHEX_BUNDLE_PATH}")
|
||||
install(FILES $<TARGET_FILE:updater> DESTINATION "${IMHEX_BUNDLE_PATH}")
|
||||
|
||||
# Update library references to make the bundle portable
|
||||
postprocess_bundle(imhex_all main)
|
||||
@@ -262,15 +263,19 @@ macro(createPackage)
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
|
||||
set(CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/resources/dist/macos/AppIcon.icns")
|
||||
set(CPACK_BUNDLE_PLIST "${CMAKE_BINARY_DIR}/${BUNDLE_NAME}/Contents/Info.plist")
|
||||
set(CPACK_BUNDLE_PLIST "${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}/Contents/Info.plist")
|
||||
|
||||
if (IMHEX_RESIGN_BUNDLE)
|
||||
message(STATUS "Resigning bundle...")
|
||||
find_program(CODESIGN_PATH codesign)
|
||||
if (CODESIGN_PATH)
|
||||
add_custom_command(TARGET imhex_all POST_BUILD COMMAND "codesign" ARGS "--force" "--deep" "--sign" "-" "${CMAKE_BINARY_DIR}/${BUNDLE_NAME}")
|
||||
install(CODE "message(STATUS \"Signing bundle '${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}'...\")")
|
||||
install(CODE "execute_process(COMMAND ${CODESIGN_PATH} --force --deep --entitlements ${CMAKE_SOURCE_DIR}/resources/macos/Entitlements.plist --sign - ${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME} COMMAND_ERROR_IS_FATAL ANY)")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
install(CODE [[ message(STATUS "MacOS Bundle finalized. DO NOT TOUCH IT ANYMORE! ANY MODIFICATIONS WILL BREAK IT FROM NOW ON!") ]])
|
||||
else()
|
||||
downloadImHexPatternsFiles("${IMHEX_MAIN_OUTPUT_DIRECTORY}")
|
||||
endif()
|
||||
else()
|
||||
install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
@@ -338,8 +343,11 @@ macro(configureCMake)
|
||||
|
||||
if (LD_LLD_PATH)
|
||||
set(CMAKE_LINKER ${LD_LLD_PATH})
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=lld")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=lld")
|
||||
|
||||
if (NOT XCODE)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=lld")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=lld")
|
||||
endif()
|
||||
else ()
|
||||
message(WARNING "lld not found, using default linker!")
|
||||
endif ()
|
||||
@@ -374,6 +382,15 @@ macro(configureCMake)
|
||||
set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "Disable deprecated warnings" FORCE)
|
||||
endmacro()
|
||||
|
||||
function(configureProject)
|
||||
if (XCODE)
|
||||
# Support Xcode's multi configuration paradigm by placing built artifacts into separate directories
|
||||
set(IMHEX_MAIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/Configs/$<CONFIG>" PARENT_SCOPE)
|
||||
else()
|
||||
set(IMHEX_MAIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
macro(setDefaultBuiltTypeIfUnset)
|
||||
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Using RelWithDebInfo build type as it was left unset" FORCE)
|
||||
@@ -381,12 +398,14 @@ macro(setDefaultBuiltTypeIfUnset)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
function(loadVersion version)
|
||||
function(loadVersion version plain_version)
|
||||
set(VERSION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/VERSION")
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${VERSION_FILE})
|
||||
file(READ "${VERSION_FILE}" read_version)
|
||||
string(STRIP ${read_version} read_version)
|
||||
string(REPLACE ".WIP" "" read_version_plain ${read_version})
|
||||
set(${version} ${read_version} PARENT_SCOPE)
|
||||
set(${plain_version} ${read_version_plain} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(detectBadClone)
|
||||
@@ -476,20 +495,71 @@ function(downloadImHexPatternsFiles dest)
|
||||
message(STATUS "Finished downloading ImHex-Patterns")
|
||||
|
||||
else ()
|
||||
set(imhex_patterns_SOURCE_DIR "")
|
||||
|
||||
# Maybe patterns are cloned to a subdirectory
|
||||
set(imhex_patterns_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ImHex-Patterns")
|
||||
if (NOT EXISTS ${imhex_patterns_SOURCE_DIR})
|
||||
set(imhex_patterns_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ImHex-Patterns")
|
||||
endif()
|
||||
|
||||
# Or a sibling directory
|
||||
if (NOT EXISTS ${imhex_patterns_SOURCE_DIR})
|
||||
set(imhex_patterns_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../ImHex-Patterns")
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
if (EXISTS ${imhex_patterns_SOURCE_DIR})
|
||||
if (NOT EXISTS ${imhex_patterns_SOURCE_DIR})
|
||||
message(WARNING "Failed to locate ImHex-Patterns repository, some resources will be missing during install!")
|
||||
elseif(XCODE)
|
||||
# The Xcode build has multiple configurations, which each need a copy of these files
|
||||
file(GLOB_RECURSE sourceFilePaths LIST_DIRECTORIES NO CONFIGURE_DEPENDS RELATIVE "${imhex_patterns_SOURCE_DIR}"
|
||||
"${imhex_patterns_SOURCE_DIR}/constants/*"
|
||||
"${imhex_patterns_SOURCE_DIR}/encodings/*"
|
||||
"${imhex_patterns_SOURCE_DIR}/includes/*"
|
||||
"${imhex_patterns_SOURCE_DIR}/patterns/*"
|
||||
"${imhex_patterns_SOURCE_DIR}/magic/*"
|
||||
"${imhex_patterns_SOURCE_DIR}/nodes/*"
|
||||
)
|
||||
list(FILTER sourceFilePaths EXCLUDE REGEX "_schema.json$")
|
||||
|
||||
foreach(relativePath IN LISTS sourceFilePaths)
|
||||
file(GENERATE OUTPUT "${dest}/${relativePath}" INPUT "${imhex_patterns_SOURCE_DIR}/${relativePath}")
|
||||
endforeach()
|
||||
else()
|
||||
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic nodes)
|
||||
foreach (FOLDER ${PATTERNS_FOLDERS_TO_INSTALL})
|
||||
install(DIRECTORY "${imhex_patterns_SOURCE_DIR}/${FOLDER}" DESTINATION ${dest} PATTERN "**/_schema.json" EXCLUDE)
|
||||
install(DIRECTORY "${imhex_patterns_SOURCE_DIR}/${FOLDER}" DESTINATION "${dest}" PATTERN "**/_schema.json" EXCLUDE)
|
||||
endforeach ()
|
||||
endif ()
|
||||
|
||||
endfunction()
|
||||
|
||||
# Compress debug info. See https://github.com/WerWolv/ImHex/issues/1714 for relevant problem
|
||||
macro(setupDebugCompressionFlag)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckLinkerFlag)
|
||||
|
||||
check_cxx_compiler_flag(-gz=zstd ZSTD_AVAILABLE_COMPILER)
|
||||
check_linker_flag(CXX -gz=zstd ZSTD_AVAILABLE_LINKER)
|
||||
check_cxx_compiler_flag(-gz COMPRESS_AVAILABLE_COMPILER)
|
||||
check_linker_flag(CXX -gz COMPRESS_AVAILABLE_LINKER)
|
||||
|
||||
if (NOT DEBUG_COMPRESSION_FLAG) # Cache variable
|
||||
if (ZSTD_AVAILABLE_COMPILER AND ZSTD_AVAILABLE_LINKER)
|
||||
message("Using Zstd compression for debug info because both compiler and linker support it")
|
||||
set(DEBUG_COMPRESSION_FLAG "-gz=zstd" CACHE STRING "Cache to use for debug info compression")
|
||||
elseif (COMPRESS_AVAILABLE_COMPILER AND COMPRESS_AVAILABLE_LINKER)
|
||||
message("Using default compression for debug info because both compiler and linker support it")
|
||||
set(DEBUG_COMPRESSION_FLAG "-gz" CACHE STRING "Cache to use for debug info compression")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(IMHEX_COMMON_FLAGS "${IMHEX_COMMON_FLAGS} ${DEBUG_COMPRESSION_FLAG}")
|
||||
endmacro()
|
||||
|
||||
macro(setupCompilerFlags target)
|
||||
# IMHEX_COMMON_FLAGS: flags common for C, C++, Objective C, etc.. compilers
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
# Define strict compilation flags
|
||||
if (IMHEX_STRICT_WARNINGS)
|
||||
@@ -503,7 +573,7 @@ macro(setupCompilerFlags target)
|
||||
set(IMHEX_CXX_FLAGS "-fexceptions -frtti")
|
||||
|
||||
# Disable some warnings
|
||||
set(IMHEX_C_CXX_FLAGS "-Wno-unknown-warning-option -Wno-array-bounds -Wno-deprecated-declarations")
|
||||
set(IMHEX_C_CXX_FLAGS "-Wno-unknown-warning-option -Wno-array-bounds -Wno-deprecated-declarations -Wno-unknown-pragmas")
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
@@ -522,11 +592,24 @@ macro(setupCompilerFlags target)
|
||||
set(IMHEX_C_CXX_FLAGS "${IMHEX_C_CXX_FLAGS} -pthread -Wno-dollar-in-identifier-extension -Wno-pthreads-mem-growth")
|
||||
endif ()
|
||||
|
||||
if (IMHEX_COMPRESS_DEBUG_INFO)
|
||||
setupDebugCompressionFlag()
|
||||
endif()
|
||||
|
||||
# Set actual CMake flags
|
||||
set_target_properties(${target} PROPERTIES COMPILE_FLAGS "${IMHEX_COMMON_FLAGS} ${IMHEX_C_CXX_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}")
|
||||
|
||||
# Only generate minimal debug information for stacktraces in RelWithDebInfo builds
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -g1")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -g1")
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
# Add flags for debug info in inline functions
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -gstatement-frontiers -ginline-points")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -gstatement-frontiers -ginline-points")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# uninstall target
|
||||
@@ -592,6 +675,14 @@ macro(addBundledLibraries)
|
||||
set(NLOHMANN_JSON_LIBRARIES nlohmann_json::nlohmann_json)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_LUNASVG)
|
||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/lunasvg EXCLUDE_FROM_ALL)
|
||||
set(LUNASVG_LIBRARIES lunasvg)
|
||||
else()
|
||||
find_package(LunaSVG REQUIRED)
|
||||
set(LUNASVG_LIBRARIES lunasvg)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_LLVM)
|
||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/llvm-demangle EXCLUDE_FROM_ALL)
|
||||
else()
|
||||
@@ -610,7 +701,16 @@ macro(addBundledLibraries)
|
||||
set(JTHREAD_LIBRARIES jthread)
|
||||
endif()
|
||||
|
||||
if (USE_SYSTEM_BOOST)
|
||||
find_package(boost REQUIRED)
|
||||
set(BOOST_LIBRARIES boost::regex)
|
||||
else()
|
||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/boost ${CMAKE_CURRENT_BINARY_DIR}/boost EXCLUDE_FROM_ALL)
|
||||
set(BOOST_LIBRARIES boost::regex)
|
||||
endif()
|
||||
|
||||
set(LIBPL_BUILD_CLI_AS_EXECUTABLE OFF CACHE BOOL "" FORCE)
|
||||
set(LIBPL_ENABLE_PRECOMPILED_HEADERS ${IMHEX_ENABLE_PRECOMPILED_HEADERS} CACHE BOOL "" FORCE)
|
||||
|
||||
if (WIN32)
|
||||
set(LIBPL_SHARED_LIBRARY ON CACHE BOOL "" FORCE)
|
||||
@@ -653,20 +753,20 @@ macro(addBundledLibraries)
|
||||
if (${Backtrace_FOUND})
|
||||
message(STATUS "Backtrace enabled! Header: ${Backtrace_HEADER}")
|
||||
|
||||
if (Backtrace_HEADER STREQUAL "execinfo.h")
|
||||
if (Backtrace_HEADER STREQUAL "backtrace.h")
|
||||
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
|
||||
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
|
||||
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
|
||||
add_compile_definitions(HEX_HAS_EXECINFO)
|
||||
elseif (Backtrace_HEADER STREQUAL "backtrace.h")
|
||||
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
|
||||
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
|
||||
add_compile_definitions(BACKTRACE_HEADER=\"${Backtrace_HEADER}\")
|
||||
add_compile_definitions(BACKTRACE_HEADER=<${Backtrace_HEADER}>)
|
||||
add_compile_definitions(HEX_HAS_BACKTRACE)
|
||||
endif ()
|
||||
elseif (Backtrace_HEADER STREQUAL "execinfo.h")
|
||||
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
|
||||
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
|
||||
add_compile_definitions(BACKTRACE_HEADER=<${Backtrace_HEADER}>)
|
||||
add_compile_definitions(HEX_HAS_EXECINFO)
|
||||
endif()
|
||||
endif()
|
||||
endif ()
|
||||
endif ()
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
function(enableUnityBuild TARGET)
|
||||
@@ -732,7 +832,7 @@ function(generateSDKDirectory)
|
||||
if (WIN32)
|
||||
set(SDK_PATH "./sdk")
|
||||
elseif (APPLE)
|
||||
set(SDK_PATH "${BUNDLE_NAME}/Contents/Resources/sdk")
|
||||
set(SDK_PATH "${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}/Contents/Resources/sdk")
|
||||
else()
|
||||
set(SDK_PATH "share/imhex/sdk")
|
||||
endif()
|
||||
@@ -748,6 +848,9 @@ function(generateSDKDirectory)
|
||||
if (NOT USE_SYSTEM_NLOHMANN_JSON)
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/nlohmann_json DESTINATION "${SDK_PATH}/lib/third_party")
|
||||
endif()
|
||||
if (NOT USE_SYSTEM_NLOHMANN_JSON)
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/boost DESTINATION "${SDK_PATH}/lib/third_party")
|
||||
endif()
|
||||
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/cmake/modules DESTINATION "${SDK_PATH}/cmake")
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/cmake/build_helpers.cmake DESTINATION "${SDK_PATH}/cmake")
|
||||
@@ -758,4 +861,19 @@ endfunction()
|
||||
function(addIncludesFromLibrary target library)
|
||||
get_target_property(library_include_dirs ${library} INTERFACE_INCLUDE_DIRECTORIES)
|
||||
target_include_directories(${target} PRIVATE ${library_include_dirs})
|
||||
endfunction()
|
||||
|
||||
function(precompileHeaders target includeFolder)
|
||||
if (NOT IMHEX_ENABLE_PRECOMPILED_HEADERS)
|
||||
return()
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE TARGET_INCLUDES "${includeFolder}/**/*.hpp")
|
||||
set(SYSTEM_INCLUDES "<algorithm>;<array>;<atomic>;<chrono>;<cmath>;<cstddef>;<cstdint>;<cstdio>;<cstdlib>;<cstring>;<exception>;<filesystem>;<functional>;<iterator>;<limits>;<list>;<map>;<memory>;<optional>;<ranges>;<set>;<stdexcept>;<string>;<string_view>;<thread>;<tuple>;<type_traits>;<unordered_map>;<unordered_set>;<utility>;<variant>;<vector>")
|
||||
set(INCLUDES "${SYSTEM_INCLUDES};${TARGET_INCLUDES}")
|
||||
string(REPLACE ">" "$<ANGLE-R>" INCLUDES "${INCLUDES}")
|
||||
target_precompile_headers(${target}
|
||||
PUBLIC
|
||||
"$<$<COMPILE_LANGUAGE:CXX>:${INCLUDES}>"
|
||||
)
|
||||
endfunction()
|
||||
149
cmake/ide_helpers.cmake
Normal file
149
cmake/ide_helpers.cmake
Normal file
@@ -0,0 +1,149 @@
|
||||
|
||||
option(IMHEX_IDE_HELPERS_OVERRIDE_XCODE_COMPILER "Enable choice of compiler for Xcode builds, despite CMake's best efforts" OFF)
|
||||
option(IMHEX_IDE_HELPERS_INTRUSIVE_IDE_TWEAKS "Enable intrusive CMake tweaks to better support IDEs with folder support" OFF)
|
||||
|
||||
# The CMake infrastructure silently ignores the CMAKE_<>_COMPILER settings when
|
||||
# using the `Xcode` generator.
|
||||
#
|
||||
# A particularly nasty (and potentially only) way of getting around this is to
|
||||
# temporarily lie about the generator being used, while CMake determines and
|
||||
# locks in the compiler to use.
|
||||
#
|
||||
# Needless to say, this is hacky and fragile. Use at your own risk!
|
||||
if (IMHEX_IDE_HELPERS_OVERRIDE_XCODE_COMPILER AND CMAKE_GENERATOR STREQUAL "Xcode")
|
||||
set(CMAKE_GENERATOR "Unknown")
|
||||
enable_language(C CXX)
|
||||
|
||||
set(CMAKE_GENERATOR "Xcode")
|
||||
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CC "${CMAKE_C_COMPILER}")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CXX "${CMAKE_CXX_COMPILER}")
|
||||
|
||||
if (CLANG)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_LD "${CMAKE_C_COMPILER}")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS "${CMAKE_CXX_COMPILER}")
|
||||
endif()
|
||||
|
||||
# By default Xcode passes a `-index-store-path=<...>` parameter to the compiler
|
||||
# during builds to build code completion indexes. This is not supported by
|
||||
# anything other than AppleClang
|
||||
set(CMAKE_XCODE_ATTRIBUTE_COMPILER_INDEX_STORE_ENABLE "NO")
|
||||
endif()
|
||||
|
||||
# Generate a launch/build scheme for all targets
|
||||
set(CMAKE_XCODE_GENERATE_SCHEME YES)
|
||||
|
||||
# Utility function that helps avoid messing with non-standard targets
|
||||
macro(returnIfTargetIsNonTweakable target)
|
||||
get_target_property(targetIsAliased ${target} ALIASED_TARGET)
|
||||
get_target_property(targetIsImported ${target} IMPORTED)
|
||||
|
||||
if (targetIsAliased OR targetIsImported)
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_target_property(targetType ${target} TYPE)
|
||||
if (targetType MATCHES "INTERFACE_LIBRARY|UNKNOWN_LIBRARY")
|
||||
return()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Targets usually don't specify their private headers, nor group their source files
|
||||
# which results in very spotty coverage by IDEs with folders support
|
||||
#
|
||||
# Unfortunately, CMake does not have a `target_source_group` like construct yet, therefore
|
||||
# we have to play by the limitations of `source_group`.
|
||||
#
|
||||
# A particularly problematic part is that the function must be called within the directoryies
|
||||
# scope for the grouping to take effect.
|
||||
#
|
||||
# See: https://discourse.cmake.org/t/topic/7388
|
||||
function(tweakTargetForIDESupport target)
|
||||
returnIfTargetIsNonTweakable(${target})
|
||||
|
||||
# Don't assume directory structure of third parties
|
||||
get_target_property(targetSourceDir ${target} SOURCE_DIR)
|
||||
if (targetSourceDir MATCHES "third_party")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Add headers to target
|
||||
get_target_property(targetSourceDir ${target} SOURCE_DIR)
|
||||
if (targetSourceDir)
|
||||
file(GLOB_RECURSE targetPrivateHeaders CONFIGURE_DEPENDS "${targetSourceDir}/include/*.hpp")
|
||||
|
||||
target_sources(${target} PRIVATE "${targetPrivateHeaders}")
|
||||
endif()
|
||||
|
||||
# Organize target sources into directory tree
|
||||
get_target_property(sources ${target} SOURCES)
|
||||
foreach(file IN LISTS sources)
|
||||
get_filename_component(path "${file}" ABSOLUTE)
|
||||
|
||||
if (NOT path MATCHES "^${targetSourceDir}")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
source_group(TREE "${targetSourceDir}" PREFIX "Source Tree" FILES "${file}")
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
if (IMHEX_IDE_HELPERS_INTRUSIVE_IDE_TWEAKS)
|
||||
# See tweakTargetForIDESupport for rationale
|
||||
|
||||
function(add_library target)
|
||||
_add_library(${target} ${ARGN})
|
||||
|
||||
tweakTargetForIDESupport(${target})
|
||||
endfunction()
|
||||
|
||||
function(add_executable target)
|
||||
_add_executable(${target} ${ARGN})
|
||||
|
||||
tweakTargetForIDESupport(${target})
|
||||
endfunction()
|
||||
endif()
|
||||
|
||||
# Adjust target's FOLDER property, which is an IDE only preference
|
||||
function(_tweakTarget target path)
|
||||
get_target_property(targetType ${target} TYPE)
|
||||
|
||||
if (TARGET generator-${target})
|
||||
set_target_properties(generator-${target} PROPERTIES FOLDER "romfs/${target}")
|
||||
endif()
|
||||
if (TARGET romfs_file_packer-${target})
|
||||
set_target_properties(romfs_file_packer-${target} PROPERTIES FOLDER "romfs/${target}")
|
||||
endif()
|
||||
if (TARGET libromfs-${target})
|
||||
set_target_properties(libromfs-${target} PROPERTIES FOLDER "romfs/${target}")
|
||||
endif()
|
||||
|
||||
if (${targetType} MATCHES "EXECUTABLE|LIBRARY")
|
||||
set_target_properties(${target} PROPERTIES FOLDER "${path}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
macro(_tweakTargetsRecursive dir)
|
||||
get_property(subdirectories DIRECTORY ${dir} PROPERTY SUBDIRECTORIES)
|
||||
foreach(subdir IN LISTS subdirectories)
|
||||
_tweakTargetsRecursive("${subdir}")
|
||||
endforeach()
|
||||
|
||||
if(${dir} STREQUAL ${CMAKE_SOURCE_DIR})
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_property(targets DIRECTORY "${dir}" PROPERTY BUILDSYSTEM_TARGETS)
|
||||
file(RELATIVE_PATH rdir ${CMAKE_SOURCE_DIR} "${dir}/..")
|
||||
|
||||
foreach(target ${targets})
|
||||
_tweakTarget(${target} "${rdir}")
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
# Tweak all targets this CMake build is aware about
|
||||
function(tweakTargetsForIDESupport)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
_tweakTargetsRecursive("${CMAKE_SOURCE_DIR}")
|
||||
endfunction()
|
||||
@@ -11,6 +11,14 @@ if (UNIX)
|
||||
set(CORECLR_SUBARCH "arm64")
|
||||
endif()
|
||||
endif()
|
||||
if (APPLE)
|
||||
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
|
||||
set(CORECLR_ARCH "osx-arm64")
|
||||
set(CORECLR_SUBARCH "arm64")
|
||||
else()
|
||||
set(CORECLR_ARCH "osx-x64")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT DOTNET_EXECUTABLE)
|
||||
set(DOTNET_EXECUTABLE dotnet)
|
||||
@@ -81,4 +89,5 @@ if (CoreClrEmbed_INCLUDE_DIR AND CoreClrEmbed_LIBRARY)
|
||||
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)
|
||||
set(CoreClrEmbed_VERSION "${CORECLR_RUNTIME_VERSION_FULL}" CACHE STRING "CoreClrEmbed version" FORCE)
|
||||
endif()
|
||||
@@ -1,4 +1,4 @@
|
||||
find_file(libyara.a YARA_LIBRARIES)
|
||||
find_library(YARA_LIBRARIES NAMES yara)
|
||||
find_file(yara.h YARA_INCLUDE_DIRS)
|
||||
|
||||
mark_as_advanced(YARA_LIBRARIES YARA_INCLUDE_DIRS)
|
||||
@@ -38,4 +38,8 @@ if (ZSTD_FOUND)
|
||||
message(STATUS "Found Zstd: ${ZSTD_LIBRARY}")
|
||||
endif()
|
||||
|
||||
mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY)
|
||||
mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY)
|
||||
|
||||
add_library(ZSTD::zstd INTERFACE IMPORTED)
|
||||
set_property(TARGET ZSTD::zstd PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${ZSTD_INCLUDE_DIR})
|
||||
set_property(TARGET ZSTD::zstd PROPERTY INTERFACE_LINK_LIBRARIES ${ZSTD_LIBRARY})
|
||||
@@ -36,8 +36,12 @@ macro(add_imhex_plugin)
|
||||
|
||||
# Add include directories and link libraries
|
||||
target_include_directories(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_INCLUDES})
|
||||
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE libimhex ${IMHEX_PLUGIN_LIBRARIES} ${FMT_LIBRARIES} imgui_all_includes libwolv)
|
||||
target_link_libraries(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_LIBRARIES})
|
||||
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE libimhex ${FMT_LIBRARIES} imgui_all_includes libwolv)
|
||||
addIncludesFromLibrary(${IMHEX_PLUGIN_NAME} libpl)
|
||||
addIncludesFromLibrary(${IMHEX_PLUGIN_NAME} libpl-gen)
|
||||
|
||||
precompileHeaders(${IMHEX_PLUGIN_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
|
||||
# Add IMHEX_PROJECT_NAME and IMHEX_VERSION define
|
||||
target_compile_definitions(${IMHEX_PLUGIN_NAME} PRIVATE IMHEX_PROJECT_NAME="${IMHEX_PLUGIN_NAME}")
|
||||
@@ -51,7 +55,7 @@ macro(add_imhex_plugin)
|
||||
# Configure build properties
|
||||
set_target_properties(${IMHEX_PLUGIN_NAME}
|
||||
PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins
|
||||
RUNTIME_OUTPUT_DIRECTORY "${IMHEX_MAIN_OUTPUT_DIRECTORY}/plugins"
|
||||
CXX_STANDARD 23
|
||||
PREFIX ""
|
||||
SUFFIX ${IMHEX_PLUGIN_SUFFIX}
|
||||
@@ -68,10 +72,23 @@ macro(add_imhex_plugin)
|
||||
add_subdirectory(${IMHEX_BASE_FOLDER}/lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs)
|
||||
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE ${LIBROMFS_LIBRARY})
|
||||
|
||||
foreach(feature ${IMHEX_PLUGIN_FEATURES})
|
||||
string(TOUPPER ${feature} feature)
|
||||
add_definitions(-DIMHEX_PLUGIN_${IMHEX_PLUGIN_NAME}_FEATURE_${feature}=0)
|
||||
endforeach()
|
||||
set(FEATURE_DEFINE_CONTENT)
|
||||
|
||||
if (IMHEX_PLUGIN_FEATURES)
|
||||
list(LENGTH IMHEX_PLUGIN_FEATURES IMHEX_FEATURE_COUNT)
|
||||
math(EXPR IMHEX_FEATURE_COUNT "${IMHEX_FEATURE_COUNT} - 1" OUTPUT_FORMAT DECIMAL)
|
||||
foreach(index RANGE 0 ${IMHEX_FEATURE_COUNT} 2)
|
||||
list(SUBLIST IMHEX_PLUGIN_FEATURES ${index} 2 IMHEX_PLUGIN_FEATURE)
|
||||
list(GET IMHEX_PLUGIN_FEATURE 0 feature_define)
|
||||
list(GET IMHEX_PLUGIN_FEATURE 1 feature_description)
|
||||
|
||||
string(TOUPPER ${feature_define} feature_define)
|
||||
add_definitions(-DIMHEX_PLUGIN_${IMHEX_PLUGIN_NAME}_FEATURE_${feature_define}=0)
|
||||
set(FEATURE_DEFINE_CONTENT "${FEATURE_DEFINE_CONTENT}{ \"${feature_description}\", IMHEX_FEATURE_ENABLED(${feature_define}) },")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
target_compile_options(${IMHEX_PLUGIN_NAME} PRIVATE -DIMHEX_PLUGIN_FEATURES_CONTENT=${FEATURE_DEFINE_CONTENT})
|
||||
|
||||
# Add the new plugin to the main dependency list so it gets built by default
|
||||
if (TARGET imhex_all)
|
||||
@@ -84,13 +101,39 @@ macro(add_imhex_plugin)
|
||||
|
||||
# Fix rpath
|
||||
if (APPLE)
|
||||
set_target_properties(${IMHEX_PLUGIN_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks;@executable_path/plugins")
|
||||
set_target_properties(
|
||||
${IMHEX_PLUGIN_NAME}
|
||||
PROPERTIES
|
||||
INSTALL_RPATH "@executable_path/../Frameworks;@executable_path/plugins"
|
||||
)
|
||||
elseif (UNIX)
|
||||
set_target_properties(${IMHEX_PLUGIN_NAME} PROPERTIES INSTALL_RPATH_USE_ORIGIN ON INSTALL_RPATH "$ORIGIN/")
|
||||
set(PLUGIN_RPATH "")
|
||||
list(APPEND PLUGIN_RPATH "$ORIGIN")
|
||||
|
||||
if (IMHEX_PLUGIN_ADD_INSTALL_PREFIX_TO_RPATH)
|
||||
list(APPEND PLUGIN_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
endif()
|
||||
|
||||
set_target_properties(
|
||||
${IMHEX_PLUGIN_NAME}
|
||||
PROPERTIES
|
||||
INSTALL_RPATH_USE_ORIGIN ON
|
||||
INSTALL_RPATH "${PLUGIN_RPATH}"
|
||||
)
|
||||
endif()
|
||||
|
||||
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt AND IMHEX_ENABLE_UNIT_TESTS AND IMHEX_ENABLE_PLUGIN_TESTS)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/tests)
|
||||
target_link_libraries(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_NAME}_tests)
|
||||
target_compile_definitions(${IMHEX_PLUGIN_NAME}_tests PRIVATE IMHEX_PROJECT_NAME="${IMHEX_PLUGIN_NAME}-tests")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(add_romfs_resource input output)
|
||||
if (NOT EXISTS ${input})
|
||||
message(WARNING "Resource file ${input} does not exist")
|
||||
endif()
|
||||
|
||||
configure_file(${input} ${CMAKE_CURRENT_BINARY_DIR}/romfs/${output} COPYONLY)
|
||||
|
||||
list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/romfs)
|
||||
|
||||
@@ -14,12 +14,11 @@ if(CMAKE_GENERATOR)
|
||||
# Being called as include(PostprocessBundle), so define a helper function.
|
||||
set(_POSTPROCESS_BUNDLE_MODULE_LOCATION "${CMAKE_CURRENT_LIST_FILE}")
|
||||
function(postprocess_bundle out_target in_target)
|
||||
add_custom_command(TARGET ${out_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -DBUNDLE_PATH="$<TARGET_FILE_DIR:${in_target}>/../.."
|
||||
-DCODE_SIGN_CERTIFICATE_ID="${CODE_SIGN_CERTIFICATE_ID}"
|
||||
-DEXTRA_BUNDLE_LIBRARY_PATHS="${EXTRA_BUNDLE_LIBRARY_PATHS}"
|
||||
-P "${_POSTPROCESS_BUNDLE_MODULE_LOCATION}"
|
||||
)
|
||||
|
||||
install(CODE "set(BUNDLE_PATH ${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME})")
|
||||
install(CODE "set(CODE_SIGN_CERTIFICATE_ID ${CODE_SIGN_CERTIFICATE_ID})")
|
||||
install(CODE "set(EXTRA_BUNDLE_LIBRARY_PATHS ${EXTRA_BUNDLE_LIBRARY_PATHS})")
|
||||
install(SCRIPT ${_POSTPROCESS_BUNDLE_MODULE_LOCATION})
|
||||
endfunction()
|
||||
return()
|
||||
endif()
|
||||
@@ -42,7 +41,7 @@ file(GLOB_RECURSE plugins "${BUNDLE_PATH}/Contents/MacOS/plugins/*.hexplug")
|
||||
# makes it sometimes break on libraries that do weird things with @rpath. Specify
|
||||
# equivalent search directories until https://gitlab.kitware.com/cmake/cmake/issues/16625
|
||||
# is fixed and in our minimum CMake version.
|
||||
set(extra_dirs "/usr/local/lib" "/lib" "/usr/lib" ${EXTRA_BUNDLE_LIBRARY_PATHS} "${BUNDLE_PATH}/Contents/MacOS/plugins")
|
||||
set(extra_dirs "/usr/local/lib" "/lib" "/usr/lib" ${EXTRA_BUNDLE_LIBRARY_PATHS} "${BUNDLE_PATH}/Contents/MacOS/plugins" "${BUNDLE_PATH}/Contents/Frameworks")
|
||||
message(STATUS "Fixing up application bundle: ${extra_dirs}")
|
||||
|
||||
# BundleUtilities is overly verbose, so disable most of its messages
|
||||
|
||||
@@ -29,6 +29,10 @@ add_subdirectory_if_exists(lib/third_party/nlohmann_json)
|
||||
set(NLOHMANN_JSON_LIBRARIES nlohmann_json PARENT_SCOPE)
|
||||
set(NLOHMANN_JSON_LIBRARIES nlohmann_json)
|
||||
|
||||
add_subdirectory_if_exists(lib/third_party/boost)
|
||||
set(BOOST_LIBRARIES boost::regex PARENT_SCOPE)
|
||||
set(BOOST_LIBRARIES boost::regex)
|
||||
|
||||
add_subdirectory(lib/external/libwolv EXCLUDE_FROM_ALL)
|
||||
|
||||
set(LIBPL_ENABLE_CLI OFF CACHE BOOL "" FORCE)
|
||||
|
||||
13
dist/compiling/docker.md
vendored
13
dist/compiling/docker.md
vendored
@@ -18,11 +18,11 @@ docker buildx build . -f <DOCKERFILE_PATH> --progress plain --build-arg 'JOBS=4'
|
||||
|
||||
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 |
|
||||
| Wanted build | Dockerfile path | Target |
|
||||
|--------------|-----------------------------|--------|
|
||||
| MacOS M1 | dist/macOS/arm64.Dockerfile | - |
|
||||
| AppImage | dist/appimage/Dockerfile | - |
|
||||
| Web version | dist/web/Dockerfile | raw |
|
||||
|
||||
We'll explain this command in the next section
|
||||
|
||||
@@ -43,6 +43,7 @@ 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-arg <key>=<value>` is to allow 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)
|
||||
- `--target <target>` specifies which docker target to build
|
||||
|
||||
8
dist/compiling/linux.md
vendored
8
dist/compiling/linux.md
vendored
@@ -13,14 +13,8 @@ CC=gcc-12 CXX=g++-12 \
|
||||
cmake -G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
..
|
||||
make -j 4 install
|
||||
ninja install
|
||||
```
|
||||
|
||||
All paths follow the XDG Base Directories standard, and can thus be modified
|
||||
|
||||
2
dist/compiling/macos.md
vendored
2
dist/compiling/macos.md
vendored
@@ -15,7 +15,7 @@ OBJC=$(brew --prefix llvm)/bin/clang \
|
||||
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
|
||||
cmake -G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX=./install \
|
||||
-DCMAKE_INSTALL_PREFIX="./install" \
|
||||
-DIMHEX_GENERATE_PACKAGE=ON \
|
||||
..
|
||||
ninja install
|
||||
|
||||
2
dist/compiling/windows.md
vendored
2
dist/compiling/windows.md
vendored
@@ -14,7 +14,7 @@ mkdir build
|
||||
cd build
|
||||
cmake -G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCMAKE_INSTALL_PREFIX="./install" \
|
||||
-DIMHEX_USE_DEFAULT_BUILD_SETTINGS=ON \
|
||||
..
|
||||
ninja install
|
||||
|
||||
48
dist/gen_release_notes.py
vendored
Normal file
48
dist/gen_release_notes.py
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def get_commits(branch: str, start_tag: str, end_tag: str) -> list[str]:
|
||||
try:
|
||||
commits_raw = subprocess.check_output([ "git", "--no-pager", "log", branch, "--no-color", "--pretty=oneline", "--abbrev-commit", f"{start_tag}..{end_tag}"], stderr=subprocess.DEVNULL).decode("UTF-8").split("\n")
|
||||
except:
|
||||
return []
|
||||
|
||||
commits = []
|
||||
for line in commits_raw:
|
||||
commits.append(line[9:])
|
||||
|
||||
return commits
|
||||
|
||||
def main(args: list) -> int:
|
||||
if len(args) != 2:
|
||||
print(f"Usage: {args[0]} prev_minor")
|
||||
return 1
|
||||
|
||||
last_minor_version = f"v1.{args[1]}"
|
||||
|
||||
master_commits = get_commits("master", f"{last_minor_version}.0", "master")
|
||||
|
||||
for i in range(1, 100):
|
||||
branch_commits = get_commits(f"releases/{last_minor_version}.X", f"{last_minor_version}.0", f"{last_minor_version}.{i}")
|
||||
|
||||
if len(branch_commits) == 0:
|
||||
break
|
||||
|
||||
master_commits = [commit for commit in master_commits if commit not in branch_commits]
|
||||
|
||||
sorted_commits = {}
|
||||
for commit in master_commits:
|
||||
category, commit_name = commit.split(":", 1)
|
||||
|
||||
if category not in sorted_commits:
|
||||
sorted_commits[category] = []
|
||||
sorted_commits[category].append(commit_name)
|
||||
|
||||
for category in sorted_commits:
|
||||
print(f"## {category}\n")
|
||||
for commit in sorted_commits[category]:
|
||||
print(f"- {commit}")
|
||||
print(f"\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit(main(sys.argv))
|
||||
19
dist/get_deps_tumbleweed.sh
vendored
Executable file
19
dist/get_deps_tumbleweed.sh
vendored
Executable file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
zypper install \
|
||||
cmake \
|
||||
ninja \
|
||||
gcc12 \
|
||||
gcc12-c++ \
|
||||
freetype2-devel \
|
||||
libcurl-devel \
|
||||
dbus-1-devel \
|
||||
file-devel \
|
||||
Mesa-libGL-devel \
|
||||
libglfw-devel \
|
||||
mbedtls-devel \
|
||||
gtk3-devel \
|
||||
libzstd-devel \
|
||||
zlib-devel \
|
||||
bzip3-devel \
|
||||
xz-devel
|
||||
1
dist/imhex.desktop
vendored
1
dist/imhex.desktop
vendored
@@ -8,3 +8,4 @@ Type=Application
|
||||
StartupNotify=true
|
||||
Categories=Development;IDE;
|
||||
StartupWMClass=imhex
|
||||
Keywords=static-analysis;reverse-engineering;disassembler;disassembly;hacking;forensics;hex-editor;cybersecurity;security;binary-analysis;
|
||||
|
||||
238
dist/langtool.py
vendored
Normal file → Executable file
238
dist/langtool.py
vendored
Normal file → Executable file
@@ -1,104 +1,208 @@
|
||||
#!/usr/bin/env python3
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import argparse
|
||||
import json
|
||||
|
||||
# This fixes a CJK full-width character input issue
|
||||
# which makes left halves of deleted characters displayed on screen
|
||||
# pylint: disable=unused-import
|
||||
import re
|
||||
import readline
|
||||
|
||||
DEFAULT_LANG = "en_US"
|
||||
DEFAULT_LANG_PATH = "plugins/*/romfs/lang/"
|
||||
INVALID_TRANSLATION = ""
|
||||
|
||||
|
||||
def handle_missing_key(command, lang_data, key, value):
|
||||
if command == "check":
|
||||
print(f"Error: Translation {lang_data['code']} is missing translation for key '{key}'")
|
||||
exit(2)
|
||||
elif command == "translate" or command == "create":
|
||||
print(f"Key \033[1m'{key}': '{value}'\033[0m is missing in translation '{lang_data['code']}'")
|
||||
new_value = input("Enter translation: ")
|
||||
lang_data["translations"][key] = new_value
|
||||
elif command == "update":
|
||||
lang_data["translations"][key] = INVALID_TRANSLATION
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 3:
|
||||
print(f"Usage: {Path(sys.argv[0]).name} <check|translate|update|create> <lang folder path> <language>")
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="langtool",
|
||||
description="ImHex translate tool",
|
||||
)
|
||||
parser.add_argument(
|
||||
"command",
|
||||
choices=[
|
||||
"check",
|
||||
"translate",
|
||||
"update",
|
||||
"create",
|
||||
"retranslate",
|
||||
"untranslate",
|
||||
"fmtzh",
|
||||
],
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c", "--langdir", default=DEFAULT_LANG_PATH, help="Language folder glob"
|
||||
)
|
||||
parser.add_argument("-l", "--lang", default="", help="Language to translate")
|
||||
parser.add_argument(
|
||||
"-r", "--reflang", default="", help="Language for reference when translating"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-k", "--keys", help="Keys to re-translate (only in re/untranslate mode)"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
command = args.command
|
||||
lang = args.lang
|
||||
|
||||
print(f"Running in {command} mode")
|
||||
lang_files_glob = f"{lang}.json" if lang != "" else "*.json"
|
||||
|
||||
lang_folders = set(Path(".").glob(args.langdir))
|
||||
if len(lang_folders) == 0:
|
||||
print(f"Error: {args.langdir} matches nothing")
|
||||
return 1
|
||||
|
||||
command = sys.argv[1]
|
||||
if command not in ["check", "translate", "update", "create"]:
|
||||
print(f"Unknown command: {command}")
|
||||
return 1
|
||||
for lang_folder in lang_folders:
|
||||
if not lang_folder.is_dir():
|
||||
print(f"Error: {lang_folder} is not a folder")
|
||||
return 1
|
||||
|
||||
print(f"Using langtool in {command} mode")
|
||||
default_lang_data = {}
|
||||
default_lang_path = lang_folder / Path(DEFAULT_LANG + ".json")
|
||||
if not default_lang_path.exists():
|
||||
print(
|
||||
f"Error: Default language file {default_lang_path} does not exist in {lang_folder}"
|
||||
)
|
||||
return 1
|
||||
with default_lang_path.open("r", encoding="utf-8") as file:
|
||||
default_lang_data = json.load(file)
|
||||
|
||||
lang_folder_path = Path(sys.argv[2])
|
||||
if not lang_folder_path.exists():
|
||||
print(f"Error: {lang_folder_path} does not exist")
|
||||
return 1
|
||||
|
||||
if not lang_folder_path.is_dir():
|
||||
print(f"Error: {lang_folder_path} is not a folder")
|
||||
return 1
|
||||
|
||||
lang = sys.argv[3] if len(sys.argv) > 3 else ""
|
||||
|
||||
print(f"Processing language files in {lang_folder_path}...")
|
||||
|
||||
default_lang_file_path = lang_folder_path / Path(DEFAULT_LANG + ".json")
|
||||
if not default_lang_file_path.exists():
|
||||
print(f"Error: Default language file {default_lang_file_path} does not exist")
|
||||
return 1
|
||||
|
||||
print(f"Using file '{default_lang_file_path.name}' as template language file")
|
||||
|
||||
with default_lang_file_path.open("r", encoding="utf-8") as default_lang_file:
|
||||
default_lang_data = json.load(default_lang_file)
|
||||
reference_lang_data = None
|
||||
reference_lang_path = lang_folder / Path(args.reflang + ".json")
|
||||
if reference_lang_path.exists():
|
||||
with reference_lang_path.open("r", encoding="utf-8") as file:
|
||||
reference_lang_data = json.load(file)
|
||||
|
||||
if command == "create" and lang != "":
|
||||
lang_file_path = lang_folder_path / Path(lang + ".json")
|
||||
lang_file_path = lang_folder / Path(lang + ".json")
|
||||
if lang_file_path.exists():
|
||||
print(f"Error: Language file {lang_file_path} already exists")
|
||||
return 1
|
||||
continue
|
||||
|
||||
print(f"Creating new language file '{lang_file_path.name}'")
|
||||
exist_lang_data = None
|
||||
for lang_folder1 in lang_folders:
|
||||
lang_file_path1 = lang_folder1 / Path(lang + ".json")
|
||||
if lang_file_path1.exists():
|
||||
with lang_file_path1.open("r", encoding="utf-8") as file:
|
||||
exist_lang_data = json.load(file)
|
||||
break
|
||||
|
||||
print(f"Creating new language file '{lang_file_path}'")
|
||||
|
||||
with lang_file_path.open("w", encoding="utf-8") as new_lang_file:
|
||||
new_lang_data = {
|
||||
"code": lang,
|
||||
"language": input("Enter language: "),
|
||||
"country": input("Enter country: "),
|
||||
"translations": {}
|
||||
"language": (
|
||||
exist_lang_data["language"]
|
||||
if exist_lang_data
|
||||
else input("Enter language name: ")
|
||||
),
|
||||
"country": (
|
||||
exist_lang_data["country"]
|
||||
if exist_lang_data
|
||||
else input("Enter country name: ")
|
||||
),
|
||||
"translations": {},
|
||||
}
|
||||
json.dump(new_lang_data, new_lang_file, indent=4, ensure_ascii=False)
|
||||
|
||||
for additional_lang_file_path in lang_folder_path.glob("*.json"):
|
||||
if not lang == "" and not additional_lang_file_path.stem == lang:
|
||||
lang_files = set(lang_folder.glob(lang_files_glob))
|
||||
if len(lang_files) == 0:
|
||||
print(f"Warn: Language file for '{lang}' does not exist in '{lang_folder}'")
|
||||
for lang_file_path in lang_files:
|
||||
if (
|
||||
lang_file_path.stem == f"{DEFAULT_LANG}.json"
|
||||
or lang_file_path.stem == f"{args.reflang}.json"
|
||||
):
|
||||
continue
|
||||
|
||||
if additional_lang_file_path.name.startswith(DEFAULT_LANG):
|
||||
continue
|
||||
print(f"\nProcessing '{lang_file_path}'")
|
||||
if not (command == "update" or command == "create"):
|
||||
print("\n----------------------------\n")
|
||||
|
||||
print(f"\nProcessing file '{additional_lang_file_path.name}'\n----------------------------\n")
|
||||
|
||||
with additional_lang_file_path.open("r+", encoding="utf-8") as additional_lang_file:
|
||||
additional_lang_data = json.load(additional_lang_file)
|
||||
with lang_file_path.open("r+", encoding="utf-8") as target_lang_file:
|
||||
lang_data = json.load(target_lang_file)
|
||||
|
||||
for key, value in default_lang_data["translations"].items():
|
||||
if key not in additional_lang_data["translations"] or additional_lang_data["translations"][key] == INVALID_TRANSLATION:
|
||||
handle_missing_key(command, additional_lang_data, key, value)
|
||||
has_translation = (
|
||||
key in lang_data["translations"]
|
||||
and lang_data["translations"][key] != INVALID_TRANSLATION
|
||||
)
|
||||
if not has_translation and not (
|
||||
(command == "retranslate" or command == "untranslate")
|
||||
and re.compile(args.keys).fullmatch(key)
|
||||
):
|
||||
continue
|
||||
if command == "check":
|
||||
print(
|
||||
f"Error: Translation {lang_data['code']} is missing translation for key '{key}'"
|
||||
)
|
||||
exit(2)
|
||||
elif (
|
||||
command == "translate"
|
||||
or command == "retranslate"
|
||||
or command == "untranslate"
|
||||
):
|
||||
if command == "untranslate" and not has_translation:
|
||||
continue
|
||||
reference_tranlsation = (
|
||||
" '%s'" % reference_lang_data["translations"][key]
|
||||
if reference_lang_data
|
||||
else ""
|
||||
)
|
||||
print(
|
||||
f"\033[1m'{key}' '{value}'{reference_tranlsation}\033[0m => {lang_data['language']}",
|
||||
end="",
|
||||
)
|
||||
if has_translation:
|
||||
translation = lang_data["translations"][key]
|
||||
print(f" <= \033[1m'{translation}'\033[0m")
|
||||
print() # for a new line
|
||||
if command == "untranslate":
|
||||
lang_data["translations"][key] = INVALID_TRANSLATION
|
||||
continue
|
||||
try:
|
||||
new_value = input("=> ")
|
||||
lang_data["translations"][key] = new_value
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
elif command == "update" or command == "create":
|
||||
lang_data["translations"][key] = INVALID_TRANSLATION
|
||||
elif command == "fmtzh":
|
||||
if has_translation:
|
||||
lang_data["translations"][key] = fmtzh(
|
||||
lang_data["translations"][key]
|
||||
)
|
||||
|
||||
keys_to_remove = []
|
||||
for key, value in additional_lang_data["translations"].items():
|
||||
for key, value in lang_data["translations"].items():
|
||||
if key not in default_lang_data["translations"]:
|
||||
keys_to_remove.append(key)
|
||||
|
||||
for key in keys_to_remove:
|
||||
additional_lang_data["translations"].pop(key)
|
||||
print(f"Removed unused key '{key}' from translation '{additional_lang_data['code']}'")
|
||||
lang_data["translations"].pop(key)
|
||||
print(
|
||||
f"Removed unused key '{key}' from translation '{lang_data['code']}'"
|
||||
)
|
||||
|
||||
additional_lang_file.seek(0)
|
||||
additional_lang_file.truncate()
|
||||
json.dump(additional_lang_data, additional_lang_file, indent=4, sort_keys=True, ensure_ascii=False)
|
||||
target_lang_file.seek(0)
|
||||
target_lang_file.truncate()
|
||||
json.dump(
|
||||
lang_data,
|
||||
target_lang_file,
|
||||
indent=4,
|
||||
sort_keys=True,
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
def fmtzh(text: str) -> str:
|
||||
text = re.sub(r"(\.{3}|\.{6})", "……", text)
|
||||
text = text.replace("!", "!")
|
||||
text = re.sub(r"([^\.\na-zA-Z\d])\.$", "\1。", text, flags=re.M)
|
||||
text = text.replace("?", "?")
|
||||
return text
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit(main())
|
||||
|
||||
6
dist/macOS/arm64.Dockerfile
vendored
6
dist/macOS/arm64.Dockerfile
vendored
@@ -35,9 +35,9 @@ EOF
|
||||
|
||||
## Download libmagic
|
||||
### Clone libmagic
|
||||
RUN git clone https://github.com/file/file /mnt/file
|
||||
RUN git clone --depth 1 --branch FILE5_45 https://github.com/file/file /mnt/file
|
||||
### Download libmagic dependencies
|
||||
RUN --mount=type=cache,target=/var/lib/apt/lists/ apt install -y libtool autoconf
|
||||
RUN --mount=type=cache,target=/var/lib/apt/lists/ apt update && apt install -y libtool autoconf
|
||||
|
||||
# -- DOWNLOADING + BUILDING STUFF
|
||||
|
||||
@@ -170,4 +170,4 @@ EOF
|
||||
|
||||
|
||||
FROM scratch
|
||||
COPY --from=build /mnt/ImHex/build/install/imhex.app ImHex.app
|
||||
COPY --from=build /mnt/ImHex/build/install/imhex.app imhex.app
|
||||
|
||||
13
dist/rpm/imhex.spec
vendored
13
dist/rpm/imhex.spec
vendored
@@ -1,5 +1,7 @@
|
||||
%define source_date_epoch_from_changelog 0
|
||||
|
||||
Name: imhex
|
||||
Version: 1.26.2
|
||||
Version: VERSION
|
||||
Release: 0%{?dist}
|
||||
Summary: A hex editor for reverse engineers and programmers
|
||||
|
||||
@@ -95,10 +97,6 @@ CXXFLAGS+=" -std=gnu++2b"
|
||||
%set_build_flags
|
||||
CXXFLAGS+=" -std=gnu++2b"
|
||||
%endif
|
||||
# build binaries required for tests
|
||||
%cmake_build --target unit_tests
|
||||
%ctest --exclude-regex '(Helpers/StoreAPI|Helpers/TipsAPI|Helpers/ContentAPI)'
|
||||
# Helpers/*API exclude tests that require network access
|
||||
|
||||
|
||||
%install
|
||||
@@ -128,7 +126,4 @@ cp -a lib/third_party/xdgpp/LICENSE %{buildroot
|
||||
%{_datadir}/applications/%{name}.desktop
|
||||
%{_libdir}/libimhex.so*
|
||||
%{_libdir}/%{name}/
|
||||
%{_metainfodir}/net.werwolv.%{name}.metainfo.xml
|
||||
|
||||
|
||||
%changelog
|
||||
%{_metainfodir}/net.werwolv.%{name}.metainfo.xml
|
||||
1
dist/web/Dockerfile
vendored
1
dist/web/Dockerfile
vendored
@@ -59,6 +59,7 @@ cmake /imhex
|
||||
-DIMHEX_OFFLINE_BUILD=ON \
|
||||
-DIMHEX_STATIC_LINK_PLUGINS=ON \
|
||||
-DIMHEX_EXCLUDE_PLUGINS="script_loader" \
|
||||
-DIMHEX_COMPRESS_DEBUG_INFO=OFF \
|
||||
-DNATIVE_CMAKE_C_COMPILER=gcc \
|
||||
-DNATIVE_CMAKE_CXX_COMPILER=g++ \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
|
||||
2
dist/web/source/index.html
vendored
2
dist/web/source/index.html
vendored
@@ -62,7 +62,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="loading" class="centered">
|
||||
<img src="https://raw.githubusercontent.com/WerWolv/ImHex/master/plugins/builtin/romfs/assets/dark/banner.png" id="logo" alt="ImHex Logo">
|
||||
<img src="https://raw.githubusercontent.com/WerWolv/ImHex/master/plugins/builtin/romfs/assets/dark/banner.svg" id="logo" alt="ImHex Logo">
|
||||
<h1>A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</h1>
|
||||
<h2>Available both natively and on the web</h2>
|
||||
<h5>ImHex runs directly in your web browser with the help of Emscripten and WebAssembly.</h5>
|
||||
|
||||
13
dist/web/source/style.css
vendored
13
dist/web/source/style.css
vendored
@@ -137,7 +137,7 @@ a:hover {
|
||||
|
||||
|
||||
:root {
|
||||
--progress: 25%;
|
||||
--progress: 0%;
|
||||
}
|
||||
|
||||
.progress-bar-container {
|
||||
@@ -174,4 +174,15 @@ a:hover {
|
||||
.progress-moved .progress-bar {
|
||||
width: var(--progress);
|
||||
background-color: #3864cb;
|
||||
}
|
||||
|
||||
#logo {
|
||||
height: 25%;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.canvas-fixed {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
137
dist/web/source/wasm-config.js
vendored
137
dist/web/source/wasm-config.js
vendored
@@ -100,7 +100,77 @@ var notWorkingTimer = setTimeout(() => {
|
||||
|
||||
var Module = {
|
||||
preRun: [],
|
||||
postRun: [],
|
||||
postRun: function() {
|
||||
// Patch the emscripten GLFW module to send mouse and touch events in the right order
|
||||
// For ImGui interactions to correctly work with touch input, MousePos events need
|
||||
// to be processed first and then MouseButton events in the next frame. By default,
|
||||
// GLFW does the exact opposite, which causes buttons to require two taps to register
|
||||
// and windows get "stuck" to the cursor when dragged or resized
|
||||
GLFW.onMousemove = event => {
|
||||
if (event.type === "touchmove") {
|
||||
event.preventDefault();
|
||||
let primaryChanged = false;
|
||||
for (let i of event.changedTouches) {
|
||||
if (GLFW.primaryTouchId === i.identifier) {
|
||||
Browser.setMouseCoords(i.pageX, i.pageY);
|
||||
primaryChanged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!primaryChanged) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Browser.calculateMouseEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
GLFW.onMouseButtonChanged = (event, status) => {
|
||||
if (!GLFW.active) return;
|
||||
if (event.target != Module["canvas"]) return;
|
||||
const isTouchType = event.type === "touchstart" || event.type === "touchend" || event.type === "touchcancel";
|
||||
let eventButton = 0;
|
||||
if (isTouchType) {
|
||||
event.preventDefault();
|
||||
let primaryChanged = false;
|
||||
if (GLFW.primaryTouchId === null && event.type === "touchstart" && event.targetTouches.length > 0) {
|
||||
const chosenTouch = event.targetTouches[0];
|
||||
GLFW.primaryTouchId = chosenTouch.identifier;
|
||||
Browser.setMouseCoords(chosenTouch.pageX, chosenTouch.pageY);
|
||||
primaryChanged = true;
|
||||
} else if (event.type === "touchend" || event.type === "touchcancel") {
|
||||
for (let i of event.changedTouches) {
|
||||
if (GLFW.primaryTouchId === i.identifier) {
|
||||
GLFW.primaryTouchId = null;
|
||||
primaryChanged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!primaryChanged) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Browser.calculateMouseEvent(event);
|
||||
eventButton = GLFW.DOMToGLFWMouseButton(event);
|
||||
}
|
||||
if (status == 1) {
|
||||
GLFW.active.buttons |= (1 << eventButton);
|
||||
try {
|
||||
event.target.setCapture();
|
||||
} catch (e) {}
|
||||
} else {
|
||||
GLFW.active.buttons &= ~(1 << eventButton);
|
||||
}
|
||||
|
||||
if (GLFW.active.cursorPosFunc) {
|
||||
getWasmTableEntry(GLFW.active.cursorPosFunc)(GLFW.active.id, Browser.mouseX, Browser.mouseY);
|
||||
}
|
||||
if (GLFW.active.mouseButtonFunc) {
|
||||
getWasmTableEntry(GLFW.active.mouseButtonFunc)(GLFW.active.id, eventButton, status, GLFW.getModBits(GLFW.active));
|
||||
}
|
||||
};
|
||||
},
|
||||
onRuntimeInitialized: function() {
|
||||
// Triggered when the wasm module is loaded and ready to use.
|
||||
document.getElementById("loading").style.display = "none"
|
||||
@@ -111,13 +181,55 @@ var Module = {
|
||||
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);
|
||||
const canvas = document.getElementById('canvas');
|
||||
canvas.addEventListener("webglcontextlost", function(e) {
|
||||
alert('WebGL context lost, please reload the page');
|
||||
e.preventDefault();
|
||||
}, false);
|
||||
|
||||
return canvas;
|
||||
// Turn long touches into right-clicks
|
||||
let timer = null;
|
||||
canvas.addEventListener('touchstart', event => {
|
||||
timer = setTimeout(() => {
|
||||
let eventArgs = {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
view: window,
|
||||
screenX: event.touches[0].screenX,
|
||||
screenY: event.touches[0].screenY,
|
||||
clientX: event.touches[0].clientX,
|
||||
clientY: event.touches[0].clientY,
|
||||
button: 2,
|
||||
buttons: 2,
|
||||
relatedTarget: event.target,
|
||||
region: event.region
|
||||
}
|
||||
|
||||
canvas.dispatchEvent(new MouseEvent('mousedown', eventArgs));
|
||||
canvas.dispatchEvent(new MouseEvent('mouseup', eventArgs));
|
||||
}, 400);
|
||||
});
|
||||
|
||||
canvas.addEventListener('touchend', event => {
|
||||
if (timer) {
|
||||
clearTimeout(timer);
|
||||
timer = null;
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof WebGL2RenderingContext !== 'undefined') {
|
||||
let gl = canvas.getContext('webgl2', { stencil: true });
|
||||
if (!gl) {
|
||||
console.error('WebGL 2 not available, falling back to WebGL');
|
||||
gl = canvas.getContext('webgl', { stencil: true });
|
||||
}
|
||||
if (!gl) {
|
||||
alert('WebGL not available with stencil buffer');
|
||||
}
|
||||
return canvas;
|
||||
} else {
|
||||
alert('WebGL 2 not supported by this browser');
|
||||
}
|
||||
})(),
|
||||
setStatus: function(text) { },
|
||||
totalDependencies: 0,
|
||||
@@ -144,14 +256,9 @@ if (urlParams.has("lang")) {
|
||||
window.addEventListener('resize', js_resizeCanvas, false);
|
||||
function js_resizeCanvas() {
|
||||
let canvas = document.getElementById('canvas');
|
||||
|
||||
canvas.top = document.documentElement.clientTop;
|
||||
canvas.left = document.documentElement.clientLeft;
|
||||
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")
|
||||
|
||||
if (GLFW.active && GLFW.active.windowPosFunc) {
|
||||
getWasmTableEntry(GLFW.active.windowPosFunc)(GLFW.active.id, GLFW.active.x, GLFW.active.y);
|
||||
}
|
||||
|
||||
GLFW.onWindowSizeChanged();
|
||||
}
|
||||
2
lib/external/libromfs
vendored
2
lib/external/libromfs
vendored
Submodule lib/external/libromfs updated: 61f7e412dd...03adcfdde0
2
lib/external/libwolv
vendored
2
lib/external/libwolv
vendored
Submodule lib/external/libwolv updated: 2ddf596306...0e3ba3aa6f
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
Submodule lib/external/pattern_language updated: 2dae41613b...c7bca89b1a
@@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 3.16)
|
||||
project(libimhex)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
set(LIBIMHEX_SOURCES
|
||||
source/api/imhex_api.cpp
|
||||
@@ -37,6 +36,10 @@ set(LIBIMHEX_SOURCES
|
||||
source/helpers/logger.cpp
|
||||
source/helpers/tar.cpp
|
||||
source/helpers/debugging.cpp
|
||||
source/helpers/default_paths.cpp
|
||||
source/helpers/imgui_hooks.cpp
|
||||
|
||||
source/test/tests.cpp
|
||||
|
||||
source/providers/provider.cpp
|
||||
source/providers/memory_provider.cpp
|
||||
@@ -77,37 +80,6 @@ else()
|
||||
target_compile_definitions(libimhex PRIVATE IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||
endif()
|
||||
|
||||
enableUnityBuild(libimhex)
|
||||
setupCompilerFlags(libimhex)
|
||||
|
||||
include(GenerateExportHeader)
|
||||
generate_export_header(libimhex)
|
||||
|
||||
target_include_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} include ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIR} ${MAGIC_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${LIBBACKTRACE_INCLUDE_DIRS})
|
||||
target_link_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${MBEDTLS_LIBRARY_DIR} ${MAGIC_LIBRARY_DIRS})
|
||||
|
||||
if (NOT EMSCRIPTEN)
|
||||
# curl is only used in non-emscripten builds
|
||||
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${CURL_LIBRARIES})
|
||||
endif()
|
||||
|
||||
|
||||
if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD)
|
||||
if (WIN32)
|
||||
set_target_properties(libimhex PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
|
||||
target_link_options(libimhex PRIVATE -Wl,--export-all-symbols)
|
||||
elseif (APPLE)
|
||||
find_library(FOUNDATION NAMES Foundation)
|
||||
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
|
||||
endif ()
|
||||
|
||||
target_link_libraries(libimhex PRIVATE microtar libwolv ${NFD_LIBRARIES} magic dl ${JTHREAD_LIBRARIES})
|
||||
target_link_libraries(libimhex PUBLIC libpl ${IMGUI_LIBRARIES})
|
||||
endif()
|
||||
|
||||
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${NLOHMANN_JSON_LIBRARIES} imgui_all_includes ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES})
|
||||
|
||||
set_property(TARGET libimhex PROPERTY INTERPROCEDURAL_OPTIMIZATION FALSE)
|
||||
|
||||
if (DEFINED IMHEX_COMMIT_HASH_LONG AND DEFINED IMHEX_COMMIT_BRANCH)
|
||||
set(GIT_COMMIT_HASH_LONG "${IMHEX_COMMIT_HASH_LONG}")
|
||||
@@ -142,4 +114,42 @@ endif ()
|
||||
|
||||
addDefineToSource(source/api/imhex_api.cpp "IMHEX_VERSION=\"${IMHEX_VERSION_STRING}\"")
|
||||
|
||||
add_dependencies(imhex_all libimhex)
|
||||
enableUnityBuild(libimhex)
|
||||
setupCompilerFlags(libimhex)
|
||||
|
||||
include(GenerateExportHeader)
|
||||
generate_export_header(libimhex)
|
||||
|
||||
target_include_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} include ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIR} ${MAGIC_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${LIBBACKTRACE_INCLUDE_DIRS})
|
||||
target_link_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${MBEDTLS_LIBRARY_DIR} ${MAGIC_LIBRARY_DIRS})
|
||||
|
||||
if (NOT EMSCRIPTEN)
|
||||
# curl is only used in non-emscripten builds
|
||||
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} CURL::libcurl)
|
||||
endif()
|
||||
|
||||
|
||||
if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD)
|
||||
if (WIN32)
|
||||
set_target_properties(libimhex PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
|
||||
target_link_options(libimhex PRIVATE -Wl,--export-all-symbols)
|
||||
elseif (APPLE)
|
||||
find_library(FOUNDATION NAMES Foundation)
|
||||
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
|
||||
endif ()
|
||||
|
||||
target_link_libraries(libimhex PRIVATE microtar libwolv ${NFD_LIBRARIES} magic dl ${JTHREAD_LIBRARIES})
|
||||
target_link_libraries(libimhex PUBLIC libpl ${IMGUI_LIBRARIES})
|
||||
|
||||
precompileHeaders(libimhex "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
endif()
|
||||
|
||||
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${NLOHMANN_JSON_LIBRARIES} imgui_all_includes ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${LUNASVG_LIBRARIES} ${BOOST_LIBRARIES})
|
||||
|
||||
set_property(TARGET libimhex PROPERTY INTERPROCEDURAL_OPTIMIZATION FALSE)
|
||||
|
||||
add_dependencies(imhex_all libimhex)
|
||||
|
||||
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}" PERMISSIONS ${LIBRARY_PERMISSIONS})
|
||||
set_target_properties(libimhex PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set_target_properties(libimhex PROPERTIES PREFIX "")
|
||||
@@ -151,7 +151,7 @@ namespace hex {
|
||||
if (m_icon.isValid())
|
||||
return m_icon;
|
||||
|
||||
m_icon = ImGuiExt::Texture(m_iconData.data(), m_iconData.size(), ImGuiExt::Texture::Filter::Linear);
|
||||
m_icon = ImGuiExt::Texture::fromImage(m_iconData.data(), m_iconData.size(), ImGuiExt::Texture::Filter::Linear);
|
||||
|
||||
return m_icon;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -98,7 +99,7 @@ namespace hex {
|
||||
bool m_requiresRestart = false;
|
||||
std::function<bool()> m_enabledCallback;
|
||||
std::function<void(Widget&)> m_changedCallback;
|
||||
std::optional<std::string> m_tooltip;
|
||||
std::optional<UnlocalizedString> m_tooltip;
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
@@ -112,7 +113,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const std::optional<std::string>& getTooltip() const {
|
||||
const std::optional<UnlocalizedString>& getTooltip() const {
|
||||
return m_interface.m_tooltip;
|
||||
}
|
||||
|
||||
@@ -175,6 +176,21 @@ namespace hex {
|
||||
float m_min, m_max;
|
||||
};
|
||||
|
||||
class SliderDataSize : public Widget {
|
||||
public:
|
||||
SliderDataSize(u64 defaultValue, u64 min, u64 max) : m_value(defaultValue), m_min(min), m_max(max) { }
|
||||
bool draw(const std::string &name) override;
|
||||
|
||||
void load(const nlohmann::json &data) override;
|
||||
nlohmann::json store() override;
|
||||
|
||||
[[nodiscard]] i32 getValue() const { return m_value; }
|
||||
|
||||
protected:
|
||||
u64 m_value;
|
||||
u64 m_min, m_max;
|
||||
};
|
||||
|
||||
class ColorPicker : public Widget {
|
||||
public:
|
||||
explicit ColorPicker(ImColor defaultColor);
|
||||
@@ -340,6 +356,8 @@ namespace hex {
|
||||
void write(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const std::common_type_t<T> &value) {
|
||||
impl::getSetting(unlocalizedCategory, unlocalizedName, value) = value;
|
||||
impl::runOnChangeHandlers(unlocalizedCategory, unlocalizedName, value);
|
||||
|
||||
impl::store();
|
||||
}
|
||||
|
||||
using OnChangeCallback = std::function<void(const SettingsValue &)>;
|
||||
@@ -756,6 +774,7 @@ namespace hex {
|
||||
const std::multimap<u32, MainMenuItem>& getMainMenuItems();
|
||||
|
||||
const std::multimap<u32, MenuItem>& getMenuItems();
|
||||
const std::vector<MenuItem*>& getToolbarMenuItems();
|
||||
std::multimap<u32, MenuItem>& getMenuItemsMutable();
|
||||
|
||||
const std::vector<DrawCallback>& getWelcomeScreenEntries();
|
||||
@@ -898,6 +917,11 @@ namespace hex {
|
||||
*/
|
||||
void addMenuItemToToolbar(const UnlocalizedString &unlocalizedName, ImGuiCustomCol color);
|
||||
|
||||
/**
|
||||
* @brief Reconstructs the toolbar items list after they have been modified
|
||||
*/
|
||||
void updateToolbarItems();
|
||||
|
||||
/**
|
||||
* @brief Adds a new sidebar item
|
||||
* @param icon The icon to use for the item
|
||||
@@ -931,7 +955,7 @@ namespace hex {
|
||||
|
||||
void addProviderName(const UnlocalizedString &unlocalizedName);
|
||||
|
||||
using ProviderCreationFunction = std::unique_ptr<prv::Provider>(*)();
|
||||
using ProviderCreationFunction = std::function<std::unique_ptr<prv::Provider>()>;
|
||||
void add(const std::string &typeName, ProviderCreationFunction creationFunction);
|
||||
|
||||
const std::vector<std::string>& getEntries();
|
||||
@@ -963,12 +987,34 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
using Callback = std::function<std::string(prv::Provider *provider, u64 address, size_t size)>;
|
||||
struct Entry {
|
||||
struct ExportMenuEntry {
|
||||
UnlocalizedString unlocalizedName;
|
||||
Callback callback;
|
||||
};
|
||||
|
||||
const std::vector<Entry>& getEntries();
|
||||
struct FindOccurrence {
|
||||
Region region;
|
||||
enum class DecodeType { ASCII, Binary, UTF16, Unsigned, Signed, Float, Double } decodeType;
|
||||
std::endian endian = std::endian::native;
|
||||
bool selected;
|
||||
};
|
||||
|
||||
using FindExporterCallback = std::function<std::vector<u8>(const std::vector<FindOccurrence>&, std::function<std::string(FindOccurrence)>)>;
|
||||
struct FindExporterEntry {
|
||||
UnlocalizedString unlocalizedName;
|
||||
std::string fileExtension;
|
||||
FindExporterCallback callback;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Retrieves a list of all registered data formatters used by the 'File -> Export' menu
|
||||
*/
|
||||
const std::vector<ExportMenuEntry>& getExportMenuEntries();
|
||||
|
||||
/**
|
||||
* @brief Retrieves a list of all registered data formatters used in the Results section of the 'Find' view
|
||||
*/
|
||||
const std::vector<FindExporterEntry>& getFindExporterEntries();
|
||||
|
||||
}
|
||||
|
||||
@@ -978,7 +1024,14 @@ namespace hex {
|
||||
* @param unlocalizedName The unlocalized name of the formatter
|
||||
* @param callback The function to call to format the data
|
||||
*/
|
||||
void add(const UnlocalizedString &unlocalizedName, const impl::Callback &callback);
|
||||
void addExportMenuEntry(const UnlocalizedString &unlocalizedName, const impl::Callback &callback);
|
||||
|
||||
/**
|
||||
* @brief Adds a new data exporter for Find results
|
||||
* @param unlocalizedName The unlocalized name of the formatter
|
||||
* @param callback The function to call to format the data
|
||||
*/
|
||||
void addFindExportFormatter(const UnlocalizedString &unlocalizedName, const std::string fileExtension, const impl::FindExporterCallback &callback);
|
||||
|
||||
}
|
||||
|
||||
@@ -1039,7 +1092,7 @@ namespace hex {
|
||||
};
|
||||
|
||||
struct MiniMapVisualizer {
|
||||
using Callback = std::function<ImColor(const std::vector<u8>&)>;
|
||||
using Callback = std::function<void(u64, std::span<const u8>, std::vector<ImColor>&)>;
|
||||
|
||||
UnlocalizedString unlocalizedName;
|
||||
Callback callback;
|
||||
|
||||
@@ -2,28 +2,30 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
#include <string_view>
|
||||
#include <functional>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <wolv/types/type_name.hpp>
|
||||
|
||||
#define EVENT_DEF_IMPL(event_name, event_name_string, should_log, ...) \
|
||||
struct event_name final : public hex::impl::Event<__VA_ARGS__> { \
|
||||
constexpr static auto Id = [] { return hex::impl::EventId(event_name_string); }(); \
|
||||
constexpr static auto ShouldLog = (should_log); \
|
||||
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
|
||||
\
|
||||
static EventManager::EventList::iterator subscribe(Event::Callback function) { return EventManager::subscribe<event_name>(function); } \
|
||||
static void subscribe(void *token, Event::Callback function) { EventManager::subscribe<event_name>(token, function); } \
|
||||
static void unsubscribe(const EventManager::EventList::iterator &token) noexcept { EventManager::unsubscribe(token); } \
|
||||
static void unsubscribe(void *token) noexcept { EventManager::unsubscribe<event_name>(token); } \
|
||||
static void post(auto &&...args) noexcept { EventManager::post<event_name>(std::forward<decltype(args)>(args)...); } \
|
||||
};
|
||||
#define EVENT_DEF_IMPL(event_name, event_name_string, should_log, ...) \
|
||||
struct event_name final : public hex::impl::Event<__VA_ARGS__> { \
|
||||
constexpr static auto Id = [] { return hex::impl::EventId(event_name_string); }(); \
|
||||
constexpr static auto ShouldLog = (should_log); \
|
||||
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
|
||||
\
|
||||
static EventManager::EventList::iterator subscribe(Event::Callback function) { return EventManager::subscribe<event_name>(std::move(function)); } \
|
||||
static void subscribe(void *token, Event::Callback function) { EventManager::subscribe<event_name>(token, std::move(function)); } \
|
||||
static void unsubscribe(const EventManager::EventList::iterator &token) noexcept { EventManager::unsubscribe(token); } \
|
||||
static void unsubscribe(void *token) noexcept { EventManager::unsubscribe<event_name>(token); } \
|
||||
static void post(auto &&...args) { EventManager::post<event_name>(std::forward<decltype(args)>(args)...); } \
|
||||
}
|
||||
|
||||
#define EVENT_DEF(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, true, __VA_ARGS__)
|
||||
#define EVENT_DEF_NO_LOG(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, false, __VA_ARGS__)
|
||||
@@ -56,6 +58,10 @@ namespace hex {
|
||||
return m_hash == other.m_hash;
|
||||
}
|
||||
|
||||
constexpr auto operator<=>(const EventId &other) const {
|
||||
return m_hash <=> other.m_hash;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_hash;
|
||||
};
|
||||
@@ -71,11 +77,13 @@ namespace hex {
|
||||
|
||||
explicit Event(Callback func) noexcept : m_func(std::move(func)) { }
|
||||
|
||||
void operator()(Params... params) const noexcept {
|
||||
template<typename E>
|
||||
void call(Params... params) const {
|
||||
try {
|
||||
m_func(params...);
|
||||
} catch (const std::exception &e) {
|
||||
log::error("An exception occurred while handling event: {}", e.what());
|
||||
log::error("An exception occurred while handling event {}: {}", wolv::type::getTypeName<E>(), e.what());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +103,7 @@ namespace hex {
|
||||
*/
|
||||
class EventManager {
|
||||
public:
|
||||
using EventList = std::list<std::pair<impl::EventId, std::unique_ptr<impl::EventBase>>>;
|
||||
using EventList = std::multimap<impl::EventId, std::unique_ptr<impl::EventBase>>;
|
||||
|
||||
/**
|
||||
* @brief Subscribes to an event
|
||||
@@ -108,7 +116,7 @@ namespace hex {
|
||||
std::scoped_lock lock(getEventMutex());
|
||||
|
||||
auto &events = getEvents();
|
||||
return events.insert(events.end(), std::make_pair(E::Id, std::make_unique<E>(function)));
|
||||
return events.insert({ E::Id, std::make_unique<E>(function) });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,7 +168,7 @@ namespace hex {
|
||||
});
|
||||
|
||||
if (iter != tokenStore.end()) {
|
||||
getEvents().remove(*iter->second);
|
||||
getEvents().erase(iter->second);
|
||||
tokenStore.erase(iter);
|
||||
}
|
||||
|
||||
@@ -172,17 +180,17 @@ namespace hex {
|
||||
* @param args Arguments to pass to the event
|
||||
*/
|
||||
template<impl::EventType E>
|
||||
static void post(auto &&...args) noexcept {
|
||||
static void post(auto && ...args) {
|
||||
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)...);
|
||||
}
|
||||
auto [begin, end] = getEvents().equal_range(E::Id);
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
const auto &[id, event] = *it;
|
||||
(*static_cast<E *const>(event.get())).template call<E>(std::forward<decltype(args)>(args)...);
|
||||
}
|
||||
|
||||
#if defined (DEBUG)
|
||||
if (E::ShouldLog)
|
||||
if constexpr (E::ShouldLog)
|
||||
log::debug("Event posted: '{}'", wolv::type::getTypeName<E>());
|
||||
#endif
|
||||
}
|
||||
@@ -262,6 +270,7 @@ namespace hex {
|
||||
EVENT_DEF(EventProviderDataModified, prv::Provider *, u64, u64, const u8*);
|
||||
EVENT_DEF(EventProviderDataInserted, prv::Provider *, u64, u64);
|
||||
EVENT_DEF(EventProviderDataRemoved, prv::Provider *, u64, u64);
|
||||
EVENT_DEF(EventProviderDirtied, prv::Provider *);
|
||||
|
||||
/**
|
||||
* @brief Called when a project has been loaded
|
||||
@@ -271,6 +280,7 @@ namespace hex {
|
||||
EVENT_DEF_NO_LOG(EventFrameBegin);
|
||||
EVENT_DEF_NO_LOG(EventFrameEnd);
|
||||
EVENT_DEF_NO_LOG(EventSetTaskBarIconState, u32, u32, u32);
|
||||
EVENT_DEF_NO_LOG(EventImGuiElementRendered, ImGuiID, const std::array<float, 4>&);
|
||||
|
||||
EVENT_DEF(RequestAddInitTask, std::string, bool, std::function<bool()>);
|
||||
EVENT_DEF(RequestAddExitTask, std::string, std::function<bool()>);
|
||||
@@ -308,4 +318,9 @@ namespace hex {
|
||||
* The 'from' provider should not have any per provider data after this, and should be immediately deleted
|
||||
*/
|
||||
EVENT_DEF(MovePerProviderData, prv::Provider *, prv::Provider *);
|
||||
|
||||
/**
|
||||
* Called when ImHex managed to catch an error in a general try/catch to prevent/recover from a crash
|
||||
*/
|
||||
EVENT_DEF(EventCrashRecovered, const std::exception &);
|
||||
}
|
||||
@@ -3,11 +3,13 @@
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <wolv/io/fs.hpp>
|
||||
|
||||
@@ -73,7 +75,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t, bool)>;
|
||||
using HoveringFunction = std::function<bool(const prv::Provider *, u64, const u8*, size_t)>;
|
||||
using HoveringFunction = std::function<std::set<Region>(const prv::Provider *, u64, size_t)>;
|
||||
|
||||
const std::map<u32, Highlighting>& getBackgroundHighlights();
|
||||
const std::map<u32, HighlightingFunction>& getBackgroundHighlightingFunctions();
|
||||
@@ -291,7 +293,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
void resetClosingProvider();
|
||||
const std::vector<prv::Provider*>& getClosingProviders();
|
||||
std::set<prv::Provider*> getClosingProviders();
|
||||
|
||||
}
|
||||
|
||||
@@ -432,6 +434,7 @@ namespace hex {
|
||||
void setInitialWindowProperties(InitialWindowProperties properties);
|
||||
|
||||
void setGPUVendor(const std::string &vendor);
|
||||
void setGLRenderer(const std::string &renderer);
|
||||
|
||||
void addInitArgument(const std::string &key, const std::string &value = { });
|
||||
|
||||
@@ -571,6 +574,12 @@ namespace hex {
|
||||
*/
|
||||
const std::string& getGPUVendor();
|
||||
|
||||
/**
|
||||
* @brief Gets the current GPU vendor
|
||||
* @return The current GPU vendor
|
||||
*/
|
||||
const std::string& getGLRenderer();
|
||||
|
||||
/**
|
||||
* @brief Checks if ImHex is running in portable mode
|
||||
* @return Whether ImHex is running in portable mode
|
||||
@@ -595,6 +604,16 @@ namespace hex {
|
||||
*/
|
||||
std::string getArchitecture();
|
||||
|
||||
|
||||
struct LinuxDistro {
|
||||
std::string name;
|
||||
std::string version;
|
||||
};
|
||||
/**
|
||||
* @brief Gets information related to the Linux distribution, if running on Linux
|
||||
*/
|
||||
std::optional<LinuxDistro> getLinuxDistro();
|
||||
|
||||
/**
|
||||
* @brief Gets the current ImHex version
|
||||
* @return ImHex version
|
||||
@@ -620,6 +639,12 @@ namespace hex {
|
||||
*/
|
||||
bool isDebugBuild();
|
||||
|
||||
/**
|
||||
* @brief Checks if this version of ImHex is a nightly build
|
||||
* @return True if this version is a nightly, false if it's a release
|
||||
*/
|
||||
bool isNightlyBuild();
|
||||
|
||||
enum class UpdateType {
|
||||
Stable,
|
||||
Nightly
|
||||
@@ -664,6 +689,12 @@ namespace hex {
|
||||
*/
|
||||
std::optional<InitialWindowProperties> getInitialWindowProperties();
|
||||
|
||||
/**
|
||||
* @brief Gets the module handle of libimhex
|
||||
* @return Module handle
|
||||
*/
|
||||
void* getLibImHexModuleHandle();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -698,6 +729,7 @@ namespace hex {
|
||||
std::vector<GlyphRange> glyphRanges;
|
||||
Offset offset;
|
||||
u32 flags;
|
||||
std::optional<u32> defaultSize;
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
@@ -716,8 +748,8 @@ namespace hex {
|
||||
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);
|
||||
void loadFont(const std::fs::path &path, const std::vector<GlyphRange> &glyphRanges = {}, Offset offset = {}, u32 flags = 0, std::optional<u32> defaultSize = std::nullopt);
|
||||
void loadFont(const std::string &name, const std::span<const u8> &data, const std::vector<GlyphRange> &glyphRanges = {}, Offset offset = {}, u32 flags = 0, std::optional<u32> defaultSize = std::nullopt);
|
||||
|
||||
constexpr static float DefaultFontSize = 13.0;
|
||||
|
||||
|
||||
@@ -46,7 +46,13 @@ namespace hex {
|
||||
* @brief Get a list of all layouts
|
||||
* @return List of all added layouts
|
||||
*/
|
||||
static std::vector<Layout> getLayouts();
|
||||
static const std::vector<Layout> &getLayouts();
|
||||
|
||||
/**
|
||||
* @brief Removes the layout with the given name
|
||||
* @param name Name of the layout
|
||||
*/
|
||||
static void removeLayout(const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief Handles loading of layouts if needed
|
||||
|
||||
@@ -102,12 +102,9 @@ namespace hex {
|
||||
std::string m_unlocalizedString;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
// {fmt} formatter for hex::Lang
|
||||
inline auto format_as(const hex::Lang &entry) {
|
||||
return entry.get();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -15,8 +15,10 @@ struct ImGuiContext;
|
||||
namespace hex {
|
||||
|
||||
struct SubCommand {
|
||||
std::string commandKey;
|
||||
std::string commandDesc;
|
||||
std::string commandLong;
|
||||
std::string commandShort;
|
||||
|
||||
std::string commandDescription;
|
||||
std::function<void(const std::vector<std::string>&)> callback;
|
||||
};
|
||||
|
||||
@@ -104,6 +106,10 @@ namespace hex {
|
||||
|
||||
static bool load();
|
||||
static bool load(const std::fs::path &pluginFolder);
|
||||
|
||||
static bool loadLibraries();
|
||||
static bool loadLibraries(const std::fs::path &libraryFolder);
|
||||
|
||||
static void unload();
|
||||
static void reload();
|
||||
static void initializeNewPlugins();
|
||||
@@ -111,6 +117,7 @@ namespace hex {
|
||||
|
||||
static void addPlugin(const std::string &name, PluginFunctions functions);
|
||||
|
||||
static Plugin* getPlugin(const std::string &name);
|
||||
static const std::list<Plugin>& getPlugins();
|
||||
static const std::vector<std::fs::path>& getPluginPaths();
|
||||
static const std::vector<std::fs::path>& getPluginLoadPaths();
|
||||
@@ -121,6 +128,7 @@ namespace hex {
|
||||
static std::list<Plugin>& getPluginsMutable();
|
||||
|
||||
static AutoReset<std::vector<std::fs::path>> s_pluginPaths, s_pluginLoadPaths;
|
||||
static AutoReset<std::vector<uintptr_t>> s_loadedLibraries;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -119,6 +119,8 @@ namespace hex {
|
||||
decltype(m_steps)::iterator m_currentStep, m_latestStep;
|
||||
};
|
||||
|
||||
static void init();
|
||||
|
||||
/**
|
||||
* @brief Gets a list of all tutorials
|
||||
* @return List of all tutorials
|
||||
@@ -145,6 +147,10 @@ namespace hex {
|
||||
*/
|
||||
static void startTutorial(const UnlocalizedString &unlocalizedName);
|
||||
|
||||
static void startHelpHover();
|
||||
static void addInteractiveHelpText(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, UnlocalizedString unlocalizedString);
|
||||
static void addInteractiveHelpLink(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, std::string link);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Draws the tutorial
|
||||
|
||||
@@ -13,18 +13,22 @@ namespace hex {
|
||||
struct Workspace {
|
||||
std::string layout;
|
||||
std::fs::path path;
|
||||
bool builtin;
|
||||
};
|
||||
|
||||
static void createWorkspace(const std::string &name, const std::string &layout = "");
|
||||
static void switchWorkspace(const std::string &name);
|
||||
|
||||
static void importFromFile(const std::fs::path &path);
|
||||
static bool exportToFile(std::fs::path path = {}, std::string workspaceName = {});
|
||||
static bool exportToFile(std::fs::path path = {}, std::string workspaceName = {}, bool builtin = false);
|
||||
|
||||
static void removeWorkspace(const std::string &name);
|
||||
|
||||
static const auto& getWorkspaces() { return *s_workspaces; }
|
||||
static const auto& getCurrentWorkspace() { return s_currentWorkspace; }
|
||||
|
||||
static void reset();
|
||||
static void reload();
|
||||
|
||||
static void process();
|
||||
|
||||
@@ -32,7 +36,7 @@ namespace hex {
|
||||
WorkspaceManager() = default;
|
||||
|
||||
static AutoReset<std::map<std::string, Workspace>> s_workspaces;
|
||||
static decltype(s_workspaces)::Type::iterator s_currentWorkspace, s_previousWorkspace;
|
||||
static decltype(s_workspaces)::Type::iterator s_currentWorkspace, s_previousWorkspace, s_workspaceToRemove;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -50,14 +50,23 @@ namespace hex {
|
||||
|
||||
T& operator=(const T &value) {
|
||||
m_value = value;
|
||||
m_valid = true;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
T& operator=(T &&value) noexcept {
|
||||
m_value = std::move(value);
|
||||
m_valid = true;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
private:
|
||||
friend void ImHexApi::System::impl::cleanup();
|
||||
|
||||
void reset() override {
|
||||
if constexpr (requires { m_value.reset(); }) {
|
||||
m_value.reset();
|
||||
@@ -68,9 +77,12 @@ namespace hex {
|
||||
} else {
|
||||
m_value = { };
|
||||
}
|
||||
|
||||
m_valid = false;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_valid = true;
|
||||
T m_value;
|
||||
};
|
||||
|
||||
|
||||
111
lib/libimhex/include/hex/helpers/default_paths.hpp
Normal file
111
lib/libimhex/include/hex/helpers/default_paths.hpp
Normal file
@@ -0,0 +1,111 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace hex::paths {
|
||||
|
||||
namespace impl {
|
||||
|
||||
class DefaultPath {
|
||||
protected:
|
||||
constexpr DefaultPath() = default;
|
||||
virtual ~DefaultPath() = default;
|
||||
|
||||
public:
|
||||
DefaultPath(const DefaultPath&) = delete;
|
||||
DefaultPath(DefaultPath&&) = delete;
|
||||
DefaultPath& operator=(const DefaultPath&) = delete;
|
||||
DefaultPath& operator=(DefaultPath&&) = delete;
|
||||
|
||||
virtual std::vector<std::fs::path> all() const = 0;
|
||||
virtual std::vector<std::fs::path> read() const;
|
||||
virtual std::vector<std::fs::path> write() const;
|
||||
};
|
||||
|
||||
class ConfigPath : public DefaultPath {
|
||||
public:
|
||||
explicit ConfigPath(std::fs::path postfix) : m_postfix(std::move(postfix)) {}
|
||||
|
||||
std::vector<std::fs::path> all() const override;
|
||||
|
||||
private:
|
||||
std::fs::path m_postfix;
|
||||
};
|
||||
|
||||
class DataPath : public DefaultPath {
|
||||
public:
|
||||
explicit DataPath(std::fs::path postfix) : m_postfix(std::move(postfix)) {}
|
||||
|
||||
std::vector<std::fs::path> all() const override;
|
||||
std::vector<std::fs::path> write() const override;
|
||||
|
||||
private:
|
||||
std::fs::path m_postfix;
|
||||
};
|
||||
|
||||
class PluginPath : public DefaultPath {
|
||||
public:
|
||||
explicit PluginPath(std::fs::path postfix) : m_postfix(std::move(postfix)) {}
|
||||
|
||||
std::vector<std::fs::path> all() const override;
|
||||
|
||||
private:
|
||||
std::fs::path m_postfix;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> getDataPaths(bool includeSystemFolders);
|
||||
std::vector<std::fs::path> getConfigPaths(bool includeSystemFolders);
|
||||
|
||||
const static inline impl::ConfigPath Config("config");
|
||||
const static inline impl::ConfigPath Recent("recent");
|
||||
|
||||
const static inline impl::PluginPath Libraries("lib");
|
||||
const static inline impl::PluginPath Plugins("plugins");
|
||||
|
||||
const static inline impl::DataPath Patterns("patterns");
|
||||
const static inline impl::DataPath PatternsInclude("includes");
|
||||
const static inline impl::DataPath Magic("magic");
|
||||
const static inline impl::DataPath Yara("yara");
|
||||
const static inline impl::DataPath YaraAdvancedAnalysis("yara/advanced_analysis");
|
||||
const static inline impl::DataPath Backups("backups");
|
||||
const static inline impl::DataPath Resources("resources");
|
||||
const static inline impl::DataPath Constants("constants");
|
||||
const static inline impl::DataPath Encodings("encodings");
|
||||
const static inline impl::DataPath Logs("logs");
|
||||
const static inline impl::DataPath Scripts("scripts");
|
||||
const static inline impl::DataPath Inspectors("scripts/inspectors");
|
||||
const static inline impl::DataPath Themes("themes");
|
||||
const static inline impl::DataPath Nodes("scripts/nodes");
|
||||
const static inline impl::DataPath Layouts("layouts");
|
||||
const static inline impl::DataPath Workspaces("workspaces");
|
||||
|
||||
constexpr static inline std::array<const impl::DefaultPath*, 20> All = {
|
||||
&Config,
|
||||
&Recent,
|
||||
|
||||
&Libraries,
|
||||
&Plugins,
|
||||
|
||||
&Patterns,
|
||||
&PatternsInclude,
|
||||
&Magic,
|
||||
&Yara,
|
||||
&YaraAdvancedAnalysis,
|
||||
&Backups,
|
||||
&Resources,
|
||||
&Constants,
|
||||
&Encodings,
|
||||
&Logs,
|
||||
&Scripts,
|
||||
&Inspectors,
|
||||
&Themes,
|
||||
&Nodes,
|
||||
&Layouts,
|
||||
&Workspaces,
|
||||
};
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <string_view>
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/ranges.h>
|
||||
|
||||
namespace hex {
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
@@ -31,36 +29,7 @@ namespace hex::fs {
|
||||
void openFolderExternal(const std::fs::path &dirPath);
|
||||
void openFolderWithSelectionExternal(const std::fs::path &selectedFilePath);
|
||||
|
||||
enum class ImHexPath : u32 {
|
||||
Patterns = 0,
|
||||
PatternsInclude,
|
||||
Magic,
|
||||
Plugins,
|
||||
Yara,
|
||||
YaraAdvancedAnalysis,
|
||||
Config,
|
||||
Backups,
|
||||
Resources,
|
||||
Constants,
|
||||
Encodings,
|
||||
Logs,
|
||||
Recent,
|
||||
Scripts,
|
||||
Inspectors,
|
||||
Themes,
|
||||
Libraries,
|
||||
Nodes,
|
||||
Layouts,
|
||||
Workspaces,
|
||||
|
||||
END
|
||||
};
|
||||
|
||||
bool isPathWritable(const std::fs::path &path);
|
||||
|
||||
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting = false);
|
||||
|
||||
// Temporarily expose these for the migration function
|
||||
std::vector<std::fs::path> getDataPaths();
|
||||
std::vector<std::fs::path> appendPath(std::vector<std::fs::path> paths, const std::fs::path &folder);
|
||||
}
|
||||
@@ -1,72 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include <future>
|
||||
#if defined(OS_WEB)
|
||||
|
||||
#include <emscripten/fetch.h>
|
||||
#include <future>
|
||||
|
||||
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;
|
||||
#include <emscripten/fetch.h>
|
||||
|
||||
// Execute the request
|
||||
auto result = this->executeImpl<T>(response);
|
||||
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;
|
||||
|
||||
// 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());
|
||||
// Execute the request
|
||||
auto result = this->executeImpl<T>(response);
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
// 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());
|
||||
|
||||
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(m_attr.requestMethod, m_method.c_str());
|
||||
m_attr.attributes = EMSCRIPTEN_FETCH_SYNCHRONOUS | EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
|
||||
|
||||
if (!m_body.empty()) {
|
||||
m_attr.requestData = m_body.c_str();
|
||||
m_attr.requestDataSize = m_body.size();
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<const char*> headers;
|
||||
for (auto it = m_headers.begin(); it != m_headers.end(); it++) {
|
||||
headers.push_back(it->first.c_str());
|
||||
headers.push_back(it->second.c_str());
|
||||
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");
|
||||
}
|
||||
headers.push_back(nullptr);
|
||||
m_attr.requestHeaders = headers.data();
|
||||
|
||||
// Send request
|
||||
emscripten_fetch_t* fetch = emscripten_fetch(&m_attr, m_url.c_str());
|
||||
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");
|
||||
}
|
||||
|
||||
data.resize(fetch->numBytes);
|
||||
std::copy(fetch->data, fetch->data + fetch->numBytes, data.begin());
|
||||
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(m_attr.requestMethod, m_method.c_str());
|
||||
m_attr.attributes = EMSCRIPTEN_FETCH_SYNCHRONOUS | EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
|
||||
|
||||
if (!m_body.empty()) {
|
||||
m_attr.requestData = m_body.c_str();
|
||||
m_attr.requestDataSize = m_body.size();
|
||||
}
|
||||
|
||||
std::vector<const char*> headers;
|
||||
for (auto it = m_headers.begin(); it != m_headers.end(); it++) {
|
||||
headers.push_back(it->first.c_str());
|
||||
headers.push_back(it->second.c_str());
|
||||
}
|
||||
headers.push_back(nullptr);
|
||||
m_attr.requestHeaders = headers.data();
|
||||
|
||||
// Send request
|
||||
emscripten_fetch_t* fetch = emscripten_fetch(&m_attr, 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() });
|
||||
}
|
||||
|
||||
return Result<T>(fetch->status, { data.begin(), data.end() });
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -1,145 +1,149 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <future>
|
||||
#if !defined(OS_WEB)
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <string>
|
||||
#include <future>
|
||||
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include <wolv/utils/string.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
|
||||
namespace hex {
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
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;
|
||||
namespace hex {
|
||||
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToFile);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &file);
|
||||
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;
|
||||
|
||||
return this->executeImpl<T>(response);
|
||||
});
|
||||
}
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToFile);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &file);
|
||||
|
||||
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(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(m_curl, CURLOPT_MIMEPOST, mime);
|
||||
|
||||
std::vector<u8> responseData;
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(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(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(m_curl, CURLOPT_MIMEPOST, mime);
|
||||
|
||||
std::vector<u8> responseData;
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(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(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(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(m_curl, CURLOPT_URL, m_url.c_str());
|
||||
curl_easy_setopt(m_curl, CURLOPT_CUSTOMREQUEST, m_method.c_str());
|
||||
|
||||
setDefaultConfig();
|
||||
|
||||
if (!m_body.empty()) {
|
||||
curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, m_body.c_str());
|
||||
return this->executeImpl<T>(response);
|
||||
});
|
||||
}
|
||||
|
||||
curl_slist *headers = nullptr;
|
||||
headers = curl_slist_append(headers, "Cache-Control: no-cache");
|
||||
ON_SCOPE_EXIT { curl_slist_free_all(headers); };
|
||||
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());
|
||||
|
||||
for (auto &[key, value] : m_headers) {
|
||||
std::string header = hex::format("{}: {}", key, value);
|
||||
headers = curl_slist_append(headers, header.c_str());
|
||||
curl_mime *mime = curl_mime_init(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(m_curl, CURLOPT_MIMEPOST, mime);
|
||||
|
||||
std::vector<u8> responseData;
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &responseData);
|
||||
|
||||
return this->executeImpl<T>(responseData);
|
||||
});
|
||||
}
|
||||
curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headers);
|
||||
|
||||
{
|
||||
std::scoped_lock lock(m_transmissionMutex);
|
||||
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(m_curl);
|
||||
curl_mimepart *part = curl_mime_addpart(mime);
|
||||
|
||||
auto result = curl_easy_perform(m_curl);
|
||||
if (result != CURLE_OK){
|
||||
char *url = nullptr;
|
||||
curl_easy_getinfo(m_curl, CURLINFO_EFFECTIVE_URL, &url);
|
||||
log::error("Http request '{0} {1}' failed with error {2}: '{3}'", m_method, url, u32(result), curl_easy_strerror(result));
|
||||
checkProxyErrors();
|
||||
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());
|
||||
|
||||
return { };
|
||||
curl_easy_setopt(m_curl, CURLOPT_MIMEPOST, mime);
|
||||
|
||||
std::vector<u8> responseData;
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(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(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(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(m_curl, CURLOPT_URL, m_url.c_str());
|
||||
curl_easy_setopt(m_curl, CURLOPT_CUSTOMREQUEST, m_method.c_str());
|
||||
|
||||
setDefaultConfig();
|
||||
|
||||
if (!m_body.empty()) {
|
||||
curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, 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] : m_headers) {
|
||||
std::string header = hex::format("{}: {}", key, value);
|
||||
headers = curl_slist_append(headers, header.c_str());
|
||||
}
|
||||
curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headers);
|
||||
|
||||
{
|
||||
std::scoped_lock lock(m_transmissionMutex);
|
||||
|
||||
auto result = curl_easy_perform(m_curl);
|
||||
if (result != CURLE_OK){
|
||||
char *url = nullptr;
|
||||
curl_easy_getinfo(m_curl, CURLINFO_EFFECTIVE_URL, &url);
|
||||
log::error("Http request '{0} {1}' failed with error {2}: '{3}'", m_method, url, u32(result), curl_easy_strerror(result));
|
||||
checkProxyErrors();
|
||||
|
||||
return { };
|
||||
}
|
||||
}
|
||||
|
||||
long statusCode = 0;
|
||||
curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &statusCode);
|
||||
|
||||
return Result<T>(statusCode, { data.begin(), data.end() });
|
||||
}
|
||||
|
||||
long statusCode = 0;
|
||||
curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &statusCode);
|
||||
|
||||
return Result<T>(statusCode, { data.begin(), data.end() });
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <fmt/color.h>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
#include <wolv/utils/guards.hpp>
|
||||
|
||||
namespace hex::log {
|
||||
|
||||
@@ -19,8 +18,11 @@ namespace hex::log {
|
||||
[[maybe_unused]] void redirectToFile();
|
||||
[[maybe_unused]] void enableColorPrinting();
|
||||
|
||||
[[nodiscard]] std::recursive_mutex& getLoggerMutex();
|
||||
[[nodiscard]] bool isLoggingSuspended();
|
||||
[[nodiscard]] bool isDebugLoggingEnabled();
|
||||
|
||||
void lockLoggerMutex();
|
||||
void unlockLoggerMutex();
|
||||
|
||||
struct LogEntry {
|
||||
std::string project;
|
||||
@@ -37,16 +39,19 @@ namespace hex::log {
|
||||
if (isLoggingSuspended()) [[unlikely]]
|
||||
return;
|
||||
|
||||
std::scoped_lock lock(getLoggerMutex());
|
||||
lockLoggerMutex();
|
||||
ON_SCOPE_EXIT { unlockLoggerMutex(); };
|
||||
|
||||
auto dest = getDestination();
|
||||
printPrefix(dest, ts, level, IMHEX_PROJECT_NAME);
|
||||
try {
|
||||
printPrefix(dest, ts, level, IMHEX_PROJECT_NAME);
|
||||
|
||||
auto message = fmt::format(fmt::runtime(fmt), args...);
|
||||
fmt::print(dest, "{}\n", message);
|
||||
fflush(dest);
|
||||
auto message = fmt::format(fmt::runtime(fmt), args...);
|
||||
fmt::print(dest, "{}\n", message);
|
||||
fflush(dest);
|
||||
|
||||
addLogEntry(IMHEX_PROJECT_NAME, level, std::move(message));
|
||||
addLogEntry(IMHEX_PROJECT_NAME, level, std::move(message));
|
||||
} catch (const std::exception&) { }
|
||||
}
|
||||
|
||||
namespace color {
|
||||
@@ -63,13 +68,14 @@ namespace hex::log {
|
||||
|
||||
void suspendLogging();
|
||||
void resumeLogging();
|
||||
void enableDebugLogging();
|
||||
|
||||
[[maybe_unused]] void debug(const std::string &fmt, auto && ... args) {
|
||||
#if defined(DEBUG)
|
||||
if (impl::isDebugLoggingEnabled()) [[unlikely]] {
|
||||
hex::log::impl::print(fg(impl::color::debug()) | fmt::emphasis::bold, "[DEBUG]", fmt, args...);
|
||||
#else
|
||||
} else {
|
||||
impl::addLogEntry(IMHEX_PROJECT_NAME, "[DEBUG]", fmt::format(fmt::runtime(fmt), args...));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] void info(const std::string &fmt, auto && ... args) {
|
||||
@@ -88,23 +94,28 @@ namespace hex::log {
|
||||
hex::log::impl::print(fg(impl::color::fatal()) | fmt::emphasis::bold, "[FATAL]", fmt, args...);
|
||||
}
|
||||
|
||||
|
||||
[[maybe_unused]] void print(const std::string &fmt, auto && ... args) {
|
||||
std::scoped_lock lock(impl::getLoggerMutex());
|
||||
impl::lockLoggerMutex();
|
||||
ON_SCOPE_EXIT { impl::unlockLoggerMutex(); };
|
||||
|
||||
auto dest = impl::getDestination();
|
||||
auto message = fmt::format(fmt::runtime(fmt), args...);
|
||||
fmt::print(dest, "{}", message);
|
||||
fflush(dest);
|
||||
try {
|
||||
auto dest = impl::getDestination();
|
||||
auto message = fmt::format(fmt::runtime(fmt), args...);
|
||||
fmt::print(dest, "{}", message);
|
||||
fflush(dest);
|
||||
} catch (const std::exception&) { }
|
||||
}
|
||||
|
||||
[[maybe_unused]] void println(const std::string &fmt, auto && ... args) {
|
||||
std::scoped_lock lock(impl::getLoggerMutex());
|
||||
impl::lockLoggerMutex();
|
||||
ON_SCOPE_EXIT { impl::unlockLoggerMutex(); };
|
||||
|
||||
auto dest = impl::getDestination();
|
||||
auto message = fmt::format(fmt::runtime(fmt), args...);
|
||||
fmt::print(dest, "{}\n", message);
|
||||
fflush(dest);
|
||||
try {
|
||||
auto dest = impl::getDestination();
|
||||
auto message = fmt::format(fmt::runtime(fmt), args...);
|
||||
fmt::print(dest, "{}\n", message);
|
||||
fflush(dest);
|
||||
} catch (const std::exception&) { }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,10 @@ namespace hex {
|
||||
constexpr static Region Invalid() {
|
||||
return { 0, 0 };
|
||||
}
|
||||
|
||||
constexpr bool operator<(const Region &other) const {
|
||||
return this->address < other.address;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ namespace hex {
|
||||
using SizeType = typename SizeTypeImpl<Size>::Type;
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr T changeEndianess(const T &value, size_t size, std::endian endian) {
|
||||
[[nodiscard]] constexpr T changeEndianness(const T &value, size_t size, std::endian endian) {
|
||||
if (endian == std::endian::native)
|
||||
return value;
|
||||
|
||||
@@ -172,8 +172,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr T changeEndianess(const T &value, std::endian endian) {
|
||||
return changeEndianess(value, sizeof(value), endian);
|
||||
[[nodiscard]] constexpr T changeEndianness(const T &value, std::endian endian) {
|
||||
return changeEndianness(value, sizeof(value), endian);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u128 bitmask(u8 bits) {
|
||||
@@ -298,31 +298,7 @@ namespace hex {
|
||||
|
||||
[[nodiscard]] std::optional<std::string> getEnvironmentVariable(const std::string &env);
|
||||
|
||||
[[nodiscard]] inline std::string limitStringLength(const std::string &string, size_t maxLength) {
|
||||
// If the string is shorter than the max length, return it as is
|
||||
if (string.size() < maxLength)
|
||||
return string;
|
||||
|
||||
// If the string is longer than the max length, find the last space before the max length
|
||||
auto it = string.begin() + maxLength;
|
||||
while (it != string.begin() && !std::isspace(*it)) --it;
|
||||
|
||||
// If there's no space before the max length, just cut the string
|
||||
if (it == string.begin()) {
|
||||
it = string.begin() + maxLength;
|
||||
|
||||
// Try to find a UTF-8 character boundary
|
||||
while (it != string.begin() && (*it & 0x80) != 0x00) --it;
|
||||
++it;
|
||||
}
|
||||
|
||||
// If we still didn't find a valid boundary, just return the string as is
|
||||
if (it == string.begin())
|
||||
return string;
|
||||
|
||||
// Append
|
||||
return std::string(string.begin(), it) + "…";
|
||||
}
|
||||
[[nodiscard]] std::string limitStringLength(const std::string &string, size_t maxLength);
|
||||
|
||||
[[nodiscard]] std::optional<std::fs::path> getInitialFilePath();
|
||||
|
||||
@@ -331,4 +307,14 @@ namespace hex {
|
||||
|
||||
[[nodiscard]] std::string formatSystemError(i32 error);
|
||||
|
||||
/**
|
||||
* Gets the shared library handle for a given pointer
|
||||
* @param symbol Pointer to any function or variable in the shared library
|
||||
* @return The module handle
|
||||
* @warning Important! Calling this function on functions defined in other modules will return the handle of the current module!
|
||||
* This is because you're not actually passing a pointer to the function in the other module but rather a pointer to a thunk
|
||||
* that is defined in the current module.
|
||||
*/
|
||||
[[nodiscard]] void* getContainingModule(void* symbol);
|
||||
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
void setupMacosWindowStyle(GLFWwindow *window, bool borderlessWindowMode);
|
||||
|
||||
void enumerateFontsMacos();
|
||||
|
||||
void macosHandleTitlebarDoubleClickGesture(GLFWwindow *window);
|
||||
bool macosIsWindowBeingResizedByUser(GLFWwindow *window);
|
||||
void macosMarkContentEdited(GLFWwindow *window, bool edited = true);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -37,15 +37,34 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[maybe_unused]] static auto& getFeaturesImpl() {
|
||||
static std::vector<hex::Feature> features;
|
||||
return features;
|
||||
}
|
||||
|
||||
#if defined (IMHEX_STATIC_LINK_PLUGINS)
|
||||
#define IMHEX_PLUGIN_VISIBILITY_PREFIX static
|
||||
#else
|
||||
#define IMHEX_PLUGIN_VISIBILITY_PREFIX extern "C" [[gnu::visibility("default")]]
|
||||
#endif
|
||||
|
||||
#define IMHEX_FEATURE_ENABLED(feature) WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(IMHEX_PLUGIN_, IMHEX_PLUGIN_NAME), _FEATURE_), feature)
|
||||
#define IMHEX_DEFINE_PLUGIN_FEATURES() IMHEX_DEFINE_PLUGIN_FEATURES_IMPL()
|
||||
#define IMHEX_DEFINE_PLUGIN_FEATURES_IMPL() \
|
||||
template<> \
|
||||
struct PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation> { \
|
||||
static void* getFeatures(); \
|
||||
}; \
|
||||
void* PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures() { \
|
||||
return &getFeaturesImpl(); \
|
||||
} \
|
||||
static auto initFeatures = [] { getFeaturesImpl() = std::vector<hex::Feature>({ IMHEX_PLUGIN_FEATURES_CONTENT }); return 0; }()
|
||||
|
||||
#define IMHEX_PLUGIN_FEATURES ::getFeaturesImpl()
|
||||
|
||||
/**
|
||||
* This macro is used to define all the required entry points for a plugin.
|
||||
* Name, Author and Description will be displayed in the in the plugin list on the Welcome screen.
|
||||
* Name, Author and Description will be displayed in the plugin list on the Welcome screen.
|
||||
*/
|
||||
#define IMHEX_PLUGIN_SETUP(name, author, description) IMHEX_PLUGIN_SETUP_IMPL(name, author, description)
|
||||
#define IMHEX_LIBRARY_SETUP(name) IMHEX_LIBRARY_SETUP_IMPL(name)
|
||||
@@ -85,6 +104,7 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
|
||||
ImGui::SetCurrentContext(ctx); \
|
||||
GImGui = ctx; \
|
||||
} \
|
||||
IMHEX_DEFINE_PLUGIN_FEATURES(); \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void* getFeatures() { \
|
||||
return PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures(); \
|
||||
} \
|
||||
@@ -129,16 +149,3 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
|
||||
return &g_subCommands; \
|
||||
} \
|
||||
std::vector<hex::SubCommand> g_subCommands
|
||||
|
||||
#define IMHEX_FEATURE_ENABLED(feature) WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(IMHEX_PLUGIN_, IMHEX_PLUGIN_NAME), _FEATURE_), feature)
|
||||
#define IMHEX_PLUGIN_FEATURES() IMHEX_PLUGIN_FEATURES_IMPL()
|
||||
#define IMHEX_PLUGIN_FEATURES_IMPL() \
|
||||
extern std::vector<hex::Feature> g_features; \
|
||||
template<> \
|
||||
struct PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation> { \
|
||||
static void* getFeatures(); \
|
||||
}; \
|
||||
void* PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures() { \
|
||||
return &g_features; \
|
||||
} \
|
||||
std::vector<hex::Feature> g_features
|
||||
|
||||
@@ -35,8 +35,6 @@ namespace hex::prv {
|
||||
[[nodiscard]] u64 getActualSize() const override { return m_data.size(); }
|
||||
|
||||
void resizeRaw(u64 newSize) override;
|
||||
void insertRaw(u64 offset, u64 size) override;
|
||||
void removeRaw(u64 offset, u64 size) override;
|
||||
|
||||
[[nodiscard]] std::string getName() const override { return m_name; }
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace hex::prv {
|
||||
* @brief Gets the type name of this provider
|
||||
* @note This is mainly used to be stored in project files and recents to be able to later on
|
||||
* recreate this exact provider type. This needs to be unique across all providers, this is usually something
|
||||
* like "hex.builtin.provider.memory" or "hex.builtin.provider.file"
|
||||
* like "hex.builtin.provider.mem_file" or "hex.builtin.provider.file"
|
||||
* @return The provider's type name
|
||||
*/
|
||||
[[nodiscard]] virtual std::string getTypeName() const = 0;
|
||||
@@ -161,13 +161,13 @@ namespace hex::prv {
|
||||
*/
|
||||
[[nodiscard]] virtual std::string getName() const = 0;
|
||||
|
||||
void resize(u64 newSize);
|
||||
bool resize(u64 newSize);
|
||||
void insert(u64 offset, u64 size);
|
||||
void remove(u64 offset, u64 size);
|
||||
|
||||
virtual void resizeRaw(u64 newSize) { hex::unused(newSize); }
|
||||
virtual void insertRaw(u64 offset, u64 size) { hex::unused(offset, size); }
|
||||
virtual void removeRaw(u64 offset, u64 size) { hex::unused(offset, size); }
|
||||
virtual void insertRaw(u64 offset, u64 size);
|
||||
virtual void removeRaw(u64 offset, u64 size);
|
||||
|
||||
virtual void save();
|
||||
virtual void saveAs(const std::fs::path &path);
|
||||
@@ -258,7 +258,7 @@ namespace hex::prv {
|
||||
*/
|
||||
bool m_skipLoadInterface = false;
|
||||
|
||||
std::string m_errorMessage;
|
||||
std::string m_errorMessage = "Unspecified error";
|
||||
|
||||
u64 m_pageSize = MaxPageSize;
|
||||
};
|
||||
|
||||
@@ -74,21 +74,30 @@ namespace hex {
|
||||
return m_data | std::views::values;
|
||||
}
|
||||
|
||||
void setOnCreateCallback(std::function<void(const prv::Provider *, T&)> callback) {
|
||||
void setOnCreateCallback(std::function<void(prv::Provider *, T&)> callback) {
|
||||
m_onCreateCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void setOnDestroyCallback(std::function<void(prv::Provider *, T&)> callback) {
|
||||
m_onDestroyCallback = std::move(callback);
|
||||
}
|
||||
|
||||
private:
|
||||
void onCreate() {
|
||||
EventProviderOpened::subscribe(this, [this](prv::Provider *provider) {
|
||||
auto [it, inserted] = m_data.emplace(provider, T());
|
||||
auto &[key, value] = *it;
|
||||
if (m_onCreateCallback)
|
||||
m_onCreateCallback(key, value);
|
||||
m_onCreateCallback(provider, value);
|
||||
});
|
||||
|
||||
EventProviderDeleted::subscribe(this, [this](prv::Provider *provider){
|
||||
m_data.erase(provider);
|
||||
if (auto it = m_data.find(provider); it != m_data.end()) {
|
||||
if (m_onDestroyCallback)
|
||||
m_onDestroyCallback(provider, m_data.at(provider));
|
||||
|
||||
m_data.erase(it);
|
||||
}
|
||||
});
|
||||
|
||||
EventImHexClosing::subscribe(this, [this] {
|
||||
@@ -113,6 +122,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void onDestroy() {
|
||||
|
||||
EventProviderOpened::unsubscribe(this);
|
||||
EventProviderDeleted::unsubscribe(this);
|
||||
EventImHexClosing::unsubscribe(this);
|
||||
@@ -121,7 +131,7 @@ namespace hex {
|
||||
|
||||
private:
|
||||
std::map<const prv::Provider *, T> m_data;
|
||||
std::function<void(const prv::Provider *, T&)> m_onCreateCallback;
|
||||
std::function<void(prv::Provider *, T&)> m_onCreateCallback, m_onDestroyCallback;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -27,6 +27,7 @@ namespace hex::prv::undo {
|
||||
|
||||
void groupOperations(u32 count, const UnlocalizedString &unlocalizedName);
|
||||
void apply(const Stack &otherStack);
|
||||
void reapply();
|
||||
|
||||
[[nodiscard]] bool canUndo() const;
|
||||
[[nodiscard]] bool canRedo() const;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/api/plugin_manager.hpp>
|
||||
|
||||
#include <wolv/utils/preproc.hpp>
|
||||
|
||||
@@ -28,16 +29,20 @@
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define INIT_PLUGIN(name) \
|
||||
if (!hex::test::initPluginImpl(name)) TEST_FAIL();
|
||||
|
||||
namespace hex::test {
|
||||
|
||||
using Function = int(*)();
|
||||
struct Test {
|
||||
std::function<int()> function;
|
||||
Function function;
|
||||
bool shouldFail;
|
||||
};
|
||||
|
||||
class Tests {
|
||||
public:
|
||||
static auto addTest(const std::string &name, const std::function<int()> &func, bool shouldFail) noexcept {
|
||||
static auto addTest(const std::string &name, Function func, bool shouldFail) noexcept {
|
||||
s_tests.insert({
|
||||
name, {func, shouldFail}
|
||||
});
|
||||
@@ -50,7 +55,7 @@ namespace hex::test {
|
||||
}
|
||||
|
||||
private:
|
||||
static inline std::map<std::string, Test> s_tests;
|
||||
static std::map<std::string, Test> s_tests;
|
||||
};
|
||||
|
||||
template<class F>
|
||||
@@ -86,4 +91,5 @@ namespace hex::test {
|
||||
return TestSequence<F>(executor.getName(), std::forward<F>(f), executor.shouldFail());
|
||||
}
|
||||
|
||||
bool initPluginImpl(std::string name);
|
||||
}
|
||||
@@ -76,14 +76,21 @@ namespace ImGuiExt {
|
||||
};
|
||||
|
||||
Texture() = default;
|
||||
Texture(const ImU8 *buffer, int size, Filter filter = Filter::Nearest, int width = 0, int height = 0);
|
||||
Texture(std::span<const std::byte> bytes, Filter filter = Filter::Nearest, int width = 0, int height = 0);
|
||||
explicit Texture(const char *path, Filter filter = Filter::Nearest);
|
||||
explicit Texture(const std::fs::path &path, Filter filter = Filter::Nearest);
|
||||
Texture(unsigned int texture, int width, int height);
|
||||
Texture(const Texture&) = delete;
|
||||
Texture(Texture&& other) noexcept;
|
||||
|
||||
static Texture fromImage(const ImU8 *buffer, int size, Filter filter = Filter::Nearest);
|
||||
static Texture fromImage(std::span<const std::byte> buffer, Filter filter = Filter::Nearest);
|
||||
static Texture fromImage(const char *path, Filter filter = Filter::Nearest);
|
||||
static Texture fromImage(const std::fs::path &path, Filter filter = Filter::Nearest);
|
||||
static Texture fromGLTexture(unsigned int texture, int width, int height);
|
||||
static Texture fromBitmap(const ImU8 *buffer, int size, int width, int height, Filter filter = Filter::Nearest);
|
||||
static Texture fromBitmap(std::span<const std::byte> buffer, int width, int height, Filter filter = Filter::Nearest);
|
||||
static Texture fromSVG(const char *path, int width = 0, int height = 0, Filter filter = Filter::Nearest);
|
||||
static Texture fromSVG(const std::fs::path &path, int width = 0, int height = 0, Filter filter = Filter::Nearest);
|
||||
static Texture fromSVG(std::span<const std::byte> buffer, int width = 0, int height = 0, Filter filter = Filter::Nearest);
|
||||
|
||||
|
||||
~Texture();
|
||||
|
||||
Texture& operator=(const Texture&) = delete;
|
||||
@@ -116,6 +123,8 @@ namespace ImGuiExt {
|
||||
int m_width = 0, m_height = 0;
|
||||
};
|
||||
|
||||
float GetTextWrapPos();
|
||||
|
||||
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data);
|
||||
|
||||
bool IconHyperlink(const char *icon, const char *label, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
|
||||
@@ -124,7 +133,7 @@ namespace ImGuiExt {
|
||||
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);
|
||||
void HelpHover(const char *text, const char *icon = "(?)", ImU32 iconColor = ImGui::GetColorU32(ImGuiCol_ButtonActive));
|
||||
|
||||
void UnderlinedText(const char *label, ImColor color = ImGui::GetStyleColorVec4(ImGuiCol_Text), const ImVec2 &size_arg = ImVec2(0, 0));
|
||||
|
||||
@@ -143,6 +152,8 @@ namespace ImGuiExt {
|
||||
bool InputHexadecimal(const char* label, u32 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputHexadecimal(const char* label, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
|
||||
bool SliderBytes(const char *label, u64 *value, u64 min, u64 max, ImGuiSliderFlags flags = ImGuiSliderFlags_None);
|
||||
|
||||
inline bool HasSecondPassed() {
|
||||
return static_cast<ImU32>(ImGui::GetTime() * 100) % 100 <= static_cast<ImU32>(ImGui::GetIO().DeltaTime * 100);
|
||||
}
|
||||
@@ -154,6 +165,7 @@ namespace ImGuiExt {
|
||||
|
||||
struct Styles {
|
||||
float WindowBlur = 0.0F;
|
||||
float PopupWindowAlpha = 0.0F; // Alpha used by Popup tool windows when the user is not hovering over them
|
||||
} styles;
|
||||
};
|
||||
|
||||
@@ -175,11 +187,16 @@ namespace ImGuiExt {
|
||||
|
||||
void SmallProgressBar(float fraction, float yOffset = 0.0F);
|
||||
|
||||
inline void TextFormatted(const std::string &fmt, auto &&...args) {
|
||||
ImGui::TextUnformatted(hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
|
||||
inline void TextFormatted(std::string_view fmt, auto &&...args) {
|
||||
if constexpr (sizeof...(args) == 0) {
|
||||
ImGui::TextUnformatted(fmt.data(), fmt.data() + fmt.size());
|
||||
} else {
|
||||
const auto string = hex::format(fmt, std::forward<decltype(args)>(args)...);
|
||||
ImGui::TextUnformatted(string.c_str(), string.c_str() + string.size());
|
||||
}
|
||||
}
|
||||
|
||||
inline void TextFormattedSelectable(const std::string &fmt, auto &&...args) {
|
||||
inline void TextFormattedSelectable(std::string_view fmt, auto &&...args) {
|
||||
auto text = hex::format(fmt, std::forward<decltype(args)>(args)...);
|
||||
|
||||
ImGui::PushID(text.c_str());
|
||||
@@ -187,8 +204,8 @@ namespace ImGuiExt {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2());
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4());
|
||||
|
||||
ImGui::PushItemWidth(-FLT_MIN);
|
||||
ImGui::InputText("##", const_cast<char *>(text.c_str()), text.size(), ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::PushItemWidth(ImGui::CalcTextSize(text.c_str()).x + ImGui::GetStyle().FramePadding.x * 2);
|
||||
ImGui::InputText("##", const_cast<char *>(text.c_str()), text.size(), ImGuiInputTextFlags_ReadOnly | ImGuiInputTextFlags_NoHorizontalScroll);
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
@@ -197,19 +214,28 @@ namespace ImGuiExt {
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
inline void TextFormattedColored(ImColor color, const std::string &fmt, auto &&...args) {
|
||||
ImGui::TextColored(color, "%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
|
||||
inline void TextFormattedColored(ImColor color, std::string_view fmt, auto &&...args) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color.Value);
|
||||
ImGuiExt::TextFormatted(fmt, std::forward<decltype(args)>(args)...);
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
inline void TextFormattedDisabled(const std::string &fmt, auto &&...args) {
|
||||
ImGui::TextDisabled("%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
|
||||
inline void TextFormattedDisabled(std::string_view fmt, auto &&...args) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
|
||||
ImGuiExt::TextFormatted(fmt, std::forward<decltype(args)>(args)...);
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
inline void TextFormattedWrapped(const std::string &fmt, auto &&...args) {
|
||||
ImGui::TextWrapped("%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
|
||||
inline void TextFormattedWrapped(std::string_view fmt, auto &&...args) {
|
||||
const bool need_backup = ImGuiExt::GetTextWrapPos() < 0.0F; // Keep existing wrap position if one is already set
|
||||
if (need_backup)
|
||||
ImGui::PushTextWrapPos(0.0F);
|
||||
ImGuiExt::TextFormatted(fmt, std::forward<decltype(args)>(args)...);
|
||||
if (need_backup)
|
||||
ImGui::PopTextWrapPos();
|
||||
}
|
||||
|
||||
inline void TextFormattedWrappedSelectable(const std::string &fmt, auto &&...args) {
|
||||
inline void TextFormattedWrappedSelectable(std::string_view 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.
|
||||
auto text = wolv::util::wrapMonospacedString(
|
||||
hex::format(fmt, std::forward<decltype(args)>(args)...),
|
||||
@@ -222,7 +248,7 @@ namespace ImGuiExt {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2());
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4());
|
||||
|
||||
ImGui::PushItemWidth(-FLT_MIN);
|
||||
ImGui::PushItemWidth(ImGui::CalcTextSize(text.c_str()).x + ImGui::GetStyle().FramePadding.x * 2);
|
||||
ImGui::InputTextMultiline(
|
||||
"##",
|
||||
const_cast<char *>(text.c_str()),
|
||||
@@ -239,13 +265,13 @@ namespace ImGuiExt {
|
||||
}
|
||||
|
||||
void TextUnformattedCentered(const char *text);
|
||||
inline void TextFormattedCentered(const std::string &fmt, auto &&...args) {
|
||||
inline void TextFormattedCentered(std::string_view fmt, auto &&...args) {
|
||||
auto text = hex::format(fmt, std::forward<decltype(args)>(args)...);
|
||||
TextUnformattedCentered(text.c_str());
|
||||
}
|
||||
|
||||
|
||||
inline void TextFormattedCenteredHorizontal(const std::string &fmt, auto &&...args) {
|
||||
inline void TextFormattedCenteredHorizontal(std::string_view 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);
|
||||
@@ -276,7 +302,7 @@ namespace ImGuiExt {
|
||||
bool BeginBox();
|
||||
void EndBox();
|
||||
|
||||
void BeginSubWindow(const char *label, ImVec2 size = ImVec2(0, 0), ImGuiChildFlags flags = ImGuiChildFlags_None);
|
||||
bool BeginSubWindow(const char *label, bool *collapsed = nullptr, 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) {
|
||||
@@ -297,6 +323,9 @@ namespace ImGuiExt {
|
||||
bool ToggleSwitch(const char *label, bool *v);
|
||||
bool ToggleSwitch(const char *label, bool v);
|
||||
|
||||
bool PopupTitleBarButton(const char* label, bool p_enabled);
|
||||
void PopupTitleBarText(const char* text);
|
||||
|
||||
template<typename T>
|
||||
constexpr ImGuiDataType getImGuiDataType() {
|
||||
if constexpr (std::same_as<T, u8>) return ImGuiDataType_U8;
|
||||
|
||||
@@ -80,6 +80,8 @@ namespace hex {
|
||||
*/
|
||||
[[nodiscard]] virtual ImGuiWindowFlags getWindowFlags() const;
|
||||
|
||||
[[nodiscard]] virtual bool shouldStoreWindowState() const { return true; }
|
||||
|
||||
[[nodiscard]] const char *getIcon() const { return m_icon; }
|
||||
|
||||
[[nodiscard]] bool &getWindowOpenState();
|
||||
@@ -156,6 +158,7 @@ namespace hex {
|
||||
explicit Floating(UnlocalizedString unlocalizedName) : Window(std::move(unlocalizedName), "") {}
|
||||
|
||||
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const override { return ImGuiWindowFlags_NoDocking; }
|
||||
[[nodiscard]] bool shouldStoreWindowState() const override { return false; }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -178,12 +181,13 @@ namespace hex {
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape)))
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Escape))
|
||||
this->getWindowOpenState() = false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool hasCloseButton() const { return true; }
|
||||
[[nodiscard]] virtual bool hasCloseButton() const { return true; }
|
||||
[[nodiscard]] bool shouldStoreWindowState() const override { return false; }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <hex/api/event_manager.hpp>
|
||||
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
#include <hex/helpers/default_paths.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@@ -197,7 +198,7 @@ namespace hex {
|
||||
constexpr static auto AchievementsFile = "achievements.json";
|
||||
|
||||
void AchievementManager::loadProgress() {
|
||||
for (const auto &directory : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
for (const auto &directory : paths::Config.read()) {
|
||||
auto path = directory / AchievementsFile;
|
||||
|
||||
if (!wolv::io::fs::exists(path)) {
|
||||
@@ -246,7 +247,7 @@ namespace hex {
|
||||
if (json.empty())
|
||||
return;
|
||||
|
||||
for (const auto &directory : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
for (const auto &directory : paths::Config.write()) {
|
||||
auto path = directory / AchievementsFile;
|
||||
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
#include <hex/helpers/default_paths.hpp>
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/data_processor/node.hpp>
|
||||
@@ -51,10 +52,14 @@ namespace hex {
|
||||
if (!settings[unlocalizedCategory].contains(unlocalizedName))
|
||||
settings[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
|
||||
if (settings[unlocalizedCategory][unlocalizedName].is_null())
|
||||
settings[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
|
||||
return settings[unlocalizedCategory][unlocalizedName];
|
||||
}
|
||||
|
||||
#if defined(OS_WEB)
|
||||
|
||||
void load() {
|
||||
char *data = (char *) MAIN_THREAD_EM_ASM_INT({
|
||||
let data = localStorage.getItem("config");
|
||||
@@ -70,7 +75,11 @@ namespace hex {
|
||||
for (const auto &[category, rest] : *impl::s_onChangeCallbacks) {
|
||||
for (const auto &[name, callbacks] : rest) {
|
||||
for (const auto &[id, callback] : callbacks) {
|
||||
callback(getSetting(category, name, {}));
|
||||
try {
|
||||
callback(getSetting(category, name, {}));
|
||||
} catch (const std::exception &e) {
|
||||
log::error("Failed to load setting [{}/{}]: {}", category, name, e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,7 +102,7 @@ namespace hex {
|
||||
|
||||
void load() {
|
||||
bool loaded = false;
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
for (const auto &dir : paths::Config.read()) {
|
||||
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Read);
|
||||
|
||||
if (file.isValid()) {
|
||||
@@ -109,14 +118,21 @@ namespace hex {
|
||||
for (const auto &[category, rest] : *impl::s_onChangeCallbacks) {
|
||||
for (const auto &[name, callbacks] : rest) {
|
||||
for (const auto &[id, callback] : callbacks) {
|
||||
callback(getSetting(category, name, {}));
|
||||
try {
|
||||
callback(getSetting(category, name, {}));
|
||||
} catch (const std::exception &e) {
|
||||
log::error("Failed to load setting [{}/{}]: {}", category, name, e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void store() {
|
||||
const auto &settingsData = getSettingsData();
|
||||
if (!s_settings.isValid())
|
||||
return;
|
||||
|
||||
const auto &settingsData = *s_settings;
|
||||
|
||||
// During a crash settings can be empty, causing them to be overwritten.
|
||||
if (settingsData.empty()) {
|
||||
@@ -127,7 +143,7 @@ namespace hex {
|
||||
if (result.empty()) {
|
||||
return;
|
||||
}
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
for (const auto &dir : paths::Config.write()) {
|
||||
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Create);
|
||||
|
||||
if (file.isValid()) {
|
||||
@@ -138,7 +154,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
for (const auto &dir : paths::Config.write()) {
|
||||
wolv::io::fs::remove(dir / SettingsFile);
|
||||
}
|
||||
}
|
||||
@@ -297,6 +313,23 @@ namespace hex {
|
||||
}
|
||||
|
||||
|
||||
bool SliderDataSize::draw(const std::string &name) {
|
||||
return ImGuiExt::SliderBytes(name.c_str(), &m_value, m_min, m_max);
|
||||
}
|
||||
|
||||
void SliderDataSize::load(const nlohmann::json &data) {
|
||||
if (data.is_number_integer()) {
|
||||
m_value = data.get<u64>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for slider!");
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json SliderDataSize::store() {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
|
||||
ColorPicker::ColorPicker(ImColor defaultColor) {
|
||||
m_value = {
|
||||
defaultColor.Value.x,
|
||||
@@ -533,6 +566,11 @@ namespace hex {
|
||||
|
||||
pl::PatternLanguage& getRuntime() {
|
||||
static PerProvider<pl::PatternLanguage> runtime;
|
||||
AT_FIRST_TIME {
|
||||
runtime.setOnCreateCallback([](prv::Provider *provider, pl::PatternLanguage &runtime) {
|
||||
configureRuntime(runtime, provider);
|
||||
});
|
||||
};
|
||||
|
||||
return *runtime;
|
||||
}
|
||||
@@ -558,7 +596,7 @@ namespace hex {
|
||||
);
|
||||
}
|
||||
|
||||
runtime.setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude) | fs::getDefaultPaths(fs::ImHexPath::Patterns));
|
||||
runtime.setIncludePaths(paths::PatternsInclude.read() | paths::Patterns.read());
|
||||
|
||||
for (const auto &[ns, name, paramCount, callback, dangerous] : impl::getFunctions()) {
|
||||
if (dangerous)
|
||||
@@ -783,6 +821,12 @@ namespace hex {
|
||||
return *s_menuItems;
|
||||
}
|
||||
|
||||
static AutoReset<std::vector<MenuItem*>> s_toolbarMenuItems;
|
||||
const std::vector<MenuItem*>& getToolbarMenuItems() {
|
||||
return s_toolbarMenuItems;
|
||||
}
|
||||
|
||||
|
||||
std::multimap<u32, MenuItem>& getMenuItemsMutable() {
|
||||
return *s_menuItems;
|
||||
}
|
||||
@@ -892,11 +936,35 @@ namespace hex {
|
||||
if (menuItem.unlocalizedNames.back() == unlocalizedName) {
|
||||
menuItem.toolbarIndex = maxIndex + 1;
|
||||
menuItem.icon.color = color;
|
||||
updateToolbarItems();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MenuItemSorter {
|
||||
bool operator()(const auto *a, const auto *b) const {
|
||||
return a->toolbarIndex < b->toolbarIndex;
|
||||
}
|
||||
};
|
||||
|
||||
void updateToolbarItems() {
|
||||
std::set<ContentRegistry::Interface::impl::MenuItem*, MenuItemSorter> menuItems;
|
||||
|
||||
for (auto &[priority, menuItem] : impl::getMenuItemsMutable()) {
|
||||
if (menuItem.toolbarIndex != -1) {
|
||||
menuItems.insert(&menuItem);
|
||||
}
|
||||
}
|
||||
|
||||
impl::s_toolbarMenuItems->clear();
|
||||
for (auto menuItem : menuItems) {
|
||||
impl::s_toolbarMenuItems->push_back(menuItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function, const impl::EnabledCallback &enabledCallback) {
|
||||
impl::s_sidebarItems->push_back({ icon, function, enabledCallback });
|
||||
@@ -945,17 +1013,28 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
static AutoReset<std::vector<Entry>> s_entries;
|
||||
const std::vector<Entry>& getEntries() {
|
||||
return *s_entries;
|
||||
static AutoReset<std::vector<ExportMenuEntry>> s_exportMenuEntries;
|
||||
const std::vector<ExportMenuEntry>& getExportMenuEntries() {
|
||||
return *s_exportMenuEntries;
|
||||
}
|
||||
|
||||
static AutoReset<std::vector<FindExporterEntry>> s_findExportEntries;
|
||||
const std::vector<FindExporterEntry>& getFindExporterEntries() {
|
||||
return *s_findExportEntries;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void add(const UnlocalizedString &unlocalizedName, const impl::Callback &callback) {
|
||||
void addExportMenuEntry(const UnlocalizedString &unlocalizedName, const impl::Callback &callback) {
|
||||
log::debug("Registered new data formatter: {}", unlocalizedName.get());
|
||||
|
||||
impl::s_entries->push_back({ unlocalizedName, callback });
|
||||
impl::s_exportMenuEntries->push_back({ unlocalizedName, callback });
|
||||
}
|
||||
|
||||
void addFindExportFormatter(const UnlocalizedString &unlocalizedName, const std::string fileExtension, const impl::FindExporterCallback &callback) {
|
||||
log::debug("Registered new export formatter: {}", unlocalizedName.get());
|
||||
|
||||
impl::s_findExportEntries->push_back({ unlocalizedName, fileExtension, callback });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
@@ -75,7 +77,11 @@ namespace hex {
|
||||
|
||||
static AutoReset<std::optional<ProviderRegion>> s_currentSelection;
|
||||
void setCurrentSelection(const std::optional<ProviderRegion> ®ion) {
|
||||
*s_currentSelection = region;
|
||||
if (region == Region::Invalid()) {
|
||||
clearSelection();
|
||||
} else {
|
||||
*s_currentSelection = region;
|
||||
}
|
||||
}
|
||||
|
||||
static PerProvider<std::optional<Region>> s_hoveredRegion;
|
||||
@@ -178,24 +184,24 @@ namespace hex {
|
||||
impl::s_hoveringFunctions->erase(id);
|
||||
}
|
||||
|
||||
static u32 tooltipId = 0;
|
||||
static u32 s_tooltipId = 0;
|
||||
u32 addTooltip(Region region, std::string value, color_t color) {
|
||||
tooltipId++;
|
||||
impl::s_tooltips->insert({ tooltipId, { region, std::move(value), color } });
|
||||
s_tooltipId++;
|
||||
impl::s_tooltips->insert({ s_tooltipId, { region, std::move(value), color } });
|
||||
|
||||
return tooltipId;
|
||||
return s_tooltipId;
|
||||
}
|
||||
|
||||
void removeTooltip(u32 id) {
|
||||
impl::s_tooltips->erase(id);
|
||||
}
|
||||
|
||||
static u32 tooltipFunctionId;
|
||||
static u32 s_tooltipFunctionId;
|
||||
u32 addTooltipProvider(TooltipFunction function) {
|
||||
tooltipFunctionId++;
|
||||
impl::s_tooltipFunctions->insert({ tooltipFunctionId, std::move(function) });
|
||||
s_tooltipFunctionId++;
|
||||
impl::s_tooltipFunctions->insert({ s_tooltipFunctionId, std::move(function) });
|
||||
|
||||
return tooltipFunctionId;
|
||||
return s_tooltipFunctionId;
|
||||
}
|
||||
|
||||
void removeTooltipProvider(u32 id) {
|
||||
@@ -212,7 +218,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void clearSelection() {
|
||||
impl::s_currentSelection.reset();
|
||||
impl::s_currentSelection->reset();
|
||||
}
|
||||
|
||||
void setSelection(const Region ®ion, prv::Provider *provider) {
|
||||
@@ -262,18 +268,20 @@ namespace hex {
|
||||
|
||||
static i64 s_currentProvider = -1;
|
||||
static AutoReset<std::vector<std::unique_ptr<prv::Provider>>> s_providers;
|
||||
static AutoReset<std::list<std::unique_ptr<prv::Provider>>> s_providersToRemove;
|
||||
|
||||
namespace impl {
|
||||
|
||||
static std::vector<prv::Provider*> s_closingProviders;
|
||||
static std::set<prv::Provider*> s_closingProviders;
|
||||
void resetClosingProvider() {
|
||||
s_closingProviders.clear();
|
||||
}
|
||||
|
||||
const std::vector<prv::Provider*>& getClosingProviders() {
|
||||
std::set<prv::Provider*> getClosingProviders() {
|
||||
return s_closingProviders;
|
||||
}
|
||||
|
||||
static std::recursive_mutex s_providerMutex;
|
||||
}
|
||||
|
||||
prv::Provider *get() {
|
||||
@@ -293,6 +301,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
void setCurrentProvider(i64 index) {
|
||||
std::scoped_lock lock(impl::s_providerMutex);
|
||||
|
||||
if (TaskManager::getRunningTaskCount() > 0)
|
||||
return;
|
||||
|
||||
@@ -306,6 +316,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
void setCurrentProvider(NonNull<prv::Provider*> provider) {
|
||||
std::scoped_lock lock(impl::s_providerMutex);
|
||||
|
||||
if (TaskManager::getRunningTaskCount() > 0)
|
||||
return;
|
||||
|
||||
@@ -326,6 +338,7 @@ namespace hex {
|
||||
|
||||
void markDirty() {
|
||||
get()->markDirty();
|
||||
EventProviderDirtied::post(get());
|
||||
}
|
||||
|
||||
void resetDirty() {
|
||||
@@ -340,6 +353,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
void add(std::unique_ptr<prv::Provider> &&provider, bool skipLoadInterface, bool select) {
|
||||
std::scoped_lock lock(impl::s_providerMutex);
|
||||
|
||||
if (TaskManager::getRunningTaskCount() > 0)
|
||||
return;
|
||||
|
||||
@@ -354,6 +369,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
void remove(prv::Provider *provider, bool noQuestions) {
|
||||
std::scoped_lock lock(impl::s_providerMutex);
|
||||
|
||||
if (provider == nullptr)
|
||||
return;
|
||||
|
||||
@@ -361,7 +378,7 @@ namespace hex {
|
||||
return;
|
||||
|
||||
if (!noQuestions) {
|
||||
impl::s_closingProviders.push_back(provider);
|
||||
impl::s_closingProviders.insert(provider);
|
||||
|
||||
bool shouldClose = true;
|
||||
EventProviderClosing::post(provider, &shouldClose);
|
||||
@@ -409,20 +426,37 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
provider->close();
|
||||
EventProviderClosed::post(provider);
|
||||
static std::mutex eraseMutex;
|
||||
|
||||
// Move provider over to a list of providers to delete
|
||||
eraseMutex.lock();
|
||||
auto removeIt = s_providersToRemove->emplace(s_providersToRemove->end(), std::move(*it));
|
||||
eraseMutex.unlock();
|
||||
|
||||
// Remove left over references from the main provider list
|
||||
s_providers->erase(it);
|
||||
impl::s_closingProviders.erase(provider);
|
||||
|
||||
if (s_currentProvider >= i64(s_providers->size()) && !s_providers->empty())
|
||||
setCurrentProvider(s_providers->size() - 1);
|
||||
|
||||
if (s_providers->empty())
|
||||
EventProviderChanged::post(provider, nullptr);
|
||||
|
||||
EventProviderClosed::post(removeIt->get());
|
||||
RequestUpdateWindowTitle::post();
|
||||
|
||||
TaskManager::runWhenTasksFinished([it, provider] {
|
||||
EventProviderDeleted::post(provider);
|
||||
std::erase(impl::s_closingProviders, provider);
|
||||
// Do the destruction of the provider in the background once all tasks have finished
|
||||
TaskManager::runWhenTasksFinished([removeIt] {
|
||||
EventProviderDeleted::post(removeIt->get());
|
||||
TaskManager::createBackgroundTask("Closing Provider", [removeIt](Task &) {
|
||||
eraseMutex.lock();
|
||||
auto provider = std::move(*removeIt);
|
||||
s_providersToRemove->erase(removeIt);
|
||||
eraseMutex.unlock();
|
||||
|
||||
s_providers->erase(it);
|
||||
if (s_currentProvider >= i64(s_providers->size()))
|
||||
setCurrentProvider(0);
|
||||
|
||||
if (s_providers->empty())
|
||||
EventProviderChanged::post(provider, nullptr);
|
||||
provider->close();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -437,7 +471,6 @@ namespace hex {
|
||||
|
||||
namespace ImHexApi::System {
|
||||
|
||||
|
||||
namespace impl {
|
||||
|
||||
// Default to true means we forward to ourselves by default
|
||||
@@ -499,6 +532,11 @@ namespace hex {
|
||||
s_gpuVendor = vendor;
|
||||
}
|
||||
|
||||
static AutoReset<std::string> s_glRenderer;
|
||||
void setGLRenderer(const std::string &renderer) {
|
||||
s_glRenderer = renderer;
|
||||
}
|
||||
|
||||
static AutoReset<std::map<std::string, std::string>> s_initArguments;
|
||||
void addInitArgument(const std::string &key, const std::string &value) {
|
||||
static std::mutex initArgumentsMutex;
|
||||
@@ -599,6 +637,11 @@ namespace hex {
|
||||
return impl::s_initialWindowProperties;
|
||||
}
|
||||
|
||||
void* getLibImHexModuleHandle() {
|
||||
return hex::getContainingModule(reinterpret_cast<void*>(&getLibImHexModuleHandle));
|
||||
}
|
||||
|
||||
|
||||
const std::map<std::string, std::string>& getInitArguments() {
|
||||
return *impl::s_initArguments;
|
||||
}
|
||||
@@ -638,6 +681,10 @@ namespace hex {
|
||||
return impl::s_gpuVendor;
|
||||
}
|
||||
|
||||
const std::string &getGLRenderer() {
|
||||
return impl::s_glRenderer;
|
||||
}
|
||||
|
||||
bool isPortableVersion() {
|
||||
static std::optional<bool> portable;
|
||||
if (portable.has_value())
|
||||
@@ -658,7 +705,11 @@ namespace hex {
|
||||
#if defined(OS_WINDOWS)
|
||||
return "Windows";
|
||||
#elif defined(OS_LINUX)
|
||||
return "Linux";
|
||||
#if defined(OS_FREEBSD)
|
||||
return "FreeBSD";
|
||||
#else
|
||||
return "Linux";
|
||||
#endif
|
||||
#elif defined(OS_MACOS)
|
||||
return "macOS";
|
||||
#elif defined(OS_WEB)
|
||||
@@ -720,6 +771,25 @@ namespace hex {
|
||||
#endif
|
||||
}
|
||||
|
||||
std::optional<LinuxDistro> getLinuxDistro() {
|
||||
wolv::io::File file("/etc/os-release", wolv::io::File::Mode::Read);
|
||||
std::string name;
|
||||
std::string version;
|
||||
|
||||
auto fileContent = file.readString();
|
||||
for (const auto &line : wolv::util::splitString(fileContent, "\n")) {
|
||||
if (line.find("PRETTY_NAME=") != std::string::npos) {
|
||||
name = line.substr(line.find("=") + 1);
|
||||
std::erase(name, '\"');
|
||||
} else if (line.find("VERSION_ID=") != std::string::npos) {
|
||||
version = line.substr(line.find("=") + 1);
|
||||
std::erase(version, '\"');
|
||||
}
|
||||
}
|
||||
|
||||
return { { name, version } };
|
||||
}
|
||||
|
||||
std::string getImHexVersion(bool withBuildType) {
|
||||
#if defined IMHEX_VERSION
|
||||
if (withBuildType) {
|
||||
@@ -762,6 +832,10 @@ namespace hex {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isNightlyBuild() {
|
||||
return getImHexVersion(false).ends_with("WIP");
|
||||
}
|
||||
|
||||
bool updateImHex(UpdateType updateType) {
|
||||
// Get the path of the updater executable
|
||||
std::fs::path executablePath;
|
||||
@@ -788,7 +862,7 @@ namespace hex {
|
||||
|
||||
EventImHexClosing::subscribe([executablePath, updateTypeString] {
|
||||
hex::executeCommand(
|
||||
hex::format("{} {}",
|
||||
hex::format("\"{}\" \"{}\"",
|
||||
wolv::util::toUTF8String(executablePath),
|
||||
updateTypeString
|
||||
)
|
||||
@@ -867,9 +941,9 @@ namespace hex {
|
||||
s_fontSize = size;
|
||||
}
|
||||
|
||||
static AutoReset<std::unique_ptr<ImFontAtlas>> s_fontAtlas;
|
||||
static AutoReset<ImFontAtlas*> s_fontAtlas;
|
||||
void setFontAtlas(ImFontAtlas* fontAtlas) {
|
||||
s_fontAtlas = std::unique_ptr<ImFontAtlas>(fontAtlas);
|
||||
s_fontAtlas = fontAtlas;
|
||||
}
|
||||
|
||||
static ImFont *s_boldFont = nullptr;
|
||||
@@ -915,7 +989,7 @@ namespace hex {
|
||||
};
|
||||
}
|
||||
|
||||
void loadFont(const std::fs::path &path, const std::vector<GlyphRange> &glyphRanges, Offset offset, u32 flags) {
|
||||
void loadFont(const std::fs::path &path, const std::vector<GlyphRange> &glyphRanges, Offset offset, u32 flags, std::optional<u32> defaultSize) {
|
||||
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));
|
||||
@@ -927,17 +1001,19 @@ namespace hex {
|
||||
fontFile.readVector(),
|
||||
glyphRanges,
|
||||
offset,
|
||||
flags
|
||||
flags,
|
||||
defaultSize
|
||||
});
|
||||
}
|
||||
|
||||
void loadFont(const std::string &name, const std::span<const u8> &data, const std::vector<GlyphRange> &glyphRanges, Offset offset, u32 flags) {
|
||||
void loadFont(const std::string &name, const std::span<const u8> &data, const std::vector<GlyphRange> &glyphRanges, Offset offset, u32 flags, std::optional<u32> defaultSize) {
|
||||
impl::s_fonts->emplace_back(Font {
|
||||
name,
|
||||
{ data.begin(), data.end() },
|
||||
glyphRanges,
|
||||
offset,
|
||||
flags
|
||||
flags,
|
||||
defaultSize
|
||||
});
|
||||
}
|
||||
|
||||
@@ -950,7 +1026,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
ImFontAtlas* getFontAtlas() {
|
||||
return impl::s_fontAtlas->get();
|
||||
return impl::s_fontAtlas;
|
||||
}
|
||||
|
||||
ImFont* Bold() {
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
#include <hex/api/layout_manager.hpp>
|
||||
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
#include <hex/helpers/default_paths.hpp>
|
||||
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/ui/view.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -40,10 +42,7 @@ namespace hex {
|
||||
fileName += ".hexlyt";
|
||||
|
||||
std::fs::path layoutPath;
|
||||
for (const auto &path : hex::fs::getDefaultPaths(fs::ImHexPath::Layouts)) {
|
||||
if (!hex::fs::isPathWritable(layoutPath))
|
||||
continue;
|
||||
|
||||
for (const auto &path : paths::Layouts.write()) {
|
||||
layoutPath = path / fileName;
|
||||
}
|
||||
|
||||
@@ -64,10 +63,25 @@ namespace hex {
|
||||
}
|
||||
|
||||
|
||||
std::vector<LayoutManager::Layout> LayoutManager::getLayouts() {
|
||||
const std::vector<LayoutManager::Layout>& LayoutManager::getLayouts() {
|
||||
return s_layouts;
|
||||
}
|
||||
|
||||
void LayoutManager::removeLayout(const std::string& name) {
|
||||
for (const auto &layout : *s_layouts) {
|
||||
if (layout.name == name) {
|
||||
if (wolv::io::fs::remove(layout.path)) {
|
||||
log::info("Removed layout '{}'", name);
|
||||
} else {
|
||||
log::error("Failed to remove layout '{}'", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LayoutManager::reload();
|
||||
}
|
||||
|
||||
|
||||
void LayoutManager::closeAllViews() {
|
||||
for (const auto &[name, view] : ContentRegistry::Views::impl::getEntries())
|
||||
view->getWindowOpenState() = false;
|
||||
@@ -75,28 +89,26 @@ namespace hex {
|
||||
|
||||
void LayoutManager::process() {
|
||||
if (s_layoutPathToLoad->has_value()) {
|
||||
const auto pathString = wolv::util::toUTF8String(**s_layoutPathToLoad);
|
||||
|
||||
LayoutManager::closeAllViews();
|
||||
ImGui::LoadIniSettingsFromDisk(pathString.c_str());
|
||||
|
||||
s_layoutPathToLoad = std::nullopt;
|
||||
log::info("Loaded layout from {}", pathString);
|
||||
wolv::io::File file(**s_layoutPathToLoad, wolv::io::File::Mode::Read);
|
||||
s_layoutStringToLoad = file.readString();
|
||||
s_layoutPathToLoad->reset();
|
||||
}
|
||||
|
||||
if (s_layoutStringToLoad->has_value()) {
|
||||
LayoutManager::closeAllViews();
|
||||
ImGui::LoadIniSettingsFromMemory((*s_layoutStringToLoad)->c_str());
|
||||
|
||||
s_layoutStringToLoad = std::nullopt;
|
||||
log::info("Loaded layout from string");
|
||||
s_layoutStringToLoad->reset();
|
||||
log::info("Loaded new Layout");
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutManager::reload() {
|
||||
s_layouts->clear();
|
||||
|
||||
for (const auto &directory : hex::fs::getDefaultPaths(fs::ImHexPath::Layouts)) {
|
||||
for (const auto &directory : paths::Layouts.read()) {
|
||||
for (const auto &entry : std::fs::directory_iterator(directory)) {
|
||||
const auto &path = entry.path();
|
||||
|
||||
@@ -119,8 +131,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
void LayoutManager::reset() {
|
||||
s_layoutPathToLoad.reset();
|
||||
s_layoutStringToLoad.reset();
|
||||
s_layoutPathToLoad->reset();
|
||||
s_layoutStringToLoad->reset();
|
||||
s_layouts->clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/default_paths.hpp>
|
||||
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
@@ -18,24 +19,50 @@
|
||||
|
||||
namespace hex {
|
||||
|
||||
static uintptr_t loadLibrary(const std::fs::path &path) {
|
||||
#if defined(OS_WINDOWS)
|
||||
auto handle = uintptr_t(LoadLibraryW(path.c_str()));
|
||||
|
||||
if (handle == uintptr_t(INVALID_HANDLE_VALUE) || handle == 0) {
|
||||
log::error("Loading library '{}' failed: {} {}!", wolv::util::toUTF8String(path.filename()), ::GetLastError(), hex::formatSystemError(::GetLastError()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return handle;
|
||||
#else
|
||||
auto handle = uintptr_t(dlopen(wolv::util::toUTF8String(path).c_str(), RTLD_LAZY));
|
||||
|
||||
if (handle == 0) {
|
||||
log::error("Loading library '{}' failed: {}!", wolv::util::toUTF8String(path.filename()), dlerror());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return handle;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void unloadLibrary(uintptr_t handle, const std::fs::path &path) {
|
||||
#if defined(OS_WINDOWS)
|
||||
if (handle != 0) {
|
||||
if (FreeLibrary(HMODULE(handle)) == FALSE) {
|
||||
log::error("Error when unloading library '{}': {}!", wolv::util::toUTF8String(path.filename()), hex::formatSystemError(::GetLastError()));
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (handle != 0) {
|
||||
if (dlclose(reinterpret_cast<void*>(handle)) != 0) {
|
||||
log::error("Error when unloading library '{}': {}!", path.filename().string(), dlerror());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Plugin::Plugin(const std::fs::path &path) : m_path(path) {
|
||||
log::info("Loading plugin '{}'", wolv::util::toUTF8String(path.filename()));
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
m_handle = uintptr_t(LoadLibraryW(path.c_str()));
|
||||
|
||||
if (m_handle == uintptr_t(INVALID_HANDLE_VALUE) || m_handle == 0) {
|
||||
log::error("Loading plugin '{}' failed: {} {}!", wolv::util::toUTF8String(path.filename()), ::GetLastError(), hex::formatSystemError(::GetLastError()));
|
||||
return;
|
||||
}
|
||||
#else
|
||||
m_handle = uintptr_t(dlopen(wolv::util::toUTF8String(path).c_str(), RTLD_LAZY));
|
||||
|
||||
if (m_handle == 0) {
|
||||
log::error("Loading plugin '{}' failed: {}!", wolv::util::toUTF8String(path.filename()), dlerror());
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
m_handle = loadLibrary(path);
|
||||
if (m_handle == 0)
|
||||
return;
|
||||
|
||||
const auto fileName = path.stem().string();
|
||||
|
||||
@@ -89,15 +116,7 @@ namespace hex {
|
||||
log::info("Trying to unload plugin '{}'", getPluginName());
|
||||
}
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
if (m_handle != 0)
|
||||
if (FreeLibrary(HMODULE(m_handle)) == FALSE) {
|
||||
log::error("Error when unloading plugin '{}': {}!", wolv::util::toUTF8String(m_path.filename()), hex::formatSystemError(::GetLastError()));
|
||||
}
|
||||
#else
|
||||
if (m_handle != 0)
|
||||
dlclose(reinterpret_cast<void*>(m_handle));
|
||||
#endif
|
||||
unloadLibrary(m_handle, m_path);
|
||||
}
|
||||
|
||||
bool Plugin::initializePlugin() const {
|
||||
@@ -284,6 +303,35 @@ namespace hex {
|
||||
return true;
|
||||
}
|
||||
|
||||
AutoReset<std::vector<uintptr_t>> PluginManager::s_loadedLibraries;
|
||||
|
||||
bool PluginManager::loadLibraries() {
|
||||
bool success = true;
|
||||
for (const auto &loadPath : paths::Libraries.read())
|
||||
success = PluginManager::loadLibraries(loadPath) && success;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool PluginManager::loadLibraries(const std::fs::path& libraryFolder) {
|
||||
bool success = true;
|
||||
for (const auto &entry : std::fs::directory_iterator(libraryFolder)) {
|
||||
if (!(entry.path().extension() == ".dll" || entry.path().extension() == ".so" || entry.path().extension() == ".dylib"))
|
||||
continue;
|
||||
|
||||
auto handle = loadLibrary(entry);
|
||||
if (handle == 0) {
|
||||
success = false;
|
||||
}
|
||||
|
||||
PluginManager::s_loadedLibraries->push_back(handle);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PluginManager::initializeNewPlugins() {
|
||||
for (const auto &plugin : getPlugins()) {
|
||||
if (!plugin.isLoaded())
|
||||
@@ -304,6 +352,11 @@ namespace hex {
|
||||
plugins.pop_back();
|
||||
}
|
||||
|
||||
while (!s_loadedLibraries->empty()) {
|
||||
unloadLibrary(s_loadedLibraries->back(), "");
|
||||
s_loadedLibraries->pop_back();
|
||||
}
|
||||
|
||||
getPluginsMutable() = std::move(savedPlugins);
|
||||
}
|
||||
|
||||
@@ -321,6 +374,15 @@ namespace hex {
|
||||
return plugins;
|
||||
}
|
||||
|
||||
Plugin* PluginManager::getPlugin(const std::string &name) {
|
||||
for (auto &plugin : getPluginsMutable()) {
|
||||
if (plugin.getPluginName() == name)
|
||||
return &plugin;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const std::vector<std::fs::path>& PluginManager::getPluginPaths() {
|
||||
return s_pluginPaths;
|
||||
}
|
||||
@@ -335,5 +397,4 @@ namespace hex {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -412,18 +412,24 @@ namespace hex {
|
||||
void TaskManager::runDeferredCalls() {
|
||||
std::scoped_lock lock(s_deferredCallsMutex);
|
||||
|
||||
for (const auto &call : s_deferredCalls)
|
||||
call();
|
||||
for (const auto &[location, call] : s_onceDeferredCalls)
|
||||
call();
|
||||
|
||||
s_deferredCalls.clear();
|
||||
s_onceDeferredCalls.clear();
|
||||
while (!s_deferredCalls.empty()) {
|
||||
auto callback = s_deferredCalls.front();
|
||||
s_deferredCalls.pop_front();
|
||||
callback();
|
||||
}
|
||||
while (!s_onceDeferredCalls.empty()) {
|
||||
auto node = s_onceDeferredCalls.extract(s_onceDeferredCalls.begin());
|
||||
node.mapped()();
|
||||
}
|
||||
}
|
||||
|
||||
void TaskManager::runWhenTasksFinished(const std::function<void()> &function) {
|
||||
std::scoped_lock lock(s_tasksFinishedMutex);
|
||||
|
||||
for (const auto &task : s_tasks) {
|
||||
task->interrupt();
|
||||
}
|
||||
|
||||
s_tasksFinishedCallbacks.push_back(function);
|
||||
}
|
||||
|
||||
@@ -437,7 +443,7 @@ namespace hex {
|
||||
static auto setThreadDescription = reinterpret_cast<SetThreadDescriptionFunc>(
|
||||
reinterpret_cast<uintptr_t>(
|
||||
::GetProcAddress(
|
||||
::GetModuleHandle("Kernel32.dll"),
|
||||
::GetModuleHandleW(L"Kernel32.dll"),
|
||||
"SetThreadDescription"
|
||||
)
|
||||
)
|
||||
|
||||
@@ -17,18 +17,25 @@ namespace hex {
|
||||
AutoReset<std::string> s_imageTheme;
|
||||
AutoReset<std::string> s_currTheme;
|
||||
|
||||
std::recursive_mutex s_themeMutex;
|
||||
}
|
||||
|
||||
|
||||
void ThemeManager::addThemeHandler(const std::string &name, const ColorMap &colorMap, const std::function<ImColor(u32)> &getFunction, const std::function<void(u32, ImColor)> &setFunction) {
|
||||
std::unique_lock lock(s_themeMutex);
|
||||
|
||||
(*s_themeHandlers)[name] = { colorMap, getFunction, setFunction };
|
||||
}
|
||||
|
||||
void ThemeManager::addStyleHandler(const std::string &name, const StyleMap &styleMap) {
|
||||
std::unique_lock lock(s_themeMutex);
|
||||
|
||||
(*s_styleHandlers)[name] = { styleMap };
|
||||
}
|
||||
|
||||
void ThemeManager::addTheme(const std::string &content) {
|
||||
std::unique_lock lock(s_themeMutex);
|
||||
|
||||
try {
|
||||
auto theme = nlohmann::json::parse(content);
|
||||
|
||||
@@ -66,7 +73,7 @@ namespace hex {
|
||||
if (color == 0x00000000)
|
||||
return ImVec4(0, 0, 0, -1);
|
||||
|
||||
return ImColor(hex::changeEndianess(color, std::endian::big));
|
||||
return ImColor(hex::changeEndianness(color, std::endian::big));
|
||||
}
|
||||
|
||||
nlohmann::json ThemeManager::exportCurrentTheme(const std::string &name) {
|
||||
@@ -83,7 +90,7 @@ namespace hex {
|
||||
|
||||
for (const auto &[key, value] : handler.colorMap) {
|
||||
auto color = handler.getFunction(value);
|
||||
theme["colors"][type][key] = fmt::format("#{:08X}", hex::changeEndianess(u32(color), std::endian::big));
|
||||
theme["colors"][type][key] = fmt::format("#{:08X}", hex::changeEndianness(u32(color), std::endian::big));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +113,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
void ThemeManager::changeTheme(std::string name) {
|
||||
std::unique_lock lock(s_themeMutex);
|
||||
|
||||
if (!s_themes->contains(name)) {
|
||||
if (s_themes->empty()) {
|
||||
return;
|
||||
@@ -168,12 +177,12 @@ namespace hex {
|
||||
const float scale = style.needsScaling ? 1_scaled : 1.0F;
|
||||
|
||||
if (value.is_number_float()) {
|
||||
if (const auto newValue = std::get_if<float*>(&style.value); newValue != nullptr)
|
||||
if (const auto newValue = std::get_if<float*>(&style.value); newValue != nullptr && *newValue != nullptr)
|
||||
**newValue = value.get<float>() * scale;
|
||||
else
|
||||
log::warn("Style variable '{}' was of type ImVec2 but a float was expected.", name);
|
||||
} else if (value.is_array() && value.size() == 2 && value[0].is_number_float() && value[1].is_number_float()) {
|
||||
if (const auto newValue = std::get_if<ImVec2*>(&style.value); newValue != nullptr)
|
||||
if (const auto newValue = std::get_if<ImVec2*>(&style.value); newValue != nullptr && *newValue != nullptr)
|
||||
**newValue = ImVec2(value[0].get<float>() * scale, value[1].get<float>() * scale);
|
||||
else
|
||||
log::warn("Style variable '{}' was of type float but a ImVec2 was expected.", name);
|
||||
@@ -191,6 +200,8 @@ namespace hex {
|
||||
hex::log::error("Theme '{}' has invalid image theme!", name);
|
||||
s_imageTheme = "dark";
|
||||
}
|
||||
} else {
|
||||
s_imageTheme = "dark";
|
||||
}
|
||||
|
||||
s_currTheme = name;
|
||||
@@ -211,6 +222,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
void ThemeManager::reset() {
|
||||
std::unique_lock lock(s_themeMutex);
|
||||
|
||||
s_themes->clear();
|
||||
s_styleHandlers->clear();
|
||||
s_themeHandlers->clear();
|
||||
|
||||
@@ -21,6 +21,11 @@ namespace hex {
|
||||
AutoReset<std::map<ImGuiID, std::string>> s_highlights;
|
||||
AutoReset<std::vector<std::pair<ImRect, std::string>>> s_highlightDisplays;
|
||||
|
||||
AutoReset<std::map<ImGuiID, std::function<void()>>> s_interactiveHelpItems;
|
||||
ImRect s_hoveredRect;
|
||||
ImGuiID s_hoveredId;
|
||||
bool s_helpHoverActive = false;
|
||||
|
||||
|
||||
class IDStack {
|
||||
public:
|
||||
@@ -56,8 +61,42 @@ namespace hex {
|
||||
ImVector<ImGuiID> idStack;
|
||||
};
|
||||
|
||||
ImGuiID calculateId(const auto &ids) {
|
||||
IDStack idStack;
|
||||
|
||||
for (const auto &id : ids) {
|
||||
std::visit(wolv::util::overloaded {
|
||||
[&idStack](const Lang &id) {
|
||||
idStack.add(id.get());
|
||||
},
|
||||
[&idStack](const auto &id) {
|
||||
idStack.add(id);
|
||||
}
|
||||
}, id);
|
||||
}
|
||||
|
||||
return idStack.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TutorialManager::init() {
|
||||
EventImGuiElementRendered::subscribe([](ImGuiID id, const std::array<float, 4> bb){
|
||||
const auto boundingBox = ImRect(bb[0], bb[1], bb[2], bb[3]);
|
||||
|
||||
const auto element = hex::s_highlights->find(id);
|
||||
if (element != hex::s_highlights->end()) {
|
||||
hex::s_highlightDisplays->emplace_back(boundingBox, element->second);
|
||||
}
|
||||
|
||||
if (id != 0 && boundingBox.Contains(ImGui::GetMousePos())) {
|
||||
if ((s_hoveredRect.GetArea() == 0 || boundingBox.GetArea() < s_hoveredRect.GetArea()) && s_interactiveHelpItems->contains(id)) {
|
||||
s_hoveredRect = boundingBox;
|
||||
s_hoveredId = id;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const std::map<std::string, TutorialManager::Tutorial>& TutorialManager::getTutorials() {
|
||||
return s_tutorials;
|
||||
@@ -72,6 +111,28 @@ namespace hex {
|
||||
return s_tutorials->try_emplace(unlocalizedName, Tutorial(unlocalizedName, unlocalizedDescription)).first->second;
|
||||
}
|
||||
|
||||
void TutorialManager::startHelpHover() {
|
||||
TaskManager::doLater([]{
|
||||
s_helpHoverActive = true;
|
||||
});
|
||||
}
|
||||
|
||||
void TutorialManager::addInteractiveHelpText(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, UnlocalizedString text) {
|
||||
auto id = calculateId(ids);
|
||||
|
||||
s_interactiveHelpItems->emplace(id, [text = std::move(text)]{
|
||||
log::info("{}", Lang(text).get());
|
||||
});
|
||||
}
|
||||
|
||||
void TutorialManager::addInteractiveHelpLink(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, std::string link) {
|
||||
auto id = calculateId(ids);
|
||||
|
||||
s_interactiveHelpItems->emplace(id, [link = std::move(link)]{
|
||||
hex::openWebpage(link);
|
||||
});
|
||||
}
|
||||
|
||||
void TutorialManager::startTutorial(const UnlocalizedString &unlocalizedName) {
|
||||
s_currentTutorial = s_tutorials->find(unlocalizedName);
|
||||
if (s_currentTutorial == s_tutorials->end())
|
||||
@@ -81,6 +142,30 @@ namespace hex {
|
||||
}
|
||||
|
||||
void TutorialManager::drawHighlights() {
|
||||
if (s_helpHoverActive) {
|
||||
const auto &drawList = ImGui::GetForegroundDrawList();
|
||||
drawList->AddText(ImGui::GetMousePos() + scaled({ 10, -5, }), ImGui::GetColorU32(ImGuiCol_Text), "?");
|
||||
|
||||
const bool mouseClicked = ImGui::IsMouseClicked(ImGuiMouseButton_Left);
|
||||
if (s_hoveredId != 0) {
|
||||
drawList->AddRectFilled(s_hoveredRect.Min, s_hoveredRect.Max, 0x30FFFFFF);
|
||||
|
||||
if (mouseClicked) {
|
||||
auto it = s_interactiveHelpItems->find(s_hoveredId);
|
||||
if (it != s_interactiveHelpItems->end()) {
|
||||
it->second();
|
||||
}
|
||||
}
|
||||
|
||||
s_hoveredId = 0;
|
||||
s_hoveredRect = {};
|
||||
}
|
||||
|
||||
if (mouseClicked || ImGui::IsKeyPressed(ImGuiKey_Escape)) {
|
||||
s_helpHoverActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &[rect, unlocalizedText] : *s_highlightDisplays) {
|
||||
const auto drawList = ImGui::GetForegroundDrawList();
|
||||
|
||||
@@ -241,39 +326,13 @@ namespace hex {
|
||||
m_onAppear();
|
||||
|
||||
for (const auto &[text, ids] : m_highlights) {
|
||||
IDStack idStack;
|
||||
|
||||
for (const auto &id : ids) {
|
||||
std::visit(wolv::util::overloaded {
|
||||
[&idStack](const Lang &id) {
|
||||
idStack.add(id.get());
|
||||
},
|
||||
[&idStack](const auto &id) {
|
||||
idStack.add(id);
|
||||
}
|
||||
}, id);
|
||||
}
|
||||
|
||||
s_highlights->emplace(idStack.get(), text);
|
||||
s_highlights->emplace(calculateId(ids), text);
|
||||
}
|
||||
}
|
||||
|
||||
void TutorialManager::Tutorial::Step::removeHighlights() const {
|
||||
for (const auto &[text, ids] : m_highlights) {
|
||||
IDStack idStack;
|
||||
|
||||
for (const auto &id : ids) {
|
||||
std::visit(wolv::util::overloaded {
|
||||
[&idStack](const Lang &id) {
|
||||
idStack.add(id.get());
|
||||
},
|
||||
[&idStack](const auto &id) {
|
||||
idStack.add(id);
|
||||
}
|
||||
}, id);
|
||||
}
|
||||
|
||||
s_highlights->erase(idStack.get());
|
||||
s_highlights->erase(calculateId(ids));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,15 +427,4 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ImGuiTestEngineHook_ItemAdd(ImGuiContext*, ImGuiID id, const ImRect& bb, const ImGuiLastItemData*) {
|
||||
const auto element = hex::s_highlights->find(id);
|
||||
if (element != hex::s_highlights->end()) {
|
||||
hex::s_highlightDisplays->emplace_back(bb, element->second);
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiTestEngineHook_ItemInfo(ImGuiContext*, ImGuiID, const char*, ImGuiItemStatusFlags) {}
|
||||
void ImGuiTestEngineHook_Log(ImGuiContext*, const char*, ...) {}
|
||||
const char* ImGuiTestEngine_FindItemDebugLabel(ImGuiContext*, ImGuiID) { return nullptr; }
|
||||
}
|
||||
@@ -3,28 +3,35 @@
|
||||
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
#include <hex/helpers/default_paths.hpp>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
AutoReset<std::map<std::string, WorkspaceManager::Workspace>> WorkspaceManager::s_workspaces;
|
||||
decltype(WorkspaceManager::s_workspaces)::Type::iterator WorkspaceManager::s_currentWorkspace = s_workspaces->end();
|
||||
decltype(WorkspaceManager::s_workspaces)::Type::iterator WorkspaceManager::s_previousWorkspace = s_workspaces->end();
|
||||
decltype(WorkspaceManager::s_workspaces)::Type::iterator WorkspaceManager::s_workspaceToRemove = s_workspaces->end();
|
||||
|
||||
void WorkspaceManager::createWorkspace(const std::string& name, const std::string &layout) {
|
||||
s_currentWorkspace = s_workspaces->insert_or_assign(name, Workspace {
|
||||
.layout = layout.empty() ? LayoutManager::saveToString() : layout,
|
||||
.path = {}
|
||||
.layout = layout.empty() ? LayoutManager::saveToString() : layout,
|
||||
.path = {},
|
||||
.builtin = false
|
||||
}).first;
|
||||
|
||||
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Workspaces)) {
|
||||
if (exportToFile(path / (name + ".hexws")))
|
||||
for (const auto &workspaceFolder : paths::Workspaces.write()) {
|
||||
const auto workspacePath = workspaceFolder / (name + ".hexws");
|
||||
if (exportToFile(workspacePath)) {
|
||||
s_currentWorkspace->second.path = workspacePath;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +44,10 @@ namespace hex {
|
||||
}
|
||||
|
||||
void WorkspaceManager::importFromFile(const std::fs::path& path) {
|
||||
if (std::ranges::any_of(*s_workspaces, [path](const auto &pair) { return pair.second.path == path; })) {
|
||||
return;
|
||||
}
|
||||
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Read);
|
||||
if (!file.isValid()) {
|
||||
log::error("Failed to load workspace from file '{}'", path.string());
|
||||
@@ -50,10 +61,12 @@ namespace hex {
|
||||
|
||||
const std::string name = json["name"];
|
||||
std::string layout = json["layout"];
|
||||
const bool builtin = json.value("builtin", false);
|
||||
|
||||
(*s_workspaces)[name] = Workspace {
|
||||
.layout = std::move(layout),
|
||||
.path = path
|
||||
.path = path,
|
||||
.builtin = builtin
|
||||
};
|
||||
} catch (nlohmann::json::exception &e) {
|
||||
log::error("Failed to load workspace from file '{}': {}", path.string(), e.what());
|
||||
@@ -61,41 +74,77 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
bool WorkspaceManager::exportToFile(std::fs::path path, std::string workspaceName) {
|
||||
bool WorkspaceManager::exportToFile(std::fs::path path, std::string workspaceName, bool builtin) {
|
||||
if (path.empty()) {
|
||||
if (s_currentWorkspace == s_workspaces->end())
|
||||
if (s_currentWorkspace == s_workspaces->end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
path = s_currentWorkspace->second.path;
|
||||
}
|
||||
|
||||
if (workspaceName.empty())
|
||||
if (workspaceName.empty()) {
|
||||
workspaceName = s_currentWorkspace->first;
|
||||
}
|
||||
|
||||
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||
|
||||
if (!file.isValid())
|
||||
if (!file.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nlohmann::json json;
|
||||
json["name"] = workspaceName;
|
||||
json["layout"] = LayoutManager::saveToString();
|
||||
json["builtin"] = builtin;
|
||||
|
||||
file.writeString(json.dump(4));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WorkspaceManager::removeWorkspace(const std::string& name) {
|
||||
bool deletedCurrentWorkspace = false;
|
||||
for (const auto &[workspaceName, workspace] : *s_workspaces) {
|
||||
if (workspaceName == name) {
|
||||
log::info("Removing workspace file '{}'", wolv::util::toUTF8String(workspace.path));
|
||||
if (wolv::io::fs::remove(workspace.path)) {
|
||||
log::info("Removed workspace '{}'", name);
|
||||
|
||||
if (workspaceName == s_currentWorkspace->first) {
|
||||
deletedCurrentWorkspace = true;
|
||||
}
|
||||
} else {
|
||||
log::error("Failed to remove workspace '{}'", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WorkspaceManager::reload();
|
||||
|
||||
if (deletedCurrentWorkspace && !s_workspaces->empty()) {
|
||||
s_currentWorkspace = s_workspaces->begin();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WorkspaceManager::process() {
|
||||
if (s_previousWorkspace != s_currentWorkspace) {
|
||||
if (s_previousWorkspace != s_workspaces->end())
|
||||
exportToFile(s_previousWorkspace->second.path, s_previousWorkspace->first);
|
||||
log::info("Updating workspace");
|
||||
if (s_previousWorkspace != s_workspaces->end()) {
|
||||
exportToFile(s_previousWorkspace->second.path, s_previousWorkspace->first, s_previousWorkspace->second.builtin);
|
||||
}
|
||||
|
||||
LayoutManager::closeAllViews();
|
||||
ImGui::LoadIniSettingsFromMemory(s_currentWorkspace->second.layout.c_str());
|
||||
|
||||
s_previousWorkspace = s_currentWorkspace;
|
||||
|
||||
if (s_workspaceToRemove != s_workspaces->end()) {
|
||||
s_workspaces->erase(s_workspaceToRemove);
|
||||
s_workspaceToRemove = s_workspaces->end();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +155,26 @@ namespace hex {
|
||||
s_previousWorkspace = s_workspaces->end();
|
||||
}
|
||||
|
||||
void WorkspaceManager::reload() {
|
||||
WorkspaceManager::reset();
|
||||
|
||||
for (const auto &defaultPath : paths::Workspaces.read()) {
|
||||
for (const auto &entry : std::fs::directory_iterator(defaultPath)) {
|
||||
if (!entry.is_regular_file()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto &path = entry.path();
|
||||
if (path.extension() != ".hexws") {
|
||||
continue;
|
||||
}
|
||||
|
||||
WorkspaceManager::importFromFile(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
153
lib/libimhex/source/helpers/default_paths.cpp
Normal file
153
lib/libimhex/source/helpers/default_paths.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
#include <hex/helpers/default_paths.hpp>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#elif defined(OS_LINUX) || defined(OS_WEB)
|
||||
#include <xdg.hpp>
|
||||
# endif
|
||||
|
||||
namespace hex::paths {
|
||||
|
||||
std::vector<std::fs::path> getDataPaths(bool includeSystemFolders) {
|
||||
std::vector<std::fs::path> paths;
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
// In the portable Windows version, we just use the executable directory
|
||||
// Prevent the use of the AppData folder here
|
||||
if (!ImHexApi::System::isPortableVersion()) {
|
||||
PWSTR wAppDataPath = nullptr;
|
||||
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &wAppDataPath))) {
|
||||
paths.emplace_back(wAppDataPath);
|
||||
CoTaskMemFree(wAppDataPath);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(OS_MACOS)
|
||||
|
||||
paths.push_back(wolv::io::fs::getApplicationSupportDirectoryPath());
|
||||
|
||||
#elif defined(OS_LINUX) || defined(OS_WEB)
|
||||
|
||||
paths.push_back(xdg::DataHomeDir());
|
||||
|
||||
auto dataDirs = xdg::DataDirs();
|
||||
std::copy(dataDirs.begin(), dataDirs.end(), std::back_inserter(paths));
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOS)
|
||||
|
||||
if (includeSystemFolders) {
|
||||
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value()) {
|
||||
paths.push_back(*executablePath);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
for (auto &path : paths)
|
||||
path = path / "imhex";
|
||||
|
||||
if (ImHexApi::System::isPortableVersion() || includeSystemFolders) {
|
||||
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value())
|
||||
paths.push_back(executablePath->parent_path());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// Add additional data directories to the path
|
||||
auto additionalDirs = ImHexApi::System::getAdditionalFolderPaths();
|
||||
std::ranges::copy(additionalDirs, std::back_inserter(paths));
|
||||
|
||||
// Add the project file directory to the path, if one is loaded
|
||||
if (ProjectFile::hasPath()) {
|
||||
paths.push_back(ProjectFile::getPath().parent_path());
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> getConfigPaths(bool includeSystemFolders) {
|
||||
#if defined(OS_WINDOWS)
|
||||
return getDataPaths(includeSystemFolders);
|
||||
#elif defined(OS_MACOS)
|
||||
return getDataPaths(includeSystemFolders);
|
||||
#elif defined(OS_LINUX) || defined(OS_WEB)
|
||||
hex::unused(includeSystemFolders);
|
||||
return {xdg::ConfigHomeDir() / "imhex"};
|
||||
#endif
|
||||
}
|
||||
|
||||
static std::vector<std::fs::path> appendPath(std::vector<std::fs::path> paths, std::fs::path folder) {
|
||||
folder.make_preferred();
|
||||
|
||||
for (auto &path : paths)
|
||||
path = path / folder;
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
static std::vector<std::fs::path> getPluginPaths() {
|
||||
std::vector<std::fs::path> paths = getDataPaths(true);
|
||||
|
||||
// Add the system plugin directory to the path if one was provided at compile time
|
||||
#if defined(OS_LINUX) && defined(SYSTEM_PLUGINS_LOCATION)
|
||||
paths.push_back(SYSTEM_PLUGINS_LOCATION);
|
||||
#endif
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::vector<std::fs::path> DefaultPath::read() const {
|
||||
auto result = this->all();
|
||||
|
||||
std::erase_if(result, [](const auto &entryPath) {
|
||||
return !wolv::io::fs::isDirectory(entryPath);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> DefaultPath::write() const {
|
||||
auto result = this->read();
|
||||
|
||||
std::erase_if(result, [](const auto &entryPath) {
|
||||
return !hex::fs::isPathWritable(entryPath);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> ConfigPath::all() const {
|
||||
return appendPath(getConfigPaths(false), m_postfix);
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> DataPath::all() const {
|
||||
return appendPath(getDataPaths(true), m_postfix);
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> DataPath::write() const {
|
||||
auto result = appendPath(getDataPaths(false), m_postfix);
|
||||
|
||||
std::erase_if(result, [](const auto &entryPath) {
|
||||
return !hex::fs::isPathWritable(entryPath);
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> PluginPath::all() const {
|
||||
return appendPath(getPluginPaths(), m_postfix);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,13 +13,48 @@
|
||||
#include <shellapi.h>
|
||||
#elif defined(OS_LINUX) || defined(OS_WEB)
|
||||
#include <xdg.hpp>
|
||||
# if defined(OS_FREEBSD)
|
||||
#include <sys/syslimits.h>
|
||||
# else
|
||||
#include <limits.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(OS_WEB)
|
||||
#include <emscripten.h>
|
||||
#else
|
||||
#include <nfd.hpp>
|
||||
#if defined(OS_WINDOWS)
|
||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||
#endif
|
||||
#if defined(OS_MACOS)
|
||||
// macOS platform headers can't be compiled with gcc
|
||||
#define GLFW_NATIVE_INCLUDE_NONE
|
||||
typedef uint32_t CGDirectDisplayID;
|
||||
typedef void *id;
|
||||
typedef void NSWindow;
|
||||
#define GLFW_EXPOSE_NATIVE_COCOA
|
||||
#endif
|
||||
#if defined(OS_LINUX)
|
||||
#define GLFW_EXPOSE_NATIVE_X11
|
||||
#endif
|
||||
#if defined(OS_LINUX) && defined(GLFW_WAYLAND_APP_ID)
|
||||
#define GLFW_EXPOSE_NATIVE_WAYLAND
|
||||
#endif
|
||||
#include <nfd_glfw3.h>
|
||||
#if defined(OS_LINUX) && defined(GLFW_WAYLAND_APP_ID)
|
||||
#undef GLFW_EXPOSE_NATIVE_WAYLAND
|
||||
#endif
|
||||
#if defined(OS_LINUX)
|
||||
#undef GLFW_EXPOSE_NATIVE_X11
|
||||
#endif
|
||||
#if defined(OS_MACOS)
|
||||
#undef GLFW_EXPOSE_NATIVE_COCOA
|
||||
#undef GLFW_NATIVE_INCLUDE_NONE
|
||||
#endif
|
||||
#if defined(OS_WINDOWS)
|
||||
#undef GLFW_EXPOSE_NATIVE_WIN32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <filesystem>
|
||||
@@ -28,6 +63,9 @@
|
||||
#include <wolv/io/fs.hpp>
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/xchar.h>
|
||||
|
||||
namespace hex::fs {
|
||||
|
||||
static AutoReset<std::function<void(const std::string&)>> s_fileBrowserErrorCallback;
|
||||
@@ -44,7 +82,7 @@ namespace hex::fs {
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
hex::unused(
|
||||
ShellExecute(nullptr, "open", wolv::util::toUTF8String(filePath).c_str(), nullptr, nullptr, SW_SHOWNORMAL)
|
||||
ShellExecuteW(nullptr, L"open", filePath.c_str(), nullptr, nullptr, SW_SHOWNORMAL)
|
||||
);
|
||||
#elif defined(OS_MACOS)
|
||||
hex::unused(system(
|
||||
@@ -62,9 +100,8 @@ namespace hex::fs {
|
||||
}
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
hex::unused(system(
|
||||
hex::format("explorer.exe {}", wolv::util::toUTF8String(dirPath)).c_str()
|
||||
));
|
||||
auto args = fmt::format(L"\"{}\"", dirPath.c_str());
|
||||
ShellExecuteW(nullptr, L"open", L"explorer.exe", args.c_str(), nullptr, SW_SHOWNORMAL);
|
||||
#elif defined(OS_MACOS)
|
||||
hex::unused(system(
|
||||
hex::format("open {}", wolv::util::toUTF8String(dirPath)).c_str()
|
||||
@@ -81,9 +118,8 @@ namespace hex::fs {
|
||||
}
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
hex::unused(system(
|
||||
hex::format(R"(explorer.exe /select,"{}")", wolv::util::toUTF8String(selectedFilePath)).c_str()
|
||||
));
|
||||
auto args = fmt::format(L"/select,\"{}\"", selectedFilePath.c_str());
|
||||
ShellExecuteW(nullptr, L"open", L"explorer.exe", args.c_str(), nullptr, SW_SHOWNORMAL);
|
||||
#elif defined(OS_MACOS)
|
||||
hex::unused(system(
|
||||
hex::format(
|
||||
@@ -228,20 +264,22 @@ namespace hex::fs {
|
||||
NFD::UniquePathU8 outPath;
|
||||
NFD::UniquePathSet outPaths;
|
||||
nfdresult_t result = NFD_ERROR;
|
||||
nfdwindowhandle_t nativeWindow{};
|
||||
NFD_GetNativeWindowFromGLFWWindow(ImHexApi::System::getMainWindowHandle(), &nativeWindow);
|
||||
|
||||
// Open the correct file dialog based on the mode
|
||||
switch (mode) {
|
||||
case DialogMode::Open:
|
||||
if (multiple)
|
||||
result = NFD::OpenDialogMultiple(outPaths, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str());
|
||||
result = NFD::OpenDialogMultiple(outPaths, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str(), nativeWindow);
|
||||
else
|
||||
result = NFD::OpenDialog(outPath, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str());
|
||||
result = NFD::OpenDialog(outPath, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str(), nativeWindow);
|
||||
break;
|
||||
case DialogMode::Save:
|
||||
result = NFD::SaveDialog(outPath, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str());
|
||||
result = NFD::SaveDialog(outPath, validExtensionsNfd.data(), validExtensionsNfd.size(), defaultPath.empty() ? nullptr : defaultPath.c_str(), nullptr, nativeWindow);
|
||||
break;
|
||||
case DialogMode::Folder:
|
||||
result = NFD::PickFolder(outPath, defaultPath.empty() ? nullptr : defaultPath.c_str());
|
||||
result = NFD::PickFolder(outPath, defaultPath.empty() ? nullptr : defaultPath.c_str(), nativeWindow);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -282,170 +320,6 @@ namespace hex::fs {
|
||||
|
||||
#endif
|
||||
|
||||
std::vector<std::fs::path> getDataPaths() {
|
||||
std::vector<std::fs::path> paths;
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
// In the portable Windows version, we just use the executable directory
|
||||
// Prevent the use of the AppData folder here
|
||||
if (!ImHexApi::System::isPortableVersion()) {
|
||||
PWSTR wAppDataPath = nullptr;
|
||||
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &wAppDataPath))) {
|
||||
paths.emplace_back(wAppDataPath);
|
||||
CoTaskMemFree(wAppDataPath);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(OS_MACOS)
|
||||
|
||||
paths.push_back(wolv::io::fs::getApplicationSupportDirectoryPath());
|
||||
|
||||
#elif defined(OS_LINUX) || defined(OS_WEB)
|
||||
|
||||
paths.push_back(xdg::DataHomeDir());
|
||||
|
||||
auto dataDirs = xdg::DataDirs();
|
||||
std::copy(dataDirs.begin(), dataDirs.end(), std::back_inserter(paths));
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOS)
|
||||
|
||||
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value())
|
||||
paths.push_back(*executablePath);
|
||||
|
||||
#else
|
||||
|
||||
for (auto &path : paths)
|
||||
path = path / "imhex";
|
||||
|
||||
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value())
|
||||
paths.push_back(executablePath->parent_path());
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// Add additional data directories to the path
|
||||
auto additionalDirs = ImHexApi::System::getAdditionalFolderPaths();
|
||||
std::ranges::copy(additionalDirs, std::back_inserter(paths));
|
||||
|
||||
// Add the project file directory to the path, if one is loaded
|
||||
if (ProjectFile::hasPath()) {
|
||||
paths.push_back(ProjectFile::getPath().parent_path());
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
static std::vector<std::fs::path> getConfigPaths() {
|
||||
#if defined(OS_WINDOWS)
|
||||
return getDataPaths();
|
||||
#elif defined(OS_MACOS)
|
||||
return getDataPaths();
|
||||
#elif defined(OS_LINUX) || defined(OS_WEB)
|
||||
return {xdg::ConfigHomeDir() / "imhex"};
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> appendPath(std::vector<std::fs::path> paths, const std::fs::path &folder) {
|
||||
for (auto &path : paths)
|
||||
path = path / folder;
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> getPluginPaths() {
|
||||
std::vector<std::fs::path> paths = getDataPaths();
|
||||
|
||||
// Add the system plugin directory to the path if one was provided at compile time
|
||||
#if defined(OS_LINUX) && defined(SYSTEM_PLUGINS_LOCATION)
|
||||
paths.push_back(SYSTEM_PLUGINS_LOCATION);
|
||||
#endif
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting) {
|
||||
std::vector<std::fs::path> result;
|
||||
|
||||
// Return the correct path based on the ImHexPath enum
|
||||
switch (path) {
|
||||
case ImHexPath::END:
|
||||
return { };
|
||||
case ImHexPath::Constants:
|
||||
result = appendPath(getDataPaths(), "constants");
|
||||
break;
|
||||
case ImHexPath::Config:
|
||||
result = appendPath(getConfigPaths(), "config");
|
||||
break;
|
||||
case ImHexPath::Backups:
|
||||
result = appendPath(getDataPaths(), "backups");
|
||||
break;
|
||||
case ImHexPath::Encodings:
|
||||
result = appendPath(getDataPaths(), "encodings");
|
||||
break;
|
||||
case ImHexPath::Logs:
|
||||
result = appendPath(getDataPaths(), "logs");
|
||||
break;
|
||||
case ImHexPath::Plugins:
|
||||
result = appendPath(getPluginPaths(), "plugins");
|
||||
break;
|
||||
case ImHexPath::Libraries:
|
||||
result = appendPath(getPluginPaths(), "lib");
|
||||
break;
|
||||
case ImHexPath::Resources:
|
||||
result = appendPath(getDataPaths(), "resources");
|
||||
break;
|
||||
case ImHexPath::Magic:
|
||||
result = appendPath(getDataPaths(), "magic");
|
||||
break;
|
||||
case ImHexPath::Patterns:
|
||||
result = appendPath(getDataPaths(), "patterns");
|
||||
break;
|
||||
case ImHexPath::PatternsInclude:
|
||||
result = appendPath(getDataPaths(), "includes");
|
||||
break;
|
||||
case ImHexPath::Yara:
|
||||
result = appendPath(getDataPaths(), "yara");
|
||||
break;
|
||||
case ImHexPath::YaraAdvancedAnalysis:
|
||||
result = appendPath(getDefaultPaths(ImHexPath::Yara), "advanced_analysis");
|
||||
break;
|
||||
case ImHexPath::Recent:
|
||||
result = appendPath(getConfigPaths(), "recent");
|
||||
break;
|
||||
case ImHexPath::Scripts:
|
||||
result = appendPath(getDataPaths(), "scripts");
|
||||
break;
|
||||
case ImHexPath::Inspectors:
|
||||
result = appendPath(getDefaultPaths(ImHexPath::Scripts), "inspectors");
|
||||
break;
|
||||
case ImHexPath::Nodes:
|
||||
result = appendPath(getDefaultPaths(ImHexPath::Scripts), "nodes");
|
||||
break;
|
||||
case ImHexPath::Themes:
|
||||
result = appendPath(getDataPaths(), "themes");
|
||||
break;
|
||||
case ImHexPath::Layouts:
|
||||
result = appendPath(getDataPaths(), "layouts");
|
||||
break;
|
||||
case ImHexPath::Workspaces:
|
||||
result = appendPath(getDataPaths(), "workspaces");
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove all paths that don't exist if requested
|
||||
if (!listNonExisting) {
|
||||
std::erase_if(result, [](const auto &entryPath) {
|
||||
return !wolv::io::fs::isDirectory(entryPath);
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool isPathWritable(const std::fs::path &path) {
|
||||
constexpr static auto TestFileName = "__imhex__tmp__";
|
||||
|
||||
|
||||
15
lib/libimhex/source/helpers/imgui_hooks.cpp
Normal file
15
lib/libimhex/source/helpers/imgui_hooks.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include <hex/api/event_manager.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
void ImGuiTestEngineHook_ItemAdd(ImGuiContext*, ImGuiID id, const ImRect& bb, const ImGuiLastItemData*) {
|
||||
std::array<float, 4> boundingBox = { bb.Min.x, bb.Min.y, bb.Max.x, bb.Max.y };
|
||||
hex::EventImGuiElementRendered::post(id, boundingBox);
|
||||
}
|
||||
|
||||
void ImGuiTestEngineHook_ItemInfo(ImGuiContext*, ImGuiID, const char*, ImGuiItemStatusFlags) {}
|
||||
void ImGuiTestEngineHook_Log(ImGuiContext*, const char*, ...) {}
|
||||
const char* ImGuiTestEngine_FindItemDebugLabel(ImGuiContext*, ImGuiID) { return nullptr; }
|
||||
@@ -1,12 +1,17 @@
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <hex/api/task_manager.hpp>
|
||||
#include <hex/api/event_manager.hpp>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/default_paths.hpp>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
|
||||
#include <mutex>
|
||||
#include <chrono>
|
||||
#include <fmt/chrono.h>
|
||||
#include <hex/api/task_manager.hpp>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#include <Windows.h>
|
||||
@@ -20,6 +25,7 @@ namespace hex::log {
|
||||
bool s_colorOutputEnabled = false;
|
||||
std::recursive_mutex s_loggerMutex;
|
||||
bool s_loggingSuspended = false;
|
||||
bool s_debugLoggingEnabled = false;
|
||||
|
||||
}
|
||||
|
||||
@@ -31,16 +37,33 @@ namespace hex::log {
|
||||
s_loggingSuspended = false;
|
||||
}
|
||||
|
||||
void enableDebugLogging() {
|
||||
s_debugLoggingEnabled = true;
|
||||
}
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::recursive_mutex& getLoggerMutex() {
|
||||
return s_loggerMutex;
|
||||
void lockLoggerMutex() {
|
||||
s_loggerMutex.lock();
|
||||
}
|
||||
|
||||
void unlockLoggerMutex() {
|
||||
s_loggerMutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
bool isLoggingSuspended() {
|
||||
return s_loggingSuspended;
|
||||
}
|
||||
|
||||
bool isDebugLoggingEnabled() {
|
||||
#if defined(DEBUG)
|
||||
return true;
|
||||
#else
|
||||
return s_debugLoggingEnabled;
|
||||
#endif
|
||||
}
|
||||
|
||||
FILE *getDestination() {
|
||||
if (s_loggerFile.isValid())
|
||||
return s_loggerFile.getHandle();
|
||||
@@ -59,13 +82,13 @@ namespace hex::log {
|
||||
void redirectToFile() {
|
||||
if (s_loggerFile.isValid()) return;
|
||||
|
||||
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Logs, true)) {
|
||||
for (const auto &path : paths::Logs.all()) {
|
||||
wolv::io::fs::createDirectories(path);
|
||||
s_loggerFile = wolv::io::File(path / hex::format("{0:%Y%m%d_%H%M%S}.log", fmt::localtime(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()))), wolv::io::File::Mode::Create);
|
||||
s_loggerFile.disableBuffering();
|
||||
|
||||
if (s_loggerFile.isValid()) {
|
||||
s_colorOutputEnabled = true;
|
||||
s_colorOutputEnabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -121,14 +144,12 @@ namespace hex::log {
|
||||
fmt::print(dest, "{0}", std::string(projectNameLength > MaxTagLength ? 0 : MaxTagLength - projectNameLength, ' '));
|
||||
}
|
||||
|
||||
void assertionHandler(bool expr, const char* exprString, const char* file, int line) {
|
||||
if (!expr) {
|
||||
log::error("Assertion failed: {} at {}:{}", exprString, file, line);
|
||||
void assertionHandler(const char* exprString, const char* file, int line) {
|
||||
log::error("Assertion failed: {} at {}:{}", exprString, file, line);
|
||||
|
||||
#if defined (DEBUG)
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
#if defined (DEBUG)
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace color {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/default_paths.hpp>
|
||||
|
||||
#include <wolv/utils/guards.hpp>
|
||||
#include <wolv/utils/string.hpp>
|
||||
@@ -29,7 +30,7 @@ namespace hex::magic {
|
||||
std::string magicFiles;
|
||||
|
||||
std::error_code error;
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
|
||||
for (const auto &dir : paths::Magic.read()) {
|
||||
for (const auto &entry : std::fs::directory_iterator(dir, error)) {
|
||||
auto path = std::fs::absolute(entry.path());
|
||||
|
||||
@@ -64,12 +65,12 @@ namespace hex::magic {
|
||||
if (magicFiles->empty())
|
||||
return true;
|
||||
|
||||
std::array<char, 1024> cwd = { 0x00 };
|
||||
std::array<char, 1024> cwd = { };
|
||||
if (getcwd(cwd.data(), cwd.size()) == nullptr)
|
||||
return false;
|
||||
|
||||
std::optional<std::fs::path> magicFolder;
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
|
||||
for (const auto &dir : paths::Magic.write()) {
|
||||
if (std::fs::exists(dir) && fs::isPathWritable(dir)) {
|
||||
magicFolder = dir;
|
||||
break;
|
||||
@@ -105,8 +106,13 @@ namespace hex::magic {
|
||||
ON_SCOPE_EXIT { magic_close(ctx); };
|
||||
|
||||
if (magic_load(ctx, magicFiles->c_str()) == 0) {
|
||||
if (auto result = magic_buffer(ctx, data.data(), data.size()); result != nullptr)
|
||||
return wolv::util::replaceStrings(result, "\\012-", "\n-");
|
||||
if (auto description = magic_buffer(ctx, data.data(), data.size()); description != nullptr) {
|
||||
auto result = wolv::util::replaceStrings(description, "\\012-", "\n-");
|
||||
if (result.ends_with("- data"))
|
||||
result = result.substr(0, result.size() - 6);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,8 +136,13 @@ namespace hex::magic {
|
||||
ON_SCOPE_EXIT { magic_close(ctx); };
|
||||
|
||||
if (magic_load(ctx, magicFiles->c_str()) == 0) {
|
||||
if (auto result = magic_buffer(ctx, data.data(), data.size()); result != nullptr)
|
||||
return wolv::util::replaceStrings(result, "\\012-", "\n-");
|
||||
if (auto mimeType = magic_buffer(ctx, data.data(), data.size()); mimeType != nullptr) {
|
||||
auto result = wolv::util::replaceStrings(mimeType, "\\012-", "\n-");
|
||||
if (result.ends_with("- application/octet-stream"))
|
||||
result = result.substr(0, result.size() - 26);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,8 +173,13 @@ namespace hex::magic {
|
||||
ON_SCOPE_EXIT { magic_close(ctx); };
|
||||
|
||||
if (magic_load(ctx, magicFiles->c_str()) == 0) {
|
||||
if (auto result = magic_buffer(ctx, data.data(), data.size()); result != nullptr)
|
||||
return wolv::util::replaceStrings(result, "\\012-", "\n-");
|
||||
if (auto extension = magic_buffer(ctx, data.data(), data.size()); extension != nullptr) {
|
||||
auto result = wolv::util::replaceStrings(extension, "\\012-", "\n-");
|
||||
if (result.ends_with("- ???"))
|
||||
result = result.substr(0, result.size() - 5);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace hex {
|
||||
result.push_back(addressBytes[2]);
|
||||
result.push_back(addressBytes[1]);
|
||||
result.push_back(addressBytes[0]);
|
||||
pushBytesBack<u16>(result, changeEndianess<u16>(bytes.size(), std::endian::big));
|
||||
pushBytesBack<u16>(result, changeEndianness<u16>(bytes.size(), std::endian::big));
|
||||
|
||||
for (auto byte : bytes)
|
||||
result.push_back(byte);
|
||||
@@ -189,7 +189,7 @@ namespace hex {
|
||||
result.push_back(addressBytes[2]);
|
||||
result.push_back(addressBytes[1]);
|
||||
result.push_back(addressBytes[0]);
|
||||
pushBytesBack<u16>(result, changeEndianess<u16>(bytes.size(), std::endian::big));
|
||||
pushBytesBack<u16>(result, changeEndianness<u16>(bytes.size(), std::endian::big));
|
||||
|
||||
for (auto byte : bytes)
|
||||
result.push_back(byte);
|
||||
|
||||
@@ -90,11 +90,7 @@ namespace hex {
|
||||
bool Tar::contains(const std::fs::path &path) const {
|
||||
mtar_header_t header;
|
||||
|
||||
auto fixedPath = path.string();
|
||||
#if defined(OS_WINDOWS)
|
||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
||||
#endif
|
||||
|
||||
const auto fixedPath = wolv::io::fs::toNormalizedPathString(path);
|
||||
return mtar_find(m_ctx.get(), fixedPath.c_str(), &header) == MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
@@ -115,10 +111,7 @@ namespace hex {
|
||||
std::vector<u8> Tar::readVector(const std::fs::path &path) const {
|
||||
mtar_header_t header;
|
||||
|
||||
auto fixedPath = path.string();
|
||||
#if defined(OS_WINDOWS)
|
||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
||||
#endif
|
||||
const auto fixedPath = wolv::io::fs::toNormalizedPathString(path);
|
||||
int ret = mtar_find(m_ctx.get(), fixedPath.c_str(), &header);
|
||||
if (ret != MTAR_ESUCCESS){
|
||||
log::debug("Failed to read vector from path {} in tarred file {}: {}",
|
||||
@@ -143,18 +136,12 @@ namespace hex {
|
||||
for (const auto &part : path.parent_path()) {
|
||||
pathPart /= part;
|
||||
|
||||
auto fixedPath = pathPart.string();
|
||||
#if defined(OS_WINDOWS)
|
||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
||||
#endif
|
||||
auto fixedPath = wolv::io::fs::toNormalizedPathString(pathPart);
|
||||
mtar_write_dir_header(m_ctx.get(), fixedPath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
auto fixedPath = path.string();
|
||||
#if defined(OS_WINDOWS)
|
||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
||||
#endif
|
||||
const auto fixedPath = wolv::io::fs::toNormalizedPathString(path);
|
||||
mtar_write_file_header(m_ctx.get(), fixedPath.c_str(), data.size());
|
||||
mtar_write_data(m_ctx.get(), data.data(), data.size());
|
||||
}
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
#include <wolv/utils/guards.hpp>
|
||||
#elif defined(OS_LINUX)
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#include <hex/helpers/utils_linux.hpp>
|
||||
#elif defined(OS_MACOS)
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#include <hex/helpers/utils_macos.hpp>
|
||||
#elif defined(OS_WEB)
|
||||
#include "emscripten.h"
|
||||
@@ -353,7 +355,7 @@ namespace hex {
|
||||
url = "https://" + url;
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
ShellExecute(nullptr, "open", url.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
|
||||
ShellExecuteA(nullptr, "open", url.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
|
||||
#elif defined(OS_MACOS)
|
||||
openWebpageMacos(url.c_str());
|
||||
#elif defined(OS_LINUX)
|
||||
@@ -677,6 +679,44 @@ namespace hex {
|
||||
return value;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string limitStringLength(const std::string &string, size_t maxLength) {
|
||||
// If the string is shorter than the max length, return it as is
|
||||
if (string.size() < maxLength)
|
||||
return string;
|
||||
|
||||
// If the string is longer than the max length, find the last space before the max length
|
||||
auto it = string.begin() + maxLength / 2;
|
||||
while (it != string.begin() && !std::isspace(*it)) --it;
|
||||
|
||||
// If there's no space before the max length, just cut the string
|
||||
if (it == string.begin()) {
|
||||
it = string.begin() + maxLength / 2;
|
||||
|
||||
// Try to find a UTF-8 character boundary
|
||||
while (it != string.begin() && (*it & 0xC0) == 0x80) --it;
|
||||
}
|
||||
|
||||
// If we still didn't find a valid boundary, just return the string as is
|
||||
if (it == string.begin())
|
||||
return string;
|
||||
|
||||
auto result = std::string(string.begin(), it) + "…";
|
||||
|
||||
// If the string is longer than the max length, find the last space before the max length
|
||||
it = string.end() - 1 - maxLength / 2;
|
||||
while (it != string.end() && !std::isspace(*it)) ++it;
|
||||
|
||||
// If there's no space before the max length, just cut the string
|
||||
if (it == string.end()) {
|
||||
it = string.end() - 1 - maxLength / 2;
|
||||
|
||||
// Try to find a UTF-8 character boundary
|
||||
while (it != string.end() && (*it & 0xC0) == 0x80) ++it;
|
||||
}
|
||||
|
||||
return result + std::string(it, string.end());
|
||||
}
|
||||
|
||||
static std::optional<std::fs::path> s_fileToOpen;
|
||||
extern "C" void openFile(const char *path) {
|
||||
log::info("Opening file: {0}", path);
|
||||
@@ -784,4 +824,24 @@ namespace hex {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void* getContainingModule(void* symbol) {
|
||||
#if defined(OS_WINDOWS)
|
||||
MEMORY_BASIC_INFORMATION mbi;
|
||||
if (VirtualQuery(symbol, &mbi, sizeof(mbi)))
|
||||
return mbi.AllocationBase;
|
||||
|
||||
return nullptr;
|
||||
#elif !defined(OS_WEB)
|
||||
Dl_info info = {};
|
||||
if (dladdr(symbol, &info) == 0)
|
||||
return nullptr;
|
||||
|
||||
return dlopen(info.dli_fname, RTLD_LAZY);
|
||||
#else
|
||||
hex::unused(symbol);
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -88,6 +88,42 @@
|
||||
CFRelease(fontDescriptors);
|
||||
}
|
||||
|
||||
void macosHandleTitlebarDoubleClickGesture(GLFWwindow *window) {
|
||||
NSWindow* cocoaWindow = glfwGetCocoaWindow(window);
|
||||
|
||||
// Consult user preferences: "System Settings -> Desktop & Dock -> Double-click a window's title bar to"
|
||||
NSString* action = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleActionOnDoubleClick"];
|
||||
|
||||
if (action == nil || [action isEqualToString:@"None"]) {
|
||||
// Nothing to do
|
||||
} else if ([action isEqualToString:@"Minimize"]) {
|
||||
if ([cocoaWindow isMiniaturizable]) {
|
||||
[cocoaWindow miniaturize:nil];
|
||||
}
|
||||
} else if ([action isEqualToString:@"Maximize"]) {
|
||||
// `[NSWindow zoom:_ sender]` takes over pumping the main runloop for the duration of the resize,
|
||||
// and would interfere with our renderer's frame logic. Schedule it for the next frame
|
||||
|
||||
CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^{
|
||||
if ([cocoaWindow isZoomable]) {
|
||||
[cocoaWindow zoom:nil];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool macosIsWindowBeingResizedByUser(GLFWwindow *window) {
|
||||
NSWindow* cocoaWindow = glfwGetCocoaWindow(window);
|
||||
|
||||
return cocoaWindow.inLiveResize;
|
||||
}
|
||||
|
||||
void macosMarkContentEdited(GLFWwindow *window, bool edited) {
|
||||
NSWindow* cocoaWindow = glfwGetCocoaWindow(window);
|
||||
|
||||
[cocoaWindow setDocumentEdited:edited];
|
||||
}
|
||||
|
||||
@interface HexDocument : NSDocument
|
||||
|
||||
@end
|
||||
|
||||
@@ -31,41 +31,4 @@ namespace hex::prv {
|
||||
m_data.resize(newSize);
|
||||
}
|
||||
|
||||
void MemoryProvider::insertRaw(u64 offset, u64 size) {
|
||||
auto oldSize = this->getActualSize();
|
||||
this->resizeRaw(oldSize + size);
|
||||
|
||||
std::vector<u8> buffer(0x1000);
|
||||
const std::vector<u8> zeroBuffer(0x1000);
|
||||
|
||||
auto position = oldSize;
|
||||
while (position > offset) {
|
||||
const auto readSize = std::min<size_t>(position - offset, buffer.size());
|
||||
|
||||
position -= readSize;
|
||||
|
||||
this->readRaw(position, buffer.data(), readSize);
|
||||
this->writeRaw(position, zeroBuffer.data(), readSize);
|
||||
this->writeRaw(position + size, buffer.data(), readSize);
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryProvider::removeRaw(u64 offset, u64 size) {
|
||||
auto oldSize = this->getActualSize();
|
||||
std::vector<u8> buffer(0x1000);
|
||||
|
||||
const auto newSize = oldSize - size;
|
||||
auto position = offset;
|
||||
while (position < newSize) {
|
||||
const auto readSize = std::min<size_t>(newSize - position, buffer.size());
|
||||
|
||||
this->readRaw(position + size, buffer.data(), readSize);
|
||||
this->writeRaw(position, buffer.data(), readSize);
|
||||
|
||||
position += readSize;
|
||||
}
|
||||
|
||||
this->resizeRaw(oldSize - size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -74,7 +74,11 @@ namespace hex::prv {
|
||||
}
|
||||
}
|
||||
|
||||
void Provider::resize(u64 newSize) {
|
||||
bool Provider::resize(u64 newSize) {
|
||||
if (newSize >> 63) {
|
||||
log::error("new provider size is very large ({}). Is it a negative number ?", newSize);
|
||||
return false;
|
||||
}
|
||||
i64 difference = newSize - this->getActualSize();
|
||||
|
||||
if (difference > 0)
|
||||
@@ -83,6 +87,7 @@ namespace hex::prv {
|
||||
EventProviderDataRemoved::post(this, this->getActualSize() + difference, -difference);
|
||||
|
||||
this->markDirty();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Provider::insert(u64 offset, u64 size) {
|
||||
@@ -97,6 +102,52 @@ namespace hex::prv {
|
||||
this->markDirty();
|
||||
}
|
||||
|
||||
void Provider::insertRaw(u64 offset, u64 size) {
|
||||
auto oldSize = this->getActualSize();
|
||||
this->resizeRaw(oldSize + size);
|
||||
|
||||
std::vector<u8> buffer(0x1000);
|
||||
const std::vector<u8> zeroBuffer(0x1000);
|
||||
|
||||
auto position = oldSize;
|
||||
while (position > offset) {
|
||||
const auto readSize = std::min<size_t>(position - offset, buffer.size());
|
||||
|
||||
position -= readSize;
|
||||
|
||||
this->readRaw(position, buffer.data(), readSize);
|
||||
this->writeRaw(position, zeroBuffer.data(), readSize);
|
||||
this->writeRaw(position + size, buffer.data(), readSize);
|
||||
}
|
||||
}
|
||||
|
||||
void Provider::removeRaw(u64 offset, u64 size) {
|
||||
if (offset > this->getActualSize() || size == 0)
|
||||
return;
|
||||
|
||||
if ((offset + size) > this->getActualSize())
|
||||
size = this->getActualSize() - offset;
|
||||
|
||||
auto oldSize = this->getActualSize();
|
||||
|
||||
std::vector<u8> buffer(0x1000);
|
||||
|
||||
const auto newSize = oldSize - size;
|
||||
auto position = offset;
|
||||
while (position < newSize) {
|
||||
const auto readSize = std::min<size_t>(newSize - position, buffer.size());
|
||||
|
||||
this->readRaw(position + size, buffer.data(), readSize);
|
||||
this->writeRaw(position, buffer.data(), readSize);
|
||||
|
||||
position += readSize;
|
||||
}
|
||||
|
||||
this->resizeRaw(newSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Provider::applyOverlays(u64 offset, void *buffer, size_t size) const {
|
||||
for (auto &overlay : m_overlays) {
|
||||
auto overlayOffset = overlay->getAddress();
|
||||
|
||||
@@ -79,6 +79,7 @@ namespace hex::prv::undo {
|
||||
for (u32 i = 0; i < count; i += 1) {
|
||||
i64 index = startIndex + i;
|
||||
|
||||
m_undoStack[index]->undo(m_provider);
|
||||
operation->addOperation(std::move(m_undoStack[index]));
|
||||
}
|
||||
|
||||
@@ -93,6 +94,13 @@ namespace hex::prv::undo {
|
||||
}
|
||||
}
|
||||
|
||||
void Stack::reapply() {
|
||||
for (const auto &operation : m_undoStack) {
|
||||
operation->redo(m_provider);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool Stack::add(std::unique_ptr<Operation> &&operation) {
|
||||
|
||||
@@ -15,11 +15,12 @@ namespace hex::subcommands {
|
||||
std::optional<SubCommand> findSubCommand(const std::string &arg) {
|
||||
for (auto &plugin : PluginManager::getPlugins()) {
|
||||
for (auto &subCommand : plugin.getSubCommands()) {
|
||||
if (hex::format("--{}", subCommand.commandKey) == arg) {
|
||||
if (hex::format("--{}", subCommand.commandLong) == arg || hex::format("-{}", subCommand.commandShort) == arg) {
|
||||
return subCommand;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -27,7 +28,8 @@ namespace hex::subcommands {
|
||||
// If no arguments, do not even try to process arguments
|
||||
// (important because this function will exit ImHex if an instance is already opened,
|
||||
// and we don't want that if no arguments were provided)
|
||||
if (args.empty()) return;
|
||||
if (args.empty())
|
||||
return;
|
||||
|
||||
std::vector<std::pair<SubCommand, std::vector<std::string>>> subCommands;
|
||||
|
||||
@@ -76,18 +78,18 @@ namespace hex::subcommands {
|
||||
}
|
||||
|
||||
// Save last command to run
|
||||
if (currentSubCommand) {
|
||||
if (currentSubCommand.has_value()) {
|
||||
subCommands.emplace_back(*currentSubCommand, currentSubCommandArgs);
|
||||
}
|
||||
|
||||
// Run the subcommands
|
||||
for (auto& subCommandPair : subCommands) {
|
||||
subCommandPair.first.callback(subCommandPair.second);
|
||||
for (auto &[subcommand, args] : subCommands) {
|
||||
subcommand.callback(args);
|
||||
}
|
||||
|
||||
// Exit the process if its not the main instance (the commands have been forwarded to another instance)
|
||||
// Exit the process if it's not the main instance (the commands have been forwarded to another instance)
|
||||
if (!ImHexApi::System::isMainInstance()) {
|
||||
exit(0);
|
||||
std::exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,12 +97,15 @@ namespace hex::subcommands {
|
||||
log::debug("Forwarding subcommand {} (maybe to us)", cmdName);
|
||||
|
||||
std::vector<u8> data;
|
||||
for (const auto &arg: args) {
|
||||
data.insert(data.end(), arg.begin(), arg.end());
|
||||
data.push_back('\0');
|
||||
if (!args.empty()) {
|
||||
for (const auto &arg: args) {
|
||||
data.insert(data.end(), arg.begin(), arg.end());
|
||||
data.push_back('\0');
|
||||
}
|
||||
|
||||
data.pop_back();
|
||||
}
|
||||
data.erase(data.end()-1);
|
||||
|
||||
|
||||
SendMessageToMainInstance::post(hex::format("command/{}", cmdName), data);
|
||||
}
|
||||
|
||||
@@ -112,8 +117,8 @@ namespace hex::subcommands {
|
||||
|
||||
std::vector<std::string> args;
|
||||
|
||||
for (const auto &arg_view : std::views::split(string, char(0x00))) {
|
||||
std::string arg(arg_view.data(), arg_view.size());
|
||||
for (const auto &argument : std::views::split(string, char(0x00))) {
|
||||
std::string arg(argument.data(), argument.size());
|
||||
args.push_back(arg);
|
||||
}
|
||||
|
||||
|
||||
23
lib/libimhex/source/test/tests.cpp
Normal file
23
lib/libimhex/source/test/tests.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#include <hex/test/tests.hpp>
|
||||
|
||||
namespace hex::test {
|
||||
std::map<std::string, Test> Tests::s_tests;
|
||||
|
||||
bool initPluginImpl(std::string name) {
|
||||
if (name != "Built-in") {
|
||||
if(!initPluginImpl("Built-in")) return false;
|
||||
}
|
||||
|
||||
hex::Plugin *plugin = hex::PluginManager::getPlugin(name);
|
||||
if (plugin == nullptr) {
|
||||
hex::log::fatal("Plugin '{}' was not found !", name);
|
||||
return false;
|
||||
}else if (!plugin->initializePlugin()) {
|
||||
hex::log::fatal("Failed to initialize plugin '{}' !", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
hex::log::info("Initialized plugin '{}' successfully", name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <imgui_internal.h>
|
||||
#include <implot.h>
|
||||
#include <implot_internal.h>
|
||||
#include <cimgui.h>
|
||||
#include <opengl_support.h>
|
||||
|
||||
#undef IMGUI_DEFINE_MATH_OPERATORS
|
||||
@@ -11,14 +12,17 @@
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
#include <lunasvg.h>
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
|
||||
#include <hex/api/task_manager.hpp>
|
||||
#include <hex/api/theme_manager.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
|
||||
namespace ImGuiExt {
|
||||
@@ -27,6 +31,32 @@ namespace ImGuiExt {
|
||||
|
||||
namespace {
|
||||
|
||||
bool isOpenGLExtensionSupported(const char *name) {
|
||||
static std::set<std::string> extensions;
|
||||
|
||||
if (extensions.empty()) {
|
||||
GLint extensionCount = 0;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &extensionCount);
|
||||
|
||||
for (GLint i = 0; i < extensionCount; i++) {
|
||||
std::string extension = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i));
|
||||
extensions.emplace(std::move(extension));
|
||||
}
|
||||
}
|
||||
|
||||
return extensions.contains(name);
|
||||
}
|
||||
|
||||
bool isOpenGLVersionAtLeast(u8 major, u8 minor) {
|
||||
static GLint actualMajor = 0, actualMinor = 0;
|
||||
if (actualMajor == 0 || actualMinor == 0) {
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &actualMajor);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &actualMinor);
|
||||
}
|
||||
|
||||
return actualMajor > major || (actualMajor == major && actualMinor >= minor);
|
||||
}
|
||||
|
||||
constexpr auto getGLFilter(Texture::Filter filter) {
|
||||
switch (filter) {
|
||||
using enum Texture::Filter;
|
||||
@@ -39,74 +69,189 @@ namespace ImGuiExt {
|
||||
return GL_NEAREST;
|
||||
}
|
||||
|
||||
[[maybe_unused]] GLint getMaxSamples(GLenum target, GLenum format) {
|
||||
GLint maxSamples;
|
||||
|
||||
glGetInternalformativ(target, format, GL_SAMPLES, 1, &maxSamples);
|
||||
return maxSamples;
|
||||
}
|
||||
|
||||
GLuint createTextureFromRGBA8Array(const ImU8 *buffer, int width, int height, Texture::Filter filter) {
|
||||
GLuint texture;
|
||||
|
||||
// Generate texture
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getGLFilter(filter));
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getGLFilter(filter));
|
||||
|
||||
#if defined(GL_UNPACK_ROW_LENGTH)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
|
||||
// Allocate storage for the texture
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
GLuint createMultisampleTextureFromRGBA8Array(const ImU8 *buffer, int width, int height, Texture::Filter filter) {
|
||||
// Create a regular texture from the RGBA8 array
|
||||
GLuint texture = createTextureFromRGBA8Array(buffer, width, height, filter);
|
||||
|
||||
if (filter == Texture::Filter::Nearest) {
|
||||
return texture;
|
||||
}
|
||||
|
||||
if (!isOpenGLVersionAtLeast(3,2)) {
|
||||
return texture;
|
||||
}
|
||||
|
||||
if (!isOpenGLExtensionSupported("GL_ARB_texture_multisample")) {
|
||||
return texture;
|
||||
}
|
||||
|
||||
#if defined(GL_TEXTURE_2D_MULTISAMPLE)
|
||||
static const auto sampleCount = std::min(static_cast<GLint>(8), getMaxSamples(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8));
|
||||
|
||||
// Generate renderbuffer
|
||||
GLuint renderbuffer;
|
||||
glGenRenderbuffers(1, &renderbuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
|
||||
glRenderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_DEPTH24_STENCIL8, width, height);
|
||||
|
||||
// Generate framebuffer
|
||||
GLuint framebuffer;
|
||||
glGenFramebuffers(1, &framebuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
|
||||
// Unbind framebuffer on exit
|
||||
ON_SCOPE_EXIT {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
};
|
||||
|
||||
// Attach texture to color attachment 0
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, texture, 0);
|
||||
|
||||
// Attach renderbuffer to depth-stencil attachment
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
|
||||
|
||||
// Check framebuffer status
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
hex::log::error("Driver claims to support texture multisampling but it's not working");
|
||||
return texture;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Texture::Texture(const ImU8 *buffer, int size, Filter filter, int width, int height) {
|
||||
Texture Texture::fromImage(const ImU8 *buffer, int size, Filter filter) {
|
||||
if (size == 0)
|
||||
return;
|
||||
return {};
|
||||
|
||||
unsigned char *imageData = nullptr;
|
||||
|
||||
if (width == 0 || height == 0)
|
||||
imageData = stbi_load_from_memory(buffer, size, &m_width, &m_height, nullptr, 4);
|
||||
|
||||
if (imageData == nullptr) {
|
||||
if (width * height * 4 > size)
|
||||
return;
|
||||
|
||||
imageData = static_cast<unsigned char *>(STBI_MALLOC(size));
|
||||
std::memcpy(imageData, buffer, size);
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
}
|
||||
Texture result;
|
||||
imageData = stbi_load_from_memory(buffer, size, &result.m_width, &result.m_height, nullptr, 4);
|
||||
if (imageData == nullptr)
|
||||
return;
|
||||
return {};
|
||||
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
GLuint texture = createMultisampleTextureFromRGBA8Array(imageData, result.m_width, result.m_height, filter);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getGLFilter(filter));
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getGLFilter(filter));
|
||||
|
||||
#if defined(GL_UNPACK_ROW_LENGTH)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
|
||||
STBI_FREE(imageData);
|
||||
|
||||
m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
|
||||
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Texture::Texture(std::span<const std::byte> bytes, Filter filter, int width, int height) : Texture(reinterpret_cast<const ImU8*>(bytes.data()), bytes.size(), filter, width, height) { }
|
||||
Texture Texture::fromImage(std::span<const std::byte> buffer, Filter filter) {
|
||||
return Texture::fromImage(reinterpret_cast<const ImU8*>(buffer.data()), buffer.size(), filter);
|
||||
}
|
||||
|
||||
Texture::Texture(const std::fs::path &path, Filter filter) : Texture(reinterpret_cast<const char *>(path.u8string().c_str()), filter) { }
|
||||
|
||||
Texture::Texture(const char *path, Filter filter) {
|
||||
unsigned char *imageData = stbi_load(path, &m_width, &m_height, nullptr, 4);
|
||||
Texture Texture::fromImage(const std::fs::path &path, Filter filter) {
|
||||
return Texture::fromImage(wolv::util::toUTF8String(path).c_str(), filter);
|
||||
}
|
||||
|
||||
Texture Texture::fromImage(const char *path, Filter filter) {
|
||||
Texture result;
|
||||
unsigned char *imageData = stbi_load(path, &result.m_width, &result.m_height, nullptr, 4);
|
||||
if (imageData == nullptr)
|
||||
return;
|
||||
return {};
|
||||
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
GLuint texture = createMultisampleTextureFromRGBA8Array(imageData, result.m_width, result.m_height, filter);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getGLFilter(filter));
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getGLFilter(filter));
|
||||
|
||||
#if defined(GL_UNPACK_ROW_LENGTH)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
|
||||
STBI_FREE(imageData);
|
||||
|
||||
m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
|
||||
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Texture::Texture(unsigned int texture, int width, int height) : m_textureId(reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture))), m_width(width), m_height(height) {
|
||||
Texture Texture::fromGLTexture(unsigned int glTexture, int width, int height) {
|
||||
Texture texture;
|
||||
texture.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(glTexture));
|
||||
texture.m_width = width;
|
||||
texture.m_height = height;
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
Texture Texture::fromBitmap(std::span<const std::byte> buffer, int width, int height, Filter filter) {
|
||||
return Texture::fromBitmap(reinterpret_cast<const ImU8*>(buffer.data()), buffer.size(), width, height, filter);
|
||||
}
|
||||
|
||||
Texture Texture::fromBitmap(const ImU8 *buffer, int size, int width, int height, Filter filter) {
|
||||
if (width * height * 4 > size)
|
||||
return {};
|
||||
|
||||
GLuint texture = createMultisampleTextureFromRGBA8Array(buffer, width, height, filter);
|
||||
|
||||
Texture result;
|
||||
result.m_width = width;
|
||||
result.m_height = height;
|
||||
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Texture Texture::fromSVG(const char *path, int width, int height, Filter filter) {
|
||||
auto document = lunasvg::Document::loadFromFile(path);
|
||||
auto bitmap = document->renderToBitmap(width, height);
|
||||
|
||||
auto texture = createMultisampleTextureFromRGBA8Array(bitmap.data(), bitmap.width(), bitmap.height(), filter);
|
||||
|
||||
Texture result;
|
||||
result.m_width = bitmap.width();
|
||||
result.m_height = bitmap.height();
|
||||
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Texture Texture::fromSVG(const std::fs::path &path, int width, int height, Filter filter) {
|
||||
return Texture::fromSVG(wolv::util::toUTF8String(path).c_str(), width, height, filter);
|
||||
}
|
||||
|
||||
Texture Texture::fromSVG(std::span<const std::byte> buffer, int width, int height, Filter filter) {
|
||||
auto document = lunasvg::Document::loadFromData(reinterpret_cast<const char*>(buffer.data()), buffer.size());
|
||||
auto bitmap = document->renderToBitmap(width, height);
|
||||
bitmap.convertToRGBA();
|
||||
|
||||
auto texture = createMultisampleTextureFromRGBA8Array(bitmap.data(), bitmap.width(), bitmap.height(), filter);
|
||||
|
||||
Texture result;
|
||||
result.m_width = bitmap.width();
|
||||
result.m_height = bitmap.height();
|
||||
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Texture::Texture(Texture&& other) noexcept {
|
||||
@@ -137,8 +282,11 @@ namespace ImGuiExt {
|
||||
if (m_textureId == nullptr)
|
||||
return;
|
||||
|
||||
auto glTextureId = static_cast<GLuint>(reinterpret_cast<intptr_t>(m_textureId));
|
||||
glDeleteTextures(1, &glTextureId);
|
||||
glDeleteTextures(1, reinterpret_cast<GLuint*>(&m_textureId));
|
||||
}
|
||||
|
||||
float GetTextWrapPos() {
|
||||
return GImGui->CurrentWindow->DC.TextWrapPos;
|
||||
}
|
||||
|
||||
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data) {
|
||||
@@ -179,7 +327,10 @@ namespace ImGuiExt {
|
||||
PushStyleColor(ImGuiCol_Text, ImU32(col));
|
||||
|
||||
Text("%s %s", icon, label);
|
||||
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(col));
|
||||
|
||||
if (hovered)
|
||||
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(col));
|
||||
|
||||
PopStyleColor();
|
||||
|
||||
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
|
||||
@@ -208,7 +359,10 @@ namespace ImGuiExt {
|
||||
const ImU32 col = hovered ? GetColorU32(ImGuiCol_ButtonHovered) : GetColorU32(ImGuiCol_ButtonActive);
|
||||
PushStyleColor(ImGuiCol_Text, ImU32(col));
|
||||
TextEx(label, nullptr, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
|
||||
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(col));
|
||||
|
||||
if (hovered)
|
||||
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(col));
|
||||
|
||||
PopStyleColor();
|
||||
|
||||
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
|
||||
@@ -360,26 +514,25 @@ namespace ImGuiExt {
|
||||
return pressed;
|
||||
}
|
||||
|
||||
void HelpHover(const char *text) {
|
||||
const auto iconColor = GetStyleColorVec4(ImGuiCol_ButtonActive);
|
||||
|
||||
void HelpHover(const char *text, const char *icon, ImU32 iconColor) {
|
||||
PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||
PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0));
|
||||
PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0));
|
||||
PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, GetStyle().FramePadding.y));
|
||||
PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
|
||||
PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0F);
|
||||
|
||||
PushStyleColor(ImGuiCol_Text, iconColor);
|
||||
Button("(?)");
|
||||
Button(icon);
|
||||
PopStyleColor();
|
||||
|
||||
if (IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
|
||||
SetNextWindowSizeConstraints(ImVec2(GetTextLineHeight() * 25, 0), ImVec2(GetTextLineHeight() * 25, FLT_MAX));
|
||||
SetNextWindowSizeConstraints(ImVec2(GetTextLineHeight() * 25, 0), ImVec2(GetTextLineHeight() * 35, FLT_MAX));
|
||||
BeginTooltip();
|
||||
TextFormattedWrapped("{}", text);
|
||||
EndTooltip();
|
||||
}
|
||||
|
||||
PopStyleVar();
|
||||
PopStyleVar(2);
|
||||
PopStyleColor(3);
|
||||
}
|
||||
|
||||
@@ -422,14 +575,30 @@ namespace ImGuiExt {
|
||||
ImGuiID hoveredID = GetHoveredID();
|
||||
|
||||
bool result = false;
|
||||
if (IsItemHovered() && (currTime - lastMoveTime) >= 0.5 && hoveredID == lastHoveredID) {
|
||||
if (IsItemHovered(ImGuiHoveredFlags_DelayNormal) && (currTime - lastMoveTime) >= 0.5 && hoveredID == lastHoveredID) {
|
||||
if (!std::string_view(text).empty()) {
|
||||
BeginTooltip();
|
||||
if (isSeparator)
|
||||
SeparatorText(text);
|
||||
const auto textWidth = CalcTextSize(text).x;
|
||||
|
||||
const auto maxWidth = 300 * hex::ImHexApi::System::getGlobalScale();
|
||||
const bool wrapping = textWidth > maxWidth;
|
||||
|
||||
if (wrapping)
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(maxWidth, 0), ImVec2(maxWidth, FLT_MAX));
|
||||
else
|
||||
TextUnformatted(text);
|
||||
EndTooltip();
|
||||
ImGui::SetNextWindowSize(ImVec2(textWidth + GetStyle().WindowPadding.x * 2, 0));
|
||||
|
||||
if (BeginTooltip()) {
|
||||
if (isSeparator)
|
||||
SeparatorText(text);
|
||||
else {
|
||||
if (wrapping)
|
||||
TextFormattedWrapped("{}", text);
|
||||
else
|
||||
TextFormatted("{}", text);
|
||||
}
|
||||
|
||||
EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
result = true;
|
||||
@@ -574,7 +743,7 @@ namespace ImGuiExt {
|
||||
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered
|
||||
: ImGuiCol_Button);
|
||||
RenderNavHighlight(bb, id);
|
||||
RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
|
||||
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
|
||||
RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, nullptr, &label_size, style.ButtonTextAlign, &bb);
|
||||
|
||||
// Automatically close popups
|
||||
@@ -599,7 +768,9 @@ namespace ImGuiExt {
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
|
||||
ImVec2 size = CalcItemSize(ImVec2(1, 1) * GetCurrentWindow()->MenuBarHeight(), label_size.x + style.FramePadding.x * 2.0F, label_size.y + style.FramePadding.y * 2.0F);
|
||||
ImVec2 size = CalcItemSize(ImVec2(1, 1) * GetCurrentWindow()->MenuBarHeight, label_size.x + style.FramePadding.x * 2.0F, label_size.y + style.FramePadding.y * 2.0F);
|
||||
|
||||
ImVec2 padding = (size - label_size) / 2;
|
||||
|
||||
const ImRect bb(pos, pos + size);
|
||||
ItemSize(size, style.FramePadding.y);
|
||||
@@ -616,7 +787,7 @@ namespace ImGuiExt {
|
||||
: ImGuiCol_MenuBarBg);
|
||||
RenderNavHighlight(bb, id);
|
||||
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
|
||||
RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb);
|
||||
RenderTextClipped(bb.Min + padding, bb.Max - padding, symbol, nullptr, &size, style.ButtonTextAlign, &bb);
|
||||
|
||||
PopStyleColor();
|
||||
|
||||
@@ -679,20 +850,13 @@ namespace ImGuiExt {
|
||||
|
||||
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
|
||||
const ImVec2 frame_size = CalcItemSize(ImVec2(0, 0), CalcTextSize(prefix).x, label_size.y + style.FramePadding.y * 2.0F);
|
||||
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
|
||||
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(CalcItemWidth(), frame_size.y));
|
||||
|
||||
SetCursorPosX(GetCursorPosX() + frame_size.x);
|
||||
|
||||
char buf[64];
|
||||
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), type, value, format);
|
||||
|
||||
bool value_changed = false;
|
||||
if (InputTextEx(label, nullptr, buf, IM_ARRAYSIZE(buf), ImVec2(CalcItemWidth() - frame_size.x, label_size.y + style.FramePadding.y * 2.0F), flags))
|
||||
value_changed = DataTypeApplyFromText(buf, type, value, format);
|
||||
|
||||
if (value_changed)
|
||||
MarkItemEdited(GImGui->LastItemData.ID);
|
||||
|
||||
RenderNavHighlight(frame_bb, id);
|
||||
RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
|
||||
|
||||
@@ -700,6 +864,19 @@ namespace ImGuiExt {
|
||||
RenderText(ImVec2(frame_bb.Min.x + style.FramePadding.x, frame_bb.Min.y + style.FramePadding.y), prefix);
|
||||
PopStyleVar();
|
||||
|
||||
bool value_changed = false;
|
||||
PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0);
|
||||
PushStyleColor(ImGuiCol_FrameBg, 0x00000000);
|
||||
PushStyleColor(ImGuiCol_FrameBgHovered, 0x00000000);
|
||||
PushStyleColor(ImGuiCol_FrameBgActive, 0x00000000);
|
||||
if (InputTextEx(label, nullptr, buf, IM_ARRAYSIZE(buf), ImVec2(CalcItemWidth() - frame_size.x, label_size.y + style.FramePadding.y * 2.0F), flags))
|
||||
value_changed = DataTypeApplyFromText(buf, type, value, format);
|
||||
PopStyleColor(3);
|
||||
PopStyleVar();
|
||||
|
||||
if (value_changed)
|
||||
MarkItemEdited(GImGui->LastItemData.ID);
|
||||
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
@@ -711,6 +888,21 @@ namespace ImGuiExt {
|
||||
return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U64, "%llX", flags | ImGuiInputTextFlags_CharsHexadecimal);
|
||||
}
|
||||
|
||||
bool SliderBytes(const char *label, u64 *value, u64 min, u64 max, ImGuiSliderFlags flags) {
|
||||
std::string format;
|
||||
if (*value < 1024) {
|
||||
format = hex::format("{} Bytes", *value);
|
||||
} else if (*value < 1024 * 1024) {
|
||||
format = hex::format("{:.2f} KB", *value / 1024.0);
|
||||
} else if (*value < 1024 * 1024 * 1024) {
|
||||
format = hex::format("{:.2f} MB", *value / (1024.0 * 1024.0));
|
||||
} else {
|
||||
format = hex::format("{:.2f} GB", *value / (1024.0 * 1024.0 * 1024.0));
|
||||
}
|
||||
|
||||
return ImGui::SliderScalar(label, ImGuiDataType_U64, value, &min, &max, format.c_str(), flags | ImGuiSliderFlags_Logarithmic);
|
||||
}
|
||||
|
||||
void SmallProgressBar(float fraction, float yOffset) {
|
||||
ImGuiWindow *window = GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
@@ -982,17 +1174,37 @@ namespace ImGuiExt {
|
||||
PopStyleVar();
|
||||
}
|
||||
|
||||
void BeginSubWindow(const char *label, ImVec2 size, ImGuiChildFlags flags) {
|
||||
bool BeginSubWindow(const char *label, bool *collapsed, ImVec2 size, ImGuiChildFlags flags) {
|
||||
const bool hasMenuBar = !std::string_view(label).empty();
|
||||
|
||||
bool result = false;
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0F);
|
||||
if (ImGui::BeginChild(hex::format("{}##SubWindow", label).c_str(), size, ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY | flags, hasMenuBar ? ImGuiWindowFlags_MenuBar : ImGuiWindowFlags_None)) {
|
||||
result = true;
|
||||
|
||||
if (hasMenuBar && ImGui::BeginMenuBar()) {
|
||||
ImGui::TextUnformatted(label);
|
||||
if (collapsed == nullptr)
|
||||
ImGui::TextUnformatted(label);
|
||||
else {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, ImGui::GetStyle().FramePadding.y));
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, 0x00);
|
||||
if (ImGui::Button(label))
|
||||
*collapsed = !*collapsed;
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
if (collapsed != nullptr && *collapsed) {
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - (ImGui::GetStyle().FramePadding.y * 2));
|
||||
ImGuiExt::TextFormattedDisabled("...");
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void EndSubWindow() {
|
||||
@@ -1073,9 +1285,9 @@ namespace ImGuiExt {
|
||||
window->DrawList->AddRectFilled(knob_bb.Min, knob_bb.Max, GetColorU32(held ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : *v ? ImGuiCol_ButtonActive : ImGuiCol_Button), size.y / 2);
|
||||
|
||||
if (*v)
|
||||
window->DrawList->AddCircleFilled(knob_bb.Max - ImVec2(size.y / 2, size.y / 2), (size.y - style.ItemInnerSpacing.y) / 2, GetColorU32(ImGuiCol_Text), 16);
|
||||
window->DrawList->AddCircleFilled(knob_bb.Max - ImVec2(size.y / 2, size.y / 2), (size.y - style.ItemInnerSpacing.y) / 2, GetColorU32(ImGuiCol_ScrollbarGrabActive), 16);
|
||||
else
|
||||
window->DrawList->AddCircleFilled(knob_bb.Min + ImVec2(size.y / 2, size.y / 2), (size.y - style.ItemInnerSpacing.y) / 2, GetColorU32(ImGuiCol_Text), 16);
|
||||
window->DrawList->AddCircleFilled(knob_bb.Min + ImVec2(size.y / 2, size.y / 2), (size.y - style.ItemInnerSpacing.y) / 2, GetColorU32(ImGuiCol_ScrollbarGrabActive), 16);
|
||||
|
||||
ImVec2 label_pos = ImVec2(knob_bb.Max.x + style.ItemInnerSpacing.x, knob_bb.Min.y + style.FramePadding.y);
|
||||
if (g.LogEnabled)
|
||||
@@ -1091,6 +1303,59 @@ namespace ImGuiExt {
|
||||
return ToggleSwitch(label, &v);
|
||||
}
|
||||
|
||||
bool PopupTitleBarButton(const char* label, bool p_enabled)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
const ImGuiID id = window->GetID(label);
|
||||
const ImRect title_rect = window->TitleBarRect();
|
||||
const ImVec2 size(g.FontSize, g.FontSize); // Button size matches font size for aesthetic consistency.
|
||||
const ImVec2 pos = window->DC.CursorPos;
|
||||
const ImVec2 max_pos = pos + size;
|
||||
const ImRect bb(pos.x, title_rect.Min.y, max_pos.x, title_rect.Max.y);
|
||||
|
||||
ImGui::PushClipRect(title_rect.Min, title_rect.Max, false);
|
||||
|
||||
// Check for item addition (similar to how clipping is handled in the original button functions).
|
||||
bool is_clipped = !ItemAdd(bb, id);
|
||||
bool hovered, held;
|
||||
bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None);
|
||||
if (is_clipped)
|
||||
{
|
||||
ImGui::PopClipRect();
|
||||
return pressed;
|
||||
}
|
||||
|
||||
// const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
|
||||
// window->DrawList->AddCircleFilled(bb.GetCenter(), ImMax(2.0f, g.FontSize * 0.5f + 1.0f), bg_col);
|
||||
|
||||
// Draw the label in the center
|
||||
ImU32 text_col = GetColorU32(p_enabled || hovered ? ImGuiCol_Text : ImGuiCol_TextDisabled);
|
||||
window->DrawList->AddText(bb.GetCenter() - ImVec2(g.FontSize * 0.45F, g.FontSize * 0.5F), text_col, label);
|
||||
|
||||
// Return the button press state
|
||||
ImGui::PopClipRect();
|
||||
return pressed;
|
||||
}
|
||||
|
||||
void PopupTitleBarText(const char* text) {
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
const ImRect title_rect = window->TitleBarRect();
|
||||
const ImVec2 size(g.FontSize, g.FontSize); // Button size matches font size for aesthetic consistency.
|
||||
const ImVec2 pos = window->DC.CursorPos;
|
||||
const ImVec2 max_pos = pos + size;
|
||||
const ImRect bb(pos.x, title_rect.Min.y, max_pos.x, title_rect.Max.y);
|
||||
|
||||
ImGui::PushClipRect(title_rect.Min, title_rect.Max, false);
|
||||
|
||||
// Draw the label in the center
|
||||
ImU32 text_col = GetColorU32(ImGuiCol_Text);
|
||||
window->DrawList->AddText(bb.GetCenter() - ImVec2(g.FontSize * 0.45F, g.FontSize * 0.5F), text_col, text);
|
||||
|
||||
// Return the button press state
|
||||
ImGui::PopClipRect();
|
||||
}
|
||||
}
|
||||
|
||||
namespace ImGui {
|
||||
@@ -1111,4 +1376,4 @@ namespace ImGui {
|
||||
return ImGui::InputTextWithHint(label, hint, buffer.data(), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGuiExt::UpdateStringSizeCallback, &buffer);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
std::string View::toWindowName(const UnlocalizedString &unlocalizedName) {
|
||||
return Lang(unlocalizedName) + "###" + unlocalizedName.get();
|
||||
return fmt::format("{}###{}", Lang(unlocalizedName), unlocalizedName.get());
|
||||
}
|
||||
|
||||
}
|
||||
2
lib/third_party/HashLibPlus
vendored
2
lib/third_party/HashLibPlus
vendored
Submodule lib/third_party/HashLibPlus updated: 7609c542c9...1823dd1162
3
lib/third_party/boost/CMakeLists.txt
vendored
Normal file
3
lib/third_party/boost/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
project(boost)
|
||||
|
||||
add_subdirectory(regex)
|
||||
10
lib/third_party/boost/regex/CMakeLists.txt
vendored
Normal file
10
lib/third_party/boost/regex/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
project(boost-regex)
|
||||
|
||||
add_library(boost-regex INTERFACE)
|
||||
|
||||
target_include_directories(boost-regex INTERFACE
|
||||
include
|
||||
)
|
||||
target_compile_definitions(boost-regex INTERFACE BOOST_REGEX_STANDALONE)
|
||||
|
||||
add_library(boost::regex ALIAS boost-regex)
|
||||
43
lib/third_party/boost/regex/include/boost/cregex.hpp
vendored
Normal file
43
lib/third_party/boost/regex/include/boost/cregex.hpp
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org/libs/regex for most recent version.
|
||||
* FILE cregex.cpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares POSIX API functions
|
||||
* + boost::RegEx high level wrapper.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_RE_CREGEX_HPP
|
||||
#define BOOST_RE_CREGEX_HPP
|
||||
|
||||
#ifndef BOOST_REGEX_CONFIG_HPP
|
||||
#include <boost/regex/config.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_REGEX_CXX03
|
||||
#include <boost/regex/v4/cregex.hpp>
|
||||
#else
|
||||
#include <boost/regex/v5/cregex.hpp>
|
||||
#endif
|
||||
|
||||
#endif /* include guard */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
100
lib/third_party/boost/regex/include/boost/regex.h
vendored
Normal file
100
lib/third_party/boost/regex/include/boost/regex.h
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2000
|
||||
* Dr John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org/libs/regex for documentation.
|
||||
* FILE regex.h
|
||||
* VERSION 3.12
|
||||
* DESCRIPTION: Declares POSIX API functions
|
||||
*/
|
||||
|
||||
#ifndef BOOST_RE_REGEX_H
|
||||
#define BOOST_RE_REGEX_H
|
||||
|
||||
#include <boost/cregex.hpp>
|
||||
|
||||
/*
|
||||
* add using declarations to bring POSIX API functions into
|
||||
* global scope, only if this is C++ (and not C).
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
|
||||
using boost::regoff_t;
|
||||
using boost::regex_tA;
|
||||
using boost::regmatch_t;
|
||||
using boost::REG_BASIC;
|
||||
using boost::REG_EXTENDED;
|
||||
using boost::REG_ICASE;
|
||||
using boost::REG_NOSUB;
|
||||
using boost::REG_NEWLINE;
|
||||
using boost::REG_NOSPEC;
|
||||
using boost::REG_PEND;
|
||||
using boost::REG_DUMP;
|
||||
using boost::REG_NOCOLLATE;
|
||||
using boost::REG_ESCAPE_IN_LISTS;
|
||||
using boost::REG_NEWLINE_ALT;
|
||||
using boost::REG_PERL;
|
||||
using boost::REG_AWK;
|
||||
using boost::REG_GREP;
|
||||
using boost::REG_EGREP;
|
||||
using boost::REG_ASSERT;
|
||||
using boost::REG_INVARG;
|
||||
using boost::REG_ATOI;
|
||||
using boost::REG_ITOA;
|
||||
|
||||
using boost::REG_NOTBOL;
|
||||
using boost::REG_NOTEOL;
|
||||
using boost::REG_STARTEND;
|
||||
|
||||
using boost::reg_comp_flags;
|
||||
using boost::reg_exec_flags;
|
||||
using boost::regcompA;
|
||||
using boost::regerrorA;
|
||||
using boost::regexecA;
|
||||
using boost::regfreeA;
|
||||
|
||||
#ifndef BOOST_NO_WREGEX
|
||||
using boost::regcompW;
|
||||
using boost::regerrorW;
|
||||
using boost::regexecW;
|
||||
using boost::regfreeW;
|
||||
using boost::regex_tW;
|
||||
#endif
|
||||
|
||||
using boost::REG_NOERROR;
|
||||
using boost::REG_NOMATCH;
|
||||
using boost::REG_BADPAT;
|
||||
using boost::REG_ECOLLATE;
|
||||
using boost::REG_ECTYPE;
|
||||
using boost::REG_EESCAPE;
|
||||
using boost::REG_ESUBREG;
|
||||
using boost::REG_EBRACK;
|
||||
using boost::REG_EPAREN;
|
||||
using boost::REG_EBRACE;
|
||||
using boost::REG_BADBR;
|
||||
using boost::REG_ERANGE;
|
||||
using boost::REG_ESPACE;
|
||||
using boost::REG_BADRPT;
|
||||
using boost::REG_EEND;
|
||||
using boost::REG_ESIZE;
|
||||
using boost::REG_ERPAREN;
|
||||
using boost::REG_EMPTY;
|
||||
using boost::REG_E_MEMORY;
|
||||
using boost::REG_E_UNKNOWN;
|
||||
using boost::reg_errcode_t;
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* BOOST_RE_REGEX_H */
|
||||
|
||||
|
||||
|
||||
|
||||
41
lib/third_party/boost/regex/include/boost/regex.hpp
vendored
Normal file
41
lib/third_party/boost/regex/include/boost/regex.hpp
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org/libs/regex for documentation.
|
||||
* FILE regex.cpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: Declares boost::basic_regex<> and associated
|
||||
* functions and classes. This header is the main
|
||||
* entry point for the template regex code.
|
||||
*/
|
||||
|
||||
|
||||
/* start with C compatibility API */
|
||||
|
||||
#ifndef BOOST_RE_REGEX_HPP
|
||||
#define BOOST_RE_REGEX_HPP
|
||||
|
||||
#ifndef BOOST_REGEX_CONFIG_HPP
|
||||
#include <boost/regex/config.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_REGEX_CXX03
|
||||
#include <boost/regex/v4/regex.hpp>
|
||||
#else
|
||||
#include <boost/regex/v5/regex.hpp>
|
||||
#endif
|
||||
|
||||
#endif // include
|
||||
|
||||
|
||||
|
||||
|
||||
1134
lib/third_party/boost/regex/include/boost/regex/concepts.hpp
vendored
Normal file
1134
lib/third_party/boost/regex/include/boost/regex/concepts.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
480
lib/third_party/boost/regex/include/boost/regex/config.hpp
vendored
Normal file
480
lib/third_party/boost/regex/include/boost/regex/config.hpp
vendored
Normal file
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE config.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: regex extended config setup.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_CONFIG_HPP
|
||||
#define BOOST_REGEX_CONFIG_HPP
|
||||
|
||||
#if !((__cplusplus >= 201103L) || (defined(_MSC_VER) && (_MSC_VER >= 1600)) || defined(BOOST_REGEX_CXX03))
|
||||
# define BOOST_REGEX_CXX03
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_REGEX_RECURSIVE) && !defined(BOOST_REGEX_CXX03)
|
||||
# define BOOST_REGEX_CXX03
|
||||
#endif
|
||||
|
||||
#if defined(__has_include)
|
||||
#if !defined(BOOST_REGEX_STANDALONE) && !__has_include(<boost/version.hpp>)
|
||||
#define BOOST_REGEX_STANDALONE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Borland C++ Fix/error check
|
||||
* this has to go *before* we include any std lib headers:
|
||||
*/
|
||||
#if defined(__BORLANDC__) && !defined(__clang__)
|
||||
# include <boost/regex/config/borland.hpp>
|
||||
#endif
|
||||
#ifndef BOOST_REGEX_STANDALONE
|
||||
#include <boost/version.hpp>
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
*
|
||||
* Asserts:
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
#ifdef BOOST_REGEX_STANDALONE
|
||||
#include <cassert>
|
||||
# define BOOST_REGEX_ASSERT(x) assert(x)
|
||||
#else
|
||||
#include <boost/assert.hpp>
|
||||
# define BOOST_REGEX_ASSERT(x) BOOST_ASSERT(x)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Include all the headers we need here:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
# ifndef BOOST_REGEX_USER_CONFIG
|
||||
# define BOOST_REGEX_USER_CONFIG <boost/regex/user.hpp>
|
||||
# endif
|
||||
|
||||
# include BOOST_REGEX_USER_CONFIG
|
||||
|
||||
#ifndef BOOST_REGEX_STANDALONE
|
||||
# include <boost/config.hpp>
|
||||
# include <boost/predef.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
/*
|
||||
* C build,
|
||||
* don't include <boost/config.hpp> because that may
|
||||
* do C++ specific things in future...
|
||||
*/
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
# ifdef _MSC_VER
|
||||
# define BOOST_MSVC _MSC_VER
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* Legacy support:
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#if defined(BOOST_NO_STD_LOCALE) || defined(BOOST_NO_CXX11_HDR_MUTEX) || defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) \
|
||||
|| defined(BOOST_NO_CXX11_HDR_ATOMIC) || defined(BOOST_NO_CXX11_ALLOCATOR) || defined(BOOST_NO_CXX11_SMART_PTR) \
|
||||
|| defined(BOOST_NO_CXX11_STATIC_ASSERT) || defined(BOOST_NO_NOEXCEPT)
|
||||
#ifndef BOOST_REGEX_CXX03
|
||||
# define BOOST_REGEX_CXX03
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Boilerplate regex config options:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* Obsolete macro, use BOOST_VERSION instead: */
|
||||
#define BOOST_RE_VERSION 500
|
||||
|
||||
/* fix: */
|
||||
#if defined(_UNICODE) && !defined(UNICODE)
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#define BOOST_REGEX_JOIN(X, Y) BOOST_REGEX_DO_JOIN(X, Y)
|
||||
#define BOOST_REGEX_DO_JOIN(X, Y) BOOST_REGEX_DO_JOIN2(X,Y)
|
||||
#define BOOST_REGEX_DO_JOIN2(X, Y) X##Y
|
||||
|
||||
#ifdef BOOST_FALLTHROUGH
|
||||
# define BOOST_REGEX_FALLTHROUGH BOOST_FALLTHROUGH
|
||||
#else
|
||||
|
||||
#if defined(__clang__) && (__cplusplus >= 201103L) && defined(__has_warning)
|
||||
# if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
|
||||
# define BOOST_REGEX_FALLTHROUGH [[clang::fallthrough]]
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(BOOST_REGEX_FALLTHROUGH) && defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1800) && (__cplusplus >= 201703)
|
||||
# define BOOST_REGEX_FALLTHROUGH [[fallthrough]]
|
||||
#endif
|
||||
#if !defined(BOOST_REGEX_FALLTHROUGH) && defined(__GNUC__) && (__GNUC__ >= 7)
|
||||
# define BOOST_REGEX_FALLTHROUGH __attribute__((fallthrough))
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_REGEX_FALLTHROUGH)
|
||||
# define BOOST_REGEX_FALLTHROUGH
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_NORETURN
|
||||
# define BOOST_REGEX_NORETURN BOOST_NORETURN
|
||||
#else
|
||||
# define BOOST_REGEX_NORETURN
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Define a macro for the namespace that details are placed in, this includes the Boost
|
||||
* version number to avoid mismatched header and library versions:
|
||||
*/
|
||||
#define BOOST_REGEX_DETAIL_NS BOOST_REGEX_JOIN(re_detail_, BOOST_RE_VERSION)
|
||||
|
||||
/*
|
||||
* Fix for gcc prior to 3.4: std::ctype<wchar_t> doesn't allow
|
||||
* masks to be combined, for example:
|
||||
* std::use_facet<std::ctype<wchar_t> >.is(std::ctype_base::lower|std::ctype_base::upper, L'a');
|
||||
* returns *false*.
|
||||
*/
|
||||
#if defined(__GLIBCPP__) && defined(BOOST_REGEX_CXX03)
|
||||
# define BOOST_REGEX_BUGGY_CTYPE_FACET
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If there isn't good enough wide character support then there will
|
||||
* be no wide character regular expressions:
|
||||
*/
|
||||
#if (defined(BOOST_NO_CWCHAR) || defined(BOOST_NO_CWCTYPE) || defined(BOOST_NO_STD_WSTRING))
|
||||
# if !defined(BOOST_NO_WREGEX)
|
||||
# define BOOST_NO_WREGEX
|
||||
# endif
|
||||
#else
|
||||
# if defined(__sgi) && (defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION))
|
||||
/* STLPort on IRIX is misconfigured: <cwctype> does not compile
|
||||
* as a temporary fix include <wctype.h> instead and prevent inclusion
|
||||
* of STLPort version of <cwctype> */
|
||||
# include <wctype.h>
|
||||
# define __STLPORT_CWCTYPE
|
||||
# define _STLP_CWCTYPE
|
||||
# endif
|
||||
|
||||
#if defined(__cplusplus) && defined(BOOST_REGEX_CXX03)
|
||||
# include <boost/regex/config/cwchar.hpp>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If Win32 support has been disabled for boost in general, then
|
||||
* it is for regex in particular:
|
||||
*/
|
||||
#if defined(BOOST_DISABLE_WIN32) && !defined(BOOST_REGEX_NO_W32)
|
||||
# define BOOST_REGEX_NO_W32
|
||||
#endif
|
||||
|
||||
/* disable our own file-iterators and mapfiles if we can't
|
||||
* support them: */
|
||||
#if defined(_WIN32)
|
||||
# if defined(BOOST_REGEX_NO_W32) || BOOST_PLAT_WINDOWS_RUNTIME
|
||||
# define BOOST_REGEX_NO_FILEITER
|
||||
# endif
|
||||
#else /* defined(_WIN32) */
|
||||
# if !defined(BOOST_HAS_DIRENT_H)
|
||||
# define BOOST_REGEX_NO_FILEITER
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* backwards compatibitity: */
|
||||
#if defined(BOOST_RE_NO_LIB)
|
||||
# define BOOST_REGEX_NO_LIB
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && !defined(_MSC_VER) && (defined(_WIN32) || defined(__CYGWIN__))
|
||||
/* gcc on win32 has problems if you include <windows.h>
|
||||
(sporadically generates bad code). */
|
||||
# define BOOST_REGEX_NO_W32
|
||||
#endif
|
||||
#if defined(__COMO__) && !defined(BOOST_REGEX_NO_W32) && !defined(_MSC_EXTENSIONS)
|
||||
# define BOOST_REGEX_NO_W32
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_REGEX_STANDALONE
|
||||
# if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__)
|
||||
# define BOOST_REGEX_MSVC _MSC_VER
|
||||
#endif
|
||||
#elif defined(BOOST_MSVC)
|
||||
# define BOOST_REGEX_MSVC BOOST_MSVC
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Set up dll import/export options:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if (defined(BOOST_REGEX_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)) && !defined(BOOST_REGEX_STATIC_LINK) && defined(BOOST_SYMBOL_IMPORT)
|
||||
# if defined(BOOST_REGEX_SOURCE)
|
||||
# define BOOST_REGEX_BUILD_DLL
|
||||
# define BOOST_REGEX_DECL BOOST_SYMBOL_EXPORT
|
||||
# else
|
||||
# define BOOST_REGEX_DECL BOOST_SYMBOL_IMPORT
|
||||
# endif
|
||||
#else
|
||||
# define BOOST_REGEX_DECL
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_REGEX_CXX03
|
||||
#if !defined(BOOST_REGEX_NO_LIB) && !defined(BOOST_REGEX_SOURCE) && !defined(BOOST_ALL_NO_LIB) && defined(__cplusplus)
|
||||
# define BOOST_LIB_NAME boost_regex
|
||||
# if defined(BOOST_REGEX_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)
|
||||
# define BOOST_DYN_LINK
|
||||
# endif
|
||||
# ifdef BOOST_REGEX_DIAG
|
||||
# define BOOST_LIB_DIAGNOSTIC
|
||||
# endif
|
||||
# include <boost/config/auto_link.hpp>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Set up function call type:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(_MSC_VER) && defined(_MSC_EXTENSIONS)
|
||||
#if defined(_DEBUG) || defined(__MSVC_RUNTIME_CHECKS) || defined(_MANAGED) || defined(BOOST_REGEX_NO_FASTCALL)
|
||||
# define BOOST_REGEX_CALL __cdecl
|
||||
#else
|
||||
# define BOOST_REGEX_CALL __fastcall
|
||||
#endif
|
||||
# define BOOST_REGEX_CCALL __cdecl
|
||||
#endif
|
||||
|
||||
#if defined(__BORLANDC__) && !defined(BOOST_DISABLE_WIN32)
|
||||
#if defined(__clang__)
|
||||
# define BOOST_REGEX_CALL __cdecl
|
||||
# define BOOST_REGEX_CCALL __cdecl
|
||||
#else
|
||||
# define BOOST_REGEX_CALL __fastcall
|
||||
# define BOOST_REGEX_CCALL __stdcall
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_REGEX_CALL
|
||||
# define BOOST_REGEX_CALL
|
||||
#endif
|
||||
#ifndef BOOST_REGEX_CCALL
|
||||
#define BOOST_REGEX_CCALL
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Set up localisation model:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/* backwards compatibility: */
|
||||
#ifdef BOOST_RE_LOCALE_C
|
||||
# define BOOST_REGEX_USE_C_LOCALE
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_RE_LOCALE_CPP
|
||||
# define BOOST_REGEX_USE_CPP_LOCALE
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
# define BOOST_REGEX_USE_C_LOCALE
|
||||
#endif
|
||||
|
||||
/* use C++ locale when targeting windows store */
|
||||
#if BOOST_PLAT_WINDOWS_RUNTIME
|
||||
# define BOOST_REGEX_USE_CPP_LOCALE
|
||||
# define BOOST_REGEX_NO_WIN32_LOCALE
|
||||
#endif
|
||||
|
||||
/* Win32 defaults to native Win32 locale: */
|
||||
#if defined(_WIN32) && \
|
||||
!defined(BOOST_REGEX_USE_WIN32_LOCALE) && \
|
||||
!defined(BOOST_REGEX_USE_C_LOCALE) && \
|
||||
!defined(BOOST_REGEX_USE_CPP_LOCALE) && \
|
||||
!defined(BOOST_REGEX_NO_W32) && \
|
||||
!defined(BOOST_REGEX_NO_WIN32_LOCALE)
|
||||
# define BOOST_REGEX_USE_WIN32_LOCALE
|
||||
#endif
|
||||
/* otherwise use C++ locale if supported: */
|
||||
#if !defined(BOOST_REGEX_USE_WIN32_LOCALE) && !defined(BOOST_REGEX_USE_C_LOCALE) && !defined(BOOST_REGEX_USE_CPP_LOCALE) && !defined(BOOST_NO_STD_LOCALE)
|
||||
# define BOOST_REGEX_USE_CPP_LOCALE
|
||||
#endif
|
||||
/* otherwise use C locale: */
|
||||
#if !defined(BOOST_REGEX_USE_WIN32_LOCALE) && !defined(BOOST_REGEX_USE_C_LOCALE) && !defined(BOOST_REGEX_USE_CPP_LOCALE)
|
||||
# define BOOST_REGEX_USE_C_LOCALE
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_REGEX_MAX_STATE_COUNT
|
||||
# define BOOST_REGEX_MAX_STATE_COUNT 100000000
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Error Handling for exception free compilers:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef BOOST_NO_EXCEPTIONS
|
||||
/*
|
||||
* If there are no exceptions then we must report critical-errors
|
||||
* the only way we know how; by terminating.
|
||||
*/
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
# define BOOST_REGEX_NOEH_ASSERT(x)\
|
||||
if(0 == (x))\
|
||||
{\
|
||||
std::string s("Error: critical regex++ failure in: ");\
|
||||
s.append(#x);\
|
||||
std::runtime_error e(s);\
|
||||
boost::throw_exception(e);\
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* With exceptions then error handling is taken care of and
|
||||
* there is no need for these checks:
|
||||
*/
|
||||
# define BOOST_REGEX_NOEH_ASSERT(x)
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Stack protection under MS Windows:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if !defined(BOOST_REGEX_NO_W32) && !defined(BOOST_REGEX_V3)
|
||||
# if(defined(_WIN32) || defined(_WIN64) || defined(_WINCE)) \
|
||||
&& !(defined(__GNUC__) || defined(__BORLANDC__) && defined(__clang__)) \
|
||||
&& !(defined(__BORLANDC__) && (__BORLANDC__ >= 0x600)) \
|
||||
&& !(defined(__MWERKS__) && (__MWERKS__ <= 0x3003))
|
||||
# define BOOST_REGEX_HAS_MS_STACK_GUARD
|
||||
# endif
|
||||
#elif defined(BOOST_REGEX_HAS_MS_STACK_GUARD)
|
||||
# undef BOOST_REGEX_HAS_MS_STACK_GUARD
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) && defined(BOOST_REGEX_HAS_MS_STACK_GUARD)
|
||||
|
||||
namespace boost{
|
||||
namespace BOOST_REGEX_DETAIL_NS{
|
||||
|
||||
BOOST_REGEX_DECL void BOOST_REGEX_CALL reset_stack_guard_page();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Algorithm selection and configuration.
|
||||
* These options are now obsolete for C++11 and later (regex v5).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if !defined(BOOST_REGEX_RECURSIVE) && !defined(BOOST_REGEX_NON_RECURSIVE)
|
||||
# if defined(BOOST_REGEX_HAS_MS_STACK_GUARD) && !defined(_STLP_DEBUG) && !defined(__STL_DEBUG) && !(defined(_MSC_VER) && (_MSC_VER >= 1400)) && defined(BOOST_REGEX_CXX03)
|
||||
# define BOOST_REGEX_RECURSIVE
|
||||
# else
|
||||
# define BOOST_REGEX_NON_RECURSIVE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_REGEX_NON_RECURSIVE
|
||||
# ifdef BOOST_REGEX_RECURSIVE
|
||||
# error "Can't set both BOOST_REGEX_RECURSIVE and BOOST_REGEX_NON_RECURSIVE"
|
||||
# endif
|
||||
# ifndef BOOST_REGEX_BLOCKSIZE
|
||||
# define BOOST_REGEX_BLOCKSIZE 4096
|
||||
# endif
|
||||
# if BOOST_REGEX_BLOCKSIZE < 512
|
||||
# error "BOOST_REGEX_BLOCKSIZE must be at least 512"
|
||||
# endif
|
||||
# ifndef BOOST_REGEX_MAX_BLOCKS
|
||||
# define BOOST_REGEX_MAX_BLOCKS 1024
|
||||
# endif
|
||||
# ifdef BOOST_REGEX_HAS_MS_STACK_GUARD
|
||||
# undef BOOST_REGEX_HAS_MS_STACK_GUARD
|
||||
# endif
|
||||
# ifndef BOOST_REGEX_MAX_CACHE_BLOCKS
|
||||
# define BOOST_REGEX_MAX_CACHE_BLOCKS 16
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Diagnostics:
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef BOOST_REGEX_CONFIG_INFO
|
||||
BOOST_REGEX_DECL void BOOST_REGEX_CALL print_regex_library_info();
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_REGEX_DIAG)
|
||||
# pragma message ("BOOST_REGEX_DECL" BOOST_STRINGIZE(=BOOST_REGEX_DECL))
|
||||
# pragma message ("BOOST_REGEX_CALL" BOOST_STRINGIZE(=BOOST_REGEX_CALL))
|
||||
# pragma message ("BOOST_REGEX_CCALL" BOOST_STRINGIZE(=BOOST_REGEX_CCALL))
|
||||
#ifdef BOOST_REGEX_USE_C_LOCALE
|
||||
# pragma message ("Using C locale in regex traits class")
|
||||
#elif BOOST_REGEX_USE_CPP_LOCALE
|
||||
# pragma message ("Using C++ locale in regex traits class")
|
||||
#else
|
||||
# pragma message ("Using Win32 locale in regex traits class")
|
||||
#endif
|
||||
#if defined(BOOST_REGEX_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)
|
||||
# pragma message ("Dynamic linking enabled")
|
||||
#endif
|
||||
#if defined(BOOST_REGEX_NO_LIB) || defined(BOOST_ALL_NO_LIB)
|
||||
# pragma message ("Auto-linking disabled")
|
||||
#endif
|
||||
#ifdef BOOST_REGEX_NO_EXTERNAL_TEMPLATES
|
||||
# pragma message ("Extern templates disabled")
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
72
lib/third_party/boost/regex/include/boost/regex/config/borland.hpp
vendored
Normal file
72
lib/third_party/boost/regex/include/boost/regex/config/borland.hpp
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE boost/regex/config/borland.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: regex borland-specific config setup.
|
||||
*/
|
||||
|
||||
|
||||
#if defined(__BORLANDC__) && !defined(__clang__)
|
||||
# if (__BORLANDC__ == 0x550) || (__BORLANDC__ == 0x551)
|
||||
// problems with std::basic_string and dll RTL:
|
||||
# if defined(_RTLDLL) && defined(_RWSTD_COMPILE_INSTANTIATE)
|
||||
# ifdef BOOST_REGEX_BUILD_DLL
|
||||
# error _RWSTD_COMPILE_INSTANTIATE must not be defined when building regex++ as a DLL
|
||||
# else
|
||||
# pragma message("Defining _RWSTD_COMPILE_INSTANTIATE when linking to the DLL version of the RTL may produce memory corruption problems in std::basic_string, as a result of separate versions of basic_string's static data in the RTL and you're exe/dll: be warned!!")
|
||||
# endif
|
||||
# endif
|
||||
# ifndef _RTLDLL
|
||||
// this is harmless for a staic link:
|
||||
# define _RWSTD_COMPILE_INSTANTIATE
|
||||
# endif
|
||||
// external templates cause problems for some reason:
|
||||
# define BOOST_REGEX_NO_EXTERNAL_TEMPLATES
|
||||
# endif
|
||||
# if (__BORLANDC__ <= 0x540) && !defined(BOOST_REGEX_NO_LIB) && !defined(_NO_VCL)
|
||||
// C++ Builder 4 and earlier, we can't tell whether we should be using
|
||||
// the VCL runtime or not, do a static link instead:
|
||||
# define BOOST_REGEX_STATIC_LINK
|
||||
# endif
|
||||
//
|
||||
// VCL support:
|
||||
// if we're building a console app then there can't be any VCL (can there?)
|
||||
# if !defined(__CONSOLE__) && !defined(_NO_VCL)
|
||||
# define BOOST_REGEX_USE_VCL
|
||||
# endif
|
||||
//
|
||||
// if this isn't Win32 then don't automatically select link
|
||||
// libraries:
|
||||
//
|
||||
# ifndef _Windows
|
||||
# ifndef BOOST_REGEX_NO_LIB
|
||||
# define BOOST_REGEX_NO_LIB
|
||||
# endif
|
||||
# ifndef BOOST_REGEX_STATIC_LINK
|
||||
# define BOOST_REGEX_STATIC_LINK
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#if __BORLANDC__ < 0x600
|
||||
//
|
||||
// string workarounds:
|
||||
//
|
||||
#include <cstring>
|
||||
#undef strcmp
|
||||
#undef strcpy
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
207
lib/third_party/boost/regex/include/boost/regex/config/cwchar.hpp
vendored
Normal file
207
lib/third_party/boost/regex/include/boost/regex/config/cwchar.hpp
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
*
|
||||
* Copyright (c) 1998-2002
|
||||
* John Maddock
|
||||
*
|
||||
* Use, modification and distribution are subject to the
|
||||
* Boost Software License, Version 1.0. (See accompanying file
|
||||
* LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* LOCATION: see http://www.boost.org for most recent version.
|
||||
* FILE boost/regex/config/cwchar.hpp
|
||||
* VERSION see <boost/version.hpp>
|
||||
* DESCRIPTION: regex wide character string fixes.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REGEX_CONFIG_CWCHAR_HPP
|
||||
#define BOOST_REGEX_CONFIG_CWCHAR_HPP
|
||||
|
||||
#include <cwchar>
|
||||
#include <cwctype>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER)
|
||||
// apparently this is required for the RW STL on Linux:
|
||||
#undef iswalnum
|
||||
#undef iswalpha
|
||||
#undef iswblank
|
||||
#undef iswcntrl
|
||||
#undef iswdigit
|
||||
#undef iswgraph
|
||||
#undef iswlower
|
||||
#undef iswprint
|
||||
#undef iswprint
|
||||
#undef iswpunct
|
||||
#undef iswspace
|
||||
#undef iswupper
|
||||
#undef iswxdigit
|
||||
#undef iswctype
|
||||
#undef towlower
|
||||
#undef towupper
|
||||
#undef towctrans
|
||||
#undef wctrans
|
||||
#undef wctype
|
||||
#endif
|
||||
|
||||
namespace std{
|
||||
|
||||
#ifndef BOOST_NO_STDC_NAMESPACE
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
#ifdef iswalnum
|
||||
inline int (iswalnum)(wint_t i)
|
||||
{ return iswalnum(i); }
|
||||
#undef iswalnum
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswalnum;
|
||||
#endif
|
||||
|
||||
#ifdef iswalpha
|
||||
inline int (iswalpha)(wint_t i)
|
||||
{ return iswalpha(i); }
|
||||
#undef iswalpha
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswalpha;
|
||||
#endif
|
||||
|
||||
#ifdef iswcntrl
|
||||
inline int (iswcntrl)(wint_t i)
|
||||
{ return iswcntrl(i); }
|
||||
#undef iswcntrl
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswcntrl;
|
||||
#endif
|
||||
|
||||
#ifdef iswdigit
|
||||
inline int (iswdigit)(wint_t i)
|
||||
{ return iswdigit(i); }
|
||||
#undef iswdigit
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswdigit;
|
||||
#endif
|
||||
|
||||
#ifdef iswgraph
|
||||
inline int (iswgraph)(wint_t i)
|
||||
{ return iswgraph(i); }
|
||||
#undef iswgraph
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswgraph;
|
||||
#endif
|
||||
|
||||
#ifdef iswlower
|
||||
inline int (iswlower)(wint_t i)
|
||||
{ return iswlower(i); }
|
||||
#undef iswlower
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswlower;
|
||||
#endif
|
||||
|
||||
#ifdef iswprint
|
||||
inline int (iswprint)(wint_t i)
|
||||
{ return iswprint(i); }
|
||||
#undef iswprint
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswprint;
|
||||
#endif
|
||||
|
||||
#ifdef iswpunct
|
||||
inline int (iswpunct)(wint_t i)
|
||||
{ return iswpunct(i); }
|
||||
#undef iswpunct
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswpunct;
|
||||
#endif
|
||||
|
||||
#ifdef iswspace
|
||||
inline int (iswspace)(wint_t i)
|
||||
{ return iswspace(i); }
|
||||
#undef iswspace
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswspace;
|
||||
#endif
|
||||
|
||||
#ifdef iswupper
|
||||
inline int (iswupper)(wint_t i)
|
||||
{ return iswupper(i); }
|
||||
#undef iswupper
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswupper;
|
||||
#endif
|
||||
|
||||
#ifdef iswxdigit
|
||||
inline int (iswxdigit)(wint_t i)
|
||||
{ return iswxdigit(i); }
|
||||
#undef iswxdigit
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::iswxdigit;
|
||||
#endif
|
||||
|
||||
#ifdef towlower
|
||||
inline wint_t (towlower)(wint_t i)
|
||||
{ return towlower(i); }
|
||||
#undef towlower
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::towlower;
|
||||
#endif
|
||||
|
||||
#ifdef towupper
|
||||
inline wint_t (towupper)(wint_t i)
|
||||
{ return towupper(i); }
|
||||
#undef towupper
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using :: towupper;
|
||||
#endif
|
||||
|
||||
#ifdef wcscmp
|
||||
inline int (wcscmp)(const wchar_t *p1, const wchar_t *p2)
|
||||
{ return wcscmp(p1,p2); }
|
||||
#undef wcscmp
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::wcscmp;
|
||||
#endif
|
||||
|
||||
#ifdef wcscoll
|
||||
inline int (wcscoll)(const wchar_t *p1, const wchar_t *p2)
|
||||
{ return wcscoll(p1,p2); }
|
||||
#undef wcscoll
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE) && !defined(UNDER_CE)
|
||||
using ::wcscoll;
|
||||
#endif
|
||||
|
||||
#ifdef wcscpy
|
||||
inline wchar_t *(wcscpy)(wchar_t *p1, const wchar_t *p2)
|
||||
{ return wcscpy(p1,p2); }
|
||||
#undef wcscpy
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::wcscpy;
|
||||
#endif
|
||||
|
||||
#ifdef wcslen
|
||||
inline size_t (wcslen)(const wchar_t *p)
|
||||
{ return wcslen(p); }
|
||||
#undef wcslen
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::wcslen;
|
||||
#endif
|
||||
|
||||
#ifdef wcsxfrm
|
||||
size_t wcsxfrm(wchar_t *p1, const wchar_t *p2, size_t s)
|
||||
{ return wcsxfrm(p1,p2,s); }
|
||||
#undef wcsxfrm
|
||||
#elif defined(BOOST_NO_STDC_NAMESPACE)
|
||||
using ::wcsxfrm;
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BOOST_NO_STDC_NAMESPACE
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user